def sleeping_gas(x, y, radius, duration): path = util.set_full_explore_map(game.current_map) libtcod.dijkstra_compute(path, x, y) for i in range(-radius, radius + 1): for j in range(-radius, radius + 1): if libtcod.dijkstra_get_distance(path, x + i, y + j) <= radius and libtcod.dijkstra_get_distance(path, x + i, y + j) >= 0: game.current_map.tile[x + i][y + j].update({'icon': game.current_map.tile[x + i][y + j]['icon'], 'back_light_color': libtcod.Color(115, 220, 225), 'back_dark_color': libtcod.Color(0, 143, 189), 'lerp': round(libtcod.random_get_float(game.rnd, 0, 1), 1), 'duration': game.turns + duration, 'type': 'sleep_gas'}) for obj in game.current_map.objects: if obj.item is None: if obj.x == x + i and obj.y == y + j: if obj.name == 'player': game.message.new('You are caught in a sleeping cloud!', game.turns) if 'sleep' not in game.player.flags: dice = util.roll_dice(1, 50) if dice > game.player.wisdom + (game.player.karma / 2): game.message.new('You fall asleep!', game.turns, libtcod.Color(0, 143, 189)) game.player.flags.append('sleep') else: if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y): game.message.new(obj.entity.article.capitalize() + obj.entity.get_name() + ' is caught in a sleeping cloud!', game.turns) if 'sleep' not in obj.entity.flags: dice = util.roll_dice(1, 3) if dice == 3: if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y): game.message.new(obj.entity.article.capitalize() + obj.entity.get_name() + ' falls asleep!', game.turns) obj.entity.flags.append('sleep')
def stats_bonus(self): self.strength = self.base_strength self.dexterity = self.base_dexterity self.intelligence = self.base_intelligence self.wisdom = self.base_wisdom self.endurance = self.base_endurance self.karma = self.base_karma self.set_max_health() self.set_max_mana() self.set_max_stamina() for i in range(len(self.equipment)): if 'str_bonus' in self.equipment[i].flags: self.strength += self.equipment[i].bonus if 'dex_bonus' in self.equipment[i].flags: self.dexterity += self.equipment[i].bonus if 'int_bonus' in self.equipment[i].flags: self.intelligence += self.equipment[i].bonus if 'wis_bonus' in self.equipment[i].flags: self.wisdom += self.equipment[i].bonus if 'end_bonus' in self.equipment[i].flags: self.endurance += self.equipment[i].bonus if 'health_bonus1' in self.equipment[i].flags: if self.equipment[i].bonus == 0: self.equipment[i].bonus = util.roll_dice(1, 6) self.max_health += self.equipment[i].bonus if 'mana_bonus1' in self.equipment[i].flags: if self.equipment[i].bonus == 0: self.equipment[i].bonus = util.roll_dice(1, 6) self.max_mana += self.equipment[i].bonus if 'stamina_bonus1' in self.equipment[i].flags: if self.equipment[i].bonus == 0: self.equipment[i].bonus = util.roll_dice(1, 6) self.max_stamina += self.equipment[i].bonus
def attack(self, target, ranged=False): attacker = util.roll_dice(1, 50) defender = util.roll_dice(1, 50) weapon = None weapon_type = 'weapon' missile = None missile_slot_type = 'missile' for i in range(len(self.equipment)): if self.equipment[i].type == 'weapon': weapon = self.equipment[i] for j in range(len(self.equipment[i].flags)): if 'missile_' in self.equipment[i].flags[j]: weapon_type = self.equipment[i].flags[j] if self.equipment[i].type == 'missile': missile = self.equipment[i] for j in range(len(self.equipment[i].flags)): if 'missile_' in self.equipment[i].flags[j]: missile_slot_type = self.equipment[i].flags[j] if ranged and weapon_type != missile_slot_type: game.message.new("You don't have any ammo for that weapon!", game.turns, libtcod.light_red) else: if not target.entity.is_hostile(): target.entity.becomes_hostile() if ranged: effects.missile_attack(game.char.x, game.char.y, target.x, target.y) if (attacker != 1 and defender != 50 and ((attacker + self.attack_rating()) >= (defender + target.entity.defense_rating) or attacker == 50 or defender == 1)) or target.entity.is_disabled(): damage = 0 if weapon is not None: quality_bonus = 0.75 + (0.25 * weapon.quality) damage = int(weapon.dice.roll_dice() * quality_bonus) damage += self.damage_modifiers(weapon) if damage == 0: damage = util.roll_dice(1, 4) game.message.new('You hit ' + target.entity.get_name(True) + ' for ' + str(damage) + ' pts of damage.', game.turns, libtcod.light_yellow) target.entity.take_damage(target.x, target.y, damage, 'player') if target.entity.is_dead(): game.message.new('The ' + target.entity.get_name() + ' dies!', game.turns, libtcod.light_orange) self.gain_xp(target.entity.give_xp()) self.mks += 1 target.entity.loot(target.x, target.y) target.delete() self.skills[self.find_weapon_type()].gain_xp(2) else: if ranged: item = game.baseitems.create_item(missile.status, missile.prefix, missile.name, missile.suffix, missile.flags) obj = mapgen.Object(target.x, target.y, item.icon, item.name, item.color, True, item=item) obj.first_appearance = game.turns game.current_map.objects.append(obj) obj.send_to_back() game.message.new('You missed the ' + target.entity.get_name() + '.', game.turns) self.skills[self.find_weapon_type()].gain_xp(1) if ranged: missile.lose_quantity() self.lose_stamina(1) game.player_move = True
def damage_modifiers(self, obj): modifier = 0 if 'damage_bonus1' in obj.flags: modifier += util.roll_dice(1, 6) if 'damage_bonus2' in obj.flags: modifier += util.roll_dice(1, 6, 2) if 'damage_bonus3' in obj.flags: modifier += util.roll_dice(1, 6, 3) return modifier
def attack(self): attacker = util.roll_dice(1, 50) defender = util.roll_dice(1, 50) if (attacker != 1 and defender != 50 and ((attacker + self.attack_rating) >= (defender + game.player.defense_rating()) or attacker == 50 or defender == 1)) or game.player.is_disabled(): damage = self.damage.roll_dice() game.message.new(self.article.capitalize() + self.get_name() + ' hits you for ' + str(damage) + ' pts of damage.', game.turns, libtcod.light_red) game.player.take_damage(damage, self.article + self.name) else: game.message.new(self.article.capitalize() + self.get_name() + ' attacks you but misses.', game.turns)
def place_doors(self): for y in range(1, self.map_height - 1): for x in range(1, self.map_width - 1): if (self.tile[x + 1][y]['name'] == 'floor' and self.tile[x - 1][y]['name'] == 'floor' and self.tile[x][y - 1]['name'] == 'wall' and self.tile[x][y + 1]['name'] == 'wall') or (self.tile[x + 1][y]['name'] == 'wall' and self.tile[x - 1][y]['name'] == 'wall' and self.tile[x][y - 1]['name'] == 'floor' and self.tile[x][y + 1]['name'] == 'floor'): if util.roll_dice(1, 50) == 50: if util.roll_dice(1, 40) + self.threat_level >= 40: self.set_tile_values('locked door', x, y) else: self.set_tile_values('door', x, y)
def roll_from_dice_string(dice_string, size): if dice_string == 'D3': return roll_dice(3, size=size) elif dice_string == 'D6': return roll_dice(6, size=size) elif dice_string == '2D6': return roll_dice(6, size=size) + roll_dice(6, size=size) else: raise Exception('Invalid dice string')
def loot(self, x, y): corpse = util.roll_dice(1, 100) if corpse <= self.corpse: d = game.baseitems.create_corpse(self.name, self.weight) drop = mapgen.Object(x, y, d.icon, d.name, d.color, True, item=d) game.current_map.objects.append(drop) drop.send_to_back() drop_chance = util.roll_dice(1, 100) if drop_chance >= 80: drop = game.baseitems.loot_generation(x, y, self.level) game.current_map.objects.append(drop) drop.send_to_back()
def transitions(self): coord = [self.location_level - game.WORLDMAP_WIDTH, self.location_level - 1, self.location_level + 1, self.location_level + game.WORLDMAP_WIDTH, self.location_level - game.WORLDMAP_WIDTH - 1, self.location_level - game.WORLDMAP_WIDTH + 1, self.location_level + game.WORLDMAP_WIDTH - 1, self.location_level + game.WORLDMAP_WIDTH + 1] for i in range(len(coord)): terrain = util.find_terrain_type(coord[i]) length = 5 aa = self.map_width if i in [1, 2]: aa = self.map_height if game.terrain[terrain]['elevation'] > game.terrain[util.find_terrain_type(self.location_level)]['maxelev']: if i < 4: for x in range(aa): for y in range(length): if i == 0: self.set_tile_values(game.terrain[terrain]['type'], x, y) if i == 1: self.set_tile_values(game.terrain[terrain]['type'], y, x) if i == 2: self.set_tile_values(game.terrain[terrain]['type'], self.map_width - y - 1, x) if i == 3: self.set_tile_values(game.terrain[terrain]['type'], x, self.map_height - y - 1) dice = util.roll_dice(1, 100) if dice < 50: length -= 1 else: length += 1 if length < 3: length = 3 if length > 7: length = 7 else: for x in range(aa, 5): for y in range(length): if i == 4: self.set_tile_values(game.terrain[terrain]['type'], x, y) if i == 5: self.set_tile_values(game.terrain[terrain]['type'], self.map_width - x - 1, y) if i == 6: self.set_tile_values(game.terrain[terrain]['type'], x, self.map_height - y - 1) if i == 7: self.set_tile_values(game.terrain[terrain]['type'], self.map_width - x - 1, self.map_height - y - 1) dice = util.roll_dice(1, 100) if dice < 50: length -= 1 else: length += 1 if length < 3: length = 3 if length > 7: length = 7
def check_active_effects(): for y in range(game.current_map.map_height): for x in range(game.current_map.map_width): if 'duration' in game.current_map.tile[x][y]: if game.current_map.tile[x][y]['duration'] < game.turns: explored = game.current_map.tile_is_explored(x, y) game.current_map.set_tile_values(game.current_map.tile[x][y]['name'], x, y) if game.current_map.tile_is_invisible(x, y): game.current_map.tile[x][y].pop('invisible', None) if explored: game.current_map.tile[x][y].update({'explored': True}) for obj in game.current_map.objects: if obj.name == 'player': if 'type' in game.current_map.tile[game.char.x][game.char.y]: if game.current_map.tile[game.char.x][game.char.y]['type'] == 'poison_gas': game.message.new('You step into poisonous gas!', game.turns) if 'poison' not in game.player.flags: dice = util.roll_dice(1, 50) if dice > game.player.endurance + (game.player.karma / 2): game.message.new('You are poisoned!', game.turns, libtcod.Color(0, 112, 0)) game.player.flags.append('poison') if game.current_map.tile[game.char.x][game.char.y]['type'] == 'sleep_gas': if 'sleep' not in game.player.flags: game.message.new('You step into sleeping gas!', game.turns) dice = util.roll_dice(1, 50) if dice > game.player.wisdom + (game.player.karma / 2): game.message.new('You fall asleep!', game.turns, libtcod.Color(0, 143, 189)) game.player.flags.append('sleep') elif obj.entity: if 'type' in game.current_map.tile[obj.x][obj.y]: if game.current_map.tile[obj.x][obj.y]['type'] == 'poison_gas': if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y): game.message.new(obj.entity.article.capitalize() + obj.entity.get_name() + ' step into poisonous gas!', game.turns) if 'poison' not in obj.entity.flags: dice = util.roll_dice(1, 3) if dice == 3: obj.entity.flags.append('poison') if game.current_map.tile[obj.x][obj.y]['type'] == 'sleep_gas': if 'sleep' not in obj.entity.flags: if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y): game.message.new(obj.entity.article.capitalize() + obj.entity.get_name() + ' step into sleeping gas!', game.turns) dice = util.roll_dice(1, 3) if dice == 3: if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y): game.message.new(obj.entity.article.capitalize() + obj.entity.get_name() + ' falls asleep!', game.turns) obj.entity.flags.append('sleep')
def missile_attack(sx, sy, dx, dy, trap=False): cx, cy = sx, sy if sx == dx: char = '|' if sy == dy: char = chr(196) if (sx < dx and sy > dy) or (sx > dx and sy < dy): char = '/' if (sx < dx and sy < dy) or (sx > dx and sy > dy): char = '\\' path = util.set_full_explore_map(game.current_map, False) libtcod.path_compute(path, sx, sy, dx, dy) while not libtcod.path_is_empty(path): cx, cy = libtcod.path_walk(path, False) libtcod.console_blit(game.con, 0, 0, game.MAP_WIDTH, game.MAP_HEIGHT, 0, game.MAP_X, game.MAP_Y) libtcod.console_put_char_ex(0, game.MAP_X + cx - game.curx, game.MAP_Y + cy - game.cury, char, libtcod.light_gray, libtcod.black) libtcod.console_flush() time.sleep(0.05) if trap: for obj in game.current_map.objects: if obj.x == dx and obj.y == dy and not obj.item: damage = util.roll_dice(1, 6) if obj.name == 'player': game.message.new('You are hit by an arrow for ' + str(damage) + ' pts of damage!', game.turns, libtcod.Color(160, 0, 0)) game.player.take_damage(damage, 'an arrow trap') else: obj.entity.take_damage(obj.x, obj.y, damage, 'an arrow', True)
def fireball(x, y, radius): path = util.set_full_explore_map(game.current_map) libtcod.dijkstra_compute(path, x, y) for step in range(0, radius + 1): player_fov = False for i in range(-radius, radius + 1): for j in range(-radius, radius + 1): if libtcod.map_is_in_fov(game.fov_map, x + i, y + j) and libtcod.dijkstra_get_distance(path, x + i, y + j) <= step and libtcod.dijkstra_get_distance(path, x + i, y + j) >= 0: (front, back, lerp) = util.render_tiles_animations(x + i, y + j, libtcod.Color(160, 0, 0), libtcod.Color(64, 0, 0), libtcod.Color(0, 0, 0), round(libtcod.random_get_float(game.rnd, 0, 1), 1)) libtcod.console_put_char_ex(0, game.MAP_X + x - game.curx + i, game.MAP_Y + y - game.cury + j, '*', front, back) player_fov = True if player_fov: libtcod.console_flush() time.sleep(0.05) player_fov = False for obj in game.current_map.objects: damage = util.roll_dice(1, 10) if obj.name == 'player': if libtcod.dijkstra_get_distance(path, game.char.x, game.char.y) <= radius: game.message.new('You are hit by a fireball for ' + str(damage) + ' pts of damage!', game.turns, libtcod.Color(160, 0, 0)) game.player.take_damage(damage, 'a fireball') elif obj.entity: if libtcod.dijkstra_get_distance(path, obj.x, obj.y) <= radius: obj.entity.take_damage(obj.x, obj.y, damage, 'a fireball', True)
def roll_dice(cade, message): # of the form "1d6" dice = message.content cade.send_message(message.channel, message.author.name + ' rolled {0}!'.format(util.roll_dice(dice)))
def bash(): attempt = False for x in range(-1, 2): for y in range(-1, 2): if 'locked' in game.current_map.tile[game.char.x + x][game.char.y + y]: dice = util.roll_dice(1, 40) name = game.current_map.tile[game.char.x + x][game.char.y + y]['name'] if game.player.strength >= dice: game.message.new('You bash open the ' + name + '.', game.turns) if name == 'locked door': game.current_map.set_tile_values('opened door', game.char.x + x, game.char.y + y) if name == 'locked chest': if 'trapped' in game.current_map.tile[game.char.x + x][game.char.y + y]: game.current_map.tile[game.char.x + x][game.char.y + y].update({game.chest_trap[libtcod.random_get_int(game.rnd, 0, len(game.chest_trap) - 1)]: True}) game.current_map.tile[game.char.x + x][game.char.y + y].pop('trapped', None) util.trigger_trap(game.char.x + x, game.char.y + y, chest=True) game.current_map.set_tile_values('empty chest', game.char.x + x, game.char.y + y) nb_items = libtcod.random_get_int(game.rnd, 2, 4) for i in range(nb_items): game.current_map.objects.append(game.baseitems.loot_generation(game.char.x + x, game.char.y + y, game.current_map.threat_level)) else: game.message.new('You failed to bash open the ' + name + '.', game.turns) game.player.take_damage(1, 'bashing a ' + name) game.player.lose_stamina(1) game.player_move = True attempt = True if not attempt: game.message.new('You bash air. You find it strangely exhilarating.', game.turns)
def check_condition(self, x, y): if 'stuck' in self.flags: dice = util.roll_dice(1, 10) if dice == 10: self.flags.remove('stuck') if 'poison' in self.flags: dice = util.roll_dice(1, 10) if dice == 10: self.flags.remove('poison') else: self.take_damage(x, y, 1, 'poison') if 'sleep' in self.flags: dice = util.roll_dice(1, 10) if dice == 10: if libtcod.map_is_in_fov(game.fov_map, x, y): game.message.new('The ' + self.get_name() + 'woke up.', game.turns) self.flags.remove('sleep')
def poison_needle(x, y): for obj in game.current_map.objects: if obj.x == x and obj.y == y and not obj.item: damage = util.roll_dice(1, 4) if obj.name == 'player': game.message.new('You are hit by a poison needle!', game.turns) if 'poison' not in game.player.flags: dice = util.roll_dice(1, 50) if dice > game.player.endurance + (game.player.karma / 2): game.message.new('You are poisoned!', game.turns, libtcod.Color(0, 112, 0)) game.player.flags.append('poison') game.player.take_damage(damage, 'a poison needle') else: if 'poison' not in obj.entity.flags: dice = util.roll_dice(1, 3) if dice == 3: obj.entity.flags.append('poison') obj.entity.take_damage(obj.x, obj.y, damage, 'a poison needle')
def check_condition(self): if 'stuck' in self.flags: dice = util.roll_dice(1, 120) if self.strength + (self.karma / 2) >= dice: game.message.new('You can move freely again.', game.turns) self.flags.remove('stuck') if 'poison' in self.flags: dice = util.roll_dice(1, 120) if self.endurance + (self.karma / 2) >= dice: game.message.new('You are no longer poisoned.', game.turns) self.flags.remove('poison') else: self.take_damage(1, 'poison') if 'sleep' in self.flags: dice = util.roll_dice(1, 120) if self.wisdom + (self.karma / 2) >= dice: game.message.new('You wake up.', game.turns) self.flags.remove('sleep')
def loot_generation(self, x, y, level): prefix, suffix = None, None status = '' # generate base item dice = util.roll_dice(1, 100) if dice <= 10: d = self.get_item_by_type('money', level) else: if dice <= 80: d = self.get_item_by_level(level) elif dice <= 99: d = self.get_item_by_level(level + 1) else: d = self.get_item_by_level(level + 2) # generate prefix pdice = util.roll_dice(1, 100) if pdice >= 100 - (level * 6): if pdice <= 85: prefix = game.prefix.get_prefix_by_level(level, d.type) else: prefix = game.prefix.get_prefix_by_level(level + 1, d.type) # generate suffix sdice = util.roll_dice(1, 100) if sdice >= 100 - (level * 6): if sdice <= 85: suffix = game.suffix.get_suffix_by_level(level, d.type) else: suffix = game.suffix.get_suffix_by_level(level + 1, d.type) # generate status stdice = util.roll_dice(1, 100) if stdice <= 90: status = 'uncursed ' elif stdice <= 95: status = 'blessed ' else: status = 'cursed ' loot = self.generate_item_stats(status, prefix, d, suffix) obj = mapgen.Object(x, y, loot.icon, loot.name, loot.color, True, item=loot) return obj
def pick_up(self, ts): if self.type == 'money': multiplier = 1 if self.name == 'gold pieces': gold = util.roll_dice(2, 15 * (game.current_map.threat_level - 10)) multiplier = 10000 elif self.name == 'silver pieces': gold = util.roll_dice(2, 15 * (game.current_map.threat_level - 5)) multiplier = 100 else: gold = util.roll_dice(2, 15 * game.current_map.threat_level) game.message.new('You pick up ' + str(gold) + ' ' + self.name + '.', game.turns, libtcod.gold) game.player.money += gold * multiplier else: self.quantity = 1 game.message.new('You pick up ' + self.get_name(True) + '.', game.turns, libtcod.green) self.turn_created = ts game.player.inventory.append(self) game.player_move = True
def place_traps(self, ground): traps = util.roll_dice(1, 3) for i in range(0, traps): x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) while self.tile[x][y]['type'] != ground: x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) self.set_tile_values('trap', x, y, 'trap') temp_tile = game.tiles.get_tile(ground) self.tile[x][y].update({'icon': temp_tile.icon, 'color': temp_tile.color, 'dark_color': libtcod.color_lerp(libtcod.black, temp_tile.color, 0.3)})
def climb_down_stairs(): location_name = game.current_map.location_name location_abbr = game.current_map.location_abbr location_id = game.current_map.location_id threat_level = game.current_map.threat_level dungeon_type = game.current_map.type map_width = game.DUNGEON_MAP_WIDTH map_height = game.DUNGEON_MAP_HEIGHT op = (0, 0, 0) if game.current_map.tile[game.char.x][game.char.y]['icon'] != '>': game.message.new('You see no stairs going in that direction!', game.turns) else: if game.current_map.location_id > 0: level = game.current_map.location_level + 1 game.message.new('You climb down the stairs.', game.turns) util.store_map(game.current_map) IO.autosave(False) map_width = game.current_map.map_width map_height = game.current_map.map_height dice = util.roll_dice(1, 10) if dice == 10: threat_level += 1 else: level = 1 for (id, name, abbr, x, y, tlevel, dtype) in game.worldmap.dungeons: if y * game.WORLDMAP_WIDTH + x == game.current_map.location_level: location_id = id location_name = name location_abbr = abbr threat_level = tlevel dungeon_type = dtype if dtype == 'Maze': map_width = game.MAP_WIDTH map_height = game.MAP_HEIGHT game.message.new('You enter the ' + location_name + '.', game.turns) util.decombine_maps() op = (game.current_map.location_level, game.char.x, game.char.y) util.store_map(game.current_map) for i in range(len(game.border_maps)): util.store_map(game.border_maps[i]) IO.autosave() util.loadgen_message() game.current_map = util.fetch_map({'name': location_name, 'id': location_id, 'abbr': location_abbr, 'level': level, 'threat': threat_level, 'map_width': map_width, 'map_height': map_height, 'type': dungeon_type}, dir='up') game.current_map.overworld_position = op IO.autosave_current_map() game.current_map.check_player_position() util.initialize_fov() game.fov_recompute = True game.player_move = True
def create_cave_maze(self, type, floor, wall, prob, oper): rooms = [0] * 2 for x in range(1, self.map_width - 1): for y in range(1, self.map_height - 1): if util.roll_dice(1, 100) < prob: self.set_tile_values(floor, x, y) for i in range(self.map_width * self.map_height * 5): x = libtcod.random_get_int(game.rnd, 1, self.map_width - 2) y = libtcod.random_get_int(game.rnd, 1, self.map_height - 2) if oper: if self.check_cell_neighbours(x, y) > 4: self.set_tile_values(wall, x, y) else: self.set_tile_values(floor, x, y) else: if self.check_cell_neighbours(x, y) > 4: self.set_tile_values(floor, x, y) else: self.set_tile_values(wall, x, y) # create rooms with up and down stairs x = libtcod.random_get_int(game.rnd, 2, self.map_width - 6) y = libtcod.random_get_int(game.rnd, 2, self.map_height - 6) rooms[0] = Rect(x, y, 5, 5) self.create_room(rooms[0], floor) (new_x1, new_y1) = rooms[0].center() game.char.x = new_x1 game.char.y = new_y1 count = 0 while (abs(x - new_x1) < 25) or (abs(y - new_y1) < 12): x = libtcod.random_get_int(game.rnd, 2, self.map_width - 6) y = libtcod.random_get_int(game.rnd, 2, self.map_height - 6) count += 1 if count == 50: return False rooms[1] = Rect(x, y, 5, 5) self.create_room(rooms[1], floor) (new_x2, new_y2) = rooms[1].center() # check if path to stairs is blocked if yes dig a tunnel path = util.set_full_explore_map(self, False) if not libtcod.path_compute(path, game.char.x, game.char.y, new_x2, new_y2): return False self.set_tile_values('stairs going up', game.char.x, game.char.y) self.up_staircase = (game.char.x, game.char.y) self.set_tile_values('stairs going down', new_x2, new_y2) self.down_staircase = (new_x2, new_y2) return True
def take_turn(self, x, y): if libtcod.map_is_in_fov(game.fov_map, x, y) and self.is_hostile(): #move towards player if far away dx, dy = 0, 0 if self.distance_to_player(game.char, x, y) >= 2: dx, dy = self.move_towards_player(game.char, x, y) if not self.can_move(x + dx, y + dy, True): dx, dy = 0, 0 else: self.attack() else: dx, dy = libtcod.random_get_int(game.rnd, -1, 1), libtcod.random_get_int(game.rnd, -1, 1) if x + dx < 0 or x + dx >= game.current_map.map_width: dx = 0 if y + dy < 0 or y + dy >= game.current_map.map_height: dy = 0 if not self.can_move(x + dx, y + dy, True): dx, dy = 0, 0 if all(i == 'ai_neutral' and i != 'ai_hostile' for i in self.flags): if self.distance_to_player(game.char, x, y) <= 2: turn_hostile = util.roll_dice(1, 100) if turn_hostile <= 10: self.flags.append('ai_hostile') elif all(i in self.flags for i in ['ai_neutral', 'ai_hostile']): return_neutral = util.roll_dice(1, 100) if return_neutral <= 10: self.flags[:] = (value for value in self.flags if value != 'ai_hostile') #retry if destination is blocked while game.current_map.tile_is_blocked(x + dx, y + dy): if dx == 0 and dy == 0: break dx, dy = libtcod.random_get_int(game.rnd, -1, 1), libtcod.random_get_int(game.rnd, -1, 1) if x + dx < 0 or x + dx >= game.current_map.map_width: dx = 0 if y + dy < 0 or y + dy >= game.current_map.map_height: dy = 0 return x + dx, y + dy
def place_monsters(self): x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) while self.tile_is_blocked(x, y) or libtcod.map_is_in_fov(game.fov_map, x, y): x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) # fetch monster to place base on threat level dice = util.roll_dice(1, 100, extra_roll=True) if dice <= 85: d = game.monsters.get_monster_by_level(self.threat_level, self.tile[x][y]['name'], self.type) else: d = game.monsters.get_monster_by_level(self.threat_level + 1, self.tile[x][y]['name'], self.type) if d: monster = Object(x, y, d.icon, d.name, d.color, blocks=True, entity=d) self.objects.insert(1, monster)
def stuck(x, y, victim='You'): for obj in game.current_map.objects: if obj.x == x and obj.y == y and not obj.item: dice = util.roll_dice(1, 10) if victim == 'You': if 'stuck' not in game.player.flags: game.player.flags.append('stuck') game.message.new('You are stuck in a bear trap!', game.turns) game.player.take_damage(dice, 'a bear trap') else: obj.entity.flags.append('stuck') obj.entity.take_damage(obj.x, obj.y, dice, 'a bear trap') if libtcod.map_is_in_fov(game.fov_map, x, y): game.message.new(victim + ' is stuck in a bear trap!', game.turns) elif not obj.entity.is_dead(): game.message.new('You hear a scream.', game.turns)
def attack_rating_modifiers(self): modifier = 0 for i in range(len(self.equipment)): if 'ar_bonus1' in self.equipment[i].flags: modifier += util.roll_dice(1, 4) if 'ar_bonus2' in self.equipment[i].flags: modifier += util.roll_dice(1, 4, 2) if 'ar_bonus3' in self.equipment[i].flags: modifier += util.roll_dice(1, 4, 3) if 'burdened' in self.flags: modifier -= util.roll_dice(1, 4) if 'strained' in self.flags: modifier -= util.roll_dice(1, 4, 2) if 'overburdened' in self.flags: modifier -= util.roll_dice(1, 4, 3) if 'hungry' in self.flags: modifier -= util.roll_dice(1, 4) if 'famished' in self.flags: modifier -= util.roll_dice(1, 4, 2) if 'starving' in self.flags: modifier -= util.roll_dice(1, 4, 3) return modifier
def roll_contest(cade, message): # of the form "1d6" dice = message.content cade.send_message(message.channel, message.author.name + " started a contest of " + dice) rolls = [] for user in message.server.members: if user.id == cade.user.id: continue roll = util.roll_dice(dice) rolls.append((user, roll)) cade.send_message(message.channel, user.name + " rolled a " + str(roll)) time.sleep(1) winner = max(rolls, key=lambda x: x[1]) cade.send_message(message.channel, "The winner is " + winner[0].name + "!")
def place_objects(self): num_monsters = self.randomize(self.max_monsters / 5, self.max_monsters, 3) num_items = self.randomize(self.max_items / 5, self.max_items, 3) if self.type in ['Mountain Peak', 'Sea', 'Ocean']: num_items = 0 if self.type == 'Mountain Peak': num_monsters = 0 for i in range(num_monsters): self.place_monsters() for i in range(num_items): x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) while self.tile_is_blocked(x, y) or self.tile[x][y]['name'] in ['high mountains', 'deep water', 'very deep water']: x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) chest = util.roll_dice(1, 20) if chest == 20: self.set_tile_values('locked chest', x, y) else: self.objects.append(game.baseitems.loot_generation(x, y, self.threat_level))
def stat_gain(self, st, dx, iq, wi, en): fate = util.roll_dice(1, 100) msg = 'You gain ' if fate <= st: self.strength += 1 self.base_strength += 1 msg += 'strength!' elif fate <= st + dx: self.dexterity += 1 self.base_dexterity += 1 msg += 'dexterity!' elif fate <= st + dx + iq: self.intelligence += 1 self.base_intelligence += 1 msg += 'intelligence!' elif fate <= st + dx + iq + wi: self.wisdom += 1 self.base_wisdom += 1 msg += 'wisdom!' elif fate <= st + dx + iq + wi + en: self.endurance += 1 self.base_endurance += 1 msg += 'endurance!' game.message.new(msg, game.turns, libtcod.light_fuchsia)
def create_outdoor_map(self, default_tile): deep_water_tiles = 0 shallow_water_tiles = 1 sand_tiles = 2 grass_tiles = 3 dirt_tiles = 4 medium_grass_tiles = 5 rocks_tiles = 6 tall_grass_tiles = 7 trees_tiles = 8 hills_tiles = 9 tiles = [0] * 10 icons = ['deep water', 'shallow water', 'sand', 'grass', 'dirt', 'medium grass', 'a pile of rocks', 'tall grass', 'tree', 'hills'] map_size = self.map_width * self.map_height heightmap = game.worldmap.hm_list[self.location_level] # assign values per terrain types if self.type in ['Mountains']: tiles[hills_tiles] = self.randomize(int(map_size * 0.045), int(map_size * 0.180), 3) tiles[tall_grass_tiles] = self.randomize(int(map_size * 0.035), int(map_size * 0.140), 3) if self.type in ['High Hills']: tiles[trees_tiles] = self.randomize(int(map_size * 0.035), int(map_size * 0.140), 3) tiles[tall_grass_tiles] = self.randomize(int(map_size * 0.045), int(map_size * 0.180), 3) tiles[rocks_tiles] = self.randomize(int(map_size * 0.025), int(map_size * 0.100), 3) tiles[medium_grass_tiles] = self.randomize(int(map_size * 0.040), int(map_size * 0.160), 3) tiles[dirt_tiles] = self.randomize(int(map_size * 0.006), int(map_size * 0.024), 3) if self.type in ['Low Hills']: maxhm = (game.terrain['Low Hills']['maxelev'] - game.terrain['Low Hills']['elevation']) * 1000 hm = int(max(1, (heightmap - game.terrain['Low Hills']['elevation']) * 1000)) bonus = float(hm) / float(maxhm) tiles[hills_tiles] = self.randomize(int((map_size * 0.060) + (map_size * 0.060 * (bonus * 0.4))), int((map_size * 0.240) + (map_size * 0.240 * (bonus * 0.4))), 3) tiles[trees_tiles] = self.randomize(int(map_size * 0.035), int(map_size * 0.140), 3) tiles[tall_grass_tiles] = self.randomize(int(map_size * 0.025), int(map_size * 0.100), 3) tiles[rocks_tiles] = self.randomize(int((map_size * 0.012) + (map_size * 0.012 * (bonus * 0.4))), int((map_size * 0.050) + (map_size * 0.050 * (bonus * 0.4))), 3) tiles[dirt_tiles] = self.randomize(int(map_size * 0.006), int(map_size * 0.024), 3) tiles[grass_tiles] = self.randomize(int(max(1, (map_size * 0.010) - (map_size * 0.010 * (bonus * 0.4)))), int(max(map_size * 0.010, (map_size * 0.040) - (map_size * 0.040 * (bonus * 0.4)))), 3) if self.type == 'Forest': maxhm = (game.terrain['Forest']['maxelev'] - game.terrain['Forest']['elevation']) * 1000 hm = int(max(1, (heightmap - game.terrain['Forest']['elevation']) * 1000)) bonus = float(hm) / float(maxhm) tiles[trees_tiles] = self.randomize(int((map_size * 0.052) + (map_size * 0.052 * (bonus * 0.4))), int((map_size * 0.210) + (map_size * 0.210 * (bonus * 0.4))), 3) tiles[tall_grass_tiles] = self.randomize(int((map_size * 0.018) + (map_size * 0.018 * (bonus * 0.4))), int((map_size * 0.075) + (map_size * 0.075 * (bonus * 0.4))), 3) tiles[rocks_tiles] = self.randomize(int(map_size * 0.012), int(map_size * 0.050), 3) tiles[medium_grass_tiles] = self.randomize(int((map_size * 0.025) + (map_size * 0.025 * (bonus * 0.4))), int((map_size * 0.100) + (map_size * 0.100 * (bonus * 0.4))), 3) tiles[dirt_tiles] = self.randomize(int(map_size * 0.006), int(map_size * 0.024), 3) if self.type == 'Plains': maxhm = (game.terrain['Plains']['maxelev'] - game.terrain['Plains']['elevation']) * 1000 hm = int(max(1, (heightmap - game.terrain['Plains']['elevation']) * 1000)) bonus = float(hm) / float(maxhm) tiles[trees_tiles] = self.randomize(int((map_size * 0.012) + (map_size * 0.012 * (bonus * 0.4))), int((map_size * 0.050) + (map_size * 0.050 * (bonus * 0.4))), 3) tiles[tall_grass_tiles] = self.randomize(int((map_size * 0.012) + (map_size * 0.012 * (bonus * 0.4))), int((map_size * 0.050) + (map_size * 0.050 * (bonus * 0.4))), 3) tiles[rocks_tiles] = self.randomize(int(map_size * 0.006), int(map_size * 0.024), 3) tiles[medium_grass_tiles] = self.randomize(int((map_size * 0.012) + (map_size * 0.012 * (bonus * 0.4))), int((map_size * 0.050) + (map_size * 0.050 * (bonus * 0.4))), 3) tiles[dirt_tiles] = self.randomize(int(map_size * 0.006), int(map_size * 0.024), 3) tiles[sand_tiles] = self.randomize(int(max(1, (map_size * 0.006) - (map_size * 0.006 * (bonus * 0.4)))), int(max(map_size * 0.006, (map_size * 0.024) - (map_size * 0.024 * (bonus * 0.4)))), 3) tiles[shallow_water_tiles] = self.randomize(int(map_size * 0.001), int(map_size * 0.004), 3) if self.type == 'Coast': tiles[rocks_tiles] = self.randomize(int(map_size * 0.012), int(map_size * 0.050), 3) tiles[dirt_tiles] = self.randomize(int(map_size * 0.012), int(map_size * 0.050), 3) tiles[grass_tiles] = self.randomize(int(map_size * 0.006), int(map_size * 0.024), 3) tiles[shallow_water_tiles] = self.randomize(int(map_size * 0.001), int(map_size * 0.004), 3) if self.type == 'Shore': maxhm = (game.terrain['Shore']['maxelev'] - game.terrain['Shore']['elevation']) * 1000 hm = int(max(1, (heightmap - game.terrain['Shore']['elevation']) * 1000)) bonus = float(hm) / float(maxhm) tiles[sand_tiles] = self.randomize(int((map_size * 0.001) + (map_size * 0.001 * (bonus * 0.4))), int((map_size * 0.004) + (map_size * 0.004 * (bonus * 0.4))), 3) # print "---" # print "Level:", self.location_level, " x:", self.location_level % game.WORLDMAP_WIDTH, " y:", self.location_level / game.WORLDMAP_WIDTH # print "Heightmap:", heightmap # print "Hills:", tiles[hills_tiles] # print "Trees:", tiles[trees_tiles] # print "Tall grass:", tiles[tall_grass_tiles] # print "Rocks:", tiles[rocks_tiles] # print "Medium grass:", tiles[medium_grass_tiles] # print "Dirt:", tiles[dirt_tiles] # print "Grass:", tiles[grass_tiles] # print "Sand:", tiles[sand_tiles] # print "Shallow water:", tiles[shallow_water_tiles] # print "Deep water:", tiles[deep_water_tiles] # place tiles on map for j in range(len(tiles)): for i in range(tiles[j]): x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) while self.tile[x][y]['name'] != default_tile: x = libtcod.random_get_int(game.rnd, 0, self.map_width - 1) y = libtcod.random_get_int(game.rnd, 0, self.map_height - 1) self.set_tile_values(icons[j], x, y) if icons[j] == 'tree': dice = util.roll_dice(1, 100) if dice % 2 == 0: self.set_tile_values(icons[j], x, y, type='trees2') if icons[j] == 'shallow water' or (self.type == 'Shore' and icons[j] in ['sand', 'deep water']): length = self.randomize(10, 20, 3) direction = self.randomize(1, 40, 3) startx = x starty = y while length > 0: nextstep = util.roll_dice(1, 3) stepx, stepy = 0, 0 if nextstep == 1: if direction % 4 == 0: stepx -= 1 if direction % 4 == 1: stepy -= 1 if direction % 4 == 2: stepx += 1 if direction % 4 == 3: stepy += 1 elif nextstep == 2: if direction % 4 == 0: stepx += 1 if direction % 4 == 1: stepy += 1 if direction % 4 == 2: stepx -= 1 if direction % 4 == 3: stepy -= 1 else: if direction % 4 == 0: stepy -= 1 if direction % 4 == 1: stepx += 1 if direction % 4 == 2: stepy += 1 if direction % 4 == 3: stepx -= 1 startx += stepx starty += stepy if startx < self.map_width and starty < self.map_height: self.set_tile_values(icons[j], startx, starty) length -= 1 self.transitions() self.place_dungeons()
def modify_wound_rolls(self, wound_rolls, target): failed_rolls = np.argwhere(wound_rolls <= self.value) reroll = roll_dice(6, size=len(failed_rolls)) for i, failed_roll_loc in enumerate(failed_rolls): wound_rolls[failed_roll_loc] = reroll[i] return wound_rolls
def modify_damage_rolls(self, damage_rolls): for i, damage in enumerate(damage_rolls): resilient_rolls = roll_dice(6, size=damage) damage_reduced = (resilient_rolls >= self.value).sum() damage_rolls[i] = damage - damage_reduced return damage_rolls
def modify_hit_rolls(self, hit_rolls, hit_target): failed_rolls = np.argwhere(hit_rolls <= self.value) reroll = roll_dice(6, size=len(failed_rolls)) for i, failed_roll_loc in enumerate(failed_rolls): hit_rolls[failed_roll_loc] = reroll[i] return hit_rolls
def modify_wound_rolls(self, wound_rolls, target): second_roll = roll_dice(6, size=wound_rolls.size) res = np.maximum(wound_rolls, second_roll) return res
def simulate_unit(attacking_unit, weapon, n_shots, target_unit, active_abilities): # Sort abilities on their "order" value save_target_abilities = sort_abilities(active_abilities, with_method='modify_save_target') hit_mod_abilities = sort_abilities(active_abilities, with_method='modify_hit_rolls') wound_mod_abilities = sort_abilities(active_abilities, with_method='modify_wound_rolls') damage_mod_abilities = sort_abilities(active_abilities, with_method='modify_damage_rolls') hit_target_value = attacking_unit.ws if weapon.weapon_type == WeaponType.MELEE else attacking_unit.bs t, s, wound_target_value = calculate_wound_target_value( attacking_unit, weapon, target_unit) save_target_value = calculate_save_target_value(weapon, target_unit, save_target_abilities) sims_attacks_hits_wounds_damages_kills = [] for sim in range(N_SIMS): # If applicable, roll for n_attacks weapon_effective_attacks = weapon.effective_attacks(attacking_unit) if 'D' in str( weapon_effective_attacks ): # TODO don't do this string conversion in the tight loop n_attacks = sum( roll_from_dice_string(weapon_effective_attacks, size=n_shots)) else: n_attacks = n_shots # Roll the attack dice hit_rolls = roll_dice(6, size=n_attacks) for ability in hit_mod_abilities: hit_rolls = ability.modify_hit_rolls(hit_rolls, hit_target_value) n_hits = (hit_rolls >= hit_target_value).sum() # Roll the wound dice wound_rolls = roll_dice(6, size=n_hits) for ability in wound_mod_abilities: wound_rolls = ability.modify_wound_rolls(wound_rolls, wound_target_value) n_wounds = (wound_rolls >= wound_target_value).sum() # Roll the save dice save_rolls = roll_dice(6, size=n_wounds) n_unsaved = n_wounds - (save_rolls >= save_target_value).sum() # Roll damage damage_rolls = maybe_roll_from_dice_string(weapon.d, size=n_unsaved) for ability in damage_mod_abilities: damage_rolls = ability.modify_damage_rolls(damage_rolls) total_damage = sum(damage_rolls) # Allocate damage and count kills n_kills, allocated_damage = 0, 0 for dmg in damage_rolls: allocated_damage += dmg if allocated_damage >= target_unit.w: n_kills += 1 allocated_damage = 0 sims_attacks_hits_wounds_damages_kills.append( (n_attacks, n_hits, n_wounds, total_damage, n_kills)) # Unzip results and calculate percentiles all_attacks, all_hits, all_wounds, all_damages, all_kills = \ (list(res) for res in zip(*sims_attacks_hits_wounds_damages_kills)) index_5th = int(.05 * N_SIMS) index_25th = int(.25 * N_SIMS) index_median = int(.5 * N_SIMS) index_75th = int(.75 * N_SIMS) index_95th = int(.95 * N_SIMS) all_attacks.sort() attacks_result = ( all_attacks[index_5th], all_attacks[index_25th], all_attacks[index_median], all_attacks[index_75th], all_attacks[index_95th], ) all_hits.sort() hits_result = ( all_hits[index_5th], all_hits[index_25th], all_hits[index_median], all_hits[index_75th], all_hits[index_95th], ) all_wounds.sort() wounds_result = ( all_wounds[index_5th], all_wounds[index_25th], all_wounds[index_median], all_wounds[index_75th], all_wounds[index_95th], ) all_damages.sort() damages_result = ( all_damages[index_5th], all_damages[index_25th], all_damages[index_median], all_damages[index_75th], all_damages[index_95th], ) all_kills.sort() kills_result = ( all_kills[index_5th], all_kills[index_25th], all_kills[index_median], all_kills[index_75th], all_kills[index_95th], ) return [ attacks_result, "{}+".format(hit_target_value), hits_result, "{}+".format(wound_target_value), wounds_result, "{}+".format(save_target_value), damages_result, kills_result ]
def roll(self) -> int: return roll_dice()
def use_skill(): skills = [] for x in game.player.skills: if x.can_use: skills.append(x) output = [x.name for x in skills] choice = game.messages.box('Use a skill', 'Up/down to select, ENTER to use, ESC to exit', 'center_mapx', 'center_mapy', 65, max(19, len(output) + 4), output, step=2, mouse_exit=True) if choice != -1: if output[choice] == 'Detect Traps': skills[choice].active() if output[choice] == 'Artifacts': output2 = game.player.inventory + game.player.equipment choice2 = game.messages.box('Use skill on which item', 'Up/down to select, ENTER to use, ESC to exit', 'center_mapx', 'center_mapy', 65, max(19, len(output) + 4), output2, inv=True, step=2, mouse_exit=True) if choice2 != -1: if output2[choice2].is_identified(): game.message.new('That item is already identified.', game.turns) elif output2[choice2].assay == game.player.level: game.message.new('You already tried to identify that item. You can do it once per item per level.', game.turns) else: if output2[choice2].level * 5 > skills[choice].level: game.message.new('Your skill is not high enough to identity that item.', game.turns) output2[choice2].assay = game.player.level skills[choice].gain_xp(1) else: game.message.new('You identify the item!', game.turns) output2[choice2].flags.append('identified') skills[choice].gain_xp(5) game.player_move = True if output[choice] == 'Disarm Traps': attempt = False for x in range(-1, 2): for y in range(-1, 2): if 'trapped' in game.current_map.tile[game.char.x + x][game.char.y + y]: dice = libtcod.random_get_int(game.rnd, 0, 150) if skills[choice].level >= dice: if game.current_map.tile[game.char.x + x][game.char.y + y]['type'] == 'trap': game.current_map.set_tile_values('floor', game.char.x + x, game.char.y + y) game.message.new('You disarm the trap.', game.turns) else: game.message.new('You disarm the trap chest.', game.turns) game.current_map.tile[game.char.x + x][game.char.y + y].pop('trapped', None) skills[choice].gain_xp(5) else: game.message.new('You failed to disarm the trap.', game.turns) dice = util.roll_dice(1, 50) if dice > game.player.karma: if game.current_map.tile[game.char.x + x][game.char.y + y]['type'] == 'trap': util.trigger_trap(game.char.x + x, game.char.y + y) else: game.current_map.tile[game.char.x + x][game.char.y + y].update({game.chest_trap[libtcod.random_get_int(game.rnd, 0, len(game.chest_trap) - 1)]: True}) game.current_map.tile[game.char.x + x][game.char.y + y].pop('trapped', None) util.trigger_trap(game.char.x + x, game.char.y + y, chest=True) skills[choice].gain_xp(1) game.player_move = True attempt = True if not attempt: game.message.new('There are no traps in your surroundings.', game.turns) if output[choice] == 'Lockpicking': attempt = False for x in range(-1, 2): for y in range(-1, 2): if 'locked' in game.current_map.tile[game.char.x + x][game.char.y + y]: dice = libtcod.random_get_int(game.rnd, 0, 150) name = game.current_map.tile[game.char.x + x][game.char.y + y]['name'] if skills[choice].level >= dice: game.message.new('You unlock the ' + name + '.', game.turns) if name == 'locked door': game.current_map.set_tile_values('opened door', game.char.x + x, game.char.y + y) if name == 'locked chest': game.current_map.set_tile_values('empty chest', game.char.x + x, game.char.y + y) nb_items = util.roll_dice(2, 4) for i in range(nb_items): game.current_map.objects.append(game.baseitems.loot_generation(game.char.x + x, game.char.y + y, game.current_map.threat_level)) skills[choice].gain_xp(5) else: game.message.new('You failed to unlock the ' + name + '.', game.turns) if 'trapped' in game.current_map.tile[game.char.x + x][game.char.y + y]: dice = util.roll_dice(1, 30) if game.player.karma < dice: game.current_map.tile[game.char.x + x][game.char.y + y].update({game.chest_trap[libtcod.random_get_int(game.rnd, 0, len(game.chest_trap) - 1)]: True}) game.current_map.tile[game.char.x + x][game.char.y + y].pop('trapped', None) util.trigger_trap(game.char.x + x, game.char.y + y, chest=True) skills[choice].gain_xp(1) game.player_move = True attempt = True if not attempt: game.message.new('There is nothing to unlock in your surroundings.', game.turns) game.draw_gui = True