#coding: utf-8
import workflow, ast
levels = int(workflow.get_variable('levels'))
theme = workflow.get_variable('theme')
name = workflow.get_variable('name')
monster_dict = ast.literal_eval(workflow.get_variable('monster_dict'))
treasure_dict = ast.literal_eval(workflow.get_variable('treasure'))
# Script to generate random dungeons for ACKS Rome
import random, collections
room_aspects = ['Uneven footing','Difficult to see','Maze-like','Poorly lit','Scattered old bones','Trickling water','Collapsed Corridor','Unnatural Light','Ancient Runes','Flora growing through cracks','Secret Passages','Littered with Traps','Dust-filled','Crumbling Stone','Unending Stairway','Light From Outside','Terrible Odor','Sounds of Underground Lake','Scurrying Creatures','Ancient Murals','Endless Chasm','Walls Closing In','Low Ceiling','Busted Statues','L shaped','Mysterious Well','Celtic Runes','Rotting corpses','Scratchings about the greater darkness','Round','Oblong','Narrow walkways']
room_size = {'Small': [4,4], 'Medium': [10,10], 'Large': [20,20], 'Massive': [40,40]}
traps = {'Arrow Trap': 'When triggered, an arrow fires from a hidden location, attacking one adventurer as a 1st level fighter for 1d6+1 damage.', 'Bricks from Ceiling': "When triggered, bricks fall from the ceiling. Each adventurer in a 10' radius must make a saving throw versus Blast or suffer 2d6 points of damage.", 'Camouflaged Pit Trap': "When triggered, a pit opens beneath the feet of all adventurers in a 10' x 10' square. Adventurers who fall down the pit take 1d6 points of damage per 10' fallen. Pits should generally be 10' deep per dungeon level.", 'Poison Dart Trap': 'When triggered, a dart fires from a hidden location, attacking one adventurer as a 1st level fighter for 1d4+1 damage. If the adventurer is hit, he must save versus Poison or die.', 'Poison Needle Trap': "When triggered, a small needle pops out of a lock. The adventurer who triggered the trap must save versus Poison or die.", 'Portcullis Trap': "When triggered, a portcullis falls suddenly downward. The adventurer who triggered the trap must make a save versus Blast or suffer 3d6 points of damage. The way will then be blocked, and party members may be separated.", 'Rolling Rock Trap': "When triggered, a rock rolls out from a hidden location. All adventurers in the room or hallway must save versus Blast or suffer 2d6 points of damage."}
unique_enc = {1: ['Rot grub', 'spitting cobra', 'skeleton','runes','statue'], 2: ['Green slime', 'wood golem', 'yellow mold','cursed item','ghost or spirit'], 3: ['ghost or spirit','Gelatinous cube', 'gray ooze', 'animated statue (iron, crystal)', 'doppelganger', 'shadow'], 4: ['Animated statue (stone)', 'ochre jelly', 'rust monster'], 5: ['Golem (bone)', 'invisible stalker', 'mummy'], 6: ['Golem (amber, bronze)', 'black pudding', 'djinni', 'efreeti', 'elemental','bound demon/devil']}
unprot_treasure = {1: ['A', 'B', 'C', 'D', 'E', 'F'], 2: ['C', 'D', 'E', 'F', 'G', 'H'], 3: ['E', 'F', 'G', 'H', 'I', 'J'], 4: ['G', 'H', 'I', 'J', 'K', 'L'], 5: ['I', 'J', 'K', 'L', 'M', 'N'], 6: ['M', 'N', 'O', 'P', 'Q', 'R']}
wandering_m = {1: [['Beetle, Giant Fire',1,8,0],['Centipede, Giant',2,4,0],['Ferret, Giant',1,8,0],['Goblin',2,4,0], ['Kobold',4,4,0], ['Brigand',2,4,0],['Goblin',1,12,0], ['NPC Party',1,4,2],['Orc',2,4,0], ['Rat, Giant',3,6,0],['Skeleton',3,4,0],['Stirge',1,10,0]],
2: [['Bat, Giant',1,10,0],['Fly, Giant Carnivorous',1,8,0],['Ghoul',1,6,0],['Gnoll',1,6,0],['Hobgoblin',1,6,0],['Lizardman',2,4,0],['Insect Swarm, 2HD',1,10,0], ['Berserker',1,6,0],['NPC Party',1,4,2],['Snake, Pit Viper',1,8,0],['Troglodyte',1,8,0],['Zombie',2,4,0]],
3: [['Ant, Giant',2,4,0],['Bugbear',2,4,0],['Carcass Scavenger',1,3,0],['Gargoyle',1,6,0],['Lizard, Giant Draco',1,3,0],['Werewolf',1,6,0],['NPC Party',1,4,2],['Ogre',1,6,0], ['Scorpion, Giant',1,6,0],['Throghrin',1,6,0],['Wight',1,6,0],['Wolf, Dire',1,4,0]],
4: [['Boar, Giant',1,4,0],['Cockatrice',1,3,0],['Wereboar',1,4,0],['Weretiger',1,4,0],['Medusa',1,3,0],['Minotaur',1,6,0],['NPC Party',1,4,2],['Owl Bear',1,4,0],['Phase Tiger',1,4,0],['Rhagodessa, Giant',1,4,0],['Snake, Giant Python',1,3,0],['Wraith',1,4,0]],
5: [['Ankheg',1,6,0],['Basilisk',1,6,0],['Caecilian',1,3,0],['Ettin',1,2,0],['Giant, Hill',1,4,0],['Giant, Stone',1,2,0],['Hell Hound, Greater',2,4,0],['NPC Party',1,4,3],['Salamander, Flame',1,4,1],['Spectre',1,4,0],['Troll',1,8,0],['Wyvern',1,2,0]],
6: [['Cyclops',1,1,0],['Demon Boar',1,4,0],['Dragon, 20HD',1,1,0],['Giant, Cloud',1,2,0],['Gorgon',1,2,0],['Hydra, 12HD',1,1,0],['Lamia',1,1,0],['NPC Party',1,4,3],['Purple Worm',1,2,0],['Remorhaz, 15HD',1,1,0],['Skittering Maw',1,1,0],['Vampire, 9HD',1,4,0]]}
wm_level = {1:[0,0,10,11,13],2:[0,4,10,12,13],3:[2,4,10,12,13],4:[2,4,10,12,13],5:[2,4,10,13,14],6:[2,4,13,14,15]}
treasure_list = ['Copper',"Silver",'Electrum','Gold','Platinum']
gem_list = ['Gem','Jewelry']
gem_value = {'ornamental': 50, 'gems': 200, 'brilliants':4000, 'trinkets': 225, 'jewelry': 1000, 'regalia': 11000}
coin_value = {'Copper': .01, 'Silver': .1, 'Electrum': .5, 'Gold': 1, 'Platinum': 5}
def roll_em(dice,pips,mod):
total = 0
for i in range(1,dice+1):
total += random.randint(1,pips)
total += mod
return total
def dungeon_gen(levels):
room_list = {}
dungeon_dict = {}
for level in range(1,levels+1):
dungeon_dict['level '+str(level)] = {}
rooms = roll_em(2,10,0)
for room in range(1,rooms+1):
dungeon_dict['level '+str(level)][room] = []
x = roll_em(1,100,0)
# **** empty room ****
if x < 30:
if roll_em(1,100,0) < 15:
treasure = random.choice(unprot_treasure[level])
treasure_hoard = generate_treasure(str(treasure))
else:
treasure = 'None'
treasure_hoard = ''
dungeon_dict['level '+str(level)][room] = '{}, Empty, {}, Treasure: {} <br> Notes: {}'.format(str(random.choice(room_size.keys())).title(),str(random.choice(room_aspects)),treasure, treasure_hoard)
# **** monster room ****
elif x < 60:
wm_mod = roll_em(1,12,0)
mod_level = 0
if wm_mod < wm_level[level][0]:
mod_level = level -2
elif wm_mod < wm_level[level][1]:
mod_level = level -1
elif wm_mod < wm_level[level][2]:
mod_level = level
elif wm_mod < wm_level[level][3]:
mod_level = level +1
elif wm_mod < wm_level[level][4]:
mod_level = level +2
if mod_level < 1:
mod_level = 1
rm_monster = random.choice(wandering_m[mod_level])
monster_name = rm_monster[0]
monster_die = int(rm_monster[1])
monster_pips = int(rm_monster[2])
monster_mod = int(rm_monster[3])
if roll_em(1,100,0) < 15:
treasure = 'by monster'
else:
treasure = 'None'
dungeon_dict['level '+str(level)][room] = '{}, Monster: {}, {}, Treasure: {} <br> Notes: {}'.format(str(random.choice(room_size.keys())).title(),rm_monster[0],str(random.choice(room_aspects)),treasure,str(encounter(rm_monster[0],rm_monster[1],rm_monster[2],rm_monster[3]).translate(None,'"').lstrip(',')))
# **** Trap Room ****
elif x < 75:
if roll_em(1,100,0) < 15:
treasure = random.choice(unprot_treasure[level])
treasure_hoard = generate_treasure(str(treasure))
else:
treasure = 'None'
treasure_hoard = ''
trap = random.choice(traps.keys())
dungeon_dict['level '+str(level)][room] = '{}, Trap: {}, {}, Treasure: {} <br> Notes: {}<br> {}'.format(str(random.choice(room_size.keys())).title(),trap,str(random.choice(room_aspects)),treasure,traps[trap],treasure_hoard)
# **** Unique Room ****
else:
if roll_em(1,100,0) < 15:
treasure = random.choice(unprot_treasure[level])
treasure_hoard = generate_treasure(str(treasure))
else:
treasure = 'None'
treasure_hoard = ''
unique = random.choice(unique_enc[level])
dungeon_dict['level '+str(level)][room] = '{}, Unique: {}, {}, Treasure: {} <br> Notes: This room has a puzzle, mystery or something special about it. <br>{} '.format(str(random.choice(room_size.keys())).title(),unique,str(random.choice(room_aspects)),treasure,treasure_hoard)
dun_string = '**{}** - {} - {} Level \n \n'.format(name.title(),theme.title(),levels)
for level in collections.OrderedDict(sorted(dungeon_dict.items(), key=lambda t: t[0])):
dun_string += '**{}**: \n'.format(level).title()
for k,v in dungeon_dict[level].items():
dun_string += '* Room {}: {}\n'.format(k,str(v).strip('[]').translate(None,"'"))
dun_string += ' <br> <br>'
#print dungeon_dict
return dun_string
def encounter(monster,dice,pips,mod):
try:
mon_dict = monster_dict[monster.title()]
except KeyError:
mon_dict = monster_dict['Goblin']
print monster
# Determining the number of creatures encountered, the distance (as per a wooded encounter) and surprise.
tot_enc = 0
if int(pips) == 1:
tot_enc = 1
enc1 = "Encounter: {} {}.".format(tot_enc,monster)
else:
tot_enc = roll_em(int(dice),int(pips),mod)
enc1 = "Encounter: {} {}.".format(tot_enc,mon_dict['Natural Spelling Plural'])
# Determining hit dice and hit points for creatures (NOTE: I screwed up some low hp creatures in the CSV file. Will need to fix.)
hd = 1
hp = []
x = 0
try:
int(mon_dict['HD'])
except ValueError:
raise
mon_dict['HD'] = 1
for i in range(1,100):
print '********************'+mon_dict[""]+'**********************'
num_beasties = 0
if tot_enc > 26:
num_beasties = 26
else:
num_beasties = tot_enc
if int(mon_dict['Pips']) == 0:
hd = str(mon_dict['HD'])
for beast in range(1,num_beasties+1):
x = roll_em(int(mon_dict['HD']),8,0)
hp.append(x)
elif mon_dict['HD'] in (0,'',""):
hd = str(mon_dict['Pips'])+'hp'
for beast in range(1,num_beasties+1):
x = mon_dict['Pips']
hp.append(x)
else:
hd = str(mon_dict['HD'])+'+'+str(mon_dict['Pips'])
for beast in range(1,num_beasties+1):
x = roll_em(int(mon_dict['HD']),8,int(mon_dict['Pips']))
hp.append(x)
if mon_dict['2nd Move Type'] == '':
two_move = 'None'
else:
two_move = mon_dict['2nd Move Type']+" "+mon_dict['2nd Move Spd']
# Final part of the stat block and returning the full script to the map.
enc3 = '>**Al**: {}, **Move**: {}, **Alt**: {}, **AC**: {}, **HD**: {}<br>**HP**: {}<br>**Atk**: {}, **Dam**: {}<br>**Save**: {}, **Morale**: {}, **Treasure**: {}, **XP**: {} (total {}xp)<br> **Special**: {}.'.format(mon_dict['Align'],mon_dict['Move'],two_move,str(mon_dict['AC']),str(hd),str(hp).strip('[]'),mon_dict['Attacks'],mon_dict['Damage'],mon_dict['Save'],str(mon_dict['Morale']),str(mon_dict['Treasure Type']),str(mon_dict['XP']),int(mon_dict['XP'])*num_beasties,mon_dict['Special Attack'])
full_text = enc1+'\n'+enc3
#print(full_text)
#print('')
return full_text
def generate_treasure(t_type):
total = 0
treasure = ''
treasure = '**Treasure Type {}**<br> '.format(t_type)
for item in treasure_list:
amount = 0
prob = int(treasure_dict[t_type][item])
x = roll_em(1,100,0)
if x <= prob:
amount = roll_em(int(treasure_dict[t_type][item+'_amount'][1]),int(treasure_dict[t_type][item+'_amount'][3]),0)
amount *= 1000
treasure += '* {}: {} coins <br> '.format(item,amount)
total += (amount * float(coin_value[item]))
for item in gem_list:
amount = 0
prob = int(treasure_dict[t_type][item])
x = roll_em(1,100,0)
if x <= prob:
amount = int(roll_em(int(treasure_dict[t_type][item+'_amount'][1]),int(treasure_dict[t_type][item+'_amount'][3]),int(treasure_dict[t_type][item+'_amount'][5])))
treasure += '* {}: {} {} (value {} each) <br> '.format(item,amount,treasure_dict[t_type][item+'_type'],gem_value[treasure_dict[t_type][item+'_type']])
total += (amount * gem_value[treasure_dict[t_type][item+'_type']])
treasure += '* Magic {} <br> '.format(treasure_dict[t_type]['Magic '])
treasure += 'The total value of this hoard is {}gp <br>'.format(int(total))
return treasure
workflow.set_output(dungeon_gen(levels))
There are no comments yet.