Foreword

Thank you for picking up "Kirikiri/KAGEX Course ~Digital Novel Production~". In this book, we will explain scripts for novel games using Kirikiri/KAGEX. In recent years, novel games have become more advanced in terms of direction and systems, and scripting has become increasingly difficult. With Kirikiri/KAGEX, these things can be achieved relatively easily, but the drawback is that the manuals are almost non-existent or unfriendly. I hope this book can improve that situation even a little.

When it comes to novel game production tools, the traditional Kirikiri and NScripter are well-known. Recently, others like YU-RIS, CatSystem2, and Ren'Py from overseas have also emerged. The target of this book is Kirikiri, but instead of KAG, which is often featured in commercial manual books, we will use a system called KAGEX. KAGEX is a modified and expanded version of KAG, and it allows you to create modern-style novel games relatively easily. We'll leave the details for the main text. It has become truly convenient compared to KAG, and even those who have used KAG might be surprised.

Novel game production itself seems to be on the decline compared to a while ago. This trend is somewhat disheartening. I haven't checked it yet, but TYPE-MOON's new work "Witch on the Holy Night" is supposedly amazing, so I wonder if Kirikiri users might increase again. However, if you download Kirikiri and try to touch KAG, you might give up because of the sheer gap. That's where KAGEX comes in, and by extension, this book.

I'd also like to briefly introduce myself here. My name is sakano, and I operate under a personal doujin circle called Biscrat. Although I am still a university student, I have made several doujin games. Usually, I primarily undertake scripting for novel game production. I am always looking for work, so if you need anything, please contact me via the contact information at the end of the book.

I have made several novel games, though it was through trial and error. I have tried to reflect that experience in this book as much as possible. Since this is from the perspective of a single programmer involved in novel game production, the content may be biased. To complete a novel game, various elements like scenarios and graphics are needed, not just scripts. Making a game takes effort and is truly difficult, but it also has its own kind of fun. I hope this book helps you in your creative activities. I look forward to being able to play the game you create.

                       December 30, 2011 sakano

Index

1. Introduction 5

Kirikiri is free software that can make many things 5

TJS is the script language used in Kirikiri 5

KAG is a system for making adventure games in Kirikiri 6

KAGEX is a system for making novel games, modified from KAG 6

Scripting languages and programming languages 6

Adventure games and novel games 7

About "Digital" Novels 8

The flow of digital novel production 9

2. Preparing the Development Environment 13

Displaying file extensions 13

Obtaining the Kirikiri/KAGEX SDK 13

Compression/Decompression 15

Obtaining asset files 15

Preparing the development folder 15

Preparing .Net Framework 4 16

Preparing a text editor 16

3. Script Basics 18

Folder structure 18

Displaying text 19

About running Kirikiri 20

About Debug Mode 21

About Shortcut Keys 22

Displaying images 22

Omission of vowel marks (Chōonpu) 22

About layers 22

About image formats 23

Displaying backgrounds 24

Image positioning 26

Pixels (pixel) 27

Displaying character sprites (Tachie) 28

Character sprite X-offset definition 30

Display levels 31

Displaying event CGs 32

Displaying other images 32

Comments 34

Shorthand notation 34

Playing BGM 38

About music file formats 39

Playing sound effects 39

True and False 40

Omitting the True Attribute Value 41

Script execution order 41

Specifying save data names 44

Deleting save data 45

Choices 46

Attribute values containing spaces 46

4. Image Operation Scripts 48

Transition basics 48

Other transitions 52

About synchronous/asynchronous transitions 53

Opacity 54

Actions via the time attribute 55

Actions via the path attribute 59

Image rotation 60

Rotation origin 61

Display origin 63

Scale ratio 65

Flipping 66

Slant ratio 67

Blur 68

Raster scroll 70

Relative specification 71

Percentage specification 72

Initial value specification 73

Rotation origin action 74

Word registration 74

Camera operation 75

Screen shaking 81

Extended transitions 82

Transition definitions 84

Auto transition definitions 85

Fade time definitions 90

Backup 90

Data exchange 91

Version control 91

5. Sound Operation Scripts 93

Synchronous/asynchronous playback 93

Fade-in/out 94

Volume specification 95

About volume settings 98

Panning 100

Loop tuner 101

Voice playback 103

Delayed execution 107

Facial expression scripts, etc. 108

6. Message Operation Scripts 110

Text display position 110

About color specification 112

Text frame 112

Showing/hiding message layers 113

Choices 115

7. Extras 119

About objects 119

Supplements目次---節">Supplement 119#9;119

Scenario script/System script 119

Macros 120

envinit.tjs 120

Choices 121

TJS-related talk 121

Variables 121

System scripts 122

Release 124

Menus, etc. 124

Voice 124

Video playback 124

Wait 124

About [Tags] 125

About Line Mode 125

About full-screen text display 125

Transitions 125

Time out 125

  1. Introduction

What exactly is Kirikiri/KAGEX that this book explains? That's what this is about. Since it doesn't matter too much, I hope you'll relax and read through it.

There might be some unfamiliar words mixed in, but in short, "Kirikiri" is free software that can do various things. You can create software that displays text, graphics, sounds, and more on a computer.

A large number of games across various genres like novel, shooting, role-playing, simulation, and action, as well as non-game applications, have been produced. In particular, it is heavily used commercially for the production of 18+ eroge. Examples include "Fate/stay night" and "Fate/hollow ataraxia" by "TYPE-MOON", and "STEINS;GATE 8bit" by "Nitroplus", which were games developed using Kirikiri.

The Kirikiri engine itself is made using a programming language called C++. Since it is developed as open source, you can even modify the engine itself if you can use C++. However, since this book is for beginners, we cannot touch upon this level of discussion at all. If you become able to handle C++, the range of what you can do expands significantly, so please try it if you are interested.

