Compare commits

...
Author SHA1 Message Date
Goober5000 19ca467c41 Merge pull request #4513 from EatThePath/cleanup-eval-stack
Clean up the lua stack after EvalStringWithReturn's function creation
2022-07-27 23:29:52 -04:00
David Gibson 73736280f9 Clean up the lua stack after EvalStringWithReturn's function creation 2022-07-27 19:18:26 -05:00
Goober5000 d5546f95e8 Merge pull request #4510 from Goober5000/warn_about_too_many_sexps
prevent too many dynamic SEXPs from breaking the SEXP system
2022-07-24 17:10:10 -04:00
Goober5000 29edfeedea display category name 2022-07-24 15:08:49 -04:00
Goober5000 8cf20b0175 prevent too many dynamic SEXPs from breaking the SEXP system
SEXP categories will not support more than 256 SEXPs; this is why the CHANGE2 category had to be created when CHANGE got full.  Unfortunately, dynamic SEXPs will count toward this limit, so mysterious errors will occur for the ones whose category indexes roll over.  The problem is not easily fixable, but at least the engine can detect the situation, warn about it, and refrain from adding any problematic SEXPs.

Since too many *total* SEXPs would cause a similar problem, this adds a warning for that case too.
2022-07-24 15:06:13 -04:00
Goober5000 c85040efc4 prevent a crash on game exit (#4507)
When `mission_campaign_clear()` is called, all persistent SEXP nodes (those used by the campaign) are marked as non-persistent.  When `sexp_shutdown()` was moved in #4503, this caused `Sexp_nodes` to be nullptr when the campaign was cleared, which caused a crash.  This reorders the shutdown functions to prevent the crash.
2022-07-22 20:39:20 -05:00
MageKing17 a16be863f3 Actually grab the object's type when doing type checks. (#4505)
PR #4500 added some checks, but accidentally compared `aip->target_objnum` to an object type (although the assertion message correctly retrieved the object type, leading to the bizarre assertion that `OBJ_SHIP`, i.e. 1, was an invalid target object type). This commit makes them all access the `Objects[]` array and retrieve the `.type`, just as the assertion message does (and the pre-#4500 conditional did).

Related to #4504, in that it's the source of the failed assertions, although I can't be sure it was the cause of the crashes without testing.
2022-07-20 21:08:40 -04:00
BMagnu de80c254ae Ensure that SEXP shudown is before script shutdown (#4503)
* Ensure that SEXP shudown is before script shutdown

* Move before scpui destroy call
2022-07-19 18:56:42 -05:00
Allen A. Babb d703fcacc3 Move processing of thrust keys to be within the same block as the throttle keys (#4501)
* Remove do_thrust_keys() function
* Clean up documentation of Viewer_mode flags
2022-07-19 18:55:55 -05:00
Goober5000 ddef6ea377 Merge pull request #4498 from Baezon/clear-goals-fix
Bugfix for not present ships in `clear-goals`
2022-07-19 09:57:48 -04:00
BMagnu 2b2333f692 Ensure sufficient stack size for Lua values (#4482)
* Ensure sufficient stack size

* Fix Warning

* Fix formatting

* Rename variable and add docs
2022-07-19 10:14:41 +00:00
JohnAFernandez 4a819d7b20 Include more valid object types in this check (#4500)
* Include more valid object types in this check

The previous version of the fix only included ships because it was believed to be the object that a ship used to be guarding.  Now it's clear that this is an object that the ship is currently targeting *after* guarding something.

So remove the UNREACHABLE and manually check the valid object types with an assert.  Then only continue with the function if it is the right target type.

* typo
2022-07-19 01:47:51 -04:00
Asteroth a79dd70138 bug fix for not present ships in clear-goals 2022-07-14 16:19:37 -04:00
Goober5000 d5af6b5775 Merge pull request #4496 from Goober5000/fix_4495
check all possible extensions for audio files
2022-07-14 13:19:03 -04:00
Goober5000 e3b24ea9e2 check all possible extensions for audio files
When the code checks for the existence of an audio file, be sure to check all relevant extensions.

This fixes #4495.  Tested with both ST:R personas as well as the Vasudan persona.
2022-07-14 01:38:05 -04:00
Joshua Glatt 8645210c0a Fix type checking and FRED help for containers in special argument lists (#4486) 2022-07-13 19:52:21 -07:00
Goober5000 8c39bf54d4 Merge pull request #4491 from Goober5000/time_updates
some fixes for playing movies via script
2022-07-13 20:00:26 -04:00
Goober5000 bb43411bb1 elaborate script descriptions 2022-07-13 12:30:01 -04:00
Asteroth 622ae3ef2c Fix some bugs with maneuvers (#4483)
* split ai_control_info_check and player-not-use-ai wipes maneuvers

* remove redundant flag upkeep and clarify logic
2022-07-13 00:08:08 -04:00
Goober5000 ab7a1d8fd7 some fixes for playing movies via script
The movie player code was missing some important functionality, in particular:
1) There was only one timing method to get real-time elapsed time, which was not suitable for pausing or time compression
2) There was an improper cast for the FPS property, causing a script error
3) The `getSeconds` method lost precision during casting

This patches those deficiencies.
2022-07-12 23:35:27 -04:00
Asteroth a246ef21aa make sure to cap bank_vel (#4487) 2022-07-12 20:15:42 -04:00
JohnAFernandez e8d379a91c Fix an nprintf being in the wrong logic branch (#4485) 2022-07-11 21:29:06 -04:00
Goober5000 45862e06a9 Merge pull request #4461 from daftmugi/fix/accidental-skip-cutscene
Prevent accidental skip cutscene at loading screen
2022-07-11 11:20:00 -04:00
Goober5000 f96a27feb4 Merge pull request #4370 from JohnAFernandez/Ensure-obj_team-is_called_safely
Do our best to avoid invalid types in obj_team
2022-07-09 23:06:11 -04:00
Goober5000 f935a4ac38 Merge pull request #4475 from Goober5000/fix_erroneous_angle_modification
fix erroneous position/angle modification
2022-07-09 22:58:15 -04:00
Goober5000 601addd5c2 more feedback 2022-07-09 01:56:24 -04:00
Goober5000 7cfbdcd6cf address feedback 2022-07-08 19:29:51 -04:00
Goober5000 a009dc188c Merge pull request #4470 from jg18/issue_4405
Provide a limited partial fix for FRED keyboard shortcuts
2022-07-08 18:56:40 -04:00
Goober5000 bb6d7515df Merge pull request #4477 from notimaginative/fix_fireball_lod_assertion
fix lod assertion check (it can equal the max)
2022-07-08 18:56:26 -04:00
Goober5000 f33b8d987e Merge pull request #4478 from notimaginative/fix_psnet_memory_error
fix memset() on nullptr in psnet_get_addr()
2022-07-08 18:56:07 -04:00
Goober5000 2fd98c908b Merge pull request #4476 from Goober5000/fix_4472
use proper bounds check when bashing hull in red-alert
2022-07-08 18:53:52 -04:00
Taylor Richards bf1a9f192a fix memset() on nullptr in psnet_get_addr()
"addr" is optional and allowed to be null, so we've got to check
it before zeroing
2022-07-08 13:24:58 -04:00
Taylor Richards ec8cb1ba71 fix lod assertion check (it can equal the max) 2022-07-08 13:22:39 -04:00
John Fernandez e9e722244b Return here if not a ship 2022-07-08 12:24:19 -04:00
John Fernandez 2449dd6f70 Equals is ok here 2022-07-08 12:17:53 -04:00
John Fernandez 2748cc6f97 Return here if not a ship in release 2022-07-08 12:17:02 -04:00
John Fernandez 660f72dcc7 Clearer Assertions(TM) 2022-07-08 12:09:52 -04:00
John Fernandez f1506987eb Make assertions more readable. 2022-07-08 12:09:52 -04:00
John Fernandez e0d2d76dc2 Add an else unreachable. 2022-07-08 12:09:52 -04:00
John Fernandez 09b35edae1 More helpful assertions here 2022-07-08 12:09:52 -04:00
John Fernandez 390ddb3fc8 Do our best to avoid invalid types in obj_team 2022-07-08 12:09:52 -04:00
Goober5000 0ab523bcf4 Merge pull request #4462 from the-maddin/fix-gcc12-warnings
Fix gcc12 warnings
2022-07-07 21:41:04 -04:00
Goober5000 d72c5dbe75 Merge pull request #4471 from Goober5000/snd_aav_fix
reset the adjusted volume when the mission closes
2022-07-07 21:40:29 -04:00
Goober5000 324ccf37cb use proper bounds check when bashing hull in red-alert
This range check is to ensure that the ship's hull is in a valid range, so it should therefore check that the hull is less than the max strength, not less than the current strength.  This was inadvertently changed in 593be42e66 and a04e83ab01, but retail behavior is to set the exact hull from the previous mission.

Tested for both regular ships and delayed-arrival ships.  Fixes #4472.
2022-07-07 21:31:14 -04:00
Taylor Richards 20094df4cd address issues causing network connectivity failures on macOS (#4473) 2022-07-07 03:15:27 -04:00
Goober5000 8db280ea83 fix erroneous position/angle modification
Due to rounding and conversion approximations, it was possible for FRED to think the position and/or angle was modified when no such modification had occurred.  This could result in erroneous updates.  In the case of angles this could result in a group of ships being assigned the wrong orientation.

Follow-up to #2614.
2022-07-07 02:57:06 -04:00
Goober5000 a12e74fe9d reset the adjusted volume when the mission closes
Move `snd_aav_init` to `game_level_close` so that it is always called when the mission exits, not just in the `GS_STATE_GAME_PLAY` state.

Fixes #4468.
2022-07-06 12:08:56 -04:00
the-maddin 82e2b67ed8 remove magic number, static assert about lod level
assumption
2022-07-06 09:22:49 +02:00
Joshua Glatt 3311704253 Provide a limited partial fix for FRED keyboard shortcuts 2022-07-05 21:29:11 -07:00
the-maddin 7f7eed7a48 comment to clarify 2022-07-05 23:38:57 +02:00
the-maddin a95938a418 remove #define 2022-07-05 23:38:41 +02:00
the-maddin 557a6a989c skip LODs instead of ERRORing 2022-07-05 23:35:37 +02:00
Asteroth 0f168ecc5b warn on mismatched turret objects (#4458) 2022-07-04 21:55:55 -04:00
Joshua Glatt 1768f5bb1b Handle syntax checking and caching for nodes with dynamic values (#4460) 2022-07-03 23:57:54 -07:00
JohnAFernandez 9e6790f317 Prevent a crash by exiting here (#4449)
* Prevent a crash by exiting here

And make an assertion more explicit, just in case.

* Fix comment
2022-07-03 22:28:08 -04:00
JohnAFernandez 993a9e9f18 Merge pull request #4463 from Kiloku/bugfix/3321-clamp-values-from-pilot-file
Clamp values to their correct ranges when loading and saving pilot and campaign files
2022-07-03 10:18:30 -04:00
kiloku 516548d6be No clamping bools 2022-07-03 07:49:35 -03:00
kiloku d1800d8622 Use the labels displayed in the menus 2022-07-03 07:48:03 -03:00
Daft Mugi c9dd97d223 Prevent accidental skip cutscene at loading screen
`os_ignore_events()` deferred events instead of ignoring them. The
player could accidentally skip a cutscene at the loading screen and
not see any indication there was a cutscene.

This only removes deferred skip-cutscene key events, except ESC, right
before the cutscene plays. This makes it less likely for a player to
accidentally skip the cutscene.

This also renames `buffered_events` to `deferred_events` and
`os_ignore_events()` to `os_defer_events_on_load_screen()`, which more
accurately describes the behavior.

Fixes #4419.
2022-07-02 16:58:52 -05:00
Goober5000 c0ea9f5ffc Merge pull request #4455 from Goober5000/sexp_error_msg_tweak
refine SEXP error reporting
2022-07-02 13:22:04 -04:00
kiloku 319c8cc2a1 Clamp values before saving 2022-07-02 09:47:46 -03:00
kiloku 07b8e8d6cb Clamp settings values when loading 2022-07-01 22:56:19 -03:00
the-maddin 80e2908aa3 GCC12 warning format-overflow
Fireball filename field could potentially overflow
when adding LOD filename extensions. Added explicit
lengths and checks.
2022-07-02 01:03:32 +02:00
Daft Mugi 25a6bf2b87 Prevent accidental skip cutscene at loading screen
os_ignore_events() was buffering events instead of ignoring them. This
caused any skip-cutscene key to be buffered during the loading screen,
which would later be handled during the cutscene. From the player's
perspective, there was no cutscene.

This changes os_ignore_events() to ignore events.

Fixes #4419.
2022-07-01 14:40:10 -05:00
Joshua Glatt 1930943d2d Auto-accept completed campaign mission before exiting game from debriefing screen via options menu (#4450) 2022-06-30 19:26:25 -07:00
the-maddin ed16a81e37 GCC12 warning array compare
not comparing ship_info name addresses, but
ship_info argument address with address of
iterator element.
2022-07-01 00:59:57 +02:00
Asteroth 0121e439aa tweak to getTurretHeading() docs (#4456) 2022-06-30 15:07:14 -04:00
Goober5000 6fb72499f9 make all the error messages consistent 2022-06-30 03:15:53 -04:00
Goober5000 eb69133a57 refine SEXP error reporting
Sync the "mission save" and "error reporting" versions of the SEXP variable string.  Also use `stuff_sexp_text_string` to print the "bad node" token rather than `Sexp_nodes[bad_node].text`, so that a human-readable token is displayed instead of a magic number like 26.

Related to #4226, as the generated error message is formatted differently enough to be confusing.
2022-06-30 02:50:08 -04:00
Goober5000 2fcc3ecbf8 Merge pull request #4434 from Goober5000/sync_orientation
sync Orientation virtvars
2022-06-29 19:29:13 -04:00
JohnAFernandez 30b2b6caa7 Merge pull request #4407 from JohnAFernandez/Fix-Hud-Brackets
A comprehensive fix for the `player.target_is_dying` variable.
2022-06-29 12:31:07 -04:00
John Fernandez 4250aab601 Hud Bracket fixes
1) A comprehensive fix for the is_target_dying variable

2) Also do distance correctly for non-player target brackets by adding a check that we're dealing with the target before using the current target distance.  Then also calc distance if it is not the player target.

3) Update comments and checks to be consistent

Many of these did not reflect how the variable was actually used, so update the comments.
2022-06-29 11:40:12 -04:00
Goober5000 a9e6c328cf Merge pull request #4448 from Goober5000/async_mprintfs
add some logging to waitAsync
2022-06-28 13:55:33 -04:00
m!m 07b6c17db0 Merge pull request #4445 from the-maddin/ignore-gcc11-warning
Ignore Wshadow warnings in stale librocket headers
2022-06-28 18:11:58 +02:00
Goober5000 2ce953aee8 address feedback 2022-06-28 12:04:16 -04:00
Goober5000 05f71a30fb add some logging to waitAsync
Log when the context is created, completes, and is aborted.  Adds insight for the situation described in #4432.
2022-06-28 12:02:13 -04:00
Goober5000 5dfef48bf6 Merge pull request #4452 from Goober5000/default_enabled_nprintf_categories
set up debug_filter.cfg to have default filters that can be turned off
2022-06-28 12:01:33 -04:00
wookieejedi f280f11824 Fix AI Goal Display Strings (#4451)
* Fix AI Goal Display Strings

Okay so previously, if a target goal was not valid the code was
`strcpy(outbuf, XSTR("no orders", 495)); `

but then it was changed to
`outbuf += XSTR("no orders", 495);`

So it would instead append the "no orders" instead of properly replace the whole string. Looks just like a copy and paster oversight, since all the other text appends the name of the target with the order.

This PR correctly replaces, rather than appends that text. Fixes #4345

* appease clang

* use more simple =
2022-06-28 09:33:29 -04:00
Goober5000 e7b73da90e Merge pull request #4447 from Goober5000/fix_4412_harder
even more fixes for the skip-training-mission crash
2022-06-27 23:50:02 -04:00
Goober5000 8698993d44 set up debug_filter.cfg to have default filters that can be turned off
Small refactoring of the debug filter, needed as a prerequisite for #4448.
2022-06-27 23:36:49 -04:00
wookieejedi 7b04d401fe Fix Seg Fault on Standalones with Safer Check for Secondaries (#4446)
Tests with standalone multiplayer builds revealed that the server would seg fault if a player tried to switch secondaries if the ship did not have secondaries. Tests with standalones showed this fixed the bug. Thanks to chief for the bug IDing and the fix code.
2022-06-26 22:20:48 -04:00
Goober5000 a2b05f085b even more fixes for the skip-training-mission crash
As noted in #4412, it's possible for `Campaign.current_mission` to be -1 even in campaign mode.  This explictly checks for that.
2022-06-26 19:08:50 -04:00
the-maddin 6e612cdc97 msvc compat 2022-06-26 21:57:09 +02:00
the-maddin 9a55d90f5d Ignore Wshadow warnings in stale librocket header
GCC 11 raises a warning due to a parameter "word"
shadowing a typedef "word".
2022-06-26 21:19:35 +02:00
Tyler Blount cc2b9fcf94 Use correct needs elements for post build action (#4439) 2022-06-25 19:00:26 -05:00
Goober5000 ed8af9d197 Merge pull request #4440 from Goober5000/fix_message_source_error
better handling of invalid message sources
2022-06-25 16:44:23 -04:00
Goober5000 43f8b123a8 better handling of invalid message sources
Another bug discovered by Durandal.  The message sender was a variable containing an invalid value, and the game crashed.  This handles it more gracefully.

Tested and verified.
2022-06-25 15:56:52 -04:00
Goober5000 a930301ec1 Merge pull request #4437 from Goober5000/fix_remove_form_on_wing
fix crash when removing form-on-wing
2022-06-25 15:35:24 -04:00
Tyler Blount 112f2bb5ba Merge pull request #4438 from z64555/fix/post-build-release-autotrigger01
Fix/post build release autotrigger01
2022-06-25 09:55:11 -07:00
z64555 5b8dce1dda Try encapsulating the OR in the same brackets. 2022-06-25 10:23:57 -05:00
z64555 b6c684644a use inputs context instead of github.events.inputs context 2022-06-25 10:06:32 -05:00
Goober5000 d754f7fe0d fix crash when removing form-on-wing
This goal was missed in `ai_remove_goal_sexp_sub`, so add handling for it.  Also make the error message clearer in case another goal is missed in the future.
2022-06-25 00:41:34 -04:00
wookieejedi 2beaa886ca Fixes Team Colors not working with show-ship (#4436)
Updates the `show-ship` function to account for team colors. Also, cleans up the function a bit. Tested and works as expected. Fixes #4435
2022-06-24 22:06:13 -04:00
Goober5000 53bc7861bf sync Orientation virtvars
The two `VIRTVAR`s for Orientation in subsystems and submodel instances do the same thing, but did not have the same code - in particular, the subsystem version did not update the subsystem angle and turret angle.  This syncs them up.
2022-06-23 10:08:34 -04:00
Taylor Richards 9de4a49c42 stop non-printable keys adding text to multi msg buffer (#4433)
Arrow, function, Ctrl, Alt ... and any other non-ascii keys
would previously add a blank space to the multi msg buffer.
This prevents that from happening, making sure that it's an
ascii character before appending it to the buffer.

(Retail bug??)
2022-06-23 05:55:52 -04:00
Goober5000 6e5626722a Merge pull request #4431 from Goober5000/skybox_none
fix clearing a skybox model when it isn't the mission default
2022-06-20 20:33:16 -04:00
Goober5000 1fa5068555 Merge pull request #4428 from Goober5000/fix_4412
more fixes for the skip-training-mission crash
2022-06-20 20:33:06 -04:00
Goober5000 d7f0051394 fix clearing a skybox model when it isn't the mission default
The previous way to clear a skybox was to set it to "default", and if the mission had no skybox then it would be cleared.  The skybox code can correctly handle the lack of a skybox, but if you pass an empty string to the skybox preloader it fails with a file not found error.  This fixes the preloader, and also adds "none" as an explicit no-skybox parameter.
2022-06-20 02:33:25 -04:00
Goober5000 6b9dacb598 more fixes for the skip-training-mission crash
Certain campaign-related functions would run even when the game was not in campaign mode (e.g. when playing in the tech room).  Normally these would be benign, but with a new pilot or with a skipped mission, the current campaign mission would be -1 and a crash would occur.

Should fully fix #4412.
2022-06-19 23:09:53 -04:00
Allen A. Babb eef9a340b1 Flush the mouse state after toggling between Use_mouse_to_fly in scripting/api/libs/controls.cpp::MouseControlStatus (#4426)
See the discussion in issue #4173 for details.
2022-06-19 20:43:42 -05:00
Tyler Blount 4a9c6567cc Merge pull request #4425 from z64555/fix/post-build-release-autotrigger
Autotrigger on either workflow_call or push event.
2022-06-19 09:40:24 -07:00
z64555 ead7f10006 Autotrigger on either workflow_call or push event. 2022-06-19 07:21:50 -05:00
Taylor Richards c7abceaf30 fix control chars test that also excluded space key (#4424) 2022-06-19 06:32:53 -04:00
Tyler Blount a057917958 Merge pull request #4423 from notimaginative/fix_hud_preset_parsing
fix parsing issues with hud color presets
2022-06-18 16:48:38 -07:00
Taylor Richards 010441fdbf fix parsing issues with hud color presets
The first issue is that if a gauge isn't found it will fail to parse
any remaining gauges in the file. The second issue is that when saving
the preset the game uses translated strings for the gauge name but
when loading the preset it uses untranslated strings.

This should address both issues while keeping the original purpose
of the changes as well as not breaking existing presets or requiring
any mod changes.

Ref: http://scp.indiegames.us/mantis/view.php?id=3099
2022-06-18 13:38:41 -04:00
Goober5000 b32698012a Merge pull request #4420 from Goober5000/main_hall_popup_priority
only display one popup when the player gets to the main hall
2022-06-18 13:05:41 -04:00
Goober5000 581fec1079 Merge pull request #4413 from Goober5000/ending_campaign_by_skipping_mission
end the campaign properly when a mission is skipped
2022-06-18 13:05:35 -04:00
BMagnu a44adde0e5 Followup improvement for the LuaAI AI Control Helper (#4422)
* Followup improvement for the LuaAI AI Control Helper

* Update docs
2022-06-18 18:31:50 +09:00
Taylor Richards e88542580e Merge pull request #4410 from notimaginative/fix_hud_config_presets
Fix issues with loading of hud config presets
2022-06-18 05:09:31 -04:00
Taylor Richards b5043417fc override default path creation when path must be from root
The default file path is always the primary mod user directory, however
some files are only ever created and read from the root user directory.
This allows for an override in such cases so that the location_flags
variable will match the intended root path.

Fixes #4384
2022-06-17 21:11:49 -04:00
Asteroth 049fa72df3 change bank to target vel from target position (#4417) 2022-06-18 06:06:36 +09:00
Goober5000 b8231a4ec1 only display one popup when the player gets to the main hall
There are three popups of decreasing priority that can appear in the main hall screen: campaign not found, pilot upgraded, and player tip.  Only one of these should actually be displayed -- the first popup will take the player to a different screen, rendering subsequent popups useless; and the second popup is more important than the third popup.  This PR prioritizes the popups accordingly.
2022-06-17 13:25:29 -04:00
Goober5000 1b563360ed Merge pull request #4401 from Goober5000/add_isActive_checks
add isActive checks for new-style script hooks
2022-06-16 19:42:36 -04:00
Fabian Woltermann 3ee1321d9d Merge pull request #4416 from The-E/fix/4415_several_lab_issues
Two minor lab fixes
2022-06-16 23:12:25 +02:00
Fabian Woltermann fb9304bae0 Fix #4415: Make sure that changing team colors only happens when there are team colors to change and only dump the envmap to disk if there actually is an envmap to dump 2022-06-16 22:14:26 +02:00
Goober5000 87e6a1350d Merge pull request #4414 from Goober5000/split_subsys_warnings
split subsystem warning display checks
2022-06-16 01:09:11 -04:00
Goober5000 bf05cadd14 split subsystem warning display checks
Since "No subsystems found" and "Not all subsystems have a record in ships.tbl" are different warnings, they should have different flags.  Follow-up to #4408.
2022-06-16 00:21:39 -04:00
Goober5000 29fe214d16 end the campaign properly when a mission is skipped
The "skip training" button and the "exit loop" button should both check whether the campaign is actually over before attempting to load the next mission.  The fix is simple - just use the same logic as in `mission_campaign_skip_to_next`.

Fixes #4412.
2022-06-16 00:02:48 -04:00
Goober5000 e27bf0c925 Merge pull request #4403 from Goober5000/fred_error_tweaks
some tweaks to the FRED error checking
2022-06-15 23:21:27 -04:00
Taylor Richards 83c4858f18 allow default hud config files to come from the file cache 2022-06-15 13:58:19 -04:00
JohnAFernandez 6104e6fcd3 Merge pull request #4404 from JohnAFernandez/Let's-support-the-hack-that-was-such-a-good-idea
Fix the standalone ship being added to ship list
2022-06-15 11:25:39 -04:00
Allen A. BabbandMageKing17 113b57df29 Changelog.py improvements and post-release-build.yaml debugging (#4380)
* Echo the event name to debug Auto trigger
* Add argparse library to changelog.py
* Allow user to authenticate with github creds (such as PAT's)

* Update ci/post/changelog.py

Use clearer notation for while loop

Co-authored-by: MageKing17 <[email protected]>

* Update ci/post/changelog.py

Co-authored-by: MageKing17 <[email protected]>

Co-authored-by: MageKing17 <[email protected]>
2022-06-14 22:26:56 -07:00
Joshua Glatt a25e12a041 Ignore weapons-locked slot status in selection screens when irrelevant (#4399) 2022-06-14 21:04:39 -07:00
Joshua Glatt fa29b91e68 Disallow Replace Container Data with special argument list (#4392) 2022-06-14 21:03:11 -07:00
BMagnu 6b91a6210c Properly set rotation data from LuaAI (#4406)
* Properly set rotation data from LuaAI

* Update Variable Name
2022-06-14 23:46:03 +00:00
John Fernandez 6098675cc0 A docked standalone ship is not possible. 2022-06-14 09:49:18 -04:00
John Fernandez 01331436c9 Fix the standalone ship being added to ship list
While it may seem counterintuitive, we have to keep the standalone bogus ship from being added to the ship list so that we don't have to exclude it from all the places it could cause crashes or mysterious AI behaviors.  Both were being observed, and this should fix them.
2022-06-13 21:39:03 -04:00
Goober5000 dbdc2457e0 some tweaks to the FRED error checking
1) Restore original behavior where function would exit after one error check (for consistency)
2) Exclude player ships from the check for ships in a wing sharing the same orders
2022-06-13 21:14:15 -04:00
Goober5000 7013981de5 add isActive checks for new-style script hooks
What it says on the tin.  Follow-up to #3538.  Fixes #4398.
2022-06-13 02:13:14 -04:00
Goober5000 8b9ac5f8a9 Merge pull request #4391 from Goober5000/fix_tech_db_default_flags
fix use of default tech database flags
2022-06-12 19:36:20 -04:00
JohnAFernandez 7cf2832113 Merge pull request #4389 from JohnAFernandez/Remove-pointless-Asserts
Remove a pointless assert
2022-06-11 23:08:46 -04:00
Goober5000 6f5de692b9 Merge pull request #4376 from Goober5000/suppress_bitop_warnings
disable compilation warnings in BitOp
2022-06-11 20:16:11 -04:00
Goober5000 67b3c6ce46 fix use of default tech database flags
The "default" tech database flags indicate whether entries are in the tech room by default, that is when the table is originally parsed and the campaign is started.  Flags may be changed later, so that when the tech database is "reset to default" the flags can be returned to the known state as specified in the tables.

A bug was introduced back in commit c924e3997a (!) based on a misinterpretation of what "default" meant.  This fixes the bug and clarifies the flags.

Fixes #4390.
2022-06-11 18:03:21 -04:00
John Fernandez b3f0016d0e Remove a pointless assert 2022-06-11 15:02:09 -04:00
Joshua Glatt bd864baead Clean up list modifier code (#4363) 2022-06-10 17:31:25 -07:00
wookieejedi e6956b1b4c Fix FRED Crash with Team Colors (#4379)
`p_objp` uses cannot be used if FRED is running, and this PR adds that check to the updated team color fixes from #4207.

Fixes #4374
2022-06-10 08:32:29 -04:00
Allen A. Babb e0fd189833 re-enable mod-only controls that have a tab. (#4377) 2022-06-09 21:26:21 -05:00
Goober5000 28f06adc12 disable compilation warnings in BitOp
Since bit.c is a third-party file, we can't modify it, so let's instead disable the warnings for it.

Follow-up to #4274.  Fixes #4366.
2022-06-09 20:17:42 -04:00
BMagnu 3f830fbe78 Force legacy order for HUD commands (#4375) 2022-06-10 02:25:37 +09:00
Tyler Blount 0371b2d889 Merge pull request #4373 from scp-fs2open/fix/ci-re-str-cast
Don't try casting a string to an int
2022-06-08 19:11:55 -07:00
Tyler Blount 1bae96df07 Missed a parenthesis 2022-06-08 18:18:56 -07:00
Tyler Blount f3880eb03f Don't try casting a string to an int 2022-06-08 17:53:43 -07:00
Tyler Blount 263bf57c79 Merge pull request #4371 from scp-fs2open/fix/ci-regex-string
Check string, not number in release version regex
2022-06-08 10:15:32 -07:00
Tyler Blount d665c1ccf1 Actually look for a string in regex
`REVISION_STR_VERSION_PATTERN` is not currently matching against a string, it is matching against a number
2022-06-08 09:09:14 -07:00
Tyler Blount 5bde8bfebf Check either possibility for cmake set function (#4369)
There are two possible functions that can appear in `version_override.cmake`, so we need to make sure both are handled
2022-06-08 05:20:31 -05:00
Allen A. Babb a002219373 Use correct usage of subprocess.check_output() (#4368) 2022-06-08 01:17:23 +00:00
Allen A. Babb a923f64691 Fix Post Release Build action
Attempt 2.  Use ${{ }} style to reference env (#4365)
2022-06-07 14:54:31 +00:00
Allen A. Babb 7e06ccac7d Hopefully fix the post-build-release yaml (#4364)
* Directly use inputs for actions/checkout
2022-06-07 09:07:19 -05:00
Goober5000 2ff2732cc4 Merge pull request #4355 from Goober5000/lua_addSomeHookDoc
Convert some Lua hooks to the new style to add documentation
2022-06-06 23:24:10 -04:00
JohnAFernandez b328495b31 Correct some Bad Documentation (#4360)
authored-by: johnafernandez <jafernandez,[email protected]>
2022-06-06 19:31:05 -05:00
Goober5000 9acbd9bc94 enhance ActiveActions to accommodate both old-style and new-style script hooks 2022-06-06 17:26:07 -04:00
Goober5000 3a1e1b23d5 Merge pull request #4359 from Baezon/fix-music-start-delay
Small fix for music initialization
2022-06-06 17:24:22 -04:00
Taylor Richards e1ddbd5875 save PXO stats to local pilot file (#4354)
Retail saved tracker stats to the local pilot file after read, however
the newer pilot file code doesn't work the same way. This adds the
ability to properly update the pilot file with multiplayer stats from
the tracker during login.

NOTE: This will always overwrite multi stats in the pilot file with
the stats from the tracker!
2022-06-06 15:04:16 -04:00
Goober5000 1dfe0ab644 Merge pull request #4358 from Goober5000/xstr_entries_4259
add additional XSTR entries
2022-06-05 21:43:36 -04:00
Asteroth 22a71ea3e7 fix event_music_set_start_delay 2022-06-05 21:43:01 -04:00
Goober5000 8821cdf2cd add additional XSTR entries
Add entries requested by @Achille44.  Fixes #4259.
2022-06-05 21:09:01 -04:00
Goober5000 3ad92cce4e tweak strdup handling for argument vector (#4307)
* tweak strdup handling for argument vector
Follow-up to #4293
2022-06-05 18:58:11 -05:00
Goober5000 90576274fb Merge pull request #4357 from Goober5000/fs1_message_conversion_additional_check
additional checks for FS1 message conversion
2022-06-05 19:25:44 -04:00
Goober5000 3b49699b19 additional checks for FS1 message conversion
Before setting the `MQF_CONVERT_TO_COMMAND` flag, check to make sure the conversion will succeed.

This should ensure proper behavior for any case where command-conversion is needed.  I've tested it with both a message that should not be converted and a message that should, and both behave as expected.

Follow-up to #4150 and #4078.  Fixes #4356.
2022-06-05 18:02:39 -04:00
Goober5000 3a4794305f Convert some Lua hooks to the new style to add documentation
This takes a few of the existing hooks and converts them to the new style of hook definition which can include more extensive documentation and enumeration of supported hook variables.

This is an updated version of #3151 to work with the latest codebase.

NOTE: Before this can be integrated into the codebase, it needs an implementation for `bool script_state::IsActiveAction(int hookId)` which apparently only has support for old-style script hooks.
2022-06-05 16:38:03 -04:00
Fabian Woltermann 7facbcc262 Merge pull request #3769 from EatThePath/debug-viz-sphere
Implemented debug sphere queuing and rendering.
2022-06-05 18:24:52 +02:00
d38cc1f3db Controls6: Keyboard Localization and Scripted Contols (#4133)
Locale Sensitive Controls and Textfield Input
+ Add Keyboard Layout sensitive InputBoxes
+ Remove obsolete helper function

* Fig [] usage and remove old keybinding names
+ Fix Compile Warnings
+ Fix Compile Warnings 2
+ Fix Clang Warnings
+ Fix faulty style + remove lambda
+ Change reverse-lookup map to iterating function
+ Added controlconfigdefault.tbl generator
+ Fixed gcc warning
+ Fixed msvc warning
+ make debug console keyboard layout independent
+ Expand DCF Functionality for saving control presets
+ Address Issues

* Controls/update tbl (#5)

Updates controlconfigdefaults.tbl to write Primary and Secondary bindings.

* Added Scripting Hooks for controlsconfigdefault.tbl (#6)

* Handle Asserted Switch cases

* Controls is a library and should be in the libs folder

* Add Lock & EnableScripting Functionality and expose it to scripting API

* Added scripting isLocked

* Move Key Hooks to register-able callback

* Add option to remove hook

* Repurpose CCI.used for Axes

* Morph bitfield into a singleton class

* Add encoding conversion helpers
+ Add keyname conversion if needed
+ Merge refactored encoding functions
+ Change keycode encoding call
+ remove bad type modifier
+ Move Conversion functions to util/unicode
+ Change Encoding Enum to Enum Class
+ Adapt KeyName call for encoding enum class
+ Fix Warning due to enum class
+ Change validation to own function

* Make mActionToVal Assertion more helpful
* Fix typo
* Fix style
* Use constant, not magic number
* Document Ignored_keys[]
* Doxy class controls_lua_override_cache a bit better
* Put NameToVal safeties back in
* Reorder the +Disable and $Disable: options, and be exclusive
* Reorder the +Locked and $Loacked options, and be exclusive
* Revert changes in ValToJoy
* Revert errant duplicates
* Refactor printJoyJSON() to use getJsonArray for consistency
* Remove unused FS2toSDL map
* Remove ADE_FUNC(AxisActionInverted)

* Address gcc-5 issues
* Remove unused param for textify_scancode
* Declare textify_scancode_universal() in controlsconfig.h for use
* Clean up textify_scancode() and *_universal() a smidge for clarity

* Address most clang-9 issues

* Modernize NULL to nullptr

* Expand logic and document in controlsconfig::check_control() for clarity.
* Fix typo

* Remove unecassary static_cast
*  Use Assertion instead of Assert within control_config_common_read_section()
* mprintf()'s need new lines!

Co-authored-by: Birk Magnussen <[email protected]>
Co-authored-by: Birk Magnussen <[email protected]>
2022-06-05 10:19:46 -05:00
Joshua Glatt b893075efe Detect concurrent container modification (#4330)
* add node subtype for container names

* clean up and port changes to qtFRED

* fix parsing when container is the last argument

* fix serializing container name nodes

* fix parsing again

* disallow spaces in container names

* check for spaces and & chars while parsing container names

* early WIP for trying to get list containers of strings working as argument options

* indicate which SEXPs will be supported for now

* clean up

* add FRED/qtFRED support

* remove [in]validate-argument from supported SEXPs

* support map containers with string keys

* update FRED and qtFRED

* clean up

* update FRED help text

* revert some unneeded changes

* fix style

* remove added assertion

* backport useful changes from PR #4263 and then some

* clean up backport

* move condition_node evaluation outside of argument loop

* fix does_blank_of_op_support_container_args()

* fix assertion

* add OPF_DATA_OR_STR_CONTAINER and use restore old behavior of OPF_ANYTHING

* revert some unnecessary changes

* fix CI

* detect attempts to modify container while it is being used as special argument (WIP)

* evaluate conditional for each loop

* update placeholder text for new SEXP arg type

* finish/clean up
2022-06-05 08:47:51 -05:00
Goober5000 e3ad6664e0 Cached subsystem indexing (#4316)
* add subsystem indexer and ensure that ship_get_indexed_subsys and ship_get_first_subsys are independent

* also add reverse lookup from subsys to index

* update indexer to accommodate subsystem pointers being changed

* use clearer function names, and fix the type of subsys_list_indexer

* add assertions

* address latest feedbcak
2022-06-05 08:44:54 -05:00
JohnAFernandez 9abfb1e3f3 Merge pull request #4349 from JohnAFernandez/Multi-Bump
Multi Bump for 22.2 release
2022-06-05 00:55:15 -04:00
JohnAFernandez 2004d00588 Merge pull request #4144 from JohnAFernandez/Interpolation-Overhaul2
Interpolation Overhaul 2
2022-06-05 00:55:09 -04:00
JohnAFernandez abb8bbaf68 Merge pull request #4264 from notimaginative/multi_sexp_fixes
Multi sexp fixes
2022-06-05 00:55:03 -04:00
JohnAFernandez 6baadfef6f Merge pull request #4306 from BMagnu/de_bitfieldify_player_orders
De-Bitfield-y Player Orders
2022-06-05 00:54:55 -04:00
Taylor Richards b6378d6b0b revert multi bump (will be added in a separate PR) 2022-06-04 23:19:11 -04:00
John Fernandez a6cb299f28 Feedback 2022-06-04 23:06:56 -04:00
JohnAFernandez 88c788a7b4 Interpolation Overhaul
Add files to partition interpolation code, base interpolation timing on Missiontime on remote instance vs. Mission time on the local instance.
2022-06-04 12:55:13 -04:00
JohnAFernandez 06c3087038 Merge pull request #4314 from JohnAFernandez/Fix-Rollback-Primary-Collisions
Fix rollback primary collisions
2022-06-04 12:43:12 -04:00
Goober5000 5e8815146d add some extra safeguards to gr.drawString (#4327)
* add some extra safeguards to gr.drawString

These will add insight if the errors reported by RedMadeJoe pop up again.  The root cause is in the script, but this will prevent FSO from choking.

* Add static bool for warning
2022-06-04 09:12:16 -05:00
Kiloku 01a4d01fd3 Draw 3d lines in space with Lua (#4331)
* Add support for drawing batched 3D lines of arbitrary color and thickness.

* Add draw3dLine lua function.

* Move line texture out of graphics.h into graphics.cpp, also rename it for proper code style.

* Move line texture generation to batching.cpp, create dedicated batching_add_line function and add support for a line with variable thickness at the start and end.

* Use references in the verts loop

* Add bound checks for line widths

* Warn if the Lua script uses invalid widths
2022-06-04 09:10:15 -05:00
wookieejedi 619e0e125e Add option to expand warning on unbound keys (#4342)
In Training missions, the game will check if keys used in directives are bound or unbound, and if unbound will display a message to the player to bind the key.

This is limited to only Training missions though, so this PR adds a `game_settings` option to allow modders to use that check in singleplayer mission types too, which is very useful for mods that rely on key presses in non-training missions. Also fixes #4340.
2022-06-04 08:17:24 -04:00
John Fernandez f18c4d39cc Bump for 22.2 release 2022-06-04 02:17:51 -04:00
John Fernandez ba5406f13c Add safety checks for bad ref objects
This will allow FSO to fall back to the old system when the reference object is somehow not a ship.
2022-06-04 01:58:01 -04:00
John Fernandez 779594b66a Feedback 2022-06-04 01:48:51 -04:00
John Fernandez 2163cfc5d3 Remove superfluous buggy check plus two more fixes
1. Also include number of frames variable

2. remove stale comment
2022-06-04 01:48:51 -04:00
John Fernandez b4c1c83a84 Fix further problems with time calc +
One other fix
2022-06-04 01:48:51 -04:00
John Fernandez d0d12b572a Check for collisions, and cull collided bolts
Add a function that removes colliders after collision detection so that we don't have dup collisions after rollback resim ends
2022-06-04 01:48:51 -04:00
John Fernandez 7b61f20eda Add old_position to rollback to fix rb collision 2022-06-04 01:48:51 -04:00
Tyler Blount e38c30bca6 Merge pull request #4346 from Kiloku/fix_line_endings
Fix line endings in the core codebase
2022-06-03 19:11:41 -07:00
Tyler Blount 7d87aad3f3 Merge pull request #4347 from Kiloku/fix_line_endings_other_files
Fix line endings in a few more files
2022-06-03 19:11:29 -07:00
Goober5000 6a37be55ba Merge pull request #4348 from EatThePath/load-fennel
Add Fennel script support to cfile.
2022-06-03 20:41:15 -04:00
Joshua Glatt 1f625f3a7f Support using containers with random-multiple-of SEXP (#4326) 2022-06-03 17:09:24 -07:00
David Gibson de98902de4 add .fnl to the scripts file extensions 2022-06-03 15:58:23 -05:00
EatThePath 13db223f03 Merge branch 'master' into debug-viz-sphere 2022-06-03 14:51:16 -05:00
Tyler Blount 92c1ca2bb7 Merge pull request #4317 from notimaginative/stub_graphics_fixes
fix a bunch of graphics functions to respect GR_STUB
2022-06-03 11:18:43 -07:00
Taylor Richards 7fb8e64434 log non-psnet packets for debugging (#4339)
Previously, debug builds would assert if a packet was not a psnet packet
type. Port scans and general traffic checks could trigger this for any
public server. So we should just log these events instead, taking into
account that some of this traffic could be malicious in nature.
2022-06-03 14:16:49 -04:00
EatThePath 91b516c1c4 Merge pull request #4208 from EatThePath/weapon_lights
Weapon lights
2022-06-03 13:01:15 -05:00
kiloku 764e730e80 Fix line endings in a few more files 2022-06-03 14:28:58 -03:00
David Gibson d10309d3d4 fixed up copy-paste mistakes in new light_add functions 2022-06-03 12:13:58 -05:00
kiloku b7e99089d7 Fix line endings in the core codebase 2022-06-03 13:31:09 -03:00
Goober5000 154e5f6b4b Merge pull request #4344 from JohnAFernandez/timestamps_again
Use correct function for regular stamp
2022-06-02 15:22:31 -04:00
John Fernandez 6e9745c671 Use correct function for regular stamp 2022-06-02 14:12:49 -04:00
JohnAFernandez 709de972e6 Merge pull request #4343 from JohnAFernandez/Another-Timestamp-Function
Add overload for timestamp_elapsed_safe
2022-06-02 12:27:59 -04:00
John Fernandez 43b89d29b6 Add overload for timestamp_elapsed_safe
Why?  Cause multi
2022-06-02 11:34:52 -04:00
Joshua Glatt 6bfe6071d0 Add apply-container-filter SEXP (#4333) 2022-06-02 07:12:38 -07:00
JohnAFernandez 0bbd099853 Add timestamp get delta (#4334)
* Add timestamp get delta

For returning the delta between two timestamps, as a counterpart to timestamp_delta.
2022-06-02 09:35:52 -04:00
Goober5000 12f9ccc46f Merge pull request #4341 from Goober5000/campaign_error_check_fix
better error checking of campaign loop branches in FRED
2022-06-01 23:39:29 -04:00
Goober5000 bc1f36a423 better error checking of campaign loop branches in FRED
In the FRED campaign editor, error checking for campaign branches did not correctly handle loop branches.  This avoids performing inapplicable error checking for loop branches, adds a new applicable check, and excludes loop branches from the count of regular branches.  Fixes error checking for the FS2 main campaign.
2022-06-01 19:57:00 -04:00
Goober5000 5672f0ed53 Merge pull request #4332 from Goober5000/no_departure_warp_cleanup
clean up ship arrival and departure effects
2022-06-01 18:54:36 -04:00
Fabian Woltermann 9514f9babb Merge pull request #4168 from virusman/pr/mac-builds
Set up Mac builds on CI
2022-06-01 19:26:25 +02:00
Joshua Glatt 151bfd2f26 Support using string-valued containers in some when-argument SEXPs (#4305) 2022-06-01 07:57:15 -07:00
virusman f7d83978fc Move Mac ccache setup to CMakeLists.txt 2022-05-31 21:26:58 -07:00
virusman 014b73e54e PR review changes 2022-05-31 21:26:58 -07:00
virusman cd267972b9 Fix cache id for Qt 2022-05-31 21:26:58 -07:00
virusman 97a67958a7 Set up Mac builds on CI 2022-05-31 21:26:58 -07:00
Goober5000 d2f4a982e6 Merge pull request #4323 from Goober5000/4313_followup
minor cleanup of turret names
2022-05-31 23:06:00 -04:00
Goober5000 a745f6179a Merge pull request #4319 from Goober5000/draw_resized
Add gr.CurrentResizeMode
2022-05-31 20:47:25 -04:00
Birk Magnussen e3544e687e Free up order 0 for no-order 2022-05-31 21:36:22 +02:00
Goober5000 3088477a3e Merge pull request #4274 from Goober5000/lua_bitop
add Lua BitOp 1.0.2
2022-05-31 13:21:00 -04:00
Goober5000 b92f362a80 update containers to hopefully fix CI 2022-05-31 12:52:55 -04:00
Goober5000 ee1330669a add Lua BitOp 1.0.2
Adds the standard Lua extension library for bit operations in Lua 5.1.
http://bitop.luajit.org/

Note that this library is normally called "bit", but it is added here as "luabit" because there is already a FSO scripting library called "bit".
2022-05-31 10:23:44 -04:00
Goober5000 c1003f76b8 add new virtvar for getting and setting resize mode, and use it in drawString and drawStringResized 2022-05-31 00:21:10 -04:00
Goober5000 aa4a58e53b clean up ship arrival and departure effects
Due to both the AI code and the ship movement code calling warp departure logic, enabling `Framerate_independent_turning` caused ships with the no-departure-warp flag to depart twice.  Removing the call to `shipfx_actually_warpout` fixes this.

More fundamentally, this untangles and organizes the arrival and departure logic as it pertains to effects.  The actual arrival and departure code is moved to the `shipfx_actually_warpin` and `shipfx_actually_warpout functions`.  This simplifies `WarpEffect::warpEnd()` and allows `WarpEffect` and its subclasses to only concern themselves with the visual effects.

This also fixes a logging statement that could never actually be printed due to `delta_ms` being the wrong sign in the if() check.
2022-05-30 22:04:21 -04:00
Goober5000 85ed537960 Merge pull request #4324 from Goober5000/timestamp_comparisons
timestamp comparisons
2022-05-30 19:12:53 -04:00
Goober5000 a5ae3e7de8 Merge pull request #4328 from MageKing17/bugfix/missionparse-escort-assertion
Remove pointless assertion in mission parsing.
2022-05-30 19:12:44 -04:00
David Gibson 52fd857736 Simplified internal references to debug_sphere members 2022-05-30 14:50:09 -05:00
BMagnu 370e12dba5 Make number of player orders FRED can handle dynamic (#4290)
* Give FRED the ability to check dynamic player orders

* Fix Warning

* incorporate feedback

* Incorporate Feedback 2
2022-05-31 04:13:59 +09:00
Goober5000 5b44ea6a34 augment Assertion messages 2022-05-30 15:06:41 -04:00
Goober5000 28631b743c Merge pull request #4325 from EatThePath/bugfix/fix_4161
removed vestigial bit-depth asserts for aabitmaps.
2022-05-30 13:03:47 -04:00
MageKing17 8c1693df46 Remove pointless assertion in mission parsing.
When parsing escort priority, FSO asserts that the escort flag is set,
but this assertion is only valid in missions output by FRED; it's fairly
trivial to use notepad to remove the flag without removing escort
priority, thereby triggering the assertion. Furthermore, there doesn't
actually seem to be a problem if a parse object has an escort priority
without the escort flag; the engine won't actually use the priority
until/unless the ship is manually added to the escort list, and then it
doesn't matter that one is set.
2022-05-29 12:04:21 -07:00
Joshua Glatt c5be6095b2 Fix is_for_op() to follow existing conventions (#4322) 2022-05-29 10:42:33 -07:00
Birk Magnussen 3f227e7eeb Incorporate Feedback 2022-05-29 10:48:10 +02:00
David Gibson d2ddcfe4e0 removed vestigial bit-depth asserts for aabitmaps. 2022-05-28 16:57:05 -05:00
David Gibson 859d44f3a3 Rendering changes to stablize debug_sphere coloration 2022-05-28 16:37:47 -05:00
Goober5000 7780cf4617 timestamp comparisons
Add methods to compare timestamps, as well as methods to calculate deltas from existing timestamps.

Follow-up to #4286.
2022-05-28 17:13:24 -04:00
David Gibson 45b6362777 Applied automatic formatting to the new debug_sphere files
Restructured debug sphere code for efficiency
2022-05-28 16:10:48 -05:00
David Gibson c6c5d37f48 Converted debug sphere to class 2022-05-28 15:48:28 -05:00
David Gibson 753856421d dead code cleanup 2022-05-28 15:48:28 -05:00
David Gibson 90eb343aa9 Implemented debug sphere queuing and rendering. 2022-05-28 15:48:28 -05:00
Goober5000 39d9251e2c Merge pull request #4286 from Goober5000/timestamp_since
add timestamp_since
2022-05-28 16:35:28 -04:00
Goober5000 5f5d210a9b minor cleanup of turret names
Small follow-up to #4313 based on review comments that were 2 minutes too late.
2022-05-28 16:07:36 -04:00
The Force cfdeeb7109 Allow Weapon To Override Turret Name (#4313)
* Allow Weapon To Override Turret Name

* Loop through all banks rather than just the first

* Fix gcc warning
2022-05-28 15:55:39 -04:00
Goober5000 62cacb3f08 address feedback 2022-05-28 14:41:20 -04:00
EatThePath d1397147e4 Merge pull request #4308 from MageKing17/cleanup/deprecated-cmdline-flags
Handle deprecated cmdline flags programmatically.
2022-05-28 11:37:28 -05:00
Taylor Richards f5cbed9cdb use proper buffer size for PXO chat line (#4318)
fixes #4285
2022-05-28 08:53:48 -04:00
BMagnu f193c5233d Add LuaAI validity callbacks (#4304)
* Add callback for user specified availability status

* Add target restrict hook

* Fix Restrict hook and add not self restrict type

* Fix documentation

* Fix typo

* scope the ai achievability enum

* fix scoped achievabiliy
2022-05-28 21:18:28 +09:00
Goober5000 65998e8d04 Merge pull request #4320 from Goober5000/name_length_fixes
fix NAME_LENGTH discrepancy
2022-05-28 00:38:22 -04:00
Goober5000 d6c4fb8e53 fix NAME_LENGTH discrepancy
The ship creation code had an off-by-one error while checking the maximum length.  Fixes #4297.
2022-05-27 22:24:45 -04:00
Taylor Richards f6f16b6a32 clang-tidy fixes 2022-05-27 17:47:38 -04:00
Taylor Richards 39434fe7b1 fix a bunch of graphics functions to respect GR_STUB 2022-05-27 12:49:49 -04:00
Joshua Glatt 84023002db Add for-container-data and for-map-container-keys SEXPs (#4296) 2022-05-26 21:39:14 -07:00
BMagnu e22b8e44b7 Fix for real now (#4312) 2022-05-26 21:46:38 +09:00
Joshua Glatt 3fb034ab7f Add container name subtype to Sexp_nodes (#4299) 2022-05-25 21:26:05 -07:00
BMagnu 6ef7616dcc Fix orders accepted list parse (#4310) 2022-05-25 19:05:47 +00:00
MageKing17 46310c0667 Handle deprecated cmdline flags programmatically.
Instead of keeping the old variables around (except renamed to include "_deprecated") and manually checking them one at a time with a lot of duplicated code, use existing information to generate the messages automatically.
2022-05-24 20:39:37 -07:00
Birk Magnussen 13d245a101 fix builtin 2022-05-24 21:04:36 +02:00
Goober5000 53aec7e4e4 Merge pull request #4293 from Goober5000/for_operator_memory_fixes
fix some memory management problems in the for-* operators
2022-05-24 11:18:37 -04:00
BMagnu c06007bcac Fred and clang tidy 2022-05-24 14:46:25 +02:00
BMagnu 50ef38bf21 Adapt QTFred 2022-05-24 14:02:45 +02:00
BMagnu 7dbb16bf06 Fix Warning 2022-05-24 13:56:07 +02:00
BMagnu ca3207de47 Tidyup 2022-05-24 13:50:22 +02:00
BMagnu 00078b9c77 Multi Bump 2022-05-24 13:42:18 +02:00
BMagnu 7155163223 Remove bitfield indexed player orders 2022-05-24 13:38:56 +02:00
BMagnu cfb5a04aa9 Activate LuaAI custom message parsing (#4303)
* Add parsing for specifying order accept messages

* Write out acknowledge in comment
2022-05-23 20:44:54 +00:00
BMagnu cd2aac4faa Fix FRED Add/Replace (#4301)
* Fix ID mangle
2022-05-23 20:40:14 +00:00
Joshua Glatt c8ace18317 Add copy-container SEXP (#4291) 2022-05-23 08:55:27 -07:00
Goober5000 54413fa0fb fix some memory management problems in the for-* operators
1) In `for-counter`, when `just_count` is true there is a memory leak, since the code never enters `test_argument_vector_for_condition`, but for the same reason, duplicating the string is not necessary in that case, so just add a blank string
2) Remove unnecessary `vm_strdup` calls from the other for-* operators
3) `const`ify argument management
2022-05-22 22:55:12 -04:00
David Gibson dc31a9f663 Corrected copy and paste error in light profile value setting 2022-05-22 10:14:34 -05:00
Goober5000 663e3ade36 Merge pull request #4289 from Goober5000/3860_followup
briefing icon behavior tweaks per request
2022-05-22 00:36:23 -04:00
Goober5000 bfddd5f758 briefing icon behavior tweaks per request
Per #3860, don't disable any of the icon dropdowns, and don't change the ship class when the icon type is a special popup.
2022-05-21 18:25:45 -04:00
BMagnu 48baf8c0af Fix HUD squad menu PageDown (#4283)
* Fix HUD squad menu PageDown

* Clang Tidy
2022-05-22 05:57:59 +09:00
David Gibson 1699bf1570 Corrected order of operations in lightprofiles modifier processing 2022-05-20 14:34:10 -05:00
Goober5000 805e858123 Merge pull request #4277 from Goober5000/hud_target_distance
add hu.getTargetDistance()
2022-05-20 14:18:06 -04:00
Goober5000 260526cbd6 add hu.getTargetDistance()
Add a scripting function to return the distance as seen on the HUD.
2022-05-19 21:03:45 -04:00
Goober5000 ede0645d3b Merge pull request #4273 from Goober5000/resolve_4270
resolve FIXME for AIM_GET_BEHIND
2022-05-19 20:51:31 -04:00
Goober5000 e473ff011c add timestamp_since
Add `timestamp_since()` and modify a few places that use `timestamp_until()`.
2022-05-18 22:24:20 -04:00
Goober5000 7222c8a398 resolve FIXME for AIM_GET_BEHIND
This mode was never actually implemented, even in retail, so there is no FIXME as such.  Tweak the code to reflect this.  Fixes #4270.
2022-05-18 21:27:20 -04:00
Goober5000 48d5211e68 Merge pull request #4275 from naomimyselfandi/scpui-stage-hooks
Allow SCPUI to run `$On Briefing Stage:` hooks
2022-05-18 18:47:24 -04:00
BMagnu f707d471da Replace +Orders Accepted: Bitfield with flag list (#4282)
* Deprecate '+Orders Accepted:' Bitfield

* Add retail compat mode
2022-05-19 06:24:02 +09:00
Taylor Richards 5e79021da3 use SCP_string for constructing multi/event log lines (#4284) 2022-05-18 13:56:37 -04:00
EatThePath 4d66740f7a Merge pull request #4279 from qazwsxal/image-based-lighting
Lab Environment-Map Export
2022-05-17 22:12:14 -05:00
The Force 0d3290f14d Enable Doxygen for QTFred (#4281) 2022-05-17 22:08:32 -05:00
Taylor Richards b4f95c3b0c Merge pull request #4266 from notimaginative/fix_multi_timestamps
address multiple timestamp issues with multi
2022-05-17 20:07:09 -04:00
Taylor Richards 932c91b526 Merge pull request #4280 from notimaginative/multi_debug_helpers
add improvements to aid in multi troubleshooting
2022-05-17 20:05:55 -04:00
Naomi Coffman 0f9fee8d7c Lua indexes start at 1 2022-05-17 18:59:28 -04:00
Taylor Richards 4581897b09 remove obsolete time stoppage for screenshots
With the new timestamp code this particular instance should no longer
be necessary. And prevents sync issues in multi with it gone
2022-05-17 13:55:08 -04:00
The Force 883566ad05 Add TBL Viewer (#4233) 2022-05-17 08:38:37 -05:00
Taylor Richards 62f41ceb73 fix options screen breaking multi
The options screen (F2) isn't a paused state in multi so we can't
stop time while it's active
2022-05-17 07:52:09 -04:00
Taylor Richards df6cf572ac convert multi timestamp()'s to ui_timestamp() where appropriate
A bit overkill for some of this but just covering the bases.

 * fix issues with in-game join
 * fix multi messaging and multi pause screen
 * make sure maintenance stuff (pings, voice, file xfer, etc.) isn't
   affected by pausing or time compression
2022-05-17 07:50:50 -04:00
Adam Leach 1d16bb28a4 Keep clang tidy happy (NULL->nullptr) 2022-05-17 11:11:47 +01:00
Adam Leach 862cf0d82c Keep clang -Werror=unused-but-set-variable happy. 2022-05-17 09:05:20 +01:00
Taylor Richards ead4376f47 fix unittests when non-interactive is used 2022-05-16 16:23:34 -04:00
Taylor Richards a8618a569c add improvements to aid in multi troubleshooting:
- report when multi.cfg is missing
 - add game version, multi version, cmdline, and PXO status
   to multi.log
 - use non-interactive mode by default on standalone and
   enable it as soon as possible
2022-05-16 15:47:30 -04:00
Adam Leach 98846a3f88 Clean up comments 2022-05-16 19:51:23 +01:00
Adam Leach dbd7b2f49a Update usage info in lab with M key 2022-05-16 19:23:24 +01:00
Adam Leach 743cd5035d Flip Y coord 2022-05-16 19:05:43 +01:00
Adam Leach 22b1f08592 Cleanup render target and don't produce cubemap images 2022-05-16 19:05:43 +01:00
Adam Leach 530118785a spherical environment map generation 2022-05-16 19:05:43 +01:00
Adam Leach d84486c357 remove superfluous filepath format 2022-05-16 19:05:43 +01:00
Adam Leach 2744af109a Dump Environment maps with "M" key in lab 2022-05-16 19:05:43 +01:00
BMagnu 5c4be3d392 LuaAI (#4198)
* Basic LuaAI

* LuaAI Player Order Support

* Add Player Order Target Restricts

* Fix init order

* Add AI helper API

* Fix subcategory stuff

* Fix Compiler Warnings

* Remove AI Mode switch Int3's

* Fix Lua docs

* Compiler warnings 2

* Clang Tidy

* Incorporate Feedback

* Incorporate Feedback 2

* Incorporate Feedback 3

* Incorporate Feedback 4

* Clang Tidy
2022-05-16 18:36:34 +09:00
Naomi Coffman 701a8de527 Allow SCPUI to run $On Briefing Stage: hooks 2022-05-15 19:44:48 -04:00
Goober5000 303480eecf Merge pull request #4257 from jg18/fix/fred-with-container-names
Ensure Replace/Add String and (Add) Paste are disabled for container name nodes
2022-05-15 13:47:26 -04:00
Goober5000 f9aad01349 Merge pull request #4267 from naomimyselfandi/cancel-future-waves
Add cancel-future-waves
2022-05-15 12:34:05 -04:00
Goober5000 1269feae44 Merge pull request #4271 from Goober5000/maybePlayCutscene_fix
fix maybePlayCutscene arguments
2022-05-15 12:33:04 -04:00
David Gibson a214488395 shifted profile name for default profile parse to variable, and other small fixes to weapon color implementation 2022-05-14 18:58:21 -05:00
David Gibson 7dbb831efa Addressed some memory management problems in new weapon color code 2022-05-14 18:37:38 -05:00
Taylor Richards 4587c33e05 enable newer options of subtitle sexps for multi 2022-05-14 19:23:20 -04:00
Goober5000 3c22bf9c49 Merge pull request #4268 from Goober5000/clean_up_wing_waves
some wing wave cleanup
2022-05-14 14:31:25 -04:00
Goober5000 fa52bf747d fix maybePlayCutscene arguments
This must have been coded as `ui:maybePlayCutscene` when it should be `ui.maybePlayCutscene`
2022-05-14 14:30:04 -04:00
Naomi Coffman 2ffa4ca982 Document how cancelling interacts with is-destroyed-delay and friends 2022-05-14 07:46:56 -04:00
Goober5000 833326aa76 some wing wave cleanup
In the process of looking through `num_waves` and `current_wave` for #4267, I found a couple of confusing bits of code.  This clarifies things.
2022-05-14 01:34:42 -04:00
Goober5000 ba225dcf20 Merge pull request #4265 from notimaginative/standalone_crash_fix
fix a standalone crash from disabled uniform buffer manager
2022-05-14 00:06:27 -04:00
naomimyselfandi 0d461c1fc4 Replace "Always_show_goals" with "Toggle_showing_goals" (#4263)
* Replace "Always_show_goals" with "Toggle_showing_goals"

The "Always_show_goals" flag is a no-op on anything other than a
training mission. This replaces it with a new flag which toggles
whether the goals are shown instead, in keeping with the existing
"Toggle_debriefing" flag.

* Rename other occurrences of Always_show_goals

* Update stale comment

* Update stale member names

* Remove unused #define
2022-05-13 22:19:59 -05:00
Naomi Coffman f8fdda34a6 Fix shadowing 2022-05-13 22:19:01 -04:00
Naomi Coffman 798f1c8c2f Fix documentation typo 2022-05-13 21:50:01 -04:00
Naomi Coffman 1228a56e42 Add cancel-future-waves 2022-05-13 21:46:39 -04:00
Taylor Richards ab483eeea8 fix a standalone crash from disabled uniform buffer manager 2022-05-13 04:00:25 -04:00
Taylor Richards d1c12cc57f try to handle unknown sexp data more gracefully
fixes #3773
2022-05-13 00:35:40 -04:00
Goober5000 3d646e591d Merge pull request #4258 from Baezon/fix-sun-position-compensation-math
Correct sun position compensation math
2022-05-12 20:02:05 -04:00
Goober5000 20efcb9717 Merge pull request #4261 from Goober5000/disable_sun_bank
disable sun bank controls
2022-05-12 20:01:42 -04:00
Goober5000 b1a59ec8b3 Merge pull request #4262 from Goober5000/coverity_followup_fixes
miscellaneous fixes related to old Coverity fixes
2022-05-12 20:01:36 -04:00
Goober5000 7bece7a946 guard against negative turret_enemy_objnum 2022-05-12 01:50:09 -04:00
Goober5000 7606df6082 miscellaneous fixes related to old Coverity fixes
1) Remove the extra branch in `check_ok_to_fire` that was added in SVN revision 10392, or commit 0d54630e83.  If there was an actual Coverity error, this does not fix it at the proper location.  More importantly, this breaks certain turret firing behavior.
2) Fix a couple of bounds checks.
3) Remove an incorrect stale comment.

This fixes the broken turret swarm weapons that were uncovered by the fixes in #2959.
2022-05-12 01:03:50 -04:00
Goober5000 e534adf107 Merge pull request #4159 from Goober5000/test_replace
guard against off-by-one errors in replace_one and replace_all
2022-05-11 22:11:39 -04:00
JohnAFernandez 1acd763e4d Limit all MP client collisions to prevent bugs (#4209)
Players are still affected by collisions locally, but other ships will literally pass through each other until updated by the server.  A timestamp controls the frequency of collisions with the player ship.
2022-05-11 19:11:09 -07:00
Goober5000 6101627381 Merge pull request #4260 from Goober5000/4243_followup
revised disabling of Enter and Escape
2022-05-11 22:04:50 -04:00
Goober5000 741231be77 disable sun bank controls
Per Asteroth, and following PR #4258, sun banking is no longer meaningful and should be disabled.
2022-05-11 19:31:55 -04:00
Goober5000 e21575558e Merge pull request #4249 from Goober5000/fix_change_alt_name
fix assignment of alt-name when using the hash
2022-05-11 19:15:56 -04:00
Goober5000 dd287c4288 revised disabling of Enter and Escape
Turns out PR #4243 actually introduced a bug that appeared to implement the feature.  The previous implementation had the effect of intercepting all keypresses and routing them to the main window.  This fixes that bug by using `CDialog` instead of `CWnd`.  It also turns out that the `hWnd` window handle for some reason does not match the expected window, but fortunately, this implementation is only called in the correct window so the restriction is not needed.
2022-05-11 19:09:04 -04:00
Asteroth aa316433f1 qtfred too 2022-05-11 17:56:06 -04:00
Asteroth 9f63b17328 make sure to clamp 2022-05-11 15:26:03 -04:00
Asteroth 2e37aceab9 correct sun math 2022-05-11 14:13:39 -04:00
Joshua Glatt 42a7861990 Ensure Replace/Add String and (Add) Paste are disabled for container name nodes 2022-05-10 21:53:26 -07:00
Joshua Glatt e44456333e Fix clear-container SEXP (#4255) 2022-05-10 21:39:59 -07:00
Goober5000 be8cfe1180 Merge pull request #4256 from Goober5000/4121_followup
partial revert of targeting distance ranking change
2022-05-10 23:53:59 -04:00
Goober5000 b16d953bed partial revert of targeting distance ranking change
Normally, when the player cycles through targets using (for example) the hostile targeting key, the targets will be shown in order of distance.  In PR #4121, this was changed from bounding-box distance to center-distance, which has very little noticeable effect on the cycle except that it now agrees with the AI strategy for measuring distance.

However, when the player targets a hostile for the first time, or when the cycle resets after 1.5 seconds have passed, the first ship targeted will be the closest ship *or* the ship with the closest turret.  And furthermore, when the target cycle continues, the next ship targeted will be the next ship farther away.  There can be a dramatic difference between a turret, which may be very close, and the center of the ship, which may be very far away.  The target cycle will continue with these far-away ships, and this has the effect of leapfrogging any ships that are closer that should be targeted first.

There isn't any easy way to tell that a ship has been targeted because of its turret, and not because of some other targeting key or because the cycle has restarted, but fortunately the bounding-box distance is a reasonable approximation because turrets tend to be on the bounding boxes.  So this commit simply restores the distance functions to what they were before.  The other fixes from #4121 are not related and remain in place.
2022-05-10 22:51:01 -04:00
Goober5000 047458fc0c Merge pull request #4253 from Goober5000/fix_set_camera_facing
keep default identity orientation when host flag is active
2022-05-10 01:11:11 -04:00
Goober5000 1273cbcdc9 keep default identity orientation when host flag is active
When the `$Use host orientation for set-camera-facing` flag in game_settings.tbl is active, the camera will use the host's orientation as a basis for rotation.  However if there is no host, the camera unintentionally inherited its old stale orientation.  Instead the camera should base its new orientation on the identity matrix which is the expected behavior.
2022-05-10 00:35:50 -04:00
Goober5000 71a861bd6f more feedback, a fix, and a new test case 2022-05-10 00:30:48 -04:00
Goober5000 d7a4fc5eb1 modify tests 2022-05-09 21:51:09 -04:00
Goober5000 55be80dd6a address feedback 2022-05-09 21:00:21 -04:00
Goober5000 b278e95877 Merge pull request #4242 from Goober5000/fred_parse_cleanup
clean up some parse problems in FRED
2022-05-09 02:41:45 -04:00
Goober5000 215d90ccc0 Merge pull request #4250 from Goober5000/ship_created_cues
assign cues when a ship is ship-created
2022-05-09 02:41:36 -04:00
Goober5000 18a311e779 Merge pull request #4252 from Goober5000/new_timestamp_fix
use the proper time for the newly added timestamps
2022-05-09 02:41:14 -04:00
Joshua Glatt 7fd20c667a Implement query_modified() for Add/Modify Container FRED dialog (#4247) 2022-05-08 20:16:41 -07:00
Joshua Glatt 6f8e60eb17 SEXP containers, Part 8: Change SEXPs (#3862) 2022-05-08 20:15:59 -07:00
Goober5000 b29f183aee assign cues when a ship is ship-created
Assign locked-* cues when a ship is created so that their arrival and departure cues are not -1.  Supersedes PR #4248.
2022-05-08 23:15:33 -04:00
Goober5000 2f23a794fb use the proper time for the newly added timestamps
The new timestamps should use the timestamp ticker, which accounts for pauses and time compression, not the standard timer, which measures absolute elapsed time.  This fixes the bug reported on Discord where the supernova timer did not pause when the game was paused.
2022-05-08 22:58:47 -04:00
Goober5000 ba88b01f51 fix assignment of alt-name when using the hash
Alt-names with hashes that were added by the `change-alt-name` sexp used to have their hashes truncated properly.  This most likely broke when hash truncation was moved from the HUD code to the "display name" code.  This PR truncates hashes in the same way as truncation elsewhere.
2022-05-08 21:53:13 -04:00
Tyler Blount 1091a93752 Merge pull request #4246 from Baezon/no-mem-leak-bsp-changes
Fix memory leak and use tmap verts directly
2022-05-08 12:46:05 -07:00
Joshua Glatt a654b61d0c SEXP containers, Part 7: Status SEXPs (#3861) 2022-05-08 08:15:59 -07:00
David Gibson 1947f0d9bd Use custom color for beam lights 2022-05-07 17:21:28 -05:00
David Gibson 4aba6defdb Use custom colors for missile and laser weapon lights 2022-05-07 17:21:28 -05:00
David Gibson 29f7a38482 now parse and store light colors into weapon info 2022-05-07 17:21:28 -05:00
David Gibson 5c0b5480c8 Moves the light size multipliers one step closer to the user 2022-05-07 17:21:28 -05:00
David Gibson 20e139baf9 Now allow light setup directly via hdr color object 2022-05-07 17:21:28 -05:00
David Gibson bd9d16fd69 Lighting profiles support for tuning dynamic light values 2022-05-07 17:21:28 -05:00
David Gibson 6c473e7c09 pareshi for HDR colors 2022-05-07 17:21:28 -05:00
David Gibson e03bb48bb3 Implemented HDR color type for HDR light data 2022-05-07 17:21:28 -05:00
David Gibson e3927104bb Implemented optional parse into bool parsehi 2022-05-07 17:21:28 -05:00
Asteroth 2e4a568e2b update the swap bsp functions 2022-05-07 17:12:00 -04:00
Asteroth 326a0c32d0 fix memory leak and use tmap verts directly 2022-05-07 16:43:23 -04:00
Goober5000 4344642d3e further bugfixing and modify function return values 2022-05-07 15:08:26 -04:00
Goober5000 0e13c32d73 testing found a legit bug 2022-05-07 15:08:26 -04:00
Goober5000 79769ba76f more test cases 2022-05-07 15:08:26 -04:00
Goober5000 b404b137a0 guard against off-by-one errors in replace_one and replace_all
Also add some test cases for checking correct behavior.
2022-05-07 15:08:21 -04:00
Goober5000 c7a16a109a Merge pull request #4232 from Goober5000/fix_3860
add some UX guards to the briefing editor icons
2022-05-07 14:51:54 -04:00
Goober5000 99bbc23b64 Merge pull request #4245 from Baezon/sun-background-fix
Fix background sun positioning as well
2022-05-07 14:51:28 -04:00
Goober5000 aeedcc22a1 Merge pull request #4243 from Goober5000/fix_4240
disable Enter and Escape in the container dialog
2022-05-07 14:48:15 -04:00
Goober5000 0fb6fbec6d Merge pull request #4239 from Goober5000/fix_reset_tech_database
fix two bugs associated with custom tech databases
2022-05-07 14:47:39 -04:00
Asteroth 4dbaf40991 correct sun position too 2022-05-07 13:17:43 -04:00
Goober5000 505f8a93d0 disable Enter and Escape in the container dialog
Override some MFC signal paths to prevent Enter and Escape from doing their default behavior.  Also add a "save changes" prompt to the Cancel and Close buttons.

Fixes #4240.
2022-05-06 21:33:24 -04:00
Goober5000 9cafab6e26 clean up some parse problems in FRED
These were first noticed by @TheForce172 in PR #4241.  Instead manually editing the parse buffer, call the parsing functions to properly free the memory used by parsing the tables.  Also remove redundant calls to `ship_init`.
2022-05-06 20:01:15 -04:00
Goober5000 bb2bd3fc1d Merge pull request #4186 from Goober5000/fred_background_angle_fix
background bitmap fix
2022-05-06 18:43:38 -04:00
Goober5000 5e436dd276 fix two bugs associated with custom tech databases
1) In commit 770fce8de5, a flag was incorrectly ported from a bit to a flagset, which caused ships not in the tech db to not be removed.
2) Perhaps due to the pilot file upgrade, campaigns which had their tech databases reset would immediately load stale techroom data from the savefile.  This change writes the savefile after the reset so that subsequent reloads will load the correct data.
2022-05-05 22:42:20 -04:00
Goober5000 4c948569c8 address feedback 2022-05-03 22:22:25 -04:00
Goober5000 5bde7cd1b6 Merge branch 'fred_background_angle_fix' of github.com:Goober5000/fs2open.github.com into fred_background_angle_fix 2022-05-02 19:50:29 -04:00
Goober5000 4b935731ca fix is_sun argument 2022-05-02 19:49:55 -04:00
Asteroth c1fdb640b1 add wiki link 2022-05-02 01:36:13 -04:00
Joshua Glatt 670665d0af SEXP containers, Part 6: FRED/qtFRED SEXP trees (#3852) 2022-05-01 20:27:39 -07:00
Goober5000 298265c831 replace names ending in 2 with names ending in new 2022-05-01 23:21:21 -04:00
MageKing17 65d4423b41 Make the "$Player Weapon Precedence:" list actually give precedence. (#4225)
Theoretically, the list actually had precedence when a table entry had fewer banks than the model, which would fill the extra banks with the first applicable weapon in the precedence list... except the engine `Error`s before that can happen, so it didn't actually do that. When a mission's loadout doesn't include one or more of the weapons the ship thinks it should have (i.e. it's left to its default loadout and one or more of those are missing), the missing weapons are replaced from the `Player_weapon_precedence` list. However, it didn't actually check precedence: it just went through every weapon type in order, and picked the first applicable one that also happened to be on the `Player_weapon_precedence` list.

This commit makes it so that instead of iterating through every weapon ID, we just iterate through the ones in the `Player_weapon_precedence` list (which is now a vector, thanks to #4201). Not only does this mean that higher entries in the list will be chosen first (meaning actual precedence), but since the vector will often be much shorter than `Weapon_info`, it should also take fewer iterations to find a valid weapon (or decide none of them are valid). This is technically a backwards-incompatible change, but since it only affects missions where a ship on the loadout screen lacks a weapon in its assigned loadout, it should be a relatively minor break.
2022-05-01 20:10:12 -07:00
Goober5000 30c168693b change 'fixed' to 'corrected' 2022-05-01 23:07:04 -04:00
Goober5000 ba18cecf44 add clarifying comment 2022-05-01 23:06:50 -04:00
wookieejedi fff19927e7 Add Subsystem Flag to Hide Turrets from Ship Loadout Stats (#4235)
* Add Subsystem Flag to Hide Turrets from Ship Loadout Stats

The statistics summary window in the ship loadout editor shows various aspects and stats of the selected ship. These can be toggled and customized through the ships table, but one line is actually autogenerated, `+Turrets`. This is unideal for certain ships, especially those which use turrets on ships in non-standard ways (for example having an AI controlled turret which shoots bombs). In these cases, the turrets are not actual turrets, and it is confusing for players seeing that there is a turret on the ship in the loadout editor. (I can give more detailed examples using FotG if needed).

This PR adds a subsystem flag which allows the modders to hide a turret subsystem so it is not counted in the auto generation of the `Turrets` summary line. (As a slight cleanup I also removed cleaned up the whitespace formatting on a nearby, but unrelated line).

* sync names

* fix renaming
2022-05-01 17:10:56 -04:00
BMagnu 316ef398e8 Encapsulate testing for LoS in a function and expose to Lua (#4234)
* Allow extracting userobjects from LuaTable

* Encapsulate test_los function and expose to lua

* Incorporate feedback

* Tidyup objcollide

* Fix LuaValue template

* Fix Warnings

* Fix Clang Tidy

* Update comments as suggested, Co-authored-by: m!m
2022-05-02 05:50:22 +09:00
Goober5000 53a2533169 Merge pull request #4212 from Goober5000/4088_followup
patch the freeing of SEXP nodes
2022-05-01 12:19:39 -04:00
EatThePath d698175670 Merge pull request #4222 from TRBlount/cleanup-model-code-1
Model code cleanup #1
2022-04-30 21:23:00 -05:00
EatThePath de39f591a1 Merge pull request #4020 from jg18/qtfred-replace-number-string
Implement Replace Data for Number and String in qtFRED
2022-04-30 21:22:32 -05:00
EatThePath 898bbd7260 Merge pull request #4230 from qazwsxal/bugfix/paste_proper
Clearer event editor Paste function names and saner defaults
2022-04-30 21:21:42 -05:00
Goober5000 3a322edbcf Merge pull request #4224 from MageKing17/feature/unlimited-ship-flags
Allow an unlimited number of ship flags to be parsed at once.
2022-04-30 14:17:08 -04:00
Goober5000 fd56d8f850 Merge pull request #4231 from Goober5000/additional_script_conditions
fix up conditions for script hooks
2022-04-30 02:24:03 -04:00
Goober5000 8951dc19b1 add some UX guards to the briefing editor icons
1) Prevent the ship class from being changed if the icon image has a special closeup (like a jump node)
2) If the icon image is changed to a special closeup, automatically choose a ship class that doesn't have a custom icon

Fixes #3860
2022-04-30 01:37:48 -04:00
Goober5000 a061a08d4d address feedback 2022-04-30 01:01:02 -04:00
Goober5000 69e0f66d4b fix up conditions for script hooks
For script hooks which use conditions, be more consistent about evaluating both objects involved, as well as evaluating the different types of objects.

Fixes #3874.
2022-04-29 22:37:30 -04:00
Adam Leach f392c66c93 Swap menu order of paste commands to follow previous convention 2022-04-30 00:11:52 +01:00
Adam Leach 3d9b0c70cd Better descriptive name for paste operation. 2022-04-30 00:02:42 +01:00
Adam Leach 3b5f6424a1 Use CTRL+SHIFT+V for overwrite-paste 2022-04-29 23:58:34 +01:00
Adam Leach 5de12e2e50 move over item handle calls too. 2022-04-29 23:21:19 +01:00
Adam Leach 32c0f246e2 Revert re-ordering of menu items 2022-04-29 22:59:03 +01:00
Adam Leach b3e3fcf1d4 Updated menu name 2022-04-29 22:06:59 +01:00
Adam Leach 3f39cbd76a Clearer Paste function names and saner defaults 2022-04-29 21:41:04 +01:00
EatThePath 2e2a632055 Merge pull request #4229 from EatThePath/bad_lpt_line
Bad lpt line
2022-04-29 08:36:40 -05:00
David Gibson e2dd86ba99 Renamed a now badly named variable 2022-04-28 21:55:23 -05:00
David Gibson 79c8d67281 Proper error handling for un-recognized lighting profile lines 2022-04-28 18:26:12 -05:00
Goober5000 855b7fe78c Merge pull request #4218 from Goober5000/fix_4170
make variable list parsing a little more robust
2022-04-28 18:29:10 -04:00
BMagnu 3aa6cd8a87 Add cockpit FoV (#4220)
* Add cockpit FoV

* Add override documentation for SEXP
2022-04-29 03:45:18 +09:00
MageKing17 acaa93a9d2 Avoid setting .rest for Locked_sexp_true/false with malformed SEXPs. (#4221)
* Avoid setting .rest for Locked_sexp_true/false with malformed SEXPs.

When FRED puts a `true` in the middle of a list of arguments, it wraps it in a nested list as `(true)`, because it's technically an operator; however, if someone writes a SEXP by hand, they could easily forget to do this, and in such cases, this causes `Locked_sexp_true` to be inserted into the middle of the list. If it's not the last element of the list, it will then have its `.rest` attribute set to the next node in the list. If this is a temporary SEXP (i.e. from Lua's `runSEXP()` function), this used to be a temporary problem, but PR #4088 changed the global search for any node with `.rest` set to the node being freed to require an explicit parent node. This means that `Locked_sexp_true.rest` remains set to a freed node, which can cause further issues. If such a malformed SEXP *isn't* temporary it can cause even more issues, even pre-#4088.

This commit changes `get_sexp()` so that if it detects `true` or `false` in the middle of a list (and not a single-element list), it will put it into a single-element sub-list, hopefully preventing any modification of `Locked_sexp_true` or `Locked_sexp_false`, as giving a `Warning`. This should cause it to behave as though `true` or `false` was actually `(true)` or `(false)`, respectively, and therefore run as expected.

* Add comment and remove unused variable declaration.

Thanks to @PhantomHoover for the wording on the comment.
2022-04-27 20:54:00 -07:00
Tyler Blount a2f6f791e4 Forgot some magic numbers 2022-04-27 15:22:07 -07:00
Goober5000 76bb1b6232 Merge pull request #4213 from Goober5000/hud_targetbox_flashes
add a script function to flash parts of the target box
2022-04-27 14:02:32 -04:00
MageKing17 0f3f5eeeb9 Actually clear delayed SSM parsing data when it's no longer needed. (#4223)
Back in #104, I made an *attempt* at clearing the delayed SSM parsing data once it'd been validated; however, for some reason, I only cleared half of the variables, and I only used `.clear()` rather than `.clear()` followed by `.shrink_to_fit()` (which means the same amount of memory was still reserved for these variables that would never be used again). While making #4201 I happened to comes across the "swap with empty temporary" paradigm do to both at once, so I decided to apply it to this old thing, as well as clearing all four variables rather than just two. Additionally, since these mappings don't actually care about ordering, I made them `unordered_map`s while I was at it. It's probably not a significant memory savings, but since we'd never need to use that memory after parsing, I figured we might as well reclaim it anyway.
2022-04-27 10:50:53 -07:00
MageKing17 95a0e2f17c Allow an unlimited number of ship flags to be parsed at once.
For some reason, ship flag parsing was still using a fixed-size array instead of a vector, limiting it to 20 flags parsed in a single entry. Since there wasn't really a reason to do that (it was basically parsing to a vector anyway, then resizing it down to the limit, then stuffing the C-strings into the array), I changed it to a vector.
2022-04-26 21:58:21 -07:00
Tyler Blount 33c53198a6 Update model typecast macros, add safe casts, clean up mistakes and unused function 2022-04-26 21:55:43 -07:00
EatThePath 05b94bb26b Merge pull request #4205 from EatThePath/parsehi_initial
Move of special parsing functions out of lighting_profiles into new file
2022-04-26 21:45:29 -05:00
Tyler Blount 64a213c667 Cleanup magic numbers and vertex loading for TMAPs 2022-04-26 18:35:48 -07:00
Asteroth 3e00b94a89 Early return instead of assert on 0 or less sized hud brackets (#4215)
* early return on 0 size brackets

* add comment
2022-04-26 18:10:31 -04:00
Joshua Glatt fe236b337f SEXP containers, Part 4: Text replacement (#3490) 2022-04-26 10:24:55 -07:00
wookieejedi 1de7ffc782 Fix RTT Cockpits Gauges with Change Ship Class (#4216)
* Fix RTT Cockpits Gauges with Change Ship Class

Previously, using the `change-ship-class` sexp or scripting function did not update RTT cockpit gauges. This PR adds the cockpit code update functions to fix the issue. Tested and works as expected.

* comment consistency
2022-04-25 22:18:02 -04:00
EatThePath ecac97c58a Beam light cleanup (#4211)
* beam_add_light_small() is only ever used in one place which always passes a point. Calculating the point inside is removed as redundant and obfuscating.

* Repeated beam light width calculation moved to function

* Repeated beam light state validation moved to function

* Repeated beam light noise generation moved to function

* cleanup superfluous parameter
2022-04-25 21:09:43 -05:00
Goober5000 97092997e9 make variable list parsing a little more robust
Properly report errors and warnings, and don't create duplicate variables.  Fixes #4170.
2022-04-25 18:43:38 -04:00
David Gibson e08805a5e2 actually remove the removed function 2022-04-25 16:31:48 -05:00
MageKing17 84ea99c371 Always record primary bank ammo capacity during ship creation. (#4217)
`ship_set_default_weapons()` (which is called by `ship_create()`) was only setting `swp->primary_bank_capacity` for a bank if the default weapon for that bank was ballistic; if the ship was then equipped with an ammo-using primary and the `set-primary-ammo` SEXP was used on it, it would think the bank had a capacity of zero, resulting in 0 ammo.

This commit simply moves the assignment outside of the conditional, so that primary bank capacities are always recorded in the `ship_weapon` class.
2022-04-25 19:25:31 +00:00
Goober5000 435a525e4f add a script function to flash parts of the target box
Add the `hu.flashTargetBox()` function.  Also move the `STR` macro to scp_defines.h and rename it `SCP_TOKEN_TO_STR`.
2022-04-24 23:14:49 -04:00
wookieejedi 30ae011d10 Fix Texture Replace and Team Colors with Ship Changes (#4207)
* Fix Texture Replace with Ship Changes

Tabled `$Texture Replace` did not work on ships where the class is changed in the loadout or with the `change-ship-class` sexp. This was because the replacement textures only were loaded during mission parse, and the `change_ship_type` did not account for loading new textures from ship classes that were not in the initial mission parse. Part of the bug was also that the code that updates texture replacements was after the texture page-in section of `change_ship_type`.

This PR fixes that bug by properly loading the textures in when the ship class changes. It also moves the code to within the `ship_model_change` function (which is only used in the `change_ship_type` function) so that the texture loading happens correctly before texture page in.

* fix accidental whitespace changes

* fix comment

* also fix team colors

* comment spelling fix

* appease clang

* properly clear replace textures between ship changes
2022-04-24 18:58:44 -07:00
JohnAFernandez 7466595478 Reinforcements Dialog (#3607)
Creates a working version of the reinforcements Dialog.
2022-04-24 21:40:32 -04:00
Goober5000 ca6a9017c6 patch the freeing of SEXP nodes
Followup to #4088.  A few calls of `free_sexp` (especially in `free_sexp2`) did not supply the calling node, which left inconsistent SEXP tree structures and caused a crash in TranscendE1M6.  This fixes the crash and fills in some of these places.
2022-04-24 20:41:03 -04:00
Goober5000 f394708f09 this should work 2022-04-24 18:48:12 -04:00
EatThePath c636ea5659 Remove light filtering data (#3737)
Removed useless light_ignore_objnum and affected_objnum lighting data, light_add_point_unique() subsequently removed as well, and cleaned up unused parameters.
2022-04-24 17:12:46 -05:00
Goober5000 47bd900918 moar 2022-04-24 18:12:23 -04:00
Goober5000 a6e3c74ad1 try this 2022-04-24 17:56:44 -04:00
Goober5000 0fc7c334a1 Merge pull request #4206 from Goober5000/hud_gauge_functions
add some script functions for HUD gauge data
2022-04-24 17:30:23 -04:00
Goober5000 83bd293a3a add some script functions for HUD gauge data
These are useful for adapting scripts based on whether HUD gauges are scaled and whether they use different coordinates or fonts.
2022-04-24 16:39:10 -04:00
Asteroth eb5be1c577 it wants double brackets i guess?? 2022-04-24 16:15:04 -04:00
Asteroth df39ac45d7 fill fix/unfix angles 2022-04-24 15:15:35 -04:00
Kiloku dca2ae715f Add a ship flag to allow the firing fail sound to play with locked primaries (#4203)
* Add a flag to allow the firing fail sound to play with locked primaries

* Adds an equivalent flag for Secondaries

* Make the flags accessible to FRED

* Fix whitespace mistakes

* Yet another whitespace fix

* Move primary fail sound flag check up to avoid wasting processing with unused shots

* Move secondary locked check up to avoid doing unnecessary checks
2022-04-24 13:09:50 -04:00
EatThePath 884e722109 Merge pull request #4191 from EatThePath/particlechance
Random chance of particle spawning
2022-04-23 20:23:44 -05:00
MageKing17 7184fbe781 Delay processing "$Player Weapon Precedence:" until after parsing. (#4201)
The `stuff_int_list()` call converts the weapon names into the appropriate index into the `Weapon_info` array; however, in `weapon_do_post_parse()`, we call `weapon_sort_by_type()`, which reorders the array; this makes these indices potentially point to the wrong weapon. Additionally, there's no protection against someone `+remove`ing one of the weapons in the list in a later TBM.

This commit makes it so we instead store the names into a vector of strings, then convert them into indices after `weapon_sort_by_type()` has already been called. Additionally, `Player_weapon_precedence` is changed from a fixed-size array to a vector, since it's usually not as long as `MAX_WEAPON_TYPES`.

Fixes #4199.
2022-04-23 14:55:36 -07:00
David Gibson a6611bf5b6 Corrected particle chance error handling 2022-04-23 15:29:59 -05:00
David Gibson a5091a4cb9 Move of special parsing functions out of lighting_profiles into new file 2022-04-23 14:43:35 -05:00
MageKing17 66619b9e46 Don't treat a bare <argument> as an error. (#4200)
PR #3750 made `check_sexp_syntax()` less permissive of node trees containing `<argument>`, which causes problems given that FRED saves `modify-variable`'s second argument as a `SEXP_ATOM_NUMBER`, as now `check_sexp_syntax()` complains that `<argument>` isn't a valid number. This commit both makes the `SEXP_ATOM_NUMBER` check skip the number validation logic if the `SNF_SPECIAL_ARG_IN_NODE` flag is set, as well as removing the `SEXP_ATOM_STRING` type check from the later `SNF_SPECIAL_ARG_IN_NODE` check (for making sure it's inside an `-argument` SEXP).
2022-04-22 22:16:41 +00:00
Goober5000 59064fdf89 fix bugs 2022-04-22 02:39:41 -04:00
Goober5000 af0b1fc9bb add FRED dialog support for flag 2022-04-22 02:06:16 -04:00
Goober5000 a64a587c63 save old versions of angles if background doesn't have flag 2022-04-22 00:25:14 -04:00
wookieejedi 675a806912 Fix FRED accessibility of new flag ai-attackable-if-no-collide V2 (#4194)
Turns out the `MAX_OBJECT_FLAG_NAMES` was not increased originally, so this PR increases it to match the new amount now that `ai-attackable-if-no-collide` flag was added.
2022-04-21 11:51:32 -04:00
Goober5000 e9ad970c20 Merge pull request #4192 from Goober5000/formation_fix
probably fix #4187
2022-04-21 00:17:40 -04:00
Tyler Blount d11c89d8b1 Merge pull request #4190 from Baezon/more-bsp-enhancements
More Pof space optimizations
2022-04-20 20:10:44 -07:00
Goober5000 ce6458b64f probably fix #4187
My guess is that, in `ai_ship_destroy`, if the dead ship's goal object has already died in the same frame, the `goal_objnum` will be -1 when `ai_formation_object_recalculate_slotnums` is about to be called.
2022-04-20 20:23:47 -04:00
David Gibson 0a20827620 test-ready random particle spawning 2022-04-20 18:54:22 -05:00
Goober5000 fa4c66dfac consolidate angle fixes into stars_fix_background_angles; add new script and sexp functions that use correct angles 2022-04-20 15:55:33 -04:00
Asteroth 8a188c56f6 add a doxy 2022-04-20 15:37:04 -04:00
wookieejedi 87ed583b28 Fix FRED accessibility of new flag ai-attackable-if-no-collide (#4189)
PR #4174 added this feature, this PR allows it to be useable with FRED.
2022-04-20 15:26:05 -04:00
Asteroth 3e2030bf01 clean up 2022-04-20 15:21:42 -04:00
JohnAFernandez 1396d44265 Basic Implementation for Attackable_if_no_collide (#4174)
A work-around for the default behavior where turrets will ignore ships that have no-collide set.  This allows turrets to target such ships.
2022-04-19 16:54:04 -05:00
Goober5000 d0c07f5dd8 Merge pull request #4172 from Goober5000/subtitle_screen_scale3
add optional flag to not change subtitle aspect ratio
2022-04-19 12:00:25 -04:00
Asteroth 527b46443b background bitmap fix, part 2
Uses simpler and more correct math for bg bitmap angles, and when old values are parsed, they are translated into correct values
2022-04-19 02:09:44 -04:00
Goober5000 f7dd1172c6 background bitmap fix, part 1
Adds the framework for loading and saving backgrounds with correct or incorrect angles.  Backgrounds in FSO will all have fixed angles internally, and newly created backgrounds in FRED will have fixed angles, but existing mission files will have incorrect angles.  The parser will determine whether the mission file contains fixed or unfixed angles and act accordingly.  (Actually fixing the angles will be done in part 2.)
2022-04-18 23:50:54 -04:00
Asteroth 2e4a657b57 more clean up and removing dead code 2022-04-18 18:05:46 -04:00
Asteroth 13a465825e swap tmap_num and nverts 2022-04-18 17:59:08 -04:00
Asteroth 943e5c395b first version of bsp space optimizations 2022-04-18 17:12:01 -04:00
John Fernandez c035f1341c Change type from int to const ubyte
This will remove the almost completely superfluous `if ( (type<0) || (type > MAX_TYPE_ID )) {` check by precluding it from ever happening.
2022-04-18 06:35:37 -04:00
John Fernandez 19ef658f56 Upgrade unknown packet type to mprintf
If we're not going to Assert that the packet type be known, at least always dump the unknown packet type to the log.
2022-04-18 06:35:37 -04:00
John Fernandez 34ba050242 Upgrade Cmdline_dump_packet_type to include length
Helps us by also dumping the amount of data that has been processed from that packet so far.

Also, dump how much data we need to get through to finish the packet correctly.
2022-04-18 06:35:37 -04:00
EatThePath f9b6bf56c9 Merge pull request #4176 from EatThePath/fso-go-brrr
Remove sound limit caps and raise max channels
2022-04-17 20:01:09 -05:00
Goober5000 4101d01e82 Merge pull request #4177 from Goober5000/fix_hud_gauge
various HUD gauge fixes
2022-04-17 19:47:09 -04:00
Goober5000 d785b9c141 tweak the function, per feedback 2022-04-17 18:38:33 -04:00
David Gibson bc2fca0469 Made allowances to not monopolize the reported max channels 2022-04-17 16:42:10 -05:00
Goober5000 681b2005ea various HUD gauge fixes
1) Fix part of the lookup logic in `hud_get_default_gauge_index`
2) Add back part of the lookup that was removed in #4003
3) Use custom checks with the `default_hud_gauges` list
4) Add a clarification comment to `default_hud_gauges`

Fixes #4171
2022-04-17 01:54:28 -04:00
JohnAFernandez a464e8615c Create commandline option for logging data packets (#4175)
* Basic logging of packet types

Add a commandline Parameter for loggin packet type

This is to help with debugging specific multi bugs.
2022-04-17 03:32:23 +00:00
David Gibson 32fe227f6d Removed the cap on enhanced sound +Limit: entirely. 2022-04-16 21:26:44 -05:00
David Gibson 1ecebe3ef3 Made the maximum number of channels used by openAL dynamic 2022-04-16 21:26:12 -05:00
David Gibson 20cea22a05 Decoupled max RTV voice channels from the enhanced sound limit. 2022-04-16 21:25:18 -05:00
Tyler Blount c7979129c7 Merge pull request #4163 from TRBlount/vertnorm_max_inc
Increase POF vertex limit
2022-04-16 10:57:18 -07:00
Tyler Blount 75cdc8efa2 Some extra feedback changes and documentation 2022-04-15 20:36:54 -07:00
Tyler Blount 10b1fa89cf Style and review changes 2022-04-15 15:38:55 -07:00
Tyler Blount a804d21764 Error reports for TMAP2 2022-04-14 20:03:17 -07:00
Goober5000 618804c1ff add optional flag to not change subtitle aspect ratio
Follow-up to #4158.  Allows use of the specified subtitle width and height in all cases, without stretching it to the screen's current aspect ratio.
2022-04-14 10:13:11 -04:00
Goober5000 bcc0d51040 Merge pull request #4158 from Goober5000/subtitle_screen_scale2
add the ability for subtitles to be scaled correctly to the screen
2022-04-14 10:11:56 -04:00
Tyler Blount 61a0973ad4 Clang tidy fix #3 2022-04-13 12:14:33 -07:00
Tyler Blount a387fdeb36 Another clang tidy fix 2022-04-13 12:00:51 -07:00
Tyler Blount e742920c93 Clang tidy fixes 2022-04-13 11:26:16 -07:00
Tyler Blount 2688e7cec5 More CI fixes 2022-04-13 11:26:16 -07:00
Tyler Blount 8066ac02cc Fix CI warnings 2022-04-13 11:26:16 -07:00
Tyler Blount 30e7747d6e More signed to unsigned conversions 2022-04-13 11:26:16 -07:00
Asteroth 38e02566c7 remove center and radius fields 2022-04-13 11:26:16 -07:00
Tyler Blount 60c39c698a Initial changes required to bump per-subobject vertex limit 2022-04-13 11:26:16 -07:00
EatThePath 4f562c73dc Merge pull request #4128 from EatThePath/Pseudo-InvSqrFalloff
Switched light shader attenuation math to something that looks more real
2022-04-12 22:41:59 -05:00
Tyler Blount 658860db57 Merge pull request #4167 from z64555/update-prebuilt01
Update PREBUILT_VERSION_NAME to latest (mac libs)
2022-04-12 18:38:41 -07:00
Adam Leach 2a7a93bbe4 Fix for #3629 (#4165)
* Zero init envmap name to prevent mistaken bm_load call, fix for #3629

* guards on envmap bm_load failure for lab renderer.
2022-04-12 21:35:06 -04:00
Goober5000 59528308a5 Merge pull request #4169 from Goober5000/subspace_sexp_preload
add preload ability for mission-set-subspace
2022-04-12 21:28:36 -04:00
Goober5000 c294d2b4ff add small optimization 2022-04-12 20:57:07 -04:00
Goober5000 0c7350dc23 add preload ability for mission-set-subspace
Page in the subspace stuff if the mission-set-subspace sexp is used.
2022-04-12 20:51:26 -04:00
z64555 ae8529e4c4 Update PREBUILT_VERSION_NAME to latest (mac libs) 2022-04-12 19:10:39 -05:00
Goober5000 00e2ef29f5 Merge pull request #4126 from z64555/actions/actions01
Fix auto-trigger for post-release build workflow, Checkout passed release tag, Fix version string
2022-04-12 12:26:24 -04:00
Goober5000 b6310539e7 Merge pull request #4162 from Goober5000/fix_subys_crash
prevent crashes in the event of a subsystem mismatch
2022-04-12 12:25:19 -04:00
Goober5000 0d982ecf52 prevent crashes in the event of a subsystem mismatch
Set the subsystem name pointers to nullptr so that we don't try to free random memory.  Also set the subsystem percentages to 0 for consistency.
2022-04-11 20:08:54 -04:00
Goober5000 fce754f899 Merge pull request #4160 from virusman/pr/mac-fix-unittests-compile
Change include order to fix compilation of unit tests on Mac
2022-04-11 19:58:00 -04:00
virusman 51b57bc2d8 Change include order to fix compilation of unit tests on Mac 2022-04-10 21:06:28 -07:00
Goober5000 06f3bb77d1 add the ability for subtitles to be scaled correctly to the screen
By specifying a base resolution in game_settings.tbl, subtitles can be scaled to the screen in the same way as HUD gauges.  This can be used to prevent subtitles from appearing smaller at larger resolutions.

Depends on and is a follow-up to #4157.
2022-04-10 23:41:45 -04:00
Goober5000 8f48c1e3e2 Merge pull request #4157 from Goober5000/subtitle_screen_scale
add game_settings.tbl option to specify subtitle coords in pixels
2022-04-10 23:40:27 -04:00
David Gibson 9ed3eb1f2e style fix 2022-04-10 22:12:42 -05:00
z64555 b85f688080 Remove auto-include 2022-04-10 21:20:43 -05:00
Goober5000 3c695af35c Merge pull request #4155 from Goober5000/insertion_sort_update
Insertion sort update
2022-04-10 15:15:50 -04:00
Goober5000 2c64cd946d update documentation 2022-04-10 14:20:06 -04:00
z64555 32a9cace6d Remove redundant import
* clean up documentation a bit
* use a more straightforward regex for slicing out page number
* use for loop instead of while loop
* Test workflow successes differently for release and nightly
* move tag_name definition up to before its used in validation block
* Add a hopefully more straightforward existance check for tag_name
2022-04-10 12:42:15 -05:00
Goober5000 56351c6fb9 Merge pull request #4156 from Goober5000/supernova_timestamp
upgrade supernova timestamps
2022-04-10 13:31:51 -04:00
Goober5000 f3a94d4fc8 add game_settings.tbl option to specify subtitle coords in pixels
What it says on the tin.  This allows more precise positioning of subtitles, and a future PR will add the ability to scale them according to screen resolution.
2022-04-09 20:43:42 -04:00
Asteroth 916a5653dd Merge pull request #4151 from Baezon/fix-cockpit-engine-sound
Fix cockpit engine sound volume changing unexpectedly
2022-04-09 19:45:27 -04:00
Goober5000 7cc47c8233 exclude windebug from clang 2022-04-09 14:08:22 -04:00
Goober5000 06e560ae76 use move assignment when possible 2022-04-09 14:07:56 -04:00
Goober5000 4933906d18 upgrade supernova timestamps
This adds a type-safe TIMESTAMP, similar to UI_TIMESTAMP.  Eventually all of the FSO codebase will be switched over to this new type.  In the meantime, just the supernova code is switched over.
2022-04-09 13:23:03 -04:00
Goober5000 b15c00b012 Merge pull request #4153 from Goober5000/supernova_refactor
refactor supernova code
2022-04-09 13:07:14 -04:00
Joshua Glatt e0d89e41ba Add SEXP constants for containers (#4146) 2022-04-08 22:07:14 -07:00
Goober5000 2ff2aa46e4 turns out j cannot be size_t after all 2022-04-09 00:03:19 -04:00
Goober5000 0e07b07aa5 lazily copy elements of the array 2022-04-08 23:42:20 -04:00
Goober5000 dc458964c1 turn insertion_sort into a templated function that uses assignment, so that it can be used with non-POD types 2022-04-08 23:15:49 -04:00
Goober5000 256f3a46a2 fix a potential overflow due to a cast by changing the type to size_t, plus other tweaks 2022-04-08 22:34:55 -04:00
Goober5000 8fa332b869 refactor supernova code
A bit of cleanup, refactoring, and bugfixing...

1) The supernova code now uses enums to represent states, and those state transitions now all happen in `supernova_process` instead of being scattered around.
2) Some state transition bugs were fixed - e.g. the HUD is now disabled when the camera cuts to the external view, instead of when the camera stops moving; and the particles start and the simulation stops when the comments say they do.
3) There is now a game_settings.tbl flag to make the HUD countdown timer reach zero when the supernova hits, instead of reaching 5s.  This only affects the HUD display; actual timing is not changed.
4) Don't apply lightshafts if the supernova glare is in effect - partial fix for #4152.
2022-04-08 22:02:34 -04:00
Goober5000 93eeab4f67 Merge pull request #4150 from Goober5000/4078_followup
add an additional check to the convert-to-Command logic
2022-04-08 13:10:12 -04:00
Asteroth e37574d6d5 fix engine sound level at sip->max_speed 2022-04-07 22:59:41 -04:00
Goober5000 a2558bec5f add an additional check to the convert-to-Command logic
The FS1 behavior for converting wingmen messages to Command messages specifically applies to in-mission messages with multiple files corresponding to the possible senders.  There is no situation where a built-in message needs to be converted, and in fact built-in messages can't usually be substituted because most built-in messages are distinct.  This commit adds an extra check for that case.  It has the effect of "fixing" #4149 even though that isn't really a bug.
2022-04-07 00:50:47 -04:00
Goober5000 284ba488f3 Merge pull request #4111 from Goober5000/fred_object_orientation
Fred object orientation features
2022-04-06 15:04:40 -04:00
Goober5000 a159eba0ce Merge pull request #4147 from Goober5000/fix_show_subtitle
fix show-subtitle again
2022-04-06 08:33:29 -04:00
Goober5000 69e9d26c71 fix show-subtitle again
When the RGB values of the legacy `show-subtitle` were fixed (#2578) the `width` argument was inadvertently deleted, resulting in an off-by-one error for all subsequent arguments.  This fixes that.
2022-04-06 00:44:58 -04:00
Goober5000 7aaca0a84a Merge pull request #4127 from Goober5000/spooled_music_vector
vectorize Soundtracks and Spooled_music
2022-04-05 14:21:18 -04:00
JohnAFernandez d3a6d9c719 Check for valid index before accessing Weapon_info (#4145)
Use a default value if we cannot directly access it.
2022-04-05 12:49:22 -04:00
EatThePath c20ae7cd6b $AI ignores aspect lock for leading: AIP flag implemented (#4141) 2022-04-05 07:43:28 -04:00
Goober5000 ccff68164a Merge pull request #4143 from Goober5000/remove_daisy_chained_mission_flag
remove daisy-chained mission flag
2022-04-04 21:39:02 -04:00
Goober5000 0d12b0554c remove daisy-chained mission flag
This flag is not the sort of thing that should depend on the FREDder, and in any case it probably isn't needed.  So this removes it.
2022-04-04 16:03:36 -04:00
Goober5000 9e26d4a664 Merge pull request #4093 from Goober5000/player_load_hook
add player loaded hook
2022-04-04 15:58:47 -04:00
Goober5000 1b9a02ff5f Merge pull request #4101 from Goober5000/same_warp_when_docked
add flags to keep same warp effects when docked
2022-04-04 14:24:19 -04:00
Goober5000 493c9e004f add flags to keep same warp effects when docked
Same arrival warp when docked, same departure warp when docked, and associated changes to FRED, set-arrival-info, and set-departure-info.

Also fixes the nav-carry flag to properly save when a mission is saved.  Previously that flag would always be cleared.

Implements feature from #4095.
2022-04-04 12:31:03 -04:00
EatThePath 857c643253 collide_remove_weapons is too expensive. Removed it from weapon_create, instead simply don't create shots when at weapon limit. (#4134) 2022-04-04 20:49:37 +09:00
The Force 552a8ff32b Feature/texture replacement dialog (#4050)
* Files and Ui

* Finish Texture replacement editor

* Fix oversight

* Actually Save Submaps

* Appease gcc


More appeasing 


Finish error checking


Remove accidental shadowing


Appease gcc


appease clang


clang

* Really Windows?

* Enable multiedit if ship class same

* Address Error message Feedback

* Work around gcc
2022-04-04 07:38:51 -04:00
Goober5000 798eecdadf Merge pull request #4139 from BMagnu/anim_techroom
Fix techroom turret lookup and make animations more robust
2022-04-03 23:46:46 -04:00
BMagnu e2504bd162 Add 'pause on reverse' animation flag (#4084) 2022-04-04 10:39:02 +09:00
EatThePath e577e8db81 lua ship.checkVisibility mimicing sexp ship-is-visible (#4132)
* Implemented ship.checkVisibility for luaAPI, sharing logic with sexp isVisible. Made new function for the shared functionality

* Fixed a viewer-viewed mixup
2022-04-04 10:38:56 +09:00
Birk Magnussen abfa4b8fb5 Make Animations more Robust and fix techroom turret lookup 2022-04-04 10:36:26 +09:00
wookieejedi 063d7afcfe Fix destroyed submodels showing in techroom (#4138)
The check to not show `-destroyed` submodels is within `model_replicate_submodel_instance`, and that was only called for moveable submodels in the lab. This PR runs it for all submodels now. Tested and fix works as expected.
2022-04-04 09:32:07 +09:00
Goober5000 5ac80c26aa Merge pull request #4121 from Goober5000/make_target_distance_consistent
make HUD target distance consistent
2022-04-03 14:41:03 -04:00
Goober5000 4d33ed6c92 make HUD target distance consistent
Several careful tweaks to improve handling of distance as measured on the HUD.

1) Use `Player_ai->current_target_distance` for rendered HUD gauges which display the distance, because the distance is calculated in `hud_update_frame` (which is called from `game_simulation_frame`) and is used for a couple of these gauges already.  This change makes it all consistent.
1b) Some gauges which depend on distance but do not actually display it (e.g. the lead indicator) still calculate their distance immediately before using it.  I didn't change these because a) the calculation is still correct, even if redundant, and b) there is a small possibility of `hud_update_frame` changing the target after the distance is calculated, so these gauges are guaranteed to have the correct calculation.

2) On discovering that the `evaluate_ship_as_closest_target` specifically switched from bbox-distance to center-distance, I changed all "target closest X" functions to consistently evaluate center-distance.  I believe Volition did this to prioritize small fighters when dogfighting next to large ships.

3) Moved `hud_target_change_check` below the computation of `Player_ai->current_target_distance` because it uses the computed distance to determine the acceleration trend.  This way it will use the distance of the current frame, not the previous one.

4) Minor move of a `Target_static_looping` check into `hud_target_change_check` because it made sense.
2022-04-03 13:46:44 -04:00
Goober5000 7153f6b12e Merge pull request #4090 from Goober5000/nebula_background_ui
FRED Nebula background UI enhancements
2022-04-03 13:07:59 -04:00
Goober5000 a8ab80be21 Merge pull request #4135 from Goober5000/border_for_colored_events
address highlighting for events with background colors
2022-04-03 12:55:19 -04:00
Goober5000 68c8cdec1e Merge pull request #4136 from Goober5000/bastion_update
follow-up to 4074
2022-04-03 12:36:07 -04:00
Goober5000 10bfc687d9 m!m's fix 2022-04-03 12:34:54 -04:00
Goober5000 87eb2945f2 follow-up to 4074: elaborate the most common error message 2022-04-03 02:07:55 -04:00
z64555 de31fc4dc9 Create new GithubAPI class
* Add thread_url to forum.py for create_release()
2022-04-02 23:16:24 -05:00
Goober5000 47d5582a31 address highlighting for events with background colors
Events with background colors had their highlighting behavior disabled, because since an event has to be selected to add a color, users thought the color adding didn't work.  However it was pointed out in #4129 that users still would like to know which event is selected.  So this PR attempts to solve the problem by drawing a border over a selected event if that event has a background color.
2022-04-03 00:14:31 -04:00
z64555 8a410957ff Remove unused upload_url artifact
* Move doxy of upload-artifact
* Remove printing out secrets of HLP API and key (its censored, anyway)
2022-04-02 21:35:09 -05:00
Goober5000 e3c872b621 add player loaded hook
This hook will be called whenever a player is successfully loaded.
2022-04-02 18:45:46 -04:00
EatThePath db0598720d Add delay into ai_new_maybe_reposition_attack_subsys for performance reasons (#4087) 2022-04-02 14:04:08 -04:00
Goober5000 8062b67442 Merge pull request #4117 from Goober5000/fred_dynamic_iffs
dynamic IFF list in the ship select editor
2022-04-02 14:01:07 -04:00
Goober5000 636b4e81df Merge pull request #3960 from Goober5000/scripted_decals
add scripting support for decals
2022-04-02 13:57:40 -04:00
Goober5000 da02709fb0 Merge pull request #4118 from Goober5000/volition_list_range
add a class encapsulation for Volition's linked list
2022-04-02 13:57:27 -04:00
David Gibson ceb202e336 Switched light shader attenuation math to something that looks more real 2022-04-02 10:03:55 -05:00
Goober5000 3acf2d69b0 vectorize Soundtracks and Spooled_music
This removes the limits on soundtracks and menu music.  Some design tweaks are thrown in as well.
2022-04-02 00:52:43 -04:00
Goober5000 3863c8fd14 Merge pull request #4085 from Goober5000/campaign_start_hook
add campaign start hook
2022-04-01 23:59:08 -04:00
Goober5000 a75ad7573e Merge pull request #4096 from Goober5000/lua_sexp_help_updates
enhance help text for Lua sexps
2022-04-01 23:58:55 -04:00
Goober5000 dfeefad3f9 Merge pull request #4056 from Goober5000/nav_color
add capability (plus sexps) to set navpoint color
2022-04-01 23:31:08 -04:00
Goober5000 5e8c5934ed Merge pull request #4062 from Goober5000/weapon_list_iter
add missile list iterator
2022-04-01 23:31:00 -04:00
Goober5000 5324d90425 Merge pull request #4123 from Goober5000/fix_4122
Make sure that zero-length strings still get the proper height;  fixes missing whitespace in the credits
2022-04-01 23:28:17 -04:00
Goober5000 3d983207f2 bump version to 22.1.x (#4124) 2022-04-01 22:13:27 -05:00
Goober5000 67a2732c69 Merge pull request #4125 from Goober5000/22_0_changelog
21.0-22.0 changelog
2022-04-01 23:11:18 -04:00
z64555 a91833e13a Add asarium and z64555 as code owners to ci/ 2022-04-01 22:10:28 -05:00
Goober5000 363b5743eb more details 2022-04-01 22:40:24 -04:00
Goober5000 ddb69482cf changelog 2022-04-01 22:30:09 -04:00
z64555 81e86e6173 Maybe fix auto-trigger
* Move validation to before execution
* More debug messages
2022-04-01 21:27:55 -05:00
z64555 8513783049 Get version string from version_override.cmake and
version.cmake
2022-04-01 21:27:54 -05:00
z64555 3b7427c898 Checkout the given release tag, instead of HEAD 2022-04-01 21:27:54 -05:00
z64555 184bb632f6 Don't use version.cmake for versioning ID
* Use tag_name for versioning
2022-04-01 21:27:53 -05:00
z64555 ecf90fe3fe Use different changelog formatting 2022-04-01 21:27:53 -05:00
z64555 7cde6a8805 Fix bug exiting loop 2022-04-01 21:27:53 -05:00
z64555 de3d8779e8 Add python script to extract the PR titles from github for use as a human-readable changelog 2022-04-01 21:27:53 -05:00
z64555 bffd3750f8 Add POST_SIZE_MAX attribute
* Doxy ForumAPI methods
2022-04-01 21:27:52 -05:00
Goober5000 534c1f2c33 fix 4122
Make sure that zero-length strings still get the proper height.

Fixes #4122.  Follow-up to #4071.
2022-04-01 18:32:07 -04:00
Tyler Blount 1d3e62f007 Bump FSO version to 22.0 2022-04-01 14:18:23 -07:00
Goober5000 4b0c366328 fix 2022-03-31 15:21:31 -04:00
Goober5000 e362105261 tweak things and add const_iterator 2022-03-30 13:37:22 -04:00
Goober5000 8ac7853dee add a class encapsulation for Volition's linked list
This should allow collections which use the Volition linked list (for example `obj_used_list`) to be iterated using range-based `for` loops.
2022-03-29 23:39:57 -04:00
Goober5000 2232ec228f dynamic IFF list in the ship select editor
Allow all IFFs to be listed, even when the number exceeds 10.  Follow-up to #4116.  Related to #4090 as it uses the same multi-selection method.
2022-03-29 22:08:05 -04:00
Goober5000 132818ff86 Merge pull request #4116 from Goober5000/fix_4115
prevent the ship select dialog from crashing if there are too many IFFs
2022-03-29 19:20:50 -04:00
Goober5000 963e06e390 prevent the ship select dialog from crashing if there are too many IFFs 2022-03-29 13:24:54 -04:00
m!m d24175a393 Merge pull request #4110 from freijon/master
Don't ignore user-set LDFLAGS
2022-03-28 21:25:39 +02:00
Jonas Frei 10b68c17d2 Copy user-set LDFLAGS for clang toolchain 2022-03-28 20:50:21 +02:00
Goober5000 70d553a663 fix the formula 2022-03-28 02:17:07 -04:00
Goober5000 3c583e53f2 add flag to point ships while incorporating the ship's uvec 2022-03-28 01:56:48 -04:00
Goober5000 d195c1333c add CalcRelativeCoords dlg 2022-03-28 01:31:35 -04:00
Goober5000 77f96638d7 add independent vs relative option to the orientation editor 2022-03-28 01:11:43 -04:00
Jonas Frei 79cff94a88 Don't ignore user-set LDFLAGS 2022-03-28 06:52:17 +02:00
wookieejedi 12d391a7a5 Fix LUA Steering Control Override (#4104)
* Fix LUA Steering Control Override

I've been using `LUA_FULL_CONTROLS` in the updated mouse-as-a-joystick script, and it works well, but there's one last small bug I'd like to fix. `LUA_FULL_CONTROLS` affects things that beyond just steering values, which has the unfortunate side-effect of also overriding non-steering controls such as cruise percent. It would be less intrusive to use the `LUA_STEERING_CONTROLS`. Unfortunately, `LUA_STEERING_CONTROLS` just sets everything to 0, which I think is a code issue bug that has been around since the lua controls were added in 2010 (https://github.com/scp-fs2open/fs2open.github.com/commit/2a69aaa23ba0def3dbfb9f566706e7130a33866f).

This PR fixes usage of `LUA_STEERING_CONTROLS`, and in testing everything works as expected (including fixing the cruise percent issue). Also, I do not think there are any scripts that use `LUA_STEERING_CONTROLS`, but if desired I can make a new version called `LUA_STEERING_CONTROLS_FIXED` or something to that effect.

* correct order of if-check
2022-03-27 16:00:44 -04:00
Goober5000 3cb66670d0 Merge pull request #4107 from Goober5000/remove_parent_type
remove Object.parent_type
2022-03-27 15:22:01 -04:00
Goober5000 63445dec5a remove Object.parent_type
It's theoretically possible for `parent_type` to get out of sync with the parent's type, particularly if the parent is destroyed.  Since the field is almost never used, it can be removed.

Should fix #4105.
2022-03-27 12:38:48 -04:00
Goober5000 e84fc4fcd8 enhance help text for Lua sexps
Two enhancements:
1) Allow the SEXP help description to take up multiple lines.  Since the parser did not originally use `stuff_string` with `F_MULTITEXT`, this required some creative parsing.
2) Generate the text for minimum and maximum number of arguments.
2022-03-25 02:09:10 -04:00
Goober5000 d92e8f4155 add nebula fog color override, plus missionsave support which wasn't implemented before 2022-03-22 10:27:22 -04:00
Goober5000 475e3eb95e add ui for nebula fog color and nebula poofs, plus implement poof list 2022-03-20 19:33:37 -04:00
Goober5000 375ae25ac9 add campaign start hook
This hook will be called when a campaign is started for the first time (whether in Player Select or in the campaign room), or is reset.
2022-03-20 14:48:32 -04:00
Goober5000 a047be61d5 add capability (plus sexps) to set navpoint color
This is useful because certain backgrounds (such as a nebula) will make it hard to see the default navpoint color.  Also this means that different navpoints can now have different colors.
2022-03-07 03:32:50 -05:00
Goober5000 79c096a488 add missile list iterator
Add mn.getMissileList(), similar to mn.getShipList().  See also #3660.
2022-03-07 03:27:11 -05:00
Goober5000 18a8e280dc add scripting support for decals
This extends the existing decal system so that decals can be created through scripting.
2022-03-01 19:07:39 -05:00
Joshua Glatt d129bcb6b7 revert unrelated but necessary fix 2022-02-11 23:51:18 -08:00
Joshua Glatt 2403cd7c44 add Replace Data for Number/String 2022-02-11 23:18:03 -08:00
407 changed files with 25203 additions and 10171 deletions

No files matched your search

+2
View File
@@ -1,6 +1,8 @@
cmake/ @asarium
ci/ @asarium @z64555
code/executor/ @asarium
code/scpui/ @asarium
+94 -1
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -210,3 +210,96 @@ jobs:
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
build_mac:
strategy:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64]
name: Mac
runs-on: macos-latest
steps:
- name: Cache Qt
id: cache-qt-mac
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Set up test version
shell: bash
run: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"]
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Package build result
working-directory: ./build
run: cd bin && tar -cvzf macos-build.tar *.app
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
mac_zip:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
steps:
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v2
with:
name: mac-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: mac-FastDebug
path: builds
- name: Create Distribution package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
- name: Upload result package
working-directory: ./builds
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh nightly
+12 -45
View File
@@ -34,23 +34,6 @@ jobs:
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
- name: Store upload URL
run: |
echo -n "${{ steps.create_release.outputs.upload_url }}" > upload_url
- name: Persist upload URL
uses: actions/upload-artifact@v2
# Upload the url file for use with other runners
# upload-artifact.inputs:
# if-no-files-found=warn What to do if path fails to find any files.
# warn Display a warning but do not fail the action
# error Display an error and fail the action
# ignore No display, No fail
# retention-days=0 Days to keep the artifact.
# 0 Use default retention policy of the repo
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
with:
name: upload_url # name of artifact
path: ${{ github.workspace }}/upload_url # source location of artifact to upload
build_linux:
strategy:
@@ -61,7 +44,7 @@ jobs:
name: Linux
needs: create_release # Don't run this job until create_release is done and successful
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -134,6 +117,15 @@ jobs:
run: $GITHUB_WORKSPACE/ci/linux/generate_appimage.sh $GITHUB_WORKSPACE/build/install
- name: Upload build result
uses: actions/upload-artifact@v2
# Upload the url file for use with other runners
# upload-artifact.inputs:
# if-no-files-found=warn What to do if path fails to find any files.
# warn Display a warning but do not fail the action
# error Display an error and fail the action
# ignore No display, No fail
# retention-days=0 Days to keep the artifact.
# 0 Use default retention policy of the repo
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
with:
name: linux-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/install/*.AppImage
@@ -148,21 +140,6 @@ jobs:
with:
submodules: true
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
- name: Download upload URL
uses: actions/download-artifact@v1
# Downloads and extracts uploaded artifact by name
# github_token default ${{secrets.GITHUB_TOKEN}}
# name name of artifact to download
# latest Download latest artifact (default true)
# path Where to save the artifact, (default extract_here)
# repo Source repo of artifact (default ${{github.repository}})
with:
name: upload_url
path: .
- name: Extract upload URL
# Extract the URL from file and stuff it into a shell variable
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- name: Download Release builds
# Grab the release builds
uses: actions/download-artifact@v2
@@ -291,16 +268,6 @@ jobs:
submodules: true
fetch-depth: '0'
- name: Download upload URL
uses: actions/download-artifact@v1
with:
name: upload_url
path: .
- name: Extract upload URL
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- name: Download Release builds
uses: actions/download-artifact@v2
with:
@@ -348,6 +315,6 @@ jobs:
needs: [linux_zip, windows_zip]
uses: ./.github/workflows/post-build-release.yaml
with:
linux_result: ${{ needs.build_linux.result }}
windows_result: ${{ needs.build_windows.result }}
linux_result: ${{ needs.linux_zip.result }}
windows_result: ${{ needs.windows_zip.result }}
releaseTag: ${{ github.ref_name }}
+93 -1
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -224,3 +224,95 @@ jobs:
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
build_mac:
strategy:
matrix:
configuration: [FastDebug, Release]
compiler: [clang]
arch: [x86_64]
name: Mac
runs-on: macos-latest
steps:
- name: Cache Qt
id: cache-qt-mac
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: Set up test version
shell: bash
run: |
[[ "${{ github.ref }}" =~ ^refs\/heads\/test\/(.*)$ ]]
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR ${BASH_REMATCH[1]})" > "version_override.cmake"
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Package build result
working-directory: ./build
run: cd bin && tar -cvzf macos-build.tar *.app
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
mac_zip:
name: Build Mac distribution zip
needs: build_mac
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
steps:
- uses: actions/checkout@v2
name: Checkout
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v2
with:
name: mac-Release
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: mac-FastDebug
path: builds
- name: Create Distribution package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
- name: Upload result package
working-directory: ./builds
env:
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
DATACORDER_USER: ${{ secrets.DATACORDER_USER }}
DATACORDER_SSHPASS: ${{ secrets.DATACORDER_PASSWORD }}
run: $GITHUB_WORKSPACE/ci/linux/upload_dist_package.sh test
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
- name: Cache Qt
id: cache-qt-lin
+12 -7
View File
@@ -6,10 +6,10 @@ on:
inputs:
linux_result: # job.result; either success, failure, canceled or skipped
required: true
type: boolean
type: string
windows_result: # job.result
required: true
type: boolean
type: string
releaseTag:
required: true
type: string
@@ -30,26 +30,31 @@ env:
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
RELEASE_TAG: ${{ github.event.inputs.releaseTag }}
RELEASE_TAG: ${{ inputs.releaseTag }}
jobs:
post_builds:
name: Post builds on Nebula and the forums
runs-on: ubuntu-latest
steps:
- name: Caller
# Name of what called this yaml. Used to debug auto/manual step being triggered
run: echo "github.event_name= ${{ github.event_name }}"
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: '0'
ref: ${{ env.RELEASE_TAG }}
- name: Install Python dependencies
run: pip install -r ci/post/requirements.txt
- name: Post Builds (Auto trigger)
if: ${{ github.event_name == 'workflow_call' }}
if: ${{ (github.event_name == 'workflow_call') || (github.event_name == 'push') }}
env:
LINUX_RESULT: ${{ github.event.inputs.linux_result }}
WINDOWS_RESULT: ${{ github.event.inputs.windows_result }}
LINUX_RESULT: ${{ inputs.linux_result }}
WINDOWS_RESULT: ${{ inputs.windows_result }}
run: python ci/post/main.py release
- name: Post Builds (Manual trigger)
@@ -59,6 +64,6 @@ jobs:
LINUX_RESULT: success
WINDOWS_RESULT: success
run: |
echo "releaseTag= ${{ github.event.inputs.releaseTag }}"
echo "releaseTag= ${{ env.RELEASE_TAG }}"
echo "repository= ${{ github.repository }}"
python ci/post/main.py release
+62 -1
View File
@@ -22,7 +22,7 @@ jobs:
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -156,3 +156,64 @@ jobs:
else
"./bin/$CONFIGURATION/unittests" --gtest_shuffle
fi
build_mac:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [clang]
arch: [x86_64]
cmake_options: [""]
name: Mac
runs-on: macos-latest
steps:
- name: Cache Qt
id: cache-qt-mac
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-mac.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
ARCHITECTURE: ${{ matrix.arch }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja all
- name: Run Tests
working-directory: ./build
env:
CONFIGURATION: ${{ matrix.configuration }}
XDG_RUNTIME_DIR: /root
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
- name: Run Clang Tidy
# Clang-tidy reuses the precompiled headers so this only makes sense for the clang compilers
if: startsWith(matrix.compiler, 'clang-')
run: $GITHUB_WORKSPACE/ci/linux/clang_tidy.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
- name: Process clang-tidy warnings
if: startsWith(matrix.compiler, 'clang-')
uses: asarium/clang-tidy-action@v1
with:
fixesFile: clang-fixes.yaml
+2 -1
View File
@@ -43,7 +43,8 @@ PROJECT(FS2_Open)
find_program(CCACHE_PROGRAM ccache)
# Currently only GCC support ccache properly without generating additional warnings
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Enable ccache on Mac even for clang
if(CCACHE_PROGRAM AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR APPLE))
if(NOT CMAKE_C_COMPILER_LAUNCHER)
message(STATUS "Using ccache for C compilation: ${CCACHE_PROGRAM}")
SET(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM})
+51
View File
@@ -3,6 +3,52 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [22.0.0] - 2022-04-01 ([Thread](https://www.hard-light.net/forums/index.php?topic=98125.0))
### Changed
- Controls5 PR (aka multi-joy)
- Timing system upgrade
- Model animation code upgrades
## [21.4.0] - 2021-09-27 ([Thread](https://www.hard-light.net/forums/index.php?topic=97802.0))
### Changed
- Multiple features; see thread
- Multiple bugfixes; see thread
### Deprecations
- `script-eval` has been deprecated in favor of `script-eval-block`
- renamed `hud-set-retail-gauge-active` to `hud-set-builtin-gauge-active`
## [21.2.0] - 2021-05-02 ([Thread](https://www.hard-light.net/forums/index.php?topic=97561.0))
### Changed
- Added a dynamic action system for more modder control of effects
- Removed fireball limit
- Fixed bomb intercept in multiplayer
- Changed nebula fog distance from a linear to exponential model
- Turrets on moving subobjects enabled
- LZ4 Compression added for game files
## [21.0.0] - 2021-01-27 ([Thread](https://www.hard-light.net/forums/index.php?topic=97293.0))
### Changed
- More OpenGL optimizations
- Full type information output for Lua documentation. Very useful for writing Lua scripts.
- A new -weaponspew command-line option for printing MediaVP-style statistics, plus a weapon comparison spreadsheet, to the debug log.
- Improved ship lookup behavior in SEXPs for improved performance.
- BPTC/BC7 texture compression support
- Refactoring and new features for the ship lab.
- Missile multi-lock. It's finally in an official build!
- Enhancements to the model code in preparation for cool features in 21.2.
- IPv6 support for multiplayer
- A lot of general fixes for multiplayer.
### Deprecated
- Dropped support for Windows XP
- Scripting:
- `ba.getFrametime()`: The parameter value was used incorrectly inside the implementation. To avoid breaking existing scripts and to improve readability this has been split into `ba.getMissionFrametime()` and `ba.getRealFrametime()`.
- `gr.drawMonochromeImage()`: `gr.drawImage()` got a new parameter for drawing monochrome images and is more flexible in general so the monochrome variant is no longer needed.
## [19.0.0] - 2020-01-25 ([Thread](https://www.hard-light.net/forums/index.php?topic=96226.0))
### Meta
- With this release we decided to drop the "`3.Major_revision.Minor_revision`" versioning scheme in favor of a year based scheme since the Major and Minor versions did not have much meaning anymore. Instead the scheme will now be "`<year>.<number that is incremented every release>.0`". The last 0 is still there because some of our systems expect that. It will be gone at some point.
@@ -25,6 +71,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
- Refactored bitmap slot handling and removed the fixed upper limit on the number of bitmaps. No more bmpman corruption!
## [3.8.0] - 2017-08-22 ([Release Thread](https://www.hard-light.net/forums/index.php?topic=93812.0))
### Added
- Support for APNG animations: [APNG](https://en.wikipedia.org/wiki/APNG) is a variant of the established PNG format which allows to store animations instead of single frames in a PNG file. This change allows to use these animation files in FSO which significantly improves usability for modders since they no longer have to store all individual frames as separate images.
@@ -49,6 +96,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
- "Tons" of bugfixes
## [3.7.2] - 2015-04-23 ([Release thread](http://www.hard-light.net/forums/index.php?topic=89597.0))
### Added
- MediaVPS 2014 Support
@@ -79,16 +127,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Raised the per-model debris limit to 48 (previously 32).
- Increased the per-frame debris limit to 96 (previously 64)
## [3.6.18] - 2013-03-01 ([Release thread](http://www.hard-light.net/forums/index.php?topic=83889.0))
### Fixed
- Critical damage bug which caused heavy balance issues in the game
## [3.6.16] - 2013-01-31 ([Release thread](http://www.hard-light.net/forums/index.php?topic=83577.0))
### Added
- Diaspora TC support
### Changed
- Performance Improvements
## [3.6.14] - 2012-10-23 - ([Release thread](https://www.hard-light.net/forums/index.php?topic=82648.0))
### Added
- Objecttype tables support for deciding how enemies respond to ship classes when disabled
+1 -1
View File
@@ -19,5 +19,5 @@ BASE_COMMIT=$(git merge-base $1 $2)
echo "Running clang-tidy on changed files"
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
-regex '(code(?!\/graphics\/shaders\/compiled)|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
+15 -4
View File
@@ -15,8 +15,16 @@ if [ "$COMPILER" = "clang-9" ]; then
fi
LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
if [ "$RUNNER_OS" = "macOS" ]; then
CXXFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
CFLAGS="-mtune=generic -pipe -Wno-unknown-pragmas"
PLATFORM_CMAKE_OPTIONS=""
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
else
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
fi
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
@@ -30,7 +38,10 @@ export CXXFLAGS
export CFLAGS
export LD_LIBRARY_PATH
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS \
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_BUILD_APPIMAGE=ON -DCMAKE_BUILD_TYPE=$CONFIGURATION \
if [ "$RUNNER_OS" = "macOS" ]; then
brew install ninja
fi
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS $PLATFORM_CMAKE_OPTIONS \
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DCMAKE_BUILD_TYPE=$CONFIGURATION \
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON \
-DSHADERS_ENABLE_COMPILATION=ON ..
+6
View File
@@ -25,6 +25,12 @@ elif [ "$OS" = "Windows" ]; then
echo "::set-output name=debug_path::$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z"
echo "::set-output name=debug_name::$(get_package_name)-debug-$ARCH-$SIMD.7z"
echo "::set-output name=debug_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")"
elif [ "$OS" = "Mac" ]; then
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *
echo "::set-output name=package_path::$(pwd)/$(get_package_name)-builds-Mac.tar.gz"
echo "::set-output name=package_name::$(get_package_name)-builds-Mac.tar.gz"
echo "::set-output name=package_mime::$(file -b --mime-type "$(pwd)/$(get_package_name)-builds-Mac.tar.gz")"
else
echo "Invalid OS: $OS"
fi
+1 -1
View File
@@ -5,7 +5,7 @@ HERE=$(dirname "$SCRIPT")
export LD_LIBRARY_PATH=$(pwd)/bin/lib:$LD_LIBRARY_PATH
if [ "$CONFIGURATION" = "Debug" ]; then
if [ "$CONFIGURATION" = "Debug"] && [[ "$RUNNER_OS" != "macOS" ]] ; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$HERE/valgrind.supp" ./bin/unittests --gtest_shuffle
else
+169
View File
@@ -0,0 +1,169 @@
# Retrives a log of commit messages and attempts to pretty them into a human-readbile format
import argparse
import os
import re
import requests
import sys
from datetime import datetime
from subprocess import check_output
MAX_PAGES = 100 # maximum number of PR pages to go through
warnings = 0
def get_last_page(response: requests.Response) -> int:
"""
@brief Extract the last page number from the response header
@param[in] response The response from a GET call
@returns The page number of the last page, or MAX_PAGES
"""
# The link header is a dictionary in string form, and for that matter the
# value is in front of the key. It is of the form '<<url1>>; rel=<key1>, <url2>, <key2>'
link = response.headers['link']
link = link.split(',')
for x in link:
y = x.split(';') # <url>; rel=<key>
if "last" not in y[1]: # look for rel='last'
continue
# grab the page number from the URL
# group(0) is `page=123`, group(1) is `123`
last_page = int( re.search(r'page=(\d+)', y[0]).group(1) )
if not last_page:
print("Error: Could not find page number in url! URL: %s", y[0])
sys.exit(1)
if last_page > MAX_PAGES:
return MAX_PAGES
else:
return last_page
def main():
parser = argparse.ArgumentParser(description="Retrieves a log of commit messages and attempts to pretty them into a human-readable format")
parser.add_argument("start_date",
help="Day of the earliest commit to add to the log.")
parser.add_argument("-u", "--user", nargs=2, metavar=("NAME", "TOKEN"), default=["", ""],
help="Github username and token/password")
args = parser.parse_args()
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
start_date = datetime.strptime(args.start_date, "%Y-%m-%d")
print("start_date: {}".format(start_date))
# Retrive the git log for master, since start date, order by date, in ascending order, use YYYY-MM-DD date format,
# each line is of the form "<author short date> | <message>", only grab commits from master,
# output to `fsofordigest.txt`,
# check_output(("git log master", "--after=2021-09-15", "--date-order", "--reverse", "--date=short",
# "--pretty=\"%as | %s\"", "--first-parent",
# "--output fsofordigest.txt"), text=True)
# The commit messages are either of the form "<body> (#<PR_number>)" or "Merge pull request #<PR_number> from <source_repo>"
# For our purposes, we want them be all of the form "<body> (#<PR_number>)"
# Typically, the second form does not have a usable body, so we'll have to pull the PR title from github
# Github's REST API allows us to retrieve PR's, but due to it being HTTP requests it has to page in the data.
# We can loop over the GET request and check for a merge date.
# The GET request doesn't have sorting by merge date, but does have sorting by the last time it was updated... which is usually
# also the merge date but not always.
# Key attributes within the PR JSON objects:
# "merged_at: <date>" # Date the PR was merged in
# "merged: <bool>" # If the PR was merged yet
# "html_url: <string>" # URL of the PR's HEAD commit, used by some clients to pull in the PR branch
# "number: <int>" # The PR id number
# "title: <string>" # Title of the PR
# "body: <string>" # The body paragraph detailing the PR
# "labels: [label_object]" # All labels attached to this PR
changelog = {}
url = "https://api.github.com/repos/scp-fs2open/fs2open.github.com/pulls"
page = 1
last_page = MAX_PAGES
while page <= last_page:
# GET <url>?base=master&sort=updated&direction=desc&state=closed&page=1
response = requests.get(url,
auth=(args.user[0], args.user[1]),
params={
"base": "master",
"direction": "desc",
"page": page,
"state": "closed",
"sort": "updated"
})
# Check if good response
if (response.status_code != 200) :
print("Error: ", response.status_code)
print(response.json()['message'])
sys.exit(1)
else:
print("Request successful: 200")
print("page={}".format(page))
# Update the last_page index at first iteration and possibly last iteration
# This should cover the edge case of a new PR being added to the database before this script is finished
if (page == 1) or (page == last_page):
last_page = get_last_page(response)
print("last_page={}".format(last_page))
# assume pulls are organized from newest to oldest
for pull in response.json():
if (pull['state'] != 'closed'):
# This pull is not merged, so ignore
print("Found irrelevant pull, skipping...")
print("state: {}; number: {}".format(pull['state'], pull['number']))
continue
if (pull['merged_at'] == None):
# This pull wasn't merged, skip
print("Found closed pull #{} ({}), skipping...".format(pull['number'], pull['closed_at']))
continue
merge_date = datetime.strptime(pull['merged_at'], "%Y-%m-%dT%H:%M:%SZ")
updated_date = datetime.strptime(pull['updated_at'], "%Y-%m-%dT%H:%M:%SZ")
if (merge_date < start_date) and (updated_date >= start_date):
# This pull is too old, but was updated within our timeframe. skip
print("Found old pull #{} ({}), skipping...".format(pull['number'], pull['merged_at']))
continue
if (updated_date < start_date):
# This pull is too old
print("Found old pull #{} ({}), stopping loop...".format(pull['number'], pull['updated_at']))
page = last_page + 1
break
# Add the pull to the changelog, indexed by its pull.number
if pull['number'] not in changelog:
# only add if the key isn't there already
changelog[pull['number']] = {
"date": merge_date,
"title": pull['title'],
"labels": pull['labels'],
"url": pull['html_url']
}
print("Added pull #{} ({})".format(pull['number'], merge_date))
# Else, silently ignore duplicate (for now...)
page += 1 # iterate to next page
# Write the changelog to file
# 2021-09-28 | (#3661) Fix homing child weapons in niche circumstances
print("Writing to change.log...")
str = ''
for key, value in changelog.items():
str += "{} | (#{}) {} \n".format(value['date'].strftime("%Y-%m-%d"), key, value['title'])
with open("change.log", "w") as file:
file.write(str)
print("Done!")
main()
+41 -3
View File
@@ -8,12 +8,27 @@ from file_list import ReleaseFile
class ForumAPI:
POST_SIZE_MAX = 50000
"""!
Maximum number of characters allowed in a post, including BBCode (03/17/2022)
Check with HLP admins occasionally to verify this limit, they can set it in the forum's admin panel
"""
def __init__(self, config):
self.config = config
def create_post(self, title, content, board):
print(self.config["hlp"]["api"])
print(self.config["hlp"]["key"])
"""!
@brief Create a post on the forums
@param[in] title Title of the post
@param[in] content Body of the post
@param[in] board Which board/forum to post to
@returns { "thread_url": <url_of_created_thread> }
"""
if (self.config["hlp"]["api"] == "") or (self.config["hlp"]["key"] == ""):
print("Post failed! No API or API_KEY given!")
return
@@ -27,8 +42,19 @@ class ForumAPI:
if resp.text != "OK":
print("Post failed! Response: %s" %resp.text)
return resp.json()
def post_nightly(self, date, revision, files, log, success):
"""!
@brief Post a new Nightly topic on the forums using nightly.mako
@param[in] date The date to use
@param[in] version The build's version
@param[in] groups dict[Any, file_list.FileGroup]; FileGroups of SSE2, AVX, etc.
@param[in] sources URL's of builds on github or fs2net
"""
print("Posting nightly thread...")
title = "Nightly: {} - Revision {}".format(date, revision)
@@ -46,6 +72,17 @@ class ForumAPI:
self.create_post(title, rendered, self.config["nightly"]["hlp_board"])
def post_release(self, date, version: semantic_version.Version, groups, sources):
"""!
@brief Post a new Release topic on the forums using release.mako.
@param[in] date The date to use
@param[in] version The build's version
@param[in] groups dict[Any, file_list.FileGroup]; FileGroups of SSE2, AVX, etc.
@param[in] sources URL's of builds on github or fs2net
@returns If Successful, the URL of the created post
"""
print("Posting release thread...")
title = "Release: {}".format(version)
@@ -62,4 +99,5 @@ class ForumAPI:
print("Creating post...")
self.create_post(title, rendered, self.config["release"]["hlp_board"])
json = self.create_post(title, rendered, self.config["release"]["hlp_board"])
return json["thread_url"]
+85
View File
@@ -0,0 +1,85 @@
# Class for use with interfacing with github via HTTP requests
import requests
from util import retry_multi, GLOBAL_TIMEOUT
class GithubAPI:
headers = {
"Accept": "application/vnd.github.v3+json"
}
url_root = "https://api.github.com"
def __init__(self, config):
self.config = config
@retry_multi(5)
def get(self, path):
"""!
@brief Performs a GET request with the given path. To be used with Github's REST API.
@returns If successful, returns a .JSON object
"""
url = self.url_root + path
# GET https://api.github.com/<path> Accept: "application/vnd.github.v3+json"
response = requests.get(url, headers=self.headers, timeout=GLOBAL_TIMEOUT)
response.raise_for_status() # Raise a RequestException if we failed, and trigger retry
return response.json()
def get_release(self, tag_name):
"""!
@brief Retrieves the Github Release metadata as a JSON object
@see https://docs.github.com/en/rest/reference/releases#get-a-release-by-tag-name
"""
return self.get("/repos/{}/releases/tags/{}".format(self.config["github"]["repo"], tag_name))
def patch(self, path, data):
"""!
@brief Performs a PATCH request with the given path and body data (as dictionary)
@returns If successful, returns a .JSON object
"""
url = self.url_root + path
response = requests.patch(url, headers=self.headers, timeout=GLOBAL_TIMEOUT, data=data)
response.raise_for_status()
return response.json()
def update_release(self, release_id, tag_name="", name="", body="", draft=None, prerelease=None):
"""!
@brief Updates a Github Release
@param[in] release_id The id of the release, as obtained by get_release()
@param[in] tag_name (optional) The git tag this release is associated with
@param[in] name (optional) The name of the release
@param[in] body (optional) Body text describing the release
@param[in] draft (optional) If true, the release is marked as a "draft"
@param[in] prerelease (optional) If true, the release is marked as a "prerelease"
@note If an optional argument is not provided, then its associated data is not changed
"""
path = "/repos/{}/releases/{}".format(self.config["github"]["repo"], release_id)
# Add to the data JSON if options are specified
data = {}
if tag_name != "":
data["tag_name"] = tag_name
if name != "":
data["name"] = name
if body != "":
data["body"] = body
if draft != None:
data["draft"] = data
if prerelease != None:
data["prerelease"] = prerelease
self.patch(path, data)
+86 -41
View File
@@ -38,9 +38,11 @@ import nebula
import forum
# Compile regexes for extracting version components
MAJOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MAJOR (\d+)\)")
MINOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MINOR (\d+)\)")
BUILD_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_BUILD (\d+)\)")
MAJOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MAJOR (\d+)\)")
MINOR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_MINOR (\d+)\)")
BUILD_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_BUILD (\d+)\)")
REVISION_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION (\d+)\)")
REVISION_STR_VERSION_PATTERN = re.compile("(?:set_if_not_defined|set)\(FSO_VERSION_REVISION_STR (\w+)\)")
LOG_FORMAT = """
------------------------------------------------------------------------%n
@@ -60,45 +62,64 @@ def _match_version_number(text, regex):
"""
match = regex.search(text)
return int(match.group(1))
def _match_version_str(text, regex):
"""! Extracts the version component represented by `regex` from `text`
@param [in] `text` Filename with version string 'MAJOR.MINOR.BUILD'
@param [in] `regex` Regex pattern of component to look for
@return The version component as integer
"""
match = regex.search(text)
return match.group(1)
def get_source_version(date_version: datetime, tag_name: str) -> semantic_version.Version:
"""! Retrieves the build's version from `version.cmake`, forms it as a string, and appends the date
"""! Retrieves the version string from version_override.cmake (and version.cmake)
@param[in] `date_version` Date this build is published for release
@param[in] `tag_name` Tag of this release, used to determine if release, rc, or nightly
@return If release: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION` from version.cmake, or
@return If rc: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION` from tag_name, or
@return If nightly: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION-date` from version.cmake
@return If release: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD`
@return If rc: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD-FSO_VERSION_REVISION_STR`
@return If nightly: `FSO_VERSION_MAJOR.FSO_VERSION_MINOR.FSO_VERSION_BUILD-FSO_VERSION_REVISION_STR` (uses both version_override.cmake and version.cmake)
@note This is the version used to identify in Nebula and the forums. version_override.cmake is used for the builds
made by CI tools and version.cmake is used for builds made by devs.
"""
major = minor = build = version = 0
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
with open(os.path.join("..", "..", "version_override.cmake"), "r") as f:
filetext = f.read()
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
# revision = _match_version_number(filetext, REVISION_VERSION_PATTERN)
revision_str = _match_version_str(filetext, REVISION_STR_VERSION_PATTERN)
print("Parsing version_override.cmake...")
if "rc" in tag_name.lower():
# Release candidates idenfity with their unstable version (ex: 21.5.0-03052022) within the game and the logs, but
# the builds are named with the target release version (ex: 22.0.0). Since this script works on the builds we
# need to grab the target release version from tag_name
x = tag_name.upper().split("_")
# "release" = x[0], year = x[1], major = x[2], minor = x[3], build = x[4],
version = semantic_version.Version("{}.{}.{}-{}".format(x[1], x[2], x[3], x[4]))
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, revision_str))
elif "release" in tag_name.lower():
version = semantic_version.Version("{}.{}.{}".format(major, minor, build))
elif "nightly" in tag_name.lower():
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, date_version))
# Nightly's version_override.cmake only has FSO_VERSION_REVISION and FSO_VERSION_REVISION_STR set
# So, we have to pull the rest of the version string from version.cmake
print("Parsing version.cmake...")
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, revision_str))
else:
print("ERROR: malformed tag_name %s" % tag_name)
print(" ERROR: malformed tag_name %s" % tag_name)
sys.exit(1)
print("version: {}".format(version))
print("version.prerelease: {}".format(version.prerelease))
print(" version: {}".format(version))
print(" version.prerelease: {}".format(version.prerelease))
return version
@@ -145,17 +166,43 @@ def main():
print("ERROR: Invalid release mode %s passed. Expected release or nightly!" % sys.argv[1])
sys.exit(1)
linux_success = os.environ["LINUX_RESULT"] == "success"
windows_success = os.environ["WINDOWS_RESULT"] == "success"
if (sys.argv[1] == "release"):
if not (linux_success and windows_success):
# bail if this is a release and either build workflow failed
print("ERROR: One or more builds failed to publish! Cannot post release.")
sys.exit(1)
else:
if not (linux_success or windows_success):
# bail if this is a nightly build and both build workflows failed
print("ERROR: All builds failed to publish! Cannot post nightly.")
sys.exit(1)
# bail if tag_name doesn't match with sys.argv[1]
tag_name = os.environ["RELEASE_TAG"] ##!< commit tag string
if (sys.argv[1] == "release") and (not tag_name.startswith("release_")):
print("ERROR: Invalid tag name detected. Expected release_ prefix for release builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
if (sys.argv[1] == "nightly") and (not tag_name.startswith("nightly_")):
print("ERROR: Invalid tag name detected. Expected nightly_ prefix for nightly builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
# bail if tag_name does not exist in the repo
if not check_output(("git", "show-ref", "--tags", "refs/tags/%s" % tag_name), text=True):
print("ERROR: Couldn't find tag %s in repo (git show-ref)!" % tag_name)
sys.exit(1)
# Populate version and date
date = datetime.now() ##!< current date
version = get_source_version(date.strftime(DATEFORMAT_VERSION), tag_name) ##!< form full version string
success = os.environ["LINUX_RESULT"] == "success" and os.environ["WINDOWS_RESULT"] == "success" ##!< true if both linux and windows builds successful
# check that tag_name is actually in the git repo and find the previous tag release
# find the previous tag release (used by nightly)
tags = check_output(("git", "for-each-ref", "--sort=-taggerdate", "--format='%(tag)'", "refs/tags"), text=True).splitlines() # retrieve all tags in the repo by using git on the shell
# NOTE: check_output returns canonical string representation. use repr() on strings its being compared to
previous_tag = None
found = False
for tag in tags:
if found:
# Look for the "previous" tag with the same configuration ('release_' or 'nightly_')
@@ -169,24 +216,20 @@ def main():
if not found:
# couldn't find tag, bail
print("ERROR: Couldn't find tag %s in repo!" % tag_name)
print("ERROR: Couldn't find tag %s in repo! (git for-each-ref)" % tag_name)
sys.exit(1)
if not previous_tag:
if (sys.argv[1] == "nightly") and (not previous_tag):
# couldn't find previous tag, bail
print("ERROR: Could not find a previous tag for %s!" % tag_name)
sys.exit(1)
if sys.argv[1] == "release":
# Release specific action
if not tag_name.startswith("release_"):
# Safety check tag is from a release
print("ERROR: Invalid tag name detected. Expected release_ prefix for release builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
print("Retrieving file list...")
files, sources = file_list.get_release_files(tag_name, config)
print("Hashing files")
print("Hashing files...")
for file in files:
installer.get_hashed_file_list(file)
@@ -222,30 +265,27 @@ def main():
# print(installer.render_installer_config(version, groups, config))
# Publish release builds to Nebula
print("Publishing to Nebula...")
nebula.submit_release(
nebula.render_nebula_release(version, "rc" if version.prerelease else "stable", files, config),
config)
# Publish forum post, using the release.mako template
print("Publishing to Hard-light.net...")
fapi = forum.ForumAPI(config)
fapi.post_release(date.strftime(DATEFORMAT_FORUM), version, groups, sources)
else:
# Dead for now, nightly publish is done elsewhere
# Nightly specific action
if not tag_name.startswith("nightly_"):
# safety check tag is from a nightly
print("ERROR: Invalid tag name detected. Expected nightly_ prefix for nightly builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
print("Retrieving file list")
print("Retrieving file list...")
files = file_list.get_ftp_files("nightly", tag_name, config)
print("Hashing files")
print("Hashing files...")
for file in files:
installer.get_hashed_file_list(file)
# Publish nightly builds to Nebula
print("Publishing to Nebula...")
nebula.submit_release(
nebula.render_nebula_release(version, "nightly", files, config),
config)
@@ -254,7 +294,12 @@ def main():
log = check_output(("git", "log", "%s^..%s^" % (previous_tag, tag_name), "--no-merges", "--stat", "--pretty=format:\"%s\"" % LOG_FORMAT.strip()))
# Publish forum post, using the nighty.mako template
print("Publishing to Hard-light.net...")
fapi = forum.ForumAPI(config)
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, success)
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, (linux_success and windows_success))
main()
print("Done!")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -8,7 +8,7 @@ if(DOXYGEN_FOUND)
FILE(TO_NATIVE_PATH ${OUTPUT_DIR} OUTPUT_DIR)
SET(OUTPUT_DIR \"${OUTPUT_DIR}\")
SET(INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/code" "${CMAKE_CURRENT_SOURCE_DIR}/freespace2" "${CMAKE_CURRENT_SOURCE_DIR}/fred2" "${CMAKE_CURRENT_SOURCE_DIR}/wxfred2")
SET(INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/code" "${CMAKE_CURRENT_SOURCE_DIR}/freespace2" "${CMAKE_CURRENT_SOURCE_DIR}/fred2" "${CMAKE_CURRENT_SOURCE_DIR}/wxfred2" "${CMAKE_CURRENT_SOURCE_DIR}/qtfred")
SET(INPUT_DIRS)
FOREACH(DIR IN LISTS INPUTS)
+4
View File
@@ -100,6 +100,10 @@ set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS "")
if(DEFINED ENV{LDFLAGS})
set(CMAKE_EXE_LINKER_FLAGS $ENV{LDFLAGS})
endif()
if (CLANG_USE_LIBCXX)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
endif()
+5
View File
@@ -27,6 +27,11 @@ endif()
set(COMPILER_FLAGS "")
set(LINKER_FLAGS "")
# Don't ignore user-set LDFLAGS
if(DEFINED ENV{LDFLAGS})
set(LINKER_FLAGS $ENV{LDFLAGS})
endif()
if (GCC_USE_GOLD)
OPTION(GCC_INCREMENTAL_LINKING "Use incremental linking" OFF)
set(LINKER_FLAGS "${LINKER_FLAGS} -fuse-ld=gold")
+2 -2
View File
@@ -6,8 +6,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 21)
set_if_not_defined(FSO_VERSION_MINOR 5)
set_if_not_defined(FSO_VERSION_MAJOR 22)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
+3
View File
@@ -106,3 +106,6 @@ set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYM
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[variant=Debug] "NO")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
# Prevent GCC warnings in third-party BitOp... see GitHub #4366
suppress_file_warnings(scripting/lua/bitop/bit.c)
+2 -2
View File
@@ -1,11 +1,11 @@
#pragma once
#include "actions/expression/nodes/AbstractExpression.h"
#include "globalincs/pstypes.h"
#include "ParseContext.h"
#include "actions/expression/nodes/AbstractExpression.h"
namespace actions {
namespace expression {
@@ -1,11 +1,11 @@
#pragma once
#include "actions/expression/ParseContext.h"
#include "actions/expression/Value.h"
#include <Parser.h>
#include <Token.h>
#include "actions/expression/ParseContext.h"
#include "actions/expression/Value.h"
namespace actions {
namespace expression {
namespace nodes {
+20 -2
View File
@@ -17,6 +17,7 @@
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "object/waypoint.h"
#include "parse/sexp.h"
#include "physics/physics.h"
#include "ship/ship_flags.h"
@@ -71,6 +72,7 @@ extern ai_flag_name Ai_flag_names[];
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
#define AITTV_IGNORE_BANK (1<<2) // Goober5000 - ignore bank when turning
#define AITTV_SLOW_BANK_ACCEL (1<<3) // Asteroth - used by formation flying
#define AITTV_FORCE_DELTA_BANK (1<<4) // Lafiel - Always use the provided delta bank and override calculated values
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
@@ -103,11 +105,13 @@ typedef struct ai_goal {
int index;
} dockee;
object_ship_wing_point_team lua_ai_target;
} ai_goal;
#define AIM_CHASE 0
#define AIM_EVADE 1
#define AIM_GET_BEHIND 2
#define AIM_GET_BEHIND 2 // This mode is not actually implemented.
#define AIM_STAY_NEAR 3 // Stay near another ship.
#define AIM_STILL 4 // Sit still. Don't move. Hold your breath. Don't blink.
#define AIM_GUARD 5 // Guard an object
@@ -127,8 +131,9 @@ typedef struct ai_goal {
#define AIM_SENTRYGUN 19 // AI mode for sentry guns only (floating turrets)
#define AIM_WARP_OUT 20 // Commence warp out sequence. Point in legal direction. Then call John's code.
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
#define AIM_LUA 22 // Generic Lua-based AI mode
#define MAX_AI_BEHAVIORS 22 // Number of AIM_xxxx types
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
#define MAX_WAYPOINTS_PER_LIST 20
#define MAX_ENEMY_DISTANCE 2500.0f // Maximum distance from which a ship will pursue an enemy.
@@ -267,6 +272,8 @@ extern pnode *Ppfp; // Free pointer in path points.
// Goober5000 (based on the "you can only remember 7 things in short-term memory" assumption)
#define MAX_IGNORE_NEW_OBJECTS 7
#define AI_DYNAMIC_PATH_RECHECK_DELAY 1*1000
typedef struct ai_info {
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
int shipnum; // Ship using this slot, -1 means none.
@@ -343,6 +350,9 @@ typedef struct ai_info {
int submode_parm1; // SUSHI: Another optional parameter
fix next_predict_pos_time; // Next time to predict position.
int next_dynamic_path_check_time; //ETP: Time of next path check in ai_new_maybe_reposition_attack_subsys
vec3d last_dynamic_path_goal; //ETP: Remebers last target location in ai_new_maybe_reposition_attack_subsys
//SUSHI: like last_predicted_enemy_pos, but for aiming (which currently ignores predicted position)
//Unlike the predicted position stuff, also takes into account velocity
//Only used against small ships
@@ -493,6 +503,8 @@ typedef struct ai_info {
int multilock_check_timestamp; // when to check for multilock next
SCP_vector<std::pair<int, ship_subsys*>> ai_missile_locks_firing; // a list of missile locks (locked objnum, locked subsys) the ai is currently firing
object_ship_wing_point_team lua_ai_target;
} ai_info;
// Goober5000
@@ -536,6 +548,8 @@ extern int Ai_firing_enabled;
extern const char *Skill_level_names(int skill_level, int translate = 1);
extern int Ai_goal_signature;
extern control_info AI_ci;
// need access to following data in AiBig.cpp
extern object *Pl_objp;
extern object *En_objp;
@@ -573,6 +587,7 @@ extern void ai_do_default_behavior(object *obj);
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum);
extern vec3d ai_get_acc_limit(vec3d* vel_limit, const object* objp);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, vec3d* turnrate_mod = nullptr);
extern void init_ai_object(int objnum);
extern void ai_init(void); // Call this one to parse ai.tbl.
@@ -671,4 +686,7 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr);
#endif
+1
View File
@@ -144,6 +144,7 @@ namespace AI {
Fighterbay_departures_use_carrier_orient,
Prevent_negative_turret_ammo,
Fix_keep_safe_distance,
Ignore_aspect_when_leading,
NUM_VALUES
};
+2
View File
@@ -598,6 +598,8 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$fix keep-safe-distance:", AI::Profile_Flags::Fix_keep_safe_distance);
set_flag(profile, "$AI ignores aspect lock for leading:", AI::Profile_Flags::Ignore_aspect_when_leading);
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
+58 -50
View File
@@ -560,61 +560,69 @@ bool ai_new_maybe_reposition_attack_subsys() {
return false;
// not in sight, gotta get there
vec3d tgt2pl = Pl_objp->pos - target_objp->pos;
vec3d tgt2subsys = gsubpos - target_objp->pos;
float pl_dist = vm_vec_mag(&tgt2pl);
float subsys_dist = vm_vec_mag(&tgt2subsys) * 1.3f; // add a bit to this, we don't want to go directly at the subsys, we want to go above it
float angle2subsys = vm_vec_delta_ang(&tgt2pl, &tgt2subsys, nullptr);
float angle2goal = angle2subsys;
if (angle2goal > 1.2f) // let's not try to go more than about 70 degrees around the ship
angle2goal = 1.2f;
// we'll start by travelling along the sphere at our current distance around the ship
// remember that goal_pos will be relative to our target_ship (so we can scale in and out easily)
vec3d goal_pos, cross;
vm_vec_cross(&cross, &tgt2pl, &tgt2subsys);
vm_vec_normalize(&cross);
vm_vec_negate(&cross);
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
// then scale in (or out) towards our subsys
vec3d world_goal_pos;
float new_radius = ((subsys_dist - pl_dist) * (angle2goal / angle2subsys)) + pl_dist;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, new_radius / pl_dist);
world_goal_pos += target_objp->pos;
vec3d* good_pos = nullptr;
if (pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f)) {
// ok best case won't work
if (pl_dist > subsys_dist) {
//we're farther away than the subsys, let's try at our current distance
world_goal_pos = goal_pos + target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
// For performance reasons we only recheck once a second, otherwise we reuse the last found target.
if (timestamp_elapsed(aip->next_dynamic_path_check_time)) {
vec3d tgt2pl = Pl_objp->pos - target_objp->pos;
vec3d tgt2subsys = gsubpos - target_objp->pos;
float pl_dist = vm_vec_mag(&tgt2pl);
float subsys_dist = vm_vec_mag(&tgt2subsys) * 1.3f; // add a bit to this, we don't want to go directly at the subsys, we want to go above it
float angle2subsys = vm_vec_delta_ang(&tgt2pl, &tgt2subsys, nullptr);
float angle2goal = angle2subsys;
if (angle2goal > 1.2f) // let's not try to go more than about 70 degrees around the ship
angle2goal = 1.2f;
// we'll start by travelling along the sphere at our current distance around the ship
// remember that goal_pos will be relative to our target_ship (so we can scale in and out easily)
vec3d goal_pos, cross;
vm_vec_cross(&cross, &tgt2pl, &tgt2subsys);
vm_vec_normalize(&cross);
vm_vec_negate(&cross);
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
// then scale in (or out) towards our subsys
vec3d world_goal_pos;
float new_radius = ((subsys_dist - pl_dist) * (angle2goal / angle2subsys)) + pl_dist;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, new_radius / pl_dist);
world_goal_pos += target_objp->pos;
if (pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f)) {
// ok best case won't work
if (pl_dist > subsys_dist) {
//we're farther away than the subsys, let's try at our current distance
world_goal_pos = goal_pos + target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// ok, let's start moving it away and see if that's better
for (float i = 1.0f; i < 4.0f; i += 1.0f) {
if (good_pos)
break;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, (new_radius / pl_dist) * powf(1.3f,i));
world_goal_pos += target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// welp this sucks, just run away i guess
if (!good_pos) {
vm_vec_copy_normalize(&world_goal_pos, &tgt2pl);
world_goal_pos *= target_objp->radius + pl_dist;
world_goal_pos += target_objp->pos;
good_pos = &world_goal_pos;
}
}
// ok, let's start moving it away and see if that's better
for (float i = 1.0f; i < 4.0f; i += 1.0f) {
if (good_pos)
break;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, (new_radius / pl_dist) * powf(1.3f,i));
world_goal_pos += target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// welp this sucks, just run away i guess
if (!good_pos) {
vm_vec_copy_normalize(&world_goal_pos, &tgt2pl);
world_goal_pos *= target_objp->radius + pl_dist;
world_goal_pos += target_objp->pos;
else
good_pos = &world_goal_pos;
}
aip->next_dynamic_path_check_time = timestamp( AI_DYNAMIC_PATH_RECHECK_DELAY );
}
else{ //Not enough time has passed till recheck.
good_pos = &aip->last_dynamic_path_goal;
}
else
good_pos = &world_goal_pos;
ai_turn_towards_vector(good_pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
float subsys_distance = vm_vec_dist(&Pl_objp->pos, &gsubpos);
+405 -304
View File
File diff suppressed because it is too large. Load diff
+123 -81
View File
@@ -11,6 +11,7 @@
#include "ai/aigoals.h"
#include "ai/ailua.h"
#include "globalincs/linklist.h"
#include "mission/missionlog.h"
#include "mission/missionparse.h"
@@ -53,12 +54,6 @@ struct ship_registry_entry;
// goals given from the player to other ships in the game are also handled in this
// code
#define AI_GOAL_ACHIEVABLE 1
#define AI_GOAL_NOT_ACHIEVABLE 2
#define AI_GOAL_NOT_KNOWN 3
#define AI_GOAL_SATISFIED 4
int Ai_goal_signature;
int Num_ai_dock_names = 0;
char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
@@ -100,7 +95,7 @@ int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
// HUD what a ship's current orders are. If the AI goal doesn't correspond to something that
// ought to be printable, then NULL is used.
// JAS: Converted to a function in order to externalize the strings
const char *Ai_goal_text(int goal)
const char *Ai_goal_text(int goal, int submode)
{
switch(goal) {
case AI_GOAL_CHASE:
@@ -131,10 +126,15 @@ const char *Ai_goal_text(int goal)
return XSTR( "rearm ", 484);
case AI_GOAL_FLY_TO_SHIP:
return XSTR( "rendezvous with ", 1597);
case AI_GOAL_LUA:
auto mode = ai_lua_find_mode(submode);
if (mode == nullptr)
return nullptr;
return mode->hudText;
}
// Avoid compiler warning
return NULL;
return nullptr;
}
void ai_maybe_add_form_goal(wing* wingp)
@@ -240,8 +240,8 @@ int ai_query_goal_valid( int ship, int ai_goal_type )
{
int accepted;
if (ai_goal_type == AI_GOAL_NONE)
return 1; // anything can have no orders.
if (ai_goal_type == AI_GOAL_NONE || ai_goal_type == AI_GOAL_LUA)
return 1; // anything can have no orders or Lua'd orders.
accepted = 0;
@@ -306,7 +306,7 @@ void ai_clear_ship_goals( ai_info *aip )
// add scripting hook for 'On Goals Cleared' --wookieejedi
if (Script_system.IsActiveAction(CHA_ONGOALSCLEARED)) {
Script_system.SetHookObject("Ship", &Objects[Ships[aip->shipnum].objnum]);
Script_system.RunCondition(CHA_ONGOALSCLEARED);
Script_system.RunCondition(CHA_ONGOALSCLEARED, &Objects[Ships[aip->shipnum].objnum]);
Script_system.RemHookVars({"Ship"});
}
}
@@ -659,7 +659,7 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
// from the mission goals (i.e. those goals which come from events) in that we don't
// use sexpressions for goals from the player...so we enumerate all the parameters
void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name, ai_goal *aigp )
void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name, ai_goal *aigp, const object_ship_wing_point_team& lua_target )
{
Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
@@ -667,6 +667,7 @@ void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name,
aigp->type = type; // from player for sure -- could be to ship or to wing
aigp->ai_mode = mode; // major mode for this goal
aigp->ai_submode = submode; // could mean different things depending on mode
aigp->lua_ai_target = lua_target;
if ( mode == AI_GOAL_WARP ) {
if (submode >= 0) {
@@ -812,7 +813,7 @@ void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipn
// is issued to ship or wing (from player), mode is AI_GOAL_*. submode is the submode the
// ship should go into. shipname is the object of the action. aip is the ai_info pointer
// of the ship receiving the order
void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip )
void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip, const object_ship_wing_point_team& lua_target)
{
int empty_index;
ai_goal *aigp;
@@ -821,7 +822,7 @@ void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, a
// get a pointer to the goal structure
aigp = &aip->goals[empty_index];
ai_add_goal_sub_player( type, mode, submode, shipname, aigp );
ai_add_goal_sub_player( type, mode, submode, shipname, aigp, lua_target );
// if the goal is to dock, then we must determine which dock points on the two ships to use.
// If the target of the dock is a cargo type container, then we should use DOCK_TYPE_CARGO
@@ -838,7 +839,7 @@ void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, a
// adds a goal from the player to the given wing (which in turn will add it to the proper
// ships in the wing
void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum )
void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum, const object_ship_wing_point_team& lua_target)
{
int i, empty_index;
wing *wingp = &Wings[wingnum];
@@ -849,7 +850,7 @@ void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, i
int num = wingp->ship_index[i];
if ( num == -1 ) // ship must have been destroyed or departed
continue;
ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index] );
ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index], lua_target );
}
}
@@ -857,7 +858,7 @@ void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, i
// there are more waves to come. We use the same method here as when adding a goal to
// a ship -- find the first empty entry. If none exists, take the oldest entry and replace it.
empty_index = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index] );
ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index], lua_target );
}
@@ -1041,7 +1042,24 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
break;
default:
Int3(); // get ALLENDER -- invalid ai-goal specified for ai object!!!!
const ai_mode_lua* luaAIMode = ai_lua_find_mode(op);
if(luaAIMode != nullptr){
//Found a LuaAI mode sexp for this
int localnode = CDR(node);
aigp->ai_mode = AI_GOAL_LUA;
aigp->ai_submode = op;
if(luaAIMode->needsTarget) {
eval_object_ship_wing_point_team(&aigp->lua_ai_target, localnode);
localnode = CDR(localnode);
}
aigp->priority = atoi( CTEXT(localnode) );
}
else {
UNREACHABLE("Invalid SEXP-OP number %d for an AI goal!", op);
}
}
if ( aigp->priority > MAX_GOAL_PRIORITY ) {
@@ -1217,8 +1235,28 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_IGNORE_NEW;
break;
case OP_AI_FORM_ON_WING:
priority = 99;
goalmode = AI_GOAL_FORM_ON_WING;
break;
default:
Int3( );
const ai_mode_lua* luaAIMode = ai_lua_find_mode(op);
if(luaAIMode != nullptr){
//Found a LuaAI mode sexp for this
int localnode = CDR(node);
goalmode = AI_GOAL_LUA;
goalsubmode = op;
if(luaAIMode->needsTarget) {
localnode = CDR(localnode);
}
priority = localnode >= 0 ? atoi( CTEXT(localnode) ) : -1;
}
else {
UNREACHABLE("Invalid SEXP-OP %s (number %d) for an AI goal!", Sexp_nodes[node].text, op);
}
break;
};
@@ -1238,13 +1276,13 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
return goalindex;
}
// code to add ai goals to wings.
// code to remove ai goals from wings.
void ai_remove_wing_goal_sexp(int sexp, wing *wingp)
{
int i;
int goalindex = -1;
// add the ai goal for any ship that is currently arrived in the game (only if fred isn't running)
// remove the ai goal for any ship that is currently arrived in the game (only if fred isn't running)
if ( !Fred_running ) {
for (i = 0; i < wingp->current_count; i++) {
int num = wingp->ship_index[i];
@@ -1256,6 +1294,8 @@ void ai_remove_wing_goal_sexp(int sexp, wing *wingp)
}
}
// remove the sexpression index from the wing's list of goal sexpressions if
// there are more waves to come
if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running)
{
ai_remove_goal_sexp_sub( sexp, wingp->ai_goals );
@@ -1409,10 +1449,10 @@ void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip )
// function to determine if an ai goal is achieveable or not. Will return
// one of the AI_GOAL_* values. Also determines is a goal was successful.
int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
{
int status;
int return_val;
ai_achievability return_val;
object *objp;
ai_info *aip;
int index = -1, sindex = -1;
@@ -1425,8 +1465,11 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// these orders are always achievable.
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
|| (aigp->ai_mode == AI_GOAL_CHASE_ANY) || (aigp->ai_mode == AI_GOAL_STAY_STILL)
|| (aigp->ai_mode == AI_GOAL_PLAY_DEAD) || (aigp->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT) )
return AI_GOAL_ACHIEVABLE;
|| (aigp->ai_mode == AI_GOAL_PLAY_DEAD) || (aigp->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT))
return ai_achievability::ACHIEVABLE;
if (aigp->ai_mode == AI_GOAL_LUA)
return ai_lua_is_achievable(aigp, objnum);
// warp (depart) only achievable if there's somewhere to depart to
if (aigp->ai_mode == AI_GOAL_WARP)
@@ -1435,14 +1478,14 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// always valid if has working subspace drive, not disabled, and not limited by subsystem strength
if ( ship_can_warp_full_check(shipp) )
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
// if we can't warp, we can only depart if the ship (or its wing) departs to a fighter bay and the mothership is present
if (ship_can_bay_depart(shipp)) {
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
else {
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
}
}
@@ -1454,10 +1497,10 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
sindex = ship_name_lookup( aigp->target_name );
if (sindex < 0)
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
aigp->flags.set(AI::Goal_Flags::Goal_override);
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
// check to see if we have a valid list. If not, then try to set one up. If that
@@ -1468,10 +1511,10 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if ( aigp->wp_list == NULL ) {
Warning(LOCATION, "Unknown waypoint list %s - not found in mission file. Killing ai goal", aigp->target_name );
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
}
}
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
// chasing all ships of a certain ship class is achievable if there are ships of that class present;
@@ -1480,14 +1523,14 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if ( aigp->ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
for (objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
if ((objp->type == OBJ_SHIP) && !strcmp(aigp->target_name, Ship_info[Ships[objp->instance].ship_info_index].name)) {
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
}
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
}
return_val = AI_GOAL_SATISFIED;
return_val = ai_achievability::SATISFIED;
// next, determine if the goal has been completed successfully
switch ( aigp->ai_mode )
@@ -1589,7 +1632,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
if ( status )
return_val = AI_GOAL_NOT_ACHIEVABLE;
return_val = ai_achievability::NOT_ACHIEVABLE;
} else {
status = 0;
}
@@ -1604,7 +1647,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if ( !status ) {
status = mission_log_get_time( LOG_WING_DESTROYED, aigp->target_name, NULL, NULL);
if ( status )
return_val = AI_GOAL_NOT_ACHIEVABLE;
return_val = ai_achievability::NOT_ACHIEVABLE;
}
break;
@@ -1618,14 +1661,14 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
Assert( aigp->target_instance >= 0 );
if ( Weapons[aigp->target_instance].objnum == -1 )
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
// if the signatures don't match, then goal isn't achievable.
if ( Objects[Weapons[aigp->target_instance].objnum].signature != aigp->target_signature )
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
// otherwise, we should be good to go
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
break;
}
@@ -1649,22 +1692,22 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
sindex = wing_name_lookup( aigp->target_name );
if (sindex < 0)
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
wing *wingp = &Wings[sindex];
if ( wingp->flags[Ship::Wing_Flags::Gone] )
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
else if ( wingp->total_arrived_count == 0 )
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
else
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
// Goober5000 - undocking from an unspecified object is always achievable;
// undocking from a specified object is handled below
else if ( (aigp->ai_mode == AI_GOAL_UNDOCK) && (aigp->target_name == NULL) )
{
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
else
{
@@ -1705,7 +1748,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
{
// if the ship has no turrets, we can't disarm it!
if (Ships[ship_name_lookup(aigp->target_name)].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
}
// if the goal is an ignore/disable/disarm goal, then
@@ -1747,12 +1790,12 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
Int3(); // for now, allender wants to know about these things!!!!
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
}
// if ship is disabled, don't know if it can dock or not
if ( Ships[objp->instance].flags[Ship::Ship_Flags::Disabled] )
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
// we must also determine if we're prevented from docking for any reason
sindex = ship_name_lookup(aigp->target_name);
@@ -1774,7 +1817,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
else if (obstacle_objp != objp)
{
// return NOT_KNOWN which will place the goal on hold until the dockpoint is clear
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
}
}
@@ -1794,7 +1837,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
ai_add_goal_ship_internal( aip, AI_GOAL_UNDOCK, Ships[obstacle_objp->instance].ship_name, -1, -1, 0 );
// return NOT_KNOWN which will place the goal on hold until the undocking is complete.
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
}
}
@@ -1808,7 +1851,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
{
// only put it on hold if it's someone other than the guy we're undocking from right now!!
if (aip->goal_objnum != Ships[ship_name_lookup(aigp->target_name)].objnum)
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
}
} else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
@@ -1819,11 +1862,11 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
sindex = ship_name_lookup( aigp->target_name );
if ( sindex != -1 ) {
aigp->ai_submode = ship_get_subsys_index( &Ships[sindex], aigp->docker.name );
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
} else {
Int3();
return AI_GOAL_NOT_ACHIEVABLE; // force this goal to be invalid
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
} else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
@@ -1836,7 +1879,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
return AI_GOAL_SATISFIED;
return ai_achievability::SATISFIED;
}
switch ( aigp->ai_mode )
@@ -1857,13 +1900,13 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
case AI_GOAL_FLY_TO_SHIP:
{
if ( status == SHIP_STATUS_ARRIVED )
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
else if ( status == SHIP_STATUS_NOT_ARRIVED )
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
else if ( status == SHIP_STATUS_GONE )
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
else if ( status == SHIP_STATUS_UNKNOWN )
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
Int3(); // get allender -- bad logic
break;
@@ -1878,66 +1921,61 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// we mark the goal as not achievable.
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
Int3(); // get Allender. this shouldn't happen!!!
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
}
if ( status == SHIP_STATUS_GONE )
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
sindex = ship_name_lookup( aigp->target_name );
if ( sindex < 0 ) {
Int3();
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
}
// if desitnation currently being repaired, then goal is stil active
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
// if the destination ship is dying or departing (but not completed yet), the mark goal as
// not achievable.
if ( Ships[sindex].is_dying_or_departing())
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
// if the destination object is no longer awaiting repair, then remove the item
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
return AI_GOAL_NOT_ACHIEVABLE;
return ai_achievability::NOT_ACHIEVABLE;
// not repairing anything means that he can do this goal!!!
if ( !(aip->ai_flags[AI::AI_Flags::Repairing]) )
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
// test code!!!
if ( aip->goal_objnum == -1 ) {
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
// if he is repairing something, he can satisfy his repair goal (his goal_objnum)
// return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
// satisfied.
if ( aip->goal_objnum != Ships[sindex].objnum )
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
return AI_GOAL_ACHIEVABLE;
return ai_achievability::ACHIEVABLE;
}
default:
Int3(); // invalid case in switch:
}
return AI_GOAL_NOT_KNOWN;
return ai_achievability::NOT_KNOWN;
}
// Compare function for sorting ai_goals based on priority.
// Return values set to sort array in _decreasing_ order.
int ai_goal_priority_compare(const void *a, const void *b)
int ai_goal_priority_compare(const ai_goal *ga, const ai_goal *gb)
{
ai_goal *ga, *gb;
ga = (ai_goal *) a;
gb = (ai_goal *) b;
// first, sort based on whether or not the ON_HOLD flag is set for the goal.
// If the flag is set, don't push the goal higher in the list even if priority
// is higher since goal cannot currently be achieved.
@@ -1985,7 +2023,7 @@ int ai_goal_priority_compare(const void *a, const void *b)
void prioritize_goals(ai_info *aip)
{
// First sort based on priority field.
insertion_sort(aip->goals, MAX_AI_GOALS, sizeof(ai_goal), ai_goal_priority_compare);
insertion_sort(aip->goals, MAX_AI_GOALS, ai_goal_priority_compare);
}
// Scan the list of goals at aip->goals.
@@ -1999,7 +2037,7 @@ void validate_mission_goals(int objnum, ai_info *aip)
// loop through all of the goals to determine which goal should be followed.
// This determination will be based on priority, and the time at which it was issued.
for ( i = 0; i < MAX_AI_GOALS; i++ ) {
int state;
ai_achievability state;
ai_goal *aigp;
aigp = &aip->goals[i];
@@ -2018,18 +2056,18 @@ void validate_mission_goals(int objnum, ai_info *aip)
state = ai_mission_goal_achievable( objnum, aigp );
// if this order is no longer a valid one, remove it
if ( (state == AI_GOAL_NOT_ACHIEVABLE) || (state == AI_GOAL_SATISFIED) ) {
if ( (state == ai_achievability::NOT_ACHIEVABLE) || (state == ai_achievability::SATISFIED) ) {
ai_remove_ship_goal( aip, i );
continue;
}
// if the status is achievable, and the on_hold flag is set, clear the flagb
if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
if ( (state == ai_achievability::ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
aigp->flags.remove(AI::Goal_Flags::Goal_on_hold);
// if the goal is not known, then set the ON_HOLD flag so that it doesn't get counted as
// a goal to be pursued
if (state == AI_GOAL_NOT_KNOWN)
if (state == ai_achievability::NOT_KNOWN)
aigp->flags.set(AI::Goal_Flags::Goal_on_hold); // put this goal on hold until it becomes true
}
@@ -2397,13 +2435,17 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
other_obj = &Objects[Ships[shipnum].objnum];
ai_rearm_repair( objp, current_goal->docker.index, other_obj, current_goal->dockee.index );
break;
case AI_GOAL_LUA:
ai_lua_start(current_goal, objp);
break;
default:
Int3();
break;
}
if (old_form_objnum != -1)
if (old_form_objnum >= 0)
ai_formation_object_recalculate_slotnums(old_form_objnum);
}
+8 -4
View File
@@ -14,6 +14,7 @@
#include "globalincs/globals.h"
#include "globalincs/pstypes.h"
#include "parse/sexp.h"
struct wing;
struct ai_info;
@@ -59,6 +60,7 @@ struct ai_goal;
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
#define AI_GOAL_LUA (1<<27) // 0x04000000
// now the masks for ship types
@@ -82,6 +84,8 @@ struct ai_goal;
#define MAX_AI_DOCK_NAMES 25
enum class ai_achievability { ACHIEVABLE, NOT_ACHIEVABLE, NOT_KNOWN, SATISFIED };
typedef flag_def_list ai_goal_list;
extern ai_goal_list Ai_goal_names[];
@@ -90,7 +94,7 @@ extern int Num_ai_goals;
extern int Num_ai_dock_names;
extern char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
extern const char *Ai_goal_text(int goal);
extern const char *Ai_goal_text(int goal, int submode);
// extern function definitions
extern void ai_post_process_mission();
@@ -103,14 +107,14 @@ extern int ai_goal_num(ai_goal *goals);
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip);
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
extern void ai_add_wing_goal_sexp( int sexp, int type, wing *wingp );
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name );
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name);
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
extern void ai_remove_wing_goal_sexp( int sexp, wing *wingp );
// adds goals to ships/sings through player orders
extern void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
extern void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum );
extern void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip, const object_ship_wing_point_team& lua_target = object_ship_wing_point_team());
extern void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum, const object_ship_wing_point_team& lua_target = object_ship_wing_point_team());
extern void ai_remove_ship_goal( ai_info *aip, int index );
extern void ai_clear_ship_goals( ai_info *aip );
+239
View File
@@ -0,0 +1,239 @@
#include "ai/ailua.h"
#include "hud/hudsquadmsg.h"
#include "iff_defs/iff_defs.h"
#include "parse/sexp/sexp_lookup.h"
#include "parse/sexp/LuaAISEXP.h"
#include "scripting/api/objs/ai_helper.h"
#include "scripting/api/objs/enums.h"
#include "scripting/api/objs/oswpt.h"
#include "scripting/api/objs/ship.h"
#include "scripting/scripting.h"
static std::unordered_map<int, ai_mode_lua> Lua_ai_modes;
static std::unordered_map<int, player_order_lua> Lua_player_orders;
void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
Lua_ai_modes.emplace(sexp_op, mode);
}
bool ai_lua_add_order(int sexp_op, player_order_lua order) {
Player_orders.emplace_back(vm_strdup(order.parseText.c_str()), vm_strdup(order.displayText.c_str()), -1, sexp_op);
Player_orders.back().localize();
Lua_player_orders.emplace(sexp_op, std::move(order));
return true;
}
bool ai_lua_has_mode(int sexp_op){
return Lua_ai_modes.count(sexp_op) > 0;
}
const ai_mode_lua* ai_lua_find_mode(int sexp_op){
auto aiLuaMode = Lua_ai_modes.find(sexp_op);
if(aiLuaMode == Lua_ai_modes.end())
return nullptr;
else
return &aiLuaMode->second;
}
const player_order_lua* ai_lua_find_player_order(int sexp_op) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return nullptr;
else
return &aiLuaOrder->second;
}
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
if (!action.isValid()) {
Error(LOCATION,
"Lua AI SEXP called without a valid action function! A script probably failed to set the action for some reason.");
return;
}
luacpp::LuaValueList luaParameters;
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target)));
}
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
if (retVals[0].getValue<bool>())
ai_mission_goal_complete(aip);
}
}
void ai_lua(ai_info* aip){
Assertion(aip->mode == AIM_LUA, "Tried to invoke LuaAI on a ship not in LuaAI-Mode");
const auto& lua_ai = Lua_ai_modes.at(aip->submode);
auto dynamicSEXP = sexp::get_dynamic_sexp(aip->submode);
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
const auto& action = lua_ai_sexp->getActionFrame();
run_ai_lua_action(action, lua_ai, aip);
}
}
void ai_lua_start(ai_goal* aigp, object* objp){
Assert(objp->type == OBJ_SHIP);
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
ai_info *aip = &Ai_info[Ships[objp->instance].ai_index];
aip->mode = AIM_LUA;
aip->submode = aigp->ai_submode;
aip->lua_ai_target = aigp->lua_ai_target;
aip->submode_start_time = Missiontime;
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
auto dynamicSEXP = sexp::get_dynamic_sexp(aigp->ai_submode);
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
const auto& action = lua_ai_sexp->getActionEnter();
run_ai_lua_action(action, lua_ai, aip);
}
}
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
ship* target = &Ships[Objects[target_objnum].instance];
const player_order_lua& order = *ai_lua_find_player_order(sexp_op);
switch (order.targetRestrictions) {
case player_order_lua::target_restrictions::TARGET_ALL:
return true;
case player_order_lua::target_restrictions::TARGET_OWN:
return target->team == self->team;
case player_order_lua::target_restrictions::TARGET_ALLIES:
return !iff_x_attacks_y(self->team, target->team);
case player_order_lua::target_restrictions::TARGET_ENEMIES:
return iff_x_attacks_y(self->team, target->team);
case player_order_lua::target_restrictions::TARGET_SAME_WING:
return target->wingnum != -1 && self->wingnum == target->wingnum;
case player_order_lua::target_restrictions::TARGET_PLAYER_WING:
return target->wingnum != -1 && Ships[Player_obj->instance].wingnum == target->wingnum;
case player_order_lua::target_restrictions::TARGET_ALL_CAPS:
return Ship_info[target->ship_info_index].is_big_ship();
case player_order_lua::target_restrictions::TARGET_ALLIED_CAPS:
return !iff_x_attacks_y(self->team, target->team) && Ship_info[target->ship_info_index].is_big_ship();
case player_order_lua::target_restrictions::TARGET_ENEMY_CAPS:
return iff_x_attacks_y(self->team, target->team) && Ship_info[target->ship_info_index].is_big_ship();
case player_order_lua::target_restrictions::TARGET_NOT_SELF:
return self->objnum != target_objnum;
}
return false;
}
bool ai_lua_is_valid_target_lua(const ai_mode_lua& mode, int sexp_op, int target_objnum, ship* self) {
auto dynamicSEXP = sexp::get_dynamic_sexp(sexp_op);
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
const auto& action = lua_ai_sexp->getTargetRestrict();
if (!action.isValid())
return true;
luacpp::LuaValueList luaParameters;
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[self->objnum]))));
if (mode.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]))));
}
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
return retVals[0].getValue<bool>();
}
else {
Error(LOCATION, "LuaAI target restriction function did not return a valid boolean!");
}
}
return true;
}
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self) {
const ai_mode_lua& mode = *ai_lua_find_mode(sexp_op);
//All targetless AI modes are fine
if (mode.needsTarget) {
//No target is then not valid
if (target_objnum == -1)
return false;
//As of now, only accept ships
if (Objects[target_objnum].type != OBJ_SHIP)
return false;
if (!ai_lua_is_valid_target_intrinsic(sexp_op, target_objnum, self))
return false;
}
//If we haven't bailed yet, query the custom callback
return ai_lua_is_valid_target_lua(mode, sexp_op, target_objnum, self);
}
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum){
const auto& lua_ai = Lua_ai_modes.at(aigp->ai_submode);
auto dynamicSEXP = sexp::get_dynamic_sexp(aigp->ai_submode);
if (dynamicSEXP != nullptr && typeid(*dynamicSEXP) == typeid(sexp::LuaAISEXP)) {
auto lua_ai_sexp = static_cast<sexp::LuaAISEXP*>(dynamicSEXP);
const auto& action = lua_ai_sexp->getAchievable();
if (!action.isValid())
return ai_achievability::ACHIEVABLE;
luacpp::LuaValueList luaParameters;
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_Ship.Set(object_h(&Objects[objnum]))));
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aigp->lua_ai_target)));
}
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::USERDATA) {
scripting::api::enum_h enumData;
retVals[0].getValue(scripting::api::l_Enum.Get(&enumData));
if (!enumData.IsValid()) {
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
return ai_achievability::ACHIEVABLE;
}
switch (enumData.index) {
case scripting::api::LE_LUAAI_ACHIEVABLE:
return ai_achievability::ACHIEVABLE;
case scripting::api::LE_LUAAI_NOT_YET_ACHIEVABLE:
return ai_achievability::NOT_KNOWN;
case scripting::api::LE_LUAAI_UNACHIEVABLE:
return ai_achievability::NOT_ACHIEVABLE;
default:
Error(LOCATION, "LuaAI SEXP achievability hook returned an invalid avilability enum.");
return ai_achievability::ACHIEVABLE;
}
}
else {
Error(LOCATION, "LuaAI SEXP achievability hook did not return any avilability enum!");
}
}
return ai_achievability::ACHIEVABLE;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "ai/ai.h"
#include "ai/aigoals.h"
#include "mission/missionmessage.h"
#include "ship/ship.h"
#include "globalincs/globals.h"
struct ai_mode_lua {
bool needsTarget;
const char* hudText;
};
struct player_order_lua {
int ai_message = MESSAGE_YESSIR;
SCP_string parseText = "";
SCP_string displayText = "";
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
};
void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode);
bool ai_lua_add_order(int sexp_op, player_order_lua order);
bool ai_lua_has_mode(int sexp_op);
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
const player_order_lua* ai_lua_find_player_order(int sexp_op);
void ai_lua(ai_info* aip);
void ai_lua_start(ai_goal* aigp, object* objp);
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self);
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
+15 -13
View File
@@ -434,7 +434,7 @@ int valid_turret_enemy(object *objp, object *turret_parent)
}
// don't shoot at ships without collision check
if (!(objp->flags[Object::Object_Flags::Collides])) {
if (!(objp->flags[Object::Object_Flags::Collides]) && !(objp->flags[Object::Object_Flags::Attackable_if_no_collide])) {
return 0;
}
@@ -1782,6 +1782,8 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
#endif
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, turret)) {
auto turret_enemy_objp = (turret->turret_enemy_objnum >= 0) ? &Objects[turret->turret_enemy_objnum] : nullptr;
ship_weapon* swp = &turret->weapons;
turret->turret_last_fire_direction = *firing_vec;
@@ -1818,13 +1820,13 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 1.0f;
fire_info.beam_info_index = turret_weapon_class;
fire_info.beam_info_override = NULL;
fire_info.beam_info_override = nullptr;
fire_info.shooter = &Objects[parent_objnum];
fire_info.target = &Objects[turret->turret_enemy_objnum];
fire_info.target = turret_enemy_objp;
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
fire_info.target_subsys = turret->targeted_subsys;
else
fire_info.target_subsys = NULL;
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
@@ -1841,8 +1843,8 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
turret->last_fired_weapon_info_index = turret_weapon_class;
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", turret_enemy_objp);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum], objp);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
}
@@ -1984,8 +1986,8 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
wp->turret_subsys = turret;
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", turret_enemy_objp);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum], objp);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
@@ -2015,7 +2017,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
if ( MULTIPLAYER_MASTER && (weapon_objnum != -1) ) {
int subsys_index;
subsys_index = ship_get_index_from_subsys(turret, parent_objnum );
subsys_index = ship_get_subsys_index(turret);
Assert( subsys_index != -1 );
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range );
@@ -2103,7 +2105,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum], &Objects[weapon_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
@@ -2124,7 +2126,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
if ( MULTIPLAYER_MASTER && (weapon_objnum != -1) ) {
int subsys_index;
subsys_index = ship_get_index_from_subsys(tsi->turret, tsi->parent_objnum );
subsys_index = ship_get_subsys_index(tsi->turret);
Assert( subsys_index != -1 );
send_turret_fired_packet( tsi->parent_objnum, subsys_index, weapon_objnum );
}
@@ -2740,7 +2742,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
{
//something did fire, get the lowest valid timestamp
// don't do this if we already set a turret timestamp previously in the function
if (timestamp_until(ss->turret_next_fire_stamp) <= 0)
if (timestamp_since(ss->turret_next_fire_stamp) > 0)
{
int minimum_stamp = -1;
@@ -2749,7 +2751,7 @@ void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
int stamp = (i < MAX_SHIP_PRIMARY_BANKS) ? swp->next_primary_fire_stamp[i] : swp->next_secondary_fire_stamp[i - MAX_SHIP_PRIMARY_BANKS];
// valid timestamps start at 2; stamp must be in the future
if (stamp < 2 || timestamp_until(stamp) <= 0)
if (stamp < 2 || timestamp_since(stamp) > 0)
continue;
// find minimum
+8 -6
View File
@@ -32,7 +32,7 @@
#include "object/objcollide.h"
#include "object/object.h"
#include "parse/parselo.h"
#include "scripting/scripting.h"
#include "scripting/global_hooks.h"
#include "particle/particle.h"
#include "render/3d.h"
#include "ship/ship.h"
@@ -1511,11 +1511,12 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
if ( timestamp_elapsed(asp->final_death_time) ) {
vec3d relvec, vfh, tvec;
bool skip = false;
bool hooked = Script_system.IsActiveAction(CHA_DEATH);
bool hooked = scripting::hooks::OnDeath->isActive();
if (hooked) {
Script_system.SetHookObject("Self", pasteroid_obj);
skip = Script_system.IsConditionOverride(CHA_DEATH, pasteroid_obj);
skip = scripting::hooks::OnDeath->isOverride(
scripting::hook_param_list(scripting::hook_param("Self", 'o', pasteroid_obj)),
pasteroid_obj);
}
if (!skip)
{
@@ -1623,8 +1624,9 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
asp->final_death_time = timestamp(-1);
}
if (hooked) {
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
Script_system.RemHookVar("Self");
scripting::hooks::OnDeath->run(
scripting::hook_param_list(scripting::hook_param("Self", 'o', pasteroid_obj)),
pasteroid_obj);
}
}
}
+15
View File
@@ -1581,3 +1581,18 @@ bool IsVisited(int nav)
return 1;
return 0;
}
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void Nav_SetColor(const char *nav, bool visited, ubyte r, ubyte g, ubyte b)
{
int n = FindNav(nav);
if (n >= 0 && n < MAX_NAVPOINTS)
{
auto rgb = visited ? Navs[n].visited_color : Navs[n].normal_color;
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
}
}
+12
View File
@@ -31,6 +31,8 @@ class NavPoint
public:
char m_NavName[32];
int flags;
ubyte normal_color[3];
ubyte visited_color[3];
const void *target_obj;
int waypoint_num; //only used when flags & NP_WAYPOINT
@@ -42,6 +44,14 @@ public:
m_NavName[0] = 0;
flags = 0;
normal_color[0] = 0x80;
normal_color[1] = 0x80;
normal_color[2] = 0xFF;
visited_color[0] = 0xFF;
visited_color[1] = 0xFF;
visited_color[2] = 0x00;
target_obj = nullptr;
waypoint_num = -1;
}
@@ -155,6 +165,8 @@ unsigned int DistanceTo(int nav);
bool IsVisited(const char *nav);
bool IsVisited(int nav);
void Nav_SetColor(const char *nav, bool visited, ubyte r, ubyte g, ubyte b);
void send_autopilot_msg(const char *msg, const char *snd=nullptr);
void send_autopilot_msgID(int msgid);
#endif
+2 -9
View File
@@ -592,12 +592,9 @@ void bm_convert_format(bitmap *bmp, ushort flags) {
return;
if (Is_standalone) {
Assert(bmp->bpp == 8);
return;
} else {
if (flags & BMP_AABITMAP)
Assert(bmp->bpp == 8);
else
if(!(flags & BMP_AABITMAP))
Assert((bmp->bpp == 16) || (bmp->bpp == 32));
}
@@ -1875,9 +1872,7 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
}
// otherwise do it as normal
else {
if (flags & BMP_AABITMAP) {
Assert(bpp == 8);
} else if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
} else if ((flags & BMP_TEX_DXT1) || (flags & BMP_TEX_DXT3) || (flags & BMP_TEX_DXT5) || (flags & BMP_TEX_BC7)) {
Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
@@ -1887,8 +1882,6 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) {
(be->type == BM_TYPE_CUBEMAP_DXT3) ||
(be->type == BM_TYPE_CUBEMAP_DXT5));
Assert(bpp >= 16);
} else {
Assert(0); //?
}
}
+97 -27
View File
@@ -9,11 +9,13 @@
#include "model/model.h" //polymodel, model_get
#include "options/Option.h"
#include "parse/parselo.h"
#include "parse/sexp_container.h"
#include "playerman/player.h" //player_get_padlock_orient
#include "ship/ship.h" //compute_slew_matrix
//*************************IMPORTANT GLOBALS*************************
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
float COCKPIT_ZOOM_DEFAULT = 0.75f;
float Sexp_fov = 0.0f;
warp_camera Warp_camera;
@@ -241,7 +243,16 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
{
vec3d position;
matrix orient_buf;
auto orient = Use_host_orientation_for_set_camera_facing ? &orient_buf : nullptr;
matrix *orient = nullptr;
if (Use_host_orientation_for_set_camera_facing)
{
// we want to retrieve the camera's orientation, so provide a buffer for it
orient = &orient_buf;
// reset the camera's orientation state because if we have no host object, that is what the camera will default to
c_ori = vmd_identity_matrix;
}
this->get_info(&position, orient, false);
@@ -597,11 +608,46 @@ void warp_camera::get_info(vec3d *position, matrix *orientation)
#define MAX_SUBTITLE_LINES 64
subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char* in_imageanim, float in_display_time,
float in_fade_time, const color *in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width,
int in_height, bool in_post_shaded, float in_line_height_factor)
: display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), line_height_factor(1.0f),
image_id(-1), time_displayed(-1.0f), time_displayed_end(-1.0f), post_shaded(false)
float in_fade_time, const color* in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width,
int in_height, bool in_post_shaded, int in_line_height_modifier, bool in_adjust_wh)
: display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), line_height_modifier(0),
image_id(-1), time_displayed(-1.0f), time_displayed_end(-1.0f), post_shaded(false), do_screen_scaling(false)
{
if ((in_text == nullptr || *in_text == '\0') && (in_imageanim == nullptr || *in_imageanim == '\0'))
return;
auto screen_w = gr_screen.center_w;
auto screen_h = gr_screen.center_h;
// we might be doing screen scaling
if (Show_subtitle_screen_base_res[0] > 0 && Show_subtitle_screen_base_res[1] > 0)
{
// The way this works is we specify our subtitle coordinates relative to a base resolution, e.g. 1024x768.
// The base resolution is adjusted behind the scenes to match the aspect ratio of the current resolution
// (and the subtitle coordinates are adjusted as well). Then the adjusted subtitles are resized by the
// graphics code when they are drawn to the screen.
do_screen_scaling = true;
// we might need to adjust the coordinates for aspect ratio
if (in_adjust_wh)
{
if (Show_subtitle_screen_base_res[0] != Show_subtitle_screen_adjusted_res[0])
{
in_x_pos = in_x_pos * Show_subtitle_screen_adjusted_res[0] / Show_subtitle_screen_base_res[0];
in_width = in_width * Show_subtitle_screen_adjusted_res[0] / Show_subtitle_screen_base_res[0];
}
if (Show_subtitle_screen_base_res[1] != Show_subtitle_screen_adjusted_res[1])
{
in_y_pos = in_y_pos * Show_subtitle_screen_adjusted_res[1] / Show_subtitle_screen_base_res[1];
in_height = in_height * Show_subtitle_screen_adjusted_res[1] / Show_subtitle_screen_base_res[1];
}
}
// use these because we will be scaling the subtitle when it is displayed
screen_w = Show_subtitle_screen_adjusted_res[0];
screen_h = Show_subtitle_screen_adjusted_res[1];
}
// Initialize color
gr_init_color(&text_color, 0, 0, 0);
@@ -612,13 +658,11 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
memset( &text_pos, 0, 2*sizeof(int) );
memset( &image_pos, 0, 4*sizeof(int) );
if ( ((in_text != NULL) && (strlen(in_text) <= 0)) && ((in_imageanim != NULL) && (strlen(in_imageanim) <= 0)) )
return;
if (in_text != NULL && in_text[0] != '\0')
{
text_buf = in_text;
sexp_replace_variable_names_with_values(text_buf);
sexp_container_replace_refs_with_values(text_buf);
in_text = text_buf.c_str();
}
@@ -644,7 +688,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
else
gr_init_alphacolor(&text_color, 255, 255, 255, 255);
text_fontnum = in_text_fontnum;
line_height_factor = in_line_height_factor;
line_height_modifier = in_line_height_modifier;
//Setup display and fade time
display_time = fl_abs(in_display_time);
@@ -683,7 +727,15 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
if(w > tw)
tw = w;
th += fl2i(line_height_factor * h);
if (line_height_modifier != 0.0f)
{
if (Show_subtitle_uses_pixels)
h = line_height_modifier;
else
h = fl2i(h * line_height_modifier / 100.0f);
}
th += h;
}
// restore old font
@@ -708,20 +760,20 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
//Center it?
if(center_x)
image_pos.x = (gr_screen.center_w - tw)/2 + gr_screen.center_offset_x;
image_pos.x = (screen_w - tw)/2;
if(center_y)
image_pos.y = (gr_screen.center_h - th)/2 + gr_screen.center_offset_y;
image_pos.y = (screen_h - th)/2;
}
if(in_x_pos < 0 && !center_x)
image_pos.x += gr_screen.center_offset_x + gr_screen.center_w + in_x_pos;
image_pos.x += screen_w + in_x_pos;
else if(!center_x)
image_pos.x += gr_screen.center_offset_x + in_x_pos;
image_pos.x += in_x_pos;
if(in_y_pos < 0 && !center_y)
image_pos.y += gr_screen.center_offset_y + gr_screen.center_h + in_y_pos;
image_pos.y += screen_h + in_y_pos;
else if(!center_y)
image_pos.y += gr_screen.center_offset_y + in_y_pos;
image_pos.y += in_y_pos;
image_pos.w = in_width;
image_pos.h = in_height;
@@ -777,24 +829,32 @@ void subtitle::do_frame(float frametime)
int x = text_pos.x;
int y = text_pos.y;
auto sizing_mode = do_screen_scaling ? GR_RESIZE_FULL : GR_RESIZE_NONE;
if (do_screen_scaling)
gr_set_screen_scale(Show_subtitle_screen_adjusted_res[0], Show_subtitle_screen_adjusted_res[1]);
// do the actual drawing ---------------------
for(SCP_vector<SCP_string>::iterator line = text_lines.begin(); line != text_lines.end(); ++line)
{
gr_string(x, y, (char*)line->c_str(), GR_RESIZE_NONE);
y += fl2i(line_height_factor * font_height);
}
gr_string(x, y, (char*)line->c_str(), sizing_mode);
// restore old font
if (old_fontnum >= 0)
{
font::set_font(old_fontnum);
if (line_height_modifier != 0.0f)
{
if (Show_subtitle_uses_pixels)
font_height = line_height_modifier;
else
font_height = fl2i(font_height * line_height_modifier / 100.0f);
}
y += font_height;
}
if(image_id >= 0)
{
gr_set_bitmap(image_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, text_color.alpha/255.0f);
// scaling?
// image scaling?
if (image_pos.w > 0 || image_pos.h > 0)
{
int orig_w, orig_h;
@@ -806,16 +866,25 @@ void subtitle::do_frame(float frametime)
scale.xyz.z = 1.0f;
gr_push_scale_matrix(&scale);
gr_bitmap(fl2i(image_pos.x / scale.xyz.x), fl2i(image_pos.y / scale.xyz.y), GR_RESIZE_NONE);
gr_bitmap(fl2i(image_pos.x / scale.xyz.x), fl2i(image_pos.y / scale.xyz.y), sizing_mode);
gr_pop_scale_matrix();
}
// no scaling
else
{
gr_bitmap(image_pos.x, image_pos.y, GR_RESIZE_NONE);
gr_bitmap(image_pos.x, image_pos.y, sizing_mode);
}
}
// finished the actual drawing ---------------
if (do_screen_scaling)
gr_reset_screen_scale();
// restore old font
if (old_fontnum >= 0)
font::set_font(old_fontnum);
time_displayed += frametime;
}
@@ -832,7 +901,7 @@ void subtitle::clone(const subtitle &sub)
{
text_lines = sub.text_lines;
text_fontnum = sub.text_fontnum;
line_height_factor = sub.line_height_factor;
line_height_modifier = sub.line_height_modifier;
// copy the structs
text_pos = sub.text_pos;
@@ -855,6 +924,7 @@ void subtitle::clone(const subtitle &sub)
time_displayed_end = sub.time_displayed_end;
post_shaded = sub.post_shaded;
do_screen_scaling = sub.do_screen_scaling;
}
subtitle& subtitle::operator=(const subtitle &sub)
+5 -2
View File
@@ -123,7 +123,7 @@ private:
float fade_time;
color text_color;
int text_fontnum;
float line_height_factor;
int line_height_modifier;
//Done with set
char imageanim[MAX_FILENAME_LEN];
@@ -137,11 +137,13 @@ private:
float time_displayed_end;
bool post_shaded;
bool do_screen_scaling;
public:
subtitle(int in_x_pos, int in_y_pos, const char* in_text = NULL, const char* in_imageanim = NULL,
float in_display_time = 0, float in_fade_time = 0.0f, const color *in_text_color = NULL, int in_text_fontnum = -1,
bool center_x = false, bool center_y = false, int in_width = 0, int in_height = 0, bool post_shaded = false,
float in_line_height_factor = 1.0f);
int in_line_height_modifier = 0, bool in_adjust_wh = true);
~subtitle();
subtitle(const subtitle &sub) { clone(sub); }
@@ -154,6 +156,7 @@ public:
//Some global stuff
extern SCP_vector<subtitle> Subtitles;
extern float VIEWER_ZOOM_DEFAULT;
extern float COCKPIT_ZOOM_DEFAULT;
extern float Sexp_fov;
//Helpful functions
+4 -4
View File
@@ -74,7 +74,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf .otf", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA },
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", /* DON'T add pilot files here!! */ CF_TYPE_DATA },
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
@@ -86,7 +86,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ 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", 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_INTERFACE_MARKUP, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "markup", ".rml", CF_TYPE_INTERFACE },
@@ -635,7 +635,7 @@ void cf_create_directory(int dir_type, uint32_t location_flags)
//
// parameters: *filepath ==> name of file to open (may be path+name)
// *mode ==> specifies how file should be opened (eg "rb" for read binary)
// passing NULL to mode deletes the file if it exists and returns NULL
// passing NULL to mode triggers an assert and returns NULL
// type ==> one of: CFILE_NORMAL
// CFILE_MEMORY_MAPPED
// dir_type => override extension check, value is one of CF_TYPE* #defines
@@ -782,7 +782,7 @@ CFILE* _cfopen(const char* source, int line, const char* file_path, const char*
//
// parameters: *filepath ==> name of file to open (may be path+name)
// *mode ==> specifies how file should be opened (eg "rb" for read binary)
// passing NULL to mode deletes the file if it exists and returns NULL
// passing NULL to mode triggers an assert and returns NULL
// dir_type => override extension check, value is one of CF_TYPE* #defines
//
+16 -4
View File
@@ -1551,7 +1551,7 @@ int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* fil
}
bool skip_packfiles = false;
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
if ( (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
skip_packfiles = true;
} else if (Get_file_list_child != NULL) {
skip_packfiles = true;
@@ -1708,7 +1708,7 @@ int cf_get_file_list(int max, char** list, int pathtype, const char* filter, int
}
bool skip_packfiles = false;
if ((pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
if ((pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
skip_packfiles = true;
}
else if (Get_file_list_child != NULL) {
@@ -1887,7 +1887,7 @@ int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char**
}
bool skip_packfiles = false;
if ((pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
if ((pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
skip_packfiles = true;
}
else if (Get_file_list_child != NULL) {
@@ -1981,8 +1981,10 @@ int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char**
// Output: path - Fully qualified pathname.
//Returns 0 if the result would be too long (invalid result)
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename, bool localize,
uint32_t location_flags)
uint32_t _location_flags)
{
uint32_t location_flags = _location_flags;
if ( filename && strchr(filename, DIR_SEPARATOR_CHAR) ) {
// Already has full path
strncpy( path, filename, path_max );
@@ -1990,6 +1992,16 @@ int cf_create_default_path_string(char* path, uint path_max, int pathtype, const
} else {
cf_root* root = nullptr;
// override location flags for path types which should always come from the root (NOT mod directories)
// NOTE: cache directories should NOT be added here to avoid possible mod breakage
switch(pathtype) {
case CF_TYPE_PLAYERS:
case CF_TYPE_MULTI_PLAYERS:
case CF_TYPE_SINGLE_PLAYERS:
location_flags = CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT;
break;
}
for (auto i = 0; i < Num_roots; ++i) {
auto current_root = cf_get_root(i);
+66 -116
View File
@@ -19,6 +19,7 @@
#include "hud/hudconfig.h"
#include "io/joy.h"
#include "network/multi.h"
#include "network/multi_log.h"
#include "options/OptionsManager.h"
#include "osapi/osapi.h"
#include "parse/sexp.h"
@@ -42,6 +43,7 @@
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sstream>
#include <jansson.h>
@@ -195,6 +197,7 @@ Flag exe_params[] =
{ "-no_enhanced_sound", "Disable enhanced sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
{ "-portable_mode", "Store config in portable location", false, 0, EASY_DEFAULT, "Launcher", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-portable_mode", },
{ "-joy_info", "Outputs SDL joystick info", true, 0, EASY_DEFAULT, "Launcher", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-joy_info",},
{ "-standalone", "Run as standalone server", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-standalone", },
{ "-startgame", "Skip mainhall and start hosting", false, 0, EASY_DEFAULT, "Multiplayer", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-startgame", },
@@ -222,6 +225,7 @@ Flag exe_params[] =
{ "-noshadercache", "Disables the shader cache", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noshadercache", },
{ "-prefer_ipv4", "Prefer IPv4 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv4", },
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
{ "-log_multi_packet", "Log multi packet types ", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-log_multi_packet",},
#ifdef WIN32
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
#endif
@@ -242,6 +246,7 @@ Flag exe_params[] =
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
{ "-output_script_json", "Output scripting doc to scripting.json", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_script_json", },
{ "-controlconfig_tbl", "Save control presets to table", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-controlconfig_tbl", },
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
{ "-reparse_mainhall", "Reparse mainhall.tbl when loading halls", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-reparse_mainhall", },
@@ -310,6 +315,7 @@ int Cmdline_use_last_pilot = 0;
// Graphics related
cmdline_parm fov_arg("-fov", "Vertical field-of-view factor", AT_FLOAT); // Cmdline_fov -- comand line FOV -Bobboau
cmdline_parm fov_cockpit_arg("-fov_cockpit", "Vertical field-of-view factor for Cockpits", AT_FLOAT);
cmdline_parm clip_dist_arg("-clipdist", "Changes the distance from the viewpoint for the near-clipping plane", AT_FLOAT); // Cmdline_clip_dist
cmdline_parm spec_static_arg("-spec_static", "Adjusts suns contribution to specular highlights", AT_FLOAT);
cmdline_parm spec_point_arg("-spec_point", "Adjusts laser weapons contribution to specular highlights", AT_FLOAT);
@@ -423,6 +429,7 @@ char *Cmdline_gateway_ip = nullptr;
// Launcher related options
cmdline_parm portable_mode("-portable_mode", NULL, AT_NONE);
cmdline_parm joy_info("-joy_info", "Outputs SDL joystick info", AT_NONE);
bool Cmdline_portable_mode = false;
@@ -444,6 +451,7 @@ cmdline_parm nograb_arg("-nograb", NULL, AT_NONE);
cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
cmdline_parm log_multi_packet_arg("-log_multi_packet", nullptr, AT_NONE);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -464,6 +472,7 @@ bool Cmdline_nograb = false;
bool Cmdline_noshadercache = false;
bool Cmdline_prefer_ipv4 = false;
bool Cmdline_prefer_ipv6 = false;
bool Cmdline_dump_packet_type = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -537,6 +546,7 @@ cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", A
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
cmdline_parm output_script_json_arg("-output_script_json", nullptr, AT_NONE); // m!m
cmdline_parm generate_controlconfig_arg("-controlconfig_tbl", nullptr, AT_NONE);
// Deprecated flags - CommanderDJ
cmdline_parm deprecated_spec_arg("-spec", "Deprecated", AT_NONE);
@@ -553,18 +563,6 @@ cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NON
cmdline_parm deprecated_no_emissive_arg("-no_emissive_light", "Deprecated", AT_NONE);
cmdline_parm deprecated_postprocess_arg("-post_process", "Deprecated", AT_NONE);
int Cmdline_deprecated_spec = 0;
int Cmdline_deprecated_glow = 0;
int Cmdline_deprecated_normal = 0;
int Cmdline_deprecated_env = 0;
int Cmdline_deprecated_tbp = 0;
int Cmdline_deprecated_jpgtga = 0;
int Cmdline_deprecated_nohtl = 0;
bool Cmdline_deprecated_brief_lighting = 0;
bool Cmdline_deprecated_missile_lighting = false;
bool Cmdline_deprecated_cache_bitmaps = false;
bool Cmdline_deprecated_postprocess = false;
#ifndef NDEBUG
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
void cmdline_debug_print_cmdline()
@@ -590,61 +588,41 @@ void cmdline_debug_print_cmdline()
mprintf(("\n"));
//Print log messages about any deprecated flags we found - CommanderDJ
if(Cmdline_deprecated_spec == 1)
{
mprintf(("Deprecated flag '-spec' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_glow == 1)
{
mprintf(("Deprecated flag '-glow' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_normal == 1)
{
mprintf(("Deprecated flag '-normal' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_env == 1)
{
mprintf(("Deprecated flag '-env' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_tbp == 1)
{
mprintf(("Deprecated flag '-tbp' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_jpgtga == 1)
{
mprintf(("Deprecated flag '-jpgtga' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_nohtl == 1)
{
mprintf(("Deprecated flag '-nohtl' found. Please remove from your cmdline.\n"));
}
if(Cmdline_deprecated_brief_lighting == 1)
{
mprintf(("Deprecated flag '-brief_lighting' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_missile_lighting)
{
mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_cache_bitmaps) {
mprintf(("Deprecated flag '-cache_bitmaps' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_postprocess) {
mprintf(("Deprecated flag '-post_process' found. Please remove from your cmdline.\n"));
//Do it programmatically, rather than enumerating them by hand - MageKing17
for (parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
if (parmp->name_found && !stricmp("deprecated", parmp->help)) {
mprintf(("Deprecated flag '%s' found. Please remove from your cmdline.\n", parmp->name));
}
}
}
#endif
// prints simple cmdline to multi.log
void cmdline_print_cmdline_multi()
{
cmdline_parm *parmp;
int found = 0;
std::ostringstream cmdline;
for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
if ( parmp->name_found ) {
cmdline << " " << parmp->name;
if (parmp->args) {
cmdline << " " << parmp->args;
}
found++;
}
}
if ( !found ) {
cmdline << " <none>";
}
ml_printf("Command line:%s", cmdline.str().c_str());
}
// Return true if this character is an extra char (white space and quotes)
int is_extra_space(char ch)
{
@@ -1526,6 +1504,11 @@ bool SetCmdlineParams()
return false;
}
if (joy_info.found()) {
io::joystick::printJoyJSON();
return false;
}
if (no_fpscap.found())
{
Cmdline_NoFPSCap = 1;
@@ -1557,6 +1540,9 @@ bool SetCmdlineParams()
// is this a standalone server??
if (standalone_arg.found()) {
Is_standalone = 1;
// also enable non-interactive by default here
Cmdline_noninteractive = true;
}
}
@@ -1813,6 +1799,16 @@ bool SetCmdlineParams()
}
}
if ( fov_cockpit_arg.found() ) {
auto val = fov_cockpit_arg.get_float();
if (val > 0.1) {
COCKPIT_ZOOM_DEFAULT = val;
}
else {
COCKPIT_ZOOM_DEFAULT = VIEWER_ZOOM_DEFAULT;
}
}
if( clip_dist_arg.found() ) {
Min_draw_distance = Cmdline_clip_dist = clip_dist_arg.get_float();
}
@@ -1941,6 +1937,9 @@ bool SetCmdlineParams()
Cmdline_output_sexp_info = true;
}
if (generate_controlconfig_arg.found())
Generate_controlconfig_table = true;
if ( no_pbo_arg.found() )
{
Cmdline_no_pbo = 1;
@@ -2168,63 +2167,10 @@ bool SetCmdlineParams()
}
//Deprecated flags - CommanderDJ
if( deprecated_spec_arg.found() )
{
Cmdline_deprecated_spec = 1;
}
if( deprecated_glow_arg.found() )
{
Cmdline_deprecated_glow = 1;
}
if( deprecated_normal_arg.found() )
{
Cmdline_deprecated_normal = 1;
}
if( deprecated_env_arg.found() )
{
Cmdline_deprecated_env = 1;
}
if( deprecated_tbp_arg.found() )
{
Cmdline_deprecated_tbp = 1;
}
if( deprecated_jpgtga_arg.found() )
{
Cmdline_deprecated_jpgtga = 1;
}
if ( deprecated_htl_arg.found() )
{
Cmdline_deprecated_nohtl = 1;
}
if ( deprecated_brieflighting_arg.found() )
{
Cmdline_deprecated_brief_lighting = 1;
}
if (deprecated_missile_lighting_arg.found())
{
Cmdline_deprecated_missile_lighting = true;
}
if (deprecated_cache_bitmaps_arg.found()) {
Cmdline_deprecated_cache_bitmaps = true;
}
if (deprecated_no_emissive_arg.found()) {
Cmdline_emissive = 0;
}
if (deprecated_postprocess_arg.found()) {
Cmdline_deprecated_postprocess = true;
}
if (deprecated_fxaa_arg.found() ) {
Gr_aa_mode = AntiAliasMode::FXAA_Medium;
@@ -2280,6 +2226,10 @@ bool SetCmdlineParams()
}
}
if (log_multi_packet_arg.found()) {
Cmdline_dump_packet_type = true;
}
return true;
}
+1
View File
@@ -125,6 +125,7 @@ extern bool Cmdline_nograb;
extern bool Cmdline_noshadercache;
extern bool Cmdline_prefer_ipv4;
extern bool Cmdline_prefer_ipv6;
extern bool Cmdline_dump_packet_type;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
+63 -20
View File
@@ -190,8 +190,8 @@ static unsigned int Defaults_cycle_pos = 0; // the controls preset that was last
int Control_config_overlay_id;
struct conflict {
int first = -1; // index of other control in conflict with this one
int second = -1; // index of other control in conflict with this one
int first = -1; // index of other control in conflict with this one
int second = -1; // index of other control in conflict with this one
};
SCP_vector<conflict> Conflicts;
@@ -1137,8 +1137,7 @@ void control_config_toggle_invert()
item.second.invert_toggle();
break;
default:
// unhandled
mprintf(("Unhandled selItem in control_config_toggle_invert(): %i", static_cast<int>(Selected_item)));
UNREACHABLE("Unhandled selItem in control_config_toggle_invert(): %i\n", static_cast<int>(Selected_item));
}
}
@@ -1287,6 +1286,15 @@ int control_config_accept()
}
SCP_string str = cstr;
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(),
[str](CC_preset& p) { return (p.name == str) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode)); });
if (it != Control_config_presets.end()) {
popup(flags, 1, POPUP_OK, "You may not overwrite a default preset. Please choose another name.");
goto retry;
}
// Check if a preset file with name already exists. If so, prompt the user
CFILE* fp = cfopen((str + ".json").c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
@@ -1657,8 +1665,7 @@ void control_config_draw_selected_preset() {
auto preset_it = control_config_get_current_preset();
if (preset_it != Control_config_presets.end()) {
sprintf(preset_str, XSTR("Preset: %s", 1659), preset_it->name.c_str());
sprintf(preset_str, XSTR("Preset: %s", 1659), preset_it->name.c_str());
} else {
sprintf(preset_str, XSTR("Preset: custom", 1660), "");
}
@@ -2532,7 +2539,7 @@ int check_control_used(int id, int key)
return 0;
}
if (item.disabled)
if (item.disabled || item.locked)
return 0;
short z = item.get_btn(CID_KEYBOARD); // Get the key that's bound to this control
@@ -2601,30 +2608,43 @@ int check_control_used(int id, int key)
int check_control(int id, int key)
{
if (check_control_used(id, key)) {
if (Ignored_keys[id]) {
if (Ignored_keys[id] > 0) {
Ignored_keys[id]--;
}
return 0;
}
return 1;
const bool is_control_used = check_control_used(id, key) != 0;
const bool is_ignored = Ignored_keys[id] != 0;
//Decrement Ignored_keys if key was pressed and is ignored
if (is_control_used && Ignored_keys[id] > 0) {
Ignored_keys[id]--;
}
if (Control_config[id].continuous_ongoing) {
int control_triggered = 0; // boolean as int (0 = false, 1 = true); Weirdness for compatibility with control_run_lua();
if (is_control_used && !is_ignored) {
control_triggered = 1;
}
if (Control_config[id].type == CC_TYPE_CONTINUOUS) {
// Only call lua in here when it's a continuous button
if (control_run_lua(static_cast<IoActionId>(id), control_triggered)) {
// lua has taken care of the control already. Mark as not triggered to prevent hardcode from executing.
control_triggered = 0;
} // Else, let hardcode process the control
}
if (!is_control_used && Control_config[id].continuous_ongoing) {
// If we reach this point, then it means this is a continuous control
// which has just been released
if (Script_system.IsActiveAction(CHA_ONACTIONSTOPPED)) {
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, nullptr, id);
Script_system.RemHookVar("Action");
}
Control_config[id].continuous_ongoing = false;
}
return 0;
return control_triggered;
}
/**
@@ -2753,7 +2773,8 @@ void control_get_axes_readings(int *axis_v, float frame_time)
mouse_get_delta(&axe[MOUSE_ID][MOUSE_X_AXIS], &axe[MOUSE_ID][MOUSE_Y_AXIS], &axe[MOUSE_ID][MOUSE_Z_AXIS]);
for (int action = 0; action < Action::NUM_VALUES; ++action) {
CCI & item = Control_config[action + JOY_AXIS_BEGIN];
const auto action_id = static_cast<IoActionId>(action + JOY_AXIS_BEGIN);
CCI & item = Control_config[action_id];
// Assume actions are all axis actions, no need to check
// Assumes all axes are uniquely bound to an action
@@ -2766,6 +2787,28 @@ void control_get_axes_readings(int *axis_v, float frame_time)
if (!item.second.empty()) {
scale_invert(item.second, action, item.type, frame_time, axe, axis_v);
}
//Call Lua hooks
if (control_run_lua(action_id, axis_v[action])) {
Assert(item.type == CC_TYPE_AXIS_ABS || item.type == CC_TYPE_AXIS_REL);
switch (item.type) {
case CC_TYPE_AXIS_ABS:
axis_v[action] = item.used;
break;
case CC_TYPE_AXIS_REL:
axis_v[action] = 0;
break;
case CC_TYPE_AXIS_BTN_NEG:
case CC_TYPE_AXIS_BTN_POS:
default:
//This should never happen, especially with the above Assertion. This is required as incomplete switches on an enum generate warnings
break;
}
}
//Store values for possible lua override
item.used = axis_v[action];
}
}
@@ -2781,7 +2824,7 @@ void control_used(int id)
if (Control_config[id].used < Last_frame_timestamp) {
if (!Control_config[id].continuous_ongoing) {
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTION, nullptr, id);
Script_system.RunCondition(CHA_ONACTION, nullptr, nullptr, id);
Script_system.RemHookVar("Action");
if (Control_config[id].type == CC_TYPE_CONTINUOUS)
+136 -35
View File
@@ -12,6 +12,7 @@
#define CONTROLS_CONFIG_H
#include "globalincs/pstypes.h"
#include "scripting/scripting.h"
#define CONTROL_CONFIG_XSTR 507
@@ -21,6 +22,7 @@
#define CCF_AXIS 0x08 //!< btn is an axis
#define CCF_HAT 0x04 //!< btn is a hat
#define CCF_BALL 0x02 //!< btn is a ball
#define CCF_BUTTON 0x01 //!< btn is actually a button
/*!
* These are used to index a corresponding axis value from an array.
@@ -320,6 +322,15 @@ enum {
};
}
/*!
* Where the preset is located in memory
*/
enum class Preset_t {
hardcode, // Preset is defined hardcode
tbl, // Preset is defined in controlconfigdefaults.tbl
pst // Preset is defined in a .json
};
class CCB;
/*!
@@ -361,6 +372,16 @@ public:
*/
bool empty() const;
/**
* Takes the given binding.
*/
void take(CID _cid, short _btn, char _flags = 0);
/**
* Validates the binding, clearing it if necassary
*/
void validate();
/*!
* Returns a copy of ::btn
*/
@@ -376,16 +397,6 @@ public:
*/
char get_flags() const;
/**
* Takes the given binding.
*/
void take(CID _cid, short _btn, char _flags = 0);
/**
* Validates the binding, clearing it if necassary
*/
void validate();
/*!
* Returns a human-readable string of this binding
*/
@@ -468,12 +479,12 @@ public:
/*!
* Checks if the given CCB is exactly equal to this
*/
bool operator==(const CCB&);
bool operator==(const CCB&) const;
/*!
* Checks if the given CCB differs from this
*/
bool operator!=(const CCB&);
bool operator!=(const CCB&) const;
/*!
* Returns True if this CCB's first isn't empty and the given CCB has a binding that can conflict with it
@@ -499,6 +510,21 @@ public:
* Returns a pointer to first, or second, whichever has *all* flags in the given mask
*/
CC_bind* find_flags(const char);
/*!
* Sets the inversion state of both bindings
*/
void invert(bool);
/*!
* Toggles the inversion state of Primary and copies it to Secondary
*/
void invert_toggle();
/*!
* Is true if both bindings are inverted, false otherwise
*/
bool is_inverted() const;
};
/*!
@@ -508,8 +534,13 @@ class CC_preset {
public:
SCP_vector<CCB> bindings;
SCP_string name;
Preset_t type;
public:
CC_preset() = default;
CC_preset(const CC_preset& A) = default;
CC_preset& operator=(const CC_preset&);
/*!
* Checks if the given preset is a duplicate of this one
*/
@@ -534,8 +565,10 @@ public:
CC_type type; //!< manner control should be checked in
// Items used during gameplay
int used; //!< has control been used yet in mission? If so, this is the timestamp
int used; //!< has control been used yet in mission? If so, this is the timestamp. For axes, this denotes the last frame's value
bool disabled = true; //!< whether this action should be available at all
bool locked = false; //!< whether this action will be triggered by the respectively bound key
bool scriptEnabledByDefault = false; //!< whether this binding will execute it's registered hooks if triggered. Resets each mission
bool continuous_ongoing; //!< whether this action is a continuous one and is currently ongoing
public:
@@ -613,9 +646,10 @@ extern int Control_config_overlay_id;
extern SCP_vector<CCI> Control_config; //!< Stores the keyboard configuration
extern SCP_vector<CC_preset> Control_config_presets; // tabled control presets; pointers to config_item arrays
extern const char **Scan_code_text;
extern const char **Joy_button_text; // String table of button labels. XSTR'd on init.
extern bool Generate_controlconfig_table;
// string table constants for labels and stuff.
#define NUM_AXIS_TEXT JOY_NUM_AXES
#define NUM_MOUSE_TEXT MOUSE_NUM_BUTTONS
@@ -690,7 +724,10 @@ bool control_config_use_preset_by_name(const SCP_string &name);
*
* @returns an iterator to the current preset, or
* @returns ::iterator Control_config_presets.end() if current bindings are not in a preset
*
* @note Similar to preset_find_duplicate, this function has additional logic in its search to ignore disabled controls
*/
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic = false);
/*!
@@ -726,10 +763,9 @@ int translate_key_to_index(const char *key, bool find_override=true);
const char *translate_key(char *key);
/**
* @brief Converts the specified key code to a human readable string, according to the selected locale
* @brief Converts the specified key code to a human readable string, according to the selected locale and keyboard layout
*
* @param[in] code The key code to convert
* @param[in] use_default_locale If true, return the default locale (English) translation of the key
* @param[in] code The key scancode to convert
*
* @return The text representation of the code.
*
@@ -737,7 +773,18 @@ const char *translate_key(char *key);
*
* @note The return value is translated according to localization settings
*/
const char *textify_scancode(int code, bool use_default_locale = false);
const char *textify_scancode(int code);
/**
* @brief Converts the specified key code to a human readable string. Uses the English locale and QWERTY layout.
*
* @param[in] code The key scancode to convert
*
* @return The text representation of the code
*
* @note Not thread safe. Has an internal buffer for the return value which is overwritten on each call.
*/
const char *textify_scancode_universal(int code);
/*!
* @brief Checks how long a control has been active
@@ -784,6 +831,35 @@ void control_get_axes_readings(int *axis_v, float frame_time);
*/
void control_used(int id);
/**
* @brief Runs a given controlbindings lua hook added in ccd.tbl
*
* @return Whether the control should be overridden
*/
bool control_run_lua(IoActionId id, int value);
/**
* @brief Resets the cache for script evaluations for continuous buttons. Should be called once per frame.
*
*/
void control_reset_lua_cache();
/**
* @brief Registers a new hook for the keybinding action system.
* Parameters set if it is a normal or an override function, as well as if it is enabled by default or needs to be enabled manually each mission
*/
void control_register_hook(IoActionId id, const luacpp::LuaFunction& hook, bool is_override, bool enabledByDefault);
/**
* @brief Enables or disables the respective Lua hook
*/
void control_enable_hook(IoActionId id, bool enable);
/**
* @brief Resets every hooks enable state to the tabled value. Call on Mission start
*/
void control_reset_hook();
/**
* @brief Clears the bindings of all controls
*/
@@ -836,18 +912,17 @@ CID CIDToVal(const char * str);
/**
* Reverse lookups the CID to get its stringified name
* @return Pointer to the stringified name of the CID, or
* @return nullptr if not found
* @return The stringified name of the CID, or
* @return "NONE" if not found
*/
const char * ValToCID(CID id);
SCP_string ValToCID(CID id);
/**
* Reverse lookups the CID to get its stringified name
* @return Pointer to the stringified name of the CID, or
* @return nullptr if not found, or invalid id
* @return The stringified name of the CID, or
* @return "NONE" if not found, or invalid id
*/
const char * ValToCID(int id);
SCP_string ValToCID(int id);
/**
* Lookups the given stringified enum to find its value
*/
@@ -855,8 +930,8 @@ char CCFToVal(const char * str);
/**
* Constructs a enum string from the CCF_FLAGS
* @return Pointer to the stringified name of the CCF, or
* @return nullptr if not found, or invalid id
* @return The stringified name of the CCF, or
* @return "NONE" if not found, or invalid id
*/
SCP_string ValToCCF(char id);
@@ -868,8 +943,8 @@ short InputToVal(CID cid, const char * str);
/**
* Constructs a enumstring from the input binding, depending on the CID
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
* @return The stringified name of the input, or
* @return "NONE" if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
*/
@@ -883,8 +958,8 @@ short MouseToVal(const char * str);
/**
* Constructs a enum string from the mouse input
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
* @return The stringified name of the input, or
* @return "NONE" if not found, or invalid CC_bind
* TODO XSTR
*
* @note This requires a CCB due to the way things are encoded
@@ -899,8 +974,8 @@ short KeyboardToVal(const char * str);
/**
* Constructs an enum string from the key binding
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
* @return The stringified name of the input, or
* @return "NONE" f not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
* TODO XSTR
@@ -915,11 +990,37 @@ short JoyToVal(const char * str);
/**
* Constructs a enum string from the Joystick input
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
* @return The stringified name of the input, or
* @return "NONE" if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
* TODO XSTR
*/
SCP_string ValToJoy(const CC_bind &bind);
/**
* Lookups the given string to find its tab value
*/
char CCTabToVal(const char *str);
/**
* Reverse lookups the given tab in mCCTabToVal to retrieve the string name
*
* @return The stringified name of the input, or
* @return nullptr if not found, or invalid tab
*
*/
SCP_string ValToCCTab(char tab);
/**
* Lookups the given string to find its CC_type value. =
*/
CC_type CCTypeToVal(const char *str);
/**
* Reverse lookups the given CC_type to retrieve the string name
*/
SCP_string ValToCCType(CC_type type);
#endif
File diff suppressed because it is too large. Load diff
+32 -14
View File
@@ -47,7 +47,7 @@ void load_preset_files() {
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!fp) {
mprintf(("PLR => Unable to open '%s' for loading!\n", file.c_str()));
mprintf(("PST => Unable to open '%s' for loading!\n", file.c_str()));
// try next
continue;
}
@@ -55,7 +55,7 @@ void load_preset_files() {
try {
handler.reset(new PresetFileHandler(fp, true));
} catch (const std::exception& e) {
mprintf(("PLR => Failed to open JSON: `%s`\n", e.what()));
mprintf(("PST => Failed to open JSON: `%s`\n", e.what()));
continue;
}
@@ -74,6 +74,7 @@ void load_preset_files() {
// Start reading in data
CC_preset preset;
preset.name = file;
preset.type = Preset_t::pst;
preset.bindings.resize(Control_config.size());
size_t size;
@@ -104,6 +105,7 @@ void load_preset_files() {
str = handler->readString("input");
auto btn = InputToVal(cid, str.c_str());
item.first.take(cid, btn, flags);
handler->endSectionRead(); // Primary
@@ -124,21 +126,16 @@ void load_preset_files() {
handler->endArrayRead(); // Actions
// Done with the file
bool unique = true;
auto it = Control_config_presets.begin();
for (; it != Control_config_presets.end(); ++it) {
if (preset.is_duplicate_of(*it)) {
unique = false;
break;
}
}
auto it = preset_find_duplicate(preset);
if (unique) {
if (it == Control_config_presets.end()) {
Control_config_presets.push_back(preset);
} else {
Warning(LOCATION, "Preset '%s' is a duplicate of '%s', ignoring", preset.name.c_str(), it->name.c_str());
}
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
// Complain and ignore if the preset names or the type differs
Warning(LOCATION, "PST => Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
} // else, silent ignore
}
}
@@ -220,6 +217,27 @@ bool save_preset_file(CC_preset preset, bool overwrite) {
return true;
}
SCP_vector<CC_preset>::iterator preset_find_duplicate(const CC_preset& new_preset) {
SCP_vector<CC_preset>::iterator it = Control_config_presets.begin(); // NOLINT(modernize-use-auto)
for (; it != Control_config_presets.end(); ++it) {
size_t i;
for (i = 0; i < it->bindings.size(); ++i) {
if (new_preset.bindings[i] != it->bindings[i]) {
// These two differ, check the next in the vector
break;
}
}
if (i == it->bindings.size()) {
// These two are equal
break;
}
}
return it;
}
PresetFileHandler::PresetFileHandler(CFILE* cfp, bool reading) : _cfp(cfp) {
Assertion(cfp != nullptr, "File pointer must be valid!");
+8
View File
@@ -216,6 +216,14 @@ bool save_preset_file(CC_preset preset, bool overwrite);
*/
void load_preset_files();
/**
* @brief Checks if the given preset is a duplicate within Control_config_presets vector
* @returns iterator to the duplicate if found, or
* @returns iterator to Control_config_presets.end() otherwise
*/
SCP_vector<CC_preset>::iterator preset_find_duplicate(const CC_preset& new_preset);
/**
* @brief Returns true if a preset file with the given name exists.
*/
+1
View File
@@ -51,6 +51,7 @@ void processEvents()
{
io::mouse::CursorManager::get()->showCursor(false);
os_remove_deferred_cutscene_key_events();
os_poll();
}
+5 -3
View File
@@ -668,9 +668,11 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
// ensure vel is valid
Assert( !vm_is_vec_nan(&obj->phys_info.vel) );
OnDebrisCreatedHook->run(scripting::hook_param_list(
scripting::hook_param("Debris", 'o', obj),
scripting::hook_param("Source", 'o', source_obj)));
if (OnDebrisCreatedHook->isActive()) {
OnDebrisCreatedHook->run(scripting::hook_param_list(
scripting::hook_param("Debris", 'o', obj),
scripting::hook_param("Source", 'o', source_obj)));
}
if (db->is_hull) {
MONITOR_INC(NumHullDebris,1);
+24 -5
View File
@@ -488,6 +488,21 @@ void dc_putc(char c)
line_str->push_back(c);
}
bool handle_textInputEvent(const SDL_Event& event) {
if (event.text.text[0] != '\0' && event.text.text[0] != '\1') {
for (char c : event.text.text) {
if (c < 32)
break;
if (dc_command_buf.size() < MAX_CLI_LEN) {
dc_command_buf.push_back(c);
}
}
}
return true;
}
void debug_console(void (*_func)(void))
{
int done = 0;
@@ -500,6 +515,9 @@ void debug_console(void (*_func)(void))
dc_init();
}
auto textListener = os::events::addEventListener(SDL_TEXTINPUT, 10000, &handle_textInputEvent);
SDL_StartTextInput();
dc_draw(TRUE);
while (!done) {
@@ -586,11 +604,9 @@ void debug_console(void (*_func)(void))
break;
default:
// Not any of the control key codes, so it's probably a letter or number.
ubyte c = (ubyte)key_to_ascii(k);
if ((c != 255) && (dc_command_buf.size() < MAX_CLI_LEN)) {
dc_command_buf.push_back(c);
}
// Leave handling of key input to SDL
break;
}
// Do the passed function
@@ -602,6 +618,9 @@ void debug_console(void (*_func)(void))
dc_draw(TRUE);
}
SDL_StopTextInput();
os::events::removeEventListener(textListener);
while( key_inkey() ) {
os_poll();
}
+181 -211
View File
@@ -9,179 +9,158 @@
#include "tracing/tracing.h"
#include "ship/ship.h"
namespace {
namespace decals {
class DecalDefinition {
SCP_string _name;
DecalDefinition::DecalDefinition(SCP_string name) : _name(std::move(name)) {
}
SCP_string _diffuseFilename;
bool _loopDiffuse = true;
SCP_string _glowFilename;
bool _loopGlow = true;
SCP_string _normalMapFilename;
bool _loopNormal = true;
int _diffuseBitmap = -1;
int _glowBitmap = -1;
int _normalBitmap = -1;
public:
explicit DecalDefinition(SCP_string name) : _name(std::move(name)) {
DecalDefinition::~DecalDefinition() {
if (_diffuseBitmap >= 0) {
bm_release(_diffuseBitmap);
}
if (_glowBitmap >= 0) {
bm_release(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_release(_normalBitmap);
}
}
~DecalDefinition() {
if (_diffuseBitmap >= 0) {
bm_release(_diffuseBitmap);
DecalDefinition::DecalDefinition(DecalDefinition&& other) noexcept {
*this = std::move(other); // Use operator implementation
}
DecalDefinition& DecalDefinition::operator=(DecalDefinition&& other) noexcept {
std::swap(_name, other._name);
std::swap(_diffuseFilename, other._diffuseFilename);
std::swap(_glowFilename, other._glowFilename);
std::swap(_normalMapFilename, other._normalMapFilename);
std::swap(_diffuseBitmap, other._diffuseBitmap);
std::swap(_glowBitmap, other._glowBitmap);
std::swap(_normalBitmap, other._normalBitmap);
std::swap(_loopDiffuse, other._loopDiffuse);
std::swap(_loopGlow, other._loopGlow);
std::swap(_loopNormal, other._loopNormal);
return *this;
}
void DecalDefinition::parse() {
if (optional_string("+Diffuse:")) {
stuff_string(_diffuseFilename, F_FILESPEC);
if (!bm_validate_filename(_diffuseFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _diffuseFilename.c_str());
_diffuseFilename = "";
}
if (_glowBitmap >= 0) {
bm_release(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_release(_normalBitmap);
if (optional_string("+Loop:")) {
stuff_boolean(&_loopDiffuse);
}
}
if (optional_string("+Glow:")) {
stuff_string(_glowFilename, F_FILESPEC);
// Disallow copying
DecalDefinition(const DecalDefinition&) = delete;
DecalDefinition& operator=(const DecalDefinition&) = delete;
// Move constructor and operator
DecalDefinition(DecalDefinition&& other) noexcept {
*this = std::move(other); // Use operator implementation
}
DecalDefinition& operator=(DecalDefinition&& other) noexcept {
std::swap(_name, other._name);
std::swap(_diffuseFilename, other._diffuseFilename);
std::swap(_glowFilename, other._glowFilename);
std::swap(_normalMapFilename, other._normalMapFilename);
std::swap(_diffuseBitmap, other._diffuseBitmap);
std::swap(_glowBitmap, other._glowBitmap);
std::swap(_normalBitmap, other._normalBitmap);
std::swap(_loopDiffuse, other._loopDiffuse);
std::swap(_loopGlow, other._loopGlow);
std::swap(_loopNormal, other._loopNormal);
return *this;
}
void parse() {
if (optional_string("+Diffuse:")) {
stuff_string(_diffuseFilename, F_FILESPEC);
if (!bm_validate_filename(_diffuseFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _diffuseFilename.c_str());
_diffuseFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopDiffuse);
}
if (!bm_validate_filename(_glowFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _glowFilename.c_str());
_glowFilename = "";
}
if (optional_string("+Glow:")) {
stuff_string(_glowFilename, F_FILESPEC);
if (!bm_validate_filename(_glowFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _glowFilename.c_str());
_glowFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopGlow);
}
}
if (optional_string("+Normal:")) {
stuff_string(_normalMapFilename, F_FILESPEC);
if (!bm_validate_filename(_normalMapFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _normalMapFilename.c_str());
_normalMapFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopNormal);
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopGlow);
}
}
if (optional_string("+Normal:")) {
stuff_string(_normalMapFilename, F_FILESPEC);
void loadBitmaps() {
if (_diffuseBitmap == -1 && VALID_FNAME(_diffuseFilename)) {
_diffuseBitmap = bm_load_either(_diffuseFilename.c_str());
if (_diffuseBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_diffuseFilename.c_str(),
_name.c_str());
}
if (!bm_validate_filename(_normalMapFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _normalMapFilename.c_str());
_normalMapFilename = "";
}
if (_glowBitmap == -1 && VALID_FNAME(_glowFilename)) {
_glowBitmap = bm_load_either(_glowFilename.c_str());
if (_glowBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_glowFilename.c_str(),
_name.c_str());
}
}
if (_normalBitmap == -1 && VALID_FNAME(_normalMapFilename)) {
_normalBitmap = bm_load_either(_normalMapFilename.c_str());
if (_normalBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_normalMapFilename.c_str(),
_name.c_str());
}
}
}
void pageIn() {
if (_diffuseBitmap >= 0) {
bm_page_in_texture(_diffuseBitmap);
}
if (_glowBitmap >= 0) {
bm_page_in_texture(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_page_in_texture(_normalBitmap);
if (optional_string("+Loop:")) {
stuff_boolean(&_loopNormal);
}
}
}
bool bitmapsLoaded() {
// Since both bitmap types are optional we need to check if either is loaded to determine if any bitmap is loaded
return _diffuseBitmap >= 0 || _glowBitmap >= 0 || _normalBitmap >= 0;
void DecalDefinition::loadBitmaps() {
if (_diffuseBitmap == -1 && VALID_FNAME(_diffuseFilename)) {
_diffuseBitmap = bm_load_either(_diffuseFilename.c_str());
if (_diffuseBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_diffuseFilename.c_str(),
_name.c_str());
}
}
if (_glowBitmap == -1 && VALID_FNAME(_glowFilename)) {
_glowBitmap = bm_load_either(_glowFilename.c_str());
if (_glowBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_glowFilename.c_str(),
_name.c_str());
}
}
if (_normalBitmap == -1 && VALID_FNAME(_normalMapFilename)) {
_normalBitmap = bm_load_either(_normalMapFilename.c_str());
if (_normalBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_normalMapFilename.c_str(),
_name.c_str());
}
}
}
const SCP_string& getName() const {
return _name;
void DecalDefinition::pageIn() {
if (_diffuseBitmap >= 0) {
bm_page_in_texture(_diffuseBitmap);
}
int getDiffuseBitmap() const {
return _diffuseBitmap;
if (_glowBitmap >= 0) {
bm_page_in_texture(_glowBitmap);
}
int getGlowBitmap() const {
return _glowBitmap;
if (_normalBitmap >= 0) {
bm_page_in_texture(_normalBitmap);
}
int getNormalBitmap() const {
return _normalBitmap;
}
bool isDiffuseLooping() const {
return _loopDiffuse;
}
bool isGlowLooping() const {
return _loopGlow;
}
bool isNormalLooping() const {
return _loopNormal;
}
};
}
SCP_vector<DecalDefinition> decalDefinitions;
bool DecalDefinition::bitmapsLoaded() {
// Since both bitmap types are optional we need to check if either is loaded to determine if any bitmap is loaded
return _diffuseBitmap >= 0 || _glowBitmap >= 0 || _normalBitmap >= 0;
}
const SCP_string& DecalDefinition::getName() const {
return _name;
}
int DecalDefinition::getDiffuseBitmap() const {
return _diffuseBitmap;
}
int DecalDefinition::getGlowBitmap() const {
return _glowBitmap;
}
int DecalDefinition::getNormalBitmap() const {
return _normalBitmap;
}
bool DecalDefinition::isDiffuseLooping() const {
return _loopDiffuse;
}
bool DecalDefinition::isGlowLooping() const {
return _loopGlow;
}
bool DecalDefinition::isNormalLooping() const {
return _loopNormal;
}
SCP_vector<DecalDefinition> DecalDefinitions;
// Variable to indicate if the system is able to work correctly on the current system
bool decal_system_active = true;
bool Decal_system_active = true;
void parse_decals_table(const char* filename) {
try {
@@ -197,7 +176,7 @@ void parse_decals_table(const char* filename) {
DecalDefinition def(name);
def.parse();
decalDefinitions.push_back(std::move(def));
DecalDefinitions.push_back(std::move(def));
}
required_string("#End");
@@ -208,17 +187,17 @@ void parse_decals_table(const char* filename) {
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
// we need deferred lighting
decal_system_active = false;
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
}
if (!gr_is_capable(CAPABILITY_NORMAL_MAP)) {
// We need normal mapping for the full feature range
decal_system_active = false;
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
}
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
// WWe need separate blending functions for different color buffers
decal_system_active = false;
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
}
}
@@ -314,35 +293,41 @@ float smoothstep(float edge0, float edge1, float x) {
namespace decals {
void initialize() {
decalDefinitions.clear();
if (gr_screen.mode == GR_STUB) {
Decal_system_active = false;
return;
}
DecalDefinitions.clear();
graphics::decal_draw_list::globalInit();
parse_modular_table(NOX("*-dcl.tbm"), parse_decals_table);
}
void shutdown() {
graphics::decal_draw_list::globalShutdown();
// Free allocated resources
decalDefinitions.clear();
DecalDefinitions.clear();
}
int getDecalConfig(const SCP_string& name) {
int index = 0;
for (auto& def : decalDefinitions) {
if (!stricmp(def.getName().c_str(), name.c_str())) {
return index;
}
++index;
}
int findDecalDefinition(const SCP_string& name) {
auto ii = std::find_if(DecalDefinitions.begin(), DecalDefinitions.end(), [&](const DecalDefinition& def)
{
return def.getName() == name;
});
return -1;
if (ii == DecalDefinitions.end())
return -1;
return static_cast<int>(std::distance(DecalDefinitions.begin(), ii));
}
void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
SCP_string name;
stuff_string(name, F_NAME);
auto decalRef = getDecalConfig(name);
auto decalRef = findDecalDefinition(name);
if (decalRef < 0) {
error_display(0, "Decal definition '%s' is unknown!", name.c_str());
@@ -367,8 +352,9 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
}
}
}
void loadBitmaps(const creation_info& info) {
if (!decal_system_active) {
if (!Decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
@@ -376,15 +362,16 @@ void loadBitmaps(const creation_info& info) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) DecalDefinitions.size(),
"Invalid decal handle detected!");
auto& def = decalDefinitions[info.definition_handle];
auto& def = DecalDefinitions[info.definition_handle];
def.loadBitmaps();
}
void pageInDecal(const creation_info& info) {
if (!decal_system_active) {
if (!Decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
@@ -392,10 +379,10 @@ void pageInDecal(const creation_info& info) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) DecalDefinitions.size(),
"Invalid decal handle detected!");
decalDefinitions[info.definition_handle].pageIn();
DecalDefinitions[info.definition_handle].pageIn();
}
void initializeMission() {
@@ -411,48 +398,25 @@ matrix4 getDecalTransform(Decal& decal) {
auto pm = model_get(pmi->model_num);
vec3d worldPos;
model_instance_local_to_global_point(&worldPos,
matrix worldOrient;
model_instance_local_to_global_point_orient(&worldPos,
&worldOrient,
&decal.position,
&decal.orientation,
pm,
pmi,
decal.submodel,
&objp->orient,
&objp->pos);
vec3d worldDir;
model_instance_local_to_global_dir(&worldDir,
&decal.orientation.vec.fvec,
pm,
pmi,
decal.submodel,
&objp->orient);
// The decal API sees the "direction" of a decal to be along the normal of the surface it is attached to. However,
// this will lead to a situation where we would look at the decal texture "from behind" causing the texture to
// appear flipped. We fix that here for the graphics transform.
vm_vec_scale(&worldDir, -1.0f);
vec3d worldUp;
model_instance_local_to_global_dir(&worldUp,
&decal.orientation.vec.uvec,
pm,
pmi,
decal.submodel,
&objp->orient);
matrix worldOrient;
vm_vector_2_matrix(&worldOrient, &worldDir, &worldUp);
// appear flipped. We fix that here for the graphics transform by inverting the Z scaling.
// Apply scaling
worldOrient.a2d[0][0] *= decal.scale.xyz.x;
worldOrient.a2d[0][1] *= decal.scale.xyz.x;
worldOrient.a2d[0][2] *= decal.scale.xyz.x;
worldOrient.a2d[1][0] *= decal.scale.xyz.y;
worldOrient.a2d[1][1] *= decal.scale.xyz.y;
worldOrient.a2d[1][2] *= decal.scale.xyz.y;
worldOrient.a2d[2][0] *= decal.scale.xyz.z;
worldOrient.a2d[2][1] *= decal.scale.xyz.z;
worldOrient.a2d[2][2] *= decal.scale.xyz.z;
vm_vec_scale(&worldOrient.vec.rvec, decal.scale.xyz.x);
vm_vec_scale(&worldOrient.vec.uvec, decal.scale.xyz.y);
vm_vec_scale(&worldOrient.vec.fvec, -decal.scale.xyz.z);
matrix4 mat4;
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
@@ -461,7 +425,7 @@ matrix4 getDecalTransform(Decal& decal) {
}
void renderAll() {
if (!decal_system_active) {
if (!Decal_system_active) {
return;
}
@@ -492,9 +456,9 @@ void renderAll() {
int glow_bm = -1;
int normal_bm = -1;
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int) decalDefinitions.size(),
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int) DecalDefinitions.size(),
"Invalid decal handle detected!");
auto& decalDef = decalDefinitions[decal.definition_handle];
auto& decalDef = DecalDefinitions[decal.definition_handle];
auto decal_time = mission_time - decal.creation_time;
auto progress = decal_time / decal.lifetime;
@@ -525,9 +489,9 @@ void renderAll() {
draw_list.render();
}
void
addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
if (!decal_system_active) {
void addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
if (!Decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
@@ -535,9 +499,9 @@ addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) DecalDefinitions.size(),
"Invalid decal handle detected!");
auto& def = decalDefinitions[info.definition_handle];
auto& def = DecalDefinitions[info.definition_handle];
if (!def.bitmapsLoaded()) {
// If this decal was never used before then the bitmaps are not loaded so we need to do that here.
@@ -554,9 +518,15 @@ addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos
newDecal.position = local_pos;
newDecal.orientation = local_orient;
newDecal.scale.xyz.x = info.radius;
newDecal.scale.xyz.y = info.radius;
newDecal.scale.xyz.z = info.radius;
if (info.width < 0.0f || info.height < 0.0f) {
newDecal.scale.xyz.x = info.radius;
newDecal.scale.xyz.y = info.radius;
newDecal.scale.xyz.z = info.radius;
} else {
newDecal.scale.xyz.x = info.width;
newDecal.scale.xyz.y = info.height;
newDecal.scale.xyz.z = MIN(info.width, info.height);
}
active_decals.push_back(newDecal);
}
+53
View File
@@ -8,6 +8,52 @@
namespace decals {
class DecalDefinition {
SCP_string _name;
SCP_string _diffuseFilename;
bool _loopDiffuse = true;
SCP_string _glowFilename;
bool _loopGlow = true;
SCP_string _normalMapFilename;
bool _loopNormal = true;
int _diffuseBitmap = -1;
int _glowBitmap = -1;
int _normalBitmap = -1;
public:
explicit DecalDefinition(SCP_string name);
~DecalDefinition();
// Disallow copying
DecalDefinition(const DecalDefinition&) = delete;
DecalDefinition& operator=(const DecalDefinition&) = delete;
// Move constructor and operator
DecalDefinition(DecalDefinition&& other) noexcept;
DecalDefinition& operator=(DecalDefinition&& other) noexcept;
void parse();
void loadBitmaps();
void pageIn();
bool bitmapsLoaded();
const SCP_string& getName() const;
int getDiffuseBitmap() const;
int getGlowBitmap() const;
int getNormalBitmap() const;
bool isDiffuseLooping() const;
bool isGlowLooping() const;
bool isNormalLooping() const;
};
extern SCP_vector<DecalDefinition> DecalDefinitions;
extern bool Decal_system_active;
/**
* @brief A reference to a decal definition
*/
@@ -19,6 +65,8 @@ typedef int DecalReference;
struct creation_info {
DecalReference definition_handle = -1;
float radius = -1.0f;
float width = -1.0f;
float height = -1.0f;
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
};
@@ -28,6 +76,11 @@ struct creation_info {
void initialize();
/**
* Returns the index of this decal, or -1 if not found
*/
int findDecalDefinition(const SCP_string& name);
/**
* @brief Parses the information for a decal reference
*
+3 -3
View File
@@ -56,7 +56,7 @@ void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
// Positional light source
lightDir = lightPosition - position.xyz;
float dist = length(lightDir);
attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
if(dist > lightRadius && lightType != LT_TUBE) {
discard;
@@ -81,7 +81,7 @@ void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
if(dist > lightRadius) {
discard;
}
attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
} else if (lightType == LT_CONE) {
float coneDot = dot(normalize(-lightDir), coneDir);
if(dualCone) {
@@ -98,7 +98,7 @@ void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
}
}
}
attenuation *= attenuation;
lightDir = normalize(lightDir);
}
}
@@ -0,0 +1,20 @@
#define M_PI 3.1415926535897932384626433832795
uniform samplerCube envmap;
in vec4 fragTexCoord;
out vec4 fragOut0;
layout (location = 0) out vec4 outColor;
void main() {
const float theta = -fragTexCoord.x * (2.0 * M_PI);
const float phi = fragTexCoord.y * (M_PI) - (0.5 * M_PI);
const float st = sin(theta);
const float ct = cos(theta);
const float sp = sin(phi);
const float cp = cos(phi);
const vec3 sampVec = vec3(cp * ct, sp, cp * st);
fragOut0 = vec4(texture(envmap, sampVec).rgb, 1.0);
}
+12 -1
View File
@@ -407,10 +407,21 @@ void fireball_parse_tbl()
{
if (fi.lod_count > 1)
{
Assertion(fi.lod_count <= MAX_FIREBALL_LOD, "Fireball LOD (%d) greater than MAX_FIREBALL_LOD %d.", fi.lod_count, MAX_FIREBALL_LOD);
static_assert(MAX_FIREBALL_LOD < 10, "The fireball LOD naming scheme needs to be changed for LODs > 9");
auto lod0 = fi.lod[0].filename;
constexpr int MAX_BASENAME_LEN = MAX_FILENAME_LEN - 3; // ensure base file name + _*lod* fits in filename field
if (strlen(lod0) > MAX_BASENAME_LEN)
{
Warning(LOCATION, "A fireball base file name may not be longer than %d characters due to the LOD naming scheme.\nLODs other than LOD0 will be skipped for fireball %s", MAX_BASENAME_LEN, lod0);
fi.lod_count = 1;
continue;
}
for (int j = 1; j < fi.lod_count; ++j)
sprintf(fi.lod[j].filename, "%s_%d", lod0, j);
sprintf(fi.lod[j].filename, "%.*s_%d", MAX_BASENAME_LEN, lod0, j % MAX_FIREBALL_LOD /*to show gcc12 format string is safe*/);
}
}
+51 -68
View File
@@ -68,8 +68,8 @@ typedef struct tagSNDPATTERN {
SNDPATTERN Patterns[MAX_PATTERNS]; // holds data on sections of a SoundTrack
// Holds filenames for the different sections of a soundtrack
SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
int Num_soundtracks;
SCP_vector<SOUNDTRACK_INFO> Soundtracks;
int Current_soundtrack_num; // Active soundtrack for the current mission.. index into Soundtracks[]
int Current_pattern = -1; // currently playing part of track
@@ -87,12 +87,6 @@ static int Victory2_music_played;
static int Next_arrival_timestamp;
static int Check_for_battle_music;
// stores the number of measures for the different patterns (data from music.tbl)
float Pattern_num_measures[MAX_SOUNDTRACKS][MAX_PATTERNS];
// stores the number of bytes per measure (data from music.tbl)
int Pattern_samples_per_measure[MAX_SOUNDTRACKS][MAX_PATTERNS];
typedef struct pattern_info
{
const char *pattern_name;
@@ -256,11 +250,10 @@ extern int hud_target_invalid_awacs(object *objp);
// Holds file names of spooled music that is played at menus, briefings, credits etc.
// Indexed into by a #define enumeration of the different kinds of spooled music
menu_music Spooled_music[MAX_SPOOLED_MUSIC];
int Num_music_files; // Number of spooled music files
SCP_vector<menu_music> Spooled_music;
// Array that holds indicies into Spooled_music[], these specify which music is played in briefing/debriefing
int Mission_music[NUM_SCORES];
int Mission_music[NUM_SCORES];
// -------------------------------------------------------------------------------------------------
@@ -285,23 +278,11 @@ void event_music_init()
return;
}
int i, j;
//MUST be called before parsing stuffzors.
Num_music_files = 0;
Num_soundtracks = 0; // Global
Soundtracks.clear();
Spooled_music.clear();
event_music_reset_choices();
// Goober5000
// set all the filenames to "none" so we're compatible with the extra NRMLs in FS1 music
memset(Soundtracks, 0, MAX_SOUNDTRACKS * sizeof(SOUNDTRACK_INFO));
for (i = 0; i < MAX_SOUNDTRACKS; i++)
for (j = 0; j < MAX_PATTERNS; j++)
strcpy_s(Soundtracks[i].pattern_fnames[j], NOX("none.wav"));
// Goober5000
memset(Spooled_music, 0, MAX_SPOOLED_MUSIC * sizeof(menu_music));
//Do teh parsing
event_music_parse_musictbl("music.tbl");
@@ -567,9 +548,9 @@ void event_music_level_start(int force_soundtrack)
return;
}
Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < Num_soundtracks);
Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < (int)Soundtracks.size());
if (Current_soundtrack_num < 0 || Current_soundtrack_num > Num_soundtracks)
if (Current_soundtrack_num < 0 || Current_soundtrack_num > (int)Soundtracks.size())
return;
strack = &Soundtracks[Current_soundtrack_num];
@@ -582,13 +563,13 @@ void event_music_level_start(int force_soundtrack)
// tracks because their patterns weren't -1
for (i = 0; i < MAX_PATTERNS; i++)
{
if (!strnicmp(strack->pattern_fnames[i], NOX("none.wav"), 4))
if (!strnicmp(strack->patterns[i].fname, NOX("none.wav"), 4))
{
Patterns[i].handle = -1;
continue;
}
Patterns[i].handle = audiostream_open( strack->pattern_fnames[i], ASF_EVENTMUSIC );
Patterns[i].handle = audiostream_open( strack->patterns[i].fname, ASF_EVENTMUSIC );
if (Patterns[i].handle >= 0)
{
@@ -609,8 +590,8 @@ void event_music_level_start(int force_soundtrack)
Patterns[i].loop_for = Patterns[i].default_loop_for;
Patterns[i].force_pattern = FALSE;
Patterns[i].can_force = pip->pattern_can_force;
Patterns[i].samples_per_measure = Pattern_samples_per_measure[Current_soundtrack_num][i];
Patterns[i].num_measures = Pattern_num_measures[Current_soundtrack_num][i];
Patterns[i].samples_per_measure = strack->patterns[i].samples_per_measure;
Patterns[i].num_measures = strack->patterns[i].num_measures;
}
Num_enemy_arrivals = 0;
@@ -679,6 +660,18 @@ void event_music_first_pattern()
// this yields a relative start time of 1 second. Mission start will now use relative rather than absolute delay.
void event_music_set_start_delay()
{
if (Event_music_inited == FALSE) {
return;
}
if (Event_music_enabled == FALSE) {
return;
}
if (Event_music_level_inited == FALSE) {
return;
}
Pattern_timer_id = timestamp(1000);
}
@@ -694,11 +687,8 @@ void event_music_level_close()
if ( Event_music_level_inited == FALSE )
return;
if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS ) {
SOUNDTRACK_INFO *strack;
Assert( Current_soundtrack_num >= 0 && Current_soundtrack_num < MAX_SOUNDTRACKS );
strack = &Soundtracks[Current_soundtrack_num];
if ( Current_soundtrack_num >= 0 && Current_soundtrack_num < (int)Soundtracks.size() ) {
auto strack = &Soundtracks[Current_soundtrack_num];
// close the pattern files
for ( i = 0; i < strack->num_patterns; i++ ) {
@@ -1156,16 +1146,16 @@ bool parse_soundtrack_line(int strack_idx, int pattern_idx)
}
if ( count == 0 ) {
Pattern_num_measures[strack_idx][pattern_idx] = (float)atof(token); //Num_measures
} else if(count == 1) {
Pattern_samples_per_measure[strack_idx][pattern_idx] = atoi(token); //Samples per measure
if (count == 0) {
Soundtracks[strack_idx].patterns[pattern_idx].num_measures = (float)atof(token); //Num_measures
} else if (count == 1) {
Soundtracks[strack_idx].patterns[pattern_idx].samples_per_measure = atoi(token); //Samples per measure
}
count++;
} // end while
strcpy_s(Soundtracks[strack_idx].pattern_fnames[pattern_idx], fname);
strcpy_s(Soundtracks[strack_idx].patterns[pattern_idx].fname, fname);
return true;
}
@@ -1189,28 +1179,27 @@ void parse_soundtrack()
}
//Get a valid strack_idx
if(strack_idx < 0 && (nocreate || Num_soundtracks >= MAX_SOUNDTRACKS))
if (strack_idx < 0 && nocreate)
{
if(Num_soundtracks >= MAX_SOUNDTRACKS) {
Warning(LOCATION, "Maximum number of soundtracks reached after '%s'; max is '%d'", Soundtracks[MAX_SOUNDTRACKS-1].name, MAX_SOUNDTRACKS);
}
//Track doesn't exist and has nocreate, so don't create it
if ( !skip_to_start_of_string_either("#SoundTrack Start", "#Menu Music Start") && !skip_to_string("#SoundTrack End")) {
error_display(1, "Couldn't find #Soundtrack Start, #Menu Music Start or #Soundtrack End.");
}
return;
}
else if(strack_idx < 0)
else if (strack_idx < 0)
{
//If we don't have this soundtrack already, create it
strack_idx = Num_soundtracks;
strack_idx = (int)Soundtracks.size();
Soundtracks.emplace_back();
strcpy_s(Soundtracks[strack_idx].name, namebuf);
Soundtracks[strack_idx].flags = 0;
Soundtracks[strack_idx].num_patterns = 0;
strcpy_s(Soundtracks[strack_idx].name, namebuf);
Num_soundtracks++;
// set all the filenames to "none" so we're compatible with the extra NRMLs in FS1 music
for (auto &pattern : Soundtracks[strack_idx].patterns)
strcpy_s(pattern.fname, NOX("none.wav"));
}
// Goober5000
@@ -1301,11 +1290,11 @@ void parse_soundtrack()
for (i = 0; i < Soundtracks[strack_idx].num_patterns; i++)
{
// check for "none"
if (!strlen(Soundtracks[strack_idx].pattern_fnames[i]) || !strnicmp(Soundtracks[strack_idx].pattern_fnames[i], "none", 4))
if (!strlen(Soundtracks[strack_idx].patterns[i].fname) || !strnicmp(Soundtracks[strack_idx].patterns[i].fname, "none", 4))
continue;
// check for file
if (!cf_exists_full(Soundtracks[strack_idx].pattern_fnames[i], CF_TYPE_MUSIC))
if (!cf_exists_full_ext(Soundtracks[strack_idx].patterns[i].fname, CF_TYPE_MUSIC, NUM_AUDIO_EXT, audio_ext_list))
return;
}
@@ -1328,22 +1317,19 @@ void parse_menumusic()
int idx = event_music_get_spooled_music_index(spoolname);
if(idx < 0 && (nocreate || Num_music_files >= MAX_SPOOLED_MUSIC))
if (idx < 0 && nocreate)
{
if(Num_music_files >= MAX_SPOOLED_MUSIC) {
Warning(LOCATION, "Could not load spooled music file after '%s' as maximum number of spooled music was reached (Max is %d)", Spooled_music[Num_music_files - 1].name, MAX_SPOOLED_MUSIC);
}
if (!skip_to_start_of_string_either("$Name:", "#Menu Music End")) {
Error(LOCATION, "Couldn't find $Name or #Menu Music End. Music.tbl or -mus.tbm is invalid.\n");
}
return;
}
else if(idx < 0)
else if (idx < 0)
{
idx = Num_music_files;
idx = (int)Spooled_music.size();
Spooled_music.emplace_back();
Spooled_music[idx].flags = 0;
strcpy_s( Spooled_music[idx].name, spoolname );
strcpy_s( Spooled_music[idx].filename, "");
}
@@ -1366,9 +1352,6 @@ void parse_menumusic()
// chief1983 - use type list defined in ffmpeg.h
if ( cf_exists_full_ext(Spooled_music[idx].filename, CF_TYPE_MUSIC, NUM_AUDIO_EXT, audio_ext_list) )
Spooled_music[idx].flags |= SMF_VALID;
if (!nocreate)
Num_music_files++;
}
// -------------------------------------------------------------------------------------------------
@@ -1617,7 +1600,7 @@ int event_music_next_soundtrack(int delta)
}
new_soundtrack = Current_soundtrack_num + delta;
if ( new_soundtrack >= Num_soundtracks )
if ( new_soundtrack >= (int)Soundtracks.size() )
new_soundtrack = 0;
event_music_level_close();
@@ -1633,7 +1616,7 @@ void event_sexp_change_soundtrack(const char *name)
int i, new_soundtrack = -1;
for (i = 0; i < Num_soundtracks; i++) {
for (i = 0; i < (int)Soundtracks.size(); i++) {
if ( !stricmp(name, Soundtracks[i].name) ) {
new_soundtrack = i;
}
@@ -1677,7 +1660,7 @@ void event_music_set_soundtrack(const char *name)
int event_music_get_soundtrack_index(const char *name)
{
// find the correct index for the event music
for ( int i = 0; i < Num_soundtracks; i++ ) {
for ( int i = 0; i < (int)Soundtracks.size(); i++ ) {
if ( !stricmp(name, Soundtracks[i].name) ) {
return i;
}
@@ -1689,7 +1672,7 @@ int event_music_get_soundtrack_index(const char *name)
int event_music_get_spooled_music_index(const char *name)
{
// find the correct index for the event music
for ( int i = 0; i < Num_music_files; i++ ) {
for ( int i = 0; i < (int)Spooled_music.size(); i++ ) {
if ( !stricmp(name, Spooled_music[i].name) ) {
return i;
}
+8 -10
View File
@@ -67,32 +67,30 @@ typedef struct menu_music {
char filename[MAX_FILENAME_LEN]; // name music is stored on disk as
} menu_music;
#define MAX_SPOOLED_MUSIC 50 // max number of briefing/mainhall/credits tracks
// Goober5000 - spooled music flags
#define SMF_VALID (1 << 0)
extern menu_music Spooled_music[MAX_SPOOLED_MUSIC];
extern int Num_music_files;
extern SCP_vector<menu_music> Spooled_music;
// event music soundtrack storage
typedef struct tagSOUNDTRACK_INFO {
int flags;
int num_patterns;
char name[NAME_LENGTH];
char pattern_fnames[MAX_PATTERNS][MAX_FILENAME_LEN];
char name[NAME_LENGTH];
struct {
char fname[MAX_FILENAME_LEN];
float num_measures;
int samples_per_measure;
} patterns[MAX_PATTERNS];
} SOUNDTRACK_INFO;
#define MAX_SOUNDTRACKS 30 // max number of battle tracks
// Goober5000 - event music flags
#define EMF_VALID (1 << 0)
#define EMF_ALLIED_ARRIVAL_OVERLAY (1 << 1)
#define EMF_CYCLE_FS1 (1 << 2)
extern SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS];
extern int Num_soundtracks;
extern SCP_vector<SOUNDTRACK_INFO> Soundtracks;
void event_music_init();
+2 -2
View File
@@ -823,7 +823,7 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
int temp_limit;
stuff_int(&temp_limit);
if ((temp_limit > 0) && (static_cast<uint>(temp_limit) <= SND_ENHANCED_MAX_LIMIT))
if (temp_limit > 0)
{
gs->enhanced_sound_data.limit = (unsigned int)temp_limit;
}
@@ -927,7 +927,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
int temp_limit;
stuff_int(&temp_limit);
if ((temp_limit > 0) && (static_cast<uint>(temp_limit) <= SND_ENHANCED_MAX_LIMIT))
if (temp_limit > 0)
{
gs->enhanced_sound_data.limit = (unsigned int)temp_limit;
}
+161 -1
View File
@@ -7,7 +7,7 @@
*
*/
#include <utility> // for std::move
#ifndef _LINKLIST_H
#define _LINKLIST_H
@@ -83,4 +83,164 @@ do { \
#define NOT_EMPTY(head) ((head)->next != (head))
#define EMPTY(head) ((head) == nullptr || (head)->next == (head))
// Note that since these iterators operate on pointer collections, the dereference of an iterator using operator* returns a pointer.
template <class T>
class volition_linked_list
{
T* head;
public:
class iterator
{
T* ptr;
public:
iterator(T* x)
: ptr(x)
{}
iterator(const iterator& it)
: ptr(it.ptr)
{}
iterator& operator++()
{
ptr = GET_NEXT(ptr);
return *this;
}
iterator operator++(int)
{
iterator tmp(*this);
operator++();
return tmp;
}
iterator& operator--()
{
ptr = GET_PREV(ptr);
return *this;
}
iterator operator--(int)
{
iterator tmp(*this);
operator--();
return tmp;
}
bool operator==(const iterator& rhs) const
{
return ptr == rhs.ptr;
}
bool operator!=(const iterator& rhs) const
{
return ptr != rhs.ptr;
}
T*& operator*()
{
return ptr;
}
T* operator->()
{
return ptr;
}
};
class const_iterator
{
const T* ptr;
public:
const_iterator(const T* x)
: ptr(x)
{}
const_iterator(const const_iterator& it)
: ptr(it.ptr)
{}
const_iterator& operator++()
{
ptr = GET_NEXT(ptr);
return *this;
}
const_iterator operator++(int)
{
const_iterator tmp(*this);
operator++();
return tmp;
}
const_iterator& operator--()
{
ptr = GET_PREV(ptr);
return *this;
}
const_iterator operator--(int)
{
const_iterator tmp(*this);
operator--();
return tmp;
}
bool operator==(const const_iterator& rhs) const
{
return ptr == rhs.ptr;
}
bool operator!=(const const_iterator& rhs) const
{
return ptr != rhs.ptr;
}
const T*& operator*()
{
return ptr;
}
const T* operator->()
{
return ptr;
}
};
iterator begin() const
{
return iterator(GET_FIRST(head));
}
iterator end() const
{
return iterator(END_OF_LIST(head));
}
const_iterator cbegin() const
{
return const_iterator(GET_FIRST(head));
}
const_iterator cend() const
{
return const_iterator(END_OF_LIST(head));
}
volition_linked_list(T* ptr)
: head(ptr)
{}
};
template <class T>
volition_linked_list<T> list_range(T* head)
{
return volition_linked_list<T>(head);
}
#endif
+2 -1
View File
@@ -114,7 +114,8 @@ typedef struct vec2d {
} vec2d;
// Euler angles for a rotation: h=heading, b=bank and p=pitch; angles are around the y, z and x axes
// respectively and are performed in that order.
// respectively and are performed in that order. (Strictly speaking these are Tait-Bryan angles,
// not classic Euler angles.)
typedef struct angles {
float p, b, h;
} angles_t;
+5
View File
@@ -6,6 +6,11 @@
#define SCP_TOKEN_CONCAT1(x, y) x ## y
#define SCP_TOKEN_CONCAT(x, y) SCP_TOKEN_CONCAT1(x, y)
// these are useful for embedding numbers in strings
// see https://stackoverflow.com/questions/5459868/concatenate-int-to-string-using-c-preprocessor
#define SCP_TOKEN_TO_STR1(x) #x
#define SCP_TOKEN_TO_STR(x) SCP_TOKEN_TO_STR1(x)
#define SCP_UNUSED(x) (void)(x)
#endif // SCP_DEFINES_H
-40
View File
@@ -427,46 +427,6 @@ DCF(detail, "Turns on/off parts of the game for speed testing" )
}
#endif
// Goober5000
// (Taylor says that for optimization purposes malloc/free should be used rather than vm_malloc/vm_free here)
// NOTE: Because this uses memcpy, it should only be used to sort POD elements!
void insertion_sort(void *array_base, size_t array_size, size_t element_size, int (*fncompare)(const void *, const void *))
{
int i, j;
void *current;
char *array_byte_base;
// this is used to avoid having to cast array_base to (char *) all the time
array_byte_base = (char *) array_base;
// allocate space for the element being moved
current = malloc(element_size);
if (current == NULL)
{
Int3();
return;
}
// loop
for (i = 1; (unsigned) i < array_size; i++)
{
// grab the current element
memcpy(current, array_byte_base + (i * element_size), element_size);
// bump other elements toward the end of the array
for (j = i - 1; (j >= 0) && (fncompare(array_byte_base + (j * element_size), current) > 0); j--)
{
memcpy(array_byte_base + ((j + 1) * element_size), array_byte_base + (j * element_size), element_size);
}
// insert the current element at the correct place
memcpy(array_byte_base + ((j + 1) * element_size), current, element_size);
}
// free the allocated space
free(current);
}
// Stuff that can't be included in vmallocator.h
std::locale SCP_default_locale("");
+68 -17
View File
@@ -31,23 +31,23 @@
#define GM_CAMPAIGN_MODE (1 << 10) // are we currently in a campaign.
#define GM_LAB (1 << 11) // We are currently in the F3 lab
#define VM_EXTERNAL (1 << 0) // Set if not viewing from player position.
#define VM_TRACK (1 << 1) // Set if viewer is tracking target.
#define VM_DEAD_VIEW (1 << 2) // Set if viewer is watching from dead view.
#define VM_CHASE (1 << 3) // Chase view.
#define VM_OTHER_SHIP (1 << 4) // View from another ship.
#define VM_CAMERA_LOCKED (1 << 5) // Set if player does not have control of the camera
#define VM_WARP_CHASE (1 << 6) // View while warping out (form normal view mode)
#define VM_PADLOCK_UP (1 << 7)
#define VM_PADLOCK_REAR (1 << 8)
#define VM_PADLOCK_LEFT (1 << 9)
#define VM_PADLOCK_RIGHT (1 << 10)
#define VM_WARPIN_ANCHOR (1 << 11) // special warpin camera mode
#define VM_TOPDOWN (1 << 12) //Camera is looking down on ship
#define VM_FREECAMERA (1 << 13) //Camera is not attached to any particular object, probably under SEXP control
#define VM_CENTERING (1 << 14) // View is springing to center
#define VM_EXTERNAL (1 << 0) // Set if not viewing from player position.
#define VM_TRACK (1 << 1) // Set if viewer is tracking target.
#define VM_DEAD_VIEW (1 << 2) // Set if viewer is watching from dead view.
#define VM_CHASE (1 << 3) // Chase view.
#define VM_OTHER_SHIP (1 << 4) // View from another ship.
#define VM_CAMERA_LOCKED (1 << 5) // Set if player does not have control of the camera
#define VM_WARP_CHASE (1 << 6) // View while warping out (form normal view mode)
#define VM_PADLOCK_UP (1 << 7) // Set when player is looking up
#define VM_PADLOCK_REAR (1 << 8) // Set when player is looking behind
#define VM_PADLOCK_LEFT (1 << 9) // Set when player is looking left
#define VM_PADLOCK_RIGHT (1 << 10) // Set when player is looking right
#define VM_WARPIN_ANCHOR (1 << 11) // special warpin camera mode
#define VM_TOPDOWN (1 << 12) // Camera is looking down on ship
#define VM_FREECAMERA (1 << 13) // Camera is not attached to any particular object, probably under SEXP control
#define VM_CENTERING (1 << 14) // View is springing to center
#define VM_PADLOCK_ANY (VM_PADLOCK_UP|VM_PADLOCK_REAR|VM_PADLOCK_LEFT|VM_PADLOCK_RIGHT)
#define VM_PADLOCK_ANY (VM_PADLOCK_UP | VM_PADLOCK_REAR | VM_PADLOCK_LEFT | VM_PADLOCK_RIGHT)
//-----Cutscene stuff
//No bars
@@ -213,7 +213,58 @@ int current_detail_level();
// Goober5000
void insertion_sort(void *array, size_t array_size, size_t element_size, int (*fncompare)(const void *, const void *));
// A sort for use with small or almost-sorted lists. Iteration time is O(n) for a fully-sorted list.
// This uses a type-safe version of the function prototype for stdlib's qsort, although the size is an int rather than a size_t (for the reasons that j is an int).
// The fncompare function should return <0, 0, or >0 as the left item is less than, equal to, or greater than the right item.
template <typename T>
void insertion_sort(T* array_base, int array_size, int (*fncompare)(const T*, const T*))
{
// NOTE: j *must* be a signed type because j reaches -1 and j+1 must be 0.
int i, j;
T *current, *current_buf;
// allocate space for the element being moved
// (Taylor says that for optimization purposes malloc/free should be used rather than vm_malloc/vm_free here)
current_buf = (T*)malloc(sizeof(T));
if (current_buf == nullptr)
{
UNREACHABLE("Malloc failed!");
return;
}
// loop
for (i = 1; i < array_size; i++)
{
// grab the current element
// this does a lazy move/copy because if the array is mostly sorted,
// there's no sense copying sorted items to their own places
bool lazily_copied = false;
current = &array_base[i];
// bump other elements toward the end of the array
for (j = i - 1; (j >= 0) && (fncompare(&array_base[j], current) > 0); j--)
{
if (!lazily_copied)
{
// this may look strange but it is just copying the data
// into the buffer, then pointing to the buffer
*current_buf = std::move(*current);
current = current_buf;
lazily_copied = true;
}
array_base[j + 1] = std::move(array_base[j]);
}
if (lazily_copied)
{
// insert the current element at the correct place
array_base[j + 1] = std::move(*current);
}
}
// free the allocated space
free(current_buf);
}
#endif
+4 -10
View File
@@ -313,11 +313,8 @@ void Add_Symbol( int section, int offset, const char *name, char *module )
}
int Sym_compare( const void *arg1, const void *arg2 )
int Sym_compare( const MemSymbol *sym1, const MemSymbol *sym2 )
{
MemSymbol * sym1 = (MemSymbol *)arg1;
MemSymbol * sym2 = (MemSymbol *)arg2;
if ( sym1->section < sym2->section ) {
return -1;
} else if ( sym1->section > sym2->section ) {
@@ -331,11 +328,8 @@ int Sym_compare( const void *arg1, const void *arg2 )
}
}
int Sym_compare1( const void *arg1, const void *arg2 )
int Sym_compare1( const MemSymbol *sym1, const MemSymbol *sym2 )
{
MemSymbol * sym1 = (MemSymbol *)arg1;
MemSymbol * sym2 = (MemSymbol *)arg2;
if ( sym1->size < sym2->size ) {
return 1;
} else if ( sym1->size > sym2->size ) {
@@ -349,7 +343,7 @@ void DumpSymbols()
{
int i;
insertion_sort( Symbols, Num_symbols, sizeof(MemSymbol), Sym_compare );
insertion_sort( Symbols, Num_symbols, Sym_compare );
for (i=0;i<Num_symbols; i++ ) {
MemSymbol * sym1 = &Symbols[i];
@@ -361,7 +355,7 @@ void DumpSymbols()
}
}
insertion_sort( Symbols, Num_symbols, sizeof(MemSymbol), Sym_compare1 );
insertion_sort( Symbols, Num_symbols, Sym_compare1 );
FILE *fp = fopen( "dump", "wt" );
+56 -20
View File
@@ -1435,7 +1435,7 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
auto res = ResolutionOption->getValue();
width = res.width;
height = res.height;
} else {
} else if ( !Is_standalone ) {
// We cannot continue without this, quit, but try to help the user out first
ptr = os_config_read_string(nullptr, NOX("VideocardFs2open"), nullptr);
@@ -1540,6 +1540,15 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
depth = d_depth;
}
// if we are in standalone mode then just use special defaults
if (Is_standalone) {
mode = GR_STUB;
width = 640;
height = 480;
depth = 16;
center_aspect_ratio = -1.0f;
}
if (gr_get_resolution_class(width, height) != GR_640) {
// check for hi-res interface files so that we can verify our width/height is correct
// if we don't have it then fall back to 640x480 mode instead
@@ -1556,15 +1565,6 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
}
}
// if we are in standalone mode then just use special defaults
if (Is_standalone) {
mode = GR_STUB;
width = 640;
height = 480;
depth = 16;
center_aspect_ratio = -1.0f;
}
// These compiler macros will force windowed mode at the specified resolution if
// built in debug mode. This helps if you run with the debugger active as the
// game won't be switching from fullscreen to minimized every time you hit a breakpoint or
@@ -1616,14 +1616,12 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
mprintf(("Initializing path renderer...\n"));
graphics::paths::PathRenderer::init();
if ( !Is_standalone ) {
gr_light_init();
gr_light_init();
// Initialize uniform buffer managers
uniform_buffer_managers_init();
// Initialize uniform buffer managers
uniform_buffer_managers_init();
gpu_heap_init();
}
gpu_heap_init();
mprintf(("Checking graphics capabilities:\n"));
mprintf((" Persistent buffer mapping: %s\n",
@@ -2534,6 +2532,10 @@ void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float a
static void output_uniform_debug_data()
{
if (gr_screen.mode == GR_STUB) {
return;
}
int line_height = gr_get_font_height() + 1;
gr_set_color_fast(&Color_bright_white);
@@ -2555,7 +2557,9 @@ void gr_flip(bool execute_scripting)
TRACE_SCOPE(tracing::LuaOnFrame);
// WMC - Do conditional hooks. Yippee!
OnFrameHook->run();
if (OnFrameHook->isActive()) {
OnFrameHook->run();
}
// WMC - Do scripting reset stuff
Script_system.EndFrame();
}
@@ -2590,9 +2594,33 @@ void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
gr_string(x, y, time.c_str(), resize_mode);
}
static void uniform_buffer_managers_init() { UniformBufferManager.reset(new graphics::util::UniformBufferManager()); }
static void uniform_buffer_managers_deinit() { UniformBufferManager.reset(); }
static void uniform_buffer_managers_retire_buffers() { UniformBufferManager->onFrameEnd(); }
static void uniform_buffer_managers_init()
{
if (gr_screen.mode == GR_STUB) {
return;
}
UniformBufferManager.reset(new graphics::util::UniformBufferManager());
}
static void uniform_buffer_managers_deinit()
{
if (gr_screen.mode == GR_STUB) {
return;
}
UniformBufferManager.reset();
}
static void uniform_buffer_managers_retire_buffers()
{
if (gr_screen.mode == GR_STUB) {
return;
}
UniformBufferManager->onFrameEnd();
}
graphics::util::UniformBuffer gr_get_uniform_buffer(uniform_block_type type, size_t num_elements, size_t element_size_override)
{
@@ -2727,6 +2755,10 @@ size_t vertex_layout::hash() const {
static std::unique_ptr<graphics::util::GPUMemoryHeap> gpu_heaps [static_cast<size_t>(GpuHeap::NUM_VALUES)];
static void gpu_heap_init() {
if (gr_screen.mode == GR_STUB) {
return;
}
for (size_t i = 0; i < static_cast<size_t>(GpuHeap::NUM_VALUES); ++i) {
auto enumVal = static_cast<GpuHeap>(i);
@@ -2822,6 +2854,10 @@ static void make_gamma_ramp(float gamma, ushort* ramp)
void gr_set_gamma(float gamma)
{
if (gr_screen.mode == GR_STUB) {
return;
}
Gr_gamma = gamma;
// new way - but not while running FRED
+6
View File
@@ -204,6 +204,8 @@ enum shader_type {
SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT,
SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING,
SDR_TYPE_ENVMAP_SPHERE_WARP,
NUM_SHADER_TYPES
};
@@ -713,6 +715,9 @@ typedef struct screen {
// dumps the current screen to a file
std::function<void(const char* filename)> gf_print_screen;
// transforms and dumps the current environment map to a file
std::function<void(const char* filename)> gf_dump_envmap;
// Retrieves the zbuffer mode.
std::function<int()> gf_zbuffer_get;
@@ -997,6 +1002,7 @@ extern void gr_activate(int active);
// old Descent-style gr_xxx calls.
#define gr_print_screen GR_CALL(gr_screen.gf_print_screen)
#define gr_dump_envmap GR_CALL(gr_screen.gf_dump_envmap)
//#define gr_flip GR_CALL(gr_screen.gf_flip)
void gr_flip(bool execute_scripting = true);
+225
View File
@@ -0,0 +1,225 @@
#include "graphics/color.h"
#include "graphics/2d.h"
#include "globalincs/pstypes.h"
#include "globalincs/vmallocator.h"
#include "math/floating.h"
void hdr_color::set_vecf(const SCP_vector<float>& input)
{
size_t l = input.size();
Assertion(l >= 3, "attempted to set color values invalid component count");
this->red = input.at(0);
this->green = input.at(1);
this->blue = input.at(2);
if (l > 3)
this->alpha = input.at(3);
if (l > 4)
this->intensity = input.at(4);
}
/*
* @brief Fills a vector with the raw float color components of the color, in the order red, green, blue, alpha,
* intensity
*
* @param to_fill: The fector that will be filled with the color compoents
*/
void hdr_color::get_v5f(SCP_vector<float>& to_fill) const
{
to_fill.clear();
to_fill.push_back(this->red);
to_fill.push_back(this->green);
to_fill.push_back(this->blue);
to_fill.push_back(this->alpha);
to_fill.push_back(this->intensity);
}
hdr_color::hdr_color()
{
this->red = 1.0f;
this->green = 1.0f;
this->blue = 1.0f;
this->alpha = 1.0f;
this->intensity = 1.0f;
}
hdr_color::hdr_color(float new_r, float new_g, float new_b, float new_a, float new_i)
{
this->red = new_r;
this->green = new_g;
this->blue = new_b;
this->alpha = new_a;
this->intensity = new_i;
}
hdr_color::hdr_color(const hdr_color* const source_color)
{
this->red = source_color->red;
this->green = source_color->green;
this->blue = source_color->blue;
this->alpha = source_color->alpha;
this->intensity = source_color->intensity;
}
/**
* @brief Sets RGB values from three 0-255 ints
*/
void hdr_color::set_rgb(int new_r, int new_g, int new_b)
{
this->red = i2fl(new_r) / 255.0f;
this->green = i2fl(new_g) / 255.0f;
this->blue = i2fl(new_b) / 255.0f;
}
/**
* @brief Sets RGBA values from an old style color object
*/
void hdr_color::set_rgb(const color* const new_color)
{
this->set_rgb(new_color->red, new_color->green, new_color->blue);
this->alpha = i2fl(new_color->alpha);
}
/**
* @brief Sets RGB values from an array of three 0-255 ints
*/
void hdr_color::set_rgb(const int* const new_rgb)
{
this->set_rgb(new_rgb[0], new_rgb[1], new_rgb[2]);
}
/**
* @brief retreives unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::r() const
{
return red;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::r(float in)
{
red = in;
return red;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component from 0-255 int.
*/
float hdr_color::r(int in)
{
red = i2fl(in) / 255.0f;
return red;
}
/**
* @brief retreives unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::g() const
{
return green;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::g(float in)
{
green = in;
return green;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component from 0-255 int.
*/
float hdr_color::g(int in)
{
green = i2fl(in) / 255.0f;
return green;
}
/**
* @brief retreives unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::b() const
{
return blue;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::b(float in)
{
blue = in;
return blue;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component from 0-255 int.
*/
float hdr_color::b(int in)
{
blue = i2fl(in) / 255.0f;
return blue;
}
/**
* @brief retreives unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::a() const
{
return alpha;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::a(float in)
{
alpha = in;
return alpha;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component from 0-255 int.
*/
float hdr_color::a(int in)
{
alpha = i2fl(in) / 255.0f;
return alpha;
}
/**
* @brief retreives unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::i() const
{
return intensity;
}
/**
* @brief sets and returns unmultiplied 0.0f-1.0f color component.
*/
float hdr_color::i(float in)
{
intensity = in;
return intensity;
}
/**
* @brief Resets to a full alpha, 100% white.
*/
void hdr_color::reset()
{
this->red = 1.0f;
this->green = 1.0f;
this->blue = 1.0f;
this->alpha = 1.0f;
this->intensity = 1.0f;
}
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include "graphics/2d.h"
#include "graphics/color.h"
#include "globalincs/pstypes.h"
#include "globalincs/vmallocator.h"
class hdr_color{
private:
float red,green,blue,alpha,intensity;
public:
hdr_color();
hdr_color(const float new_r, const float new_g, const float new_b, const float new_a = 1.0f, const float new_i =1.0f);
hdr_color(const hdr_color* const source_color);
void reset();
void get_v5f(SCP_vector<float>& outvec) const;
void set_vecf(const SCP_vector<float>& input);
void set_rgb(const int new_r,const int new_g,const int new_b);
void set_rgb(const color* const new_rgb);
void set_rgb(const int* const new_rgb);
float r() const;
float r(const float in);
float r(const int in);
float g() const;
float g(const float in);
float g(const int in);
float b() const;
float b(const float in);
float b(const int in);
float a() const;
float a(const float in);
float a(const int in);
float i() const;
float i(const float in);
};
+38
View File
@@ -0,0 +1,38 @@
#include "debug_sphere.h"
#include "globalincs/vmallocator.h"
#include "render/3d.h"
SCP_vector<debug_sphere> debug_sphere::Spheres;
debug_sphere::debug_sphere(const vec3d& pos_in, float rad_in)
{
pos = pos_in;
radius = rad_in;
}
void debug_sphere::add(const vec3d& pos, float rad)
{
Spheres.emplace_back(pos, rad);
}
void debug_sphere::clear()
{
Spheres.clear();
}
void debug_sphere::render()
{
color uicolor = gr_screen.current_color;
color render_color;
render_color.red = 255;
render_color.green = 255;
render_color.blue = 255;
render_color.alpha = 64;
gr_set_color_fast(&render_color);
for (auto& s : Spheres) {
g3_draw_sphere_ez(&(s.pos), s.radius);
}
gr_set_color_fast(&uicolor);
clear();
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "globalincs/pstypes.h"
#include "globalincs/vmallocator.h"
class debug_sphere {
public:
static void add(const vec3d& pos, float radius);
static void render();
debug_sphere(const vec3d& pos, float radius);
private:
static SCP_vector<debug_sphere> Spheres;
static void clear();
vec3d pos;
float radius;
};
+31
View File
@@ -205,6 +205,10 @@ static void pre_render_init_lights() {
}
void gr_set_light(light* fs_light) {
if (gr_screen.mode == GR_STUB) {
return;
}
// init the light
gr_light grl;
FSLight2GLLight(fs_light, &grl);
@@ -213,6 +217,10 @@ void gr_set_light(light* fs_light) {
}
void gr_set_center_alpha(int type) {
if (gr_screen.mode == GR_STUB) {
return;
}
if (!type) {
return;
}
@@ -275,11 +283,19 @@ void gr_set_center_alpha(int type) {
}
void gr_reset_lighting() {
if (gr_screen.mode == GR_STUB) {
return;
}
gr_lights.clear();
Num_active_gr_lights = 0;
}
void gr_calculate_ambient_factor(int ambient_factor) {
if (gr_screen.mode == GR_STUB) {
return;
}
gr_user_ambient = (float) ((ambient_factor * 2) - 255) / 255.0f;
}
@@ -288,6 +304,10 @@ void gr_light_shutdown() {
}
void gr_light_init() {
if (gr_screen.mode == GR_STUB) {
return;
}
gr_calculate_ambient_factor();
// allocate memory for enabled lights
@@ -295,6 +315,9 @@ void gr_light_init() {
}
void gr_set_lighting() {
if (gr_screen.mode == GR_STUB) {
return;
}
//Valathil: Sort lights by priority
extern bool Deferred_lighting;
@@ -326,6 +349,10 @@ void gr_set_lighting() {
}
void gr_set_ambient_light(int red, int green, int blue) {
if (gr_screen.mode == GR_STUB) {
return;
}
gr_light_ambient[0] = i2fl(red) / 255.0f;
gr_light_ambient[1] = i2fl(green) / 255.0f;
gr_light_ambient[2] = i2fl(blue) / 255.0f;
@@ -335,6 +362,10 @@ void gr_set_ambient_light(int red, int green, int blue) {
}
void gr_lighting_fill_uniforms(void* data_out, size_t buffer_size) {
if (gr_screen.mode == GR_STUB) {
return;
}
Assertion(sizeof(gr_light_uniforms) <= buffer_size, "Insufficient buffer supplied.");
memcpy(reinterpret_cast<graphics::model_light*>(data_out), gr_light_uniforms, sizeof(gr_light_uniforms));
+27
View File
@@ -53,6 +53,26 @@ void material_set_unlit(material* mat_info, int texture, float alpha, bool blend
}
}
void material_set_unlit_opaque(material* mat_info, int texture, bool depth_testing)
{
mat_info->set_texture_map(TM_BASE_TYPE, texture);
gr_alpha_blend blend_mode = ALPHA_BLEND_NONE;
gr_zbuffer_type depth_mode = material_determine_depth_mode(depth_testing, false);
mat_info->set_blend_mode(blend_mode);
mat_info->set_depth_mode(depth_mode);
mat_info->set_cull_mode(false);
mat_info->set_color(1.0f, 1.0f, 1.0f, 1.0f);
if ( texture >= 0 && bm_has_alpha_channel(texture) ) {
mat_info->set_texture_type(material::TEX_TYPE_XPARENT);
}
}
void material_set_unlit_emissive(material* mat_info, int texture, float alpha, float color_scale)
{
material_set_unlit(mat_info, texture, alpha, true, true);
@@ -161,6 +181,13 @@ void material_set_batched_bitmap(batched_bitmap_material* mat_info, int base_tex
mat_info->set_color_scale(color_scale);
}
void material_set_batched_opaque_bitmap(batched_bitmap_material* mat_info, int base_tex, float color_scale) {
material_set_unlit_opaque(mat_info, base_tex, true);
mat_info->set_color_scale(color_scale);
}
void material_set_nanovg(nanovg_material* mat_info, int base_tex) {
material_set_unlit(mat_info, base_tex, 1.0f, true, false);
+1
View File
@@ -373,6 +373,7 @@ void material_set_unlit_volume(particle_material* mat_info, int texture, bool po
void material_set_distortion(distortion_material *mat_info, int texture, bool thruster);
void material_set_movie(movie_material *mat_info, int y_bm, int u_bm, int v_bm);
void material_set_batched_bitmap(batched_bitmap_material* mat_info, int base_tex, float alpha, float color_scale);
void material_set_batched_opaque_bitmap(batched_bitmap_material* mat_info, int base_tex, float color_scale);
void material_set_nanovg(nanovg_material* mat_info, int base_tex);
void material_set_decal(material* mat_info, int diffuse_tex, int glow_tex, int normal_tex);
+54 -1
View File
@@ -7,7 +7,7 @@
#endif
#include "gropengl.h"
#include "ShaderProgram.h"
#include "gropenglbmpman.h"
#include "gropengldeferred.h"
#include "gropengldraw.h"
@@ -290,6 +290,58 @@ void gr_opengl_print_screen(const char *filename)
}
}
void gr_opengl_dump_envmap(const char* filename)
{
char tmp[MAX_PATH_LEN];
GLubyte* pixels = nullptr;
_mkdir(os_get_config_path("envmaps").c_str());
auto width = 512; // These are the hardcoded envmap dimensions
auto height = 512; // in future envmap resolution should be dynamic, or at least extracted from envmap_render_target
auto sphere_width = 4 * width;
auto sphere_height = 2 * height;
auto env_tex = bm_get_gr_info<tcache_slot_opengl>(gr_screen.envmap_render_target);
glBindTexture(env_tex->texture_target, env_tex->texture_id);
// Save the previous render target so we can reset it once we are done here
auto previous_target = gr_screen.rendering_to_texture;
// New render target
int sm_flags = (BMP_FLAG_RENDER_TARGET_STATIC);
int spheremap_render_target = bm_make_render_target(sphere_width, sphere_height, sm_flags);
bm_set_render_target(spheremap_render_target);
// Set up cubemap to spherical shader and draw
int env_shader = gr_opengl_maybe_create_shader(SDR_TYPE_ENVMAP_SPHERE_WARP, 0);
opengl_shader_set_current(env_shader);
GL_state.Texture.Enable(0, GL_TEXTURE_CUBE_MAP, env_tex->texture_id);
Current_shader->program->Uniforms.setTextureUniform("envmap", 0);
gr_clear();
opengl_draw_full_screen_textured(0.0f, 0.0f, Scene_texture_u_scale, Scene_texture_v_scale);
bm_set_render_target(previous_target);
// load texture info and write to file
auto sphere_tex = bm_get_gr_info<tcache_slot_opengl>(spheremap_render_target);
glBindTexture(sphere_tex->texture_target, sphere_tex->texture_id);
pixels = (GLubyte*)vm_malloc(sphere_width * sphere_height * 4, memory::quiet_alloc);
glGetTexImage(sphere_tex->texture_target, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
snprintf(tmp, MAX_PATH_LEN - 1, "envmaps/%s.png", filename);
if (!png_write_bitmap(os_get_config_path(tmp).c_str(), 4 * width, 2 * height, true, pixels)) {
ReleaseWarning(LOCATION, "Failed to write envmap to \"%s\".", os_get_config_path(tmp).c_str());
}
// cleanup
if (!bm_release(spheremap_render_target, 1)) {
Warning(LOCATION, "Unable to release environment map render target.");
}
if (pixels != nullptr) {
vm_free(pixels);
}
}
void gr_opengl_shutdown()
{
opengl_tcache_shutdown();
@@ -807,6 +859,7 @@ void opengl_setup_function_pointers()
// gr_screen.gf_rect = gr_opengl_rect;
gr_screen.gf_print_screen = gr_opengl_print_screen;
gr_screen.gf_dump_envmap = gr_opengl_dump_envmap;
gr_screen.gf_zbuffer_get = gr_opengl_zbuffer_get;
gr_screen.gf_zbuffer_set = gr_opengl_zbuffer_set;
+10 -9
View File
@@ -211,13 +211,14 @@ void gr_opengl_deferred_lighting_finish()
case Light_Type::Point:
vm_vec_scale(&light_data->specLightColor, static_point_factor);
light_data->lightRadius = MAX(l.rada, l.radb) * 1.25f;
light_data->scale.xyz.x = MAX(l.rada, l.radb) * 1.28f;
light_data->scale.xyz.y = MAX(l.rada, l.radb) * 1.28f;
light_data->scale.xyz.z = MAX(l.rada, l.radb) * 1.28f;
light_data->lightRadius = MAX(l.rada, l.radb);
//A small padding factor is added to guard against potentially clipping the edges of the light with facets of the volume mesh.
light_data->scale.xyz.x = MAX(l.rada, l.radb) * 1.05f;
light_data->scale.xyz.y = MAX(l.rada, l.radb) * 1.05f;
light_data->scale.xyz.z = MAX(l.rada, l.radb) * 1.05f;
break;
case Light_Type::Tube: {
light_data->lightRadius = l.radb * 1.5f;
light_data->lightRadius = l.radb;
light_data->lightType = LT_TUBE;
vec3d a;
@@ -228,8 +229,9 @@ void gr_opengl_deferred_lighting_finish()
//origin we must extend it here. Later the position will be adjusted as well.
length += light_data->lightRadius * 2.0f;
light_data->scale.xyz.x = l.radb * 1.53f;
light_data->scale.xyz.y = l.radb * 1.53f;
//A small padding factor is added to guard against potentially clipping the edges of the light with facets of the volume mesh.
light_data->scale.xyz.x = l.radb * 1.05f;
light_data->scale.xyz.y = l.radb * 1.05f;
light_data->scale.xyz.z = length;
vm_vec_scale(&light_data->specLightColor, static_tube_factor);
@@ -276,8 +278,7 @@ void gr_opengl_deferred_lighting_finish()
//to allow smooth fall-off from all angles. Since the light volume starts at the mesh
//origin we must extend it, which has been done above, and then move it backwards one radius.
vm_vec_normalize(&dir);
//1.5 multiplier matches scaling used earlier to scale light radius for all tubes
vm_vec_scale_sub(&newPos, &l.vec2, &dir, l.radb * 1.5f);
vm_vec_scale_sub(&newPos, &l.vec2, &dir, l.radb);
gr_opengl_draw_deferred_light_cylinder(&newPos, &orient);
++element_index;
break;
+82 -82
View File
@@ -1,82 +1,82 @@
#include "graphics/opengl/gropenglquery.h"
#include "graphics/opengl/gropengl.h"
namespace {
struct query_object_slot {
bool used = false;
GLuint name = 0;
};
SCP_vector<query_object_slot> query_objects;
int get_new_query_slot() {
auto end = query_objects.end();
for (auto iter = query_objects.begin(); iter != end; ++iter) {
if (!iter->used) {
return (int) std::distance(query_objects.begin(), iter);
}
}
query_objects.emplace_back();
return (int) (query_objects.size() - 1);
}
query_object_slot& get_query_slot(int handle) {
Assertion(handle >= 0 && handle < (int)query_objects.size(), "Query object index %d is invalid!", handle);
return query_objects[handle];
}
}
int gr_opengl_create_query_object() {
auto idx = get_new_query_slot();
auto& slot = query_objects[idx];
slot.used = true;
glGenQueries(1, &slot.name);
return idx;
}
void gr_opengl_query_value(int obj, QueryType type) {
auto& slot = get_query_slot(obj);
switch(type) {
case QueryType::Timestamp:
Assertion(GLAD_GL_ARB_timer_query, "Timestamp queries are not available! Availability must be checked before calling this function!");
glQueryCounter(slot.name, GL_TIMESTAMP);
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
}
bool gr_opengl_query_value_available(int obj) {
auto& slot = get_query_slot(obj);
GLuint available;
glGetQueryObjectuiv(slot.name, GL_QUERY_RESULT_AVAILABLE, &available);
return available == GL_TRUE;
}
std::uint64_t gr_opengl_get_query_value(int obj) {
auto& slot = get_query_slot(obj);
GLuint64 available;
glGetQueryObjectui64v(slot.name, GL_QUERY_RESULT, &available);
return available;
}
void gr_opengl_delete_query_object(int obj) {
auto& slot = get_query_slot(obj);
glDeleteQueries(1, &slot.name);
slot.name = 0;
slot.used = false;
}
#include "graphics/opengl/gropenglquery.h"
#include "graphics/opengl/gropengl.h"
namespace {
struct query_object_slot {
bool used = false;
GLuint name = 0;
};
SCP_vector<query_object_slot> query_objects;
int get_new_query_slot() {
auto end = query_objects.end();
for (auto iter = query_objects.begin(); iter != end; ++iter) {
if (!iter->used) {
return (int) std::distance(query_objects.begin(), iter);
}
}
query_objects.emplace_back();
return (int) (query_objects.size() - 1);
}
query_object_slot& get_query_slot(int handle) {
Assertion(handle >= 0 && handle < (int)query_objects.size(), "Query object index %d is invalid!", handle);
return query_objects[handle];
}
}
int gr_opengl_create_query_object() {
auto idx = get_new_query_slot();
auto& slot = query_objects[idx];
slot.used = true;
glGenQueries(1, &slot.name);
return idx;
}
void gr_opengl_query_value(int obj, QueryType type) {
auto& slot = get_query_slot(obj);
switch(type) {
case QueryType::Timestamp:
Assertion(GLAD_GL_ARB_timer_query, "Timestamp queries are not available! Availability must be checked before calling this function!");
glQueryCounter(slot.name, GL_TIMESTAMP);
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
}
bool gr_opengl_query_value_available(int obj) {
auto& slot = get_query_slot(obj);
GLuint available;
glGetQueryObjectuiv(slot.name, GL_QUERY_RESULT_AVAILABLE, &available);
return available == GL_TRUE;
}
std::uint64_t gr_opengl_get_query_value(int obj) {
auto& slot = get_query_slot(obj);
GLuint64 available;
glGetQueryObjectui64v(slot.name, GL_QUERY_RESULT, &available);
return available;
}
void gr_opengl_delete_query_object(int obj) {
auto& slot = get_query_slot(obj);
glDeleteQueries(1, &slot.name);
slot.name = 0;
slot.used = false;
}
+9 -9
View File
@@ -1,9 +1,9 @@
#ifndef _GROPENGLQUERY_H
#define _GROPENGLQUERY_H
#pragma once
#include "graphics/2d.h"
#ifndef _GROPENGLQUERY_H
#define _GROPENGLQUERY_H
#pragma once
#include "graphics/2d.h"
int gr_opengl_create_query_object();
@@ -13,6 +13,6 @@ bool gr_opengl_query_value_available(int obj);
std::uint64_t gr_opengl_get_query_value(int obj);
void gr_opengl_delete_query_object(int obj);
#endif // _GROPENGLQUERY_H
void gr_opengl_delete_query_object(int obj);
#endif // _GROPENGLQUERY_H
+3
View File
@@ -156,6 +156,9 @@ static opengl_shader_type_t GL_shader_types[] = {
{ SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING, "smaa-neighbour-v.sdr", "smaa-neighbour-f.sdr", nullptr,
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Neighborhood Blending", false },
{ SDR_TYPE_ENVMAP_SPHERE_WARP, "post-v.sdr", "envmap-sphere-warp-f.sdr", nullptr,
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Environment Map Generation", false },
};
// clang-format on
+17
View File
@@ -5,6 +5,7 @@
#include "options/Option.h"
#include "parse/parselo.h"
#include "ship/ship.h"
#include "starfield/supernova.h"
namespace graphics {
namespace {
@@ -208,6 +209,14 @@ void PostProcessingManager::setBloomShadersOk(bool ok)
bool gr_lightshafts_enabled()
{
if (gr_screen.mode == GR_STUB) {
return false;
}
// supernova glare should disable lightshafts
if (supernova_stage() >= SUPERNOVA_STAGE::CLOSE) {
return false;
}
if (!graphics::Post_processing_manager->getLightshaftParams().on) {
return false;
@@ -222,6 +231,10 @@ bool gr_lightshafts_enabled()
int gr_bloom_intensity()
{
if (gr_screen.mode == GR_STUB) {
return 0;
}
if (graphics::Post_processing_manager == nullptr || !graphics::Post_processing_manager->bloomShadersOk()) {
return 0;
}
@@ -235,6 +248,10 @@ int gr_bloom_intensity()
void gr_set_bloom_intensity(int intensity)
{
if (gr_screen.mode == GR_STUB) {
return;
}
if (Using_in_game_options) {
graphics::Post_processing_bloom_intensity = intensity;
} else {
+96
View File
@@ -46,6 +46,10 @@ static void gr_flash_internal(int r, int g, int b, int a, bool alpha_flash)
}
void gr_flash(int r, int g, int b) {
if (gr_screen.mode == GR_STUB) {
return;
}
if (!(r || g || b)) {
return;
}
@@ -54,6 +58,10 @@ void gr_flash(int r, int g, int b) {
}
void gr_flash_alpha(int r, int g, int b, int a) {
if (gr_screen.mode == GR_STUB) {
return;
}
if (!(r || g || b || a)) {
return;
}
@@ -152,6 +160,10 @@ static void bitmap_ex_internal(int x,
}
void gr_aabitmap(int x, int y, int resize_mode, bool mirror) {
if (gr_screen.mode == GR_STUB) {
return;
}
GR_DEBUG_SCOPE("Draw AA-bitmap");
int w, h, do_resize;
@@ -222,6 +234,10 @@ void gr_aabitmap(int x, int y, int resize_mode, bool mirror) {
&gr_screen.current_color);
}
void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode, bool mirror) {
if (gr_screen.mode == GR_STUB) {
return;
}
int reclip;
#ifndef NDEBUG
@@ -349,6 +365,10 @@ void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode,
}
//these are penguins bitmap functions
void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
int reclip;
#ifndef NDEBUG
int count = 0;
@@ -748,6 +768,10 @@ void endDrawing(graphics::paths::PathRenderer* path) {
}
void gr_string(float sx, float sy, const char* s, int resize_mode, int in_length) {
if (gr_screen.mode == GR_STUB) {
return;
}
GR_DEBUG_SCOPE("Render string");
using namespace font;
@@ -917,10 +941,18 @@ static void gr_line(float x1, float y1, float x2, float y2, int resize_mode) {
}
void gr_line(int x1, int y1, int x2, int y2, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
gr_line(i2fl(x1), i2fl(y1), i2fl(x2), i2fl(y2), resize_mode);
}
void gr_aaline(vertex* v1, vertex* v2) {
if (gr_screen.mode == GR_STUB) {
return;
}
float x1 = v1->screen.xyw.x;
float y1 = v1->screen.xyw.y;
float x2 = v2->screen.xyw.x;
@@ -931,6 +963,10 @@ void gr_aaline(vertex* v1, vertex* v2) {
}
void gr_gradient(int x1, int y1, int x2, int y2, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
if (!gr_screen.current_color.is_alphacolor) {
gr_line(x1, y1, x2, y2, resize_mode);
return;
@@ -953,10 +989,18 @@ void gr_gradient(int x1, int y1, int x2, int y2, int resize_mode) {
endDrawing(path);
}
void gr_pixel(int x, int y, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
gr_line(x, y, x, y, resize_mode);
}
void gr_circle(int xc, int yc, int d, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
auto path = beginDrawing(resize_mode);
path->circle(i2fl(xc), i2fl(yc), d / 2.0f);
@@ -966,6 +1010,10 @@ void gr_circle(int xc, int yc, int d, int resize_mode) {
endDrawing(path);
}
void gr_unfilled_circle(int xc, int yc, int d, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
auto path = beginDrawing(resize_mode);
path->circle(i2fl(xc), i2fl(yc), d / 2.0f);
@@ -975,6 +1023,10 @@ void gr_unfilled_circle(int xc, int yc, int d, int resize_mode) {
endDrawing(path);
}
void gr_arc(int xc, int yc, float r, float angle_start, float angle_end, bool fill, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
// Ensure that angle_start < angle_end
if (angle_end < angle_start) {
float temp = angle_start;
@@ -1001,6 +1053,10 @@ void gr_arc(int xc, int yc, float r, float angle_start, float angle_end, bool fi
endDrawing(path);
}
void gr_curve(int xc, int yc, int r, int direction, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
using namespace graphics::paths;
auto path = beginDrawing(resize_mode);
@@ -1048,6 +1104,10 @@ void gr_curve(int xc, int yc, int r, int direction, int resize_mode) {
}
void gr_rect(int x, int y, int w, int h, int resize_mode, float angle) {
if (gr_screen.mode == GR_STUB) {
return;
}
auto path = beginDrawing(resize_mode);
if (angle != 0) {
// If we don't do this translation before and after rotating, the rotation will use 0,0 as the pivot, flinging the rectangle far away.
@@ -1065,6 +1125,10 @@ void gr_rect(int x, int y, int w, int h, int resize_mode, float angle) {
}
void gr_shade(int x, int y, int w, int h, int resize_mode) {
if (gr_screen.mode == GR_STUB) {
return;
}
auto r = (int) gr_screen.current_shader.r;
auto g = (int) gr_screen.current_shader.g;
auto b = (int) gr_screen.current_shader.b;
@@ -1083,6 +1147,10 @@ void gr_shade(int x, int y, int w, int h, int resize_mode) {
}
void gr_2d_start_buffer() {
if (gr_screen.mode == GR_STUB) {
return;
}
Assertion(!buffering_nanovg, "Tried to enable 2D buffering but it was already enabled!");
buffering_nanovg = true;
@@ -1092,6 +1160,10 @@ void gr_2d_start_buffer() {
}
void gr_2d_stop_buffer() {
if (gr_screen.mode == GR_STUB) {
return;
}
Assertion(buffering_nanovg, "Tried to stop 2D buffering but it was not enabled!");
buffering_nanovg = false;
@@ -1106,6 +1178,10 @@ static size_t immediate_buffer_size = 0;
static const int IMMEDIATE_BUFFER_RESIZE_BLOCK_SIZE = 2048;
size_t gr_add_to_immediate_buffer(size_t size, void* data) {
if (gr_screen.mode == GR_STUB) {
return 0;
}
GR_DEBUG_SCOPE("Add data to immediate buffer");
if (!gr_immediate_buffer_handle.isValid()) {
@@ -1132,6 +1208,10 @@ size_t gr_add_to_immediate_buffer(size_t size, void* data) {
return old_offset;
}
void gr_reset_immediate_buffer() {
if (gr_screen.mode == GR_STUB) {
return;
}
if (!gr_immediate_buffer_handle.isValid()) {
// we haven't used the immediate buffer yet
return;
@@ -1150,6 +1230,10 @@ void gr_render_primitives_immediate(material* material_info,
int n_verts,
void* data,
size_t size) {
if (gr_screen.mode == GR_STUB) {
return;
}
auto offset = gr_add_to_immediate_buffer(size, data);
gr_render_primitives(material_info, prim_type, layout, 0, n_verts, gr_immediate_buffer_handle, offset);
@@ -1162,6 +1246,10 @@ void gr_render_primitives_2d_immediate(material* material_info,
void* data,
size_t size)
{
if (gr_screen.mode == GR_STUB) {
return;
}
gr_set_2d_matrix();
gr_render_primitives_immediate(material_info, prim_type, layout, n_verts, data, size);
@@ -1315,6 +1403,10 @@ static void draw_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode,
void gr_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode, float angle)
{
if (gr_screen.mode == GR_STUB) {
return;
}
material mat_params;
material_set_interface(&mat_params,
gr_screen.current_bitmap,
@@ -1326,6 +1418,10 @@ void gr_bitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode, float ang
void gr_aabitmap_list(bitmap_rect_list* list, int n_bm, int resize_mode, float angle)
{
if (gr_screen.mode == GR_STUB) {
return;
}
material render_mat;
render_mat.set_blend_mode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
render_mat.set_depth_mode(ZBUFFER_TYPE_NONE);
+4
View File
@@ -418,6 +418,10 @@ void shadows_end_render()
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
{
if (gr_screen.mode == GR_STUB) {
return;
}
GR_DEBUG_SCOPE("Render shadows");
TRACE_SCOPE(tracing::BuildShadowMap);
+3 -3
View File
@@ -41,7 +41,7 @@ namespace font
int w, h;
w = 0;
h = 0;
h = text == nullptr ? 0 : fl2i(this->getHeight());
longest_width = 0;
// Maintain old behavior where textLen was an int
@@ -49,8 +49,8 @@ namespace font
bool checkLength = textLen >= 0;
if (text != nullptr && textLen != 0) {
h += fl2i(this->getHeight());
if (text != nullptr && textLen != 0)
{
while (*text)
{
// Process one or more
+1 -2
View File
@@ -688,8 +688,7 @@ void gr_get_string_size(int *w1, int *h1, const char *text, int len)
float w = 0.0f;
float h = 0.0f;
if (len != 0)
FontManager::getCurrentFont()->getStringSize(text, static_cast<size_t>(len), -1, &w, &h);
FontManager::getCurrentFont()->getStringSize(text, static_cast<size_t>(len), -1, &w, &h);
if (w1)
{
+72 -33
View File
@@ -57,6 +57,7 @@
#include "weapon/emp.h"
#include "weapon/weapon.h"
// This contains not only the retail HUD gauges but also any custom HUD gauges that are not specific to a ship.
SCP_vector<std::unique_ptr<HudGauge>> default_hud_gauges;
// new values for HUD alpha
@@ -369,12 +370,13 @@ void HudGauge::getPosition(int *x, int *y)
*y = position[1];
}
void HudGauge::initBaseResolution(int w, int h)
void HudGauge::initBaseResolution(int w, int h, float aq)
{
Assert(w >= 640 && h >= 480);
base_w = w;
base_h = h;
aspect_quotient = aq;
}
void HudGauge::initSlew(bool slew)
@@ -389,6 +391,43 @@ void HudGauge::initFont(int input_font_num)
}
}
int HudGauge::getFont()
{
return font_num;
}
void HudGauge::initOriginAndOffset(float originX, float originY, int offsetX, int offsetY)
{
tabled_origin[0] = originX;
tabled_origin[1] = originY;
tabled_offset[0] = offsetX;
tabled_offset[1] = offsetY;
}
void HudGauge::getOriginAndOffset(float *originX, float *originY, int *offsetX, int *offsetY)
{
*originX = tabled_origin[0];
*originY = tabled_origin[1];
*offsetX = tabled_offset[0];
*offsetY = tabled_offset[1];
}
void HudGauge::initCoords(bool use_coords, int coordsX, int coordsY)
{
tabled_use_coords = use_coords;
tabled_coords[0] = coordsX;
tabled_coords[1] = coordsY;
}
void HudGauge::getCoords(bool *use_coords, int *coordsX, int *coordsY)
{
*use_coords = tabled_use_coords;
*coordsX = tabled_coords[0];
*coordsY = tabled_coords[1];
}
const char* HudGauge::getCustomGaugeName()
{
return custom_name;
@@ -524,6 +563,11 @@ int HudGauge::getBaseHeight()
return base_h;
}
float HudGauge::getAspectQuotient()
{
return aspect_quotient;
}
int HudGauge::getConfigType()
{
//return gauge_type;
@@ -1377,7 +1421,6 @@ void hud_maybe_popup_weapons_gauge()
void hud_update_frame(float /*frametime*/)
{
object *targetp;
vec3d target_pos;
int can_target;
update_throttle_sound();
@@ -1463,8 +1506,6 @@ void hud_update_frame(float /*frametime*/)
hud_update_closest_turret();
}
hud_target_change_check();
// check to see if we are in messaging mode. If so, send the key to the code
// to deal with the message. hud_sqaudmsg_do_frame will return 0 if the key
// wasn't used in messaging mode, otherwise 1. In the event the key was used,
@@ -1474,15 +1515,15 @@ void hud_update_frame(float /*frametime*/)
}
if (Player_ai->target_objnum == -1) {
if (Target_static_looping.isValid()) {
snd_stop(Target_static_looping);
}
Player->target_is_dying = -1; // according to comments elsewhere in the code, set to -1 when no target
hud_target_change_check();
return;
}
targetp = &Objects[Player_ai->target_objnum];
if ( Player_ai->targeted_subsys != NULL ) {
vec3d target_pos;
get_subsystem_world_pos(targetp, Player_ai->targeted_subsys, &target_pos);
// get new distance of current target
@@ -1509,11 +1550,12 @@ void hud_update_frame(float /*frametime*/)
}
}
} else {
target_pos = targetp->pos;
Player_ai->current_target_distance = hud_find_target_distance(targetp,Player_obj);
}
// moved past the if() block so that the target tracker has the current frame's target distance
hud_target_change_check();
bool stop_targeting_this_thing = false;
// check to see if the target is still alive
@@ -1623,7 +1665,7 @@ void hud_render_preprocess(float frametime)
Player->subsys_in_view = -1;
hud_target_clear_display_list();
if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() >= 3) ) {
if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_stage() >= SUPERNOVA_STAGE::HIT) ) {
return;
}
@@ -1734,17 +1776,16 @@ void HudGaugeMissionTime::render(float /*frametime*/)
}
/**
* @brief Show supernova warning it there's a supernova coming
* @brief Show supernova warning if there's a supernova coming
*/
void hud_maybe_display_supernova()
{
float time_left;
time_left = supernova_time_left();
if(time_left < 0.0f){
if (!supernova_active()) {
return;
}
auto time_left = supernova_hud_time_left();
gr_set_color_fast(&Color_bright_red);
if (Lcl_pl) {
gr_printf(Supernova_coords[gr_screen.res][0], Supernova_coords[gr_screen.res][1], "Wybuch supernowej: %.2f s", time_left);
@@ -1794,7 +1835,7 @@ void hud_render_gauges(int cockpit_display_num)
return;
}
} else {
if( supernova_active() >= 3 ) {
if( supernova_stage() >= SUPERNOVA_STAGE::HIT) {
return;
}
}
@@ -1908,10 +1949,8 @@ void update_throttle_sound()
if ( object_get_gliding(Player_obj) ) { // Backslash
percent_throttle = Player_obj->phys_info.forward_thrust;
} else if ( Ships[Player_obj->instance].current_max_speed == 0 ) {
percent_throttle = Player_obj->phys_info.fspeed / Ship_info[Ships[Player_obj->instance].ship_info_index].max_speed;
} else {
percent_throttle = Player_obj->phys_info.fspeed / Ships[Player_obj->instance].current_max_speed;
percent_throttle = Player_obj->phys_info.fspeed / Ship_info[Ships[Player_obj->instance].ship_info_index].max_speed;
}
if (percent_throttle != last_percent_throttle || !Player_engine_snd_loop.isValid()) {
@@ -3869,11 +3908,6 @@ HudGauge* hud_get_custom_gauge(const char* name, bool check_all_gauges)
}
}
}
for (auto &gauge : default_hud_gauges) {
if (!stricmp(name, gauge->getCustomGaugeName())) {
return gauge.get();
}
}
}
// if the player is flying a ship with a custom set of gauges, check those
else if (player_sip && !player_sip->hud_gauges.empty()) {
@@ -3884,12 +3918,19 @@ HudGauge* hud_get_custom_gauge(const char* name, bool check_all_gauges)
}
}
// fall back to checking the custom gauges in the default list
for (auto &gauge : default_hud_gauges) {
if (gauge->isCustom() && !stricmp(name, gauge->getCustomGaugeName())) {
return gauge.get();
}
}
return nullptr;
}
int hud_get_default_gauge_index(const char *name)
{
int config_type = -1;
int config_type = -1, object_type = -1;
// default gauges had two different lists
for (int i = 0; i < NUM_HUD_GAUGES; i++) {
@@ -3902,15 +3943,15 @@ int hud_get_default_gauge_index(const char *name)
if (config_type < 0) {
for (int i = 0; i < Num_hud_gauge_types; i++) {
if (!stricmp(name, Hud_gauge_types[i].name)) {
config_type = Hud_gauge_types[i].def;
object_type = Hud_gauge_types[i].def;
break;
}
}
}
if (config_type >= 0) {
if (config_type >= 0 || object_type >= 0) {
for (int i = 0; i < (int)default_hud_gauges.size(); i++) {
if (default_hud_gauges[i]->getConfigType() == config_type) {
if (default_hud_gauges[i]->getConfigType() == config_type || default_hud_gauges[i]->getObjectType() == object_type) {
return i;
}
}
@@ -4026,14 +4067,12 @@ HudGauge(HUD_OBJECT_SUPERNOVA, HUD_DIRECTIVES_VIEW, false, false, 0, 255, 255, 2
void HudGaugeSupernova::render(float /*frametime*/)
{
float time_left;
// if there's a supernova coming
time_left = supernova_time_left();
if(time_left < 0.0f){
if (!supernova_active()) {
return;
}
auto time_left = supernova_hud_time_left();
gr_set_color_fast(&Color_bright_red);
if (Lcl_pl) {
renderPrintf(position[0], position[1], "Wybuch supernowej: %.2f s", time_left);
+17 -2
View File
@@ -220,6 +220,13 @@ protected:
int font_num;
// useful information to keep around for scripts
float tabled_origin[2];
int tabled_offset[2];
bool tabled_use_coords;
int tabled_coords[2];
float aspect_quotient;
bool lock_color;
bool sexp_lock_color;
bool reticle_follow;
@@ -262,21 +269,29 @@ public:
virtual ~HudGauge();
void initPosition(int x, int y);
void initBaseResolution(int w, int h);
void initSlew(bool slew);
void initBaseResolution(int w, int h, float aq);
void initFont(int input_font_num);
void initOriginAndOffset(float originX, float originY, int offsetX, int offsetY);
void initCoords(bool use_coords, int coordsX, int coordsY);
void initSlew(bool slew);
void initCockpitTarget(const char* display_name, int _target_x, int _target_y, int _target_w, int _target_h, int _canvas_w, int _canvas_h);
void initRenderStatus(bool render);
bool isCustom();
int getBaseWidth();
int getBaseHeight();
float getAspectQuotient();
int getConfigType();
int getObjectType();
void getPosition(int *x, int *y);
bool isOffbyDefault();
bool isActive();
int getFont();
void getOriginAndOffset(float *originX, float *originY, int *offsetX, int *offsetY);
void getCoords(bool* use_coords, int* coordsX, int* coordsY);
void updateColor(int r, int g, int b, int a = 255);
const color& getColor();
+15 -4
View File
@@ -57,9 +57,9 @@ void draw_brackets_square(graphics::line_draw_list* draw_list, int x1, int y1, i
}
width = x2 - x1;
Assert( width > 0);
height = y2 - y1;
Assert( height > 0);
if (width < 1 || height < 1)
return;
// make the brackets extend 25% of the way along the width or height
int bracket_width = width/4;
@@ -395,7 +395,12 @@ void HudGaugeBrackets::renderObjectBrackets(object *targetp, color *clr, int w_c
int bound_rc;
SCP_list<CJumpNode>::iterator jnp;
if ( Player->target_is_dying <= 0 || (Player_ai->target_objnum >= 0 && targetp != &Objects[Player_ai->target_objnum])) {
bool not_player_target = (Player_ai->target_objnum < 0 || targetp != &Objects[Player_ai->target_objnum]);
// target_is_dying is set to zero when the target is not dying, -1 when no target. Only 1, aka "TRUE", is invalid.
if ( not_player_target || Player->target_is_dying <= 0) {
int modelnum;
switch ( targetp->type ) {
@@ -475,7 +480,13 @@ void HudGaugeBrackets::renderObjectBrackets(object *targetp, color *clr, int w_c
int target_objnum = -1;
if(flags & TARGET_DISPLAY_DIST) {
distance = hud_find_target_distance(targetp, Player_obj);
// since we can have either the target, or rogue asteroids bracketed,
// check which case we are in, and then do the correct distance.
if (not_player_target) {
distance = hud_find_target_distance(targetp, &Player_obj->pos);
} else {
distance = Player_ai->current_target_distance;
}
}
if(flags & TARGET_DISPLAY_DOTS) {
+3
View File
@@ -16,7 +16,10 @@
#include "graphics/line_draw_list.h"
void hud_init_brackets();
// requires that x2 > x1 and y2 > y1
void draw_brackets_square(graphics::line_draw_list* draw_list, int x1, int y1, int x2, int y2, int resize_mode = GR_RESIZE_FULL);
void draw_brackets_square_quick(graphics::line_draw_list* draw_list, int x1, int y1, int x2, int y2, int thick=0);
void draw_brackets_diamond_quick(graphics::line_draw_list* draw_list, int x1, int y1, int x2, int y2);
+12 -6
View File
@@ -1613,6 +1613,7 @@ void hud_config_color_load(const char *name)
int idx;
char str[1024];
char *fname;
ubyte r, g, b, a;
fname = cf_add_ext(name, ".hcf");
@@ -1630,13 +1631,18 @@ void hud_config_color_load(const char *name)
while (optional_string("+Gauge:")) {
stuff_string(str, F_NAME, sizeof(str));
required_string("+RGBA:");
stuff_ubyte(&r);
stuff_ubyte(&g);
stuff_ubyte(&b);
stuff_ubyte(&a);
for (idx = 0; idx < NUM_HUD_GAUGES; idx++) {
if (!stricmp(str, Hud_Gauge_Names[idx])) {
required_string("+RGBA:");
stuff_ubyte(&HUD_config.clr[idx].red);
stuff_ubyte(&HUD_config.clr[idx].green);
stuff_ubyte(&HUD_config.clr[idx].blue);
stuff_ubyte(&HUD_config.clr[idx].alpha);
if (!stricmp(str, HC_gauge_descriptions(idx))) {
HUD_config.clr[idx].red = r;
HUD_config.clr[idx].green = g;
HUD_config.clr[idx].blue = b;
HUD_config.clr[idx].alpha = a;
break;
}
}
+2 -1
View File
@@ -194,7 +194,8 @@ void HudGaugeLock::renderOld(float frametime)
return;
}
if (Player->target_is_dying) {
// 1 is the only value for which your target is actually dying
if (Player->target_is_dying == 1) {
return;
}
+4 -2
View File
@@ -603,8 +603,10 @@ void hud_sourced_print(int source, const char *msg)
HUD_msg_buffer.push_back(new_msg);
// Invoke the scripting hook
OnHudMessageReceivedHook->run(scripting::hook_param_list(scripting::hook_param("Text", 's', msg),
scripting::hook_param("SourceType", 'i', source)));
if (OnHudMessageReceivedHook->isActive()) {
OnHudMessageReceivedHook->run(scripting::hook_param_list(scripting::hook_param("Text", 's', msg),
scripting::hook_param("SourceType", 'i', source)));
}
}
int hud_query_scrollback_size()
+2 -4
View File
@@ -40,10 +40,8 @@ void hud_draw_navigation()
unsigned int alpha = HUD_COLOR_ALPHA_MAX * 16;
if (Navs[CurrentNav].flags & NP_VISITED)
gr_init_alphacolor( &NavColor, 0xFF, 0xFF, 0x00, alpha);
else
gr_init_alphacolor( &NavColor, 0x80, 0x80, 0xff, alpha);
auto rgb = (Navs[CurrentNav].flags & NP_VISITED) ? Navs[CurrentNav].visited_color : Navs[CurrentNav].normal_color;
gr_init_alphacolor( &NavColor, rgb[0], rgb[1], rgb[2], alpha );
g3_rotate_vertex(&target_point, target_pos);
g3_project_vertex(&target_point);
+26 -15
View File
@@ -1168,7 +1168,7 @@ void check_color(int *colorp)
}
}
void adjust_base_res(int *base_res, int *force_scaling_above_res, bool scaling = true)
void adjust_base_res(int *base_res, const int *force_scaling_above_res, float *aspect_quotient, bool scaling = true)
{
// Don't scale gauge if:
// no scaling is set and current res is between base res and "force scaling above res"
@@ -1178,6 +1178,7 @@ void adjust_base_res(int *base_res, int *force_scaling_above_res, bool scaling =
gr_screen.center_w <= force_scaling_above_res[0] || gr_screen.center_h <= force_scaling_above_res[1])) ||
(gr_screen.center_w >= base_res[0] && gr_screen.center_h == base_res[1]) ||
(gr_screen.center_w == base_res[0] && gr_screen.center_h >= base_res[1])) {
*aspect_quotient = 1.0f;
base_res[0] = gr_screen.center_w;
base_res[1] = gr_screen.center_h;
return;
@@ -1189,11 +1190,11 @@ void adjust_base_res(int *base_res, int *force_scaling_above_res, bool scaling =
base_res[1] = force_scaling_above_res[1];
}
float aspect_quotient = ((float)gr_screen.center_w / (float)gr_screen.center_h) / ((float)base_res[0] / (float)base_res[1]);
if (aspect_quotient >= 1.0) {
base_res[0] = (int)(base_res[0] * aspect_quotient);
*aspect_quotient = ((float)gr_screen.center_w / (float)gr_screen.center_h) / ((float)base_res[0] / (float)base_res[1]);
if (*aspect_quotient >= 1.0f) {
base_res[0] = (int)(base_res[0] * *aspect_quotient);
} else {
base_res[1] = (int)(base_res[1] / aspect_quotient);
base_res[1] = (int)(base_res[1] / *aspect_quotient);
}
}
@@ -1237,7 +1238,7 @@ std::unique_ptr<T> gauge_load_common(gauge_settings* settings, T* preAllocated =
stuff_int_list(settings->force_scaling_above_res, 2);
}
adjust_base_res(settings->base_res, settings->force_scaling_above_res, settings->scale_gauge);
adjust_base_res(settings->base_res, settings->force_scaling_above_res, &settings->aspect_quotient, settings->scale_gauge);
// If no positioning information is specified, use the default position
bool use_default_pos = true;
@@ -1261,7 +1262,7 @@ std::unique_ptr<T> gauge_load_common(gauge_settings* settings, T* preAllocated =
}
}
} else {
adjust_base_res(settings->base_res, settings->force_scaling_above_res, settings->scale_gauge);
adjust_base_res(settings->base_res, settings->force_scaling_above_res, &settings->aspect_quotient, settings->scale_gauge);
}
} else {
if(gr_screen.res == GR_640) {
@@ -1272,7 +1273,7 @@ std::unique_ptr<T> gauge_load_common(gauge_settings* settings, T* preAllocated =
settings->base_res[1] = 768;
}
adjust_base_res(settings->base_res, settings->force_scaling_above_res, settings->scale_gauge);
adjust_base_res(settings->base_res, settings->force_scaling_above_res, &settings->aspect_quotient, settings->scale_gauge);
if (settings->set_position && !settings->use_coords) {
settings->coords[0] = (int)(settings->base_res[0] * settings->origin[0]) + settings->offset[0];
@@ -1344,8 +1345,11 @@ std::unique_ptr<T> gauge_load_common(gauge_settings* settings, T* preAllocated =
instance.reset(new T());
}
instance->initBaseResolution(settings->base_res[0], settings->base_res[1]);
instance->initBaseResolution(settings->base_res[0], settings->base_res[1], settings->aspect_quotient);
instance->initFont(settings->font_num);
instance->initOriginAndOffset(settings->origin[0], settings->origin[1], settings->offset[0], settings->offset[1]);
instance->initCoords(settings->use_coords, settings->coords[0], settings->coords[1]);
instance->initChase_view_only(settings->chase_view_only);
if (settings->set_position) {
instance->initPosition(settings->coords[0], settings->coords[1]);
@@ -1407,7 +1411,7 @@ void load_gauge_custom(gauge_settings* settings)
stuff_int_list(settings->force_scaling_above_res, 2);
}
adjust_base_res(settings->base_res, settings->force_scaling_above_res, settings->scale_gauge);
adjust_base_res(settings->base_res, settings->force_scaling_above_res, &settings->aspect_quotient, settings->scale_gauge);
// If no positioning information is specified, use the default position
bool use_default_pos = true;
@@ -1519,9 +1523,13 @@ void load_gauge_custom(gauge_settings* settings)
}
std::unique_ptr<HudGauge> hud_gauge(new HudGauge(gauge_type, settings->slew, r, g, b, name, text, filename, txtoffset_x, txtoffset_y));
hud_gauge->initBaseResolution(settings->base_res[0], settings->base_res[1]);
hud_gauge->initBaseResolution(settings->base_res[0], settings->base_res[1], settings->aspect_quotient);
hud_gauge->initPosition(settings->coords[0], settings->coords[1]);
hud_gauge->initFont(settings->font_num);
hud_gauge->initOriginAndOffset(settings->origin[0], settings->origin[1], settings->offset[0], settings->offset[1]);
hud_gauge->initCoords(settings->use_coords, settings->coords[0], settings->coords[1]);
hud_gauge->initRenderStatus(active_by_default);
hud_gauge->updateColor(colors[0], colors[1], colors[2]);
hud_gauge->lockConfigColor(lock_color);
@@ -2941,7 +2949,7 @@ void load_gauge_radar_dradis(gauge_settings* settings)
stuff_int_list(settings->force_scaling_above_res, 2);
}
adjust_base_res(settings->base_res, settings->force_scaling_above_res, settings->scale_gauge);
adjust_base_res(settings->base_res, settings->force_scaling_above_res, &settings->aspect_quotient, settings->scale_gauge);
if(optional_string("Origin:")) {
stuff_float_list(settings->origin, 2);
@@ -2967,7 +2975,7 @@ void load_gauge_radar_dradis(gauge_settings* settings)
settings->base_res[1] = 768;
}
adjust_base_res(settings->base_res, settings->force_scaling_above_res, settings->scale_gauge);
adjust_base_res(settings->base_res, settings->force_scaling_above_res, &settings->aspect_quotient, settings->scale_gauge);
settings->coords[0] = (int)(settings->base_res[0] * settings->origin[0]) + settings->offset[0];
settings->coords[1] = (int)(settings->base_res[1] * settings->origin[1]) + settings->offset[1];
@@ -3060,12 +3068,15 @@ void load_gauge_radar_dradis(gauge_settings* settings)
}
std::unique_ptr<HudGaugeRadarDradis> hud_gauge(new HudGaugeRadarDradis());
hud_gauge->initBaseResolution(settings->base_res[0], settings->base_res[1]);
hud_gauge->initBaseResolution(settings->base_res[0], settings->base_res[1], settings->aspect_quotient);
hud_gauge->initPosition(settings->coords[0], settings->coords[1]);
hud_gauge->initFont(settings->font_num);
hud_gauge->initOriginAndOffset(settings->origin[0], settings->origin[1], settings->offset[0], settings->offset[1]);
hud_gauge->initCoords(settings->use_coords, settings->coords[0], settings->coords[1]);
hud_gauge->initRadius(Radar_radius[0], Radar_radius[1]);
hud_gauge->initBitmaps(xy_fname, xz_yz_fname, sweep_fname, target_fname, unknown_fname);
hud_gauge->initCockpitTarget(display_name, display_offset[0], display_offset[1], display_size[0], display_size[1], canvas_size[0], canvas_size[1]);
hud_gauge->initFont(settings->font_num);
hud_gauge->initSound(loop_snd, loop_snd_volume, arrival_beep_snd, departure_beep_snd, stealth_arrival_snd, stealth_departure_snd, arrival_beep_delay, departure_beep_delay);
hud_gauge->initChase_view_only(settings->chase_view_only);
+2
View File
@@ -30,6 +30,7 @@ typedef struct gauge_settings {
int font_num;
bool scale_gauge;
int force_scaling_above_res[2];
float aspect_quotient;
SCP_vector<int>* ship_idx;
color *use_clr;
float origin[2];
@@ -45,6 +46,7 @@ typedef struct gauge_settings {
base_res[0] = -1;
base_res[1] = -1;
memcpy(force_scaling_above_res, Force_scaling_above_res_global, sizeof(force_scaling_above_res));
aspect_quotient = 1.0f;
origin[0] = 0.0f;
origin[1] = 0.0f;
offset[0] = 0;
+20 -9
View File
@@ -309,12 +309,21 @@ ship_info *sip = &Ship_info[Player_ship->ship_info_index];
}
void HudGaugeReticle::getFirepointStatus() {
// allow the firepoint status to be empty when a multiplayer observer
// this is not a bug, the observer will simply *not* have any firepoints.
if (Objects[Player->objnum].type == OBJ_OBSERVER) {
// only multiplayer instances should be getting here!
Assertion((Game_mode & GM_MULTIPLAYER), "Somehow FSO thinks its player object is an observer even though it's not in Multiplayer. Please report!");
return;
}
//First, get the player ship
ship_info* sip;
ship* shipp;
polymodel* pm;
Assert(Objects[Player->objnum].type == OBJ_SHIP);
Assertion(Objects[Player->objnum].type == OBJ_SHIP, "HudGaugeReticle::getFirepointStatus was passed an invalid object type of %d. Please report!", Objects[Player->objnum].type);
if (Objects[Player->objnum].type == OBJ_SHIP) {
shipp = &Ships[Objects[Player->objnum].instance];
@@ -459,8 +468,9 @@ void HudGaugeThrottle::initMatchSpeedOffsets(int x, int y, bool custom)
Match_speed_offsets[1] = y;
Use_custom_match_speed = custom;
font::FSFont* fsFont = font::get_font(font_num);
auto match_speed_str = XSTR("m", 1667);
font::FSFont* fsFont = font::get_font(font_num);
if (fsFont->getType() == font::VFNT_FONT)
{
ubyte sc = lcl_get_font_index(font_num);
@@ -468,7 +478,7 @@ void HudGaugeThrottle::initMatchSpeedOffsets(int x, int y, bool custom)
// a) the german font has no special m (its an a)
// b) the font has no special characters
if (sc == 0 || Lcl_gr) {
Match_speed_icon = 'm';
Match_speed_icon = match_speed_str[0];
}
else {
Match_speed_icon = sc + 3;
@@ -478,13 +488,12 @@ void HudGaugeThrottle::initMatchSpeedOffsets(int x, int y, bool custom)
else
{
// Default version for other fonts, draw a black character on a rectangle
Match_speed_icon = 'm';
Match_speed_icon = match_speed_str[0];
Match_speed_draw_background = true;
}
SCP_stringstream stream;
SCP_stringstream stream;
stream << static_cast<char>(Match_speed_icon);
const SCP_string& iconStr = stream.str();
gr_get_string_size(&Match_speed_icon_width, nullptr, iconStr.c_str());
@@ -584,7 +593,7 @@ void HudGaugeThrottle::render(float /*frametime*/)
if ( Show_percent ) {
if ( Player_obj->phys_info.flags & PF_AFTERBURNER_ON ) {
strcpy_s(buf, "A/B");
strcpy_s(buf, XSTR( "A/B", 1669 ));
} else {
sprintf(buf, XSTR( "%d%%", 326), (int)std::lround( (desired_speed/max_speed)*100 ));
}
@@ -641,8 +650,10 @@ void HudGaugeThrottle::renderThrottleSpeed(float current_speed, int y_end)
renderPrintf(sx, sy, "%s", buf);
if ( object_get_gliding(Player_obj) ) {
auto glide_str = XSTR("GLIDE", 1668);
if ( Use_custom_glide ) {
renderString(position[0] + Glide_offsets[0], position[1] + Glide_offsets[1], "GLIDE");
renderString(position[0] + Glide_offsets[0], position[1] + Glide_offsets[1], glide_str);
} else {
int offset;
if ( current_speed <= 9.5 ) {
@@ -653,7 +664,7 @@ void HudGaugeThrottle::renderThrottleSpeed(float current_speed, int y_end)
offset = -13;
}
renderString(sx+offset, sy + h, "GLIDE");
renderString(sx+offset, sy + h, glide_str);
}
} else if ( Players[Player_num].flags & PLAYER_FLAGS_MATCH_TARGET ) {
if ( Use_custom_match_speed ) {
+129 -119
View File
@@ -12,6 +12,7 @@
#include "ai/aigoals.h"
#include "ai/ailua.h"
#include "gamesnd/gamesnd.h"
#include "globalincs/linklist.h"
#include "hud/hudmessage.h"
@@ -33,7 +34,6 @@
#include "weapon/emp.h"
#include "weapon/weapon.h"
// defines for different modes in the squad messaging system
#define DEFAULT_MSG_TIMEOUT (8 * 1000) // number of seconds * 1000 to get milliseconds
@@ -156,25 +156,38 @@ int keys_used[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_
SCP_string Comm_order_types[NUM_COMM_ORDER_TYPES];
int player_order::orderingCounter = 0;
std::vector<player_order> Player_orders = {
player_order("attack ship", "Destroy my target", 299, ATTACK_TARGET_ITEM),
player_order("disable ship", "Disable my target", 300, DISABLE_TARGET_ITEM ),
player_order("disarm ship", "Disarm my target", 301, DISARM_TARGET_ITEM ),
player_order("disable subsys","Destroy subsystem", 302, DISABLE_SUBSYSTEM_ITEM ),
player_order("guard ship", "Protect my target", 303, PROTECT_TARGET_ITEM ),
player_order("ignore ship", "Ignore my target", 304, IGNORE_TARGET_ITEM ),
player_order("form on wing","Form on my wing", 305, FORMATION_ITEM ),
player_order("cover me", "Cover me", 306, COVER_ME_ITEM ),
player_order("attack any", "Engage enemy", 307, ENGAGE_ENEMY_ITEM ),
player_order("dock", "Capture my target", 308, CAPTURE_TARGET_ITEM),
player_order("rearm me", "Rearm me", 309, REARM_REPAIR_ME_ITEM),
player_order("abort rearm", "Abort rearm", 310, ABORT_REARM_REPAIR_ITEM),
player_order("depart", "Depart", 311, DEPART_ITEM),
player_order("stay near me", "Stay near me", -1, STAY_NEAR_ME_ITEM),
player_order("stay near ship", "Stay near my target",-1, STAY_NEAR_TARGET_ITEM),
player_order("keep safe dist", "Keep safe distance", -1, KEEP_SAFE_DIST_ITEM)
player_order("no order", "No Order", -1, -1, NO_ORDER_ITEM), //Required to keep defines in sync with array indices
player_order("attack ship", "Destroy my target", 299, -1, ATTACK_TARGET_ITEM),
player_order("disable ship", "Disable my target", 300, -1, DISABLE_TARGET_ITEM),
player_order("disarm ship", "Disarm my target", 301, -1, DISARM_TARGET_ITEM),
player_order("disable subsys","Destroy subsystem", 302, -1, DISABLE_SUBSYSTEM_ITEM),
player_order("guard ship", "Protect my target", 303, -1, PROTECT_TARGET_ITEM),
player_order("ignore ship", "Ignore my target", 304, -1, IGNORE_TARGET_ITEM),
player_order("form on wing","Form on my wing", 305, -1, FORMATION_ITEM),
player_order("cover me", "Cover me", 306, -1, COVER_ME_ITEM),
player_order("attack any", "Engage enemy", 307, -1, ENGAGE_ENEMY_ITEM),
player_order("dock", "Capture my target", 308, -1, CAPTURE_TARGET_ITEM),
player_order("rearm me", "Rearm me", 309, -1, REARM_REPAIR_ME_ITEM),
player_order("abort rearm", "Abort rearm", 310, -1, ABORT_REARM_REPAIR_ITEM),
player_order("depart", "Depart", 311, -1, DEPART_ITEM),
player_order("stay near me", "Stay near me", -1, -1, STAY_NEAR_ME_ITEM),
player_order("stay near ship", "Stay near my target",-1, -1, STAY_NEAR_TARGET_ITEM),
player_order("keep safe dist", "Keep safe distance", -1, -1, KEEP_SAFE_DIST_ITEM)
};
const std::set<size_t> default_messages{ ATTACK_TARGET_ITEM , DISABLE_TARGET_ITEM , DISARM_TARGET_ITEM , PROTECT_TARGET_ITEM , IGNORE_TARGET_ITEM , FORMATION_ITEM , COVER_ME_ITEM , ENGAGE_ENEMY_ITEM , DEPART_ITEM , DISABLE_SUBSYSTEM_ITEM };
const std::set<size_t> enemy_target_messages{ ATTACK_TARGET_ITEM , DISABLE_TARGET_ITEM , DISARM_TARGET_ITEM , IGNORE_TARGET_ITEM , STAY_NEAR_TARGET_ITEM , CAPTURE_TARGET_ITEM , DISABLE_SUBSYSTEM_ITEM };
const std::set<size_t> friendly_target_messages{ PROTECT_TARGET_ITEM };
const std::set<size_t> target_messages = []() {
std::set<size_t> setunion;
std::set_union(enemy_target_messages.cbegin(), enemy_target_messages.cend(), friendly_target_messages.cbegin(), friendly_target_messages.cend(), std::inserter(setunion, setunion.end()));
return setunion;
}();
void hud_init_comm_orders()
{
int i;
@@ -194,22 +207,21 @@ void hud_init_comm_orders()
Comm_order_types[i] = temp_comm_order_types[i];
}
for(auto& order : Player_orders) {
order.localized_name = XSTR(order.hud_name.c_str(), order.hud_xstr);
}
for (auto& order : Player_orders)
order.localize();
std::sort(Player_orders.begin(), Player_orders.end(), [](const player_order& o1, const player_order& o2) {
return o1.legacy_id < o2.legacy_id;
});
}
// Text to display on the messaging menu when using the shortcut keys
const char *comm_order_get_text(int item)
{
for(const auto& order : Player_orders){
if(order.id == item)
return order.localized_name.c_str();
}
Assertion(item < (int)Player_orders.size(), "Did not find order with index %d!", item);
UNREACHABLE("Did not find order with id %d!", item);
return nullptr;
return Player_orders[item].localized_name.c_str();
}
SCP_vector<squadmsg_history> Squadmsg_history;
@@ -217,7 +229,7 @@ SCP_vector<squadmsg_history> Squadmsg_history;
// forward declarations
void hud_add_issued_order(const char *name, int order);
void hud_update_last_order(const char *target, int order_source, int special_index);
bool hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip = nullptr);
bool hud_squadmsg_is_target_order_valid(size_t order, ai_info *aip = nullptr);
bool hud_squadmsg_ship_valid(ship *shipp, object *objp = nullptr);
bool hud_squadmsg_ship_order_valid( int shipnum, int order );
@@ -332,10 +344,7 @@ bool hud_squadmsg_ship_valid(ship *shipp, object *objp)
// if a messaging shortcut, be sure this ship can process the order
if ( Msg_shortcut_command != -1 ) {
bool accepts_any = false;
for(size_t order : shipp->orders_accepted)
accepts_any |= (bool)(Player_orders[order].id & Msg_shortcut_command);
if ( !accepts_any )
if (shipp->orders_accepted.count((size_t) Msg_shortcut_command) == 0)
return false;
else if ( !hud_squadmsg_ship_order_valid(objp->instance, Msg_shortcut_command) )
@@ -586,11 +595,13 @@ int hud_squadmsg_get_key()
return i;
// play general fail sound if inactive item hit.
else if ( (i < Num_menu_items) && !(MsgItems[i].active) )
else if ((i + First_menu_item < Num_menu_items) && !(MsgItems[i + First_menu_item].active)) {
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
else if ( (i < Num_menu_items) && (MsgItems[i].active) ) // only return keys that are associated with menu items
return i;
else if ((i + First_menu_item < Num_menu_items) && (MsgItems[i + First_menu_item].active)) { // only return keys that are associated with menu items
return i + First_menu_item;
}
else {
Msg_key_used = 0; // if no #-key pressed for visible item, break and allow timer to
@@ -723,7 +734,7 @@ bool hud_squadmsg_ship_order_valid( int shipnum, int order )
Assert( shipnum >= 0 && shipnum < MAX_SHIPS );
ship *shipp = &Ships[shipnum];
switch ( order )
switch ( order )
{
case DEPART_ITEM:
// disabled ships can't depart.
@@ -745,31 +756,27 @@ bool hud_squadmsg_ship_order_valid( int shipnum, int order )
// returns true or false if the Players target is valid for the given order
// find_order is true when we need to search the comm_orders array for the order entry. We have
// to do this action in some cases since all we know is the actual "value" of the order
bool hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip )
bool hud_squadmsg_is_target_order_valid(size_t order, ai_info *aip )
{
int target_objnum;
size_t i;
ship *shipp, *ordering_shipp;
object *objp;
if ( aip == NULL )
aip = Player_ai;
// find the comm_menu item for this command
if ( find_order ) {
for (i = 0; i < Player_orders.size(); i++ ) {
if ( Player_orders[i].id == order )
break;
}
Assert( i < Player_orders.size() );
order = (int)i;
target_objnum = aip->target_objnum;
ordering_shipp = &Ships[aip->shipnum];
//If it's a lua order, defer to luaai
if (Player_orders[order].lua_id != -1) {
return ai_lua_is_valid_target(Player_orders[order].lua_id, target_objnum, ordering_shipp);
}
// orders which don't operate on targets are always valid
if ( !(Player_orders[order].id & TARGET_MESSAGES) )
if ( target_messages.count(order) == 0 )
return true;
target_objnum = aip->target_objnum;
// order isn't valid if there is no player target
if ( target_objnum == -1 ) {
@@ -778,7 +785,6 @@ bool hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip
objp = &Objects[target_objnum];
ordering_shipp = &Ships[aip->shipnum];
// target isn't a ship, then return false
if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_WEAPON) )
@@ -793,7 +799,7 @@ bool hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip
return false;
}
if ( (Player_orders[order].id == ATTACK_TARGET_ITEM )
if ( order == ATTACK_TARGET_ITEM
&& ((Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Bomb]) || (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Fighter_Interceptable]))
&& (Weapons[objp->instance].team != ordering_shipp->team) ) {
return true;
@@ -817,24 +823,24 @@ bool hud_squadmsg_is_target_order_valid(int order, int find_order, ai_info *aip
}
// if the order is a disable order or depart, and the ship is disabled, order isn't active
if ( (Player_orders[order].id == DISABLE_TARGET_ITEM) && (shipp->flags[Ship::Ship_Flags::Disabled]) ){
if ( (order == DISABLE_TARGET_ITEM) && (shipp->flags[Ship::Ship_Flags::Disabled]) ){
return false;
}
// same as above except for disarmed.
if ( (Player_orders[order].id == DISARM_TARGET_ITEM) && ((shipp->subsys_info[SUBSYSTEM_TURRET].type_count == 0) || (shipp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f)) ){
if ( (order == DISARM_TARGET_ITEM) && ((shipp->subsys_info[SUBSYSTEM_TURRET].type_count == 0) || (shipp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f)) ){
return false;
}
// if order is disable subsystem, and no subsystem targeted or no hits, then order not valid
if ( (Player_orders[order].id == DISABLE_SUBSYSTEM_ITEM) && ((aip->targeted_subsys == nullptr) || (aip->targeted_subsys->current_hits <= 0.0f)) ){
if ( (order == DISABLE_SUBSYSTEM_ITEM) && ((aip->targeted_subsys == nullptr) || (aip->targeted_subsys->current_hits <= 0.0f)) ){
return false;
}
// check based on target's and player's team
if ( (shipp->team == ordering_shipp->team) && (FRIENDLY_TARGET_MESSAGES & Player_orders[order].id) ){
if ( (shipp->team == ordering_shipp->team) && (friendly_target_messages.count(order) > 0) ){
return true;
} else if ( (shipp->team != ordering_shipp->team) && (ENEMY_TARGET_MESSAGES & Player_orders[order].id) ){
} else if ( (shipp->team != ordering_shipp->team) && (enemy_target_messages.count(order) > 0) ){
return true;
} else {
return false;
@@ -911,11 +917,7 @@ void hud_squadmsg_send_to_all_fighters( int command, int player_num )
// don't send the command if the "wing" won't accept the command. We do this by looking at
// the set of orders accepted for the wing leader
bool accepts_current = false;
for(size_t order : shipp->orders_accepted)
accepts_current |= (bool)(Player_orders[order].id & command);
if ( !accepts_current )
if (shipp->orders_accepted.count((size_t)command) == 0)
continue;
// send the command to the wing
@@ -951,11 +953,7 @@ void hud_squadmsg_send_to_all_fighters( int command, int player_num )
continue;
// don't send command if ship won't accept if
bool accepts_current = false;
for(size_t order : shipp->orders_accepted)
accepts_current |= (bool)(Player_orders[order].id & command);
if ( !accepts_current )
if (shipp->orders_accepted.count((size_t)command) == 0)
continue;
if (send_message) {
@@ -1009,6 +1007,7 @@ int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message,
ai_info *ainfo;
int ai_mode, ai_submode; // ai mode and submode needed for ship commands
char *target_shipname; // ship number of possible targets
object_ship_wing_point_team lua_target;
int message;
int target_team, ship_team; // team id's for the ship getting message and any target the player has
ship *ordering_shipp;
@@ -1045,10 +1044,10 @@ int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message,
// a shortcut to save on repetitive coding. If the order is a 'target' order, make the default
// mesage be "no target"
message = MESSAGE_NOSIR;
if ( (command & TARGET_MESSAGES) && (ainfo->target_objnum == -1) )
if ( target_messages.count((size_t)command) > 0 && (ainfo->target_objnum == -1) )
message = MESSAGE_NO_TARGET;
if ( hud_squadmsg_is_target_order_valid(command, 1, ainfo) ) {
if ( hud_squadmsg_is_target_order_valid((size_t) command, ainfo) ) {
target_shipname = NULL;
target_team = -1;
@@ -1126,7 +1125,7 @@ int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message,
}
ai_mode = AI_GOAL_DESTROY_SUBSYSTEM;
ai_submode = ship_get_subsys_index( &Ships[Objects[ainfo->target_objnum].instance], ainfo->targeted_subsys->system_info->subobj_name );
ai_submode = ship_find_subsys( &Ships[Objects[ainfo->target_objnum].instance], ainfo->targeted_subsys->system_info->subobj_name );
special_index = ai_submode;
message = MESSAGE_ATTACK_TARGET;
break;
@@ -1244,16 +1243,24 @@ int hud_squadmsg_send_ship_command( int shipnum, int command, int send_message,
message = MESSAGE_YESSIR;
break;
default:
Int3(); // get Allender -- illegal message
default: {
Assert(command < (int) Player_orders.size()); // get Allender -- illegal message
ai_mode = AI_GOAL_LUA;
ai_submode = Player_orders[command].lua_id;
auto lua_porder = ai_lua_find_player_order(Player_orders[command].lua_id);
message = lua_porder->ai_message;
if (ainfo->target_objnum != -1)
lua_target = object_ship_wing_point_team(&Ships[Objects[ainfo->target_objnum].instance]);
break;
}
}
// handle case of messaging one ship. Deal with messaging all fighters next.
if ( ai_mode != AI_GOAL_NONE ) {
Assert(ai_submode != -1234567);
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, ai_mode, ai_submode, target_shipname, &Ai_info[Ships[shipnum].ai_index] );
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, ai_mode, ai_submode, target_shipname, &Ai_info[Ships[shipnum].ai_index], lua_target );
if( update_history == SQUADMSG_HISTORY_ADD_ENTRY ) {
hud_add_issued_order(Ships[shipnum].ship_name, command);
hud_update_last_order(target_shipname, player_num, special_index);
@@ -1293,6 +1300,7 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
ai_info *ainfo;
int ai_mode, ai_submode; // ai mode and submode needed for ship commands
char *target_shipname; // ship number of possible targets
object_ship_wing_point_team lua_target;
int message_sent, message;
int target_team, wing_team; // team for the wing and the player's target
ship *ordering_shipp;
@@ -1331,10 +1339,10 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
// a shortcut to save on repetative coding
message = MESSAGE_NOSIR;
if ( (command & TARGET_MESSAGES) && (ainfo->target_objnum == -1) )
if ( (target_messages.count((size_t)command) > 0) && (ainfo->target_objnum == -1) )
message = MESSAGE_NO_TARGET;
if ( hud_squadmsg_is_target_order_valid(command, 1, ainfo) ) {
if ( hud_squadmsg_is_target_order_valid((size_t)command, ainfo) ) {
target_shipname = NULL;
target_team = -1;
@@ -1399,7 +1407,7 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
Assert( ainfo->targeted_subsys->current_hits > 0.0f);
ai_mode = AI_GOAL_DESTROY_SUBSYSTEM;
ai_submode = ship_get_subsys_index( &Ships[Objects[ainfo->target_objnum].instance], ainfo->targeted_subsys->system_info->subobj_name );
ai_submode = ship_find_subsys( &Ships[Objects[ainfo->target_objnum].instance], ainfo->targeted_subsys->system_info->subobj_name );
special_index = ai_submode;
message = MESSAGE_ATTACK_TARGET;
break;
@@ -1462,15 +1470,23 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
case KEEP_SAFE_DIST_ITEM:
return 0;
default:
Int3(); // get Allender -- illegal message
default: {
Assert(command < (int) Player_orders.size()); // get Allender -- illegal message
ai_mode = AI_GOAL_LUA;
ai_submode = Player_orders[command].lua_id;
auto lua_porder = ai_lua_find_player_order(Player_orders[command].lua_id);
message = lua_porder->ai_message;
if(ainfo->target_objnum != -1)
lua_target = object_ship_wing_point_team(&Ships[Objects[ainfo->target_objnum].instance]);
break;
}
}
if ( ai_mode != AI_GOAL_NONE ) {
Assert(ai_submode != -1234567);
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, ai_mode, ai_submode, target_shipname, wingnum );
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, ai_mode, ai_submode, target_shipname, wingnum, lua_target );
if( update_history == SQUADMSG_HISTORY_ADD_ENTRY ) {
hud_add_issued_order(Wings[wingnum].name, command);
@@ -1572,8 +1588,6 @@ void hud_squadmsg_type_select( )
{
int k, i;
First_menu_item = 0;
// Add the items
for (i = 0; i < NUM_COMM_ORDER_TYPES; i++)
{
@@ -1697,13 +1711,13 @@ void hud_squadmsg_ship_select()
k = hud_squadmsg_get_key();
if ( k != -1 ) { // if true, we have selected a ship.
if ( Msg_shortcut_command == -1 ) {
Msg_instance = MsgItems[First_menu_item + k].instance; // store the instance id in a global
Msg_instance = MsgItems[k].instance; // store the instance id in a global
hud_squadmsg_do_mode( SM_MODE_SHIP_COMMAND ); // and move to a new mode
} else {
// we must convert the Msg_shortcut_command value to a value that the message
// system normally uses to select a command. Since the menu
//Assert( Msg_shortcut_command != IGNORE_TARGET_ITEM );
hud_squadmsg_send_ship_command( MsgItems[First_menu_item+k].instance, Msg_shortcut_command, 1, SQUADMSG_HISTORY_ADD_ENTRY);
hud_squadmsg_send_ship_command( MsgItems[k].instance, Msg_shortcut_command, 1, SQUADMSG_HISTORY_ADD_ENTRY);
hud_squadmsg_toggle();
}
}
@@ -1724,11 +1738,11 @@ void hud_squadmsg_wing_select()
k = hud_squadmsg_get_key();
if ( k != -1 ) { // if true, we have selected a ship.
if ( Msg_shortcut_command == -1 ) { // do normal menu stuff when no hoykey active
Msg_instance = MsgItems[First_menu_item + k].instance; // store the instance id in a global
Msg_instance = MsgItems[k].instance; // store the instance id in a global
hud_squadmsg_do_mode( SM_MODE_WING_COMMAND ); // and move to a new mode
} else {
//Assert( Msg_shortcut_command != IGNORE_TARGET_ITEM );
hud_squadmsg_send_wing_command( MsgItems[First_menu_item+k].instance, Msg_shortcut_command, 1, SQUADMSG_HISTORY_ADD_ENTRY );
hud_squadmsg_send_wing_command( MsgItems[k].instance, Msg_shortcut_command, 1, SQUADMSG_HISTORY_ADD_ENTRY );
hud_squadmsg_toggle();
}
}
@@ -1893,11 +1907,11 @@ void hud_squadmsg_reinforcement_select()
hud_squadmsg_toggle(); // take us out of message mode
rnum = MsgItems[First_menu_item + k].instance;
rnum = MsgItems[k].instance;
// check to see if trying to call a reinforcement not yet available. If so, maybe play message, but
// definately bail
if ( MsgItems[First_menu_item + k].active == 0 ) {
if ( MsgItems[k].active == 0 ) {
return;
}
@@ -1912,12 +1926,17 @@ void hud_squadmsg_reinforcement_select()
}
}
bool hud_order_comparator(size_t a, size_t b) {
return Player_orders[a].ordering < Player_orders[b].ordering;
}
// function to display list of commands for a ship
void hud_squadmsg_ship_command()
{
int k;
std::set<size_t> orders, default_orders;
std::set<size_t> orders;
std::set<size_t, decltype(&hud_order_comparator)> default_orders(&hud_order_comparator);
// when adding ship commands, we must look at the type of ship, and what messages that
// ship allows. First, place all messages that are possible onto the menu, then
@@ -1926,33 +1945,31 @@ void hud_squadmsg_ship_command()
// show on comm menu.
if ( Msg_instance != MESSAGE_ALL_FIGHTERS ) {
orders = Ships[Msg_instance].orders_accepted;
default_orders = ship_get_default_orders_accepted( &Ship_info[Ships[Msg_instance].ship_info_index] );
const auto& default_orders_accepted = ship_get_default_orders_accepted(&Ship_info[Ships[Msg_instance].ship_info_index]);
default_orders.insert(default_orders_accepted.cbegin(), default_orders_accepted.cend());
} else {
for(size_t i = 0; i < Player_orders.size(); i++){
if(Player_orders[i].id & DEFAULT_MESSAGES)
default_orders.insert(i);
}
orders = default_orders;
orders = default_messages;
default_orders.insert(default_messages.cbegin(), default_messages.cend());
}
First_menu_item = 0;
Num_menu_items = 0;
for(size_t order_id : default_orders) {
Assert (Num_menu_items < MAX_MENU_ITEMS);
MsgItems[Num_menu_items].text = Player_orders[order_id].localized_name;
MsgItems[Num_menu_items].instance = Player_orders[order_id].id;
MsgItems[Num_menu_items].instance = (int)order_id;
MsgItems[Num_menu_items].active = 0;
// check the bit to see if the command is active
if (orders.find(order_id) != orders.end())
MsgItems[Num_menu_items].active = 1;
// if the order cannot be carried out by the ship, then item should be inactive
if ((Msg_instance != MESSAGE_ALL_FIGHTERS) && !hud_squadmsg_ship_order_valid(Msg_instance, Player_orders[order_id].id))
if ((Msg_instance != MESSAGE_ALL_FIGHTERS) && !hud_squadmsg_ship_order_valid(Msg_instance, (int)order_id))
MsgItems[Num_menu_items].active = 0;
// do some other checks to possibly gray out other items.
// if no target, remove any items which are associated with the players target
if (!hud_squadmsg_is_target_order_valid((int)order_id, 0))
if (!hud_squadmsg_is_target_order_valid(order_id, nullptr))
MsgItems[Num_menu_items].active = 0;
// if messaging all fighters, see if we should gray out the order if no one will accept it,
@@ -1960,10 +1977,10 @@ void hud_squadmsg_ship_command()
if (Msg_instance == MESSAGE_ALL_FIGHTERS) {
ship_obj* so;
ship* shipp;
int partial_accept, all_accept; // value which tells us what to do with menu item
bool partial_accept, all_accept; // value which tells us what to do with menu item
all_accept = Player_orders[order_id].id;
partial_accept = 0;
all_accept = true;
partial_accept = false;
for (so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so)) {
// don't send messge to ships not on player's team, or that are in a wing.
@@ -1975,11 +1992,9 @@ void hud_squadmsg_ship_command()
if (!(Ship_info[shipp->ship_info_index].is_fighter_bomber()))
continue;
int local_accepted = 0;
for(size_t accepted_order : shipp->orders_accepted)
local_accepted |= Player_orders[accepted_order].id;
bool local_accepted = shipp->orders_accepted.count(order_id) > 0;
all_accept &= local_accepted; // 'and'ing will either keep this bit set or zero it properly
partial_accept |= (local_accepted & Player_orders[order_id].id); // 'or'ing will tell us if at least one accepts
partial_accept |= local_accepted; // 'or'ing will tell us if at least one accepts
}
if (!all_accept) {
@@ -2021,7 +2036,8 @@ void hud_squadmsg_wing_command()
wing *wingp;
int shipnum;
std::set<size_t> default_orders, orders;
std::set<size_t> orders;
std::set<size_t, decltype(&hud_order_comparator)> default_orders(&hud_order_comparator);
// when adding commands for wings, we will look at all of the ships in the wing, and create
// the order list from that set of ships. In the future, we may want to do something else....
@@ -2034,10 +2050,7 @@ void hud_squadmsg_wing_command()
default_orders.insert(setAdd.begin(), setAdd.end());
}
for(size_t i = 0; i < Player_orders.size(); i++){
if (Player_orders[i].id & CAPTURE_TARGET_ITEM) // we cannot capture any target with a wing.
default_orders.erase(i);
}
default_orders.erase(CAPTURE_TARGET_ITEM); // we cannot capture any target with a wing.
Num_menu_items = 0;
shipnum = wingp->ship_index[wingp->special_ship];
@@ -2049,7 +2062,7 @@ void hud_squadmsg_wing_command()
// to be available in the wing.
Assert ( Num_menu_items < MAX_MENU_ITEMS );
MsgItems[Num_menu_items].text = Player_orders[order_id].localized_name;
MsgItems[Num_menu_items].instance = Player_orders[order_id].id;
MsgItems[Num_menu_items].instance = (int)order_id;
MsgItems[Num_menu_items].active = 0;
// possibly grey out the menu item depending on whether or not the "wing" will accept this order
@@ -2242,11 +2255,7 @@ int hud_squadmsg_hotkey_select( int k )
continue;
// be sure that this ship can accept this command
bool accepts_current = false;
for(size_t order : Ships[objp->instance].orders_accepted)
accepts_current |= (bool)(Player_orders[order].id & Msg_shortcut_command);
if ( !accepts_current )
if ( Ships[objp->instance].orders_accepted.count(Msg_shortcut_command) == 0)
continue;
hud_squadmsg_send_ship_command( objp->instance, Msg_shortcut_command, send_message, SQUADMSG_HISTORY_ADD_ENTRY );
@@ -2412,16 +2421,17 @@ int hud_query_order_issued(const char *to, const char *order_name, const char *t
for (i = 0; i < (int) Player_orders.size(); i++)
if (!stricmp(order_name, Player_orders[i].hud_name.c_str()))
order = Player_orders[i].id;
if (!stricmp(order_name, Player_orders[i].hud_name.c_str())) {
order = i;
break;
}
// Goober5000 - if not found, check compatibility
if (order == -1)
{
if (!stricmp(order_name, "Attack my target"))
{
i = 0; // it maps to option 0, "Destroy my target"
order = Player_orders[i].id;
order = ATTACK_TARGET_ITEM;
}
}
@@ -2450,7 +2460,7 @@ int hud_query_order_issued(const char *to, const char *order_name, const char *t
continue;
}
int subsys_index = ship_get_subsys_index(&Ships[target_ship], special_argument);
int subsys_index = ship_find_subsys(&Ships[target_ship], special_argument);
// if the order is for s different subsystem
if (Squadmsg_history[i].special_index != subsys_index) {
continue;
+30 -25
View File
@@ -30,42 +30,52 @@
class object;
// defines for messages that can be sent from the player. Defined at bitfields so that we can enable
// and disable messages on a message by message basis
// defines for messages that can be sent from the player. Indexes into Player_orders
#define ATTACK_TARGET_ITEM (1<<0)
#define DISABLE_TARGET_ITEM (1<<1)
#define DISARM_TARGET_ITEM (1<<2)
#define PROTECT_TARGET_ITEM (1<<3)
#define IGNORE_TARGET_ITEM (1<<4)
#define FORMATION_ITEM (1<<5)
#define COVER_ME_ITEM (1<<6)
#define ENGAGE_ENEMY_ITEM (1<<7)
#define CAPTURE_TARGET_ITEM (1<<8)
#define NO_ORDER_ITEM 0
#define ATTACK_TARGET_ITEM 1
#define DISABLE_TARGET_ITEM 2
#define DISARM_TARGET_ITEM 3
#define PROTECT_TARGET_ITEM 4
#define IGNORE_TARGET_ITEM 5
#define FORMATION_ITEM 6
#define COVER_ME_ITEM 7
#define ENGAGE_ENEMY_ITEM 8
#define CAPTURE_TARGET_ITEM 9
// the next are for the support ship only
#define REARM_REPAIR_ME_ITEM (1<<9)
#define ABORT_REARM_REPAIR_ITEM (1<<10)
#define STAY_NEAR_ME_ITEM (1<<11)
#define STAY_NEAR_TARGET_ITEM (1<<12)
#define KEEP_SAFE_DIST_ITEM (1<<13)
#define REARM_REPAIR_ME_ITEM 10
#define ABORT_REARM_REPAIR_ITEM 11
#define STAY_NEAR_ME_ITEM 12
#define STAY_NEAR_TARGET_ITEM 13
#define KEEP_SAFE_DIST_ITEM 14
// next item for all ships again -- to try to preserve relative order within the message menu
#define DEPART_ITEM (1<<14)
#define DEPART_ITEM 15
// out of order, but it was this way in the original source
#define DISABLE_SUBSYSTEM_ITEM (1<<15)
#define DISABLE_SUBSYSTEM_ITEM 16
// used for Message box gauge
#define NUM_MBOX_FRAMES 3
typedef struct player_order {
private:
//Needed, because legacy order-id's were not assigned in order
static int orderingCounter;
//Used to ensure that built-in order indexing is always correct
int legacy_id;
friend void hud_init_comm_orders();
public:
SCP_string parse_name;
SCP_string hud_name;
int hud_xstr;
int id;
SCP_string localized_name;
player_order(SCP_string parsename, SCP_string hudname, int hudxstr, int orderid = 0) : parse_name(std::move(parsename)), hud_name(std::move(hudname)), hud_xstr(hudxstr), id(orderid), localized_name("") { }
int lua_id;
int ordering;
player_order(SCP_string parsename, SCP_string hudname, int hudxstr, int luaid = -1, int legacyid = 999999) : legacy_id(legacyid), parse_name(std::move(parsename)), hud_name(std::move(hudname)), hud_xstr(hudxstr), localized_name(""), lua_id(luaid), ordering(orderingCounter++) { }
inline void localize() { localized_name = XSTR(hud_name.c_str(), hud_xstr); }
} player_order;
extern std::vector<player_order> Player_orders;
@@ -74,7 +84,6 @@ extern std::vector<player_order> Player_orders;
// might not allow some messages
//WMC - Formerly FIGHTER_MESSAGES
#define DEFAULT_MESSAGES (ATTACK_TARGET_ITEM | DISABLE_TARGET_ITEM | DISARM_TARGET_ITEM | PROTECT_TARGET_ITEM | IGNORE_TARGET_ITEM | FORMATION_ITEM | COVER_ME_ITEM | ENGAGE_ENEMY_ITEM | DEPART_ITEM | DISABLE_SUBSYSTEM_ITEM)
/*
#define BOMBER_MESSAGES FIGHTER_MESSAGES // bombers can do the same things as fighters
@@ -92,10 +101,6 @@ extern std::vector<player_order> Player_orders;
// these messages require an active target. They are also the set of messages
// which cannot be given to a ship when the target is on the same team, or the target
// is not a ship.
#define ENEMY_TARGET_MESSAGES (ATTACK_TARGET_ITEM | DISABLE_TARGET_ITEM | DISARM_TARGET_ITEM | IGNORE_TARGET_ITEM | STAY_NEAR_TARGET_ITEM | CAPTURE_TARGET_ITEM | DISABLE_SUBSYSTEM_ITEM )
#define FRIENDLY_TARGET_MESSAGES (PROTECT_TARGET_ITEM)
#define TARGET_MESSAGES (ENEMY_TARGET_MESSAGES | FRIENDLY_TARGET_MESSAGES)
+19 -6
View File
@@ -1530,6 +1530,8 @@ void hud_target_missile(object *source_obj, int next_flag)
continue;
}
Assertion(Objects[so->objnum].type == OBJ_SHIP, "hud_target_missile was about to call obj_team with a non-ship obejct with type %d. Please report!", Objects[so->objnum].type);
// only allow targeting of hostile bombs
if (!iff_x_attacks_y(Player_ship->team, obj_team(A))) {
continue;
@@ -1716,11 +1718,8 @@ typedef struct eval_next_turret {
float dist;
} eval_next_turret;
int turret_compare_func(const void *e1, const void *e2)
int turret_compare_func(const eval_next_turret *p1, const eval_next_turret *p2)
{
eval_next_turret *p1 = (eval_next_turret*)e1;
eval_next_turret *p2 = (eval_next_turret*)e2;
Assert(p1->type != TYPE_NONE);
Assert(p2->type != TYPE_NONE);
@@ -1850,7 +1849,7 @@ void hud_target_live_turret(int next_flag, int auto_advance, int only_player_tar
// sort the list if we're not using turret straight ahead of us
if (!use_straight_ahead_turret) {
insertion_sort(ent, num_live_turrets, sizeof(eval_next_turret), turret_compare_func);
insertion_sort(ent, num_live_turrets, turret_compare_func);
}
if (use_straight_ahead_turret) {
@@ -2124,6 +2123,8 @@ bool evaluate_ship_as_closest_target(esct *esct_p)
// consider the ship alone if there are no attacking turrets
if ( !turret_is_attacking ) {
// Volition switched distance evaluation methods here... presumably this is to prioritize small fighters when dogfighting next to large ships...
// Since this is used specifically for finding an ordering of targets and does not involve any visual displays, distance-to-center is reasonable.
//new_distance = hud_find_target_distance(objp, Player_obj);
new_distance = vm_vec_dist_quick(&objp->pos, &Player_obj->pos);
@@ -4407,9 +4408,16 @@ void hud_target_change_check()
// check if the main target has changed
if (Player_ai->last_target != Player_ai->target_objnum) {
// acquired target
if ( Player_ai->target_objnum != -1){
snd_play( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::TARGET_ACQUIRE)), 0.0f );
}
// cleared target
else {
if (Target_static_looping.isValid()) {
snd_stop(Target_static_looping);
}
}
// if we have a hotkey set active, see if new target is in set. If not in
// set, deselect the current hotkey set.
@@ -4517,6 +4525,7 @@ void HudGaugeTargetTriangle::render(float /*frametime*/)
object *targetp = &Objects[Player_ai->target_objnum];
// draw the targeting triangle that orbits the outside of the outer circle of the reticle
// checking !target_is_dying is correct here, since you do not want -1 (no target) or 1(is actually dying)
if (!Player->target_is_dying && maybeFlashSexp() != 1) {
hud_set_iff_color(targetp, 1);
@@ -6311,7 +6320,11 @@ void HudGaugeOffscreen::render(float /*frametime*/)
int dir;
if(target_display_list[i].objp) {
dist = hud_find_target_distance( target_display_list[i].objp, Player_obj );
if (OBJ_INDEX(target_display_list[i].objp) == Player_ai->target_objnum) {
dist = Player_ai->current_target_distance;
} else {
dist = hud_find_target_distance( target_display_list[i].objp, Player_obj );
}
} else {
// if we don't have a corresponding object, use given position to figure out distance
dist = vm_vec_dist_quick(&Player_obj->pos, &target_display_list[i].target_pos);
+20 -7
View File
@@ -1566,6 +1566,23 @@ void get_turret_subsys_name(ship_weapon *swp, char *outstr)
//WMC - find the first weapon, if there is one
if (swp->num_primary_banks || swp->num_secondary_banks) {
// allow the first weapon on the turret to specify the name
for (int i = 0; i < swp->num_primary_banks; ++i) {
auto wip = &Weapon_info[swp->primary_bank_weapons[i]];
if (*(wip->altSubsysName) != '\0') {
sprintf(outstr, "%s", wip->altSubsysName);
return;
}
}
for (int i = 0; i < swp->num_secondary_banks; ++i) {
auto wip = &Weapon_info[swp->secondary_bank_weapons[i]];
if (*(wip->altSubsysName) != '\0') {
sprintf(outstr, "%s", wip->altSubsysName);
return;
}
}
// otherwise use a general name based on the type of weapon(s) on the turret
auto flags = turret_weapon_aggregate_flags(swp);
// check if beam or flak using weapon flags
@@ -1578,17 +1595,13 @@ void get_turret_subsys_name(ship_weapon *swp, char *outstr)
sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
} else if (turret_weapon_has_subtype(swp, WP_LASER)) {
// ballistic too! - Goober5000
if (flags[Weapon::Info_Flags::Ballistic])
{
if (flags[Weapon::Info_Flags::Ballistic]) {
sprintf(outstr, "%s", XSTR("Turret", 1487));
}
// the TVWP has some primaries flagged as bombs
else if (flags[Weapon::Info_Flags::Bomb])
{
else if (flags[Weapon::Info_Flags::Bomb]) {
sprintf(outstr, "%s", XSTR("Missile lnchr", 1569));
}
else
{
} else {
sprintf(outstr, "%s", XSTR("Laser turret", 1568));
}
} else {
Loaded 100 of 407 files, more files were not shown because too many files have changed in this diff. Show more