A Full-Screen Slide in Mid-Game: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
(create this article)
 
(Fix code blocks)
Line 6: Line 6:
  gui guis/my_slide.gui
  gui guis/my_slide.gui
  show <number of seconds you want slide to appear>
  show <number of seconds you want slide to appear>
Unlike the usual case, the values of this entity's spawnargs "lines" and "text" will be ignored. Also, the slide will disappear abruptly at "show" time, not fade out.
Unlike the unaltered case, for what we're doing here, the values of this entity's spawnargs "lines" and "text" will be ignored. Also, the slide will disappear abruptly at "show" time, not fade out.


Arrange for your player to trigger this entity. Finally, we will customize my_slide.gui. In particular, we will make it possible for the user to terminate the slide early, by clicking the LMB on it. The text we will display will be hardcoded into the .gui, not passed as a spawnarg or (as would be the case with readabiles) retrieved from an .xd file.
Arrange for your player to trigger this entity. Finally, we will customize my_slide.gui. In particular, we will make it possible for the user to terminate the slide early, by clicking the LMB on it. The text we will display will be hardcoded into the .gui, not passed as a spawnarg or (as would be the case with readabiles) retrieved from an .xd file.
Line 14: Line 14:
  {
  {
  visible 1
  visible 1
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
        onAction {
onAction {
            set "MySlide::visible" "0";  
        set "MySlide::visible" "0";  
        }
}
    windowDef Text1 {
windowDef Text1 {
        rect        10, 10, 620, 460 // x, y (relative to parent origin), w, h. Adjust to control margins.
    rect        10, 10, 620, 460 // x, y (relative to parent origin), w, h. Adjust to control margins.
        text        "Amazing Let's try word wrapping this box exceeds screen width."
    text        "Amazing Let's try word wrapping this box exceeds screen width."
        textscale 1
    textscale 1
        font "fonts/popsies"
    font "fonts/popsies"
    }
  }
  }
  }
Almost always, you use “rect 0,0,640,480” in the parent windowDef to establish a logical coordinate system stretched over the screen dimensions. By default, a TDM menu cursor will appear, to remind the user that they can exit early by clicking… really anywhere. You can suppress this cursor with “nocursor 1”. Choose the font from the standard TDM ones (e.g., carleton is used for briefings). Adjust the font size with float “textscale”, but 1 or less is best.
Almost always, you use “rect 0,0,640,480” in the parent windowDef to establish a logical coordinate system stretched over the screen dimensions. By default, a TDM menu cursor will appear, to remind the user that they can exit early by clicking... really anywhere. You can suppress this cursor with "nocursor 1". Choose the font from the standard TDM ones (e.g., carleton is used for briefings). Adjust the font size with float "textscale", but 1 or less is best.


The text will be word-wrapped and left-justified. You can add “textalign 1” to center it (except first line stays left-justified; ugh. Stick in some leading spaces).
The text will be word-wrapped and left-justified. You can add "textalign 1" to center it (except first line stays left-justified; ugh. Stick in some leading spaces).


This is not very different than the standard atdm:gui_message treatment with the “…no_art” gui. However, if you want to have titles and paragraphs with different fonts, sizes, locations, or margins, you can just add additional windowDefs. So, for example, instead of full-screen, you could possibly use this method to provide a subtitle.
This is not very different than the standard atdm:gui_message treatment with the "...no_art" gui. However, if you want to have titles and paragraphs with different fonts, sizes, locations, or margins, you can just add additional windowDefs. So, for example, instead of full-screen, you could possibly use this method to provide a subtitle.
==Case 2 – Opaque Black Background, White Letters==
==Case 2 – Opaque Black Background, White Letters==
  windowDef MySlide
  windowDef MySlide
  {
  {
  visible 1
  visible 1
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  Backcolor   0, 0, 0, 1 // Black background
  backcolor   0, 0, 0, 1 // Black background
        onAction {
onAction {
            set "MySlide::visible" "0";  
    set "MySlide::visible" "0";  
          set "gui::MySlideDone" "1";
    set "gui::MySlideDone" "1";
        }
}
    windowDef Text1 { same as previous example }
windowDef Text1 { ... same as previous example ... }
  }
  }
With an opaque full-screen background, it is more necessary for the rest of the game to know when the slide is done, particularly if it’s up more than a few seconds. So onAction sets a variable, that can be then polled for in a script, shown next.
With an opaque full-screen background, it is more necessary for the rest of the game to know when the slide is done, particularly if it’s up more than a few seconds. So onAction sets a variable, that can be then polled for in a script, shown next.
Line 56: Line 56:
   while(handlenum == 0)
   while(handlenum == 0)
   {
   {
  handlenum = e.gui;
    handlenum = e.gui;
sys.wait(0.1);
  sys.wait(0.1);
   }
   }
   float maxtime = $atdm_gui_message_slide.getFloatKey("show");
   float maxtime = $atdm_gui_message_slide.getFloatKey("show");
