Print Text on screen during gameplay

Aerisetta

Active member
Please see video example of narrator from dragons crown. The text appears at the bottom while it is spoken.

I want to create this effect. While the player is playing and fighting I will have voiced narration but I need subtitles as well. Currently I have to make an image per subtitle but i want to make a lot and was wondering if there was a ready made solution where I only need to provide a text string and it can be printed out like in Dragon's Crown. The text can appear all at once.

 
you can use settextobj to display text and there is even a timeout option so it only stays for a fixed amount of time.

more info on how it works here: Documentation Project
oh thank you, this sounds like exactly what i'm looking for

um... can i get an example of where I would write this? settextobj(1, 120, 180, 5, 999999999, "Malik is cool", 1000); //this one is displayed for 10 seconds.

Should it be an indivdual script?
Inside a None object?
Spawn in the level txt?

EDIT: Woo i got it working by putting it in a none object like this

anim idle
@script
if(frame>=0){
void self = getlocalvar("self");
settextobj(1, 500, 500, 1, 999999999, "Malik is cool", 1000);
}
@end_script
loop 0
#delay 300
#frame data/chars/misc/empty.gif
delay 800
offset 0 0
sound data/chars/text/Text_Campaign_Temple_Ruins_1a1.wav
frame data/chars/misc/empty.gif
delay 1
frame data/chars/misc/empty.gif
delay 800
sound data/chars/text/Text_Campaign_Temple_Ruins_1a2.wav
frame data/chars/misc/empty.gif
frame data/chars/misc/empty.gif
 
Last edited:
Actually, need some help, is there any reason why "Subtitle Line 2" is displayed but it is displayed at the TOP RIGHT with FONT1?

So it did not carry over the properties to the 2nd textobj

Code:
name Text_Campaign_Temple_Ruins_1a
type none
speed      10
facing 1
setlayer     1000000001
shadow 0
lifespan 50




anim    idle
@script
  if(frame == 0){
    void self = getlocalvar("self");
    settextobj(0, 800, 200, 9, 999999999, "Subtitle Line 1", 1600);
  }
  else if(frame == 1){
    changetextobjproperty(0, "text", "Subtitle Line 2", 1600);
  }
@end_script  
    loop    0
    delay    800
    offset    0 0
    sound    data/chars/text/Text_Campaign_Temple_Ruins_1a1.wav
    frame    data/chars/misc/empty.gif
    delay    1
    frame    data/chars/misc/empty.gif
    delay    800
    sound    data/chars/text/Text_Campaign_Temple_Ruins_1a2.wav
    frame    data/chars/misc/empty.gif

EDIT: Okay i solved the above by making the textobj last longer, switch, then time it to be finished after the change.
I feel it's kinda janky way to do it though.

Code:
anim    idle
@script
  if(frame == 0){
    void self = getlocalvar("self");
    settextobj(0, 800, 200, 9, 999999999, "Subtitle Line 1", 4000);
  }
  else if(frame == 1){
    changetextobjproperty(0, "text", "Subtitle Line 2");
  }
@end_script    
    loop    0
    delay    800
    offset    0 0
    sound    data/chars/text/Text_Campaign_Temple_Ruins_1a1.wav
    frame    data/chars/misc/empty.gif
    delay    1
    frame    data/chars/misc/empty.gif
    delay    800
    sound    data/chars/text/Text_Campaign_Temple_Ruins_1a2.wav
    frame    data/chars/misc/empty.gif
 
Last edited:
Don't omit positions for changetextobjproperty. If I recall the parameters correctly it should look like this:

C:
changetextobjproperty(0, "text", "Subtitle Line 2", 800, 200, 1600);

Also, you're making this harder by putting it in inline code. I keep browbeating y'all and you won't listen - Stop using inline code with @script tags! Write a function and call it with @cmd. This will make things so much simpler for you in the long run.

DC
 
Also, you're making this harder by putting it in inline code. I keep browbeating y'all and you won't listen - Stop using inline code with @script tags! Write a function and call it with @cmd. This will make things so much simpler for you in the long run.

DC

I still don't know how to write function properly so I used tons of inline code since it easier
yeah they'll make things simpler in the long run and also keep mods looking neat like Kratus, Ilu and danno did to their mod
 
I still don't know how to write function properly so I used tons of inline code since it easier
yeah they'll make things simpler in the long run and also keep mods looking neat like Kratus, Ilu and danno did to their mod
Same for me on some parts. I understand how you feel about making inline code easier. Putting scripts in non-animation scripts is harder than animation script itself. But non-animation scripts such as ondraw and entity scripts (usually called "script" in the character header), have benefits/advantages in their own. Drawing text on screen with animation script is easy if it's something with one line like this. (I copied this text script and modified it into mine from @Blade Master's Fire Heart mod). These are just my own inputs.

C:
#include "data/scripts/script.c"

void drawdialog1(int index, char text){
    settextobj(index, 52, 200, 0, 410000000, text); //settextobj(index,x,y,font,z,text,time)
}

