Skip to content

Commit d8131ab

Browse files
authored
QtFRED help dialog and documentation (scp-fs2open#7380)
* help dialog and documentation * compile help in headless mode * scene browser help file * attempt to get CI working for linux * debug attempt * Fix split method to use QString::SkipEmptyParts * Revert "debug attempt" This reverts commit cb046e1. * clang * update help * correct name * Inject sexps.html into help and add find in page controls * update help based on recent commits * better tutorial asset loading * no const * update help again
1 parent 1d63244 commit d8131ab

74 files changed

Lines changed: 5351 additions & 3 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

code/cfile/cfile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
8585
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
8686
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA },
8787
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
88-
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA }
88+
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html .qch .css .png .jpg", CF_TYPE_DATA }
8989
};
9090
// clang-format on
9191

qtfred/CMakeLists.txt

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ SET(QT5_INSTALL_ROOT "" CACHE PATH
88

99
list(APPEND CMAKE_PREFIX_PATH "${QT5_INSTALL_ROOT}")
1010

11-
find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED)
11+
find_package(Qt5 COMPONENTS Widgets OpenGL Help REQUIRED)
1212

1313
include(source_groups.cmake)
1414

@@ -56,7 +56,7 @@ set(CMAKE_MAP_IMPORTED_CONFIG_FASTDEBUG Release Debug)
5656
target_link_libraries(qtfred
5757
PUBLIC
5858
code
59-
Qt5::Widgets Qt5::OpenGL)
59+
Qt5::Widgets Qt5::OpenGL Qt5::Help)
6060

6161
include(CreateLaunchers)
6262
create_target_launcher(qtfred
@@ -72,6 +72,66 @@ INSTALL(
7272
)
7373
COPY_FILES_TO_TARGET(qtfred)
7474

75+
# --- QtFRED built-in help ---
76+
get_target_property(_QTFRED_QMAKE Qt5::qmake IMPORTED_LOCATION)
77+
execute_process(
78+
COMMAND "${_QTFRED_QMAKE}" -query QT_INSTALL_BINS
79+
OUTPUT_VARIABLE _QTFRED_QT_BINS
80+
OUTPUT_STRIP_TRAILING_WHITESPACE)
81+
execute_process(
82+
COMMAND "${_QTFRED_QMAKE}" -query QT_INSTALL_LIBS
83+
OUTPUT_VARIABLE _QTFRED_QT_LIBS
84+
OUTPUT_STRIP_TRAILING_WHITESPACE)
85+
find_program(QHELPGENERATOR_EXECUTABLE
86+
NAMES qhelpgenerator
87+
HINTS "${_QTFRED_QT_BINS}"
88+
REQUIRED)
89+
90+
set(QTFRED_HELP_QHP "${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/qtfred.qhp")
91+
set(QTFRED_HELP_QCH "${CMAKE_CURRENT_BINARY_DIR}/qtfred_help.qch")
92+
93+
file(GLOB_RECURSE QTFRED_HELP_SOURCES
94+
"${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/*.html"
95+
"${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/*.css"
96+
"${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/*.qhp")
97+
98+
# qhelpgenerator is a Qt application and needs a platform plugin at build time.
99+
# On headless Linux CI the Qt platform plugins fail to dlopen because the Qt
100+
# shared libs are not in LD_LIBRARY_PATH for dlopen-loaded plugins (DT_RUNPATH
101+
# in the main binary does not propagate to dlopen). Pass the Qt lib dir and
102+
# force the offscreen (no-display) platform explicitly.
103+
add_custom_command(
104+
OUTPUT "${QTFRED_HELP_QCH}"
105+
COMMAND ${CMAKE_COMMAND} -E env
106+
"QT_QPA_PLATFORM=offscreen"
107+
"LD_LIBRARY_PATH=${_QTFRED_QT_LIBS}"
108+
"${QHELPGENERATOR_EXECUTABLE}" "${QTFRED_HELP_QHP}" -o "${QTFRED_HELP_QCH}"
109+
DEPENDS ${QTFRED_HELP_SOURCES}
110+
COMMENT "Compiling QtFRED help (qtfred_help.qch)"
111+
VERBATIM)
112+
113+
add_custom_target(qtfred_help
114+
DEPENDS "${QTFRED_HELP_QCH}"
115+
SOURCES ${QTFRED_HELP_SOURCES})
116+
117+
add_dependencies(qtfred qtfred_help)
118+
119+
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/help-src"
120+
PREFIX "help-src"
121+
FILES ${QTFRED_HELP_SOURCES})
122+
123+
add_custom_command(TARGET qtfred_help POST_BUILD
124+
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:qtfred>/help"
125+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
126+
"${QTFRED_HELP_QCH}"
127+
"$<TARGET_FILE_DIR:qtfred>/help/qtfred_help.qch"
128+
VERBATIM)
129+
130+
install(FILES "${QTFRED_HELP_QCH}"
131+
DESTINATION ${BINARY_DESTINATION}/help
132+
COMPONENT "qtFRED")
133+
# --- end QtFRED built-in help ---
134+
75135
enable_clang_tidy(qtfred)
76136

