Compare commits

...
Author SHA1 Message Date
JohnAFernandez 05f2db381a Create temp_coverity_scan.yaml
Temporary coverity scan workflow until the scheduled one gets a review
2023-10-30 11:10:32 -04:00
John Fernandez 6038076bf0 Add current_cmeasure > -1 check
This is an actual edge case bug.  If no countermeasure was set, and then one was set, there might be a garbage timestamp set that would give an incorrect countermeasure delay on next use.
2023-10-30 10:56:45 -04:00
John Fernandez 40c8cbbb25 Add check for negative index
For coverity 1523515
2023-10-30 10:56:45 -04:00
John Fernandez bd7429c353 Get rid of Extraneous check
Coverity 1523341 is pointing out this check, but shipp->ship_info_index is checked earlier just before we set the shipp pointer on line 1243
2023-10-30 10:56:45 -04:00
John Fernandez faf130adb3 Add Assertion for Coverity 1093701 2023-10-30 10:56:45 -04:00
John Fernandez f7fef072df Feedback 2023-10-30 10:56:18 -04:00
John Fernandez 0da6a4a64c Coverity 1523287
Fall back to standard behavior if no allowed paths.

Missing bracket
2023-10-30 10:56:18 -04:00
John Fernandez f542fea96e coverity 1523419
Avoid dividing by zero when there is just one autoscale ai class
2023-10-30 10:56:18 -04:00
John Fernandez 742326e42e Coverity 1523548 Divide by zero
Make sure we only use autoscale delay if there is more than one autoscale ai class.
2023-10-30 10:56:18 -04:00
John Fernandez e25a6517fc Add a check for 0
To avoid division by zero (in dubious circumstances) explicitly check for zero.  For coverity 1523313
2023-10-30 10:56:18 -04:00
John Fernandez be0c78dc72 Add checks for options_multi_vox_plist_get
For coverity 1093612, this function *should* never return zero, but it is no catastrophic if it does.  Allowing it to return a negative value in some unknown edge case would allow it to clobber some other global data.

So now add a check for negative values and take no action if those negative values are reached.  Assert on debug.
2023-10-30 10:55:41 -04:00
John Fernandez ef681affbf Make sure we don't clobber other memory
If this index is negative one return early before we accidentally clobber other data.

Coverity 1523181
2023-10-30 10:55:41 -04:00
Goober5000 3a2ac5ab5f Merge pull request #5726 from Goober5000/persona_index_check
check for out-of-range persona
2023-10-30 00:01:03 -04:00
Goober5000 435676a67d Merge pull request #5730 from Goober5000/class_type_check
make sure class_type exists when used
2023-10-30 00:00:47 -04:00
Goober5000 4fbe3b7131 make sure class_type exists when used
A mission in Mantle caused an invalid vector access when checking whether to vaporize a ship whose ship type was -1.  Turns out having "no type" is actually allowed, so I audited all `class_type` accesses throughout the code for potential -1 accesses.  Most were properly checked but a few were not.  A few others needed to be tweaked.