void drawdialog2(int index, char text){
    settextobj(index, 52, 210, 0, 410000000, text);
}

void suicide(){
    void self = getlocalvar("self");
    killentity(self);
}

Example:
C:
name victory
health 2
type text
palette none
shadow 0
nolife 1
speed 10
setlayer 410000000
load black
#load quotes
facing 1

animationscript data/scripts/textpos.c

############### ARCADE MODE (SOLO) ####################

anim idle # RYU (solo mode)

    offset 64 64
    delay 650
    @cmd spawn06 "Black" 0 0 660
    @cmd    changeopenborvariant "nojoin" 1
    @cmd    changeopenborvariant "nopause" 1
    @cmd    playmusic "data/music/fightend.ogg" 0
    @cmd    drawdialog1 0 "You_must_defeat_my_Shoryuken_to"
    @cmd    drawdialog2 1 "stand_a_chance!"
    frame data/sprites/ports/ryu2.png
    delay 90
    @cmd    changeopenborvariant "nojoin" 0
    @cmd    changeopenborvariant "nopause" 0
    @cmd    jumptobranch "end" 1
    frame data/sprites/ports/ryu2.png

My Mod - 0864.png

But the menu text created by @msmalik681 was hard to edit because of so many text options with scripts to edit in inline. However, I managed to create this animation script with @cmd's based on his without using inline code. (I was thinking of making it easier without inline code, so I did it.) It's easier to do it than ondrawscript and inline code, but I would like to learn how to do it in ondraw. machok, here's one inline code that works well.

C:
name    ChoiceVS
type    text
subtype noskip
shadow    0
#animationscript data/scripts/paus0001.c

anim idle
@script
    void self = getlocalvar("self");
    int index = getentityproperty(self, "playerindex");
    void up = playerkeys(index, 0, "moveup");
    void down = playerkeys(index, 0, "movedown");
    void pick = playerkeys(index, 0, "anybutton"); // "anybutton" is used for pressing or holding any of 6 buttons (4 attacks, jump, and special)

    int Cframe = getentityproperty(self, "animpos");
    void Restart = openborvariant("current_branch");

    changeopenborvariant("nopause", 1);

    if(frame >= 1)
    {
    if(Cframe == 3 && down) {updateframe(self, 4);} // Press down to highlight the select character option from restart game option
    if(Cframe == 6 && down) {updateframe(self, 7);} // Press down to highlight the quit game option from select character option
    if(Cframe == 6 && up) {updateframe(self, 1);} // Press up to highlight the restart game option from select character option
    if(Cframe == 9 && up) {updateframe(self, 4);} // Press up to highlight the select character option from quit game option
    if(Cframe == 9 && down) {updateframe(self, 1);} // Press down to highlight restart game option from quit game option
    if(Cframe == 3 && up) {updateframe(self, 7);} // Press up to highlight quit game option from restart game option

    if(Cframe == 3 && pick) { jumptobranch(Restart, 1); updateframe(self, 10); } // Restart game
    if(Cframe == 6 && pick) { jumptobranch("VS_Select", 1); updateframe(self, 10); } // Select Character
    if(Cframe == 9 && pick) { jumptobranch("ended", 2); updateframe(self, 10); } // Quit game
    }
@end_script
    delay 11 # <== This is the source of highlighting options for speed
    offset 8 14
    #@cmd paus0001 1 7500
    frame    none #0

    sound    data/sounds/beep.wav
    frame    none #1
    @cmd    settextobj 0 120 80 1 999999999 "Restart_Game" #settextobj will crash if space is used in text part instead of underscore. Should use underscore
    @cmd    settextobj 1 120 90 0 999999999 "Select_Character"
    @cmd    settextobj 2 120 100 0 999999999 "Quit_Game"

    #@cmd paus0001 1 7500
#@cmd    drawstring 160 80 1 "Restart Game" 999999999 #drawstring doesn't crash if space is used in text
    frame    none #2
    @cmd    updateframe getlocalvar("self") 2
    frame    none #3

    sound    data/sounds/beep.wav
    frame    none #4
    @cmd    settextobj 0 120 80 0 999999999 "Restart_Game"
    @cmd    settextobj 1 120 90 1 999999999 "Select_Character"
    @cmd    settextobj 2 120 100 0 999999999 "Quit_Game"
    frame    none #5
    @cmd    updateframe getlocalvar("self") 5
    frame    none #6

    sound    data/sounds/beep.wav
    frame    none #7
    @cmd    settextobj 0 120 80 0 999999999 "Restart_Game"
    @cmd    settextobj 1 120 90 0 999999999 "Select_Character"
    @cmd    settextobj 2 120 100 1 999999999 "Quit_Game"
    frame    none #8
    @cmd    updateframe getlocalvar("self") 8
    frame    none #9
    sound    data/sounds/beep2.wav
    #delay    10
    #@cmd    clearglobalvar
    frame    none #10
    frame    none #11
    frame    none #12
    frame    none #13
    frame    none #14

My Mod - 0865.png