Line 63: Line 63:
   while(maxtime > 0)
   while(maxtime > 0)
   {
   {
slide_done = $player1.getGuiFloat(handlenum, "MySlideDone");
  slide_done = $player1.getGuiFloat(handlenum, "MySlideDone");
if(slide_done == 1) // user did gui's onAction, with LMB
  if(slide_done == 1) // user did gui's onAction, with LMB
  break;
  break;
maxtime -= 0.1;
  maxtime -= 0.1;
sys.wait(0.1);
  sys.wait(0.1);
    }
  }
   // Optionally add code here to move player from blue room.
   // Optionally add code here to move player from blue room.
   $player1.setGuiFloat(handlenum, "MySlideDone", 0); // reset just in case
   $player1.setGuiFloat(handlenum, "MySlideDone", 0); // reset just in case
}


==Case 3 – Opaque Image Background, Black Letters==
==Case 3 – Opaque Image Background, Black Letters==
Line 76: Line 77:
  {
  {
  visible 1
  visible 1
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  background "models/darkmod/props/textures/parchment_freshpaper"
  background "models/darkmod/props/textures/parchment_freshpaper"
        onAction {
onAction {
            set "MySlide::visible" "0";  
    set "MySlide::visible" "0";  
        }
    }
     windowDef Text1 {
     windowDef Text1 {
         rect        10, 10, 620, 460 // x, y (relative to parent origin), w, h
         rect        10, 10, 620, 460 // x, y (relative to parent origin), w, h
Line 94: Line 95:
You could just burn the text into the background image. But translators will be unhappy unless you also provide them with the corresponding text-free image.
You could just burn the text into the background image. But translators will be unhappy unless you also provide them with the corresponding text-free image.
==Case 4 – Two-Level Image Background, Black Letters==
==Case 4 – Two-Level Image Background, Black Letters==
There are a number of pre-existing TDM “parchment” and “scroll” backgrounds that have wide transparent perimeters. You can substitute one of these directly (so you see the game world around the edges), or create a child windowDef with one of these, atop a parent’s opaque background (black in this example):
There are a number of pre-existing TDM "parchment" and "scroll" backgrounds that have wide transparent perimeters. You can substitute one of these directly (so you see the game world around the edges), or create a child windowDef with one of these, atop a parent’s opaque background (black in this example):


  windowDef MySlide
  windowDef MySlide
  {
  {
  visible 1
  visible 1
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
  Backcolor   0, 0, 0, 1 // Black background
  backcolor   0, 0, 0, 1 // Black background
        onAction {
onAction {
            set "MySlide::visible" "0";  
    set "MySlide::visible" "0";  
        }
}
        windowDef Scroll1
windowDef Scroll1{
{
    visible 1
visible 1
    rect 0,0,640,480 // x, y, w, h. This can be bigger than the parent if you want to reduce transparent perimeter
rect 0,0,640,480 // x, y, w, h. This can be bigger than the parent if you want to reduce transparent perimeter
    background "dds/guis/assets/readables/scroll"
background "dds/guis/assets/readables/scroll"
}
windowDef Text1 { ... same as previous example ... }
  }
  }


    windowDef Text1 { … same as previous example … }
==An Example==
}
An outgrown of Case 4 can be found in FM “Away 0: Stolen Heart”, where it is used to put up a substitute full-screen slide when “Skip Cutscene” is selected.
 
Image here
 
This uses multiple windowDefs to position text blocks atop the scroll. The "Done" text provides a target for the cursor, but the gamer can really click anywhere. The corresponding script function (in emily_related.script) is far more complicated than above, because it handles FM-specific chores.


==For More==
==For More==
The information here draws on 2004-vintage GUI tutorials by Doom creator John Cormac, but adapted to TDM.
The information here draws on 2004-vintage GUI tutorials by Doom creator John Cormac, but adapted to TDM.
Examples of Case 4 can be found in FM “Away 0: Stolen Heart”, where it is used to put up a substitute full-screen slide when “Skip Cutscene” is selected. The corresponding script functions (in emily_related.script) are far more complicated.

Revision as of 03:00, 25 November 2021

by Geep, 2021

Overview

Suppose you want to briefly show some text on-screen, but the existing TDM message gui’s don’t quite do what you want. Here’s how you can easily modify them.

Start by creating an atdm:gui_message entity in your map. Then, in the Entity Inspector, alter these 2 lines:

gui	guis/my_slide.gui
show	<number of seconds you want slide to appear>

Unlike the unaltered case, for what we're doing here, the values of this entity's spawnargs "lines" and "text" will be ignored. Also, the slide will disappear abruptly at "show" time, not fade out.

Arrange for your player to trigger this entity. Finally, we will customize my_slide.gui. In particular, we will make it possible for the user to terminate the slide early, by clicking the LMB on it. The text we will display will be hardcoded into the .gui, not passed as a spawnarg or (as would be the case with readabiles) retrieved from an .xd file.

Case 1 – Transparent Background, White Letters

In your FM’s “guis” folder, create my_slide.gui with content:

windowDef MySlide
{
	visible 1
	rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
	onAction {
        set "MySlide::visible" "0"; 
	}
	windowDef Text1 {
	     rect        10, 10, 620, 460 // x, y (relative to parent origin), w, h. Adjust to control margins.
	     text        "Amazing Let's try word wrapping this box exceeds screen width."
	     textscale 1
	     font "fonts/popsies"
 	}
}

Almost always, you use “rect 0,0,640,480” in the parent windowDef to establish a logical coordinate system stretched over the screen dimensions. By default, a TDM menu cursor will appear, to remind the user that they can exit early by clicking... really anywhere. You can suppress this cursor with "nocursor 1". Choose the font from the standard TDM ones (e.g., carleton is used for briefings). Adjust the font size with float "textscale", but 1 or less is best.

The text will be word-wrapped and left-justified. You can add "textalign 1" to center it (except first line stays left-justified; ugh. Stick in some leading spaces).

This is not very different than the standard atdm:gui_message treatment with the "...no_art" gui. However, if you want to have titles and paragraphs with different fonts, sizes, locations, or margins, you can just add additional windowDefs. So, for example, instead of full-screen, you could possibly use this method to provide a subtitle.

Case 2 – Opaque Black Background, White Letters

windowDef MySlide
{
	visible 1
	rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
	backcolor   0, 0, 0, 1 // Black background
	onAction {
	     set "MySlide::visible" "0"; 
	     set "gui::MySlideDone" "1";
	}
	windowDef Text1 { ... same as previous example ... }
}

With an opaque full-screen background, it is more necessary for the rest of the game to know when the slide is done, particularly if it’s up more than a few seconds. So onAction sets a variable, that can be then polled for in a script, shown next.

Sample Script Code to Put Up a Slide then Wait

void full_screen_slide()
{
  sys.trigger($atdm_gui_message_slide); // show the slide
 // Optionally add code here to move player to blue room.
 // We’ll need to get the gui’s overlay handle, from the attached default scriptobject, which is “tdm_gui_message”.
 // By casting, we get access to it here.
  tdm_gui_message e = $atdm_gui_message_slide;
  // Can take a while for the overlay handle to be created and for e.gui to be non-zero.
  // If spawnarg "delay" is zero, the default, a 0.1 second delay is imposed. 
  float handlenum = 0;
  while(handlenum == 0)
  {
  	  handlenum = e.gui;
	  sys.wait(0.1);
  }
  float maxtime = $atdm_gui_message_slide.getFloatKey("show");
  float slide_done == 0;
  while(maxtime > 0)
  {
	  slide_done = $player1.getGuiFloat(handlenum, "MySlideDone");
	  if(slide_done == 1) // user did gui's onAction, with LMB
		break;
	  maxtime -= 0.1;
	  sys.wait(0.1);
  }
  // Optionally add code here to move player from blue room.
  $player1.setGuiFloat(handlenum, "MySlideDone", 0); // reset just in case
}

Case 3 – Opaque Image Background, Black Letters

windowDef MySlide
{
	visible 1
	rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
	background	"models/darkmod/props/textures/parchment_freshpaper"
	onAction {
	     set "MySlide::visible" "0"; 
    }
    windowDef Text1 {
        rect        10, 10, 620, 460 // x, y (relative to parent origin), w, h
        text        "Amazing Let's try word wrapping this box exceeds screen width."
        forecolor   1, 1, 1, 1 // Black opaque font
        textscale 1
        font "fonts/popsies"
    }
}

Variants

We’re using a stock TDM background here, but you can have your FM include a custom .jpg, .tga, or .dds image as background. As is usual with TDM, “background” assumes the filepath from the FM’s root, and does not want the file extension to be stated here.

You could just burn the text into the background image. But translators will be unhappy unless you also provide them with the corresponding text-free image.

Case 4 – Two-Level Image Background, Black Letters

There are a number of pre-existing TDM "parchment" and "scroll" backgrounds that have wide transparent perimeters. You can substitute one of these directly (so you see the game world around the edges), or create a child windowDef with one of these, atop a parent’s opaque background (black in this example):

windowDef MySlide
{
	visible 1
	rect 0,0,640,480 // x, y, w, h. Origin upper-left screen corner.
	backcolor   0, 0, 0, 1 // Black background
	onAction {
	     set "MySlide::visible" "0"; 
	}
	windowDef Scroll1{
	     visible 1
	     rect 0,0,640,480 // x, y, w, h. This can be bigger than the parent if you want to reduce transparent perimeter
	     background	"dds/guis/assets/readables/scroll"
	}
	windowDef Text1 { ... same as previous example ... }
}

An Example

An outgrown of Case 4 can be found in FM “Away 0: Stolen Heart”, where it is used to put up a substitute full-screen slide when “Skip Cutscene” is selected.

Image here

This uses multiple windowDefs to position text blocks atop the scroll. The "Done" text provides a target for the cursor, but the gamer can really click anywhere. The corresponding script function (in emily_related.script) is far more complicated than above, because it handles FM-specific chores.

For More

The information here draws on 2004-vintage GUI tutorials by Doom creator John Cormac, but adapted to TDM.