Skip to content

Script Basics

This document assumes you have no programming foundation and will gradually explain concepts related to Yin.Story. If you already know JavaScript, you can directly jump to Yin.Object Extensions.

Script Language

Yin.Story relies on Yin.Object for construction, using JavaScript as the scripting language. We strive to reduce script complexity, allowing you to start scripting by understanding just a few basic concepts.

What is a Script?

Computers execute instructions line by line from scripts. For example:

Comments in Code

Gray text after // are comments explaining the next line. Comments are optional and not executed.

js
// Set three variables: money=529,900, faceScore=999999999999, liuruyanslove=false
let money = 529900, faceScore = 999999999999, liuruyanslove = false
// If money + faceScore > 100,000,000
if (money + faceScore > 100000000) {
    // Set liuruyanslove to true
    liuruyanslove = true
}
else {
    // Set liuruyanslove to false
    liuruyanslove = false
}

What is an Object?

An object is a collection of data (variables) and functionality. For example:

js
// Create a 'me' object
let me = {
    title: 'Xiao Ming',
    money: 529900, // Assets
    faceScore: 999999999999, // Appearance score
    cp: 500, // Combat power
    mate: null // No mate
}

// Create an NPC array containing two NPCs
let NPCList = [
    {
        title: 'Liu Ruyan',
        money: 10000000,
        faceScore: 99999999999,
        cp: 10000
    },
    {
        title: 'Ruhua',
        money: 300,
        faceScore: 5,
        cp: 9999999999 // Combat power overflow!!
    }
]

// If my assets + appearance score > 100,000,000
if (me.money + me.faceScore > 100000000) {
    // My mate = Liu Ruyan
    me.mate = 'Liu Ruyan'

    // The following are optional code snippets
    // Liu Ruyan is at the 0th index in NPCList (arrays use 0-based indexing)
    // In programming, we primarily use array indices (starting from 0) to access elements
    me.mate = 0
    // Or assign the actual value
    me.mate = NPCList[0]
}
// If the condition "my assets + my looks > 100000000" is not met
else {
    // My partner = null
    me.mate = null
}

// At this moment, Ruhua starts to forcibly take over and becomes my partner
// Create a variable called Ruhua, whose value is taken from the 1st element of the NPCList array (arrays use 0-based indexing)
// Ruhua is the 1st element in NPCList
let ruhua = NPCList[1]

// If my partner is null
if (me.mate === null) {
    // If my combat power < Ruhua's combat power
    if (me.cp < ruhua.cp) {
        // My partner = Ruhua
        me.mate = 'Ruhua'
    }
}
// If "my partner is null" is not true
else {
    // Create a variable called 'partner' and leave it unassigned for now
    let mate
    // Liu Ruyan is the 0th element in NPCList  
    // Assign the value of 'partner' from the 0th element of the NPCList array (arrays use 0-based indexing)
    mate = NPCList[0]

    // The following are optional code snippets  
    // If using the index of the array in the optional code snippet above - me.mate = 0  
    // Then the variable 'mate' can be assigned from the value at the index 'me.mate' in the NPCList array  
    mate = NPCList[me.mate]
    // If using a specific value in the optional code snippet above - me.mate = NPCList[0]  
    // Then the variable 'mate' can be directly assigned from 'me.mate'  
    mate = me.mate
    // In programming, we often use the optional code snippet approach because it supports more flexibility (e.g., multiple partners) rather than specifying Liu Ruyan explicitly  

    // If my combat power + my partner's (Liu Ruyan's) combat power < Ruhua's combat power  
    if (me.cp + mate.cp < ruhua.cp) {
        // My partner = Ruhua 👍  
        me.mate = 'Ruhua'
    }
}

What is a Function?

A function is a collection of script instructions. For example, the companion judgment logic from the object section can be encapsulated into a reusable function.

In this system, functions are typically attached to objects. Example:

js
// Create an object called 'me' that contains multiple key-value pairs
let me = {
    title: 'Xiao Ming',
    money: 529900, // Assets
    faceScore: 999999999999, // Appearance score
    cp: 500, // Combat power
    mate: null, // No mate
    /**
     * Make an NPC become my partner
     * @param npc {Object} - Input is a character object
     * @return {Object|null} - Output is the current partner or null
     */
    beMyMate(npc) {
        let ruhua = NPCList[1];

        // If there is already a partner, and the partner is not Ruhua
        // Note: When the function is attached to an object (as in this case), 'this' refers to the object 'me' within this function
        if (this.mate !== null && this.mate !== ruhua) {
            // Cannot change the partner, return the current partner as the output
            return this.mate;
            // The function ends here, and no further scripts are executed
        }

        // If my assets + my looks > npc's assets + npc's looks
        if (this.money + this.faceScore > npc.money + npc.faceScore) {

            // If my combat power + npc's combat power >= Ruhua's combat power
            if (this.cp + npc.cp >= ruhua.cp) {
                // My partner = npc
                this.mate = npc;
                // Return npc as the output
                return npc;
                // The function ends here, and no further scripts are executed
            }
        }
            // If my assets + my looks > npc's assets + npc's looks is not true
        // But if my combat power >= Ruhua's combat power
        else if (this.cp >= ruhua.cp) {

            // Break free from Ruhua's constraint, clear the partner
            this.mate = null;
            // Return null as the output
            return null;
            // The function ends here, and no further scripts are executed
        }

        // If the function reaches this point, Ruhua is forcibly bound as the partner
        this.mate = ruhua;
        // Return the character Ruhua as the output
        return ruhua;
    }
}

Yin.Object Extension

The core of Yin.Story relies on Yin.Object for its construction. The data objects are extended from native JavaScript objects, adding features such as persistence and hot synchronization.
These changes also affect how child objects and arrays are accessed.

Due to persistence, Yin.Object assigns an address to each object. The object address can be found on the second line of the object panel when opened. Clicking the address will copy it, or you can right-click the object and select reference to copy the object address.

For example, the place of 片头 is Element.6964ae79ef2432c0cc8e8de3.

Objects in Yin

We can bind scripts to data objects to enhance their functionality. By clicking the plus sign next to the script in the editor, a script can be created and bound to the data object. At this point, the editor will generate JSDoc for the script to provide code hints.

Below is an explanation using the display condition of an event script from Yin.Story as an example:

js
// Script for an event object
export default {
    // Event show condition
    async show(save) {
        // Get the target scene of this event
        const scene = await this.target;

        // Get the target scene by address, check the second line after opening the object
        const target = await this._yin.get('Element.6964ae79ef2432c0cc8e8de3');

        // Get the event list of the target scene
        const events = await target.events;
        // Retrieve the complete list
        await events.all();


        save.data.somevalue = 123;
        // Save the story data
        await save._save();

        // Save this event, but since the player does not have permission to manage this event, this will throw an error.
        await this._save();
    }
}

Congratulations!

You've completed all foundational knowledge for scripting in Yin.Story. The next guide will teach practical operations.