77137
if (WIN32)
@@ -120,6 +180,19 @@ if (WIN32)
120180
DESTINATION ${BINARY_DESTINATION}/platforms
121181
COMPONENT "qtFRED"
122182
)
183+
184+
# Qt Help requires the SQLite SQL driver
185+
set(qsqlite_path "${QT_INSTALL_PLUGINS}/sqldrivers/qsqlite$<$<CONFIG:Debug>:d>.dll")
186+
187+
add_custom_command(TARGET qtfred
188+
POST_BUILD
189+
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${qsqlite_path}" "$<TARGET_FILE_DIR:qtfred>/sqldrivers/qsqlite$<$<CONFIG:Debug>:d>.dll"
190+
VERBATIM)
191+
192+
install(FILES ${qsqlite_path}
193+
DESTINATION ${BINARY_DESTINATION}/sqldrivers
194+
COMPONENT "qtFRED"
195+
)
123196
elseif(FSO_BUILD_APPIMAGE)
124197
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen" @ONLY)
125198
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<title>AI - QtFRED Help</title>
6+
<link rel="stylesheet" type="text/css" href="../css/help.css"/>
7+
</head>
8+
<body>
9+
<nav class="breadcrumb"><a href="../index.html">QtFRED Help</a> &rsaquo; Concepts &rsaquo; AI</nav>
10+
<h1>AI</h1>
11+
<p>Ship AI behavior in FSO is controlled by three layered systems: the
12+
<strong>AI profile</strong>, the <strong>AI class</strong>, and
13+
<strong>AI goals and orders</strong>. Each layer handles a different aspect of
14+
behavior and they work together at runtime.</p>
15+
16+
<h2>AI profile</h2>
17+
<p>The AI profile is a mission-wide setting chosen in
18+
<a href="../dialogs/MissionSpecsDialog.html">Mission Specs</a>. It is primarily a
19+
<strong>difficulty scaling system</strong>: it defines per-difficulty-level values
20+
for things like damage multipliers, weapon fire delays, turn time, shield recharge
21+
rates, and aim behavior; controlling how the mission feels across the Very Easy
22+
through Insane difficulty range. Profiles also contain a large set of behavioral
23+
flags that toggle specific AI behaviors on or off.</p>
24+
<p>Profiles are defined in <code>ai_profiles.tbl</code> and missions select from
25+
that list; custom profiles cannot be defined inside the mission file itself. If no
26+
profile is specified, the table's default profile is used. Most missions are fine
27+
with the default.</p>
28+
29+
<h2>AI class</h2>
30+
<p>The AI class is a named skill preset assigned to individual ships. It controls
31+
the skill level of that specific ship within the envelope set by the profile;
32+
how well it aims, how it maneuvers, how it uses afterburners, and so on.</p>
33+
<p>Every ship class has a default AI class defined in its table entry. The
34+
<a href="../dialogs/ShipEditorDialog.html">Ship Editor</a> lets you override that
35+
default for a specific ship instance, and individual turrets can be given their
36+
own AI class in the <a href="../dialogs/ShipWeaponsDialog.html">Weapons</a>
37+
dialog.</p>
38+
39+
<h2>AI goals and orders</h2>
40+
<p>Goals and orders are specific tasks assigned to a ship or wing: attack a
41+
target, guard a ship, dock with a vessel, fly a waypoint path, and so on. There
42+
are two ways to set them:</p>
43+
<ul>
44+
<li><strong>Initial orders</strong> - set in the
45+
<a href="../dialogs/ShipInitialOrdersDialog.html">Initial Orders</a>
46+
dialog. These are the tasks a ship starts the mission with.</li>
47+
<li><strong>Runtime goals</strong> - issued via SEXPs during the mission,
48+
typically from events. These override or supplement initial orders.</li>
49+
</ul>
50+
<p>When a ship has multiple active goals, it pursues them in priority order.
51+
Priority is a value from 1 to 200 where higher values take precedence. Goals
52+
issued by the player via the comm menu use priorities in the 90–100 range, so
53+
goals with a priority above 89 may outrank player orders.</p>
54+
55+
<h2>How the layers interact</h2>
56+
<p>Think of it as: the <strong>profile</strong> sets the rules of the game, the
57+
<strong>class</strong> sets how skilled the ship is within those rules, and the
58+
<strong>goals and orders</strong> tell the ship what to do. A high-skill AI
59+
class given a low-priority goal can still be overridden by a player order; a
60+
locked-in high-priority goal will hold regardless of player input.</p>
61+
</body>
62+
</html>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<title>Campaign Flow - QtFRED Help</title>
6+
<link rel="stylesheet" type="text/css" href="../css/help.css"/>
7+
</head>
8+
<body>
9+
<nav class="breadcrumb"><a href="../index.html">QtFRED Help</a> &rsaquo; Concepts &rsaquo; Campaign Flow</nav>
10+
<h1>Campaign Flow</h1>
11+
<p>A campaign is a sequence of missions linked together in the
12+
<a href="../dialogs/CampaignEditorDialog.html">Campaign Editor</a>. The campaign
13+
file controls which mission plays next, branches the story based on outcomes, and
14+
carries state between missions through goals and variables.</p>
15+
16+
<h2>How missions end</h2>
17+
<p>A mission ends when the player reaches the debrief screen. There are two
18+
distinct end conditions that affect what state is saved:</p>
19+
<table>
20+
<tr><th>Condition</th><th>When it occurs</th><th>What is saved</th></tr>
21+
<tr><td>Mission completed</td><td>The player accepts the debriefing after
22+
flying the mission.</td><td>Variables with <em>Save on Mission
23+
Completed</em> persistence, plus all goal states.</td></tr>
24+
<tr><td>Mission closed</td><td>The player exits the mission by any means,
25+
including failure or replaying.</td><td>Variables with <em>Save on Mission
26+
Close</em> persistence.</td></tr>
27+
</table>
28+
29+
<h2>Goal states</h2>
30+
<p>Every mission goal ends in one of three states: complete, failed, or
31+
incomplete. The campaign SEXP tree reads these states using
32+
<code>goal-true</code> and <code>goal-false</code> operators to decide which
33+
mission to branch to next. This is how outcomes carry forward; whether an
34+
important ship survived, whether a bonus objective was met, and so on.</p>
35+
<p>Goals do not automatically determine success or failure. The campaign SEXPs
36+
are what interpret goal states and produce outcomes. A mission where all primary
37+
goals are complete can still branch to a "defeat" mission if the campaign logic
38+
is written that way.</p>
39+
40+
<h2>Variables across missions</h2>
41+
<p>Variables set during a mission only persist into subsequent missions if their
42+
persistence is configured accordingly. See the
43+
<a href="../dialogs/VariablesAndContainersDialog.html">Variables &amp; Containers</a>
44+
dialog for the persistence options. Variables saved to the player file
45+
(<em>Eternal</em>) persist for the lifetime of the player profile, even across
46+
different campaigns.</p>
47+
48+
<h2>Branching</h2>
49+
<p>The campaign editor arranges missions as nodes connected by branches. Each
50+
branch has a SEXP condition. After a mission completes, the engine evaluates the
51+
outgoing branches in order and follows the first one whose condition is true. If
52+
no branch condition is met, the player is returned to the main menu. To end the
53+
campaign properly (playing the end cutscene and triggering campaign completion)
54+
use the <code>end-campaign</code> SEXP.</p>
55+
<p>Common branching patterns include:</p>
56+
<ul>
57+
<li>Checking whether a primary goal succeeded to route to a victory or
58+
defeat mission.</li>
59+
<li>Checking whether an optional goal was completed to unlock bonus
60+
missions.</li>
61+
<li>Reading a variable set earlier in the campaign to take a story
62+
branch.</li>
63+
</ul>
64+
</body>
65+
</html>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<title>Custom Data - QtFRED Help</title>
6+
<link rel="stylesheet" type="text/css" href="../css/help.css"/>
7+
</head>
8+
<body>
9+
<nav class="breadcrumb"><a href="../index.html">QtFRED Help</a> &rsaquo; Concepts &rsaquo; Custom Data</nav>
10+
<h1>Custom Data</h1>
11+
12+
<div class="stub-notice">Full documentation for this concept is not yet written.</div>
13+
</body>
14+
</html>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<title>IFF &amp; Teams - QtFRED Help</title>
6+
<link rel="stylesheet" type="text/css" href="../css/help.css"/>
7+
</head>
8+
<body>
9+
<nav class="breadcrumb"><a href="../index.html">QtFRED Help</a> &rsaquo; Concepts &rsaquo; IFF &amp; Teams</nav>
10+
<h1>IFF &amp; Teams</h1>
11+
<p>IFF stands for <em>Identification Friend or Foe</em>. Every ship in a mission
12+
belongs to a team, and every team has a defined relationship with every other team.
13+
Those relationships determine how ships behave toward one another: whether they
14+
attack, ignore, or treat each other as allies.</p>
15+
16+
<h2>Team relationships</h2>
17+
<p>Team relationships are defined in <code>iff_defs.tbl</code>, not in the mission
18+
file. The common defaults are:</p>
19+
<table>
20+
<tr><th>Team</th><th>Typical role</th></tr>
21+
<tr><td>Friendly</td><td>Player's side. Ships the player can target for
22+
orders and that friendly AI protects.</td></tr>
23+
<tr><td>Hostile</td><td>Enemy. Ships that actively attack Friendly
24+
ships.</td></tr>
25+
<tr><td>Neutral</td><td>Neither side. Not attacked unless attacked
26+
first.</td></tr>
27+
<tr><td>Unknown</td><td>Unidentified. Treated as neutral until scanned or
28+
otherwise identified.</td></tr>
29+
<tr><td>Traitor</td><td>Formerly friendly ships that have turned hostile.
30+
Attacked by all sides.</td></tr>
31+
</table>
32+
<p>Mods can define additional teams and custom relationships between them. The
33+
teams available in your mission depend on what <code>iff_defs.tbl</code> provides
34+
for the loaded mod.</p>
35+
36+
<h2>What team membership affects</h2>
37+
<ul>
38+
<li><strong>AI targeting</strong> - ships attack any ship they have a hostile
39+
relationship with and avoid attacking allies.</li>
40+
<li><strong>Escort and guard behavior</strong> - AI set to guard a ship will
41+
also engage enemies threatening it.</li>
42+
<li><strong>Comm menu</strong> - the player can only issue orders to ships on
43+
the Friendly team.</li>
44+
<li><strong>HUD</strong> - target brackets, colors, and the hostile/friendly
45+
indicators on the radar all derive from IFF relationships.</li>
46+
<li><strong>SEXPs</strong> — many SEXP operators accept a team argument to
47+
act on all ships of a given team at once.</li>
48+
</ul>
49+
50+
<h2>Changing team at runtime</h2>
51+
<p>A ship's team can be changed during the mission using SEXPs. This is how
52+
defection scenarios work: reassigning a ship to the Traitor or Hostile team
53+
immediately causes former allies to engage it.</p>
54+
55+
<div class="note">The Team field in the <a href="../dialogs/ShipEditorDialog.html">Ship Editor</a>
56+
sets the team at mission start. Runtime changes are made through SEXPs and are
57+
not reflected back in the editor.</div>
58+
</body>
59+
</html>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8"/>
5+
<title>Messages - QtFRED Help</title>
6+
<link rel="stylesheet" type="text/css" href="../css/help.css"/>
7+
</head>
8+
<body>
9+
<nav class="breadcrumb"><a href="../index.html">QtFRED Help</a> &rsaquo; Concepts &rsaquo; Messages</nav>
10+
<h1>Messages</h1>
11+
<p>Messages are the in-mission communications the player sees and hears. These
12+
include wingmate callouts, command briefings, enemy taunts. Each message is
13+
defined once in the mission's global message list and can be triggered by any event.</p>
14+
15+
<h2>Message anatomy</h2>
16+
<table>
17+
<tr><th>Field</th><th>Description</th></tr>
18+
<tr><td>Name</td><td>Internal identifier used to reference the message from
19+
events and SEXPs.</td></tr>
20+
<tr><td>Text</td><td>The text displayed in the message box.</td></tr>
21+
<tr><td>Audio file</td><td>The voice file played with the message.</td></tr>
22+
<tr><td>Persona</td><td>The voice persona associated with this message, used
23+
to select the appropriate voice variant.</td></tr>
24+
<tr><td>Sender</td><td>The ship that sends the message.</td></tr>
25+
</table>
26+
27+
<h2>Priority</h2>
28+
<p>Each message has a priority - <strong>Low</strong>, <strong>Normal</strong>, or
29+
<strong>High</strong> - that controls how it interacts with other messages playing
30+
at the same time.</p>
31+
<table>
32+
<tr><th>Priority</th><th>Behavior</th></tr>
33+
<tr><td>Low</td><td>Queued behind any currently playing or queued messages.
34+
Will not interrupt anything.</td></tr>
35+
<tr><td>Normal</td><td>Queued behind messages of equal or higher priority.
36+
Interrupts low-priority messages.</td></tr>
37+
<tr><td>High</td><td>Interrupts any lower-priority message currently
38+
playing.</td></tr>
39+
</table>
40+
<p>Within the same priority level, messages play in the order they were
41+
triggered.</p>
42+
43+
<h2>Triggering messages</h2>
44+
<p>Messages are sent by events in the
45+
<a href="../dialogs/MissionEventsDialog.html">Mission Events</a> dialog using a
46+
send-message SEXP. The same message can be triggered by multiple events, and the
47+
same event can send multiple messages.</p>
48+
49+
<h2>Personas</h2>
50+
<p>Personas are defined in the game tables and control the voice set used for a
51+
message. Assigning a persona to both a message and a ship creates a consistent
52+
"voice" for that character across the mission. A ship with a Command persona
53+
is eligible to serve as the Command sender in
54+
<a href="../dialogs/MissionSpecsDialog.html">Mission Specs</a>.</p>
55+
</body>
56+
</html>

0 commit comments

Comments
 (0)