Level Endings - Classic Style
by
AkyV
Download a project file illustrating this tutorial
I think everybody who played Tomb Raider before TR4 knows what 'classic level-ending' means:
So, the game freezes, the list of statistics
pops up and we can hear a typical audio file. And, after that, the game
loads the next level, of course.
And we can do the same in NGLE:
It's easy:
1. Don't use FINISH trigger
where you want the end of the level. Instead of that, place a FLIPEFFECT
there that activates a TriggerGroup - for example, TriggerGroup#1:
; Set
Trigger Type - FLIPEFFECT 118
;
Exporting: TRIGGER(257:0) for FLIPEFFECT(118)
; <#> :
TriggerGroup. Perform <&>TriggerGroup from script.dat in (E)way
; <&> :
TriggerGroup= 1
; (E) :
Single performing (to use when in TriggerGroup there are only commands)
; Values
to add in script command: $2000, 118, $101
2. Place the entry of that TriggerGroup in the Script:
TriggerGroup= 1, $2000, 130, $0, $2000, 129, $2C, $2000, 223, $0, $2000,
82, $2
; Set
Trigger Type - FLIPEFFECT 130
;
Exporting: TRIGGER(0:0) for FLIPEFFECT(130)
; <#> :
Sound. (CD) Stop CD track of <&>Channel
; <&> :
Channel 1 (Background track)
;
(E) :
; Values
to add in script command: $2000, 130, $0
; Set
Trigger Type - FLIPEFFECT 129
;
Exporting: TRIGGER(44:0) for FLIPEFFECT(129)
; <#> :
Sound. (CD) Play <&>CD track in (E) way on channel2
; <&> :
AUDIO\044
; (E) :
Single playback
; Values
to add in script command: $2000, 129, $2C
; Set
Trigger Type - FLIPEFFECT 223
;
Exporting: TRIGGER(0:0) for FLIPEFFECT(223)
; <#> :
Show Statistics Screen
;
<&> :
;
(E) :
; Values
to add in script command: $2000, 223, $0
; Set
Trigger Type - FLIPEFFECT 82
;
Exporting: TRIGGER(2:0) for FLIPEFFECT(82)
; <#> :
Delay. Load <&>level in (E)seconds
;
<&> : 2
; (E) :
Forever (use other action/effect to disable it)
; Values
to add in script command: $2000, 82, $2
So that's what happens when TriggerGroup#1 has just been activated:
1. The background audio stops.
2. Then that 'typical audio'
of audio folder starts. - In this example that audio file has ID 044.
(But it could be anything else.)
3. Then the game freezes and the
Statistics Screen pops up.
4. Hit ESC. - This is the way to close
Statistics Screen and make the TriggerGroup go on.
So, if you hit
ESC, then the Statistics closes and the game starts to load the level
that has the given [Level] block in Script. In this example that block
is the second one. (But it could be anything else.)
Notes:
1. Now we use 'single playback' for the typical audio, as in TR2.
But you can use loop mode, as in TR3, if you want. (Still on channel2.)
2. Nothing will be activated if the game awaits the player to hit
ESC.
That's why you can't place the audio triggers between the
triggers of the Statistics and the level-jump.
3. When the player
hits ESC then the game will be active for a short moment, after the
frozen state expired, before the loading starts.
In some situations
it could be a bit ugly. - Just think about it with this example:
Lara
has just jumped back, to grab a ledge and hang down. Under her, there's
the square with the TriggerGroup#1-activator trigger. So the game
freezes, the Statistics Screen pops up. The player releases CTRL and hit
ESC. The game will be active for a moment so the player will see Lara
falling down before the level-jump, because CTRL isn't just pushed down.
4. It's not a problem if you
use that setup at the 'temporary end' of a level - i.e. if you can get
back to that level later.
Moreover, actually, you can use the setup
anywhere in the level (reform that to work properly under the new
circumstances: for example, you don't need level-jumping trigger in this
case, of course), 'just to show the Statistics for the player, before
(s)he continues playing'.
5. Don't forget to clear up and adjust
the usual specialties of the level-jump:
Is ResetHUB needed?
Is
Lara just riding a motorbike when jumping to the other level?
Etc.
New
type statistics
You don't need
to use the Statistics Screen everyway. I.e. you can use your own
statistics, if you want.
Now I show in a simple example how to make
your own statistics:
a, You will use a background picture where
the statistics entries will be written on. - Save the picture in Pix
subfolder of Level Editor main folder, with name 'Image', an ID and BMP
extension, for example, as Image11.bmp.
I mean, in fact, this is only
a frame, because the picture will cover the texts, so the picture is
transparent at the points where it is overlapped with the texts. - This
time the frame is very simple:
The magenta part should be
transparent in the game.
You need an Image command in Script for
that bmp:
Image= 1, 11, IF_TRANSPARENCE+IF_QUIT_ESCAPE,
IGNORE, IGNORE, 250, 250, 500, 500
The Image#1 command says it
will use Image11.bmp, placed it in '250, 250, 500, 500' position.
IF_TRANSPARENCE means the magenta part will be transparent.
The
presence of the picture will freeze the game (if it doesn't, then the
Image#1 command had an IF_POP_IMAGE constant).
IF_QUIT_ESCAPE means
you will delete the picture off the screen by hitting ESC.
The
picture will be drawn on the screen by this trigger:
; Set
Trigger Type - FLIPEFFECT 217
;
Exporting: TRIGGER(1:0) for FLIPEFFECT(217)
; <#> :
Images. Show image with data in <&>Image script command for (E)Seconds
; <&> :
Image= 1
; (E) :
Forever (use other action/effect to disable it)
; Values
to add in script command: $2000, 217, $1
----------------------------------
b, The Statistics will
show now these things:
- title ('Statistics') with the name of
the level
- how many big medipacks Lara's used in the level so far
- how many enemies Lara's shot in the level so far
This trigger
will print the title and the level name on the screen:
; Set
Trigger Type - FLIPEFFECT 203
;
Exporting: TRIGGER(256:0) for FLIPEFFECT(203)
; <#> :
Text. Print formatted text <&>ExtaNg string with (E)formatting data
; <&> :
0: Statistics\nCOASTAL RUINS
; (E) :
Parameters=PARAM_PRINT_TEXT, 1
; Values
to add in script command: $2000, 203, $100
As you see, the title and the level name come from ExtraNG #0 entry
now. ('\n' means: 'I hit ENTER'.)
This is the PARAM_PRINT_TEXT that
the trigger uses:
Parameters= PARAM_PRINT_TEXT, 1, CL_RED,
IGNORE, IGNORE, IGNORE, 300, 300
So the text will be red, and in
'300, 300' position.
----------------------------------
The medipack amount will be calculated with this GlobalTrigger now:
GlobalTrigger= 1, IGNORE, GT_USED_BIG_MEDIPACK, IGNORE, IGNORE, 4,
IGNORE
So, if Lara uses a big medipack then TriggerGroup#4 will
be activated:
TriggerGroup= 4, $2000, 231, $148
; Set
Trigger Type - FLIPEFFECT 231
;
Exporting: TRIGGER(328:0) for FLIPEFFECT(231)
; <#> :
Variables. Numeric. Add to <&>Variable the (E)value
; <&> :
Local Byte Delta1
; (E) :
Value 1
; Values
to add in script command: $2000, 231, $148
It means 1 will be added to Local Byte Delta1 variable every time
when Lara uses a big medipack.
This trigger will print the entry
of the big medipack on the screen:
; Set
Trigger Type - FLIPEFFECT 203
;
Exporting: TRIGGER(513:0) for FLIPEFFECT(203)
; <#> :
Text. Print formatted text <&>ExtaNg string with (E)formatting data
; <&> :
1: Big Medipack Used #0048
; (E) :
Parameters=PARAM_PRINT_TEXT, 2
; Values
to add in script command: $2000, 203, $201
As you see, the 'Big Medipack Used' text and its actual value (#0048
means the value of Local Byte Delta1) - i.e. how many big medipacks
Lara's used so far in the level - come from ExtraNG #1 entry now.
This is the PARAM_PRINT_TEXT that the trigger uses:
Parameters=
PARAM_PRINT_TEXT, 2, CL_GOLD, IGNORE, IGNORE, IGNORE, 300, 400
So
the text will be colored gold, and in '300, 400' position.
----------------------------------
The killed (shot) enemies will
be calculated this way now:
First of all, place this trigger on a
square where LARA object is placed:
; Set
Trigger Type - FLIPEFFECT 244
;
Exporting: TRIGGER(20560:0) for FLIPEFFECT(244)
; <#> :
Variables. Memory. Copy to <&>Numeric Variable the (E)Savegame Memory
value
; <&> :
Local Short Alfa1
; (E) :
Statistics. Killed Enemies (Short)
; Values
to add in script command: $2000, 244, $5050
So, if Lara starts this level then the data about how many enemies
she's killed so far will goes to Local Short Alfa1 variable. (Be
careful: this trigger is not allowed to be activated again.)
When
the level ends, this trigger records the data about how many enemies
Lara's killed so far - and puts the value into Current Value variable:
; Set
Trigger Type - FLIPEFFECT 244
;
Exporting: TRIGGER(20735:0) for FLIPEFFECT(244)
; <#> :
Variables. Memory. Copy to <&>Numeric Variable the (E)Savegame Memory
value
; <&> :
Current Value
; (E) :
Statistics. Killed Enemies (Short)
; Values
to add in script command: $2000, 244, $50FF
Then this trigger subtracts the starting value (Local Short Alfa1)
from the ending value (Current Value), giving a new value to Current
Value:
; Set
Trigger Type - FLIPEFFECT 286
;
Exporting: TRIGGER(80:0) for FLIPEFFECT(286)
; <#> :
Variables. Numeric. Subtract from CurrentValue the <&>Numeric Variable
; <&> :
Local Short Alfa1
;
(E) :
; Values
to add in script command: $2000, 286, $50
(So, for example, if the starting value is 18 and the ending value
is 27, then 27-18=9 will be the new value of the Current Value that
means Lara's shot 9 enemies in the level.)
This trigger will
print the entry of the killed enemies on the screen:
; Set
Trigger Type - FLIPEFFECT 203
;
Exporting: TRIGGER(770:0) for FLIPEFFECT(203)
; <#> :
Text. Print formatted text <&>ExtaNg string with (E)formatting data
; <&> :
2: Enemy Killed #0800
; (E) :
Parameters=PARAM_PRINT_TEXT, 3
; Values
to add in script command: $2000, 203, $302
As you see, the 'Enemy Killed' text and its actual value (#0800
means the value of Current Value) come from ExtraNG #2 entry now.
This is the PARAM_PRINT_TEXT that the trigger uses:
Parameters=
PARAM_PRINT_TEXT, 3, CL_GOLD, IGNORE, IGNORE, IGNORE, 300, 450
So
the text will be colored gold, and in '300, 450' position.
(See
more about these Script commands and constants in NG Center\Reference,
and about the variables in Variables demo project of Paolone.)
And the solution is:
Attention!
As you
see, the example above shows level data and not game data.
And now, let's see the whole script setup:
TriggerGroup= 1,
$2000, 127, $1
TriggerGroup= 2, $2000, 130, $0, $2000, 129, $2C,
$2000, 203, $100, $2000, 203, $201, >
$2000, 244, $50FF, $2000, 286,
$50, $2000, 203, $302
TriggerGroup= 3, $2000, 217, $1, $2000, 82, $2
TriggerGroup= 4, $2000, 231, $148
Organizer= 1, FO_TICK_TIME, IGNORE,
0, 2, 1, 3
Image= 1, 11, IF_TRANSPARENCE+IF_QUIT_ESCAPE, IGNORE,
IGNORE, 250, 250, 500, 500
Parameters= PARAM_PRINT_TEXT, 1, CL_RED,
IGNORE, IGNORE, IGNORE, 300, 300
Parameters= PARAM_PRINT_TEXT, 2,
CL_GOLD, IGNORE, IGNORE, IGNORE, 300, 400
Parameters=
PARAM_PRINT_TEXT, 3, CL_GOLD, IGNORE, IGNORE, IGNORE, 300, 450
GlobalTrigger= 1, IGNORE, GT_USED_BIG_MEDIPACK, IGNORE, IGNORE, 4,
IGNORE
And that's what will happen in the game:
First of all,
Lara activates TRIGGER(20560:0) for FLIPEFFECT(244) trigger at the start
of the level to define the killed enemies actual value.
Later, when
Lara activates TriggerGroup#1 at the end of the level by TRIGGER(257:0)
for FLIPEFFECT(118) trigger, then it means Organizer#1 will be activated
($2000, 127, $1). - We need an Organizer to split the operation into two
parts with some time slip now, or else it won't work properly. (As you
see - by FO_TICK_TIME constant and the second 1 in the Organizer= 1
command - the time slip is very small, only 1 frame.)
The first part
of the operation is defined in TriggerGroup#2 that is activated at once
(see '0, 2' in Organizer= 1) when Lara reaches the end of the level.
TriggerGroup#2 stops the background audio ($2000, 130, $0), starts
044.wav ($2000, 129, $2C), prints the title+level name ($2000, 203,
$100), and prints the bigmedi data ($2000, 203, $201). Then calculates
the 'killed enemies' data ($2000, 244, $50FF, $2000, 286, $50) and
prints that ($2000, 203, $302).
The second part of the operation is
defined in TriggerGroup#3 that is activated (see '1, 3' in Organizer= 1)
1 frame after TriggerGroup#2 has been activated.
TriggerGroup#3 puts
Image11.bmp on the screen ($2000, 217, $1), and - if the player hits ESC
so that TriggerGroup#3 can continue - loads Level#2 ($2000, 82, $2).
Note:
Be cautious with the setup if it contains level data and not game data.
For example, do you want that value of the big medipack (Local Byte
Delta1) to be zero when Lara comes back to the level? Because, if you
make that zero (somehow), then the Statistics will show you partial data
when Lara leaves the level (finally, this time). But if you don't make
that zero then the partial data of the first level part and the partial
data of the second level part will be added in the Statistics at the
final end of the level and shows total big medipack data on the level.
Forming the texts
As you see above, you can do text-forming customization on your
Statistics (color, position etc.) - anyway, whether you use the original
Statistics or some new one.
Caring about forming texts is a bit
complicated in NGLE so I decided I'd show you all the forming rules, and
not only the ones about the Statistics.
First of
all, I'll define the text types I'll use in the description below:
- OLD TEXT: texts you can also find in TRLR or TRLE: texts in the
inventory, in the Statistics Screen etc.
- NGLE TEXT: texts
(except Ammo and Feature Text) that the new NGLE features use: the
amount of done rotations (parallel bars), the text for the standby
effect, the timer of 'Enemy. Timer. Show the trigger count-down for
<#>enemy using (E)format' ACTION trigger etc.
- AMMO TEXT: text
that is used for showing ammo amount on the screen (this time it is not
the ammo amount in the inventory)
- FEATURE TEXT: texts of
text/picture NGLE features (diary, new savegame panel)
-
INDEPENDENT TEXT: texts that you write mostly into ExtraNG section of
Strings to print them by Text FLIPEFFECTs
To form the texts, these are the tools:
- Defining basic fonts (except Feature Text) for all the levels of the
game: see font.pc in graphics\wads folder.
- Defining fonts (except Feature Text) for a given level: put a
FONT_GRAPHICS object into the WAD of the level (see: new font demo
project of Paolone), then use NG Font Editor in NG Center\Tools.
- Defining fonts for Feature Text: see WindowsFont Script command.
- Customizing Old Text colors: see CUST_SET_TEXT_COLOR Script constant.
(It works only on the kind of Old Text you give in the command.)
Customizing of the level texts, the customization command must be placed
in a [Level] block usually.
Customizing of the level texts - if you want the validity of the
customization for the whole game - or the title texts, the customization
command must be placed in [Title] block.
- Customizing (in Script) Old Text sizes: see TextFormat Script command
(only SizeCharacterMenu field is valid now), placing that in [Title]
block. Valid for all the Old Texts of the game (except: the text of
Legend Script command).
- Customizing (in Script) NGLE Texts: see TextFormat command (every
field is valid now, except SizeCharacterMenu), placing that in a [Level]
block. - Using an NGLE feature like that in the title you can use
TextFormat in [Title] block to form the text of the feature.
(I think this operation doesn't work on all the NGLE texts. It works,
for example, for the standby effect text or the enemy timer etc.)
- Customizing (in the game) NGLE Texts, if they can be affected by
TextFormat command: use 'Text. Set' FLIPEFFECTs. It overwrites (on that
level) TextFormat command values or the latest similar 'Text. Set'
trigger of that level. It works for the texts that are just written or
the texts that will be written. It is valid only on that level, until
the next FLIPEFFECT like that.
- Annulling (on the actual level) every effect of TextFormat command or
all 'Text. Set' FLIPEFFECTs for the NGLE Texts that are just written or
the NGLE Texts that will be written: see 'Text. Reset all text
formatting settings with default values' FLIPEFFECT.
- Customizing Ammo Text: see CUST_SHOW_AMMO_COUNTER Script constant.
Place it in a [Level] block usually. Place it in [Title] block, if you
want it to be valid for the whole game.
- Customizing (in Script) 'A' type Independent Texts: see TextFormat
command (every field is valid now, except SizeCharacterMenu), placing
that in a [Level] block. - Using a text like that in the title level you
can use TextFormat in [Title] block to form the text.
'A' type Independent Texts are the texts that will be written on the
screen by a FLIPEFFECT that doesn't use a PARAM_PRINT_TEXT Script
constant.
- Customizing (in the game) 'A' type Independent Texts: use 'Text. Set'
FLIPEFFECTs. It overwrites (on that level) TextFormat command values or
the latest similar 'Text. Set' trigger of that level. It works for the
texts that will be written. It is valid only on that level, until the
next FLIPEFFECT like that. - Only the proper FLIPEFFECT can be used.
- Annulling (on the actual level) every effect of TextFormat command or
all 'Text. Set' FLIPEFFECTs for the 'A' type Independent Texts that will
be written: see 'Text. Reset all text formatting settings with default
values' FLIPEFFECT.
- Customizing 'B' type Independent Texts: see PARAM_PRINT_TEXT Script
constant.
'B' type Independent Texts are the texts that will be written on the
screen by a FLIPEFFECT that uses a PARAM_PRINT_TEXT Script constant.
Made
using TRNG 1.2.2.6