What's New

Here are the most recent additions to the website. To find the latest for a specific category that you are interested in, just click on the "Categories" links on the right side of the screen. To get the Deluxe version of the article (a.k.a the version where the pretty pictures also show), click on the Article title to go to the Article's own page.

Divider

Hot Off the Press

Python and Scribus Scripts to Deal Story Cards

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.

Input

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;

  • Challenges.txt
  • Characters.txt
  • Events.txt
  • Locations.txt
  • Objects.txt
  • Endings.txt

These are a text list of story elements. Each line is a separate story element. For instance here is a fragment from the Characters.txt.

Fragment of Characters.txt

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[0]]
    CardCat = CardCategory.split(".")
    CCateg = CardCat[0] + ": "
    Entry = CCateg + line[1]
    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[0]])   #Pull out the index and use it to get the image file name.
    scribus.loadImage(Imgnames[EntryCd[0]], 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[1], '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.

Scribus Story Card Dealer Script 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.

Lire la suite - Read More …

Par Hamish Trolove, Catégorie : Tutorials

Tags : Scribus / Python / Graphics / Tools /

Recent Articles

Hand Installing pySerial into Python Installations

Le Sun 30 October 2016

This is a development step along the route of designing a Homebuilt VR System. PySerial is a useful python library for accessing the serial port. As such it is ideal for allowing us to directly connect the Arduino output to the Blender Game Engine python environment for efficient transfer of sensor readings to motion in the virtual environment. This page describes how to install pySerial in standalone applications with their own embedded Python environments without the need to do all kinds of extra things like installing and using pip or Easy-Installer.

Par Hamish Trolove, Catégorie : Tech Projects

Tags : VR / Arduino / Blender / Python /

Lire la suite - Read More …

The GY87 Combined Sensor Test Sketch

Le Thu 15 September 2016

I am intending to use a GY87 board on my Homebuilt VR system. This page describes the connections and an Arduino sketch that tests all of the GY87 board's sensors together and outputs the data to the Serial Port.

Par Hamish Trolove, Catégorie : Tech Projects

Tags : VR / Arduino / Electronics / Sensors /

Lire la suite - Read More …

A Homebuilt Virtual Reality System

Le Wed 07 September 2016

The project is a work in progress. It describes a home built VR system based on the Quanum FPV headset used for FPV piloting of remote controlled aircraft, and making use of the GY87 10 degree of Freedom sensor to provide head tracking. It is envisaged this will be coupled to a computer running a game engine like Blender, Unity or Godot which will allow the user to build and share their own virtual environments.

Par Hamish Trolove, Catégorie : Tech Projects

Tags : VR / Arduino / Blender / Electronics / Games / Sensors /

Lire la suite - Read More …