def generate(self): shops = 0 hotel = 0 taverns = util.roll(1, self.rank, -1) if self.rank >= 3: if util.coinflip(): shops = util.roll(1, self.rank, -2) hotel = util.coinflip() #roll for number of houses. it'lee be 4-8 houses for small village #and 6-12 for town. and much for for large city. but that's it for now house_count = util.roll(self.rank, 3, self.rank) noble_house_count = util.roll(1, self.rank, -3) gl.logger.debug( 'Generating buildings: %d rooms, %d noble, %d tavern, %d shops, %d hotel' % (house_count, noble_house_count, taverns, shops, hotel)) gen = self.create_room_generator(house_count, noble_house_count, taverns, shops, hotel) self.generate_road() for x in (noble_house_count, taverns, shops, hotel): house_count += util.cap_lower(x, 0, 0) gl.logger.debug('Total number of houses: %d' % house_count) if self.room_placer is None: self.generate_rooms_random_place(house_count, gen) else: self.room_placer(self, house_count, gen)
def adjust_x_y_anywhere(self, x, y, x2, y2, delta = None, allow_crop= True): w,h = x2 - x, y2 - y #will move up or down if delta is None: delta = util.coinflip() if delta == 0 : delta = -1 itercnt = 100 while True: itercnt -= 1 #dont want it to hang foreva if itercnt <= 0: return None okay = True for i in range (x, x2): for j in range (y, y2): #if it's a road - then adjust our coords if self._map[j][i].is_road(): y += delta; y2 += delta okay = False if min(y, y2) <= 0 or max(y, y2) >= self.height: return None #were not okay, breaking break #coords were adjusted break for main While loop if not okay: break #no road crossed, were safe if okay: break if not allow_crop: if x < 0 or y < 0 or x+w >= len(self._map[0]) or y+h >= len(self._map): return None return x, y
def create_room_generator(self, house_count, noble_house_count, taverns, shops, hotel): prefix = '' if self.rank <= 3: prefix = 'small_' elif self.rank >= 7: prefix = 'large_' else: prefix = 'med_' all_houses = [] rooms_gen = StaticRoomGenerator(prefix + 'rooms') #place general houses for i in xrange(0, house_count): all_houses.append(lambda: rooms_gen.random()) #place noble houses if noble_house_count > 0: noble_room_gen = StaticRoomGenerator(prefix + 'noble') for i in xrange(0, noble_house_count): all_houses.append(lambda: noble_room_gen.random()) #place 1 residence if self.rank >= 7 and util.coinflip(): gl.logger.debug('Generating residence') residence_room_gen = StaticRoomGenerator('residence') all_houses.append(lambda: residence_room_gen.random()) if taverns > 0: tavern_room_gen = StaticRoomGenerator(prefix + 'tavern') for x in xrange(0, taverns): all_houses.append(lambda: tavern_room_gen.random()) if shops > 0: shop_room_gen = StaticRoomGenerator(prefix + 'shop') for x in xrange(0, shops): all_houses.append(lambda: shop_room_gen.random()) if hotel > 0: hotel_gen = StaticRoomGenerator(prefix + 'hotels') all_houses.append(lambda: hotel_gen.random()) shuffle(all_houses) for house in all_houses: yield house()
def create_room_generator(self, house_count, noble_house_count, taverns, shops, hotel): prefix = '' if self.rank <= 3: prefix = 'small_' elif self.rank >=7: prefix = 'large_' else: prefix = 'med_' all_houses = [] rooms_gen = StaticRoomGenerator(prefix + 'rooms') #place general houses for i in xrange(0, house_count): all_houses.append(lambda : rooms_gen.random()) #place noble houses if noble_house_count > 0: noble_room_gen = StaticRoomGenerator(prefix + 'noble') for i in xrange(0, noble_house_count): all_houses.append(lambda: noble_room_gen.random()) #place 1 residence if self.rank >= 7 and util.coinflip(): gl.logger.debug('Generating residence') residence_room_gen = StaticRoomGenerator('residence') all_houses.append(lambda: residence_room_gen.random()) if taverns > 0: tavern_room_gen = StaticRoomGenerator(prefix+'tavern') for x in xrange(0, taverns): all_houses.append(lambda: tavern_room_gen.random()) if shops > 0: shop_room_gen = StaticRoomGenerator(prefix + 'shop') for x in xrange (0, shops): all_houses.append(lambda: shop_room_gen.random()) if hotel > 0: hotel_gen = StaticRoomGenerator(prefix + 'hotels') all_houses.append(lambda: hotel_gen.random()) shuffle(all_houses) for house in all_houses: yield house()
def gen_artefact_weapon(base_type=None, price=1000, unique=None): cost = price if base_type is None: base_type = random.choice(items.weapons) wep = base_type() cost -= _make_brand(wep) cost -= _make_randart(wep, unique) if util.coinflip(): cost -= _add_misc(wep, cost) else: cost /= 2 _add_enchants(wep, cost) return wep
def acquire_weapon(npc, unique=None): cost = TOP_COST_WEP + random.randrange(-1 * TOP_COST_WEP_RANGE, TOP_COST_WEP_RANGE) base_type = random.choice(items.weapons) cost -= base_type.base_cost wep = base_type() if util.coinflip(): cost -= _make_brand(wep) if util.onechancein(5): cost += FIXED_ART_UP cost -= _make_randart(wep, unique) cost -= _add_misc(wep, cost) _add_enchants(wep, cost) return wep
def random_rotate_and_clone_map(map, settings = 'any', params = None): """ random_rotate(...) -> (map, (rev_x, rev_y, swap_x_y)) Rotates a map. """ if not rotate_setting.has_key(settings) : raise RuntimeError('Not valid orientation [%s] passed to random_rotate' % settings) settings = rotate_setting[settings] map = __clone_map(map) if settings == NO_FLIP: return map, (0, 0, 0) if params and settings & FORCE_ALL != FORCE_ALL: rev_x, rev_y, swap_x_y = params else: rev_x, rev_y = util.coinflip(), util.coinflip() swap_x_y = util.coinflip() if settings & FORCE_VERTICAL_FLIP == FORCE_VERTICAL_FLIP: rev_x = 1 settings |= VERTICAL_FLIP if settings & FORCE_HORIZONTAL_FLIP == FORCE_HORIZONTAL_FLIP: rev_y = 1 settings |= HORIZONTAL_FLIP if settings & FORCE_ROTATE == FORCE_ROTATE: swap_x_y = 1 settings |= ROTATE if rev_x and (settings & VERTICAL_FLIP == VERTICAL_FLIP): for line in map: line.reverse() if rev_y and (settings & HORIZONTAL_FLIP == HORIZONTAL_FLIP): map.reverse() if swap_x_y and (settings & ROTATE == ROTATE): new_map = [] for x in xrange(0, len(map[0])): new_line = [] for y in xrange(0, len(map)): new_line.append(map[y][x]) new_map.append(new_line) return new_map, (swap_x_y, rev_x, rev_y) return map, (swap_x_y, rev_x, rev_y)
def generate(self): shops = 0 hotel = 0 taverns = util.roll(1, self.rank, -1) if self.rank >=3: if util.coinflip(): shops = util.roll(1, self.rank, -2) hotel = util.coinflip() #roll for number of houses. it'lee be 4-8 houses for small village #and 6-12 for town. and much for for large city. but that's it for now house_count = util.roll(self.rank,3, self.rank) noble_house_count = util.roll(1, self.rank, -3) gl.logger.debug('Generating buildings: %d rooms, %d noble, %d tavern, %d shops, %d hotel' % (house_count, noble_house_count, taverns, shops, hotel)) gen = self.create_room_generator(house_count, noble_house_count, taverns, shops, hotel) self.generate_road() for x in (noble_house_count, taverns, shops, hotel): house_count += util.cap_lower(x, 0, 0) gl.logger.debug('Total number of houses: %d' % house_count) if self.room_placer is None: self.generate_rooms_random_place(house_count, gen) else: self.room_placer(self, house_count, gen)
def take_damage(self, mob, dmgs, attack): for dmg in dmgs: for i in range(0, self.base_ac + 1): if util.coinflip(): dmg -= 1 if dmg <= 0: break if dmg > 0 and self.hp > 0: gl.message(mob.name.capitalize() + ' hits ' + self.name + ' for ' + str(dmg) + ' damage.', 5) self.hp -= dmg if isinstance(self, Player): if self.hp <= self.base_hp * gl.__hp_warning__: gl.message('Low HP!!!', 'WARN') elif self.hp > 0: gl.message (mob.name.capitalize() + ' fails to harm ' + self.name, 1) if self.hp <= 0: self.die(mob)
def assign_random_name_from_list(instances, names, demon = False): for npc in world.mNPC: if npc.name is not None: continue if isinstance(npc, instances) and len(names) > 0: if util.coinflip(): name = choice(names) names.remove(name) if debug_names: npc.name = name + str(npc.__class__) npc.is_demon = demon logger.debug('Creating reference NPC ' +str(npc.__class__) +' for ' + name + ' from background') for npc in world.mNPC: if isinstance(npc, instances) and npc.name is not None: names.append(npc.name)
def take_damage(self, mob, dmgs, attack): """ take_damage(source, [int], attack) => None This method inflicts damage to a creature of amount specified as dmgs list whic was dealt by mob """ for dmg in dmgs: for i in range(0, self.base_ac + 1): if util.coinflip(): dmg -= 1 if dmg <= 0: continue if dmg > 0 and self.hp > 0: gl.message(mob.name.capitalize() + ' hits ' + self.name + ' for ' + str(dmg) + ' damage.', 5) self.hp -= dmg elif self.hp > 0: gl.message (mob.name.capitalize() + ' fails to harm ' + self.name) if self.hp <= 0: self.die(mob)
def assign_random_name_from_list(instances, names, demon=False): for npc in world.mNPC: if npc.name is not None: continue if isinstance(npc, instances) and len(names) > 0: if util.coinflip(): name = choice(names) names.remove(name) if debug_names: npc.name = name + str(npc.__class__) npc.is_demon = demon logger.debug('Creating reference NPC ' + str(npc.__class__) + ' for ' + name + ' from background') for npc in world.mNPC: if isinstance(npc, instances) and npc.name is not None: names.append(npc.name)
def join_blobs(MapDef, join_chance=1): tree = BSPTree() for x in xrange(1, MapDef.width): for y in xrange(1, MapDef.height): #check all tiles surrounding current tile = MapDef.tile_at(x, y) if not (tile_passable(tile) or tile.type == ftype.door): continue for dx in (-1, 0): for dy in (-1, 0): _x, _y = x + dx, y + dy tile = MapDef.tile_at(_x, _y) #if this is floor tile if tile_passable(tile) or tile.type == ftype.door: root1 = tree.find((x, y)) root2 = tree.find((_x, _y)) if root1 != root2: tree.union(root1, root2) roots = tree.split_sets().keys() prev_x, prev_y = None, None for root in roots: x,y = -1,-1 ticks = 50 while True: if ticks <= 0: x, y = root break ticks -= 1 x,y = randint(root[0], max(MapDef.width - 5, root[0])), randint(root[1], max(MapDef.height - 5, root[1])) if tree.find((x, y)) == root: break if prev_x and util.one_chance_in(join_chance): if util.coinflip(): create_v_tunnel(MapDef, prev_y, y, x, None, None) create_h_tunnel(MapDef, prev_x, x, y, None, None) else: create_h_tunnel(MapDef, prev_x, x, y, None, None) create_v_tunnel(MapDef, prev_y, y, x, None, None) prev_x, prev_y = x, y print 'XXXXXXXXXXX' MapDef.debug_print() return tree
def take_damage(self, mob, dmgs, attack): for dmg in dmgs: for i in range(0, self.base_ac + 1): if util.coinflip(): dmg -= 1 if dmg <= 0: break if dmg > 0 and self.hp > 0: gl.message( mob.name.capitalize() + ' hits ' + self.name + ' for ' + str(dmg) + ' damage.', 5) self.hp -= dmg if isinstance(self, Player): if self.hp <= self.base_hp * gl.__hp_warning__: gl.message('Low HP!!!', 'WARN') elif self.hp > 0: gl.message( mob.name.capitalize() + ' fails to harm ' + self.name, 1) if self.hp <= 0: self.die(mob)
def player_move_into(self, player, x, y, map): #todo check player is flying (maybe) if self.reacted: return True, True, True #already pressed self.reacted = True #todo - take skills in account gl.message('%s step on the pressure plate' % player.pronoun.capitalize()) self.found(player) fts = map.current.find_feature(self.affected, multiple=True) if fts: for ft, x, y in fts: if self.action == 'remove': map.current.replace_feature_atxy(x, y, with_what=map.map_src.floor) if self.action == 'remove': if util.coinflip(): gl.message('You hear grinding noise') else: gl.message('You hear some strange shrieking noise') map.init_fov() else: gl.message('Nothing seems to happen') return True, True, True
def player_move_into(self, player, x, y, map): #todo check player is flying (maybe) if self.reacted: return True, True, True #already pressed self.reacted = True #todo - take skills in account gl.message('%s step on the pressure plate' % player.pronoun.capitalize()) self.found(player) fts = map.current.find_feature(self.affected, multiple=True) if fts: for ft, x, y in fts: if self.action == 'remove': map.current.replace_feature_atxy( x, y, with_what=map.map_src.floor) if self.action == 'remove': if util.coinflip(): gl.message('You hear grinding noise') else: gl.message('You hear some strange shrieking noise') map.init_fov() else: gl.message('Nothing seems to happen') return True, True, True
def adjust_x_y_anywhere(self, x, y, x2, y2, delta=None, allow_crop=True): w, h = x2 - x, y2 - y #will move up or down if delta is None: delta = util.coinflip() if delta == 0: delta = -1 itercnt = 100 while True: itercnt -= 1 #dont want it to hang foreva if itercnt <= 0: return None okay = True for i in range(x, x2): for j in range(y, y2): #if it's a road - then adjust our coords if self._map[j][i].is_road(): y += delta y2 += delta okay = False if min(y, y2) <= 0 or max(y, y2) >= self.height: return None #were not okay, breaking break #coords were adjusted break for main While loop if not okay: break #no road crossed, were safe if okay: break if not allow_crop: if x < 0 or y < 0 or x + w >= len( self._map[0]) or y + h >= len(self._map): return None return x, y
# 1 for killable target (quest target itself), 2 for talk-only-target, 3 for guard-type (guard quest item), 4 break-down plot (change plot) # ! denotes NPCs which are occasionaly generated during quest generation-only! #Actualy we don't want classic quests. instead let's use the quest as some meating point for plot-oriented-NPC. i.e. if the player is sent #to obtain amulet from and wafull demon not neccessarily he should get it. Instead he should be given some important information and be directed to the next quest #######FIRST_PHASE: (all the NPC inhabiting the world instead of those, generated inside quesut ly) #first let's define our world's population: this will include # all the NPC's of all types we have, except those which can be placed inside quesuts only #let's roll for number of NPC. let it lay from . NOTE that we will also add types denoted by ! later. mNPC_count = util.roll(*MNPC_ROLL) #now let's roll for number of quest-givers. we do want them to exist min_quest_fivers = util.roll(*QUEST_GIVER_ROLL) #now let's roll for immobile NPCs. we don't want many of them. let em be 0-3 at 50% chance for now immobile_npc = 0 if util.coinflip(): to_roll = util.roll(*IMMOBILE_NPC_ROLL) for i in range(0, to_roll): immobile_npc += util.coinflip() unique_npc = util.roll(*UNIQUES_ROLL) traders_npc = util.roll(*TRADERS_ROLL) logger.debug("Rolled for %d main NPCs (%d NPC able to issue quests), %d immobile NPCs, %d uniques, %d traders)", mNPC_count, min_quest_fivers, immobile_npc, unique_npc, traders_npc) logger.debug("Total of %d NPCs (%d with traders)", mNPC_count + immobile_npc + unique_npc, mNPC_count + immobile_npc + unique_npc + traders_npc) #now toss #generate_plot() class QuestNPC(object): #denotes if this NPC-type can be generate at first phase non_worldgen = False __metaclass__ = util.AutoAdd
result.append(rnd()) if rnd in QuestNPC.quest_giver_NPC: actual_quest_givers += 1 world.mNPC.extend(result) #now let's generate deities deity_coun= util.roll(*DEITY_ROLL) deities = [] for x in xrange(0, deity_coun): deity = DeityNPC() deities.append(deity) world.mNPC.extend(deities) world.quest_givers = filter(lambda x: x.__class__ in QuestNPC.quest_giver_NPC, result) #now let's roll for immobile NPCs. we don't want many of them. let em be 0-3 at 50% chance for now immobile_npc = 0 if util.coinflip(): to_roll = util.roll(*IMMOBILE_NPC_ROLL) for i in range(0, to_roll): immobile_npc += util.coinflip() #for now let's place immobile NPCs together with main NPCs for i in xrange(0, immobile_npc): world.mNPC.append(ImmobileNPC()) unique_npc = util.roll(*UNIQUES_ROLL) #now let's generate a king - why not? king = KingNPC() world.king = king king.name = util.gen_name(check_unique=world.npc_names) logger.debug('Generated king %s' % (king.name)) for x in range(2, util.roll(2, 3, 1)): guard = GoodNPC() guard.name = util.gen_name(check_unique=world.npc_names)
def _make_brand(wep): if util.coinflip(): wep.brand = "fire" return 200 else: return 0