Follow along using the SCROLL (alpha version, bugs, no-guarantees, etc) REPL environment.
In the previous post, I covered the basics of using SCROLL
to generate a random hierarchy of entities together with their attributes.
I covered:
- Defining classes of entities
- Defining class attributes of various types
- Rolling values from a list
- Generating a list of entities
- The basics of using templates to generate text
In this post I will continue and explore:
- Collecting and re-using generated entities
- Using data injection to link entities together
- Using scope references to access ancestors entity values
To me, one of the neat things about HEXROLL is its ability to link entities together. This is done in a way that is just enough to prompt you with cool plot hook to further develop.
Let’s take a look at how this linking thing actually works.
Collections
By using collections we can instruct an entity to ‘collect’ references to other entities generated as part of its hierarchy, regardless to their depth.
For example, in the previous post we generated realms that contain settlements, which in turn, contain NPCs.
Let’s extended that model and use a collection directive to store references to all generated NPCs inside the realm:
Realm {
<< Npc
name @ [
* Ishabor
* Zeratha
* Inaba
]
[3..6 settlements!] @@ [
* Town
* Village
]
}
We use the <<
operator followed by a class name to tell SCROLL
to store a reference to any generated entity of that class within its hierarchy.
<< Npc
This allows us to re-use collected entities in other entities within the same parent class.
For example, we can use the collected NPCs to form factions with members from any part of the realm:
Faction {
name! @ [
* The Flaming Lambs
* The Army of Justice
]
[6..13 members!] ? Npc
<html%
<h1>{{name}}</h1>
<h2>Members</h2>
<ul>
{% for member in members %}
<li> {{ member.full_name}} </li>
{% endfor %}
</ul>
%html>
}
We use the ?
operator (pop entity) instead of the @
operator to ask SCROLL
to use one of the referenced NPCs as a faction member.
Note that by using the ?
operator, we tag any randomly selected entity as used. Alternatively, we can use the %
operator (pick entity) to select a random entity from a collection rather than use it.
Data Injection
Data injection in SCROLL
is a method to share data between entities - specifically when generated on different “branches” of the directed graph.
For example, we can use data injection to populate faction NPCs with their faction name:
Faction {
name! @ [
* The Flaming Lambs
* The Army of Justice
]
[6..13 members!] ? Npc {
faction = &name
}
<html%
<h1>{{name}}</h1>
<h2>Members</h2>
<ul>
{% for member in members %}
<li> {{ member.full_name}} </li>
{% endfor %}
</ul>
%html>
}
To indicate the attributes we want to inject, we use a {
curly braced }
block immediately after the class name we want to reuse (Npc
in this case). This tells SCROLL
that for each used entity it picks or pops from a collection, it has to set additional injected values.
[6..13 members!] ? Npc {
faction = &name
}
We then specify faction
as the attribute we want to inject to and &name
as the value, which means, copy the value from the owning entity attribute name
. The &
operator means copy in this context.
Note that there’s another way to reference attributes when injecting data by using the pointer operator *
- but we will cover this in a later post.
Now that we have injected data into selected NPCs, we can use it to enrich their description:
Npc {
first_name @ [
* Walatus
* Ajutor
* Sieggo
* Milia
* Petesia
* Lefsy
* Latilde
]
last_name @ [
* Bossinia
* Brightmer
* Ermenbald
* Hildeward
* Siclebald
* Zawissius
]
age @ 7d12
faction = 0
description! = <%
{{first_name}} {{last_name}}
({{age}} years old)
{% if faction %}
{{faction}}
{% endif %}
%>
}
First, we declared the faction
attribute and set it to 0
- telling the generator that this attribute is currently holding no value. We could also use the keywords null
or false
.
Next, in the faction description
attribute, we check whether or not faction
was set externally, and if it holds a value, we use it.
Note that another way of do this is using the template function maybe
, but I will cover this in the next post.
Scope References
In cases when an entity needs a value from one of its ancestors, we can use a scope reference:
Faction {
name! @ [
* The Flaming Lambs
* The Army of Justice
]
realm_name = :Realm.name
realm_class = :Realm.class
objective! = <%
{{name}} objective is to overthrow
{{realm_name}}'s ruler and gain control over
the {{realm_class}}.
%>
[6..13 members!] % Npc {
faction = &name
}
<html%
<h1>{{name}}</h1>
<p> {{objective}} </p>
<h2>Members</h2>
<ul>
{% for member in members %}
<li> {{ member.full_name}} </li>
{% endfor %}
</ul>
%html>
}
We use the :
operator followed by an ancestral class name to refer to a parent, and then use .
to reference a specific attribute:
realm_name = :Realm.name
realm_class = :Realm.class
In this case, we created to new faction
attributes, realm_name
and realm_class
, and using the parent Realm
entity to set their values accordingly.
Putting everything together
Copy and paste the following into the REPL editor:
Npc {
first_name @ [
* Walatus
* Ajutor
* Sieggo
* Milia
* Petesia
* Lefsy
* Latilde
]
last_name @ [
* Bossinia
* Brightmer
* Ermenbald
* Hildeward
* Siclebald
* Zawissius
]
full_name! = <% {{first_name}} {{last_name}} %>
age @ 7d12
faction = 0
description! = <%
{{first_name}} {{last_name}}
({{age}} years old)
{% if faction %}
<br/>
<strong>Member of {{faction}}</strong>
{% endif %}
%>
}
Settlement {
name @ [
* Akkis
* Bazuul
* Devilville
* Ecrean
* Frostfyord
* Khezal
]
<html%
{{title}} is home for: <ul>
{% for npc in npcs %}
<li> {{ npc.description }} </li>
{% endfor %} </ul>
%html>
}
Village (Settlement) {
title! = "The Village of {{name}}"
[6..12 npcs!] @ Npc
}
Town (Settlement) {
title! = "The Town of {{name}}"
[12..24 npcs!] @ Npc
}
Faction {
name! @ [
* The Flaming Lambs
* The Army of Justice
]
[6..13 members!] % Npc {
faction = &Name
}
<html%
<h1>{{name}}</h1>
<h2>Members</h2>
<ul>
{% for member in members %}
<li> {{ member.full_name}} </li>
{% endfor %}
</ul>
%html>
}
Realm {
<< Npc
name @ [
* Ishabor
* Zeratha
* Inaba
]
[3..6 settlements!] @@ [
* Town
* Village
]
faction! @ Faction
}
Kingdom (Realm) {
title! = "Kingdom of {{name}}"
}
Duchy (Realm) {
title! = "Duchy of {{name}}"
}
main {
realm! @@ [
* Kingdom
* Duchy
]
<html%
<p>
Our realm is the
<strong>{{realm.title}}</strong>.
</p>
<p>
The realm has the following settlements:
{% for s in realm.settlements %}
<p> {{html(s)}} </p>
{% endfor %}
</p>
{{html(realm.faction)}}
%html>
}
The next post on SCROLL
will be dedicated to template functions and how they can be used to process entity values when rendering HTML, as well as to some of the less frequently used features of the language. Until then.. Enjoy the Crawl!
Ithai