Skip to content

Drama โ€‹

A drama is the rich dialog that usually has options and additional actions.

Routing โ€‹

To give character a default drama, place id.xlsx in LangMod/**/Dialog/Drama/, using the character's ID as the file name (e.g., tinymita.xlsx for tinymita).

To use a different drama file, add the tag addDrama(DramaFileId) to the character's source row.

You can also use C# API chara.SetDramaOverride(DramaFileId) or chara.ShowDialog(DramaId, step).

Refer to the game sheets in Elin/Package/_Elona/Lang/_Dialog/Drama when making new drama sheets, or download the Tiny Mita example for a template.

Hot Reload

Drama sheets can be edited during gameplay. Changes apply automatically next time the dialog opens.

Definition โ€‹

Line โ€‹

A drama sheet is read top to bottom and consists of multiple lines. Each line has these fields (defined in the first row):

  • step: Marks the start of a step; all following lines belong to this step until another step appears.
  • jump: The step to jump to after this line runs.
  • if / if2: Conditions to check before execution. If if2 is present, both must be true.
  • action: The action to perform.
  • param: Parameter for the action.
  • actor: The speaker for the action or talk line.
    • ?: ???.
    • tg: Target drama character. Default when actor is blank.
    • narrator: Default narrator.
    • pc: Player.
  • id: Unique ID, required for text and choice lines. Not needed for other lines.
  • text_XX / text_JP / text_EN / text: Dialogue content. XX is a language code (e.g., text_CN, text_ZHTW). text is the fallback if a non-builtin language is missing. text_JP and text_EN is required, but you don't have to provide translations.

(Click to zoom) img

Step โ€‹

Drama flow is organized into steps. Each step contains one or many lines, which can include dialogue, actions, and conditions.

main is the default starting step, and end exits the drama.

When creating a sheet, avoid creating step names starting with _ or flag to prevent conflicts with internal steps.

Builtin Steps

After executing inject/Unique action, a lot of builtin drama steps will be injected into the drama sheet. To use them, simply set them as the jump target. Some steps are already used in the default inject/Unique dialogues and you usually do not need to re-use them on your own.

step nameusage
_banishEnd the drama
_byeEnd the drama
_toggleSharedEquipToggle tg shared equipment usage
_daMakeMaidSet tg as maid
_joinPartyIf tg trait is joinable, set as party member. THIS IS NOT INVITING
_leavePartyRemove tg from party, and sent to home zone
_makeLivestockSet tg as faction livestock
_makeResidentSet tg as faction resident
_departRemove tg from faction
_rumorRumor
_sleepBesideToggle tg sleep beside player state
_disableLoyalToggle tg loyal state
_sucktg sucks pc. Prioritizes blood sucking over cat huffing
_insultToggle tg taunt state
_makeHomeSet current zone branch as tg home branch
_inviteTry inviting tg as ally, checks player attributes and tg invitable state. To unconditionally invite as ally, use expanded action join_party()
_GuideGuide player to a list of locations
_tailHave sex, for money
_whoreHave sex, cost money
_bloomDeepen bond with tg
_buyBuy stuff from tg
_buyPlanBuy research plan from tg
_giveGive stuff to tg
_blessingBlessing upon party
_trainTrain skills with tg
_changeDomainChange tg domain
_reviveRevive dead allies
_buySlaveBuy slave from tg
_tradeTrade items with tg
_identifyIdentify items with tg
_identifyAllIdentify all items with tg
_identifySPIdentify items with tg using superior skill
_boutChallenge to a duel
_newsSpawn a random dungeon on map
_healHeal the player
_foodBuy some food from tg
_depositDeposit with tg
_withdrawWithdraw with tg
_copyItemDuplicate item with tg
_extraTaxPay additional tax
_upgradeHearthUpgrade hearth stone
_sellFameSell fame
_investZoneInvest current zone
_investShopInvest tg barter shop
_changeTitleChange player title
_buyLandExpand current zone map
_disableMoveSet tg to not move
_enableMoveSet tg can move

Actions โ€‹

Text lines are the most common. They only have id, text columns, and optionally if condition. When executed, text lines require player input (click or key press) to advance.

Action lines (except choice) execute automatically without input. If both action and text are present, text is generally ignored.

For example, an action line placed after a text line won't execute until the text line is clicked to advance.

Builtin Actions
actionparamdescription
injectUniqueInsert "Let's Talk" and a lot of useful steps
choiceAdd a choice to the last text line. Requires text and jump
choice/byeInsert a default bye choice
cancelSet right click / escape key behavior. Requires jump, usually set to end
setFlagflag name,value(optional)Set a flag with value or default 1 if not provided
reloadReload the drama so any flag changes made in the current drama can be applied. Requires jump, usually set to main. Don't confuse this with hot reload during development - for that you only need to save the changes and it will be reloaded next time you start the drama
enableToneEnable dialog tone for the entire drama
addActorAdd a drama actor to use later, text can be used to set a name override. This is done automatically when you fill in new id in actor cell. Requires character id in actor
invokemethod nameCall a method. All of them are hardcoded for specific use.
setBGimage name(optional)Set an image as background or use empty to clear it. Can be provided Texture folder
BGMBGM idSwitch the BGM to specific one by id. Check the Sound & BGM page for custom BGM
stopBGMStop the BGM and do not continue
lastBGMStop the BGM and continue the last one played
soundsound idPlay a sound by id. Check the Sound & BGM page for custom sounds
waitdurationPause the execution in this line for seconds, good to use when you want the animation or stuff to finish
alphaIn alphaOutdurationAlpha transition(transparency) in seconds
alphaInOutduration,wait timealphaIn first, wait in seconds, then alphaOut
fadeIn fadeOutduration,white/black(optional)Fade transition in seconds
fadeInOutduration,wait time,white/black(optional)fadeIn first, wait in seconds, then fadeOut
hideUItransitionHide the HUD elements with a transition in seconds. Restored when exiting drama
hideDialogHide the drama dialog so you can do cutscenes, however text lines force show dialogs, so you need to combine this with wait
endExplicitly end the drama. Same as jump to drama step end
addKeyItemkeyitem idAdd keyitem with id to the player
dropitem idDrop an item as reward at player's position
addResourceresource name,countAdd home resource by count
shakeShake the screen
slapSlap the drama owner character
destroyItemitem idFind and destroy the item with id from player's inventory
focusImmediately move and focus camera to the drama owner character
focusCharacharacter id,speed(optional)Move and focus camera to the character with id on the same map
focusPCspeed(optional)Move and focus camera to the player
unfocusReset and unfocus camera
destroycharacter idDestroy a character with id on the same map
saveSave game
setHourhourSet the game time in hours

When providing multiple parameters, they are separated by comma(,) with no spaces in between.

Text โ€‹

Substitutions โ€‹

textvalue
#tg_histg's possessive pronoun
#tg_himtg's object pronoun
#tgtg character name
#last_choicetext of the last choice
#newlinenewline character
#costHirecost to hire tg (number, localized)
#self / #mefull name of character tg (including title)
#histg's possessive pronoun
#himtg's object pronoun
#1 ~ #5external variables refDrama1 ~ refDrama5 (number auto-formatted)
#godname of the god (if tg is not empty, uses its faith; otherwise random religion)
#player / #titleplayer's title
#zonecurrent zone name
#guild_titletitle of the guild associated with the current plot
#guildname of the guild in the current plot
#raceplayer's race name
#pcplayer's short name
#pc_fullplayer's full name (including title)
#pc_hisplayer's possessive pronoun
#pc_himplayer's object pronoun
#pc_raceplayer's race
#akaplayer's alias
#bigdaddylocalized string "bigdaddy"
#festivalfestival name (if the zone has a festival, use its name; otherwise generic)
#brother2"brother" or "sister" (based on player gender)
#brotherrandom term for brother/sister (randomly from bro or sis list)
#onii2random term for older brother/sister (from onii2/onee2 lists)
#oniirandom term for older brother/sister (from onii/onee lists)
#genderrandom term based on player gender (from gendersDrama list)
#he"he" or "she" (based on player gender)
#Hesame as above, but with initial capital letter

Dynamic Content โ€‹

Text columns starting with #eval <C# script here..> that returns a string can evaluate text content dynamically.

Conditions โ€‹

Conditions determine whether the line should be executed or not.

Static Conditions โ€‹

Static conditions are evaluated once on load.

Attach conditions to any line using the if (and optionally if2) column.

ConditionParamDescription
hasFlagflag namePlayer has flag and value โ‰  0
!hasFlagflag namePlayer doesnโ€™t have flag or value = 0
hasMelilithCurseโ€”Player has Melilith curse
merchantโ€”Player is at Merchant Guild
fighterโ€”Player is at Fighter Guild
thiefโ€”Player is at Thief Guild
mageโ€”Player is at Mage Guild
hasItemitem idPlayer has the item in inventory
isCompletedquest idPlayer has completed the quest

Simple value checks (most common for flags/counters):

=,example_flag,1
>,example_counter,20
!,example_flag,69

Most lines only need the if column. Add an if2 column if you need multiple conditions.

Dynamic Conditions โ€‹

To enable/disable a line dynamically, use:

  • invoke* condition expression, or
  • eval action that returns a bool

Branching โ€‹

Set jump to a drama step to branch into that step.

Set jump to eval_result and use an eval action that returns a string to dynamically choose the jump target.

Invoke* Expression โ€‹

In the drama sheet, a special action invoke* (or i* for short) can be used to call expansion methods:

Syntax โ€‹

The pseudocode syntax is simple, set action to invoke* or i*, and param to one of the valid methods:

actionparamactor
invoke*/i*honk_honk(arg1, arg2)pc

This invokes a method called honk_honk with 2 parameters, arg1 and arg2.

Parameter โ€‹

Parameters are separated by comma , and written within the parentheses of the expansion method, similar to code syntax. If there're no parameters, use empty () parentheses.

Most of the methods also take actor cell as the target character to execute the method on, such as pc or tg(the drama target character), or any valid character id. Default is tg.

If the jump in the same line has any value, then the return value of the expansion method will be used to determine if the jump can be executed. Returns true will execute the jump, otherwise not.

Value Expression Syntax โ€‹

DramaValueExpression is used to evaluate or assign values.

Examples:

ExpressionMeaning
69Assign value 69
=69Assign value 69
+5Increase original value by 5
-3Decrease original value by 3
*10Multiply original value by 10
/2Divide original value by 2
==69Check if equal to 69
!=114Check if not equal to 114
>10Check if greater than 10
>=20Check if greater than or equal to 20
<5Check if less than 5
<=3Check if less than or equal to 3

Expanded Actions โ€‹

methodparamdescriptionjump
add_itemitem id, material alias(optional), level(optional), count(optional)Add the item with id to actor, default random material, auto level, and count of 1always
equip_itemitem id, material alias(optional), level(optional)Equip the item with id on actor, default random material, auto levelalways
destroy_itemitem id, count(optional)Destroy items with id on actor, default of 1always
join_faithreligion id(optional)Make actor join the specific religion with id or leave the current religion with empty religion idIf success
join_partyMake actor join player party unconditionallyalways
apply_conditioncondition alias, powerApply a condition with id to actor, default power 100always
remove_conditioncondition aliasRemove the condition on actoralways

Expanded Scene Play โ€‹

methodparamdescriptionjump
move_next_tocharacter idMove actor next to the character with id on the same mapalways
move_tilex offset, y offsetMove actor with the relative tile offset, such as 1, 1 or 2, -1always
move_tox, yMove actor to the absolute tile position on the map, such as 64, 44 or 12, 0always
move_zonezone id, level(optional)Move actor to a specific zone with id, and specific level, default level 0if success
move_zone_2zone full nameMove actor to a specific zone using zone full name syntax, such as derphy@-1if success
play_animeanime idPlay animation on actoralways
play_effecteffect idPlay effect on actoralways
play_effect_ateffect id, x, yPlay effect at tile position on the mapalways
play_emoteemote idPlay emote on actoralways
play_screen_effectscreen effect idPlay screen effectalways
pop_texttextPop a text bubble above actor headalways
set_portraitportrait id(optional)Set actor portrait used during dialog to a specific one or reset with empty id, from Portrait folder, e.g. UN_myChara_happy.png could be set with happy or UN_myChara_happyalways
set_portrait_overrideportrait id(optional)Set actor portrait used outside of dialog to a specific one or reset with empty id, from Portrait folder. Must be full id. This does not affect current dialog portrait(as changed above)always
set_spritetexture id(optional)Set the custom sprite override for actor or reset with empty id, from Texture folderalways
show_bookcategory/book idOpen a book, supports LangMod/**/Text folder, for example, use Book/ok for Text/Book/ok.txtIf success

Expanded Modifications โ€‹

methodparamdescriptionjump
mod_affinityvalue expressionModify actor affinity with value expressionIf success
mod_currencycurrency type, value expressionModify actor currency with value expression. money money2 plat medal influence casino_coin ecopoalways
mod_elementelement alias, power(optional)Modifies a specified element (feat/resistance/skill, etc.) for the actor, default power 1. Different types of elements use different power scalingalways
mod_element_expelement alias, value expressionModifies the exp of a specified element for the actorIf success
mod_famevalue expressionModify player fame with value expressionalways
mod_flagflag, value expressionModify the flag value from actor with value expression, such as +1, =1, 0. This supports non player characteralways
mod_keyitemkeyitem alias, value expression(optional)Modify player's keyitem value with expression, default =1If success

Expanded Conditions โ€‹

These are still expansion methods that uses invoke* action same as above, but their return value is important.

methodparamdescriptionjump
if_affinityvalue expressionCheck actor affinity with expression, such as <5, >=90, !=0If satisfies
if_conditioncondition aliasCheck if actor has active condition with aliasIf active
if_currencycurrency type, value expressionCheck actor currency with value expression. money money2 plat medal influence casino_coin ecopoIf satisfies
if_elementelement alias, value expressionCheck actor element with expressionIf satisfies
if_faithreligion id, reward rank(optional)Check if actor is certain religion and above reward rank, default >0If satisfies
if_famevalue expressionCheck player's fame with value expressionIf satisfies
if_flagflag name, value expressionCheck actor flag value with expression, such as =5, 1, !=0If satisfies
if_lvvalue expressionCheck actor level with value expressionIf satisfies
if_has_itemitem id, value expression(optional)Checks if actor possesses a quantity of the item that meets the expression, default >=1If satisfies
if_hostilityhostility value expressionChecks if actor meets a specific hostility, such as =Ally or >Enemy. Value in ascending order: Enemy, Neutral, Friend, AllyIf satisfies
if_in_partytrue or false(optional)Check if actor is in player's party, default to trueIf satisfies
if_keyitemkeyitem alias, value expression(optional)Check if player has keyitem with expression, default >0If satisfies
if_racerace idCheck if actor is of certain raceIf satisfies
if_tagtagCheck if actor has certain tag defined in Chara rowIf defined
if_zonezone id, level(optional)Check if actor is in certain zone and optionally check levelIf present
if_zone_2zone full nameCheck if actor is in certain zone with zone full name syntax, such as derphy@-1If present

Special Methods โ€‹

methodparamdescriptionjump
console_cmdcmd param1 param2...Run console commandalways
evalC# script or file with <<<path.cs syntaxExecute the C# script. It's recommended to use eval action (instead of invoke* with eval())If returns true
andand(if_flag(flag1, >0), if_flag(flag2, <0)...)Take invoke* expressions as parameters, evaluates all of themIf all satisfies
oror(if_race(lich), if_race(snail)...)Take invoke* expressions as parameters, evaluates all of themIf any satisfies
notnot(if_zone(dungeon), if_zone(field), if_zone(underground)...)Take invoke* expressions as parameters, evaluates all of themIf none satisfies

API โ€‹

Elin offers easy API to add custom expansion methods from your own script DLL.

Action Parser โ€‹

Parsers are called on registered action lines that isn't builtin during drama loading, and are responsible for creating events.

cs
[ElinDramaActionParser("my_action")]
public static bool ExampleParser(DramaManager dm, Dictionary<string, string> line) 
{
    dm.AddEvent(new DramaEventTalk(line["actor"], () => {
        // processing
        return "A text line!";
    }));
    // this line is handled
    return true;
}
// or register manually
CustomDramaExpansion.AddDramaActionParser("my_action", ExampleParser);

Action Invoke โ€‹

Invokes are automatically compiled into invoke* expressions and are called when the line is executed during drama play.

cs
[ElinDramaActionInvoke]
public static bool add_item(DramaManager dm, Dictionary<string, string> line,
                            string itemId,
                            string materialAlias = "wood",
                            int lv = -1,
                            int count = 1)
{
    var chara = dm.GetChara(line["actor"]);

    var mat = sources.materials.alias.TryGetValue(materialAlias, "wood");
    var item = ThingGen.Create(itemId, mat.id, lv).SetNum(count);
    chara.Pick(item);

    return true;
}

[ElinDramaActionInvoke("nodiscard")]
public static bool if_element(DramaManager dm, Dictionary<string, string> line,
                              string elementAlias,
                              DramaValueExpression expr) 
{
    var chara = dm.GetChara(line["actor"]);
    return chara.HasElement(elementAlias) && expr.Compare(chara.Evalue(elementAlias));
}
cs
[ElinDramaActionInvoke]
public static bool console_cmd(DramaManager dm, Dictionary<string, string> line, 
                               params string[] parameters)
{
    string.Join(' ', parameters).EvaluateAsCommand();
    return true;
}

Drama invoke methods must be static, return bool, and paramters start with DramaManager dm, Dictionary<string, string> line.

The actual expression parameters can be auto converted by Elin, or passed as string[]. Auto convertable parameters can be any builtin data types, DramaValueExpression, or custom types with static bool TryParse(string, out T) method.

See CustomDramaExpansion implementation for example usages.

Scripting โ€‹

You can run C# code directly in a drama sheet using the eval action.

It offers the same scripting capabilities as regular C#, with these differences:

  • Script state is tied to the current drama instance (persists until the drama ends, then auto-resets).
  • Shortcuts: dm = DramaManager, line = current line Dictionary<string, string>, tg = target Chara, pc = player Chara.

Return value behavior:

  • bool + valid jump target โ†’ determines whether to jump.
  • string + jump cell set to eval_result โ†’ uses the string as the new jump target.
  • No return value โ†’ treated as a simple action.

Import a script file from the same folder with: <<<script_snippet.cs

Passing Variables โ€‹

Use the shared Script dictionary:

cs
// First eval
var value = EClass.rnd(100) * 5;
Script["random_value"] = value;

// Later eval
var value = (int)Script["random_value"];

Common Examples โ€‹

FunctionCode
Jump to stepdm.Goto("my_new_step");
Add "Let's chat!" optiondm.InjectUniqueRumor();
Add temporary talkdm.AddTempTalk("topic", "actor", "jump");
Get Chara instancevar chara = dm.GetChara("tg");
Recruit to partychara.MakeAlly();
Modify levelchara.SetLv(chara.LV + 5);

Need help? Ask on Elona Discord: @freshcloth or reach via email.

This project is an unofficial documentation site and is not affiliated with, endorsed by, or associated with Elin or Lafrontier / Noa. All trademarks are the property of their respective owners.