Unlocking chapters in your mod: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(unlock caramelldansen in rockband)
(formatting)
 
(11 intermediate revisions by 7 users not shown)
Line 1: Line 1:
[[Category:Level Design]] [[Category:Tutorials]] [[Category:Programming]]
{{languageBar}}
 
=Valve Approach=
=Valve Approach=
This approach shows the ''best'' way to update chapters in your mod.
This approach shows the ''best'' way to update chapters in your mod.
== Renaming ==
== Renaming ==
Your maps should be renamed to conform to a pattern which allows you and the game to tell at a glance where a map is chronologically.  
Your maps should be renamed to conform to a pattern which allows you and the game to tell at a glance where a map is chronologically.


Notice [[Half-Life 2|Half-Life 2's]] maps are named according to this pattern:
Notice {{hl2|2}}'s maps are named according to this pattern:
"d#_areaname_##"
{{code|preset=1|d#_areaname_##}}
where  
where
* "#" represents the "day" of the game, is 1 for the beginning, 2 for the middle, and 3 for the endgame
* "#" represents the "day" of the game, is 1 for the beginning, 2 for the middle, and 3 for the endgame
* "##" is some numbered segment of an area "areaname"
* "##" is some numbered segment of an area "areaname"
Example: d1_trainstation_01
Example: {{code|preset=1|d1_trainstation_01}}


However, [[Half-Life|Half-Life 1's]] pattern might make unlocking the chapters a little easier:
However, {{hl|2}}'s pattern might make unlocking the chapters a little easier:
"c#a$"
{{code|preset=1|c#a$}}
where
where
* # is the '''c'''hapter number
* # is the '''c'''hapter number
* $ is the '''a'''rea of the chapter with an extra letter appended as necessary.
* $ is the '''a'''rea of the chapter with an extra letter appended as necessary.
Examples: c1a4 c4a1b
Examples: {{code|preset=1|c1a4}} {{code|preset=1|c4a1b}}


== Updating ==
== Updating ==
In <code>gameinterface.cpp</code>, modify <code>void UpdateChapterRestrictions( const char* mapname )</code> and the array <code>static TITLECOMMENT gTitleComments[]</code> to conform to your maps' naming format.
In {{path|gameinterface|cpp}}, modify {{code|preset=1|highlight=cpp|void UpdateChapterRestrictions( const char* mapname )}} and the array {{code|preset=1|highlight=cpp|static TITLECOMMENT gTitleComments[]}} to conform to your maps' naming format.


Each TITLECOMMENT in gTitleComments contains a <code>char* pBSPName</code> (the map name or part of a map name) and a <code>char* pTitleName</code> (the chapter that map or set of maps is part of). If you want the map e2m4 to be part of Chapter 2 of the mod Doom, add <code>{"e2m4", "#Doom_Chapter2_Title"}</code> to the array (with a trailing comma if it's not last, of course). Replace "e2m4" with simply "e2" and <i>all</i> maps starting with "e2" will be part of Chapter 2.
Each {{mono|TITLECOMMENT}} in {{mono|gTitleComments}} contains a {{code|preset=1|highlight=cpp|char* pBSPName}} (the map name or part of a map name) and a {{code|preset=1|highlight=cpp|char* pTitleName}} (the chapter that map or set of maps is part of). If you want the map e2m4 to be part of Chapter 2 of the mod Doom, add {{code|preset=1|{"e2m4", "#Doom_Chapter2_Title"} }} to the array (with a trailing comma if it's not last, of course). Replace "e2m4" with simply "e2" and ''all'' maps starting with "e2" will be part of Chapter 2.
 
Note the comment right above gTitleComments, which reads "This list gets searched for the first partial match, so some are out of order". Meaning, if e2m9 is part of Chapter 3 and the rest of the "e2" maps are in Chapter 2, then <code>{"e2m9", "#Doom_Chapter3_Title"}</code> must come <i>before</i> <code>{"e2", "#Doom_Chapter2_Title"}</code> in the array.
Note the comment right above {{mono|gTitleComments}}, which reads "This list gets searched for the first partial match, so some are out of order". Meaning, if e2m9 is part of Chapter 3 and the rest of the "e2" maps are in Chapter 2, then {{code|preset=1|{"e2m9", "#Doom_Chapter3_Title"} }} must come ''before'' {{code|preset=1|{"e2", "#Doom_Chapter2_Title"} }} in the array.


=== Necessary Fixes ===
=== Necessary Fixes ===
UpdateChapterRestrictions has an inherent flaw which only comes to light when Steam runs a Source mod. Steam puts the mod's entire path in the command line; the mod MyMod might be run with <code>hl2.exe -game "C:\Steam\SteamApps\SourceMods\MyMod"</code>.  
{{code|preset=1|UpdateChapterRestrictions}} has an inherent flaw which only comes to light when {{steamicon|4}} runs a {{src|4}} mod. {{steamicon|1}} puts the mod's entire path in the command line; the mod "MyMod" might be run with {{code|preset=1|hl2.exe -game "C:\Steam\SteamApps\SourceMods\MyMod"}}.


But UpdateChapterRestrictions assumes "-game" to be just "mymod"(Mod name in lowercase), so <code>char chapterNumberPrefix[64]</code> ends up as <code>#C:\Steam\SteamApps\SourceMods\MyMod_chapter</code>, rather than <code>#mymod_chapter</code> as it should be.
But {{code|preset=1|UpdateChapterRestrictions}} assumes "-game" to be just "mymod" (Mod name in lowercase), so {{code|preset=1|highlight=cpp|char chapterNumberPrefix[64]}} ends up as <code>#C:\Steam\SteamApps\SourceMods\MyMod_chapter</code>, rather than <code>#mymod_chapter</code> as it should be.


You can solve this problem in one of two ways. The first and easiest is to dispense with the "-game" parameter and simply hardcode "#mymod_chapter" as the chapterNumberPrefix. The second, which may be copied and pasted across mods, is to lop off the parent folders one by one, perhaps with strtok, until only the mod folder is left.
You can solve this problem in one of two ways. The first and easiest is to dispense with the "-game" parameter and simply hardcode <code>#mymod_chapter</code> as the {{mono|chapterNumberPrefix}}. The second, which may be copied and pasted across mods, is to lop off the parent folders one by one, perhaps with {{code|strtok|preset=1}}, until only the mod folder is left.


=Map Hack Approach=
=Map Hack Approach=
This tutorial will demonstrate unlocking chapters for your game mods using entities. If you are unfamiliar with adding chapters to your mod read and review the [[Adding chapters to your mod]] tutorial before this one.
This tutorial will demonstrate unlocking chapters for your game mods using entities. If you are unfamiliar with adding chapters to your mod read and review the [[Adding chapters to your mod]] tutorial before this one.


caramell dansen metal version in rockband
== Create the {{ent|trigger_once}} brush ==
Create a {{ent|trigger_once}} brush in Map2. This will be used as the trigger that will begin the process of unlocking a chapter. Map2 is the map that will be considered the first map for the second chapter. Be sure to give the {{ent|trigger_once}} brush a name, something like {{mono|"Trigger001_UnlockChapter2"}} for example.


== Create the point entities ==
== Create the point entities ==
Use the entity tool the create a [[logic_relay]] entity. Set the name of the logic_relay entity to '''Logic001_UnlockChapter2'''. Set the logic_relay '''Start Disabled''' property to Yes.
Use the entity tool the create a {{ent|logic_relay}} entity. Set the name of the {{ent|logic_relay}} entity to {{mono|"Logic001_UnlockChapter2"}}. Set the {{ent|logic_relay}} '''Start Disabled''' property to Yes.


Now use the entity tool to create a [[point_clientcommand]] entity, and set the name to '''UnlockChapter2'''.
Now use the entity tool to create a {{ent|point_clientcommand}} entity, and set the name to {{mono|"UnlockChapter2"}}.


== Add the outputs for the [[logic relay]] ==
== Add the outputs for the {{ent|logic_relay}} ==
Open the object properties dialog for the [[logic_relay]] entity we created earlier, and select the Outputs tab.
Open the object properties dialog for the {{ent|logic_relay}} entity we created earlier, and select the Outputs tab.
Now add two outputs using the add button and fill in the info as follows:
Now add two outputs using the add button and fill in the info as follows:
{|  
:{| border=1 cellpadding="2" cellspacing="1"
! My Output !!Target Entity!!Target Input!!Parameter!!Delay!!Only Once
|- align=left style="background:#DCDCDC; color:black"
|-  
!
| OnTrigger||UnlockChapter2||Command||incrementvar sv_unlockedchapters 2 100 -1||0.01||Yes
! My Output > !! Target Entity !! Target Input !! Parameter !! Delay !! Only Once
|-  
|-
| OnTrigger||UnlockChapter2||Command||incrementvar sv_unlockedchapters 2 100 1 ||0.02||Yes  
| [[File:Io11.png]] || OnTrigger || {{mono|UnlockChapter2}} || Command || {{mono|incrementvar sv_unlockedchapters 2 100 -1}} || 0.01 || Yes
|-
| [[File:Io11.png]] || OnTrigger || {{mono|UnlockChapter2}} || Command || {{mono|incrementvar sv_unlockedchapters 2 100 1}} || 0.02 || Yes
|}
|}


The '2' after the <code>incrementvar sv_unlockedchapters</code> is the chapter to make available. If you have more than 100 chapters in your mod (unlikely), make that value high enough to encompass them all.
The '2' after the {{cmd|incrementvar|sv_unlockedchapters}} is the chapter to make available. If you have more than 100 chapters in your mod (unlikely), make that value high enough to encompass them all.


===How it works===
===How it works===
The [[incrementvar]] command takes a minValue, a maxValue and a delta. Using a delta of <code>0</code> sets the sv_unlockedchapters to the maxValue which can be avoided by decrementing the var, then re-incrementing it, ensuring that the chapter to unlock is set, but not forcing it to that value if it is already higher.
The {{cmd|incrementvar}} command takes a minValue, a maxValue and a delta. Using a delta of {{code|preset=1|0}} sets the {{cmd|sv_unlockedchapters}} to the maxValue which can be avoided by decrementing the var, then re-incrementing it, ensuring that the chapter to unlock is set, but not forcing it to that value if it is already higher.


== Add the outputs for the [[trigger_once]] brush entity ==
== Add the outputs for the {{ent|trigger_once}} brush entity ==
Next open the object properties dialog box for the [[trigger_once]] entity we created earlier called '''Trigger001_UnlockChapter2''', and select the Outputs tab. Now add a output using the add button and fill in the info as it appears in the picture below...<br>
Next open the object properties dialog box for the {{ent|trigger_once}} entity we created earlier called {{mono|"Trigger001_UnlockChapter2"}}, and select the Outputs tab. Now add the outputs from the table below.
[[Image:UnlockChapObjectProps2.png]]
 
:{| border=1 cellpadding="2" cellspacing="1"
|- align=left style="background:#DCDCDC; color:black"
!
! My Output > !! Target Entity !! Target Input !! Parameter !! Delay !! Only Once
|-
| [[File:Io11.png]] || OnStartTouch || {{mono|Trigger001_UnlockChapter2}} || Enable || &nbsp; || 0.01 || Yes
|-
| [[File:Io11.png]] || OnStartTouch || {{mono|Trigger001_UnlockChapter2}} || Disable || &nbsp; || 0.05 || Yes
|-
| [[File:Io11.png]] || OnTrigger || {{mono|Logic001_UnlockChapter2}} || Enable || &nbsp; || 0.02 || Yes
|-
| [[File:Io11.png]] || OnTrigger || {{mono|Logic001_UnlockChapter2}} || Trigger || &nbsp; || 0.03 || Yes
|-
| [[File:Io11.png]] || OnTrigger || {{mono|Logic001_UnlockChapter2}} || Disable || &nbsp; || 0.04 || Yes
|}


== Testing ==
== Testing ==
Now save, compile, and run. After your mod is loaded, type <code>showtriggers 1</code> in console. Once you have done so, play the map and walk through the [[trigger_once]] entity. After you have walked through it, press escape and select '''New Game''' from the game menu. You should see that chapter 2 in your mod has been unlocked.  
Now save, compile, and run. After your mod is loaded, type {{cmd|showtriggers_toggle}} in the console. Once you have done so, play the map and walk through the {{ent|trigger_once}} entity. After you have walked through it, press escape and select '''New Game''' from the game menu. You should see that chapter 2 in your mod has been unlocked.
After you quit the game open up the {{path|cfg/config|cfg}} file in your mod and scroll down near the bottom of the file. You will notice that the line that used to read {{code|preset=1|sv_unlockedchapters "1"}} now reads {{code|preset=1|sv_unlockedchapters "2"}}.


After you quit the game open up the <code>cfg/config.cfg</code> file in your mod and scroll down near the botton of the file. You will notice that the line that used to read <code>sv_unlockedchapters "1"</code> now reads <code>sv_unlockedchapters "2"</code>.
[[Category:Level Design]]
[[Category:Tutorials]]
[[Category:Programming]]

Latest revision as of 11:59, 8 July 2025

English (en)Русский (ru)Translate (Translate)

Valve Approach

This approach shows the best way to update chapters in your mod.

Renaming

Your maps should be renamed to conform to a pattern which allows you and the game to tell at a glance where a map is chronologically.

Notice Half-Life 2 Half-Life 2's maps are named according to this pattern: d#_areaname_## where

  • "#" represents the "day" of the game, is 1 for the beginning, 2 for the middle, and 3 for the endgame
  • "##" is some numbered segment of an area "areaname"

Example: d1_trainstation_01

However, Half-Life Half-Life's pattern might make unlocking the chapters a little easier: c#a$ where

  • # is the chapter number
  • $ is the area of the chapter with an extra letter appended as necessary.

Examples: c1a4 c4a1b

Updating

In 🖿gameinterface.cpp, modify void UpdateChapterRestrictions( const char* mapname ) and the array static TITLECOMMENT gTitleComments[] to conform to your maps' naming format.

Each TITLECOMMENT in gTitleComments contains a char* pBSPName (the map name or part of a map name) and a char* pTitleName (the chapter that map or set of maps is part of). If you want the map e2m4 to be part of Chapter 2 of the mod Doom, add {"e2m4", "#Doom_Chapter2_Title"} to the array (with a trailing comma if it's not last, of course). Replace "e2m4" with simply "e2" and all maps starting with "e2" will be part of Chapter 2.

Note the comment right above gTitleComments, which reads "This list gets searched for the first partial match, so some are out of order". Meaning, if e2m9 is part of Chapter 3 and the rest of the "e2" maps are in Chapter 2, then {"e2m9", "#Doom_Chapter3_Title"} must come before {"e2", "#Doom_Chapter2_Title"} in the array.

Necessary Fixes

UpdateChapterRestrictions has an inherent flaw which only comes to light when Steam Steam runs a Source Source mod. Steam puts the mod's entire path in the command line; the mod "MyMod" might be run with hl2.exe -game "C:\Steam\SteamApps\SourceMods\MyMod".

But UpdateChapterRestrictions assumes "-game" to be just "mymod" (Mod name in lowercase), so char chapterNumberPrefix[64] ends up as #C:\Steam\SteamApps\SourceMods\MyMod_chapter, rather than #mymod_chapter as it should be.

You can solve this problem in one of two ways. The first and easiest is to dispense with the "-game" parameter and simply hardcode #mymod_chapter as the chapterNumberPrefix. The second, which may be copied and pasted across mods, is to lop off the parent folders one by one, perhaps with strtok, until only the mod folder is left.

Map Hack Approach

This tutorial will demonstrate unlocking chapters for your game mods using entities. If you are unfamiliar with adding chapters to your mod read and review the Adding chapters to your mod tutorial before this one.

Create the trigger_once brush

Create a trigger_once brush in Map2. This will be used as the trigger that will begin the process of unlocking a chapter. Map2 is the map that will be considered the first map for the second chapter. Be sure to give the trigger_once brush a name, something like "Trigger001_UnlockChapter2" for example.

Create the point entities

Use the entity tool the create a logic_relay entity. Set the name of the logic_relay entity to "Logic001_UnlockChapter2". Set the logic_relay Start Disabled property to Yes.

Now use the entity tool to create a point_clientcommand entity, and set the name to "UnlockChapter2".

Add the outputs for the logic_relay

Open the object properties dialog for the logic_relay entity we created earlier, and select the Outputs tab. Now add two outputs using the add button and fill in the info as follows:

My Output > Target Entity Target Input Parameter Delay Only Once
Io11.png OnTrigger UnlockChapter2 Command incrementvar sv_unlockedchapters 2 100 -1 0.01 Yes
Io11.png OnTrigger UnlockChapter2 Command incrementvar sv_unlockedchapters 2 100 1 0.02 Yes

The '2' after the incrementvar sv_unlockedchapters is the chapter to make available. If you have more than 100 chapters in your mod (unlikely), make that value high enough to encompass them all.

How it works

The incrementvar command takes a minValue, a maxValue and a delta. Using a delta of 0 sets the sv_unlockedchapters to the maxValue which can be avoided by decrementing the var, then re-incrementing it, ensuring that the chapter to unlock is set, but not forcing it to that value if it is already higher.

Add the outputs for the trigger_once brush entity

Next open the object properties dialog box for the trigger_once entity we created earlier called "Trigger001_UnlockChapter2", and select the Outputs tab. Now add the outputs from the table below.

My Output > Target Entity Target Input Parameter Delay Only Once
Io11.png OnStartTouch Trigger001_UnlockChapter2 Enable   0.01 Yes
Io11.png OnStartTouch Trigger001_UnlockChapter2 Disable   0.05 Yes
Io11.png OnTrigger Logic001_UnlockChapter2 Enable   0.02 Yes
Io11.png OnTrigger Logic001_UnlockChapter2 Trigger   0.03 Yes
Io11.png OnTrigger Logic001_UnlockChapter2 Disable   0.04 Yes

Testing

Now save, compile, and run. After your mod is loaded, type showtriggers_toggle in the console. Once you have done so, play the map and walk through the trigger_once entity. After you have walked through it, press escape and select New Game from the game menu. You should see that chapter 2 in your mod has been unlocked. After you quit the game open up the 🖿cfg/config.cfg file in your mod and scroll down near the bottom of the file. You will notice that the line that used to read sv_unlockedchapters "1" now reads sv_unlockedchapters "2".