(I suspect this is something that would be on the Coverity list if it isn't already.)
2023-10-29 15:17:22 -04:00
Goober5000 87a4ae1e41 check for out-of-range persona
For missions which use the Persona Index method, make sure the mod doesn't load a persona index that is out of range for the personas it knows about.
2023-10-28 21:23:25 -04:00
mjn-mixael c738941ccf Provide Lua a way to toggle the mainhall help overlay 2023-10-28 19:16:09 -04:00
John Fernandez 5c25bb9bcb Just use the already existing SCP_string
The destination strings in player_order are already SCP_strings, so no need to use manual allocation
2023-10-28 19:15:25 -04:00
John Fernandez e0bc6d0ed7 Fix memory leak in tga file writing
Yes.  I know, I know, we're not going to use this code anymore.  But just in case, I don't want this memory leak to have the possibility to exist in the future.
2023-10-28 19:15:25 -04:00
Mike Nelson ec706a6a87 Allow SCPUI saving current player data to file (#5718)
* Allow saving current player data to file

* return nil, dummy

* unused
2023-10-27 07:32:37 -04:00
John Fernandez 5d0127a764 Fix workflow by adding reference branch 2023-10-26 23:41:28 -04:00
Mike Nelson 91c15e6f48 Player general orders (#5638) 2023-10-26 19:22:44 -04:00
Asteroth a9fc7bab8a fix for particle culling (#5719) 2023-10-26 16:08:09 -04:00
Taylor Richards 042c85d213 revert workaround for the windows runner breakage (#5722) 2023-10-26 13:53:27 -04:00
Goober5000 bb3d59ecbe Merge pull request #5715 from Baezon/fix-hud-target-triangle
Bugfix HUD target direction triangle
2023-10-25 23:19:26 -04:00
Goober5000 d1c57391cf Merge pull request #5699 from Goober5000/handle_shuffled_parse_objects
handle parse objects that are out of order
2023-10-25 23:18:19 -04:00
Mike Nelson 5986b7143f Adds custom data for intel entries (#5660)
* adds custom data for intel entries

* update tests

* This one, too
2023-10-25 07:32:03 -04:00
wookieejedi 5d447951b4 Add Game Option to refresh selected weapon in loadout (#5713)
* Add Game Option to refresh selected weapon in loadout

This PR adds an option to always ensure the viewed weapon is one that can actually be on the selected ship when first clicking on the weapon loadout.

If you go to the loadout in the briefing and view the weapons on your ship, then go and change your ship class and go back to the weapon loadout screen, you will see that the weapon shown in the window on the right side is from your very first viewing before you changed your ship class. Displaying a weapon not allowed on a ship by default can be confusing to players, especially on mods like FotG where most ships have unique weapons.

The player can still of course click on a non-allowed weapon to view it, but with this PR the player will be initially shown a selected weapon that is allowed on the ship when opening the loadout editor.

Tested and works as expected.

* update order to be near weapon bools
2023-10-25 07:31:23 -04:00
Sébastien Noel f149c36b44 Fix a few typos (#5598) 2023-10-24 20:33:45 -04:00
Asteroth 34b6cf74ab whoops forgot the rval 2023-10-24 15:16:12 -04:00
Asteroth bc33f90e32 early return if z is 0 2023-10-24 14:32:56 -04:00
MageKing17 bb47531c55 Make lock_fov settable for aspect/javelin missiles. (#5493)
The code has always checked a per-weapon-class value called `lock_fov` when comparing the dot product of a ship to its target to see if it can lock on to it, however the weapon table hasn't ever included a way to set this value; it's always the default value of 0.85. This just adds "+Lock FOV:" entries to aspect/javelin homing missile parsing after "+Seeker Strength:", which will set `lock_fov` as long as the supplied input is between 0 and 360 degrees.
2023-10-24 07:26:54 -04:00
Asteroth aed90493ec make g3_project_vertex unconditionally project 2023-10-23 17:53:30 -04:00
John Fernandez d54c3e51e3 Apply Workaround to windows Build 2023-10-23 15:47:27 -04:00
Goober5000 a215bea0d0 unswap the net signatures 2023-10-23 15:29:06 -04:00
Goober5000 ec23f6bd0e Merge pull request #5709 from Goober5000/fix_loadout_crash
fix a crash in the apply-loadout-to-wing routine
2023-10-23 12:21:30 -04:00
John Fernandez d93d56e1c9 remove redundant setting of object_host 2023-10-23 10:24:13 -04:00
John Fernandez d2265325e9 check for nullptr to avoid nullptr dereference
For coverity 1093467
2023-10-23 10:24:13 -04:00
John Fernandez 2bb22a2153 Return to avoid nullptr dereference
For coverity 1093461.  If this is null, the function is done at this point.
2023-10-23 10:24:13 -04:00
John Fernandez 018c22eee1 Make sure Net_player is not null here
For coverity 1093460. Net_player should never be null here, but it is C++ after all.
2023-10-23 10:24:13 -04:00
John Fernandez 6ef60c67ca Make sure Multi_pxo_channels is not null
For coverity 1093458
2023-10-23 10:24:13 -04:00
John Fernandez 982e8d7f85 Add net_player nullptr check
Address coverity 1093457 by adding a nullptr check and Assertion.  This *should* never happen, but that's what asserts are for, right?
2023-10-23 10:24:13 -04:00
John Fernandez 8affd53cf6 Remove Unused Functions
These functions have not been called from what I can tell since the source code was released.  But they did happen to trigger a clang warning, so it's time to get rid of them.
2023-10-23 07:50:29 -04:00
Mike Nelson eeaf894b15 Message notes feature (#5541)
* Add stage notes feature for mission messages

* don't keep notes outside the mission editor

* use F_MULTITEXT and do lcl_replacements

* this should be multitext too
2023-10-23 07:38:33 -04:00
Goober5000 b546d897ae fix a crash in the apply-loadout-to-wing routine
If a wing has fewer than four ships, clicking the apply-to-all button will cause a vector subscript out of range error.  This fixes it.
2023-10-23 00:44:33 -04:00
John Fernandez d8aea4ad30 Add CMakePresets.json to gitignore 2023-10-22 22:54:24 -04:00
Goober5000 829692b7bd Merge pull request #5468 from Goober5000/5462_followup
additional cleanup from PR 5462
2023-10-22 17:10:42 -04:00
Goober5000 855935d4eb Merge pull request #5706 from Goober5000/fix_5705
fix change-soundtrack after <No Music>
2023-10-22 16:12:30 -04:00
Goober5000 f83efb54c0 fix change-soundtrack after <No Music>
The fix in #5578 assumed that a previously playing soundtrack would properly set the timestamp, but if no soundtrack was previously played at all, this wouldn't happen.  So if we deliberately don't play a soundtrack, be sure to set the timestamp as if `event_music_do_frame()` had been called.

Fixes #5705.
2023-10-22 15:31:02 -04:00
Mike Nelson 3ca26587eb add default player weapon flag (#5600) 2023-10-22 13:23:30 -04:00
John Fernandez 3e2bb36d4b Fix Redefined Macro Warning
Clarify
2023-10-22 00:37:18 -04:00
Goober5000 02bd62ff3c Merge pull request #5700 from Goober5000/special_to_supercap
change "special warp physics" to "supercap warp physics"
2023-10-21 17:34:20 -04:00
Goober5000 e1e0239914 also the dialog text 2023-10-21 16:40:31 -04:00
Goober5000 e621dbe997 Merge pull request #5464 from Goober5000/render_constify
add const where appropriate to the modelrender API
2023-10-21 15:57:24 -04:00
Goober5000 ea5c328c13 change "special warp physics" to "supercap warp physics"
Per discussion with @Baezon, this is a more precise term.
2023-10-21 15:51:16 -04:00
Goober5000 8c0bc25303 Merge pull request #5671 from Goober5000/subsystem_calculation_fix
add "Calculate subsystem hitpoints after parsing" option
2023-10-21 14:08:37 -04:00
Goober5000 6b0a3b7606 handle parse objects that are out of order
Occasionally, FRED can save a mission with a wing's ships out of order; this can happen if ships are deleted and FRED finds a free index in the middle of the ship list.  This can cause benign but confusing mismatches in the ship registry, the hotkey list, and other places -- and it's also possible some mismatches may not be so benign, e.g. in multiplayer.  Anyway, it's better for the ships to appear in the order the wing expects them, so this adds a routine to swap them around if necessary.
2023-10-21 13:40:09 -04:00
Mike Nelson 9afe76b5d2 force msaa in-game toggle to require restart (#5688) 2023-10-21 11:44:15 -04:00
Mike Nelson ad27664ebc Pause and Resume voices (#5636)
* pause and resume voices

* Use newer styling rather than the sound.cpp styling
2023-10-21 10:23:53 -04:00
Goober5000 2fe182a4b1 Merge pull request #5604 from Goober5000/drawString_tweak
small speedup to drawString
2023-10-21 01:28:23 -04:00
Goober5000 60c2718b91 add spacing 2023-10-20 23:26:46 -04:00
Tyler Blount 15d9b9b3db Merge pull request #5689 from MjnMixael/fix_lightshafts_optimization
Fix lightshafts and bloom in-game options
2023-10-20 15:09:03 -07:00
mjn-mixael d00003e199 Merge branch 'master' into fix_lightshafts_optimization 2023-10-20 16:11:34 -05:00
Tyler Blount 991d0ee2d6 Merge pull request #5696 from MjnMixael/deferred_lighting_ingame
Add deferred lighting as an in-game option
2023-10-20 14:09:33 -07:00
mjn-mixael 3eee74a31c remove unneeded header 2023-10-20 14:16:22 -05:00
mjn-mixael 941d5f7ec3 Move the option definition to a file that doesn't require glad.h for building and resolve xstr issue 2023-10-20 14:01:50 -05:00
Asteroth 0cde26dd6e make invalid model_subsystem model nums a hard error (#5591) 2023-10-20 14:40:48 -04:00
Mike Nelson 7804f7fff5 add feature to always display the damage gauge (#5518) 2023-10-20 14:40:27 -04:00
Asteroth 832cec27ad bugfix missile time determination (#5595) 2023-10-20 14:40:02 -04:00
Mike Nelson 31acb115c2 Add nebula-fade-poof SEXP (#5612)
* nebula-fade-poofs

* Move this up because order of operations is important.

* Add some documentation

* Respect time compression

* Fix sexp description

* Make sure faded poofs do not flicker

* optimize
2023-10-20 14:39:38 -04:00
Goober5000 f9591b3a92 Merge pull request #5664 from Goober5000/fix_cheat_status
fix incorrect setting of disabled/disarmed flags when cheating
2023-10-20 14:27:37 -04:00
mjn-mixael 21f92194f1 Add deferred lighting as an in-game option 2023-10-20 12:38:53 -05:00
wookieejedi c605451460 Fix glare shining through cockpits in freelook (#5690)
Fixes #3098. The `shipfx_eye_in_shadow` function did a collision check for cockpits, bit did not previously take into account of the viewpoint had a non-forward orientation (ie the player was using free look). This PR sets the collide check to take that into account with a 1 line fix. Tested with multiple FotG cockpits and fixes the issue.
2023-10-20 07:39:25 -04:00
Taylor Richards 2acdc65875 add workaround for broken windows workflow (#5693)
Temporary fix for broken windows workflow. Hopefully a more permanent
solution will be found soon and we can then remove this.

Reference: https://github.com/actions/runner-images/issues/8598
2023-10-19 17:39:04 -04:00
Goober5000 b7de2fd644 Merge pull request #5554 from Goober5000/set_armor_type_generic
enhance set-armor-type to work with generic subsystems
2023-10-19 14:09:50 -04:00
Tyler Blount a226a81d80 Merge pull request #5692 from JohnAFernandez/master
Revert one "Fix" and add comments
2023-10-19 09:25:36 -07:00
John Fernandez eb39532f7c Revert one "Fix" and add comments
Only one of these was an actual memory leak.

Add comments to clarify
2023-10-19 11:42:24 -04:00
JohnAFernandez 1478ace3e0 Avoid edge case divide by zero (#5683)
* Add a divide by zero check

For coverity 1107324.  Keeps framecount from dividing by zero in very rare circumstances.

* Add a clarifying comment

This marks isNaturalNumberFactor() so that we know it is the best way to get whether a number is a natural number.

Modulo division is slower and gives the same results.

* Spoiled by Rust
2023-10-19 07:57:12 -04:00
JohnAFernandez 7edc5bf842 Change underlying type to avoid endianness problem (#5680)
Before this change if the wrong endianness was used, the c style cast that was used here would lead to the argument being passed to getsockopt to lack the actual information.

Fixes coverity 1093482

(Directly cast to socklen_t)
2023-10-19 07:56:21 -04:00
JohnAFernandez b8dc7d643d Fix two small memory leaks (#5679)
Fixes 1093679 and 1093680 from coverity by freeing if an early return is reached.
2023-10-19 07:55:23 -04:00
Goober5000 883ed32796 ai-disable-ship-tactical and ai-disarm-ship-tactical (#5512)
Add "tactical" versions of disable and disarm goals which only perform the specific task without implying anything else.  The target ship is not protected and attack goals are not cleared from other ships.

There is also a new AI profiles flag to make this the default hud squad message command instead of the classic disable/disarm.
2023-10-19 07:50:49 -04:00
Mike Nelson f3dfc85c0f weapon ignores countermeasures flag (#5628) 2023-10-19 07:49:06 -04:00
mjn-mixael e32ea7b694 Merge branch 'master' into fix_lightshafts_optimization
# Conflicts:
#	code/graphics/post_processing.cpp
2023-10-18 23:09:43 -05:00
Tyler Blount 7ef70f6d4d Merge pull request #5627 from MjnMixael/new_controls_xstrs
Add built-in xstrs for SCP-added controls
2023-10-18 20:21:49 -07:00
Tyler Blount 1b1afbf8d7 Merge branch 'master' into new_controls_xstrs 2023-10-18 19:51:26 -07:00
Tyler Blount bfdf05469b Merge pull request #5622 from MjnMixael/scpui_options_localization
SCPUI Options Localization
2023-10-18 19:50:43 -07:00
mjn-mixael aee48373ab Make sure these post processing variables are not optimized out of non Debug builds 2023-10-18 15:07:21 -05:00
mjn-mixael a2f1638a99 adjust XSTR IDs 2023-10-18 13:55:46 -05:00
mjn-mixael 762cf4cb88 We'll get this right eventually 2023-10-18 13:45:55 -05:00
mjn-mixael 705287c8d4 "nothing" to see here 2023-10-18 13:26:05 -05:00
mjn-mixael e2aac31912 Merge branch 'master' into scpui_options_localization
# Conflicts:
#	code/camera/camera.cpp
2023-10-18 12:49:48 -05:00
Tyler Blount a9f5a11813 Merge pull request #5686 from MjnMixael/lua_add_scrollback
Lua add scrollback
2023-10-18 10:21:01 -07:00
mjn-mixael b8728ed828 get team rather than team index 2023-10-18 08:59:24 -05:00
mjn-mixael de1110650f Adjust XSTR IDs per feedback 2023-10-18 08:42:25 -05:00
BMagnu b3295e5a2d Fix near z planes for the cockpit rendering (#5654)
* Properly unify cockpit near planes

* Properly pass near plane to deferred shader
2023-10-18 08:08:22 -04:00
Tyler Blount a6c1b1b04a Merge pull request #5605 from naomimyselfandi/more-message-filters
More message filters
2023-10-18 00:36:24 -07:00
Goober5000 b5fdf52e8c Merge pull request #5428 from Goober5000/remove_key_save
remove hud_squadmsg_save_keys()
2023-10-18 03:25:09 -04:00
Goober5000 c43f5bdd58 Merge pull request #5516 from Goober5000/pof_version_fix
POF version fix
2023-10-18 03:24:55 -04:00
Tyler Blount dc7fc774b8 Merge pull request #5662 from MjnMixael/on_intro_hook
Intro about to play hook
2023-10-18 00:24:44 -07:00
Goober5000 dad16f76c4 Merge pull request #5574 from Goober5000/generateWeaponGroupId
add mn.generateWeaponGroupId()
2023-10-17 20:06:27 -04:00
Goober5000 d10c59f6cc Merge pull request #5629 from Goober5000/arrival_warp_distance
add support for predicting arrival warp distance
2023-10-17 20:06:17 -04:00
Goober5000 3bd2fc9a56 Merge pull request #5677 from Goober5000/fix_5529
rewrite primary weapon cycling
2023-10-17 20:06:10 -04:00
Goober5000 fabff58d09 Merge pull request #5684 from Goober5000/prevent_repeated_death
don't kill/self-destruct ship if it's already dying
2023-10-17 20:05:29 -04:00
Mike Nelson 2fd3bf091d add waytpoint as allowed lua sexp parameter type (#5631) 2023-10-17 19:28:40 -04:00
Mike Nelson b4442d3423 double the allowed cargo (#5626) 2023-10-17 19:27:43 -04:00
Mike Nelson cf4cae7264 add dkjson as a default lua file (#5534) 2023-10-17 19:26:39 -04:00
Mike Nelson ebea1b1240 remove new lines from default generated mission (#5519) 2023-10-17 19:25:06 -04:00
mjn-mixael 54341acb9b allow use of enums 2023-10-16 15:54:53 -05:00
mjn-mixael 07fd188064 lua method to add a message directly to the message log.
(cherry picked from commit 1caceeaa2b9ebe654a102e293146dc23b9f3c2ee)
2023-10-16 15:21:37 -05:00
BMagnu 0cbe06884b Allow to Capture Mouse in FSO window (#5678)
* Allow to capture mouse, and also make window present

* Fix Typo
2023-10-17 03:57:21 +09:00
Goober5000 c1d3e5a2ad Merge pull request #5597 from Goober5000/maneuver_despite_engines
add a maneuver-despite-engines flag
2023-10-16 14:40:05 -04:00
Naomi Coffman 2bcedc34cc Respond to PR feedback 2023-10-16 12:36:48 -04:00
Goober5000 16892c3e46 Merge pull request #5670 from Goober5000/fly_to_ship_upgrade
fix and upgrade ai-fly-to-ship
2023-10-16 04:26:23 -04:00
Goober5000 5c88b75b94 Merge pull request #5524 from Goober5000/splash_aspect_ratio
aspect-ratio-specific splash screens
2023-10-16 03:26:10 -04:00
Goober5000 987c705bc9 address feedback 2023-10-16 03:24:53 -04:00
Goober5000 b89cbbd530 fix and upgrade ai-fly-to-ship
The ai-fly-to-ship goal was added early in FSO's development but never worked right.  Until recently it could crash; and even aside from the crash the AI would try to reach the target's exact position, causing repeated collisions.  This folds ai-fly-to-ship into ai-stay-near-ship, since the behaviors are conceptually the same except for fly-to being satisfied as soon as the target is in range.

This also adds a new "escort" mode usable by both behaviors.  The default Volition behavior is to swoop toward the target in a long, graceful arc; the new mode generates a goal point and flies directly to that point.  These can be toggled via an optional sexp parameter.

There is also some minor cleanup and a new vec3d operator for convenience.

Needed for Scroll; depends on #5667.
2023-10-16 03:24:52 -04:00
Goober5000 d3383d9d87 Merge pull request #5667 from Goober5000/refactor_mission_goal_achievable
refactor ai_mission_goal_achievable
2023-10-16 03:23:43 -04:00
Goober5000 4f6d9c36a8 don't kill/self-destruct ship if it's already dying
If a ship is in the process of dying, it shouldn't be killed or self-destructed again.  This fixes a bug noticed by RedMageJoe during the Derelict playthrough.

(This situation is distinct from a ship being hit while in the middle of its death roll.  That shortens the death roll but does not try to kill the ship again.)
2023-10-16 00:36:10 -04:00
JohnAFernandez a36157f582 Merge pull request #5540 from MjnMixael/lua_mod_root
LUA get mod root
2023-10-15 23:16:40 -04:00
JohnAFernandez 3837455004 Merge pull request #5617 from MjnMixael/allow_no_subcategory
Allow Lua SEXPs to not specify a subcategory
2023-10-15 23:15:59 -04:00
JohnAFernandez 808f7a88c6 Merge pull request #5557 from MjnMixael/lua_launch_url
Lua method to launch arbitrary url
2023-10-15 23:15:08 -04:00
Goober5000 79702273d5 some tweaks and clarifications 2023-10-15 16:55:50 -04:00
BMagnu d06018bcad Bump version to 23.3 (#5681) 2023-10-15 19:23:34 +00:00
Goober5000 ac87cde80d supercap check should come from params 2023-10-15 14:16:51 -04:00
Goober5000 06d9e02c34 sync up tokens 2023-10-15 13:48:23 -04:00
Asteroth 40233ae05f use a constant for excess speed 2023-10-15 13:43:49 -04:00
Goober5000 57192065d6 change assert to assertion 2023-10-15 13:43:49 -04:00
Goober5000 d2031a476a some fixes 2023-10-15 13:43:49 -04:00
Asteroth c60ea2d4a7 move supercap warp time constant 2023-10-15 13:43:49 -04:00
Asteroth 6843d48358 add math for predicting warp in distance 2023-10-15 13:43:47 -04:00
Goober5000 066b251052 implement UI work for arrival warp distance 2023-10-15 13:42:27 -04:00
BMagnu 4596600627 Fix hiDPI (#5673) 2023-10-16 01:44:33 +09:00
BMagnu ea262f90c0 Make version parsing available (#5655)
* Make version parsing available

* Consolidate version parsing

* Recode version parsing and write test

* remove copy paste error
2023-10-16 01:44:25 +09:00
BMagnu 02e84f212a Fix HUD slewing (#5656)
* Fixup HUD for slewing

* Fix Training Message box

* Lead indicator slew

* Fix HUD Message Head

* Correctly render messages

* Fix HUD offset handling

* HUD offset never makes any sense

* Cleanup offset code

* Remove unused parameter

* Fix Talking Head in RTT mode
2023-10-16 01:44:17 +09:00
Goober5000 a1d92afebf Merge pull request #5659 from Goober5000/objecttypes_warp_range_factor
allow modification of warp audible range via objecttypes.tbl
2023-10-15 12:43:23 -04:00
Goober5000 a20f3ca030 Merge pull request #5561 from Goober5000/special_warp_physics
add "special warp physics" to custom warpin parameters
2023-10-15 12:42:22 -04:00
Goober5000 e132fcf74c Merge pull request #5585 from Goober5000/beam_api_stuff
additional beam-related features for Lua
2023-10-15 12:41:05 -04:00
Goober5000 7a4df25fc5 Merge pull request #5566 from Goober5000/allowed_in_campaign
add AllowedInCampaign virtvar
2023-10-14 17:01:50 -04:00
Mike Nelson 08dfcc8b74 lua access to Support Ship availability (#5570) 2023-10-15 05:40:12 +09:00
Mike Nelson 0def45b381 add death message as a dialog hv (#5542) 2023-10-15 05:40:05 +09:00
Goober5000 be6a2b9196 add gr.killAllParticles (#5481)
Some scripts under development will benefit from access to the `particle::kill_all()` function.
2023-10-15 05:39:53 +09:00
Mike Nelson f7413be1d8 preload subspace tunnel flag (#5532) 2023-10-15 05:39:42 +09:00
Mike Nelson 02233fc439 Set timer padding sexp (#5535)
* set timer padding sexp

* allow negative padding
2023-10-15 05:39:33 +09:00
BMagnu febd8cd2ad Allow an asymmetric FOV / Frustrum (#5657)
* Enable Asymmetric Projection FOV

* Properly apply asymmetric FOV to g3_rotate_ functions

* De-CPP14-ify

* cleanup

* Make GCC happy

* Fix Vertical Asymmetric FOV

* Fix printf
2023-10-15 05:39:24 +09:00
Goober5000 bf7125724d small updates 2023-10-12 18:07:11 -04:00
Goober5000 efce98db47 rewrite primary weapon cycling
Remove a whole bunch of ad-hoc code piled on top of the retail weapon cycling behavior, then replace it with a robust algorithm that takes all relevant attributes into account.

Fixes #5529.
2023-10-12 17:50:04 -04:00
Goober5000 45abdefc07 add "Calculate subsystem hitpoints after parsing" option
Subsystem hitpoints are calculated as a percentage of the ship's hull strength as they are parsed.  If a modular table modifies the ship's hull strength, the subsystems are not modified at the same time.  This can lead to unreasonably large or small subsystem hitpoint values, as recently seen in the 1.3.0 version of Cardinal Spear.

This PR adds an option to defer hitpoint calculation until after parsing so that the subsystem is a percentage of the correct hull strength.  Since this may affect the balance of existing mods, it is off by default unless the build targets 24.0 or later.

This also removes the long-unused `hull_percentage_of_hits` check and adds several log statements for significant options in game_settings.tbl.
2023-10-06 20:52:22 -04:00
Goober5000 73c612034b log the filename 2023-10-06 13:07:46 -04:00
Goober5000 1ae9aaab21 Merge pull request #5669 from Goober5000/additional_shipstatus_fixes
additional ShipStatus fixes
2023-10-06 01:13:45 -04:00
Goober5000 3a46ed66ba additional ShipStatus fixes
Update the Lua enums to be consistent with the new ShipStatus enums.

Separately, add an extra ship registry check in the event a ship doesn't exist in the ship registry.
2023-10-06 00:38:23 -04:00
Goober5000 f98806b034 refactor ai_mission_goal_achievable
Change `ai_mission_goal_achievable` to use the ship registry instead of looking up the target repeatedly.
2023-10-05 23:15:28 -04:00
Goober5000 1812efa209 Merge pull request #5666 from Goober5000/fix_briefing_popup
fix replacement textures in briefing popup
2023-10-05 23:07:28 -04:00
Goober5000 2966757e62 Merge pull request #5668 from Goober5000/better_message
tweak error message
2023-10-05 23:07:20 -04:00
Goober5000 bc3aad374e tweak error message
For better debugging.
2023-10-05 22:23:02 -04:00
Goober5000 dcfea6f141 modify and address feedback 2023-10-05 17:32:53 -04:00
Goober5000 c5d192524e Merge pull request #5665 from notimaginative/add_mac_to_forum_posts
add macOS builds back to forum release build posts
2023-10-05 02:24:10 -04:00
Goober5000 7a47cc0521 fix replacement textures in briefing popup
Use the same method for texture replacement in briefing popups that is already used in the tech room.

Also don't render shadows when the jump node is displayed, since it's not being lit anyway.
2023-10-05 00:59:57 -04:00
Taylor Richards a33cc0f6c4 add macOS builds back to forum release build posts 2023-10-05 00:22:55 -04:00
Goober5000 af4ec4facc Merge pull request #5663 from Goober5000/fix_5661
remove incorrect setting of ship status
2023-10-04 23:10:52 -04:00
Goober5000 d897643217 tweak messages per feedback 2023-10-04 22:25:29 -04:00
Goober5000 5688ba8637 fix incorrect setting of disabled/disarmed flags when cheating
Normally the disabled/disarmed flags are only set if the destroyed subsystem is actually an engine or turret.  This should be done for cheats as well, otherwise, for example, destroying any subsystem on a non-engined ship will cause it to become disabled.
2023-10-04 22:18:44 -04:00
Goober5000 6631975e45 some additional fixes 2023-10-04 21:15:30 -04:00
Goober5000 fa2b135bb1 remove incorrect setting of ship status
There is a bit of code in missionparse that sets the parse object because in-game joining needs it.  This is unrelated to ship status, so the status shouldn't be changed.  This fixes the bug and adds a comment to clarify the situation, as well as some warnings to help track down incorrect joining states.

Fixes #5661.  Follow-up to #5658 (where the regression was introduced) and #4836 (which fixed in-game joining).
2023-10-04 20:46:22 -04:00
mjn-mixael 1ce9d46822 Intro about to play hook 2023-10-04 11:16:48 -05:00
Tyler Blount 7f4d78f44a Merge pull request #5639 from Goober5000/red_alert_wing_status
add wing status to red-alert system
2023-10-03 18:11:30 -07:00
Tyler Blount 10f484a504 Merge pull request #5649 from Goober5000/fix_ship_status
fix ShipStatus states to correctly account for exploding ships
2023-10-03 18:11:25 -07:00
Tyler Blount f0c8c9ad74 Merge pull request #5658 from Goober5000/fix_barrel_roll
fix barrel roll crash in Star Fox: Event Horizon
2023-10-03 18:11:18 -07:00
Goober5000 79579eda94 fix barrel roll crash in Star Fox: Event Horizon
The Star Fox barrel roll effect is achieved using a script which spawns a new ship.  The script sets no-collide on this spawned ship, but it also tries to set the ship flag for all future ships -- and future ships require a parse object, which doesn't exist for a created ship.  This patches the FALLTHROUGH in the sexp code to account for that possibility.

Separately, there are other ways a parse object pointer could become null through unusual code states, so this adds an INVALID status and several additional checks to defend against this crash in other circumstances.
2023-10-03 14:00:22 -04:00
Goober5000 f7b9896294 allow modification of warp audible range via objecttypes.tbl
The retail warp range multiplier can yield ridiculous results, like an Elysium warp being audible over 9000 meters away.  So allow the multiplier to be set via ship type.
2023-10-03 12:50:05 -04:00
Goober5000 be8ec82649 Merge pull request #5642 from BMagnu/fix_null_shiphit
Fix null dereference when a subsystem is hit for damage by a null object
2023-10-02 20:20:56 -04:00
Goober5000 b72b7688f9 Merge pull request #5634 from Baezon/fix-ai-subsys-attack-subobj
Fix for improved subsys attack pathing
2023-10-02 20:20:32 -04:00
Birk Magnussen c2e01864d5 Incorporate feedback 2023-10-02 17:48:03 +02:00
Goober5000 7a4d4466fd Merge pull request #5651 from Goober5000/fly_to_ship_mode_fix
fix crash when a ship has the fly-to-ship goal
2023-10-02 11:14:05 -04:00
Goober5000 ec75cac4d9 fix crash when a ship has the fly-to-ship goal
Add the missing AI mode in the switch block.  Also remove some redundant `break`s.
2023-10-02 00:04:02 -04:00
Goober5000 b6c0e8b562 fix ShipStatus states to correctly account for exploding ships
Adds a `DEATH_ROLL` status to specifically cover the state after ships have been destroyed but before they exit.  I've also audited all code that interacts with the ship registry to use the correct state with this new state taken into consideration.

This fixes access to exploding ships that was broken when the ship registry framework was introduced.  In particular, the `when destroyed X beam-lock-all X` QoL feature now works again.
2023-10-01 18:10:55 -04:00
JohnAFernandez 8d0570846b Merge pull request #5647 from notimaginative/fix_mac_id10t_error
fix bad extraction command in mac distribution zip
2023-10-01 12:55:19 -04:00
Taylor Richards 93d0624b3e fix bad extraction command in mac distribution zip 2023-10-01 03:22:15 -04:00
Goober5000 563445466e Merge pull request #5646 from Goober5000/warning_message_tweaks
tweak some model warning messages
2023-09-30 22:32:40 -04:00
Goober5000 b7e9d4c9cb tweak some model warning messages
Per a thread in the TBP forum, elaborate on these model warnings a bit.

Two other small code tweaks as well.
2023-09-30 20:06:41 -04:00
Birk Magnussen 348fb5ffb4 Change to variables 2023-10-01 01:25:38 +02:00
Taylor Richards d754c2cb50 tweak directory copying for frameworks on macOS (#5641)
CMake's copy_directory functions follow symlinks recursively as opposed to
preserving them. For mac frameworks, which make use of symlinks for versioning,
this causes the files to be duplicated multiple times in the copied framework.
Using rsync instead, just for frameworks, will properly duplicate the framework
while still avoiding the "file exists" error from cp.
2023-09-30 08:51:35 -04:00
Taylor Richards b760c5dec8 tweak mac build packaging (#5640)
Use GNU tar instead of the default bsdtar. This works around some weird
corruption bug triggered by the combination of the GitHub runner-VM, the llvm
linker, and bsdtar.

Adjust intermediate filenames such that they don't get uploaded to
indiegames by mistake.

Unpack builds as a single step instead of two.
2023-09-30 08:51:01 -04:00
JohnAFernandez 9c9b06a1b1 Merge pull request #5635 from MjnMixael/fix_gameplay_help
Do not clear Help Text
2023-09-30 05:02:20 -04:00
Birk Magnussen 30da49be81 Fix null dereference when hit for damage by a null object 2023-09-30 09:55:47 +02:00
Goober5000 c2d0eafc36 add wing status to red-alert system
If consecutive red-alert missions have different numbers of ships in a wing, then calculating the number of waves will not be correct.  This necessitates the addition of wing status to the stored data for red-alert sequences.

Not only must wing data be stored in `Red_alert_wing_status`, but also in the CSG file.  This necessitates a version bump.  Fortunately, the current design of CSG files allows extra data to be added to a section without breaking old builds, since the CSG loader will just skip over the unrecognized data.

This also renames `red_alert_wingman_status` to `red_alert_ship_status` since it's not limited to wingmen, as well as fixing the omission of exited ships if they are in the player's wing but don't have the red-alert-carry flag.

Fixes #5637.  Follow-up to #4457 and #5609.
2023-09-28 21:14:11 -04:00
mjn-mixael e3c7f81412 do not clear this 2023-09-27 23:17:32 -05:00
Asteroth 2b155c7a30 separate variable 2023-09-27 16:40:29 -04:00
Goober5000 df69993a84 Merge pull request #5633 from Goober5000/tweak_weapon_detonation
fix weapon detonation
2023-09-27 15:30:44 -04:00
Asteroth 3fb5bf1f5f fix world pos getting of target subsys 2023-09-27 14:35:53 -04:00
Goober5000 6823e24350 fix weapon detonation
Add some extra logic implied by the `Begun_detonation` flag.  Missiles that are homing can have their targets, headings, speeds, and lifetimes changed for various reasons.  If a missile has begun detonation, particularly if it is in "detonation limbo" because it is flying across a bowl-shaped turret, we don't want to change any of that.  The "detonation limbo" weapon lifetime is only accurate if all of those values remain constant.

Follow up to #4006.
2023-09-27 13:30:37 -04:00
MageKing17 305a7f6630 Show both name and callsign in escort list.
In #5477, I made the escort list respect hidden names by copying the behavior from `message_queue_process()`, which already checked those flags; however, this resulted in some dramatic behavioral changes for mods using callsigns for escort ships, and while making the behavior optional was a possibility, feedback suggested everyone would rather it just behaved like the target box and displayed both. So I replaced the code with similar logic from hudtargetbox.cpp, except with the "replace hidden name with ship class" code taking priority.
2023-09-26 16:33:45 -07:00
mjn-mixael 14a98e1470 add built-in xstrs for these controls 2023-09-26 10:07:29 -05:00
Goober5000 4ba6191e0c Merge pull request #5623 from notimaginative/fix_macos_packaging
fix macOS build packaging issues
2023-09-25 17:14:44 -04:00
mjn-mixael cb5bf05424 update comments here 2023-09-25 15:58:11 -05:00
Tyler Blount b4f633767e Merge pull request #5616 from Goober5000/HomingSubsys_fix
some fixes for setting HomingSubsystem in script
2023-09-25 13:56:24 -07:00
Naomi Coffman 15db3b17bc Respond to PR feedback 2023-09-24 11:09:31 -04:00
mjn-mixael ba2c37a1fe xstr the boolean default on/off as well 2023-09-22 23:24:52 -05:00
mjn-mixael aa997dd9ed Fix some overlapping xstrs 2023-09-22 23:11:08 -05:00
Taylor Richards 6dbfba2c9f fix macOS build packaging issues
- handle double archiving of macOS builds so they'll work properly with Knossos
 - fix issue where only a single configuration was included in the package
   (Release or FastDebug, not both)
2023-09-22 22:14:15 -04:00
Taylor Richards 9748de5ec1 Merge pull request #5621 from notimaginative/use_static_libstdc++
use static libstdc++
2023-09-22 22:13:05 -04:00
mjn-mixael a0a523223c clean up options builders and use delayed xstr for localization 2023-09-22 19:15:42 -05:00
Taylor Richards 0765c7be95 try and fix clang build error 2023-09-22 16:17:23 -04:00
Taylor Richards 73f8e57961 statically link to libstdc++
Statically link to libstdc++ for CI/CD builds in an attempt
to avoid compatibility issues without relying on a crippled
docker build image.

Should properly fix #5571
2023-09-22 15:13:43 -04:00
Taylor Richards 743d8dd666 Revert "Revert "Update build image with curl and jq preinstalled""
This reverts commit f67814aaae.
2023-09-22 15:12:20 -04:00
mjn-mixael 8fbf22a055 allow lua sexps to not specify a subcategory 2023-09-21 10:12:17 -05:00
Goober5000 7b410b2116 some fixes for setting HomingSubsystem in script
1. Allow setting the homing subsystem if the homing object has already been set
2. Use the `weapon_set_tracking_info` function if setting both object and subsystem, as it handles several important homing things
2023-09-20 23:29:04 -04:00
Tyler Blount 8fed4437ee Merge pull request #5614 from MjnMixael/fix_setting_mission_stats
Fix setting mission stats
2023-09-20 10:57:05 -07:00
Tyler Blount ad25418f92 Merge pull request #5613 from MjnMixael/fix_get_shipclass_kills
Fix Lua API Error with Player Stats
2023-09-20 10:52:15 -07:00
mjn-mixael 5972457ad5 fix setting mission stats 2023-09-19 10:57:30 -05:00
mjn-mixael 35876bc17e fix api error 2023-09-18 23:15:56 -05:00
Goober5000 46fa212db6 Merge pull request #5610 from Goober5000/collide_and_no_collide_sync
sync setting and getting of collides and no_collide
2023-09-17 18:28:22 -04:00
Goober5000 d0d65cd30c Merge pull request #5609 from Goober5000/red_alert_followup
improve checks for red-alert status
2023-09-17 18:28:15 -04:00
Goober5000 cb0e9ce601 sync setting and getting of collides and no_collide
The `collides` and `no_collide` flags are equivalent, but opposite.  So when sexps or scripts get or set those flags, allow each to be used as an anti-synonym (not exactly an antonym) for the other.
2023-09-17 01:23:31 -04:00
Goober5000 13bc0362c8 improve checks for red-alert status
Two fixes for red alert missions:
1. Since any ship in the wing can be stored, not just the wing leader, the "prospective name" check should check for all possible names in each wave
2. If a wing wasn't actually stored, the red alert code should not reset the wing's wave number to 0

Follow-up to #4457.
2023-09-17 00:17:39 -04:00
Goober5000 5749b856df Merge pull request #5606 from Goober5000/revert_5547
Revert 5547 and 5580
2023-09-16 15:39:35 -04:00
Goober5000 f67814aaae Revert "Update build image with curl and jq preinstalled"
This reverts commit 0219e65b00.
2023-09-16 14:58:39 -04:00
Goober5000 24daea79f3 Revert "Change ubuntu-latest to ubuntu-20.04"
This reverts commit 45306da4fe.
2023-09-16 14:58:27 -04:00
Goober5000 0f013f920b Revert "modify per feedback"
This reverts commit 679c3606c5.
2023-09-16 14:58:17 -04:00
Naomi Coffman 0811c7037b Allow (easily) requiring an exact mood match 2023-09-16 13:47:00 -04:00
Naomi Coffman f13a5b3736 Allow specifying tiebreakers between builtin messages 2023-09-16 13:47:00 -04:00
Naomi Coffman 04a5778235 Allow filtering builtin messages by nearby ships 2023-09-16 13:47:00 -04:00
Goober5000 5a941c1d59 small speedup to drawString
Since `gr_string` can accept a length parameter, there's no need to copy each line before it is drawn.

Related to #5495 but not one of the two options mentioned.
2023-09-16 13:43:11 -04:00
Goober5000 d0c3c7db21 Merge pull request #5602 from Goober5000/sexp_fixes
fix crash in unusually formatted handwritten SEXP
2023-09-16 13:34:26 -04:00
Goober5000 be678c2f54 Merge pull request #5603 from Goober5000/fix_message_candidates
fix random selection of message candidates
2023-09-16 13:34:14 -04:00
Naomi Coffman 9586f21780 Add team filters to messages 2023-09-16 10:24:40 -04:00
Goober5000 ed5a5861f7 aspect-ratio-specific splash screens
Adds the ability to specify an aspect ratio, or a range of aspect ratios, to be used by splash screens.
2023-09-16 02:18:10 -04:00
Goober5000 16180306ad fix random selection of message candidates
The `Random::next(low, high)` function returns a value in [low, high].  This location should use the single-argument version, `Random::next(int modulus)`, which returns a value in [0, modulus-1].
2023-09-16 02:12:22 -04:00
Goober5000 865045a231 fix crash in unusually formatted handwritten SEXP
As reported by Colt, there was a crash in the in-mission jump sequence in Shepherds where the mission previously worked.  The proximate cause was a handwritten SEXP called via script that omitted whitespace before an opening parenthesis.  This was incorrectly recognized by the upgraded SEXP parser as an invalid SEXP.  Unfortunately, a separate bug in `get_line_num()` caused a crash when the parser tried to display a warning, because the function tried to calculate the line number of a SEXP that did not come from a parsed file.

This commit fixes the parser to recognize opening parentheses even when no whitespace precedes them, moves the output to the 'unexpected end of sexp' warnings will they will now be seen, and fixes `get_line_num()` to work when there is no parsed text.

Follow-up to #5520.
2023-09-15 15:12:44 -04:00
Tyler Blount 0b54c741a6 Merge pull request #5599 from MjnMixael/fix_scpui_reset_loadout
Actually reset the weapon pool with SCPUI
2023-09-14 15:26:32 -07:00
mjn-mixael baa34f1ffe Actually reset the weapon pool, dummy 2023-09-14 10:46:52 -05:00
Goober5000 89b33ebbc5 add a maneuver-despite-engines flag
This flag ignores engine status when determining whether and how a ship can maneuver.  Implements #5503.
2023-09-13 22:36:58 -04:00
Goober5000 53e6edf8bb documentation 2023-09-10 17:40:02 -04:00
Tyler Blount 0220ad0563 Merge pull request #5594 from MjnMixael/fix_campaign_saving_scpui
Save player after changing campaign in scpui
2023-09-10 13:55:59 -07:00
Tyler Blount 910521bdfe Merge pull request #4457 from JohnAFernandez/restore-red-alert-flags
Fix wing persistence and ensure checks for depleted wings are valid
2023-09-10 13:55:34 -07:00
Goober5000 7003e5caa2 get the wave count correct 2023-09-10 13:49:31 -04:00
mjn-mixael 8efe146300 save player after changing campaign in scpui 2023-09-09 23:01:59 -05:00
Asteroth a14fb35713 initialize trail info better (#5588) 2023-09-09 02:41:55 -04:00
Goober5000 2d0dc7798d unused variable 2023-09-09 00:41:44 -04:00
Goober5000 8242e3b94b small edits 2023-09-08 19:40:53 -04:00
Goober5000 16cb6b3f2f rewrite red-alert bashing routine 2023-09-08 19:13:58 -04:00
Goober5000 8c9be400a6 Merge branch 'master' into restore-red-alert-flags 2023-09-08 00:57:54 -04:00
Goober5000 7974a682ef Merge pull request #5581 from TRBlount/briefing_icon_scale_followup
Follow-up for briefing icon scaling
2023-09-07 23:12:11 -04:00
Goober5000 41af098d19 Merge pull request #5582 from TRBlount/starfield_timestamp_fix
Update starfield animation handling
2023-09-07 23:12:04 -04:00
Goober5000 4c95370f74 add parse object flag for starting wing, and move starting wing checks to post-processing 2023-09-07 20:56:54 -04:00
Goober5000 a6730a997c feedback 2023-09-07 19:15:56 -04:00
Goober5000 c5b84d9406 Merge pull request #5589 from Goober5000/beam_armor_fix
supply parameter for is_beam in all armor checks
2023-09-07 16:40:52 -04:00
Tyler Blount d2f5a12d5f Add parentheses to make order of operations more clear 2023-09-06 19:26:20 -07:00
Tyler Blount 6f6e839bbf Update starfield animation handling 2023-09-06 19:23:48 -07:00
Goober5000 065524fd4b Merge pull request #5586 from Goober5000/firepoint_followup
fix the logic for lighting up firing points
2023-09-06 18:22:27 -04:00
Goober5000 c84cb7ab64 supply parameter for is_beam in all armor checks
For certain calculations involving armor, the `GetDamage` function needs to know if the damage is being applied by a beam so it can apply the calculations with the proper frametime.  The parameter was not provided in all cases, so this fixes that.

Follow-up to #1609.
2023-09-06 18:17:37 -04:00
Goober5000 587ed4e41f convert magic number to constant 2023-09-06 12:13:36 -04:00
Goober5000 8b8daece46 additional beam-related features for Lua
1. Add a `vanish()` function for beam objects, to be consistent with other object types
2. Add a `BeamFree` virtvar, analogous to `TurretLocked`
3. Add timestamp variants of TurretLocked and BeamFree to be consistent with sexps
4. Add `BeamLife`, `BeamWarmup`, and `BeamWarmdown` virtvars so scripts can access table properties
5. Add "On Beam Death", "On Beam Warmup", and "On Beam Warmdown" hooks
6. Clarify some existing documentation and patch a couple things
2023-09-06 00:28:07 -04:00
John Fernandez d73d46feb2 Stupidest typo in history 2023-09-04 14:50:01 -04:00
Goober5000 a881b339cc fix the logic for lighting up firing points
The firing point gauge did not work as advertised; this fixes it.  Unselected weapons are dimmed, selected weapons are normal, and firing weapons are bright.
2023-09-04 14:25:06 -04:00
Tyler Blount 1f90be0a86 Merge pull request #5584 from Goober5000/firepoint_fix
fix crash in firepoint gauge
2023-09-04 11:06:42 -07:00
Goober5000 4ce02ce291 fix crash in firepoint gauge
The gauge assumes that all firepoints will always have weapons, but it's possible for a ship to have less than the maximum number of weapons.
2023-09-03 18:07:40 -04:00
John Fernandez 7d83ece711 And make sure we can call the constructor 2023-09-01 19:34:25 -04:00
John Fernandez 9ee1a6eb23 Add a constructor for red_alert_wing_status 2023-09-01 19:25:36 -04:00
John Fernandez f258554304 add bash wingman status
And function calls.
2023-09-01 19:02:19 -04:00
John Fernandez 994048eb24 Create Struct And functions for restoring wings
This needs to be separate from ships
2023-09-01 16:54:46 -04:00
Tyler Blount 0af3197a90 Follow-up for briefing icon scaling 2023-09-01 12:15:41 -07:00
Goober5000 e5824b41bb Merge pull request #5580 from Goober5000/ubuntu_version_tweak
Change ubuntu-latest to ubuntu-20.04
2023-09-01 12:41:25 -04:00
Goober5000 679c3606c5 modify per feedback 2023-08-31 17:30:08 -04:00
Mike Nelson acbab034cc wtf (#5579) 2023-08-30 23:03:48 -04:00
Goober5000 45306da4fe Change ubuntu-latest to ubuntu-20.04 2023-08-30 22:57:29 -04:00
Goober5000 f09c7b3ba5 Merge pull request #5577 from Goober5000/additional_music_checks
additional music checks
2023-08-30 13:11:28 -04:00
John Fernandez 964f495238 A theoretical fix for invalid checks
Replace `wingp->num_waves == 0` with valid `wingp->current_wave >= wingp->num_waves` and correct six year old copy paste error.
2023-08-29 01:25:33 -04:00
Goober5000 865f7e725c Merge pull request #5578 from Goober5000/soundtrack_start_fix
fix soundtrack timestamp when change-soundtrack is called immediately
2023-08-27 16:33:28 -04:00
Goober5000 6a550a6701 additional music checks
This adds several fixes to make the event and menu music more robust:
1. The game will now run with zero soundtracks.  All accesses into a potentially empty vector should now have checks.
2. Soundtracks and menu music are now checked for validity before being played (not just when importing a FSM mission).
3. The parsing validity checks and the in-game event music now check for skippable patterns using the same function.
4. Zero measures and zero samples-per-measure now cause the game to skip a pattern.  Negative values now trigger a warning.
5. Omitting some or all of the `$Name:` lines for a soundtrack will not cause an assert.

Fixes #5576.  Follow-up to #5572.
2023-08-25 19:22:03 -04:00
Goober5000 ad2531efcc fix soundtrack timestamp when change-soundtrack is called immediately
There is a built-in delay for the event music to start playing, but this delay gets stepped on if `change-soundtrack` is called when the mission first starts.  So don't set the delay unless it has already elapsed at least once before.
2023-08-25 19:20:21 -04:00
Goober5000 8af06b9e78 Merge pull request #5575 from Goober5000/obj_sound_fix
fix persistent sounds not clearing their tally
2023-08-25 19:08:06 -04:00
Goober5000 b6eef2e8f2 fix persistent sounds not clearing their tally
When a non-looping persistent sound expires, `obj_snd_stop()` actually does need to be called.  Even though the sound is no longer playing, the `Num_obj_sounds_playing` tally needs to be decremented, otherwise it will eventually exceed its limit and prevent any additional persistent sounds from playing.  And it turns out `obj_snd_stop()` returns gracefully for sounds that aren't playing.

Follow-up to #3510.  Fixes a bug that appears to have been around since retail.
2023-08-25 13:27:09 -04:00
Goober5000 344e231058 add mn.generateWeaponGroupId()
The `mn.createWeapon()` function takes an optional group ID for weapons that share lighting, but the internal `weapon_create_group_id()` function was never exposed to the API.  This adds that.
2023-08-25 02:39:40 -04:00
BMagnu 2feeb34629 Move light calculation out of vertex shader (#5573) 2023-08-25 05:46:02 +09:00
Goober5000 9d28ba568c Merge pull request #5572 from Goober5000/5567_followup
fix validity check for soundtracks
2023-08-23 22:28:53 -04:00
Goober5000 1b6ed75d73 filename is already truncated 2023-08-23 21:10:05 -04:00
Goober5000 4cf7ab3474 fix validity check for soundtracks
Since event music soundtracks use the exact file extension specified (see #5567), the validity check should also use the exact file extension specified.

Also, move the validity check to after parsing has completed because extensions may be overridden.
2023-08-23 20:39:26 -04:00
Goober5000 bd4b9cb0d7 Merge pull request #5568 from Goober5000/fix_campaign_crash
fix crash in campaign editor
2023-08-22 20:32:13 -04:00
Goober5000 926e10584c Merge pull request #5567 from Goober5000/event_music_extension_agnostic
handle extension mismatch in event music
2023-08-22 20:32:05 -04:00
Goober5000 defab61664 handle extension mismatch in event music
Currently, menu music will trim the extension and look for both OGG and WAV files, but event music will use the exact extension specified.  This is intended but could lead to unexpected results in mods, so display a warning for the modder.
2023-08-22 15:48:21 -04:00
Goober5000 7dc971a6f2 fix crash in campaign editor
The crash in #5514 appears to be caused by some of the graphics code not being in the expected state for the synchronization.  Looking at the code in `render_frame()`, a `gr_flip()` happens after one frame ends and before the next frame begins.  That implies that this `gr_flip()` should not be here, as it is in the middle of a frame.  For additional evidence, `gr_flip()` modifies the "uniform buffer manager" state, and that is part of the stack trace preceding the crash.  Removing this `gr_flip()` fixes the crash.

The strange thing is that this code *doesn't run at all* while the campaign editor is active.  I verified this by adding a MessageBox in place of `gr_flip()`; the MessageBox doesn't display until the campaign editor is exited.  And yet, FRED crashes with `gr_flip()` present and doesn't crash with it removed.  This calls for a new category of bug; I propose "spookybug", from spooky action-at-a-distance.

Fixes #5514.
2023-08-22 12:47:14 -04:00
Goober5000 e0a6ca9abd Merge pull request #5563 from Goober5000/movie_subtitle_font_tweak
fix $Movie subtitle font: for custom fonts
2023-08-21 16:42:11 -04:00
Goober5000 210a9a8309 add AllowedInCampaign virtvar
These can be used to set whether a ship or weapon is allowed in loadouts, without necessarily waiting for the mission to be accepted.
2023-08-21 16:32:56 -04:00
Goober5000 613fad21c9 fix $Movie subtitle font: for custom fonts
The default movie subtitle font is font01.vf, but mods with custom font tables might not use this font.  So this changes the handling slightly so that the movie player will use whatever the first available font is.

Follow-up to #1523.  Fixes a sometimes spurious warning in mod initialization.
2023-08-19 13:25:13 -04:00
Goober5000 91497d5056 Merge pull request #5560 from Goober5000/fred_help
improve launching of FRED help
2023-08-17 21:25:16 -04:00
Goober5000 6b3e50dade add "special warp physics" to custom warpin parameters
Supercaps use a physics flag on warpin that makes them slow down faster than they would under the normal physics code.  This adds that flag as an option for custom warp parameters.

Since flags are not yet parsed when warp parameters are parsed, the code needs to skip ahead and peek at the flags in the same way as the weapon override.
2023-08-16 19:07:30 -04:00
Goober5000 e796a4fe00 improve launching of FRED help
1. Fall back to the FREDzone help docs if the local files cannot be found
2. Tweak url_launch error message and add a return value

This consequently removes the ReleaseWarning which wasn't the friendliest or clearest way to tell the user about a missing help file.
2023-08-16 12:28:53 -04:00
Goober5000 03f01604d9 Merge pull request #5559 from Goober5000/fix_5515
assign weapon particle effects properly
2023-08-16 11:27:30 -04:00
Goober5000 1547526057 Merge pull request #5558 from Goober5000/streaminganim_extension
some streaming animation fixes
2023-08-16 11:27:21 -04:00
Goober5000 7602b88756 assign weapon particle effects properly
Since `std::unordered_map.insert` does nothing if a key already exists, use bracket notation.  Fixes #5515.
2023-08-15 23:16:07 -04:00
Goober5000 4812ff529d Merge pull request #5550 from Goober5000/modular_weapon_flags
fix flags in modular weapon entries being cleared
2023-08-15 17:41:26 -04:00
Goober5000 fe42c7bdff make alpha value work for streaming EFFs 2023-08-14 18:07:21 -04:00
Goober5000 f706d6c0a0 use the correct resize mode 2023-08-14 17:40:47 -04:00
Goober5000 16b9225533 remove extensions from streaming animations
Since other functions in the scripting API remove extensions before loading the files, and since the internal functions expect them to be removed, the streaming anim API should handle that too.
2023-08-14 16:41:20 -04:00
mjn-mixael 9a7500de36 lua method to launch arbitrary url 2023-08-13 09:27:30 -05:00
Goober5000 64d9b6fb74 Merge pull request #5548 from Goober5000/stay_near_ship_fixes
ai-stay-near-ship fixes
2023-08-13 09:27:52 -04:00
Goober5000 b40f5a15b2 Merge pull request #5553 from Goober5000/nightly_porphyrion_to_perses
nightly build updates
2023-08-10 00:07:24 -04:00
Goober5000 52a5c356cf Merge pull request #5551 from Goober5000/dock_goal_achievability
remove Int3()'s in ai_mission_goal_achievable
2023-08-09 23:51:56 -04:00
Goober5000 e71dba4207 enhance set-armor-type to work with generic subsystems 2023-08-09 18:21:19 -04:00
Goober5000 3b42ee42ca put the hull and shields at the top to be consistent with other sexps 2023-08-09 17:23:13 -04:00
Goober5000 b270c44ede use https for indiegames 2023-08-09 15:17:45 -04:00
Goober5000 6cf6f8a6fe update server 2023-08-09 15:14:43 -04:00
Goober5000 c273496c1e remove obsolete build files 2023-08-09 15:08:36 -04:00
Goober5000 8933aaff38 address feedback and add more chex 2023-08-09 15:01:41 -04:00
Goober5000 a3de0db735 remove Int3()'s in ai_mission_goal_achievable
As reported by Woutersmits, the GTT Nova did not dock with the GTD Hall in the first mission of Black Horizon.  Attempting to run a debug build caused a CTD.  Investigation showed that there was an invalid dockpoint triggering an Int3().  The dockpoint has been fixed, but to aid troubleshooting in the future, the Int3()'s in this function have been changed to more appropriate functions.
2023-08-09 04:11:47 -04:00
Goober5000 0dcb60f805 fix flags in modular weapon entries being cleared
When weapon flags are parsed in a modular table and override the previous set of flags, certain flags must be kept to preserve the behavior of the weapon.  The previous `preset_wi_flags` technique only worked if all such flags (homing, has-display-name, even whether the weapon turns) were set in the same modular table.  If a modular table overrode the flags but didn't specify those lines over again, mysterious and subtle bugs would occur.

This modifies the flag parsing to explicitly preserve all appropriate flags from the existing weapon entry, which fixes the bug.  It also allows all of the flags to be specified in one place, rather than scattering `preset_wi_flags` assignments throughout `parse_weapon`.  And this also adds quite a few flags to the flag list that were not handled at all under the previous design.

Finally this fixes a few incorrect assignments of default values to fields that should only happen the first time a weapon entry is parsed.
2023-08-09 01:49:35 -04:00
MageKing17 1bc7732b6e Merge pull request #5549 from MjnMixael/fix_sexp_descriptions
Correct a few sexp descriptions
2023-08-08 22:44:41 -07:00
mjn-mixael 2a64abfe92 correct a few sexp descriptions 2023-08-08 17:00:12 -05:00
Goober5000 d1e81be2aa ai-stay-near-ship fixes
Three fixes:
1. In commit fa0878b6b3 for PR #5338, the optional distance parameter was inadvertently changed to a bool.  This fixes the parameter.
2. The distance parameter was previously parsed using `atoi` which works for number literals, so change to `eval_num` to allow sexp return values.
3. Make `eval_num` consistent with `eval_sexp` in the sense that evaluating an empty list is valid and returns false or 0.

Also takes advantage of the fact that `is_sexp_true` works for empty lists to streamline optional arguments in `ai_add_goal_sub_sexp`.
2023-08-08 13:07:21 -04:00
Goober5000 e285641ac6 Merge pull request #5528 from Goober5000/detonate_on_expiration
'detonate on expiration' weapon flag
2023-08-07 22:18:58 -04:00
Goober5000 d3b1ad4328 remove vestigial debug variables 2023-08-07 16:59:02 -04:00
Tyler Blount 914f0e13e3 Merge pull request #5526 from Goober5000/hud_set_coords
add screen resolution scaling for hud-set-coords
2023-08-06 15:22:08 -07:00
m!m df68da3dd6 Merge pull request #5547 from asarium/image_curl_jq
Update build image with curl and jq preinstalled
2023-08-06 18:15:05 +02:00
asarium 0219e65b00 Update build image with curl and jq preinstalled
The install step in the CI pipeline is no longer needed after this
change and has been removed.
2023-08-06 17:09:42 +02:00
m!m cc171a6344 Merge pull request #5546 from asarium/fix_file_exists
Fix "File exists" error
2023-08-06 16:44:23 +02:00
asarium 7d066a1c45 Fix "File exists" error
Copying a file with cp on top of another one is not allowed by default
so switching the command to use the CMake provided one will fix the
issue and will also unify the commands for all platforms.

The directory support is necessary for Mac where the SDL library is
actually a directory.
2023-08-06 14:46:46 +02:00
Tyler Blount 6677fcabae Merge pull request #5513 from Goober5000/fred_campaign_path
fix a couple bugs in the campaign editor
2023-08-04 13:46:44 -07:00
Tyler Blount 171d36bf7f Merge pull request #5527 from Goober5000/fix_5507
add model filename back into debug log
2023-08-04 13:46:35 -07:00
Tyler Blount 9018ddf0d5 Merge pull request #5539 from MjnMixael/fix_bitmap_fps
Fix animated background bitmaps rendering with incorrect framerate
2023-08-04 13:46:28 -07:00
Tyler Blount d847236dd2 Merge pull request #5537 from MjnMixael/fix_loadout_ctd
Fix: Prevent loadout related CTD
2023-08-04 13:46:20 -07:00
mjn-mixael bb6b010487 lua get mod root 2023-08-02 12:04:33 -05:00
mjn-mixael 0ee3d099ab and not or dummy 2023-08-02 09:28:07 -05:00
mjn-mixael 9aa48579b0 also check upper range 2023-08-02 09:19:26 -05:00
mjn-mixael bb28d0b859 account for very low framerates 2023-08-02 09:17:01 -05:00
mjn-mixael 2ef3a935e4 Fix animated background bitmaps rendering with incorrect framerate 2023-08-02 08:23:52 -05:00
mjn-mixael 233fa38890 Prevent loadout related CTD 2023-08-01 16:16:30 -05:00
Goober5000 e91d6ed17b 'detonate on expiration' weapon flag
For mods which want primary weapons to 'detonate', setting the detonation range is not reliable because, due to rounding imprecision, either the range (which detonates) or the lifetime (which does not) may happen first.  So this adds a flag to always detonate a weapon when its lifetime expires.  Secondary weapons have this flag by default, but primary weapons can add this flag in the $Flags list.  Additionally, if the detonation range and the predicted range due to lifetime are equal, the flag is added automatically.

Resolves #5521.
2023-07-29 18:23:38 -04:00
Goober5000 f6c86464aa add model filename back into debug log
In #4702 this log line was changed to the 'Model' category, which made it hidden by default.  This was missed in review but should be restored as it is a fairly important line.

Fixes #5507.
2023-07-29 15:29:29 -04:00
Goober5000 dd0af0e07c add screen resolution scaling for hud-set-coords
The hud-set-coords SEXP has always used exact pixels, without regard for the current screen resolution.  This adds a similar scaling mechanism as is used for show-subtitle.

Fixes #5525.
2023-07-29 15:21:43 -04:00
Goober5000 24031db712 Merge pull request #5520 from Goober5000/variable_token_fixes
SEXP parsing cleanup and fixes
2023-07-29 14:18:44 -04:00
Goober5000 d82b02a54a Merge pull request #5517 from Goober5000/fix_fred_bugs
fix mission corruption in FRED
2023-07-29 14:15:10 -04:00
Goober5000 a21876127d comment 2023-07-28 19:54:42 -04:00
Goober5000 f64de84e7c address feedback 2023-07-28 17:08:22 -04:00
Goober5000 feadc0bd69 feedback 2023-07-28 16:45:44 -04:00
Goober5000 1252d794db Merge pull request #5509 from Baezon/fix-laser-single-segment-trails
Some more fixes for laser single segment trails
2023-07-27 23:12:49 -04:00
Goober5000 58fcbde152 Merge pull request #5511 from z64555/fillValues_more_error
Add more error checking in joy-sdl.cpp.
2023-07-27 23:12:24 -04:00
Goober5000 b3970798e1 variables will only be referenced in nodes, not generators like for-counter 2023-07-27 16:14:06 -04:00
Goober5000 da34e25bc3 handle things properly on parse error 2023-07-27 16:07:15 -04:00
Goober5000 7fc75c0d6c more robust handling of Mp, especially after error 2023-07-27 15:04:38 -04:00
Goober5000 859978fd84 upgrade container parsing as well; and check for malformed variable tokens 2023-07-27 03:38:17 -04:00
Goober5000 7781d9fcda fix sexp variables in argument lists 2023-07-27 02:19:54 -04:00
Asteroth 03e876f65b no shadow 2023-07-27 00:58:10 -04:00
Goober5000 9480869e0a make variable parsing more robust; don't assume that an @ is always followed by a valid variable name; fix length checks; soften non-fatal Errors to error_display(0) 2023-07-27 00:04:15 -04:00
Goober5000 481e82303c use tokens in sexp help 2023-07-26 14:55:31 -04:00
Goober5000 689ac56bc8 fix mission corruption in FRED
When using the mission importer, missions were being corrupted for very subtle reasons: due to some code reordering in prior commits, `raw_ptr` would be initialized to `Parse_text_raw` before `Parse_text_raw` itself was initialized.  This assignment was done in the `CFred_mission_save` constructor and the ordering dependency is not obvious.  Since this is a highly fragile situation and has the potential to affect any use of `parse_comments()` in FRED, it's better to explicitly assign `raw_ptr` when it is needed, and just initialize it to nullptr in the constructor.

This also sets the version number to the legacy version (0.10) when the mission is saved in the retail format.
2023-07-26 03:39:17 -04:00
Goober5000 c80f787d34 POF version fix
Modelread.cpp supports POF versions as low as 1900, but early model versions were not loaded properly because they relied on preprocessor directives rather than version checks.  This changes the POF loading to correctly check version numbers and chunk IDs.

Fixes crashes when attempting to load a FS1 model.
2023-07-26 00:00:17 -04:00
Goober5000 c5469982c8 fix a couple bugs in the campaign editor
1. When saving a campaign, the save directory should be the one that the campaign was just loaded from.  If prompting the user, this should be the default save directory.  This fixes a bug where campaigns were saved to %APPDATA% instead of where the FREDder might expect.  This has been a bug ever since the migration of the game files from FreeSpace2 to %APPDATA%.
2. When saving a campaign, save only the external mission flags, not the working flags that are maintained during gameplay but have no meaning in the saved file.
2023-07-25 01:49:10 -04:00
z64555 db64a212d6 Adds more error checking in joy-sdl.cpp.
* In fillValues(), Check the size values returned by SDL to assert they are non-negative.  If they are negative, abort vector resize and mprintf the SDL Error.
2023-07-24 19:01:08 -05:00
Asteroth 0a07b7e0ad some fixes for laser single segment trails 2023-07-24 18:37:03 -04:00
Tyler Blount 833d181700 Merge pull request #5504 from Baezon/fix-cmeasure-single-segment-trail
Fix for countermeasures with a single segment trail
2023-07-23 10:08:35 -07:00
Tyler Blount dfc716d91a Merge pull request #5501 from naomimyselfandi/zero-out-persona-bitfields
Explicitly zero out persona bitfields
2023-07-23 09:58:49 -07:00
Goober5000 8dd6a27418 Merge pull request #5475 from Goober5000/ai_autoscaling_check
prevent AI autoscaling for only a single autoscaled class
2023-07-22 21:46:25 -04:00
Asteroth 691ae8752e fix for countermeasures with a single segment trail 2023-07-20 23:42:35 -04:00
Asteroth 14b4fd3465 Fix weapon flags +override handling wrt spawn flag (#5488)
* fix wep flags +override wrt spawn

* Revert "fix wep flags +override wrt spawn"

This reverts commit 08a2bee1ca.

* parse +override ahead of time

* use string list instead

* hopefully fix whitespace???
2023-07-19 17:09:11 -04:00
Naomi Coffman fc6a1402c3 Explicitly zero out persona bitfields
Personae have a flag and a species bitfield. They're built up during parsing, but never explicitly zeroed out. This leads to ships occasionally getting an incorrect persona (especially common with support ships, which never have an explicit persona).

Additionally, this commit addresses an issue with the UES Aranyaka (and potentially other support ships belonging to species without a support persona). I'm honestly not sure why they were ever able to speak; however, with this change, they'll never be able to. As such, this commit introduces a "default support persona" to retain the desired behavior.
2023-07-19 15:04:18 -04:00
MageKing17 275f96d80c Remove Int3()s from message_translate_tokens().
In f350e06851, two Int3()s were added to `message_translate_tokens()`, to check for possible out-of-bounds errors. However, in c70fdc3a52, just a couple months later, the code being protected by those bounds checks were put into `else` branches, meaning the `Int3()`s became redundant. This wouldn't actually cause any problems unless somebody passed a string with two `$`s at least 40 characters apart to `message_translate_tokens()`. Cue #4876, which started calling `message_translate_tokens()` on debriefing stages and recommendations, which can contain color tags. This still wouldn't cause problems as long as the color tags are in pairs within close proximity (`translate_key()` would say "that's not the name of a scan code" and leave the text between the two tags alone), but as soon as two color tags are far enough apart to trip the bounds check conditional, the `Int3()` would be hit. This is still fine on Release builds, which ignore `Int3()`s, but triggers a breakpoint on debug builds, which depending on the user's system, can result in a CTD. Since, as far as I can tell, the `Int3()`s haven't actually been meaningful since 2006, I've just removed them (and inverted the conditionals), and testing by the affected user confirms that it no longer CTDs.
2023-07-18 13:34:26 -07:00
Goober5000 850d706df2 prevent AI autoscaling for only a single autoscaled class
When only one AI class performs autoscaling, the math formulas which use autoscaling will become meaningless (e.g. in `ai_maybe_launch_cmeasure()`) or will cause divide-by-zero errors (e.g. in `ai_manage_shield()`).  And autoscaling is not very useful outside of the specific ways that Volition used it.  So this adds some warnings and disables single-occurrence autoscaling.

Fixes #5474.
2023-07-18 01:05:18 -04:00
Goober5000 b06c8e72e1 Merge pull request #5499 from Goober5000/fireball_fix
fix Lua API access to Fireballs array
2023-07-18 00:34:53 -04:00
Asteroth b1fd9ffffb Improve performance of collision retiming (#5496)
* fast version of setting position and orientation

* preliminary stale collide time

* add global collision cache stale flag instead

* clean up

* more clean up

* no periods >.>

* bring back single object version

* rename and bring back stale object list

* use a set
2023-07-18 00:28:49 -04:00
Goober5000 e2c264cec4 fix Lua API access to Fireballs array
When fireballs were made dynamic in 609ed4ed94, the `MAX_FIREBALLS` #define lost any relationship to the fireball collection.  This removes it and also correctly specifies the size of the fireball collection.

This fixes a CTD when accessing items in `mn.Fireballs` via script.
2023-07-17 23:33:22 -04:00
Fabian Woltermann 3f889137d7 Merge pull request #5497 from The-E/fix/warn_for_invalid_trail_textures
Add a warning for cases when we couldn't load a trail bitmap
2023-07-17 23:53:48 +02:00
Fabian Woltermann 19f1e6b4ee remove bothersome warning 2023-07-17 23:07:37 +02:00
Goober5000 7e692ebca6 Merge pull request #5498 from Goober5000/5492_followup
add missing #includes to fix compilation
2023-07-17 16:17:03 -04:00
Goober5000 0067a57f8f add missing #includes to fix compilation
These #include lines are needed for the changes introduced in #5492.  Not sure why they weren't picked up by CI, or why they work in some compilers but not others.
2023-07-17 14:58:24 -04:00
Fabian Woltermann e028162dc2 update batching assertions 2023-07-17 18:54:12 +02:00
Fabian Woltermann 9b26439dd3 Add a warning for cases when we couldn't load a trail bitmap 2023-07-17 17:12:33 +02:00
Tyler Blount 1431270287 Merge pull request #5483 from Baezon/hud-gauge-load-safety
Improved hud gauge loading safety
2023-07-16 15:49:17 -07:00
Tyler Blount 06e74fa976 Merge pull request #5491 from MageKing17/bugfix/demo-missing-campaign
When playing the demo, don't try to reset if no campaign is active.
2023-07-16 15:47:59 -07:00
Tyler Blount 318fde51d7 Merge pull request #5492 from MageKing17/bugfix/voice-recognition-while-paused
Ignore voice recognition events while game is paused.
2023-07-16 15:47:51 -07:00
Goober5000 15daaf2633 additional cleanup from PR 5462
Some streamlining and constifying of the readyroom popup list and associated functions.

Followup to #5462.
2023-07-13 01:54:25 -04:00
MageKing17 d253302fc9 Also check popup_active() and popupdead_is_active(). 2023-07-12 16:07:17 -07:00
MageKing17 560eb31e4f Ignore voice recognition events while game is paused.
If you pause the game, say something into the microphone, then unpause, it can abruptly perform an action based on voice recognition; this is probably counter to player expectations. This adds a `gameseq_get_state() != GS_STATE_GAME_PAUSED` check to the existing conditional.
2023-07-12 15:09:36 -07:00
MageKing17 493df37287 When playing the demo, don't try to reset if no campaign is active.
If the "Campaign Room only available in full version" popup is shown, it tries to reset `Active_campaign_index`, except that if a pilot is loaded with a missing campaign file, `Active_campaign_index` is -1. This causes an out-of-bounds array access, so let's present an alternate popup in this case (either one to select whatever the first campaign file found is, or the generic `popup_game_feature_not_in_demo()` if no campaign files are found).
2023-07-12 14:53:40 -07:00
BMagnu 32298b89fd Properly deinit io lib LuaFunctions (#5485) 2023-07-11 07:03:52 +09:00
Asteroth d6ee515873 remove testing prints 2023-07-07 01:22:40 -04:00
Asteroth bc09f0672b better hud gauge load safety 2023-07-07 01:20:11 -04:00
Goober5000 17d36156cb add const where appropriate to the modelrender API
See title.  There were some cascade effects, but the changes are mostly contained to the model code.  The calls to `gr_render_model` and `g3_render_primitives` use `const_cast` because constifying that API would require a whole other PR.
2023-06-18 14:05:46 -04:00
Goober5000 99450fa643 remove hud_squadmsg_save_keys()
Remove this function and associated items, since they are commented out and unused.
2023-05-27 13:39:47 -04:00
329 changed files with 7440 additions and 4396 deletions

No files matched your search

+11 -9
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
steps:
# - name: Cache Qt
# id: cache-qt-lin
@@ -31,11 +31,6 @@ jobs:
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
# seriously, what the fuck why do i have to do this
- name: Add curl to the container
run: |
apt-get update -y
apt -y install curl jq
- uses: actions/checkout@v1
name: Checkout
with:
@@ -292,13 +287,15 @@ jobs:
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
working-directory: ./build/bin
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
mac_zip:
name: Build Mac distribution zip
needs: build_mac
@@ -321,6 +318,11 @@ jobs:
with:
name: mac-FastDebug
path: builds
- name: Unpack builds
working-directory: ./builds
run: |
tar -xvzf macos-build-Release.tgz
tar -xvzf macos-build-FastDebug.tgz
- name: Create Distribution package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
+16 -9
View File
@@ -44,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-8a6bbbe
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
steps:
# - name: Cache Qt
# id: cache-qt-lin
@@ -87,15 +87,12 @@ jobs:
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- name: Add curl to the container
run: |
apt-get update -y
apt -y install curl jq
- uses: actions/checkout@v1
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
name: Checkout
with:
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
ref: '${{ github.ref }}'
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
@@ -149,6 +146,7 @@ jobs:
with:
submodules: true
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
ref: '${{ github.ref }}'
- name: Download Release builds
# Grab the release builds
uses: actions/download-artifact@v2
@@ -195,6 +193,7 @@ jobs:
name: Checkout
with:
submodules: true
ref: '${{ github.ref }}'
# - name: Cache Qt
# # Cache Qt
# id: cache-qt-win
@@ -289,7 +288,7 @@ jobs:
with:
submodules: true
fetch-depth: '0'
ref: '${{ github.ref }}'
- name: Download Release builds
uses: actions/download-artifact@v2
with:
@@ -361,6 +360,7 @@ jobs:
with:
submodules: true
fetch-depth: 0
ref: '${{ github.ref }}'
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
@@ -384,13 +384,15 @@ jobs:
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
working-directory: ./build/bin
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
mac_zip:
name: Build Mac distribution zip
needs: build_mac
@@ -413,6 +415,11 @@ jobs:
with:
name: mac-FastDebug
path: builds
- name: Unpack builds
working-directory: ./builds
run: |
tar -xvzf macos-build-Release.tgz
tar -xvzf macos-build-FastDebug.tgz
- name: Create Distribution package
id: generate_package
working-directory: ./builds
-4
View File
@@ -20,10 +20,6 @@ jobs:
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Add curl to the container
run: |
apt-get update -y
apt -y install curl jq
- uses: actions/checkout@v1
name: Checkout
with:
+11 -8
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
steps:
# - name: Cache Qt
# id: cache-qt-lin
@@ -31,10 +31,6 @@ jobs:
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- name: Add curl to the container
run: |
apt-get update -y
apt -y install curl jq
- uses: actions/checkout@v1
name: Checkout
with:
@@ -304,13 +300,15 @@ jobs:
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
working-directory: ./build/bin
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
# Ref: https://github.com/actions/runner-images/issues/2619
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
- name: Upload build result
uses: actions/upload-artifact@v2
with:
name: mac-${{ matrix.configuration }}
path: ${{ github.workspace }}/build/bin/macos-build.tar
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
mac_zip:
name: Build Mac distribution zip
needs: build_mac
@@ -333,6 +331,11 @@ jobs:
with:
name: mac-FastDebug
path: builds
- name: Unpack builds
working-directory: ./builds
run: |
tar -xvzf macos-build-Release.tgz
tar -xvzf macos-build-FastDebug.tgz
- name: Create Distribution package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
+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-8a6bbbe
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
steps:
# - name: Cache Qt
# id: cache-qt-lin
+81
View File
@@ -0,0 +1,81 @@
name: Weekly Coverity Scan for Freespace Open
# adapted from code by "albert-github" on the doxygen repository
# many thanks for figuring this out first so it could be less painful for us!
# This mode is for testing
on: [push, pull_request]
# In production, push on a specific schedule
#on:
# schedule:
# - cron: "1 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
env:
QT_VERSION: 5.12.9
coverity_email: [email protected]
coverity_token: ${{ secrets.COVERITY_TOKEN }}
jobs:
build:
name: Build FSO With Coverity Wrapper
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
steps:
- name: Install Dependencies
run: |
sudo apt-get install ninja-build
sudo apt install cmake libsdl2-dev g++
sudo apt-get install libopenal-dev
sudo apt-get install -y libudev-dev
sudo apt-get install doxygen
sudo apt install graphviz
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
# pipe results of wget to a log file because it's very verbose and rarely fails
- name: Install Coverity
run: |
wget -o wgetlog.txt -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ env.coverity_token }}&project=scp-fs2open/fs2open.github.com" -O coverity_tool.tgz
mkdir cov-scan
tar ax -f coverity_tool.tgz --strip-components=1 -C cov-scan
- name: Setup Environment
run: |
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
with:
vulkan-query-version: 1.3.204.0
vulkan-components: Vulkan-Headers, Vulkan-Loader
vulkan-use-cache: true
- name: Configure CMake for FSO
env:
CONFIGURATION: Release
compiler: gcc-5
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Build FSO with Coverity Wrapper
working-directory: ./build
env:
CONFIGURATION: Release
run: cov-build --dir cov-int ninja -k 20 all
- name: Compress Results
working-directory: ./build
run: tar zcf cov-scan.tgz cov-int
#Comment this out when testing to keep from running into upload limits
- name: Upload to Coverity
run: |
cd build
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form [email protected] --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
+2 -6
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-8a6bbbe
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
steps:
# - name: Cache Qt
# id: cache-qt-lin
@@ -38,10 +38,6 @@ jobs:
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
# setup-python: 'false'
# aqtversion: ==1.1.3
- name: Add curl to the container
run: |
apt-get update -y
apt -y install curl jq
- uses: actions/checkout@v1
name: Checkout
with:
@@ -245,4 +241,4 @@ jobs:
if: startsWith(matrix.compiler, 'clang-')
uses: asarium/clang-tidy-action@v1
with:
fixesFile: clang-fixes.yaml
fixesFile: clang-fixes.yaml
+1
View File
@@ -250,6 +250,7 @@ documentation/doxygen/*
projects/*
/.vs
CMakeSettings.json
CMakePresets.json
# Weird files created by Linux
.fuse_hidden*
-175
View File
@@ -1,175 +0,0 @@
language: bash
sudo: required
dist: xenial
cache:
directories:
- $HOME/cmake-3.8
- $HOME/.ccache
- $HOME/curl_cache
addons:
apt:
packages: &global_deps
- ninja-build
- libopenal-dev
- libreadline6-dev
- libpng12-dev
- libjpeg62-dev
- liblua5.1-0-dev
- libjansson-dev
- libsdl2-dev
- libfreetype6-dev
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
notification_email: [email protected]
build_command: "ci/travis/script.sh"
# must match TRAVIS_BRANCH check below
branch_pattern: coverity_scan
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
# also note that fork's don't get access to secure keys
# you have to test using a branch in the main repo
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
# These declarations set DATACORDER_USER and DATACORDER_PASSWORD
- secure: "dpBH/dDN3bmU/NFlh+2v9isNx9wX0ocoRy+W+kBXRH32sosUGp26REhMqgVRpBNP5oxPBU8ic5bEogxAYWCB+0xUygBbkxAwyMPgoA34s0OXdTCY/ofw14ni8qqV2Ffy7fQJbP/jkMURyiMHx3kBTxNv3YjxKJqLnOuOMlQLpT8="
- secure: "tLMRBD1Ufp5iKNwlqPDVbbuczgusaXNoBJyAnPATpJq2YwlkW4j3PqP9rW5vd85+52xam2EOP20w9PoBR5J6FLdiXRu4Lf7yCEhSHFAgowVqQj8QcJpPlyXr90bM4emFGrGqpdxVwxyQ5AFhKwLuEZKsI14GYLN+UMEwpNCMing="
deploy:
- provider: releases
api_key:
secure: "q619+eQTe7lv8UVphK4OIzU8Jw84KBbVkuprN2sWIubRcV3IbZr2+WahJoUMt+nyhiy3YjDYtstO2ZgkxupwnZgwGUBVIiD1c4SPuyy+HTjNMOtiVsEUHT2hf+xPAemWpTlK5HcwhMmHAOh6rt6dEj57QOg0gcmGiwD/tCbEriA="
skip_cleanup: true
file_glob: true
file: "/tmp/builds/*"
on:
condition: '"$RELEASE_BUILD" == true'
tags: true
- provider: script
script: bash ci/travis/ftp_deploy.sh
on:
condition: '"$NIGHTLY_BUILD" == true'
tags: true
- provider: script
skip_cleanup: true
script: bash ci/travis/ftp_deploy.sh
on:
condition: $TEST_BUILD = true
all_branches: true
matrix:
include:
# note that gcc Debug MUST be 1st for Coverity
- os: linux
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=gcc-9 CXX=g++-9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- g++-9
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-9
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Debug"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
- os: linux
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Release" CC=gcc-9 CXX=g++-9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- g++-9
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-xenial'
packages:
- *global_deps
- g++-9
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Release"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
# There is a GCC compiler bug with MinGW that causes compilation failures on Windows at the moment
allow_failures:
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
fast_finish: true
before_install:
# ugly hack; if running a coverity scan abort all except the 1st build
# see note re gcc compiler above needing to be 1st
# also note that branch_pattern & the TRAVIS_BRANCH check must match
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
# build process
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
- source "./ci/travis/check_release.sh"
- "./ci/travis/before_install.sh"
install:
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
- "./ci/travis/install.sh"
- export PATH=$HOME/cmake-3.6/bin:$PATH
before_script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
-2
View File
@@ -1,7 +1,5 @@
FreeSpace2 *S*ource *C*ode *P*roject
==
[![Travis-CI Build Status](https://travis-ci.org/scp-fs2open/fs2open.github.com.svg?branch=master)](https://travis-ci.org/scp-fs2open/fs2open.github.com)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/scp-fs2open/fs2open.github.com?branch=master&svg=true)](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
[![Coverity](https://img.shields.io/coverity/scan/870.svg)](https://scan.coverity.com/projects/870)
Building
-62
View File
@@ -1,62 +0,0 @@
version: 1.0.0.{build}
image: Visual Studio 2015
configuration:
- Debug
- Release
clone_depth: 10
environment:
matrix:
- BuildID: 0
CMAKE_GENERATOR: Visual Studio 14 2015
PlatformToolset: v140
QT_DIR: C:\Qt\5.9\msvc2015
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
PlatformToolset: v140
QT_DIR: C:\Qt\5.9\msvc2015_64
before_build:
- git submodule update --init --recursive
build_script:
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
test_script:
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
deploy:
- provider: GitHub
auth_token:
secure: h55Scpy+3vmo1Yb7WlSIGA4d9DRnsbzUYc2LYsQdByQHZHbqrqjBpicH0D2FFLEO
on:
ReleaseBuild: true # deploy on release push only
- provider: FTP
protocol: sftp
host: scp.indiegames.us
username:
secure: SFivQZfatqWHXK1ijYK3GQ==
password:
secure: q6Zk/412o1ri+NEya1dl1Q==
folder: public_html/builds/nightly/$(VersionName)
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: sftp
host: porphyrion.feralhosting.com
username:
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
password:
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$(VersionName)
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: sftp
host: porphyrion.feralhosting.com
username:
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
password:
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$(VersionName)
on:
TestBuild: true # deploy on test build push only
-164
View File
@@ -1,164 +0,0 @@
class BuildConfig {
[string]$Generator
[string]$PackageType
[string]$Toolset
[string]$SimdType
[string]$QtDir
[Bool]$SourcePackage
}
$NightlyConfigurations = @(
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# },
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$false;
# }
)
$ReleaseConfigurations = @(
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$true;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015";
# PackageType="Win32-AVX";
# Toolset="v140";
# SimdType="AVX";
# QtDir="C:\Qt\5.9\msvc2015";
# SourcePackage=$false;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64";
# Toolset="v140";
# SimdType="SSE2";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# }
# [BuildConfig]@{
# Generator="Visual Studio 14 2015 Win64";
# PackageType="Win64-AVX";
# Toolset="v140";
# SimdType="AVX";
# QtDir="C:\Qt\5.9\msvc2015_64";
# SourcePackage=$false;
# }
)
$BuildConfigurations = $null
# Default values
$ReleaseBuild = $false
$NightlyBuild = $false
$TestBuild = $false
# Set to true to test either the release or the nightly part of this script
$ReleaseTest = $false
$NightlyTest = $false
$TestBuildTest = $false
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
# Tag matches
$ReleaseBuild = $true
$PackageName = "fs2_open_$($matches[1])"
$BuildConfigurations = $ReleaseConfigurations
}
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
# Tag matches
$NightlyBuild = $true
$PackageName = "nightly_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
}
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
# Tag matches
$TestBuild = $true
$PackageName = "test_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
# Override the revision string so that the builds are named correctly
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
}
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
$buildID = [convert]::ToInt32($env:BuildID) * 2
if ($Env:Configuration -eq "Release") {
$buildID = $buildID + 1
}
$DeployBuild = $false
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
$DeployBuild = $true
}
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
New-Item build -type directory
Set-Location -Path build
if ($DeployBuild) {
# Release build
if ($buildID -ge $BuildConfigurations.Length) {
# Not needed
exit 0
}
$buildConfig = $BuildConfigurations[$buildID]
if ($buildConfig.SourcePackage -eq $True) {
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
}
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=OFF `
-DFSO_INSTALL_DEBUG_FILES="ON" `
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
$Configs = @("Release", "FastDebug")
foreach ($config in $Configs) {
cmake --build . --config "$config" --target INSTALL -- /verbosity:minimal
if (! ($?)) {
Add-AppveyorMessage "A release build failed!"
exit 1
}
}
7z a -xr'!*.pdb' "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
7z a "$($PackageName)-debug-$($buildConfig.PackageType).7z" "$env:APPVEYOR_BUILD_FOLDER/../install/*.pdb"
Push-AppveyorArtifact "$($PackageName)-debug-$($buildConfig.PackageType).7z"
} else {
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
-DFSO_BUILD_QTFRED=OFF -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
if (! ($?)) {
exit 1
}
}
-13
View File
@@ -1,13 +0,0 @@
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
# Skip tests for deployment
exit 0
} else {
write "Running unit tests..."
# Run unit tests
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
if (! ($?)) {
exit 1
}
}
+3 -1
View File
@@ -22,7 +22,7 @@ if [ "$RUNNER_OS" = "macOS" ]; then
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
else
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
fi
@@ -30,6 +30,8 @@ fi
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
# force clang to silently allow -static-libstdc++ flag
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
fi
mkdir build
+1 -1
View File
@@ -26,7 +26,7 @@ elif [ "$OS" = "Windows" ]; then
echo "debug_name=$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")" >> $GITHUB_OUTPUT
elif [ "$OS" = "Mac" ]; then
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *.app
echo "package_path=$(pwd)/$(get_package_name)-builds-Mac.tar.gz" >> $GITHUB_OUTPUT
echo "package_name=$(get_package_name)-builds-Mac.tar.gz" >> $GITHUB_OUTPUT
+2 -2
View File
@@ -15,7 +15,7 @@ if [ "$UPLOAD_TYPE" = "nightly" ]; then
any_success=true
fi
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly"; then
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/nightly"; then
any_success=true
fi
@@ -24,7 +24,7 @@ if [ "$UPLOAD_TYPE" = "nightly" ]; then
exit 1
fi
elif [ "$UPLOAD_TYPE" = "test" ]; then
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/test"
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/test"
else
echo "Unknown upload type $UPLOAD_TYPE"
exit 1
+7 -3
View File
@@ -19,7 +19,7 @@
# HLP_API:
# HLP_KEY:
# LINUX_RESULT: bool, if the linux builds were sucessfully uploaded
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
import sys
@@ -137,8 +137,8 @@ def main():
"pass": os.environ["INDIEGAMES_SSHPASS"],
"path": "public_html/builds/{type}/{version}/",
"mirrors": (
"https://porphyrion.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
"http://scp.indiegames.us/builds/{type}/{version}/{file}",
"https://perses.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
"https://scp.indiegames.us/builds/{type}/{version}/{file}",
),
},
"nebula": {
@@ -260,6 +260,10 @@ def main():
if "Linux" not in groups.keys():
print("ERROR: No Linux builds were detected!")
sys.exit(1)
if "Mac" not in groups.keys():
print("ERROR: No Mac builds were detected!")
sys.exit(1)
# z64: What dose this do???
# print(installer.render_installer_config(version, groups, config))
+13 -6
View File
@@ -18,11 +18,11 @@ Launchers, if you don't have one already:
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
[b]Important:[/b] For best compatibility with FSO 3.8 and later you should use at least wxLauncher 0.12.
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=https://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
[img]http://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
[img]https://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
[b]64-bit:[/b] ${build(groups["Win64"].mainFile)}
@@ -44,7 +44,7 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url] and it will download the best build specifically for your PC!
[/hidden]
[img]http://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
${build(groups["Linux"].mainFile)}
@@ -52,14 +52,21 @@ These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] wh
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
[img]http://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]OS X[/size][/color]
[b][color=red]Not available[/color][/b] We recently lost access to our Mac CI environment which we usually used for compiling these builds so for the time being, there will be no builds for this OS.
[img]https://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]macOS[/size][/color]
[size=8pt]macOS 10.9+, 64-bit (Intel)[/size]
${build(groups["Mac"].mainFile)}
These builds are not signed and so by default will fail to launch. To run them simply right-click on the app, click open, then click open again on the security confirmation dialog. You should only have to do this once for each app.
If running the game through Knossos or Knossos.NET this step should not be necessary.
[size=8pt][color=red][b]NOTE:[/b][/color] macOS builds currently have limited support and may exhibit issues not present on other platforms.[/size]
[hidden=TrackIR Users]
[size=12pt]Important!![/size]
An external DLL is required for FSO to use TrackIR functions. The following DLL is simply unpacked in to your main FreeSpace2 root dir.
TrackIR is only supported on Windows.
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=https://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
Known issues:
[list]
-8
View File
@@ -1,8 +0,0 @@
#!/usr/bin/env sh
set -ex
if [ "$NIGHTLY_BUILD" = true ]; then
echo "Generating bintray config..."
sed -e "s/\$VERSION_NAME/$VERSION_NAME/" ci/bintray.template.json > ci/bintray.json
fi
-20
View File
@@ -1,20 +0,0 @@
#!/usr/bin/env sh
set -ex
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export DEBIAN_FRONTEND=noninteractive
sudo add-apt-repository -y "ppa:msulikowski/valgrind" # For fixing a bug with valgrind 3.11 which does not recognize the rdrand instruction
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo add-apt-repository -y 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
sudo apt-get -yq update
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
# Nothing to do here
:
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
# Nothing to do here
:
fi
-50
View File
@@ -1,50 +0,0 @@
#!/usr/bin/env bash
set -ex
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
mkdir -p /tmp/builds
if [ "$RELEASE_BUILD" = true ]; then
# Package the source code in release builds
PARENT_DIR="$(basename "$PWD")"
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
fi
fi
mkdir -p build
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
export CXXFLAGS
export CFLAGS
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
if [ "$BUILD_DEPLOYMENT" = true ]; then
for config in $BUILD_CONFIGS
do
mkdir -p $config
cd $config
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
cd ..
done
else
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF ..
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
if [ "$BUILD_DEPLOYMENT" = true ]; then
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
else
cmake -G "Xcode" $CMAKE_OPTIONS ..
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
else
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
fi
fi
-74
View File
@@ -1,74 +0,0 @@
#!/usr/bin/env sh
RELEASE_BUILD=false
NIGHTLY_BUILD=false
TEST_BUILD=false
BUILD_DEPLOYMENT=false
BUILD_CONFIGS="Release FastDebug"
VERSION_NAME=""
PACKAGE_NAME=""
RELEASE_PATTERN="^release_(.*)$"
NIGHTLY_PATTERN="^nightly_(.*)$"
TEST_BUILD_PATTERN="^test\/(.*)$"
# These are for testing
NIGHTLY_TEST=false
RELEASE_TEST=false
TEST_BUILD_TEST=false
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
echo "This is a release tag!";
RELEASE_BUILD=true;
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
fi
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
echo "This is a nightly tag!";
NIGHTLY_BUILD=true;
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
fi
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
echo "This is a test build branch!";
TEST_BUILD=true;
if [ "$TEST_BUILD_TEST" = true ]; then
VERSION_NAME="test";
PACKAGE_NAME="test_test";
else
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
fi
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
fi
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
BUILD_DEPLOYMENT=true;
fi
if [ "$BUILD_DEPLOYMENT" = true ]; then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
echo "Skipping non-release compiler";
exit 0;
fi
if ([[ "$CONFIGURATION" == "Debug" ]]); then
echo "Skipping non-release configuration";
exit 0;
fi
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
echo "Skipping non-release platform"
exit 0
fi
fi
export RELEASE_BUILD
export NIGHTLY_BUILD
export TEST_BUILD
export BUILD_DEPLOYMENT
export BUILD_CONFIGS
export VERSION_NAME
export PACKAGE_NAME
-89
View File
@@ -1,89 +0,0 @@
#!/usr/bin/env bash
set -e
set -u
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
# Before
echo "Before:"
curl -V
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ -f ~/curl_cache/curl*.deb ]; then
cd ~/curl_cache
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
else
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
mkdir /tmp/curl
cd /tmp/curl
sudo apt-get update
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
apt-get source curl
sudo apt-get build-dep curl
cd curl-*
export DEB_BUILD_OPTIONS="nocheck"
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
cd ..
dpkg -l | grep curl
ls -al
if [ ! -d ~/curl_cache ]; then
mkdir ~/curl_cache
fi
cp libcurl3*.deb curl*.deb ~/curl_cache
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install libssh2
if [ -d ~/curl_cache/curl ]; then
cd ~/curl_cache/curl
sudo make install
else
mkdir /tmp/curl
cd /tmp/curl
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
tar -xjf curl-7.64.0.tar.bz2
cd curl-7.64.0
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
if [ ! -d ~/curl_cache ]; then
mkdir ~/curl_cache
fi
cp -a . ~/curl_cache/curl
sudo make install
fi
export PATH=/usr/local/bin:$PATH
fi
# After
echo "After:"
curl -V
fi
cd /tmp/builds
for file in *; do
if [ "$TEST_BUILD" = true ]; then
# Upload to datacorder
curl -k "sftp://porphyrion.feralhosting.com/www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
else
# Upload to indiegames
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
# Upload to datacorder
curl -k "sftp://porphyrion.feralhosting.com/~/www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
fi
done
-47
View File
@@ -1,47 +0,0 @@
#!/usr/bin/env bash
set -ex
FILENAME=
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export DEBIAN_FRONTEND=noninteractive
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
# If the cache does not currently contain CMake then download and install it
mkdir -p $HOME/cmake-3.8/
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
fi
export PATH=$HOME/cmake-3.8/bin:$PATH
cd $HOME
if [ "${BUILD_DEPLOYMENT}" = true ]; then
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
chmod a+x ./appimagetool
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
chmod a+x ./linuxdeployqt
fi
sudo apt-get -yq install valgrind
if [[ "$CC" = "clang-9" ]]; then
sudo apt-get -yq install clang-9 clang-tidy-9
fi
if [[ "$CC" = "clang-4.0" ]]; then
# Fix a header bug present in ubuntu...
sudo ln -s /usr/include/libcxxabi/__cxxabi_config.h /usr/include/c++/v1/__cxxabi_config.h
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
gem install xcpretty
brew update
brew outdated cmake || brew upgrade cmake
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
choco install mingw ninja
fi
cmake --version
-68
View File
@@ -1,68 +0,0 @@
#!/usr/bin/env sh
set -ex
mkdir -p /tmp/builds
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
cd build
for config in $BUILD_CONFIGS
do
cd "$config"
# Compile all targets
ninja all
# Install Freespace2 targets
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Freespace2 -P cmake_install.cmake
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
FILENAME="$(find /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
: <<'END'
# Install qtFRED targets
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
PREV="$(pwd)"
cd /tmp/release/$config/qtfred
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
# Move our AppRun script to the right location
mv usr/AppRun AppRun
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
cd "$PREV"
END
cd ..
done
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cd build
for config in $BUILD_CONFIGS
do
cmake --build . --config "$config" --target install | tee build.log \
| xcpretty
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
exit $XCODE_RET
fi
done
ls -al /tmp/release
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-MacOSX.tar.gz *)
fi
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env sh
set -e
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
ninja -k 20 all
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
else
./bin/unittests --gtest_shuffle
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
XCODE_RET=${PIPESTATUS[0]}
if [ "$XCODE_RET" -ne "0" ]; then
tar -cvzf build.log.tar.gz build.log
curl --upload-file build.log.tar.gz "https://keep.sh"
exit $XCODE_RET
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
cmake --build . --config "$CONFIGURATION"
else
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
fi
fi
+30 -17
View File
@@ -67,30 +67,43 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
MACRO(COPY_FILE_TO_TARGET _target _file)
if(UNIX)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
)
if (IS_DIRECTORY "${_file}")
get_filename_component(_dirName "${_file}" NAME)
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
# Otherwise we end up creating duplicate files in the copied framework.
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
COMMENT "copying '${_file}'..."
VERBATIM
)
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
COMMENT "copying '${_file}'..."
VERBATIM
)
endif()
else()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "copying '${_file}'..."
VERBATIM
)
endif()
endmacro(COPY_FILE_TO_TARGET)
MACRO(COPY_FILES_TO_TARGET _target)
if(UNIX)
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
)
endif()
ADD_CUSTOM_COMMAND(
TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
VERBATIM
)
FOREACH(file IN LISTS TARGET_COPY_FILES)
COPY_FILE_TO_TARGET("${_target}" "${file}")
ENDFOREACH(file)
+1 -1
View File
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 23)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
+9 -18
View File
@@ -56,12 +56,6 @@ extern const int Num_ai_flag_names;
#define AIDO_DOCK_NOW 2 // Immediately move into dock position. For ships that start mission docked.
#define AIDO_UNDOCK 3 // Set goal of undocking with object.
// Submodes for seeking safety.
#define AISS_1 41 // Pick a spot to fly to.
#define AISS_2 42 // Flying to spot.
#define AISS_3 43 // Gotten near spot, fly about there.
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2
// Flags to ai_turn_towards_vector().
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
@@ -93,7 +87,7 @@ extern const int Num_ai_flag_names;
#define AIM_BAY_DEPART 18 // Departing to a fighter bay, following path to do so
#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_FLY_TO_SHIP 21 // Rendezvous with a ship. Like stay-near, but non-perpetual.
#define AIM_LUA 22 // Generic Lua-based AI mode
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
@@ -186,6 +180,12 @@ typedef struct ai_class {
#define AIS_UNDOCK_3 33
#define AIS_UNDOCK_4 34
// Submodes for seeking safety.
#define AISS_1 41 // Pick a spot to fly to.
#define AISS_2 42 // Flying to spot.
#define AISS_3 43 // Gotten near spot, fly about there.
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2. (Not implemented.)
// Submodes for Guard behavior
#define AIS_GUARD_PATROL 101
#define AIS_GUARD_ATTACK 102
@@ -240,7 +240,6 @@ typedef struct ai_info {
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
int shipnum; // Ship using this slot, -1 means none.
int behavior; // AI behavior; vestigial field from early development of FS1
int mode;
int previous_mode;
int mode_time; // timestamp at which current mode elapses.
@@ -308,6 +307,7 @@ typedef struct ai_info {
fix submode_start_time; // time at which we entered the current submode
int submode_parm0; // parameter specific to current submode
int submode_parm1; // SUSHI: Another optional parameter
float submode_float0; // Goober5000: a float 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
@@ -373,11 +373,6 @@ typedef struct ai_info {
float ai_turret_max_aim_update_delay;
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
union {
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
};
ship_subsys* targeted_subsys; // Targeted subobject on current target. NULL if none;
ship_subsys* last_subsys_target; // last known subsystem target
int targeted_subsys_parent; // Parent objnum of subobject, not necessarily targeted
@@ -565,7 +560,7 @@ extern void ai_attack_wing(object *attacker, int wingnum);
extern void ai_deathroll_start(object *ship_obj);
extern int set_target_objnum(ai_info *aip, int objnum);
extern void ai_form_on_wing(object *objp, object *goal_objp);
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
@@ -625,10 +620,6 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
// moved to header file by Goober5000
void ai_announce_ship_dying(object *dying_objp);
// added by kazan
void ai_start_fly_to_ship(object *objp, int shipnum);
void ai_fly_to_ship();
//Moved declaration here for player ship -WMC
void ai_process_subobjects(int objnum);
+2 -1
View File
@@ -122,7 +122,7 @@ namespace AI {
Smart_shield_management,
Smart_subsystem_targeting_for_turrets,
Strict_turret_tagged_only_targeting,
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
Turrets_ignore_target_radius,
Use_actual_primary_range,
Use_subsystem_path_point_radii,
@@ -156,6 +156,7 @@ namespace AI {
Whackable_debris,
Whackable_asteroids,
Dynamic_goals_afterburn_hard,
Hudsquadmsg_tactical_disarm_disable,
NUM_VALUES
};
+8 -1
View File
@@ -552,7 +552,9 @@ void parse_ai_profiles_tbl(const char *filename)
profile->flags.set(AI::Profile_Flags::All_nonshielded_ships_can_manage_ets, temp);
}
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
// ----------
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
set_flag(profile, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
@@ -623,6 +625,8 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
set_flag(profile, "$hud squad messages use tactical disarm/disable:", AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
{
@@ -812,4 +816,7 @@ void ai_profile_t::reset()
if (mod_supports_version(23, 2, 0)) {
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
}
if (mod_supports_version(23, 4, 0)) {
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
}
}
+5 -5
View File
@@ -535,11 +535,11 @@ bool ai_new_maybe_reposition_attack_subsys() {
// get world pos of eye (stored in geye)
ep = &(pm->view_positions[Ships[Pl_objp->instance].current_viewpoint]);
model_local_to_global_point(&geye, &ep->pnt, pm->id, 0, &Pl_objp->orient, &Pl_objp->pos);
model_local_to_global_point(&geye, &ep->pnt, pm, 0, &Pl_objp->orient, &Pl_objp->pos);
// get world pos of subsystem
vm_vec_unrotate(&gsubpos, &aip->targeted_subsys->system_info->pnt, &En_objp->orient);
vm_vec_add2(&gsubpos, &En_objp->pos);
polymodel* tgt_pm = model_get(Ship_info[Ships[target_objp->instance].ship_info_index].model_num);
model_local_to_global_point(&gsubpos, &vmd_zero_vector, tgt_pm, aip->targeted_subsys->system_info->subobj_num, &En_objp->orient, &En_objp->pos);
// you're in sight! shoot it!
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
@@ -914,13 +914,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
}
if (tswp->num_secondary_banks > 0) {
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
int current_bank = tswp->current_secondary_bank;
if (current_bank > -1 && valid_secondary) {
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
// If ship is protected and very low on hits, don't fire missiles.
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
+112 -159
View File
@@ -386,7 +386,7 @@ int is_preferred_weapon(int weapon_num, object *firer_objp, object *target_objp)
continue;
auto ship_entry = &Ship_registry[hfi->ship_registry_index];
if (ship_entry->status != ShipStatus::PRESENT)
if (!ship_entry->objp)
continue;
int signature = ship_entry->objp->signature;
@@ -954,6 +954,21 @@ void ai_init()
"ai autoscaling. If that's not desired then use a tbl instead of a tbm!\n"));
}
// autoscaling is meaningless if only one AI class has it, and will produce either ineffectual or
// divide-by-zero math expressions if $use adjusted AI class autoscale: is enabled
int num_autoscaled_classes = 0;
int autoscaled_class_index = -1;
for (int i = 0; i < Num_ai_classes; ++i) {
if (Ai_classes[i].ai_class_autoscale) {
num_autoscaled_classes++;
autoscaled_class_index = i;
}
}
if (num_autoscaled_classes == 1) {
Warning(LOCATION, "Autoscaling is meaningless when only one AI class has autoscaling enabled. Turning off autoscaling for %s.", Ai_classes[autoscaled_class_index].name);
Ai_classes[autoscaled_class_index].ai_class_autoscale = false;
}
atexit(free_ai_stuff);
ai_inited = 1;
@@ -1301,7 +1316,7 @@ void ai_turn_towards_vector(vec3d* dest, object* objp, vec3d* slide_vec, vec3d*
// Don't allow a ship to turn if it has no engine strength.
// AL 3-12-98: objp may not always be a ship!
if ( (objp->type == OBJ_SHIP) && !(flags & AITTV_VIA_SEXP) ) {
if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
if (!Ships[objp->instance].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
return;
}
@@ -3447,36 +3462,6 @@ void ai_dock_with_object(object *docker, int docker_index, object *dockee, int d
}
/*
* Cause a ship to fly toward a ship.
*/
void ai_start_fly_to_ship(object *objp, int shipnum)
{
ai_info *aip;
aip = &Ai_info[Ships[objp->instance].ai_index];
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics] && AutoPilotEngaged)
{
aip->ai_flags.remove(AI::AI_Flags::Formation_wing);
}
else
{
aip->ai_flags.set(AI::AI_Flags::Formation_wing);
}
aip->ai_flags.remove(AI::AI_Flags::Formation_object);
aip->mode = AIM_FLY_TO_SHIP;
aip->submode_start_time = Missiontime;
aip->target_objnum = Ships[shipnum].objnum;
// clear targeted subsystem
set_targeted_subsys(aip, nullptr, -1);
Assert(aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC);
}
// Cause a ship to fly its waypoints.
// flags tells:
// WPF_REPEAT Set -> repeat waypoints.
@@ -3518,7 +3503,7 @@ void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags)
/**
* Make *objp stay within dist units of *other_objp
*/
void ai_do_stay_near(object *objp, object *other_objp, float dist)
void ai_do_stay_near(object *objp, object *other_objp, float dist, int additional_data)
{
ai_info *aip;
@@ -3531,7 +3516,8 @@ void ai_do_stay_near(object *objp, object *other_objp, float dist)
aip->mode = AIM_STAY_NEAR;
aip->submode = -1;
aip->submode_start_time = Missiontime;
aip->stay_near_distance = dist;
aip->submode_float0 = dist;
aip->submode_parm0 = additional_data;
aip->goal_objnum = OBJ_INDEX(other_objp);
aip->goal_signature = other_objp->signature;
}
@@ -4907,84 +4893,6 @@ void ai_waypoints()
}
}
// --------------------------------------------------------------------------
// make Pl_objp fly toward a ship
void ai_fly_to_ship()
{
ai_info *aip;
object* target_p = NULL;
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
if ( aip->mode != AIM_FLY_TO_SHIP ) {
Warning(LOCATION,
"ai_fly_to_ship called for '%s' when ai_info.mode not equal to AIM_FLY_TO_SHIP. Is actually '%d'",
Ships[Pl_objp->instance].ship_name,
aip->mode);
aip->mode = AIM_NONE;
return;
}
if ( aip->active_goal < 0 || aip->active_goal >= MAX_AI_GOALS ) {
Warning(LOCATION,
"'%s' is trying to fly-to a ship without an active AI_GOAL\n\n"
"Active ai mode is '%d'",
Ships[Pl_objp->instance].ship_name,
aip->active_goal);
aip->mode = AIM_NONE;
return;
}
Assert( aip->goals[aip->active_goal].target_name != NULL );
if ( aip->goals[aip->active_goal].target_name[0] == '\0' ) {
Warning(LOCATION, "'%s' is trying to fly-to-ship without a name for the ship", Ships[Pl_objp->instance].ship_name);
aip->mode = AIM_NONE;
ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
return;
}
for (int j = 0; j < MAX_SHIPS; j++)
{
if (Ships[j].objnum != -1 && !stricmp(aip->goals[aip->active_goal].target_name, Ships[j].ship_name))
{
target_p = &Objects[Ships[j].objnum];
break;
}
}
if ( target_p == NULL ) {
#ifndef NDEBUG
for (int i = 0; i < MAX_AI_GOALS; i++)
{
if (aip->mode == AIM_FLY_TO_SHIP || aip->goals[i].ai_mode == AI_GOAL_FLY_TO_SHIP)
{
mprintf(("Ship '%s' told to fly to target ship '%s'\n",
Ships[Pl_objp->instance].ship_name,
aip->goals[i].target_name));
}
}
#endif
Warning(LOCATION, "Ship '%s' told to fly to a ship but none of the ships it was told to fly to exist.\n"
"See log before this message for list of ships set as fly-to tagets",
Ships[Pl_objp->instance].ship_name);
aip->mode = AIM_NONE;
ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
return;
} else {
bool done, treat_as_ship;
ai_fly_to_target_position(&(target_p->pos), &done, &treat_as_ship);
if ( done ) {
// remove the goal from the AI goals of the ship pr wing, respectively.
// Wether or not we should treat this as a ship or a wing is determined by
// ai_fly_to_target when it marks the AI directive as complete
if ( treat_as_ship ) {
ai_mission_goal_complete( aip ); // this call should reset the AI mode
} else {
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
}
}
}
}
// Make Pl_objp avoid En_objp
// Not like evading. This is for avoiding a collision!
// Note, use sliding if available.
@@ -5656,7 +5564,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < ship_info_size());
//made it so it only selects puncture weapons if the active goal is to disable something -Bobboau
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISABLE_SHIP)))
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL)))
{
if (swp->current_primary_bank >= 0)
{
@@ -5881,7 +5789,7 @@ void set_primary_weapon_linkage(object *objp)
// puncture weapons
if ( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) )
{
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISARM_SHIP) )
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISABLE_SHIP_TACTICAL|AI_GOAL_DISARM_SHIP|AI_GOAL_DISARM_SHIP_TACTICAL) )
{
// only continue if both primaries are puncture weapons
if ( swp->num_primary_banks == 2 ) {
@@ -9471,9 +9379,15 @@ void ai_chase()
firing_range = MIN((swip->max_speed * swip->lifetime * 0.75f), swip->weapon_range);
else
{
float secondary_range_mult = (aip->ai_secondary_range_mult == FLT_MIN)
? (float)(Game_skill_level + 1 + (3 * ai_maybe_autoscale(aip->ai_class)/(ai_maybe_autoscale(Num_ai_classes) - 1)))/NUM_SKILL_LEVELS
: aip->ai_secondary_range_mult;
float secondary_range_mult;
// Cyborg: need to check for division by zero, coverity 1523419
if (aip->ai_secondary_range_mult == FLT_MIN && (ai_maybe_autoscale(Num_ai_classes) > 1))
secondary_range_mult = (float)(Game_skill_level + 1 + (3 * ai_maybe_autoscale(aip->ai_class)/(ai_maybe_autoscale(Num_ai_classes) - 1)))/NUM_SKILL_LEVELS;
else if (aip->ai_secondary_range_mult == FLT_MIN)
secondary_range_mult = (float)(Game_skill_level + 2)/NUM_SKILL_LEVELS; // default to using the default retail class Captain out of the seven there are total when we don't have enough autoscale classes or just one regular class. (This simplifies to 2 + Game_skill_level / Num of skill levels)
else
secondary_range_mult = aip->ai_secondary_range_mult;
firing_range = MIN((swip->max_speed * swip->lifetime * secondary_range_mult), swip->weapon_range);
}
@@ -9776,7 +9690,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
// Goober5000 - moved out here to save calculations
if (dock_mode != DOA_DOCK_STAY)
if (ship_get_subsystem_strength(&Ships[docker_objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
if (!Ships[docker_objp->instance].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[docker_objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
return 9999.9f;
// If dockee has moved much, then path will be recreated.
@@ -11342,24 +11256,52 @@ void ai_still()
// Make *Pl_objp stay near another ship.
void ai_stay_near()
{
ai_info *aip;
int goal_objnum;
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
goal_objnum = aip->goal_objnum;
auto aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
int goal_objnum = aip->goal_objnum;
if ((goal_objnum < 0) || (Objects[goal_objnum].type != OBJ_SHIP) || (Objects[goal_objnum].signature != aip->goal_signature)) {
aip->mode = AIM_NONE;
} else {
float dist, max_dist, scale;
vec3d rand_vec, goal_pos, vec_to_goal;
object *goal_objp;
}
// "escort" behavior
else if (aip->submode_parm0 != 0) {
vec3d rand_vec, center_to_goal, center_to_objp;
auto goal_objp = &Objects[goal_objnum];
float max_dist = aip->submode_float0;
goal_objp = &Objects[goal_objnum];
// Figure out a goal point to fly to
// Make not all ships pursue same point.
// Calculate the seed from both shipnums so the same Pl_objp doesn't always choose the same spot
static_randvec((goal_objp->instance * MAX_SHIPS) + (Pl_objp->instance), &rand_vec);
aip->goal_point = goal_objp->pos + max_dist * rand_vec;
// Make sure point is on the near side of goal_objp (relative to Pl_objp's position).
center_to_goal = aip->goal_point - goal_objp->pos;
center_to_objp = Pl_objp->pos - goal_objp->pos;
if (vm_vec_dot(&center_to_goal, &center_to_objp) < 0.0f) {
vm_vec_negate(&rand_vec);
aip->goal_point = goal_objp->pos + max_dist * rand_vec;
}
// Fly to the point
auto dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
if (dist > max_dist) {
turn_towards_point(Pl_objp, &aip->goal_point, nullptr, 0.0f);
accelerate_ship(aip, dist / max_dist - 0.8f);
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &aip->goal_point);
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
ai_afterburn_hard(Pl_objp, aip);
}
}
// standard behavior
else {
vec3d rand_vec, goal_pos, vec_to_goal;
auto goal_objp = &Objects[goal_objnum];
float max_dist = aip->submode_float0;
// Make not all ships pursue same point.
static_randvec(OBJ_INDEX(Pl_objp), &rand_vec);
// Calculate the seed from both shipnums so the same Pl_objp doesn't always choose the same spot
static_randvec((goal_objp->instance * MAX_SHIPS) + (Pl_objp->instance), &rand_vec);
// Make sure point is in front hemisphere (relative to Pl_objp's position.
vm_vec_sub(&vec_to_goal, &goal_objp->pos, &Pl_objp->pos);
@@ -11368,28 +11310,22 @@ void ai_stay_near()
}
// Scale the random vector by an amount proportional to the distance from Pl_objp to the true goal.
dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
max_dist = aip->stay_near_distance;
scale = dist - max_dist/2;
float dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
float scale = dist - max_dist/2;
if (scale < 0.0f)
scale = 0.0f;
vm_vec_scale_add(&goal_pos, &goal_objp->pos, &rand_vec, scale);
if (max_dist < Pl_objp->radius + goal_objp->radius + 25.0f)
max_dist = Pl_objp->radius + goal_objp->radius + 25.0f;
// Fly to the point
if (dist > max_dist) {
turn_towards_point(Pl_objp, &goal_pos, NULL, 0.0f);
turn_towards_point(Pl_objp, &goal_pos, nullptr, 0.0f);
accelerate_ship(aip, dist / max_dist - 0.8f);
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &goal_pos);
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
ai_afterburn_hard(Pl_objp, aip);
}
}
}
// Warn player if dock path is obstructed.
@@ -12141,7 +12077,7 @@ object *get_wing_leader(int wingnum)
// If this ship is disabled, try another ship in the wing.
int n = 0;
while (ship_get_subsystem_strength(&Ships[ship_num], SUBSYSTEM_ENGINE) == 0.0f) {
while (!Ships[ship_num].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[ship_num], SUBSYSTEM_ENGINE) == 0.0f) {
n++;
if (n >= wingp->current_count) {
@@ -12484,7 +12420,7 @@ int ai_formation()
} else { // Formation flying in waypoint mode.
Assert(aip->ai_flags[AI::AI_Flags::Formation_wing]);
if ( (aip->mode != AIM_WAYPOINTS) && (aip->mode != AIM_FLY_TO_SHIP) ) {
if ( aip->mode != AIM_WAYPOINTS ) {
aip->ai_flags.remove(AI::AI_Flags::Formation_wing);
return 1;
}
@@ -13114,10 +13050,25 @@ void ai_manage_shield(object *objp, ai_info *aip)
// Scale between 1x and 3x based on ai_class (SUSHI: only if autoscale is on)
if (aip->ai_class_autoscale)
{
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
delay = delay + delay * (float)(3 * (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) / (ai_get_autoscale_index(Num_ai_classes) - 1));
else
delay = delay + delay * (float)(3 * (Num_ai_classes - aip->ai_class - 1) / (Num_ai_classes - 1));
int number_of_as_classes = ai_get_autoscale_index(Num_ai_classes);
// Cyborg: Make sure that autoscale index is greater than one before dividing, coverity 1523548
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale] && number_of_as_classes > 1)
delay = delay + delay * (float)(3 * (number_of_as_classes - ai_get_autoscale_index(aip->ai_class) - 1) / (number_of_as_classes - 1));
else {
static bool autoscale_checked = false;
// warn if there's only one autoscale ai class
if (number_of_as_classes == 1 && !autoscale_checked) {
mprintf(("Warning! Having only 1 autoscale ai class will disable autoscale features that rely on division."));
autoscale_checked = true;
}
// Only adjust if we have more than one ai class to avoid div by 0
if (Num_ai_classes > 1){
delay = delay + delay * (float)(3 * (Num_ai_classes - aip->ai_class - 1) / (Num_ai_classes - 1));
}
}
}
// set timestamp
@@ -13487,8 +13438,14 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
}
}
// cycle through the allowed paths
bay_path = allowed_bay_paths[Ai_last_arrive_path % num_allowed_paths];
// Cyborg: to avoid divide by zero and avoid a logic path that should not exist check for 0 allowed paths -- Coverity 1523287
if (num_allowed_paths == 0) {
bay_path = Ai_last_arrive_path % bay->num_paths;
UNREACHABLE("Parent_shipp in ai_acquire_emerge_path somehow does not have any allowed bay paths!");
} else {
// cycle through the allowed paths
bay_path = allowed_bay_paths[Ai_last_arrive_path % num_allowed_paths];
}
}
// choose from among all paths
else
@@ -13906,6 +13863,7 @@ void ai_execute_behavior(ai_info *aip)
case AIM_STILL:
ai_still();
break;
case AIM_FLY_TO_SHIP: // same code as stay-near
case AIM_STAY_NEAR:
ai_stay_near();
break;
@@ -13915,9 +13873,6 @@ void ai_execute_behavior(ai_info *aip)
case AIM_WAYPOINTS:
ai_waypoints();
break;
case AIM_FLY_TO_SHIP:
ai_fly_to_ship();
break;
case AIM_DOCK:
ai_dock();
break;
@@ -14884,7 +14839,7 @@ void ai_frame(int objnum)
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_started);
}
// moved call to ai_do_repair frame here from below because of the subsequent if statment returning
// moved call to ai_do_repair frame here from below because of the subsequent if statement returning
// if the ship is getting repaired
// If waiting to be repaired, just stop and sit.
ai_do_repair_frame(Pl_objp, aip, flFrametime);
@@ -15006,9 +14961,9 @@ void ai_frame(int objnum)
if ( aip->targeted_subsys->current_hits <= 0.0f ) {
int subsys_type;
if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP ) {
if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP_TACTICAL ) {
subsys_type = SUBSYSTEM_ENGINE;
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP ) {
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL ) {
subsys_type = SUBSYSTEM_TURRET;
} else {
subsys_type = -1;
@@ -15264,6 +15219,7 @@ void init_ai_object(int objnum)
aip->submode_start_time = 0;
aip->submode_parm0 = 0;
aip->submode_parm1 = 0;
aip->submode_float0 = 0.0f;
aip->active_goal = -1;
aip->goal_check_time = timestamp(0);
aip->last_predicted_enemy_pos = near_vec;
@@ -16073,22 +16029,19 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
return;
}
break;
case AIM_FLY_TO_SHIP:
case AIM_WAYPOINTS:
if (sip->is_fighter_bomber())
break;
else
return;
break;
return;
case AIM_SAFETY:
if ((aip->submode != AISS_1) || (Missiontime - aip->submode_start_time > i2f(1))) {
aip->submode = AISS_1;
aip->submode_start_time = Missiontime;
}
return;
break;
case AIM_WARP_OUT:
return;
break;
case AIM_LUA:
return;
default:
+167 -135
View File
@@ -51,6 +51,8 @@ struct ship_registry_entry;
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
#define PURGE_GOALS_ALL_SHIPS (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
#define PURGE_GOALS_ONE_SHIP (AI_GOAL_IGNORE_NEW)
@@ -75,7 +77,9 @@ ai_goal_list Ai_goal_names[] =
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
{ "Guard ship", AI_GOAL_GUARD, 0 },
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
{ "Disable ship (tactical)",AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
@@ -120,8 +124,10 @@ const char *Ai_goal_text(int goal, int submode)
case AI_GOAL_GUARD_WING:
return XSTR( "guard ", 480);
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
return XSTR( "disable ", 481);
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
return XSTR( "disarm ", 482);
case AI_GOAL_EVADE_SHIP:
return XSTR( "evade ", 483);
@@ -528,11 +534,12 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
// ignore goals should get rid of any kind of attack goal
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
purge_goal->flags.set(AI::Goal_Flags::Purge);
break;
// disarm/disable goals should remove attacks from certain ships types
// (but not tactical disarm/disable)
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISABLE_SHIP:
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
@@ -549,12 +556,17 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
}
// grab the ship type of the ship that is being disarmed/disabled
ship_type_info *crippled_ships_type = &Ship_types[Ship_info[Ships[ship_index].ship_info_index].class_type];
int crippled_ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
// work through all the ship types which to see if the class matching our ai ship must ignore the ship
if (ai_ship_type < 0 || crippled_ship_type < 0)
break;
ship_type_info *crippled_ship_type_info = &Ship_types[crippled_ship_type];
// work through all the ship types to see if the class matching our ai ship must ignore the ship
// being disarmed/disabled
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
for ( j=0 ; j < (int)crippled_ship_type_info->ai_cripple_ignores.size(); j++) {
if (crippled_ship_type_info->ai_cripple_ignores[j] == ai_ship_type) {
purge_goal->flags.set(AI::Goal_Flags::Purge);
}
}
@@ -931,14 +943,16 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
break;
case OP_AI_DISABLE_SHIP:
aigp->ai_mode = AI_GOAL_DISABLE_SHIP;
case OP_AI_DISABLE_SHIP_TACTICAL:
aigp->ai_mode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->ai_submode = -SUBSYSTEM_ENGINE;
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
break;
case OP_AI_DISARM_SHIP:
aigp->ai_mode = AI_GOAL_DISARM_SHIP;
case OP_AI_DISARM_SHIP_TACTICAL:
aigp->ai_mode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->ai_submode = -SUBSYSTEM_TURRET;
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
@@ -976,7 +990,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
// this goal needs some extra setup
// if this doesn't work, the goal will be immediately removed
auto ship_entry = ship_registry_get(aigp->target_name);
if (ship_entry->status == ShipStatus::PRESENT)
if (ship_entry && ship_entry->shipp)
{
auto target_aip = &Ai_info[ship_entry->shipp->ai_index];
target_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair);
@@ -1022,15 +1036,32 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
break;
case OP_AI_FLY_TO_SHIP:
case OP_AI_STAY_NEAR_SHIP:
{
bool is_nan, is_nan_forever;
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->priority = atoi( CTEXT(CDDR(node)) );
// distance from ship
if ( CDDDR(node) < 0 )
aigp->float_data = 300.0f;
else
aigp->float_data = i2fl(atoi( CTEXT(CDDDR(node)) ));
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
aigp->float_data = i2fl(eval_num(CDDDR(node), is_nan, is_nan_forever));
// (the CDDDDR argument is whether to afterburn, and is handled at the end of the function, so don't handle it here)
// whether to "escort" the ship
if ( CDDDDDR(node) >= 0 )
aigp->int_data = is_sexp_true(CDDDDDR(node)) ? 1 : 0;
if (op == OP_AI_FLY_TO_SHIP)
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
else
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
break;
}
case OP_AI_FORM_ON_WING:
aigp->priority = 99;
@@ -1046,7 +1077,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
case OP_AI_EVADE_SHIP:
case OP_AI_IGNORE:
case OP_AI_IGNORE_NEW:
case OP_AI_FLY_TO_SHIP:
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
@@ -1073,14 +1103,10 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
aigp->ai_mode = AI_GOAL_CHASE_WING;
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
} else if ( op == OP_AI_IGNORE ) {
aigp->ai_mode = AI_GOAL_IGNORE;
} else if ( op == OP_AI_IGNORE_NEW ) {
aigp->ai_mode = AI_GOAL_IGNORE_NEW;
} else if ( op == OP_AI_FLY_TO_SHIP ) {
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
} else
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
@@ -1117,39 +1143,42 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
}
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
if (is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
}
if ( op == OP_AI_DESTROY_SUBSYS ) {
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
if (is_sexp_true(CDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Target_own_team);
}
// maybe get the afterburn hard flag
if (op == OP_AI_CHASE_ANY) {
if ((CDDR(node) != -1) && is_sexp_true(CDDR(node)))
if (is_sexp_true(CDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
if (op == OP_AI_GUARD ||
op == OP_AI_GUARD_WING ||
op == OP_AI_WAYPOINTS ||
op == OP_AI_WAYPOINTS_ONCE ||
op == OP_AI_FLY_TO_SHIP) {
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
op == OP_AI_WAYPOINTS_ONCE) {
if (is_sexp_true(CDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
if (op == OP_AI_CHASE ||
op == OP_AI_CHASE_WING ||
op == OP_AI_CHASE_SHIP_CLASS ||
op == OP_AI_DISABLE_SHIP ||
op == OP_AI_DISABLE_SHIP_TACTICAL ||
op == OP_AI_DISARM_SHIP ||
op == OP_AI_STAY_NEAR_SHIP) {
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
op == OP_AI_DISARM_SHIP_TACTICAL ||
op == OP_AI_STAY_NEAR_SHIP ||
op == OP_AI_FLY_TO_SHIP) {
if (is_sexp_true(CDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
if (op == OP_AI_DESTROY_SUBSYS || op == OP_AI_DOCK) {
if ((CDDDDDR(node) != -1) && is_sexp_true(CDDDDDR(node)))
if (is_sexp_true(CDDDDDR(node)))
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
}
@@ -1219,11 +1248,13 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
priority = ( CDR( CDR( CDR(node) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( node ) ) ) ) ) : -1;
break;
case OP_AI_DISABLE_SHIP:
goalmode = AI_GOAL_DISABLE_SHIP;
case OP_AI_DISABLE_SHIP_TACTICAL:
goalmode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
break;
case OP_AI_DISARM_SHIP:
goalmode = AI_GOAL_DISABLE_SHIP;
case OP_AI_DISARM_SHIP_TACTICAL:
goalmode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
break;
case OP_AI_WARP_OUT:
@@ -1253,11 +1284,8 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
break;
case OP_AI_PLAY_DEAD:
goalmode = AI_GOAL_PLAY_DEAD;
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
break;
case OP_AI_PLAY_DEAD_PERSISTENT:
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
goalmode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
break;
case OP_AI_KEEP_SAFE_DISTANCE:
@@ -1299,12 +1327,9 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
goalmode = AI_GOAL_STAY_NEAR_SHIP;
break;
case OP_AI_IGNORE:
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_IGNORE;
break;
case OP_AI_IGNORE_NEW:
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
goalmode = AI_GOAL_IGNORE_NEW;
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
break;
case OP_AI_FORM_ON_WING:
priority = 99;
@@ -1526,13 +1551,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
{
int status;
ai_achievability return_val;
ai_info *aip;
int index = -1, sindex = -1;
int modelnum = -1;
auto objp = &Objects[objnum];
Assert( objp->instance != -1 );
aip = &Ai_info[Ships[objp->instance].ai_index];
auto shipp = &Ships[objp->instance];
auto aip = &Ai_info[shipp->ai_index];
// these orders are always achievable.
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
@@ -1543,11 +1566,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (aigp->ai_mode == AI_GOAL_LUA)
return ai_lua_is_achievable(aigp, objnum);
auto target_ship_entry = aigp->target_name == nullptr ? nullptr : ship_registry_get(aigp->target_name);
// warp (depart) only achievable if there's somewhere to depart to
if (aigp->ai_mode == AI_GOAL_WARP)
{
ship *shipp = &Ships[objp->instance];
// always valid if has working subspace drive, not disabled, and not limited by subsystem strength
if ( ship_can_warp_full_check(shipp) )
return ai_achievability::ACHIEVABLE;
@@ -1566,9 +1589,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// if the wing target is valid then be sure to set the override bit so that it always
// gets executed next
if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
sindex = ship_name_lookup( aigp->target_name );
if (sindex < 0)
if (!target_ship_entry || !target_ship_entry->shipp)
return ai_achievability::NOT_ACHIEVABLE;
aigp->flags.set(AI::Goal_Flags::Goal_override);
@@ -1625,11 +1646,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid
sindex = ship_name_lookup( aigp->target_name );
// can't determine the status of this goal if ship not valid
// or we haven't found a valid subsystem index yet
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
if ( !target_ship_entry || !target_ship_entry->shipp || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
status = 0;
break;
}
@@ -1638,46 +1658,46 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// as 0 so we can continue. (The subsystem name must be turned into an index into the ship's subsystems
// for this goal to be valid).
Assert ( aigp->ai_submode >= 0 );
ssp = ship_get_indexed_subsys( &Ships[sindex], aigp->ai_submode );
ssp = ship_get_indexed_subsys( target_ship_entry->shipp, aigp->ai_submode );
if (ssp != NULL) {
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
status = (ssp->current_hits <= 0.0f) ? 1 : 0;
} else {
// not supposed to ever happen, but could if there is a mismatch between the table and model subsystems
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, Ships[sindex].ship_name));
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, target_ship_entry->shipp->ship_name));
status = 0;
}
break;
}
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
{
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid
sindex = ship_name_lookup(aigp->target_name);
// can't determine the status of this goal if ship not valid
if (sindex < 0) {
if (!target_ship_entry || !target_ship_entry->shipp) {
status = 0;
} else {
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
status = (Ships[sindex].subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
status = (target_ship_entry->shipp->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
}
break;
}
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
{
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
// destroyed when shipnum is valid
sindex = ship_name_lookup(aigp->target_name);
// can't determine the status of this goal if ship not valid
if (sindex < 0) {
if (!target_ship_entry || !target_ship_entry->shipp) {
status = 0;
} else {
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
status = (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
status = (target_ship_entry->shipp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
}
break;
}
@@ -1696,22 +1716,23 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// MWA -- 4/22/98. Check for the ship actually being in the mission before
// checking departure and destroyed. In multiplayer, since ships can respawn,
// they get log entries for being destroyed even though they have respawned.
sindex = ship_name_lookup( aigp->target_name );
if ( sindex < 0 ) {
status = mission_log_get_time( LOG_SHIP_DEPARTED, aigp->target_name, NULL, NULL);
if ( !status ) {
status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->target_name, NULL, NULL);
if ( !status ) {
status = mission_log_get_time( LOG_SELF_DESTRUCTED, aigp->target_name, NULL, NULL);
}
}
if ( status )
return_val = ai_achievability::NOT_ACHIEVABLE;
// Goober5000 - update this to use ship registry status with similar logic
if (target_ship_entry && target_ship_entry->status == ShipStatus::EXITED) {
status = 1;
return_val = ai_achievability::NOT_ACHIEVABLE;
} else {
status = 0;
}
// fly-to-ship can potentially be determined
if (aigp->ai_mode == AI_GOAL_FLY_TO_SHIP && target_ship_entry && target_ship_entry->objp) {
auto dist = vm_vec_dist(&target_ship_entry->objp->pos, &objp->pos);
if (dist < aigp->float_data) {
return_val = ai_achievability::SATISFIED;
status = 1;
}
}
break;
}
@@ -1749,7 +1770,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
default:
Int3();
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode);
status = 0;
break;
}
@@ -1764,12 +1785,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// the if statement.
if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) )
{
sindex = wing_name_lookup( aigp->target_name );
int wingnum = wing_name_lookup( aigp->target_name );
if (sindex < 0)
if (wingnum < 0)
return ai_achievability::NOT_KNOWN;
wing *wingp = &Wings[sindex];
wing *wingp = &Wings[wingnum];
if ( wingp->flags[Ship::Wing_Flags::Gone] )
return ai_achievability::NOT_ACHIEVABLE;
@@ -1786,24 +1807,22 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
else
{
auto ship_entry = ship_registry_get(aigp->target_name);
if (!ship_entry)
if (!target_ship_entry)
{
status = SHIP_STATUS_UNKNOWN;
}
// goal ship is currently in mission
else if (ship_entry->status == ShipStatus::PRESENT)
else if (target_ship_entry->status == ShipStatus::PRESENT || target_ship_entry->status == ShipStatus::DEATH_ROLL)
{
status = SHIP_STATUS_ARRIVED;
}
// goal ship is still on the arrival list
else if (ship_entry->status == ShipStatus::NOT_YET_PRESENT)
else if (target_ship_entry->status == ShipStatus::NOT_YET_PRESENT)
{
status = SHIP_STATUS_NOT_ARRIVED;
}
// goal ship has left the area
else if (ship_entry->status == ShipStatus::EXITED)
else if (target_ship_entry->status == ShipStatus::EXITED)
{
status = SHIP_STATUS_GONE;
}
@@ -1814,16 +1833,21 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
if (status == SHIP_STATUS_UNKNOWN)
{
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", shipp->ship_name, aigp->target_name));
}
}
// Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP))
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL))
{
// 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_achievability::NOT_ACHIEVABLE;
if (target_ship_entry && target_ship_entry->shipp) {
// if the ship has no turrets, we can't disarm it!
if (target_ship_entry->shipp->subsys_info[SUBSYSTEM_TURRET].type_count == 0)
return ai_achievability::NOT_ACHIEVABLE;
} else {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
// if the goal is an ignore/disable/disarm goal, then
@@ -1845,37 +1869,36 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// this goal will get removed.
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
int modelnum = Ship_info[shipp->ship_info_index].model_num;
Assert( modelnum >= 0 );
index = model_find_dock_name_index(modelnum, aigp->docker.name);
aigp->docker.index = index;
aigp->docker.index = model_find_dock_name_index(modelnum, aigp->docker.name);
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
}
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
sindex = ship_name_lookup(aigp->target_name);
if ( sindex != -1 ) {
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
aigp->dockee.index = index;
if (target_ship_entry && target_ship_entry->shipp) {
int modelnum = Ship_info[target_ship_entry->shipp->ship_info_index].model_num;
aigp->dockee.index = model_find_dock_name_index(modelnum, aigp->dockee.name);
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
} else
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
}
if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
Int3(); // for now, allender wants to know about these things!!!!
Warning(LOCATION, "Cannot determine docking information for %s!", shipp->ship_name); // for now, allender wants to know about these things!!!!
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] )
if ( shipp->flags[Ship::Ship_Flags::Disabled] )
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);
Assert( sindex >= 0 );
object *goal_objp = &Objects[Ships[sindex].objnum];
if (!target_ship_entry || !target_ship_entry->shipp) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
auto goal_objp = target_ship_entry->objp;
// if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
// [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
@@ -1924,9 +1947,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// might happen too, so err on the safe side. (Yay for emergent paragraph justification!)
if ((aip->mode == AIM_DOCK) && (aip->submode >= AIS_UNDOCK_0))
{
// 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_achievability::NOT_KNOWN;
if ( target_ship_entry && target_ship_entry->shipp ) {
// only put it on hold if it's someone other than the guy we're undocking from right now!!
if (aip->goal_objnum != target_ship_entry->shipp->objnum)
return ai_achievability::NOT_KNOWN;
} else {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
}
} else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
@@ -1934,23 +1962,21 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
// the ship's subsystem list
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
sindex = ship_name_lookup( aigp->target_name );
if ( sindex != -1 ) {
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
if ( target_ship_entry && target_ship_entry->shipp ) {
aigp->ai_submode = ship_find_subsys( target_ship_entry->shipp, aigp->docker.name );
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
} else {
Int3();
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
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) ) {
object *ignored;
// for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
sindex = ship_name_lookup( aigp->target_name );
Assert( sindex != -1 ); // should be true because of above status
ignored = &Objects[Ships[sindex].objnum];
if (!target_ship_entry || !target_ship_entry->shipp) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
}
auto ignored = target_ship_entry->objp;
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
@@ -1966,7 +1992,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
case AI_GOAL_GUARD:
case AI_GOAL_GUARD_WING:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
@@ -1983,7 +2011,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
else if ( status == SHIP_STATUS_UNKNOWN )
return ai_achievability::NOT_KNOWN;
Int3(); // get allender -- bad logic
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, shipp->ship_name); // get allender -- bad logic
break;
}
@@ -1995,31 +2023,29 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
// we mark the goal as not achievable.
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
Int3(); // get Allender. this shouldn't happen!!!
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
return ai_achievability::NOT_ACHIEVABLE;
}
if ( status == SHIP_STATUS_GONE )
return ai_achievability::NOT_ACHIEVABLE;
sindex = ship_name_lookup( aigp->target_name );
if ( sindex < 0 ) {
Int3();
if ( !target_ship_entry || !target_ship_entry->shipp ) {
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
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] )
// if destination currently being repaired, then goal is still active
if ( Ai_info[target_ship_entry->shipp->ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
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())
if ( target_ship_entry->shipp->is_dying_or_departing())
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]) )
if ( !(Ai_info[target_ship_entry->shipp->ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
return ai_achievability::NOT_ACHIEVABLE;
// not repairing anything means that he can do this goal!!!
@@ -2034,14 +2060,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// 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 )
if ( aip->goal_objnum != target_ship_entry->shipp->objnum )
return ai_achievability::NOT_KNOWN;
return ai_achievability::ACHIEVABLE;
}
default:
Int3(); // invalid case in switch:
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode); // invalid case in switch:
}
return ai_achievability::NOT_KNOWN;
@@ -2315,12 +2341,6 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
}
case AI_GOAL_FLY_TO_SHIP:
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
ai_start_fly_to_ship(objp, shipnum);
break;
case AI_GOAL_DOCK: {
shipnum = ship_name_lookup( current_goal->target_name );
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
@@ -2395,22 +2415,27 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
// when destroying a subsystem, we can destroy a specific instance of a subsystem
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
// instances of a specific type
// when destroying a subsystem, we can destroy a specific instance of a subsystem
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
// instances of a specific type
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISARM_SHIP: {
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL: {
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
ai_attack_object( objp, other_obj);
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
// don't protect-ship for tactical goals
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
if (aip->target_objnum != -1) {
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
}
} else // Just in case this ship had been protected, unprotect it.
@@ -2488,14 +2513,17 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// labels for support ship commands
case AI_GOAL_STAY_NEAR_SHIP: {
case AI_GOAL_STAY_NEAR_SHIP:
case AI_GOAL_FLY_TO_SHIP:
{
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
ai_do_stay_near(objp, other_obj, dist);
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
ai_do_stay_near(objp, other_obj, dist, additional_data);
break;
}
}
case AI_GOAL_KEEP_SAFE_DISTANCE:
// todo MK: hook to keep support ship at a safe distance
@@ -2543,7 +2571,9 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_GUARD:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
case AI_GOAL_EVADE_SHIP:
@@ -2617,7 +2647,9 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
case AI_GOAL_DESTROY_SUBSYSTEM:
case AI_GOAL_GUARD:
case AI_GOAL_DISABLE_SHIP:
case AI_GOAL_DISABLE_SHIP_TACTICAL:
case AI_GOAL_DISARM_SHIP:
case AI_GOAL_DISARM_SHIP_TACTICAL:
case AI_GOAL_IGNORE:
case AI_GOAL_IGNORE_NEW:
case AI_GOAL_EVADE_SHIP:
+5 -3
View File
@@ -73,15 +73,17 @@ struct ai_info;
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
#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
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
#define AI_GOAL_LUA (1<<27) // 0x08000000
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
// now the masks for ship types
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
//WMC - Don't need these anymore. Whee!
/*
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
+162 -5
View File
@@ -18,9 +18,9 @@ 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) {
Player_orders.emplace_back(vm_strdup(order.parseText.c_str()), vm_strdup(order.displayText.c_str()), -1, sexp_op);
Player_orders.emplace_back(order.parseText, order.displayText, -1, sexp_op);
Player_orders.back().localize();
Lua_player_orders.emplace(sexp_op, std::move(order));
return true;
@@ -48,6 +48,134 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op) {
return &aiLuaOrder->second;
}
int ai_lua_get_num_general_orders() {
int count = 0;
for (const auto& order : Lua_player_orders) {
if (order.second.generalOrder) {
count++;
}
}
return count;
}
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
{
SCP_vector<SCP_string> list;
for (const auto& order : Lua_player_orders) {
const SCP_string &cat = order.second.category;
// If it's not a general order then move on
if (!order.second.generalOrder) {
continue;
}
// If the order is not enabled then move on
if (enabled_only && !order.second.cur_enabled) {
continue;
}
Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");
for (size_t i = 0; i <= list.size(); i++) {
// reached the end of the list, so add it
if (i == list.size()) {
list.push_back(cat);
break;
}
// if it's already in the list then don't add it
if (cat == list[i]) {
break;
}
}
}
return list;
}
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
{
SCP_vector<SCP_string> list;
for (auto order : Lua_player_orders) {
if (order.second.generalOrder) {
bool add = false;
// Only enabled orders
if (onlyEnabled && order.second.cur_enabled) {
add = true;
// Only valid orders
} else if (onlyValid && order.second.cur_valid) {
add = true;
// Only orders that match the category requested
} else if ((!category.empty()) && (order.second.category == category)) {
add = true;
// All general orders
} else {
add = true;
}
if (add) {
list.push_back(order.second.parseText);
}
}
}
return list;
}
int ai_lua_find_general_order_id(const SCP_string& name) {
for (const auto& order : Lua_player_orders) {
if (order.second.parseText == name) {
return order.first;
}
}
return -1;
}
void ai_lua_enable_general_order(int sexp_op, bool enable) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return;
else
aiLuaOrder->second.cur_enabled = enable;
}
void ai_lua_validate_general_order(int sexp_op, bool validity)
{
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return;
else
aiLuaOrder->second.cur_valid = validity;
}
void ai_lua_reset_general_orders() {
for (auto order : Lua_player_orders) {
ai_lua_enable_general_order(order.first, false);
ai_lua_validate_general_order(order.first, false);
}
}
bool ai_lua_is_general_order(int sexp_op) {
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
if (aiLuaOrder == Lua_player_orders.end())
return false;
return aiLuaOrder->second.generalOrder;
}
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
if (!action.isValid()) {
Error(LOCATION,
@@ -56,7 +184,11 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
}
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 (aip->shipnum >= 0){
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
} else {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
}
if (lua_ai.needsTarget) {
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
}
@@ -67,8 +199,13 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
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);
if (retVals[0].getValue<bool>()) {
// If we don't have a ship then it's a general order and we have nothing else to do
if (aip->shipnum >= 0) {
ai_mission_goal_complete(aip);
}
}
}
}
@@ -103,6 +240,26 @@ void ai_lua_start(ai_goal* aigp, object* objp){
run_ai_lua_action(action, lua_ai, aip);
}
// For sending general orders that don't run on a ship.
// Essentially just runs arbitrary lua script when the command is called
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
{
//Create a dummy aip to pass the target data
ai_info aip;
aip.shipnum = -1;
if (target_objnum >= 0) {
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
}
const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);
const auto& lua_ai_sexp = lua_ai->sexp;
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];
+13
View File
@@ -19,6 +19,10 @@ struct player_order_lua {
int ai_message = MESSAGE_YESSIR;
SCP_string parseText = "";
SCP_string displayText = "";
bool generalOrder = false;
SCP_string category = "";
bool cur_enabled = false;
bool cur_valid = false;
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;
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
};
@@ -29,8 +33,17 @@ 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);
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
int ai_lua_get_num_general_orders();
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
int ai_lua_find_general_order_id(const SCP_string& name);
void ai_lua_enable_general_order(int sexp_op, bool enable);
void ai_lua_validate_general_order(int sexp_op, bool validity);
void ai_lua_reset_general_orders();
bool ai_lua_is_general_order(int sexp_op);
void ai_lua(ai_info* aip);
void ai_lua_start(ai_goal* aigp, object* objp);
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
+1 -1
View File
@@ -1104,7 +1104,7 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
if ((sip->class_type >= 0) && (Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
int target_objnum = aip->target_objnum;
if (Objects[target_objnum].signature == aip->target_signature) {
+1 -1
View File
@@ -670,7 +670,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
* @param file_mapped Whether to use memory-mapped file or not.
*
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
* @return Pointer to anim that is loaded if sucess, NULL if failure.
* @return Pointer to anim that is loaded if success, NULL if failure.
*/
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
{
+1 -1
View File
@@ -1030,7 +1030,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
float dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
// if asteroid is within view or far enough away then wrap
if (dot > cos(Proj_fov)) {
if (dot > cos(g3_get_hfov(Proj_fov))) {
if (range_override) {
return true;
} else {
+1 -1
View File
@@ -1023,7 +1023,7 @@ void nav_warp(bool prewarp=false)
// retime collision pairs
if (Objects[Ships[i].objnum].flags[Object::Object_Flags::Collides])
obj_collide_retime_cached_pairs(&Objects[Ships[i].objnum]);
obj_collide_obj_cache_stale(&Objects[Ships[i].objnum]);
}
}
}
+2 -2
View File
@@ -598,7 +598,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
// make sure that we have valid data
if (data == nullptr) {
UNREACHABLE("No valid data recieved for 3D Bitmap creation!");
UNREACHABLE("No valid data received for 3D Bitmap creation!");
return -1;
}
@@ -2602,7 +2602,7 @@ void *bm_malloc(int n, size_t size) {
void bm_page_in_aabitmap(int handle, int nframes) {
int i;
if (handle == -1)
if (handle < 0)
return;
Assert(bm_get_entry(handle)->handle == handle);
+53 -21
View File
@@ -14,8 +14,8 @@
#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;
fov_t VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
fov_t COCKPIT_ZOOM_DEFAULT = 0.75f;
float Sexp_fov = 0.0f;
warp_camera Warp_camera;
@@ -27,6 +27,33 @@ SCP_vector<camera*> Cameras;
camid Current_camera;
camid Main_camera;
asymmetric_fov operator* (const asymmetric_fov& left, const float& right) {
return asymmetric_fov{ left.left * right, left.right * right, left.up * right, left.down * right };
}
asymmetric_fov operator+ (const asymmetric_fov& left, const float& right) {
float ar = (left.up - left.down) / (left.right - left.left);
return asymmetric_fov{ left.left - right * 0.5f, left.right + right * 0.5f, left.up + right * 0.5f * ar, left.down - right * 0.5f * ar };
}
asymmetric_fov operator- (const asymmetric_fov& left, const float& right) {
float ar = (left.up - left.down) / (left.right - left.left);
return asymmetric_fov{ left.left + right * 0.5f, left.right - right * 0.5f, left.up - right * 0.5f * ar, left.down + right * 0.5f * ar };
}
#define APPLY_TO_FOV_T(op, name) \
struct apply_##name##_to_fov { \
float r; \
template<typename T> \
fov_t operator()(const T& l) { \
return fov_t(l op r); \
} \
}; \
fov_t operator op (const fov_t& zoom, const float& scale) { \
return mpark::visit(apply_##name##_to_fov{scale}, zoom); \
}
APPLY_TO_FOV_T(*, mul)
APPLY_TO_FOV_T(+, add)
APPLY_TO_FOV_T(-, sub)
static SCP_string fov_display(float val)
{
auto degrees = fl_degrees(val);
@@ -34,15 +61,20 @@ static SCP_string fov_display(float val)
sprintf(out, u8"%.1f\u00B0", degrees);
return out;
}
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
.category("Graphics")
.range(0.436332f, 1.5708f)
.bind_to(&VIEWER_ZOOM_DEFAULT)
.display(fov_display)
.default_val(0.75f)
.level(options::ExpertLevel::Advanced)
.importance(60)
.finish();
auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
std::pair<const char*, int>{"Field Of View", 1703},
std::pair<const char*, int>{"The vertical field of view", 1704})
.category("Graphics")
.range(0.436332f, 1.5708f)
.change_listener([](const float& val, bool) {
VIEWER_ZOOM_DEFAULT = val;
return true;
})
.display(fov_display)
.default_val(0.75f)
.level(options::ExpertLevel::Advanced)
.importance(60)
.finish();
//*************************CLASS: camera*************************
//This is where the camera class begins! :D
@@ -85,7 +117,7 @@ void camera::reset()
func_custom_orientation = NULL;
fov.clear();
fov.set(VIEWER_ZOOM_DEFAULT);
fov.set(g3_get_hfov(VIEWER_ZOOM_DEFAULT));
pos_x.clear();
pos_y.clear();
@@ -104,7 +136,7 @@ void camera::set_name(const char *in_name)
strncpy(name, in_name, NAME_LENGTH-1);
}
void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
void camera::set_fov(fov_t in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
{
if(in_fov_time == 0.0f && in_fov_acceleration_time == 0.0f && in_fov_deceleration_time == 0.0f)
{
@@ -114,26 +146,23 @@ void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_
}
flags &= ~CAM_STATIONARY_FOV;
if(in_fov <= 0.0f)
if(g3_get_hfov(in_fov) <= 0.0f)
{
fov.setVD(in_fov_time, in_fov_acceleration_time, 0.0f);
}
fov.setAVD(in_fov, in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
fov.setAVD(g3_get_hfov(in_fov), in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
}
void camera::set_object_host(object *objp, int n_object_host_submodel)
{
if(objp == NULL)
object_host = object_h();
object_host = object_h(objp);
object_host_submodel = n_object_host_submodel;
set_custom_position_function(NULL);
set_custom_orientation_function(NULL);
if(n_object_host_submodel > 0)
{
if(objp->type == OBJ_SHIP)
if(objp != nullptr && objp->type == OBJ_SHIP)
{
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
@@ -319,11 +348,14 @@ int camera::get_object_target_submodel()
return object_target_submodel;
}
float camera::get_fov()
fov_t camera::get_fov()
{
if(!(flags & CAM_STATIONARY_FOV))
{
fov.get(&c_fov, NULL);
float fov_now;
fov.get(&fov_now, nullptr);
return fov_now;
//TODO enable moving asymmetric fov
}
return c_fov;
+18 -5
View File
@@ -10,6 +10,8 @@
#include <string>
#include <mpark/variant.hpp>
#define CAM_STATIONARY_FOV (1<<0)
#define CAM_STATIONARY_ORI (1<<1)
#define CAM_STATIONARY_POS (1<<2)
@@ -18,6 +20,17 @@
#define EXTERN_CAM_BBOX_CONSTANT_PADDING 5.0f
#define EXTERN_CAM_BBOX_MULTIPLIER_PADDING 1.5f
struct asymmetric_fov {
float left, right, up, down;
friend asymmetric_fov operator* (const asymmetric_fov&, const float&);
friend asymmetric_fov operator+ (const asymmetric_fov&, const float&);
friend asymmetric_fov operator- (const asymmetric_fov&, const float&);
};
using fov_t = mpark::variant<float, asymmetric_fov>;
fov_t operator* (const fov_t&, const float&);
fov_t operator+ (const fov_t&, const float&);
fov_t operator- (const fov_t&, const float&);
class camera
{
protected:
@@ -41,7 +54,7 @@ protected:
avd_movement ori[9];
//Cache stuff
float c_fov;
fov_t c_fov;
vec3d c_pos;
matrix c_ori;
public:
@@ -59,7 +72,7 @@ public:
void set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *pos));
void set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *ori));
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
void set_fov(fov_t in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
@@ -74,7 +87,7 @@ public:
int get_object_host_submodel();
object *get_object_target();
int get_object_target_submodel();
float get_fov();
fov_t get_fov();
void get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation = true);
//Is
@@ -155,8 +168,8 @@ public:
//Some global stuff
extern SCP_vector<subtitle> Subtitles;
extern float VIEWER_ZOOM_DEFAULT;
extern float COCKPIT_ZOOM_DEFAULT;
extern fov_t VIEWER_ZOOM_DEFAULT;
extern fov_t COCKPIT_ZOOM_DEFAULT;
extern float Sexp_fov;
//Helpful functions
+1 -1
View File
@@ -438,7 +438,7 @@ int cfile_flush_dir(int dir_type)
// filename = name of filename or filepath to process
// ext = extension to add. Must start with the period
// Returns: new filename or filepath with extension.
char *cf_add_ext(const char *filename, const char *ext)
const char *cf_add_ext(const char *filename, const char *ext)
{
static char path[MAX_PATH_LEN];
+1 -1
View File
@@ -171,7 +171,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
void cfile_close();
// add an extension to a filename if it doesn't already have it
char *cf_add_ext(const char *filename, const char *ext);
const char *cf_add_ext(const char *filename, const char *ext);
// return filename of a CFILE you called cfopen() successfully on.
const char *cf_get_filename(const CFILE *cfile);
+9 -2
View File
@@ -188,6 +188,7 @@ Flag exe_params[] =
//flag launcher text FSO on_flags off_flags category reference URL
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
@@ -406,6 +407,7 @@ cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
cmdline_parm deadzone("-deadzone",
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
@@ -414,6 +416,7 @@ int Cmdline_ship_choice_3d = 0;
int Cmdline_weapon_choice_3d = 0;
int Cmdline_autopilot_interruptable = 1;
int Cmdline_stretch_menu = 0;
bool Cmdline_capture_mouse = false;
int Cmdline_no_screenshake = 0;
int Cmdline_deadzone = -1;
@@ -835,7 +838,7 @@ void os_validate_parms(int argc, char *argv[])
// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
printf("Website: http://scp.indiegames.us\n");
printf("Website: https://scp.indiegames.us\n");
printf("Github (bug reporting): https://github.com/scp-fs2open/fs2open.github.com/issues\n\n");
printf("Usage: fs2_open [options]\n");
@@ -1646,7 +1649,7 @@ bool SetCmdlineParams()
// be sure that this string fits in our limits
if ( strlen(Cmdline_game_password) >= MAX_PASSWD_LEN ) {
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d charaters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d characters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
}
}
@@ -1871,6 +1874,10 @@ bool SetCmdlineParams()
if ( stretch_menu.found() ) {
Cmdline_stretch_menu = 1;
}
if ( capture_mouse.found() ) {
Cmdline_capture_mouse = true;
}
// new lighting lines
if ( ambient_power_arg.found() )
Cmdline_ambient_power = ambient_power_arg.get_float();
+1
View File
@@ -86,6 +86,7 @@ extern int Cmdline_ship_choice_3d;
extern int Cmdline_weapon_choice_3d;
extern int Cmdline_autopilot_interruptable;
extern int Cmdline_stretch_menu;
extern bool Cmdline_capture_mouse;
extern int Cmdline_no_screenshake;
extern int Cmdline_deadzone;
+8
View File
@@ -51,6 +51,14 @@ void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
objp->phys_info.max_vel.xyz.z = -25.0f;
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
// if this cmeasure has a single segment trail, let the trail know since we just changed the velocity
// yeah this is hacky but that's what this function gets for CHANGING the velocity on objects with a ""CONSTANT VELOCITY""
weapon* wp = &Weapons[objp->instance];
if (wp->trail_ptr && wp->trail_ptr->single_segment) {
wp->trail_ptr->vel[0] = objp->phys_info.vel;
wp->trail_ptr->vel[1] = objp->phys_info.vel;
}
}
/**
+5 -4
View File
@@ -1359,9 +1359,6 @@ bool control_config_accept(bool API_Access)
}
}
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
if (!API_Access) {
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
@@ -1630,7 +1627,7 @@ void control_config_close(bool API_Access)
Ui_window.destroy();
common_free_interface_palette(); // restore game palette
}
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
game_flush();
if (Game_mode & GM_MULTIPLAYER) {
@@ -2536,6 +2533,10 @@ void control_config_do_frame(float frametime)
if (List_buttons[i].pressed()) {
// Select the pressed line
Selected_line = i + Scroll_offset;
// Cyborg - Quick assertion for Coverity 1093701. Not likely to happen, but we check for a negative Selected Line later.
Assertion(Selected_line > -1, "control_config_do_frame() has somehow managed to get a negative Selected_line index of %d. Please get an SCP member.", Selected_line);
Selected_item = selItem::None;
List_buttons[i].get_mouse_pos(&x, &y);
+30 -26
View File
@@ -45,27 +45,29 @@ int Failed_key_index;
// Joystick configuration
int Joy_dead_zone_size = 10;
auto DeadZoneOption =
options::OptionBuilder<int>("Input.JoystickDeadZone", "Deadzone", "The deadzone of the selected joystick.")
.category("Input")
.range(0, 45)
.level(options::ExpertLevel::Beginner)
.default_val(10)
.bind_to(&Joy_dead_zone_size)
.importance(1)
.finish();
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
std::pair<const char*, int>{"Deadzone", 1377},
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
.category("Input")
.range(0, 45)
.level(options::ExpertLevel::Beginner)
.default_val(10)
.bind_to(&Joy_dead_zone_size)
.importance(1)
.finish();
int Joy_sensitivity = 9;
auto SensitivityOption =
options::OptionBuilder<int>("Input.JoystickSensitivity", "Sensitivity", "The sentitivity of the selected joystick.")
.category("Input")
.range(0, 9)
.level(options::ExpertLevel::Beginner)
.default_val(9)
.bind_to(&Joy_sensitivity)
.importance(2)
.finish();
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
std::pair<const char*, int>{"Sensitivity", 1745},
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
.category("Input")
.range(0, 9)
.level(options::ExpertLevel::Beginner)
.default_val(9)
.bind_to(&Joy_sensitivity)
.importance(2)
.finish();
//! arrays which hold the key mappings. The array index represents a key-independent action.
//! please use SPACES for aligning the fields of this array
@@ -158,8 +160,8 @@ void control_config_common_init_bindings() {
// flight controls (flight modes)
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 0, "Glide When Pressed", CC_TYPE_CONTINUOUS)
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 0, "Toggle Gliding", CC_TYPE_TRIGGER)
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
// flight controls (axes)
(JOY_HEADING_AXIS, JOY_X_AXIS, MOUSE_X_AXIS, SHIP_TAB, 1016, "Turn (Yaw) Axis", CC_TYPE_AXIS_REL)
@@ -173,7 +175,7 @@ void control_config_common_init_bindings() {
(FIRE_SECONDARY, KEY_SPACEBAR, 1, WEAPON_TAB, 1, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS)
(CYCLE_NEXT_PRIMARY, KEY_PERIOD, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Forward", CC_TYPE_TRIGGER)
(CYCLE_PREV_PRIMARY, KEY_COMMA, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Backward", CC_TYPE_TRIGGER)
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 0, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 1776, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
(CYCLE_SECONDARY, KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Forward", CC_TYPE_TRIGGER)
(CYCLE_NUM_MISSLES, KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER)
(LAUNCH_COUNTERMEASURE, KEY_X, 3, WEAPON_TAB, 1, "Launch Countermeasure", CC_TYPE_TRIGGER)
@@ -209,8 +211,8 @@ void control_config_common_init_bindings() {
(PADLOCK_DOWN, -1, 32, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
(PADLOCK_LEFT, -1, 34, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
(PADLOCK_RIGHT, -1, 35, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 0, "Top-Down View", CC_TYPE_TRIGGER)
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 0, "Target Padlock View", CC_TYPE_TRIGGER)
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 1777, "Top-Down View", CC_TYPE_TRIGGER)
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 1778, "Target Padlock View", CC_TYPE_TRIGGER)
(RADAR_RANGE_CYCLE, KEY_RAPOSTRO, -1, COMPUTER_TAB, 1, "Cycle Radar Range", CC_TYPE_TRIGGER)
(SQUADMSG_MENU, KEY_C, -1, COMPUTER_TAB, 1, "Communications Menu", CC_TYPE_TRIGGER)
@@ -235,8 +237,8 @@ void control_config_common_init_bindings() {
// Navigation and Autopilot
(SHOW_NAVMAP, -1, -1, NO_TAB, 1, "Show Nav Map", CC_TYPE_TRIGGER, true)
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 0, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 0, "Cycle Nav Points", CC_TYPE_TRIGGER)
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 1779, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 1780, "Cycle Nav Points", CC_TYPE_TRIGGER)
// Escort
(ADD_REMOVE_ESCORT, KEY_ALTED | KEY_E, -1, COMPUTER_TAB, 1, "Add or Remove Escort", CC_TYPE_TRIGGER)
@@ -258,7 +260,7 @@ void control_config_common_init_bindings() {
// HUD
(TOGGLE_HUD, KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, 1, "Toggle HUD", CC_TYPE_TRIGGER)
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 0, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
// Custom Controls
@@ -799,6 +801,8 @@ void control_config_common_init()
Mouse_button_text[6] = vm_strdup(XSTR("Wheel Down", 1656));
Mouse_button_text[7] = vm_strdup(XSTR("Wheel Left", 1657));
Mouse_button_text[8] = vm_strdup(XSTR("Wheel Right", 1658));
Script_system.OnStateDestroy.add([](lua_State*) -> void { Lua_hooks.clear(); });
}
/*
+1 -1
View File
@@ -108,7 +108,7 @@ class Decoder {
* @note A implementation should initialize the datastructures required for decoding here.
*
* @param fileName The name of the file that should be opened
* @return @c true if the initialization was successfull, @c false otherwise
* @return @c true if the initialization was successful, @c false otherwise
*/
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
+8 -3
View File
@@ -174,10 +174,15 @@ void determine_display_positions(Player* player, PlaybackState* state) {
void initialize_player_state(Player* player, PlaybackState* state) {
determine_display_positions(player, state);
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
if (!Movie_subtitle_font.empty()) {
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
}
else if (font::FontManager::numberOfFonts() > 0) {
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
}
}
+1 -1
View File
@@ -119,7 +119,7 @@
* half-rate linear filtering on GCN.
*
* If SMAA is applied to 64-bit color buffers, switching to point filtering
* when accesing them will increase the performance. Search for
* when accessing them will increase the performance. Search for
* 'SMAASamplePoint' to see which textures may benefit from point
* filtering, and where (which is basically the color input in the edge
* detection and resolve passes).
+27 -21
View File
@@ -3,8 +3,6 @@
#include "shadows.sdr" //! #include "shadows.sdr"
in vec3 beamVec;
in vec3 lightPosition;
out vec4 fragOut0;
uniform sampler2D ColorBuffer;
@@ -26,6 +24,13 @@ layout (std140) uniform globalDeferredData {
float invScreenWidth;
float invScreenHeight;
float nearPlane;
};
layout (std140) uniform matrixData {
mat4 modelViewMatrix;
mat4 projMatrix;
};
layout (std140) uniform lightData {
@@ -63,23 +68,24 @@ vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
vec3 centerToRay = max(dot(lightDir, reflectDir),sourceRadius) * reflectDir - lightDir;
return lightDir + centerToRay * clamp(sourceRadius/length(centerToRay), 0.0, 1.0);
}
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDir, out float attenuation, out float area_normalisation)
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDirOut, out float attenuation, out float area_normalisation)
{
if (lightType == LT_DIRECTIONAL) {
lightDir = normalize(lightPosition);
lightDirOut = normalize(lightDir);
attenuation = 1.0;
area_normalisation = 1.0;
} else {
vec3 lightPosition = modelViewMatrix[3].xyz;
// Positional light source
if (lightType == LT_POINT) {
lightDir = lightPosition - position.xyz;
float dist = length(lightDir);
lightDirOut = lightPosition - position.xyz;
float dist = length(lightDirOut);
// this chunk is unneccessary if sourceRadius= 0.0, but let's avoid a branch.
// given a sphere of radius sourceRadius centered at lightDir,
// move lightDir towards the ray defined by reflectDir
lightDir = ExpandLightSize(lightDir, reflectDir);
dist = length(lightDir);
// this chunk is unnecessary if sourceRadius= 0.0, but let's avoid a branch.
// given a sphere of radius sourceRadius centered at lightDirOut,
// move lightDirOut towards the ray defined by reflectDir
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
dist = length(lightDirOut);
// Energy conservation term
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
area_normalisation = alpha/alpha_adjust;
@@ -93,7 +99,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
}
else if (lightType == LT_TUBE) { // Tube light
vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
vec3 beamDir = normalize(beamVec);
//The actual 'lighting element' is shorter than the light volume cylinder
//To compensate the light is moved forward along the beam one radius and the length shortened
@@ -113,15 +119,15 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
vec3 r = d - a_t * dot(d, a_t) - c * dot(d,c);
float neardist = dot(r, r)/dot(b_t, r);
// Move along the beam by the distance we calculated
lightDir = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
lightDirOut = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
// Somebody with a symbolic expression simplifier or a wrinklier brain than me
// should figure out how to optimise these calcs - qaz
// this chunk is unneccessary if sourceRadius = 0.0, but let's avoid a branch.
// this chunk is unnecessary if sourceRadius = 0.0, but let's avoid a branch.
// Same principle as in LT_POINT, treat chosen location as a spherelight.
lightDir = ExpandLightSize(lightDir, reflectDir);
float dist = length(lightDir);
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
float dist = length(lightDirOut);
// Energy conservation term
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
area_normalisation = alpha/alpha_adjust;
@@ -134,9 +140,9 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
}
else if (lightType == LT_CONE) {
lightDir = lightPosition - position.xyz;
float coneDot = dot(normalize(-lightDir), coneDir);
float dist = length(lightDir);
lightDirOut = lightPosition - position.xyz;
float coneDot = dot(normalize(-lightDirOut), coneDir);
float dist = length(lightDirOut);
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
area_normalisation = 1.0;
@@ -155,7 +161,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
}
}
attenuation *= attenuation;
lightDir = normalize(lightDir);
lightDirOut = normalize(lightDirOut);
}
}
@@ -164,7 +170,7 @@ void main()
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
vec3 position = texture(PositionBuffer, screenPos).xyz;
if(abs(dot(position, position)) < 0.1)
if(abs(dot(position, position)) < nearPlane * nearPlane)
discard;
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
@@ -27,17 +27,11 @@ layout (std140) uniform lightData {
float sourceRadius;
};
out vec3 lightPosition;
out vec3 beamVec;
void main()
{
if (lightType == LT_DIRECTIONAL) {
gl_Position = vec4(vertPosition.xyz, 1.0);
lightPosition = lightDir;
} else {
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
lightPosition = modelViewMatrix[3].xyz;
if(lightType == LT_TUBE)
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ in vec4 fragTexCoord;
out vec4 fragOut0;
// Iteratively optimised points to give low discrepancy distribution on arbritrary hemisphere.
// Iteratively optimised points to give low discrepancy distribution on arbitrary hemisphere.
const vec3 points[128] = vec3[128](
vec3(-0.2268, 0.6185, 0.7523),
vec3( 0.9958, -0.0871, -0.0277),
+2 -2
View File
@@ -33,7 +33,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
// Cook-Torrance BRDF Model (Specular Reflection) = Distibution * Fresnel * Geometry / (4*dotNV*dotNL)
// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)
// Distribution Term - Trowbridge-Reitz GGX
@@ -49,7 +49,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
// Smith's method:
// Microsurfaces block light rays coming in from the light
// AND block light rays reflecting to the camera.
// Hence, model both seperately and multiply.
// Hence, model both separately and multiply.
float g1vNL = GeometrySchlickGGX(dotNL, k);
float g1vNV = GeometrySchlickGGX(dotNV, k);
float geometry = g1vNL * g1vNV;
+714
View File
@@ -0,0 +1,714 @@
-- Module options:
local always_try_using_lpeg = true
local register_global_module_table = false
local global_module_name = 'json'
--[==[
David Kolf's JSON module for Lua 5.1/5.2
Version 2.5
For the documentation see the corresponding readme.txt or visit
<http://dkolf.de/src/dkjson-lua.fsl/>.
You can contact the author by sending an e-mail to 'david' at the
domain 'dkolf.de'.
Copyright (C) 2010-2014 David Heiko Kolf
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]==]
-- global dependencies:
local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
local error, require, pcall, select = error, require, pcall, select
local floor, huge = math.floor, math.huge
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
string.rep, string.gsub, string.sub, string.byte, string.char,
string.find, string.len, string.format
local strmatch = string.match
local concat = table.concat
local json = { version = "dkjson 2.5" }
if register_global_module_table then
_G[global_module_name] = json
end
local _ENV = nil -- blocking globals in Lua 5.2
pcall (function()
-- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them.
local debmeta = require "debug".getmetatable
if debmeta then getmetatable = debmeta end
end)
json.null = setmetatable ({}, {
__tojson = function () return "null" end
})
local function isarray (tbl)
local max, n, arraylen = 0, 0, 0
for k,v in pairs (tbl) do
if k == 'n' and type(v) == 'number' then
arraylen = v
if v > max then
max = v
end
else
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
return false
end
if k > max then
max = k
end
n = n + 1
end
end
if max > 10 and max > arraylen and max > n * 2 then
return false -- don't create an array with too many holes
end
return true, max
end
local escapecodes = {
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
}
local function escapeutf8 (uchar)
local value = escapecodes[uchar]
if value then
return value
end
local a, b, c, d = strbyte (uchar, 1, 4)
a, b, c, d = a or 0, b or 0, c or 0, d or 0
if a <= 0x7f then
value = a
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
value = (a - 0xc0) * 0x40 + b - 0x80
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
else
return ""
end
if value <= 0xffff then
return strformat ("\\u%.4x", value)
elseif value <= 0x10ffff then
-- encode as UTF-16 surrogate pair
value = value - 0x10000
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
else
return ""
end
end
local function fsub (str, pattern, repl)
-- gsub always builds a new string in a buffer, even when no match
-- exists. First using find should be more efficient when most strings
-- don't contain the pattern.
if strfind (str, pattern) then
return gsub (str, pattern, repl)
else
return str
end
end
local function quotestring (value)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
if strfind (value, "[\194\216\220\225\226\239]") then
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
value = fsub (value, "\216[\128-\132]", escapeutf8)
value = fsub (value, "\220\143", escapeutf8)
value = fsub (value, "\225\158[\180\181]", escapeutf8)
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
value = fsub (value, "\239\187\191", escapeutf8)
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
end
return "\"" .. value .. "\""
end
json.quotestring = quotestring
local function replace(str, o, n)
local i, j = strfind (str, o, 1, true)
if i then
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
else
return str
end
end
-- locale independent num2str and str2num functions
local decpoint, numfilter
local function updatedecpoint ()
decpoint = strmatch(tostring(0.5), "([^05+])")
-- build a filter that can be used to remove group separators
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
end
updatedecpoint()
local function num2str (num)
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
end
local function str2num (str)
local num = tonumber(replace(str, ".", decpoint))
if not num then
updatedecpoint()
num = tonumber(replace(str, ".", decpoint))
end
return num
end
local function addnewline2 (level, buffer, buflen)
buffer[buflen+1] = "\n"
buffer[buflen+2] = strrep (" ", level)
buflen = buflen + 2
return buflen
end
function json.addnewline (state)
if state.indent then
state.bufferlen = addnewline2 (state.level or 0,
state.buffer, state.bufferlen or #(state.buffer))
end
end
local encode2 -- forward declaration
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
local kt = type (key)
if kt ~= 'string' and kt ~= 'number' then
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
end
if prev then
buflen = buflen + 1
buffer[buflen] = ","
end
if indent then
buflen = addnewline2 (level, buffer, buflen)
end
buffer[buflen+1] = quotestring (key)
buffer[buflen+2] = ":"
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
end
local function appendcustom(res, buffer, state)
local buflen = state.bufferlen
if type (res) == 'string' then
buflen = buflen + 1
buffer[buflen] = res
end
return buflen
end
local function exception(reason, value, state, buffer, buflen, defaultmessage)
defaultmessage = defaultmessage or reason
local handler = state.exception
if not handler then
return nil, defaultmessage
else
state.bufferlen = buflen
local ret, msg = handler (reason, value, state, defaultmessage)
if not ret then return nil, msg or defaultmessage end
return appendcustom(ret, buffer, state)
end
end
function json.encodeexception(reason, value, state, defaultmessage)
return quotestring("<" .. defaultmessage .. ">")
end
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
local valtype = type (value)
local valmeta = getmetatable (value)
valmeta = type (valmeta) == 'table' and valmeta -- only tables
local valtojson = valmeta and valmeta.__tojson
if valtojson then
if tables[value] then
return exception('reference cycle', value, state, buffer, buflen)
end
tables[value] = true
state.bufferlen = buflen
local ret, msg = valtojson (value, state)
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
tables[value] = nil
buflen = appendcustom(ret, buffer, state)
elseif value == nil then
buflen = buflen + 1
buffer[buflen] = "null"
elseif valtype == 'number' then
local s
if value ~= value or value >= huge or -value >= huge then
-- This is the behaviour of the original JSON implementation.
s = "null"
else
s = num2str (value)
end
buflen = buflen + 1
buffer[buflen] = s
elseif valtype == 'boolean' then
buflen = buflen + 1
buffer[buflen] = value and "true" or "false"
elseif valtype == 'string' then
buflen = buflen + 1
buffer[buflen] = quotestring (value)
elseif valtype == 'table' then
if tables[value] then
return exception('reference cycle', value, state, buffer, buflen)
end
tables[value] = true
level = level + 1
local isa, n = isarray (value)
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
isa = false
end
local msg
if isa then -- JSON array
buflen = buflen + 1
buffer[buflen] = "["
for i = 1, n do
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
if i < n then
buflen = buflen + 1
buffer[buflen] = ","
end
end
buflen = buflen + 1
buffer[buflen] = "]"
else -- JSON object
local prev = false
buflen = buflen + 1
buffer[buflen] = "{"
local order = valmeta and valmeta.__jsonorder or globalorder
if order then
local used = {}
n = #order
for i = 1, n do
local k = order[i]
local v = value[k]
if v then
used[k] = true
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
prev = true -- add a seperator before the next element
end
end
for k,v in pairs (value) do
if not used[k] then
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
prev = true -- add a seperator before the next element
end
end
else -- unordered
for k,v in pairs (value) do
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
prev = true -- add a seperator before the next element
end
end
if indent then
buflen = addnewline2 (level - 1, buffer, buflen)
end
buflen = buflen + 1
buffer[buflen] = "}"
end
tables[value] = nil
else
return exception ('unsupported type', value, state, buffer, buflen,
"type '" .. valtype .. "' is not supported by JSON.")
end
return buflen
end
function json.encode (value, state)
state = state or {}
local oldbuffer = state.buffer
local buffer = oldbuffer or {}
state.buffer = buffer
updatedecpoint()
local ret, msg = encode2 (value, state.indent, state.level or 0,
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
if not ret then
error (msg, 2)
elseif oldbuffer == buffer then
state.bufferlen = ret
return true
else
state.bufferlen = nil
state.buffer = nil
return concat (buffer)
end
end
local function loc (str, where)
local line, pos, linepos = 1, 1, 0
while true do
pos = strfind (str, "\n", pos, true)
if pos and pos < where then
line = line + 1
linepos = pos
pos = pos + 1
else
break
end
end
return "line " .. line .. ", column " .. (where - linepos)
end
local function unterminated (str, what, where)
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
end
local function scanwhite (str, pos)
while true do
pos = strfind (str, "%S", pos)
if not pos then return nil end
local sub2 = strsub (str, pos, pos + 1)
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
-- UTF-8 Byte Order Mark
pos = pos + 3
elseif sub2 == "//" then
pos = strfind (str, "[\n\r]", pos + 2)
if not pos then return nil end
elseif sub2 == "/*" then
pos = strfind (str, "*/", pos + 2)
if not pos then return nil end
pos = pos + 2
else
return pos
end
end
end
local escapechars = {
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
}
local function unichar (value)
if value < 0 then
return nil
elseif value <= 0x007f then
return strchar (value)
elseif value <= 0x07ff then
return strchar (0xc0 + floor(value/0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0xffff then
return strchar (0xe0 + floor(value/0x1000),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0x10ffff then
return strchar (0xf0 + floor(value/0x40000),
0x80 + (floor(value/0x1000) % 0x40),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
else
return nil
end
end
local function scanstring (str, pos)
local lastpos = pos + 1
local buffer, n = {}, 0
while true do
local nextpos = strfind (str, "[\"\\]", lastpos)
if not nextpos then
return unterminated (str, "string", pos)
end
if nextpos > lastpos then
n = n + 1
buffer[n] = strsub (str, lastpos, nextpos - 1)
end
if strsub (str, nextpos, nextpos) == "\"" then
lastpos = nextpos + 1
break
else
local escchar = strsub (str, nextpos + 1, nextpos + 1)
local value
if escchar == "u" then
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
if value then
local value2
if 0xD800 <= value and value <= 0xDBff then
-- we have the high surrogate of UTF-16. Check if there is a
-- low surrogate escaped nearby to combine them.
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
else
value2 = nil -- in case it was out of range for a low surrogate
end
end
end
value = value and unichar (value)
if value then
if value2 then
lastpos = nextpos + 12
else
lastpos = nextpos + 6
end
end
end
end
if not value then
value = escapechars[escchar] or escchar
lastpos = nextpos + 2
end
n = n + 1
buffer[n] = value
end
end
if n == 1 then
return buffer[1], lastpos
elseif n > 1 then
return concat (buffer), lastpos
else
return "", lastpos
end
end
local scanvalue -- forward declaration
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
local len = strlen (str)
local tbl, n = {}, 0
local pos = startpos + 1
if what == 'object' then
setmetatable (tbl, objectmeta)
else
setmetatable (tbl, arraymeta)
end
while true do
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
local char = strsub (str, pos, pos)
if char == closechar then
return tbl, pos + 1
end
local val1, err
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
char = strsub (str, pos, pos)
if char == ":" then
if val1 == nil then
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
end
pos = scanwhite (str, pos + 1)
if not pos then return unterminated (str, what, startpos) end
local val2
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
tbl[val1] = val2
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
char = strsub (str, pos, pos)
else
n = n + 1
tbl[n] = val1
end
if char == "," then
pos = pos + 1
end
end
end
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
pos = pos or 1
pos = scanwhite (str, pos)
if not pos then
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
end
local char = strsub (str, pos, pos)
if char == "{" then
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
elseif char == "[" then
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
elseif char == "\"" then
return scanstring (str, pos)
else
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
if pstart then
local number = str2num (strsub (str, pstart, pend))
if number then
return number, pend + 1
end
end
pstart, pend = strfind (str, "^%a%w*", pos)
if pstart then
local name = strsub (str, pstart, pend)
if name == "true" then
return true, pend + 1
elseif name == "false" then
return false, pend + 1
elseif name == "null" then
return nullval, pend + 1
end
end
return nil, pos, "no valid JSON value at " .. loc (str, pos)
end
end
local function optionalmetatables(...)
if select("#", ...) > 0 then
return ...
else
return {__jsontype = 'object'}, {__jsontype = 'array'}
end
end
function json.decode (str, pos, nullval, ...)
local objectmeta, arraymeta = optionalmetatables(...)
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
end
function json.use_lpeg ()
local g = require ("lpeg")
if g.version() == "0.11" then
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
end
local pegmatch = g.match
local P, S, R = g.P, g.S, g.R
local function ErrorCall (str, pos, msg, state)
if not state.msg then
state.msg = msg .. " at " .. loc (str, pos)
state.pos = pos
end
return false
end
local function Err (msg)
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
end
local SingleLineComment = P"//" * (1 - S"\n\r")^0
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
local PlainChar = 1 - S"\"\\\n\r"
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
local HexDigit = R("09", "af", "AF")
local function UTF16Surrogate (match, pos, high, low)
high, low = tonumber (high, 16), tonumber (low, 16)
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
else
return false
end
end
local function UTF16BMP (hex)
return unichar (tonumber (hex, 16))
end
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
local Char = UnicodeEscape + EscapeSequence + PlainChar
local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
local Fractal = P"." * R"09"^0
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
local SimpleValue = Number + String + Constant
local ArrayContent, ObjectContent
-- The functions parsearray and parseobject parse only a single value/pair
-- at a time and store them directly to avoid hitting the LPeg limits.
local function parsearray (str, pos, nullval, state)
local obj, cont
local npos
local t, nt = {}, 0
repeat
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
if not npos then break end
pos = npos
nt = nt + 1
t[nt] = obj
until cont == 'last'
return pos, setmetatable (t, state.arraymeta)
end
local function parseobject (str, pos, nullval, state)
local obj, key, cont
local npos
local t = {}
repeat
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
if not npos then break end
pos = npos
t[key] = obj
until cont == 'last'
return pos, setmetatable (t, state.objectmeta)
end
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
local Value = Space * (Array + Object + SimpleValue)
local ExpectedValue = Value + Space * Err "value expected"
ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
local DecodeValue = ExpectedValue * g.Cp ()
function json.decode (str, pos, nullval, ...)
local state = {}
state.objectmeta, state.arraymeta = optionalmetatables(...)
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
if state.msg then
return nil, state.pos, state.msg
else
return obj, retpos
end
end
-- use this function only once:
json.use_lpeg = function () return json end
json.using_lpeg = true
return json -- so you can get the module using json = require "dkjson".use_lpeg()
end
if always_try_using_lpeg then
pcall (json.use_lpeg)
end
return json
+29 -4
View File
@@ -1,5 +1,5 @@
#Ship types
#Ship types
$Name: Navbuoy
$Max Debris Speed: 200
$FF Multiplier: 1.0
@@ -12,6 +12,7 @@ $AI:
+Turrets attack this: YES
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
$Name: Sentry Gun
$Counts for Alone: YES
$On Hotkey List: YES
@@ -32,6 +33,7 @@ $AI:
+Turrets attack this: YES
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
$Name: Escape Pod
$Praise Destruction: YES
$On Hotkey List: YES
@@ -50,6 +52,7 @@ $AI:
+Turrets attack this: YES
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
$Name: Cargo
$Scannable: YES
$Max Debris Speed: 200
@@ -63,6 +66,7 @@ $Fog:
$AI:
+Passive docks: ( "cargo" )
$Vaporize Percent Chance: 0.0
$Name: Support
$Counts for Alone: YES
$Praise Destruction: YES
@@ -89,6 +93,7 @@ $AI:
+Active docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
;;WMC - Stealth ships always have another type, so this isn't used
$Name: Stealth
$Counts for Alone: YES
@@ -114,6 +119,7 @@ $AI:
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
$Name: Fighter
$Counts for Alone: YES
$Praise Destruction: YES
@@ -141,6 +147,7 @@ $AI:
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
$Name: Bomber
$Counts for Alone: YES
$Praise Destruction: YES
@@ -168,7 +175,8 @@ $AI:
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
$Name: Fighter/bomber
$Counts for Alone: YES
$Praise Destruction: YES
@@ -195,6 +203,7 @@ $AI:
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Vaporize Percent Chance: 0.0
$Name: Transport
$Counts for Alone: YES
$Praise Destruction: YES
@@ -204,6 +213,7 @@ $Show Attack Direction: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 2.0
$Warp Sound Range Multiplier: 6.0
$Beams Easily Hit: YES
$Protected on cripple: YES
$Fog:
@@ -223,6 +233,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Freighter
$Counts for Alone: YES
$Praise Destruction: YES
@@ -233,6 +244,7 @@ $Scannable: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 1.75
$Warp Sound Range Multiplier: 6.0
$Beams Easily Hit: YES
$Protected on cripple: YES
$Fog:
@@ -253,6 +265,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: AWACS
$Counts for Alone: YES
$Praise Destruction: YES
@@ -262,6 +275,7 @@ $Show Attack Direction: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 0.8
$Warp Sound Range Multiplier: 6.0
$Beams Easily Hit: YES
$Protected on cripple: YES
$Fog:
@@ -281,6 +295,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Gas Miner
$Counts for Alone: YES
$Praise Destruction: YES
@@ -290,6 +305,7 @@ $Show Attack Direction: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 1.0
$Warp Sound Range Multiplier: 6.0
$Beams Easily Hit: YES
$Protected on cripple: YES
$Fog:
@@ -309,6 +325,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Cruiser
$Counts for Alone: YES
$Praise Destruction: YES
@@ -318,6 +335,7 @@ $Show Attack Direction: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 0.9
$Warp Sound Range Multiplier: 6.0
$Beams Easily Hit: YES
$Protected on cripple: YES
$Fog:
@@ -337,6 +355,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Corvette
$Counts for Alone: YES
$Praise Destruction: YES
@@ -346,6 +365,7 @@ $Show Attack Direction: YES
$Max Debris Speed: 150
$FF Multiplier: 1.0
$EMP Multiplier: 0.3333
$Warp Sound Range Multiplier: 6.0
$Beams Easily Hit: YES
$Protected on cripple: YES
$Fog:
@@ -365,6 +385,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Capital
$Counts for Alone: YES
$Praise Destruction: YES
@@ -394,6 +415,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Super Cap
$Counts for Alone: YES
$Praise Destruction: YES
@@ -421,6 +443,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Drydock
$Counts for Alone: YES
$Praise Destruction: YES
@@ -446,6 +469,7 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Knossos Device
$Counts for Alone: YES
$Praise Destruction: YES
@@ -469,4 +493,5 @@ $AI:
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
#End
#End
+1 -1
View File
@@ -311,7 +311,7 @@ static char* GetFilePart(char *source)
SCP_string safe_string;
// Entry point into the main exception handling routine. This routine is put into an except()
// statment at the beginning of a thread and is called anytime that there is a program exception
// statement at the beginning of a thread and is called anytime that there is a program exception
// The data is stored in a file called ErrorLog.txt in the data directory.
//
// data: pointer to the exception data
+36 -29
View File
@@ -48,44 +48,51 @@ bool fireballs_parsed = false;
bool Fireball_use_3d_warp = false;
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp", "3D Warp", "Use a 3D model for warp effects")
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Fireball_use_3d_warp)
.importance(65)
.finish();
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp",
std::pair<const char*, int>{"3D Warp", 1770},
std::pair<const char*, int>{"Use a 3D model for warp effects", 1771})
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Fireball_use_3d_warp)
.importance(65)
.finish();
/**
* Play warp in sound for warp effect
*/
void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
{
gamesnd_id sound_index;
float range_multiplier = 1.0f;
object *fireball_objp;
Assert((fb != NULL) && (fb->objnum >= 0));
if((fb == NULL) || (fb->objnum < 0)){
return;
}
fireball_objp = &Objects[fb->objnum];
auto fireball_objp = &Objects[fb->objnum];
auto sound_index = gamesnd_id(GameSounds::WARP_IN);
sound_index = gamesnd_id(GameSounds::WARP_IN);
if(fb->warp_open_sound_index.isValid()) {
if (fb->warp_open_sound_index.isValid()) {
sound_index = fb->warp_open_sound_index;
} else if ((ship_class >= 0) && (ship_class < ship_info_size())) {
if ( Ship_info[ship_class].is_huge_ship() ) {
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_IN);
fb->flags |= FBF_WARP_CAPITAL_SIZE;
} else if ( Ship_info[ship_class].is_big_ship() ) {
range_multiplier = 6.0f;
fb->flags |= FBF_WARP_CRUISER_SIZE;
}
}
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
if (ship_class >= 0 && ship_class < ship_info_size()) {
if (Ship_info[ship_class].is_huge_ship()) {
fb->flags |= FBF_WARP_CAPITAL_SIZE;
} else if (Ship_info[ship_class].is_big_ship()) {
fb->flags |= FBF_WARP_CRUISER_SIZE;
}
// originally 6.0 for SIF_BIG_SHIP and 1.0 for everything else
if (Ship_info[ship_class].class_type >= 0)
fb->warp_sound_range_multiplier = Ship_types[Ship_info[ship_class].class_type].warp_sound_range_multiplier;
else
fb->warp_sound_range_multiplier = 1.0f;
}
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
}
/**
@@ -93,15 +100,14 @@ void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
*/
void fireball_play_warphole_close_sound(fireball *fb)
{
gamesnd_id sound_index;
Assert((fb != NULL) && (fb->objnum >= 0));
if((fb == NULL) || (fb->objnum < 0)){
return;
}
auto fireball_objp = &Objects[fb->objnum];
auto sound_index = gamesnd_id(GameSounds::WARP_OUT);
object *fireball_objp;
fireball_objp = &Objects[fb->objnum];
sound_index = gamesnd_id(GameSounds::WARP_OUT);
if ( fb->warp_close_sound_index.isValid() ) {
if (fb->warp_close_sound_index.isValid()) {
sound_index = fb->warp_close_sound_index;
} else if ( fb->flags & FBF_WARP_CAPITAL_SIZE ) {
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_OUT);
@@ -109,7 +115,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
return;
}
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0F, SND_PRIORITY_SINGLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
}
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
@@ -845,6 +851,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
new_fireball->warp_close_sound_index = warp_close_sound;
new_fireball->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
new_fireball->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
new_fireball->warp_sound_range_multiplier = 1.0f;
matrix orient;
if(orient_override != NULL){
+3 -2
View File
@@ -40,8 +40,6 @@ class asteroid_info;
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
#define MAX_FIREBALLS 200
extern int fireball_used[MAX_FIREBALL_TYPES];
// all this moved here by Goober5000 because it makes more sense in the H file
@@ -94,6 +92,9 @@ typedef struct fireball {
gamesnd_id warp_close_sound_index;
float warp_open_duration;
float warp_close_duration;
// the sound multiplier is based on the ship class, but we lose that while the warp is closing
float warp_sound_range_multiplier;
} fireball;
// end move
+9 -7
View File
@@ -24,13 +24,15 @@
bool Fireball_warp_flash = false;
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash", "Warp Flash", "Show flash upon warp open or close")
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to_once(&Fireball_warp_flash)
.importance(65)
.finish();
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash",
std::pair<const char*, int>{"Warp Flash", 1768},
std::pair<const char*, int>{"Show flash upon warp open or close", 1769})
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to_once(&Fireball_warp_flash)
.importance(65)
.finish();
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
{
+3 -2
View File
@@ -16,6 +16,7 @@
#include "gamesnd/gamesnd.h"
#include "globalincs/alphacolors.h"
#include "io/key.h"
#include "mission/missionmessage.h"
#include "missionui/missionscreencommon.h"
#include "sound/audiostr.h"
#include "ui/ui.h"
@@ -516,8 +517,7 @@ void gameplay_help_leave()
// unpause all game sounds
weapon_unpause_sounds();
audiostream_unpause_all();
Help_text.clear();
message_resume_all();
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
game_flush();
@@ -633,6 +633,7 @@ void gameplay_help_do_frame(float /*frametime*/)
// make sure game sounds are paused
weapon_pause_sounds();
audiostream_pause_all();
message_pause_all();
k = Ui_window.process() & ~KEY_DEBUGGED;
gameplay_help_process_key(k);
+94 -44
View File
@@ -45,13 +45,15 @@ static bool music_volume_change_listener(float new_val, bool /*initial*/)
return true;
}
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music", "Music", "Volume used for playing music")
.category("Audio")
.default_val(Default_music_volume)
.range(0.0f, 1.0f)
.change_listener(music_volume_change_listener)
.importance(1)
.finish();
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music",
std::pair<const char*, int>{"Music", 1371},
std::pair<const char*, int>{"Volume used for playing music", 1760})
.category("Audio")
.default_val(Default_music_volume)
.range(0.0f, 1.0f)
.change_listener(music_volume_change_listener)
.importance(1)
.finish();
typedef struct tagSNDPATTERN {
int default_next_pattern; // Needed so the next_pattern member can be reset
@@ -257,6 +259,19 @@ SCP_vector<menu_music> Spooled_music;
int Mission_music[NUM_SCORES];
bool event_music_pattern_is_skippable(const SOUNDTRACK_PATTERN_INFO &pattern)
{
// check for blank or "none"
if (pattern.fname[0] == '\0' || !strnicmp(pattern.fname, NOX("none.wav"), 4))
return true;
// no content means this pattern isn't intended to play
if (pattern.num_measures == 0 || pattern.samples_per_measure == 0)
return true;
return false;
}
// -------------------------------------------------------------------------------------------------
// event_music_init()
//
@@ -289,6 +304,51 @@ void event_music_init()
// look for any modular tables
parse_modular_table(NOX("*-mus.tbm"), event_music_parse_musictbl);
// now that we've parsed everything, check the validity
for (auto &soundtrack : Soundtracks)
{
bool all_patterns_valid = true;
// Goober5000 - set the valid flag according to whether we can load all our patterns
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
for (int i = 0; i < soundtrack.num_patterns; i++)
{
auto filename = soundtrack.patterns[i].fname;
// some patterns aren't played for various legitimate reasons
if (event_music_pattern_is_skippable(soundtrack.patterns[i]))
continue;
// check for negative numbers (zero is allowed)
if (soundtrack.patterns[i].num_measures < 0 || soundtrack.patterns[i].samples_per_measure < 0)
{
Warning(LOCATION, "Soundtrack file %s has a negative 'num_measures' or 'samples_per_measure'; this is not allowed", soundtrack.patterns[i].fname);
all_patterns_valid = false;
break;
}
// check for file with exact extension
// (since event music specifies samples and measures, the audio format is important; so we don't want to assume any format will work)
if (!cf_exists_full(filename, CF_TYPE_MUSIC))
{
#ifndef NDEBUG
// see if the file exists with a different extension
auto res = cf_find_file_location_ext(filename, NUM_AUDIO_EXT, audio_ext_list, CF_TYPE_MUSIC);
if (res.found)
Warning(LOCATION, "Soundtrack file %s was not found with its specified extension, but another file %s exists in the modpack. Please update the extension and adjust audio specifications if necessary.", filename, res.name_ext.c_str());
#endif
Warning(LOCATION, "One or more files in '%s' could not be loaded. The soundtrack will not be used.", soundtrack.name);
all_patterns_valid = false;
break;
}
}
if (all_patterns_valid)
soundtrack.flags |= EMF_VALID;
}
Event_music_inited = TRUE;
Event_music_begun = FALSE;
@@ -410,7 +470,7 @@ void event_music_do_frame()
// start off the music delayed
if ( timestamp_elapsed(Pattern_timer_id) ) {
Pattern_timer_id = TIMESTAMP::invalid();
Pattern_timer_id = TIMESTAMP::never();
Event_music_begun = TRUE;
if ( Current_pattern != -1 && Patterns[Current_pattern].handle >= 0) {
//WMC - removed in favor of if
@@ -544,14 +604,14 @@ void event_music_level_start(int force_soundtrack)
if (force_soundtrack != -1)
Current_soundtrack_num = force_soundtrack;
// Check that soundtrack index is in range, except that < 0 means no soundtrack
if (Current_soundtrack_num < 0)
{
Pattern_timer_id = TIMESTAMP::never(); // update the timestamp as if a soundtrack did start
return;
}
Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < (int)Soundtracks.size());
if (Current_soundtrack_num < 0 || Current_soundtrack_num > (int)Soundtracks.size())
Assert(Current_soundtrack_num < (int)Soundtracks.size());
if (Current_soundtrack_num >= (int)Soundtracks.size())
return;
strack = &Soundtracks[Current_soundtrack_num];
@@ -564,7 +624,7 @@ 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->patterns[i].fname, NOX("none.wav"), 4))
if (event_music_pattern_is_skippable(strack->patterns[i]))
{
Patterns[i].handle = -1;
continue;
@@ -644,7 +704,9 @@ void event_music_first_pattern()
// if we really are initializing the level
if (Missiontime == 0) {
Pattern_timer_id = TIMESTAMP::invalid(); // don't let this start quite yet; see event_music_set_start_delay()
} else {
}
// don't step on a timestamp in progress; only set it if it has elapsed at least once already
else if (Pattern_timer_id.isNever()) {
Pattern_timer_id = TIMESTAMP::immediate(); // start immediately
}
@@ -1166,9 +1228,6 @@ void parse_soundtrack()
int i, strack_idx = -1;
bool nocreate = false;
//Start parsing soundtrack
//required_string("#Soundtrack Start");
//Get the name, and do we have this track already?
required_string("$SoundTrack Name:");
stuff_string(namebuf, F_NAME, NAME_LENGTH);
@@ -1284,23 +1343,6 @@ void parse_soundtrack()
//We're done here.
required_string("#SoundTrack End");
// Goober5000 - set the valid flag according to whether we can load all our patterns
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
for (i = 0; i < Soundtracks[strack_idx].num_patterns; i++)
{
// check for "none"
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_ext(Soundtracks[strack_idx].patterns[i].fname, CF_TYPE_MUSIC, NUM_AUDIO_EXT, audio_ext_list))
return;
}
// made it here okay, so it's valid
Soundtracks[strack_idx].flags |= EMF_VALID;
}
void parse_menumusic()
@@ -1579,7 +1621,7 @@ int hostile_ships_present()
// NOTE: callers to this function are advised to allocate a 256 byte buffer
void event_music_get_info(char *outbuf)
{
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 || Current_pattern < 0 ) {
strcpy(outbuf,XSTR( "Event music is not playing", 213));
}
else {
@@ -1598,7 +1640,7 @@ int event_music_next_soundtrack(int delta)
{
int new_soundtrack;
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Soundtracks.empty() ) {
return -1;
}
@@ -1631,7 +1673,7 @@ void event_sexp_change_soundtrack(const char *name)
}
event_music_level_close();
Current_soundtrack_num = -1;
Current_soundtrack_num = -1;
event_music_level_start(new_soundtrack);
}
@@ -1642,7 +1684,7 @@ void event_sexp_change_soundtrack(const char *name)
// NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
void event_music_get_soundtrack_name(char *outbuf)
{
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 ) {
strcpy(outbuf, XSTR( "Event music is not playing", 213));
}
else {
@@ -1653,11 +1695,15 @@ void event_music_get_soundtrack_name(char *outbuf)
// set the current soundtrack based on name
void event_music_set_soundtrack(const char *name)
{
Current_soundtrack_num = event_music_get_soundtrack_index(name);
int index = event_music_get_soundtrack_index(name);
if ( Current_soundtrack_num == -1 ) {
if (index >= 0 && Soundtracks[index].flags & EMF_VALID)
Current_soundtrack_num = index;
else
Current_soundtrack_num = -1;
if (Current_soundtrack_num == -1)
mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
}
}
int event_music_get_soundtrack_index(const char *name)
@@ -1674,7 +1720,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
// find the correct index for the spooled music
for ( int i = 0; i < (int)Spooled_music.size(); i++ ) {
if ( !stricmp(name, Spooled_music[i].name) ) {
return i;
@@ -1694,8 +1740,12 @@ void event_music_set_score(int score_index, const char *name)
{
Assert(score_index < NUM_SCORES);
// find the correct index for the event music
Mission_music[score_index] = event_music_get_spooled_music_index(name);
int index = event_music_get_spooled_music_index(name);
if (index >= 0 && Spooled_music[index].flags & SMF_VALID)
Mission_music[score_index] = index;
else
Mission_music[score_index] = -1;
}
// reset what sort of music is to be used for this mission
+6 -5
View File
@@ -74,15 +74,16 @@ extern SCP_vector<menu_music> Spooled_music;
// event music soundtrack storage
typedef struct tagSOUNDTRACK_PATTERN_INFO {
char fname[MAX_FILENAME_LEN];
float num_measures;
int samples_per_measure;
} SOUNDTRACK_PATTERN_INFO;
typedef struct tagSOUNDTRACK_INFO {
int flags;
int num_patterns;
char name[NAME_LENGTH];
struct {
char fname[MAX_FILENAME_LEN];
float num_measures;
int samples_per_measure;
} patterns[MAX_PATTERNS];
SOUNDTRACK_PATTERN_INFO patterns[MAX_PATTERNS];
} SOUNDTRACK_INFO;
// Goober5000 - event music flags
+14
View File
@@ -100,6 +100,20 @@ class flagset {
return *this;
}
template<typename TIter>
flagset<T>& set_multiple_from_source(const flagset<T>& source, TIter begin, TIter end) {
auto current = begin;
while (current != end) {
if (source[*current]) {
set(*current, true);
}
current = std::next(current);
}
return *this;
}
flagset<T>& remove(T idx) {
return set(idx, false);
}
+74 -42
View File
@@ -245,57 +245,89 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
// Global used to access detail levels in game and libs
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
{ 1, "Low" },
{ 2, "Medium" },
{ 3, "High" },
{ 4, "Ultra" }, };
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
{ 1, {"Low", 1161}},
{ 2, {"Medium", 1162}},
{ 3, {"High", 1163}},
{ 4, {"Ultra", 1721}}};
const auto ModelDetailOption __UNUSED =
options::OptionBuilder<int>("Graphics.Detail", "Model Detail", "Detail level of models").importance(8).category(
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
Detail.detail_distance = val;
return true;
}).finish();
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
std::pair<const char*, int>{"Model Detail", 1739},
std::pair<const char*, int>{"Detail level of models", 1740})
.importance(8)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool) {
Detail.detail_distance = val;
return true;
})
.finish();
const auto TexturesOption __UNUSED = options::OptionBuilder<int>("Graphics.Texture",
"3D Hardware Textures",
"Level of detail of textures").importance(6).category("Graphics").values(
DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
Detail.hardware_textures = val;
return true;
}).finish();
std::pair<const char*, int>{"3D Hardware Textures", 1362},
std::pair<const char*, int>{"Level of detail of textures", 1720})
.importance(6)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool) {
Detail.hardware_textures = val;
return true;
})
.finish();
const auto ParticlesOption __UNUSED = options::OptionBuilder<int>("Graphics.Particles",
"Particles",
"Level of detail for particles").importance(5).category(
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
Detail.num_particles = val;
return true;
}).finish();
std::pair<const char*, int>{"Particles", 1363},
std::pair<const char*, int>{"Level of detail for particles", 1717})
.importance(5)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool) {
Detail.num_particles = val;
return true;
})
.finish();
const auto SmallDebrisOption __UNUSED =
options::OptionBuilder<int>("Graphics.SmallDebris", "Impact Effects", "Level of detail of impact effects").category(
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).importance(4).change_listener([](int val,
bool) {
Detail.num_small_debris = val;
return true;
}).finish();
const auto SmallDebrisOption __UNUSED = options::OptionBuilder<int>("Graphics.SmallDebris",
std::pair<const char*, int>{"Impact Effects", 1364},
std::pair<const char*, int>{"Level of detail of impact effects", 1743})
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.importance(4)
.change_listener([](int val,bool) {
Detail.num_small_debris = val;
return true;
})
.finish();
const auto ShieldEffectsOption __UNUSED = options::OptionBuilder<int>("Graphics.ShieldEffects",
"Shield Hit Effects",
"Level of detail of shield impacts").importance(3).category(
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
Detail.shield_effects = val;
return true;
}).finish();
std::pair<const char*, int>{"Shield Hit Effects", 1718},
std::pair<const char*, int>{"Level of detail of shield impacts", 1719})
.importance(3)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool) {
Detail.shield_effects = val;
return true;
})
.finish();
const auto StarsOption __UNUSED =
options::OptionBuilder<int>("Graphics.Stars", "Stars", "Number of stars in the mission").importance(2).category(
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
Detail.num_stars = val;
return true;
}).finish();
const auto StarsOption __UNUSED = options::OptionBuilder<int>("Graphics.Stars",
std::pair<const char*, int>{"Stars", 1366},
std::pair<const char*, int>{"Number of stars in the mission", 1698})
.importance(2)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool) {
Detail.num_stars = val;
return true;
})
.finish();
// Call this with:
// 0 - lowest
+48 -32
View File
@@ -53,41 +53,10 @@ version parse_version() {
return v;
}
version parse_version_inline() {
version v;
SCP_string input;
stuff_string(input, F_RAW);
size_t start_pos = 0;
size_t end_pos = input.find('.');
v.major = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
if (end_pos == SCP_string::npos)
return v;
start_pos = end_pos + 1;
end_pos = input.find('.', start_pos);
v.minor = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
if (end_pos == SCP_string::npos)
return v;
start_pos = end_pos + 1;
end_pos = input.find('.', start_pos);
v.build = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
if (end_pos == SCP_string::npos)
return v;
start_pos = end_pos + 1;
end_pos = input.find('.', start_pos);
v.revision = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
return v;
return version(std::move(input), 0);
}
version get_executable_version() {
version v;
@@ -102,6 +71,53 @@ version get_executable_version() {
version::version(int major_in, int minor_in, int build_in, int revision_in) :
major(major_in), minor(minor_in), build(build_in), revision(revision_in) {
}
version::version(const SCP_string& semver, int missing) : major(missing), minor(missing), build(missing), revision(missing) {
int i = 0;
auto str = semver;
int has_fields = 0;
while (i <= 4) {
size_t pos = str.find_first_of('.');
SCP_string ver;
if (pos != SCP_string::npos) {
ver = str.substr(0, pos);
str.erase(0, pos + 1);
}
else {
ver = str;
str.clear();
}
if (!ver.empty() && std::find_if(ver.begin(), ver.end(), [](char c) { return !std::isdigit(c, SCP_default_locale); }) == ver.end()) {
switch (has_fields) {
case 0:
major = std::stoi(ver.c_str());
++has_fields;
break;
case 1:
minor = std::stoi(ver.c_str());
++has_fields;
break;
case 2:
build = std::stoi(ver.c_str());
++has_fields;
break;
case 3:
revision = std::stoi(ver.c_str());
++has_fields;
break;
default:
UNREACHABLE("Version parsing broken, get a coder!");
break;
}
}
else
break; //Break out of the loop if the first string is not a digit.
i++;
}
}
bool version::isValid() const { return major != 0 || minor != 0 || build != 0 || revision != 0; }
bool version::operator<(const version& v) const {
+2
View File
@@ -57,6 +57,8 @@ struct version {
version(int major, int minor = 0, int build = 0, int revision = 0);
version(const SCP_string& semver, int missing = -1);
bool isValid() const;
bool operator<(const version& other) const;
+138 -128
View File
@@ -112,35 +112,38 @@ static bool gamma_change_listener(float new_val, bool initial)
return true;
}
static auto GammaOption __UNUSED =
options::OptionBuilder<float>("Graphics.Gamma", "Brightness", "The brighness value used for the game window")
.category("Graphics")
.default_val(1.0f)
.enumerator(gamma_value_enumerator)
.display(gamma_display)
.change_listener(gamma_change_listener)
.finish();
static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma",
std::pair<const char*, int>{"Brightness", 1375},
std::pair<const char*, int>{"The brightness value used for the game window", 1738})
.category("Graphics")
.default_val(1.0f)
.enumerator(gamma_value_enumerator)
.display(gamma_display)
.change_listener(gamma_change_listener)
.finish();
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
{ 1, "Low" },
{ 2, "Medium" },
{ 3, "High" },
{ 4, "Ultra" }, };
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
{ 1, {"Low", 1161}},
{ 2, {"Medium", 1162}},
{ 3, {"High", 1163}},
{ 4, {"Ultra", 1721}}};
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting", "Lighting", "Level of detail of the lighting")
.importance(1)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool initial) {
Detail.lighting = val;
if (!initial) {
gr_recompile_all_shaders(nullptr);
}
return true;
})
.finish();
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting",
std::pair<const char*, int>{"Lighting", 1367},
std::pair<const char*, int>{"Level of detail of the lighting", 1715})
.importance(1)
.category("Graphics")
.values(DetailLevelValues)
.default_val(MAX_DETAIL_LEVEL)
.change_listener([](int val, bool initial) {
Detail.lighting = val;
if (!initial) {
gr_recompile_all_shaders(nullptr);
}
return true;
})
.finish();
os::ViewportState Gr_configured_window_state = os::ViewportState::Windowed;
@@ -162,17 +165,18 @@ static bool mode_change_func(os::ViewportState state, bool initial)
return true;
}
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
"Controls how the game window is created.")
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.values({{os::ViewportState::Fullscreen, "Fullscreen"},
{os::ViewportState::Borderless, "Borderless"},
{os::ViewportState::Windowed, "Windowed"}})
.importance(98)
.default_val(os::ViewportState::Fullscreen)
.change_listener(mode_change_func)
.finish();
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode",
std::pair<const char*, int>{"Window Mode", 1772},
std::pair<const char*, int>{"Controls how the game window is created", 1773})
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.values({{os::ViewportState::Fullscreen, {"Fullscreen", 1679}},
{os::ViewportState::Borderless, {"Borderless", 1675}},
{os::ViewportState::Windowed, {"Windowed", 1676}}})
.importance(98)
.default_val(os::ViewportState::Fullscreen)
.change_listener(mode_change_func)
.finish();
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, tl::nullopt, CHA_ONFRAME);
@@ -188,6 +192,7 @@ int gr_stencil_mode = 0;
// Default clipping distances
const float Default_min_draw_distance = 1.0f;
const float Default_max_draw_distance = 1e10;
float Min_draw_distance_cockpit = 0.02f;
float Min_draw_distance = Default_min_draw_distance;
float Max_draw_distance = Default_max_draw_distance;
@@ -251,18 +256,19 @@ static bool videodisplay_change(int display, bool initial)
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
return true;
}
static auto VideoDisplayOption =
options::OptionBuilder<int>("Graphics.Display", "Primary display", "The display used for rendering.")
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.deserializer(videodisplay_deserializer)
.serializer(videodisplay_serializer)
.enumerator(videodisplay_enumerator)
.display(videodisplay_display)
.default_val(0)
.change_listener(videodisplay_change)
.importance(99)
.finish();
static auto VideoDisplayOption = options::OptionBuilder<int>("Graphics.Display",
std::pair<const char*, int>{"Primary display", 1741},
std::pair<const char*, int>{"The display used for rendering", 1742})
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.deserializer(videodisplay_deserializer)
.serializer(videodisplay_serializer)
.enumerator(videodisplay_enumerator)
.display(videodisplay_display)
.default_val(0)
.change_listener(videodisplay_change)
.importance(99)
.finish();
struct ResolutionInfo {
uint32_t width = 0;
@@ -359,80 +365,83 @@ static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
}
*/
}
static auto ResolutionOption =
options::OptionBuilder<ResolutionInfo>("Graphics.Resolution", "Resolution", "The rendering resolution.")
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.deserializer(resolution_deserializer)
.serializer(resolution_serializer)
.enumerator(resolution_enumerator)
.display(resolution_display)
.default_func(resolution_default)
.change_listener(resolution_change)
.importance(100)
.finish();
static auto ResolutionOption = options::OptionBuilder<ResolutionInfo>("Graphics.Resolution",
std::pair<const char*, int>{"Resolution", 1748},
std::pair<const char*, int>{"The rendering resolution", 1749})
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.deserializer(resolution_deserializer)
.serializer(resolution_serializer)
.enumerator(resolution_enumerator)
.display(resolution_display)
.default_func(resolution_default)
.change_listener(resolution_change)
.importance(100)
.finish();
bool Gr_enable_soft_particles = false;
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
"Enable or disable soft particle rendering.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(true)
.bind_to_once(&Gr_enable_soft_particles)
.importance(68)
.finish();
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles",
std::pair<const char*, int>{"Soft Particles", 1761},
std::pair<const char*, int>{"Enable or disable soft particle rendering", 1762})
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(true)
.bind_to_once(&Gr_enable_soft_particles)
.importance(68)
.finish();
flagset<FramebufferEffects> Gr_framebuffer_effects;
static auto FramebufferEffectsOption __UNUSED =
options::OptionBuilder<flagset<FramebufferEffects>>(
"Graphics.FramebufferEffects", "Framebuffer effects",
"Controls which framebuffer effects will be applied to the scene.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{{}, "None"},
{{FramebufferEffects::Shockwaves}, "Shockwaves"},
{{FramebufferEffects::Thrusters}, "Thrusters"},
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, "All"}})
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
.bind_to_once(&Gr_framebuffer_effects)
.importance(77)
.finish();
static auto FramebufferEffectsOption __UNUSED = options::OptionBuilder<flagset<FramebufferEffects>>("Graphics.FramebufferEffects",
std::pair<const char*, int>{"Framebuffer effects", 1732},
std::pair<const char*, int>{"Controls which framebuffer effects will be applied to the scene", 1733})
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{{}, {"None", 211}},
{{FramebufferEffects::Shockwaves}, {"Shockwaves", 1688}},
{{FramebufferEffects::Thrusters}, {"Thrusters", 1689}},
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, {"All", 1690}}})
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
.bind_to_once(&Gr_framebuffer_effects)
.importance(77)
.finish();
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
"Controls the anti aliasing mode of the engine.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{AntiAliasMode::None, "None"},
{AntiAliasMode::FXAA_Low, "FXAA Low"},
{AntiAliasMode::FXAA_Medium, "FXAA Medium"},
{AntiAliasMode::FXAA_High, "FXAA High"},
{AntiAliasMode::SMAA_Low, "SMAA Low"},
{AntiAliasMode::SMAA_Medium, "SMAA Medium"},
{AntiAliasMode::SMAA_High, "SMAA High"},
{AntiAliasMode::SMAA_Ultra, "SMAA Ultra"}})
.default_val(AntiAliasMode::None)
.bind_to(&Gr_aa_mode)
.importance(79)
.finish();
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode",
std::pair<const char*, int>{"Anti Aliasing", 1752},
std::pair<const char*, int>{"Controls the anti aliasing mode of the engine.", 1753})
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{AntiAliasMode::None, {"None", 211}},
{AntiAliasMode::FXAA_Low, {"FXAA Low", 1681}},
{AntiAliasMode::FXAA_Medium, {"FXAA Medium", 1682}},
{AntiAliasMode::FXAA_High, {"FXAA High", 1683}},
{AntiAliasMode::SMAA_Low, {"SMAA Low", 1684}},
{AntiAliasMode::SMAA_Medium, {"SMAA Medium", 1685}},
{AntiAliasMode::SMAA_High, {"SMAA High", 1686}},
{AntiAliasMode::SMAA_Ultra, {"SMAA Ultra", 1687}}})
.default_val(AntiAliasMode::None)
.bind_to(&Gr_aa_mode)
.importance(79)
.finish();
extern int Cmdline_msaa_enabled;
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples", "Multisample Anti Aliasing",
"Controls whether multisample anti aliasing is enabled, and with how many samples.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{0, "Off"},
{4, "4 Samples"},
{8, "8 Samples"},
{16, "16 Samples"}})
.default_val(0)
.bind_to(&Cmdline_msaa_enabled)
.importance(78)
.finish();
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples",
std::pair<const char*, int>{"Multisample Anti Aliasing", 1758},
std::pair<const char*, int>{"Controls whether multisample anti asliasing is enabled, and with how many samples", 1759})
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{0, {"Off", 1693}},
{4, {"4 Samples", 1694}},
{8, {"8 Samples", 1695}},
{16, {"16 Samples", 1696}}})
.default_val(0)
.bind_to_once(&Cmdline_msaa_enabled)
.importance(78)
.finish();
bool gr_is_fxaa_mode(AntiAliasMode mode)
{
@@ -444,26 +453,27 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
bool Gr_post_processing_enabled = true;
static auto PostProcessOption __UNUSED =
options::OptionBuilder<bool>("Graphics.PostProcessing", "Post processing",
"Controls whether post processing is enabled in the engine")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(false)
.bind_to_once(&Gr_post_processing_enabled)
.importance(69)
.finish();
static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.PostProcessing",
std::pair<const char*, int>{"Post processing", 1726},
std::pair<const char*, int>{"Controls whether post processing is enabled in the engine.", 1727})
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(false)
.bind_to_once(&Gr_post_processing_enabled)
.importance(69)
.finish();
bool Gr_enable_vsync = true;
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
"Controls how the engine does vertical synchronization")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(true)
.bind_to_once(&Gr_enable_vsync)
.importance(70)
.finish();
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync",
std::pair<const char*, int>{"Vertical Sync", 1766},
std::pair<const char*, int>{"Controls how the engine does vertical synchronization", 1767})
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(true)
.bind_to_once(&Gr_enable_vsync)
.importance(70)
.finish();
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
+4 -3
View File
@@ -36,6 +36,7 @@ class OverridableHook;
extern const float Default_min_draw_distance;
extern const float Default_max_draw_distance;
extern float Min_draw_distance_cockpit;
extern float Min_draw_distance;
extern float Max_draw_distance;
extern int Gr_inited;
@@ -102,7 +103,7 @@ public:
Stack.push_back(Current_transform);
}
matrix4 &get_transform()
const matrix4 &get_transform() const
{
return Current_transform;
}
@@ -115,7 +116,7 @@ public:
Stack.push_back(Current_transform);
}
void push_and_replace(matrix4 new_transform)
void push_and_replace(const matrix4 &new_transform)
{
Current_transform = new_transform;
Stack.push_back(Current_transform);
@@ -300,7 +301,7 @@ public:
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
size_t get_vertex_stride() { return Vertex_stride; }
size_t get_vertex_stride() const { return Vertex_stride; }
bool operator==(const vertex_layout& other) const;
+51 -5
View File
@@ -519,7 +519,7 @@ void generic_render_png_stream(generic_anim* ga)
* @param [in] *ga animation data
* @param [in] frametime how long this frame took
*/
void generic_anim_render_fixed_frame_delay(generic_anim* ga, float frametime)
void generic_anim_render_fixed_frame_delay(generic_anim* ga, float frametime, float alpha = 1.0f)
{
float keytime = 0.0;
@@ -580,10 +580,19 @@ void generic_anim_render_fixed_frame_delay(generic_anim* ga, float frametime)
} else {
generic_render_eff_stream(ga);
}
gr_set_bitmap(ga->bitmap_id);
if (alpha == 1.0f) {
gr_set_bitmap(ga->bitmap_id);
} else {
gr_set_bitmap(ga->bitmap_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha);
}
}
else {
gr_set_bitmap(ga->first_frame + ga->current_frame);
if (alpha == 1.0f) {
gr_set_bitmap(ga->first_frame + ga->current_frame);
} else {
gr_set_bitmap(ga->first_frame + ga->current_frame, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha);
}
}
}
}
@@ -703,7 +712,7 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
generic_anim_render_variable_frame_delay(ga, frametime, a);
}
else {
generic_anim_render_fixed_frame_delay(ga, frametime);
generic_anim_render_fixed_frame_delay(ga, frametime, a);
}
if(ga->num_frames > 0) {
@@ -719,7 +728,44 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
else if (ge->draw == true) {
// currently only for lua streaminganim objects
// and don't draw them unless requested...
gr_bitmap_uv(x, y, ge->width, ge->height, ge->u0, ge->v0, ge->u1, ge->v1, GR_RESIZE_NONE);
gr_bitmap_uv(x, y, ge->width, ge->height, ge->u0, ge->v0, ge->u1, ge->v1, ge->resize_mode);
}
}
}
}
void generic_anim_render_ex(generic_anim* ga, float frametime, int x, int y, int w, int h, bool menu, const generic_extras* ge)
{
if ((ge != nullptr) && (ga->use_hud_color == true)) {
Warning(LOCATION, "Monochrome generic anims can't use extra info (yet)");
return;
}
float a = 1.0f;
if (ge != nullptr) {
a = ge->alpha;
}
if (ga->type == BM_TYPE_PNG) {
generic_anim_render_variable_frame_delay(ga, frametime, a);
}
else {
generic_anim_render_fixed_frame_delay(ga, frametime, a);
}
if (ga->num_frames > 0) {
ga->previous_frame = ga->current_frame;
if (ga->use_hud_color) {
gr_aabitmap_ex(x, y, w, h, 0, 0, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
}
else {
if (ge == nullptr) {
gr_bitmap_ex(x, y, w, h, 0, 0, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
}
else if (ge->draw == true) {
// currently only for lua streaminganim objects
// and don't draw them unless requested...
gr_bitmap_uv(x, y, w, h, ge->u0, ge->v0, ge->u1, ge->v1, ge->resize_mode);
}
}
}
+3
View File
@@ -67,6 +67,7 @@ public:
float u0, v0, u1, v1;
float alpha;
bool draw;
int resize_mode;
generic_extras()
: width(0), height(0)
@@ -74,6 +75,7 @@ public:
, u1(1.0f), v1(1.0f)
, alpha(1.0f)
, draw(true)
, resize_mode(0) // GR_RESIZE_NONE
{}
};
@@ -89,5 +91,6 @@ int generic_anim_stream(generic_anim *ga, const bool cache = true);
int generic_bitmap_load(generic_bitmap *gb);
void generic_anim_unload(generic_anim *ga);
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr);
void generic_anim_render_ex(generic_anim* ga, float frametime, int x, int y, int w, int h, bool menu = false, const generic_extras* ge = nullptr);
void generic_anim_reset(generic_anim *ga);
#endif
+1 -1
View File
@@ -441,7 +441,7 @@ void material::set_color(int r, int g, int b, int a)
Clr.xyzw.w = i2fl(a) / 255.0f;
}
void material::set_color(color &clr_in)
void material::set_color(const color &clr_in)
{
if ( clr_in.is_alphacolor ) {
Clr.xyzw.x = i2fl(clr_in.red) / 255.0f;
+1 -1
View File
@@ -133,7 +133,7 @@ public:
void set_color(float red, float green, float blue, float alpha);
void set_color(int r, int g, int b, int a);
void set_color(color &clr_in);
void set_color(const color &clr_in);
const vec4& get_color() const;
void set_color_scale(float scale);
+27 -10
View File
@@ -16,6 +16,8 @@ matrix4 gr_texture_matrix;
matrix4 gr_env_texture_matrix;
float gr_near_plane;
bool gr_htl_projection_matrix_set = false;
static int modelview_matrix_depth = 1;
@@ -116,28 +118,43 @@ void gr_end_instance_matrix()
}
// the projection matrix; fov, aspect ratio, near, far
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far) {
void gr_set_proj_matrix(fov_t fov, float aspect, float z_near, float z_far) {
if (gr_screen.rendering_to_texture != -1) {
gr_set_viewport(gr_screen.offset_x, gr_screen.offset_y, gr_screen.clip_width, gr_screen.clip_height);
} else {
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
}
float clip_width, clip_height;
clip_height = tan( fov * 0.5f ) * z_near;
clip_width = clip_height * aspect;
gr_last_projection_matrix = gr_projection_matrix;
if (gr_screen.rendering_to_texture != -1) {
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
} else {
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
if (mpark::holds_alternative<float>(fov)) {
float clip_width, clip_height;
clip_height = tan(mpark::get<float>(fov) * 0.5f) * z_near;
clip_width = clip_height * aspect;
if (gr_screen.rendering_to_texture != -1) {
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
} else {
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
}
}
else {
const auto& afov = mpark::get<asymmetric_fov>(fov);
float clip_l = tanf(afov.left) * z_near;
float clip_r = tanf(afov.right) * z_near;
float clip_u = tanf(afov.up) * z_near;
float clip_d = tanf(afov.down) * z_near;
if (gr_screen.rendering_to_texture != -1) {
create_perspective_projection_matrix(&gr_projection_matrix, clip_l, clip_r, clip_u, clip_d, z_near, z_far);
}
else {
create_perspective_projection_matrix(&gr_projection_matrix, clip_l, clip_r, clip_d, clip_u, z_near, z_far);
}
}
gr_htl_projection_matrix_set = true;
matrix_uniform_up_to_date = false;
gr_near_plane = z_near;
}
void gr_end_proj_matrix() {
+3 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "graphics/2d.h"
#include "render/3d.h"
extern transform_stack gr_model_matrix_stack;
extern matrix4 gr_view_matrix;
@@ -8,6 +9,7 @@ extern matrix4 gr_model_view_matrix;
extern matrix4 gr_projection_matrix;
extern matrix4 gr_last_projection_matrix;
extern matrix4 gr_env_texture_matrix;
extern float gr_near_plane;
void gr_matrix_on_frame();
@@ -15,7 +17,7 @@ void gr_start_instance_matrix(const vec3d* offset, const matrix* rotation);
void gr_start_angles_instance_matrix(const vec3d* pos, const angles* rotation);
void gr_end_instance_matrix();
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far);
void gr_set_proj_matrix(fov_t fov, float aspect, float z_near, float z_far);
void gr_end_proj_matrix();
void gr_set_view_matrix(const vec3d* pos, const matrix* orient);
+6 -2
View File
@@ -27,6 +27,7 @@
#include "graphics/2d.h"
#include "graphics/matrix.h"
#include "libs/renderdoc/renderdoc.h"
#include "lighting/lighting.h"
#include "math/floating.h"
#include "model/model.h"
#include "options/Option.h"
@@ -861,6 +862,9 @@ int opengl_init_display_device()
}
}
if (Cmdline_capture_mouse)
attrs.flags.set(os::ViewPortFlags::Capture_Mouse);
auto viewport = gr_opengl_create_viewport(attrs);
if (!viewport) {
return 1;
@@ -1177,7 +1181,7 @@ static void init_extensions() {
// we require a minimum GLSL version
if (GLSL_version < MIN_REQUIRED_GLSL_VERSION) {
Error(LOCATION, "Current GL Shading Langauge Version of %d is less than the required version of %d. Switch video modes or update your drivers.", GLSL_version, MIN_REQUIRED_GLSL_VERSION);
Error(LOCATION, "Current GL Shading Language Version of %d is less than the required version of %d. Switch video modes or update your drivers.", GLSL_version, MIN_REQUIRED_GLSL_VERSION);
}
GLint max_texture_units;
@@ -1399,7 +1403,7 @@ bool gr_opengl_is_capable(gr_capability capability)
case CAPABILITY_POST_PROCESSING:
return Gr_post_processing_enabled && !Cmdline_no_fbo;
case CAPABILITY_DEFERRED_LIGHTING:
return !Cmdline_no_fbo && !Cmdline_no_deferred_lighting;
return !Cmdline_no_fbo && light_deferred_enabled();
case CAPABILITY_SHADOWS:
case CAPABILITY_THICK_OUTLINE:
return !Cmdline_no_geo_sdr_effects;
+5 -4
View File
@@ -57,7 +57,7 @@ void opengl_clear_deferred_buffers()
void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs)
{
if ( Cmdline_no_deferred_lighting)
if (!light_deferred_enabled())
return;
static const float black[] = {0, 0, 0, 1.0f};
@@ -149,7 +149,7 @@ void gr_opengl_deferred_lighting_msaa()
opengl_set_generic_uniform_data<graphics::generic_data::msaa_data>(
[&](graphics::generic_data::msaa_data* data) {
data->samples = Cmdline_msaa_enabled;
data->fov = Proj_fov;
data->fov = g3_get_hfov(Proj_fov);
});
GL_state.SetAlphaBlendMode(gr_alpha_blend::ALPHA_BLEND_NONE);
GL_state.SetZbufferType(ZBUFFER_TYPE_WRITE);
@@ -181,7 +181,7 @@ void gr_opengl_deferred_lighting_finish()
GR_DEBUG_SCOPE("Deferred lighting finish");
TRACE_SCOPE(tracing::ApplyLights);
if (Cmdline_no_deferred_lighting) {
if (!light_deferred_enabled()) {
return;
}
@@ -254,6 +254,7 @@ void gr_opengl_deferred_lighting_finish()
header->invScreenWidth = 1.0f / gr_screen.max_w;
header->invScreenHeight = 1.0f / gr_screen.max_h;
header->nearPlane = gr_near_plane;
// Only the first directional light uses shaders so we need to know when we already saw that light
bool first_directional = true;
@@ -480,7 +481,7 @@ void gr_opengl_deferred_lighting_finish()
data->noiseColorScale2 = std::get<1>(neb.getNoiseColorScale());
data->noiseColorIntensity = neb.getNoiseColorIntensity();
data->aspect = gr_screen.clip_aspect;
data->fov = Proj_fov;
data->fov = g3_get_hfov(Proj_fov);
});
{
+2 -1
View File
@@ -25,6 +25,7 @@
#include "graphics/matrix.h"
#include "graphics/paths/PathRenderer.h"
#include "graphics/util/uniform_structs.h"
#include "lighting/lighting.h"
#include "render/3d.h"
#include "tracing/tracing.h"
@@ -673,7 +674,7 @@ void gr_opengl_scene_texture_begin()
Scene_texture_v_scale = 1.0f;
}
if ( Cmdline_no_deferred_lighting ) {
if (!light_deferred_enabled()) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} else {
+1 -1
View File
@@ -398,7 +398,7 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
Error(LOCATION,
"Shader %s:%d: Malformed include line. Could not find both quote charaters.",
"Shader %s:%d: Malformed include line. Could not find both quote characters.",
filename.c_str(),
line_num);
}
+22 -20
View File
@@ -47,17 +47,19 @@ extern int GLOWMAP;
extern int SPECMAP;
extern int ENVMAP;
const SCP_vector<std::pair<int, SCP_string>> TextureFilteringValues = {{ 0, "Bilinear" },
{ 1, "Trilinear" }, };
const SCP_vector<std::pair<int, std::pair<const char*, int>>> TextureFilteringValues = {{0, {"Bilinear", 1677}},
{ 1, {"Trilinear", 1678}}};
static auto TextureFilteringOption __UNUSED = options::OptionBuilder<int>("Graphics.TextureFilter", "Texture Filtering", "Texture filtering option")
.importance(1)
.category("Graphics")
.values(TextureFilteringValues)
.default_val(0)
.bind_to_once(&GL_mipmap_filter)
.flags({options::OptionFlags::ForceMultiValueSelection})
.finish();
static auto TextureFilteringOption __UNUSED = options::OptionBuilder<int>("Graphics.TextureFilter",
std::pair<const char*, int>{"Texture Filtering", 1763},
std::pair<const char*, int>{"Texture filtering option", 1764})
.importance(1)
.category("Graphics")
.values(TextureFilteringValues)
.default_val(0)
.bind_to_once(&GL_mipmap_filter)
.flags({options::OptionFlags::ForceMultiValueSelection})
.finish();
static SCP_vector<float> anisotropic_value_enumerator()
{
@@ -100,16 +102,16 @@ static float anisotropic_default()
return max;
}
static auto AnisotropyOption =
options::OptionBuilder<float>("Graphics.Anisotropy", "Anisotropic filtering",
"Controls the amount of anisotropic filtering of the textures.")
.enumerator(anisotropic_value_enumerator)
.category("Graphics")
.display(anisotropic_display)
.default_func(anisotropic_default)
.level(options::ExpertLevel::Advanced)
.importance(78)
.finish();
static auto AnisotropyOption = options::OptionBuilder<float>("Graphics.Anisotropy",
std::pair<const char*, int>{"Anistropic filtering", 1736},
std::pair<const char*, int>{"Controls the amount of anistropic filtering of the textures", 1737})
.enumerator(anisotropic_value_enumerator)
.category("Graphics")
.display(anisotropic_display)
.default_func(anisotropic_default)
.level(options::ExpertLevel::Advanced)
.importance(78)
.finish();
// forward declarations
int opengl_free_texture(tcache_slot_opengl *t);
+2 -2
View File
@@ -974,7 +974,7 @@ void opengl_tnl_set_material_particle(particle_material * material_info)
data->srgb = High_dynamic_range ? 1 : 0;
data->blend_alpha = material_info->get_blend_mode() != ALPHA_BLEND_ADDITIVE;
if (Cmdline_no_deferred_lighting) {
if (!light_deferred_enabled()) {
data->linear_depth = 0;
} else {
data->linear_depth = 1;
@@ -984,7 +984,7 @@ void opengl_tnl_set_material_particle(particle_material * material_info)
Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
Current_shader->program->Uniforms.setTextureUniform("depthMap", 1);
if (!Cmdline_no_deferred_lighting) {
if (light_deferred_enabled()) {
Assert(Scene_position_texture != 0);
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_position_texture);
+21 -20
View File
@@ -40,27 +40,28 @@ PostEffectUniformType mapUniformNameToType(const SCP_string& uniform_name)
// used by In-Game Options menu
bool Post_processing_enable_lightshafts = true;
auto LightshaftsOption __UNUSED =
options::OptionBuilder<bool>("Graphics.Lightshafts", "Lightshafts", "Enable lightshafts (requires post-processing)")
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Post_processing_enable_lightshafts)
.importance(60)
.finish();
static auto LightshaftsOption __UNUSED = options::OptionBuilder<bool>("Graphics.Lightshafts",
std::pair<const char*, int>{"Lightshafts", 1724},
std::pair<const char*, int>{"Enables or disables lightshafts (requires post-processing)", 1725})
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Post_processing_enable_lightshafts)
.importance(60)
.finish();
int Post_processing_bloom_intensity = 25; // using default value of Cmdline_bloom_intensity
auto BloomIntensityOption __UNUSED = options::OptionBuilder<int>("Graphics.BloomIntensity",
"Bloom intensity",
"Set bloom intensity (requires post-processing)")
.category("Graphics")
.range(0, 200)
.level(options::ExpertLevel::Advanced)
.default_val(25)
.bind_to(&Post_processing_bloom_intensity)
.importance(55)
.finish();
static auto BloomIntensityOption __UNUSED = options::OptionBuilder<int>("Graphics.BloomIntensity",
std::pair<const char*, int>{"Bloom intensity", 1701},
std::pair<const char*, int>{"Sets the bloom intensity (requires post-processing)", 1702})
.category("Graphics")
.range(0, 200)
.level(options::ExpertLevel::Advanced)
.default_val(25)
.bind_to(&Post_processing_bloom_intensity)
.importance(55)
.finish();
} // namespace
bool PostProcessingManager::parse_table()
@@ -223,7 +224,7 @@ bool gr_lightshafts_enabled()
}
if (Using_in_game_options) {
return graphics::Post_processing_enable_lightshafts;
return graphics::LightshaftsOption->getValue();
} else {
return !Cmdline_force_lightshaft_off;
}
@@ -240,7 +241,7 @@ int gr_bloom_intensity()
}
if (Using_in_game_options) {
return graphics::Post_processing_bloom_intensity;
return graphics::BloomIntensityOption->getValue();
} else {
return Cmdline_bloom_intensity;
}
+11 -7
View File
@@ -96,7 +96,7 @@ static void bitmap_ex_internal(int x,
bool aabitmap,
bool mirror,
color* clr,
int scale = 100) {
float scale_factor = 1.0f) {
if ((w < 1) || (h < 1)) {
return;
}
@@ -118,8 +118,10 @@ static void bitmap_ex_internal(int x,
bm_get_info(gr_screen.current_bitmap, &bw, &bh);
bw = (bw * scale) / 100;
bh = (bh * scale) / 100;
if (scale_factor != 1.0f) {
bw = static_cast<int>(bw * scale_factor);
bh = static_cast<int>(bh * scale_factor);
}
u0 = (i2fl(sx) / i2fl(bw));
v0 = (i2fl(sy) / i2fl(bh));
@@ -163,7 +165,7 @@ static void bitmap_ex_internal(int x,
draw_textured_quad(&render_mat, x1, y1, u0, v0, x2, y2, u1, v1);
}
void gr_aabitmap(int x, int y, int resize_mode, bool mirror, int scale) {
void gr_aabitmap(int x, int y, int resize_mode, bool mirror, float scale_factor) {
if (gr_screen.mode == GR_STUB) {
return;
}
@@ -174,8 +176,10 @@ void gr_aabitmap(int x, int y, int resize_mode, bool mirror, int scale) {
bm_get_info(gr_screen.current_bitmap, &w, &h);
w = (w * scale) / 100;
h = (h * scale) / 100;
if (scale_factor != 1.0f) {
w = static_cast<int>(w * scale_factor);
h = static_cast<int>(h * scale_factor);
}
if (resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1))) {
do_resize = 1;
@@ -239,7 +243,7 @@ void gr_aabitmap(int x, int y, int resize_mode, bool mirror, int scale) {
true,
mirror,
&gr_screen.current_color,
scale);
scale_factor);
}
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) {
+2 -1
View File
@@ -25,8 +25,9 @@ void gr_flash_alpha(int r, int g, int b, int a);
* @param y The y-coordinate of the draw call
* @param resize_mode The resize mode for translating the coordinated
* @param mirror @c true to mirror the image
* @param scale_factor a multiplier for the width and height of the bitmap
*/
void gr_aabitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false, int scale = 100);
void gr_aabitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false, float scale_factor = 1.0f);
/**
* @brief Draws a grey-scale bitmap multiplied with the current color
* @param x The x-coordinate of the draw call
+57 -41
View File
@@ -34,24 +34,20 @@ ShadowQuality Shadow_quality = ShadowQuality::Disabled;
bool Shadow_quality_uses_mod_option = false;
auto ShadowQualityOption =
options::OptionBuilder<ShadowQuality>("Graphics.Shadows", "Shadow Quality", "The quality of the shadows")
.values({{ShadowQuality::Disabled, "Disabled"},
{ShadowQuality::Low, "Low"},
{ShadowQuality::Medium, "Medium"},
{ShadowQuality::High, "High"},
{ShadowQuality::Ultra, "Ultra"}})
.change_listener([](ShadowQuality val, bool initial) {
if (initial) {
Shadow_quality = val;
}
return initial; // No dynamic changes implemented
})
.level(options::ExpertLevel::Advanced)
.category("Graphics")
.default_val(ShadowQuality::Disabled)
.importance(80)
.finish();
auto ShadowQualityOption = options::OptionBuilder<ShadowQuality>("Graphics.Shadows",
std::pair<const char*, int>{"Shadow Quality", 1750},
std::pair<const char*, int>{"The quality of the shadows", 1751})
.values({{ShadowQuality::Disabled, {"Disabled", 1779}},
{ShadowQuality::Low, {"Low", 1160}},
{ShadowQuality::Medium, {"Medium", 1161}},
{ShadowQuality::High, {"High", 1162}},
{ShadowQuality::Ultra, {"Ultra", 1721}}})
.change_listener([](ShadowQuality val, bool initial) {if (initial) {Shadow_quality = val;}return initial;})
.level(options::ExpertLevel::Advanced)
.category("Graphics")
.default_val(ShadowQuality::Disabled)
.importance(80)
.finish();
bool shadows_obj_in_frustum(object *objp, matrix *light_orient, vec3d *min, vec3d *max)
{
@@ -222,14 +218,34 @@ void shadows_debug_show_frustum(matrix* orient, vec3d *pos, float fov, float asp
g3_render_line_3d(true, &far_bottom_left, &far_top_left);
}
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d * /*pos*/, float fov, float aspect, float z_near, float z_far)
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d * /*pos*/, fov_t fov, float aspect, float z_near, float z_far)
{
// find the widths and heights of the near plane and far plane to determine the points of this frustum
float near_height = tanf(fov * 0.5f) * z_near;
float near_width = near_height * aspect;
float near_l, near_r, near_u, near_d;
float far_l, far_r, far_u, far_d;
if (mpark::holds_alternative<float>(fov)) {
near_d = tanf(mpark::get<float>(fov) * 0.5f) * z_near;
near_u = -near_d;
near_r = near_d * aspect;
near_l = -near_r;
float far_height = tanf(fov * 0.5f) * z_far;
float far_width = far_height * aspect;
far_d = tanf(mpark::get<float>(fov) * 0.5f) * z_far;
far_u = -far_d;
far_r = far_d * aspect;
far_l = -far_r;
}
else {
const auto& afov = mpark::get<asymmetric_fov>(fov);
near_d = tanf(-afov.down) * z_near;
near_u = -tanf(afov.up) * z_near;
near_r = tanf(-afov.left) * z_near;
near_l = -tanf(afov.right) * z_near;
far_d = tanf(-afov.down) * z_far;
far_u = -tanf(afov.up) * z_far;
far_r = tanf(-afov.left) * z_far;
far_l = -tanf(afov.right) * z_far;
}
vec3d up_scale = ZERO_VECTOR;
vec3d right_scale = ZERO_VECTOR;
@@ -247,40 +263,40 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
// near top left
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, -near_height);
vm_vec_scale(&up_scale, near_u);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, -near_width);
vm_vec_scale(&right_scale, near_l);
vm_vec_add(&near_top_left, &up_scale, &right_scale);
vm_vec_add2(&near_top_left, &forward_scale_near);
// near top right
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, -near_height);
vm_vec_scale(&up_scale, near_u);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, near_width);
vm_vec_scale(&right_scale, near_r);
vm_vec_add(&near_top_right, &up_scale, &right_scale);
vm_vec_add2(&near_top_right, &forward_scale_near);
// near bottom left
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, near_height);
vm_vec_scale(&up_scale, near_d);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, -near_width);
vm_vec_scale(&right_scale, near_l);
vm_vec_add(&near_bottom_left, &up_scale, &right_scale);
vm_vec_add2(&near_bottom_left, &forward_scale_near);
// near bottom right
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, near_height);
vm_vec_scale(&up_scale, near_d);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, near_width);
vm_vec_scale(&right_scale, near_r);
vm_vec_add(&near_bottom_right, &up_scale, &right_scale);
vm_vec_add2(&near_bottom_right, &forward_scale_near);
@@ -292,40 +308,40 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
// far top left
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, -far_height);
vm_vec_scale(&up_scale, far_u);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, -far_width);
vm_vec_scale(&right_scale, far_l);
vm_vec_add(&far_top_left, &up_scale, &right_scale);
vm_vec_add2(&far_top_left, &forward_scale_far);
// far top right
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, -far_height);
vm_vec_scale(&up_scale, far_u);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, far_width);
vm_vec_scale(&right_scale, far_r);
vm_vec_add(&far_top_right, &up_scale, &right_scale);
vm_vec_add2(&far_top_right, &forward_scale_far);
// far bottom left
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, far_height);
vm_vec_scale(&up_scale, far_d);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, -far_width);
vm_vec_scale(&right_scale, far_l);
vm_vec_add(&far_bottom_left, &up_scale, &right_scale);
vm_vec_add2(&far_bottom_left, &forward_scale_far);
// far bottom right
up_scale = orient->vec.uvec;
vm_vec_scale(&up_scale, far_height);
vm_vec_scale(&up_scale, far_d);
right_scale = orient->vec.rvec;
vm_vec_scale(&right_scale, far_width);
vm_vec_scale(&right_scale, far_r);
vm_vec_add(&far_bottom_right, &up_scale, &right_scale);
vm_vec_add2(&far_bottom_right, &forward_scale_far);
@@ -381,7 +397,7 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
shadows_construct_light_proj(shadow_data);
}
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, fov_t fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
{
if(Static_light.empty())
return vmd_identity_matrix;
@@ -419,7 +435,7 @@ void shadows_end_render()
gr_shadow_map_end();
}
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos)
{
if (gr_screen.mode == GR_STUB) {
return;
+4 -3
View File
@@ -12,6 +12,7 @@
#include "globalincs/pstypes.h"
#include "object/object.h"
#include "render/3d.h"
#define MAX_SHADOW_CASCADES 4
@@ -38,11 +39,11 @@ extern bool Shadow_quality_uses_mod_option;
extern matrix4 Shadow_proj_matrix[MAX_SHADOW_CASCADES];
extern float Shadow_cascade_distances[MAX_SHADOW_CASCADES];
void shadows_construct_light_frustum(vec3d *min_out, vec3d *max_out, vec3d light_vec, matrix *orient, vec3d *pos, float fov, float aspect, float z_near, float z_far);
void shadows_construct_light_frustum(vec3d *min_out, vec3d *max_out, vec3d light_vec, matrix *orient, vec3d *pos, fov_t fov, float aspect, float z_near, float z_far);
bool shadows_obj_in_frustum(object *objp, vec3d *min, vec3d *max, matrix *light_orient);
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos);
void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos);
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, fov_t fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
void shadows_end_render();
/**
+1 -1
View File
@@ -66,7 +66,7 @@ namespace font
{
if (string[i] >= Lcl_special_chars || string[i] < 0)
{
// Special character needs to be handled seperately
// Special character needs to be handled separately
return i;
}
}
+2 -1
View File
@@ -30,8 +30,9 @@ struct deferred_global_data {
float invScreenWidth;
float invScreenHeight;
float nearPlane;
float pad[2];
float pad;
};
/**
+3
View File
@@ -321,6 +321,9 @@ bool VulkanRenderer::initDisplayDevice() const
}
}
if (Cmdline_capture_mouse)
attrs.flags.set(os::ViewPortFlags::Capture_Mouse);
auto viewPort = m_graphicsOps->createViewport(attrs);
if (!viewPort) {
return false;
+35 -68
View File
@@ -71,7 +71,7 @@ SCP_vector<std::unique_ptr<HudGauge>> default_hud_gauges;
#define HUD_NEW_ALPHA_BRIGHT_HI 255
// Externals not related to the HUD code itself
extern float View_zoom;
extern fov_t View_zoom;
// globals that will control the color of the HUD gauges
int HUD_color_red = 0;
@@ -91,10 +91,6 @@ color HUD_color_debug; // grey debug text shown on HUD
static sound_handle Player_engine_snd_loop = sound_handle::invalid();
// HUD render frame offsets
float HUD_offset_x = 0.0f;
float HUD_offset_y = 0.0f;
// the offset of the player's view vector and the ship forward vector in pixels (Swifty)
int HUD_nose_x;
int HUD_nose_y;
@@ -1033,8 +1029,8 @@ void HudGauge::renderCircle(int x, int y, int diameter, bool filled)
void HudGauge::setClip(int x, int y, int w, int h)
{
int hx = fl2i(HUD_offset_x);
int hy = fl2i(HUD_offset_y);
int hx = 0;
int hy = 0;
if ( gr_screen.rendering_to_texture != -1 ) {
gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true);
@@ -1051,17 +1047,22 @@ void HudGauge::setClip(int x, int y, int w, int h)
gr_set_clip(hx, hy, w, h);
} else {
if ( reticle_follow ) {
if (reticle_follow) {
hx += HUD_nose_x;
hy += HUD_nose_y;
gr_resize_screen_pos(&hx, &hy);
gr_set_screen_scale(base_w, base_h);
gr_unsize_screen_pos(&hx, &hy);
}
else {
gr_set_screen_scale(base_w, base_h);
}
gr_resize_screen_pos(&hx, &hy);
gr_set_screen_scale(base_w, base_h);
x += hx;
y += hy;
gr_resize_screen_pos(&x, &y, &w, &h);
gr_set_clip(hx+x, hy+y, w, h, GR_RESIZE_NONE);
gr_set_clip(x, y, w, h, GR_RESIZE_NONE);
}
gr_reset_screen_scale();
@@ -1085,9 +1086,6 @@ void HudGauge::resetClip()
gr_set_clip(hx, hy, w, h);
} else {
hx = fl2i(HUD_offset_x);
hy = fl2i(HUD_offset_y);
gr_resize_screen_pos(&hx, &hy);
gr_set_screen_scale(base_w, base_h);
@@ -1778,8 +1776,8 @@ void HudGaugeMissionTime::render(float /*frametime*/)
int minutes=0;
int seconds=0;
mission_time = f2fl(Missiontime); // convert to seconds
mission_time = f2fl(Missiontime) + (float)The_mission.HUD_timer_padding; // convert to seconds
minutes=(int)(mission_time/60);
seconds=(int)mission_time%60;
@@ -2021,7 +2019,7 @@ void hud_damage_popup_init()
Damage_flash_timer = 1;
for ( i = 0; i < SUBSYSTEM_MAX; i++ ) {
Pl_hud_subsys_info[i].last_str = 1000.0f;
Pl_hud_subsys_info[i].last_str = 1.0f;
Pl_hud_subsys_info[i].flash_duration_timestamp = 1;
Pl_hud_next_flash_timestamp = 1;
Pl_hud_is_bright = 0;
@@ -2076,6 +2074,11 @@ void HudGaugeDamage::initLineHeight(int h)
line_h = h;
}
void HudGaugeDamage::initDisplayValue(bool value)
{
always_display = value;
}
void HudGaugeDamage::initBitmaps(const char *fname_top, const char *fname_middle, const char *fname_bottom)
{
damage_top.first_frame = bm_load_animation(fname_top, &damage_top.num_frames);
@@ -2136,7 +2139,7 @@ void HudGaugeDamage::render(float /*frametime*/)
for ( pss = GET_FIRST(&Player_ship->subsys_list); pss !=END_OF_LIST(&Player_ship->subsys_list); pss = GET_NEXT(pss) ) {
psub = pss->system_info;
strength = ship_get_subsystem_strength(Player_ship, psub->type);
if ( strength < 1 ) {
if ( always_display || strength < 1 ) {
// display the actual health of this specific subsystem --wookieejedi
if (pss->max_hits > 0) {
// get percentage if this subsystem has hitpoints to begin with
@@ -2273,7 +2276,7 @@ void HudGaugeDamage::render(float /*frametime*/)
// Show hull integrity if it's below 100% or if a subsystem is damaged
// The second case is just to make the display look complete
// The third case is there to make the gauge appear only if needed if the right option is set
if ( screen_integrity < 100 || !info_lines.empty() ) {
if ( always_display || screen_integrity < 100 || !info_lines.empty() ) {
DamageInfo info;
info.name = XSTR( "Hull Integrity", 220);
@@ -2407,10 +2410,11 @@ int hud_anim_load(hud_anim *ha)
* @param reverse Play animation in reverse (default 0)
* @param resize_mode Resize for non-standard resolutions
* @param mirror Mirror along y-axis so icon points left instead of right
* @param scale_factor Multiplier for the width and height
*
* @returns 1 on success, 0 on failure
*/
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int hold_last, int reverse, int resize_mode, bool mirror)
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int hold_last, int reverse, int resize_mode, bool mirror, float scale_factor)
{
int framenum;
@@ -2434,7 +2438,7 @@ int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int
if(emp_should_blit_gauge()){
gr_set_bitmap(ha->first_frame + framenum);
if ( draw_alpha ){
gr_aabitmap(ha->sx, ha->sy, resize_mode, mirror);
gr_aabitmap(ha->sx, ha->sy, resize_mode, mirror, scale_factor);
} else {
gr_bitmap(ha->sx, ha->sy, resize_mode);
}
@@ -2961,6 +2965,9 @@ void HudGaugeSupport::render(float /*frametime*/)
int show_time, w, h;
char outstr[64];
if (background.first_frame < 0)
return;
if ( !Hud_support_view_active ) {
return;
}
@@ -3742,42 +3749,8 @@ int hud_objective_notify_active()
* @param wiggedy_wack
* @param eye_orient
*/
void HUD_set_offsets(object *viewer_obj, int wiggedy_wack, matrix *eye_orient)
void HUD_set_offsets()
{
if ( (viewer_obj == Player_obj) && wiggedy_wack ){
vec3d tmp;
vertex pt;
HUD_offset_x = 0.0f;
HUD_offset_y = 0.0f;
vm_vec_scale_add( &tmp, &Eye_position, &eye_orient->vec.fvec, 100.0f );
(void) g3_rotate_vertex(&pt,&tmp);
g3_project_vertex(&pt);
gr_unsize_screen_posf( &pt.screen.xyw.x, &pt.screen.xyw.y );
HUD_offset_x -= 0.45f * (i2fl(gr_screen.clip_width_unscaled)*0.5f - pt.screen.xyw.x);
HUD_offset_y -= 0.45f * (i2fl(gr_screen.clip_height_unscaled)*0.5f - pt.screen.xyw.y);
if ( HUD_offset_x > 100.0f ) {
HUD_offset_x = 100.0f;
} else if ( HUD_offset_x < -100.0f ) {
HUD_offset_x += 100.0f;
}
if ( HUD_offset_y > 100.0f ) {
HUD_offset_y = 100.0f;
} else if ( HUD_offset_y < -100.0f ) {
HUD_offset_y += 100.0f;
}
} else {
HUD_offset_x = 0.0f;
HUD_offset_y = 0.0f;
}
if ( Viewer_mode & ( VM_TOPDOWN | VM_CHASE ) ) {
HUD_nose_x = 0;
HUD_nose_y = 0;
@@ -3841,10 +3814,7 @@ void HUD_get_nose_coordinates(int *x, int *y)
*/
void HUD_reset_clip()
{
int hx = fl2i(HUD_offset_x);
int hy = fl2i(HUD_offset_y);
gr_set_clip(hx, hy, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled);
gr_set_clip(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled);
}
/**
@@ -3852,10 +3822,7 @@ void HUD_reset_clip()
*/
void HUD_set_clip(int x, int y, int w, int h)
{
int hx = fl2i(HUD_offset_x);
int hy = fl2i(HUD_offset_y);
gr_set_clip(hx+x, hy+y, w, h);
gr_set_clip(x, y, w, h);
}
/**
@@ -3865,7 +3832,7 @@ void HUD_set_clip(int x, int y, int w, int h)
void hud_save_restore_camera_data(int save)
{
static vec3d save_view_position;
static float save_view_zoom;
static fov_t save_view_zoom;
static matrix save_view_matrix;
static matrix save_eye_matrix;
static vec3d save_eye_position;
@@ -4131,7 +4098,7 @@ void HudGaugeSupernova::render(float /*frametime*/)
}
HudGaugeFlightPath::HudGaugeFlightPath():
HudGauge(HUD_OBJECT_FLIGHT_PATH, HUD_CENTER_RETICLE, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY, 255, 255, 255)
HudGauge3DAnchor(HUD_OBJECT_FLIGHT_PATH, HUD_CENTER_RETICLE, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY, 255, 255, 255)
{
}
+24 -5
View File
@@ -129,7 +129,7 @@ void hud_render_gauges(int cockpit_display_num = -1);
void hud_stop_looped_engine_sounds();
// set the offset values for this render frame
void HUD_set_offsets(object *viewer_obj, int wiggedy_wack, matrix *eye_orient);
void HUD_set_offsets();
// returns the offset between the player's view vector and the forward vector of the ship in pixels (Swifty)
void HUD_get_nose_coordinates(int *x, int *y);
@@ -149,7 +149,7 @@ void hud_num_make_mono(char *num_str, int font_num = font::FONT1);
// functions for handling hud animations
void hud_anim_init(hud_anim *ha, int sx, int sy, const char *filename);
void hud_frames_init(hud_frames *hf);
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha=0, int loop=1, int hold_last=0, int reverse=0,int resize_mode=GR_RESIZE_FULL, bool mirror = false);
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha=0, int loop=1, int hold_last=0, int reverse=0,int resize_mode=GR_RESIZE_FULL, bool mirror = false, float scale_factor = 1.0f);
int hud_anim_load(hud_anim *ha);
// functions for displaying the support view popup
@@ -277,7 +277,7 @@ public:
void initOriginAndOffset(float originX, float originY, int offsetX, int offsetY);
void initCoords(bool use_coords, int coordsX, int coordsY);
void initSlew(bool slew);
virtual 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);
@@ -362,6 +362,21 @@ public:
void resetClip();
};
//Use this instead of HudGauge whenever you have a HudGauge that is anchored in 3D-space (i.e. takes its rendering coordinates from g3_rotate/project_vertex, as these MUST NEVER slew.
class HudGauge3DAnchor : public HudGauge {
public:
HudGauge3DAnchor()
: HudGauge() { }
HudGauge3DAnchor(int _gauge_object, int _gauge_config, bool /*_slew*/, bool _message, int _disabled_views, int r, int g, int b)
: HudGauge(_gauge_object, _gauge_config, false, _message, _disabled_views, r, g, b) { }
// constructor for custom gauges
HudGauge3DAnchor(int _gauge_config, bool /*_slew*/, int r, int g, int b, char* _custom_name, char* _custom_text, char* frame_fname, int txtoffset_x, int txtoffset_y)
: HudGauge(_gauge_config, false, r, g, b, _custom_name, _custom_text, frame_fname, txtoffset_x, txtoffset_y) { }
void initSlew(bool /*slew*/) override {};
};
class HudGaugeMissionTime: public HudGauge // HUD_MISSION_TIME
{
hud_frames time_gauge;
@@ -492,7 +507,10 @@ protected:
int next_flash;
bool flash_status;
public:
bool always_display;
public:
HudGaugeDamage();
void initBitmaps(const char *fname_top, const char *fname_middle, const char *fname_bottom);
void initHeaderOffsets(int x, int y);
@@ -503,6 +521,7 @@ public:
void initSubsysIntegValueOffsetX(int x);
void initBottomBgOffset(int offset);
void initLineHeight(int h);
void initDisplayValue(bool value);
void render(float frametime) override;
void pageIn() override;
void initialize() override;
@@ -562,7 +581,7 @@ public:
void render(float frametime) override;
};
class HudGaugeFlightPath: public HudGauge
class HudGaugeFlightPath: public HudGauge3DAnchor
{
hud_frames Marker;
+1 -1
View File
@@ -331,7 +331,7 @@ int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsy
}
HudGaugeBrackets::HudGaugeBrackets():
HudGauge(HUD_OBJECT_BRACKETS, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW, 255, 255, 255)
HudGauge3DAnchor(HUD_OBJECT_BRACKETS, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW, 255, 255, 255)
{
}
+1 -1
View File
@@ -25,7 +25,7 @@ void draw_brackets_diamond_quick(graphics::line_draw_list* draw_list, int x1, in
int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsys, int min_width, int min_height, bool draw = true, bool set_color = true, int* draw_coords = NULL);
class HudGaugeBrackets: public HudGauge
class HudGaugeBrackets: public HudGauge3DAnchor
{
protected:
int attacking_dot;
+3 -8
View File
@@ -900,7 +900,7 @@ void hud_config_render_gauges(bool API_Access)
resize = GR_RESIZE_NONE;
}
gr_aabitmap(HC_gauge_coords[i].x, HC_gauge_coords[i].y, resize, false, (int)(HC_gauge_scale * 100));
gr_aabitmap(HC_gauge_coords[i].x, HC_gauge_coords[i].y, resize, false, HC_gauge_scale);
}
/*
@@ -1266,7 +1266,7 @@ void hud_config_button_do(int n)
case HCB_SAVE_HCF:
int exists;
char *out;
const char *out;
// get the text in the input control
exists = 0;
@@ -1658,10 +1658,6 @@ void hud_config_as_observer(ship *shipp,ai_info *aif)
// store the current hud
hud_config_backup();
// bash these values so the HUD is not offset incorrectly
HUD_offset_x = 0.0f;
HUD_offset_y = 0.0f;
// initialize the observer HUD
hud_observer_init(shipp,aif);
}
@@ -1708,10 +1704,9 @@ 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");
const char *fname = cf_add_ext(name, ".hcf");
try
{
+19 -22
View File
@@ -238,6 +238,9 @@ void HudGaugeEscort::render(float /*frametime*/)
{
int i = 0;
if (Escort_gauges[0].first_frame < 0)
return;
if ( !Show_escort_view ) {
return;
}
@@ -297,7 +300,6 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
float shields, integrity;
int screen_integrity, offset, objnum = -1;
char buf[255];
const player *pl = nullptr;
auto eship = get_escort_entry_from_index(index);
@@ -309,8 +311,7 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
int np_index = find_player_index(eship->np_id);
if (np_index >= 0) {
pl = Net_players[np_index].m_player;
objnum = pl->objnum;
objnum = Net_players[np_index].m_player->objnum;
// this can occassionally happen in multi when a player still needs to respawn.
if (objnum < 0 || Objects[objnum].type != OBJ_SHIP){
@@ -347,15 +348,9 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
}
// print out ship name
// behavior largely taken from message_queue_process() in missionmessage.cpp,
// but with the multiplayer callsign behavior kept in accordance with #1674.
if (sp->callsign_index >= 0 && !pl)
{
// Without the !pl, this would just stuff short_callsign anyway, so may
// as well use the ship name and append it instead.
hud_stuff_ship_callsign(buf, sp);
}
else if (((Iff_info[sp->team].flags & IFFF_WING_NAME_HIDDEN) && (sp->wingnum != -1)) || (sp->flags[Ship::Ship_Flags::Hide_ship_name]))
// original behavior replaced with similar logic to hudtargetbox.cpp, except
// if the name is hidden, it's replaced with the class name.
if (((Iff_info[sp->team].flags & IFFF_WING_NAME_HIDDEN) && (sp->wingnum != -1)) || (sp->flags[Ship::Ship_Flags::Hide_ship_name]))
{
// If we're hiding the ship name, we probably shouldn't append the callsign either
hud_stuff_ship_class(buf, sp);
@@ -364,17 +359,19 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
{
hud_stuff_ship_name(buf, sp);
// maybe add callsign if multi and player ship
if (pl) {
SCP_string callsign;
// maybe concatenate the callsign
if (*buf)
{
char callsign[NAME_LENGTH];
callsign.reserve(32);
callsign += " (";
callsign += pl->short_callsign;
callsign += ")";
strcat_s(buf, callsign.c_str());
hud_stuff_ship_callsign(callsign, sp);
if (*callsign)
sprintf(&buf[strlen(buf)], " (%s)", callsign);
}
// maybe substitute the callsign
else
{
hud_stuff_ship_callsign(buf, sp);
}
}
+17 -7
View File
@@ -125,19 +125,25 @@ void update_ets(object* objp, float fl_frametime)
// This will translate to 71% max speed at 50% engines, and 31% max speed at 10% engines
//
float eng_current_strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
float engine_aggregate_strength;
if (ship_p->flags[Ship::Ship_Flags::Maneuver_despite_engines]) {
// Pretend our strength is 100% when this flag is active
engine_aggregate_strength = 1.0f;
} else {
engine_aggregate_strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
}
// only update max speed if aggregate engine health has changed
// which helps minimze amount of overrides to max speed
if (eng_current_strength != ship_p->prev_engine_aggregate_strength) {
// only update max speed if engine_aggregate_strength has changed
// which helps minimize amount of overrides to max speed
if (engine_aggregate_strength != ship_p->prev_engine_aggregate_strength) {
ets_update_max_speed(objp);
ship_p->prev_engine_aggregate_strength = eng_current_strength;
ship_p->prev_engine_aggregate_strength = engine_aggregate_strength;
// check if newly updated max speed should be reduced due to engine damage
// don't let engine strength affect max speed when playing on lowest skill level
if ((objp != Player_obj) || (Game_skill_level > 0)) {
if (eng_current_strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED) {
objp->phys_info.max_vel.xyz.z *= fl_sqrt(eng_current_strength);
if (engine_aggregate_strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED) {
objp->phys_info.max_vel.xyz.z *= fl_sqrt(engine_aggregate_strength);
}
}
}
@@ -888,6 +894,10 @@ void HudGaugeEts::pageIn()
*/
void HudGaugeEts::blitGauge(int index)
{
if (Ets_bar.first_frame < 0) {
return;
}
int y_start, y_end, clip_h, w, h, x, y;
clip_h = fl2i( (1 - Energy_levels[index]) * ETS_bar_h );
Loaded 100 of 329 files, more files were not shown because too many files have changed in this diff. Show more