For non-animation scripts, you can declare which animation (whether it'd be with or without frame number) or anything to use. Here's an example with Zangief's didhit script with a followcond style for performing one of the two grabs.

C:
#define glv getlocalvar
#define gep getentityproperty
#define oc openborconstant
#define pa performattack

// The function names can be abbreviated/shortened with the use of #define at the top

void main()
{
// Zangief's Double Suplex and Flying Power Bomb
// Courtesy of lagarto, for the alternative/multiple followcond style
// Multiple/Alternative Followcond(s)
    void self = glv("self"); // Calling entity
    void ani = gep(self, "animationid"); // Calling animation ID
    int frame = gep(self, "animpos"); // Calling frame
 
    if(ani == oc("ANI_freespecial15") && frame > 0)
    {// Distant from an opponent.
        pa(self, oc("ANI_follow20")); // Performing Flying Powerbomb?
    }else if(ani == oc("ANI_freespecial15") && frame == 0){ // Being close to an opponent.
        pa(self, oc("ANI_FOLLOW23")); // Performing Double Suplex?
    }
}

Now, notice I'm not using animation script. It's a didhit script with specific frames starting from the first and on, and you see attack1 depending on the number of frames you see in the didhitscript to make it look like a distance by sight.

Code:
anim freespecial15 #L Pre-special for Powerbomb or Double Suplex
    offset 337 291
    delay 6
    fastattack 1
    hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    @cmd velo001 0.7 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_346.png
    frame data/CHARS/Zangief/CVS2_Zangief_347.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_347.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_348.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_348.png
    delay 6
    hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_349.png
    delay 1
    #hitfx    data/sounds/empty.wav
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_349.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_350.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_350.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_351.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_351.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_352.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_352.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_353.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_353.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_354.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_354.png
    delay 6
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_355.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_355.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_346.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_346.png
    delay 6
    #hitfx    data/sounds/empty.wav
    attack1 300 194 107 36 0 0 1 1 0 0 0
    frame data/CHARS/Zangief/CVS2_Zangief_347.png
    delay 1
    attack1 0
    frame data/CHARS/Zangief/CVS2_Zangief_347.png
#    @cmd looper 3 2
    @cmd stop
    attack1 0
    delay 8
    frame data/CHARS/Zangief/CVS2_Zangief_118.png
    frame data/CHARS/Zangief/CVS2_Zangief_119.png
    frame data/CHARS/Zangief/CVS2_Zangief_120.png

Followups (you can ignore the @script tag here, but the camFocus used here is based on this @script tag I did in the past):
Code:
anim follow20 #Flying Powerbomb
#@script
void self = getlocalvar("self");
int full = openborvariant("levelwidth");
int half = openborvariant("levelwidth")/2;

if(frame == 0){
    changelevelproperty("scrollspeed", 0);
    changeentityproperty(self, "aggression", 30);
}
if(frame == 10){
    int full = openborvariant("levelwidth");
    changelevelproperty("scrollspeed", full);
    changeentityproperty(self, "aggression", 0);
}
@end_script
    offset 337 291
    delay 8
    landframe 10
    dropframe 7
    jumpframe 5 3 2 0
    @cmd slamstart2
    @cmd stop
    @cmd position 15 60 15 0 -1
    #@cmd    camFocus 1
    frame data/CHARS/Zangief/CVS2_Zangief_116.png
    delay 14
    @cmd position 15 54 15 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_117.png
    delay 9
    @cmd position 1 63 15 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_306.png
    @cmd position 5 83 17 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_307.png
    @cmd position 6 108 40 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_308.png
    @cmd position 15 80 45 0 -1
    delay 12
    #@cmd    camFocus 0
    frame data/CHARS/Zangief/CVS2_Zangief_356.png
    @cmd position 12 -2 83 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_357.png
    @cmd position 12 4 81 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_358.png
    @cmd position 4 70 120 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_359.png
    delay 10
    @cmd position 17 116 65 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_360.png
    delay 22
    sound data/sounds/fall.wav
    @cmd position 3 109 15 0 1
    frame data/CHARS/Zangief/CVS2_Zangief_361.png
    delay 10
    @cmd position 3 109 15 0 1
    frame data/CHARS/Zangief/CVS2_Zangief_362.png
    @cmd depost
    @cmd finish 10 1 1.2 1.5 0 -1
    #@cmd    camFocus 1
    frame data/CHARS/Zangief/CVS2_Zangief_362.png
    @cmd anichange "ANI_FOLLOW29"
    frame data/CHARS/Zangief/CVS2_Zangief_362.png

Code:
anim follow23 #Double Suplex
@script
void self = getlocalvar("self");
int full = openborvariant("levelwidth");
int half = openborvariant("levelwidth")/2;

if(frame == 0){
    changelevelproperty("scrollspeed", 0);
    changeentityproperty(self, "aggression", 30);
}
if(frame == 8){
    int full = openborvariant("levelwidth");
    changelevelproperty("scrollspeed", 0);
    changeentityproperty(self, "aggression", 0);
}
if(frame == 9){
    int half = openborvariant("levelwidth")/2;
    changelevelproperty("scrollspeed", half);
    changeentityproperty(self, "aggression", 0);
}
if(frame == 14){
changelevelproperty("scrollspeed", full);
    changeentityproperty(self, "aggression", 30);
}
@end_script
    offset 337 291
    delay 6
    jumpframe 12 3 2 0
    dropframe 13
    landframe 14
    @cmd slamstart2
    @cmd stop
    @cmd position 15 60 15 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_116.png
    delay 9
    @cmd position 15 54 15 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_117.png
    @cmd position 1 15 16 0 1
    frame data/CHARS/Zangief/CVS2_Zangief_396.png
    @cmd position 1 -37 19 0 1
    frame data/CHARS/Zangief/CVS2_Zangief_397.png
    @cmd position 5 -39 21 0 1
    frame data/CHARS/Zangief/CVS2_Zangief_398.png
    @cmd position 5 -39 21 0 1
    frame data/CHARS/Zangief/CVS2_Zangief_399.png
    @cmd position 12 -23 53 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_400.png
    @cmd position 4 86 87 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_401.png
    delay 19
    @cmd position 3 137 5 0 -1
    @cmd hurt2 10
    sound data/sounds/fall.wav
    frame data/CHARS/Zangief/CVS2_Zangief_402.png
    delay 9
    @cmd position 3 137 5 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_333.png
    @cmd position 3 137 5 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_334.png
    move 12
    @cmd position 3 54 5 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_335.png
    delay 14
    move 0
    @cmd position 12 -20 79 0 -1
    frame data/CHARS/Zangief/CVS2_Zangief_336.png
    @cmd position 4 81 103 0 -1
    delay 100
    frame data/CHARS/Zangief/CVS2_Zangief_337.png
    delay 22
    @cmd position 3 58 11 0 1
    sound data/sounds/fall.wav
    frame data/CHARS/Zangief/CVS2_Zangief_338.png
    @cmd position 3 58 11 0 1
    delay 6
    frame data/CHARS/Zangief/CVS2_Zangief_339.png
    @cmd position 3 58 11 0 1
    delay 6
    frame data/CHARS/Zangief/CVS2_Zangief_340.png
    #@cmd depost
    @cmd finish 10 2 -1.2 1.5 0 -1
    @cmd depost
    delay 1
    frame data/CHARS/Zangief/CVS2_Zangief_341.png
    @cmd attack0 "ANI_FREESPECIAL21"
    frame data/CHARS/Zangief/CVS2_Zangief_342.png
    frame data/CHARS/Zangief/CVS2_Zangief_343.png
    frame data/CHARS/Zangief/CVS2_Zangief_344.png
 
Last edited:
To be continued from my previous post...

For Aerisetta's case, I think this is all about timing the captions in gameplay. He can use settextobj with a time value before it expires. Without using the time, it will never expire unless you give its time value for how long it will remain. The last parameter of it is what I'm talking about.

C:
//settextobj(index,x,y,font,z,text,time)

He can set the text and timing like this. Or he can use the text from @Bloodbane's Versus Template sample for the text.

camptext.c:
C:
void textDialog(char text, int index, int font, int time, int x, int y, int z){
    settextobj(index, x, y, font, z, text, time); //settextobj(index,x,y,font,z,text,time)
}

Example:
Code:
name Text_Campaign_Temple_Ruins_1a
type none
speed      10
facing 1
setlayer     1000000001
shadow 0
lifespan 50
animationscript data/scripts/camptext.c


anim    idle
    loop    0
    delay    800
    offset    0 0
    sound    data/chars/text/Text_Campaign_Temple_Ruins_1a1.wav
    @cmd textDialog "This_is_a_text._Do_you_understand?" 0 2 12000 52 200 5000 # textDialog {text} {index} {font} {time} {x} {y} {z}
    @cmd textDialog "settextobj_is_set_with_seven_parameters." 1 2 12000 52 210 5000 # textDialog {text} {index} {font} {time} {x} {y} {z}
    frame    data/chars/misc/empty.gif
    delay    1
    frame    data/chars/misc/empty.gif
    delay    800
    @cmd textDialog "For_the_text,_make_sure_to_use_underscores_for_spacing_characters." 2 2 12000 12 200 5000 # textDialog {text} {index} {font} {time} {x} {y} {z}
    @cmd textDialog "Is_it_clear,_or_do_you_have_any_question?" 3 2 12000 12 210 5000 # textDialog {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/Text_Campaign_Temple_Ruins_1a2.wav
    frame    data/chars/misc/empty.gif

If it doesn't work, you can use another function and rename it differently but with the same script for index purpose.
 
Last edited:
Thank you so much @maxman for the examples you provided!!! I spent an hour or 2 trying to write it as a function as DC suggested yesterday and failed lol (i've never written one before haha)

I am actually super stoked learning how this text printing feature can work so easily because until yesterday, settextobj was only mentioned twice on the forum and not listed in the manual at all. As someone who's making something with a lot of RPG features, this opens up many possibilities (possibilities I avoided in the past because I didnt want to make images for text :P)

Some features i can think of
1. Dialogue pop up when you walk near an NPC
2. Pop up menus
3. Lore notes
4. location names
5. player states like poisoned
 
@machok I corrected my previous posts especially the one with the post-match menu. The script and the entity I provided were wrong, so I corrected it because the one I showed you doesn't work at all. The one with the name "ChoiceVS" is the one that works, and the inline code is easier as you said.

The one called "VSChoice" which I made, doesn't work. The displaying texts I did are correct, but I cannot trigger any key to confirm a choice. This is the one that doesn't work for at all.

C-like:
void Text(int x, int y, int font, char text, int layer){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int frame = getentityproperty(self, "animpos");
    int up = playerkeys(self, 0, "moveup");
    int down = playerkeys(self, 0, "movedown");
    int pick = playerkeys(self, 0, "anybutton");
    void Restart = openborvariant("current_branch");

    drawstring(x, y, font, text, layer);
    //settextobj(index, x, y, font, layer, text);

    /*if(down && frame == 3){
        updateframe(self, 4);
    }*/
}

void Restart(){
    void Restart = openborvariant("current_branch");
    jumptobranch(Restart, 1);
}

void Quit(){
    jumptobranch("end", 2);
}

void textDownTrigger(int Frame){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int down = playerkeys(self, 0, "movedown");

    if(down){
        updateframe(self, Frame);
    }
}

void textUpTrigger(int Frame){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int up = playerkeys(self, 0, "moveup");

    if(up){
        updateframe(self, Frame);
    }
}

void textPressTrigger(int Frame){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int up = playerkeys(self, 0, "moveup");
    int down = playerkeys(self, 0, "movedown");
    int pick = playerkeys(self, 0, "anybutton");

    if(pick){
        updateframe(self, Frame);
    }
}

void Text2(int index, int x, int y, int font, char text, int layer){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int frame = getentityproperty(self, "animpos");
    int up = playerkeys(self, 1, "moveup");
    int down = playerkeys(self, 1, "movedown");
    int pick = playerkeys(self, 0, "anybutton");
    void Restart = openborvariant("current_branch");

    settextobj(index, x, y, font, layer, text);

    if(settextobj(0, 120, 80, 1, 800, "Restart_Game") && pick){
        jumptobranch(Restart, 1);
    }
}

int ChangeFrame(int Frame){
    void self = getlocalvar("self");
    updateframe(self, Frame);
}

C:
name VSChoice
type Text
subtype noskip
shadow 0

animationscript data/scripts/vschoice.c

anim idle

    delay 10 # <== This is the source of highlighting options for speed
    offset 8 14
    @cmd changelevelproperty "bgspeed" 0
    sound    data/sounds/beep.wav
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #0
    #@cmd    textDownTrigger 4
    #sound    data/sounds/beep.wav # SOUND
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    #@cmd    textDownTrigger 4
    frame    none #1
    @cmd    Text2 0 120  80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    #@cmd    textDownTrigger 4
    @cmd    textPressTrigger 10 #Jump to restart
    frame    none #2
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    #@cmd    textDownTrigger 4
    @cmd    textPressTrigger 10 #Jump to restart
    @cmd    ChangeFrame 2
    frame    none #3
#########################################################
    sound    data/sounds/beep.wav
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #4
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    textDownTrigger 7
    @cmd    textPressTrigger 12 #Select_Character
    frame    none #5
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    textDownTrigger 7
    @cmd    ChangeFrame 5
    frame    none #6
#######################################################
    sound    data/sounds/beep.wav
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    frame    none #7
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    @cmd    textDownTrigger 0
    @cmd    textPressTrigger 14
    frame    none #8
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    @cmd    textDownTrigger 0
    @cmd    textPressTrigger 14
    @cmd    ChangeFrame 8
    frame    none #9
#######################################################
    sound    data/sounds/beep2.wav
    delay    5
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #10
    delay    1000
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    Restart
    frame    none #11
######################################################
    sound    data/sounds/beep2.wav
    delay    5
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #12
    delay    1000
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    jumptobranch "VS_Mode" 1
    frame    none #13
#####################################################
    sound    data/sounds/beep2.wav
    delay    5
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    frame    none #14
    delay    1000
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    @cmd    Quit
    frame    none #15

I wonder how I can get it working without using inline code. Is it because of using updateframe without specifying an animation?

5. player states like poisoned
Damage scripts:
www.chronocrash.com/forum/threads/some-takedamagescripts-to-share.1663

If there's no poison script from it, try out this one.
www.chronocrash.com/forum/resources/dungeons-and-dragons-rise-of-warduke.67

For item pickups, I don't know how you want them to be picked up for some of them because you mentioned you want lore notes, right? Some may look good for grabbing a special note.


 
Last edited:
@machok I corrected my previous posts especially the one with the post-match menu. The script and the entity I provided were wrong, so I corrected it because the one I showed you doesn't work at all. The one with the name "ChoiceVS" is the one that works, and the inline code is easier as you said.

The one called "VSChoice" which I made, doesn't work. The displaying texts I did are correct, but I cannot trigger any key to confirm a choice. This is the one that doesn't work for at all.

C-like:
void Text(int x, int y, int font, char text, int layer){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int frame = getentityproperty(self, "animpos");
    int up = playerkeys(self, 0, "moveup");
    int down = playerkeys(self, 0, "movedown");
    int pick = playerkeys(self, 0, "anybutton");
    void Restart = openborvariant("current_branch");

    drawstring(x, y, font, text, layer);
    //settextobj(index, x, y, font, layer, text);

    /*if(down && frame == 3){
        updateframe(self, 4);
    }*/
}

void Restart(){
    void Restart = openborvariant("current_branch");
    jumptobranch(Restart, 1);
}

void Quit(){
    jumptobranch("end", 2);
}

void textDownTrigger(int Frame){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int down = playerkeys(self, 0, "movedown");

    if(down){
        updateframe(self, Frame);
    }
}

void textUpTrigger(int Frame){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int up = playerkeys(self, 0, "moveup");

    if(up){
        updateframe(self, Frame);
    }
}

void textPressTrigger(int Frame){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int up = playerkeys(self, 0, "moveup");
    int down = playerkeys(self, 0, "movedown");
    int pick = playerkeys(self, 0, "anybutton");

    if(pick){
        updateframe(self, Frame);
    }
}

void Text2(int index, int x, int y, int font, char text, int layer){
    int player = getlocalvar("player");
    void self = getplayerproperty(player, "entity");
    int frame = getentityproperty(self, "animpos");
    int up = playerkeys(self, 1, "moveup");
    int down = playerkeys(self, 1, "movedown");
    int pick = playerkeys(self, 0, "anybutton");
    void Restart = openborvariant("current_branch");

    settextobj(index, x, y, font, layer, text);

    if(settextobj(0, 120, 80, 1, 800, "Restart_Game") && pick){
        jumptobranch(Restart, 1);
    }
}

int ChangeFrame(int Frame){
    void self = getlocalvar("self");
    updateframe(self, Frame);
}

C:
name VSChoice
type Text
subtype noskip
shadow 0

animationscript data/scripts/vschoice.c

anim idle

    delay 10 # <== This is the source of highlighting options for speed
    offset 8 14
    @cmd changelevelproperty "bgspeed" 0
    sound    data/sounds/beep.wav # MUSIC
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #0
    #@cmd    textDownTrigger 4
    #sound    data/sounds/beep.wav # SOUND
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    #@cmd    textDownTrigger 4
    frame    none #1
    @cmd    Text2 0 120  80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    #@cmd    textDownTrigger 4
    @cmd    textPressTrigger 10 #Jump to restart
    frame    none #2
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    #@cmd    textDownTrigger 4
    @cmd    textPressTrigger 10 #Jump to restart
    @cmd    ChangeFrame 2
    frame    none #3
#########################################################
    sound    data/sounds/beep.wav
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #4
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    textDownTrigger 7
    @cmd    textPressTrigger 12 #Select_Character
    frame    none #5
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    textDownTrigger 7
    @cmd    ChangeFrame 5
    frame    none #6
#######################################################
    sound    data/sounds/beep.wav
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    frame    none #7
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    @cmd    textDownTrigger 0
    @cmd    textPressTrigger 14
    frame    none #8
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    @cmd    textDownTrigger 0
    @cmd    textPressTrigger 14
    @cmd    ChangeFrame 8
    frame    none #9
#######################################################
    sound    data/sounds/beep2.wav
    delay    5
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #10
    delay    1000
    @cmd    Text2 0 120 80 1 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    Restart
    frame    none #11
######################################################
    sound    data/sounds/beep2.wav
    delay    5
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    frame    none #12
    delay    1000
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 1 "Select_Character" 800
    @cmd    Text2 2 120 100 0 "Quit_Game" 800
    @cmd    jumptobranch "VS_Mode" 1
    frame    none #13
#####################################################
    sound    data/sounds/beep2.wav
    delay    5
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    frame    none #14
    delay    1000
    @cmd    Text2 0 120 80 0 "Restart_Game" 800
    @cmd    Text2 1 120 90 0 "Select_Character" 800
    @cmd    Text2 2 120 100 1 "Quit_Game" 800
    @cmd    Quit
    frame    none #15

I wonder how I can get it working without using inline code. Is it because of using updateframe without specifying an animation?


Damage scripts:
www.chronocrash.com/forum/threads/some-takedamagescripts-to-share.1663

If there's no poison script from it, try out this one.
www.chronocrash.com/forum/resources/dungeons-and-dragons-rise-of-warduke.67

For item pickups, I don't know how you want them to be picked up for some of them because you mentioned you want lore notes, right? Some may look good for grabbing a special note.


Thanks a lot! I had to alter your script some to fit my use case, but here's the result!

I'll share the script later

 
That looks really nice. I did notice toward the end one of your lines went out of the box, but I'm sure that's just a minor oversight.

DC
Thanks

Yes, I haven't polished yet but I'm aware.

I have a 2 questions regarding sound and volume.

1.
Right now, all the sound effects in my game are around 10 decibel (basically maxed out) because I saw that's how the default sound files were in most openbor game. Problem is when I play the narration during gameplay, all sounds are maxed out and its hard to hear the speaker. Is there a way to lower the volume of all other sounds when playing the narration?

2.
Sometimes when I'm fighting, sounds may overlap and a sound may not play. Usually missing a sound effect is fine, but it's a big deal if a whole narration line is missing (or the level up sound that's common). Is there a way to avoid this?
 
Last edited:
@Aerisetta

Right now, all the sound effects in my game are around 10 decibel (basically maxed out) because I saw that's how the default sound files were in most openbor game. Problem is when I play the narration during gameplay, all sounds are maxed out and its hard to hear the speaker. Is there a way to lower the volume of all other sounds when playing the narration?
I know a function to lower the music volume but if I'm not wrong there's no function to reduce samples volume individually (the ones that are currently playing, for the new ones you can play in a lower volume). Instead, there's a function to stop sample channels but I'm not certain it can be useful for your purpose.

Sometimes when I'm fighting, sounds may overlap and a sound may not play. Usually missing a sound effect is fine, but it's a big deal if a whole narration line is missing (or the level up sound that's common). Is there a way to avoid this?
Usually the engine makes the opposite, accumulating sounds instead of canceling them (maybe they accumulated too much at the point they are unrecognized). Indeed OpenBOR can play 64 simultaneous sound effects in the current builds and this limit was upgraded to 256 for the next version 4.0.
In addition, you can play the same sample twice or more at the same time to artificially increase the volume instead of changing the audio file.

As a suggestion, maybe you could use music instead of sounds to play the narrator, having a few more tools to use and being able to record longer narrations.

1681182019734.png
 
@Aerisetta


I know a function to lower the music volume but if I'm not wrong there's no function to reduce samples volume individually (the ones that are currently playing, for the new ones you can play in a lower volume). Instead, there's a function to stop sample channels but I'm not certain it can be useful for your purpose.


Usually the engine makes the opposite, accumulating sounds instead of canceling them (maybe they accumulated too much at the point they are unrecognized). Indeed OpenBOR can play 64 simultaneous sound effects in the current builds and this limit was upgraded to 256 for the next version 4.0.
In addition, you can play the same sample twice or more at the same time to artificially increase the volume instead of changing the audio file.

As a suggestion, maybe you could use music instead of sounds to play the narrator, having a few more tools to use and being able to record longer narrations.

View attachment 3575
Using music is great, however from what i can tell, only 1 music track can play at one time? So if my narrator speaks the music needs to stop?

Would be great if multiple tracks can play at once, especially for adding things like ambience
 
Would be great if multiple tracks can play at once, especially for adding things like ambience
That's not going to happen because it's not really an engine limit. Music streams directly from the disk. No matter how powerful your hardware is there's only so much throughput for that.

If you want multiple tracks then you need to use sound effects. The only difference is sound effects load to memory first. There's no limit to what you can play with them. IOW multiple music tracks are already supported. It's really more accurate to say you get 64 sound channels + one bonus streaming channel.

As for the overlap, I can't believe you used up all 64 at once. That's the same number an Xbox has. There’s something else going on and I suggest troubleshooting that instead of trying to reinvent the wheel. Maybe post up some of your sound trigger code / objects so we can take a look.

DC
 
That's not going to happen because it's not really an engine limit. Music streams directly from the disk. No matter how powerful your hardware is there's only so much throughput for that.

If you want multiple tracks then you need to use sound effects. The only difference is sound effects load to memory first. There's no limit to what you can play with them. IOW multiple music tracks are already supported. It's really more accurate to say you get 64 sound channels + one bonus streaming channel.

As for the overlap, I can't believe you used up all 64 at once. That's the same number an Xbox has. There’s something else going on and I suggest troubleshooting that instead of trying to reinvent the wheel. Maybe post up some of your sound trigger code / objects so we can take a look.

DC

Yeah it's definitely not too many sounds if it can have up to 64.

I tested a few things

1. I decreased the SFX volume overall, unfortunately, the game starts to make weird clicking sounds before and after every sound effect if I try to go below 56.
2. I tried to use playsample to increase the volume, however it does not seem to go above 120? I cant feel any difference after
I tried to mix 1 and 2 together, unfortunately SFX at 56 and playsample only at 120 is not big enough of a delta to make a difference

3. the most obvious way to increase volume was actually just spawning the sound producing entity 2-3 times simultaneously. Unfortunately it was very unstable, sometimes i can hear all 3 samples playing, sometimes only 1 sample and sometimes no sound at all.

What is spawned in level
Code:
spawn TextPop_C01-01
@script
void main()
{
    void self = getlocalvar("self");
    changeentityproperty(self, "animation", openborconstant("ANI_FOLLOW1"));
}
@end_script
at 300

TextPop.c which is imported into player.c
Code:
void TextPop(char text, int index, int font, int x, int y, int z){
    settextobj(index, x, y, font, z, text); //settextobj(index,x,y,font,z,text,time)
}

void TextUpdate(char text, int index){
    changetextobjproperty(index, "text", text);
}

void TextClear(int index){
    cleartextobj(index);
}


The Entity that spawns the text and audio.
Code:
name TextPop_C01-01
type panel
speed        10
facing 1
setlayer     4999
shadow 0
animationscript        data/scripts/player.c




anim    idle
    loop    1
    delay    1000
    offset    0 0
    frame    data/chars/text/NarratorBox.gif
    @cmd    suicide
   
   
   
anim    follow1
    loop    0
    delay    800
    offset    0 0
    drawmethod    alpha 6
    drawmethod    channel 0.7
    @cmd    TextPop "Upon_hearing_rumors_of_an_Artifact_hidden_within_these_long" 0 9 50 100 5000 # TextPop {text} {index} {font} {time} {x} {y} {z}
    @cmd    TextPop "forgotten_ruins,_your_party_arrive_to_claim_it_for_yourselves." 1 9 50 130 5000 # TextPop {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/C01-01A.wav
    frame    data/chars/text/NarratorBox.gif
    delay    1
    frame    data/chars/text/NarratorBox.gif
    frame    data/chars/text/NarratorBox.gif
    delay    800
    @cmd    TextUpdate "Unfortunately,_you_discover_the_Church's_agents_have_arrived" 0 # TextPop {text} {index} {font} {time} {x} {y} {z}
    @cmd    TextUpdate "before_you,_seeking_the_Artifact_for_their_own_purposes." 1 # TextPop {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/C01-01B.wav
    frame    data/chars/text/NarratorBox.gif
    delay    1
    @cmd    TextClear 0
    @cmd    TextClear 1
    frame    data/chars/misc/empty.gif
    @cmd    suicide
   
anim    follow2
    loop    0
    delay    800
    offset    0 0
    drawmethod    alpha 6
    drawmethod    channel 0.7
    @cmd    TextPop "The_Church_of_Pure_Thoughts,_mighty_and_revered," 0 9 50 100 5000 # TextPop {text} {index} {font} {time} {x} {y} {z}
    @cmd    TextPop "rules_over_the_spiritual_life_for_all_who_live_in_Earendyl." 1 9 50 130 5000 # TextPop {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/C01-01C.wav
    frame    data/chars/text/NarratorBox.gif
    delay    1
    frame    data/chars/text/NarratorBox.gif
    frame    data/chars/text/NarratorBox.gif
    delay    800
    @cmd    TextUpdate "Harnessing_Divine_Magicks_bestowed_by_the_Church," 0 # TextPop {text} {index} {font} {time} {x} {y} {z}
    @cmd    TextUpdate "their_Priests_deliver_retribution_to_all_they_deem_'immoral'." 1 # TextPop {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/C01-01D.wav
    frame    data/chars/text/NarratorBox.gif
    delay    1
    @cmd    TextClear 0
    @cmd    TextClear 1
    frame    data/chars/misc/empty.gif
    @cmd    suicide
   
anim    follow3
    loop    0
    delay    800
    offset    0 0
    drawmethod    alpha 6
    drawmethod    channel 0.7
    @cmd    TextPop "The_Church_of_Pure_Thoughts_wage_a_crusade_against_lewdness." 0 9 50 100 5000 # TextPop {text} {index} {font} {time} {x} {y} {z}
    @cmd    TextPop "Even_procreation_is_strictly_regulated_and_scrutinized." 1 9 50 130 5000 # TextPop {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/C01-01E.wav
    frame    data/chars/text/NarratorBox.gif
    delay    1
    frame    data/chars/text/NarratorBox.gif
    frame    data/chars/text/NarratorBox.gif
    delay    800
    @cmd    TextUpdate "Their_zealous_Priests_fervently_declare_that_resisting_the_lure" 0 # TextPop {text} {index} {font} {time} {x} {y} {z}
    @cmd    TextUpdate "of_lustful_vices_is_the_only_way_to_securing_eternal_salvation." 1 # TextPop {text} {index} {font} {time} {x} {y} {z}
    sound    data/chars/text/C01-01F.wav
    frame    data/chars/text/NarratorBox.gif
    delay    1
    @cmd    TextClear 0
    @cmd    TextClear 1
    frame    data/chars/misc/empty.gif
    @cmd    suicide
       
#|edited by openBor Stats v 0.51
 
I didn't test yet but if you use stereo music you can put the narration audio on the left side and the music on the right side.
@Aerisetta Here's an example of what I said in my previous post. This way you can use narration as music maintaining the tracks playing, and control everything directly in the audio file.

 
Back
Top Bottom