Le Wed 23 November 2016
I enjoy story-telling games. I have various story telling games such as Gloom, a game I made up loosely based on Nanofictionary, The Extraordinary Adventures of Baron Munchausen, and various heavily modified versions of Atlas Games' Once Upon a Time. Of course the natural thing to do was to come up with my own game. This has a working title of “Story Soup” and about 600 cards ... which means to shuffle the cards effectively you need pretty big hands. I have yet to finalise this, but in the meantime I was keen to use it to generate some plots for some stories.
Seeing as I had the card contents on a bunch of files, writing a python script to deal a hand was straight forward. One thing lead to another and I realised the I could use the same process to generate a hand of cards in a nice looking spread on a page in Scribus all ready for printing off. This script is based on the script outlined in this article: A Scribus Script to Distribute Images Across Page
So here are the scripts I developed. They are not all that user friendly but easy to modify to suit your own purposes. They are designed to run on a bunch of text files sitting in the same directory as the script.
The scripts are automatic once they have been set going and so any files that need to be included need to be defined in the scripts themselves.
The files the scripts use to load content from are;
These are a text list of story elements. Each line is a separate story element. For instance here is a fragment from the
So you can see from this example that serious stories are probable not going to be that common.
For the Scribus script there are some corresponding files for the background images. These were all strictly sized to fit the layout used in Scribus. Again, please refer to this article: A Scribus Script to Distribute Images Across Page
Standalone Python Script
The script that can be used with any python installation is listed below. You can download it from here: StoryCard_Deallerv2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
#!/usr/bin/env python # StoryCard_Deallerv2.py # The following is a small utility to deal out a selection of cards from the # Story Soup deck. import os import random CardCollection =  # List to contain all the story cards. fnames = ["Challenges.txt","Characters.txt","Events.txt","Locations.txt","Objects.txt"] # List containing the source filenames for the different card types. CardItems = len(fnames) for CardType in range(0,CardItems-1): WorkingFile = open(fnames[CardType],"r") Filelines = WorkingFile.readlines() WorkingFile.close for line in Filelines: CardCollection.append([CardType,line]) # At this stage we should have a list with all of the cards and their type appended. We need a seperate # list for the ending cards. EndingList =  WorkingFile = open("Endings.txt","r") Filelines = WorkingFile.readlines() WorkingFile.close for line in Filelines: EndingList.append(line) StoryCardNo = 8 # Number of story cards to deal EndingCardNo = 2 # Number of ending cards to deal. StorySelection = random.sample(CardCollection,StoryCardNo) EndingSelection = random.sample(EndingList,EndingCardNo) print(StorySelection) print(EndingSelection) #Output this to a new text file. DealtCardsFile = open("DealtCards.txt","w") DealtCardsFile.writelines("Story Cards\n") for line in StorySelection: CardCategory = fnames[line] CardCat = CardCategory.split(".") CCateg = CardCat + ": " Entry = CCateg + line DealtCardsFile.writelines(Entry) DealtCardsFile.writelines("\n\n") DealtCardsFile.writelines("Endings\n") DealtCardsFile.writelines(EndingSelection) DealtCardsFile.close()
The way it works is that it loads the contents from each text file (except
Endings.txt) into a single list together with a number that represents the type of card. It does the same with the
`Endings.txt but into a separate list.
From those lists it randomly selects a defined number of story element cards and ending cards and displays these in the terminal as well as writing them to a new text file. The two lines used to define how many cards are selected are;
StoryCardNo = 8 # Number of story cards to deal EndingCardNo = 2 # Number of ending cards to deal.
Here are two examples of the output file content;
Story Cards Characters: The student Challenges: plugged the thing into the wrong thing Locations: The blacksmith's forge Characters: the surgeon Locations: dance class Locations: At the hairdressers. Characters: a lawyer Characters: A child Endings When they saw how big it was they couldn't stop laughing. Only one of them was left
and another deal.
Story Cards Locations: ruins in the forest / jungle Events: someone builds something. Locations: In a hospital ward Challenges: there were gaps in their memory Locations: In the garden with a statue everyone wanted to touch. Locations: Impassable geography (eg large cliff, or mountain pass) Locations: Sinking sand Challenges: they had been asleep for 100 years Endings Their secret was exposed ...and so he lived the rest of his life as a zombie/vampire/werebeast, which suited him just fine.
Do they sound like starters for stories to you? Yep. I think so too. The first one looks like it would be a pretty daft story, but the second one has the potential to be a bit more edgy ...with a bit of work.
The Scribus Script
The script above is the heart of this script. The difference is the use of the Scribus python functions to distribute the text around the page and place the appropriate background images for each card type. The script works in Scribus 1.4.3. I have yet to try it in the new Scribus 1.5.
Download the script from here: StoryCard_DeallerScribusv0.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
#!/usr/bin/env python """ StoryCard_DeallerScribusv0.py The following is a small utility to deal out a selection of cards from the Story Soup deck. This variation uses an index rather than the Card type name The script then pulls up the appropriate background image and drops them into A sheet of 10 cards. You will need to ensure there are enough pages in your document to hold all of the cards you generate. @author: Hamish Trolove @website: www.techmonkeybusiness.com @copyright Creative Commons - by nc sa """ import os import random import sys try: import scribus except ImportError: print ("This script only runs from within Scribus.") sys.exit(1) try: from PIL import Image except ImportError: print ("Unable to import the Python Imaging Library module.") sys.exit(1) CardCollection =  # List to contain all the story cards. fnames = ["Challenges.txt","Characters.txt","Events.txt","Locations.txt","Objects.txt"] # List containing the source filenames for the different card types. Imgnames = ["Challenges.jpg","Characters.jpg","Events.jpg","Locations.jpg","Objects.jpg","Endings.jpg"] #List of the background image names for the corresponding card types. CardItems = len(fnames) multTx = 0 # Multiplier for the column position multTy = 0 # Multiplier for the row position pageInd = 1 # Page number w = 55 #Width of Image frame h = 90 #Height of Image frame scribus.gotoPage(pageInd) # Make sure it always starts from first page StoryCardNo = 8 # Number of story cards to deal EndingCardNo = 2 # Number of ending cards to deal. NumCards = StoryCardNo + EndingCardNo #Number of cards to insert. for CardType in range(0,CardItems-1): WorkingFile = open(fnames[CardType],"r") Filelines = WorkingFile.readlines() WorkingFile.close for line in Filelines: CardCollection.append([CardType,line]) # At this stage we should have a list with all of the cards and their type appended. We need a seperate # list for the ending cards. EndingList =  WorkingFile = open("Endings.txt","r") Filelines = WorkingFile.readlines() WorkingFile.close for line in Filelines: EndingList.append([5,line]) StorySelection = random.sample(CardCollection,StoryCardNo) EndingSelection = random.sample(EndingList,EndingCardNo) print(StorySelection) print(EndingSelection) StorySelection.extend(EndingSelection) # Now we create the Scribus page(s). This is done by reading StorySelection and EndingSelection # and using the indexes in them to find the appropriate background image. for EntryCd in StorySelection: #Each entry will be another list with the index and card text. if multTy > 1: multTy = 0 multTx = 0 pageInd = pageInd + 1 scribus.gotoPage(pageInd) x = 11 + w * multTx #first corner is 11mm across. y = 15 + h * multTy #first corner is 15mm down. # create an image frame and put the image into it #The business card dimensions are known and so we are looking to drop image into this size frame. ImageFrame = scribus.createImage(x, y, w, h) #BkgndImg = Image.open(Imgnames[EntryCd]) #Pull out the index and use it to get the image file name. scribus.loadImage(Imgnames[EntryCd], ImageFrame) scribus.setScaleImageToFrame(True, False,ImageFrame) scribus.setFillColor("None", ImageFrame) scribus.setLineColor("None", ImageFrame) scribus.selectObject(ImageFrame) scribus.moveSelectionToBack() scribus.deselectAll() #BkgndImg.close() #Now add the text over the top. frame = scribus.createText(x+7.5, y+35, w-15, h-30) text = unicode(EntryCd, 'iso-8859-2') #Pull out the text for the selected card. scribus.setText(text, frame) scribus.setTextAlignment(1,frame) # ALIGN_CENTERED = 1 scribus.setFont('Algerian Regular',frame) scribus.setFontSize(14,frame) scribus.setLineSpacing(12,frame) scribus.selectObject(frame) scribus.moveSelectionToFront() scribus.deselectAll() # Control to index around the page. if multTx > 3: multTy = multTy + 1 multTx = 0 x = 11 else: multTx = multTx + 1
The output is a Scribus document which can easily be turned into a pdf.
To use this script, start a new document with a A4 page in a landscape orientation. In this case the margin are 11mm on the left and right and 15mm on the top and bottom.
Run the script by going to Scripts in the top menu bar and Execute Script. Navigate to the
StoryCard_DeallerScribusv0.py which will need to be in the same directory as your story element files, and hit “OK”.
Crash! Bang! Wollop! We have our spread of cards. The original card designs were not done with an automated system laying out the text in mind, and so there is a bit of realignment needed – or more to the point I should standardise the layout between card types. But whatever, the script does it's job.
So here is an example output.
I think I would struggle to get anything out of this spread.
Anyway, I hope this is useful at least as a basis for someone else's card dealler, story shuffler.