The current version of Kirikiri is "2", but its successor, Kirikiri 3, also seems to be under development. The best source of information regarding Kirikiri 3 is the Twitter of the creator, W.Dee (https://twitter.com/_w_dee). However, he rarely talks about Kirikiri. Kirikiri 3 is expected to have 3D capabilities and work on platforms other than Windows. Apparently, it will also support smartphones like iPhone and Android. Development doesn't seem to be progressing much, but there are high expectations.

To make something in Kirikiri, you need to use a script language called "TJS". TJS stands for Tejavajavascript, though this remains unconfirmed. TJS is easier compared to C++, but it is too complex for those without programming experience. Also, since TJS is almost exclusive to Kirikiri, there is little information, and it's hard to say that the environment for self-study is well-equipped. When studying TJS, I recommend studying programming with languages other than TJS, such as JavaScript. There are many books for beginners, and they are explained a lot on the web. If you study TJS after gaining knowledge of programming, it won't be that difficult. It may seem like a detour, but in the end, I think it will save you time.

If you download Kirikiri from the official site, the "KAG" system is included. KAG stands for Kirikiri Adventure Game and is a system that runs on Kirikiri for making adventure games.

As mentioned before, using TJS requires programming knowledge. Therefore, KAG is prepared so that even people uninterested in programming can make adventure games. The KAG system itself is made in TJS to run on Kirikiri, but if you're just using KAG to make a game, TJS knowledge isn't necessary. You can make an adventure game using only "KAG script," which is simple enough for non-programmers.

However, because KAG was made many years ago, its features are too poor for making modern adventure games. You can add most features by working hard to customize KAG yourself, but that again requires TJS knowledge. This is where KAGEX comes in.

"KAGEX" is a system for producing novel games developed by Takeshi Watanabe (https://twitter.com/wtnbgo) based on KAG. It is built as an extension of KAG. Since it was developed by a company that actually develops commercial games, various functions are available from the start. For general-format novel games, you can efficiently produce them by writing "KAGEX script". This book introduces how to use this KAGEX.

Explanations for Kirikiri/KAG can be found on the web or in books, but explanations for KAGEX barely exist. Since there are considerable differences between KAG and KAGEX, please be careful when referring to KAG explanations.

It's a minor detail, but it would be unfriendly not to explain it. Currently, computers have not reached the level where they can think and act automatically, so humans need to create commands for them in advance. Computers follow those commands and move exactly as instructed. These commands are called a "program."

And the work of creating programs is called "programming". For programming, you use "programming languages". For example, there are a huge number of them like C++, Java, Lisp, Fortran, and Prolog. "Scripting languages" are a type of programming language that are relatively simple. Examples include JavaScript, Lua, Awk, etc.—again, there are many. TJS used in Kirikiri is also a type of scripting language. As a side note, Kirikiri also allows you to use scripting languages other than TJS, such as JavaScript or Squirrel. If you want to use them, you might want to look them up.

The main content of this book is an explanation of how to write KAGEX script, the scripting language used in KAGEX.

I explained that KAG is for "adventure games" and KAGEX is for "novel games". What is the difference between adventure games and novel games? Personally, I don't think there is a widely shared definition.

Personally, adventure games are command-entry or command-selection types like "The Portopia Serial Murder Case". Novel games are games like the majority of recent 18+ novel games where choices are occasionally interspersed between the story. When I ask others, they seem to call the latter adventure games as well, so I might be wrong.

There are also classifications like adventure if the text is full-screen and novel if it's in the lower half, and it seems to vary from person to person. Or, some people say that novels are not games, and indeed there are linear novels where the player cannot intervene at all and just watches.

Since discussing gameplay elements is a heavy burden, I will omit it. Making games is fun, but researching games is also surprisingly interesting, so why not think about it for a bit?

Back to the point, since I can't quite get rid of my personal feeling that adventure games have more freedom than novel games, I'm designating KAGEX for novel games. Although since both are Kirikiri Adventure Games, I could just say they are for adventures.

Since KAG doesn't strictly limit its use, you can do various things with just KAG script if you push it. Compared to that, KAGEX is a system for producing games in the format common in 18+ novel games. The types of games you can make are narrower than with KAG, but you can produce specific games efficiently. Well, if you use TJS, you can still do a lot of things.

It only has the vague meaning that KAGEX feels narrower in use than KAG, so don't worry too much about it.

By the way, in the title of this book, I used "digital novel" instead of adventure or novel. I define a digital novel as digital content that conveys a story primarily through text expression, including both adventure and novel types. As usual, it's my personal definition that might not reach others. From here on, I will unify terms as "digital novel" without using words like novel or adventure.

I think people who like digital novels probably like reading stories. There are many other media that convey stories besides digital novels. Novels, manga, anime, movies, etc. are too many to count. Why choose a digital novel among these? Is what you want to make a novel, or perhaps a manga? Thinking about this before starting production might save you from wasting time.

Compared to games of other genres, digital novels can be made with less effort. They are produced even within the scope of hobbies like doujin activities, and a variety of works are created. That said, because there are many materials like text, sound, and graphics that must be prepared, it takes a huge amount of effort from multiple people. If you're trying to make something decent, you should be prepared. I recommend that absolute beginners try to complete one by themselves before involving others. For materials like pictures and sounds, free assets found on the internet are fine. Trying to make a major work by gathering members from the start is a recipe for failure. This is a common path to failure.

Digital novel production is hard, but let's think about the good parts. Compared to novels and manga, it has the advantage of using graphics and sounds other than text as a means of expression. Just like manga, the pictures become part of the expression rather than just text. Beautiful BGM and the voices of voice actors liven up the scenario and stir the player's emotions. Also, compared to movies and anime, the advantage is being able to use text. You don't have to prepare graphics for every single scene if you can express it with text. You can also introduce novel techniques into the text.

As a bit of a programmer, what I particularly want to say is that in digital novels, the system can also become part of the expression. Since it's a game that runs on a computer, all expressions that can be achieved on a computer are available.

"Choices" are a de facto standard game system widely adopted in digital novels. This is by no means just for letting the player select a route.

As an example, I'll introduce "When They Cry: Umineko" by "07th Expansion". There are episodes 1 to 8, and each is long, so it's not the kind of game you can easily recommend... At the climax of Episode 8, the final chapter of this game, questions related to the theme of the story are thrown at the player in the form of choices. The player, who had just been reading passively until then, is forced to stop and think actively to make a choice. It was very impressive to me, who had just been reading absentmindedly.

One more example of expression through the system is "Little Busters!" by "Key". This game is a so-called school-life game, but every day after school, a mini-game called batting practice is inserted as a club activity. The way the cute pixel art moves in the mini-game serves the role of making the player feel attached to the characters just by itself. Beyond that, the mini-game itself acts as a substitute for text expressions like "we practiced together." It also serves as an important element for visually representing the process of members gathering or character growth.

If you are a writer, I'd be happy if you could think a bit about whether that should really be expressed in text. In that regard, the work style of scenarios like "how many yen per kilobyte" is not good. It's better if there is a dedicated director who can direct the scenario as a whole. In doujin, I think you can be flexible. I'm looking forward to interesting games being produced.

The diagram on the next page is a rough flow of digital novel production. What this book explains is the "script" part. For others, I'll just give a rough explanation here. For details, you will need to consult more specialized references. Even if you ask someone else to do it, you need a minimum level of knowledge to ask them.

It follows a waterfall model where you go through stages in order. However, ideal and reality are different, and in practice, things don't proceed like this. It's common to assemble scripts even if the materials aren't all ready. There's no point in just waiting until they're done, so it's unavoidable.

・Planning

Think about what kind of game to make. If the genre isn't a digital novel, say goodbye to this book. From an outsourcing perspective, a project proposal is important. If it looks like an interesting game, people will naturally be more motivated than usual.

・Scenario Creation

In the case of digital novels, you can't do anything without the story (scenario) which is the core of the content. It seems plots are also written to determine necessary materials like graphics and sounds. The stages of planning, scenario creation, and text creation are particularly undifferentiated.

・Text Creation

If you don't write the text used in the game with the game screen somewhat in mind, you'll have trouble at the script stage. If you haven't thought about it, you might find the text overflowing from the frame. At this stage, you also put in instructions for direction to some extent. This includes which background or character sprite to display, or instructions for voice actors. In any case, be careful as novel text and game text are completely different.

・Graphic Creation

In digital novels, the style of overlapping character sprites on background images and displaying text on top has become established. In key moments, event CGs (also called one-page pictures/CG/stills) are inserted. In addition to that, system images like images for the title screen or save screen and frames for the text display area are also needed. Smaller things include the game logo or the icon for the game execution file. When using Kirikiri, you ultimately convert them to a unique file format called TLG. File formats will be explained in Chapter 3.

・Sound Creation

BGM, sound effects, system sounds (like the sound when pressing a button) are needed. In some cases, you might record voice actor voices or record a theme song. In Kirikiri, wav or ogg files can be used. mp3 is a commonly used sound file format, but it is not used in digital novel production because of licensing issues.

・Movie Creation

Needed if you use an opening movie or similar. Kirikiri can play MPEG1, WMV, and FLASH.

・Script

Combine the produced materials into a single game form. This is the part primarily explained in this book. It will be explained from the next chapter onwards.

・Distribution

Whether to have it downloaded from a webpage, distributed on a CD at events, or sold on consignment at shops, etc. Feel free.

・System Creation

Kirikiri/KAGEX handles the basic parts. It is particularly necessary if special functions are needed for each game or if mini-games are interspersed. In Kirikiri, you program using TJS or C++, etc.

・Public Relations

Games that people don't know exist won't be played. It's important. Webpages, blogs, Twitter, Pixiv, Facebook, news sites, events, magazines, papers, and more. There seem to be various options.

  1. Preparing the Development Environment

In this chapter, we will download necessary files like the Kirikiri/KAGEX SDK and set up an environment where game production is possible.

If your environment doesn't display file extensions, the following explanations will be difficult to understand, so we'll display them beforehand. Those in an environment where they are already displayed can skip this. I'll provide a basic explanation, but for those who have never heard the word "extension," the explanations in this book might be difficult. If you find yourself unable to understand, please search the internet and do your best.

In Windows, the file format (type) is identified by an "extension." Extensions are attached to the end of a file name, separated by a "." (period). For example, if the file name is "memo.txt", "txt" is the extension. "txt" is the extension for a "text file" that can be opened with Notepad or similar. There are many other extensions such as "exe", "zip", and "jpg".

Extensions are important in game development, but Windows has an unfortunate default setting where the display of extensions is omitted. We will change this setting so they are not omitted. I'll explain how to change it in Windows 7. For XP or Vista, search for something like "windows xp show extensions," and many easy-to-understand web pages with images will come up.

First, click "Control Panel" from the Start menu at the bottom left. Once the Control Panel opens, click "Appearance and Personalization" → "Folder Options." Next, select the "View" tab, find "Hide extensions for known file types" in the "Advanced settings," and uncheck it. Click the "OK" button to change the setting so extensions are not omitted.

To develop games with Kirikiri/KAGEX, you need various files like KAGEX and other plugins in addition to the Kirikiri engine. Since it's tedious to download them one by one, I have made them available for download as an SDK (Software Development Kit) on the support page of this book. Access "http://biscrat.com/book/kagex/support/" and download it.

The SDK you obtained is compressed in ZIP format. Please decompress it yourself. If you don't know how, refer to "Compression/Decompression" in the next section. When decompressed, a folder like "KAGEX_SDK" will be created. There is a "readme.txt" inside, so click and read it.

The "Kirikiri Stable SDK" folder within the "KAGEX_SDK" folder also contains "readme.txt" and "license.txt". Please read these carefully as well. They are the licenses (terms of use) for using Kirikiri. You will be allowed to use Kirikiri, which was produced by W.Dee. Of course, you cannot use it however you want, so you must follow the conditions written there. The following explanation is not formal at all and is just a very rough explanation to help understanding. Be sure to read and understand "license.txt" yourself.

Kirikiri can be used by choosing either the "GNU GPL" or "Kirikiri Original License." For making games, the "Kirikiri Original License" is more important. I have never seen an example of using Kirikiri under GPL. Under the "Kirikiri Original License," you can use Kirikiri for free. This remains the same whether you distribute the game for free or for a fee. There is no obligation to display "using Kirikiri" or similar when distributing it as a game. It's very generous. If you use C++ to modify the Kirikiri engine, there are other conditions, but this book doesn't deal with that.

The "Kirikiri Stable SDK" folder contains "kag3" and "kirikiri2" folders in addition to the license.

The "kag3" folder contains the KAG system and its manual. Since we are using KAGEX instead of KAG, we won't use the kag3 folder. You can try reading the manual, but keep in mind that it is completely different from KAGEX. Reading it poorly will cause confusion.

The "kirikiri2" folder contains the Kirikiri engine and its manual. "krkr.exe" is the Kirikiri engine itself. If you click it, a "Select Folder/Archive" window appears. Since preparation isn't finished yet, just click "Cancel" and exit. The "kr2doc" folder contains the manual (reference) for the Kirikiri engine, and the "tjs2doc" folder contains the manual for TJS used in Kirikiri. It's difficult to read them suddenly, but as you get used to it, you might start using them. Just keep the existence of the manuals in the back of your mind. The "tools" folder contains tools used in game production. This book also uses some of those tools.

"Compression" is reducing the size of a file. If the size is large, it takes time to send and receive over the internet, so most files distributed on the internet are compressed. Besides ZIP, there are various compression formats like LZH, RAR, CAB, and 7Z. ZIP is the most popular compression format.

Compressed files cannot be used directly. Restoring a compressed file to its state before compression is called "decompression" (or unzipping). To use Kirikiri, you need to decompress ZIP files, and for that, you need a dedicated application. Here, I'll introduce how to use the famous "+Lhaca".

+Lhaca can be downloaded from "http://park8.wakwak.com/~app/Lhaca/". Execute the downloaded file to install it. Once installation is complete, an icon for +Lhaca should be on your desktop. If you drag and drop the downloaded "kagex_sdk.zip" onto that icon, it will be automatically decompressed and a folder named "kagex_sdk" will appear on your desktop. That is the decompressed Kirikiri folder. Once decompressed, the "kagex_sdk.zip" is unnecessary and can be deleted.

Scripts aren't mastered just by reading a book. To allow you to try things while reading, I've made dummy assets like images and sounds used in the sample scripts of this book available for download. Like the SDK, please download and decompress them from the support page.

The SDK has all the necessary files, but they are scattered across different folders and hard to use, so we will create a development folder and arrange the files.

First, create a new folder for development. The name can be anything, but for example, create one named "Development Folder" on the desktop. It doesn't have to be on the desktop; anywhere you find easy to use is fine. Once created, double-click "make_dev_folder.bat" located in the "Tools" folder of the SDK folder. A "Select Development Folder" dialog will open, so select the "Development Folder" you just created and press the "OK" button. This will copy all files used to the "Development Folder."

Try launching "krkr.exe" copied to the "Development Folder." It's OK if the game screen displays successfully.

To use some development tools, you need to have "Microsoft .Net Framework 4" installed. Please download and install it from the Microsoft page. It can be downloaded from "http://www.microsoft.com/downloads/ja-jp/details.aspx?displaylang=ja&FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992".

To write scripts, you need software called a "text editor." If you have one you are used to, please use it. Note that "word processors" like "Microsoft Word" or "Ichitaro" are not suitable. Word processors have functions to insert images or change font sizes, but scripts only use simple text. Therefore, we use a text editor specialized in handling only characters.

I'd like to simplify things by saying "standard Windows Notepad is fine," but I'd be sad if people actually used Notepad, so I'll explain. The efficiency between Notepad and other high-performance text editors is on a different level. I use text editors like "Sakura Editor" or "Emacs." Here, I'll introduce how to set up Sakura Editor. For detailed usage, refer to the Sakura Editor help.

First, download the necessary files. Click "Download" from the Sakura Editor webpage "http://sourceforge.net/projects/sakura-editor/" to start the download. It will be a ZIP format file like "sakura-2-0-3-1.zip", so please decompress it. When decompressed, "QuickStartV2.zip" and "sakura.exe" will be inside. "QuickStartV2.zip" is unnecessary and can be deleted. For "sakura.exe", create a new folder like "Sakura Editor" and put it inside.

Next, download the Unicode-compatible file like "bron205.zip" from the "bregonig.dll" webpage "http://homepage3.nifty.com/k-takata/mysoft/bregonig.html". The number part might have changed. This is also in ZIP format, so decompress it. There will be a file named "bregonig.dll," so move it to the same folder as "sakura.exe." Other files are unnecessary and can be deleted.

Finally, download the Kirikiri configuration file for Sakura Editor from the support page of this book "http://biscrat.com/kagex/support/". It is in ZIP format, so decompress it and move the resulting "krkr_sakura" folder to the same location as "sakura.exe".

Once you've done this, click "sakura.exe" to run it. Configure it for Kirikiri. In the menu, go to "Settings" → "Type Settings List" → select an unused setting (like "Setting 20") → "Import" → select "tjs.ini" in the "krkr_sample" folder and click "Open" → "Yes" → "OK" → "OK." This completes the setup for TJS script editing. Similarly, import "ks.ini" in the "krkr_sample" folder to around Setting 21.

Finally, set up the computer so that KAGEX script files (files with the extension ks) and TJS script files (files with the extension tjs) automatically open in Sakura Editor. Specifying software to use for each extension like this is called "file association." if the text-only instructions aren't clear enough, search and you'll find easy-to-understand explanations.

In the "data" folder within the "Development Folder," there is a file called "startup.tjs." Double-click it, and a dialog like "Windows cannot open this file" will appear. Check "Select a program from a list of installed programs" and click the "OK" button. When the "Open With" dialog appears, select "sakura.exe" via the "Browse" button and click the "Open" button. Ensure "Always use the selected program to open this kind of file" is checked and click the "OK" button. "startup.tjs" will now be editable in Sakura Editor. Exit Sakura Editor once and confirm that double-clicking "startup.tjs" runs Sakura Editor. Similarly, associate "01.ks" in the "scenario" folder with Sakura Editor. The method is exactly the same. With this, files with extensions tjs and ks can be edited in Sakura Editor.

This is optional, but if you click "Show Tab Bar" from the "Settings" menu, you'll be able to use tabs when editing multiple files. It's convenient, so I recommend setting it. There are various other setting items. I recommend checking the Sakura Editor help and configuring it to your liking to increase efficiency.

  1. Script Basics

From this chapter, we will finally start writing KAGEX script. We will try basic functions like displaying text and images, and playing sounds.

During game development, you will be modifying the contents of the "data" folder in the "Development Folder." This data folder is also called the "Project Folder." All assets and script files used in the game must be placed in this project folder.

There are many folders inside that project folder as well. I'll explain them a bit here.

List of Folders for Asset Files

bgimage

Place background images here.

fgimage

Place character sprite images here.

evimage

Place event CG images here.

uiimage

Place interface images like buttons here.

rule

Place rule images for transitions here.

thum

Place images for thumbnails here.

image

Place other images here.

bgm

Place sound files for BGM here.

sound

Place sound files for sound effects here.

voice

Place sound files for voices here.

video

Place movie files here.

other

Place other files here.

List of Folders for Script Files

system

Contains the TJS scripts for the KAGEX system.

biscrat

Contains TJS scripts written by the author to extend KAGEX.

main

Place other TJS scripts here.

init

Contains files for changing KAGEX settings.

sysscn

Contains KAGEX scripts related to the system.

scenario

Contains the KAGEX scripts for the game proper.

The list of folders for asset files is as written. It's clearer to categorize them rather than putting everything in one folder. Since production tools also distinguish by folder, make sure not to put assets in the wrong folder.

As for script folders, this book won't touch upon system, biscrat, or main folders. As a next step, if you become able to use the contents of these folders, you'll be able to do various things. Try it if you're interested. The focus of this book is on the contents of the init, sysscn, and scenario folders.

The "startup.tjs" file directly under the "data" folder is the script executed first when Kirikiri is run. You won't be editing it, so don't worry. Other files like "default.rpf" are configuration files for various tools. They are not used directly.

After a long introduction, I'll finally start explaining KAGEX script. First, let's display text. The script for the game proper starts from "01.ks" in the "scenario" folder. Open "01.ks" in a text editor. Initially, the following script is written.

*start|Start

Hello.

The first line *start|Start is called a label. I'll explain labels later, so ignore them for now. The next line says Hello.. With just this, you can display "Hello." in the game. Try launching "krkr.exe," and "Hello." will be displayed.

*start|Start

Hello.

Breaking the line here will also break the line in the game.

Inserting an empty line will cause a line break in the game too.

Text can be displayed in-game just by typing it. Enter the script above into 01.ks, save it, and launch krkr.exe. Line breaks are also reflected in the game. Also, if you insert an empty line with nothing written, you can wait for a click and advance the page (clear the displayed text).

*start|Start

This is narration.

【Shiori】"Hello.

This is a character's dialogue.」

【Shiori】

「Dialogue can also be written on the next line.

Line breaks within dialogue are automatically indented based on the quotation marks.

Surrounding a character's name with 【】 displays the name of the character who spoke. The character's name is displayed in a dedicated name box, different from where normal text is displayed. When following "【Shiori】" with a line break and writing the dialogue on the next line, be careful not to include spaces after the "】".

*start|Start

【Shiori/???】"The name box displays '???'."

If you want to display text in the name box that is different from the character's actual name, such as when the name is still unknown in the story, insert a "/" (half-width slash). If you simply use "【???】", the text display will be fine, but you'll have trouble when playing voices. I'll explain this in detail in the section on voice playback in Chapter 5.

*start|Start

【Shiori/???】"You can add [Furigana''furigana] to [Kanji'kanji].」

You can also add rubies (furigana). Enclose the part you want to add ruby to with [], and write the characters for the ruby after the ' (half-width apostrophe).

That's the basics of text. Fine details like changing text color or size will be introduced in later chapters.

You can run Kirikiri by double-clicking "krkr.exe" in the "Development Folder." You can also run it by double-clicking "exec_release.bat" or "exec_debug.bat." exec_release.bat runs Kirikiri with debug mode off. Since it's more convenient to run it in debug mode during development, this is rarely used. exec_debug.bat runs it with debug mode on. Use this during development.

Also, because clicking exec_debug.bat every time you check script behavior is tedious, it's convenient to register it as a shortcut in your text editor. Most editors should have a function to register external programs as shortcuts.

Below is the method for Sakura Editor. Refer to the Sakura Editor help for details. It's a bit of a hassle, but it's a small price to pay considering you'll be launching Kirikiri dozens of times from now on. Please do this even if you are using another editor.

When you launch Sakura Editor, click "Start Recording Macro" in the "Tools" menu. Next, click "Execute External Command" also in the "Tools" menu, select "exec_debug.bat" via the "..." button, and click the "Execute" button. Kirikiri will start, but since we don't need it now, close it. Return to Sakura Editor and click "End Macro Recording & Save" in the "Tools" menu to save it as a macro. Create a new folder named "macro" in the same folder as Sakura Editor and save it as "krkr.mac".

Once the macro is saved, make it executable via a shortcut key. Click "Common Settings" in the "Settings" menu. Open the "Macro" tab and select the "macro" folder you just created via the "Browse" button. Select "krkr.mac" in the "File" field, set the name field to "Launch Kirikiri", the Id field to "0", and click the "Set" button. Next, open the "Key Assignments" tab, select "External Macro" from the "Category", and "Launch Kirikiri" will appear in the "Function" field; select it. Finally, select the key to register as a shortcut; here, we'll set it so Kirikiri can be launched with (Ctrl+Q). Check the "Ctrl" checkbox and select Ctrl+Q from the "Key" field. Press the "Assign" button in this state to complete the shortcut registration. Click the "OK" button to close the Common Settings dialog. Once registered, try pressing Ctrl+Q to confirm that Kirikiri executes.

Running Kirikiri in debug mode provides useful features for development. When debug mode is on, a window called "KAGEX Log" appears below the game window and notifies you if there is an error in the script. It might be in the way, but I recommend keeping it displayed during development. If you close this window, you can display it by clicking "KAGEX Log Mode" in the "Debug" menu of Kirikiri. There are several other items in the "Debug" menu, and some functions will be introduced later.

Mouse operation is easy, but getting used to keyboard operations significantly increases work speed. Shortcuts like Ctrl+S (holding the Ctrl key while pressing the S key) to save a file, and Ctrl+Z to undo the previous action, are very common. Knowing Ctrl+T for half-width alphanumeric, Ctrl+U for Hiragana, Ctrl+I for full-width Katakana, Ctrl+O for half-width Katakana, and Ctrl+P for full-width alphanumeric conversion is subtly convenient. Ctrl+M acts as Enter. I can't introduce them all, but there are many others. Even if there are no default shortcut keys, it's good to register functions you use often yourself. You might even register shortcuts for cursor movement. When facing the keyboard for hours a day, even stretching your finger to the right side of the keyboard is tedious. Cursor keys are a waste of time. Whether you go that far is another matter, but game production takes more time than you ever have, so you should make an effort to make things even a little easier. Well, the time saved will just be poured back into game production anyway...

Next, we will display images. If you haven't downloaded the dummy assets yet, please download them from the support page (http://biscrat.com/kagex/support/).

Images displayed in KAGEX are divided into background, character sprite, event CG, and others. (This does not include system images like text frames, buttons, and sliders. Those will be handled in Chapter 6.) Since each usage is different, I'll explain them one by one. Before that, I'll explain the basic part of image display in KAGEX.

In computer-related terms, the vowel extension mark (the dash) at the end of words is often omitted. It's "Reiya" instead of "Reiyā" (layer), and "Suraida" instead of "Suraidā" (slider). It doesn't have a major meaning. It might be hard to read, but that's how it is, so please get used to it. "Player" is an exception. "Pureiya" felt a bit weird, so the vowel is extended. This might be because I see it from a humanities perspective, looking at the relationship between the game and the player. Player? Purēyā? After agonizing over it, I unified it to "pureiyā" (player). "Pureiya" looks like it means an mp3 player. This was truly useless chatter.

Images are displayed by being pasted onto a transparent board called a "layer." It's similar to layers in image editing software like Photoshop. I'll skip the fine details, but the important part is that layers have a front-to-back relationship. Images displayed on a rear layer are hidden behind images displayed on a front layer. Layers are arranged from the back in the order: "Background < Character Sprites and Others < Event CGs." The background is at the very back, and the event CG is at the very front. Since multiple character sprites are displayed at once, there is also a front-to-back relationship between character sprites. I'll explain this in detail later. On top of all these layers, the text frame and text are displayed.

There are various image formats, but Kirikiri can handle BMP, JPEG, PNG, ERI, TLG5, TLG6, WMF, and EMF.

There are broadly two types of image formats: vector images and bitmap images. Among the formats usable in Kirikiri, WMF and EMF are vector images, but you'll rarely use them when making digital novels. Since the author has hardly used them and cannot explain them, they will be omitted. The remaining BMP, JPEG, PNG, TLG5, and TLG6 are bitmap images.

BMP format is basically not used because the file size becomes too large. I don't know much about the ERI format. I've never used it, so I'll ignore it.

JPEG and PNG formats are used quite a bit. The difference between the two is that JPEG is lossy compression and PNG is lossless compression. With lossy compression, the image becomes blurred or noisy, looking dirty. In return, you can compress the file size to be smaller. With lossless compression, the image remains as beautiful as the original, but the file size is larger compared to lossy compression. These days, hard drive capacity is large, and file size is basically not an issue, so we use PNG format, which is lossless. JPEG might be used if there are special circumstances requiring a smaller capacity. PNG also has the characteristic that indexed colors can be used. When using something called "area images" in Kirikiri, they must be in indexed color. Since this book doesn't use area images, the explanation is omitted.

TLG5 and TLG6 are Kirikiri's original image formats, and in most cases, we use these. Since both are lossless compression, images remain beautiful. TLG5 becomes larger in size than PNG, but image display is slightly faster. TLG6 becomes smaller in size than PNG, and although slower than TLG5, image display is also faster than PNG. Which one to use may be on a case-by-case basis, but I usually use TLG6.

Since TLG5 and TLG6 are Kirikiri-specific formats, they cannot be used in general image editing software like Photoshop or SAI. You first save them in PNG format and then convert them using the tools included with Kirikiri.

First, let's display a background image. For sample backgrounds, use images like "bgTown_Day.png" in the "bgimage" folder of the sample assets. Copy all images in the folder to the "bgimage" folder within the development folder.

Background image filenames must follow the format "bg[LocationName]_[TimeName]". In the samples, location names are "Town", "Sunflowers", "LivingRoom", and time names are "Day", "Evening", "Night", "Common".

To display a background, you must define the "LocationName" and "TimeName" beforehand before writing the script. Definitions normally require writing TJS scripts, but a tool has been created to make it easier. Run "autosetting.bat" in the "tools" folder of the "Development Folder." A "Select Project Folder" dialog will appear; select the "data" folder in the "Development Folder" and click "OK." It will look at the images in the "bgimage" folder and define the necessary locations and times.

Once defined, write a script and actually try to display them.

*start|Start

@stage stage=Town stime=Day

Changed location to Town and time to Day.

@stage stage=Town stime=Night

Changed location to Town and time to Night.

@stage stime=Evening

Changes the time to Evening.

@stage stage=Sunflowers

Changed location to Sunflowers.

Lines starting with @ (half-width at-mark) are command lines. Command lines are also called tags. You must use tags to display images, play sounds, or do anything else.

A tag consists of a leading "tag name" followed by "attributes." In @stage stage=Town stime=Day, "stage" is the tag name, and "stage=Town" and "stime=Day" are attributes. The tag name and each attribute are separated by half-width spaces. Furthermore, attributes are divided into attribute names and attribute values. The part before the = (half-width equal sign) is the attribute name, and the part after it is the attribute value.

To display a background, use the tag named "stage." Specify the location in the "stage" attribute and the time in the "stime" attribute. Doing so changes the game state to the specified location and time, and the background image also changes accordingly. In the tag @stage stage=Town stime=Day, the location is changed to Town and the time to Day, so "bgTown_Day.png" is displayed in the background.

Also, unnecessary attributes can be omitted. In @stage stime=Evening, the stage attribute is omitted, so the location remains Town and only the time changes to Evening. In @stage stage=Sunflowers, the time remains Evening and only the location changes to Sunflowers.

*start|Start

@stage stage=White stime=Day

Changed location to White and time to Day.

@stage stime=Evening

Changes the time to Evening.

Background remains White_Common.

The time for "White_Common.png" and "Black_Common.png" is "Common". As the name suggests, "Common" means the same image is displayed regardless of the time. In the script above, "White_Common" is displayed regardless of the time.

Background images are displayed centered on the screen. Let's try it with the sample "bgLivingRoom_Day.png", which is larger than the screen size.

*start|Start

@stage stage=LivingRoom stime=Day

Displays the LivingRoom Day background.

The center of the image displays.

@stage xpos=100 ypos=-100

Changed image position.

The top-left part displays.

The default window size is 800 pixels wide × 600 pixels high, and the size of the LivingRoom image is 1000 pixels wide × 800 pixels high. To be precise, the background image is displayed such that the center of the image aligns with the center of the window. So, with the first @stage stage=LivingRoom stime=Day, the area inside the "window frame" of the image below is displayed.

The position of the image can be changed using the "xpos" and "ypos" attributes. xpos is the horizontal direction, and you can shift the image to the right by the specified value. You can also shift it to the left by specifying a negative value. ypos is the vertical direction, and you can shift it upwards by the specified value. You can shift it downwards by specifying a negative value. In @stage xpos=100 ypos=-100, the top-left part of the image is displayed by shifting it 100px to the right and 100px down.

Specifying image positions in Kirikiri/KAGEX is basically done in pixels (px). A pixel is the smallest unit when displaying color on a monitor. For example, a screen resolution of 1920×1080 means displaying 1920px horizontally and 1080px vertically. Not just for monitors, the size of digital images is in pixels. The millions of pixels mentioned for digital cameras also refer to pixels. If you can take a picture of size 1000px × 1000px, it's 1,000,000 pixels.

Since a pixel is a logical unit, how many centimeters it is physically is not fixed. Even for the same 100px×100px image, the size displayed varies depending on the monitor. The number of pixels and the actual physical size are converted using a unit called dpi (dots per inch). Dot and pixel are basically the same thing. It is a unit often used when printing or scanning. Scanning a 10 inch × 10 inch picture at 300dpi (300 dots per inch) results in a digital image of 3000px × 3000px.

The resolution of Kirikiri/KAGEX (the number of pixels in the Kirikiri window) is 800×600, as mentioned earlier. Pulling the window frame changes the window size and the actual number of pixels in the window also changes, but while using KAGEX script, it automatically handles things, so you don't need to be aware of it. You can just think of it in a non-scaled state. When customizing with TJS, you need to be a little more careful.

Commercial games are also increasing screen sizes. Some extreme ones are 1900×1200... in doujin, 800×600 seems to still be the mainstream. The good thing about larger screen sizes is that the pictures are beautiful even when playing in full screen. If you full-screen 800×600, the picture might look dirty depending on the monitor. On the production side, it becomes hard because images need to be made larger. If you use free materials from the web, the size is often 800×600, which might also be a bottleneck.

Another topic is aspect ratio. Aspect ratio is the ratio of width to height of the resolution. 800×600 is a 4:3 aspect ratio; for popular wide support, 1280×720 is a 16:9 aspect ratio, and so on. In widescreen, the screen is wide, making text hard to read, and pictures look strange if you make them with the previous sensation. There's also a joke about CGs becoming too slanted due to wide-screening. (Reference: 2ch "Eroge should be 4:3. Wide-screening is a mistake" thread http://pele.bbspink.com/test/read.cgi/erog/1299685511/). In the reference URL, it's linked to discussions about first-person perspective, but as someone observing in a third-person cinematic way, a tilted camera is strange. I won't say wide-screening is a mistake, but I think there are better ways to do it. One is to move the text display from the bottom to the side and use the screen vertically. While assembling scripts, I often think it's a waste that the character sprite's absolute territory is hidden by the text box. If you're going to wide-screen, why not just make it a vertical screen? A girl displayed on a vertical screen is 30% cuter just because of that. The iPad device screen itself is vertical, so I have expectations there. Even on a PC, if you have 1000 vertically, you should be able to make a game with a vertical screen. Someone should do it. My apologies to laptop users.

Unrelated, but there are quite a few people who think Protagonist = Myself. I never had that idea myself. It's closer to the sensation of just watching the protagonist and a girl flirting. When applying direction, the awareness of a protagonist's perspective is thin, and I feel like I'm moving them from a third-person perspective. I often wish the protagonist had a sprite too.

Digression over. Returning to script explanation.

Next, we'll display character sprites after the background. Use images like "fgShiori_PoseA_Casual_Smile_0.png" in the "fgimage" folder of the sample assets. Copy all to the "fgimage" folder in the development folder.

Character sprite filenames follow the format "fg[CharacterName]_[PoseName]_[OutfitName]_[ExpressionName]_[DisplayLevel]". In the samples, character names are "Shiori" and "Kaede", pose names are "PoseA" and "PoseB"... and so on. When using English letters in filenames, always use lowercase. It needs to be "posea" rather than "PoseA".

For character sprites, you must define "CharacterName", "PoseName", "OutfitName", "ExpressionName", and "DisplayLevel" respectively. These can also be defined automatically with autosetting.bat. Run autosetting.bat after copying the character sprite images.

The sample images being used now can display a character sprite with a single image. This is called "Expression-Combined Type Character Sprite." In this case, the classification of pose name, outfit name, and expression name isn't very important. Even when using your own character sprite images, there's nothing special to be careful about; just change the pose name part if the pose is different, the outfit name part if the outfit is different, and the expression name part if the expression is different. The character name part is self-explanatory. The display level will probably be categorized by character sprite size. The display level must be a half-width number of 0 or higher, and the larger the number, the further forward the character sprite is displayed among character sprites. We'll look at the actual script next.

Character sprites can also be in a format where they are displayed by combining two images: "base image + expression image." This is called "Expression-Separated Type Character Sprite." Doing this can make image capacity smaller or asset management easier. How to make images for this case will be described later. Once images are made and defined, the usage in script is exactly the same for both combined and separated types.

*start|Start

@stage stage=Town stime=Day

Display the background.

@char name=Shiori pose=PoseA dress=SchoolUniform face=Smile level=0

【Shiori】"Displays the character sprite."

@char name=Shiori pos=Hide

Clears the character sprite.

@char name=Shiori face=Surprised

Change the expression and display again.

To display a character sprite, use the "char" tag. Specify the character name in the "name" attribute, pose name in "pose", outfit name in "dress", expression name in "face", and display level in "level". There are many attributes, but it's enough to specify them all once at the beginning, and thereafter only specify attributes you want to change. The "name" attribute cannot be omitted because it determines which character sprite to operate on.

The display state of a character sprite can be changed with the "pos" attribute. Setting "pos=Hide" makes the character sprite hidden. When displaying, changing expressions or poses will automatically display it.

I haven't explained how to show or hide the background, but for the background, we don't hide the background itself, but rather display a solid black image like "Black_Common.png".

Running the previous script shows the character sprite displayed in a strange position, like in the bottom-left image. Actually, character sprites are displayed such that the bottom-center of the character sprite image aligns with the center of the screen. Why it ends up at this position will be explained in detail in Chapter 4. For now, in this case, it looks just right if you shift it down by 300px like in the bottom-right image.

To shift it, you can use xpos and ypos attributes just like with the background, but you can also configure it to shift the positions of all character sprites collectively. It's more convenient to use that function to fix initial character sprite misalignment.

Open "envinit.otjs" in the "init" folder of the project folder in a text editor. This is a file that configures the behavior of autosetting.bat, which we've used several times. Once opened, look for the part written as follows:

// ■yoffset

// Specifies the Y-direction offset (shift amount) for character sprites for each display level.

yoffset[0] = 0;

yoffset[1] = 0;

yoffset[2] = 0;

Offsets can be set for each display level. They are set in the format yoffset[DisplayLevel] = Offset;. By default, the offset for display levels 0, 1, and 2 is 0 (no shift at all). Since we are using display levels 0 and 1 in the samples, we just need to set those offsets to 300px downward. In yoffset, contrary to the ypos attribute, specifying a positive value shifts it down, and a negative value shifts it up.

// ■yoffset

// Specifies the Y-direction offset (shift amount) for character sprites for each display level.

yoffset[0] = 300;

yoffset[1] = 300;

yoffset[2] = 0;

Changing it like this is OK. Once changed, run autosetting.bat in the tools folder again to apply the changes. Launch the game and confirm that the character sprite positions are shifted.

*start|Start

@char name=Shiori pose=PoseA dress=SchoolUniform face=Smile level=0

【Shiori】"Displays the character sprite."

@char name=Kaede pose=PoseA dress=Casual face=Expressionless level=1

【Kaede】"Displays another character sprite."

@char name=Kaede level=0 xpos=80

【Kaede】"Changes the display level and position."

@char name=Shiori front

【Shiori】"Moves to the front."

@char name=Shiori back

【Shiori】"Moves to the back."

Character sprites are displayed further forward as the display level increases. Kaede's character sprite is level=1, which is higher than Shiori's level=0, so it is displayed in front of Shiori's. Even after changing Kaede's level to 0 with @char name=Kaede level=0 xpos=80, because the one modified later comes forward, Kaede's character sprite remains displayed in front.

The front-to-back relationship between character sprites with the same display level can be changed with "front" and "back" attributes. Use them with only the attribute name, omitting the value, like @char name=Shiori front. The front attribute changes the order to the very front within the same display level, and the back attribute to the very back.

Next, we display event CGs. Use "evDiscovery.png" in the "evimage" folder of the sample assets. Event CG filenames follow the format "ev[EventName]".

Event names also need to be defined beforehand with autosetting.bat. After copying sample images to the "evimage" folder of the project folder, run autosetting.bat.

*start|Start

@stage stage=Town stime=Evening

@char name=Shiori pose=PoseA dress=SchoolUniform face=Smile level=0

Display the background and character sprite.

@event file=Discovery

Displays the event CG.

@stage stage=Sunflowers

Changes the background.

To display an event CG, use the "event" tag. Specify the event name in the "file" attribute. Since event CGs are displayed between display level 4 and display level 5 character sprites, when you display an event CG with @event file=Discovery, the background and character sprites are hidden behind it and become invisible. When you change the background or time with a stage tag, like @stage stage=Sunflowers, the event CG is hidden.

The display position of event CGs, like backgrounds, is centered such that the center of the image is at the center of the window. Use xpos and ypos attributes to shift the position.

You may want to display images other than backgrounds, character sprites, and event CGs. Let's try displaying "Star.png" in the "image" folder of the sample assets. Copy it to the "image" folder of the project folder.

There are no rules for the filenames of other images, so any filename you find easy to understand is fine. There is no need to define them in advance with autosetting.bat or similar.

*start|Start

@layer name=StarLayer file=Star show

Display the star.

@layer name=StarLayer hide

Hides the star.

@layer name=StarLayer show

Displays again.

Other images are displayed on "environment layers." Environment layers can be displayed using the "layer" tag. Specify the name of the environment layer in the "name" attribute and the image filename in the "file" attribute to load the image file into the environment layer with the specified name. Names can be anything, so give them a suitable name. If the name is different, it becomes a separate environment layer, so you can display multiple copies of the same image. Environment layers can be shown with the "show" attribute and hidden with the "hide" attribute, omitting the values.

*start|Start

@layer name=Star1 file=Star show

Display the star.

@layer name=Star2 file=Star show xpos=20 level=1

Displays another star.

@layer name=Star1 level=2

Moved Star1 to the front.

Environment layers also have display levels, just like character sprites. It is exactly the same, except using the "layer" tag instead of the "char" tag. "front" and "back" attributes can also be used in the same way.

Like backgrounds and event CGs, environment layers are displayed at the center such that the center of the image is at the center of the window. They are the same in that the position can be shifted with "xpos" and "ypos" attributes.

Actually, loading a file with the "file" attribute automatically displays it, so the "show" attribute in the first @layer name=Star1 file=Star show is unnecessary. I include "show" to make it clearer, but you can omit it. Conversely, if you want to load with "file" but not display it, you must include the "hide" attribute.

You may want to write notes in the script, such as instructions for direction or acting. Adding ";" (half-width semicolon) to the beginning makes that line a "comment," which does not affect the game's behavior. Lines with a semicolon are simply ignored, so you can write anything.

As a side note, in TJS scripts, lines with "//" (two half-width slashes) become comments. In envinit.otjs, there were lines like // Specifies the Y-direction offset (shift amount) for character sprites for each display level., but they were notes written as comments.

I've introduced how to display backgrounds, character sprites, event CGs, and others used in the game. These are used very frequently, but because tag names and attributes are long and tedious, they can be used with shorthand.

*start|Start

; Same as @stage stage=Town stime=Day

@Town Day

Display the background.

; Same as @stage stage=Sunflowers

@Sunflowers

Changes the location.

; Same as @stage stime=Evening

@Evening

Changes the time.

For backgrounds, you can omit the tag name "stage" and the attribute names "stage" and "stime," and use the location name or time name as the tag name. Since other attribute names like xpos cannot be omitted, it would be @stage xpos=20 or @Town xpos=20.

*start|Start

; Same as @char name=Shiori pose=PoseA dress=SchoolUniform face=Smile level=0

@Shiori PoseA SchoolUniform Smile Back

【Shiori】"Displays the character sprite."

; Same as @char name=Shiori pose=PoseA dress=Casual face=Expressionless level=1

@Kaede PoseA Casual Expressionless Front

【Kaede】"Displays another character sprite."

; Same as @char name=Kaede face=Smile

@Kaede Smile

【Kaede】"Changes the expression."

; Same as @char name=Kaede pos=Hide

@Kaede Hide

Clears the character sprite.

For character sprites, the tag name "char" and the attribute names "name", "pose", "dress", "face", "level", and "pos" can all be omitted. The character name specified in the "name" attribute can be used as the tag name.

To omit the "level" attribute specifying the display level, you must define names for the display levels. Open envinit.otjs in the init folder and look for the following part:

// ■levels

// Names the character sprite display levels for each display level.

levels[0] = "Back";

levels[1] = "Front";

levels[2] = "VeryFront";

Define in the format levels[DisplayLevel] = "DisplayLevelName";. Surround the display level name with "" (half-width double quotes). By default, "Back" can be used as shorthand for level=0, "Front" for level=1, and "VeryFront" for level=2. Rewrite as necessary and run autosetting.bat, and the defined names will be usable in scripts. The sample in this book will use them as they are without modification.

For character sprites, you can also define names for the "xpos" attribute and omit it. Refer to "envinit.otjs" for this as well.

// ■xpos

// Names positions in the X-direction.

xpos.FarLeft = -400;

xpos.BackLeft = -300;

xpos.Left = -200;

xpos.MidLeft = -100;

xpos.Center = 0;

xpos.MidRight = 100;

xpos.Right = 200;

xpos.BackRight = 300;

xpos.FarRight = 400;

Define in the format xpos.Name = xposValue;. By default, "FarLeft" is shorthand for xpos=-400, "BackLeft" for xpos=-300, "Left" for xpos=-200... and so on. Rewrite if necessary and run "autosetting.bat." The samples in this book use them as they are.

*start|Start

@Shiori PoseA SchoolUniform Smile Back Left

【Shiori】"Displays the character sprite."

@Kaede PoseA Casual Expressionless Back Right

【Kaede】"Displays another character sprite."

@Shiori Hide

@Kaede Hide

Clears the character sprites.

Actual usage is as above. Just specify them side by side, same as outfits or expressions.

*start|Start

; Same as @event file=Discovery

@Discovery

Displays the event CG.

For event CGs, the tag name "event" and the "file" attribute can be omitted. The event name becomes the tag name. When changing the position, it would be @Discovery xpos=30. To make it clearer that it is an event CG, you can also add "ev" to the tag name, like @evDiscovery. Use whichever you find easier.

*start|Start

@layer name=StarLayer file=Star show

Display the star.

; Same as @layer name=StarLayer hide

@StarLayer hide

Hides the star.

; Same as @layer name=StarLayer show

@StarLayer show

Displays again.

For environment layers, the tag name "layer" and the "name" attribute can be omitted. The environment layer name specified in "name" becomes the tag name.

However, you cannot omit them for a first-time environment layer name. Since the environment layer with the specified name is created only upon first use, it can be omitted only when it has already been created.

; An environment layer named "StarLayer" is created here.

; Omission like @StarLayer file=Star show is not possible for the first time.

@layer name=StarLayer file=Star show

Display the star.

; Same as @layer name=StarLayer xpos=100

@StarLayer xpos=100

Change the star's position.

; Same as @layer name=StarLayer delete

@StarLayer delete

Delete the environment layer.

; The next time you use it, you must create the environment layer again using "@layer" without omission.

@layer name=StarLayer file=Star show

Display the star.

Instead of hiding it with the "hide" attribute, you can also delete the created environment layer by using the "delete" attribute, like @StarLayer delete. The attribute value is omitted. If you are concerned about unused environment layers remaining, you might want to delete them. If deleted, you must create the environment layer again using "@layer" without omission the next time you use it.

Since we've covered images roughly, let's try playing BGM.

Copy "bgmLakesideVillage.ogg" and "bgmWinterBreath.ogg" from the sample "bgm" folder into the "bgm" folder of the project folder. BGM files follow the naming convention "bgm[bgmName]". For BGM, there is no need to run autosetting.bat or similar.

*start|Start

@bgm play=bgmLakesideVillage

Play BGM.

@bgm play=bgmWinterBreath loop=false

Switches the BGM. It will not loop.

@bgm stop

Stops the BGM.

To play BGM, use the "bgm" tag. When you specify the BGM filename in the "play" attribute, that file will play as the BGM. Once the BGM finishes playing to the end, it will automatically loop back to the beginning. Specifying "false" in the "loop" attribute will prevent it from looping. You can stop BGM playback with the "stop" attribute, where the attribute value is omitted.

*start|Start

; Same as @bgm play=bgmLakesideVillage

@bgmLakesideVillage

Play BGM.

; Same as @bgm play=bgmWinterBreath loop=false

@bgmWinterBreath loop=false

Switches the BGM. It will not loop.

@bgm stop

Stops the BGM.

For BGM, you can omit the tag name "bgm" and the "play" attribute when playing. If you use the BGM filename as the tag name, like @bgmLakesideVillage, that BGM will play.

The music file formats that can primarily be played in Kirikiri are PCM WAV (extension is wav) and OggVorbis (extension is ogg).

WAV is the format used in music CDs; since it is basically uncompressed, the sound quality is good, but the file size becomes large. At typical settings, a WAV file is about 10MB per minute. You might use it if file size is not an issue.

OGG uses lossy compression, so the sound quality is lower, but the file size can be made smaller. This is usually used in games. Unlike the commonly used MP3, there are no licensing fees. There are various tools available to convert from other formats like WAV or MP3 to OGG, so use whichever you like.

Since OGG and MP3 are lossy formats, sound quality deteriorates every time you edit the file. Always perform tasks like applying effects or adjusting volume on the original WAV file. After editing is finished, convert it to OGG for use in the game.

Actually, it seems to support 5.1ch surround sound as well. It might be fun if someone tried it.

In addition to WAV and OGG, it is said that MIDI, CD-DA, and the original TCWF format can be used. However, I won't explain them as I don't use them.

Next, let's play sound effects. Copy "seButton.ogg" and "seRain.ogg" from the sample "sound" folder into the "sound" folder of the project folder. Sound effects follow the naming convention "se[seName]". For sound effects, there is no need to run autosetting.bat or similar.

*start|Start

@se play=seRain loop=true

Playing a sound effect on a loop.

@se play=seButton

Played another sound effect as a one-shot.

@se name=seRain stop

Stops the sound effect.

To play sound effects, use the "se" tag. When you specify the sound effect filename in the "play" attribute, that file will play as a sound effect. Unlike BGM, sound effects do not loop by default. Playing a sound just once without looping is also called "one-shot" playback. You can enable looping for sound effects by specifying "true" in the "loop" attribute.

A major difference between BGM and sound effects is that while only one BGM track can play at a time, multiple sound effects can play simultaneously. In the script above, "seButton" is played while "seRain" is looping. The number of sound effects that can be played simultaneously defaults to 3. This can be increased in the settings, but it is rare to need to play 4 or more at once.

To stop playback, use the "stop" attribute, but since multiple sound effects can play at once, you need to specify which one to stop using the "name" attribute, like @se name=seRain stop.

*start|Start

; Same as @se play=seRain loop=true

@seRain loop=true

Playing a sound effect on a loop.

; Same as @se play=seButton

@seButton

Plays another sound effect.

; Same as @se name=seRain stop

@seRain stop

Stops the sound effect.

For sound effects, the "se" tag name and "play" attribute can be omitted. If you use the sound effect filename as the tag name, that file will play as a sound effect. When stopping, you can also omit the "name" attribute and stop it by using the filename as the tag name with the "stop" attribute.

The "loop" attribute, common to both BGM and sound effects, is specified as "true" or "false". In Japanese, true = shin (truth), false = gi (falsehood). There are many other attributes that specify true or false. It's helpful to think that specifying true turns that attribute's function on, and false turns it off. In the "loop" attribute, true turns loop playback on, and false turns it off. In the previous script, we only used loop=false for BGM and loop=true for sound effects, but you can also specify loop=true for BGM and loop=false for sound effects. However, as mentioned, since loop playback is on by default for BGM and off for sound effects, there is no real point in specifying them explicitly.

Attributes consist of an attribute name and value separated by "=", but if the value is "true", it can be omitted. @seRain loop is the same as @seRain loop=true. Do you remember omitting the attribute values for the "front" and "back" attributes when changing the display order of character sprites? Actually, those were also omissions of front=true and back=true. It carries the meaning of turning on the function to bring it to the front or turning on the function to move it to the back. Being able to specify true means you could also specify front=false or back=false, but in these cases, nothing would happen, so it's a complete waste. Ultimately, you will use them by omitting the attribute values like front or back. The same applies to the "show" and "hide" attributes in the layer tag.

KAGEX scripts are mostly made up of tags. So far, we've introduced tags like stage, char, event, etc. Text is displayed just by writing it directly, but actually, that is also a tag. The "ch" tag is used to display text. Since text is used extensively, it would be tedious to write tags every time, so it's simplified so you can write it directly. Newlines and page breaks also use their own respective tags.

KAGEX scripts are executed in order from top to bottom. It's obvious but important.

*start|Start

@stage stage=Town stime=Day

Display the background.

@char name=Shiori pose=PoseA dress=SchoolUniform face=Smile level=0

Display the character sprite.

First, @stage stage=Town stime=Day, which displays the background, is executed. Once displayed, the "ch" tag that displays the text Display the background. is executed. Next, since an empty line is inserted, a "tag to wait for the player to click" is automatically executed, and script execution pauses.

It is also helpful to know that script execution is paused here. KAGEX scripts will continue executing from the top unless paused or temporarily stopped by some tag.

When the player clicks, script execution resumes, and a "tag to advance the page" is automatically executed, clearing the text. Afterward, the character sprite is displayed with @char name=Shiori pose=PoseA dress=SchoolUniform face=Smile level=0, and finally, Display the character sprite. is shown with the "ch" tag. Since execution has finished to the end, script execution stops.

There are cases where you cannot simply execute from top to bottom, such as when the scenario branches due to choices. If Choice A or B is selected, the position where the script is executed must change accordingly.

*start|Start

This is the start.

@next target=*label1

*label2

This is label 2.

@next target=*start

*label1

This is label 1.

@next target=*label2

First, let's simply change the script execution position without using choices. For that, use the "next" tag. If you specify a label name in the "target" attribute, the script will execute from that label next. A label is a line starting with * (half-width asterisk), such as *start or *label1. Labels serve as landmarks for changing the script execution position, and are not limited to the next tag. If you tried to specify a position by line number, like line 100 of "01.ks", it would be difficult as adding just one tag would shift the target position. By using labels, it remains safe even if line numbers shift.

*start|Start, which we haven't explained until now, is also a label. Ignore the | (half-width vertical bar) at the back for now. I'll explain it shortly. The label name is the "start" part before the |. The mechanism is such that when Kirikiri is launched, KAGEX script execution starts from the *start label in "01.ks" after preparations are finished.

In the script above, after This is the start. is displayed, the script execution position changes to *label1 via @next target=*label1. This is also called "jumping" to label 1. Therefore, This is label 1. is displayed, then it jumps to *label2 in the same way, and This is label 2. is displayed. Finally, @next target=*start returns execution to *start, so "This is the start.", "This is label 1.", "This is label 2."... will continue to be displayed endlessly every time you click.

You can give labels any name you like, such as "start" or "label1", but spaces cannot be used.

*start|Start

This is the start.

@next target=*label1 storage=02.ks

Using the "storage" attribute allows you to execute scripts in a different file. Write the above script in "01.ks" as before.

Create a new text file in the "scenario" folder of the project folder and change the name, including the extension, to "02.ks". Once changed, write the following script in "02.ks".

*label1

Executes the script from 02.ks.

@next target=*start storage=01.ks

When you launch the game, execution starts as usual from *start in "01.ks". After This is the start. is displayed, it jumps to *label1 in "02.ks" via @next target=*label1 storage=02.ks. Then, it returns to *start in "01.ks" via @next target=*start storage=01.ks.

While filenames are like 01.ks or 02.ks (number + .ks), there is no rule saying they must be numbers. You can give them easy-to-understand names like "ShioriRoute.ks" or "Epilogue.ks". You can execute the script of that file by specifying it in the storage attribute like @next storage=ShioriRoute.ks target=*???.

*start|Start

The save data name is "Start".

Try saving from the menu.

*label0|0001

The save data name is "0001".

*label1

Here too, the save data name is "0001".

*|0002

The save data name here is "0002".

The part after the "|" (half-width vertical bar) in the label becomes the name of the save data. Launch the game and try saving via "Save" under "Data" in the menu. You'll notice that the data name visible in "Load" changes depending on when you save.

Passing *label0|0001 changes the data name when saved to "0001". The next *label1 does not have a save data name. In this case, it remains "0001" without changing. In *|0002, the label name is omitted. In this case, since the label name to be specified in the target attribute is unknown, it cannot be used as a landmark for executing the next tag. Such omissions can be made when you only want to change the save data name.

*start|Start

The save data name is "Start".

This is the next text without a label.

This is the text after that.

As explained with the next tag, a label must be used as a landmark to change the script execution position. This is the same when loading saved data. Therefore, when loading data saved at This is the next text without a label., it's impossible to execute the script directly from there. In KAGEX, the mechanism for loading involves jumping to *start|Start first and then fast-forwarding script execution to the actually saved This is the next text without a label..

While fast-forwarding through 2 or 3 lines ends in an instant, fast-forwarding 1000 or 2000 lines takes time. Because of this, loading data saved very far from the previous label will take time for fast-forwarding and result in a slightly sluggish behavior.

*start|Start

The save data name is "Start".

*|

This is the next text without a label.

*|

This is the text after that.

To prevent this, place labels sporadically even if they aren't otherwise needed. In my case, I place a label every 300 to 500 lines. Since these labels don't need to be targets for next tags or change save data names, they can be simplified to *| (just a half-width asterisk and vertical bar). Omitting the label name means you can't jump with a next tag, but it's fine as they can be used for jumping during loading.

Saved data is stored in the "savedata" folder in the same folder as "krkr.exe". Deleting the contents of this folder deletes the game's save data. Running "clean.bat" in the same folder as "krkr.exe" will delete the contents of the savedata folder.

If something seems wrong during development, try deleting the save data first; it might fix it. If KAGEX script label names change, the data becomes unusable to begin with. Even otherwise, various data is automatically saved when the game ends and loaded the next time the game is launched. If you've changed settings during development, a discrepancy with the data might occur, potentially causing changed settings not to be reflected or behavior to become strange.

You'll see that data is being saved if you pull the window frame to change the window size and then restart the game. The window remains at the changed size even after restarting. If you then run "clean.bat" to delete the data and launch the game again, the window size will return to normal.

In most cases, you don't need to delete the data, but try it if you find things aren't working as expected. If it's fixed, congratulations. If not, there's an issue somewhere else.

*start|Start

Let's try using choices.

Please select the one you like.

@seladd text="Return to Start" target=*start

@seladd text="Choice 1" target=*Choice1

@seladd text="Choice 2" target=*Choice2

@select

*Choice1

Selects Choice 1.

@next target=*start

*Choice2

Selects Choice 2.

@next target=*start

Choices follow a flow of registering choices with the "seladd" tag and then displaying the registered choices with the "select" tag.

In the "seladd" tag, specify the characters to display as the choice in the "text" attribute, and the label name to jump to when that choice is selected in the "target" attribute. Like the next tag, you can use the "storage" attribute to jump to a label in another file.

The "select" tag displays the choices registered with seladd tags up to that point and stops script execution until the player selects a choice. Once selected, script execution resumes from the label specified by that choice.

Suppose you want to display a choice as "Choice with Space". If you simply use @seladd text=Choice with Space, it won't work correctly because the space acts as an attribute separator. It would be interpreted as two attributes: "text=Choice" and "with", etc.

If you want to specify an attribute value that contains a space like this, surrounding it with "" (half-width double quotes) will make it work correctly. Specifically, it would be something like @seladd text="Choice with Space". This applies to any tag, not just the seladd tag. Furthermore, you can surround attribute values with "" even if they don't contain spaces. @next storage="01.ks" target="*start" will work perfectly. Surround them if it makes it easier to read. In this book, I won't use them unless necessary because typing "" is tedious.

  1. Image Operation Scripts

In Chapter 3, I only explained how to show and hide images, but in this chapter, we'll introduce scripts to make the visuals a bit more elaborate.

In Chapter 3, images appeared and disappeared instantly. In most digital novels, they fade in or out gradually. Let's try doing that. In Kirikiri, this function is called a "transition."

*start|Start

@Town Day trans=crossfade time=2000

Fades in the background.

@Shiori PoseA SchoolUniform Smile Front trans=crossfade time=1000

【Shiori】"Fades in the character sprite."

@Shiori Hide trans=crossfade time=500

Fades out the character sprite.

To perform a transition, use the "trans" attribute. If you specify "crossfade" for the trans attribute, you can perform a "crossfade transition," the most basic type of fade-in/out. Simply, it appears or disappears gradually.

Specify the time taken for the transition in milliseconds (ms) with the "time" attribute. "1 millisecond = 1/1000th of a second." Setting time=1000 means the transition takes 1000ms = 1 second. time=500 would be 500ms = 0.5 seconds.

When using the trans attribute, script execution pauses until the transition finishes. The text Fades in the background. will be displayed only after the background is fully shown. This kind of operation is called "synchronous operation."

In contrast to synchronous operation, there is the concept of "asynchronous operation." Asynchronous operation is when transitions or other tasks execute simultaneously with text display. Operations that are not asynchronous are synchronous. Let's try it for now.

*start|Start

@Town Day trans=crossfade time=2000 nosync

Asynchronously fading in the background.

@Shiori PoseA SchoolUniform Smile Front trans=crossfade time=1000 nosync

【Shiori】"Asynchronously fades in the character sprite."

@Shiori Hide trans=crossfade time=1000 sync

Synchronously faded out the character sprite.

; Jumping to the start so you can try it multiple times

@next target=*start

Adding the "nosync" attribute (omitting the value) results in asynchronous operation, and the "sync" attribute results in synchronous operation. Do you notice how text is being displayed at the same time as the background or character sprite transition? It might be easier to understand if you slow down the "Text Speed" in the "Text Settings" menu.

The final @Shiori Hide trans=crossfade time=1000 sync is a synchronous operation just like before since it has the sync attribute. Transitions default to synchronous operation, so it doesn't change whether you include the "sync" attribute or not.

The actual mechanism for asynchronous operation is that when a transition starts with @Town Day trans=crossfade time=2000 nosync, script execution continues without waiting for the transition to finish. Thus, Asynchronously fading in the background. is executed immediately, and it pauses at the click wait on the empty line.

In synchronous operation, when a transition starts, script execution pauses until it finishes, and resumes once it is done. Thus, the transition and text display do not occur simultaneously.

In synchronous operation, clicking while waiting for the transition to finish will forcibly cancel the transition and resume script execution. In asynchronous operation, it will be forcibly canceled at the point of page advance if it is still transitioning. When a transition is "canceled", it instantly reaches the post-transition state. Fade-ins will display instantly, and fade-outs will disappear instantly.

*start|Start

@Town Day trans=crossfade time=15000 nosync

Fade in the background asynchronously over 15 seconds.

If a page advance occurs during an asynchronous operation, the operation is canceled.

@Shiori PoseA SchoolUniform Smile Front trans=crossfade time=15000 nosync nowait

【Shiori】"Asynchronously fades in over 15 seconds."

With the nowait attribute, it won't be canceled even on page advance.

@Shiori stoptrans

Forcibly canceled the transition.

Asynchronous transitions with the "nowait" attribute will not be canceled by page advance. That said, since it's problematic for it to run indefinitely, you can cancel an asynchronous transition that has the nowait attribute by using the "stoptrans" attribute. Note that only the image with the "stoptrans" attribute will be canceled. In @Shiori stoptrans, even if the background was in an asynchronous transition, it won't be canceled. If used as a tag instead of an attribute, like @stoptrans, all transitions can be canceled.

*start|Start

@begintrans

@Town Day

@Shiori PoseA SchoolUniform Smile Front Right

@endtrans trans=crossfade time=2000

Synchronously transitioned both the background and character sprite at once.

@Kaede PoseA Casual Expressionless Front Left trans=crossfade time=1000 nosync

@Shiori PoseB trans=crossfade time=1000 nosync

Transition two character sprites simultaneously, asynchronously.

@begintrans

@Black

@Kaede Hide

@Shiori Hide

@endtrans trans=crossfade time=1000 sync

Cleared the background and character sprites via synchronous transition.

To transition background and character sprites simultaneously, use the "begintrans" and "endtrans" tags. Write the changes you want to make via transition between @begintrans and @endtrans. Changes related to images written between them will not be reflected at the time they are written, but will be updated all at once with the transition specified in the endtrans tag. The begintrans tag has no attributes. You will specify the transition like @endtrans trans=crossfade time=2000.

If you want to transition two or more character sprites simultaneously without including the background, you can just list them as is without using begintrans and endtrans.

*start|Start

@begintrans

@Town Day

@Shiori PoseA SchoolUniform Smile Front Right

@endtrans trans=crossfade time=5000 sync

Synchronously displayed background and character sprite.

@begintrans

@Shiori PoseB

@Kaede PoseA Casual Expressionless Front Left

@endtrans trans=crossfade time=2000

Synchronously transitioned two character sprites.

@Shiori Casual Angry trans=crossfade time=1000 nosync

@Kaede Smile trans=crossfade time=1000 nosync

@wt

Synchronously transitioned two character sprites.

When transitioning multiple character sprites simultaneously without including the background, you can use begintrans and endtrans tags, or you can use the "wt" tag. @wt pauses script execution until all transitions, synchronous or asynchronous, finish. As seen at the end of the script above, you can make it behave like a synchronous transition by starting an asynchronous transition and waiting for it to finish immediately.

When transitioning the background and character sprites together, if you transition them separately, the display might look odd, so use begintrans and endtrans to transition them together.

In the wt tag, the "canskip" attribute can be used. Specifying true allows the transition to be canceled by clicking. The default behavior is canskip=true. If you specify false, you cannot cancel the transition by clicking, and script execution resumes only after the transition finishes. Since the "canskip" attribute cannot be used in synchronous operations via the sync attribute, they can always be canceled by clicking.

In the trans attribute, you can specify various things besides crossfade. I will introduce them one by one.

Copy "rlSpiral.png" and "rlRightToLeft.png" from the sample assets "rule" folder into the "rule" folder of the project folder.

*start|Start

@Town Day trans=universal time=3000 rule=rlSpiral vague=0

Synchronously transitioned background.

@Town Night trans=universal time=3000 rule=rlSpiral vague=128 nosync

Transition the background asynchronously.

@begintrans

@Sunflowers Day

@Shiori PoseA Casual Angry Front Left

@layer name=StarLayer file=Star show

@endtrans trans=universal time=3000 rule=rlRightToLeft vague=64

【Shiori】"Transitions synchronously."

Specifying "universal" in the trans attribute results in a "universal transition." Specify the transition time in the time attribute. In the "rule" attribute, specify the filename of a monochrome grayscale image. In a universal transition, pixels are swapped starting from the black parts of the image specified in the rule attribute (called a "rule image"), ending with the white parts. The "vague" attribute is an ambiguity value; specifying a larger value makes the boundary of the swap blurrier, resulting in a smoother transition.

Words don't explain it well, so I think it's best to try changing the numbers yourself. The vague attribute can be omitted, in which case it is assumed vague=64 is specified.

Rule images must be in the "rule" folder with a filename starting with "rl".

*start|Start

@Sunflowers Day trans=scroll time=3000 from="top" stay="nostay"

Synchronously transitioned background.

@Sunflowers Evening trans=scroll time=3000 from="left" stay="stayback" nosync

Transition the background asynchronously.

@Discovery trans=scroll time=3000 from="bottom" stay="stayfore"

【Shiori】"Transitions synchronously."

Specifying "scroll" in the trans attribute results in a "scroll transition." This is a transition where images scroll (slide) to switch. Specify the transition time in the time attribute. The "from" attribute specifies the direction from which the post-change image slides in. Specify one of "left", "top", "right", or "bottom" to slide in from the left, top, right, or bottom, respectively. In the "stay" attribute, specify one of "nostay", "stayback", or "stayfore". In "nostay", both the pre-change and post-change images slide. The pre-change image is pushed out by the post-change image. In "stayback", the pre-change image slides out, and the post-change image appears from beneath it. In "stayfore", the post-change image slides in and covers the pre-change image. Again, I recommend actually trying these yourself as they are hard to describe.

*start|Start

@begintrans

@Sunflowers Day

@Shiori PoseA Casual Surprised Back Left

@endtrans fade=2000

【Shiori】"Transitions the background and character sprite synchronously."

@Shiori Hide fade=1000 nosync

Transition the character sprite asynchronously.

Since trans=crossfade is used frequently, you can also easily use the "fade" attribute. For the attribute value, specify the transition time that was previously in the time attribute for trans=crossfade.

Asynchronous operations that do other things simultaneously with text display are relatively heavy (slow) processes. Transitions themselves are heavy processes to begin with. On modern computers it's not a problem, but if used simultaneously and in large quantities, the display might stutter. In older games, synchronous transitions were used almost exclusively due to computer performance issues.

The good thing about asynchronous operations is that they don't keep the player waiting. In synchronous transitions, the player is made to wait for text to proceed while the image switches. You can skip it by clicking, but even that is tedious for some people. Occasionally, there are games where you can't skip even by clicking, but a game where you're forced to wait every time a character's expression changes is a garbage game. Regardless of content, it goes into the trash 30 seconds after starting. I really didn't want to introduce the canskip attribute of the wt tag, but I did so because restricting the range of expression is not good. Please don't use it. Not using transitions for switching might also be an option. It might be more effective to only use them in key scenes... but I'm not sure.

Currently, it seems common to use asynchronous transitions for character expression changes and synchronous transitions when the entire background changes. Asynchronous transitions also have the side effect that people might stop looking at character sprites, but there's a trend toward increasing types of expression variations. No, maybe it's settled down recently. I wonder who is even looking at them when you increase them so much. Would people who listen to the voice until the end also look at the character sprites? Voices are also increasingly being skipped with functions like voice cutting or multi-playback. Some games use face windows next to text, perhaps to show expressions.

*start|Start

@LivingRoom Day

@Shiori PoseB Casual Surprised Front Center

Displays the background and character sprite.

@Shiori opacity=128

【Shiori】"Reduces opacity to half."

@Shiori opacity=0

【Shiori】"Sets opacity to 0."

@Shiori opacity=255

【Shiori】"Restores opacity to 255."

Using the "opacity" attribute, you can change a layer's opacity from 0 to 255. If opacity is low, the image becomes semi-transparent, and images on layers behind it become visible. If high, it becomes opaque, hiding images on rear layers. It defaults to the maximum value of 255, so the background behind character sprites is completely hidden. With @Shiori opacity=128, opacity becomes half, so the background behind becomes visible. With @Shiori opacity=0, it becomes completely transparent and the character sprite is no longer visible. Returning opacity to 255 with @Shiori opacity=255 makes the character sprite visible again. The opacity attribute can be used similarly for backgrounds, event CGs, and environment layers, as well as character sprites.

Using actions allows you to change attribute values continuously. Simply specifying a value for an attribute changes it instantly, but using actions allows for expressions with movement.

*start|Start

@LivingRoom Day

@Shiori PoseA Casual Surprised Back Left

Displays the background and character sprite.

@Shiori xpos=200 time=1000

【Shiori】"Changes the xpos value over 1 second."

@LivingRoom xpos=-50 ypos=300 time=2000

Changing background xpos and ypos values over 2 seconds.

@Shiori opacity=0 time=3000

【Shiori】"Fades the character sprite to transparent over 3 seconds."

If you specify a time in milliseconds with the time attribute while changing an attribute's value, the value will change from its current value to the specified value over the specified time. This is called an "action."

In @Shiori xpos=200 time=1000, the xpos attribute value changes from its current 0 to the specified 200 over one second. Since the value of the xpos attribute changes as "0, 1, 2, 3, ..., 199, 200", it looks like the character sprite is gradually moving to the right. If you specify xpos and ypos attributes simultaneously, like @LivingRoom xpos=-50 ypos=300 time=2000, both change over two seconds. Not just xpos and ypos attributes, but also the opacity attribute can be used similarly.

*start|Start

@LivingRoom Day

@layer name=StarLayer file=Star show

Displays the background and environment layer.

@StarLayer xpos=-200 time=1000 sync

Moved environment layer with a synchronous action.

@LivingRoom xpos=100 ypos=-100 time=2000 sync

Moved background with a synchronous action.

@StarLayer opacity=0 time=3000 nosync

Making environment layer transparent with an asynchronous action.

Unlike transitions, actions default to asynchronous operation. Only the default value is different; the mechanism of synchronous/asynchronous operation is the same as with transitions. In the case of synchronous operation, script execution is interrupted until the action finishes. You can specify this with the "sync" and "nosync" attributes. Asynchronous operations are canceled on page advance.

*start|Start

@LivingRoom Day

@layer name=StarLayer file=Star xpos=-200 ypos=-200 show

Displays the background and environment layer.

@StarLayer xpos=200 ypos=200 time=10000 nowait

Moving environment layer with an asynchronous action.

With the nowait attribute, it won't be canceled even if you click.

@StarLayer stopaction

Forcibly cancels the action.

The "nowait" attribute can also be used just like with transitions. Transitions were canceled with the "stoptrans" attribute, but actions are canceled with the "stopaction" attribute. Using @stopaction as a tag can also cancel all actions.

*start|Start

@Town Evening

@Kaede PoseA Casual Expressionless Back

Display the background and character sprite.

@Town xpos=-200 time=2000

@Kaede Right time=2000

Moving background and character sprite with asynchronous actions.

@Town xpos=200 time=10000 nosync

@Kaede Left time=10000 nosync

@wact

Moved background and character sprite with synchronous actions.

When using asynchronous actions on multiple images simultaneously, like a background and a character sprite, simply listing the tags is fine. There are no tags equivalent to begintrans and endtrans for transitions.

When using synchronous actions simultaneously, the "wact" tag can be used. While the wt tag waits for transitions to finish, the wact tag waits for actions. Execute asynchronous actions simultaneously and use @wact to wait for them to finish collectively. You can also use the canskip attribute to prevent them from being skipped.

*start|Start

@Town Day fade=1000 nosync

@Town xpos=-200 time=2000 nosync

@wat

Executed background transition and action simultaneously.

While wt waits for transitions and wact for actions, the "wat" tag waits for both transitions and actions to finish. The canskip attribute can also be used similarly.

At the point they are called, the wt, wact, and wat tags pause script execution until all running transitions and actions finish. If canskip is omitted or canskip=false and a click occurs, all currently running transitions/actions are canceled.

If none are running at the time these tags are called, they are simply ignored without pausing.

*start|Start

@Town Day fade=500

Display the background.

@Town xpos=200 ypos=-200 opacity=0 time=2000

Making background transparent while moving it asynchronously.

@Town xpos=0 ypos=0 time=2000

@Town opacity=255 time=4000

Making background opaque while moving asynchronously over different times.

You can also use actions on xpos, ypos, and opacity attributes simultaneously. If written in a single tag like @Town xpos=200 ypos=-200 opacity=0 time=2000, the time specified in the time attribute will be common, but if you split it into two tags, you can specify different times. However, xpos and ypos are special and cannot be handled separately.

*start|Start

@Town Day

@layer name=Star1 file=Star show ypos=100

@layer name=Star2 file=Star show ypos=0

@layer name=Star3 file=Star show ypos=-100

Displayed background and environment layers.

@Star1 xpos=300 time=2000 accel=accel

@Star2 xpos=300 time=2000 accel=const

@Star3 xpos=300 time=2000 accel=decel

Moving Star 1 with acceleration, Star 2 at constant speed, and Star 3 with deceleration.

@Star1 xpos=-300 time=4000 accel=acdec

@Star2 xpos=-300 time=4000 accel=const

@Star3 xpos=-300 time=4000 accel=accos

Moving Star 1 with acceleration/deceleration, Star 2 at constant speed, and Star 3 with cosine acceleration/deceleration.

Reviewing: ypos attributes are higher up as numerical values increase, so when executed, Star 1 will be displayed at the top, Star 2 in the middle, and Star 3 at the bottom.

Using the "accel" attribute allows you to make attribute values change with acceleration or deceleration. The overall time taken for the action won't change from the value specified in the time attribute. Specifying "accel" for the attribute value causes the value to change slowly at first and then rapidly later. Specifying "decel" causes it to change rapidly at first and then slowly later. Specifying "const" results in values changing at a constant rate, same as when not using the "accel" attribute.

"acdec" and "accos" are acceleration/deceleration, where the first half accelerates and the second half decelerates. They hardly differ when executed. "accos" has a slightly gentler speed change.

*start|Start

@Town Day

@layer name=Star1 file=Star show

Displays the background and environment layer.

@Star1 path="(200,0,0),(200,200,255),(0,0,128)" time=4000

Moving.

@Star1 path="(-200,0,255),(-200,200,255)" time=4000 spline

Moving with a spline.

Using the "path" attribute allows for multi-point movement and opacity actions. The attribute value is a series of sets in the format "(xposValue, yposValue, opacityValue)" connected by commas. In @Star1 path="(200,0,0),(200,200,255),(0,0,128)" time=4000, the three sets are "xpos=200, ypos=0, opacity=0", "xpos=200, ypos=200, opacity=255", and "xpos=0, ypos=0, opacity=128". It moves through these three points in the time specified in the time attribute. If you only want to change position without changing opacity, keep opacity values at a constant, like 255.

Using the "spline" attribute along with the path attribute moves through each point using spline-interpolated paths. This allows for smooth movement connecting each point. sync, nosync, and nowait attributes can also be used, but the "accel" attribute cannot.

*start|Start

@Town Day

Display the background.

@Town rotate=180

Rotates the background 180°.

@Town rotate=0

Returned to original angle.

Using the "rotate" attribute allows you to rotate an image. Specify how many degrees to rotate counter-clockwise as the attribute value. Specifying a negative value rotates clockwise. Not just backgrounds, but also character sprites, event CGs, and environment layers can be rotated similarly.

*start|Start

@LivingRoom Day

Display the background.

@LivingRoom rotate=360 time=3000

Rotates the background one full turn counter-clockwise.

@LivingRoom rotate=-360 time=6000 sync accel=acdec

Rotates the background two turns clockwise.

Actions using the time attribute can also be used. In rotate=360 time=3000, the value changes from the default 0 to the specified 360 through "0, 1, 2, 3... 359, 360" via an action, so visually it rotates once counter-clockwise. In the next rotate=-360 time=6000, the rotate value changes from its current 360 to the specified -360 through "360, 359, 358, ..., 1, 0, -1, ..., -359, -360". Visually, this results in two clockwise rotations. sync, nosync, and accel attributes also work without issue.

*start|Start

@Town Day

Display the background.

@Town rotate=360 time=1000

Rotates the background once counter-clockwise.

@Town afx=0 afy=0

Changed rotation origin to the top-left of the image.

@Town rotate=720 time=1000

Rotates the background once counter-clockwise.

The "afx" and "afy" attributes allow you to specify the "rotation origin." The rotation origin is the center point (coordinate) of rotation, and the display position of that point does not shift during rotation.

The rotation origin is a point on the image specified in a Cartesian coordinate system where the top-left of the image is (0,0) and the bottom-right of the image is (imageWidth, imageHeight). Look at the image on the right. The background image size is 800×600. The horizontal axis is X (afx) and the vertical axis is Y (afy), where afx is positive to the right and afy is positive downward. As mentioned, the top-left of the image is (0,0), and since this background image is 800×600, the × point at the bottom-right of the image is (800,600). The + point at the center of the image is (400,300).

The default rotation origin for a background is the center of the image. For an 800×600 image, it is (400,300). Thus, in the first @Town rotate=360 time=1000, rotation occurs centered around that middle point, as shown in the image on the right.

Next, the rotation origin is changed to (0,0) at the top-left of the image with @Town afx=0 afy=0. At this time, the display position shifts toward the bottom-right, but I'll explain that later. For now, in the next @Town rotate=720 time=1000, rotation occurs around the top-left of the image, as shown in the image on the right. Since it has already rotated to 360 degrees, 720 degrees is specified to complete another rotation.

*start|Start

; Shifting position upward to make rotation easier to see

@Shiori SchoolUniform PoseB Sadness Back Center ypos=300

Display the character sprite.

@Shiori rotate=180 time=2000

Rotates the character sprite 180° counter-clockwise.

@Shiori afx=center afy=center

Set rotation origin to center.

@Shiori rotate=0 time=2000

Rotates the character sprite 180° clockwise.

The default rotation origin for a character sprite is the bottom-center of the image, not the center. Thus, rotation is performed centered on the bottom of the image.

Also, in afx and afy attributes, you can use words to specify instead of numerical coordinates. Specifying "center" for the afx attribute matches the rotation origin's X-coordinate to the image's horizontal center X-coordinate. Specifying "center" for the afy attribute matches the rotation origin's Y-coordinate to the image's vertical center Y-coordinate. Thus, setting afx=center afy=center makes the image center the rotation origin. Furthermore, you can specify "left" or "right" for the afx attribute. Setting afx=left makes the left edge of the image the rotation origin, and afx=right makes the right edge the rotation origin. "top" or "bottom" can be specified for the afy attribute, making the top or bottom edge of the image the rotation origin, respectively. Following this, the default rotation origin for a character sprite is afx=center afy=bottom.

The default rotation origin for backgrounds, event CGs, and environment layers is the image center, namely afx=center afy=center. Character sprites differ to prevent their feet from shifting when they rotate. While not depicted in the samples, if you use a character sprite image where the full body is drawn down to the feet, the bottom-center of the image is exactly at the feet. Since character sprites should be standing on the ground, it's often convenient if the contact point at the feet doesn't shift.

*start|Start

; Shifting position upward to make rotation easier to see

@Shiori SchoolUniform PoseB Sadness Back Center ypos=300

Display the character sprite.

@Shiori rotate=180 time=2000

Rotates the character sprite 180° counter-clockwise.

@Shiori afx=center afy=center

Set rotation origin to center.

@Shiori rotate=0 time=2000

Rotates the character sprite 180° clockwise.

In addition to the rotation origin, there is a "display origin." While the rotation origin is an image-based coordinate for the center of rotation, the display origin is a window-based coordinate for the center of display. It is specified in a Cartesian coordinate system where the top-left of the window is (0,0) and the bottom-right of the window is (windowWidth, windowHeight).

Look at the image on the right. It's almost the same as the rotation origin, but note that it's a coordinate on the window, not on the image. Since the window size is also 800×600, the bottom-right of the window is (800,600), and the center of the window is (400,300).

Images are displayed centered on the display origin. That is, the rotation origin and display origin overlap when xpos=0 ypos=0.

Displaying a background with @Town Day results in it being displayed at a position where the rotation origin (image center) overlaps with the default display origin (window center). Setting xpos=100 shifts it 100px to the right from there, and ypos=100 shifts it 100px upward.

Changing the display origin to the top-left of the window with @Town orx=0 ory=0 shifts the image position so the rotation origin (image center) overlaps with the display origin (window top-left). Conversely, if the rotation origin is changed to @Town afx=left afy=top, the image position changes accordingly. Here, since the rotation origin (image top-left) overlaps with the display origin (window top-left), the result is the same as the initial display.

Just like the rotation origin, the display origin can be specified with the orx attribute as "left", "center", or "right" (horizontal window left edge, center, or right edge X-coordinate), and the ory attribute as "top", "center", or "bottom" (vertical window top edge, center, or bottom edge Y-coordinate).

Also, although the rotation origin is a coordinate on the window, it is set separately for each image. It doesn't mean there is only one for the entire window.

The rotation origin defaults to the window center for backgrounds, character sprites, event CGs, and environment layers.

When displaying the character sprite for the first time in Chapter 3, the position of the character sprite was shifted upward. This was because the bottom of the image was positioned at the screen center due to the rotation and display origin functions. Since that position was undesirable, a vertical offset (yoffset) could be specified specifically for character sprites, which essentially behaves as if the display origin's position shifted by the specified number of pixels.

*start|Start

@Town Day

Display the background.

@Town zoomx=50

Reduced background width to 50%.

@Town zoomy=200

Enlarged background height to 200%.

@Town zoom=100

Returned background scale ratio to normal.

You can specify the image's scale ratio in "zoomx" and "zoomy" attributes. These are horizontal and vertical scale ratios, respectively, where the default 100 represents the image's original size. Setting 50 results in half the normal size, 200 results in double, and so on. You can also use the "zoom" attribute to specify the same value for both zoomx and zoomy attributes at once.

*start|Start

@Town Day

@Shiori Front SchoolUniform PoseA Smile

Display the background and character sprite.

@Town zoom=50 time=2000 sync

Shrinks the background to 50%.

@Shiori zoom=200 time=2000

Enlarging character sprite to 200%.

Actions via the time attribute can also be used for zoom, zoomx, and zoomy attributes. Just like with the rotate attribute, scaling is performed centered around the rotation origin. In other words, the display position of the rotation origin does not shift even when scaled up or down.

*start|Start

@Town Day

@Shiori Front SchoolUniform PoseB Expressionless

Display the background and character sprite.

@Town zoom=-100 time=2000

Enlarging background to -100%.

@Shiori zoomx=-100 time=2000

Enlarging character sprite width to -100%.

@Town zoom=-200 time=2000

Enlarging background to -200%.

Specifying a negative value for zoom, zoomx, or zoomy attributes flips the image centered on the rotation origin. "zoomx" flips horizontally, "zoomy" flips vertically, and "zoom" flips both vertically and horizontally. Specifying -200 results in a flipped image that is also twice as large.

*start|Start

@Town Evening

@Shiori Back Casual PoseB Expressionless

Display the background and character sprite.

@Town flipy

Flipped the background vertically.

@Shiori flipx

Flips the character sprite horizontally.

@Town flipx

Flips the background horizontally as well.

@Town flipx=false flipy=false

Returned background flip to normal.

The "flipx" and "flipy" attributes can also be used to flip images. Set true to flip and false to return to normal. Remember that the attribute value "true" can be omitted. Flipping with flipx or flipy is performed such that the image's display position does not shift, regardless of the rotation origin. Since it's easy to use, it might be more convenient than "zoom" for flipping.

*start|Start

@Town Day

@Shiori Front SchoolUniform PoseB Expressionless

Display the background and character sprite.

@Town slantx=100

Slants the background 100° horizontally.

@Shiori slantx=-100

@Shiori slantx=-100

Slants the character sprite -100° horizontally.

@Town slantx=0 slanty=100

Slant the background 100 vertically.

You can slant images by using the "slantx" and "slanty" attributes. The default for both is 0, which means no slanting at all.

When slanted, the rectangle is transformed into a parallelogram. A value of 100 results in a parallelogram with a 45-degree acute angle. It is difficult to explain well in words, so please look at the image on the right. The larger the value, the steeper the slant. Negative values slant in the opposite direction. Just like rotation and scaling, the slant is centered on the rotation origin, and the slant is applied so that its position does not shift.

*start|Start

@Town Day

The background displays.

@Town slantx=100 time=2000

The background is slanting to 100 horizontally.

@Town slantx=0 time=2000 sync

Resets the background slant.

@Town slanty=100 time=2000

The background is slanting to 100 vertically.

Actions using the "time" attribute can also be used for slanting. There are no particular points of caution. "slantx" and "slanty" can also be used simultaneously in an action. In the script above, they are used one by one to avoid confusion.

*start|Start

@Town Day

The background displays.

@Town slantx=100 time=2000

The background is slanting to 100 horizontally.

@Town slantx=0 time=2000 sync

Resets the background slant.

@Town slanty=100 time=2000

The background is slanting to 100 vertically.

You can blur images by using the "blurx" and "blury" attributes. Both default to 0, which means no blur is applied. The "blurx" attribute is for horizontal blur, and the "blury" attribute is for vertical blur. Since the image itself is not being transformed, the rotation origin is irrelevant. You can also specify the same value for both blurx and blury using the "blur" attribute.

*start|Start

@Shiori Front Casual_Clothes Pose_A Smile

Displays the character sprite.

@Shiori blurx=50 time=1000

Blurring the character sprite horizontally.

@Shiori blurx=0 blury=50 time=1000 accel=accel

Blurs the character sprite vertically.

@Shiori blur=0 time=1000 sync

Removes the blur.

@Shiori allclear

All cleared and ready.

Actions using the "time" attribute can also be used for blurring.

If you use a large blur value, colors may remain around the edges even if you set the blur to 0. In the sample above, colors remain around the edges at the point the blur is removed. Not limited to blur, colors can also remain if abrupt actions are used for rotation, scaling, or movement. This happens when colors are drawn in a range wider than the original image size. When a large value is entered for blur, colors are painted outside the original size of the image, so those parts remain.

Possible workarounds are to not use values large enough to protrude off-screen or to increase the size of the image itself. You can increase the image size by adding transparent parts around the image.

Using the "allclear" attribute will forcibly clean up colors remaining outside the image size. If you can use "allclear" immediately, you may be able to make it less noticeable. In the script above, colors remain from the time the blur is removed until the player advances to the next text and "@Shiori allclear" is executed.

*start|Start

@Town Day

@Shiori Back Casual_Clothes Pose_A Smile

Displays the background and character sprite.

@Town raster=100

Raster scrolling the background.

@Town raster=0

Stops.

@Town raster=100 rasterlines=200 rastercycle=2000

Raster scrolling.

@Town raster=200

Changed the scrolling width.

@Town raster=200 rasterlines=400

Changed the vertical line width.

@Town raster=200 rastercycle=10000

Changed the raster time.

Horizontal raster scrolling is available via the "raster" attribute. The image will scroll in a wavy, horizontal fashion.

In the "raster" attribute, specify the maximum horizontal scroll amount in pixels. You can stop raster scrolling by setting raster=0.

The "rasterlines" attribute specifies the vertical width of the lines in pixels. The scroll direction (left or right) changes every specified number of pixels. The default value is 100. The "rastercycle" attribute specifies the time it takes to complete one full left-right scroll cycle in milliseconds. The default value is 1000.

When specifying "rasterlines" or "rastercycle," you must also specify "raster" at the same time. You need to use @Town raster=200 rasterlines=400 instead of @Town rasterlines=400.

*start|Start

@Town Day

@Shiori Back Casual_Clothes Pose_A Smile

Displays the background and character sprite.

@Town raster=100 time=2000

Raster scrolling the background.

@Town raster=0 time=2000

Stopping.

Actions with the "time" attribute can be used for the "raster" attribute. With @Town raster=100 time=2000, the "raster" attribute value changes like "0,1,2,...,99,100," so the scrolling width gradually increases. @Town raster=0 time=2000 does the opposite, stopping the raster scroll over 2 seconds.

Actions cannot be used for "rasterline" and "rastercycle" attributes. They change immediately to the specified value regardless of the "time" attribute.

Up until now, only backgrounds and portraits have been used in the sample scripts, but rotation, scaling, flipping, slanting, blurring, and raster scrolling can be used in the same way for backgrounds, portraits, event CGs, and environment layers.

*start|Start

@Town Day

@Shiori Back Casual_Clothes Pose_A Smile

Displays the background and character sprite.

@Shiori xpos=@100

【Shiori】"I moved 100px to the right."

@Shiori xpos=@100

【Shiori】"I moved 100px to the right again."

@Shiori xpos=@-400

【Shiori】"I moved 400px to the left."

Adding an @ (half-width at symbol) to the beginning of an attribute value makes it a relative specification from the current value. The actual value becomes the current value of the attribute plus the specified value.

Since xpos defaults to 0, in the first @Shiori xpos=@100, the value of xpos becomes 0+100=100. In the next @Shiori xpos=@100, the xpos value is already 100, so it becomes 100+100=200. In the final @Shiori xpos=@-400, it becomes 200+(-400)=-200.

Relative specification can be used for any attribute that supports actions via the "time" attribute. Summarizing the attributes that support "time" actions: "xpos", "ypos", "opacity", "rotate", "zoomx", "zoomy", "zoom", "slantx", "slanty", "blurx", "blury", "blur", and "raster."

*start|Start

@Town Day

@Shiori Back Casual_Clothes Pose_A Smile

Displays the background and character sprite.

@Shiori xpos=100%

【Shiori】"I moved to the 100% right position."

@Shiori xpos=0% ypos=50%

【Shiori】"I moved to the 50% top position."

@Shiori rotate=100% time=2000

【Shiori】"I am rotating one full turn counter-clockwise."

@Shiori opacity=50%

【Shiori】"I set the opacity to half."

Adding a % (half-width percent sign) to the end of an attribute value makes it a percentage specification. The attributes that can use percentage specification are the same as those that can use relative specification.

For the zoomx, zoomy, zoom, slantx, and slanty attributes, they are already specified by ratios, so adding a % or not doesn't change anything.

For xpos, ypos, blurx, blury, blur, and raster, which are specified in pixels: 0% is 0, and 100% corresponds to the screen width for x, and half the screen height for y. Since the default screen width is 800, @Shiori xpos=100% shifts it right by 400 (half of 800). For the next ypos=50%, it will shift up by 150, which is 50% of 300 (half the default screen height of 600). You can also shift left by using a minus sign, like xpos=-50%.

For the rotate attribute, 100% corresponds to 360 (one full rotation). For the opacity attribute, 100% corresponds to the maximum value of 255.

*start|Start

@Town Day

@Shiori Back Casual_Clothes Pose_A Smile

Displays the background and character sprite.

@Shiori xpos=-100:100 time=2000

【Shiori】"I am moving from xpos=100 to xpos=-100."

@Shiori zoom=100:200 time=2000

【Shiori】"I'm scaling from 200% down to 100%."

@Shiori pos=Center:RightOuter time=2000

; @Shiori Center:RightOuter time=2000 is also OK

【Shiori】"I am moving from RightOuter to Center."

In actions using the "time" attribute, the attribute changes from its current value to the specified value. By appending ":initial_value" to the attribute value, you can specify the starting value for the action.

With @Shiori xpos=-100:100 time=2000, the xpos attribute will change like "100, 99, 98, ..., -99, -100." The same goes for the next @Shiori zoom=100:200 time=2000, changing as "200, 199, 198, ..., 101, 100." For the portrait's pos=Center:RightOuter, you can omit the attribute name and use it like Center:RightOuter.

Attributes that can use initial value specification are all the same attributes that can use actions via the "time" attribute.

You can also combine relative, percentage, and initial value specifications. It can look like xpos=100:@-100 or xpos=@-40%:@20, but since it's rarely necessary, I won't explain it specifically.

*start|Start

@Town Day

@Shiori Back Casual_Clothes Pose_A Smile

Displays the background and character sprite.

@Town afx=0 afy=0 time=2000

Changing the rotation origin of the background.

@Town afx=center afy=center rotate=180 time=2000

Rotates with a changing rotation origin.

Actions can also be used for the rotation origin. In @Town afx=0 afy=0 time=2000, the displayed position of the image changes as the rotation origin position changes. In @Town afx=0 afy=0 rotate=180 time=2000, the image is also rotated in addition to that.

Unlike other attributes that support actions, you cannot use relative, percentage, or initial value specifications for afx and afy attribute actions.

Using rotation origins allows for fairly complex movements, but in practice, complex movements are often handled by defining custom actions. I will introduce how to define actions later.

To fill some space, I'll go off on a tangent: IME word registration is quite useful. If you don't know what that is, please search for it.

Typing @Shiori seriously every single time is quite a chore. Now I have it set up so that "qs" converts to @Shiori and "qk" converts to @Kaede . "qs" and "qk" don't have any special meaning. I register strings I use often for each title.

For common ones, for example, "s" converts to a half-width space. Stop switching between full-width and half-width every time just to type spaces between attributes. This will come up in the voice explanation in Chapter 5, but "pdl" can convert to delayrun=label0. Even if you use it often, the attribute name is long and difficult.

You don't need to copy my method exactly, but this is one way to save labor, so please keep it in mind.

KAGEX has the concept of a "camera." Think of the images displayed by "stage", "char", "event", and "layer" tags as being projected onto the screen through a virtual camera.

I will introduce the camera function for now, but since it's tedious to use, it's actually not used that often.

*start|Start

@Town Day

@Shiori Front Right Uniform Pose_A Smile

Displays the background and character sprite.

@env camerax=50

Shifted the camera position 50 to the right.

@env cameray=50

Shifted the camera position 50 up.

@env camerazoom=200

Set the camera zoom to 200%.

@env camerarotate=45

Tilts the camera 45° counter-clockwise.

Cameras are operated using the "env" tag. The "env" tag is used for general game operations besides the camera, which I will explain later.

Use the "camerax" and "cameray" attributes of the env tag to shift the camera position. Both default to 0. Moving the camera to the right shifts the entire projected screen to the left, and moving the camera up shifts the entire projected screen down. You can specify the camera's zoom scale using the "camerazoom" attribute. The default is 100; camerazoom=200 zooms the entire screen by 2x. You can rotate the camera using the "camerarotate" attribute. The meaning of the specified value is the same as the "rotate" attribute.

*start|Start

@Town Day

@Shiori Front Right Uniform Pose_A Smile

Displays the background and character sprite.

@env camerax=-150 time=2000

Shifting the camera position 150 to the left.

@env cameray=150 time=2000

Shifting the camera position 150 up.

@env camerazoom=200 time=2000

Setting the camera zoom to 200%.

@env camerarotate=180 time=2000

Tilting the camera 180 degrees counter-clockwise.

Actions with the "time" attribute can also be used. Using actions makes the camera movement easier to understand.

The camera can be used to simply move the entire screen, but if you specify the Z-position of the images, you can achieve 2.5D movement. By 2.5D, I mean images can be placed along a depth axis. In addition to the existing horizontal (X) and vertical (Y) axes, images have a depth axis (Z). The default is 100; larger numbers are closer to the foreground. Since it's not full 3D, the camera cannot orbit around objects, but 2D images can be moved somewhat like they are in 3D space.

// ■levelz

// Specify the Z-position of portraits for each display level.

levelz[0] = 100;

levelz[1] = 100;

levelz[2] = 100;

// ■bglevelz

// Specify the Z-position of the background.

bglevelz = 100;

The Z-positions for the background and portraits must be defined beforehand. Open "envinit.otjs" in the "init" folder and find parts like the ones above. Portrait Z-positions are specified per display level in the format "levelz[display level] = Z-position;". The background Z-position is specified in the format "bglevelz = Z-position;", shared by all backgrounds. The Z-position must be a number greater than 0. Please set it as follows here:

// ■levelz

// Specify the Z-position of portraits for each display level.

levelz[0] = 100;

levelz[1] = 150;

levelz[2] = 100;

// ■bglevelz

// Specify the Z-position of the background.

bglevelz = 50;

Display level 2 is not used in the sample script, so it remains at 100. Since the portrait at display level 1 is 1.5x larger than the image at level 0, its Z-position at level 1 is set 1.5x further forward than its level 0 position. In truth, the relationship between distance and size isn't that simple, but it's tedious, so we'll leave it at this.

The background is somewhat arbitrary, but it's set 2x further back than the level 1 portrait. When using a camera, you need to consider the distance from the camera when preparing the background. Depending on the situation, you might need to separate parts by distance. Using the camera properly is hard work. For backgrounds, since indie games often use free assets, eye levels might be inconsistent or portraits might look like they're floating, so it's also okay to not worry about the small details.

After modifying and saving envinit.otjs as above, run autosetting.bat in the tools folder to apply the changes.

The Z-position does not directly specify the distance from the camera, but rather the relative position between images. The default Z-position is 100, which serves as the reference. When the Z-position is 100, moving the camera left by 10 pixels moves the image right by 10 pixels. If the Z-position is 150, it moves right by 15 pixels, and if it's 50, it moves right by 5 pixels.

When you're in a car looking out, foreground scenery flows by faster than the background. This means foreground objects appear to move more than background objects. Moving the camera is the same as moving the viewpoint's (car's) position. Moving an image with xpos and ypos attributes is like the car being stopped and the person outside the car (the subject) walking and moving.

Position specifications using xpos and ypos attributes are also affected. The same xpos=100 will shift 100 pixels right when the Z-position is 100, but it will shift 150 pixels right when the Z-position is 150.

*start|Start

@Town Day

@Kaede Back Left Casual_Clothes Pose_A Expressionless

@Shiori Front LeftCenter Uniform Pose_A Smile

Displays the background and character sprites.

@env camerax=-200 time=2000

Shifting the camera position 200 to the left.

@env cameray=200 time=2000

Shifting the camera position 200 up.

@env camerazoom=200 time=2000

Setting the camera zoom to 200%.

@env camerarotate=180 time=2000

Tilting the camera 180 degrees counter-clockwise.

If you run the script above, you should be able to see the effect of the Z-position.

As defined earlier, the Z-position of the background "Town" is 50, "Kaede" at display level 0 (Back) is 100, and "Shiori" at display level 1 (Front) is 150. Thus, when the camera shifts 150 left, "Town" shifts 100 pixels right, "Kaede" shifts 200 pixels right, and "Shiori" shifts 300 pixels right. Please try running it to see how it looks.

Zooming with the camerazoom attribute and rotating with the camerarotate attribute are not affected by the Z-position. Using the car example from before, using 5x binoculars inside the car makes everything look 5x larger regardless of distance. Tilting your head 45 degrees makes everything look tilted 45 degrees regardless of distance.

*start|Start

@Town Day

@Kaede Back Left Casual_Clothes Pose_A Expressionless

@Shiori Front LeftCenter Uniform Pose_A Smile

@layer name=Star1 file=Star levelz=80 xpos=-50 ypos=300

Displays the background, character sprites, and star.

@env camerax=-200 time=2000

Shifting the camera position 200 to the left.

@env cameray=200 time=2000

Shifting the camera position 200 up.

The Z-position for environment layers can be specified with the "levelz" attribute. This is the same position specification based on the reference value of 100 defined in envinit.otjs.

*start|Start

@Town Day

@Kaede Back Left Casual_Clothes Pose_A Expressionless

@Shiori Front LeftCenter Uniform Pose_A Smile

@layer name=Star1 file=Star xpos=-270 ypos=250 zoom=80 nocamera

Displays the background and character sprites.

@env camerax=-200 cameray=200 time=2000

Shifting the camera position 200 to the top-left.

@env camerazoom=200 camerarotate=180 time=2000

Setting the camera zoom to 200% and rotating 180 degrees.

The "nocamera" attribute can be used in char, stage, and layer tags. Images with this attribute set to true will not be affected by camerax, cameray, camerarotate, and camerazoom attributes. In the script above, the position of "Star1" does not move at all. This can be used when displaying dates or parameter images on the screen.

Event CGs are completely unaffected by the camera from the start. Therefore, you cannot specify a Z-position using the levelz attribute or similar.

*start|Start

@Town Day

@Kaede Back Left Casual_Clothes Pose_A Expressionless

@Shiori Front LeftCenter Uniform Pose_A Smile

Displays the background and character sprites.

@env shiftx=-100 time=1000

Shifting the camera 100 to the left.

@env shifty=100 time=1000

Shifting the camera 100 up.

The "shiftx" and "shifty" attributes are almost the same as camerax and cameray, but the whole thing moves by the specified number of pixels, regardless of the images' Z-positions.

With camerax=-100, the actual number of pixels shifted varies based on the image's Z-position, but with shiftx=-100, all images shift 100 pixels to the right. With shifty=100, all images shift 100 pixels down. Other points are the same as camerax and cameray attributes.

*start|Start

@Town Day

@Kaede Back Left Casual_Clothes Pose_A Expressionless

@Shiori Front LeftCenter Uniform Pose_A Smile

@layer name=Star1 file=Star xpos=-270 ypos=250 zoom=80 noshift

Displays the background, character sprites, and star.

@env shiftx=-100 time=1000

Shifting the camera 100 to the left.

@env shifty=100 time=1000

Shifting the camera 100 up.

Similar to the nocamera attribute, there is also the "noshift" attribute. If true is specified for this attribute, the image will not be affected by the shiftx and shifty attributes. In the script above, "Star1" does not move at all. Its usage is not much different from the nocamera attribute.

Event CGs are also unaffected by the shiftx and shifty attributes.

*start|Start

@Town Day blur=30

@Kaede Back Left Casual_Clothes Pose_A Expressionless blur=15

@Shiori Front Center Uniform Pose_A Smile

@layer name=Star1 file=Star xpos=-270 ypos=250 zoom=80 noshift blur=20

Displays the background, character sprites, and star.

@Town blur=15 time=1000

@Kaede blur=0 time=1000

@Star1 blur=5 time=1000

@Shiori blur=-15 time=1000

Focusing on Kaede.

@Town blur=10 time=1000

@Kaede blur=-5 time=1000

@Star1 blur=0 time=1000

@Shiori blur=-20 time=1000

Focusing on the star.

KAGEX's camera only has the simple XY position correction via Z-position as introduced here. Despite the effort required to use it, its functionality might be a bit underwhelming. It lacks depth-of-field or out-of-focus expression features. Just blurring with the blur attribute like in the script above makes it look somewhat realistic.

*start|Start

@Town Day

@Shiori Front Right Uniform Pose_A Smile

Displays the background and character sprite.

@quake time=1000 vmax=20 hmax=10

Shakes the screen for 1 second.

@quake time=2000 sync

Shakes the screen for 2 seconds.

The "quake" tag can be used to shake the entire screen. While you can also use actions to shake it, the quake tag is very convenient and easy to use. The "vmax" attribute specifies the maximum vertical shift and "hmax" specifies the maximum horizontal shift in pixels. The screen will shake randomly within the range specified by these attributes.

The vmax and hmax attributes default to 10 if omitted. The "time" attribute specifies how many milliseconds the screen should shake. By default, it operates asynchronously, but you can make it synchronous using the "sync" attribute.

*start|Start

@Town Day

@Shiori Front Right Uniform Pose_A Smile

Displays the background and character sprite.

@quake

The screen shakes.

The shaking from the quake tag is not cancelled by advancing the page.

@stopquake

Stops the screen shake.

If the time attribute is omitted from the quake tag, the screen will continue to shake indefinitely. Also, unlike actions and transitions, the asynchronous operation of the quake tag is not cancelled by advancing the page. You must use the "stopquake" tag to stop the shaking.

*start|Start

@Town Day

@Shiori Front Right Uniform Pose_A Smile

Displays the background and character sprite.

@quake message

The screen shakes.

The screen shakes continuously.

@stopquake

Stops the screen shake.

Using the "message" attribute, you can also shake the message area along with the screen. This is not recommended for use with text display as it makes it hard to read.

I have introduced three types of transitions: "crossfade," "universal," and "scroll." However, other transitions can be used by using Kirikiri plugins.

Kirikiri plugins are programs to extend Kirikiri's functionality, and they are the files with the .dll extension in the "plugin" folder within the development folder. Since the plugins located there are necessary for KAGEX to operate, they must be distributed along with the game itself when it is completed. To use a plugin, you "link" it to Kirikiri, but linking for these mandatory plugins is done automatically. Plugins containing extended transition features are not included there because they are not mandatory.

First, copy the plugin file. Copy "extrans.dll," found in the "extrans" folder inside the "plugin" folder of the SDK directory, into the "plugin" folder of your development directory.

// Linking additional plugins

// Example: Plugins.link("saveStruct.dll");

Next, link it to Kirikiri. Open "plugins.tjs" in the "init" folder of the project directory; it is written as shown above. Linking a plugin is done in a format like "Plugins.link("plugin_name.dll");".

// Linking additional plugins

// Example: Plugins.link("saveStruct.dll");

Plugins.link("extrans.dll");

Save after adding the line Plugins.link("extrans.dll");. Now "extrans.dll" will be linked when Kirikiri starts. Preparations are complete, so let's try using an extended plugin.

Since extended plugins are not directly related to KAGEX, I will only introduce them briefly. For details, please refer to the Transitions page (http://devdoc.kikyou.info/tvp/docs/kr2doc/contents/Transition.html#id295) in the Kirikiri Reference (http://devdoc.kikyou.info/tvp/docs/kr2doc/contents/). You will understand if you read "Extended Transition Plugins" while playing around with the attribute values.

*start|Start

@Town Day

Displayed the background.

@Town Evening trans=wave time=10000 wavetype=2 maxh=50 maxomega=0.2

Performed a wave transition.

@Town Night trans=mosaic time=2000 maxsize=20

A mosaic transition.

@Sunflower Day trans=turn time=2000

A turn transition.

@Sunflower Evening trans=rotatezoom time=2000 factor=0 accel=0 twist=3 twistaccel=0

A rotate-zoom transition.

@Town Day trans=rotatevanish time=2000 accel=2 twist=-2 twistaccel=0

A rotate-vanish transition.

@Town Evening trans=rotateswap time=2000 twist=2

A rotate-swap transition.

@Town Night trans=ripple time=2000 rwidth=64 roundness=1.0 speed=6.0 maxdrift=20

A ripple transition.

Specify the transition type in the "trans" attribute, the transition time in the "time" attribute, and the attributes specific to each type. Refer to the reference for details. Although not in the reference, sync and nosync attributes can also be used.

You can define frequently used transitions beforehand. Run "register_trans.exe" in the tools folder within the development folder, and select the project folder.

Click the "Add" button to define a new transition. Select the added "newtrans," input a name in the text box below the Add button, and press the Enter key to change the transition name. Here, we'll name it "RightScroll." You can also delete added transitions by clicking the "Delete" button.

Select a transition from the list on the left and set its attributes on the right. For "RightScroll," set "Transition Type" to "Scroll," "time" to "1000," "from" to "left," and "stay" to "nostay."

Once done, click "Output" in the menu. If you forget this, changes will not be reflected. Once this is finished, it can be used within scripts.

*start|Start

@Town Day

The background displays.

@Sunflower trans=RightScroll

Changed the background using RightScroll.

@Town Evening trans=RightScroll time=3000

Overrides the time attribute and RightScrolls.

@Town Night RightScroll stay=stayfore

Overrides the stay attribute and RightScrolls.

By specifying the defined transition name in the trans attribute, that transition can be used. By simultaneously specifying transition attributes, you can transition while changing part of the defined content. With @Town Evening trans=RightScroll time=3000, only the time attribute is changed, making the transition occur over 3 seconds instead of the defined 1 second.

You can also omit the "trans=" attribute name and use only the defined name, as in @Town Night RightScroll. You will basically be using it this way.

You can define predefined transitions to be used automatically when changing images. Transitions that execute automatically are called "auto-transitions."

Before defining an auto-transition, define the transitions to be used.

Run the register_trans.exe you used earlier once more. Add two transitions, "BackgroundTransition" and "PortraitTransition." Set the transition type for both to "Crossfade." For the time attribute, set BackgroundTransition to 1000 and PortraitTransition to 500. Check the "nosync" box for PortraitTransition; it will be an asynchronous transition.

Don't forget to click the "Output" menu once you've finished the settings.

Next, define the auto-transitions.

// ■envTrans

// Specify the auto-transition when any of stage, time, or event CG are changed.

autoTrans["envTrans"] = "";

// ■stageTrans

// Specify the auto-transition when stage or time are changed.

// Takes precedence over envTrans.

autoTrans["stageTrans"] = "";

// ■timeTrans

// Specify the auto-transition when time is changed.

// Takes precedence over envTrans and stageTrans.

autoTrans["timeTrans"] = "";

// ■eventTrans

// Specify the auto-transition when an event CG is changed.

// Takes precedence over envTrans.

autoTrans["eventTrans"] = "";

// ■charTrans

// Specify the auto-transition when any of pose, dress, or face of a portrait are changed.

autoTrans["charTrans"] = "";

// ■poseTrans

// Specify the auto-transition when a portrait's pose is changed.

// Takes precedence over charTrans.

autoTrans["poseTrans"] = "";

// ■dressTrans

// Specify the auto-transition when a portrait's clothing is changed.

// Takes precedence over charTrans.

autoTrans["dressTrans"] = "";

// ■faceTrance

// Specify the auto-transition when a portrait's expression is changed.

// Takes precedence over charTrans.

autoTrans["faceTrans"] = "";

// ■positionTrans

// Specify the auto-transition when any of a portrait's x/ypos, visibility, or display level are changed.

autoTrans["positionTrans"] = "";

// ■charDispTrans

// Specify the auto-transition when a portrait is shown or hidden.

// Takes precedence over positionTrans.

autoTrans["charDispTrans"] = "";

Open envinit.otjs in the init folder and find parts like those above. Define them in the format "autoTrans["Auto-Transition Type"] = "Transition Name";". Each auto-transition type, like "envTrans," has different timing for when it's used. Transitions specified in envTrans are used when any of stage, time, or event CG are changed. Read the explanations in the script above for other auto-transitions.

If multiple auto-transitions can be defined for the same change, the auto-transition with the narrower scope takes precedence. For example, for time changes, you can define "timeTrans," "stageTrans," and "envTrans." Since timeTrans applies only to time, stageTrans to time and stage, and envTrans to time, stage, and event CGs, they take precedence in this order. If timeTrans is specified, it's used; if not, stageTrans; if that isn't specified either, then envTrans will be used as the auto-transition for time changes. If envTrans is also not specified, no auto-transition occurs.

// ■envTrans

// Specify the auto-transition when any of stage, time, or event CG are changed.

autoTrans["envTrans"] = "BackgroundTransition";

// ■charTrans

// Specify the auto-transition when any of pose, dress, or face of a portrait are changed.

autoTrans["charTrans"] = "PortraitTransition";

// ■positionTrans

// Specify the auto-transition when any of a portrait's x/ypos, visibility, or display level are changed.

autoTrans["positionTrans"] = "PortraitTransition";

Since it's long, only the relevant parts are shown, but let's set the three above as a sample. Leave the others unchanged and unspecified. Once specified, run autosetting.bat.

*start|Start

@Town Day

; BackgroundTransition will execute

The background displays.

@Shiori Front Center Uniform Pose_A Smile

; PortraitTransition will execute

Shows the character sprite.

@Shiori Casual_Clothes

; PortraitTransition will execute

Changes the character sprite's clothing.

@Shiori hide

; PortraitTransition will execute

Clears the character sprite.

@Town Evening

; BackgroundTransition will execute

Changed the time.

If you run the script on the previous page, backgrounds and portraits will be displayed with auto-transitions. For background or time changes, the BackgroundTransition specified in envTrans will be executed. For portrait showing/hiding or clothing changes, the PortraitTransition specified in positionTrans or charTrans will execute. It's quite convenient as you can omit transition specifications for each tag.

*start|Start

@Town Day time=2000

The background displays.

@Shiori Front Center Uniform Pose_A Smile sync

Displays the character sprite.

@Shiori Casual_Clothes time=2000

Changes the character sprite's clothing.

@Shiori hide sync

Clears the character sprite.

@Town Evening nosync

Changing the time.

Similarly to specifying defined transitions with the trans attribute, you can change some attributes in tags where auto-transitions occur. With @Town Day time=2000, the time attribute of the auto-transition BackgroundTransition is changed, resulting in a 2-second asynchronous crossfade transition. With @Shiori hide sync, the sync attribute of PortraitTransition is changed, resulting in a 0.5-second synchronous crossfade transition.

*start|Start

@Town Day trans=scroll from=top stay=nostay time=1000

The background displays.

@Shiori Front Center Uniform Pose_A Smile notrans

Displays the character sprite without any transition.

If you specify the trans attribute as in @Town Day trans=scroll from=top stay=nostay time=1000, the auto-transition will not be used. The fade attribute, which is shorthand for trans=crossfade, is also OK. You can execute any individual transition regardless of auto-transitions.

Also, by using the "notrans" attribute as in @Shiori Front Center Uniform Pose_A Smile notrans, you can display it without any transition even if an auto-transition is set.

// ■fadeValue

// Specify the default time for fades.

fadeValue = 500;

// ■charFadeValue

// Specify the default time for portrait fades.

charFadeValue = 500;

These are each specified in milliseconds. "charFadeValue" specifies the default for portraits, and "fadeValue" for other images. If you want to change it from 500 milliseconds, rewrite it and run "autosetting.bat."

*start|Start

@Town Day fade

Displays the background with a fade.

@Shiori Front Center Uniform Pose_A Smile fade

Displays the character sprite with a fade.

Omitting the fade attribute value results in a crossfade with the time specified earlier. In @Town Day fade, it uses fadeValue, and in @Shiori Front Center Uniform Pose_A Smile fade, it uses the time specified in charFadeValue.

PC data is stored on hard drives, but hard drives are consumables. Be sure to take backups during game development. If data is lost and there is no backup, you'll have to start over from the very beginning.

Backup destinations include external hard drives, DVDs, USB sticks, and online storage. Use whatever you like. What's important here is to automate the backup. Only extremely diligent people can work hard to do manual backups every single day just in case. Data is lost when you get lazy and skip it for a while. You won't have to start from scratch, but you'll have to redo work from weeks ago. If you automate it, you'll be free from such sorrow.

Please research and figure out the actual method yourself. If you think "I'll do it later," it's over. You won't do it. You'll start doing it after it's lost. There is a saying, "The wise man learns from history, the fool from experience." I was a fool.

I've never used them myself, but recent external hard drives seem to come with software that backs up automatically. Online storage like Dropbox and SugarSync will automatically back up to the cloud just by saving files there.

When collaborating with multiple people to make a game, a massive amount of files will be generated and things will get complicated. It might be different if you're meeting directly and making it in the same place, but exchanging files over email or Skype is crazy. I can't tell you how many times I sent the wrong one. You might think "I won't do that," but you will.

Since you can't send all the game data every time over email, let's say you only send files changed since the last time. It would be fine if you sent all changed data accurately and the receiver overwrote everything accurately, but that's impossible. If you make a mistake even once somewhere, things will gradually get weirder. It might be okay with just two people, but when three, four, five people gather, someone will make a mistake.

If you're making it with multiple people, at least implement something like Dropbox. You can keep everyone's data in the same state, take backups, and keep file change histories. It's easy and convenient, but I think the price is a bit high compared to the capacity. If 50GB is enough, $10 a month is a good deal.

There are things called version control systems. Subversion, Git, Mercurial, Bazaar, etc. In digital novel production, the one actually used is likely Subversion. Version control means managing the records of file changes.

Especially when programming, there are times when you want to return a file to a previous state. This is easily done if you're using a version control system. Even when writing Kirikiri scripts, you might rewrite something and find it no longer works, but you don't know how to fix it. If you revert to the file before the changes, it's solved in one go.

Also, you can see how it would be a problem if two people were editing the same "01.ks" at the same time. This state is called a conflict, but it will notify you in such cases. With online storage like Dropbox, you might just save it without noticing.

In indie game production, it can also be used for keeping past versions. How will you keep slightly different versions like the Summer Comiket version, the SunCri version, and the Winter Comiket version? You can easily keep them with version control tags.

With Subversion, you can use a version control system relatively easily with TortoiseSVN. You need a server to place the repository, but if you're alone, it will work even if you put it on Dropbox. For team production, it's best to rent a server, but there seem to be Subversion hosting services too. In any case, if you're wondering what version control is, it's worth looking into.

  1. Sound Operation Scripts

I will introduce not only simple sound playback but also other functions like fading and volume adjustment. Character voices are also handled in this chapter.

*start|Start

@seRain nosync

Playing the sound effect asynchronously.

@seRain stop

Stops the sound effect.

@seRain sync

Played the sound effect synchronously.

@bgmLakesideVillage loop=false sync

Played the BGM synchronously.

Just like transitions and actions, sound playback has sync and async options. In synchronous playback, script execution is paused until playback finishes. In asynchronous playback, it is not paused.

Async playback is the default, but you can play synchronously by adding the sync attribute when starting playback. However, if you're using the loop attribute for looping playback, it will never end, so it must always be asynchronous. For BGM, you can play synchronously if loop=false, but I don't think it's used very often.

Unlike async execution of transitions and actions, async playback without the nowait attribute will not be stopped by advancing the page. You must use the stop attribute to stop playback.

*start|Start

@bgmLakesideVillage loop=false

Playing BGM asynchronously.

@bgm sync

Waited for the BGM to end.

The end of BGM playback with loop=false can also be awaited with @bgm sync.

*start|Start

@bgmLakesideVillage time=2000

Fading in the BGM.

@seRain loop time=2000

Fading in the sound effect.

@bgm stop time=2000

Fading out the BGM.

@seRain stop time=2000

Fading out the sound effect.

If you specify a time in milliseconds with the time attribute when playing, it will fade in over that duration. You can also fade out by adding the time attribute when stopping with the stop attribute. This is common to both BGM and sound effects.

*start|Start

@bgmLakesideVillage time=2000 sync

Faded in the BGM synchronously.

@bgm stop time=2000 sync

Faded out the BGM synchronously.

Regarding BGM fade-ins and fade-outs, you can make them operate synchronously by adding the "sync" attribute. In this case, the script execution will pause not until the BGM finishes playing, but until the fade itself finishes.

*start|Start

@seRain time=2000 sync

Plays the sound effect synchronously.

@seRain loop

The sound effect loops.

@seRain stop time=2000 sync

Fades out the sound effect synchronously.

Regarding sound effects, if you add the sync attribute during the fade-in at the start of playback, it acts as a sync for the playback itself rather than just the fade. With @seRain time=2000 sync, the script will pause until the playback finishes, not just until the fade finishes. When stopping with the stop attribute, just like BGM, adding the sync attribute will pause script execution until the fade-out is complete.

BGM volume is determined by "Master Volume" and "BGM Volume." Sound effect volume is determined by "Master Volume" and "SE Volume." Master Volume is exactly what it sounds like: a volume setting for the entire game that affects BGM, sound effects, voices, and movies. This can be set by the player from the "Master Volume" option in the "Volume Settings" in the top menu. "BGM Volume" and "SE Volume" allow for separate adjustments of BGM and sound effects, respectively. These can also be configured from the "Volume Settings" menu.

While these are values that the player can set, you can also adjust individual volumes within the script.

*start|Start

@bgmLakesideVillage fade=80

Play BGM at 80% volume.

@bgm fade=40

Set the BGM volume to 40%.

@bgm stop

@seRain loop

Stop the BGM and play a sound effect.

@seRain fade=50

Halve the sound effect volume.

@seRain fade=100

Restore the sound effect volume.

Individual volumes can be set for each playback using the "fade" attribute. Specifying 100 plays at the original volume, 50 at half volume, and 0 makes it silent. You cannot specify a number larger than 100. The volume can be changed whether it is at the start of playback or during playback.

The volume specified by the fade attribute is separate from "Master Volume," "BGM Volume," and "SE Volume." It specifies how much additional volume should be applied relative to those three settings established by the player. The actual volume at which BGM is played is the product of "Master Volume," "BGM Volume," and "Value specified by fade." If all three are at 100, the volume is 100 × 100 × 100 = 1,000,000. If all three are at 50, the volume is 50 × 50 × 50 = 125,000, which is 1/8th. Sound effects work exactly the same way, just using SE Volume instead of BGM Volume.

You don't need to worry about such complicated calculations in the script. Since "Master Volume," "BGM Volume," and "SE Volume" are values the player adjusts as they like, you only need to think about the value specified for the fade attribute. Setting fade=50 results in half the volume of the default fade=100. fade=10 is one-tenth.

*start|Start

@bgmLakesideVillage

Play BGM.

@bgm fade=50 time=2000

Halve the BGM volume with a 2-second fade.

@bgm stop

@seRain loop

Stop the BGM and play a sound effect.

@seRain fade=50 time=2000

Halve the sound effect volume with a 2-second fade.

@seRain fade=100 time=2000

Restore the sound effect volume with a 2-second fade.

By using the "fade" attribute together with the "time" attribute, you can change the volume with a fade instead of changing it abruptly.

*start|Start

@bgmLakesideVillage fade=50 time=2000 sync

Play BGM at half volume with a 2-second synchronous fade.

@bgm fade=100 time=2000 sync

Restore the BGM volume with a 2-second synchronous fade.

@bgm stop

@seRain fade=50 time=2000 sync

;Since "sync" is used at the start of sound effect playback, it syncs until playback ends.

Stop the BGM and play a sound effect with a 2-second synchronous fade.

@seRain loop

Play the sound effect loop.

@seRain fade=50 time=2000 sync

;Since "sync" is used during sound effect playback, it syncs until the fade ends.

Halved sound effect volume with a 2-second synchronous fade.

Fades using fade and time attributes can also be made synchronous by adding the sync attribute. The behavior in this case is the same as fade-in and fade-out. Specifically, for BGM, adding the sync attribute will pause script execution until the volume fade finishes. For sound effects, adding the sync attribute at the start of playback results in synchronous behavior until playback ends. Adding the sync attribute during an ongoing fade results in synchronous behavior until that fade ends.

One thing to note is that the value of the fade attribute is reset to 100 if the fade attribute is omitted in the next playback start. In @seRain loop, you might think it would play at half volume because fade=50 was specified in the preceding @seRain fade=50 time=2000 sync. However, since the playback ended once, the fade volume resets to 100. If you want to play it at 50 here as well, you must specify the fade attribute again, such as @seRain loop fade=50. Because having a value specified a long time ago persist can cause bugs, it is designed to reset to 100 at each playback start. This applies to BGM as well.

As a prerequisite, BGM and sound effects should have their volume balanced at the WAV file stage. The fade attribute is not a function meant to balance the volume levels between files. The default values for "Master Volume," "BGM Volume," and "SE Volume" (the values set when the game is first run) can also be configured in the development tools, so set those appropriately as well. Even if you balance the volume between files perfectly, if the overall game volume is too loud, the player will be startled by a blast of sound at startup. Conversely, if it's too quiet to hear, that's also a problem. Often, file volumes are adjusted so they sound right when "Master Volume," "BGM Volume," and "SE Volume" are all at 100. However, it's actually better to set all three initial values to "50" and adjust the WAV file volumes so they sound right at that level. This allows the player to make the volume either louder or quieter. If the initial setting is 100, they can only make it quieter, which can be inconvenient.

The proper place to use the fade attribute is when you need to change the volume dynamically within the game. "Dynamic" means that the behavior changes according to the situation. The antonym is "Static," which means the behavior does not change regardless of the situation.

Regarding games, elements that change based on player actions are dynamic elements. Things that don't change are static elements. Enemy characters in an action game are dynamic elements because they may or may not be defeated by the player. In-game terrain is a static element because it does not change. Nowadays, terrain can sometimes be destroyed, making it a dynamic element, but let's put that aside. The existence of dynamic elements is a characteristic of games compared to other media. Film is a completely static medium. Whether the audience is moved to tears or fast asleep, the content of the film does not change one bit.

Digital novels are sometimes called "static games" because they have fewer dynamic elements compared to other genres. Action games and the like are "dynamic games." However, dynamic elements do exist in digital novels. Typically, if something changes based on a choice, it is a dynamic element.

*start|Start

@seRain loop

Please select the volume.

@seladd text=50% target=*50percent

@seladd text=100% target=*100percent

@select

*50percent

@seRain fade=50

Volume set to 50%.

@next target=*start

*100percent

@seRain fade=100

Volume set to 100%.

@next target=*start

In the script above, the sound effect volume is changed based on the player's choice. In cases like this, it's more convenient to use the fade attribute than to prepare two separate files with different volumes. Even without direct choices, the volume might change based on a character's affection level or game progress.

The next example is a dynamic action based on a simple click by the player, rather than a choice.

*start|Start

@bgmLakesideVillage

Play BGM.

Playback in progress.

@bgm fade=50

Halve the volume.

Clicking after Playback in progress. advances to the next step where the volume is changed, but the exact part of the song where the volume changes varies dynamically depending on the timing of the player's click. It might be 5 seconds after the start, or 10 seconds. Since you can't prepare audio files for every possible case, you use the fade attribute to change the volume.

The fade attribute is not something meant to be used like "@seRain always uses fade=50." You should adjust that at the WAV file stage. Use the fade attribute only when it needs to be changed during the game. The same applies to panning, which is covered next. If a sound always moves from right to left, you should just create a WAV file that does that.

Regarding sound effects, you can specify panning (the direction the sound comes from) using the "pan" attribute. A positive value places it to the right, and a negative value places it to the left. The default is 0, and you can specify values from -100 to 100. Panning is currently only available for sound effects and cannot be used for BGM. It might be made available in the future.

*start|Start

@seRain loop

The sound effect plays.

@seRain pan=100 time=2000

Moving the sound to the right.

@seRain pan=-100 time=2000 sync

Moved the sound to the left.

@seRain pan=0 time=2000 sync

Returned to center.

The time attribute can also be used. The perceived direction of the sound will move toward the specified direction over the specified amount of time. You can also use the sync attribute for synchronous operation. The precautions are the same as for the fade attribute. The sync attribute at the start of playback results in synchronous operation until playback ends. The pan attribute is reset to 0 (not 100) at the start of the next playback.

The "canskip" attribute can be used with the synchronous sound operations introduced so far. Specifying false makes it impossible to skip the synchronous operation by clicking. The default is true, so they can be skipped.

Kirikiri comes with a development tool called "Loop Tuner." I will briefly explain how to use it. In addition to looping from start to finish, you can make it loop mid-track or place markers called labels in the music file.

"krkrlt.exe" in the tools folder is the Loop Tuner. Please try launching it. Select the file you want to configure from "Open" in the "File" menu. As an example, open "bgmLakesideVillage.ogg," which should be in the "bgm" folder of your project folder.

The black left-pointing triangle button on the right side of the menu plays the current file. The black square button stops playback.

The yellow downward-pointing triangle button in the middle of the menu creates a new label. If you click it, a yellow triangle should appear above the waveform at the bottom. That is a label. You can make as many as you like. You can change the position of a created label by dragging the yellow triangle above the waveform. You can also change the name by double-clicking it.

To create a link, press the button to the left of the new label button. A red arrow will appear at the very bottom. That is a link. The audio will loop at the linked point.

Created labels and links can be saved via the "Save" option in the "File" menu. Saving creates a file named "bgmLakesideVillage.ogg.sli" in the same folder as the .ogg file; this is the Loop Tuner data.

For detailed instructions on using Loop Tuner, please refer to the Kirikiri Reference documentation (http://devdoc.kikyou.info/tvp/docs/kr2doc/contents/LoopTuner.html). I use it based on intuition and habit, so I can't explain everything.

If there is someone handling the sound, it's best to leave it to them. They will likely be able to master it.

For now, since we want to use it as a sample, please save "LakesideVillage.ogg" after creating one link and one label named "Label 0."

Sound professionals might use more advanced specialized tools and specify loop positions by "sample count." In this case, you would directly modify the configuration file. Open "bgmLakesideVillage.ogg.sli" in the same folder as the .ogg file using a text editor.

Link { From=2504685; To=1525930; Smooth=False; Condition=no; RefValue=0; CondVar=0; }

The line is long and may wrap, but you should see a line like the one above. The number after "From=" is the sample count for the loop source, and the number after "To=" is the sample count for the loop destination. Here, change them to From=3112941; and To=1333418; and save. This will make it loop cleanly. You can verify if it's looping correctly by opening "bgmLakesideForest.ogg" in Loop Tuner again and playing it.

Files with the .sli extension where Loop Tuner settings are saved will be automatically loaded by Kirikiri during playback as long as they are placed in the same folder as the original music file.

*start|Start

@bgmLakesideVillage

Play BGM.

Even though it's just playing BGM, you can see that it loops indefinitely at the link position set in Loop Tuner.

*start|Start

@bgmLakesideVillage start=Label0

The sound effect plays.

By specifying the name of a label set in Loop Tuner in the "start" attribute, you can start playback from that label's position. This start attribute can also be used for sound effects if they have labels set.

It is no longer unusual for indie games to include voices. KAGEX comes with standard features for voice playback.

Please copy all files like "cvShiori_0001.ogg" from the "voice" folder in the sample materials into the "voice" folder of your project folder. Voice filenames follow the format "cv[CharacterName]_[4-digit Number]".

*start|Start

@Shiori voice=1

【Shiori】"Hello."

【Shiori】"This is a voice playback test."

If no name is attached, the voice won't play.

【Shiori】"The voice number automatically increases by one each time."

To play a voice, use the "char" tag. The char tag is used for general character operations, not just for sprites. Here, I'm using the shorthand notation where the character name is used as the tag name.

When you specify a voice number in the "voice" attribute, the file with that number will be played the next time 【Shiori】 displays a name. In 【Shiori】"Hello.", "cvShiori_0001" will play. For the next name display, the voice number increments by one automatically. "cvShiori_0002" will play during 【Shiori】"This is a voice playback test." and "cvShiori_0003" will play during 【Shiori】"The voice number automatically increases by one each time." automatically.

*start|Start

@Shiori voice=1

; cvShiori_0001 will play

【Shiori】"Hello."

@Kaede voice=1

; cvKaede_0001 will play

【Kaede】"Hello."

; cvShiori_0002 will play

【Shiori】"This is a voice playback test."

; cvKaede_0002 will play

【Kaede】"Voice numbers are managed per character."

; cvKaede_0003 will play

【Kaede】"They aren't affected by other characters' numbers."

Voice numbers are managed separately for each character. They play exactly as described in the comments. This remains the same even with three or more characters.

*start|Start

@Shiori voice=1

; cvShiori_0001 will play.

【Shiori/???】"Hello."

As discussed in the text display section, you can specify the actual displayed name after a forward slash. The name before the slash is used to determine which character's voice to play.

*start|Start

@Shiori voice=1

; cvShiori_0001 will play

【Shiori】"Hello."

@Shiori voice=5

; cvShiori_0005 will play

【Shiori】"You can change the number whenever you specify it."

@Shiori voice=Voice1

; Voice1 will play

【Shiori】"You can also specify it by filename."

; cvShiori_0006 will play

【Shiori】"Numbers aren't incremented on lines where a filename is specified."

If your voice file numbers are not sequential, specify the number in the voice attribute each time. Also, if there are additions to the voices or if a filename is unusual, you can specify that filename directly to play it.

*start|Start

@Shiori voice=1

; cvShiori_0001 will play

【Shiori】"Hello."

@Shiori voice=ignore

【Shiori】"No voice will play here."

; cvShiori_0002 will play

【Shiori】"This is a voice playback test."

If you specify "ignore" in the voice attribute, no voice will play the next time that character's name is displayed. It will resume playing normally after that.

*start|Start

@Shiori voice=1

; cvShiori_0001 will play

【Shiori】"Hello."

@Shiori voice=clear

【Shiori】"From now on, no voices will play for Shiori's lines."

【Shiori】"It won't play here either."

【Shiori】"No voice."

@Shiori voice=2

; cvShiori_0002 will play

【Shiori】"This is a voice playback test."

Specifying "clear" in the voice attribute stops voices from playing for all subsequent name displays for that character. You can resume voice playback by specifying a number in the voice attribute again.

*start|Start

@Shiori playvoice=2 nosync

; cvShiori_0002 will play

Playback can occur regardless of name display.

@Shiori playvoice=Voice1

; Voice1 will play

It can also be specified by filename.

@Shiori playvoice=3 waitvoice

; cvShiori_0003 will play synchronously

Voice played synchronously.

The voice attribute specifies which voice to play at the next name display, but the "playvoice" attribute allows you to play a voice file immediately. As with the voice attribute, it is specified by number or filename. You cannot use the sync attribute for synchronous playback with the playvoice attribute. Instead, use the "waitvoice" attribute.

If you just want to play audio, you could technically use @se play=cvShiori_0002 like a sound effect, but please use the voice or playvoice attributes for anything intended to be a character voice. If played as a sound effect, SE Volume will be applied instead of Voice Volume.

Voice volume is determined by "Master Volume," "Global Voice Volume," and "Individual Voice Volume." Master Volume is shared with BGM and sound effects. "Global Voice Volume" can be set from the "Voice Settings" menu. "Individual Voice Volume" is a volume setting per character. By default, it is not shown in the menu, but if character names are configured in the tools, it can be displayed in the "Voice Settings" menu.

*start|Start

@Shiori playvoice=Voice1

The voice plays.

@Shiori stopvoice

Forcibly stops the voice.

Using the "stopvoice" attribute allows you to forcibly stop a character's voice. In the script above, if you click to skip The voice plays. before the voice ends, the voice will stop mid-way.

Stepping away from voices for a moment, I will explain "Delayed Execution" here because it is often used alongside voices. Delayed execution allows you to delay the timing of a tag's execution.

*start|Start

@Shiori front middle uniform poseB expressionless

Displays the character sprite.

@Shiori left

@Shiori smile delayrun=2000

The character's expression will change.

The "delayrun" attribute can be used with "stage," "char," "event," "layer," "env," "bgm," and "se" tags. All tags are executed in order from top to bottom, but by specifying a time in milliseconds in the "delayrun" attribute, you can shift the timing when that effect occurs. With @Shiori left, the sprite moves left immediately, but with @Shiori smile delayrun=2000, the expression changes after 2 seconds. A tag with the delayrun attribute appears to be ignored at the place it is written and its effect does not appear until the specified time has elapsed.

*start|Start

@layer name=Star1 file=Star show

Displays the star.

@Star1 xpos=300 time=3000

@Star1 opacity=0 time=1000 delayrun=2000

The star will start to disappear after 2 seconds.

Delayed execution is not limited to expression changes. In the script above, the tag @Star1 opacity=0 time=1000 is executed 2 seconds later due to the delayrun attribute. As a result, the star becomes transparent over the course of 1 second, starting 2 seconds after the line was processed.

*start|Start

@Shiori front middle uniform poseB expressionless

Displays the character sprite.

@Shiori left

@Shiori right delayrun=10000 sync

Moving the sprite to the right after 10 seconds.

Delayed execution is cancelled by advancing the page.

Asynchronous actions and transitions without the nowait attribute are cancelled by advancing the page, and delayed execution is the same. It immediately jumps to the state as if the delayed execution had finished. Since the nowait attribute cannot be used with delayed execution, it will always be cancelled. Furthermore, delayed execution cannot be made into a synchronous operation with the sync attribute; it is always asynchronous.

*start|Start

@Shiori front middle uniform poseB expressionless

Displays the character sprite.

@Shiori voice=10

@Shiori poseA smile delayrun=Label0

【Shiori】"Tags can be executed in sync with the voice."

By specifying a voice file label name in the delayrun attribute, you can execute tags in sync with its playback. If you open "cvShiori_0010.ogg" in Loop Tuner, you'll see a label named "Label0" inserted just before the word "Tags" in the sentence "Tags can be executed in sync with the voice." When the voice reaches that point in playback, @Shiori poseA smile will be executed. By placing multiple labels, you can have as many delayed executions as you like within a single line. If the page is advanced before the voice reaches the specified label position, the delayed execution is cancelled, just as when a time is specified.

The most common use for delayed execution is probably changing expressions or executing actions in sync with the voice playback, as introduced last. It is convenient, but using delayed execution significantly increases the workload for scripting, so be prepared. If you run out of energy halfway through, you might end up with a game where the first half is very dynamic while the second half feels somewhat underwhelming.

Clicking "Loop Tuner" in the "Debug" menu opens the last played voice file in Loop Tuner. You can also open it with the "Shift+C" shortcut. Using this makes it easier to add labels to voice files. It is faster to advance the game to the scene where the voice is used and press Shift+C than to search for the desired file among a massive amount of voice files.

In actual scripting work, changing character sprite expressions often accounts for the bulk of the task. Usually, you prepare a script where text and voice numbers are already specified, and then you add voice labels and edit the script while running it. In this case, saving just before the part you are editing is convenient because you can check the behavior by simply loading instead of restarting the game. When loading, it reads the script at the load point, which you can use to load your edited script. Note that if label positions differ between the pre-edit and post-edit versions, things might break, requiring you to restart the game and save again.

Using the "Sprite Reference Window" from the "Debug" menu makes things a bit more convenient because you can work while viewing the combinations of sprite expressions. If you close the smaller "Sprite Change" window, you can reopen it from "Show Sub-window" in the "File" menu. You'll probably figure out how to use it as you play around with it.

As you open the game window, KAGEX log, Sprite Reference Window, Sprite Change Window, Loop Tuner, and text editor, the number of windows will keep growing. In addition to these, you might also have the console, image editing software, and Excel file name mapping tables open. Close Twitter and Skype while you're working. Well, if you want to do this properly, one monitor isn't enough. I recommend dual monitors. As of writing, I have two, but I plan to get three or more once I have the money. It's also a good idea to print out whatever can be printed and stick it next to your monitor.

  1. Message Operation Scripts

This section introduces scripts related to text display, such as changing text positions or displaying images as text frames.

*start|Start

@Town Day

@Shiori front middle uniform poseB expressionless

Displays background and character sprite.

@position layer=message0 page=fore left=100 top=100 width=600 height=400 color=&RGB(0,0,0) opacity=127

; This is wrapped because it's long, but please write it on one line.

Changed the position of the message layer.

The position and size of the message layer can be changed with the "position" tag. Use the "layer" and "page" attributes to specify which message layer's settings to change. For the layer attribute, specify the message layer number. You can use multiple message layers, but since we've been using number 0 so far, we use layer=message0. The number must always be preceded by "message." For the page attribute, specify "fore" for the foreground page and "back" for the background page. Message layers have "foreground" and "background" pages, which will be discussed later. For now, we'll use page=fore.

Specify the horizontal and vertical positions of the message layer in the "left" and "top" attributes, respectively. These are the number of pixels from the top-left corner of the window. In the "width" and "height" attributes, specify the size of the message layer in pixels.

The "color" attribute is used to specify the color of the message layer in the format color=&RGB(Red,Green,Blue). Specify the intensity of each color from 0 to 255. Here, color=&RGB(0,0,0) makes it pure black. The "opacity" attribute sets the opacity of the layer. Like the opacity attribute used for sprites, it ranges from 0 to 255. Here, opacity=127 makes it semi-transparent.

*start|Start

@Town Day

@Shiori front middle uniform poseB expressionless

@position layer=message0 page=fore left=100 top=100 width=600 height=400 color=&RGB(0,0,0) opacity=128 marginl=100 margint=100 marginr=100 marginb=100

Changed the position of the message layer.

The "marginl," "margint," "marginr," and "marginb" attributes specify the text display position within the message layer. By specifying the left, top, right, and bottom margins in pixels, you determine the position of the text. The text will be displayed inside those margins.

In the script above, the text will be displayed inside the red frame in the image on the right. There is space for one character on the right side of the text, which is an allowance for word-wrapping (kinsoku shori).

*start|Start

@White

@position layer=message0 page=fore left=100 top=100 width=600 height=400 color=&RGB(0,0,0) opacity=128 marginl=100 margint=100 marginr=100 marginb=100 nameleft=50 nametop=50 namewidth=200 nameheight=50

【Shiori】"Changed the position of the message layer."

The "nameleft" and "nametop" attributes specify the horizontal and vertical positions of the name box, respectively. These are pixels from the top-left corner of the message layer. The "namewidth" and "nameheight" attributes specify the size of the name box in pixels.

It's small and hard to see, but the name will be displayed inside the red frame in the image on the right.

*start|Start

@White

@position layer=message0 page=fore left=100 top=100 width=600 height=400 color=&RGB(0,0,0) opacity=128 marginl=100 margint=100 marginr=100 marginb=100 nameleft=50 nametop=50 namewidth=200 nameheight=50 namealign=0 namevalign=1

【Shiori】"Changed the position of the message layer."

The "namealign" and "namevalign" attributes specify where within the name box the name is displayed. namealign is the horizontal position: "-1" for left-aligned, "0" for centered, and "1" for right-aligned. namevalign is the vertical position: "-1" for top-aligned, "0" for centered, and "1" for bottom-aligned. In the script above, namealign=0 namevalign=-1 centers it horizontally and aligns it to the bottom vertically.

PC monitors use a method called "Additive Color Mixing" (RGB Color), which expresses all colors by combining red, green, and blue light. Red, Green, and Blue each have 256 levels from 0 to 255, allowing for a maximum of 256 × 256 × 256 = 16,777,216 colors. This is the "approximately 17 million colors" you often hear about.

The larger each number, the stronger that color's light. If (Red, Green, Blue) are (255, 0, 0), it's red; (0, 255, 0) is green; and (0, 0, 255) is blue. Setting all light intensities to the maximum with (255, 255, 255) results in white. For more details, look up additive color mixing.

For message layers, the color attribute isn't used much because it's more common to specify a text frame image instead.

While the color attribute of the position tag can only display a solid-colored rectangular message layer, using an image allows you to display any shape and color you like for the message layer.

Let's try displaying "message.png" from the sample uiimage folder. Copy it into the "uiimage" folder of your project folder.

*start|Start

@Town Day

@position layer=message0 page=fore frame=message opacity=255 left=0 top=400 marginl=60 margint=50 marginr=60 marginb=40 nameleft=60 nametop=0 namewidth=156 nameheight=37 namealign=0 namevalign=0

【Shiori】"Changed the message layer image."

When using an image, specify the image filename in the "frame" attribute instead of the color attribute. Since message.png is already semi-transparent, the opacity attribute is set to 255 to make it opaque (fully utilizing the image's transparency).

While the layer's position is specified with the left and top attributes, specifying the size with width and height is not necessary. The message layer will automatically be the same size as the image specified in the frame attribute. Text positions and name box positions are specified in the same way as when not using an image. The script above specifies them as shown in the image on the right.

*start|Start

@Town Day

Displays the background.

@msgoff

@msgon

Temporarily cleared the message layer.

@msgoff fade=1000

@msgon trans=scroll time=1000 from=top stay=nostay

Temporarily cleared the message layer.

The "msgoff" tag can be used to hide the message layer. A hidden message layer can be shown again with the "msgon" tag.

You can also specify transitions in msgoff and msgon tags using the trans or fade attributes. These transitions are always synchronous, and the nosync attribute cannot be used. If the transition specification is omitted, like in @msgoff, it defaults to a crossfade transition using the time specified in fadeValue, as introduced in the automatic transitions section.

*start|Start

@Town Day

Displays the background.

@msgoff

Temporarily cleared the message layer.

In the case of Temporarily cleared the message layer., the script is trying to display text while the message layer is hidden. In such cases, @msgon is automatically executed right before the text is displayed, causing the message layer to appear.

The message layer is hidden before the first line of text is displayed. Therefore, even before Displays the background., @msgon is automatically executed, causing the message layer to appear with a transition.

*start|Start

@Town Day

Displays the background.

@position layer=message0 page=fore visible=false

Temporarily cleared the message layer without a transition.

@msgoff and @msgon automatically perform crossfade transitions. If you want to clear the message layer without a transition, use the "visible" attribute of the position tag. Specifying true shows it, while false hides it.

*start|Start

@Town Day

Displays the background.

@Sunset trans=crossfade time=1000 msgoff

Time changes.

@Shiori front middle uniform poseB expressionless trans=crossfade time=500 msgoff

【Shiori】"Displays the character sprite."

Although not mentioned in the transitions section, the "msgoff" attribute can be used along with transitions via the trans attribute. Setting this attribute to true causes the message layer to be automatically hidden immediately before the transition. @Sunset trans=crossfade time=1000 msgoff behaves the same as writing @msgoff and @Sunset trans=crossfade time=1000 on separate lines. @Shiori front middle uniform poseB expressionless trans=crossfade time=500 msgoff can similarly be written as two separate lines.

In actual scripting, rather than using the msgoff attribute directly each time, it is convenient to use it when defining automatic transitions to create an effect where the message layer is always hidden when changing backgrounds.

■Afterword

I'm wrapping this up on a somewhat abrupt note, having run out of time. It's currently past 10 PM on December 30th, the day before distribution.

I initially started writing this for beginners, but halfway through, it became a bit of a mess and started heading in an unfortunate direction. You might find some excuses regarding that on my blog or Twitter. I'd like to make my case here as well, but I'll restrain myself. I hope to release something more complete for the next Summer Comiket.

While I haven't prepared it yet, I will release the SDK used in this book after Winter Comiket. I'll manage it within a week at the latest. That will likely include a supplement in the form of a manual, so please check that out. As mentioned somewhere in the text, the support webpage for this book is http://biscrat.com/book/kagex/support/.

In the next chapter, I'm making a major shift in direction to pack in some information that might be useful for KAG users when using KAGEX. I'll write down everything I can think of that might be even slightly helpful. Since I'm starting from scratch now, it might get messy, so please bear with me.

  1. Appendix
    • About Objects

Near the beginning of the main text, I used the stage, char, layer, and event tags directly, but please don't actually use them that way. You will almost certainly use shorthand notation instead. I tried to be thorough to explain the tags to beginners, but looking back now, that was a mistake.

I introduced those as "tags for displaying images" for the sake of simplicity. In reality, stage is for the stage object, char is for the character object, layer is for the environment layer object, and event is for operating event objects. Additionally, env is for environment objects, bgm is for BGM objects, and se is for sound effect objects.

KAGEX organizes concepts used in digital novels as "objects." In KAG, it was more low-level from a system perspective, where you handled layers directly using the image tag. You don't do that in KAGEX.

Characters are a particularly clear example; a character object that can be controlled with the char tag bundles together all the operations necessary for a character. Sprite display, voice playback, expression image display, and more can all be handled with a single char tag. Internally, it manages multiple layers and playback buffers, making it a much higher-level implementation compared to primitive KAG operations.

By the way, "low-level" and "high-level" are terms used in a programming sense. A low-level process means you can do a lot, but you have to do everything yourself, whereas a high-level process means its purpose is specialized but you can easily use convenient features.

Regarding character sprites, I only ended up covering sprites with pre-combined expressions. Once a project gets larger, expressions are usually separated. Since an explanation of that should be included with the development tools, please refer to those.

I wasn't able to explain action definitions in the main text, but upon looking into it properly this time, I found it much more complex than expected and skipped the explanation. I believe an explanation for this will also be included in the development tools.

The explanations in the main text are almost entirely about the scenario script part. When using KAGEX, it's easier to think about the "scenario script" for the main game and the "system script" for the title screen, save/load screens, and option screens separately. The system script was supposed to be covered in a later chapter, but it was cut.

Actually, the knowledge explained in the main text is enough for scenario scripts. Within a scenario, you mostly just display text, change a character's outfit or expression, and occasionally play sound effects or BGM. You can make a game knowing just that.

I didn't explain macros in the main text, but the core parts of KAGEX already have everything necessary. I've made several games with KAGEX and hardly ever use macros.

If I do use macros, it's just for standard effects like a flash at the end of a scene.

It is convenient to turn @endtrans into a macro. While you can register automatic transitions for sprite or background switches, automatic transitions cannot be defined for @endtrans.

@macro name=et

@endtrans BackgroundTransition *

@endmacro

Even something as simple as this works. Using @et instead of @endtrans allows you to use "BackgroundTransition" like an automatic transition.

Please define macros in "macro.ks" within the "sysinit" folder. As you can see if you take a quick look at "first.ks," it contains @call storage=macro.ks. Some beginners in KAG read macro definition scripts multiple times, but macro.ks is already prepared as a dedicated script file that is only read once immediately after startup.

While scenario scripts are very simple, they require system scripts as a preceding step. This is a barrier when transitioning from KAG. Originally, you would define the contents of stage objects and character objects in a file called "envinit.tjs" using TJS dictionary arrays. Because this is complex, it might give the impression that KAGEX is difficult. In reality, it's not that bad, but the complete lack of references makes it a sticking point at first.

In this book, I wrote envinit.otjs instead of envinit.tjs. Writing that is similar to writing config.tjs and is much simpler than writing envinit.tjs directly. Even so, it's still tedious, so I plan to make it possible via tools. Please refer to the manual when the SDK is released.

As another simplification in this book, I have fixed the naming format for images like backgrounds and sprites. Originally, not having defined these naming rules added to the barrier for beginners. Things like this should be fixed. If you use the SDK, it's fine as long as you follow the rules written in the main text. I used autosetting.bat a few times in the main text; it searches for files and converts them into envinit.tjs.

Kirikiri/KAGEX Course

~Digital Novel Production~

Date of Issue December 31, 2011 First Edition

Author sakano

Email sakano@biscrat.com

Tel 080-5095-02037

Web http://biscrat.com/

Twitter http://twitter.com/kasekey/

We look forward to your opinions and feedback.

Copyright (C) 2011 Biscrat.