diff --git a/code/cfile/cfile.cpp b/code/cfile/cfile.cpp index 0fd43a137f5..eea70ffee77 100644 --- a/code/cfile/cfile.cpp +++ b/code/cfile/cfile.cpp @@ -85,7 +85,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = { { CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA }, { CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA }, { CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA }, - { CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA } + { CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html .qch", CF_TYPE_DATA } }; // clang-format on diff --git a/qtfred/CMakeLists.txt b/qtfred/CMakeLists.txt index 6d3211ee29f..94311a35409 100644 --- a/qtfred/CMakeLists.txt +++ b/qtfred/CMakeLists.txt @@ -8,7 +8,7 @@ SET(QT5_INSTALL_ROOT "" CACHE PATH list(APPEND CMAKE_PREFIX_PATH "${QT5_INSTALL_ROOT}") -find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) +find_package(Qt5 COMPONENTS Widgets OpenGL Help REQUIRED) include(source_groups.cmake) @@ -56,7 +56,7 @@ set(CMAKE_MAP_IMPORTED_CONFIG_FASTDEBUG Release Debug) target_link_libraries(qtfred PUBLIC code - Qt5::Widgets Qt5::OpenGL) + Qt5::Widgets Qt5::OpenGL Qt5::Help) include(CreateLaunchers) create_target_launcher(qtfred @@ -72,6 +72,66 @@ INSTALL( ) COPY_FILES_TO_TARGET(qtfred) +# --- QtFRED built-in help --- +get_target_property(_QTFRED_QMAKE Qt5::qmake IMPORTED_LOCATION) +execute_process( + COMMAND "${_QTFRED_QMAKE}" -query QT_INSTALL_BINS + OUTPUT_VARIABLE _QTFRED_QT_BINS + OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND "${_QTFRED_QMAKE}" -query QT_INSTALL_LIBS + OUTPUT_VARIABLE _QTFRED_QT_LIBS + OUTPUT_STRIP_TRAILING_WHITESPACE) +find_program(QHELPGENERATOR_EXECUTABLE + NAMES qhelpgenerator + HINTS "${_QTFRED_QT_BINS}" + REQUIRED) + +set(QTFRED_HELP_QHP "${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/qtfred.qhp") +set(QTFRED_HELP_QCH "${CMAKE_CURRENT_BINARY_DIR}/qtfred_help.qch") + +file(GLOB_RECURSE QTFRED_HELP_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/*.html" + "${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/*.css" + "${CMAKE_CURRENT_SOURCE_DIR}/help-src/doc/*.qhp") + +# qhelpgenerator is a Qt application and needs a platform plugin at build time. +# On headless Linux CI the Qt platform plugins fail to dlopen because the Qt +# shared libs are not in LD_LIBRARY_PATH for dlopen-loaded plugins (DT_RUNPATH +# in the main binary does not propagate to dlopen). Pass the Qt lib dir and +# force the offscreen (no-display) platform explicitly. +add_custom_command( + OUTPUT "${QTFRED_HELP_QCH}" + COMMAND ${CMAKE_COMMAND} -E env + "QT_QPA_PLATFORM=offscreen" + "LD_LIBRARY_PATH=${_QTFRED_QT_LIBS}" + "${QHELPGENERATOR_EXECUTABLE}" "${QTFRED_HELP_QHP}" -o "${QTFRED_HELP_QCH}" + DEPENDS ${QTFRED_HELP_SOURCES} + COMMENT "Compiling QtFRED help (qtfred_help.qch)" + VERBATIM) + +add_custom_target(qtfred_help + DEPENDS "${QTFRED_HELP_QCH}" + SOURCES ${QTFRED_HELP_SOURCES}) + +add_dependencies(qtfred qtfred_help) + +source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/help-src" + PREFIX "help-src" + FILES ${QTFRED_HELP_SOURCES}) + +add_custom_command(TARGET qtfred_help POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "$/help" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${QTFRED_HELP_QCH}" + "$/help/qtfred_help.qch" + VERBATIM) + +install(FILES "${QTFRED_HELP_QCH}" + DESTINATION ${BINARY_DESTINATION}/help + COMPONENT "qtFRED") +# --- end QtFRED built-in help --- + enable_clang_tidy(qtfred) if (WIN32) @@ -120,6 +180,19 @@ if (WIN32) DESTINATION ${BINARY_DESTINATION}/platforms COMPONENT "qtFRED" ) + + # Qt Help requires the SQLite SQL driver + set(qsqlite_path "${QT_INSTALL_PLUGINS}/sqldrivers/qsqlite$<$:d>.dll") + + add_custom_command(TARGET qtfred + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${qsqlite_path}" "$/sqldrivers/qsqlite$<$:d>.dll" + VERBATIM) + + install(FILES ${qsqlite_path} + DESTINATION ${BINARY_DESTINATION}/sqldrivers + COMPONENT "qtFRED" + ) elseif(FSO_BUILD_APPIMAGE) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen" @ONLY) file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$" diff --git a/qtfred/help-src/doc/concepts/ai.html b/qtfred/help-src/doc/concepts/ai.html new file mode 100644 index 00000000000..e2364578db7 --- /dev/null +++ b/qtfred/help-src/doc/concepts/ai.html @@ -0,0 +1,62 @@ + + + + + AI - QtFRED Help + + + + +

AI

+

Ship AI behavior in FSO is controlled by three layered systems: the +AI profile, the AI class, and +AI goals and orders. Each layer handles a different aspect of +behavior and they work together at runtime.

+ +

AI profile

+

The AI profile is a mission-wide setting chosen in +Mission Specs. It is primarily a +difficulty scaling system: it defines per-difficulty-level values +for things like damage multipliers, weapon fire delays, turn time, shield recharge +rates, and aim behavior; controlling how the mission feels across the Very Easy +through Insane difficulty range. Profiles also contain a large set of behavioral +flags that toggle specific AI behaviors on or off.

+

Profiles are defined in ai_profiles.tbl and missions select from +that list; custom profiles cannot be defined inside the mission file itself. If no +profile is specified, the table's default profile is used. Most missions are fine +with the default.

+ +

AI class

+

The AI class is a named skill preset assigned to individual ships. It controls +the skill level of that specific ship within the envelope set by the profile; +how well it aims, how it maneuvers, how it uses afterburners, and so on.

+

Every ship class has a default AI class defined in its table entry. The +Ship Editor lets you override that +default for a specific ship instance, and individual turrets can be given their +own AI class in the Weapons +dialog.

+ +

AI goals and orders

+

Goals and orders are specific tasks assigned to a ship or wing: attack a +target, guard a ship, dock with a vessel, fly a waypoint path, and so on. There +are two ways to set them:

+
    +
  • Initial orders - set in the + Initial Orders + dialog. These are the tasks a ship starts the mission with.
  • +
  • Runtime goals - issued via SEXPs during the mission, + typically from events. These override or supplement initial orders.
  • +
+

When a ship has multiple active goals, it pursues them in priority order. +Priority is a value from 1 to 200 where higher values take precedence. Goals +issued by the player via the comm menu use priorities in the 90–100 range, so +goals with a priority above 89 may outrank player orders.

+ +

How the layers interact

+

Think of it as: the profile sets the rules of the game, the +class sets how skilled the ship is within those rules, and the +goals and orders tell the ship what to do. A high-skill AI +class given a low-priority goal can still be overridden by a player order; a +locked-in high-priority goal will hold regardless of player input.

+ + diff --git a/qtfred/help-src/doc/concepts/campaign-flow.html b/qtfred/help-src/doc/concepts/campaign-flow.html new file mode 100644 index 00000000000..c83471fdcfa --- /dev/null +++ b/qtfred/help-src/doc/concepts/campaign-flow.html @@ -0,0 +1,65 @@ + + + + + Campaign Flow - QtFRED Help + + + + +

Campaign Flow

+

A campaign is a sequence of missions linked together in the +Campaign Editor. The campaign +file controls which mission plays next, branches the story based on outcomes, and +carries state between missions through goals and variables.

+ +

How missions end

+

A mission ends when the player reaches the debrief screen. There are two +distinct end conditions that affect what state is saved:

+ + + + +
ConditionWhen it occursWhat is saved
Mission completedThe player accepts the debriefing after + flying the mission.Variables with Save on Mission + Completed persistence, plus all goal states.
Mission closedThe player exits the mission by any means, + including failure or replaying.Variables with Save on Mission + Close persistence.
+ +

Goal states

+

Every mission goal ends in one of three states: complete, failed, or +incomplete. The campaign SEXP tree reads these states using +goal-true and goal-false operators to decide which +mission to branch to next. This is how outcomes carry forward; whether an +important ship survived, whether a bonus objective was met, and so on.

+

Goals do not automatically determine success or failure. The campaign SEXPs +are what interpret goal states and produce outcomes. A mission where all primary +goals are complete can still branch to a "defeat" mission if the campaign logic +is written that way.

+ +

Variables across missions

+

Variables set during a mission only persist into subsequent missions if their +persistence is configured accordingly. See the +Variables & Containers +dialog for the persistence options. Variables saved to the player file +(Eternal) persist for the lifetime of the player profile, even across +different campaigns.

+ +

Branching

+

The campaign editor arranges missions as nodes connected by branches. Each +branch has a SEXP condition. After a mission completes, the engine evaluates the +outgoing branches in order and follows the first one whose condition is true. If +no branch condition is met, the player is returned to the main menu. To end the +campaign properly (playing the end cutscene and triggering campaign completion) +use the end-campaign SEXP.

+

Common branching patterns include:

+
    +
  • Checking whether a primary goal succeeded to route to a victory or + defeat mission.
  • +
  • Checking whether an optional goal was completed to unlock bonus + missions.
  • +
  • Reading a variable set earlier in the campaign to take a story + branch.
  • +
+ + diff --git a/qtfred/help-src/doc/concepts/custom-data.html b/qtfred/help-src/doc/concepts/custom-data.html new file mode 100644 index 00000000000..27660f3d1f4 --- /dev/null +++ b/qtfred/help-src/doc/concepts/custom-data.html @@ -0,0 +1,14 @@ + + + + + Custom Data - QtFRED Help + + + + +

Custom Data

+ +
Full documentation for this concept is not yet written.
+ + diff --git a/qtfred/help-src/doc/concepts/iff.html b/qtfred/help-src/doc/concepts/iff.html new file mode 100644 index 00000000000..b8abe990f7e --- /dev/null +++ b/qtfred/help-src/doc/concepts/iff.html @@ -0,0 +1,59 @@ + + + + + IFF & Teams - QtFRED Help + + + + +

IFF & Teams

+

IFF stands for Identification Friend or Foe. Every ship in a mission +belongs to a team, and every team has a defined relationship with every other team. +Those relationships determine how ships behave toward one another: whether they +attack, ignore, or treat each other as allies.

+ +

Team relationships

+

Team relationships are defined in iff_defs.tbl, not in the mission +file. The common defaults are:

+ + + + + + + +
TeamTypical role
FriendlyPlayer's side. Ships the player can target for + orders and that friendly AI protects.
HostileEnemy. Ships that actively attack Friendly + ships.
NeutralNeither side. Not attacked unless attacked + first.
UnknownUnidentified. Treated as neutral until scanned or + otherwise identified.
TraitorFormerly friendly ships that have turned hostile. + Attacked by all sides.
+

Mods can define additional teams and custom relationships between them. The +teams available in your mission depend on what iff_defs.tbl provides +for the loaded mod.

+ +

What team membership affects

+
    +
  • AI targeting - ships attack any ship they have a hostile + relationship with and avoid attacking allies.
  • +
  • Escort and guard behavior - AI set to guard a ship will + also engage enemies threatening it.
  • +
  • Comm menu - the player can only issue orders to ships on + the Friendly team.
  • +
  • HUD - target brackets, colors, and the hostile/friendly + indicators on the radar all derive from IFF relationships.
  • +
  • SEXPs — many SEXP operators accept a team argument to + act on all ships of a given team at once.
  • +
+ +

Changing team at runtime

+

A ship's team can be changed during the mission using SEXPs. This is how +defection scenarios work: reassigning a ship to the Traitor or Hostile team +immediately causes former allies to engage it.

+ +
The Team field in the Ship Editor +sets the team at mission start. Runtime changes are made through SEXPs and are +not reflected back in the editor.
+ + diff --git a/qtfred/help-src/doc/concepts/messages.html b/qtfred/help-src/doc/concepts/messages.html new file mode 100644 index 00000000000..47b11c45c4a --- /dev/null +++ b/qtfred/help-src/doc/concepts/messages.html @@ -0,0 +1,56 @@ + + + + + Messages - QtFRED Help + + + + +

Messages

+

Messages are the in-mission communications the player sees and hears. These +include wingmate callouts, command briefings, enemy taunts. Each message is +defined once in the mission's global message list and can be triggered by any event.

+ +

Message anatomy

+ + + + + + + +
FieldDescription
NameInternal identifier used to reference the message from + events and SEXPs.
TextThe text displayed in the message box.
Audio fileThe voice file played with the message.
PersonaThe voice persona associated with this message, used + to select the appropriate voice variant.
SenderThe ship that sends the message.
+ +

Priority

+

Each message has a priority - Low, Normal, or +High - that controls how it interacts with other messages playing +at the same time.

+ + + + + +
PriorityBehavior
LowQueued behind any currently playing or queued messages. + Will not interrupt anything.
NormalQueued behind messages of equal or higher priority. + Interrupts low-priority messages.
HighInterrupts any lower-priority message currently + playing.
+

Within the same priority level, messages play in the order they were +triggered.

+ +

Triggering messages

+

Messages are sent by events in the +Mission Events dialog using a +send-message SEXP. The same message can be triggered by multiple events, and the +same event can send multiple messages.

+ +

Personas

+

Personas are defined in the game tables and control the voice set used for a +message. Assigning a persona to both a message and a ship creates a consistent +"voice" for that character across the mission. A ship with a Command persona +is eligible to serve as the Command sender in +Mission Specs.

+ + diff --git a/qtfred/help-src/doc/concepts/sexps.html b/qtfred/help-src/doc/concepts/sexps.html new file mode 100644 index 00000000000..a4d22375f7d --- /dev/null +++ b/qtfred/help-src/doc/concepts/sexps.html @@ -0,0 +1,53 @@ + + + + + SEXPs - QtFRED Help + + + + +

SEXPs

+ +

A SEXP (Symbolic EXPression) is the scripting language built into +FreeSpace missions. Every condition, trigger, and action in a mission — from +checking whether a ship has been destroyed to playing a message — is expressed +as a SEXP tree.

+ +

Structure

+

SEXPs use a Lisp-style prefix notation enclosed in parentheses:

+
(operator argument1 argument2 ...)
+ +

Operators can be nested, so arguments can themselves be SEXPs:

+
(when
+    (is-destroyed-delay 0 "Epsilon 1")
+    (send-message "" "Mission-Complete" "Command")
+)
+ +

Here when is the top-level operator. Its first argument is a condition +(is-destroyed-delay) and its second argument is an action +(send-message). When the condition becomes true the action fires.

+ +

Where SEXPs appear

+

SEXPs are used in:

+
    +
  • Mission Events — the primary place to author SEXP logic; + see the Mission Events dialog.
  • +
  • Mission Goals — the completion condition for each goal; + see the Mission Goals dialog.
  • +
  • Ship arrival/departure cues — conditions on when ships + enter and leave the mission.
  • +
  • Briefing and debriefing — stage-change conditions.
  • +
+ +

Editing SEXPs in QtFRED

+

The SEXP tree editor is embedded directly in the Mission Events and Mission Goals +dialogs. Right-click any node in the tree to add, replace, or remove operators and +arguments. Hover over an operator name for a brief description of what it does.

+ +
+ Note: The full SEXP reference is maintained on the + Hard Light Productions wiki. +
+ + diff --git a/qtfred/help-src/doc/css/help.css b/qtfred/help-src/doc/css/help.css new file mode 100644 index 00000000000..a8d952e9a99 --- /dev/null +++ b/qtfred/help-src/doc/css/help.css @@ -0,0 +1,69 @@ +body { + font-family: sans-serif; + font-size: 14px; + line-height: 1.6; + max-width: 900px; + margin: 0 auto; + padding: 1em 2em; + color: #222; +} + +h1 { font-size: 1.6em; border-bottom: 2px solid #0055a5; padding-bottom: 0.2em; } +h2 { font-size: 1.25em; border-bottom: 1px solid #ccc; padding-bottom: 0.1em; margin-top: 1.5em; } +h3 { font-size: 1.05em; margin-top: 1.2em; } + +a { color: #0055a5; } +a:hover { text-decoration: underline; } + +code, kbd { + font-family: monospace; + background: #f4f4f4; + padding: 0.1em 0.3em; + border-radius: 3px; + font-size: 0.95em; +} + +pre { + background: #f4f4f4; + border: 1px solid #ddd; + padding: 0.8em 1em; + overflow-x: auto; + border-radius: 4px; +} + +table { + border-collapse: collapse; + width: 100%; + margin: 1em 0; +} + +th, td { + border: 1px solid #ccc; + padding: 0.4em 0.7em; + text-align: left; +} + +th { background: #eef2f7; } + +.note { + background: #eef6ff; + border-left: 4px solid #0055a5; + padding: 0.5em 1em; + margin: 1em 0; +} + +.stub-notice { + background: #fff8e1; + border-left: 4px solid #f0a500; + padding: 0.5em 1em; + margin: 1em 0; + font-style: italic; +} + +nav.breadcrumb { + font-size: 0.85em; + color: #666; + margin-bottom: 1em; +} + +nav.breadcrumb a { color: #0055a5; } diff --git a/qtfred/help-src/doc/dialogs/AsteroidEditorDialog.html b/qtfred/help-src/doc/dialogs/AsteroidEditorDialog.html new file mode 100644 index 00000000000..f59de99f850 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/AsteroidEditorDialog.html @@ -0,0 +1,61 @@ + + + + + Asteroid Editor - QtFRED Help + + + + +

Asteroid Editor

+

Opens via Editors › Asteroid Editor.

+

Configures the single asteroid field that can exist in a mission. The field is defined +by a rectangular outer bounding box.

+ +

Field type

+ + + + +
OptionDescription
ActiveThe field actively throws asteroids at ships. New asteroids + are aimed directly at the ships listed in the Targets + section of this editor.
PassiveAsteroids drift freely and do not target ships.
+ +

Object type

+ + + + +
OptionDescription
AsteroidSpawns large asteroids that split into medium and small + pieces when destroyed.
DebrisSpawns specific debris pieces chosen from a weighted list. + Debris does not split when destroyed.
+ +

Key fields

+ + + + + +
FieldDescription
EnabledAdds the field to the mission. Uncheck to disable + it.
NumberThe number of asteroid or debris objects present in the + field at any one time.
Avg speedBase speed of objects in the field. Each individual + object's speed is randomized around this value; the actual range depends on + the current skill level and the object's maximum speed as defined in the + table.
+ +

Outer box

+

The bounding box of the field. Set the Min and Max +coordinates on each axis to size and position the box.

+ +

Inner box

+

When enabled, defines an exclusion zone inside the outer box where objects will not +spawn. Any object that would appear inside the inner box is repositioned just outside +it.

+ +

Use Enhanced

+

Changes how the engine decides whether to spawn a new asteroid or wrap an existing +asteroid when it leaves the outer box. By default, the engine checks both the player's +view cone and a maximum distance range. When Enhanced is enabled, the distance range +check is skipped and only the view cone is used.

+ + diff --git a/qtfred/help-src/doc/dialogs/BackgroundEditorDialog.html b/qtfred/help-src/doc/dialogs/BackgroundEditorDialog.html new file mode 100644 index 00000000000..09bcbcc5dd9 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/BackgroundEditorDialog.html @@ -0,0 +1,128 @@ + + + + + Background Editor - QtFRED Help + + + + +

Background Editor

+

Opens via Editors › Background Editor.

+

Controls the visual environment that surrounds the mission: background bitmap layers, +suns, nebula, skybox, ambient lighting, and stars.

+ +

Background slots

+

A mission can define multiple backgrounds. The left drop-down selects the +active background; the one currently loaded into the scene and visible in +the viewport. Use Add and Remove to create or delete +slots. Swap exchanges all data (bitmaps, suns, flags) between the two +selected backgrounds. The Import button lets you pull backgrounds from +another mission file.

+ +

Bitmaps

+

Full-sphere background images composited behind the scene. Use Add +to open a gallery and pick a new bitmap, Change to replace the +selected one (also gallery), and Delete to remove it. You can also +use the drop-down next to the list for a quicker replacement without the gallery. +Select a bitmap in the list to edit its properties:

+ + + + + +
FieldDescription
Pitch / Bank / HeadingOrientation of the bitmap on the + sphere.
Scale X / YStretches the bitmap horizontally and + vertically.
DivisionsNumber of mesh subdivisions (1–5) used when rendering + the bitmap. Higher values improve perspective correction at the cost of + slightly more geometry. Only the vertical (Y) axis division is currently + active in the engine.
+ +

Suns

+

Works the same as Bitmaps; Add, Change (gallery), Delete, and a quick-change +drop-down. Bank is omitted since suns are circular. Select a sun in the list to +edit:

+ + + + +
FieldDescription
Pitch / HeadingPosition of the sun in the sky. This also + determines the direction of dynamic lighting cast on ships.
ScaleUniform size of the sun flare/glow image.
+ +
Save angles in correct format - a legacy checkbox +that should always be checked for new missions. It controls whether pitch/bank/heading +angles are saved using the modern coordinate convention or the older one. Unchecking +it is only relevant when maintaining compatibility with very old mission +files.
+ +

Full Nebula

+

Enables the FS2-style nebula environment. When active, the mission takes place +inside a gas cloud with fog, particle poofs, and optional lightning. This is not the +same as the volumetric nebula renderer. For that see +Volumetric Nebula.

+ + + + + + + + + + +
FieldDescription
PatternThe background texture file used for the nebula + environment.
RangeAWACS and targeting range multiplier inside the nebula. + Lower values reduce how far sensors can detect targets.
Lightning StormSelects the lightning storm type active in the + nebula, or <None> for no lightning.
PoofsA list of cloud puff particle types defined in the tables. + Check the ones you want active in the nebula.
Ship TrailsToggles engine contrail streaks left by ships + moving through the nebula clouds.
Fog Near / Far MultipliersScale the near and far fog distances. + Lower near multiplier thickens fog close to the camera; lower far + multiplier reduces maximum visibility distance.
Display background bitmaps in nebulaWhen checked, background + bitmaps defined in the Bitmaps section are still visible through the + nebula. Uncheck to let the nebula obscure them completely.
Override Fog PaletteWhen checked, uses the RGB values specified + here as the fog color instead of the nebula's default palette.
+ +

Ambient Light

+

Sets the global ambient light color applied to all ship and object surfaces. Use +the RGB sliders to tint the ambient fill.

+ +

Skybox

+

Renders a POF model as a full-environment backdrop, replacing the default +procedural starfield. Select the POF file and set Pitch / Bank / +Heading to rotate it. Leave the file field blank for no skybox.

+

The rendering flags control how the model is drawn:

+ + + + + + + + +
FlagEffect
No LightingDisables dynamic and ambient lighting on the + skybox.
All TransparentRenders the model fully transparent.
No Z-bufferDisables depth buffer writes so the skybox always + renders behind everything else.
No CullRenders both front- and back-facing polygons.
No GlowmapsDisables glow/emission map rendering on the + model.
Force ClampForces texture coordinate clamping rather than + wrapping.
+
The default flags for a new skybox are No Z-buffer, No Cull, All +Transparent, and No Lighting, which is the correct setup for most cases.
+ +

Misc

+ + + + + + +
FieldDescription
Number of StarsCount of procedurally placed background stars. + These may not be visible when a skybox is in use.
Takes place in subspaceLoads the subspace tunnel effect for the + entire mission.
Environment mapTexture used for environment-mapped reflections + and lighting on ship surfaces.
Lighting profileSelects the lighting profile from the tables to + apply to the mission.
+ +

Old Nebula

+

A legacy FS1-style nebula system. These settings are read and written for +backwards compatibility with old mission files, but the renderer that drew them was +removed.

+ + diff --git a/qtfred/help-src/doc/dialogs/BriefingEditorDialog.html b/qtfred/help-src/doc/dialogs/BriefingEditorDialog.html new file mode 100644 index 00000000000..d1555ed48ae --- /dev/null +++ b/qtfred/help-src/doc/dialogs/BriefingEditorDialog.html @@ -0,0 +1,123 @@ + + + + + Briefing Editor - QtFRED Help + + + + +

Briefing Editor

+

Opens via Editors › Briefing.

+

Sets up the pre-mission briefing shown to the player before launch. The briefing is +made up of stages; each stage has its own camera view, map icons, text, and voice file.

+ +

Map view

+

The map is a top-down 2D projection of the mission space. Its aspect ratio matches +the aspect ratio defined for the current mod. You can drag icons around directly on +the map, and use the same camera controls as the main QtFRED viewport to adjust the +view. Camera movement speed can be set via the drop-down; it only affects editing and +has no in-game effect.

+ +

Teams

+

In multiplayer missions each team can have its own independent briefing. Use the +team selector to switch which team's briefing you are editing. Copy to other +team duplicates the entire briefing (all stages) to the other team, overwriting +it.

+ +

Music

+

Music and Alt music are briefing-wide; they are +not per-stage. Music sets the track played throughout the entire briefing and the +command briefing (if present). Alt music is used instead when that track is available +in the currently loaded mod.

+ +

Stage controls

+ + + + + + +
ControlDescription
Prev / NextNavigate between stages.
Add stageAppends a new stage at the end of the briefing.
Insert stageInserts a copy of the current stage immediately + after it.
Delete stageRemoves the current stage.
+ +

Camera controls

+ + + + + + + + + +
ControlDescription
Reset cameraRestores the stage's camera to the position it had + when you first navigated to it, discarding any unsaved + changes.
Copy / PasteCopies the current stage's camera position and + orientation to the clipboard, then pastes it onto another + stage.
Camera coordsManually enter the camera position and + orientation as numeric values.
Transition timeHow long the camera takes to move to this stage's + position when advancing forward. When moving backward, the departing + stage's transition time is used instead.
Cut to next stageDisables camera movement into the next stage; + the transition is an instant cut with a static effect + instead.
Cut to previous stageSame, but applies to the transition coming + from the previous stage.
Disable grid renderingHides the map grid during this + stage.
+ +

Icon controls

+

Make icon places a blank icon on the map. Make icon from +ship lets you pick a ship from the mission and creates an icon preset to that +ship's type, a shorthand for Make Icon followed by setting the ship type +manually.

+ +

Icon properties

+ + + + + + + + + + + + + + + +
FieldDescription
IDLinks this icon to the same icon across other stages. Icons + with matching IDs are treated as the same object moving between + stages.
LabelName visible on the map.
Closeup labelName shown when the player clicks the icon to zoom + in.
Icon imageThe 2D icon graphic from + icons.tbl.
Ship type3D model shown when the player clicks the icon. If the + ship class has a special briefing icon defined, that is used instead of + the icon image.
TeamTints the icon with that team's color.
ScaleScales the icon up or down on the map.
Draw linesDraws lines between icons that are marked for + it.
Flip iconMirrors the icon horizontally.
Use cargo iconUses the cargo variant of the ship type's icon, if + one exists. Only applies to Ship Type icons.
Wing iconUses the wing variant of the ship type's icon, if one + exists. Only applies to Ship Type icons.
HighlightThe icon receives an animated highlight effect during + this stage.
Change locallyWhen checked, changes to this icon apply only to + the current stage. When unchecked, changes propagate forward to all + later stages that share the same icon ID.
+ +

Icon actions

+ + + + + +
ButtonDescription
Icon coordsSet the icon's map position as numeric + values.
DeleteRemoves the icon from this stage.
PropagateCopies this icon's current state to all following + stages that share the same icon ID.
+ +

Stage text

+

The text displayed in the briefing text box during this stage.

+ +

Voice file

+

Audio narration played during this stage.

+ +

Usage formula

+

SEXP evaluated before the briefing plays. If +true, this stage is shown; if false, it is skipped entirely.

+ + diff --git a/qtfred/help-src/doc/dialogs/CampaignEditorDialog.html b/qtfred/help-src/doc/dialogs/CampaignEditorDialog.html new file mode 100644 index 00000000000..0458c770188 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/CampaignEditorDialog.html @@ -0,0 +1,109 @@ + + + + + Campaign Editor - QtFRED Help + + + + +

Campaign Editor

+

Opens via File › Campaign Editor. The Campaign Editor opens +as its own window rather than a modal dialog.

+

Links individual missions into a branching campaign. Each mission is a node in a +graph; directed edges between nodes carry SEXP conditions that determine which mission +the player flies next.

+ +

Use retail campaign file format - saves the campaign in the older +retail-compatible format. Leave unchecked for new campaigns. +Check campaign runs the error checker against the current +campaign. Both controls are available on both tabs.

+ +

Campaign Specs tab

+ +

Identity

+ + + + + + + +
FieldDescription
NameCampaign name shown in the campaign selection + screen.
TypeSingle player, multiplayer co-op, or multiplayer team + vs. team.
DescriptionLong-form campaign description shown in the + selection screen.
Reset tech roomWhen checked, the player's tech room is cleared + at the start of the campaign and only ships and weapons unlocked during + play are available.
Custom dataOpens the Custom Data dialog for attaching arbitrary + key-value pairs to the campaign file, used by scripting and + mods.
+ +

Starting ships and weapons

+

Check which ships and weapons are available to the player at the very start of +the campaign, before any missions have been completed.

+ +

Campaign Flow tab

+ +

Mission list

+

Lists all .fs2 mission files available to add to the campaign. +Select a mission from the list then right-click in the graph view to add it as a +node.

+ +

Mission properties

+

Select a mission node in the graph to edit its properties:

+ + + + + + +
FieldDescription
Briefing cutsceneVideo played before the briefing for this + mission.
Debriefing personaIndex of the debriefing persona used after + this mission.
MainhallWhich main hall is shown between missions.
Substitute mainhallPreferred main hall to use if present in + the currently loaded mod, analogous to alt music.
+ +

Branches

+

Shows all outgoing branches from the selected mission. Each branch has a +SEXP condition; the first branch whose condition +is true is the one taken. New branches are automatically given a true +formula. Use the up/down arrows to reorder branch priority.

+ + + + + + + +
Branch typeDescription
Branch to MissionProceeds to another mission in the campaign. + The SEXP dot is black.
Branch to Campaign LoopAn optional loop the player can accept + or skip. The SEXP dot is blue.
Repeat MissionLoops back to the current mission, allowing the + player to retry it. The SEXP dot is black.
End CampaignEnds the campaign. The SEXP dot is + black.
+ +

Selecting a loop branch reveals additional fields:

+ + + + + +
FieldDescription
Loop descriptionText shown on the loop accept/skip screen + in-game.
AnimationAnimation played on the loop screen.
Voice fileNarration audio for the loop screen.
+ +

Graph view

+

Missions appear as boxes; drag connectors between them to create branches:

+ + + + + +
ConnectorCreates
Blue → GreenA normal branch. The SEXP condition determines + whether this path is taken.
Orange → GreenA loop branch. The player is given the option to + accept or skip the loop before it executes.
Blue → End Campaign nodeAn end-of-campaign branch. The campaign + ends when this branch is taken. The same SEXP priority rules + apply.
+

The End Campaign node is created automatically. Right-click a node in the graph +for additional options, including Add Repeat Mission, which creates +a branch that loops back to the same mission, the standard way to let the player +retry a mission after failure.

+ + diff --git a/qtfred/help-src/doc/dialogs/CommandBriefingDialog.html b/qtfred/help-src/doc/dialogs/CommandBriefingDialog.html new file mode 100644 index 00000000000..24911813f4c --- /dev/null +++ b/qtfred/help-src/doc/dialogs/CommandBriefingDialog.html @@ -0,0 +1,52 @@ + + + + + Command Briefing - QtFRED Help + + + + +

Command Briefing

+

Opens via Editors › Command Briefing.

+

Builds the Command Briefing shown to the player after the +Fiction Viewer and before the main +Briefing. It consists of one or more stages, +each combining a looping animation with narrated text. Stages advance automatically +when the voice clip finishes, or the player can click to skip.

+ +

Teams

+

In multiplayer missions each team can have its own independent command briefing. Use +the team selector to switch which team's command briefing you are editing. +Copy to other team duplicates the entire command briefing (all stages) +to the other team, overwriting it.

+ +

Stage controls

+ + + + + + +
ControlDescription
Prev / NextNavigate between stages.
Add stageAppends a new stage at the end.
Insert stageInserts a new stage after the current one.
Delete stageRemoves the current stage.
+ +

Per-stage fields

+ + + + + +
FieldDescription
Briefing textText displayed on screen during this stage.
Animation fileThe ANI, APNG, or EFF animation that loops in the + background during this stage.
Speech fileVoice narration played during this stage. The stage + advances automatically when the clip ends.
+ +

Custom background images

+

Overrides the default command briefing background with a custom image. Two slots +are provided to accommodate different display resolutions:

+ + + + +
SlotUsed at
Background (lo-res)480-line resolutions (e.g. 640×480).
Background (hi-res)768-line resolutions and above.
+ + diff --git a/qtfred/help-src/doc/dialogs/CustomDataDialog.html b/qtfred/help-src/doc/dialogs/CustomDataDialog.html new file mode 100644 index 00000000000..c4d22228de9 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/CustomDataDialog.html @@ -0,0 +1,29 @@ + + + + + Custom Data - QtFRED Help + + + + +

Custom Data

+

Accessed via Custom Data in the +Mission Specs dialog or the +Campaign Editor.

+

Attaches arbitrary key-value string pairs to a mission or campaign. Custom data +has no built-in effect on gameplay; it is intended to be read by Lua scripts that +know to look for specific keys.

+ +

Adding an entry

+

Fill in the Key and Value fields and click +Add to create a new entry.

+ +

Editing an entry

+

Select an entry in the list to load it into the Key and Value fields. Modify the +fields as needed and click Update to apply the changes.

+ +

Removing an entry

+

Select an entry in the list and click Remove to delete it.

+ + diff --git a/qtfred/help-src/doc/dialogs/CustomStringsDialog.html b/qtfred/help-src/doc/dialogs/CustomStringsDialog.html new file mode 100644 index 00000000000..9c3ef38be78 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/CustomStringsDialog.html @@ -0,0 +1,35 @@ + + + + + Custom Strings - QtFRED Help + + + + +

Custom Strings

+

Accessed via Custom Strings in the Mission Specs dialog.

+

Attaches arbitrary key-value-text entries to the mission. Each entry has three +fields: a key for lookup, a value, and a longer text field. The intended use is +localization support; the value holds an XSTR ID number and the text holds the +matching string, allowing Lua scripts to resolve translatable strings by key. +The fields are general purpose and can serve any other use case where a key, +a value, and a block of text need to be stored together.

+ +

Fields

+ + + + + +
FieldDescription
KeyThe name used to look up this entry.
ValueA short string associated with the key, typically an + XSTR ID number.
TextThe longer string content, typically the translatable text + matching the XSTR ID.
+ +

Editing

+

Fill in all three fields and click Add to create a new entry. +Select an entry in the list to load it into the fields, modify as needed, and click +Update to apply changes. Click Remove to delete +the selected entry.

+ + diff --git a/qtfred/help-src/doc/dialogs/CustomWingNamesDialog.html b/qtfred/help-src/doc/dialogs/CustomWingNamesDialog.html new file mode 100644 index 00000000000..8cfc54abfd3 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/CustomWingNamesDialog.html @@ -0,0 +1,32 @@ + + + + + Custom Wing Names - QtFRED Help + + + + +

Custom Wing Names

+

Accessed via Custom Wing Names in the Mission Specs dialog.

+

Overrides the default wing name sets used by the engine. All three sets are +independent; changing one does not automatically update the others.

+ +

Starting wing names

+

The three wings that appear on the pre-mission loadout screen, where players +select their ships before the mission begins. Defaults are +Alpha, Beta, and Gamma.

+ +

Squadron wing names

+

The five wings tracked on the HUD squad status display during the mission. +Defaults are Alpha, Beta, Gamma, +Delta, and Epsilon. These are independent of the starting +wing names. Conventionally the first three match, but the engine does not enforce +this.

+ +

Team-versus-team wing names

+

The two team wings used in multiplayer Team-vs-Team missions. One name per team. +The first TvT wing name must be identical to the first starting wing name; the +engine enforces this and will error if they differ.

+ + diff --git a/qtfred/help-src/doc/dialogs/DebriefingDialog.html b/qtfred/help-src/doc/dialogs/DebriefingDialog.html new file mode 100644 index 00000000000..ea73d30d27a --- /dev/null +++ b/qtfred/help-src/doc/dialogs/DebriefingDialog.html @@ -0,0 +1,58 @@ + + + + + Debriefing - QtFRED Help + + + + +

Debriefing

+

Opens via Editors › Debriefing.

+

Builds the post-mission debrief shown after the player returns to base. Each stage +has a usage formula; only stages whose formula evaluates to true are shown, so you +can deliver different feedback depending on how the mission went.

+ +

Teams

+

In multiplayer missions each team can have its own independent debriefing. Use the +team selector to switch which team's debriefing you are editing. Copy to other +team duplicates the entire debriefing (all stages) to the other team, +overwriting it.

+ +

Stage controls

+ + + + + + +
ControlDescription
Prev / NextNavigate between stages.
Add stageAppends a new stage at the end.
Insert stageInserts a new stage after the current one.
Delete stageRemoves the current stage.
+ +

Per-stage fields

+ + + + + + +
FieldDescription
Stage textThe main body text displayed and read aloud to the + player during this stage.
Recommendation textA follow-up line shown when the player presses + the Recommendations button in the debriefing screen. Optional - leave blank + to show nothing.
Voice fileAudio narration for this stage's text.
Usage formulaSEXP evaluated + after the mission ends. This stage is shown only if the formula is + true.
+ +

Music

+

Music applies to the entire debriefing, not individual stages. Three tracks can be +assigned depending on mission outcome:

+ + + + + +
TrackWhen played
SuccessAll primary and secondary goals were + completed.
AverageThe mission was passed but not all goals were + met.
FailureThe mission was failed, or the player turned + traitor.
+ + diff --git a/qtfred/help-src/doc/dialogs/ErrorCheckerDialog.html b/qtfred/help-src/doc/dialogs/ErrorCheckerDialog.html new file mode 100644 index 00000000000..1e49bf8168f --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ErrorCheckerDialog.html @@ -0,0 +1,14 @@ + + + + + Error Checker - QtFRED Help + + + + +

Error Checker

+

Accessible via Tools › Error Checker.

+
Full documentation for this tool is not yet written.
+ + diff --git a/qtfred/help-src/doc/dialogs/EventEditor.html b/qtfred/help-src/doc/dialogs/EventEditor.html new file mode 100644 index 00000000000..c24debd501a --- /dev/null +++ b/qtfred/help-src/doc/dialogs/EventEditor.html @@ -0,0 +1,15 @@ + + + + + Event Editor - QtFRED Help + + + + +

Event Editor

+

Opens via Editors › Mission Events.

+

The Event Editor is another name for the Mission Events dialog. See +Mission Events for full documentation.

+ + diff --git a/qtfred/help-src/doc/dialogs/FictionViewerDialog.html b/qtfred/help-src/doc/dialogs/FictionViewerDialog.html new file mode 100644 index 00000000000..007156807fb --- /dev/null +++ b/qtfred/help-src/doc/dialogs/FictionViewerDialog.html @@ -0,0 +1,30 @@ + + + + + Fiction Viewer - QtFRED Help + + + + +

Fiction Viewer

+

Opens via Editors › Fiction Viewer.

+

Assigns a fiction document displayed to the player in the Fiction Viewer screen before +the mission. The fiction screen appears before the +Command Briefing and main Briefing +when a story file is configured here. Leave all fields blank to skip the screen +entirely.

+ +

Key fields

+ + + + + + +
FieldDescription
Story filePath to the text file containing the fiction, relative to + the mod's data/fiction/ folder.
FontThe typeface used to render the fiction text in-game.
Voice fileOptional narration audio played while the player reads. + Relative to data/voiceovers/.
MusicBackground music track played during the fiction screen, + selected from tracks defined in the game tables.
+ + diff --git a/qtfred/help-src/doc/dialogs/GlobalShipFlagsDialog.html b/qtfred/help-src/doc/dialogs/GlobalShipFlagsDialog.html new file mode 100644 index 00000000000..549219f5e80 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/GlobalShipFlagsDialog.html @@ -0,0 +1,19 @@ + + + + + Global Ship Flags - QtFRED Help + + + + +

Global Ship Flags

+

Opens via Editors › Global Ship Flags.

+

A batch tool that sets a flag on every ship currently in the mission in one +operation. Each button prompts for confirmation before applying. The change is +immediate and cannot be undone, and ships added to the mission afterward will not +automatically receive the flag.

+

The individual flags are self-explanatory. The same flags can also be set per ship +in the Ship Editor.

+ + diff --git a/qtfred/help-src/doc/dialogs/JumpNodeEditorDialog.html b/qtfred/help-src/doc/dialogs/JumpNodeEditorDialog.html new file mode 100644 index 00000000000..d8bdee2079f --- /dev/null +++ b/qtfred/help-src/doc/dialogs/JumpNodeEditorDialog.html @@ -0,0 +1,33 @@ + + + + + Jump Node Editor - QtFRED Help + + + + +

Jump Node Editor

+

Opens via Editors › Jump Node Editor.

+

Creates and configures subspace jump nodes. Jump nodes are fixed points in space that +ships can use to enter or exit subspace. They appear on the HUD radar and can be targeted. +Select a node from the drop-down to edit its properties.

+ +

Key fields

+ + + + + + + + +
FieldDescription
Jump nodeSelects which placed node to edit.
NameInternal identifier used in SEXPs and mission scripting. + Must be unique.
Display nameName shown to the player on the HUD and in targeting. + If left blank, the internal name is used instead.
Model filePOF model rendered at the node's position. Uses the + default jump node model if left blank.
Node color (RGB)Color used to render the node model in the + mission.
Hidden by defaultWhen checked, the node starts the mission hidden +
+ + + diff --git a/qtfred/help-src/doc/dialogs/MissionCutscenesDialog.html b/qtfred/help-src/doc/dialogs/MissionCutscenesDialog.html new file mode 100644 index 00000000000..f5bf9136963 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/MissionCutscenesDialog.html @@ -0,0 +1,46 @@ + + + + + Mission Cutscenes - QtFRED Help + + + + +

Mission Cutscenes

+

Opens via Editors › Mission Cutscenes.

+

Defines cutscene movies that play at specific points around the mission. Each +cutscene entry pairs a type, which determines when it can play, with a +movie filename and a SEXP condition. The +cutscene plays when its SEXP evaluates to true.

+ +

Cutscene types

+ + + + + + + + + +
TypeWhen it plays
Fiction ViewerJust before the fiction viewer game state.
Command BriefingJust before the command briefing game state.
BriefingJust before the briefing game state.
Pre-gameJust before the mission starts, after Accept has been + pressed.
DebriefingJust before the debriefing game state.
Post-debriefingWhen the debriefing has been accepted but before + exiting the mission.
End CampaignWhen the campaign has been completed.
+ +

Cutscene list and SEXP tree

+

The main area shows all cutscenes for the mission alongside their SEXP trees. The +Display Cutscene dropdown filters the list to show one type at a +time. A description of when the selected type plays appears beneath the dropdown. +Use New Cutscene to add a new entry of the currently displayed +type.

+ +

Cutscene properties

+ + + + +
FieldDescription
TypeWhen this cutscene will play. Changing the type moves the + entry into the corresponding type group.
FilenameThe movie file to play.
+ + diff --git a/qtfred/help-src/doc/dialogs/MissionEventsDialog.html b/qtfred/help-src/doc/dialogs/MissionEventsDialog.html new file mode 100644 index 00000000000..de1799ebb9d --- /dev/null +++ b/qtfred/help-src/doc/dialogs/MissionEventsDialog.html @@ -0,0 +1,136 @@ + + + + + Mission Events - QtFRED Help + + + + +

Mission Events

+

Opens via Editors › Mission Events.

+

Mission Events is the primary scripting interface in QtFRED and where the vast majority +of mission design work happens. Each event is a named unit that pairs a condition with one +or more actions expressed as SEXPs. The engine +evaluates every event every frame; when the condition becomes true the actions fire. +Events can repeat on a cooldown, depend on other events firing first, display objectives +on the HUD, trigger messages, and much more. The event list is the brain of a mission.

+ +

Event list and SEXP tree

+

The main area shows all events in the mission alongside their SEXP trees. Selecting an +event expands its condition and action expressions for editing. Right-click any SEXP node +to add, replace, or remove operators and arguments. See +SEXPs for a full overview of the expression +language and the operators available.

+

Events are evaluated in list order each frame. Order matters: events earlier in the +list are processed first, which can affect timing when events interact.

+ +

Event list buttons

+ + + + + + +
ButtonDescription
NewAppends a new blank event at the end of the list.
InsertInserts a new blank event above the currently selected + event.
DeleteRemoves the selected event.
Move Up / Move DownReorders the selected event within the + list.
+ +

Event properties

+

These fields configure the selected event.

+ + + + + + + + + + + + + +
FieldDescription
NameInternal label shown in the event list. Referenced by the + Chain feature of other events and by SEXPs such as + event-true and event-false.
Repeat countHow many times the event's actions will run in total. + -1 means unlimited.
Trigger countHow many times the event's condition must become true + before the event stops firing entirely. Once this count reaches zero the event + is permanently disabled, overriding any remaining repeat count.
IntervalMinimum time in seconds or milliseconds between successive + firings when the repeat count is greater than 1. The interval timer resets after + each firing.
ChainedWhen checked, this event's condition is not evaluated until + the immediately preceding event in the list has become true at least once. Used + to sequence events without adding explicit timing conditions to every + SEXP.
Chain delayNumber of seconds or milliseconds after the preceding + event becomes true before this event's condition begins evaluating. Only + meaningful when Chained is checked.
Interval & Chain Delay in MilllisecondsChekcbox that + when checked changes both Chain Delay and Interval to being milliseconds instead + of seconds.
ScorePoints awarded to the player when this event becomes + true.
TeamIn multiplayer missions, restricts the event to a specific + team. Disabled for non-multiplayer missions.
Directive textText shown in the player's objective display on the + HUD when this event is active. Writing text here makes the event a directive. + Directives turn red when they can no longer become true, and blue when they + do become true.
Directive keypress textHelper text displayed beneath the directive + in green on the HUD. Keybinds can be embedded by surrounding the bind name + with $$, for example $Alt-X$, and they will be + automatically translated to the player's current control bindings.
+ +

Log flags

+

These checkboxes control when the selected event writes an entry to the engine's +debug event log (event.log). They are useful for tracing event behavior +during mission testing.

+ + + + + + + + + + +
FlagLogs when…
TrueThe event condition evaluates to true.
FalseThe event condition evaluates to false.
Always FalseThe event condition is permanently false.
Log PreviousThe event changes state; logs the previous state + alongside the new one.
First RepeatThe event fires on its first repetition. Flag is + cleared after logging once.
Last RepeatThe event fires on its final repetition.
First TriggerThe event fires on its first trigger. Flag is + cleared after logging once.
Last TriggerThe event fires on its final trigger.
+ +

Messages

+

The messages panel lists all messages defined for this mission. SEXPs such as +send-message and send-message-list reference messages by +name. Use the arrow buttons to reorder messages in the list.

+ +

Message list buttons

+ + + + + + + +
ButtonDescription
NewAppends a new blank message at the end of the list.
InsertInserts a new blank message above the selected + message.
DeleteRemoves the selected message.
Add NoteAttaches a note to the selected message that is not + visible to the player. Notes function like stage directions and are printed in + the generated script exported from the + Voice Acting Manager.
Update StuffAutomatically assigns the head animation and persona + for the selected message based on the current mission settings.
+ +

Message properties

+ + + + + + + + +
FieldDescription
NameInternal identifier used to reference this message in SEXPs. + Not shown to the player.
Message textThe text displayed on the HUD when this message is + sent.
Head ANIThe talking-head animation file shown with the message. + Choose from the dropdown for quick access or browse the gallery.
Wave fileThe audio file played when this message is sent.
PersonaWhen a message has a persona assigned and is sent with + wingman as the source, the engine finds a random ship from the + player's wing that matches this persona to act as sender. If no matching ship + exists the message falls back to Terran Command.
TeamIn Team vs. Team multiplayer, restricts this message to + players on the specified team. None sends the message to all + players.
+ + diff --git a/qtfred/help-src/doc/dialogs/MissionGoalsDialog.html b/qtfred/help-src/doc/dialogs/MissionGoalsDialog.html new file mode 100644 index 00000000000..f7984c628a3 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/MissionGoalsDialog.html @@ -0,0 +1,78 @@ + + + + + Mission Goals - QtFRED Help + + + + +

Mission Goals

+

Opens via Editors › Mission Goals.

+

Defines the goals shown to the player at the end of the briefing and tracked on +the HUD during the mission. When a goal is completed or failed a HUD popup notifies +the player. Goals are hidden during the briefing if the +Toggle Showing Goals In Briefing flag is set in +Mission Specs.

+ +
The UI uses the term Objective in some places (such as +the New Obj. button) interchangeably with Goal. The +canonical term is Goal, which matches the SEXP operator naming +convention.
+ +

Goal types

+

Goal type is a classification that affects how goals are displayed and which music +plays on completion or failure. The actual consequences of a goal being met or failed +, which debriefing stage the player sees, whether the campaign advances, are +determined by SEXPs in the +Debriefing Editor and the +Campaign Editor, which can query goal state +using operators like goal-true and goal-false.

+ + + + + +
TypeDescription
PrimaryShown to the player from the start of the mission. + Completion or failure triggers the primary goal music stinger. By convention + these are the core objectives designers tie campaign progression and debriefing + outcomes to.
SecondaryShown to the player from the start of the mission. + Completion or failure triggers the secondary goal music stinger. Designers + typically use these for optional objectives whose state is queried in the + debriefing or campaign for bonus outcomes.
BonusHidden from the player until the goal is achieved, at which + point the goal text appears on the HUD. Their state is queryable by SEXPs the + same as any other goal type.
+ +

Goal list

+

The main area displays all goals as SEXP +trees. The dropdown at the top filters the list to show one type at a time; +Primary, Secondary, or Bonus. Use New Obj. to append a new goal +of the currently filtered type.

+ +

Goal properties

+ + + + + + + +
FieldDescription
TypePrimary, Secondary, or Bonus. Changing this moves the goal + into the corresponding type group.
NameInternal identifier used in SEXPs such as + goal-true and goal-false, and in mission log + entries. Not shown to the player.
Goal textText displayed to the player in the briefing goal list + and HUD objective display.
ScorePoints awarded when this goal is completed.
TeamIn multiplayer missions, the team this goal belongs + to.
+ +

Goal flags

+ + + + +
FlagDescription
Objective InvalidMarks the goal as invalid from the start of + the mission. Invalid goals are not shown to the player and are not evaluated. + Goals can also be marked valid or invalid at runtime by SEXPs, making this + useful for goals that are conditionally activated during play.
Don't Play Completion MusicSuppresses the event music stinger + that normally plays when this goal is completed or failed.
+ + diff --git a/qtfred/help-src/doc/dialogs/MissionSpecsDialog.html b/qtfred/help-src/doc/dialogs/MissionSpecsDialog.html new file mode 100644 index 00000000000..b05acd65eb1 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/MissionSpecsDialog.html @@ -0,0 +1,144 @@ + + + + + Mission Specs - QtFRED Help + + + + +

Mission Specs

+

Opens via Editors › Mission Specs.

+

Sets mission-wide properties: identity, type, music, support options, and gameplay +flags. This is typically one of the first dialogs to fill in when starting a new +mission.

+ +

Identity

+ + + + + + +
FieldDescription
TitleMission title shown in the mission selection screen and + campaign room.
DesignerAuthor name stored in the mission file for + reference.
DescriptionShort summary shown in the mission selection + screen.
Designer notesFree-form notes visible only in the editor; not + shown to players.
+ +

Mission Type

+

Determines the gameplay rules for the mission.

+ + + + + +
TypeDescription
Single PlayerStandard single-player mission.
MultiplayerSets the mission as a multiplayer mission. A sub-type + must then be selected: Co-op, Team vs. Team, or + Dogfight (all players against all others).
TrainingIntended for tutorial content. A Skip Training + button appears on the briefing screen; selecting it marks all mission goals + complete and advances the campaign without the player having to fly the + mission.
+ +

Multiplayer

+ + + + + + +
FieldDescription
Max RespawnsNumber of times each player may respawn before they + are out of the mission.
Max Respawn DelayNumber of seconds after death before a player + automatically respawns.
Player Entry DelayNumber of seconds of mission time that pass + before the player enters the mission.
Custom Wing NamesOpens + a sub-dialog for assigning special names to player wings. Used in both single + and multiplayer missions; affects the player's wing name, which wings appear + in the loadout editor, and how wings are labeled on the wing HUD + display.
+ +

Squadron

+

Overrides the player's squadron name and logo for this mission. The logo is chosen +from a gallery popup. In campaign mode, the reassignment persists and carries forward +to all subsequent missions.

+ +

Loading Screen

+ + + + +
FieldDescription
480 (lo-res)Custom loading screen image used at lower + resolutions.
768 (hi-res)Custom loading screen image used at higher + resolutions.
+ +

Support Ships

+ + + + + + +
ControlDescription
Disallow support shipsPrevents any support ship from appearing + in this mission.
Enable hull repairAllows the support ship to repair hull damage + in addition to subsystems. Subsystem repair is always available when a support + ship is present.
Hull repair ceilingMaximum percentage of hull the support ship + can restore, when hull repair is enabled.
Subsystem repair ceilingMaximum percentage of subsystem + integrity the support ship can restore.
+ +

Ship Trails

+

Controls engine contrail visibility. By default, trails are on in +full-nebula missions and off elsewhere. Enabling the toggle reverses this +default.

+ + + + + +
ControlDescription
Toggle (off in nebula; on elsewhere)Reverses the default + contrail behavior: trails become off in nebula and on in non-nebula + missions.
Enable minimum speedWhen checked, trails are only shown when a + ship is moving at or above the configured speed.
Minimum speedSpeed threshold in meters per second below which + trails are hidden.
+ +

Command Messages

+

Configures the identity of the Command sender used for built-in mission messages.

+ + + + + +
ControlDescription
SenderThe ship that speaks as Command. Populated from huge ships + present in the current mission, plus the default + Command entry.
PersonaVoice persona used for Command messages. Populated from + personas flagged as Command personas in the game tables.
Override #Command in event messagesWhen enabled, any event + message whose sender is the literal string #Command will use the + Sender and Persona configured here instead of the default Command + identity.
+ +

Mission Music

+

Assigns the music pack used during the mission. An alternate pack can also be +specified; it will be used instead if it is present in the current mod.

+ +

AI Profile

+

Selects which AI profile from the game tables governs NPC behavior in this +mission. Different profiles vary AI aggression, skill ceiling, and target selection +logic.

+ +

Sound Environment

+

Opens the Sound Environment sub-dialog, +which configures audio reverb and environmental effects applied during the +mission.

+ +

Custom Data

+

See the Custom Data concept page.

+ +

Custom Strings

+

Opens the Custom Strings sub-dialog for +attaching arbitrary named strings to the mission.

+ +

Flags

+

A searchable list of toggles that adjust global mission behavior. Use the filter +box to find a specific flag by name, or use Select All / +Select None to bulk-toggle. Hover over any flag label for a tooltip +description.

+ + diff --git a/qtfred/help-src/doc/dialogs/MissionStatsDialog.html b/qtfred/help-src/doc/dialogs/MissionStatsDialog.html new file mode 100644 index 00000000000..f725043826e --- /dev/null +++ b/qtfred/help-src/doc/dialogs/MissionStatsDialog.html @@ -0,0 +1,42 @@ + + + + + Mission Statistics - QtFRED Help + + + + +

Mission Statistics

+

Opens via View › Mission Stats.

+

Displays a read-only summary of everything currently in the mission. Use this to get a +quick overview of mission complexity or verify counts before testing.

+ +

Tabs

+ + + + + + +
TabContents
SummaryTotal counts: ships, wings, waypoint paths, jump nodes, + mission events, mission goals, and messages.
ShipsEvery ship in the mission listed with its name, class, team, + and wing assignment.
EscortShips with the escort flag enabled in the + Ship Editor. Ships added to or removed + from the escort list at runtime via SEXPs are not reflected here.
HotkeysHotkey assignments defined statically in the mission. + Assignments made at runtime via the add-remove-hotkey SEXP are + not reflected here.
+ +

Hard limits

+ + + + +
LimitValueNotes
Max ships500Maximum number of ship instances that can + exist in the mission at any one time.
Max objects5000Maximum total object count including + ships, props, weapons, and all other object types.
+ +
This dialog is read-only. To change anything shown here, open the +relevant editor from the Editors or View menu.
+ + diff --git a/qtfred/help-src/doc/dialogs/MusicPlayerDialog.html b/qtfred/help-src/doc/dialogs/MusicPlayerDialog.html new file mode 100644 index 00000000000..adf48bb5bc4 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/MusicPlayerDialog.html @@ -0,0 +1,31 @@ + + + + + Music Player - QtFRED Help + + + + +

Music Player

+

Opens via View › Music Player.

+

Plays back music files from the game's music folder while you work, so you can +audition tracks without launching FreeSpace Open. Useful when choosing tracks for +Mission Specs, +Briefing, +Debriefing, or +Command Briefing.

+ +

Controls

+ + + + + + +
ControlDescription
Track listAll music files found in the game's music folder. + Click a track to select it.
Play / StopStart or stop playback of the selected track.
Previous / NextJump to the previous or next track in the + list.
AutoplayWhen enabled, playback advances automatically to the + next track when the current one ends, like a playlist.
+ + diff --git a/qtfred/help-src/doc/dialogs/ObjectOrientEditorDialog.html b/qtfred/help-src/doc/dialogs/ObjectOrientEditorDialog.html new file mode 100644 index 00000000000..58dc9a953ed --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ObjectOrientEditorDialog.html @@ -0,0 +1,59 @@ + + + + + Object Orientation Editor - QtFRED Help + + + + +

Object Orientation Editor

+

Opens via Editors › Object Orientation.

+

Precisely sets the position and orientation of one or more selected objects using +numeric input. Useful when you need exact coordinates or angles rather than dragging +objects in the viewport.

+ +

Position

+

X, Y, and Z set the world-space +coordinates of the object.

+ +

Orientation

+

P (pitch), B (bank), and H +(heading) set the object's facing angles. These controls are disabled when +Point To is active.

+ +

Point To

+

Instead of specifying PBH angles directly, Point To automatically +orients the object so that it faces a chosen target. Use the drop-down to select +another object in the mission to point at, or enter a specific set of world-space +coordinates to point toward instead.

+ +

Absolute vs. Relative

+ + + + +
ModeBehavior
Set absoluteThe values entered are treated as final world-space + coordinates and angles. The object is placed exactly where you specify, + regardless of where it currently is.
Set relativeThe values entered are added to the object's current + position and orientation. Entering X = 100 moves the object 100 + units further along the X axis from wherever it already is.
+ +

Transform Objects Independently vs. Relative to Origin Object

+

This option only matters when multiple objects are selected.

+ + + + +
ModeBehavior
Transform Objects IndependentlyEach selected object is transformed + on its own. The same position or orientation values are applied to every object + separately, so they all end up at the same location or facing the same + direction. Use this when you want to snap a group of objects to a common + position or give them all an identical heading.
Transform Relative to Origin ObjectThe selected objects are moved + or rotated as a group, preserving the spatial relationships between them. The + transform is applied to the group as a whole using one object as the reference + point, so the objects stay the same distance and orientation relative to each + other. Use this when repositioning or rotating a formation without breaking + it apart.
+ + diff --git a/qtfred/help-src/doc/dialogs/PreferencesDialog.html b/qtfred/help-src/doc/dialogs/PreferencesDialog.html new file mode 100644 index 00000000000..88783286106 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/PreferencesDialog.html @@ -0,0 +1,43 @@ + + + + + Preferences - QtFRED Help + + + + +

Preferences

+

Opens via File › Preferences.

+

Controls QtFRED editor settings. Changes take effect immediately; there is no +Apply button.

+ +

General

+ + + + + + +
SettingDescription
Move ships with arrow keysWhen enabled, the arrow keys nudge + selected objects in the viewport instead of scrolling the view.
Check for errors on saveRuns the built-in mission error checker + automatically each time the mission is saved.
Show SEXP help tooltipsDisplays documentation tooltips when + hovering over SEXP nodes in the condition and action trees.
Dark modeSwitches the editor UI to a dark color + theme.
+ +

Grid

+ + + + + +
SettingDescription
Grid planeWhich plane the editor grid lies on: + XZ (horizontal), XY, or YZ.
Grid centerThe world-space coordinates of the grid's center + point.
Reset gridResets the grid plane and center to defaults.
+ +

Keybindings

+

Lists every editor action alongside its current keyboard shortcut. Click a shortcut +field and press a new key combination to rebind it. Conflicts are highlighted. +Bindings are saved per-user and persist across sessions.

+ + diff --git a/qtfred/help-src/doc/dialogs/PropEditorDialog.html b/qtfred/help-src/doc/dialogs/PropEditorDialog.html new file mode 100644 index 00000000000..b6d839e5356 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/PropEditorDialog.html @@ -0,0 +1,30 @@ + + + + + Prop Editor - QtFRED Help + + + + +

Prop Editor

+

Opens via Editors › Props.

+

Configures prop objects placed in the mission. Props are static objects that cannot +move or be interacted with except for collisions.

+ +

Key fields

+ + + + +
FieldDescription
NameUnique identifier for this prop instance, used in SEXPs and + mission scripting.
Prev / NextCycles through all prop objects in the mission without + returning to the viewport.
+ +

Flags

+

A list of behavior flags that can be toggled on or off for this prop. Use the filter +field to search by name, and the Select All / Select +None buttons to bulk-toggle all visible flags. Hover over a flag for a +tooltip description.

+ + diff --git a/qtfred/help-src/doc/dialogs/ReinforcementsEditorDialog.html b/qtfred/help-src/doc/dialogs/ReinforcementsEditorDialog.html new file mode 100644 index 00000000000..1a3860df6dd --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ReinforcementsEditorDialog.html @@ -0,0 +1,39 @@ + + + + + Reinforcements - QtFRED Help + + + + +

Reinforcements Editor

+

Opens via Editors › Reinforcements.

+

Designates wings that the player can call in as reinforcements via the comm menu +during the mission. Reinforcement wings do not spawn automatically at mission start. +Instead of auto-spawning when their arrival cue becomes true, the arrival cue +determines when the option to call that reinforcement becomes available in the comm +menu. The wing then warps in only when the player actually calls it.

+ +

Wing lists

+

The left panel lists all wings in the mission. Select one or more and use +Add to designate them as reinforcements; they appear in the right +panel. Select a wing in the right panel and use Remove to revoke +its reinforcement status.

+ +

Reinforcement properties

+ + + + +
FieldDescription
UsesMaximum number of times the player can call this + reinforcement. Once the limit is reached the option disappears from the comm + menu.
DelayTime in seconds between when the player calls the + reinforcement and when the wing actually warps in.
+ +
Reinforcement wings must still have their arrival cues and arrival +location configured in the Wing Editor. The +arrival cue controls when the reinforcement option appears in the comm menu; the +arrival location controls where the wing warps in when called.
+ + diff --git a/qtfred/help-src/doc/dialogs/RelativeCoordinatesDialog.html b/qtfred/help-src/doc/dialogs/RelativeCoordinatesDialog.html new file mode 100644 index 00000000000..0992d9dcd3a --- /dev/null +++ b/qtfred/help-src/doc/dialogs/RelativeCoordinatesDialog.html @@ -0,0 +1,21 @@ + + + + + Calculate Relative Coordinates - QtFRED Help + + + + +

Calculate Relative Coordinates

+

Opens via Tools › Calculate Relative Coordinates.

+

A read-only information tool that calculates the distance and orientation from one +object to another. Select an origin object from the left list and a +satellite object from the right list; the distance and P/B/H angles +from the origin to the satellite are displayed instantly. Angles are expressed in the +origin object's local coordinate frame. Both lists include ships and waypoints. If two +objects are already selected in the viewport when the dialog opens, they are +pre-selected as origin and satellite.

+

The dialog does not modify the mission in any way.

+ + diff --git a/qtfred/help-src/doc/dialogs/ShieldSystemDialog.html b/qtfred/help-src/doc/dialogs/ShieldSystemDialog.html new file mode 100644 index 00000000000..13507a6daca --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShieldSystemDialog.html @@ -0,0 +1,39 @@ + + + + + Shield System - QtFRED Help + + + + +

Shield System

+

Opens via Editors › Shield System.

+

A convenience tool for enabling or disabling shields on ships in bulk, by ship class +or by IFF team. When applied, the dialog directly sets the shield flag on every +existing ship in the mission; it is not a runtime override. If you add new ships +after using this dialog, reopen it and apply again to include them.

+ +

By ship class (left panel)

+

Select a ship class from the dropdown and choose +Has shield system or No shield system. Applying +sets the flag on all ships of that class currently in the mission.

+ +

By IFF team (right panel)

+

Select a team from the dropdown and choose +Has shield system or No shield system. Applying +sets the flag on all ships belonging to that team currently in the mission.

+ +
When both a ship class setting and a team setting apply to the same +ship, the ship class setting takes precedence.
+
The Shield System dialog, the Ship +Editor (Initial Status and Ship Flags tabs), and +Global Ship Flags all write to the same +per-ship shield flag. There is no fixed precedence between them; whichever is +applied last takes effect. A typical workflow is to use this dialog to establish a +baseline across the mission, then make individual adjustments per ship in the Ship +Editor. If you later reopen this dialog and a team or class shows as +Mixed (some ships differ), applying without changing that setting will +leave those individual ship values intact.
+ + diff --git a/qtfred/help-src/doc/dialogs/ShipAltShipClass.html b/qtfred/help-src/doc/dialogs/ShipAltShipClass.html new file mode 100644 index 00000000000..2edfcedf80c --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipAltShipClass.html @@ -0,0 +1,40 @@ + + + + + Alt Ship Class - QtFRED Help + + + + +

Alt Ship Class

+

Accessed via the Alt Ship Class button in the Ship Editor.

+

Defines a prioritized fallback chain of ship classes to substitute if this ship's +primary class is unavailable at mission load. The engine tries the primary class +first, then works through the alt class list in order, assigning the first class +that qualifies. This is primarily useful in campaign missions where the available +ship pool can vary based on earlier choices or loadout configuration.

+ +

The alt class list

+

Each entry in the list is one fallback candidate. Order matters. The engine tries +them top to bottom and stops at the first one it can use. Use the +Up and Down buttons to reorder entries. +Add and Insert create new entries; +Delete removes the selected one.

+ +

Entry properties

+ + + + + +
FieldDescription
From ShipA fixed ship class chosen directly from the available + classes. The class is resolved at mission load.
From VariableA string variable whose value names the ship class + to use. The variable is read at mission load, so the class can be set + dynamically by earlier SEXPs in the campaign.
Default to this classControls how the engine checks availability. + When unchecked, the engine assigns this class immediately without checking + whether any slots remain in the loadout. When checked, the engine first + verifies that ships of this class are still available in the loadout; if + none remain, it skips this entry and tries the next one.
+ + diff --git a/qtfred/help-src/doc/dialogs/ShipCustomWarpDialog.html b/qtfred/help-src/doc/dialogs/ShipCustomWarpDialog.html new file mode 100644 index 00000000000..b2b77e84e9a --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipCustomWarpDialog.html @@ -0,0 +1,52 @@ + + + + + Custom Warp Params - QtFRED Help + + + + +

Custom Warp Params

+

Accessed via the Custom Warp Params button in the Arrival or Departure section of the +Ship Editor or Wing Editor.

+

Overrides the warp-in or warp-out appearance and behavior for this instance. The +dialog opens separately for arrival and departure, so each direction can have +independent settings.

+ +

Fields

+ + + + + + + + + + + + + +
FieldDescription
Warp typeThe visual style of the warp effect. Available types + include the standard hyperspace portal, Knossos device, in-place animation + (BSG-style), sweeper (Homeworld-style), and hyperspace jump with an + acceleration curve. Some fields below are only active for certain + types.
Start soundSound played when the warp effect begins. Enter the + sound name as defined in the game sound tables.
End soundSound played when the warp effect finishes.
Warpout engage timeSeconds the ship waits after the departure cue + fires before the warp animation begins. Warp-out only.
Warping speedSpeed in game units per second at which the ship + translates through the warp effect during the animation. For the hyperspace + type, the current ship speed is used if it exceeds this value.
Warping timeDuration of the warp animation in seconds.
Acceleration / Deceleration exponentExponent applied to the + speed curve during the animation. Values above 1 produce a fast start + tapering to a slow finish; values below 1 do the opposite. Only available + when the warp type is Hyperspace.
RadiusRadius of the warp portal or effect in game units. For the + sweeper type, a value of 0 or less uses the ship's bounding box + dimensions.
AnimationFilename of the animation displayed during the effect. + Only available for the sweeper warp type.
Use supercap warp physicsEnables special physics handling + designed for large capital ships. During warp-out the ship decelerates after + clearing the effect; during warp-in it slows to match its normal maximum + speed.
Player warpout speedOverrides the default speed used to calculate + the player ship's warp-out animation timing. Only available for warp-out on + player ships.
+ + diff --git a/qtfred/help-src/doc/dialogs/ShipEditorDialog.html b/qtfred/help-src/doc/dialogs/ShipEditorDialog.html new file mode 100644 index 00000000000..4b49f104411 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipEditorDialog.html @@ -0,0 +1,147 @@ + + + + + Ship Editor - QtFRED Help + + + + +

Ship Editor

+

Opens by double-clicking a ship in the viewport, or via Editors › +Ships.

+

The Ship Editor configures individual ships. When multiple ships are selected in the +viewport, editing a field applies the change to all of them simultaneously; some +fields are disabled during multi-ship editing (such as Name, which must be +unique). Some fields also behave differently or are unavailable when the selected +ship is a Player Start.

+ +

General fields

+ + + + + + + + + + + + + + + + + + +
FieldDescription
NameUnique identifier used to reference this ship in SEXPs and + mission log entries. Often visible to the player in the targeting HUD.
Display nameIf set, shown to the player instead of the ship name + in the targeting HUD and other player-facing contexts.
Ship classThe ship class from the game tables, defining the + model, stats, and weapon hardpoints.
CallsignShort identifier appended to the ship name in HUD target + boxes (e.g. the ship name may read "Alpha 1 (Braveheart)" if a callsign is + set).
Alt nameIf set, replaces the ship's class name in HUD target + boxes. Use this to display a different class name to the player without + changing the actual ship class.
AI classOverrides the AI skill level for this ship, independent + of the mission's global AI profile.
TeamIFF team (Friendly, Hostile, Neutral, etc.) determining + which ships treat this one as ally or enemy.
CargoText displayed to the player when the ship is scanned. Use + Nothing for ships with no cargo.
Cargo TitleText title displayed to the player when the ship is scanned. + This is the text before the ":" and defaults to "Cargo:" if not set.
WingRead-only. Shows which wing this ship belongs to, if + any.
HotkeyFunction key (F5–F12) that selects this ship during + play.
PersonaVoice persona used when this ship sends messages and when + auto-selecting a wingmate sender for messages with a matching persona + assigned.
Kill scorePoints awarded to the player for destroying this + ship.
Assist %Percentage of the kill score awarded to players who earn + an assist on this ship. For example, a value of 50 with a kill score of 100 + gives assisters 50 points.
Respawn priorityIn multiplayer, ships with higher values are + prioritized when the engine selects which ship a player respawns into.
Player shipRead-only indicator. Use Set Player + Ship to change this.
+ +

Buttons

+ + + + + + +
ButtonDescription
Set Player ShipConverts the selected ship between a Player Start + and a regular ship. This changes the ship's internal object type and updates + the player start count, affecting how the engine handles spawning and + player-specific logic.
Prev / NextMoves the selection to the previous or next ship in + the mission, allowing quick sequential editing without switching back to the + viewport.
Delete ShipRemoves the selected ship from the mission.
ResetResets the selected ship(s) to their ship class defaults, + including cargo, AI class, goals, hull and shield percentages, and weapon + loadout.
+ +

Subdialogs

+ + + + + + + + + + +
DialogDescription
WeaponsPrimary and secondary + weapon bank loadout.
Player OrdersConfigures + which comm menu orders the player can issue to this ship.
Texture + ReplacementOverrides specific textures on this ship + instance.
Initial StatusStarting + hull, shields, subsystem damage, and weapon ammo.
Initial OrdersAI orders + this ship follows at mission start.
Special StatsPer-instance + overrides for ship statistics.
FlagsPer-ship behavior + flags.
Alt Ship ClassFallback ship + classes used if the primary class is unavailable at mission load.
+ +

Arrival & Departure

+

Controls when and where this ship enters and leaves the mission. The cue SEXP must +evaluate to true before the arrival or departure can occur. Most arrival locations +require a target ship to be selected. Departure location options are limited to +Hyperspace or To Dock Bay.

+ +

Arrival locations

+ + + + + + + + + + + +
LocationNotes
HyperspaceWarps in from hyperspace. No target required.
Near ShipAppears near the target ship at the specified + distance.
In Front of ShipAppears in front of the target at the specified + distance.
In Back of ShipAppears behind the target at the specified + distance.
Above ShipAppears above the target at the specified + distance.
Below ShipAppears below the target at the specified + distance.
To Left of ShipAppears to the left of the target at the specified + distance.
To Right of ShipAppears to the right of the target at the + specified distance.
From Dock BayLaunches from the target ship's dock bay. Use + Restrict Paths to limit which bay paths are + used.
+ +

Fields

+ + + + + + + + + +
FieldDescription
TargetThe ship this arrival or departure is relative to. Required + for all locations except Hyperspace.
DistanceDistance from the target in meters. Arrival only; + available for positional locations (Near Ship, In Front of Ship, + etc.).
DelaySeconds after the cue becomes true before the ship + arrives or departs.
Restrict PathsSelects which dock bay paths to use. Only available + when the location is From Dock Bay or To Dock Bay.
Custom Warp ParamsOpens + a sub-dialog to configure custom warp appearance and behavior.
CueSEXP that must evaluate + to true for arrival or departure to occur.
No warp effectWhen checked, the ship appears or leaves without + the visual warp effect.
+ + diff --git a/qtfred/help-src/doc/dialogs/ShipFlagsDialog.html b/qtfred/help-src/doc/dialogs/ShipFlagsDialog.html new file mode 100644 index 00000000000..10c11f7676e --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipFlagsDialog.html @@ -0,0 +1,18 @@ + + + + + Ship Flags - QtFRED Help + + + + +

Ship Flags

+

Accessed via the Flags button in the Ship Editor.

+

A checklist of per-ship behavior flags that override the ship class defaults for +this instance. Each flag has a tooltip explaining its effect.

+

Some flags require an additional parameter when enabled. For example, the escort +flag takes a priority value. When such a flag is checked, its parameter field +appears and must be set before the flag takes effect.

+ + diff --git a/qtfred/help-src/doc/dialogs/ShipInitialOrdersDialog.html b/qtfred/help-src/doc/dialogs/ShipInitialOrdersDialog.html new file mode 100644 index 00000000000..06c5493ead4 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipInitialOrdersDialog.html @@ -0,0 +1,33 @@ + + + + + Initial Orders - QtFRED Help + + + + +

Initial Orders

+

Accessed via the Initial Orders button in the +Ship Editor or Wing Editor.

+

Sets the AI orders the ship or wing follows at mission start. Orders are evaluated +in priority order and can be overridden at runtime by events or +SEXPs.

+ +

Order properties

+ + + + + + + +
FieldDescription
OrderThe AI order to issue (attack, guard, ignore, etc.).
TargetThe ship, wing, or other object the order applies to. + Not all orders require a target.
Target subsystemLimits the order to a specific subsystem on + the target. Only available for orders that support subsystem + targeting.
BayThe dock bay to use. Only available for orders that involve + docking or launching.
PriorityDetermines which order takes precedence when multiple + orders are active. Range is 1–200. Orders with a priority above 89 may + outrank orders issued by the player during play.
+ + diff --git a/qtfred/help-src/doc/dialogs/ShipInitialStatusDialog.html b/qtfred/help-src/doc/dialogs/ShipInitialStatusDialog.html new file mode 100644 index 00000000000..e0e9e40ae4d --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipInitialStatusDialog.html @@ -0,0 +1,76 @@ + + + + + Ship Initial Status - QtFRED Help + + + + +

Ship Initial Status

+

Accessed via the Initial Status button in the Ship Editor.

+

Sets the ship's condition at mission start.

+ +

Hull & shields

+ + + + + + + + +
FieldDescription
VelocityThe ship's speed at mission start.
Hull integrityStarting hull strength as a percentage of + maximum.
Guardian thresholdMinimum hull percentage the ship can be + damaged down to. Once the ship's hull reaches this level, further damage is + absorbed without reducing it further. Set to 0 to disable. Applies to both + the hull and subsystems.
Has shield systemWhether this ship has an active shield system + at mission start.
Force shields onEnables shields regardless of other flags that + would suppress them. Only takes effect if the ship's class defines a shield + strength; it cannot create shields for a class that has none.
Shield integrityStarting shield strength as a percentage of + maximum.
+ +

Loadout locks

+ + + + +
FieldDescription
Ship lockedPrevents the player from changing this ship in the + loadout screen.
Weapons lockedPrevents the player from changing this ship's + weapons in the loadout screen.
+ +

Disabled systems

+ + + + + + +
FieldDescription
Primaries won't firePrimary weapons are disabled at mission + start.
Secondaries won't fireSecondary weapons are disabled at mission + start.
Turrets won't fireAll turrets are disabled at mission + start.
Afterburner disabledAfterburner is disabled at mission + start.
+ +

Dockpoints

+

Lists all dockpoints defined on this ship. Select a dockpoint to set it as +occupied by another ship and specify which dockpoint on that ship mates with this +one.

+ +

Subsystems

+

Lists all subsystems on this ship. Select a subsystem to set its starting +integrity as a percentage of maximum. For subsystems that can be scanned, a cargo +field may also available to set what the player finds when scanning that +subsystem. Additionally a cargo title field may be available which defaults to +"Cargo:" if not set. The cargo fields are only visible if the ship has scannable +subsystems. If the Unify Scanning Behavior mod flag is active then +all ships can have scannable cargo by setting the Toggle Subsystem Scanning +ship flag. If the mod flag is not set then huge ships always have scannable subsystems and +other ships will require the ship flag to be enabled.

+ +

Team color

+

Assigns a team color to this ship. Requires the ship to have a +-misc texture map and the desired colors to be defined in +colors.tbl.

+ + diff --git a/qtfred/help-src/doc/dialogs/ShipPlayerOrdersDialog.html b/qtfred/help-src/doc/dialogs/ShipPlayerOrdersDialog.html new file mode 100644 index 00000000000..12f1ada50f9 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipPlayerOrdersDialog.html @@ -0,0 +1,15 @@ + + + + + Player Orders - QtFRED Help + + + + +

Player Orders

+

Accessed via the Player Orders button in the Ship Editor.

+

Lists all orders the player can issue via the comm menu. Check an order to allow +the player to send it to this ship; uncheck to prevent it.

+ + diff --git a/qtfred/help-src/doc/dialogs/ShipSpecialStatsDialog.html b/qtfred/help-src/doc/dialogs/ShipSpecialStatsDialog.html new file mode 100644 index 00000000000..24c80a80643 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipSpecialStatsDialog.html @@ -0,0 +1,51 @@ + + + + + Special Stats - QtFRED Help + + + + +

Special Stats

+

Accessed via the Special Stats button in the Ship Editor.

+

Per-instance overrides for statistics normally defined by the ship class. All +sections are independently enabled and only apply when their checkbox is +checked.

+ +

Special explosion

+

Overrides the ship's death explosion with custom parameters.

+ + + + + + + + + +
FieldDescription
DamageAmount of damage dealt to nearby ships.
BlastPhysical force applied to nearby ships, pushing them + away from the explosion. Scales with distance the same way damage + does.
Inner radiusShips within this distance receive full damage + and blast.
Outer radiusShips beyond this distance receive no damage or + blast. Between the inner and outer radius, both values scale down with + distance.
Create shockwaveWhen checked, the explosion also spawns an + expanding shockwave.
Shockwave speedExpansion speed of the shockwave in game units + per second. Only available when Create shockwave is + checked.
Custom death roll timeWhen checked, overrides the duration of + the pre-death roll animation (the period of secondary explosions before the + final detonation). Set the duration in milliseconds.
+ +

Special hitpoints

+

Overrides the ship's maximum hitpoints with a flat value, replacing the ship +class table entry entirely for this instance.

+ + + + +
FieldDescription
Enable special shield hitpointsWhen checked, sets an absolute + maximum shield strength for this ship, replacing the class + default.
Enable special hitpointsWhen checked, sets an absolute maximum + hull strength for this ship, replacing the class default.
+ + diff --git a/qtfred/help-src/doc/dialogs/ShipTextureReplacementDialog.html b/qtfred/help-src/doc/dialogs/ShipTextureReplacementDialog.html new file mode 100644 index 00000000000..5efc835ad20 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipTextureReplacementDialog.html @@ -0,0 +1,36 @@ + + + + + Texture Replacement - QtFRED Help + + + + +

Texture Replacement

+

Accessed via the Texture Replacement button in the Ship Editor.

+

Overrides textures on this ship instance without modifying the ship class or its +table entry.

+ +

Texture list

+

The left panel lists all base diffuse textures on the ship's model. Select one to +set its replacement. Type the replacement texture name in the New +Texture field, no file extension needed.

+ +

Other Maps

+

When the selected texture slot has additional map types defined on the model +(glow, normal, specular, etc.), this section shows a control for each one. Each +map type has:

+
    +
  • Replace - check to enable a replacement for this map + type.
  • +
  • Inherit - automatically derives the replacement name by + appending the map type suffix to the main texture replacement name (e.g. + replacing fighter01 with myfighter and inheriting + the normal map produces myfighter-normal). Uncheck to enter the + name manually.
  • +
+

Models that only define a base diffuse texture will show no controls in this +section.

+ + diff --git a/qtfred/help-src/doc/dialogs/ShipWeaponsDialog.html b/qtfred/help-src/doc/dialogs/ShipWeaponsDialog.html new file mode 100644 index 00000000000..32182e89bf1 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/ShipWeaponsDialog.html @@ -0,0 +1,31 @@ + + + + + Ship Weapons - QtFRED Help + + + + +

Ship Weapons

+

Accessed via the Weapons button in the Ship Editor.

+

Assigns weapons to the ship's banks and turrets for this mission instance, +overriding the ship class defaults.

+ +

Mode

+

Select Primary, Secondary, or +Turret to switch which set of banks is shown. The +Tertiary option is not currently implemented.

+ +

Assigning weapons

+

The right panel lists the banks or turrets for the selected mode. Select the bank +or turret you want to change. Then select the desired weapon from the left panel and +click Set Selected to assign it.

+

Where a weapon uses ammo, the ammo count appears as a second column next to the +weapon name. Click the value to edit the starting ammo for that bank directly.

+ +

Turret AI class

+

When in Turret mode, a dropdown and button at the bottom allow the AI class of the +selected turret to be changed independently of the ship's overall AI class.

+ + diff --git a/qtfred/help-src/doc/dialogs/SoundEnvironmentDialog.html b/qtfred/help-src/doc/dialogs/SoundEnvironmentDialog.html new file mode 100644 index 00000000000..75fe39a9b2b --- /dev/null +++ b/qtfred/help-src/doc/dialogs/SoundEnvironmentDialog.html @@ -0,0 +1,29 @@ + + + + + Sound Environment - QtFRED Help + + + + +

Sound Environment

+

Accessed via Sound Environment in the Mission Specs dialog.

+

Applies an environmental reverb effect to in-game sound effects and messages. +Select a preset from the list as a starting point, then adjust the individual +parameters to taste.

+ +

Parameters

+ + + + + +
ParameterDescription
VolumeOverall level of the reverb effect mixed in with the dry + signal. Higher values make the environment sound more pronounced.
DampingHow quickly high frequencies are absorbed as the reverb + tail decays. Higher damping produces a warmer, more muffled reverb, as if + the environment has soft or absorptive surfaces.
Decay timeHow long the reverb tail rings out after a sound + stops, in seconds. Longer values simulate large or reflective spaces such as + hangars or caverns; shorter values suggest small or dampened rooms.
+ + diff --git a/qtfred/help-src/doc/dialogs/TeamLoadoutDialog.html b/qtfred/help-src/doc/dialogs/TeamLoadoutDialog.html new file mode 100644 index 00000000000..44462617217 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/TeamLoadoutDialog.html @@ -0,0 +1,86 @@ + + + + + Team Loadout - QtFRED Help + + + + +

Team Loadout

+

Opens via Editors › Team Loadout.

+

Defines the pool of ships and weapons players can choose from at the loadout screen +before a mission. The dialog has two tabs: Static Loadout for fixed +class selections and Variable Loadout for runtime-dynamic +selections driven by SEXP variables.

+ +
Team Loadout only applies to missions with the type set to +Team vs. Team in Mission Specs.
+ +

Top controls

+ + + + + +
ControlDescription
Team selectorSwitches which team's loadout is being edited.
Copy to other teamCopies the current team's loadout to all other + teams.
Skip FRED's Weapon Loadout ValidationBypasses FRED's internal + validation of the weapon loadout across all teams. Applied globally regardless + of which team is selected. Required when using the Variable Loadout tab. + Enabling this marks the mission as requiring FSO 23.3 or + later.
+ +

Static Loadout tab

+

The left pane lists all player-flyable ships available in the current mod; the right +pane lists all player-usable weapons. Both panes can be filtered by name. The +Clear, Select All, and +Multi-select controls are UI conveniences for selecting list entries +and have no effect on the mission itself.

+ +

Per-item controls

+ + + + + + + +
ControlDescription
Enabled (checkbox)Adds or removes the ship or weapon from the + loadout pool. Items already present in the mission's starting wings (defined + in Mission Specs › + Custom Wing Names) are automatically + enabled and shown with a partial check. They cannot be removed from the pool + since they are already committed to those wings.
In wingsRead-only count of how many of this ship or weapon are + already accounted for in the mission's starting wings.
ExtraAdditional quantity made available beyond what is already in + wings.
Extra from variableA number variable whose value is added to the + available quantity at runtime. Useful for adjusting pool sizes dynamically + via SEXPs during the mission.
Required (weapons only)When checked, the mission requires that + this weapon be loaded onto a player or allied ship before the player is + allowed to launch.
+ +

Variable Loadout tab

+

Variable loadout entries use SEXP string variables to define which ship or weapon +class is available, allowing the class itself to change at runtime. This is useful for +missions where the available ships or weapons depend on earlier mission choices or +campaign state.

+

Each entry works as follows: a string variable's value is the name of the +ship or weapon class to offer. Because SEXPs can change that variable's value during +the mission (or in a previous mission if the variable is persistent), the class offered +to players can vary dynamically. An additional number variable can optionally control +the quantity available.

+

Variable entry controls

+ + + + + + + +
ControlDescription
Enabled (checkbox)Includes this variable entry in the + loadout.
VariableThe string variable whose value names the ship or weapon + class to offer.
ValueShows the variable's current default value (i.e. the class + it resolves to at mission start).
ExtraStatic quantity available in addition to any count + variable.
Extra variableA number variable controlling the available quantity + at runtime.
+ + diff --git a/qtfred/help-src/doc/dialogs/VariablesAndContainersDialog.html b/qtfred/help-src/doc/dialogs/VariablesAndContainersDialog.html new file mode 100644 index 00000000000..00a4aaea540 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/VariablesAndContainersDialog.html @@ -0,0 +1,84 @@ + + + + + Variables & Containers - QtFRED Help + + + + +

Variables & Containers

+

Opens via Editors › Variables.

+

Declares named variables and containers that SEXPs +can read and write during the mission. Variables hold a single value; containers hold +collections of values. Both are referenced in SEXPs by name and can be used throughout +the event system to track state, accumulate data, and communicate between events.

+ +

Variables tab

+

The main list shows all variables in the mission with their name and default value. +String type variables are colored blue while numeric type are color orange. +The list is filterable. Use Add, Copy, and +Delete to manage entries. Double-click a variable's name or value to +edit it inline.

+ +

Variable properties

+ + + + + +
FieldDescription
NameThe identifier used to reference this variable in + SEXPs.
Default valueThe value the variable starts with at the beginning + of the mission.
TypeNumber or String. Variables are explicitly + typed and the type cannot be changed at runtime.
+ +

Persistence

+

Controls when a variable's value is saved between missions. The +Eternal checkbox (only available when a persistence mode is +selected) controls where it is saved: unchecked saves to the campaign file +(value is scoped to the current campaign); checked saves to the player's pilot file +(value persists across all campaigns and is always available).

+ + + + + +
SettingDescription
No persistenceThe variable exists only for the duration of this + mission. Its value is reset each time the mission starts. Eternal is not + available.
Save on Mission CompletedThe variable's value is saved when the + player accepts the mission outcome in the debriefing. If the player quits + without accepting, the value is not saved.
Save on Mission CloseThe variable's value is saved whenever the + mission closes, whether the player accepted, quit, or restarted.
+ +

Network variable

+

When checked, the variable's value is broadcast to all players whenever it is +modified during a multiplayer mission, keeping it synchronized across the +session.

+ +

Containers tab

+

Containers hold collections of values. The upper list shows all containers in the +mission and is filterable. List containers are colored blue while map containers are +colored orange. Use Add, Copy, and Delete +to manage containers. Double-click a container's name to edit it inline. Containers +have the same persistence and network settings as variables.

+ +

Container type

+ + + + +
TypeDescription
ListAn ordered sequence of values, all of the same type (Number + or String). Items can be added, removed, and iterated in SEXPs.
MapA collection of key-value pairs where each key maps to a + value. Keys and values each have their own type (Number or String, + independently). For example, a map with string keys and number values can + associate ship names with scores, or a map with string keys and string values + can work like a set of named labels. SEXPs access map entries by key.
+ +

Container contents

+

The lower box shows the contents of the selected container and is also filterable. +Use Add, Copy, and Delete to +manage entries, and the arrow buttons to reorder them. Double-click a key or value to +edit it inline. For Map containers, the Swap button exchanges a key +and its value.

+ + diff --git a/qtfred/help-src/doc/dialogs/VoiceActingManager.html b/qtfred/help-src/doc/dialogs/VoiceActingManager.html new file mode 100644 index 00000000000..65233e45f2f --- /dev/null +++ b/qtfred/help-src/doc/dialogs/VoiceActingManager.html @@ -0,0 +1,94 @@ + + + + + Voice Acting Manager - QtFRED Help + + + + +

Voice Acting Manager

+

Opens via Editors › Voice Acting Manager.

+

A tool for generating voice acting scripts and programmatically assigning voice file +paths across all spoken lines in a mission. It covers messages created in the Mission +Events editor, briefing stages, command briefing stages, and debriefing stages.

+ +

Abbreviations

+

Abbreviations define how voice filenames are automatically constructed. The +Example box shows a live preview as you fill in the fields.

+ + + + + + + + + + +
FieldDescription
Campaign abbreviationShort code identifying the campaign. Placed + at the start of every filename, combined with the mission + abbreviation.
Mission abbreviationShort code identifying the mission. Combined + with the campaign abbreviation at the start of the filename.
Cmd. BriefingString inserted into filenames for command briefing + lines.
BriefingString inserted into filenames for briefing lines.
DebriefingString inserted into filenames for debriefing + lines.
MessageString inserted into filenames for in-mission message + lines.
ExtensionPreferred audio file extension: .wav or + .ogg.
Include sender nameWhen checked, the name of the sending ship or + persona is included in the filename for message lines.
+ +

Generating filenames

+

Replace existing filenames - when checked, the generator will +overwrite voice file assignments that are already set. When unchecked, only lines +with no assignment are filled in.

+

Generate filenames applies the abbreviation rules to every line in +the mission, setting voice file paths according to the options above.

+ +

Script options

+

Controls how the exported script document is formatted and what it contains.

+ + + + + +
FieldDescription
FormatA free-form template defining how each line appears in the + exported script. The available substitution tokens are listed in the dialog + itself.
ExportRadio buttons selecting which source to include in the + script: everything, messages only, briefing stages only, command briefing + stages only, or debriefing stages only.
Group sent-message-list messages togetherWhen checked, messages in + the script are reordered to match the sequence they appear in mission events + (send-message-list, send-message-chain, and send-random-message operations), + rather than the default message index order. Any messages not referenced in + events are appended at the end. This is useful for voice directors who want + to work through the script in mission flow order.
+

Generate script writes the script file to disk using the format +and export settings above.

+ +

Sync Personas

+

Tools for keeping persona assignments consistent between ships and the messages they +send. The persona filter drop-down scopes all operations in this +section to a specific set of personas: wingman personas only, non-wingman personas +only, or a single named persona.

+ + + + + + + +
ButtonDescription
Copy message personas to shipsFor each mission message that has a + persona assigned, finds the ship that sends it and sets that ship's persona + to match.
Copy ship personas to messagesReverse of the above; for each + ship with a persona set, updates the messages it sends to use that same + persona.
Clear personas from ships that don't send messagesRemoves the + persona assignment from any ship that has one but does not send any messages. + Useful for cleaning up personas that were set by mistake or are no longer + needed.
Set head ANIs using personas in messages.tblFor each message with + a persona assigned, looks up a matching built-in message in + messages.tbl with the same persona and copies its head + animation assignment.
Check if messages sent by <any wingman> have at least one ship with + that personaValidates that every message addressed to + <any wingman> has a wingman persona assigned and that at + least one ship in the mission carries that persona. Reports any + discrepancies.
+ + diff --git a/qtfred/help-src/doc/dialogs/VolumetricNebulaDialog.html b/qtfred/help-src/doc/dialogs/VolumetricNebulaDialog.html new file mode 100644 index 00000000000..5dc942bd901 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/VolumetricNebulaDialog.html @@ -0,0 +1,96 @@ + + + + + Volumetric Nebula - QtFRED Help + + + + +

Volumetric Nebula

+

Opens via Editors › Volumetric Nebula.

+

Configures the volumetric nebula renderer. Unlike the classic nebula in the +Background Editor, the volumetric nebula is +rendered as a true 3D volume with light scattering, emissive glow, and procedural noise +shaping.

+ +

Key fields

+ + + + + + +
FieldDescription
EnabledAdds the volumetric nebula to the mission. Uncheck to + disable without losing settings.
ModelPOF model that defines the outer boundary shape of the nebula + volume. The mesh must be watertight; multiple disjunct meshes are allowed as + long as their polygons do not intersect.
Position (X, Y, Z)World-space position of the nebula + volume.
Color (RGB)Primary color the nebula is rendered with.
+ +

Rendering

+ + + + + + + + + + + +
FieldDescription
OpacityTarget translucency - the maximum opacity the nebula + reaches at full depth. Cannot be set to 0.
Opacity distanceDistance in metres a viewer must be inside the + nebula before it reaches its target opacity.
Render quality stepsNumber of steps used to accumulate nebula + density along each ray. Higher values reduce banding on objects inside the + volume; primarily affects frame rate.
ResolutionResolution of the nebula's 3D density texture, + stored as a power of 2 (5–8 recommended). Higher values cost more + VRAM.
OversamplingOversampling factor for the 3D texture (1–3). + Each increment quadruples loading time but reduces edge banding, especially + at lower resolutions. Primarily affects load time.
SmoothingControls how softly the hull POF's edges blend into + the surrounding nebula. Expressed as a fraction of the nebula size.
Henyey-Greenstein coefficientControls light scattering + direction. Values greater than 0 produce a cloud-like shine-through effect; + values less than 0 produce a highly reflective nebula. Practical range is + roughly 0.05–0.75.
Sun falloff factorScales how the sun's illumination falls off + with nebula depth. Values greater than 1 make the nebula's interior brighter + than physically accurate; values less than 1 make it darker.
Sun quality stepsNumber of steps taken toward the sun per + nebula slice when computing shadowing. Higher values reduce light/shadow + banding; primarily affects frame rate.
+ +

Emissive

+ + + + + +
FieldDescription
Emissive lightIntensity of the emissive glow added by light + sources inside the nebula. Higher values produce brighter + emissives.
IntensityControls how quickly an emissive light source widens + inside the nebula. Larger values spread the glow more broadly even where + there is little nebula to obscure it.
Emissive light falloffCorrects emissive alpha near the source. + Values greater than 1 darken the emissive close to its origin, producing a + more even spread; values less than 1 brighten it near the origin, making it + more intense at the center.
+ +

Noise

+

Procedural noise is layered on top of the base volume to break up uniform density +and create wispy internal structure.

+ + + + + + + + + + +
FieldDescription
Enable noiseToggles procedural noise on or off without losing + the noise settings.
Color (RGB)Tint color applied to the noise layer.
Scale baseSize of the primary noise layer in metres. The ratio + between Scale base and Scale sub should have a large denominator to avoid + visible harmonic patterns in the result.
Scale subSize of the secondary noise layer in metres.
IntensityOverall strength of the noise effect.
ResolutionResolution of the noise 3D texture, stored as a + power of 2 (5–8 recommended). Higher values cost more VRAM.
Set Base Noise FunctionNot yet implemented. Will allow a custom + ANL noise expression to replace the default base noise layer.
Set Sub Noise FunctionNot yet implemented. Will allow a custom + ANL noise expression to replace the default sub noise layer.
+ + diff --git a/qtfred/help-src/doc/dialogs/WaypointEditorDialog.html b/qtfred/help-src/doc/dialogs/WaypointEditorDialog.html new file mode 100644 index 00000000000..4602069d1e1 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/WaypointEditorDialog.html @@ -0,0 +1,36 @@ + + + + + Waypoint Editor - QtFRED Help + + + + +

Waypoint Editor

+

Opens via Editors › Waypoints.

+

Creates and edits waypoint paths. Each path is an ordered list of 3D points. Ships +given a waypoint goal fly through the points in sequence, then optionally loop. +Waypoint paths are simply ordered sequences of arbitrary positions in space and can +be used for any purpose a mission designer can express through SEXPs and AI goals.

+ +

Key fields

+ + + + + + +
FieldDescription
Waypoint pathSelects which path to edit. New paths are created by + placing waypoint objects in the viewport.
NameIdentifies the path in SEXPs and AI goal assignments. Must be + unique.
No Draw LinesWhen checked, the connecting lines between waypoints + are hidden in the viewport. The waypoint points themselves are still + visible.
Custom ColorWhen checked, enables the RGB fields below to set a + custom color for rendering this path's points and lines in the viewport. + Does not affect in-game appearance.
+ +
Individual waypoint positions are moved by selecting the waypoint +object in the viewport and dragging, or by editing its coordinates in the +Object Orientation Editor.
+ + diff --git a/qtfred/help-src/doc/dialogs/WaypointPathGeneratorDialog.html b/qtfred/help-src/doc/dialogs/WaypointPathGeneratorDialog.html new file mode 100644 index 00000000000..874adc8ff7f --- /dev/null +++ b/qtfred/help-src/doc/dialogs/WaypointPathGeneratorDialog.html @@ -0,0 +1,43 @@ + + + + + Waypoint Path Generator - QtFRED Help + + + + +

Waypoint Path Generator

+

Opens via Tools › Waypoint Path Generator.

+

Automatically generates a waypoint path whose +points are arranged in a geometric shape around a center point. Useful for creating +patrol circuits, orbit paths, and similar regular formations without placing each +point by hand.

+ +

Fields

+ + + + + + + + + + +
FieldDescription
NameName assigned to the generated waypoint path.
Center pointThe origin around which all points are placed. Enter + coordinates manually, or select an object from the drop-down to use its + current position as the center.
AxisThe axis the shape revolves around. For example, choosing the + Y axis produces a flat horizontal ring; choosing X or Z tilts it + upright.
Number of pointsHow many waypoints to place per loop around the + center. Total waypoints created equals points × loops.
LoopsHow many full revolutions around the center point the path + makes. Combined with Number of points, this produces a helix or spiral + when Drift is also set.
RadiusDistance from the center point to each generated + waypoint.
DriftOffsets each successive point by this amount along the chosen + axis, perpendicular to the revolution plane. A non-zero drift turns a flat + ring into a helix.
Variance (X, Y, Z)Adds a random offset to each point's + coordinates. The X, Y, Z values set the approximate maximum displacement in + each axis; the actual offset applied to each point is randomized within that + range. Use this to break up overly regular paths.
+ + diff --git a/qtfred/help-src/doc/dialogs/WingEditorDialog.html b/qtfred/help-src/doc/dialogs/WingEditorDialog.html new file mode 100644 index 00000000000..29108ca0336 --- /dev/null +++ b/qtfred/help-src/doc/dialogs/WingEditorDialog.html @@ -0,0 +1,111 @@ + + + + + Wing Editor - QtFRED Help + + + + +

Wing Editor

+

Opens via Editors › Wings.

+

Creates and configures wings. A wing groups ships that share arrival and departure +cues and can receive collective AI goals. Wings support multiple waves and each wave is +a fresh copy of the wing that spawns when the previous wave drops below the threshold.

+ +

General fields

+ + + + + + + + + + +
FieldDescription
NameWing name shown on the HUD and used in SEXPs + (e.g. Alpha, Gamma).
Wing leaderWhich ship in the wing acts as leader. Other members + form up on the leader.
Number of wavesHow many waves of this wing will arrive over the + course of the mission. Each wave is a full copy of the wing's ships. The first + wave is included in this count.
Wave thresholdWhen the number of surviving ships in the current + wave drops to this value or below, the next wave spawns. Set to 0 to require + the entire wave to be destroyed before the next arrives.
HotkeyFunction key (F5–F12) that selects this wing during + play.
FormationThe flight formation wing members use relative to the + leader.
Formation scaleScales the formation spacing up or down.
Squad logoLogo displayed on the ships in this wing. Choose from + the gallery of available insignia.
+ +

Buttons

+ + + + + + + + +
ButtonDescription
Align FormationRepositions all ships in the wing in the editor + viewport to match the currently selected formation. Has no effect at + runtime.
Prev / NextMoves the selection to the previous or next wing, + allowing sequential editing without switching back to the viewport.
Delete WingRemoves the wing and all of its ships from the + mission.
Disband WingDissolves the wing without deleting its ships. Each + ship becomes an independent, unassociated object in the mission.
Initial OrdersAI orders + all ships in the wing follow at mission start.
Wing FlagsOpens a checklist of per-wing behavior flags. Each flag + has a tooltip describing its effect.
+ +

Arrival & Departure

+

Controls when and where the wing enters and leaves the mission. The cue SEXP must +evaluate to true before arrival or departure can occur. Most arrival locations require +a target ship or wing to be selected. Departure location options are limited to +Hyperspace or To Dock Bay.

+ +

Arrival locations

+ + + + + + + + + + + +
LocationNotes
HyperspaceWarps in from hyperspace. No target required.
Near ShipAppears near the target at the specified distance.
In Front of ShipAppears in front of the target at the specified + distance.
In Back of ShipAppears behind the target at the specified + distance.
Above ShipAppears above the target at the specified + distance.
Below ShipAppears below the target at the specified + distance.
To Left of ShipAppears to the left of the target at the specified + distance.
To Right of ShipAppears to the right of the target at the + specified distance.
From Dock BayLaunches from the target ship's dock bay. Use + Restrict Paths to limit which bay paths are used.
+ +

Fields

+ + + + + + + + + + + +
FieldDescription
TargetThe ship or wing this arrival or departure is relative to. + Required for all locations except Hyperspace.
DistanceDistance from the target in meters. Arrival only; + available for positional locations (Near Ship, In Front of Ship, + etc.).
DelaySeconds after the cue becomes true before the wing + arrives or departs.
Delay between waves (min / max)After a new wave is triggered by + the threshold, the engine waits a random number of seconds between these two + values before the wave actually spawns. Applies to all waves after the + first.
Restrict PathsSelects which dock bay paths to use. Only available + when the location is From Dock Bay or To Dock Bay.
Custom Warp ParamsOpens + a sub-dialog to configure custom warp appearance and behavior.
CueSEXP that must evaluate + to true for arrival or departure to occur.
No warp effectWhen checked, the wing appears or leaves without + the visual warp effect.
Don't Adjust Warp When DockedBy default, ships that are docked + together warp in or out with an enlarged effect sized to cover the combined + formation. When checked, each ship instead uses its individual warp effect + size, ignoring the docked aggregate.
+ + diff --git a/qtfred/help-src/doc/fundamentals.html b/qtfred/help-src/doc/fundamentals.html new file mode 100644 index 00000000000..c6eb1410efa --- /dev/null +++ b/qtfred/help-src/doc/fundamentals.html @@ -0,0 +1,187 @@ + + + + + Fundamentals - QtFRED Help + + + + +

Fundamentals

+ +

This tutorial walks you through building a small but complete mission with events, +waypoints, messages, and a briefing. It assumes you have read the +Quickstart. Budget about 30 minutes.

+ +

The mission we are building: the player escorts a friendly transport along a waypoint +route to rendezvous with a friendly capital ship. Hostile fighters arrive shortly +after the mission starts. If the transport completes its route, the mission +succeeds.

+ +
Save often. Press Ctrl+S every few +minutes. Test in-game after each major step. Catching problems early saves a lot of +rework later.
+ +

1. Plan before you open QtFRED

+

Before placing anything, sketch out what the mission needs:

+
    +
  • A player fighter wing (Alpha)
  • +
  • A friendly transport that needs to reach a rendezvous point
  • +
  • A friendly capital ship at the destination, set as a protect target
  • +
  • A hostile fighter wing that arrives ~30 seconds in
  • +
  • A waypoint path for the transport to follow
  • +
  • Events: a timed trigger for the hostile arrival, a radio message when they arrive
  • +
  • A primary mission goal tied to the transport completing its route
  • +
  • A two-stage briefing and a debriefing
  • +
+

Knowing this upfront prevents building yourself into a corner. You will still +adjust things as you go and that is normal.

+ +

2. Place the ships

+

Open a new mission. The player ship is already there. Select it and click +Form Wing, name the wing Alpha. Move Alpha 1 to roughly +0, 0, -2000 using the +Object Orientation Editor.

+ +

Place the friendly transport near the origin. Open the +Ship Editor, name it +Transport 1, set its team to Friendly, and set its +initial velocity to 0. It will start stationary and move when given orders.

+ +

Place a friendly capital ship some distance away at the end of where the +transport's route will go. Name it Command Ship and set it to +Friendly. Open its Ship Editor and click +Flags to open the +Ship Flags subdialog. Enable +Protect Ship. This tells hostile AI not to target or attack it, +making it a safe destination for the transport to reach. Velocity 0 is fine here +too.

+ +

Place two hostile fighters somewhere off to the side. Select both, click +Form Wing, name the wing Epsilon, set team to +Hostile. Open the Arrival / Departure tab in the Ship Editor for +each Epsilon ship and set arrival location to Hyperspace. Leave +the arrival cue as true for now.

+ +
Save and do a quick test. All ships should appear. Epsilon will +arrive immediately and that is fine for now.
+ +

3. Add a waypoint path for the transport

+

Select the waypoint tool in the toolbar and Ctrl+click in the viewport +to lay out a short route from the transport's position toward the Command Ship. +Three or four points is plenty. Open the +Waypoint Editor and name the path +Transport Route.

+ +

Open the Ship Editor for Transport 1, go to +Initial Orders, and set its initial goal to +Waypoints OnceTransport Route. The +transport will fly the route once from start to finish.

+ +

Save and test. The transport should start moving along the route.

+ +

4. Delay the hostile arrival with an event

+

Open Editors › Mission Events. Click Add +event and name it Epsilon Arrives. Set its +Condition SEXP to:

+
(has-time-elapsed 30)
+

No action is needed in this event. It acts purely as a named trigger that other +things can reference.

+ +

Now go back to the Ship Editor for each ship in Epsilon wing. In the +Arrival / Departure tab, change the +Arrival cue SEXP to:

+
(is-event-true-delay 0 "Epsilon Arrives")
+

This way all of Epsilon's ships key off the same named event. If you want to +change the delay later, you only need to edit the event's condition in one place.

+ +

Save and test. The first 30 seconds should be quiet, then Epsilon jumps in.

+ +

5. Send a message when the hostiles arrive

+

Messages are created and sent from the same +Mission Events editor. On the right +side of the dialog, click Add under the message list to create a +new message. Give it the name Epsilon Inbound and write a short line of +text such as "Hostile fighters inbound! Protect the transport!" Set a +sender if desired, or leave it as <mission>.

+ +

Now create a new event and name it Epsilon Arrival Message. Set its +Condition to:

+
(has-arrived-delay 0 "Epsilon 1")
+

In the Actions tree, add a send-message SEXP and +select Epsilon Inbound as the message. Leave the priority at +Normal.

+ +

Save and test. The message should appear on screen as Epsilon jumps in.

+ +

6. Add a mission goal

+

Open Editors › Mission Goals. Add a primary goal:

+
    +
  • Description: Escort the transport to the rendezvous
  • +
  • Completion condition: + (are-waypoints-done-delay 0 "Transport 1" "Transport Route")
  • +
+

Add a secondary goal for destroying Epsilon wing if you like. See +SEXPs for an overview of how conditions are +built.

+ +

7. Write the briefing

+

Write the briefing now. Be creative and give the player a reason to protect +the transport from Epsilon wing.

+ +

Open Editors › Briefing. Build two stages:

+ + + + +
StageCameraText
1Wide view of the whole sceneExplain the mission: + escort the transport safely to the Command Ship.
2Closer on the transport's routeWarn that hostile + fighters are expected; the player must intercept them while keeping + the transport moving.
+ +

For each stage, position the briefing map camera, add icons for the relevant +ships using Make icon from ship, and type the stage text at the +bottom. See the Briefing Editor +help for full details. Set the Music track at the top of the +dialog.

+ +

Save and walk through the briefing before launching to check camera positions and +icon placement.

+ +

8. Write the debriefing

+

Open Editors › Debriefing. Add two stages:

+ + + + + + + + +
StageUsage formulaText
Success(are-waypoints-done-delay 0 "Transport 1" "Transport Route")The transport completed its route. Commend the player.
Failure(is-destroyed-delay 0 "Transport 1")The transport was lost. Acknowledge the failure.
+

Assign music tracks for success and failure in the +Debriefing music section.

+ +

9. Final test

+

Save and run a full play-through. Check:

+
    +
  • The transport moves along its route from the start
  • +
  • The first 30 seconds are calm
  • +
  • Epsilon and the arrival message both trigger at 30 seconds
  • +
  • The primary goal completes when the transport finishes the route
  • +
  • The briefing camera moves and icons look correct
  • +
  • The correct debriefing stage shows depending on outcome
  • +
+ +

Next steps

+
    +
  • Add a second hostile wave that arrives when the transport is near the end + of its route, using are-waypoints-done-delay on an earlier + waypoint as the trigger.
  • +
  • Add a Command Briefing + before the main briefing.
  • +
  • Chain this into a campaign using the + Campaign Editor.
  • +
+ + diff --git a/qtfred/help-src/doc/general/LayerManagerDialog.html b/qtfred/help-src/doc/general/LayerManagerDialog.html new file mode 100644 index 00000000000..5b92bc38cd2 --- /dev/null +++ b/qtfred/help-src/doc/general/LayerManagerDialog.html @@ -0,0 +1,31 @@ + + + + + Layer Manager - QtFRED Help + + + + +

Layer Manager

+

Opens via View › Layer Manager.

+

Organizes mission objects into named layers. Layers are an editor-only concept and +have no effect on mission gameplay. They exist purely to help manage visibility in the +viewport while editing.

+ +

Layers tab

+

Lists all layers in the mission. Each layer has a checkbox; uncheck it to hide all +objects on that layer in the viewport, check it to show them again. Newly placed objects +are automatically assigned to the Default layer.

+

Use Add to create a new layer. Use Delete to remove +the selected layer. The Default layer cannot be deleted.

+ +

Filters tab

+

Works in conjunction with layers to provide additional visibility control. Allows +hiding objects by type or by IFF team regardless of which layer they are on.

+ +
Hiding objects via layers or filters does not delete or disable them. +Hidden objects are still present in the mission file and will function normally +in-game.
+ + diff --git a/qtfred/help-src/doc/general/PreferencesDialog.html b/qtfred/help-src/doc/general/PreferencesDialog.html new file mode 100644 index 00000000000..37bf7a137ef --- /dev/null +++ b/qtfred/help-src/doc/general/PreferencesDialog.html @@ -0,0 +1,29 @@ + + + + + Preferences - QtFRED Help + + + + +

Preferences

+

Opens via File › Preferences.

+

Controls QtFRED editor settings. Changes take effect immediately; there is no +Apply button.

+ +

General

+

Miscellaneous editor options. Hover over each setting for a tooltip +description.

+ +

Grid

+

Configures the reference grid shown in the main viewport. You can set which +world-space plane the grid lies on (XZ, XY, or YZ) and adjust the grid's center +point to move it to a different position in the world. Use Reset +grid to restore the plane and center to their defaults.

+ +

Controls

+

Allows remapping the default input controls, such as camera movement and +viewport navigation. Hover over each entry for a description of what it does.

+ + diff --git a/qtfred/help-src/doc/general/SceneBrowserDialog.html b/qtfred/help-src/doc/general/SceneBrowserDialog.html new file mode 100644 index 00000000000..07a6b9a477d --- /dev/null +++ b/qtfred/help-src/doc/general/SceneBrowserDialog.html @@ -0,0 +1,45 @@ + + + + + Scene Browser - QtFRED Help + + + + +

Scene Browser

+

Opens via View › Scene Browser.

+

Shows a complete list of every object in the mission, organized by layer and then by object +type within each layer. Provides an alternative to clicking objects in the viewport for +selection and contextual actions.

+ +

Selecting objects

+

Click any object in the list to select it. Hold Ctrl or Shift +to add to the selection.

+

Right-click an object in the list to open the same context menu that +appears when right-clicking that object in the viewport.

+ +

Filtering

+

Use the search box to show only objects whose names match the typed text.

+

Use the IFF checkboxes to show or hide objects by IFF team. Unchecking +an IFF removes all objects belonging to that team from the list.

+ +

Selection shortcuts

+

Three buttons act only on the objects currently visible in the filtered list. Objects +hidden by the search or IFF filters are not affected:

+
    +
  • All - selects every visible object in the list.
  • +
  • Clear - deselects everything.
  • +
  • Invert - selects all currently unselected visible objects and + deselects all currently selected ones.
  • +
+ +

Layer visibility

+

Each layer row in the list has a checkbox. Uncheck it to hide all objects on that layer +in the viewport; check it to show them again. This is the same visibility toggle available +in the Layer Manager.

+ +
Hiding objects via the layer checkbox does not delete or disable them. +Hidden objects remain in the mission file and function normally in-game.
+ + diff --git a/qtfred/help-src/doc/general/Toolbar.html b/qtfred/help-src/doc/general/Toolbar.html new file mode 100644 index 00000000000..ea43a2e8e55 --- /dev/null +++ b/qtfred/help-src/doc/general/Toolbar.html @@ -0,0 +1,150 @@ + + + + + Toolbar - QtFRED Help + + + + +

Toolbar

+

The toolbar provides quick access to the most common editing modes and actions. +The active mode determines how clicks and drags behave in the +viewport.

+ +

Tools

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ToolShortcutDescription
Mode
SelectSClick to select objects. Drag on empty space to box-select.
Select and MoveMClick to select objects; drag a selected object to move it.
Select and RotateRClick to select objects; drag a selected object to rotate it.
Axis constraints
X ConstraintConstrains move or rotate to the X axis.
Y ConstraintConstrains move or rotate to the Y axis.
Z ConstraintConstrains move or rotate to the Z axis.
XZ ConstraintConstrains move or rotate to the XZ plane.
YZ ConstraintConstrains move or rotate to the YZ plane.
XY ConstraintConstrains move or rotate to the XY plane.
Selection
Scene BrowserHToggles the Scene Browser panel, which lists all objects in the + mission.
Lock SelectionSpacePrevents the current selection from changing.
Wings
Form WingCtrl+WForms a wing from the currently selected ships.
Disband WingCtrl+DDisbands the wing of the currently selected ships, returning them to + individual objects.
View
Zoom on SelectedAlt+ZMoves the camera to focus on the selected objects.
Zoom ExtentsShift+ZZooms the camera to fit all objects in the mission into view.
Show DistancesDToggles display of distance measurements between selected objects.
Rotate Around ObjectAlt+RToggles camera orbit mode, rotating the view around the selected + object.
Layers
Manage View LayersOpens the Layer Manager to + show or hide categories of objects.
Show All LayersMakes all hidden layers visible.
+ +

Object creation dropdowns

+

Two dropdowns at the right end of the toolbar control what is created when you +click in the viewport.

+ + + + + + + + + + + + +
DropdownUsed byDescription
ShipsCtrl+clickSelects the ship class, waypoint, or jump node to place. The object + created on Ctrl+click is determined by this selection.
PropsCtrl+Shift+clickSelects the prop class to place. The prop created on + Ctrl+Shift+click is determined by this selection.
+ + diff --git a/qtfred/help-src/doc/general/Viewport.html b/qtfred/help-src/doc/general/Viewport.html new file mode 100644 index 00000000000..28ce1eb5626 --- /dev/null +++ b/qtfred/help-src/doc/general/Viewport.html @@ -0,0 +1,38 @@ + + + + + Viewport - QtFRED Help + + + + +

Viewport

+

The main 3D view where mission objects are placed and arranged.

+ +

Creating objects

+

The toolbar dropdowns determine what type of object is created when you click in +the viewport.

+
    +
  • Ctrl+click - creates a ship, waypoint, or jump node, + depending on the toolbar selection.
  • +
  • Ctrl+Shift+click - creates a prop.
  • +
+ +

Selecting objects

+
    +
  • Click an object to select it.
  • +
  • Click and drag on empty space to draw a selection box and + select all objects within it.
  • +
  • Double-click an object to open its editor dialog.
  • +
+ +

Moving objects

+

Drag a selected object to reposition it in the mission.

+ +

Context menu

+

Right-click anywhere in the viewport to open a context menu with +options relevant to what was clicked. Available options vary depending on whether +you clicked an object, a specific object type, or empty space.

+ + diff --git a/qtfred/help-src/doc/index.html b/qtfred/help-src/doc/index.html new file mode 100644 index 00000000000..c3ecff3e76e --- /dev/null +++ b/qtfred/help-src/doc/index.html @@ -0,0 +1,90 @@ + + + + + QtFRED Help + + + +

QtFRED Help

+ +

Welcome to QtFRED - the mission editor for FreeSpace Open. This help +covers the basics of mission creation, the editor dialogs, and advanced topics.

+ +

Getting Started

+
    +
  • Quickstart — create your first flyable mission in a few minutes.
  • +
  • Fundamentals — build a complete mission with events, waypoints, messages, and a briefing.
  • +
+ +

Concepts

+ + +

General

+ + +

Dialogs

+ +

Environment

+ + +

Mission

+ + +

Narrative

+ + +

Objects

+ + +

Tools

+ + + diff --git a/qtfred/help-src/doc/qtfred.qhp b/qtfred/help-src/doc/qtfred.qhp new file mode 100644 index 00000000000..e9176fce021 --- /dev/null +++ b/qtfred/help-src/doc/qtfred.qhp @@ -0,0 +1,208 @@ + + + org.hard-light.qtfred + doc + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + index.html + quickstart.html + fundamentals.html + concepts/sexps.html + concepts/iff.html + concepts/ai.html + concepts/messages.html + concepts/campaign-flow.html + dialogs/CustomDataDialog.html + css/help.css + dialogs/AsteroidEditorDialog.html + dialogs/BackgroundEditorDialog.html + dialogs/BriefingEditorDialog.html + dialogs/CampaignEditorDialog.html + dialogs/CommandBriefingDialog.html + dialogs/DebriefingDialog.html + dialogs/ErrorCheckerDialog.html + dialogs/EventEditor.html + dialogs/FictionViewerDialog.html + dialogs/GlobalShipFlagsDialog.html + dialogs/JumpNodeEditorDialog.html + general/Viewport.html + general/Toolbar.html + general/LayerManagerDialog.html + general/SceneBrowserDialog.html + dialogs/MissionCutscenesDialog.html + dialogs/MissionEventsDialog.html + dialogs/MissionGoalsDialog.html + dialogs/MissionSpecsDialog.html + dialogs/CustomWingNamesDialog.html + dialogs/CustomStringsDialog.html + dialogs/SoundEnvironmentDialog.html + dialogs/MissionStatsDialog.html + dialogs/MusicPlayerDialog.html + dialogs/ObjectOrientEditorDialog.html + general/PreferencesDialog.html + dialogs/PropEditorDialog.html + dialogs/ReinforcementsEditorDialog.html + dialogs/RelativeCoordinatesDialog.html + dialogs/ShieldSystemDialog.html + dialogs/ShipEditorDialog.html + dialogs/ShipAltShipClass.html + dialogs/ShipCustomWarpDialog.html + dialogs/ShipFlagsDialog.html + dialogs/ShipInitialOrdersDialog.html + dialogs/ShipInitialStatusDialog.html + dialogs/ShipPlayerOrdersDialog.html + dialogs/ShipSpecialStatsDialog.html + dialogs/ShipTextureReplacementDialog.html + dialogs/ShipWeaponsDialog.html + dialogs/TeamLoadoutDialog.html + dialogs/VariablesAndContainersDialog.html + dialogs/VoiceActingManager.html + dialogs/VolumetricNebulaDialog.html + dialogs/WaypointEditorDialog.html + dialogs/WaypointPathGeneratorDialog.html + dialogs/WingEditorDialog.html + + + diff --git a/qtfred/help-src/doc/quickstart.html b/qtfred/help-src/doc/quickstart.html new file mode 100644 index 00000000000..b07705ef12d --- /dev/null +++ b/qtfred/help-src/doc/quickstart.html @@ -0,0 +1,67 @@ + + + + + Quickstart - QtFRED Help + + + + +

Quickstart: Your First Mission

+ +

This guide walks you through creating a simple flyable mission from scratch. By the +end you will have a player ship and a hostile wing to fight. The whole thing takes +about five minutes.

+ +

1. Open a new mission

+

Launch QtFRED. Go to File › New. The viewport shows empty +space with a reference grid. QtFRED automatically places one ship, this is your +player start.

+ +

2. Put the player in Alpha wing

+

Click the player ship in the viewport to select it, then click the +Form Wing button in the toolbar. Type Alpha and click +OK. The ship is renamed Alpha 1.

+
The player ship must be in Alpha wing. The engine looks for Alpha 1 +as the default player start.
+ +

3. Add enemies

+

Use the ship class drop-down in the toolbar to select a hostile ship class. It +will appear in red. Hold Ctrl and left-click in the viewport twice to place +two ships. Select both of them (drag a box or shift-click), then click +Form Wing again. Name the wing Epsilon. The ships are +renamed Epsilon 1 and Epsilon 2 and are hostile by default.

+ +

4. Optionally add more waves

+

With Epsilon wing selected, open Editors › Wings to open the +Wing Editor. Increase +Number of waves to 2 and set a short delay between waves. A second +wave will jump in after the first is destroyed.

+ +

5. Fill in Mission Specs

+

Open Editors › Mission Specs. Give the mission a +Title and a short Description. These appear in the +mission selection screen. Set music tracks if desired.

+ +

6. Add a mission goal

+

Open Editors › Mission Goals. Add a primary goal with a +description such as Destroy all hostiles. Set the completion condition to a +SEXP that evaluates to true when Epsilon wing is destroyed, for example +is-destroyed-delay. See SEXPs for an +overview of the scripting system.

+ +

7. Save and play

+

Press Ctrl+S to save. QtFRED saves to your mod's +data/missions/ folder by default. Launch FreeSpace Open, go to the +Tech Room › Mission Simulator › Single Missions, and your mission will +appear there.

+ +

Next steps

+ + + diff --git a/qtfred/help-src/qtfred.qhp b/qtfred/help-src/qtfred.qhp new file mode 100644 index 00000000000..56944439cbf --- /dev/null +++ b/qtfred/help-src/qtfred.qhp @@ -0,0 +1,205 @@ + + + org.hard-light.qtfred + doc + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + doc/index.html + doc/quickstart.html + doc/fundamentals.html + doc/concepts/sexps.html + doc/concepts/iff.html + doc/concepts/ai.html + doc/concepts/messages.html + doc/concepts/campaign-flow.html + doc/dialogs/CustomDataDialog.html + doc/css/help.css + doc/dialogs/AsteroidEditorDialog.html + doc/dialogs/BackgroundEditorDialog.html + doc/dialogs/BriefingEditorDialog.html + doc/dialogs/CampaignEditorDialog.html + doc/dialogs/CommandBriefingDialog.html + doc/dialogs/DebriefingDialog.html + doc/dialogs/ErrorCheckerDialog.html + doc/dialogs/EventEditor.html + doc/dialogs/FictionViewerDialog.html + doc/dialogs/GlobalShipFlagsDialog.html + doc/dialogs/JumpNodeEditorDialog.html + doc/general/Viewport.html + doc/general/Toolbar.html + doc/general/LayerManagerDialog.html + doc/dialogs/MissionCutscenesDialog.html + doc/dialogs/MissionEventsDialog.html + doc/dialogs/MissionGoalsDialog.html + doc/dialogs/MissionSpecsDialog.html + doc/dialogs/CustomWingNamesDialog.html + doc/dialogs/CustomStringsDialog.html + doc/dialogs/SoundEnvironmentDialog.html + doc/dialogs/MissionStatsDialog.html + doc/dialogs/MusicPlayerDialog.html + doc/dialogs/ObjectOrientEditorDialog.html + doc/general/PreferencesDialog.html + doc/dialogs/PropEditorDialog.html + doc/dialogs/ReinforcementsEditorDialog.html + doc/dialogs/RelativeCoordinatesDialog.html + doc/dialogs/ShieldSystemDialog.html + doc/dialogs/ShipEditorDialog.html + doc/dialogs/ShipAltShipClass.html + doc/dialogs/ShipCustomWarpDialog.html + doc/dialogs/ShipFlagsDialog.html + doc/dialogs/ShipInitialOrdersDialog.html + doc/dialogs/ShipInitialStatusDialog.html + doc/dialogs/ShipPlayerOrdersDialog.html + doc/dialogs/ShipSpecialStatsDialog.html + doc/dialogs/ShipTextureReplacementDialog.html + doc/dialogs/ShipWeaponsDialog.html + doc/dialogs/TeamLoadoutDialog.html + doc/dialogs/VariablesAndContainersDialog.html + doc/dialogs/VoiceActingManager.html + doc/dialogs/VolumetricNebulaDialog.html + doc/dialogs/WaypointEditorDialog.html + doc/dialogs/WaypointPathGeneratorDialog.html + doc/dialogs/WingEditorDialog.html + + + diff --git a/qtfred/help-src/qtfred_help_resources.qrc.in b/qtfred/help-src/qtfred_help_resources.qrc.in new file mode 100644 index 00000000000..1bda2fff0fb --- /dev/null +++ b/qtfred/help-src/qtfred_help_resources.qrc.in @@ -0,0 +1,5 @@ + + + @QTFRED_HELP_QCH@ + + diff --git a/qtfred/help-src/tutorial-template.html b/qtfred/help-src/tutorial-template.html new file mode 100644 index 00000000000..b73b283828a --- /dev/null +++ b/qtfred/help-src/tutorial-template.html @@ -0,0 +1,137 @@ + + + + + + + Your Tutorial Title Here + + + + +

Your Tutorial Title Here

+ +

+ A short paragraph introducing what this tutorial covers and what the reader + will be able to do by the end of it. +

+ + +
+ This is a note box. Use it for tips, prerequisites, or warnings that + should stand out from the body text. +
+ +

1. First Step

+ +

+ Walk through the first thing the reader needs to do. Reference dialog names + in bold. Use Ctrl+Click for keyboard shortcuts + and inline code for values the user types. +

+ + +

+ Double-click the ship to open the + Ship Editor. + Set the team to Friendly and close the dialog. +

+ +

2. Second Step

+ +

+ Continue with the next task. For multi-line commands or SEXP expressions, + use a <pre> block: +

+ +
(has-time-elapsed 60)
+ + +

Reference Table (optional)

+ + + + + + + + + + + + + + + + + + + + + +
SettingRecommended valueNotes
TeamFriendlyRequired for player ships
AI classNonePlayer-controlled ships ignore AI class
+ +

Next Steps

+ +
    +
  • + Learn about + SEXPs + to drive mission logic with conditions and actions. +
  • +
  • + Set up arrival and departure cues in the + Ship Editor. +
  • +
  • + Add mission objectives in + Mission Goals. +
  • +
+ + + diff --git a/qtfred/source_groups.cmake b/qtfred/source_groups.cmake index c6428a92f12..eb5d003d27f 100644 --- a/qtfred/source_groups.cmake +++ b/qtfred/source_groups.cmake @@ -104,6 +104,8 @@ add_file_folder("Source/Mission/Dialogs" src/mission/dialogs/WaypointPathGeneratorDialogModel.h src/mission/dialogs/WingEditorDialogModel.cpp src/mission/dialogs/WingEditorDialogModel.h + src/mission/dialogs/HelpTopicsDialogModel.cpp + src/mission/dialogs/HelpTopicsDialogModel.h ) add_file_folder("Source/Mission/Dialogs/MissionSpecs" src/mission/dialogs/MissionSpecs/CustomDataDialogModel.cpp @@ -170,6 +172,8 @@ add_file_folder("Source/UI/Dialogs" src/ui/dialogs/FormWingDialog.h src/ui/dialogs/GlobalShipFlagsDialog.cpp src/ui/dialogs/GlobalShipFlagsDialog.h + src/ui/dialogs/HelpTopicsDialog.cpp + src/ui/dialogs/HelpTopicsDialog.h src/ui/dialogs/JumpNodeEditorDialog.cpp src/ui/dialogs/JumpNodeEditorDialog.h src/ui/dialogs/LayerManagerDialog.cpp @@ -370,6 +374,7 @@ add_file_folder("UI" ui/ShipAltShipClass.ui ui/ShipWeaponsDialog.ui ui/VariableDialog.ui + ui/HelpTopicsDialog.ui ui/WingEditorDialog.ui ui/WingFlagsDialog.ui ui/SaveAsTemplateDialog.ui diff --git a/qtfred/src/main.cpp b/qtfred/src/main.cpp index af25bf86c56..e52d1068377 100644 --- a/qtfred/src/main.cpp +++ b/qtfred/src/main.cpp @@ -20,6 +20,7 @@ #include "globalincs/pstypes.h" #include "ui/FredView.h" +#include "ui/dialogs/HelpTopicsDialog.h" #include "ui/Theme.h" #include "FredApplication.h" @@ -216,6 +217,10 @@ int main(int argc, char* argv[]) { // Allow other parts of the code to execute code that needs to run after everything has been set up fredApp->initializeComplete(); + // Initialize the help engine and kick off search indexing in the background + // so the Search tab is ready before the user first opens Help Topics. + QTimer::singleShot(0, [] { fso::fred::dialogs::HelpTopicsDialog::prewarm(); }); + if (Cmdline_start_mission) { // Automatically load a mission if specified on the command line QTimer::singleShot(500, [&]() { diff --git a/qtfred/src/mission/dialogs/HelpTopicsDialogModel.cpp b/qtfred/src/mission/dialogs/HelpTopicsDialogModel.cpp new file mode 100644 index 00000000000..a4fad82a51a --- /dev/null +++ b/qtfred/src/mission/dialogs/HelpTopicsDialogModel.cpp @@ -0,0 +1,210 @@ +#include "HelpTopicsDialogModel.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cfile/cfile.h" + +// Declared in cfile... must be at file scope so the tutorial discovery code can see it. +extern int cfile_inited; + +namespace fso::fred::dialogs { + +// --------------------------------------------------------------------------- +// Static member definitions +// --------------------------------------------------------------------------- +QHelpEngine* HelpTopicsDialogModel::_helpEngine = nullptr; +QList HelpTopicsDialogModel::_tutorials; +QHash HelpTopicsDialogModel::_tutorialContent; +TutorialEntry HelpTopicsDialogModel::_sexpOperatorReference; +bool HelpTopicsDialogModel::_hasSexpOperatorReference = false; + +// --------------------------------------------------------------------------- +HelpTopicsDialogModel::HelpTopicsDialogModel(QObject* parent) : QObject(parent) {} + +// --------------------------------------------------------------------------- +void HelpTopicsDialogModel::prewarm() { + if (ensureEngineReady()) + _helpEngine->searchEngine()->scheduleIndexDocumentation(); + _tutorialContent.clear(); + _hasSexpOperatorReference = false; + _tutorials = discoverTutorials(); +} + +QHelpEngine* HelpTopicsDialogModel::helpEngine() { + return _helpEngine; +} + +const QList& HelpTopicsDialogModel::tutorials() { + return _tutorials; +} + +const QHash& HelpTopicsDialogModel::tutorialContent() { + return _tutorialContent; +} + +const TutorialEntry* HelpTopicsDialogModel::sexpOperatorReference() { + return _hasSexpOperatorReference ? &_sexpOperatorReference : nullptr; +} + +// --------------------------------------------------------------------------- +bool HelpTopicsDialogModel::ensureEngineReady() { + if (_helpEngine != nullptr) + return !_helpEngine->registeredDocumentations().isEmpty(); + + const QString collectionFile = resolveCollectionFile(); + if (collectionFile.isEmpty()) { + mprintf(("QtFRED help: could not determine a writable location for the help collection\n")); + return false; + } + + // Parent to qApp so Qt manages the lifetime. Destroyed cleanly before the event loop exits. + _helpEngine = new QHelpEngine(collectionFile, qApp); + if (!_helpEngine->setupData()) { + mprintf(("QtFRED help: could not initialize engine: %s\n", + _helpEngine->error().toUtf8().constData())); + delete _helpEngine; + _helpEngine = nullptr; + return false; + } + + const QString contentFile = resolveContentFile(); + if (contentFile.isEmpty()) { + mprintf(("QtFRED help: could not find qtfred_help.qch\n")); + delete _helpEngine; + _helpEngine = nullptr; + return false; + } + + const QString ns = QHelpEngineCore::namespaceName(contentFile); + if (!ns.isEmpty()) { + // Always unregister and re-register. Qt copies file content from the .qch into the + // .qhc SQLite database at registration time. If the .qch is rebuilt without + // re-registration the .qhc tables become stale: findFile() succeeds but fileData() + // returns 0 bytes. Forcing re-registration each startup is cheap and guarantees the + // collection database is always in sync with the current .qch. + if (_helpEngine->registeredDocumentations().contains(ns)) + _helpEngine->unregisterDocumentation(ns); + + if (!_helpEngine->registerDocumentation(contentFile)) { + mprintf(("QtFRED help: failed to register %s: %s\n", + contentFile.toUtf8().constData(), + _helpEngine->error().toUtf8().constData())); + } else { + mprintf(("QtFRED help: registered namespace '%s' from %s\n", + ns.toUtf8().constData(), + contentFile.toUtf8().constData())); + } + } + + return !_helpEngine->registeredDocumentations().isEmpty(); +} + +// --------------------------------------------------------------------------- +QString HelpTopicsDialogModel::resolveCollectionFile() { + const QString appDataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + if (appDataDir.isEmpty()) + return {}; + QDir(appDataDir).mkpath(QStringLiteral("help")); + return QDir(appDataDir).filePath(QStringLiteral("help/qtfred.qhc")); +} + +QString HelpTopicsDialogModel::resolveContentFile() { + // Check the FSO VFS for a mod override in data/freddocs/. + if (cfile_inited) { + CFileLocation loc = cf_find_file_location("qtfred_help.qch", CF_TYPE_FREDDOCS); + if (loc.found && !loc.full_name.empty()) + return QString::fromStdString(loc.full_name); + } + + // Fall back to the built-in .qch deployed next to the executable. + return QDir(QCoreApplication::applicationDirPath()).filePath( + QStringLiteral("help/qtfred_help.qch")); +} + +// --------------------------------------------------------------------------- +QString HelpTopicsDialogModel::extractHtmlTitle(const QString& filePath) { + QFile f(filePath); + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + return {}; + // Titles are always in the , so a small read is enough. + const QString head = QString::fromUtf8(f.read(4096)); + const QRegularExpression re(QStringLiteral("]*>([^<]+)"), + QRegularExpression::CaseInsensitiveOption); + const auto m = re.match(head); + if (m.hasMatch()) + return m.captured(1).trimmed(); + return QFileInfo(filePath).completeBaseName(); +} + +QList HelpTopicsDialogModel::discoverTutorials() { + QList result; + if (cfile_inited) { + SCP_vector filenames; + cf_get_file_list(filenames, CF_TYPE_FREDDOCS, "*.html"); + for (const auto& filename : filenames) { + // Skip files in subdirectories. Only surface top-level tutorials. + // Mods can use subdirectories for assets or linked pages without flooding the list. + if (filename.find('/') != SCP_string::npos || filename.find('\\') != SCP_string::npos) + continue; + + // cf_get_file_list strips extensions; re-add it for the lookup and URL. + const std::string fullFilename = filename + ".html"; + CFileLocation loc = cf_find_file_location(fullFilename.c_str(), CF_TYPE_FREDDOCS); + if (!loc.found) + continue; + + const QString fullPath = QString::fromStdString(loc.full_name); + const QString urlPath = QStringLiteral("/") + QString::fromStdString(fullFilename); + + QFile f(fullPath); + if (!f.open(QIODevice::ReadOnly)) + continue; + + _tutorialContent[urlPath] = f.readAll(); + + if (QString::compare(QString::fromStdString(fullFilename), + QStringLiteral("sexps.html"), + Qt::CaseInsensitive) == 0) { + _sexpOperatorReference = {QStringLiteral("SEXP Operator Reference"), fullPath, urlPath}; + _hasSexpOperatorReference = true; + continue; + } + + result.append({extractHtmlTitle(fullPath), fullPath, urlPath}); + } + } + + // Optional fallback for developers: also accept a loose sexps.html shipped + // next to the QtFRED executable (or in its help/ subdirectory). + if (!_hasSexpOperatorReference) { + const QDir appDir(QCoreApplication::applicationDirPath()); + const QStringList fallbackPaths = { + appDir.filePath(QStringLiteral("sexps.html")), + appDir.filePath(QStringLiteral("help/sexps.html")) + }; + + for (const auto& candidate : fallbackPaths) { + QFile f(candidate); + if (!f.open(QIODevice::ReadOnly)) + continue; + + const QString urlPath = QStringLiteral("/sexps.html"); + _tutorialContent[urlPath] = f.readAll(); + _sexpOperatorReference = {QStringLiteral("SEXP Operator Reference"), candidate, urlPath}; + _hasSexpOperatorReference = true; + break; + } + } + + return result; +} + +} // namespace fso::fred::dialogs diff --git a/qtfred/src/mission/dialogs/HelpTopicsDialogModel.h b/qtfred/src/mission/dialogs/HelpTopicsDialogModel.h new file mode 100644 index 00000000000..2b005292509 --- /dev/null +++ b/qtfred/src/mission/dialogs/HelpTopicsDialogModel.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include + +class QHelpEngine; + +namespace fso::fred::dialogs { + +struct TutorialEntry { + QString title; + QString fullPath; // absolute path on disk + QString urlPath; // e.g. "/getting-started.html" — key in tutorialContent() +}; + +/** + * @brief Service model for the HelpTopicsDialog. + * + * Manages the singleton QHelpEngine and the list of mod tutorial pages discovered + * in data/freddocs/. All state is static so it is shared across the application + * lifetime regardless of how many times the dialog is opened or closed. + * + * Call prewarm() once at startup (after the VFS is ready) to initialise the engine + * and kick off search indexing in the background before the user opens Help Topics. + */ +class HelpTopicsDialogModel : public QObject { + Q_OBJECT + +public: + explicit HelpTopicsDialogModel(QObject* parent = nullptr); + + // Call once at startup... initialises the help engine, schedules full-text + // search indexing, and discovers mod tutorial pages, all before the dialog opens. + static void prewarm(); + + static QHelpEngine* helpEngine(); + static const QList& tutorials(); + static const QHash& tutorialContent(); + static const TutorialEntry* sexpOperatorReference(); + + // Exposed so HelpTopicsDialog can call it directly and show an error on failure. + static bool ensureEngineReady(); + +private: + static QString resolveCollectionFile(); + static QString resolveContentFile(); + static QString extractHtmlTitle(const QString& filePath); + static QList discoverTutorials(); + + static QHelpEngine* _helpEngine; + static QList _tutorials; + static QHash _tutorialContent; + static TutorialEntry _sexpOperatorReference; + static bool _hasSexpOperatorReference; +}; + +} // namespace fso::fred::dialogs diff --git a/qtfred/src/ui/FredView.cpp b/qtfred/src/ui/FredView.cpp index 50426531936..54c7e3ada18 100644 --- a/qtfred/src/ui/FredView.cpp +++ b/qtfred/src/ui/FredView.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -2065,6 +2067,17 @@ void FredView::on_actionMark_Wing_triggered(bool) { void FredView::on_actionError_Checker_triggered(bool) { fred->global_error_check(); } +void FredView::on_actionHelp_Topics_triggered(bool) { + // Keep a single instance alive for the session. The help engine's contentWidget(), + // indexWidget(), and search widgets are singletons owned by the engine. + static QPointer s_helpDialog; + if (!s_helpDialog) + s_helpDialog = new dialogs::HelpTopicsDialog(this); + s_helpDialog->show(); + s_helpDialog->raise(); + s_helpDialog->activateWindow(); +} + void FredView::on_actionAbout_triggered(bool) { auto dialog = new dialogs::AboutDialog(this, _viewport); dialog->setAttribute(Qt::WA_DeleteOnClose); diff --git a/qtfred/src/ui/FredView.h b/qtfred/src/ui/FredView.h index 5b517d481f1..aaec5f9f861 100644 --- a/qtfred/src/ui/FredView.h +++ b/qtfred/src/ui/FredView.h @@ -161,6 +161,7 @@ class FredView: public QMainWindow, public IDialogProvider { void on_actionError_Checker_triggered(bool); + void on_actionHelp_Topics_triggered(bool); void on_actionAbout_triggered(bool); void on_actionMission_Statistics_triggered(bool); void on_actionBackground_triggered(bool); diff --git a/qtfred/src/ui/dialogs/HelpTopicsDialog.cpp b/qtfred/src/ui/dialogs/HelpTopicsDialog.cpp new file mode 100644 index 00000000000..145d894c269 --- /dev/null +++ b/qtfred/src/ui/dialogs/HelpTopicsDialog.cpp @@ -0,0 +1,416 @@ +#include "HelpTopicsDialog.h" +#include "ui_HelpTopicsDialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mission/dialogs/HelpTopicsDialogModel.h" +#include "ui/Theme.h" + +namespace fso::fred::dialogs { + +// --------------------------------------------------------------------------- +// HelpBrowser +// --------------------------------------------------------------------------- +HelpBrowser::HelpBrowser(QWidget* parent) : QTextBrowser(parent) { + setOpenLinks(false); +} + +void HelpBrowser::changeEvent(QEvent* e) { + QTextBrowser::changeEvent(e); + if (e->type() == QEvent::PaletteChange) + reload(); +} + +QVariant HelpBrowser::loadResource(int type, const QUrl& name) { + if (name.scheme() == QStringLiteral("fredtutorial")) { + // Serve pre-loaded HTML tutorial pages. + const auto& content = HelpTopicsDialogModel::tutorialContent(); + const auto it = content.constFind(name.path()); + if (it != content.constEnd()) { + QByteArray tutorialBytes = *it; + if (name.path().endsWith(QStringLiteral(".html")) && isDarkMode()) { + const int insertAt = tutorialBytes.indexOf(""); + if (insertAt != -1) + tutorialBytes.insert(insertAt, darkModeStyleBlock()); + } + return tutorialBytes; + } + // On-demand loading for assets (images, CSS, etc.) referenced by tutorial pages. + // Falls through to the VFS lookup in cfile, handled in the model's resolveContentFile + // path, so we just return empty here for unknown assets. + return {}; + } + + if (name.scheme() == QStringLiteral("qthelp")) { + QHelpEngine* engine = HelpTopicsDialogModel::helpEngine(); + if (engine == nullptr) + return {}; + const QUrl canonical = engine->findFile(name); + if (!canonical.isValid()) + return {}; + QByteArray helpBytes = engine->fileData(canonical); + if (canonical.path().endsWith(QStringLiteral(".html")) && isDarkMode()) { + const int insertAt = helpBytes.indexOf(""); + if (insertAt != -1) + helpBytes.insert(insertAt, darkModeStyleBlock()); + } + return helpBytes; + } + + return QTextBrowser::loadResource(type, name); +} + +bool HelpBrowser::isDarkMode() const { + return palette().color(QPalette::Window).lightness() < 128; +} + +QByteArray HelpBrowser::darkModeStyleBlock() { + return QByteArrayLiteral( + ""); +} + +// --------------------------------------------------------------------------- +// HelpTopicsDialog +// --------------------------------------------------------------------------- +HelpTopicsDialog::HelpTopicsDialog(QWidget* parent) + : QDialog(parent), ui(new Ui::HelpTopicsDialog) { + ui->setupUi(this); + + bindStandardIcon(ui->backButton, QStyle::SP_ArrowLeft); + bindStandardIcon(ui->forwardButton, QStyle::SP_ArrowRight); + bindStandardIcon(ui->findPreviousButton, QStyle::SP_ArrowUp); + bindStandardIcon(ui->findNextButton, QStyle::SP_ArrowDown); + + if (!HelpTopicsDialogModel::ensureEngineReady()) { + ui->splitter->setDisabled(true); + QMessageBox::warning(this, tr("Help error"), tr("Could not load QtFRED help content.")); + return; + } + + QHelpEngine* engine = HelpTopicsDialogModel::helpEngine(); + + buildContentsTab(); + ui->navigationTabs->addTab(engine->indexWidget(), tr("Index")); + + // Search tab: full-text search of built-in help, plus tutorial matches below. + { + QHelpSearchEngine* searchEngine = engine->searchEngine(); + auto* container = new QWidget(ui->navigationTabs); + auto* layout = new QVBoxLayout(container); + layout->setContentsMargins(4, 4, 4, 4); + layout->setSpacing(4); + layout->addWidget(searchEngine->queryWidget()); + layout->addWidget(searchEngine->resultWidget(), 1); + + _tutorialSearchLabel = new QLabel(tr("Also found in custom pages:"), container); + _tutorialSearchLabel->setVisible(false); + layout->addWidget(_tutorialSearchLabel); + + _tutorialSearchResults = new QListWidget(container); + _tutorialSearchResults->setVisible(false); + layout->addWidget(_tutorialSearchResults, 1); + + ui->navigationTabs->addTab(container, tr("Search")); + + connect(searchEngine->queryWidget(), &QHelpSearchQueryWidget::search, + this, [this, searchEngine]() { + const QString query = searchEngine->queryWidget()->searchInput(); + searchEngine->search(query); + searchTutorials(query); + }); + connect(searchEngine->resultWidget(), &QHelpSearchResultWidget::requestShowLink, + this, &HelpTopicsDialog::loadHelpPage); + connect(_tutorialSearchResults, &QListWidget::itemClicked, + this, [this](QListWidgetItem* item) { + const QString urlPath = item->data(Qt::UserRole).toString(); + if (!urlPath.isEmpty()) + loadHelpPage(QUrl(QStringLiteral("fredtutorial://") + urlPath)); + }); + + searchEngine->scheduleIndexDocumentation(); + } + + // Tutorials tab: only shown when mod tutorial pages exist in data/freddocs/. + if (!HelpTopicsDialogModel::tutorials().isEmpty()) + buildTutorialsTab(); + + ui->splitter->setStretchFactor(0, 1); + ui->splitter->setStretchFactor(1, 3); + ui->splitter->setSizes({380, 820}); + + connect(ui->backButton, &QToolButton::clicked, ui->helpBrowser, &QTextBrowser::backward); + connect(ui->forwardButton, &QToolButton::clicked, ui->helpBrowser, &QTextBrowser::forward); + connect(ui->helpBrowser, &QTextBrowser::backwardAvailable, ui->backButton, &QToolButton::setEnabled); + connect(ui->helpBrowser, &QTextBrowser::forwardAvailable, ui->forwardButton, &QToolButton::setEnabled); + + connect(engine->indexWidget(), &QHelpIndexWidget::linkActivated, + this, &HelpTopicsDialog::loadHelpPage); + connect(ui->helpBrowser, &QTextBrowser::anchorClicked, + this, &HelpTopicsDialog::loadHelpPage); + + auto* findShortcut = new QShortcut(QKeySequence::Find, this); + connect(findShortcut, &QShortcut::activated, this, [this] { + ui->findLineEdit->setFocus(); + ui->findLineEdit->selectAll(); + }); + auto* findNextShortcut = new QShortcut(QKeySequence::FindNext, this); + connect(findNextShortcut, &QShortcut::activated, this, [this] { findInPage(false); }); + auto* findPreviousShortcut = new QShortcut(QKeySequence::FindPrevious, this); + connect(findPreviousShortcut, &QShortcut::activated, this, [this] { findInPage(true); }); + + connect(ui->findLineEdit, &QLineEdit::textChanged, this, [this](const QString& text) { + const bool hasQuery = !text.trimmed().isEmpty(); + ui->findPreviousButton->setEnabled(hasQuery); + ui->findNextButton->setEnabled(hasQuery); + }); + connect(ui->findLineEdit, &QLineEdit::returnPressed, this, [this] { findInPage(false); }); + connect(ui->findPreviousButton, &QToolButton::clicked, this, [this] { findInPage(true); }); + connect(ui->findNextButton, &QToolButton::clicked, this, [this] { findInPage(false); }); + + // Load the help home page. + const auto registeredDocuments = engine->registeredDocumentations(); + if (!registeredDocuments.isEmpty()) { + const auto homePage = engine->findFile( + QUrl(QStringLiteral("qthelp://%1/doc/index.html").arg(registeredDocuments.front()))); + if (homePage.isValid()) + loadHelpPage(homePage); + } +} + +HelpTopicsDialog::~HelpTopicsDialog() = default; + +// --------------------------------------------------------------------------- +void HelpTopicsDialog::prewarm() { + HelpTopicsDialogModel::prewarm(); +} + +void HelpTopicsDialog::findInPage(bool backward) { + const QString query = ui->findLineEdit->text().trimmed(); + if (query.isEmpty()) + return; + + const QTextDocument::FindFlags flags = backward ? QTextDocument::FindBackward + : QTextDocument::FindFlags{}; + if (ui->helpBrowser->find(query, flags)) + return; + + // Wrap around when no further match is found from the current cursor. + QTextCursor cursor = ui->helpBrowser->textCursor(); + cursor.movePosition(backward ? QTextCursor::End : QTextCursor::Start); + ui->helpBrowser->setTextCursor(cursor); + if (!ui->helpBrowser->find(query, flags)) { + QMessageBox::information(this, + tr("Find in page"), + tr("No matches found for \"%1\".").arg(query)); + } +} + +void HelpTopicsDialog::buildContentsTab() { + QHelpEngine* engine = HelpTopicsDialogModel::helpEngine(); + if (engine == nullptr) + return; + + auto* container = new QWidget(ui->navigationTabs); + auto* layout = new QVBoxLayout(container); + layout->setContentsMargins(0, 0, 0, 0); + + _contentsTree = new QTreeView(container); + _contentsTree->setHeaderHidden(true); + _contentsModel = new QStandardItemModel(_contentsTree); + + auto* helpContentModel = qobject_cast(engine->contentWidget()->model()); + if (helpContentModel != nullptr) { + for (int row = 0; row < helpContentModel->rowCount(); ++row) { + const QModelIndex index = helpContentModel->index(row, 0); + addHelpContentItem(_contentsModel->invisibleRootItem(), + helpContentModel->contentItemAt(index)); + } + } + + const TutorialEntry* sexpReference = HelpTopicsDialogModel::sexpOperatorReference(); + if (sexpReference != nullptr) { + QStandardItem* fundamentals = findContentItemByTitle(_contentsModel->invisibleRootItem(), + QStringLiteral("Fundamentals")); + if (fundamentals != nullptr) { + auto* extraItem = new QStandardItem(sexpReference->title); + extraItem->setData(QUrl(QStringLiteral("fredtutorial://") + sexpReference->urlPath), + Qt::UserRole); + QStandardItem* parentItem = fundamentals->parent(); + if (parentItem == nullptr) + parentItem = _contentsModel->invisibleRootItem(); + parentItem->insertRow(fundamentals->row() + 1, extraItem); + } + } + + _contentsTree->setModel(_contentsModel); + layout->addWidget(_contentsTree); + + ui->navigationTabs->addTab(container, tr("Contents")); + + connect(_contentsTree, &QTreeView::clicked, this, [this](const QModelIndex& index) { + if (!index.isValid() || _contentsModel == nullptr) + return; + const auto* item = _contentsModel->itemFromIndex(index); + if (item == nullptr) + return; + const QUrl url = item->data(Qt::UserRole).toUrl(); + if (url.isValid()) + loadHelpPage(url); + }); +} + +void HelpTopicsDialog::addHelpContentItem(QStandardItem* parent, QHelpContentItem* contentItem) { + if (parent == nullptr || contentItem == nullptr) + return; + + auto* item = new QStandardItem(contentItem->title()); + item->setData(contentItem->url(), Qt::UserRole); + parent->appendRow(item); + + for (int i = 0; i < contentItem->childCount(); ++i) + addHelpContentItem(item, contentItem->child(i)); +} + +QStandardItem* HelpTopicsDialog::findContentItemByTitle(QStandardItem* root, const QString& title) const { + if (root == nullptr) + return nullptr; + + for (int i = 0; i < root->rowCount(); ++i) { + QStandardItem* child = root->child(i); + if (child == nullptr) + continue; + if (child->text() == title) + return child; + if (QStandardItem* nested = findContentItemByTitle(child, title)) + return nested; + } + return nullptr; +} + +void HelpTopicsDialog::buildTutorialsTab() { + _tutorialsWidget = new QListWidget(ui->navigationTabs); + for (const auto& t : HelpTopicsDialogModel::tutorials()) { + auto* item = new QListWidgetItem(t.title, _tutorialsWidget); + item->setData(Qt::UserRole, t.urlPath); + item->setToolTip(t.fullPath); + } + ui->navigationTabs->addTab(_tutorialsWidget, tr("Tutorials")); + + connect(_tutorialsWidget, &QListWidget::itemClicked, this, [this](QListWidgetItem* item) { + const QString urlPath = item->data(Qt::UserRole).toString(); + if (!urlPath.isEmpty()) + loadHelpPage(QUrl(QStringLiteral("fredtutorial://") + urlPath)); + }); +} + +void HelpTopicsDialog::searchTutorials(const QString& query) { + _tutorialSearchResults->clear(); + + const QString trimmed = query.trimmed(); + QList searchablePages = HelpTopicsDialogModel::tutorials(); + if (const TutorialEntry* sexpReference = HelpTopicsDialogModel::sexpOperatorReference()) + searchablePages.append(*sexpReference); + + if (trimmed.isEmpty() || searchablePages.isEmpty()) { + _tutorialSearchLabel->setVisible(false); + _tutorialSearchResults->setVisible(false); + return; + } + + static const QRegularExpression tagRe(QStringLiteral("<[^>]+>")); + const QStringList terms = trimmed.split(QLatin1Char(' '), QString::SkipEmptyParts); + + for (const auto& t : searchablePages) { + const auto& content = HelpTopicsDialogModel::tutorialContent(); + const auto it = content.constFind(t.urlPath); + if (it == content.constEnd()) + continue; + + // Strip tags for plain-text matching. + QString text = QString::fromUtf8(*it); + text.remove(tagRe); + text = text.simplified(); + + // All terms must be present. + bool allFound = true; + int firstPos = -1; + for (const auto& term : qAsConst(terms)) { + const int pos = text.indexOf(term, 0, Qt::CaseInsensitive); + if (pos < 0) { allFound = false; break; } + if (firstPos < 0 || pos < firstPos) firstPos = pos; + } + if (!allFound) + continue; + + // Build a short context snippet around the first match. + const int start = qMax(0, firstPos - 60); + const int len = qMin(160, text.length() - start); + QString snippet = text.mid(start, len).simplified(); + if (start > 0) snippet.prepend(QStringLiteral("\u2026 ")); + if (start + len < text.length()) snippet.append(QStringLiteral(" \u2026")); + + auto* item = new QListWidgetItem(t.title, _tutorialSearchResults); + item->setData(Qt::UserRole, t.urlPath); + item->setToolTip(snippet); + } + + const bool hasResults = _tutorialSearchResults->count() > 0; + _tutorialSearchLabel->setVisible(hasResults); + _tutorialSearchResults->setVisible(hasResults); +} + +void HelpTopicsDialog::loadHelpPage(const QUrl& url) { + if (!url.isValid()) + return; + // Open http/https links in the system browser rather than the help viewer. + const QString scheme = url.scheme(); + if (scheme == QStringLiteral("http") || scheme == QStringLiteral("https")) { + QDesktopServices::openUrl(url); + return; + } + ui->helpBrowser->setSource(url); +} + +void HelpTopicsDialog::navigateTo(const QString& keywordId) { + QHelpEngine* engine = HelpTopicsDialogModel::helpEngine(); + if (engine == nullptr) + return; + const auto links = engine->linksForIdentifier(keywordId); + if (!links.isEmpty()) + loadHelpPage(links.constBegin().value()); +} + +} // namespace fso::fred::dialogs diff --git a/qtfred/src/ui/dialogs/HelpTopicsDialog.h b/qtfred/src/ui/dialogs/HelpTopicsDialog.h new file mode 100644 index 00000000000..2de9b945e7f --- /dev/null +++ b/qtfred/src/ui/dialogs/HelpTopicsDialog.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include + +class QLabel; +class QListWidget; +class QListWidgetItem; +class QHelpContentItem; +class QStandardItem; +class QStandardItemModel; +class QTreeView; + +namespace fso::fred::dialogs { + +namespace Ui { +class HelpTopicsDialog; +} + +/** + * @brief Custom text browser that serves qthelp:// and fredtutorial:// URLs. + * + * Declared here (rather than as a private inner class) so that the .ui file can + * promote a QTextBrowser to this type via Qt Designer's custom-widget mechanism. + */ +class HelpBrowser : public QTextBrowser { + Q_OBJECT + +public: + explicit HelpBrowser(QWidget* parent = nullptr); + +protected: + void changeEvent(QEvent* e) override; + QVariant loadResource(int type, const QUrl& name) override; + +private: + bool isDarkMode() const; + static QByteArray darkModeStyleBlock(); +}; + +// --------------------------------------------------------------------------- + +class HelpTopicsDialog : public QDialog { + Q_OBJECT + +public: + explicit HelpTopicsDialog(QWidget* parent = nullptr); + ~HelpTopicsDialog() override; + + // Call once at startup to initialise the help engine, schedule search indexing, + // and discover mod tutorial pages... all before the user opens Help Topics. + static void prewarm(); + +public slots: // NOLINT(readability-redundant-access-specifiers) + void navigateTo(const QString& keywordId); + +private: + void loadHelpPage(const QUrl& url); + void findInPage(bool backward = false); + void buildContentsTab(); + void addHelpContentItem(QStandardItem* parent, QHelpContentItem* contentItem); + QStandardItem* findContentItemByTitle(QStandardItem* root, const QString& title) const; + void buildTutorialsTab(); + void searchTutorials(const QString& query); + + std::unique_ptr ui; + + // Widgets created dynamically (not in .ui) for the Search and Tutorials tabs. + QLabel* _tutorialSearchLabel = nullptr; + QListWidget* _tutorialSearchResults = nullptr; + QListWidget* _tutorialsWidget = nullptr; + QTreeView* _contentsTree = nullptr; + QStandardItemModel* _contentsModel = nullptr; +}; + +} // namespace fso::fred::dialogs diff --git a/qtfred/ui/HelpTopicsDialog.ui b/qtfred/ui/HelpTopicsDialog.ui new file mode 100644 index 00000000000..99039adada3 --- /dev/null +++ b/qtfred/ui/HelpTopicsDialog.ui @@ -0,0 +1,142 @@ + + + fso::fred::dialogs::HelpTopicsDialog + + + + 0 + 0 + 1200 + 800 + + + + QtFRED Help + + + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Find in page + + + true + + + + + + + false + + + Find previous + + + + + + + false + + + Find next + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Back + + + + + + + false + + + Forward + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + fso::fred::dialogs::HelpBrowser + QTextBrowser +
ui/dialogs/HelpTopicsDialog.h
+
+
+ + +