ChapelR The Speech Box System how to use variable images SugarCube 2

Twine Version: 2.3.14
Story Format: SugarCube 2

Hi all,

Been trying to get this to work for AGES. I have made a combat system that pulls different enemies from a passage. (sets different combat variables etc). I have used the below to change the display name based on a variable (this works), I also want to be able to change the image based on a variable as well.

I define the character like so (Have tried loads of different ways to call the image.

In Storyinit

<<character 'enemy' '$enemyname' '[img["images/enemies" + "$enemypic" + .jpg]]'>>

Then I load it in a passage like so:

<<set $enemyname = "angry man">>

<<set $enemypic = "angryman">>

I have used every different method I can think of, but am running into a real roadblock. Any ideas?

Three issues:

  1. You’re quoting the variables you’re using when you should not be. In general, unless the macro you’re using tells you to do so, you never quote variables.
  2. You’re attempting to use the [img[]] markup as an argument to <<character>> and I’m not sure that works.
  3. The <<character>> macro allows you to predefine persistent, usually significant, characters. You seem to be attempting to use it to create short-lived/temporary characters, which may be better handled via the <<say>> macro.

Regardless. You’d predefine a character with <<character>> like so:

<<character 'enemy' $enemyname `'images/enemies' + $enemypic + '.jpg'`>>

And use it as follows:

<<enemy>>Get the hero!<</enemy>>

In case <<say>> seems a better fit, usage of that would look like the following:

<<say $enemyname `'images/enemies' + $enemypic + '.jpg'`>>Get the hero!<</say>>

SEE: Chapel’s Speech Box system.

1 Like

Thank you for the response. I have tried it and it is still not showing up :(. It might need altering in the javascript to get it to work, but this is way outside my level of understanding.

(function () {
// v1.1.1
‘use strict’;

var characters = new Map();

function addCharacter (name, displayname, icon) {
  if(icon === undefined && displayname){
  	icon = displayname;
  	displayname = null;
    if (State.length) {
        throw new Error('addCharacter() -> must be called before story starts');
    if (!name || !icon) {
        console.error('addCharacter() -> invalid arguments');
    if (characters.has(name)) {
        console.error('addCharacter() -> overwriting character "' + name + '"');
    characters.set(name, {displayName: displayname, image: icon});

function say ($output, character, text, imgSrc) {
    var $box = $(document.createElement('div'))
        .addClass(Util.slugify(character) + ' say');

    // portrait
    var _img = characters.has(character) ? characters.get(character).image : null;        
    var $img = $(document.createElement('img'))
        .attr('src', imgSrc || _img || '');

    if ($img.attr('src') && $img.attr('src').trim()) {

    // name and content boxes
  var _name =  character.toUpperFirst();
  if (characters.has(character) && characters.get(character).displayName) {
        _name = characters.get(character).displayName;


    if ($output) {
        if (!($output instanceof $)) {
            $output = $($output);

    return $box;

setup.say = say;
setup.addCharacter = addCharacter;

Macro.add('character', {
    // character macro
    handler : function () {
        addCharacter(this.args[0], this.args[1], this.args[2]);

$(document).one(':passagestart', function () {
    // construct array of character names
    var names = Array.from(characters.keys());
    // generate macros
    Macro.add(names, {
        tags : null,
        handler : function () {
            if ( !== 'say') {
                say(this.output,, this.payload[0].contents);
            } else {
                say(this.output, this.args[0], this.payload[0].contents, this.args[1]);


You never state what the value of $enemypic looks like.

Based on the path & file name structure of image file reference shown in of your original example…

<<character 'enemy' '$enemyname' '[img["images/enemies" + "$enemypic" + .jpg]]'>>

…and the same structure used in TME’s correction of your original example…

<<character 'enemy' $enemyname `'images/enemies' + $enemypic + '.jpg'`>>

…the String value stored in the $enemypic would need to start with a forward slash / character.

eg. If $enemypic equalled ‘/orc’ then the image file related expression in TME’s example would evaluate as follows…

`'images/enemies' + $enemypic + '.jpg'`

=> `'images/enemies' + '/orc' + '.jpg'`

=> 'images/enemies/orc.jpg'

However if the String value stored in the $enemypic variable doesn’t start with a forward slash / character, then you would need to modify TME’s expression to include that slash after the word enemies

`'images/enemies/' + $enemypic + '.jpg'`

It worked!!! Thank you so much. I cannot believe it was due to a forward slash. I am so happy yet feel so stupid :slight_smile: