Dynamic Subtitles Tool
This code is over 6 months old. The code may have expired and might no longer function.
It is highly recommended that you use the workshop.codes editor to integrate this into your gamemode!
- Automatic variables prevent variable conflicts
- Mixins will simplify subtitle calls in your code
Join my Discord for help and discussions.
This is a tool that adds dynamic subtitles to the viewer's screen, with an optional hero speech sound effect. The import code in this post contains a simple demo. To add it to your code, create a new empty file (if you are using the website editor) and paste the code below into it. It currently uses 1 global variable, 3 player variables and 1 subroutine.
rule("[DS] Initialize")
{
event
{
Ongoing - Global;
}
actions
{
Global.dsGlobals[0] = Workshop Setting Integer(Custom String("Dynamic Subtitles"), Custom String("Subtitle speed (chars/second)"), 30, 5, 63, 0);
Global.dsGlobals[1] = Workshop Setting Toggle(Custom String("Dynamic Subtitles"), Custom String("Hero speech sound effects (uses a dummy bot)"), True, 1);
Create HUD Text(All Players(All Teams), Null, Null, Custom String(" \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n "),
Top, 0.1, Null, Null, Null, Visible To, Default Visibility);
If(Global.dsGlobals[1]);
Wait(Random Real(1, 2), Ignore Condition);
Create Dummy Bot(Hero(Tracer), Current Game Mode == Game Mode(Deathmatch) ? Team(All) : Team(Team 2), -1, Up * 1000, Up);
Global.dsGlobals[2] = Last Created Entity;
Start Forcing Dummy Bot Name(Global.dsGlobals[2], Custom String("DS BOT"));
Set Status(Global.dsGlobals[2], Null, Phased Out, 999999);
Disable Movement Collision With Players(Global.dsGlobals[2]);
Set Gravity(Global.dsGlobals[2], False);
Set Invisible(Global.dsGlobals[2], All);
Start Forcing Player Position(Global.dsGlobals[2], Global.dsGlobals[3], True);
End;
}
}
rule("[DS] Start Dialogue")
{
event
{
Subroutine;
StartDialogue;
}
actions
{
Abort If(Event Player.dsLinesArray == Empty Array);
Event Player.dsPlayers[0] = True;
If(Global.dsGlobals[1]);
Start Forcing Player To Be Hero(Global.dsGlobals[2], Hero Of(Event Player));
Global.dsGlobals[3] = Event Player;
End;
Event Player.dsPlayers[1] = 0;
Event Player.dsPlayers[2] = False;
Destroy HUD Text(Event Player.dsPlayers[3]);
Wait(0.1, Ignore Condition);
// Main text
Create HUD Text(Players Within Radius(Event Player, 30, Team(All), Off), Null, Custom String("{0} {1} ({2}M) ", Hero Icon String(Hero Of(Event Player)), Event Player, Round To Integer(Distance Between(Local Player, Event Player), To Nearest)), Event Player.dsPlayers[4], Top, 0.2, Color(white), Event Player.dsPlayers[5], Color(white), Visible To String and Color, Default Visibility);
Event Player.dsPlayers[3] = Last Text ID;
While(Event Player.dsLinesArray != Empty Array);
Event Player.dsPlayers[2] = False;
Event Player.dsPlayers[4] = Custom String("");
Event Player.dsPlayers[1] = 0;
For Player Variable(Event Player, dsCtrl, 0, String Length(Event Player.dsLinesArray[0]), 1);
Event Player.dsPlayers[6] = Char In String(Event Player.dsLinesArray[0], Event Player.dsCtrl);
// Triggers
"Pause at punctuation"
If(Event Player.dsPlayers[2] && String Contains(Event Player.dsPlayers[6], Custom String(" ")));
Event Player.dsPlayers[2] = False;
Wait(20 / Global.dsGlobals[0], Ignore Condition);
End;
If(String Contains(Custom String("!?.-—"), Event Player.dsPlayers[6]));
Event Player.dsPlayers[2] = True;
End;
"Trigger speech on new word"
If(String Contains(Event Player.dsPlayers[6], Custom String(" ")));
Event Player.dsPlayers[1] += 1;
Set Status(Global.dsGlobals[2], Null, Hacked, 0.1);
End;
Event Player.dsPlayers[4] = Custom String("{0}{1}", Event Player.dsPlayers[4], Event Player.dsPlayers[6]);
// Skip If(Has Status(Global.dsGlobals[2], Hacked), 1);
// Set Status(Global.dsGlobals[2], Null, Hacked, 0.1);
"Line break"
If(Event Player.dsPlayers[1] >= 10);
Event Player.dsPlayers[1] = 0;
Event Player.dsPlayers[4] = Custom String("{0}{1}", Event Player.dsPlayers[4], Custom String("\n"));
End;
Wait(1 / Global.dsGlobals[0], Ignore Condition);
End;
Wait(3.5, Ignore Condition);
Modify Player Variable(Event Player, dsLinesArray, Remove From Array By Index, 0);
End;
Event Player.dsPlayers[0] = False;
Destroy HUD Text(Event Player.dsPlayers[3]);
}
}
@mixin parseDialogue(lines = Array(
Custom String("You will suffer as I, Ramattra, have suffered! Your torment will outlast the stars!"),
Custom String("When the universe dwindles into dust, there you will be, still suffering as I have... suffered.")), color = Team Of(Event Player))
{
Event Player.dsLinesArray = Mixin.lines;
Event Player.dsPlayers[5] = Mixin.color;
Start Rule(StartDialogue, Restart Rule);
}
If you're not using the website editor, delete the @mixin part and, instead, use the code lines within it every time you want to call for a subtitle. Otherwise, to call a subtitle for dialogue inside a rule using the mixin:
- Add @include parseDialogue(arrayOfLines, speakerColor) as an action in your desired rule. Currently, the subtitles are created from the Event Player context and are visible in the HUD of anyone within a certain distance from the speaker, but you can easily modify these parameters as you please.
- Replace those paramaters with whatever you want. The first one must be an Array(line1, line1 etc.), the second one must be a color or custom color. If you just want the character to say one line, just add one custom string to the array.
- The hero will then say the lines in order and stop on its own.
Some important things you should know:
- You can make many heroes speak at the same time, as the tool will stack the subtitles on the screen, but only the latest speaker will have the speech sound effects if they're turned on since they rely on a dummy bot to occur.
- If your mode already has HUD text at the center, you'll need to adjust it or change the HUD text created by this tool to put the subtitles in an appropriate position.
- You'll also notice a config screen intended for you or any host to tune the character speed and to toggle the speech bot.
Have fun!
Controls
Snippet
Loading...