• Register

In The Broken Hourglass, players control an ordinary citizen of Mal Nassrin, fading star of the Tolmiran Empire. The city is under siege by some unexplained and unidentified magical force--no one may enter or leave, and the city's water supply has been reduced to a trickle. Caught in a devastating explosion which obliterates a large area of the city, you begin the game as a recuperating refugee caught up among an eager group of vigilantes and makeshift militiamen hoping to put the city to rights before complete chaos takes hold.

Post tutorial Report RSS Introduction to wscript in The Broken Hourglass

This tutorial gives a brief introduction to wscript, the functional programming language used to govern event scripting in The Broken Hourglass.

Posted by on - Basic Client Side Coding

[page=Introduction to wscript]
Tutorial Image
The Broken Hourglass uses a novel scripting language under the hood called wscript. Here's the official definition of wscript:

The WeiNGINE scripting language wscript is a strongly-typed functional programming language with parametric polymorphism, first-class functions, and variable updates in the style of Objective CAML.

Don't worry--you don't have to understand all of those terms in order to successfully edit and compose scripts in a WeiNGINE game. (Although it certainly doesn't hurt.)

Two important concepts to know and understand are:

· wscript is object-oriented. Every thing in the game can have a number of predefined engine attributes (such as location on a map, or a Strength statistical value) as well as any number of arbitrary variables attached to it.

· wscript is event-driven. scripts are evaluated and run whenever a script hook event takes place. There are dozens of script hook events in the game, ranging from the manipulation of doors and containers to the computation of an attack roll, to a creature joining or leaving a party.

[page=The Way Of Things]

Resources such as items, creatures, and spells all fall under the umbrella of a scripting "thing." We refer to things in wscript with a matched pair of strings, separated by a double colon. Generally speaking, the left side of a thing is the name of the thing, while the right side is the type of resource it is.

For example--

"makarios"::"CREATURE"
and
"greatsword"::"ITEM"

are both things--the creature internally named "makarios" and the item internally known as "greatsword", respectively.

Because wscript is object-oriented, variables and attributes of a thing are referred to as belonging to that thing in a wscript expression. So to query the Appearance (sprite) being used by the Makarios creature, the syntax would be:

"makarios"::"CREATURE".Appearance

If a game event required that a script cause Makarios's appearance to change into a bowl of oatmeal as defined by a sprite animation file known as bowl-of-oatmeal, we would execute the following:

"makarios"::"CREATURE".Appearance <- "bowl-of-oatmeal"

(In many scripting expressions, = and <- may be used interchangeably.= is usually employed to initialize a variable, or to express mathematical equality.)

In addition to engine-specific attributes such as Appearance, things such as "makarios"::"CREATURE" may have variables associated with them as well. These variables may be read or modified by any piece of code.

If we wanted to store a flag for each creature in the game who likes music, we could express it as:

"makarios"::"CREATURE".int.LikesMusic = 1

In addition to int (signed 31-bit integer) variables, variables may also be strings, things, or coordinate points on a map (which are expressed as "X"::"Y")

[page=Writing and Associating scripts]

In addition to being associated with events, a piece of script code must be associated with something in the game in order to do anything useful. For example, the @before_hit event hooks on both the attacker and the victim in a successful strike, so in order for code to fire, it must be associated with either an attacker or a victim (or both.)

There are two ways to associate script hook code with a thing.

The first is to assign that thing an effect which specifies the name of the script hook code and the event that hook is associated with.

Such an effect looks like this:

<script_Hook event="area_shown" hook="talk-area-shown-hook"/>

Any thing which possesses this effect will be eligible to perform the script hook named "talk-area-shown-hook", associated with the @area_shown event.

The second way to associate a block of code with a thing is with the foreach keyword. Placed at the end of a script block, foreach tells the game a thing or list of things which should be connected with the script block.

Consider this example. (We'll delve into the meaning of the code in later tutorials, but it does just about what you would think it does in English. _player1 is a special shortcut which designates the player character as a thing.)

@after_area_shown "geneia-fuad-intro" fun this_area {
once this_area "fuad-intro" do
cutscene_once_per_game "fuad-introcut" {
_action_walk_to_thing ("geneia-fuad"::"CREATURE") _player1
then
_set_facing_each_other [("geneia-fuad"::"CREATURE"), _player1]
then
_start_dialogue ("geneia-fuad"::"CREATURE") "intro"}
done ;} foreach [ "starthouse" :: "AREA" ]

The foreach [ "starthouse" :: "AREA" ] portion of this code tells the game that this piece of code should be associated with the resource starthouse.AREA. @after_area_shown is an event which takes place shortly after the game loads up an area.

Internally, the foreach and effect-based method of pairing script hooks with things are equivalent. In most cases, it is simply a matter of convenience and coder preference which method is used. Since foreach cannot be inherited, effects are typically better for associating script hooks with things which will be used as templates for many other things.

This example can be used to see the basic structure of a script block. We begin with the name of the event associated with the hook--in this case, @after_area_shown. Next, we give the script block a unique name, "geneia-fuad-intro". The fun keyword indicates that this will be a function. To understand the next word, this_area, let's look at the scripting docs for this event--



after_area_shown area : thing ->
unit
Hooks on area "AREA". Occurs whenever the console viewport shows area, but occurs slightly after that happens. Will generally occur more than once per area. Notably, this occurs when the game starts, when the game is loaded, or when the party moves from area to area.

See also @area_shown. This event is probably better for general script work involving creatures.


The middle column is the important one here--it lists all of the resources and variables which are directly (and always) involved in this event. In this case, there is just one--the area (expressed as a thing) being shown. We are able to use any label we wish to refer to the area, as long as we are consistent about it. So instead of we could have used just this_areaarea or we could have used toothbrush or absolutely anything else--so long as we consistently use that word inside the script hook whenever we are referring to the area being shown. So this_area refers to the area (expressed as a thing) which has just been shown.

Once is a special keyword which acts as a shortcut to setting (and later checking) a flag to ensure that a particular piece of code is only executed once. Once requires a thing to associate the flag with, and a string to name the flag variable, so we get that from this_area "fuad-intro" -- that is, this_area is the area being shown, and "fuad-intro" is the name of the variable. When all is said and done, this code will set "starthouse"::"AREA".int.fuad-intro = 1.

We will explore the body of the script and the concept of cutscenes in a later column. By convention, predefined library functions carry a _ prefix. You may also define and export your own functions for frequent coding use--another advanced topic.

(This tutorial was originally posted on the Planewalker Games website on 11-27-06.)

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: