Compare commits

..
Author SHA1 Message Date
z64555 31c4597b61 Manual Build Commit 2022-03-20 22:51:32 -05:00
Goober5000 db9261d9d9 Merge pull request #4088 from EatThePath/run_sexp_optimize
Remove unneeded search of whole sexp node array from free_sexp
2022-03-20 23:33:20 -04:00
David Gibson 70d1abc6ff Remove unneeded search of whole sexp node array from free_sexp 2022-03-20 18:43:53 -05:00
Goober5000 d37b4a4482 Merge pull request #4086 from Goober5000/background_fix
patch a background bug in FRED
2022-03-20 17:01:34 -04:00
Goober5000 89a50da355 patch a background bug in FRED
In FRED, deleting all suns and bitmaps should not delete the last remaining background.
2022-03-20 16:27:37 -04:00
Goober5000 76a8433b5b Merge pull request #4077 from Goober5000/fix_3672
patch some holes in the mission cleanup
2022-03-19 22:58:42 -04:00
Goober5000 acc6686f67 Merge pull request #4083 from Goober5000/xstr_tweak
small XSTR qol improvement
2022-03-19 22:12:13 -04:00
Goober5000 32c5f17d15 small XSTR qol improvement
Allow `XSTR` to be used by itself, without implying an `XSTR()` tag.
2022-03-19 16:52:54 -04:00
Goober5000 12dd79a0c7 Merge pull request #4078 from Goober5000/fix_3759
be a little more careful about converting wingman messages to Command messages
2022-03-19 14:03:47 -04:00
BMagnu 2ca4616f37 Fix the Initial animations not properly setting prev_orient (#4082) 2022-03-19 11:47:32 -04:00
BMagnu 8c976a174f Improve Performance of Global to Local functions (#4080)
* Improve Performance of global to local point

* Improve Performance of global to local point dir

* Adapt Tests
2022-03-18 02:04:15 +00:00
Goober5000 cb38d89a1b be a little more careful about converting wingman messages to Command messages
FS1 has a feature which will occasionally convert a wingman message to a Command message.  This adds a few more checks to that feature:

1) Make the command-conversion code and the alive-check code mutually exclusive;
2) If the filename is not a FS1-style persona, don't change either a) the filename, or b) the talking head

Fixes #3759.
2022-03-16 23:12:44 -04:00
Goober5000 4b29f51b0e patch some holes in the mission cleanup
Bug #3672 was caused by the dead popup not being cleaned up properly when the player-dead state was left.  Closer examination revealed some possible holes in the cleanup logic - e.g. the game assumed that the mission would proceed to the debriefing but neglected the possibility that it would exit to the main hall.  This consolidates the two dead states and attempts to make the cleanup more robust.

Fixes #3672.
2022-03-16 21:41:35 -04:00
Goober5000 4dbdcd3783 some debug console updates (#4074)
Tweak the help for the 'bastion' command and change 'dcf_fov' to 'fov'.  Also add a new 'mainhall' command that can be used in the main hall, not just the player select screen.
2022-03-15 20:50:46 -05:00
Goober5000 d7fc0bdf8e Merge pull request #4075 from Goober5000/fix_3996
fix message list crash
2022-03-15 21:05:54 -04:00
Goober5000 e41077e07f fix message list crash
PR #3342 meant that occasionally FRED would try to save a message that didn't exist.  Make sure the old saved index doesn't point past the end of the valid message list.

Fixes #3996.
2022-03-15 20:32:53 -04:00
Goober5000 9ca14b6dd2 Merge pull request #4072 from Goober5000/patch_decals
prevent decals from being used on invalid objects
2022-03-13 22:22:27 -04:00
Goober5000 bd1cf2d07d prevent decals from being used on invalid objects 2022-03-13 21:55:44 -04:00
Goober5000 4b50fe5eca Merge pull request #4071 from Goober5000/fix_text_split
fix off-by-one error in text splitting logic
2022-03-13 15:02:39 -04:00
Goober5000 48ea08219e fix off-by-one error in text splitting logic
`gr_get_string_size` takes a length parameter, but `split_str_once` was calling it with the position instead.  This led to incorrect results occasionally.  If the incorrect pixel width had the bad luck to be exactly equal to the remaining space, this would cause an infinite loop.  This fixes the bug and adds a bunch of safeguards to prevent a similar situation in the future.
2022-03-12 22:58:03 -05:00
BMagnu e2e689d454 Properly set canonical_prev_orient and exclude turrets (#4070) 2022-03-12 17:46:14 -05:00
Asteroth d86ebd5eb2 Remove new assert in model_instance_local_to_global_dir (#4069)
* remove assert and clarify hit_normal

* remove other asserts too
2022-03-12 11:55:29 +09:00
BMagnu 471c4991eb Make Anim Validation Case Insensitive (#4068) 2022-03-10 10:16:23 -05:00
Goober5000 26417e2154 Merge pull request #4064 from Baezon/fix-target-bracket
Targeting brackets should use the header's bounding box, not detail0's
2022-03-09 23:45:09 -05:00
BMagnu 222f3e00a7 Fix moving submodel collision speed calculation (#4067) 2022-03-10 01:35:34 +09:00
BMagnuandGoober5000 9ab7a4626a Fix nested and animated submodel collisions (#4065)
* Calculate per-frame rotation axis

* function prototypes

* Add new submodel localization functions

* Fix collision detection for moving submodels

* Remove offending assert

* Add safeguard for stopped animations

* Fix last frame speed calc

* Fix childs with parent submodel rotations

* Fix Warnings

* Clang Bug Workaround

* clang tidy

* Incorporate Feedback

Co-authored-by: Goober5000 <[email protected]>
2022-03-09 23:49:11 +09:00
Taylor Richards 593372eea4 Merge pull request #4063 from notimaginative/fix_bsp_swap
swap bsp data before alignment
2022-03-07 22:43:45 -05:00
Asteroth 5f3dc91a24 use header's bbox, not detail0's 2022-03-07 20:15:52 -05:00
Taylor Richards 3e2008c23c swap bsp data before alignment
Changing endianess of bsp data must be done before any other
bsp processing
2022-03-07 08:25:37 -05:00
Allen A. Babb 9b34225522 Fixes the version string in main.py (#4060)
* Form version string based off of tag_name
* Use checkout@v3
* Update documentation
2022-03-06 20:37:25 -06:00
Goober5000 b01137ab53 Merge pull request #4059 from Goober5000/warp_tweaks
two small but important warp fixes
2022-03-06 21:12:27 -05:00
Goober5000 45ead0645c Merge pull request #4061 from Goober5000/clean_up_support_goals
fix support ships breaking in in-mission jumps
2022-03-06 21:12:07 -05:00
Allen A. Babb fe0b3d2099 Clean out player t_plr before use (#4058)
* Clean out player t_plr before use
* Directly reference t_plr instead of player* p
* player* p Needs to be set in ::verify() for other pilotfile:: methods to work
2022-03-06 15:16:25 -06:00
Goober5000 d7c2a962ff fix support ships breaking in in-mission jumps
If a support ship's repair goal is removed, abort the rearm.  There is extra cleanup that needs to be done for this goal only.
2022-03-06 15:30:14 -05:00
Allen A. Babb afce512f55 Repair Automated Forum and Nebula Scripts (#4052)
* Document things
* Maybe use a format that doxygen can understand
* Use dict comprehension to clean up main.groups a bit

* More docstrings

* Move FileGroup into module its supposed to be in

* Remove nightly-trigger.yml

* Rename workflow files to better describe their actions

* Re-add post build capabilities
* Post-build may be triggered by build-release.yaml or manually
* minor doc update to file_list.get_ftp_files()

* Maybe fix yaml errors

* "You have a syntax error on L345" Gee, thanks github debugger. Could you tell me what exactly that error may be?

* More fixes

* More fixes

* fix typo

* fix typo

* Allow manual trigger to specify releaseTag

* Try omitting the default for string

* Use correct .inputs member

* try environment instead of env

* Try elevating scope of env

* Comment out stuff to directly test env passing

* See if echo is working correctly

* Test if top level env is in scope

* Try github.event instead of github.events

* Uncomment lines, use correct context signature

* Pass ref_name to post-build-release workflow

* Fix arguments to git
Stash linux package since it can fail, too

* str and repr cannot be compared

* Get repo metadata differently to allow tests on forks

* echo repository var

* config["templates"] does not have a member ["installer"] so... we'll use ["release"] instead

* debug render_installer_config.  file groups malformed?

* Print out both keys of groups dict

* debug get_release_files. print binary_file list

* Revert file_list debug print
Try sorting binary_files by ReleaseFile.name

* Add checks before running mako to improve debugging QoL
* revert change to installer.py
* maybe fix call to render_nebula_release
* type the files argument to get IDE hints

* Revert typing.... :(

* missing parenthesis

* Disabled installer mako rendering

* Error check in ForumAPI to allow tests to continue

* debug print hlp forum key stuff

* Instead of none, check ""
2022-03-05 21:48:01 -06:00
Goober5000 310898dfd9 two small but important warp fixes
1) Don't knock the player out of the warp if the sequence has already moved to stage two.  It breaks the sequence and the game will still end the mission anyway.
2) Remove the Volition code for calculating player speed.  It did not actually affect the speed, but it *did* affect the calculation of warp distance which often caused the player's ship to miss the portal.
2022-03-05 20:37:40 -05:00
m!m 9b16413f5f Merge pull request #4054 from asarium/fix/decalOrientation
Fix render orientation for decals
2022-03-01 20:58:20 +01:00
asarium ac77a6eb77 Fix render orientation for decals
The orientation was broken since the engine rendered the decal box in
the direction of the hit normal which meant that the viewer was looking
at a flipped version of the decal texture.

This fixes that by flipping the direction of the decal before passing it
to the GPU.

This also fixes the orientation for weapon decals which previously did
not take the orientation of the weapon that just impacted into account.
2022-03-01 19:14:34 +01:00
m!m aac5e35a6e Merge pull request #4053 from asarium/fix/decalOffset
Fix uniform offset calcuation for decal header
2022-02-28 19:16:01 +01:00
asarium 6c99c4f48e Fix uniform offset calcuation for decal header
This was broken by the move to a single, global uniform buffer where we
started doing suballocation so offset 0 was reading bad data.

Also fixed a crash regarding an unknown locale name on Linux.
2022-02-28 18:49:53 +01:00
Joshua Glatt 5daea9dc0f Fix Windows debug heap assertion when using Edit Data in qtFRED (#4018) 2022-02-27 14:56:54 -08:00
Goober5000 6ae5a8555c Merge pull request #4051 from Shivansps/fix_align_bsp_data_access_violation
Dont try to read chunk size if chunk type is 0
2022-02-24 12:55:30 -05:00
Shivansps 5235f14473 dont try to read chunk size if chunk type is 0
Chunk type 0 is EOF and lacks the following int indicating the total chunk size.
2022-02-23 19:07:19 -03:00
Allen A. Babb 143f64129d Changes to build-release.yaml (#4044)
* Try using softprops/action-gh-release

* Try *_path instead of *_name

* Document action dependencies
* Use consistent versioning in some places

* Maybe continue windows_zip should an upload fail

* Skip building standalone image if not on source repo.

* Stash the windows zips to artifact ftp in case the publish steps fail.
* Combine publish steps into one step
2022-02-23 09:59:48 -06:00
BMagnu 0b0f323091 Fixed incoherent case sensitivity for animation submodels (#4047) 2022-02-22 18:03:41 +00:00
Goober5000 4559d15327 Merge pull request #4045 from Goober5000/fix_popup_time
fix time resuming when popups are closed
2022-02-22 01:01:14 -05:00
Goober5000 1e067113a5 tweak name, per feedback 2022-02-22 00:31:04 -05:00
Goober5000 ac5142df8a fix time resuming when popups are closed
If time is already stopped when a popup is displayed, it should remain stopped when the popup is closed.
2022-02-21 18:50:12 -05:00
Goober5000 58ac0dfdf2 Merge pull request #4043 from Goober5000/fix_keep_safe_distance
fix the keep-safe-distance AI mode
2022-02-20 22:38:18 -05:00
Goober5000 6496059979 fix the keep-safe-distance AI mode
There were two bugs that kept this from working until now:

1) The destination goal point was calculated to take the ship right through the center of danger.  Flipping the vector now takes the ship away from danger as intended.
2) The original AI code did not turn the ship at all.  The new code turns the ship toward its goal point.

The fixed behavior is tied to the new `$fix keep-safe-distance:` flag.
2022-02-20 22:07:31 -05:00
Allen A. Babb 97eb72b3b4 Set key to -1 and let CCB::take() do the actual binding later on... instead of overwriting changes. (#4042) 2022-02-20 19:10:23 +00:00
Goober5000 6a3794ca17 Merge pull request #4038 from Goober5000/patch_glowpoint_normals
prevent Assert with glowpoints
2022-02-19 20:45:02 -05:00
Goober5000 95d0036aeb Merge pull request #4039 from Goober5000/ship_registry_fix
fix an edge case for ships destroyed before mission
2022-02-19 20:44:47 -05:00
Goober5000 1b69e6e3ad fix an edge case for ships destroyed before mission
Make sure the ship registry correctly records these ships as having exited.
2022-02-19 19:46:33 -05:00
Goober5000 a1d92251cb prevent Assert with glowpoints
It's legal for glowpoints to have a zero vector as a normal, apparently, so test for this.
2022-02-19 19:23:48 -05:00
Goober5000 71c7875dbf Merge pull request #4037 from Goober5000/scanning_features
add some new scan features
2022-02-19 02:18:45 -05:00
Goober5000 237787c256 add some new scan features
1. Add custom scan times per subsystem
2. Add scanning time and range multipliers for player ships

Resolves #4027
2022-02-18 22:39:04 -05:00
BMagnu 55cbabb05c Improve costly RTT sanity check (#4036)
* Improve costly sanity check

* Remove commented code and improve documentation
2022-02-18 03:48:26 +09:00
Kiloku 6201309aa6 Adds -deadzone parameter to command line (#3915)
* Adds command line parameter for finer deadzone control
2022-02-17 09:06:31 -06:00
Goober5000 caa3ea05f0 Merge pull request #4031 from Goober5000/scripted_submodels
add scripting support for submodels
2022-02-17 02:34:06 -05:00
Goober5000 54ff2f00ed more updates 2022-02-17 01:57:34 -05:00
Goober5000 dc2d3ae623 fix compilation and address feedback 2022-02-16 23:57:54 -05:00
Goober5000 57705db466 add scripting support for submodels
Allow scripts to reference submodels, submodel instances, and model instances.  Currently just a few properties (like Orientation and Radius) can be accessed, but this can be easily expanded in the future.

Also add relevant functions to calculate real-world positions and orientations of rotated submodels.
2022-02-16 21:45:23 -05:00
Goober5000 b005d4ab3b Merge pull request #4033 from Goober5000/submodel_function_refactor
rename and document several model coordinate functions
2022-02-16 21:42:37 -05:00
wookieejedi 1c19238e70 Expand scripting string functions (#4035) 2022-02-16 17:04:47 -05:00
Goober5000 e2f63a2340 rename and document several model coordinate functions 2022-02-15 20:59:24 -05:00
Goober5000 fad086bc15 Merge pull request #4030 from Goober5000/submodel_calculation_cleanup
clean up model point/dir/normal/orient functions
2022-02-15 13:46:22 -05:00
Goober5000 5536832ef2 Merge pull request #4032 from Goober5000/isvalid_fix
fix another isValid scripting function
2022-02-15 00:45:07 -05:00
Goober5000 09da73eec8 fix another isValid scripting function 2022-02-15 00:02:05 -05:00
Goober5000 f0371cdb0c clean up model point/dir/normal/orient functions
Consolidated these functions and replaced the `find_submodel_point_*` functions with their closest `world_find_` counterparts.  (One of those functions may not have actually worked correctly.)  Also use the correct coordinate logic when returning normals from collision info in scripting.

Related to #3985 although not yet a fix for it.
2022-02-14 23:46:43 -05:00
Allen A. Babb 71773bfa95 Don't nullify axis_out[action] value when using mouse as joy (#4029) 2022-02-14 16:18:13 +00:00
Goober5000 b8203ecd7f Merge pull request #4026 from Goober5000/return_object_with_breed
a few scripting bugfixes
2022-02-14 07:47:22 -05:00
Goober5000 4fe11d8449 a few scripting bugfixes
When returning objects, be sure to use `ade_set_object_with_breed`, per the documentation on that function.  This ensures that all relevant subclass information can be used.

Also fix the return value of streaminganim's isValid() function.
2022-02-13 23:31:16 -05:00
Tyler Blount a9338510e1 Merge pull request #4025 from z64555/mouse_to_joy0
Mouse to joy0
2022-02-13 19:59:31 -07:00
Allen A. Babb 789dc3b529 Merge pull request #4024 from scp-fs2open/revert-3954-mouse_to_joy0
Revert "Treat Mouse as Joy0 if "turned on" in options menu"
2022-02-13 19:48:59 -06:00
Allen A. Babb c7de39c50c Revert "Treat Mouse as Joy0 if "turned on" in options menu (#3954)"
This reverts commit ff8c4cdf68.
2022-02-13 19:08:52 -06:00
Allen A. Babb ff8c4cdf68 Treat Mouse as Joy0 if "turned on" in options menu (#3954)
* Treat mouse axes as Joy0 axes if Use_mouse_to_fly is true.

* Treat mouse buttons as Joy0 buttons when Use_mouse_to_fly is true
* Don't spin out of control like a 3yo on pixie sticks when treating the mouse axes as Joy0 axes

* Address CI Issues 1

* Try FALLTHROUGH macro to appease the compiler gods.

* * Change the labels in the Options menu UI for the Mouse On/Off buttons
* Nudge the hardcoded postions for the labels for bothGR_640 and GR_1024 resolutions
* Adds the following XSTR indices
  1665 "Mouse Input Mode"
  1666 "Joy-0"

* Update player_tips_controls() to mention the changes to the Mouse Input Mode
2022-02-14 00:08:23 +00:00
z64555 6a15f5ef48 Update player_tips_controls() to mention the changes to the Mouse Input Mode 2022-02-13 17:02:05 -06:00
z64555 fcfdb2942b * Change the labels in the Options menu UI for the Mouse On/Off buttons
* Nudge the hardcoded postions for the labels for bothGR_640 and GR_1024 resolutions
* Adds the following XSTR indices
  1665 "Mouse Input Mode"
  1666 "Joy-0"
2022-02-13 16:12:57 -06:00
z64555 de04373727 Try FALLTHROUGH macro to appease the compiler gods. 2022-02-13 16:08:13 -06:00
z64555 3719bcc36d Address CI Issues 1 2022-02-13 16:08:13 -06:00
z64555 f84e5782d7 Treat mouse buttons as Joy0 buttons when Use_mouse_to_fly is true
* Don't spin out of control like a 3yo on pixie sticks when treating the mouse axes as Joy0 axes
2022-02-13 16:08:12 -06:00
z64555 e5ba711645 Treat mouse axes as Joy0 axes if Use_mouse_to_fly is true. 2022-02-13 16:08:12 -06:00
Allen A. Babb cf83573b2a Improve Pilot version checks (#3988)
* rename pilotfile::version to pilotfile::plr_ver
* Fix typo in warning message
* set plr_ver and csg_ver to PLR_VERSION_INVALID on init and close
* add PLAYER_FLAGS_PLR_VER_LOWER and *_CONTROLS flags to player defines
* Add popup to intercept the player before going into the mainhall with an old pilot
* Move the Constrols5 info popup into the mainhall
* Modifiy pilotfile::verify() to allow player flags to be passed on to callers

* Rename valid_pilot_lang() to valid_pilot()
* valid_pilot() checks plr_version of the pilot and prompts the user if they want to continue loading or not
* add no_popup param to valid_pilot() to allow scripting to use it

* Correctly clear the PLR_VER_CONTROLS player flag
* operator== is not operator+=
* don't clear player flags when closing a pilot file
* player tips popup comes after any warnings
* save committed pilot on playermenu close
* doxy playermenu::player_creat_new_pilot() and magagepilot::init_new_pilot()

* * add validation/safety catch in the barracks to prompt user if they want to select/convert a pilot with version mismatch
* PLAYER_FLAGS_PLR_VER_CONTROLS is a savable flag, cleared in the mainhall after the popup is dismiessed
* Move version flag sets in plr::load_player() and plr::verify() after calls to player_read_flags()
* Drop hints to players they should use a clone of the pilot in version prompt.
* Went ahead and added a VERSION_HIGHER flag and conditional in valid_pilot()
* Move Controsl5 notice popup into playermenu, next to the player_tips_pop().  Also allows player to "Don't show this again"

* Ignore plr version flags during unit tests since .plr -> .json conversion is never a pure clone

* Address CI issues:
* clang-tidy: use nullptr (modernize-use-nullptr)

* Add XSTR support to valid_pilot() and player_tips_constrols() popups.

* * Rename new PLAYER_FLAGS to something more descriptive
* Edit Popup text to be a bit more concise
* Add missing punctuation to language popup
2022-02-13 16:07:01 -06:00
Goober5000 244d220358 Merge pull request #4022 from Goober5000/ui_timestamp
another timestamp upgrade
2022-02-13 14:32:38 -05:00
Allen A. Babb 3e227b41c4 Restrict allowable characters for preset names (#4009)
* Doxy UI_INPUTBOX methods
* extend popup_input to allow non-alphanum character whitelist
2022-02-13 13:06:07 -06:00
Goober5000 eb29d065a2 Merge pull request #4019 from BMagnu/anim_axisrot_fix2
Fix Aix Rotation Moveable
2022-02-12 20:30:11 -05:00
Goober5000 c6d87b0626 there is now no longer a need to keep timestamps running during briefing, so keep them paused until the mission starts 2022-02-12 19:34:01 -05:00
Goober5000 0c8cfd160b improve the UI_TIMESTAMP type a bit 2022-02-12 19:34:01 -05:00
Goober5000 8e2e825204 add UI_TIMESTAMP type and switch some timestamps to use it 2022-02-12 19:01:15 -05:00
Goober5000 a0815e4fe6 Merge pull request #4014 from Goober5000/event_log_tweaks
event logging tweaks
2022-02-12 15:30:30 -05:00
Goober5000 b5721c67cc Merge pull request #4015 from Goober5000/operator_patches
improve robustness of sexp operators
2022-02-12 13:38:22 -05:00
Birk Magnussen 478edf50f6 Fix Aix Rotation Moveable 2022-02-12 16:52:39 +09:00
Goober5000 c3adf704f8 improve robustness of sexp operators
1) Remove operator caching from `is-cargo-known-delay`, `cap-subsys-cargo-known-delay`, and `has-been-tagged-delay` so they can be used with `when-argument`
2) Note idiosyncrasies of `and-in-sequence` in SEXP help
3) Document logic for inverting known-true and known-false in `sexp_not`

Should fix #4013.
2022-02-10 22:17:21 -05:00
Goober5000 fe40f87606 event logging tweaks
A couple quality-of-life improvements for event logging:
1) Indent the SEXP operators according to their depth in the node tree
2) Add newlines between variables and containers
2022-02-10 21:15:15 -05:00
BMagnu b6474f795c Fix rotation localization (#4012) 2022-02-10 22:43:59 +09:00
Goober5000 2fde893be1 Merge pull request #4007 from Goober5000/fix_camera_orient
fix the camera flicker in the lab
2022-02-06 23:44:12 -05:00
Goober5000 5b87ed3f73 fix the camera flicker in the lab
As @Baezon figured out, when a host exists, `get_info` will return the orientation relative to the host.  When there is no host, `get_info` returns the absolute orientation.  In the latter case, `set_rotation_facing` does not need to do extra calculations to find the delta orientation.

Follow-up to #3989.
2022-02-06 23:06:06 -05:00
Goober5000 6a2e6e7c7d Merge pull request #4006 from Goober5000/fixed_missile_detonation
fix missile detonation for computers with high FPS
2022-02-06 18:39:57 -05:00
Goober5000 29a0736d34 fix missile detonation for computers with high FPS
There is a bit of code that detonates a missile if it misses impacting on a subsystem.  On Nyctaeus's Arachnas model, missiles could reach the center point of the main beam turret submodel without actually hitting any part of the submodel.  The fail-safe code would set the missile to detonate in that case, but on low-FPS systems the weapon would be able to actually hit the turret before it detonated.  On high-FPS systems, there is a clean miss.

This reworks the code to delay the missile detonation until it reaches the other side of the submodel, so it has time to hit some other part of it.  It also reduces the detonation time from 1/100 of a second (which is more than one frame on 120 FPS systems) to 1/1000 of a second (which is always less than one frame).
2022-02-06 17:53:19 -05:00
Goober5000 41b7f9ff1a Merge pull request #4003 from Goober5000/hud_gauge_and_string_upgrades
Hud gauge and string upgrades
2022-02-06 12:02:30 -05:00
Goober5000 18661ae4dd reverse check here because Lua will treat numbers as strings 2022-02-05 21:14:07 -05:00
Goober5000 89b9323705 fix documentation for unit tests 2022-02-05 15:46:37 -05:00
Goober5000 2e839eda0a rename hud_get_gauge to hud_get_custom_gauge for clarity 2022-02-05 15:14:23 -05:00
Goober5000 c05569180e upgrade gr.drawString to be able to use a custom sizing mode 2022-02-05 15:12:29 -05:00
Goober5000 5cf1b7ffc6 upgrade scripting to reference hud gauges by name or index, and allow a scripted hud gauge object to represent a default gauge 2022-02-05 15:11:21 -05:00
Fabian Woltermann 79d5288163 Merge pull request #4001 from The-E/fix/4000_mainhall_misc_anim_delay
Preserve the table-defined offset for initial misc animation playback
2022-02-04 17:12:26 +01:00
Goober5000 4864a1ff8b Merge pull request #4002 from Goober5000/set_skybox_check
when changing the skybox, check to see if it's the same as the current one
2022-02-04 00:05:16 -05:00
Goober5000 4ae246be57 when changing the skybox, check to see if it's the same as the current one 2022-02-03 22:43:22 -05:00
Fabian Woltermann d40d904be3 Set the first element of the misc anim delay structure during parsing, for aesthetic reasons 2022-02-03 16:54:38 +01:00
Fabian Woltermann 6ade65929c Update comments 2022-02-03 08:32:14 +01:00
Fabian Woltermann d120117899 Preserve the table-defined offset for initial misc animation playback 2022-02-02 21:35:58 +01:00
BMagnu e7d9f5a555 fix absolute moveable (#3995) 2022-02-01 05:08:39 +00:00
wookieejedi 34e74aad7b Fix limitations of GetColor script function (#3992)
* Fix limitations of GetColor script function

It is very valuable for custom HUD gauges to be able to show/use the IFF color of any given object. Previous scripting solutions were limited and did not account for traitor status, varying team combinations (i.e. TvT multiplayer), and other cases.

This PR allows scripters to get the IFF color of a given object properly, as it uses the same method that retail HUD gauges use.

Also, it turns out there was already a function `hud_get_iff_color` defined in `hud.h` It was never used though, as `hud_set_iff_color` both got the color then set it. I've added the color getting to the get function and the setting to the set function, that way the script function can easily just call the `hud_get_iff_color` function. If this is undesirable I can instead copy the entire logic of the function `hud_set_iff_color` into the script section.

Tested and works as expected.

* fix nil return

* clarify param comments
2022-01-31 23:33:19 +00:00
JohnAFernandez fba5521583 Merge pull request #3993 from JohnAFernandez/Fix-client-zombie-missiles
Partially revert 3313 to fix missiles never dying
2022-01-31 11:58:17 -05:00
Goober5000 42f834c115 Merge pull request #3989 from Goober5000/fix_3889
point camera correctly when using set-camera-facing
2022-01-31 01:21:12 -05:00
JohnAFernandez 9c7b0fbcd5 Merge pull request #3991 from JohnAFernandez/fix-edge-case-rollback-crash
Fix edge case rollback crash
2022-01-30 23:12:19 -05:00
Goober5000 6ab17aba2a move inline functions to the header file so Linux will compile 2022-01-30 22:58:24 -05:00
Goober5000 d8987b3de0 set some mod flags by default in 22.0 2022-01-30 22:58:24 -05:00
Goober5000 f6a903f2b9 correctly calculate the vector for pointing the camera 2022-01-30 22:58:24 -05:00
Goober5000 8a29586ef5 properly calculate submodel host orient 2022-01-30 22:58:24 -05:00
JohnAFernandez f5517eb782 Partially revert 3313 to fix missiles never dying
This should allow the client to cull missiles with no lifetime left once again.
2022-01-30 22:48:27 -05:00
JohnAFernandez c0b9d6a5e1 Move nprintf to better spot
The log would sometimes lie to us otherwise.
2022-01-30 22:25:07 -05:00
JohnAFernandez 82f343cd97 Make sure we don't set the frame to the one we're about to increment to
Which actually fixes the bug which caused everything in the first place
2022-01-30 22:23:55 -05:00
Goober5000 bd90781499 rename a couple variables for clarification 2022-01-30 22:23:44 -05:00
Goober5000 059babea50 add game_settings flag 2022-01-30 22:23:44 -05:00
Goober5000 73076f4909 Merge pull request #3990 from Goober5000/fix_broken_rotation
regression fix for rotating submodels
2022-01-30 22:17:34 -05:00
Goober5000 64724f8cc2 regression fix for rotating submodels
The POF format relies on some of the IDs being the values they are, so this change restores the original numbers.
2022-01-30 21:51:31 -05:00
wookieejedi 5e6119be25 Fix Damage Gauge Display (#3987)
Previously, the damage display gauge only showed the integrity for subsystem types. This was fine if there were a 1:1 match, with each type only having 1 subsystem. If there were more then 1 subsystem of a given type though, it would not display accurate information to the player.

This PR sets the displayed subsystem integrity to that actual specific subsystem, not the aggregate. Tested and works as expected (screenshot attached) and fixes #3982.
2022-01-30 17:34:24 -05:00
Goober5000 39213b9d75 Merge pull request #3979 from Goober5000/model_translation_phase_1
refactoring in preparation for model translation
2022-01-30 13:47:59 -05:00
BMagnu 79be6bb32d Fix edge case for turret lookup with template and display name (#3981) 2022-01-30 13:14:33 -05:00
Goober5000 df77ee7cf4 doh 2022-01-29 23:20:37 -05:00
Goober5000 2833b89d38 address feedback 2022-01-29 22:48:27 -05:00
BMagnu cacb1baa50 Improve Animation SEXP usability (#3976)
* Make the new animation SEXP use proper field checking and add suggested entries

* Clarify the animation SEXP description text
2022-01-30 10:27:30 +09:00
Goober5000 97952d6b6c refactoring in preparation for model translation
Mostly renaming of fields and functions, and moving some modelread sections into functions.  This reorganization will put the code on a better footing for the model translation feature.  No model translation code is included yet, and there should be no change in functionality.
2022-01-29 15:53:21 -05:00
Goober5000 d673b25041 Merge pull request #3978 from Goober5000/axis_inversion_upgrade
handle primary and secondary inversion explicitly and independently
2022-01-29 12:18:58 -05:00
Goober5000 fda33ec1fc handle primary and secondary inversion explicitly and independently
Treating both bindings together will fail when a player has one binding inverted but the other uninverted.  This was complicated by the dual-binding method mysteriously delegating to the single-binding method in certain cases.  This change removes the dual-binding methods altogether and explicitly handles the bindings individually.  It also adds additional scripting VIRTVARs for all current use cases.
2022-01-29 11:40:49 -05:00
Goober5000 244a1aac26 fix initial positions of submodels in FRED (#3975)
The new animation system sets submodel initial positions on ship creation, but FRED was also indirectly setting them by calling the techroom method.  Initial positions will not work correctly if they are set twice.
2022-01-29 04:30:41 +00:00
Goober5000 4cafff10b9 Merge pull request #3972 from BMagnu/anim_4_fixes
Various Animation Fixes
2022-01-28 22:10:27 -05:00
Goober5000 023d8c0acc Merge pull request #3974 from Goober5000/fred_bbox_fix
use the whole submodel hierarchy in FRED
2022-01-28 22:05:04 -05:00
Birk Magnussen 43078c9d27 Fix moveable flicker by forcing recalculation outside of animation stepping 2022-01-29 11:30:29 +09:00
Birk Magnussen e58af85c03 Keep canonical_prev_orient correct 2022-01-29 11:21:20 +09:00
Goober5000 ac2f474581 use the whole submodel hierarchy in FRED
The `fredhtl_render_subsystem_bounding_box` function only handled one level of submodel positioning, which worked for turrets but not more complicated submodel stacks like the Ma'at.  This properly handles all submodels in the hierarchy.

Fixes #3971.
2022-01-28 21:20:32 -05:00
Birk Magnussen adfc8e0db9 Log addition of Can_move flag 2022-01-29 11:18:52 +09:00
Goober5000 d84ec680af Merge pull request #3970 from Goober5000/submodel_rotation_lod_fix
replicate submodels that aren't associated with subsystems
2022-01-28 10:53:43 -05:00
Birk Magnussen e862c2775e Tidy up 2022-01-28 16:34:39 +09:00
Birk Magnussen 4ce2d3e029 Fix various issues in vm_closest_angle_to_matrix 2022-01-28 16:30:59 +09:00
Birk Magnussen 3aa44671d5 Set can move flag for all submodels that have been requested by the animations 2022-01-28 16:30:27 +09:00
Goober5000 7674474bb9 make clang happy, and anticipate a potential problem in the collision code 2022-01-28 01:05:42 -05:00
Goober5000 68fc947832 replicate submodels that aren't associated with subsystems
There are a few related improvements here:

1) Add a new function for iterating over the submodel hierarchy
2) Add a counterpart to the `subobj_num` field so that a submodel can refer to its ship_info subsystem
3) Update `ship_model_replicate_submodels` to replicate all movable submodels, even the ones that aren't associated with subsystems

Fixes #3967
2022-01-28 00:09:13 -05:00
BMagnu c9da6156b4 Fix missing sound stop for non-flipped sound segments (#3969) 2022-01-27 23:14:51 -05:00
wookieejedi 1fb1368882 Add getHUDConfigShowStatus for scripting (#3961)
* Add view show status for HUD gauges in scripting

Many FSO mods use scripted HUD gauges, but previously the scripted HUD gauges were always forced to be on for the player, unlike retail gauges that can be toggled in the HUD Config screen. This PR allows scripters to view the show status of a HUD gauge, which is very useful for adding a check in the script to only show the gauge if a certain gauge is active. This is similar behavior to the getColor function, which allowed scripters to get the HUD Config colors of a given default gauge.

Tested and works as expected.

* appease clang
2022-01-27 11:17:38 +09:00
BMagnu 17bcaebd58 Add axis rotation Animation Segment (#3966)
* Add axis rotation segment

* Add axis rotation moveable

* Clang

* Fix clang tidy
2022-01-27 11:16:45 +09:00
wookieejedi 795947a606 Enable Use Cargo Icon for briefing icons (#3964) 2022-01-26 17:33:41 -05:00
BMagnu 21d4690ebb Inverse Kinematics for Animations (#3962)
* Add FABRIK IK solver

* Add IK constraints

* Finish IK table entry

* Add IK Moveable and fix some edge cases

* Clang Fixes

* Implement feedback
2022-01-26 19:56:39 +09:00
BMagnu 1b118e9b5e Fix lab animation triggers (#3965) 2022-01-26 16:08:31 +09:00
BMagnu 9352835a00 Fix reverse instant trigger edge case (#3956) 2022-01-24 21:46:47 +09:00
Allen A. Babb 64ae887d28 Fix/issue 3902 (#3947)
* Make a Big ol' Wall of Text which, hopefully, somebody might actually read.
* Address issue 3902 in plr.cpp
* Handle case when axis is not bound
* Appease Linus-X
* Make wall of text less wall-y
2022-01-23 17:15:00 -06:00
Goober5000 d8d571f01c Merge pull request #3950 from Goober5000/more_timestamp_fixes
some small timestamp fixes
2022-01-23 16:18:44 -05:00
Taylor Richards 554738c8ef Merge pull request #3949 from notimaginative/psnet_ip_mode_pref
add IP version preference troubleshooting options
2022-01-23 15:43:26 -05:00
Goober5000 73c96e0f63 Merge pull request #3953 from Goober5000/small_fixes
some small fixes
2022-01-23 14:31:21 -05:00
Goober5000 70039b0432 some small fixes
1) Fix set-scanned and set-unscanned to take multiple arguments as designed.
2) Fix documentation on the "perturb" scripting functions.

Fixes #3951
2022-01-23 02:49:00 -05:00
Goober5000 6cebcfc9ac some small timestamp fixes
A few assorted fixes for timestamps:

1) The pre-player delay should be fast-forwarded by 1/4 second per frame regardless of time compression
2) If time compression is very slow, there could be a 0-millisecond change in timestamps, so don't adjust this
3) Properly handle a change in soundtrack that occurs during a mission, not just when the mission is parsed
2022-01-22 23:47:17 -05:00
Goober5000 7d0188735a Merge pull request #3948 from Goober5000/fix_3946
fix arrival delays and other mission time wonkiness
2022-01-22 20:32:03 -05:00
Taylor Richards fd1cf53809 fix dumb coder thing 2022-01-22 20:23:52 -05:00
Taylor Richards e5613fab74 allow connection fallback for PXO mod ident timeout 2022-01-22 19:40:48 -05:00
Taylor Richards 6d932df744 add options to prefer either IPv4 or IPv6
This really only applies to DNS lookups, setting the preference to either
be for IPv4 or IPv6 addresses. This makes for a far less error prone
troubleshooting method than disabling one of them outright.
2022-01-22 19:40:48 -05:00
Goober5000 7058993a2b fix arrival delays and other mission time wonkiness
The `Timestamp_microseconds_at_mission_start` variable should not, in fact, be adjusted when the timer counter variables are adjusted.

Fixes #3946.
2022-01-22 18:46:35 -05:00
Goober5000 87631a4023 Merge pull request #3936 from Goober5000/dockpoint_moving_submodel
allow dockpoints to be anchored to submodels explicitly
2022-01-22 17:50:53 -05:00
Joshua Glatt 07ea13ccf0 Update links and edit text in FRED's and qtFRED's About dialogs (#3941) 2022-01-22 14:37:49 -08:00
BMagnu dc6cd40541 Clean up Player_orders (#3918)
* Merge all three comm_order arrays

Were Comm_orders, Sexp_comm_orders, and Player_orders. Now all Player_orders.

* Fix Warnings

* Fix erroneous order warning

* Update Int3 into a warning

* Fix missing location for warning
2022-01-22 22:09:49 +09:00
Goober5000 05f740f8ff Merge pull request #3945 from Goober5000/timestamp_debugging_hack
accommodate elapsed time during debugging
2022-01-22 00:45:23 -05:00
Goober5000 65cd5ef8da add cmdline option 2022-01-22 00:16:59 -05:00
Goober5000 420f75cfe0 fred stubs 2022-01-22 00:16:59 -05:00
Goober5000 408ff91894 initialize Last_frame_timestamp 2022-01-22 00:16:59 -05:00
Goober5000 f96ea31253 the variable should be nonzero by the time we get to mission stuff, but best to handle it anyway 2022-01-21 09:48:50 -05:00
Goober5000 a1bc06aeeb accommodate elapsed time during debugging
If a breakpoint is hit in the code, the SDL time will keep running even though FSO doesn't realize things are effectively, if not actually, paused.  Detect this situation and adjust the timestamp offset to compensate.
2022-01-20 21:13:52 -05:00
Goober5000 5a21d43cdd Merge pull request #3944 from notimaginative/fix_training_mission_stats_bug
fix training mission stats bug
2022-01-20 19:26:48 -05:00
Taylor Richards 8cb7ab1c50 fix training mission stats bug
Training missions don't save kills so make sure that we don't try to
back out kills by mistake when replaying a training mission.

Fixes #3916
2022-01-20 17:50:15 -05:00
Joshua Glatt 33fa58400d Remove unneeded/leaky code from sexp_list_item in FRED and QtFRED (#3942) 2022-01-19 21:19:51 -08:00
Goober5000 c002c19b93 Merge pull request #3943 from Goober5000/tbp_warp_fix
TBP warp fix
2022-01-19 22:23:09 -05:00
Goober5000 160b75bd9a make clang happy 2022-01-19 20:50:11 -05:00
Goober5000 a436d5f3d0 remove redundant externs for clang 2022-01-19 20:08:31 -05:00
Goober5000 6db1accdb8 remove this because it is handled elsewhere, and because ships can have this flag without serving this role 2022-01-19 19:32:25 -05:00
Goober5000 9e149ff467 set the flag if a ship uses a Knossos warpin or warpout effect 2022-01-19 19:31:28 -05:00
Taylor Richards 5562a4f684 update ffmpeg support for 5.0+ API changes (#3939)
Fixes #3926
2022-01-19 14:14:06 -05:00
Goober5000 32e1194575 change int to bool 2022-01-19 01:35:32 -05:00
Taylor Richards 6bdb3d8d2b Merge pull request #3923 from notimaginative/standalone_optimizations
Standalone fixes/optimizations
2022-01-19 00:55:21 -05:00
Joshua Glatt 83faf8de99 Remove unnecessary/leaky strdup() calls in sexp_list_item in FRED/QtFRED (#3940) 2022-01-18 21:41:53 -08:00
Goober5000 3d941ca3ef Merge pull request #3938 from Goober5000/notify_about_scroll_buttons
log whether command briefing is using scroll buttons
2022-01-19 00:14:35 -05:00
Goober5000 35eca2ae50 allow 3d warp to be enabled from the table 2022-01-18 12:09:54 -05:00
Goober5000 eab2401e9e Cmdline_3dwarp is now Fireball_use_3d_warp, apparently 2022-01-18 12:09:54 -05:00
Taylor Richards d0964d7380 use proper return for invalid particle effect 2022-01-18 10:04:02 -05:00
Taylor Richards f2a99117a6 always init path renderer
This is required for truetype fonts, otherwise it crashes during font
loading. It still wastes a good bit of memory however and will need
to be addressed with a more permanent solution in the future.
2022-01-18 06:39:50 -05:00
Taylor Richards ca73b4fefb fix crash on standalone from weapon trail cleanup
A standalone server can reset itself, which triggers game_level_close(),
before game_level_init() has been called. trails_level_close() didn't account
for not being inited first and would crash.
2022-01-18 06:39:50 -05:00
Taylor Richards e81ad7024e skip tracker init popup on standalone 2022-01-18 06:39:50 -05:00
Taylor Richards 0ba94a554b fix memory leak from libpcp context (undocumented) 2022-01-18 06:39:50 -05:00
Taylor Richards d75174992d release model interp data on level close for standalones 2022-01-18 06:39:50 -05:00
Taylor Richards 45b2d2a83a release memory from object update on level close 2022-01-18 06:39:50 -05:00
Taylor Richards 11d3348d64 enable/disable extra cmdline options for standalone 2022-01-18 06:39:50 -05:00
Taylor Richards a0769910f3 free loaded models after mission on standalone 2022-01-18 06:39:43 -05:00
Taylor Richards 5e2a4c05a3 make sure particles don't get processed on standalone 2022-01-18 06:38:35 -05:00
Taylor Richards 422c20d396 avoid initializing stuff that standalones don't need 2022-01-18 06:38:34 -05:00
Goober5000 0a4d589c17 log whether command briefing is using scroll buttons
Add a logging statement to let modders know that the command briefing is deliberately using, or not using, scroll buttons.

Fixes #3550.
2022-01-17 23:52:14 -05:00
Goober5000 5531de2b84 Merge pull request #3879 from Goober5000/timestamp_redesign
convert the FSO timestamp system to use SDL time
2022-01-17 20:54:12 -05:00
Taylor Richards 6ee6ddf49f fix missing texture bug on standalone (#3937)
The file used by bmp_load()/bm_load_animation() is a hardcoded
interface image on standalone servers. If the value of dir_type
isn't ALL or INTERFACE then it can't find the image. For ship
textures this can cause primary weapon hits to not register on
the server.
2022-01-17 20:39:26 -05:00
Goober5000 4ee84b71d7 refactor some names 2022-01-17 19:03:23 -05:00
Goober5000 dfd0614311 allow dockpoints to be anchored to submodels explicitly
By anchoring a dockpoint to a submodel, the dockpoint will move when the submodel moves.  Historically this has been done by inspecting the path associated with a dockpoint, but this method will not work if there is no path or no rotation mode specified.  Here is an alternate method that allows the submodel to be specified explicitly through a dockpoint property.
2022-01-17 17:31:51 -05:00
wookieejedi 53ecfa18ed Fix Bay Door Animations for Multi and Lone Player Ship (#3932)
For a long time, bay door animations would not trigger if the player was arriving from the bay as the the only ship in the wing. This was fixed by adding a check for the player. This check uses the `Player_obj` to check if the ship is as player, which does not work on standalones since the `Player_obj` is always the Standalone Ship.

This PR changes the check to check if the flag `Player_ship` is set, which is a common strategy used to make these kinds of checks work on standalones.

Tests show the old behavior still works as expected.
2022-01-16 23:19:31 -05:00
Goober5000 9c7a9a1c20 patch a hole in the pausing and make sure timer pause/unpause is always called 2022-01-16 15:24:43 -05:00
Goober5000 73a408043b time compression now works 2022-01-16 15:24:43 -05:00
Goober5000 18f4f490d0 time compression outline, static casts 2022-01-16 15:24:43 -05:00
Goober5000 97f9aa2259 move stuff here too 2022-01-16 15:24:43 -05:00
Goober5000 cf6a460422 move some stuff around 2022-01-16 15:24:43 -05:00
Goober5000 00de4c3e7e timestamps should be running just about all the time 2022-01-16 15:24:43 -05:00
Goober5000 e3b4171f06 no need to keep Debug_dump_frames anymore 2022-01-16 15:24:43 -05:00
Goober5000 a1dadb1c0b small refactor 2022-01-16 15:24:43 -05:00
Goober5000 0dc3c914d9 tweak the event music start so that missions will be consistent regardless of the player entry delay 2022-01-16 15:24:25 -05:00
Goober5000 8e33644a8f since we used to fast-forward at the rate of 1/4 second per frame, simulate the same thing with the timer 2022-01-16 15:20:57 -05:00
Goober5000 12363fe18d qtfred 2022-01-16 15:20:57 -05:00
Goober5000 88f4163ae3 always give the game priority when starting/stopping time 2022-01-16 15:20:57 -05:00
Goober5000 1b51225c51 convert the FSO timestamp system to use SDL time
Previously, the game used a dead-reckoning system for measuring time, where several time counters were incremented as long as time was running.  This unfortunately has no way to synchronize time in the long term, and therefore in-game time will tend to run faster or slower than real time by a few percent, depending on various factors.

This PR redesigns the timestamp system to use the SDL time counter which will always keep it in sync with real time.  However this necessarily involves a bit of clever handling when the game is paused and unpaused.  It also revealed several minor bugs in several places in the code where timestamps were handled.

This PR is currently in draft status until the design can be updated to handle time compression.  In all other respects it should be working.
2022-01-16 15:20:57 -05:00
Goober5000 aad7800ed8 Merge pull request #3931 from wookieejedi/revert-mission-music-change
Revert timestamp change for event music
2022-01-16 15:19:35 -05:00
wookieejedi ef5e549dca Revert timestamp change for event music
The timestamp fix/cleanup in #3878 revealed a longstanding bug with music timestamps--the timestamps were never set to something valid later.

This is a widespread issue in the code, fortunately Goober is modifying the timestamp code to accommodate invalid timestamps.

Tested and works as expected. Fixes #3930.
2022-01-16 14:35:56 -05:00
EatThePath baa696f643 Fix first person glows (#3882)
* Split glow current brightness calculation into a new function for reuse and clarity

* Readability cleanup pass on model_render_get_point_activation

* created a new code path to add the lights for the player's ships' glowpoints without rendering their sprites.

* cleaning up unused args from new glowpoint functions

* cleanup redundant externs

* Documentation and naming pass
2022-01-16 14:26:56 -05:00
BMagnu 4e0cb87b0c properly calc anim for instant (#3928) 2022-01-16 15:07:16 +09:00
Timo Gurr 84a333c787 FFmpeg deprecations fix for FFmpeg >= 5 (#3927)
FFmpeg commit e67e02d15672 [1] dropped avcodec.h from avformat.h includes hence
add an include for it to fix build after that commit.

[1]: https://github.com/FFmpeg/FFmpeg/commit/e67e02d15672a87da1b0566e197a1e19dc7e1e33
2022-01-15 22:37:17 -05:00
wookieejedi b383ceb8aa Allow AI flag for bay orientation to account for parent uvec (#3925)
* Allow AI flag for bay orientation to account for parent `uvec`

The previously added flag `Fighterbay_arrivals_use_carrier_orient` (#3698) incorporated the parent ship's `rvec`, which greatly helped align emerging ships from fighter bays. In parent some ships though, emerging ships still showed a `uvec` that did not match the parent ship (such as FotG's Star Destroyer). This PR allows the `Fighterbay_arrivals_use_carrier_orient` flag to take parent `uvec` into account.

Note, that departing the mission into a bay already has code to ensure a `wheels-down` landing.

PR is tested and works as expected/fixes `uvec` issue.

* only set uvec as lazy option
2022-01-15 22:36:48 -05:00
wookieejedi 77c7b0271e Fix incorrect net signature for wave ships (#3924)
Previously, multiplayer missions with wings with waves would incorrectly set the `net_signature` of ships in the initial wave. The code is supposed to only set the `net_signature` if it was past the initial wave. This is because original ships in the wave have their `net signature` set at mission parse.

This PR fixes that and has been confirmed to work via multiplayer tests.
2022-01-14 22:02:38 -05:00
The Force e8a19b7974 Implements Save (#3922) 2022-01-15 01:21:04 +09:00
Allen A. Babb 677ea7e46f Fix issue #3912 (#3914)
* Move dynamic XSTR stuff out of controlsconfig.cpp and move it into controlsconfigcommon.cpp.
- Needed because these strings are used in places other than the controls menu.
2022-01-12 19:14:51 -06:00
wookieejedi fef8959cff Add AI to Fix Negative Turret Ammo (#3913)
* Add AI to Fix Negative Turret Ammo

Previously, turrets with ammo would end up firing one extra shot, resulting in a -1 ammo.

This was because of the check `ammo[bank_to_fire] >= 0`, in `aiturret.cpp`. This PR adds an AI flag to have the turret only fire if the ammo is greater than 0 (`ammo[bank_to_fire] > 0`), as opposed to greater than or equal to 0.

Tested and the flag fix works as expected.

* feedback

* set to on for target 22
2022-01-12 07:32:10 -05:00
BMagnu dd7bd1fb72 Animation Rework, Phase 4: Moveables (#3904)
* Add C++11 std::any implementation

* Add basic moveable functionality

* Add rotation moveable

* Revise Segment Parsing Register

Because apparently, the linker and I disagree on which symbols should be discarded when linked into the final application...

* Fix small problems

* Address feedback

* Address feedback 2
2022-01-12 14:54:28 +09:00
Allen A. Babb 6b26df19d1 Merge pull request #3905 from z64555/fix/issue_3901
Fix #3901: Inverted Controls Don't Save
2022-01-09 15:21:48 -06:00
BMagnu 42c1957adc Properly handle negative case (#3910) 2022-01-10 04:01:21 +09:00
Goober5000 647316e83b Merge pull request #3880 from EatThePath/lt_lab
Add tonemapping options to lab render settings
2022-01-08 17:54:45 -05:00
Goober5000 eefb827171 Merge pull request #3885 from qazwsxal/lightshaft_fix
Fix shadow check on lightshafts
2022-01-08 17:54:38 -05:00
Goober5000 75ff1383c7 Merge pull request #3908 from wookieejedi/ttf-support-for-multi-screens
Fix text overflow on multi-related screen
2022-01-08 17:53:35 -05:00
Goober5000 e4c99b1df6 Merge pull request #3909 from Goober5000/fix_3907
fix 3907
2022-01-08 17:53:18 -05:00
Goober5000 94bd93343f fix 3907
Move the initialization of `used_weapons` to `weapon_init` since that's where it belongs.  Also call `weapon_level_init` in the lab since investigation revealed a few other things that needed to be done there.
2022-01-08 16:10:18 -05:00
wookieejedi 589da9648f add comment noting default font height 2022-01-08 16:08:51 -05:00
wookieejedi 0f3f19d5d8 fix spelling 2022-01-08 15:29:20 -05:00
wookieejedi 7f8957ba0d Fix text overflow on multi-related screen
Multiplayer screens such as PXO lobby, chat boxes, and multi-game setup screens had hard coded values for the number of lines to display. These would only work correctly with the default .vf font01 from retail. If a mod or user used a TTF or other .vf font than text would spill over. This PR makes these values take into the account the font used.

Tested and works as expected with TTF fonts and the retail fonts.  Marking as draft to see what others think.
2022-01-08 13:57:58 -05:00
z64555 d74c419295 Preset identification should only be invert agnostic when reading a CSG<7 file, for all other uses of control_config_get_current_preset(), it should be exact equality with the preset. 2022-01-08 10:15:00 -06:00
Goober5000 59442efbbf Merge pull request #3872 from notimaginative/dynamic_cfile_blocks
make cfile root and file blocks dynamic
2022-01-08 02:46:55 -05:00
JohnAFernandez 5740ee8eed Merge pull request #3900 from z64555/fix/issue_3892a
Fix 3892 Amendment
2022-01-06 13:11:16 -05:00
z64555 1dd347adb9 Use correct version var when inside CSG stuffs. 2022-01-06 11:42:02 -06:00
Goober5000 94b8c283e6 Merge pull request #3897 from Goober5000/fix_first_of
fix first-of to return the correct arguments
2022-01-05 21:47:51 -05:00
Allen A. Babb 41b3d0fdaf Merge pull request #3898 from z64555/fix/issue_3892
Fix 3892
2022-01-05 20:37:09 -06:00
z64555 2289976fa9 Add catches for edge cases when control_config_get_current_preset() returnes ::end() within csg and plr read/write.
* Add assertsions during csg and plr read/write to make sure the Controls_config is initialized.
2022-01-05 19:57:57 -06:00
Goober5000 ed54b79425 fix first-of to return the correct arguments
Change the threshold logic to return the correct elements from the beginning of the list, not the end.  Fixes #3896.
2022-01-05 19:03:55 -05:00
wookieejedi ce105df6c6 Revert timestamp changes for HUD (#3895) 2022-01-05 17:22:55 -05:00
BMagnu 61b87e682c Handle forgotten 0 case for new vecmat function (#3891)
* handle forgotten 0 case

* Reduce tolerances again
2022-01-06 02:01:28 +09:00
wookieejedi ca6a1045cb Fix Particle PageIn (V2) (#3893)
It turns out the particle preloading fix revealed a long standing bug in the particle `pageIn()` function--it should be calling `bm_page_in_texture()` instead of `bm_page_in_aabitmap()`. It's been wrong the entire time and we didn't notice because of the frame bug, which was fixed in #3884. Without this fix, when it's preloaded it locks the image as 8-bit, when it force loads it's 24-bit. Tested and works as expected.

Fixes #3890.

Massive thanks to taylor for spotting this!
2022-01-05 11:29:41 -05:00
1fa6e00f39 Controls 4 and 5 - Multi-joy and Preset Files (#2958)
* Updates the AxisInverted hooks to use the new CC_bind.  Currently assumes only Joy0, so this may need further tweaking or replacement

* * Add ability to claim up to 4 joysticks for player use, using the launcher (via registry or fs2_open.ini) or the new menu system
* Hack into existing control polling system to get the new primary/secondary binding schema to work.  This should be reworked into a reverse-lookup system.
* Finally break the mouse loose from overlapping with Joystick binidngs
* Fix bug where joy button wouldn't register on search function
* Fix bug with mousewheel not always decaying as it should.
* Fix rebase conflict with selecting item during search mode

* Fix bug where mouse buttons were incorrectly labeled.

* Move some enums around

* Fix bug with joy axis labels being displayed as buttons.
* Fix possible bug where Other conflict axis wouldn't clear
* Updated default joystick axis text. A new strings.tbl will need to be supplied for localization support

* Deprecate nAxisInverted ADE functions and replace with AxisInverted(int, int, bool)

* Merge Axis mappings into Control_config
* More utility functions for CC_bind and CCB
* Adds another ADE function for inverting the axis action, instead of individual bindings
* Hacks to get plr file to compile.  Currently slices out many of the new features like secondary axis and the mouse axis, and the additional joystick bindings (joy1, joy2, joy3)

* Fix bug with uncontrollable spin (slopily)
* Fix some warnings
* Add flags for Hats and Balls for future implementation

* Fix bug where inverting an axis would trigger an assert

* Fix bug where joy wasn't detected as present

* Most axis actions should be relative, instead of absolute
* Hopefully optimize joy_get_unscaled_reading
* Properly break out of double-for search function for search and bind modes in config menu
* Refactor control_get_axes_readings to provide more consistent behavior
* Use JOY_REL_THROTTLE instead of Action::REL_THROTTLE when indexing into Control_config

* Bank axis has a default binding, Throttle does not.

* Fix bug where conflicts weren't being detected.
Fix bug where default presets weren't being detectd

* Elegantly break out of double fors with goto.
Fix bug with bind mode not detecting axis

* Save new binding scheme to playerfile
* Add cid_assign() to standardize cid assignment with shorts
* Add write and read handlers for int8_t

* Remove saving controls to csg.  This will be replaced by presets.

* Fix bug with reading pilotfile

* Use "Joy-n" instead of "joystick n" to match default identifiers in config menu

* Fix bug with CC_TYPE_TRIGGER controls always marked as used, if not bound with a key.
Fix bug with Joy-0 btn 1 triggering multiple controls that are not bound to it.

* Improve readibility of the joy info output to log
* Message when a joystick connects and using legacy system.
* Fix bug where system joystick 0 was mapped in pJoystick that should've been nullptr

* Fix bug where *not* having a joystick will cause bind mode in the config menu to immediately cancel.

* Add reverse lookup functions for actions.  mActionToVal[] does string -> int, mValToAction() does int -> string

* Add the foundation for writing the presets files.
* Adds a bunch of reverse lookup functions to get the stringified version of various enums, etc.
* presets.h and presets.cpp are in something of a barebones at this point

* Add new subdir for preset files 'player/presets'
* add utility for finding the distance of a bitfield/bitmask.  Used to translate mouse button masks into mouse button id's
* Write PresetFileHandler as standalone, instead of a subclass.  Still mostly a copy of JSONFileHandler
* Make functions to map and reverse-map the bindings for use with the preset files and ultimately the ControlConfigDefaults.tbl as well

* Check presets from file to see if they are duplicate with an existing preset.

* Check for uniqueness of presets fron controlconfigdefaults.tbl before adding them, and warn the user if there are duplicates.

* Rename the test functions into proper load/save.
* save function has some standard checks
* load function is called on init
* make finding duplicates its own function outside of the preset label rendering function
* Initial draft of saving presets in-game

* Fix bug where all loaded presets were thought to be duplicate of defaults.

* Fix bug where preset cycling would get stuck on the first preset other than default

* Fix bug where saving a mouse button saves the wrong textified string.

* Prevent preset names from being too long.
* Crash still occurs if the name is too long, as if set outside of FSO
* Workaround text running off the popups in 640x480.  Doesn't look as nice, sadly

* CSG's now track preset names instead of containing bindings
* remake control_config_reset_defaults() into control_config_use_preset()
* provide a function to get the currently selected preset.

* Do PLR backward compatibility, hopefully.

* PLR now tracks presets instead of saving the bindings.

* On Loading pre PLR3 or CSG6 data, create a new preset.

* Strip off file extension before saving preset files. Jason.json.json just looks dumb

* Add "-joy_info" commandline option.  Will output SDL joystick info of all detected joysticks to stdout

* Fix non-standard behavior with registry_read_string().
* Returning NULL instead of the default value, or an empty string, will trigger an access violation with SCP_string and other string copy functions.

* Modify io::joystick::init() to take an optional param, no_register, to use with -joy_info

* Address CI complaints

* Address CI issues 2.

* Supress preset duplicate warning if in unit tests.

* Address scripting unittest failure due to incorrect argument type. (Ints don't technically exist in LUA)

* Use Mouse enums instead of Joy enums or magic numbers

* More signed/unsigned madness

* Address CI issues 3

* Address gcc-5 issues. (No auto in lambdas)
* Fix bug with bit_distance()

* Address gcc-5 issues 2

* Address clang issues

* Address clang-tidy issues

* Address clang-tidy issues in undosys.  May need to be cherry picked to Controls2.

* Address clang-tidy issues

* Improve logic of preset name prompt.

* Fix bug with selected presets not being saved

* No, a cstr is not a std::string.
* Can't use i there because its already defined.

* Fix bug where CSG's wouldn't save selected preset
* Fix bug where presets wouldn't be loaded correctly from player files
* Fix bug where loaded preset files would not update the preset cycle position correctly

* Some QoL changes for the preset name prompt

* Address Appveyor issues.

* Add forward compatibility for player file.  This is required because currently any "missing" data in the pilotfile will trigger an Error, and crash FSO.

* Fix bug where mouse X axis was unusable.
Apparently stating that MOUSE_Z_AXIS IS MOUSE_Z_AXIS doesn't get the point across.

* Address CI issues.

* Address CI issues.
* sel default assigned to -1
* static_cast enum to an int

* Assimilate -joy_info int -get_flags, replacing the existing method that launchers use to get joystick information.

* Add '\n' to PST log messages.

* Change logic of checking joystick .ini keys:  Should the multi-joy key not be found, try legacy joy key.

* Add some more missing '\n' to mprintf messages.

* Notify the player when converting to the new multi-joy system. (Using ReleaseWarning for now...)
* Warn the player if a preset defined in their .PLR could not be found.

* Actually disable control items without a valid tab, instead of relying on the fact that they're disabled  by default.

* Add CC_preset::is_duplicate_of() method to make checking for preset uniqueness less of a brain teaser.
* Doxy the first_override param of control_config_common_read_section

* Adds the os::dialogs::Information() method, which displays an information-only dialog in similar format to Warning and Error dialogs.  Does not throw Warning nor Error exceptions
* load_player now uses os::dialogs::Information() instead of ::ReleaseWarning, thus not halting unit tests.

* Breaks retail localization support for Joystick and Mice labels - This is because the new multi-joy axis end up very confusing "Joy-0 Joystick/Mouse X Axis"
* Renames Joy_axis_text to Axis_text, intended to be used both by joysticks and the mouse.
* Moves mouse axis and button labels into an array to ease future XSTR support
* Adds asserts to ensure indices are within the array sizes of label arrays
* Adds XSTR indices for Axis labels, mouse buttons, and mouse wheels.

* Seperates conflict check comparisons from equality comparisons.
*  Conflict checks can ignore certain combinations of CC_bind::flag's; i.e. an Axis bound to a different control but is inverted or relative will still cause a conflict with another control that has the same axis
*  Equality comparisons is exact equality, allowing presets to check if binds have the same binding and flag configurations.

* More UI string changes and localization
* Tweaks positioning of top button labels in CC menu
* Adds the following XSTR's:
1659 "Preset: %s"
1660 "Preset: custom"
1661 "Next Preset"

* Fix bug where mouse axis turned into mouse button when inverting control by its control name.
* Fix bug with the new conflict checking subroutine not working with non-axis controls

* Address CI issues.

* Don't trigger modal popups while in unit tests.

* Address clang tidy issues
* use nullptr
* be consistent with conditional style
* use booleans to stuff debug states, methods with just Assertions in it will trigger a false positive on clang tidy
* use string::empty() instead of checking for "".

* Remove dead code of -joy_info.  Functionality has been merged with -get_flags

* Address clang-tidy [readability-simplify-boolean-expr]
--z64 says "I don't like it!"

* fix axis check

* Implement revised axis action virtvars for scripting. Also protect against a control mismatch in the CSG file due to a script-inverted control

* Encapsulate CC_bind properly
* Add mouse and joystick cid's to AxisInverted description

* Update translate_key() and its user to correctly translate multijoy bindings for training messages.

* Prompt user trying to escape from config menu when they have changes.
* Remove dead function.

* Fix crash during training missions due to key translation that would overflow internal buffer.
* Went back with cstring as return value instead of SCP string, because caller would need a significant refactor
* Update doxy of the textify functions

* Unify textify_scancode() and textify_scancode_universal() to ensure common code path.

* Add "Multijoy" entry to json caps. (For Knossos)

* Make CI happy.
* Remove unused lambda captures.

* Instead of overwrite during plr2 => plr3 conversion, try to use the existing preset file.

* Fix conditional for checking if file exists within presets::save_preset_file()

* Revert Majority of PR#3739
* PLR and CSG versions are incremented past versions set by 3739
* Forward compatibility feature of #3739 (Only save sexp containers into the CSG if they are used) is removed

* Remove forward compatibilty of PLR file when going in between pre- and post-Controls5 FSO versions
* Add missing startSection() and endSection() for csg_write_controls()

* Fix clang-tidy error #1

* Fix clang-tidy error #2

* fix clandy tidy error #1 part 2/2

* Fix clang tidy error 3

Co-authored-by: Goober5000 <[email protected]>
Co-authored-by: Tyler Blount <[email protected]>
Co-authored-by: wookieejedi <[email protected]>
Co-authored-by: BMagnu <[email protected]>
2022-01-04 12:01:32 -06:00
Goober5000 62e9719712 Merge pull request #3888 from Goober5000/fs1_target_behavior
add game_settings flag to not target turrets
2022-01-03 19:16:10 -05:00
Goober5000 5c122a2913 add game_settings flag to not target turrets
In FS2, the HUD will automatically target the first turret on any BIG or HUGE ship.  In FS1, this did not happen.  This adds a flag to disable the new behavior.

The change is needed because the scan view cone is significantly constrained when any turrets or subsystems are targeted.  This makes Playing Judas quite a bit more difficult than it was designed to be.
2022-01-03 18:23:27 -05:00
Goober5000 a5318e45ae Merge pull request #3887 from notimaginative/file_load_fixes
file loading performance fixes
2022-01-03 18:08:21 -05:00
Taylor Richards c7de32d0af add dir_type to bm_load()
Modify bm_load() so that it will only search in intended paths,
improving performance of both fast and slow loading of image
files. Now matches behavior of the other bm_load_*() functions.
2022-01-03 16:59:05 -05:00
Taylor Richards d9b9607e14 fix broken cfile slow search optimization
By default cf_find_file_location*() will always hit the filesystem
for certain paths. The flag for this was not reset between different
paths so it ended up always hitting the filesystem.
2022-01-03 16:58:57 -05:00
Goober5000 8710b9fac7 Merge pull request #3886 from Goober5000/small_skybox_cleanup
move various skybox variables into the header file
2022-01-03 16:34:59 -05:00
Goober5000 b6706c8b3c move various skybox variables into the header file 2022-01-03 16:00:38 -05:00
wookieejedi 0a9a7a5eea Fix Particles pageIn to use nframes (#3884)
Previously the `bm_page_in_aabitmap` call in `ParticleProperties::pageIn()` used -1 as the number of frames. It seemed particles with more than 1 frame still worked correctly, but likely prevent preloading of particles. This PR fixes that to use the actual number of frames.
2022-01-03 15:53:28 -05:00
Unknown 73ed3e3bec Fix shadow check on lightshafts 2022-01-03 19:18:21 +00:00
BMagnu 1c19199df3 Animation Rework Phase 3, Turret fix (#3877)
* Change animation turret canonicalization to now correctly calculate the closest natual turret positon

* Add angle error to vm function for convenience

* Div by Zero safety for non IEEE compliant systems

* Incorporate style changes
2022-01-03 18:54:11 +00:00
JohnAFernandez 5116d3f1ca Merge pull request #3881 from EatThePath/ppc-safety
Added ppc calculation initial value bounding and calculation fixes
2022-01-03 13:43:44 -05:00
David Gibson 47f6da591f Readability and documentation pass on new tonemapper lab options 2022-01-03 12:38:17 -06:00
Goober5000 3143d9fdcc Merge pull request #3878 from Goober5000/timer_preliminary_cleanup
Timer preliminary cleanup
2022-01-03 01:12:59 -05:00
David Gibson fe1068630f style and documentation fixes 2022-01-02 15:38:27 -06:00
David Gibson 91fe2bfc90 Implemented ppc sliders 2022-01-02 15:20:49 -06:00
David Gibson 890756cc7d Added ppc calculation initial value bounding and calculation fixes 2022-01-02 15:18:53 -06:00
David Gibson f73d452d5d adjusted the range of exposure slider 2022-01-02 13:19:49 -06:00
David Gibson f9b104aecd Lab tonemapper selection implemented 2022-01-02 13:19:49 -06:00
Goober5000 5b3207f548 use the proper timestamp function 2022-01-02 01:50:49 -05:00
Goober5000 0c6169d384 remove old comment using private API 2022-01-02 01:03:52 -05:00
Goober5000 c9ac9a3635 use correct initialization for invalid timestamp 2022-01-02 01:03:52 -05:00
Goober5000 009abe22fe fix comment 2022-01-02 01:03:52 -05:00
Goober5000 93757bcc61 replace Int3() with UNREACHABLE 2022-01-02 01:03:52 -05:00
Goober5000 28c0d51def remove redundant weapon_level_init 2022-01-02 01:03:52 -05:00
EatThePath dc0f394afd Moved the PPC tonemapper intermediate calculations to C-side to clean up shader compatibility with older versions of opengl (#3857) 2021-12-31 21:27:46 -05:00
Taylor Richards 0d7689f495 add safety catch for min block sizes 2021-12-31 15:59:33 -05:00
Taylor Richards 4ee2c82976 switch to unique_ptr's 2021-12-31 15:58:23 -05:00
Asteroth 329efb8c3a clarity function for homing objects and fix scripting target setting (#3865) 2021-12-31 13:13:56 -05:00
Goober5000 b10a230f8f Merge pull request #3873 from Goober5000/nonfatal_sexp_errors
make certain SEXP errors nonfatal
2021-12-29 23:42:13 -05:00
Goober5000 31bbda0ec0 make certain SEXP errors nonfatal
Some SEXP errors, although they indicate real problems, will not prevent the mission from running.  Add these as exceptions.  Implemented per requests from users of Blue Planet and Solaris.
2021-12-29 23:07:06 -05:00
Taylor Richards 9f28ba2a37 make cfile root and file blocks dynamic 2021-12-29 22:47:59 -05:00
Goober5000 185ee57d13 Merge pull request #3871 from Goober5000/fix_fred_crash
fix a FRED crash caused by recent changes
2021-12-29 22:37:03 -05:00
Taylor Richards e0972d5e45 take pathtype extensions into account during file indexing (#3869)
The cfilesystem cleanup PR (3734) failed to take pathtype extension
filtering into account when indexing loose files. This adds back that
functionality to prevent extra/unknown files from being indexed.

Fixes #3863
2021-12-29 22:27:04 -05:00
Goober5000 ab9f034102 fix a FRED crash caused by recent changes
This bit of code shouldn't run in FRED, but it wasn't a problem until recent changes made it so.
2021-12-29 21:45:00 -05:00
Goober5000 e4099ca562 Merge pull request #3866 from notimaginative/fix_warnings_errors
Fix warnings/errors from clang and valgrind
2021-12-29 13:19:45 -05:00
Goober5000 0966a4925f Merge pull request #3867 from notimaginative/fix_object_collider_mem
reset object colliders after each mission
2021-12-29 13:18:39 -05:00
Goober5000 d13937b6ab Merge pull request #3868 from notimaginative/fix_awacs_team_mem
set up awacs team arrays just the once
2021-12-29 13:18:03 -05:00
Taylor Richards 2d7aaa576c set up awacs team arrays just the once
Awacs team arrays only need to be initialized once but were
expanded by Iff_info.size() every second of a mission and never
cleared.

(Also includes cleanup)
2021-12-29 07:12:59 -05:00
Taylor Richards 3e0d95eff8 reset object colliders after each mission 2021-12-29 07:12:03 -05:00
Taylor Richards 8bbf2814fb silence clang compiler warnings 2021-12-29 07:07:26 -05:00
Taylor Richards 39c21f3f6f fix valgrind error in stuff_float()
The *f variable isn't initialized except on success so it
shouldn't be referenced except in that case. Matches how
stuff_int() does it.
2021-12-29 07:07:16 -05:00
Taylor Richards 6e3b75c613 silence valgrind errors in SENDTO() 2021-12-29 07:07:02 -05:00
Goober5000 a52024c5eb Merge pull request #3864 from jg18/events-editor-esc-check
Add comment on why event_editor::OnCancel() is blank
2021-12-28 18:54:23 -05:00
Joshua Glatt 40b47ed8a8 tpo fix 2021-12-28 14:56:46 -08:00
Joshua Glatt be89d88313 revert change and add comment on why event_editor::OnCancel() is blank 2021-12-28 13:49:24 -08:00
Joshua Glatt 9d79c8f947 check for unsaved changes in Events Editor before closing with Esc key 2021-12-28 11:55:35 -08:00
Goober5000 69d1551ccd Merge pull request #3858 from notimaginative/fix_ship_subsys_mem_leak
fix memory leak when reallocating ship subsystems
2021-12-28 00:30:13 -05:00
JohnAFernandez 9f42116885 Merge pull request #3856 from Baezon/phys-info-ab-speed-display
Use phys_info for max AB speed display instead of ship_info
2021-12-27 17:55:19 -05:00
Taylor Richards 9ede53b406 fix memory leak when reallocating ship subsystems 2021-12-27 17:25:50 -05:00
Asteroth 1a39961d59 use players phys info for ab max speed instead of ship info 2021-12-27 15:54:47 -05:00
Asteroth c3c75ff880 Fix weapons with submodel rotation firing (#3850)
* remove vestigal code from 'remove 'stream' weapon handling

* unused variable
2021-12-26 13:26:58 -05:00
Asteroth 7bec61f195 Make secondaries use $energy consumed (#3847)
* secondaries can consume energy, and only flash energy bar if depleted energy

* tweaks

* fix weird spacing
2021-12-26 13:25:31 -05:00
Joshua Glatt c6ecf88aec karajorma's SEXP containers, Part 5: Sexp_nodes (#3495) 2021-12-24 17:49:36 -08:00
Goober5000 2218fde9b5 Merge pull request #3851 from Goober5000/custom_language_fix
fix language indexing for custom languages
2021-12-24 20:38:11 -05:00
Taylor Richards b74b6339a8 improve handling of PXO lobby banners: (#3819)
* improve handling of PXO lobby banners:

 - add custom banners support for mods
 - remove broken banner randomization code (from retail)
 - remove banner hover outline if it's not really clickable
 - randomly choose a new banner over time if user is in lobby long enough
2021-12-24 17:25:15 -05:00
Joshua Glatt ab5aa71628 Fix random selection of points for SphereShape particles (#3841) 2021-12-24 10:06:47 -08:00
BMagnu 9930d435a2 Animation Rework Phase 3 - Fixes for Multi (#3846)
* Switch Multimsg to use netsig for animations

* Unique-ify animation ID's

* Clang Tidy

* Implement first suggestions

* Implement suggestions 2

* Add get model instance safeguard
2021-12-25 03:01:13 +09:00
Goober5000 8a803d7aef fix language indexing for custom languages
One of my XSTR and localization fixes from last year did not account for the presence of custom languages.  This PR uses the correct threshold and also adds a warning in case some mod really wants to define more than 6 additional languages.
2021-12-23 19:27:55 -05:00
Taylor Richards 0e059459d8 improve PXO data validation code (#3817)
* add batch validation for tables
* add batch validation for missions
* handle server connection errors in a more useful way
2021-12-23 09:06:26 -05:00
Goober5000 7fe3b78f18 Merge pull request #3845 from Goober5000/fix_assert
remove a redundant assert that throws false positives
2021-12-23 01:36:13 -05:00
Goober5000 8b2a3ca253 remove a redundant assert that throws false positives 2021-12-23 01:06:14 -05:00
Goober5000 6cafd64e78 Merge pull request #3837 from Goober5000/sexp_error_location
improve SEXP error handling a bit
2021-12-22 23:09:58 -05:00
Joshua Glatt 6afb6226ea Clarify logging when loading thruster textures as static images (#3839) 2021-12-22 18:58:20 -08:00
Taylor Richards 6a91127394 Merge pull request #3844 from notimaginative/fix_awacs_multi_crash
fix multi awacs crash due to code init order
2021-12-22 21:10:53 -05:00
Goober5000 09cfc6e9e4 Merge pull request #3843 from Goober5000/polymodel_instance_update
update polymodel_instance to reference object
2021-12-22 20:35:01 -05:00
Taylor Richards a40dfd7756 fix multi awacs crash due to code init order 2021-12-22 19:35:30 -05:00
Goober5000 c3dd6eb113 update polymodel_instance to reference object
See title.  All references to `model_create_instance` have been updated to supply an object number or -1.
2021-12-22 18:29:00 -05:00
Goober5000 f2c858e2fa Merge pull request #3838 from EatThePath/fix-bad-const-uniforms
Removed consts being set from uniforms to fix #3821
2021-12-21 13:21:59 -05:00
Taylor Richards 007fe45fec Merge pull request #3820 from notimaginative/reduce_bsp_align_memory
reduce memory required for bsp alignment
2021-12-20 17:57:26 -05:00
David Gibson e7d0d15e81 Removed consts being set from uniforms to fix #3821 2021-12-20 16:54:22 -06:00
Goober5000 0e828080ac qtfred 2021-12-20 14:02:33 -05:00
Goober5000 e893d15000 improve SEXP error handling a bit
1) Sync formatting of each place SEXP errors are reported
2) Add error location (event or goal) if possible when mission is loaded

Note that the two FRED error dialogs already indicate the event or goal.
2021-12-20 13:57:17 -05:00
Taylor Richards 73994bb2d8 reduce memory required for bsp alignment
Previous code allocated 4x bsp_data_size for alignment, whether it was
needed or not. Now it should allocate slightly more than 2x and only if
alignment is required.
2021-12-18 19:43:57 -05:00
Goober5000 1f531b69f1 Merge pull request #3816 from Goober5000/fred_ui_updates
Fred UI updates
2021-12-14 18:45:53 -05:00
wookieejedi d2f15afcec Set Default Detail Levels to be Consistent at Ultra Settings (#3811)
By default, new pilots have `Model` and `Nebula` detail only set to 4/5 (all others are on 5/5). Furthermore, clicking `Very High` on the model presets options still does not increase the `Model` or `Nebula` detail, as they remain at 4/5. This occurs with making a new pilot in retail, along with making new pilots in mods with a game settings default detail level of `Ultra`.

Simply changing the default values in the code for `Model` and `Nebula` detail to match the other detail levels is the easiest and cleanest solution IMO. I would be happy to alter this though to use a game settings table flag instead, if that is preferred.

Tested and works as expected.
2021-12-14 12:43:16 -05:00
Goober5000 ef917998f7 restore the proper 'class' logic, which was broken in commit 3005e447d3 2021-12-12 02:33:51 -05:00
Goober5000 cdcb8a611c update CMakeLists 2021-12-12 02:19:34 -05:00
Goober5000 8f91d82a73 even more asteroid target fixes 2021-12-12 01:50:15 -05:00
Goober5000 e31518be71 make BackgroundChooser a bit more flexible 2021-12-11 23:00:07 -05:00
Goober5000 5a35c308fb wip asteroid field dialog modifications 2021-12-11 17:21:35 -05:00
Goober5000 51aaf8f5b2 fix this, which broke at some point previously 2021-12-11 16:34:48 -05:00
Goober5000 eb0610f818 this too 2021-12-11 16:20:26 -05:00
Goober5000 04141bc122 more tweaks for the custom closeup label 2021-12-11 16:18:55 -05:00
Goober5000 9db0c7179b closeup label fixes 2021-12-11 15:00:14 -05:00
Goober5000 2f832d2883 fred ui partial updates for briefing editor and asteroid field editor 2021-12-11 14:11:10 -05:00
Goober5000 5a080c94a5 Merge pull request #3814 from notimaginative/fix_hud_config_loading
add players directory to slow search
2021-12-11 13:03:29 -05:00
Goober5000 375cebf666 Merge pull request #3813 from notimaginative/fix_get-file-list_length_bug
fix file name getting trimmed in cf_get_file_list()
2021-12-11 13:01:54 -05:00
Taylor Richards 17e9d3c0af add players directory to slow search
Fixes new hud config files not being usable until after restart.
2021-12-11 08:28:20 -05:00
Taylor Richards 3755ffe835 fix file name getting trimmed in cf_get_file_list()
Fixes bug in the old dynamic cf_get_file_list() introduced by the
3734 PR. That PR used SDL_strlcpy() to copy the filename which
always null terminates the string, but was only given the length
of the string itself as the available space, so the last character
was removed.
2021-12-11 06:05:06 -05:00
BMagnu dbe60decb4 Expose OSWPT to Lua and allow for LuaSEXP argument (#3637)
* Expose OSWPT to Lua and allow for LuaSEXP argument

* Incorporate Feedback
2021-12-11 12:37:30 +09:00
BMagnu 79283d9002 Animation Rework: Phase 3 (#3793)
* Refactor submodel handling by animation code

* Add Animation Flags

* Add Codeowner for animations

* Add new Animation Table

* Time Fix

* Weapon Launched trigger + bugfixes

* cleanup rebase artifact

* Add WeaponFired triggers

* Table deprec

* Allow multiple animations on the same trigger

* Add Translation segment

* Integrate new Animation workflow

* Small Fixes

* Submodel not found safety

* Add Pause

* Also allow dockport name

* Update Animation SEXP/Scripting + fix change ship class issue

* Multi fix + disable old animation sexp

* Weapon Scripting Function

* Fix bugs and replace bind

* Add onspawn trigger type

* Fix issue on ship death

* Fix Absolute Rotation

* Fix erroneous application of animation, add random start phase

* Disable Translation

* Fix Clang

* Incorporate feedback

* Incorporate feedback 2
2021-12-10 14:44:13 +09:00
Goober5000 9002047523 Merge pull request #3799 from TheForce172/feature/PlayerOrdersDialog
QTFred Player Orders Dialog
2021-12-09 16:17:18 -05:00
Goober5000 ea03d183bc Merge branch 'master' into feature/PlayerOrdersDialog 2021-12-09 15:44:32 -05:00
Goober5000 f707bb6990 Merge pull request #3797 from TheForce172/feature/QTShipEditorSubdialogs2
QTFred: Special Stats Dialog
2021-12-09 15:41:24 -05:00
Goober5000 347c67b9c7 Merge pull request #3798 from TheForce172/feature/SubstituteShipLabel
Substitute Ship Label
2021-12-08 13:17:26 -05:00
Goober5000 869a5bf11c Merge pull request #3704 from Baezon/asteroid-arbitrary-targets
Allow for arbitrary asteroid targets in missions
2021-12-08 13:15:52 -05:00
Goober5000 2efbd6c1c1 Merge pull request #3800 from Kiloku/draw_objects_by_center
Add functions to draw rectangles and images by passing the center position
2021-12-08 13:15:15 -05:00
Fabian Woltermann 95890d9664 Merge pull request #3810 from EatThePath/lab-doc-fix
Fixed mistake in lab camera control help
2021-12-07 19:10:51 +01:00
wookieejedi 6ae4f55e91 Fix Default Sound Levels in Game Settings Table (#3809)
The game setting table allows  modders to set the default noise levels for new pilots, but the game did not actually use the values set in mod table. This PR fixes that and adds safety range checks, too. Tested and works as expected.
2021-12-06 21:39:42 -05:00
The Force 80db70d627 Retail compatibility 2021-12-07 00:39:09 +00:00
David Gibson 2c5c09addb Fixed mistake in lab camera control help 2021-12-05 17:29:32 -06:00
BMagnu 9d60eb615a Fix the tonemapper strings (#3806) 2021-12-05 02:32:57 +09:00
Asteroth 28aea0c36b consistent capitalization (#3805) 2021-12-02 20:55:15 +00:00
Asteroth 8161bdfb2f Expose turret re-targeting delay (#3803)
* check for enemies every frame

* expose turret target recheck time

* fix

* more fix
2021-12-02 15:13:29 -05:00
EatThePath c5410c6381 Lt22 (#3801)
* New configuration table for HDR tonemapping and related data.

* lighting profiles conslidation and cleanup

* Appease CI

* Lighting profiles parser now parses all tonemapping options

* simplified light profile parsing logic further

* Refrences for tonemapping functions added

* cleaned unused function definition

* Extra documentation for lighting tables

* Fixed lighting profile value label error

* Converted current_piecewise_values to const reference
2021-12-03 04:50:45 +09:00
Asteroth b54b402aa5 review tweaks 2021-11-28 22:52:21 -05:00
Kiloku 623b84dfb1 clean-up 2021-11-28 18:43:32 -02:00
Kiloku 50180168c0 Add centered image and rectangle functions 2021-11-28 18:02:43 -02:00
The Force b3e4e5e2b8 More gcc Apeaseing 2021-11-28 17:33:33 +00:00
The Force aa0a71709b Appease gcc 2021-11-28 17:27:46 +00:00
The Force 3a86d9ad19 Player Orders Dialog 2021-11-28 17:19:16 +00:00
The Force e5428ef309 Fix typo 2021-11-28 12:23:09 +00:00
The Force 8892ad0902 Create Files 2021-11-28 12:18:37 +00:00
The Force 6bfee19268 Add Field to Qtfred Briefing editor(currently nonfunctional) 2021-11-25 17:07:36 +00:00
The Force acc6fb4cfb #3757 Substitute Ship Label In Closeup View 2021-11-25 17:06:50 +00:00
The Force 29f80b5399 Appease Clang 2021-11-25 15:31:13 +00:00
The Force 42d324cdaa Make Dialog Modal 2021-11-25 14:33:30 +00:00
The Force 0c04ed7c7d Hits Side Complete 2021-11-25 14:27:26 +00:00
The Force 76a7cfd8fc Merge buttons and activate dialog 2021-11-25 13:28:33 +00:00
The Force d7aeb2ba32 Merge Master 2021-11-25 13:16:29 +00:00
The Force ec922610c0 Completed Special Exp Side 2021-11-25 13:11:56 +00:00
Asteroth 72cb381c86 fix 2021-11-25 01:12:49 -05:00
Asteroth 20c8a37ed0 even more fix 2021-11-25 00:48:31 -05:00
Asteroth 4cb4c214c2 more fix 2021-11-25 00:32:57 -05:00
Asteroth 8518084ecc bugfix 2021-11-25 00:28:44 -05:00
Asteroth 30672aa343 add a warning for no asteroid types 2021-11-24 23:08:03 -05:00
Asteroth b0b40deae7 add a better random asteroid type picker and some fred/qtfred support 2021-11-24 23:01:16 -05:00
BMagnu b30ee67387 load techroom model subsystems into seperate buffer (#3796) 2021-11-24 13:07:40 -05:00
Asteroth 8f3b5dd2c0 address some review feedback 2021-11-24 02:42:30 -05:00
Asteroth 2517025111 correctly position tail for laser head on glows (#3789) 2021-11-21 21:48:06 -05:00
Taylor Richards ce9214974a Merge pull request #3734 from notimaginative/cfilesystem_cleanup
clean up some inconsistencies in cfilesystem
2021-11-21 14:26:12 -05:00
BMagnu c1d3f655e0 Merge pull request #3791 from EatThePath/animation_safety2
guard against trying to animate non-existent submodels in more places.
2021-11-21 14:06:53 +09:00
David Gibson c3afeffe7f Style fix 2021-11-20 19:59:09 -06:00
David Gibson dba56a1fd9 guard against trying to animate non-existent submodels in more places. 2021-11-20 19:00:15 -06:00
Goober5000 1819265c65 Merge pull request #3777 from Kiloku/draw_rotated_images
Allow drawing rotated bitmaps
2021-11-20 18:08:07 -05:00
Goober5000 f12823b3a6 Merge pull request #3790 from Kiloku/rotated-rect-use-radians
Change rectangle rotation to use radians
2021-11-20 18:00:14 -05:00
Kiloku b557017b20 Fix documentation 2021-11-20 19:36:03 -02:00
Kiloku ad308757f4 Change rect rotation to use radians 2021-11-20 18:29:00 -02:00
Kiloku 67966cec9d Use radians rather than degrees for angles 2021-11-20 18:07:30 -02:00
Asteroth 327a65917d review fixes and tweaks 2021-11-20 00:02:55 -05:00
Asteroth 32cca98349 dont do passive lightning on destroyed subsystems (#3771) 2021-11-19 23:26:43 -05:00
Asteroth 62c97006f8 take into account glow size for glow head on (#3787) 2021-11-19 12:54:01 -05:00
Asteroth 496cef91c0 dont exclude primary targets from dead targeting (#3781) 2021-11-18 03:35:24 -05:00
Goober5000 479d28e4c9 Merge pull request #3774 from Goober5000/multiple_event_check
indicate ambiguous goal or event matches
2021-11-18 00:51:32 -05:00
Goober5000 d634ce6b62 Merge pull request #3786 from Goober5000/submodel_turn_accel
refactor submodel flags and add $rotate_accel
2021-11-17 22:16:25 -05:00
Goober5000 9d6eec939c refactor submodel flags and add $rotate_accel
1) Changes the submodel flags to use a flagset instead of several booleans
2) Adds `rotate_accel` to allow submodel rotation acceleration to be specified

Submodel acceleration can now be instant; dumb-rotating submodels always instantly accelerate (and have always done so)
2021-11-17 21:45:01 -05:00
Tyler Blount aa1dbc1b0e Merge pull request #3785 from scp-fs2open/revert-3749-refactor/ci
Revert "Refactor CI scripts to make release builds more robust and flexible"
2021-11-17 14:06:36 -07:00
Tyler Blount 052d3d32c7 Revert "Refactor CI scripts to make release builds more robust and flexible" 2021-11-17 12:03:53 -07:00
Tyler Blount 48597e7751 Merge pull request #3784 from scp-fs2open/revert-3779-fix/nightly-trigger-pat
Revert "Use PAT for nightly trigger"
2021-11-17 11:55:56 -07:00
Tyler Blount 9190ba0eb4 Merge pull request #3783 from scp-fs2open/revert-3780-fix/nightly-build-cond
Revert "Fix conditional in Build Nightly action"
2021-11-17 11:29:47 -07:00
Tyler Blount 2297899005 Revert "Use PAT for nightly trigger" 2021-11-17 10:54:48 -07:00
Tyler Blount ba1e0afd31 Revert "Fix conditional in Build Nightly action" 2021-11-17 10:53:12 -07:00
Tyler Blount 383f549e05 Merge pull request #3780 from scp-fs2open/fix/nightly-build-cond
Fix conditional in Build Nightly action
2021-11-16 13:19:24 -07:00
Asteroth 98749e19b3 add flag for toggling ship passive lightning (#3772) 2021-11-16 14:18:26 -05:00
Tyler Blount e477f898b2 Fix conditional in Build Nightly action 2021-11-15 23:50:35 -07:00
Tyler Blount dbb41d2cdd Merge pull request #3779 from scp-fs2open/fix/nightly-trigger-pat
Use PAT for nightly trigger
2021-11-15 11:42:02 -07:00
Tyler Blount 5afc98d809 Use PAT for nightly trigger 2021-11-15 10:41:28 -07:00
Kiloku 719c047714 Avoid uninitialized variable 2021-11-14 16:41:38 -02:00
Kiloku 3038269804 allow drawing rotated bitmaps 2021-11-14 16:26:00 -02:00
Goober5000 56e6870761 address feedback 2021-11-14 00:32:48 -05:00
Goober5000 805cf61a36 indicate ambiguous goal or event matches
Check for multiple matches, not just missing matches.  Also streamline the syntax checking a bit more.  Fixes #3766.
2021-11-13 00:18:37 -05:00
Goober5000 c3137b8ab4 Merge pull request #3765 from Goober5000/subtitle_line_height
allow subtitles to use different line spacing
2021-11-12 22:11:31 -05:00
Goober5000 4aa74523ab address feedback 2021-11-11 18:52:41 -05:00
Asteroth aaaec24000 Ai use lock status for optimum range choice (#3762)
* ai use lock status for optimum range choice

* shadowed variable
2021-11-10 21:16:31 -05:00
Asteroth d079d7fad2 Expose nebula visibility factors (#3676)
* Expose nebula visibility factors

* separately expose size factors

* naming changes
2021-11-10 13:07:04 -05:00
Goober5000 76c9219df3 Merge pull request #3715 from TaGenius/feature/QtInitialStatusEditor
Split From #3674 Initial Status Dialog
2021-11-09 14:26:42 -05:00
The Force e795d2a9d2 Merge branch 'master' into feature/QtInitialStatusEditor 2021-11-09 16:50:47 +00:00
Goober5000 eccc34d081 Merge pull request #3717 from TaGenius/feature/QtGoalsDialog
Split From #3674 Goals Dialog
2021-11-08 23:03:19 -05:00
Asteroth b625e36858 add destroy-instantly-with-debris (#3752) 2021-11-08 11:06:34 -05:00
Goober5000 9050427706 Merge pull request #3767 from Goober5000/sexp_variable_protecc
guard against CTD in sexp variables
2021-11-07 18:25:22 -05:00
Goober5000 2f573924a7 address feedback 2021-11-07 16:26:28 -05:00
Goober5000 2e83e5211e guard against CTD in sexp variables
Don't assign strings that are too long for the string variable capacity.
2021-11-07 16:26:28 -05:00
Goober5000 c3db0ed369 Merge pull request #3761 from Goober5000/fix_3758
polish sexp syntax checking
2021-11-07 14:19:42 -05:00
The Force e8a33201f8 Merge branch 'master' into feature/QtShipEditorSubdialogs2 2021-11-07 16:28:21 +00:00
The Force ec35b5815e Merge branch 'master' into feature/QtInitialStatusEditor 2021-11-07 15:55:12 +00:00
The Force ac12cc7a80 Merge branch 'master' into feature/QtGoalsDialog 2021-11-07 15:48:16 +00:00
The Force 151039540c Add missing include 2021-11-07 15:44:13 +00:00
The Force f4a1b9a7fb Appease Clang 2021-11-07 15:44:13 +00:00
The Force 32d0ee93d4 Fix Compiler Warnings 2021-11-07 15:44:13 +00:00
The Force 49ced359c7 Goals Editor 2021-11-07 15:44:13 +00:00
The Force 31602dbefe Goals ui
finalise ui
2021-11-07 15:44:13 +00:00
The Force 101dda7f28 Split From #3674 Ship Editor Bugfixes (#3716)
* Remove Duplicate function

* Ship Editor Bugfixes

* Bugfixes for Ship editor

* Fix Compiler Warnings

* Add Tristate Checkbox

* Appease Clang

* Actually fix class bug

* Capitalization error fix

* Remove reference to goals dialog

This shouldn't have been added
2021-11-05 23:11:32 -04:00
The Force 19b3c419a7 Split From #3674 Flags Dialog (#3714)
* Create Flags UI

* initial Ship Flags editor


Ship Flags Column One Complete


Ship Flag DIalog Complete

* Fix Compiler Warnings

* Appease Clang

* Fix Scannable Misspelling

* Spelling Fixes and loose semicolon
2021-11-05 23:11:13 -04:00
Goober5000 779e69c3b4 Merge pull request #3745 from Goober5000/target_spelling
spelling fixes
2021-11-05 23:04:32 -04:00
Goober5000 b15858f686 redo initialization 2021-11-05 01:19:48 -04:00
Goober5000 b4f87fe04b Merge pull request #3764 from Goober5000/fix_rand32f
fix a major bug in ba.rand32f
2021-11-05 00:41:41 -04:00
Goober5000 cbda26b4fb allow subtitles to use different line spacing
This adds an optional extra factor to `show-subtitle` and `show-subtitle-text` to adjust the line height.  Useful for double-spacing, 1.5-spacing, etc.
2021-11-04 23:19:45 -04:00
Goober5000 e01ae9fe6f match documentation 2021-11-04 23:02:36 -04:00
Goober5000 b3bb185489 fix a major bug in ba.rand32f
The function should return the random result, not the maximum value.

Also use `ade_set_args` for consistency.
2021-11-04 21:57:29 -04:00
Goober5000 71ff21c3d5 address feedback 2021-11-02 12:03:04 -04:00
Asteroth 594491aa78 Add head-on laser bitmaps (#3748)
* version1 of 'head-on'lasers

* version 2 of head on lasers

* better handling of radius/length

* more adjustments and manual switchover angle

* add switchover rate and glow head on

* bugfix

* allow for instant switchover

* clean up and documentation for PRing

* misc fixes

* more fixes

* more fixes
2021-11-01 15:46:04 -04:00
Tyler Blount 7b7bf598b4 Merge pull request #3749 from ngld/refactor/ci
Refactor CI scripts to make release builds more robust and flexible
2021-11-01 10:28:46 -06:00
Goober5000 f960a09539 Merge pull request #3743 from Goober5000/gamesnd_tweaks
make gamesnd a little more robust
2021-10-31 21:15:58 -04:00
Goober5000 a25363e564 address feedback 2021-10-31 17:55:33 -04:00
Goober5000 71be5b7b80 make gamesnd a little more robust
a) add a new method gamesnd_game_sound_exists
b) add script support for this new method
c) use this method when checking for existence of ballistic rearming sounds
d) prevent "empty" and "none" sounds from triggering warnings
2021-10-31 17:55:33 -04:00
Goober5000 9e0802d53e make sure bad nodes are accurate 2021-10-31 16:29:08 -04:00
Goober5000 c8b773a6dd polish sexp syntax checking
Some instances of the ship syntax checker will check other nodes in the sexp tree.  In those cases, make sure to accommodate special-arg nodes.

This also merges syntax checking for goal/event names and docker/dockee points since they are highly similar.

Fixes #3758.
2021-10-31 16:16:23 -04:00
The Force 15d70c30c7 Fix Crash On second opening of select box cause by #3634 (#3760) 2021-10-31 18:41:24 +00:00
Goober5000 91be1654a3 Merge pull request #3741 from Shivansps/missing_updatedata
fix: cmdbrief not saving current stage text by closing the window
2021-10-30 01:18:52 -04:00
Goober5000 8ddf878144 Merge pull request #3755 from Goober5000/script_eval_bool
add script-eval-bool
2021-10-30 01:10:25 -04:00
Goober5000 14123b1a04 Merge pull request #3750 from Goober5000/better_argument_syntax_checking
better syntax checking for the special argument
2021-10-30 00:11:53 -04:00
Goober5000 00208af898 add script-eval-bool 2021-10-29 23:54:32 -04:00
Taylor Richards fd2785a504 Merge pull request #3754 from notimaginative/fix_escort_list_stealth_cull
fix escort list cull test which removed friendly stealth ships by mistake
2021-10-27 18:59:21 -04:00
Taylor Richards 8d7fd6893e fix escort list cull test which removed friendly stealth ships by mistake 2021-10-27 00:04:57 -04:00
Goober5000 cfc5901488 better syntax checking for the special argument
Improves syntax checking in two ways...
1) Properly checks each sibling of a special argument, rather than skipping the whole list even if just one is a special argument
2) Throws a syntax error if a special argument is found without an argument operator higher in the sexp tree, which fixes #3740
2021-10-25 01:08:44 -04:00
ngld 53b14a0cfd Refactor CI scripts to make release builds more robust and flexible 2021-10-24 01:16:48 +02:00
Goober5000 58680f766e Merge pull request #3746 from Goober5000/scripting_neb2_awacs
add scripting virtvar for Neb2_awacs
2021-10-22 11:59:29 -04:00
BMagnu 2e35e051e3 Merge pull request #3697 from Baezon/animated-neb-poofs
Add animated nebula poofs
2021-10-22 16:16:30 +09:00
Asteroth 375e1caca9 Remove 'stream' weapon handling (#3720)
* remove stream handling

* unused variable

* turn stream' into an unused flag

* yes really whitespace changes just for clang tidy
2021-10-22 16:15:56 +09:00
BMagnu 0ba5754c30 Add nullptr safety for animations (#3738)
* Add nullptr safety

* Greatly simplify docking animation logic

* Fix warnings

* Address Feedback
2021-10-21 21:18:31 +00:00
BMagnu b7258f5fea Add Bomb-locking secondaries (#3588)
* Add Bomb-locking secondaries

* Change to different flag

* Address feedback
2021-10-21 20:09:50 +09:00
Goober5000 89d0a49bdc add scripting virtvar for Neb2_awacs 2021-10-20 22:24:07 -04:00
Goober5000 e27ed05127 spelling fixes 2021-10-20 15:31:23 -04:00
Goober5000 a52e85c760 Merge pull request #3736 from EatThePath/gr_set_lighting-cleanup
Removing dead code paths
2021-10-20 11:48:19 -04:00
Goober5000 e07e8341f2 Merge pull request #3724 from Goober5000/hud_gauge_expanded_check
make hud gauge checking more robust
2021-10-20 10:21:22 -04:00
Joshua Glatt 0708dd725b Bump PLR/CSG versions and preserve pre-containers compatibility (#3739) 2021-10-19 21:53:20 -07:00
Asteroth bc24ac3ebc Add 'passive' lightning arcs to ships (#3733)
* add passive lightning arcs

* fixes and cache submodel number

* range based loop
2021-10-19 12:51:05 +09:00
Shivansps eb3224c50e fix: cmdbrief not saving current stage text by closing the window 2021-10-18 23:47:56 -03:00
BMagnu 16580ac48a Merge pull request #3732 from EatThePath/safety-animation
Protected against trying to animate non-existant submodels
2021-10-18 20:17:27 +09:00
Goober5000 f625096281 Merge pull request #3735 from BMagnu/secondary_no_ammo_turret_fix
Fix Turrets using ammo broken by #3589
2021-10-18 00:29:22 -04:00
Goober5000 5b173c6060 Merge pull request #3731 from Goober5000/state_end_script_hooks
migrate and augment mission/state end hooks
2021-10-17 19:30:58 -04:00
David Gibson 1c2b83f6aa Removing dead code paths 2021-10-17 11:05:37 -05:00
Birk Magnussen c4994c7fdd Add forgotten negation 2021-10-17 22:56:53 +09:00
Taylor Richards 64e57821eb address clang-tidy issues 2021-10-17 09:35:19 -04:00
Taylor Richards 044f4ef0e0 clean up some inconsistencies in cfilesystem:
- simplify OS specific code
 - make sure loose files are always sorted the same regardless of OS or filesystem
 - reduce differing behavior in cf_get_file_list*() variants
 - refactor case-sensitive directory handling to work everywhere it's needed
2021-10-17 08:56:35 -04:00
David Gibson 2034a3e9e5 Protected against trying to animate non-existant submodels in at least one case 2021-10-16 21:18:28 -05:00
Goober5000 b0c3b4098e migrate and augment mission/state end hooks
1) migrate On Mission End and On State End to the new hook system
2) add On Mission About To End and On State About To End
2021-10-16 21:56:20 -04:00
Asteroth f91a5bfd00 Add +arrival rvec for ship bays (#3698)
* add ship bay arrival rvec

* unused variables

* add profile flag

* add corresponding departure flag

* revert accidental changes

* fix fallout from visual studio's dumb 'rename' feature

* swap parsing of departure and arrival rvec
2021-10-15 16:48:56 -04:00
Goober5000 8af833c984 Merge pull request #3728 from Goober5000/sexp_replace_texture_edits
upgrade the replace-texture sexp
2021-10-15 13:15:06 -04:00
Goober5000 754fcb3467 upgrade the replace-texture sexp
This PR allows the sexp to replace textures with "invisible" as well as to use animated textures.
2021-10-15 00:51:09 -04:00
Goober5000 ebd31c1bd0 Merge pull request #3726 from Goober5000/pre_translation_cleanup
pre-translation cleanup
2021-10-14 11:43:41 -04:00
Goober5000 df83882d39 Merge pull request #3722 from EatThePath/ShaderCleanup
Removed unused constants from Lighting.sdr.
2021-10-14 11:42:57 -04:00
Goober5000 8e857ddd4e nullptrs for clang 2021-10-13 20:28:47 -04:00
Brian Hernandez 08548ea517 Scale distant combat related effects so they stay visible (#3656)
* Scale distant combat related effects so they stay visible
- Effects scaled so that they always maintain a minimum pixel size
- Supports lasers, beams, all trails, muzzle flashes, and thrusters
- Disabled by default, but can be configured through the game_settings.tbl

* Added comments clarifying when min pixel size scaling happens.

* Convert some NULLs to nullptr to make CLANG happy
2021-10-13 19:46:01 -04:00
Goober5000 ae63f02829 rename intrinsic rotation to intrinsic motion 2021-10-13 19:39:16 -04:00
Goober5000 9afec1fd34 add a new in() function to streamline things a bit 2021-10-13 16:52:37 -04:00
Goober5000 47fb4c1d35 use sm and parent_sm instead of submodel array indexes 2021-10-13 16:04:26 -04:00
Goober5000 db7d634a37 make hud gauge checking more robust
1) When syntax checking for hud gauges, be sure to check all gauges available because the default ship may not be the ship chosen in the player loadout.
2) Add a warning to every hud gauge check if the gauge isn't found.
3) Don't report syntax errors for hud gauges in FSO, only FRED; because every place that use a gauge will fail gracefully.
2021-10-12 22:19:39 -04:00
David Gibson c3cba091f1 Removed unused constants from Lighting.sdr. 2021-10-12 19:46:49 -05:00
Joshua Glatt 16d75b981c karajorma's SEXP containers, Part 2: Persistence (#3462) 2021-10-11 18:58:00 -07:00
Goober5000 f09730d923 Merge pull request #3719 from Goober5000/adjust_rotator_flag
rename and adjust scope of Rotators_locked flag
2021-10-11 13:47:58 -04:00
Goober5000 e1f20be856 rename and adjust scope of Rotators_locked flag
The Rotators_locked flag was created specifically as a lab option that didn't affect animations or intrinsic rotations, so return it to that scope.  Also rename it to clarify that it applies to subsystems and to be future-proof for submodel translation.
2021-10-11 12:06:17 -04:00
The Force 5cfa47a63e Fix load order problems caused by Iff vectorization (#3718)
* Fix load order problems caused by Iff vectorization

* Use Resize rather than push
2021-10-11 20:13:44 +09:00
Goober5000 8a449eb8ec Merge pull request #3713 from Goober5000/submodel_rotate_reorg
reorganize submodel rotation
2021-10-10 14:10:19 -04:00
Asteroth 0f06bf279a Add velocity inheritance for particle effects (#3691)
* implement velocity inheritance for particles

* add vel inherit for single effects

* appease clang

* review feedback
2021-10-10 13:37:31 -04:00
The Force aa0713fae6 Appease gcc 2021-10-10 14:30:01 +01:00
The Force 726d4f5cc7 Remove Misplaced Addition From Another Pull request 2021-10-10 14:14:43 +01:00
The Force 111736d86d Capitalization error fix 2021-10-10 14:08:12 +01:00
The Force 42890a3338 Add Tristate Checkbox 2021-10-10 13:58:00 +01:00
The Force 5b54ef772c Appease Clang 2021-10-10 13:31:16 +01:00
The Force 8a89c5bb05 Fix Compiler warnings 2021-10-10 13:29:35 +01:00
The Force 91331d5d4a More Bugfixes 2021-10-10 13:27:02 +01:00
The Force 84eacedb7c Some bugfixes
Shield bugfix
2021-10-10 13:25:20 +01:00
The Force 86d2ba8ebd Initial Status Dialog 2021-10-10 13:24:04 +01:00
Kiloku 0548b2fa2f Custom data in tables, tackling #3699 (#3707)
* Add custom data to ship tables

* add index check to shipclass.cpp

* fix hasCustomData name to use the proper casing

* Add custom data to weapon tables

* Add validity checks and remove superfluous empty check

* Attempt to appease clang-tidy

* Use F_RAW as recommended by @BMagnu

* Creates a function to parse maps and uses it in ship.cpp and weapons.cpp

* another attempt to appease clang-tidy

* Remove superfluous using

* Small style and grammar fixes

* Accidentally forgot this change. Rename 'delimiter' to 'end_marker'
2021-10-10 18:26:54 +09:00
BMagnu ce22482023 Merge pull request #3702 from Baezon/use-real-names-cheats
Use real names for ships/weapons in cheat commands
2021-10-10 18:24:27 +09:00
Goober5000 575c050da4 reorganize submodel rotation
This moves submodel rotation out of the AI pipeline and into object movement.  With the exception of turret rotation (which remains in the AI code) this now allows all types of submodel rotation to happen in the same place.  Many associated functions have also been cleaned up.

In addition to making the code cleaner and clearer, this will make it much easier for intrinsic rotations and new animations to be applied to non-ship objects, such as weapons.
2021-10-10 02:29:34 -04:00
wookieejedi dfa1de5470 Add Per-Ship Class Wingmen Status Dot (#3711)
* Add Per-Ship Class Wingmen Status Dot

This PR adds a ship info value `$Wingmen Gauge Dot Override:`, which  allows modders to set wingmen status dots on a per-ship class basis. If no animation is specified then the default dot animation specified in the HUD table wingmen gauge is used.

Both EatThePath and Darius stated this feature would be useful, and it will also be useful for FotG.

Tested and works as expected, including on winged ships present at mission start and delayed winged ships.
2021-10-09 19:00:16 -04:00
Kiloku 3538c55dae Add getColor to lua gr library, which returns the active color (#3687)
* Adds the getColor() function to the Graphics lua library, allowing users to check what color is active for 2D drawing.

* Adds the getColor() function to the Graphics lua library, allowing users to check what color is active for 2D drawing.
2021-10-09 17:39:41 +09:00
wookieejedi 870666dfa3 Add New Options to Wingmen Gauge (#3703)
* Add New Options to Wingmen Gauge

This PR adds two new options for modders to use in the HUD table for the wingmen gauge:
1) `Use Full Wing Names:` which draws the full wing name and does not alter the capitalization.
2) `Use Expanded Colors:` which use red, yellow, or green color to designate wingmen health (green 1.0 to > 2/3, yellow 2/3 to > 1/3, and red <= 1/3.

Also adds the bright red option to dead wingmen, which seems like it was missing before(?).

Tested and everything works as expected.

* correct string copy length

* fix out of scope case variable
2021-10-09 17:38:03 +09:00
BMagnu 1da6f4a6a2 Simplistic Ship Transparency (#3436)
* Basic per-render-model + per-ship tools

* Tidy up settable transparency for standalone use

* Force Alpha Premultiplied on external Alphamult

* Fix sexp description.
2021-10-08 21:49:13 +09:00
Asteroth c57bea8b84 NULL -> nullptr 2021-10-08 00:58:21 -04:00
Asteroth d4c2bb3e22 allow for arbitrary asteroid targets 2021-10-08 00:29:22 -04:00
Goober5000 6166ec4ce9 Merge pull request #3608 from Goober5000/perform_actions_etc
enhance the perform-actions family of sexps
2021-10-07 16:28:11 -04:00
Asteroth 5137ec1f3c use real names for in cheat commands 2021-10-07 12:03:58 -04:00
BMagnu d0bcf86ecc Wrap Docking getTime in a timestamp (#3701) 2021-10-07 06:29:51 -04:00
Asteroth 8604f783fb add no evasion flag (#3677) 2021-10-06 12:39:04 -04:00
BMagnu 12be7576f7 Animation Overhaul: Phase 2 (#3609)
* Add Generic Rotation Segment

* SEXPd rotations work

* Fully replace old animation system

* Add sound segment

* Fixes

* Trigger Hangarbay doors for lone player without AI

* Address Warnings

* Fix Docking ANimations + some bugs

* Fix sound issue + docking bug

* fix bugs, add multi handling

* Change direction into enum class

* Address feedback

* Futher clean aicode

* Address feedback

* Add Multi packet constexprs

* Fix multi constexprs

* Clarify AIS_DOCK comments

* Address multi issues

* Clang somehow detects issues where there are none...
2021-10-06 08:50:58 +09:00
Goober5000 47339e1561 Merge pull request #3671 from Goober5000/moar_sexp_documentation
expand some sexp documentation
2021-10-05 13:33:18 -04:00
Asteroth 2703fe865b Fix warnings concerning ballistic weapons (#3683)
* dont warn for provided pbank capacity but no ballistic weapons

* review feedback
2021-10-05 04:13:26 -04:00
Asteroth dbd5652eb8 add animation for nebula poofs 2021-10-05 03:01:52 -04:00
Goober5000 5364d65ec5 Merge pull request #3696 from Baezon/fix-secondary-has-ammo
Fix a possible crash with `ship_secondary_bank_has_ammo`
2021-10-04 22:17:52 -04:00
Goober5000 e5973e09ca Merge pull request #3695 from Baezon/fix-visibility-initialization
Initialize team visibility before using it
2021-10-04 22:15:08 -04:00
JohnAFernandez efeb0ee1f2 Actually fix the goal's target being sent (#3665) 2021-10-04 21:21:13 -04:00
Asteroth ca690c267c verify secondary_bank_weapons before usage 2021-10-04 18:56:51 -04:00
Asteroth 95de9e3ff5 initialize awacs data in post mission parse 2021-10-04 18:33:11 -04:00
Asteroth a1ae1d80a9 Safety for replace-texture (#3694)
* dont add replacement texture if unable to find original texture

* NULL -> nullptr
2021-10-04 01:07:38 -04:00
Allen A. Babb 64b2469235 Merge pull request #3688 from z64555/fix/issue_3685
Fix issue 3685
2021-10-02 23:57:22 -05:00
BMagnu 2b63097c12 Exclude dead subsys from targeting (#3614)
* Exclude dead subsys from targeting

* Put behaviour behind flags

* Make ML lock disappear when subsys dies

* Flip flag to change default behaviour
2021-10-03 03:57:40 +09:00
z64555 ea0ad0935d Cease Targeting properly, without going out of array bounds. Should fix issue #3685. 2021-10-02 13:54:28 -05:00
Kiloku ecea40e38f Allow Lua Scripts to draw rotated rectangles (#3623)
* Adds the angle parameter to gr.DrawRectangle, allowing scripters to draw arbitrarily rotated rectangles.

* Revert "Adds the angle parameter to gr.DrawRectangle, allowing scripters to draw arbitrarily rotated rectangles."

This reverts commit b1a0480f32.

* Adds the angle parameter to gr.DrawRectangle, allowing scripters to draw arbitrarily rotated rectangles.

* fix wrong vertex position for unfilled rotated rectangles

* Adds a @param entry to gr_rect explaining the angle parameter.

* Attempt to fix operations with int to float conversions.

* Fix parameters in documentation string

* Change NULL to nullptr to satisfy modern coding standards

* Trying to make code a bit cleaner
2021-10-02 13:11:35 -04:00
BMagnu a6093dd8c4 Add ammoless secondaries (#3589)
* Add ammoless secondaries

* Macroify 'ammo>0 || no ammo' check
2021-10-02 04:40:03 +09:00
Goober5000 2b74ba1d30 Merge pull request #3684 from Goober5000/on_death_started
add OnShipDeathStarted scripting hook
2021-10-01 14:03:00 -04:00
Asteroth 76046d8aee Clean up beam type naming scheme (#3670)
* clean up beam type naming scheme

* appease clang tidy

* cast to int for printing

* address feedback
2021-10-02 02:42:21 +09:00
Goober5000 ebcd4135a7 additional fixes, including a bugfix for #3679 2021-10-01 11:46:48 -04:00
Goober5000 6575cf6887 add OnShipDeathStarted scripting hook
This occurs at the beginning of the ship death routine, similarly to OnDepartureStarted occurring at the beginning of the ship departure routine.
2021-09-30 22:42:15 -04:00
Goober5000 470466e8c7 Merge pull request #3679 from Goober5000/killer_fixes
patch up scripted kills
2021-09-30 22:41:32 -04:00
BMagnu f0f6cabe84 Add full team option to change-iff SEXP (#3632)
* Add full Team option to change-iff

* Fix help text
2021-10-01 05:09:00 +09:00
BMagnu 37a52dcb41 Merge pull request #3630 from Kiloku/lua_expose_weapon_radius
Expose Outer and Inner Radii to the Lua API in the weaponclass type
2021-10-01 04:17:06 +09:00
BMagnu 391de411ee Vectorize IFF Defs for unlimited IFFs (#3634)
* make IFF limit a vector

* Also change QTFred

* Warnings

* remove decltypes, wrap arrays in unique_ptr
2021-09-30 14:17:28 +09:00
Goober5000 f8c0d30ee1 Merge pull request #3660 from BMagnu/Lua_ship_iter
LUA: Add iterator over ships in mission
2021-09-29 21:45:17 -04:00
The Force 9fc778d7d8 Special Stats Dialog 2021-09-29 11:04:02 +01:00
Goober5000 30d4455417 patch up scripted kills
When a ship is killed via scripting, the killer should be credited for the kill in the mission log and the correct hull percentage should be used.  Also, the script should work with either the ship or its weapon passed as the killer parameter.
2021-09-29 01:41:36 -04:00
Goober5000 a9b46f6bd3 Merge pull request #3678 from Goober5000/update_version_21.5.x
bump version to 21.5.x
2021-09-29 00:59:37 -04:00
Goober5000 8487323175 bump version to 21.5.x 2021-09-29 00:05:36 -04:00
the-maddin d309ddef1e Simplify QPlainTextEdit (#3600) 2021-09-28 13:50:04 -04:00
Goober5000 d3b37efb7d Merge pull request #3647 from Goober5000/hidden_mission_log_flag
add hide-in-mission-log ship flag
2021-09-28 11:48:21 -04:00
EatThePath a8bbe23800 Fix homing child weapons in niche circumstances (#3661)
* Deleted a line that blanked target_num on homing weapons but still let them home

* This whole block of code about missiles missing turns out to be a logical dead end anyway, ripped it out by the roots.
2021-09-28 01:42:18 -04:00
Goober5000 edf7d6cccf expand some sexp documentation
Adds important information to `ship-guardian` and `show-subtitle-image`.  Fixes #3669.
2021-09-22 22:34:49 -04:00
Birk Magnussen 07abcf2238 secure iterators against ships being removed from them while still iterating 2021-09-17 01:40:31 +09:00
Birk Magnussen 491946bfd0 Add explanation 2021-09-17 01:18:22 +09:00
Birk Magnussen 2306faa7cd Add iterator over ships 2021-09-16 22:58:33 +09:00
Goober5000 e81001f6a6 Merge pull request #3648 from Goober5000/ai_ignore_documentation
add some SEXP documentation
2021-09-15 10:03:03 -04:00
Goober5000 945427a849 Merge pull request #3657 from Goober5000/fix_3654
fix the cancel behavior when FRED is closed
2021-09-15 10:02:45 -04:00
Goober5000 9d1c93041e turns out you can actually embed numbers in strings in the preprocessor 2021-09-15 02:19:05 -04:00
Goober5000 5fb9a6f0c6 fix the cancel behavior when FRED is closed
Explicitly check whether the mission has been saved, because the automatic check doesn't provide a way to detect that it has been cancelled.

Fixes #3654.
2021-09-15 01:35:25 -04:00
Goober5000 e2a359b546 Merge pull request #3655 from brihernandez/mod_table_is_game_settings_comment
Added comment to clarify that the mod_table is about game_settings.tbl
2021-09-14 19:03:45 -04:00
Brian e48011d175 Added comment to clarify that the mod_table is about game_settings.tbl 2021-09-14 11:26:13 -04:00
Fabian Woltermann 8766c642fe Merge pull request #3652 from qazwsxal/master
Anti-glint shader trick to reduce glimmer on distant objects
2021-09-14 14:24:00 +02:00
Adam Leach 565f4d469c Anti-glint shader trick to reduce glimmer on distant objects 2021-09-14 10:26:33 +01:00
Goober5000 8e7476c1b8 Merge pull request #3651 from Goober5000/lua_gc
use public API call for Lua garbage collector
2021-09-14 02:16:54 -04:00
Goober5000 d41020222e use public API call for Lua garbage collector
As described in #3650.
2021-09-13 19:36:24 -04:00
Fabian Woltermann 9c1cf58f8d Merge pull request #3649 from Goober5000/techroom_fix
fix lab variables
2021-09-13 08:21:50 +02:00
Goober5000 183db641d7 fix lab variables 2021-09-13 01:51:13 -04:00
Goober5000 10a5a0d29a add some SEXP documentation
Per request, add some more documentation to ai-ignore and ai-ignore-new (and ai-play-dead while we're at it).

Fixes #3612.
2021-09-13 00:37:34 -04:00
Goober5000 8cf8d451a8 allow ship creation to not be visible in the mission log 2021-09-12 16:29:17 -04:00
Goober5000 49bab8fe83 add hide-in-mission-log ship flag
This flag causes any events involving this ship to not show up in the mission log.
2021-09-11 23:43:30 -04:00
JohnAFernandez 830ecf2ea2 Merge pull request #3646 from BMagnu/fix_lab_turrets
Fix Turrets in Lab
2021-09-11 12:54:45 -04:00
Birk Magnussen 472fd6f20f Fix Turrets in Lab 2021-09-12 01:30:33 +09:00
Goober5000 262e4d4489 Merge pull request #3645 from Goober5000/shipname_fix
correct shipname return type
2021-09-08 21:33:00 -04:00
Goober5000 c9d71ce1ab correct shipname return type
The return type of "shipname" is a string, so if the ship can't be found, return an empty string instead of an invalid ship.
2021-09-08 20:57:09 -04:00
Goober5000 e742bd108a Merge pull request #3635 from Goober5000/gc_on_mission_start
run Lua garbage collector on mission start
2021-09-07 14:15:58 -04:00
Goober5000 990d0b7784 run Lua garbage collector on mission start
This might fix #2961.  By explicitly running the garbage collector before a mission starts, this will ensure each mission begins with a clean slate.
2021-09-07 13:50:08 -04:00
Goober5000 7c5371af1a Merge pull request #3624 from Goober5000/fred2_cancel_confirm
confirm cancel in Event Editor
2021-09-05 14:45:14 -04:00
Goober5000 99972a17c6 Merge pull request #3625 from Goober5000/duplicate_squadron_wings
match wing names and aliases on the status gauge
2021-09-05 14:43:27 -04:00
Joshua Glatt 2e743d9cd6 Apply adjust-audio-volume SEXP for effects to looping 3D sounds (#3638) 2021-09-05 11:39:37 -07:00
Goober5000 b7681cfee9 Merge pull request #3636 from Baezon/fix-turret-resetting
Fix turrets not resetting sometimes
2021-09-05 14:31:17 -04:00
Goober5000 5eb924cedc Merge pull request #3639 from Goober5000/handle_invalid_gamesnds
handle invalid gamesnds
2021-09-05 14:29:17 -04:00
Goober5000 d561cd87c4 Merge pull request #3641 from Goober5000/fix_3619
fix nebula range in mission-set-nebula
2021-09-05 14:12:49 -04:00
Goober5000 562522e098 match wing names and aliases on the status gauge
If a wing has a hash symbol, it needs to match the squadron status gauge for the equivalent name without the hash.  This could happen for in-mission jumps or cases where a wing leaves and comes back.

Also remove an obsolete function.
2021-09-05 14:12:08 -04:00
Goober5000 f7bfd637d8 comments 2021-09-05 13:44:02 -04:00
Goober5000 235857ca10 add back fred support 2021-09-05 13:15:34 -04:00
Goober5000 f529fbc633 expand comments 2021-09-05 13:11:33 -04:00
Goober5000 22b16c32d4 Merge pull request #3631 from Goober5000/rewrite_xstr
rewrite XSTR to be more robust
2021-09-05 13:04:41 -04:00
Goober5000 b1298c2b68 address feedback 2021-09-04 18:43:46 -04:00
Goober5000 2ec18afe02 CI 2021-09-04 17:16:33 -04:00
Goober5000 7f742a2145 fix nebula range in mission-set-nebula
The mission-set-nebula sexp never initialized the nebula range, which is usually done in the background editor.  This PR allows the range to be specified, and sets it to 3000 (the same default as in the background editor) if not specified.

Fixes #3619.
2021-09-04 16:37:49 -04:00
Goober5000 b96d9f6e62 address feedback 2021-09-04 15:46:03 -04:00
Goober5000 eaa3fe0979 address feedback 2021-09-03 23:56:46 -04:00
Goober5000 1cd16b7281 string length tweak 2021-09-03 23:16:40 -04:00
Goober5000 44ce5e9b00 handle invalid gamesnds
If an entry in a game sound fails to load, mark the sound as invalid and don't try to load it afterwards.  This is the "permanent fail" fix for #3388.
2021-09-03 19:10:31 -04:00
Asteroth 13b922207b comment cleanup 2021-09-03 00:14:58 -04:00
Asteroth efc686db2d unused variable 2021-09-01 14:33:57 -04:00
Asteroth 2738919cc9 fix turrets not resetting sometimes 2021-09-01 14:29:57 -04:00
Goober5000 7e9121ed8e use blocks instead of goto; avoids skipping over initialization 2021-08-29 22:56:37 -04:00
Goober5000 f0712cfb41 rewrite XSTR to be more robust
The old XSTR parsing code was a bit of a mess and did not even properly enforce its format.  These new routines enforce the actual XSTR format and warn when it is malformed, which is helpful for catching table errors as early as possible.  This fixes #3627 and also catches mismatched quotes and other common XSTR errors.  No more wondering why comments are being mysteriously parsed instead of ignored!
2021-08-29 21:47:15 -04:00
Kiloku 15e1de386c Exposes Outer Radius and Inner Radius to the Lua API in the weaponclass object type. 2021-08-29 14:47:46 -03:00
Goober5000 af8422cf7b confirm cancel in Event Editor
This syncs up the Close and Cancel behavior.  In both cases, if there are any changes, FRED will display a prompt.
2021-08-26 16:32:18 -04:00
Asteroth 39a16019e3 Single target multilock missiles should use targeted_subsys (#3618)
* use targeted_subsys if available
2021-08-24 19:45:34 -04:00
Asteroth bbca518524 no chase cam slewing during hyperspace (#3620) 2021-08-24 19:44:07 -04:00
Goober5000 bb28c37829 Merge pull request #3616 from Goober5000/look_at_updates
fixes to look_at and intrinsic rotation
2021-08-22 22:57:26 -04:00
Goober5000 ad2335cfbf fixes to look_at and intrinsic rotation
1) Make sure the `PM_FLAG_HAS_INTRINSIC_ROTATE` flag is only set after submodels pass validation and checking
2) Maintain compatibility with old models that used `$look_at` with the submodel number instead of name
2021-08-22 22:09:18 -04:00
Allen A. Babb 7bf7bf5c1d Merge pull request #3617 from z64555/fix/axis_backups_move_too_much
Fixes a typo in controlconfig that causes an issue with std::move.
2021-08-22 16:18:20 -05:00
z64555 99b7c89883 Fixes a typo that caused an issue for some builds when trying to move the axis binding backups into the bindings during the exit state of the controls config menu. 2021-08-22 15:39:20 -05:00
Goober5000 370419b1a2 Merge pull request #3610 from Goober5000/some_ai_profiles_fixes
some ai_profiles fixes
2021-08-21 21:40:46 -04:00
Goober5000 17d1924897 make CI happy 2021-08-21 20:18:08 -04:00
Goober5000 a351e72895 some ai_profiles fixes
1) Several AI profiles options were getting reset on every iteration through the loop.  They should only be reset when the profile is initially created.
2) Keeping track of AI hits on the player ship was added by Sushi in 9246a2f74d and needs to be guarded by a flag.  This flag has been enabled for mods that set the required FSO version.
2021-08-21 19:53:46 -04:00
Asteroth cd4c6e483a add a few mor cases for checking targeting restrictions (#3605) 2021-08-20 16:11:18 -04:00
Goober5000 4dad58af6e CI fixes 2021-08-20 11:53:32 -04:00
Goober5000 91789c2251 add functional-when 2021-08-19 23:30:52 -04:00
Goober5000 03531a7932 make a distinction between perform-actions-bool-first and perform-actions-bool-last, and deprecate perform-actions 2021-08-18 23:59:17 -04:00
Asteroth 82c36b1c59 fix shockwave rotation (#3604) 2021-08-18 14:55:14 -04:00
Asteroth 47f84846e3 fix collision retiming to never be in the future (#3599) 2021-08-12 17:21:22 -04:00
Goober5000 2fe789f87b Merge pull request #3595 from Goober5000/ship_logging
improve logging of ship creation and cleanup
2021-08-11 16:17:09 -04:00
BMagnu f850725c14 Merge pull request #3597 from Baezon/fix-poof-density
Fix for 'anemic' poofs
2021-08-12 01:12:26 +09:00
Goober5000 344eb5a7ed Merge pull request #3596 from Goober5000/fix_fs1_import
fix icon on FS1 mission import
2021-08-11 12:07:24 -04:00
Goober5000 10b357172a improve and expand logging 2021-08-11 02:50:07 -04:00
Asteroth 4892ac7b01 unused param 2021-08-11 00:07:56 -04:00
Asteroth 4474b0087d comments 2021-08-10 23:41:35 -04:00
Goober5000 ee1b6263ba fix icon on FS1 mission import
The SD Demon doesn't use the support ship icon anymore, and hasn't since FSPort switched from FS2-style icons to FS1-style icons.
2021-08-10 23:26:47 -04:00
Baezon 73ced78633 fix poof density 2021-08-10 21:44:02 -04:00
Goober5000 50266c5065 Merge pull request #3580 from JohnAFernandez/qtFRED-CommandBrief-Dialog
qtFRED Command Breifing
2021-08-10 13:55:53 -04:00
JohnAFernandez 00f4797b45 qtFRED Command Breifing
Adds a fully functioning Command Briefing Dialog to qtFRED
2021-08-09 14:23:23 -04:00
BMagnu 2377b5dff2 Merge pull request #3594 from BMagnu/anim_rework_1_perf
Animation Rework Phase 1 Fixes 4 / Performance Issues
2021-08-10 01:33:53 +09:00
Goober5000 f8c41ac377 improve logging of ship creation and cleanup
It's useful for *all* ship cleanup to be logged, not just big/huge ships.  And by extension, it's also useful for ship creation to be logged.
2021-08-09 01:43:07 -04:00
Birk Magnussen aee9dc6910 Fixed bad stepAnimations call, added initial-type optimizations 2021-08-09 14:36:57 +09:00
ngld 2e5a6871c5 Merge pull request #3593 from Goober5000/wrap_no-float16
add a version guard for MSVC compiler bug fix
2021-08-08 11:29:11 +02:00
Goober5000 535b0857b6 add a version guard for MSVC compiler bug fix
Per ngld's suggestion, this adds a version check around the disabling of the qfloat16 overloads.

Follow-up to #3557.
2021-08-07 19:19:02 -04:00
Allen A. Babb 2fa7ddc552 Merge pull request #3481 from MageKing17/bugfix/mainhall-misc-apng-animations
Fix APNG misc mainhall animations.
2021-08-07 13:09:37 -05:00
BMagnu a6f821daee Merge pull request #3592 from Baezon/type-5-targetless-turrets
Handle turret fired type 5 beams without targets properly
2021-08-08 01:47:10 +09:00
Baezon 360198b99f handle turret fired beams without targets properly 2021-08-07 12:20:11 -04:00
Asteroth 7fe62aabcd Add some chase view Improvements (#3571)
* improve chase view cam

* fix comment

* comment description of acceleration
2021-08-05 11:09:08 -04:00
Goober5000 d2859f4979 Merge pull request #3585 from Goober5000/dynamic_fred_poofs
handle nebula poofs dynamically in FRED
2021-08-04 16:58:52 -04:00
Goober5000 643a87a7f1 Merge pull request #3586 from Goober5000/fred_and_teams_and_mantis_2053
ships, wings, etc. can share names with teams
2021-08-04 16:42:09 -04:00
Goober5000 d1d78c980e Merge pull request #3564 from Goober5000/turn_off_wireframe
add Draw Outlines on Selected Ships option
2021-08-04 02:12:21 -04:00
Goober5000 148df94e50 use original intent of colors 2021-08-04 01:42:42 -04:00
Goober5000 d443e9e7d0 might as well fix this too 2021-08-03 22:23:04 -04:00
Goober5000 e1bbbf9f9a ships, wings, etc. can share names with teams
Partial revert of Mantis #2053:
http://scp.indiegames.us/mantis/view.php?id=2053

The patch was speculative and there was never a confirmed bug.  By contrast, there are plenty of existing missions that use Unknown as a ship, wing, or jump node name and work just fine.
2021-08-03 22:06:57 -04:00
Goober5000 fdafe21684 handle nebula poofs dynamically in FRED
Inspired by #3584, this properly saves and restores any number of nebula poofs handled by the game.  FRED will only display checkboxes for the first six, since it still uses the static UI, but everything else is handled behind the scenes.
2021-08-03 21:21:42 -04:00
BMagnu 7ccd13bbce Merge pull request #3584 from BMagnu/fred_poof_clear
FRED: Don't clear poof flags for poof 7 and after
2021-08-04 09:41:56 +09:00
Birk Magnussen 9f45f49ec1 Only clear settable poof bitflags 2021-08-04 00:57:07 +09:00
BMagnu 6b5124a8ad Merge pull request #3582 from BMagnu/anim_rework_1_fixes_3
Animation Rework Phase 1 Fixes #3
2021-08-03 11:15:46 +09:00
Birk Magnussen 1187ebbc2c GCC Warnings 2021-08-02 23:33:26 +09:00
Birk Magnussen d92fab80ef Find turrets by sip name (since index can change) and make pointers shared 2021-08-02 22:35:41 +09:00
BMagnu 1b9dd78233 Merge pull request #3507 from Baezon/poof-overhaul
Overhaul nebula poof system
2021-08-02 18:35:40 +09:00
Baezon ebb5ed9ba6 review tweaks 2021-08-01 13:08:11 -04:00
BMagnu dabdc871a6 Merge pull request #3579 from BMagnu/anim_rework_1_fixes_2
Animation Rework Phase 1 Fixes #2
2021-08-01 14:39:38 +09:00
Birk Magnussen 77a255af63 GCC Warnigns 2021-07-30 18:05:46 +09:00
Birk Magnussen 45c904c25e Fixed memory issue and turret-specific animation handling cases 2021-07-30 17:08:24 +09:00
BMagnu 3d0bd54980 Merge pull request #3578 from BMagnu/anim_rework_1_fixes_1
Anim Rework Phase 1 Fixes
2021-07-30 03:27:39 +09:00
Birk Magnussen 7228244f0c Add forced animation start mode 2021-07-29 20:46:37 +09:00
Birk Magnussen f0f5679731 Fix flipped turret values 2021-07-29 20:21:01 +09:00
Asteroth 1306a23fd4 Merge pull request #3568 from Baezon/fix-turret-flags-no-parse-object
Move some flag setting to subsys_set()
2021-07-28 03:15:58 -04:00
Goober5000 f067a19583 Merge pull request #3576 from Goober5000/override_all_briefing_icons
allow custom briefing icons to always override standard icons
2021-07-28 00:40:42 -04:00
Goober5000 8ad52cd8e0 Merge pull request #3577 from notimaginative/fix_cmdline_password_bug
fix error with -password cmdline option
2021-07-28 00:40:22 -04:00
Taylor Richards a27976bf9a fix error with -password cmdline option 2021-07-27 19:41:01 -04:00
Goober5000 deefbf0860 allow custom briefing icons to always override standard icons
Adds the `$Custom briefing icons always override standard icons:` option to game_settings.tbl.  Implements #3575.
2021-07-27 14:16:58 -04:00
Goober5000 c0f9ad7b3c Merge pull request #3574 from Goober5000/fix_time_to_goal
fix Time To: Unknown on the HUD
2021-07-25 18:17:25 -04:00
Goober5000 482cc7d7a6 fix Time To: Unknown on the HUD
PR #3064 inadvertently caused all goals to display Time To: Unknown, even though time was only supplied for docking and waypoints.  This restores the original behavior where the Time To: line simply wasn't displayed.
2021-07-25 15:29:24 -04:00
JohnAFernandez 18754fafc1 Force Portable Initial Changes (#3562)
Allows us to at least try to use a file path with a unicode character

Typo

Fixup

Update osapi.cpp
2021-07-25 14:18:45 -04:00
Baezon d05b3fa637 handle beam free all in subsys_set 2021-07-25 11:15:01 -04:00
Goober5000 a26367db5f qtfred support 2021-07-24 14:15:06 -04:00
Goober5000 e3617169ca add Draw Outlines on Selected Ships option
This option is helpful because the mesh outlines will often obscure important information like submodel names and turret weapons.
2021-07-24 14:15:06 -04:00
Goober5000 3c487f81f3 Merge pull request #3570 from Goober5000/weapon_list_type_fix
fix WEAPON_LIST_TYPE parsing for -1
2021-07-24 14:12:33 -04:00
Goober5000 878dd4b313 this makes sense too 2021-07-23 20:59:37 -04:00
Goober5000 74d95f01bc fix WEAPON_LIST_TYPE parsing for -1
When an empty string is encountered in the weapon list, it's valid, but the -1 should actually be stored, not skipped.

This bug was preventing ship weapons from being explicitly set to None.
2021-07-23 20:52:29 -04:00
BMagnu 226d51c214 Merge pull request #3500 from BMagnu/anim_rework_1
Animation Overhaul: Phase 1
2021-07-23 23:59:26 +09:00
Asteroth 9855062732 Merge pull request #3567 from Baezon/fix-null-parse-object
Fix a nullptr bug with change_ship_type
2021-07-23 01:01:08 -04:00
Birk Magnussen 5709e24e9a save by PMI id not PMI*, rename 'time' variable 2021-07-23 13:17:11 +09:00
JohnAFernandez 13c410e864 Remove extra AI Profiles call (#3566)
This function has to be called on game/FRED/qtFRED start, and does nothing once it is called.  So there is no reason for it to be hear on mission close.
2021-07-22 22:51:11 -04:00
Birk Magnussen 5f4729bddb Remove Variable Shadowing 2021-07-23 04:38:23 +09:00
Baezon 65fa916cba move some flag setting to subsys_set 2021-07-22 15:29:22 -04:00
Birk Magnussen 473acced54 Apply new initial animations for techroom instances 2021-07-23 04:27:43 +09:00
Birk Magnussen b58b60b555 Fix Constructor Order 2021-07-23 03:31:06 +09:00
BMagnu 9c3b90f403 Merge branch 'master' into anim_rework_1 2021-07-23 03:18:32 +09:00
Birk Magnussen 3b0e02545e Move Animations from ship* to pmi* 2021-07-23 03:12:54 +09:00
Baezon 9e6e1ef123 clang tidy 2021-07-22 12:00:00 -04:00
Baezon 2e4e9855bc ensure p_objp is not null 2021-07-22 01:59:26 -04:00
Asteroth 9adc89a5a2 Merge pull request #3441 from Baezon/ballistic-beams
Add support for ballistic beams
2021-07-21 15:58:09 -04:00
Goober5000 8faa521df9 Merge pull request #3565 from Goober5000/fix_briefing_icon_override
fix briefing icons changing to ships unexpectedly
2021-07-21 12:33:59 -04:00
Baezon a3513c38b6 Merge branch 'master' into ballistic-beams 2021-07-21 02:59:33 -04:00
Goober5000 15901e430f fix briefing icons changing to ships unexpectedly
If the briefing icon doesn't actually show a ship, then don't use the ship icon override.
2021-07-20 23:21:11 -04:00
Asteroth 37584f576c Merge pull request #3561 from Baezon/no-generic-debris-for-subsystems
Minor improvement for generic debris on subsystems
2021-07-19 19:55:44 -04:00
Baezon 3863d9b5a9 dont use generic debris for subsystems 2021-07-17 20:20:54 -04:00
Goober5000 5318fba077 Merge pull request #3558 from Goober5000/qtfred_menu_update
Qtfred menu update
2021-07-17 19:54:06 -04:00
Asteroth d187a6ae99 Merge pull request #3555 from Baezon/firepoints-burst-shots
Add "num firepoints for burst shots" flag
2021-07-17 19:40:04 -04:00
Asteroth 30b35b483b Merge pull request #3556 from Baezon/audiostream-set-volume
Add setVolume function for audio_stream objects
2021-07-17 19:39:33 -04:00
Goober5000 f7f0c2ba21 Merge pull request #3559 from Goober5000/training_message_preservation
Training message preservation
2021-07-17 00:10:51 -04:00
Goober5000 f1362a694d Merge pull request #3560 from Goober5000/log_lcl_weirdness
log when missions are skipped due to XSTR mismatch
2021-07-17 00:09:34 -04:00
Baezon db55349f70 some extra safety and warning for super huge numbers of poofs 2021-07-16 22:30:39 -04:00
Baezon 2d84fdf5c6 Merge remote-tracking branch 'upstream/master' into poof-overhaul 2021-07-16 22:29:56 -04:00
Goober5000 5e7a6ece52 log when missions are skipped due to XSTR mismatch
As a follow-up to #2343, users might wonder why their mission isn't showing up in the tech room, so log a friendly message.
2021-07-16 22:17:36 -04:00
Goober5000 ff62ea010e training messages have additional idiosyncrasies 2021-07-16 22:09:11 -04:00
Goober5000 a14a746a4f don't pre-empt training messages before they finish playing 2021-07-16 20:56:33 -04:00
Goober5000 d4c0c45595 whoops 2021-07-16 00:09:37 -04:00
Goober5000 06eaeca9d7 add Move Ships When Undocking menu option 2021-07-15 23:50:20 -04:00
Goober5000 dd5c92a910 move the show teams code to the right spot and remove the todo 2021-07-15 23:49:27 -04:00
Goober5000 2de1776308 reorder misc menu and fix a couple captions 2021-07-15 23:13:12 -04:00
Goober5000 833b51e423 sync shortcut keys to what they are in FRED 2021-07-15 22:46:57 -04:00
Goober5000 726d66d0ad add the Highlight Selectable Subsystems menu item 2021-07-15 22:17:05 -04:00
Goober5000 c7e2b3c78f add the Clone Marked Objects menu item 2021-07-15 22:15:26 -04:00
Goober5000 97a93162f8 Merge pull request #3557 from Goober5000/qtbug_72073
work around MSVC 2015 and 2017 compiler bug
2021-07-15 00:03:51 -04:00
Goober5000 1fa270ad66 work around MSVC 2015 and 2017 compiler bug
This macro bypasses a compiler bug where MSVC can't distinguish the division symbol.  See https://bugreports.qt.io/browse/QTBUG-72073
2021-07-14 20:13:11 -04:00
Baezon 5b316a562d clarifying comments 2021-07-14 00:22:46 -04:00
Baezon 9c14717b81 use macro version of true/false return 2021-07-14 00:14:08 -04:00
Baezon 0b8bbb3f47 add set volume for audio streams 2021-07-13 15:29:07 -04:00
Goober5000 314833ae61 Merge pull request #3554 from Goober5000/fred_turret_info
FRED turret info
2021-07-11 21:39:46 -04:00
Goober5000 4a4d07872a Merge pull request #3553 from Goober5000/loop_mission_tweak
fix campaign loop in certain cases
2021-07-11 16:10:39 -04:00
Goober5000 fdc33d8ab5 some fixes 2021-07-11 03:52:01 -04:00
Goober5000 c0430f0b55 add menu option to display info for all turrets 2021-07-11 03:42:24 -04:00
Goober5000 0d2d94a49b display weapons along with turrets 2021-07-11 03:33:43 -04:00
Goober5000 4f46fff48c fix campaign loop in certain cases
If the loop mission and the next mission are the same, then don't show the campaign loop screen.  This prevents the campaign from getting into a campaign loop state if it shouldn't, and also allows campaign loops to be conditionally accessible.
2021-07-11 00:49:09 -04:00
Goober5000 1b1d864c59 Merge pull request #3552 from Baezon/fix-secondary-range-check
Fix a secondary range bug from AI multilock
2021-07-09 15:21:32 -04:00
Baezon f1ddfafdf3 fix a bug from ai multilock 2021-07-09 01:55:35 -04:00
Baezon 3481032ae5 add num_firepoints_burst_shots flag 2021-07-08 17:08:56 -04:00
Asteroth 3a4e5d75a3 move the event flag reset to the top of the function to avoid restting anything we just applied (#3551) 2021-07-07 03:44:17 +00:00
PhantomHoover 84b25b52d7 Be smarter about when we try to run scripting hooks: don't even bother trying if no scripts are even registered to run on them. (#3538) 2021-07-02 22:50:53 -04:00
Taylor Richards f2d3aaaf20 Merge pull request #3544 from notimaginative/fix_gtrack_packet_size
bump tracker packet sizes to match server
2021-06-29 00:57:24 -04:00
JohnAFernandez ffbcdab9da Remove Buggy Function and Let Debris End Naturally (#3540)
* Remove Buggy Function and Let Debris end natrually

Removes this retail function that was actually perpetually postponing the death of debris at long distances instead of removing them.  Debris lifetime is suitably short for the small, non-hull pieces (only a few seconds), while large pieces are supposed to be permanent.   It also culls based on player position, which is not the correct approach, since the camera can be free from the player ship.

* Remove Vestigial Variables

These variables are no longer checked for anything now that we allow debris to go through its lifetime.
2021-06-28 08:11:10 -04:00
Goober5000 8db2f374f2 Merge pull request #3545 from Goober5000/fix_3539
fix 3539
2021-06-28 00:58:48 -04:00
Goober5000 46959276f5 fix 3539
If a bad token is found in a string list, just advance the parser until the next token or EOLN.
2021-06-27 21:24:44 -04:00
Taylor Richards d5afd8d79b bump tracker packet sizes to match server
- allow for size of IPv6 game list packet (fixes #3543)

These larger packet sizes aren't required for
FS2/FS2_Open, but just keeps the code in sync.
2021-06-27 13:43:19 -04:00
Goober5000 2a8064a3e9 Merge pull request #3536 from Goober5000/lua_sexp_help
allow characters in SEXP help
2021-06-26 17:41:01 -04:00
Goober5000 9741b36442 allow characters in SEXP help
Certain characters (especially the semicolon) couldn't be used in SEXP help.  By using the same character replacement as in briefings and messages, now they can.
2021-06-25 22:38:31 -04:00
PhantomHoover 0fe59e10ad Inline matrix multiplication ops for performance improvements (#3535) 2021-06-25 22:19:42 -04:00
Asteroth e287c575ce Merge pull request #3534 from Baezon/bugfix-initial-shield-strength
Initialize `n_quadrants` before setting shield strength
2021-06-25 14:24:01 -04:00
Asteroth b14a27cdff fix model point shield handling for mini target shields (#3531) 2021-06-25 00:44:39 -04:00
Baezon 63b0f0a373 bug fix initialize n_quadrants before setting shield strength 2021-06-24 18:44:25 -04:00
Asteroth c464a1cd4c Merge pull request #3532 from Baezon/bugfix-ai-multilock-no-dumbfire
Bugfix with ai multilock and no dumbfire
2021-06-24 18:28:50 -04:00
Asteroth 6889ee856f Merge pull request #3533 from Baezon/bugfix-shield-hit-delay
Initialize shield regen hit delay
2021-06-24 18:28:29 -04:00
Baezon 292f1547c4 initialize shield regen hit delay 2021-06-24 17:38:00 -04:00
PhantomHoover a687fe0aef Reimplement matrix3 multiplication based on a common overloaded operator (#3470) 2021-06-24 17:26:51 +00:00
Baezon 31fa21bbf1 bugfix ai multilock and no dumbfire 2021-06-24 01:29:11 -04:00
Asteroth be6a7f552a Merge pull request #3443 from Baezon/trails-optimize
Optimize trail rendering
2021-06-23 16:59:51 -04:00
Baezon 93da6616f7 Merge remote-tracking branch 'upstream/master' into trails-optimize 2021-06-23 16:04:13 -04:00
Asteroth 4aeaabf337 Merge pull request #3529 from Baezon/shield-regen-hit-delay
Add shield regen hit delay
2021-06-23 16:02:15 -04:00
Asteroth 589071ac46 Merge pull request #3183 from Baezon/ai-multilock
Add AI support for multilock
2021-06-23 02:15:07 -04:00
wookieejedi ccf0e7eb04 Merge pull request #3510 from wookieejedi/add-extra-script-sound-enums
Add More Options to Scripted Persistent Sounds
2021-06-22 18:37:20 -04:00
Baezon adb7d9d195 review tweaks 2021-06-22 16:46:13 -04:00
BMagnu 7a2a4b6640 Merge pull request #3526 from BMagnu/luasexp_subcat_fix
Allow non-unique sexp subcategories
2021-06-22 22:52:10 +09:00
Goober5000 e4f9ca05c5 clang 2021-06-22 02:05:26 -04:00
Taylor Richards 0160fac2ff Refactor hud escort list to be less crazy (#2922)
* refactor hud escort list to be less crazy

 - don't keep rebuilding list
 - add and remove ships more efficiently
 - better handling of player ships in multi (fixes #1674)

* fix sorting issues

 - incomplete priority sort
 - reversed alpha sort

* fix additional sorting issue

* improve safety check in list sort function

* add safety checks to hud_add_ship_to_escort()

this wasn't meant to be used outside of the module so
it was not really safe to use with sexps previously

* remove entries properly in hud_add_remove_ship_escort()
2021-06-22 01:34:06 -04:00
Goober5000 cc2d06d37c correctly handle non-looping sounds when they have finished playing 2021-06-22 01:24:39 -04:00
wookieejedi c5b29c62c6 incorporate feedback
More modifications are still needed though, so keeping in draft status
2021-06-22 00:11:28 -04:00
Baezon 8e2d93211c add shield regen hit delay 2021-06-21 21:01:51 -04:00
Joshua Glatt eca6647dbf Fix leaking of game objects and memory in F3 lab (#3512) 2021-06-21 17:12:51 -07:00
Goober5000 b6e214a4d4 Merge pull request #3528 from Goober5000/language_sexp
add is-language
2021-06-21 15:57:03 -04:00
Goober5000 841a4b8cea add is-language
Checks whether the game is running in the specified language.  Since the fiction viewer doesn't use XSTR-style localization, this SEXP can be used to display different stages for different languages.
2021-06-21 15:00:28 -04:00
m!m 19bc18cb32 Merge pull request #3525 from asarium/build/ccacheTest
Use ccache to speed up some PR builds
2021-06-21 17:50:49 +02:00
Goober5000 823c76ec22 Merge pull request #3064 from z64555/feature/time_to_goal
Feature/time to goal
2021-06-21 11:48:05 -04:00
Goober5000 a75ad91518 Merge pull request #3469 from Goober5000/external_submodel_offset
Add external weapon model angle offset
2021-06-21 11:17:00 -04:00
Birk Magnussen bdefb55ec9 Allow non-unique sexp subcategories 2021-06-21 15:16:17 +09:00
Baezon 00f7f13371 Merge remote-tracking branch 'upstream/master' into ballistic-beams 2021-06-20 22:09:16 -04:00
Baezon 1441cc8e85 review tweaks for ballistic beams 2021-06-20 21:50:11 -04:00
Goober5000 a8a9127d81 Merge pull request #3504 from Goober5000/tstring_check_fix
maintain a copy of the default translations to check against untranslated strings
2021-06-20 21:25:32 -04:00
Joshua Glatt 028168d395 Add in-game options menu options for lightshafts and bloom (#3501)
* Add in-game options menu options for lightshafts and bloom

* move impl of new PostProcessingManager functions to .cpp file
2021-06-20 21:04:34 -04:00
Taylor Richards 7dae8940d7 support opening of web urls on PXO screens (#3485)
* support opening of web urls on PXO screens

(copied out of icculus.org version)

* add delay before allowing more clicks on links

* fix clang-tidy issues
2021-06-20 20:58:55 -04:00
Asteroth 814d44c986 Add weapon optimum range for AI fighters (#3457)
* add weapon optimum range

* review tweaks
2021-06-20 20:52:02 -04:00
Asteroth 99fb2c00ab fix shooter scaling offsets (#3521) 2021-06-20 18:30:09 -04:00
m!m f7c3ab85d3 Merge pull request #3524 from asarium/build/removeDeprecatedCMakeStuff
Remove usage of deprecated CMake module
2021-06-20 18:27:14 +02:00
asarium d03a1007df Use ccache to speed up some PR builds
This sets up ccache to speed up some builds. I hope this also works with
forks since I don't know if those are allowed to use the main repo
cache.
2021-06-20 14:24:11 +02:00
asarium b6fe676072 Remove usage of deprecated CMake module
Also removed all checks for C++11 support since we only support
compilers that have this already.
2021-06-20 12:56:20 +02:00
Goober5000 07f4f4716b handle clang 2021-06-20 02:47:19 -04:00
Asteroth 30e48c1b03 Merge pull request #3511 from Baezon/beam-attenuation-bugfix
Bugfix for beam attenuation damage
2021-06-20 02:31:48 -04:00
Asteroth 352fd3cdfc Merge pull request #3514 from Baezon/negative-hull-repair-kill
Properly handle death due to negative hull repair rate
2021-06-20 02:31:38 -04:00
Goober5000 1becca7cbe accommodate mismatches 2021-06-20 00:45:39 -04:00
Goober5000 07312ff4c0 add code for actually rotating the external models 2021-06-20 00:45:38 -04:00
Goober5000 f9c73e81f2 add code for loading external model angle offset from POF file 2021-06-20 00:45:34 -04:00
Goober5000 e2585a9a0e change secondary_point_reload_pct to be dynamic and to not rely on MAX_SLOTS 2021-06-19 23:23:53 -04:00
Goober5000 d6c65d5139 Merge pull request #3489 from Goober5000/POF_version_adjustment
add some more sophisticated POF version handling
2021-06-19 23:14:00 -04:00
Goober5000 c3551f4361 Merge pull request #3520 from Baezon/downgrade-parse-severity
Restore original error handling of stuff_int_list
2021-06-19 21:43:32 -04:00
Goober5000 d787bd7c6f Merge pull request #3522 from EatThePath/fix-hook-conditions-i-broke
Moved script initialization to take place after all table loads
2021-06-19 21:42:47 -04:00
Baezon 7dd454f563 review changes 2021-06-19 18:39:35 -04:00
Goober5000 f1deee8566 Merge pull request #3354 from Goober5000/gs_state_invalid
actually use GS_STATE_INVALID
2021-06-19 17:49:38 -04:00
David Gibson b24289e918 Moved script initialization to take place after all table loading to facilitate script condition caching. 2021-06-19 12:34:16 -05:00
Baezon 94b1d11f47 restore original error handling of sutff_int_list 2021-06-19 02:58:20 -04:00
Goober5000 c541ac91db Merge pull request #3513 from the-maddin/qt-checked-list-3
Rewrite of CheckedDataListModel
2021-06-19 00:37:40 -04:00
the-maddin eb6f7fb013 Fix some clang stuff 2021-06-18 23:10:56 +02:00
Baezon d2c24efeff properly handle death due to negative hull repair rate 2021-06-18 16:50:55 -04:00
Goober5000 318fed546f Merge pull request #3509 from BMagnu/briefing_shadows
Add shadow map generation for briefing
2021-06-18 15:54:29 -04:00
the-maddin 474f225672 be explicit for msvc
(cherry picked from commit 97e2028337265a5529d0b0a5fb76bb52e1a4ab37)
2021-06-18 20:33:34 +02:00
the-maddin 14337c22b0 Rewrite CheckedDataListModel
for better flexibility & efficiency
2021-06-18 20:21:28 +02:00
Baezon 647334f4ff redundant fwd declaration 2021-06-17 18:39:46 -04:00
wookieejedi 03d51ba400 appease clangtidy 2021-06-17 17:23:01 -04:00
Baezon 3767758ae5 bugfix beam attenuation damage 2021-06-17 17:10:35 -04:00
wookieejedi def814fa4e fix typo 2021-06-17 17:01:53 -04:00
wookieejedi 11c5af39d8 Add More Options to Scripted Persistent Sounds
This adds two new enums to persistent sounds which can be utilized by scripts.
1. OS_PLAY_ON_PLAYER, which allows persistent sounds to play on the player's ship.
2. OS_LOOPING_DISABLED, which allows the scripter to set the sound to play once and not have to then call `removeSound` later. Very handy for playing an assigned sound once with one line.

Tested and everything works as expected.
2021-06-17 16:58:25 -04:00
Birk Magnussen c6b75d3561 Add forgotten Animation Instancing 2021-06-18 04:09:03 +09:00
Goober5000 866a7c40df Merge pull request #3497 from JohnAFernandez/fix-pause-locking
fix missiles locking during pause
2021-06-17 14:58:48 -04:00
Goober5000 5076066627 Merge pull request #3508 from Goober5000/enum_bitops
add bitwise operations with enums
2021-06-17 14:53:37 -04:00
Goober5000 70546b68a5 add bitwise operations with enums
This adds `EnumAND` and `EnumOR` which will return new enums based on the specified operations.  These are handy for enums that correspond to bit fields, such as those used for object persistent sounds.
2021-06-17 14:17:16 -04:00
Baezon a6084ba707 change from radians to degrees 2021-06-17 14:04:47 -04:00
Baezon 27650ef45d proper poof toggling support 2021-06-17 13:15:07 -04:00
Birk Magnussen 4f5fb48f79 Add shadow map generation for briefing 2021-06-17 14:45:54 +09:00
Goober5000 c1d2920526 Merge pull request #3506 from Goober5000/enhance_bitops
some bitwise operation enhancements
2021-06-16 12:17:38 -04:00
Baezon 90558a5858 Merge branch 'master' into poof-overhaul 2021-06-16 03:26:58 -04:00
Birk Magnussen 390f979b7c Small parse improvement + english fixes 2021-06-16 13:51:55 +09:00
wookieejedi 7258861791 Merge pull request #3505 from wookieejedi/add-save-as-shortcut
Add Keyboard Shortcut for `Save As` in FRED
2021-06-15 20:15:22 -04:00
Goober5000 76b944e01d fix tests 2021-06-15 19:53:28 -04:00
Goober5000 8006baec65 Merge pull request #3498 from JohnAFernandez/fix-scripts-crashing-with-bad-mission-data-when-pressing-esc
Add Menu and Mission resetting to scripting state.
2021-06-15 18:15:01 -04:00
Goober5000 443e148869 some bitwise operation enhancements
Allow AND and OR to take up to 10 arguments.  Deprecate addBit and replace with setBit, and add unsetBit.
2021-06-15 17:56:49 -04:00
wookieejedi f9265301af Add Keyboard Shortcut for Save As in FRED
Finally got around to adding in the `Ctrl+Shit+S` shortcut for Save As in FRED. Tested and works as expected.
2021-06-15 16:03:02 -04:00
Birk Magnussen bd6dae97a7 Fixed Code for GCC and C++11 2021-06-16 02:10:30 +09:00
JohnAFernandez 74c6b0c3cb Add escape character for < and > in html output (#3499) 2021-06-15 12:51:40 -04:00
Goober5000 3685a78ea9 make clang happy, and fix a bug in the English handling 2021-06-15 12:40:41 -04:00
Birk Magnussen d0948e67e3 Tidy up some new code into separate functions 2021-06-15 13:27:08 +09:00
JohnAFernandez 3660761d7c Add Menu and Mission resetting to scripting state. 2021-06-14 23:16:10 -04:00
JohnAFernandez e6579fca09 fix missiles locking during pause 2021-06-14 22:37:32 -04:00
Goober5000 da0459feeb Merge pull request #3494 from Baezon/adjust-waypoint-turnrate
Bugfix for waypoint turnrate
2021-06-14 15:07:25 -04:00
Goober5000 b428899d5b Merge pull request #3496 from Goober5000/ui_cutscene
add a scripting function for playing cutscenes in the UI
2021-06-14 14:25:31 -04:00
Goober5000 00ec3431b7 add a scripting function for playing cutscenes in the UI
Implements `common_maybe_play_cutscene` as a scripting function.  Partial fix for #3367.
2021-06-14 13:48:31 -04:00
Goober5000 353d66c17d maintain a copy of the default translations to check against untranslated strings
Bug #3471 occurs because the game only keeps a translation table for the current language.  Since the mission list needs to compare untranslated strings against English strings, this adds a duplicate table for English.  However, it only keeps strings that are NAME_LENGTH or less, because the comparison only needs to be run against mission names.ssss

Fixes #3471.
2021-06-14 02:43:28 -04:00
Goober5000 84ceae724c Merge pull request #3493 from Goober5000/objsnd_bugfix
fix to #3476
2021-06-13 19:27:36 -04:00
Joshua Glatt c47518ec6e karajorma's SEXP containers, Part 3: 'Add/Modify Container' FRED dialog (#3463) 2021-06-13 15:16:27 -07:00
Baezon 76c9583e45 bugfix for waypoint turnrate 2021-06-13 16:33:57 -04:00
Goober5000 131fadfab3 fix to #3476
The default sound position should be the zero-vector, not nullptr.  Also, this adds a bit of extra type safety.
2021-06-13 15:35:44 -04:00
Goober5000 74233c029c Merge pull request #3487 from Goober5000/move_engine_sound
center the persistent sound by default
2021-06-13 00:18:47 -04:00
Goober5000 c1d8834d81 make clang happy 2021-06-11 18:46:03 -04:00
Goober5000 7b69c10e56 add some more sophisticated POF version handling
This adds additional version definitions so that features can be added which support both the aligned and non-aligned POF formats.
2021-06-11 17:53:56 -04:00
Goober5000 c0bb5bc8eb Merge pull request #3326 from Shivansps/arm_fixes_v2
POF 2118 and SLC2 support
2021-06-11 17:43:28 -04:00
m!m 2e56b3ca61 Merge pull request #3382 from asarium/build/readdClang9
Fix missing clang-9 binary in build image
2021-06-11 21:51:12 +02:00
asarium 3c3f79bc8f Fix missing clang-9 binary in build image 2021-06-11 20:54:09 +02:00
Goober5000 462a234e81 Merge pull request #3488 from Goober5000/model_version_warning
add warning for supported POF file versions
2021-06-11 11:33:26 -04:00
Goober5000 eaf14760c4 add warning for supported POF file versions
With several upcoming POF format enhancements (byte alignment, external weapon rotation, submodel translation) it makes sense to warn users if they happen to load an unsupported POF file.
2021-06-11 10:40:21 -04:00
Birk Magnussen a9e5505a7c Added Comments, light refactoring 2021-06-11 13:39:55 +09:00
Asteroth 1525b520d7 Merge pull request #3483 from Baezon/better-damage-type-handling
Improve damage type handling when dealing damage
2021-06-10 18:53:39 -04:00
Goober5000 1843f76d04 center the persistent sound by default
The assumed location of a ship's "EngineSnd" is at its rearmost extent, which is fine for ships with engines, but not suitable for stationary objects such as space stations and comm nodes.  If the ship doesn't have an "engine" subsystem, place the persistent sound in the center.
2021-06-10 18:44:46 -04:00
Goober5000 41cf0b3d52 Merge pull request #3486 from Goober5000/3476_followup
small followup fix for #3476
2021-06-10 17:11:33 -04:00
Goober5000 990b5a3908 small followup fix for #3476
Missed changing the argument type when I changed from int to enum.
2021-06-10 16:38:41 -04:00
Asteroth e4661b00b1 Add Type 5 beams (#2817)
* wip

* basics are working

* turret case is handled

* better fighter beam handling

* missing commit?

* handle missile spawn

* clean up, commenting and ssb handling

* random in sphere and per burst rot counts for "share random" flag

* clean up, clarity and comments

* accidental whitespace changes

* bugfix

* NULL -> nullptr

* more efficiency/clarity

* review tweaks and bugfixes
2021-06-09 18:53:53 -04:00
Baezon 4457471ec5 Merge remote-tracking branch 'upstream/master' into better-damage-type-handling 2021-06-09 17:24:11 -04:00
Goober5000 128107ea43 Merge pull request #3476 from Goober5000/script_obj_sound
add scripting functions to control sounds assigned to objects
2021-06-09 16:00:53 -04:00
Asteroth c840d3e032 Add No_shield_damage_from_ship_collisions flag (#3480)
* add All_ships_take_hull_damage_from_collisions flag

* rename flag and apply flag to debris and asteroid hits
2021-06-09 15:49:35 -04:00
Goober5000 35a09527e5 another #include 2021-06-09 11:52:00 -04:00
Goober5000 20e5f35fb4 include definitions 2021-06-09 11:16:17 -04:00
Goober5000 d217873281 update flags with enums 2021-06-09 10:44:40 -04:00
Baezon 37c5041c03 improve damage type handling when dealing damage 2021-06-09 03:30:52 -04:00
Birk Magnussen fb657c081c Turret fix 2021-06-09 16:04:59 +09:00
Birk Magnussen 7945baa751 Fix turret detection 2021-06-09 15:56:28 +09:00
Birk Magnussen e9a2ff0ebf Fix proper duration handling of segments and full anims 2021-06-09 15:03:46 +09:00
Asteroth 4328b66a28 fix offset initialization (#3468) 2021-06-09 01:38:09 -04:00
Asteroth 11c5bcda74 Merge pull request #3479 from Baezon/improve-particle-alpha
Improve particle alpha handling for small particles
2021-06-08 18:21:52 -04:00
MageKing17 43f9a48cb9 Get a pointer to the generic_anim.
Whoops.
2021-06-08 13:30:21 -07:00
MageKing17 c6e79a61ea Add current_frame safety check to main_hall_mouse_release_region().
There's a similar safety check for opening doors, so we should check here as well.
2021-06-08 12:28:59 -07:00
MageKing17 5d58d9ca7a Reset APNG misc animations properly (fixes #3399).
Changes the `current_frame` checks in generic.cpp so that the last frame can actually be reached (allows the mainhall code to tell the misc animation has finished), and adds a `generic_anim_reset()` function that gets called instead of manually setting `current_frame` and `anim_time` to 0. This should fix #3399.
2021-06-08 12:27:15 -07:00
Birk Magnussen 384b2e20c7 Integrate Initial Type animations 2021-06-08 21:28:15 +09:00
Birk Magnussen 20e742ed61 Generate Animations for initial-type animations 2021-06-08 14:45:35 +09:00
Baezon 29846e2101 make particle alpha distance fade be based in part on radius 2021-06-07 20:50:12 -04:00
Goober5000 a1635cdd76 Merge pull request #3301 from Baezon/beam-substitution
Implement substitution for beams
2021-06-07 11:59:34 -04:00
Goober5000 c80144ce44 Merge pull request #3473 from jg18/sexp-container-1-fixes
A few small fixes to SEXP container definition
2021-06-07 11:23:16 -04:00
Fabian Woltermann 6e11f356ea Merge pull request #3477 from Baezon/fix-accel-weapon-cull
Fix collision culling for accelerating weapons... again
2021-06-07 14:58:14 +02:00
Joshua Glatt 7e4190b97e add any() and none() for ContainerType 2021-06-06 19:41:14 -07:00
Goober5000 65e65b01b6 Merge pull request #3478 from Goober5000/fix_subsystem_stricmp
fix bug in subsystem_stricmp
2021-06-06 14:42:17 -04:00
Joshua Glatt f3773388b9 make ContainerType's '&' overload return ContainerType instead of bool 2021-06-06 11:35:54 -07:00
Goober5000 b05132a64f fix bug in subsystem_stricmp
Here's a bug that's been around ever since version 3.6.  If the subsystem names were not essentially the same, the function wouldn't do the expected string comparison.
2021-06-06 13:59:51 -04:00
Baezon 6c399ccace fix accelerating weapons culling 2021-06-06 12:23:02 -04:00
Goober5000 373a8b940a add scripting functions to assign and remove sounds on objects 2021-06-05 20:03:35 -04:00
Joshua Glatt b4d0db8846 finish implementing bitwise operations for ContainerType 2021-06-05 16:42:55 -07:00
Goober5000 9c0575f173 Merge pull request #3060 from EatThePath/range-aware-secondary-selection
Range aware secondary selection
2021-06-05 19:23:12 -04:00
Goober5000 64f5ad925b Merge pull request #3466 from Baezon/weapon-no-collide
Add "no collide" for weapons
2021-06-05 19:22:52 -04:00
Goober5000 81b06fec41 Merge pull request #3475 from MageKing17/bugfix/superfluous-child-warning
Remove superfluous warning about missing "child" flag.
2021-06-05 19:22:46 -04:00
Goober5000 3c553665aa remove the 'main' argument from obj_snd_assign 2021-06-05 17:40:58 -04:00
MageKing17 f252473b84 Remove superfluous warning about missing "child" flag.
If a weapon has "inherit parent target" but not "child", a Warning will be generated. However, there is no dependency between the two flags; the weapon will function as the modder presumably expects. The Warning even seems to indicate this, by saying "No changes in behavior will occur" (as opposed to other similar warnings, which generally indicate that a flag will be ignored). Since the situation being warned about does not actually cause any issues, the Warning is entirely superfluous. As such, I've removed it outright.
2021-06-05 13:05:40 -07:00
Goober5000 1caf54e909 Merge pull request #3472 from Goober5000/deprecate_script_eval
deprecate script-eval
2021-06-04 21:44:27 -04:00
Birk Magnussen 6aecc4660d Add forced caching of submodelID 2021-06-04 15:52:08 +09:00
Birk Magnussen c915bfd474 Appropriate refactoring of ModelAnimationSubSYSTEM -> model 2021-06-04 15:48:05 +09:00
Birk Magnussen bd2356600f Actually use new constructor 2021-06-04 15:42:31 +09:00
Birk Magnussen 9c6cc422ac Improve Code. Operate on Submodels, not subsystems. 2021-06-04 15:36:32 +09:00
Joshua Glatt 7bd74b2a7b A few small fixes to SEXP container definition 2021-06-03 21:45:16 -07:00
Asteroth 9d5eeb6e08 Merge pull request #3461 from Baezon/random-homing-target-acquisition
Add random homing target acquisition
2021-06-03 20:10:21 -04:00
Goober5000 5ffc05fa85 deprecate script-eval
The script-eval SEXP evaluates all arguments as individual script commands, which is not ideal because most FREDders expect the arguments to be concatenated.  Since the script-eval-block SEXP handles its arguments this way, it makes sense to hide the script-eval SEXP in FRED to prevent confusion.
2021-06-03 19:07:28 -04:00
MageKing17 8ae77e0356 Fix calling split_str() with a maximum line length of 0. (#3465)
Commit 6c2ebab01c (#3439) added a `max_line_length` argument to `split_str()`, but one call had the extra argument added in the wrong spot, and so a previously-pointless-but-harmless `ignored_char` of 0 became a `max_line_length` of 0, resulting (ultimately) in an exception in the unicode code when the iterator tried to decrement at the beginning of a ship's description. This gets rid of the argument entirely, rather than reordering them, because ignoring null characters doesn't really do anything anyway.

I've also added `Assertion`s to check `max_line_length` that should prevent this specific problem from occurring again in the future.
2021-06-03 15:30:34 -04:00
Birk Magnussen a113897c88 Fix some startup logic 2021-06-03 16:51:57 +09:00
Birk Magnussen 4ee04f2492 Fix oversight for ModelAnimationSubsystem 2021-06-03 16:51:56 +09:00
Birk Magnussen 093a471602 Beginnings of new System 2021-06-03 16:51:48 +09:00
Asteroth 22be402de5 remove glowpoint 'depth' (#3455) 2021-06-02 12:54:10 -04:00
Asteroth 84133c42a8 fix ai_aims_from_center flag (#3467) 2021-06-02 12:53:45 -04:00
Joshua Glatt df1c518c3b Validate user-provided values passed to Random::next() (#3464)
* Validate user-provided values passed to Random::next()

* return low value on invalid range

* call LuaError() instead of Warning() in rand32() script function
2021-06-02 12:52:30 -04:00
Asteroth 8ac4c54d43 actually limit based on player like the comment says (#3460) 2021-06-01 22:23:14 -04:00
Asteroth 1445e778f0 Add volume effects (#3446) 2021-06-01 22:20:42 -04:00
Asteroth 2b6041f766 uncouple launch sound from loop sound (#3450) 2021-06-01 22:19:30 -04:00
Baezon 59d30157d8 add no collide for weapons 2021-05-31 22:50:00 -04:00
Joshua Glatt 552201884b karajorma's SEXP containers, Part 1: Definition, parsing, and saving (#3449) 2021-05-31 09:15:48 -07:00
Baezon e053d06a5f add random homing target acquisition 2021-05-30 22:24:24 -04:00
David Gibson f677767846 added safety check assert as requested. 2021-05-30 19:32:23 -05:00
David Gibson 9b35a4e653 Nullpointer and variable name fixes for range aware selection, and moved default weapon max range into a define. 2021-05-30 19:32:23 -05:00
David Gibson 6c0bfd4df5 Tied range aware secondary selection to an aiprofiles flag 2021-05-30 18:58:46 -05:00
David Gibson 102bc28424 Added functionality to get_available_secondary_weapons to screen weapons by range. Controlling flag to be added. 2021-05-30 18:58:46 -05:00
David Gibson 081e34815c corrected misleading comment on get_subsystem_pos 2021-05-30 18:58:46 -05:00
Baezon 6cf5553147 review tweaks 2021-05-30 16:55:50 -04:00
Asteroth 80f4f1abde add weapon ambient sound (#3452) 2021-05-30 16:02:24 -04:00
Taylor Richards 2e30674823 Merge pull request #3386 from notimaginative/add_firewall_status
add firewall status
2021-05-30 10:15:43 -04:00
ngld 448d0457c8 Merge pull request #3454 from ngld/feat/betterPofParserErrors 2021-05-30 01:31:19 +02:00
JohnAFernandez 9d7acbcc9d Update Function Name and comment to describe what it actually is (#3451)
Change find_player_id to find_player_index, since that is what it does
2021-05-29 19:21:36 -04:00
ngld c8cee4cdb1 Provide better error messages for invalid vec3ds in POF files. 2021-05-30 00:21:09 +02:00
the-maddin 21aa608eb6 whitespace cleanup (#3453)
replace spaces with tabs to fix
-Wmisleading-indentation
2021-05-29 21:59:44 +00:00
Goober5000 d6a0d9fb02 Merge pull request #3447 from the-maddin/qt-checked-list-2
qtFred: improvements to my checked list
2021-05-28 22:55:56 -04:00
Asteroth edcdbd02b6 fix bug where shields could be pierced (#3448) 2021-05-28 11:10:18 -04:00
Asteroth d49e24fa0c Add healing weapons (#2873)
* basic proof of concept: healing weapons

* implement healing weapons

* remove unused parameter

* travis

* more travis

* endless travis

* earlier multi client return

* update find_submodel_instance_world_point

* review tweaks
2021-05-25 23:03:20 -04:00
the-maddin e74ebe6b84 fix type warning 2021-05-26 00:56:54 +02:00
the-maddin c197755c0e Improve CheckedDataListModel
Add text coloring support
Add contains/add functions
Row construction efficiency fixes
Whitespace cleanup
2021-05-26 00:06:41 +02:00
Goober5000 ec4de81a79 Merge pull request #3370 from Goober5000/hud_gauge_parameter_type
Hud gauge parameter type
2021-05-24 17:58:05 -04:00
Asteroth c10d6ececf optimize motion debris rendering (#3444) 2021-05-24 17:42:16 -04:00
BMagnu 6c2ebab01c Fix erroneous line break generation for non-ASCII string and high resolutions (#3439)
* Added a byte limit for line length in split function

* Fix call error

* Ádd missing limits import

* Change hardcoded values into defines

* Cleanup default argument
2021-05-24 17:38:58 -04:00
JohnAFernandez 9a682ea32f Fix ai update danger weapon and Add guardrails for other checks (#3387)
* Make sure incoming index is valid.

* Some Extra Guardrails

* One more guardrail

* Fix Typos

Nonsense not nonesense
2021-05-24 21:30:41 +00:00
Goober5000 a5f501b58a Merge pull request #3350 from Baezon/fog-setup-fixes
Some fixes to nebula fog set up
2021-05-24 16:07:11 -04:00
Asteroth 5f8cdb37bd 'const vel' is the important quality here, not 'laser' (#3442) 2021-05-22 22:48:56 -04:00
JohnAFernandez f998215b07 Fix AI targeting itself during EMP (#3431)
To keep the AI code from going crazy, we should keep the AI from targeting itself during/after EMP
2021-05-22 22:37:36 -04:00
Baezon 106b16d5eb initialize variables 2021-05-22 21:17:23 -04:00
Asteroth 61faa3fa9a improve numerical pecision (#3440) 2021-05-21 23:36:17 -04:00
Baezon 3a960db633 optimize trail drawing 2021-05-21 18:23:35 -04:00
Baezon b89d395578 unused variable 2021-05-21 17:23:38 -04:00
Baezon f33b42085e add support for ballistic beams 2021-05-21 14:57:23 -04:00
BMagnu 87f449415f Self-Shadow on 3D-Cockpits (#3437)
* Improve wookieejedi's cockpit shadows

* Rename stray bool

* Make shadow's eye pos explicit

* Tidy up stub declaration

* Add configurable shadows + requests by m!m

* make variable lowercase
2021-05-21 08:15:20 +00:00
wookieejedi a59bb99fc6 Merge pull request #3435 from wookieejedi/expose-shadow-values
Expose Shadow Cascade Distances
2021-05-18 22:20:47 -04:00
wookieejedi ca6cc21be8 incorporate feedback/extra checks 2021-05-18 09:04:56 -04:00
the-maddin b52ab8bd4e gcc11: add missing include (#3434) 2021-05-18 01:27:31 -04:00
Asteroth a5a2f9e3df add extra check for nullptr (#3433) 2021-05-18 01:11:59 -04:00
wookieejedi 40840ee3f9 specify as float tuple 2021-05-17 17:56:48 -04:00
wookieejedi 76af0129f3 Expose Shadow Cascade Distances
The shadows distances were tuned/added by swifty with the following logic:
`// these cascade distances are a result of some arbitrary tuning to give a good balance of quality and banding.`

Mods, especially TCs, may have very different sized ships compared to FS, and as such desire more precise control over shadow cascade distances.

This PR exposes those values with settings in the `game_settings.tbl`.

PR is tested and works as expected.
2021-05-17 17:17:55 -04:00
Goober5000 f91d3dbe17 Merge pull request #3421 from Goober5000/fix_add_data_for_variables
fix add-data for variable names
2021-05-17 11:53:02 -04:00
Goober5000 5ad373502c Merge pull request #3428 from z64555/fix/issue_3427
Fix/issue 3427
2021-05-16 23:22:17 -04:00
Goober5000 37c9ecd0e3 fix add-data for variable names
This properly handles variable additions by calling the replace-variable code on the new variable node immediately after the variable is added.  It's a bolted-on hack but it's the simplest way to fix the issue.  A better fix would be to completely redesign the way the sexp tree handles variables (and everything, really) but that would be a major undertaking.

Fixes #3298.
2021-05-16 23:15:19 -04:00
Tyler Blount b92cbaff64 Merge pull request #3432 from the-maddin/qtfred-win-fixes
Qtfred win fixes
2021-05-16 18:12:31 -06:00
the-maddin ed69a1584b qtfred/win32: Later SCP_mspdbcs_Cleanup (fix crash on shutdown) 2021-05-16 18:25:57 +02:00
the-maddin 789243ea06 qtfred: Replace '/' with platform specific
separator
2021-05-16 18:25:57 +02:00
Fabian Woltermann 2701b557b8 Merge pull request #3426 from The-E/feature/disable_reflect_maps_in_lab
Add an option to switch off reflect maps in the lab
2021-05-14 11:35:11 +02:00
z64555 b4fe5c9cbe * Use temp vars for readibility.
* when using gr_printf_menu, Use format string and va_list instead of the buffer string directly
2021-05-13 16:55:02 -05:00
z64555 f1ee621624 Use menu resolution instead of screen width for positioning the "Conflict!" message. 2021-05-13 13:24:21 -05:00
z64555 bcf87e8a02 When overriding a key, the key should first load in the default binding so that legacy ccfg.tbl's can toggle a modifier (shift or alt) without corrupting the bind. 2021-05-13 13:10:04 -05:00
Fabian Woltermann 3d6fe919da Add a flag to the Lab's render settings to allow Reflect maps to be toggled on or off 2021-05-13 16:02:49 +02:00
Goober5000 2e272cce2d Merge pull request #3360 from EatThePath/stricmp-begone
Remove string comparisons and switch to vector in script conditions
2021-05-10 19:58:20 -04:00
Asteroth 309bfd7825 better beam index warning (#3376) 2021-05-10 18:17:15 -04:00
Goober5000 308794801c Merge pull request #3423 from Goober5000/xstr_id_buf_bump
bump the buffer holding the XSTR id
2021-05-08 17:42:00 -04:00
the-maddin 0b26662755 Qtfred runtime fixes (#3418)
* qtfred: fix crash on shutdown

run shutdown code sooner (lastWindowClosed) to
avoid deallocating invalid glsync

* qtfred: Fix blurry sky background and startup
warning

Only render when window surface is exposed, ensure
first correct frame is rendered asap.

* fix msvc warning

initialize variable

* Clarify comment
2021-05-08 21:31:08 +00:00
Goober5000 8fe55fa659 bump the buffer holding the XSTR id
Turns out some mods really do use XSTR ids higher than 9999.  This bumps the capacity from 4 digits to 7 digits.

Fixes #3422.
2021-05-08 16:35:56 -04:00
Goober5000 9f1e556031 Merge pull request #3420 from Goober5000/fix_3419
remove unneeded warning
2021-05-08 02:13:32 -04:00
Goober5000 d77554767d remove unneeded warning
As pointed out in #3419, subsystems can in fact have 0% maximum hull.

Fixes #3419.
2021-05-07 22:35:13 -04:00
Goober5000 52e2cda4a0 Merge pull request #3416 from Goober5000/fix_3413
use the proper range check
2021-05-05 22:31:36 -04:00
Goober5000 3a888906c5 use the proper range check
The ship index was being checked against the weapon limit.

Fixes #3413.
2021-05-05 21:34:42 -04:00
MageKing17 638a25ea0d Merge pull request #3415 from Goober5000/update_version
bump version to 21.3.x
2021-05-05 17:16:58 -07:00
Goober5000 6d60647a2a bump version to 21.3.x 2021-05-05 19:35:26 -04:00
Goober5000 cd2e69eb3b Merge pull request #3411 from the-maddin/qt-checked-list
QtFred: Model for ListView of checkboxes
2021-05-05 17:37:03 -04:00
Goober5000 e92ba1849b Merge pull request #3410 from the-maddin/qtfred-fix-warnings-05-21
Fix some qtfred warnings
2021-05-05 17:33:52 -04:00
Taylor Richards ce9a0d5e08 add new popup type to handle mission/table validation (#3380)
* add new popup type to handle mission/table validation

* fix error handling when popup gets canceled

* use bool and get rid of Int3()

* use proper Game_mode check to test for standalone
2021-05-05 00:53:57 -04:00
Asteroth d971f34ee2 make all asinf and acosf safe (#3384) 2021-05-05 00:53:24 -04:00
JohnAFernandezandAsteroth 47f6d2b368 Add guardrails to object cleanup during object creation (#3371)
* Prevent Crashes from Weapons being deleted during the collision process

This puts in some safety checks to keep FSO from crashing while doing collision detection when close to the object limit.

* Remove Problematic Assertions and INT3's

Keeps FSO from crashing when low on Object slots from failed weapon and beam creations.

* Simplify Code with a good suggestion

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

Co-authored-by: Asteroth <[email protected]>
2021-05-05 00:52:11 -04:00
Joshua Glatt 144d484c85 Replace rand() calls with a Random class (#3332) 2021-05-04 18:26:06 -07:00
the-maddin 3c809a9bb5 Fix qtfred runtime warning
Initialize QApplication before call to
QCoreApplication::applicationDirPath as requested
in warning
2021-05-04 17:05:00 +02:00
the-maddin 1c1ee910fb Create model for ListView of Checkboxes
which contain additional undisplayed data. For
example the initialShips/initialWeapons lists,
which refer to the internal indices of player
ships/weapons.
2021-05-04 15:19:10 +02:00
the-maddin 6f2e707f5a Fix qtfred deprecations 2021-05-04 12:49:28 +02:00
the-maddin 3a427d923b Fix deprecation warning
(cherry picked from commit ffa0ac90b8769ba3ac6575fdc2aaad34b195e85e)
2021-05-04 12:48:53 +02:00
Goober5000 a663a7d916 Merge pull request #3408 from Goober5000/for_sexps_known_fix
tweak short-circuiting on the for-* sexps
2021-05-03 11:41:05 -04:00
Goober5000 42d96d967e Merge pull request #3397 from Goober5000/handle_weapon_none
handle weapon "None" properly
2021-05-03 11:40:54 -04:00
Goober5000 a3c5186635 add missing newlines in several mprintf statements (#3409)
Fixes #3407, and I used a regex search to find what I hope are all other examples.
2021-05-02 23:53:40 -04:00
Joshua Glatt cf7fa02e6d Fix variable replacement in text in briefings and debriefings (#3385)
* fix variable replacement in briefings/debriefings
* remove unused local variables
* multi server-side cleanup
* add client-side text replacement in multi
2021-05-02 20:46:56 -07:00
Goober5000 72aa1eebc9 tweak short-circuiting on the for-* sexps
If the `for-players` collection has no valid arguments, don't short-circuit, just to be on the safe side.

Don't short-circuit at all for the `for-ship-*` sexps, because ships can arrive and depart.
2021-04-29 23:52:21 -04:00
Goober5000 28f60df7fa Merge pull request #3406 from MageKing17/bugfix/avoid-negative-lookup-in-loadout
Avoid negative lookup when parsing loadouts.
2021-04-25 19:00:44 -04:00
MageKing17 bed18012d6 Avoid negative lookup when parsing loadouts.
#3271 changed the logic of `stuff_token_list()` in such a way that the supplied index being used to access an array was no longer skipped if it was invalid; naturally, this means that this warning was now being inevitably followed up by an out-of-bounds array access. Adding a `!skip_this_entry` check should hopefully fix the problem while still allowing the loadout count parsing code below it to run, which was presumably the reason the `continue` statement was replaced with the `skip_this_entry` variable in the first place. Fixes #3405.
2021-04-25 11:10:55 -07:00
Goober5000 d43f30053d Merge pull request #3404 from scp-fs2open/revert-3400-apng_fix
Revert "Fix APNG Animation Framecounter"
2021-04-24 22:43:40 -04:00
MageKing17 76dccbe07d Revert "Fix APNG Animation Framecounter" 2021-04-24 18:53:52 -07:00
Goober5000 3eafcde138 Merge pull request #3403 from MageKing17/bugfix/avoid-shiphit-negative-array-access
Avoid out-of-bounds array access if killed by a parentless weapon.
2021-04-24 21:13:38 -04:00
Goober5000 ca7065df46 Merge pull request #3400 from BMagnu/apng_fix
Fix APNG Animation Framecounter
2021-04-24 18:39:39 -04:00
Goober5000 cedf66cb31 Merge pull request #3402 from Baezon/fix-edge-checks
Fix fov_edge_checks
2021-04-24 18:39:32 -04:00
Baezon 03a3fbdc1c fix fov edge checks 2021-04-24 17:10:20 -04:00
MageKing17 9c6661e0e8 Avoid out-of-bounds array access if killed by a parentless weapon.
While there's code to avoid accessing the parent object of a parentless beam, there's no equivalent code to avoid accessing the parent object of a parentless weapon. This fixes this inconsistency.
2021-04-24 13:11:35 -07:00
Birk Magnussen 6bea921fbe Add short explanation 2021-04-24 23:04:00 +09:00
Birk Magnussen 79f5eda0d6 Fix APNG Animation Framecounter 2021-04-24 16:00:09 +09:00
Baezon 4e4c8449fd Merge remote-tracking branch 'upstream/master' into poof-overhaul 2021-04-22 00:06:03 -04:00
Baezon 7980891b48 overhaul poof handling 2021-04-22 00:05:22 -04:00
Goober5000 3aa61dfccb Merge pull request #3396 from Goober5000/is_visible_tweak
make is-ship-visible default to the first player
2021-04-20 00:00:31 -04:00
Goober5000 a6a7482467 handle weapon "None" properly
If the secondary weapon selection is None, the ammo count will be based on an incorrect weapon.  So guard against that.

Fixes #3393.
2021-04-19 23:38:08 -04:00
Tyler Blount 0febfb3545 Merge pull request #3394 from JohnAFernandez/Fix-that-annoying-fred-freezes-when-open-too-long-bug
Keep Fred from freezing
2021-04-19 21:18:48 -06:00
Goober5000 e1c8f5d2ed make is-ship-visible default to the first player
To be more user-friendly, and to accommodate buggy retail missions, make the one-argument version of `is-ship-visible` default to the first player in multiplayer mode..  Also, change the warning to an mprintf.
2021-04-19 23:04:27 -04:00
Goober5000 6ce2a445fe retail -> builtin 2021-04-19 22:28:29 -04:00
Goober5000 96ae629ec6 qtfred 2021-04-19 22:28:29 -04:00
Goober5000 1b9577eb85 add OPF_CUSTOM_HUD_GAUGE and apply it to relevant sexps 2021-04-19 22:28:29 -04:00
Goober5000 beeb18b46c Merge the argument list for OPF_HUD_GAUGE and OPF_HUD_GAUGE_NAME. Call it OPF_RETAIL_HUD_GAUGE. 2021-04-19 22:28:29 -04:00
JohnAFernandez 44343f8d1e Put a bandaid on Fred freezing
Could be because of variable overflows or from `thistime` somehow being much smaller than `lasttime`.

Hard to find the root cause, but manually setting the memory to bad values will no longer cause the freezing with this patch.
2021-04-19 22:00:46 -04:00
Taylor Richards 424c69d1e5 Merge pull request #3379 from notimaginative/fix_chat_error_handling
address issues with error handling in chat_api
2021-04-18 19:46:39 -04:00
JohnAFernandez 6d1354f1f6 Explicitly check that the type is a ship. (#3389)
Not all ships in the ships array are ships (if they were turned into observers), so we need to explicitly check that they are ships.
2021-04-18 05:11:30 +00:00
Tyler Blount d5c4f3e5c7 Merge pull request #3348 from TRBlount/fix/display_name_regression
Strip hashes from explicitly defined display names in tables.
2021-04-17 23:03:54 -06:00
JohnAFernandez 89bd64f4ab Make sure the Netgame state is set to prevent a crash (#3339)
If the client tries to respawn a player when the server is trying to end the game it will lead to a crash on the client side.  This sets the client's game to the correct state when an end game packet is received and adds extra checks before respawning.
2021-04-17 23:49:54 -04:00
Tyler Blount 417739665c Strip hashes from explicitly defined ship and weapon display names 2021-04-17 17:07:41 -06:00
Taylor Richards 11f2920b4f add variant of game update packet to tell PXO we want firewall status 2021-04-17 17:47:15 -04:00
Taylor Richards 9e4ab292ac fix game announcement issue causing first firewall check to fail 2021-04-16 18:35:46 -04:00
Taylor Richards 51addab005 add notification for PXO firewall test 2021-04-16 18:34:48 -04:00
MageKing17 e236a79773 Make an invalid variable name throw an error. (#3373)
There were a few assertions in the SEXP code that would trip if an invalid variable name were specified in a SEXP, but nothing that actually stopped a Release build from performing an out-of-bounds array access if someone made a typo in notepad. Since, as far as I could tell, everything should go through `get_sexp_text_for_variable()` first, I changed its `Assert()` into an `Error()` that should hopefully ensure that we avoid ever doing anything with `Sexp_variables[-1]`.
2021-04-14 21:26:11 -04:00
JohnAFernandez d523f0aef3 Make Sure Special Shield Hitpoint Max Gets Transferred (#3383)
Since the shield strength of the ships is being copied, you need to copy the special shield hitpoints, too, just like for hull.
2021-04-14 21:07:31 -04:00
Taylor Richards 697c009fb3 address issues with error handling in chat_api:
- detect server connection error messages before blindly
   moving to user login (crash fix)
 - detect read errors and fail accordingly (crash fix)
 - allow server disconnect to run even if we aren't connected (cleanup & reset)
2021-04-12 12:59:04 -04:00
JohnAFernandez 1f918fd4c6 Allow Fred to Edit and Allow Command briefs in FRED (#3372)
* Allow Fred to Edit and Allow Command briefs in FRED

They are currently allowed in the game, but not being allowed in Fred was an oversight of mine.

* Allow Command brief saving in qtFRED
2021-04-11 13:50:25 -04:00
Asteroth 3ea7a6d1ba Merge pull request #3369 from Baezon/cull-generic-debris
Properly cull generic debris
2021-04-10 21:44:56 -04:00
David Gibson 743989525b Implemented index caching for hooks refering to ship or weapon info objects. 2021-04-10 20:41:22 -05:00
David Gibson 5bca1417c2 Vectorized the hook condition lists and began chaching information inside the hook at creation to avoid string comparisons in play. CHC_VERSION, CHC_STATE, and CHC_APPLICATION converted. 2021-04-10 20:18:29 -05:00
Baezon 633cd88e83 modernize use nullptr 2021-04-10 19:38:18 -04:00
Baezon 7431aba995 properly cull generic debris 2021-04-09 21:35:26 -04:00
JohnAFernandez 328bebe83a Fix event parsing by setting flags to zero before loading. (#3363) 2021-04-07 23:41:14 -04:00
Goober5000 94e4f3d4cd Merge pull request #3362 from Baezon/no-ship-subsys-lookup
Remove unecessary ship_get_subsys in model_rotate_gun
2021-04-06 10:48:09 -04:00
Baezon b57573c439 remove unecessary ship-get-subsys 2021-04-06 02:24:05 -04:00
Goober5000 0b1d1eed56 Merge pull request #3357 from notimaginative/fix_briefing_music_reset
Only close common_select when we should
2021-04-05 23:52:35 -04:00
Goober5000 123feba557 Merge pull request #3353 from Goober5000/escape_exclamation
make double-character consolidation reusable, and reuse it
2021-04-05 23:50:39 -04:00
Taylor Richards 8c64d73a18 Merge pull request #3358 from notimaginative/fix_main_hall_sounds_in_multi
fix main hall sounds/music not getting stopped on multi clients
2021-04-04 08:19:43 -04:00
Taylor Richards e156f15561 fix main hall sounds/music not getting stopped on multi clients 2021-04-03 11:08:28 -04:00
Taylor Richards 3e1d89ba53 only close common_select when we should 2021-04-03 10:22:11 -04:00
Asteroth 4f7bad2a5c Merge pull request #3347 from Baezon/fireball-lod-fix
Make fireballs default to 1 LOD
2021-04-02 16:01:39 -04:00
Goober5000 dd621e8904 Merge pull request #3351 from PhantomHoover/feature/profile-script-hooks
Add profiling trace for scripting hooks
2021-04-02 15:07:17 -04:00
Goober5000 396d2c55a9 make double-character consolidation reusable, and reuse it
This moves the ## to # escape sequence logic from `mission_process_alt_types` to its own function where it can be used elsewhere (such as for ship class and weapon class display names that need to do the same thing).  Also, this introduces a !! escape sequence for exclamation points that is needed for exclamation points to be used in scripts, as @naomimyselfandi pointed out.
2021-04-02 00:16:19 -04:00
Goober5000 8f5064b353 actually use GS_STATE_INVALID
Make `gameseq_get_state` return GS_STATE_INVALID if the stack is invalid.

With this change, the check for stack validity can be removed in `gr_flip`.
2021-04-02 00:11:45 -04:00
Phantom Hoover 782f6f100d Add profiling trace for scripting hooks 2021-04-01 11:54:09 +01:00
Baezon 6ec1f45997 neb fog set up fixes 2021-04-01 02:17:49 -04:00
Baezon 4f76c441d6 default to 1 lod 2021-03-31 18:00:00 -04:00
Asteroth a2bd895b7b Merge pull request #3344 from Baezon/fix-huge-targeting-regression
Fix regression with huge/small only targeting
2021-03-31 16:47:17 -04:00
JohnAFernandez a4cf53694d Merge pull request #3346 from JohnAFernandez/Fix-3007
Add a safety check to the $On Frame: Hook
2021-03-31 16:46:11 -04:00
JohnAFernandez 6bd7a43e3d Add a safety check to the $On Frame: Hook
So #3007 is a larger bug than just trying to access the player's target.  The real problem is that the game state is not changed from `GS_STATE_GAME_PLAY` during the mission load when restarting the mission.  So the script thinks it's in the mission, tries to access the target and then crashes.  But this won't be the only bug.  Any script that tries to access data on Frame will run into possible problems on mission restart.
2021-03-31 15:25:38 -04:00
Baezon fffc0ebf8b fix name of class #3344 2021-03-30 22:03:25 -04:00
Goober5000 f2426de80b Merge pull request #3340 from Goober5000/num_valid_arguments_fix
make num-valid-arguments work for the for-* sexps
2021-03-30 19:32:26 -04:00
Goober5000 27f6088117 make num-valid-arguments work for the for-* sexps
This adds a hook into the for-* handlers to return the number of valid arguments.  Fixes a bug reported on Discord.
2021-03-30 18:51:24 -04:00
Goober5000 30c76f36ce Merge pull request #3342 from Goober5000/message_list_saving
modify saving of edited messages
2021-03-30 18:42:39 -04:00
Goober5000 35094851f2 modify saving of edited messages
Instead of saving based on the m_cur_msg index, which may have been reset to -1, save on the most recent positive index.  This should keep track of modified text and dropdowns even when m_cur_msg is set to -1 when the message list loses focus.

Fixes #3308.
2021-03-30 17:32:02 -04:00
Fabian Woltermann b562cf822e Merge pull request #3345 from Baezon/fix-strafing-bug
My kingdom for a semicolon!
2021-03-30 09:15:42 +02:00
Baezon 62942557d5 typo 2021-03-30 00:19:53 -04:00
Baezon 4d68bed436 fix huge targeting regression 2021-03-29 22:42:50 -04:00
Asteroth 19d5b8e68e Merge pull request #3329 from PhantomHoover/feature/split-profile-columns
Split frame profile trace into two onscreen columns if needed
2021-03-29 15:34:55 -04:00
Goober5000 9dc50706a7 Merge pull request #3309 from Baezon/turret-alt-math-fix
Update Turret_alt_math for moving subsystems
2021-03-28 18:06:05 -04:00
Goober5000 f2a0e35959 Merge pull request #3333 from Goober5000/no_xstr_entry_suppress
log missing XSTR strings only once
2021-03-28 15:17:24 -04:00
JohnAFernandez e637eea2fb Merge pull request #3337 from JohnAFernandez/Interpolation-Bug
Fix a rare but eventual crash in the interpolation code.
2021-03-28 10:00:47 -04:00
Fabian Woltermann f3e3769056 Merge pull request #3266 from The-E/fix/3250_dynamic_nebula_detail
Make nebula poof detail settings partially dynamic
2021-03-28 13:18:26 +02:00
JohnAFernandez e218f687a9 Fix a rare but eventual crash in the interpolation code.
I don't know when this was introduced but the bug is extremely obvious once someone hit the crash.  It should just be using the timestamp that the packet was received, not trying to put that timestamp into a vector whose index is server frame numbers.
2021-03-28 05:07:27 -04:00
Baezon 5e10fccdbf Merge remote-tracking branch 'upstream/master' into turret-alt-math-fix 2021-03-27 21:12:30 -04:00
Goober5000 12672d0c2b Merge pull request #3310 from Baezon/fix-fov-edge-checks
Fix Fov_edge_checks
2021-03-27 17:22:37 -04:00
Goober5000 de7081fbb3 Merge pull request #3335 from Goober5000/missing_hud_gauge_warning
change reticle log statements to warnings
2021-03-27 15:19:47 -04:00
Goober5000 d73e4d4dec change reticle log statements to warnings
Most guages in hud_guages.tbl will display a Warning if they can't be loaded, but the reticle is an exception - it only prints a log statement.  This PR changes it to be consistent with the rest of the HUD gauges.

Fixes #3090.
2021-03-27 14:19:59 -04:00
Fabian Woltermann aeefcb4657 Remove an unused constant 2021-03-27 16:23:35 +01:00
Fabian Woltermann 023dcfca76 Use the screen size as the break value, remove it from the Neb detail settings 2021-03-27 16:22:20 +01:00
Fabian Woltermann c6e9f954f0 Use the screen size as the break_* value 2021-03-27 16:11:26 +01:00
Fabian Woltermann 961d5eb171 Use bitmap height * 2 to make sure only completely off-screen poofs are culled 2021-03-27 16:11:26 +01:00
Fabian Woltermann 1a66c97c2e After loading the nebula poofs, resize the break_x and break_y values so they are equal to the largest poof bitmap in use.
Also reduce the break alpha value by 90% for all detail levels.
2021-03-27 16:11:26 +01:00
Goober5000 00e2c2ad52 log missing XSTR strings only once
The "No XSTR entry in strings.tbl for index %d" message was previously printed to the log every time the string was accessed, which for commonly-used strings will clutter up the log.  This makes the message only appear once per missing index.
2021-03-26 23:22:06 -04:00
JohnAFernandez 8991fc67cd Merge pull request #3331 from JohnAFernandez/Fix-Multi-Gamestate-Bug
Check for these states
2021-03-26 20:47:40 -04:00
JohnAFernandez 7641abf41c Check for these states
Because GS_STATE_MULTI_MISSION_SYNC is actually shared for a few different multi screens.
2021-03-26 20:18:39 -04:00
Phantom Hoover 871f7a822e Split frame profile trace into two onscreen columns if needed 2021-03-26 20:33:01 +00:00
m!m ca66664eac Merge pull request #3327 from Shivansps/over_alloc_fix
fix over alloc to store lz4 offsets
2021-03-26 18:33:21 +01:00
m!m 4c1b3551b4 Merge pull request #3328 from ngld/fix/keep_stdout
Add FSO_KEEP_STDOUT env var to skip the AttachConsole() call
2021-03-26 18:32:34 +01:00
Asteroth 07d47cb984 Merge pull request #3319 from Baezon/add-fog-color
Allow for setting of nebula fog color explicitly
2021-03-25 21:20:55 -04:00
Allen A. Babb ce9ee8c264 Merge pull request #3324 from z64555/fix/issue_3322
Fixes #3322
2021-03-25 18:43:15 -05:00
ngld 8039650248 Add FSO_KEEP_STDOUT env var to skip the AttachConsole() call
Fixes #3317
2021-03-26 00:03:51 +01:00
Shivansps cd2b578a1b fix over alloc to store offsets 2021-03-25 19:57:48 -03:00
Shivansps 052879b3e4 POF 2118 and SLC2 support 2021-03-25 19:13:12 -03:00
z64555 85ec8251e3 When in bind mode, identify mouse as CID_JOY0 instead of CID_MOUSE. Fixes #3322. 2021-03-25 09:41:37 -05:00
JohnAFernandez 7e51a13c3a Merge pull request #3296 from Shivansps/compressed-files
LZ4 Compressed files Support
2021-03-25 07:08:06 -04:00
Baezon 538b2c6c95 handle lab and use empty string #3319 2021-03-24 13:25:16 -04:00
wookieejedi d3a70e8ed6 Merge pull request #3320 from wookieejedi/disable-spew-whole-ship
Add `no impact debris` for whole ship
2021-03-24 00:56:09 -04:00
Baezon 9dc68849d6 unused variable 2021-03-23 23:59:05 -04:00
wookieejedi b6bab87601 restore original comment 2021-03-23 23:44:03 -04:00
wookieejedi b8d868f828 restore comment 2021-03-23 23:43:31 -04:00
wookieejedi 01e6a57aaa remove un-needed section 2021-03-23 23:41:57 -04:00
wookieejedi e0fe9227aa clarify whitespace 2021-03-23 23:21:40 -04:00
Baezon 803751959a rename variable for no shadowing 2021-03-23 23:20:11 -04:00
wookieejedi 9597b5962e clarify ship override for subsystems debris 2021-03-23 23:16:59 -04:00
wookieejedi 792f74b33e Add no impact debris flag for entire ship model
Previously `no impact debris` flag was only an option for use on subsystems. This PR adds that flag for the entire ship. It also turns off the impact spew of debris for all subsystems if enabled on the ship.
2021-03-23 23:04:08 -04:00
Baezon 5181e71dab Add explicit fog color 2021-03-23 22:57:54 -04:00
JohnAFernandez 3d0e0f80ae One more hiccup 2021-03-23 20:31:04 -04:00
JohnAFernandez 251125913a How many mistakes is it now? No idea. 2021-03-23 20:31:04 -04:00
JohnAFernandez 89d2d6ed46 Fix missile indicators not going away
Add the should be dead flag, in order to properly make the missiles go away, and not just detonate.
2021-03-23 20:31:04 -04:00
JohnAFernandez 06f198afc1 Forgot one 2021-03-23 20:31:04 -04:00
JohnAFernandez 19a289539a More Whitepsace and Dealing with Crazy old CI 2021-03-23 20:31:04 -04:00
JohnAFernandez c14653b391 Whitespace Adjustments 2021-03-23 20:31:04 -04:00
JohnAFernandez 2527bf31c7 Upgrade velocity compression in OO packet
Previously, the velocity could be off by up to 1 m/s.  This gives that packing function one more byte to work with, so that we have a lot more accuracy to work with.
2021-03-23 20:31:04 -04:00
JohnAFernandez 184107283a Properly Set net_signatures for wing ships
Previously wing ships were being given a net signature that was one too large.
2021-03-23 20:31:04 -04:00
JohnAFernandez 42c19cdfee Fix Missile Syncing Between Server and Client 2021-03-23 20:31:04 -04:00
JohnAFernandez 3830534978 Fix implementation of multi_pack_unpack_desired_vel_and_desired_rotvel 2021-03-23 20:31:04 -04:00
JohnAFernandez 48eef6566d Multi Version bump for 21_2
since many of the fixes and features require a multi bump.
2021-03-23 20:31:04 -04:00
the-maddin b253442545 Add -pilot cmdline flag (#3316)
* Cmdline parsing for `-pilot "<name>"`

Add cmdline parameter `-pilot` with required
argument name and export name as global var
`Cmdline_pilot`.

* Expose to scripting `isAutoselect`

Setting `-pilot` flag sets `ui.isAutoselect()` true
(as does `-benchmark_mode`).

* Skip pilot selection

and call `player_finish_select` with the given
player instead.

* More useful error message on pilot load error

Also display callsign

* Add pilot name as scripting variable

* Don't expose pilot flag to launchers

* make stored flag param `const`
2021-03-22 21:14:57 +00:00
Baezon 26314c9b97 Merge remote-tracking branch 'upstream/master' into poof-overhaul 2021-03-22 00:37:17 -04:00
Baezon 5ebb12e47c overhaul poof system 2021-03-22 00:35:31 -04:00
JohnAFernandez 1d5e9794d6 Merge pull request #3263 from BMagnu/fix_unicode_stringstbl
Fix strings.tbl in unicode mode
2021-03-21 17:41:55 -04:00
Asteroth b7a9f545fd Merge pull request #3304 from BMagnu/weapon_penetrate_flag
Add pierce ship weapon flag
2021-03-21 15:12:45 -04:00
JohnAFernandez 9541e244d1 Make sure objects and ships get cleared if leaving mission sync (#3314)
This properly clears ships if you are leaving the sync state for any other state besides the gameplay state.
2021-03-21 14:54:32 -04:00
Asteroth f12d202afe Merge pull request #3278 from Baezon/exponential-fog
Switch to exponential fog and other nebula visibility improvements
2021-03-20 16:45:24 -04:00
Goober5000 507a5f1de8 Merge pull request #3312 from Goober5000/per_mission_chase_view
add mission flag for starting missions in chase view
2021-03-20 15:36:11 -04:00
Baezon 3810b039f5 Merge remote-tracking branch 'upstream/master' into exponential-fog 2021-03-20 10:39:41 -04:00
Baezon 827754d6de minor fixes 2021-03-20 02:31:47 -04:00
Goober5000 d455e17e34 add mission flag for starting missions in chase view
Follow-up to #3305.  Some mods may want one or two missions to start in chase view without having every single mission default to chase view.  So this adds a mission flag (with FRED and qtFRED support) that will enable this on a per-mission basis.
2021-03-20 00:21:27 -04:00
Baezon 7a7999ca56 Merge remote-tracking branch 'upstream/master' into poof-overhaul 2021-03-19 20:43:17 -04:00
Shivansps db360820a9 fix build check 2021-03-19 20:51:09 -03:00
Baezon 804a222041 unused variable 2021-03-19 19:44:11 -04:00
Shivansps 6dab1e464f Merge branch 'compressed-files' of https://github.com/Shivansps/fs2open.github.com into compressed-files 2021-03-19 20:21:02 -03:00
Shivansps 86c45309e8 requested changes and simplified if on random access function 2021-03-19 20:20:58 -03:00
Birk Magnussen 4f4690a482 Fix Names and spawn on destruct 2021-03-20 03:52:54 +09:00
Baezon 1ca60e1d2f fix fov_edge_checks 2021-03-19 11:48:15 -04:00
JohnAFernandez 420c7ec171 Play directive completion sounds for clients (#2900)
* Allow Text to show failure on Clients

Function was accidentally returning false before sending an update on failure.

* Play directive sounds for clients

This adds a short client version of the function that initiates the directive completion sound.

* forgot to remove a failed experiment
2021-03-19 05:39:05 -04:00
Birk Magnussen 011f7e4d6c Change flag to Table entry 2021-03-19 18:30:39 +09:00
Asteroth 8b94e58596 Merge pull request #3284 from Baezon/fix-rand-circle-sphere-bias
Fix probability distribution of vm_vec_random_in_circle/sphere
2021-03-19 02:23:31 -04:00
Asteroth b304ccbe96 Merge pull request #3305 from Strygon/chaseviewtest
Adding "Start missions in Chase View by default" flag in game_settings.tbl
2021-03-19 02:23:08 -04:00
Baezon eb538ffba8 update turret_alt_math for moving subsystems 2021-03-19 02:13:20 -04:00
JohnAFernandez 5bb934119c Limit instances of Client Collisions to Avoid Instant Death (#3164)
* Limit instances of Client Collisions to Avoid Instant Death

* Set timestamps correctly (take 2)

* Handle server check the same everywhere

* Clearer Logic Here
2021-03-18 17:24:08 -04:00
Fabian Woltermann 8c7a8e42b2 Merge pull request #3307 from The-E/fix/3206_submodel_property_parsing
Fix for #3306
2021-03-18 17:29:10 +01:00
Fabian Woltermann 9a06e0727c Make sure we check for any carriage return characters that may sneak in too 2021-03-18 16:52:15 +01:00
Strygon 08603009fb removed the redundancy 2021-03-17 20:40:02 +01:00
JohnAFernandez 609ed4ed94 Remove the fireball limit (#3224)
* Remove the fireball limit

* Handle Feedback

(Without the main PC, so really hoping I don't do any typos)
2021-03-17 14:21:06 -04:00
Strygon 3ab9f85a7a ditto 2021-03-17 17:50:19 +01:00
Strygon 45db675c35 Renaming the bool 2021-03-17 17:49:43 +01:00
Strygon 5b01a68352 Adding a few forgotten parts of the ChaseViewDefault code 2021-03-17 17:39:27 +01:00
Strygon 67cc6a66eb Adding ChaseView Flag functionality
This is where the game would put the player into chaseview/third person if the flag for it is set in game_settings.tbl
2021-03-17 17:38:32 +01:00
Strygon 842c84da7d Adding the actual flag for default chase view 2021-03-17 17:36:25 +01:00
Strygon 6598c25fda Adding support for Chase View flag 2021-03-17 17:35:39 +01:00
Birk Magnussen 2a73fb340f Add pierce ship weapon flag 2021-03-17 17:39:04 +09:00
Baezon edee63491d Merge remote-tracking branch 'upstream/master' into poof-overhaul 2021-03-17 00:46:38 -04:00
Goober5000 d716433848 Merge pull request #3300 from Baezon/fix-flak-substitute-assert
Fix assert with combining flak and non-flak using substitute
2021-03-17 00:34:14 -04:00
Baezon 5bd351d42a initial poof overhaul 2021-03-16 11:33:34 -04:00
Shivansps ad60240eb6 Updated comment header. Feature Complete. 2021-03-16 10:11:48 -03:00
Baezon 29b03cd49f implement beam substitution 2021-03-15 23:16:05 -04:00
Shivansps f8df97b489 fix seek_end on comp_fseek
This where causing the pcx issues
2021-03-15 23:59:39 -03:00
Asteroth 95235b353b Merge pull request #2885 from Baezon/expose-huge-small-targeting
Expose ability to be targeted by 'huge' and 'small only' weapons
2021-03-15 22:32:22 -04:00
Shivansps d5feddfb8a fixed comp_fseek return 2021-03-15 20:08:58 -03:00
Baezon ce1907c52a flak should use normal mflash methods 2021-03-15 18:30:47 -04:00
JohnAFernandez 895dbdddb8 Merge pull request #3295 from Goober5000/spacebar_popup
add text to context popup
2021-03-15 09:44:00 -04:00
Baezon f5e32fa1a2 Merge remote-tracking branch 'upstream/master' into exponential-fog 2021-03-15 02:27:22 -04:00
Shivansps 9fa3baa458 fix typo 2021-03-14 23:43:22 -03:00
Shivansps 4b3760dfb4 more build fixes 2021-03-14 21:17:07 -03:00
Shivansps 142d586a1c and even more build check fixes 2021-03-14 20:29:26 -03:00
Shivansps 95103dfcb8 more build check fixes 2021-03-14 19:57:04 -03:00
Shivansps f50ea26051 Change CI struct name to upper case 2021-03-14 19:36:20 -03:00
Shivansps 983dd0b6ca changes for build check errors 2021-03-14 19:21:13 -03:00
Shivansps 3bdc5e0c27 Merge branch 'master' into compressed-files 2021-03-14 17:57:53 -03:00
Baezon 643cb6a2be update scripting functions 2021-03-14 15:37:43 -04:00
MageKing17 2348d4db64 Merge pull request #3297 from MageKing17/bugfix/sexp-ammo-safety-regression
Fix ammo safety regressions.
2021-03-14 11:45:04 -07:00
MageKing17 77534926c8 Comment clarification. 2021-03-14 11:16:54 -07:00
Shivansps ba6a471054 comment debug statements 2021-03-14 14:55:20 -03:00
MageKing17 47c409a3d5 Fix ammo safety regressions.
When various SEXP functions related to ammo were consolidated back in June (in commit 54409ec928), certain safety catches meant to avoid having too much ammo or the wrong ammo capacity after changing weapons were lost. This commit adds code that should be functionally equivalent.
2021-03-14 10:43:06 -07:00
Shivansps ce44e3522b updated header 2021-03-14 14:35:04 -03:00
Goober5000 593fbdbf21 add text to context popup
The Space Bar is a valid shortcut, so indicate as such.  Fixes #3289.
2021-03-14 12:47:15 -04:00
Shivansps c1b87bc2b6 Add missing CAP to comp goal position.
It should not be needed but at least this stops crashing when you use a unsupported format in compression (like, audio and pcx)
2021-03-14 13:34:13 -03:00
Shivansps 1f164dbb64 Removed isCompressed from compression_info 2021-03-14 11:12:00 -03:00
Shivansps 1275cbfd83 Proper lz4 reference and added position checks
LZ4 moved to lib folder and added cmakelists.
Added several position check to match cfilearchive ones for compressed files.
Changed header check to int.
2021-03-14 10:47:11 -03:00
Goober5000 69be3c8f35 Merge pull request #3293 from Goober5000/hotkey_range_check
simple hotkey range check
2021-03-14 00:04:14 -05:00
Goober5000 85fc1f7cea simple hotkey range check
This prevents the message from firing if the wing index is -1 which would cause an array underflow.  Fixes #3280.
2021-03-13 23:15:16 -05:00
Goober5000 59a5a343c8 Merge pull request #3291 from Baezon/fix-contrail-a_decay_exponent
Peoperly initialize alpha decay exponent for contrails
2021-03-13 22:14:38 -05:00
Baezon a3ce01f250 properly initialize a_decay_exponent 2021-03-13 20:33:54 -05:00
Shivansps 20cccdbf20 Updated Implementation
Moved the compression functions to separated files, added dynamic blocksize support for LZ4 and a decoder buffer to make sure every block is only read from file and decoded only once.
2021-03-13 17:15:04 -03:00
Asteroth 4b64c43ef8 Merge pull request #3274 from Baezon/shooter-damaging-weapons
Add shooter damaging weapons
2021-03-13 15:03:52 -05:00
Asteroth 4307d12762 Merge pull request #3285 from Baezon/fix-fit-and-set-obj-facing
Bugfix for FIT with set-object-facing
2021-03-13 14:59:52 -05:00
Asteroth 0d3d336d65 Merge pull request #3287 from Baezon/fix-aburn-trail
Properly initialize trail alpha exponents for afterburner trails
2021-03-13 14:59:24 -05:00
Shivansps 077338086a Improved implementation
Model load and tech room now works, it crashes at mission load.
2021-03-12 19:58:49 -03:00
Birk Magnussen 0b2ee5f76b Modify other file reading method for new encoding conversion 2021-03-13 07:50:41 +09:00
Baezon 256a047fab fix rand circle and sphere probability distribution 2021-03-12 16:13:52 -05:00
Baezon 222799b1a1 initialize trail alpha exponents for aburn trails 2021-03-12 16:03:50 -05:00
Fabian Woltermann 649fe7e3ce Merge pull request #3286 from Baezon/fix-to-the-fixed-fog
Fix for nebula fogging distance
2021-03-12 10:54:50 +01:00
Baezon 2e5e25dc09 revert #2222 and fix comment 2021-03-11 23:28:23 -05:00
Shivansps 3f9218e671 1st attempt at implementation
I just dumped everything into cfilearchive to avoid a fight with the includes that i cant win for now.

It dosent work, DDS utils complains about DDS filecode.
2021-03-11 20:51:28 -03:00
Birk Magnussen 3003d0589d Change validation to own function 2021-03-12 06:34:27 +09:00
Birk Magnussen 4bd15d43da Fix Warning due to enum class 2021-03-12 06:04:10 +09:00
Birk Magnussen 8df62e99f5 Change Enum to Enum Class 2021-03-12 05:54:25 +09:00
Birk Magnussen d93c9c4220 Adapt parsing exceptions 2021-03-12 05:45:09 +09:00
Birk Magnussen 1b5fd3c5fd Move Conversion functions to util/unicode 2021-03-12 05:42:44 +09:00
Baezon 0612a72c2f fix FIT with set-object-facing 2021-03-11 15:41:55 -05:00
Baezon 22f7ff3443 fix bias from random_circle/sphere 2021-03-11 03:02:24 -05:00
Goober5000 5105f35a31 Merge pull request #3271 from Goober5000/better_parse_lists
rewrite stuffing of lists
2021-03-10 19:19:39 -05:00
Goober5000 f025572110 rewrite stuffing of lists
Consolidate all the functions which parse lists of data.  They're almost the same except for the data itself, so use templates.

As for the templated function which handles the list, boost the robustness by adding additional checking and error messages.
2021-03-10 18:50:12 -05:00
Goober5000 ed2cc47093 Merge pull request #3269 from Goober5000/annotation_fix
Various annotation fixes
2021-03-10 18:49:39 -05:00
Goober5000 4486b9ee10 Merge pull request #2923 from z64555/controls3
Controls3 - Primary/Secondary Bindings
2021-03-10 15:53:52 -05:00
Asteroth e8603e1617 Merge pull request #3247 from Baezon/better-subsys-attacking
Add improved subsystem attacking
2021-03-10 12:21:53 -05:00
Goober5000 f67860a502 Merge pull request #3283 from Goober5000/fix_isdigit_type
fix character type for isdigit
2021-03-10 11:37:54 -05:00
Goober5000 497a0e0805 fix character type for isdigit
Just like the `std::toupper` and `std::tolower` functions (see PR #3226), `std::isdigit` is designed to work with regular `char`, not `unsigned char`.
2021-03-10 10:51:56 -05:00
Goober5000 470a996b11 Merge pull request #3281 from Goober5000/beam_range_fxi
a few turret fixes
2021-03-09 23:09:59 -05:00
Goober5000 5bb9f427b4 a few turret fixes
This correctly calculates the turret position from the center (zero position) of its submodel instead of using the offset from the main model.

This patches a few more parts of the code and also adds a missing locale argument.
2021-03-09 22:39:13 -05:00
Goober5000 52df877ed9 Merge pull request #3276 from Goober5000/special_arg_fix
add small fix from SEXP containers PR
2021-03-09 21:43:28 -05:00
Shivansps 8292d8c44a Revert "Merge branch 'arm_fixes'"
This reverts commit 2ee128cd88, reversing
changes made to a2b349855e.
2021-03-09 20:44:43 -03:00
Asteroth 0eefd352d9 Merge pull request #3264 from Baezon/32-poofs
Increase max nebula poofs to 32
2021-03-08 14:44:26 -05:00
Baezon cf2e3e8641 lightning even with 0 poofs 2021-03-08 10:50:27 -05:00
Baezon 78c79ac88d debug clean up 2021-03-08 01:37:00 -05:00
Baezon 6e54ed3dfc more exponential fog 2021-03-08 00:09:42 -05:00
Baezon f60d2d8e30 comment changes 2021-03-07 23:06:30 -05:00
Goober5000 a12a33b189 Merge pull request #3277 from Goober5000/movable_turret_fov_fix
Turrets on movable submodels
2021-03-07 21:29:28 -05:00
Baezon cf3ce54038 comment clarity 2021-03-07 14:20:55 -05:00
Goober5000 483a632c7f Merge pull request #3243 from Baezon/decouple-asteroids-species
Decouple asteroids from species
2021-03-07 13:13:13 -05:00
Goober5000 9a3fc507d6 Merge pull request #3261 from BMagnu/lua_campaignswitch
Lua add campaign switch function
2021-03-07 13:10:01 -05:00
z64555 19c0f64736 Upgrade a few Assert()'s into Assertion()'s with error messages 2021-03-07 09:56:21 -06:00
z64555 78ac82d6eb Replace Int3()'s with UNREACHABLE
* control_config_bind_btn uses UNREACHABLE macro when an unknown order is passed to it
2021-03-07 09:20:34 -06:00
Baezon 2dd40bcbd8 typo 2021-03-07 02:00:58 -05:00
JohnAFernandez 5da44a9d72 Merge pull request #3178 from Baezon/generic-debris-enhancement
Generic debris expansion and configuration
2021-03-07 00:19:25 -05:00
Goober5000 d75b0f4b4b additional minor cleanup 2021-03-06 20:03:59 -05:00
z64555 5c9582aefc Fix bug where "Clear Conflict" button was disabled on Ship tab unless the conflicted items included an axis. 2021-03-06 12:52:48 -06:00
Goober5000 ab478c4a0e Merge pull request #3275 from Goober5000/uoffset_addendum
addendum to u_offset
2021-03-05 22:44:00 -05:00
Goober5000 01daf25fe9 addendum to u_offset
This improves PR #3257 by updating the frametime after the beam fires, not before, so that the first frame will always be at offset zero
2021-03-05 22:15:55 -05:00
Goober5000 db73c27a53 add small fix from SEXP containers PR
While skimming the differencs in jg18's branch of PR #3253...
https://github.com/jg18/fs2open.github.com/tree/feature/sexp-containers-revised

...I noticed a TODO that is almost certainly a genuine bugfix.  As such, it deserves its own PR.  The line in question was last modified in 2012 by karajorma, and the bugfix should test for the special-arg in the entire actions tree rather than just the first action.
2021-03-05 22:00:51 -05:00
Baezon 3c53b74e5e switch to exponential nebula fog 2021-03-04 23:02:24 -05:00
Birk Magnussen 829e0b8b7c remove bad type modifier 2021-03-04 22:17:16 +09:00
Birk Magnussen 4b60ca467c Refactor encoding functions 2021-03-04 22:08:50 +09:00
Baezon d972f353f1 better species name handling and XSTR 2021-03-03 22:05:12 -05:00
Baezon 9c1d1e64cc better self kill text 2021-03-03 20:22:50 -05:00
Goober5000 abc153e21e Merge pull request #3273 from NovachenFS2/TranslatedAsteroids
Translateable Asteroid Name in Asteroid Fields
2021-03-03 15:26:30 -05:00
Jenna Trassa 9385206e0e Feedback & lowercase debris code 2021-03-03 20:56:24 +01:00
Goober5000 3674f06400 Merge pull request #3272 from NovachenFS2/AsteroidTimer
Translateable Asteroid Impact Time
2021-03-03 14:36:14 -05:00
Goober5000 be780af04d Merge pull request #3268 from BMagnu/replace-texture-sexp
Add replace-texture SEXP
2021-03-03 14:33:21 -05:00
Goober5000 ec1d2e091e Merge pull request #3262 from Goober5000/enable_multi_for_two_sexps
allow two SEXPs to be used in multiplayer that previously couldn't be
2021-03-03 13:59:21 -05:00
Goober5000 106da3c95f allow two SEXPs to be used in multiplayer that previously couldn't be
1) The ship-vanish SEXP (and script function) was already multiplayer-ready
2) The is-ship-visible SEXP was enhanced to add a second argument, which defaults to the player's ship in single-player mode
2021-03-03 13:22:50 -05:00
Jenna Trassa 34649c7543 Translated Asteroid Name in Asteroid Fields 2021-03-03 17:25:37 +01:00
Baezon 0fcfe68164 add self-damaging weapons 2021-03-03 11:08:04 -05:00
Jenna Trassa 8b0e79703a A translateable Asteroid Impact Time 2021-03-03 14:55:29 +01:00
Baezon c3c4c21fc2 typo 2021-03-03 02:26:23 -05:00
Birk Magnussen 8471b8e444 Change Preload Error to Warning 2021-03-03 15:48:47 +09:00
Baezon 8a5483db0b retail name compatability 2021-03-03 01:08:15 -05:00
Baezon 708de001f3 Merge remote-tracking branch 'upstream/master' into decouple-asteroids-species 2021-03-02 19:55:00 -05:00
Birk Magnussen 6cdbb8159b Change SEXP Syntax, and allow Wings 2021-03-03 06:00:47 +09:00
Goober5000 03dbdf7f09 don't display unmodified annotations 2021-03-02 15:09:28 -05:00
m!m 1561a75b13 Merge pull request #3260 from BMagnu/simulatedspeedoverrides_tb
Add scripting API for accessing registered Simulated Speech Overrides
2021-03-02 17:51:49 +01:00
Goober5000 aff1ad40f3 better handling of unexpected characters that come after numbers 2021-03-02 11:31:16 -05:00
Birk Magnussen 19f48e3a10 Tidy up leftover code 2021-03-02 22:17:06 +09:00
Birk Magnussen 2c27707e00 Add replace-texture SEXP 2021-03-02 22:03:28 +09:00
BMagnuandm!m 9a854a7066 Add change to correct typecast
Co-authored-by: m!m <[email protected]>
2021-03-02 17:09:20 +09:00
Asteroth 897492e228 Merge pull request #3257 from BMagnu/beam_reset_offset
Add flag for beams to track uoffset individually
2021-03-02 03:08:02 -05:00
Asteroth 72d7b1bc9c Merge pull request #3259 from BMagnu/lssm_warpeffect
Added flag to select the warp effect type of LSSM's
2021-03-02 03:07:43 -05:00
Goober5000 14a8db0dda check for all possible strings 2021-03-01 21:01:01 -05:00
Goober5000 258ffdf56d a token consisting of a single + or - is not a valid number 2021-03-01 21:00:48 -05:00
Baezon bd5f709e14 must be 32 bits!!! 2021-03-01 12:14:13 -05:00
Baezon b6c29e3ffd increase max poofs to 32 2021-03-01 12:00:37 -05:00
Birk Magnussen b45cb19f3c Add changes to the parse exceptions to work with utf8 encoding 2021-03-02 00:05:12 +09:00
Birk Magnussen e30c919286 Add encoding conversion helpers 2021-03-02 00:03:36 +09:00
Goober5000 c4374d11a9 replace world_to_turret_matrix 2021-03-01 00:02:44 -05:00
Goober5000 3b1aac26e8 remove most of turret_matrix stuff 2021-02-28 23:41:56 -05:00
Birk Magnussen bbc0f08541 Fix Warpout being affected as well. Fix Messages. Fix Init 2021-03-01 13:36:05 +09:00
Goober5000 d4c6c3e145 turret_norm should now be calculated properly 2021-02-28 21:48:15 -05:00
Goober5000 66b7b011c9 Merge pull request #3256 from Goober5000/switch_sexp
add switch and functional-switch operators
2021-02-28 18:00:59 -05:00
Birk Magnussen 2233d2eb9b Reflect used player object 2021-03-01 01:32:13 +09:00
Birk Magnussen e9b2047769 Add function to switch campaign 2021-03-01 01:27:14 +09:00
Birk Magnussen 781aa5c638 Fix warning 2021-03-01 00:55:05 +09:00
m!m b5212d69e4 Merge pull request #3258 from BMagnu/lua_file_cleanup
Changed File not closed error to a warning and automatic file close
2021-02-28 16:44:58 +01:00
Birk Magnussen 03eb74e616 Add scripting API for accessing registeres sso's 2021-03-01 00:32:42 +09:00
Birk Magnussen f0d5c5a499 Remove redundant close 2021-03-01 00:13:49 +09:00
Birk Magnussen 335f2476f9 Added flag to select the warp effect type of lssm's 2021-03-01 00:06:15 +09:00
Birk Magnussen 530916e0fa Changed File not closed error to a warning and automatic file close 2021-02-28 23:47:07 +09:00
Birk Magnussen b4791b3b10 Add flag for beams to track uoffset individually 2021-02-28 14:40:25 +09:00
Baezon 4bdb9165ea bugfix 2021-02-27 22:33:21 -05:00
Goober5000 8d4976dd95 add switch and functional-switch operators
Like the C equivalent, these SEXPs allow one action to be taken, or one value to be returned, based on a numeric expression.
2021-02-27 21:56:51 -05:00
m!m e393503eb2 Merge pull request #3244 from the-maddin/default_volume_issue
Set default volume on audiostream creation
2021-02-27 22:41:03 +01:00
JohnAFernandez 9c4d8f175b Merge pull request #3255 from Baezon/bugfix-trail-texture
Properly initialize trail texture stretch
2021-02-27 14:31:12 -05:00
m!m 002b8a69b1 Merge pull request #3251 from asarium/fix/actionsCompile
Add a CMake platform check for proper non-copyable type support
2021-02-27 20:08:05 +01:00
Baezon 529ba78c04 review tweak 2021-02-27 13:48:26 -05:00
Baezon 772eaa634a properly initialize texture stretch 2021-02-27 13:41:24 -05:00
asarium 7c909c6d69 Fix Visual Studio compilation around non-copyable type
This works around a compiler bug present in most older versions of MSVC
where it absolutely wanted to use a deleted copy constructor even if a
move constructor was available.

This just moves the relevant code into the default constructor.
2021-02-27 19:39:29 +01:00
JohnAFernandez a22f44ce01 Merge pull request #3187 from Baezon/swarm-cleanup
Give swarm missile handling a well-deserved makeover
2021-02-27 00:01:58 -05:00
JohnAFernandez 09671d9907 Merge pull request #3245 from Baezon/disabled-repair-fix
Bugfix for disabled fighters interupting their own support calls
2021-02-26 23:59:03 -05:00
Goober5000 da4b6b2f67 Merge pull request #3252 from Goober5000/main_hall_parsing_fix
when we're finished parsing a main hall, the next main hall should be a new one
2021-02-26 21:55:13 -05:00
the-maddin c0f351d92e fix indents 2021-02-27 00:01:08 +01:00
m!m 8700645d21 Merge pull request #3067 from asarium/lua/fullTypeCoverage
Add full type coverage for return types and variables
2021-02-26 23:06:55 +01:00
Goober5000 3fe59717c5 when we're finished parsing a main hall, the next main hall should be a new one
With modular tables, we might have modified an entry in the middle of the vector, in which case the next index would be an existing main hall.  If the next modular table then created a brand new main hall, it would overwrite that entry.  This makes sure the code always assumes the next main hall will come at the end of the list.
2021-02-26 16:47:05 -05:00
asarium 0fb712ed39 Add full type coverage for return types and variables
This introduces type parsing for all types used within the scripting
documentation. This improves the generated JSON output and also
validates new code via the unit test.
2021-02-26 22:37:37 +01:00
the-maddin 003fa68582 Remove leftover default setting 2021-02-26 22:23:46 +01:00
Baezon e3acb2c56b ai fighter support 2021-02-25 23:45:42 -05:00
Baezon 789f78aefd Merge remote-tracking branch 'upstream/master' into expose-huge-small-targeting 2021-02-25 23:36:59 -05:00
Baezon ec323a3960 combine flags 2021-02-25 23:15:29 -05:00
Baezon 86d01a3b0f Merge remote-tracking branch 'upstream/master' into disabled-repair-fix 2021-02-25 21:22:18 -05:00
Baezon a685b6f051 Merge remote-tracking branch 'upstream/master' into better-subsys-attacking 2021-02-25 21:20:51 -05:00
Goober5000 2ac85f3172 Merge pull request #3246 from Goober5000/back_inserter_include
add missing #include
2021-02-25 15:14:48 -05:00
Goober5000 18a15eed29 add missing #include
On some setups the hierarchy of #include files doesn't catch an <iterator>, so #include it explicitly.
2021-02-25 13:45:07 -05:00
m!m 413633855f Merge pull request #3248 from asarium/build/fixQt
Force aqt to a known good version
2021-02-25 19:11:01 +01:00
asarium ac5eb11c39 Force aqt to a known good version
There was another break in that package so this should hopefully make
our builds more stable.
2021-02-25 18:37:44 +01:00
m!m ca5ab260c9 Merge pull request #3242 from asarium/feature/actionExpression
Add dynamic expression support for actions
2021-02-25 18:17:34 +01:00
Baezon 80ba3b9e9c Merge remote-tracking branch 'upstream/master' into better-subsys-attacking 2021-02-25 02:30:18 -05:00
Baezon 81c771b8ea clean up 2021-02-25 02:13:02 -05:00
Baezon d86723ef07 bugfix disabled fighters calling for support 2021-02-24 16:10:04 -05:00
asarium d589234648 Some final changes 2021-02-24 18:04:19 +01:00
the-maddin 26aab09b8e Update scripting documentation audio_stream:play()
to reflect what the implementation actually does.
2021-02-24 02:16:01 +01:00
JohnAFernandez 55b8f3f642 More cleanup and Int3() refactors (#2744)
* Clean Up ai_attack_object()

There was an unused parameter, and no one has added subsystem targeting (at least to this function) in the past 20 years, so it's time to remove it and make it more readable.  Probably better to adjust that behavior somewhere else anyway.

Also changes an Int3() into

* More Int3 cleaning

Refactor a few Int3()'s in the AI code

* Feedback on is_ignore_object_sub

* Feedback, remove duplicate check, add documentation to preserve why it was there
2021-02-23 19:51:43 -05:00
the-maddin 063854384f Set sane default volumes on audiostream creation.
Looking throughthe code, it appears that
sound volumes are typically set when calling
the "play" function for in-engine uses of sounds.
No default values were, in fact, set explicitly at
creation, so they were initialized to 0.0f.

Scripting documentation, however, refers to
default volumes per type where no volume is
passed. New engine functionality should also
be able to rely on this.

I'm setting sane values found in other
parts of the sound system at stream creation,
to be used or overwritten later.
2021-02-24 01:45:05 +01:00
the-maddin 9ffcd780e9 Deduplicate stream creation code 2021-02-24 01:45:05 +01:00
the-maddin 4125d0bdba Fix stream slot leak
A wrong stream type could lead to a stream handle
being marked as used although no stream is created
2021-02-24 01:44:10 +01:00
the-maddin af29243157 Merge remote-tracking branch 'refs/remotes/upstream/master' 2021-02-23 20:52:40 +01:00
Fabian Woltermann 659d68e9b9 Merge pull request #3167 from EatThePath/cylinder-only-tube-lights
Cylinder only tube lights
2021-02-23 19:11:22 +01:00
m!m 3d856b77d9 Merge pull request #3229 from the-maddin/master
Scripting&Sound: Load sound from memory
2021-02-23 17:57:32 +01:00
Baezon f447fd4e23 unused variables 2021-02-23 01:13:08 -05:00
Baezon 8088cf0ab4 ints to floats 2021-02-23 00:53:10 -05:00
Baezon a69046000e cast to int 2021-02-23 00:12:29 -05:00
Baezon 881da211a2 misc tweaks 2021-02-22 23:23:49 -05:00
Baezon 622a28236e decouple species from asteroids 2021-02-22 22:55:34 -05:00
the-maddin d0edab2c74 Better instance preparation; no MIN macro 2021-02-23 00:47:13 +01:00
Martin Merget c715cf5c65 Merge remote-tracking branch 'refs/remotes/upstream/master' 2021-02-23 00:04:54 +01:00
z64555 1fca306fc9 Address clang-tidy issues. 2021-02-22 14:24:26 -06:00
asarium 02b1e38cd7 Add variables concept to expressions
This also includes the necessary setup work for using "position" and
"direction" in action expressions.
2021-02-22 18:39:06 +01:00
asarium 851a7663a8 Rework actions to use definitions
This introduces action definitions which can then be instantiated to
form actual actions with expressions as their parameters.
2021-02-22 18:02:22 +01:00
asarium bcaa7934c6 Allow implicit conversion from int to float
This is generally a safe operation and will make the system a bit easier
to use.
2021-02-22 18:02:22 +01:00
asarium 1d6052e81e Rework function handling 2021-02-22 18:02:22 +01:00
asarium a5a91b5acf Add Action expressions
This is a parser for a very simple language to allow for execution of
dynamic expressions with return values for use as action parameters. The
only "dynamic" part this currently supports are random ranges but more
features are planned for the future.
2021-02-22 18:02:22 +01:00
asarium aa7ea238b9 Update GTest 2021-02-22 18:02:22 +01:00
m!m 8b23ccdf2e Merge pull request #3061 from asarium/feature/actionSystem
Add dynamic action programming system
2021-02-22 18:00:58 +01:00
Baezon 5004f6ab32 Merge remote-tracking branch 'upstream/master' into ai-multilock 2021-02-21 22:15:31 -05:00
Baezon adea41e690 clarity edits 2021-02-21 21:56:34 -05:00
Baezon d463db3742 Merge remote-tracking branch 'upstream/master' into generic-debris-enhancement 2021-02-21 21:31:59 -05:00
Martin Merget 4305aed38d Factor out duplicate creation/opening code 2021-02-22 01:39:55 +01:00
z64555 f51502e4ae Make qtFred and Fred changes consistent with each other. 2021-02-21 18:16:55 -06:00
the-maddin 34eed12988 Extract shared code from AudioStream::Create and CreateMem
Also cleaned up control flow on failure as far as used macros allow.
2021-02-22 00:58:41 +01:00
the-maddin 60775e73b5 Fix MSVC builds v2 2021-02-21 22:30:17 +01:00
the-maddin e55b246756 Fix MSVC builds 2021-02-21 22:14:39 +01:00
the-maddin 438f48c835 Fix compiler/type issue 2021-02-21 21:51:34 +01:00
asarium 8f88801646 Add dynamic action programming system
This system adds the code necessary for letting content creators specify
complex events by specifying a simple, program-like sequence of
operations that will be executed by the engine when a certain event is
triggered.
2021-02-21 21:29:02 +01:00
the-maddin afc9e8132a renamed memfile functions & struct 2021-02-21 20:53:52 +01:00
the-maddin 371aaa1107 Moved, documented and renamed struct MemFileCursor 2021-02-21 20:46:55 +01:00
the-maddin ab7e6cbbe1 add LuaErrors for invalid input, fix off-by-one 2021-02-21 20:37:02 +01:00
m!m 340edd5ec0 Merge pull request #3239 from asarium/build/updateBuildImage
Update Linux build image and make consistent
2021-02-21 14:36:27 +01:00
asarium 88e6469fb4 Update Linux build image and make consistent
For some reason the last update of the PR pipeline did not update the
other workflows as well so we had some minor inconsistencies.

This should hopefully fix the nightly build issues for real this time.
2021-02-21 14:02:32 +01:00
BMagnu fd60dd342f Add vanish Lua function to some objects (#3238)
* Add vanish function to some objects

* Modify vanish function return. Modify fireball access

* Remove dedunant check for ship vanish
2021-02-21 11:59:49 +00:00
Asteroth dcd38539c2 Merge pull request #3237 from Baezon/fix-turret-inaccuracy
Bugfix to turret_inaccuracy
2021-02-21 00:19:39 -05:00
Baezon 70265c6f63 bugfix turret inaccuracy 2021-02-20 23:41:30 -05:00
JohnAFernandez 19b3f85eea Merge pull request #3220 from Baezon/turret-inaccuracy
Add turret-set-inaccuracy SEXP
2021-02-20 21:07:47 -05:00
JohnAFernandez 873ec133b4 Merge pull request #3204 from Baezon/icons-parsing-overhaul
Overhaul briefing icon parsing
2021-02-20 20:57:47 -05:00
Goober5000 88f6312fd8 Merge pull request #3234 from Goober5000/sim_hull_scripting
add SimHitpointsLeft
2021-02-20 16:51:11 -05:00
Goober5000 69c1398368 add SimHitpointsLeft 2021-02-20 16:13:14 -05:00
m!m 043b1d34c8 Merge pull request #3232 from asarium/fix/linuxNightly
Try to fix linux nightly builds
2021-02-20 21:34:51 +01:00
m!m 1226c894ed Merge pull request #3233 from asarium/build/githubRegistry
Store standalone image on GitHub
2021-02-20 21:34:40 +01:00
asarium 0fb7143f12 Store standalone image on GitHub
Docker Hub is going into a weird direction with their rate limits and
the GitHub Container Registry is better in that regard.

Old images will stay in Docker Hub for the time being though.
2021-02-20 18:34:25 +01:00
Fabian Woltermann 57c593f74e Merge pull request #3231 from Goober5000/fix_eval_numeric_sexp
fix mn.evaluateNumericSEXP
2021-02-20 14:54:53 +01:00
asarium cf3faa35cd Try to fix linux nightly builds
The default Python version appears to be too recent so let's try to have
this action use the python package that is installed in our build image.
2021-02-20 14:44:01 +01:00
Goober5000 2429b99184 fix mn.evaluateNumericSEXP
This is a follow-up to #2687.  The final implementation of evaluateNumericSEXP different from the testing implementation in a small but crucial way that prevented it from actually working.  Since it used `eval_num`, it didn't evaluate the specified SEXP node but rather the CAR (first element) of the node list.  This fixes that by putting the node in a temporary SEXP list so that `eval_num` will look in the right place.
2021-02-20 01:40:55 -05:00
Shivansps 2ee128cd88 Merge branch 'arm_fixes' 2021-02-19 21:02:53 -03:00
Shivansps a2b349855e Merge pull request #1 from scp-fs2open/master
Update fork
2021-02-19 20:53:22 -03:00
Baezon 0f451e6190 more comments 2021-02-19 10:45:32 -05:00
the-maddin 366a96bdd4 Expose audiostreams from memory to LUA
Allow scripts to play any LUA binary string containing valid WAV data.
Useful for TTS data passed in via LUASockets.
2021-02-19 01:22:24 +01:00
the-maddin 8770ad74f8 Add support for audiostream from in-memory sound 2021-02-19 01:19:05 +01:00
the-maddin 68d5467e2a Add support for in memory sound 2021-02-19 01:16:39 +01:00
the-maddin ac2fa61f6e Add support for in-memory sound
Using the memory backend, treat sound in memory like sound in cfiles.
2021-02-19 01:14:40 +01:00
the-maddin 2060a1dabe Add backend for in-memory audio
FFmpegContext can now also hold a cursor over a vector of bytes instead of a cfile to store sound data in it.
Appropriate creation, reading seeking functions included.
2021-02-19 01:10:43 +01:00
Fabian Woltermann b561156f09 Merge pull request #3226 from Goober5000/tocase
additional case functions and checks
2021-02-18 14:08:34 +01:00
Goober5000 f3bca4384f additional case functions and checks
This refactors the tolower/toupper code to use standards-conformant logic, and also adds some helpful utility functions.  Regular tolower/toupper must be supplied a value that can be represented as `unsigned char`, but the std:: functions are a bit more robust.
2021-02-18 04:23:08 -05:00
Fabian Woltermann c00ff88a5a Merge pull request #3223 from Goober5000/case_insensitive_ships
make the ship lookup case insensitive
2021-02-18 09:10:57 +01:00
Goober5000 866b64ff8d maybe this works better 2021-02-17 12:12:17 -05:00
Goober5000 3acd74e894 make the ship lookup case insensitive
Does what it says on the tin.  Fixes #3221.
2021-02-17 11:31:45 -05:00
Goober5000 ffa6e594e7 Merge pull request #3222 from Goober5000/perform_actions_documentation
add clarification
2021-02-16 19:27:30 -05:00
Goober5000 39f9df11f7 add clarification 2021-02-16 18:35:11 -05:00
Baezon a606f2cafa modernize-use-auto 2021-02-16 10:52:56 -05:00
Baezon 592855c35d NULL -> nullptr 2021-02-16 02:27:11 -05:00
Baezon 3797171fb0 Merge remote-tracking branch 'upstream/master' into turret-inaccuracy 2021-02-16 02:23:45 -05:00
Baezon 028e40a43b add turret-set-inaccuracy sexp 2021-02-16 02:21:54 -05:00
Goober5000 36ea4c225b Merge pull request #3219 from Goober5000/model_instance_in_fred
add model instance support to FRED rendering
2021-02-15 09:33:55 -05:00
Goober5000 24df0efb6e add model instance support to FRED rendering
This changes FRED to properly initialize a model instance on ship creation and also use that instance when rendering the ship.  This prevents destroyed submodels from appearing.  Fixes #3212.
2021-02-15 08:34:12 -05:00
Fabian Woltermann db2eba92d5 Merge pull request #3213 from Goober5000/message_list_chain
add send-message-chain
2021-02-15 10:50:05 +01:00
Fabian Woltermann dd0bb3ceca Merge pull request #3214 from Goober5000/fix_event_editor_closing
fix event editor closing on key press
2021-02-15 10:15:18 +01:00
Fabian Woltermann f9da8c7db2 Merge pull request #3217 from Goober5000/fix_event_editor_delete
fix event node deletion behavior
2021-02-15 10:14:51 +01:00
Goober5000 82a93e9e47 fix event node deletion behavior
The defensive coding in #3191 against illegal cut/delete operations was a little too defensive.  This properly allows deletion of events when necessary, and it still guards against a Cut operation being improperly called due to a shortcut key press.

Fixes #3216.
2021-02-14 17:12:22 -05:00
z64555 754f0ea876 Removed unused local variable. 2021-02-14 10:33:49 -06:00
z64555 9145922cb1 Fix default_item to use default_bindings. 2021-02-14 09:59:36 -06:00
z64555 47e19207f9 Merge branch 'master' into controls3
Resolved Conflicts:
	code/controlconfig/controlsconfig.cpp
	code/controlconfig/controlsconfig.h
2021-02-14 09:48:55 -06:00
Goober5000 41f9dbb003 fix event editor closing on key press
Restores the MFC functions that were taken out in #3073.  These functions appeared redundant, but they were actually necessary to intercept the MFC handling of Enter and Escape.  In addition to fixing that behavior, this PR also adds some clarifying comments and renames some functions to prevent confusion.
2021-02-14 01:32:03 -05:00
Goober5000 c067651498 add send-message-chain
Implements send-message-chain as described in issue #3185.  Also fixes the default argument for message priority, and mirrors the default argument fix to qtFRED.
2021-02-14 00:23:57 -05:00
JohnAFernandez 2361152399 Merge pull request #3211 from JohnAFernandez/Messaging_Switch_to_Normal
Make "Normal" the default option for Messages
2021-02-13 23:28:47 -05:00
JohnAFernandez 0318e3f851 Make "Normal" the default option for Messages
Moves messages to the more suitable default of normal.  Also adds clarifying documentation.
2021-02-13 15:56:09 -05:00
Goober5000 d21f7b8915 Merge pull request #3208 from PhantomHoover/fix/misc-rand-sizes
Properly fix static_rand()'s range and account for this in functions that were misusing it
2021-02-13 14:32:18 -05:00
Phantom Hoover 640640b4b4 Properly fix static_rand()'s range and account for this in functions that were misusing it 2021-02-13 16:06:47 +00:00
Fabian Woltermann f87cf7df23 Merge pull request #3207 from Baezon/waypoint-complete-fit-bugfix
Fix for waypoint completion with FIT
2021-02-13 17:01:25 +01:00
Asteroth 616e6a9bc0 Merge pull request #3180 from Baezon/split-collision-light-width
Split beam width for collision purposes and lighting purposes
2021-02-13 02:15:17 -05:00
Goober5000 303787d97c Merge pull request #3206 from Goober5000/retail_hybrid_translation_behavior
restore retail behavior of XSTR
2021-02-12 17:48:23 -05:00
MageKing17 db2bd97669 Merge pull request #3205 from MageKing17/bugfix/controlconfigoverride-default-preset
If the first #ControlConfigOverride isn't named, use "default".
2021-02-12 14:29:01 -08:00
Baezon 5e38f3c0d4 fit waypoint bugfix 2021-02-12 11:12:24 -05:00
Goober5000 1e756d1a67 restore retail behavior of XSTR
This is a follow-up to #2390.  Retail used a weird hybrid approach where internal strings were translated but external strings were not.  This restores that behavior by adding another language, LCL_RETAIL_HYBRID, which is the default.  The game can still be run in completely untranslated or completely translated mode.

All three modes have been tested and translate strings, or not, as expected.  The `$Use tabled strings for the default language:` flag has also been tested and still works.
2021-02-11 19:47:12 -05:00
Baezon ec274d58db clang-tidy 2021-02-10 21:49:49 -05:00
Baezon 682c15d6b1 clang-tidy curse you 2021-02-10 21:41:37 -05:00
MageKing17 29fbebde16 If the first #ControlConfigOverride isn't named, use "default".
This causes it to replace the first preset in the list, which more closely approximates the old behavior.
2021-02-10 17:58:08 -08:00
JohnAFernandez bd7450c4e6 Merge pull request #3198 from Baezon/landmark-logging
Add 'landmark' logging
2021-02-10 20:40:40 -05:00
Baezon b843a5be3a clean up 2021-02-10 18:15:48 -05:00
Baezon be44e287ee overhaul brief icon parsing 2021-02-10 17:36:37 -05:00
Goober5000 af16a6bc42 Merge pull request #3191 from Goober5000/fred_indents_and_colors
Additional FRED features
2021-02-10 09:45:07 -05:00
Fabian Woltermann 6b7429ab5d Merge pull request #3192 from Baezon/turret-forced-target
Add turret-set-forced-target SEXP
2021-02-10 11:39:16 +01:00
Fabian Woltermann d4be72c49b Merge pull request #3203 from JohnAFernandez/Really-fix-hud-config-crash
Actually fix radar range turning to -1 after hud gauge config
2021-02-10 11:36:30 +01:00
JohnAFernandez 86308bbf34 Actually fix radar range turning to -1 after hud gauge config
Problem was caused by negative array index write in this section of code.
2021-02-10 00:05:27 -05:00
Goober5000 3d6124c7ad Merge pull request #3144 from Goober5000/fix_look_at
reimplement look_at
2021-02-09 21:48:52 -05:00
Baezon 6357c2a856 clang tidy 2021-02-07 23:40:14 -05:00
Allen A. Babb 0f1c5e0a42 Merge pull request #3201 from z64555/unhide_chocolate
Unhide chocolate - Revert default-disable of controls unusable with retail data.
2021-02-07 17:02:32 -06:00
z64555 cb692b22ba Add note comment to the CCI_builder. Controls that don't work in retail should be default disabled, but this relies on the coders making them to get it set the first time. 2021-02-07 14:23:44 -06:00
z64555 0b03c3f672 Add me to the cool kids club. Wait, no, not that one. 2021-02-07 14:15:35 -06:00
z64555 15d3dde5fa Unhide non-retail controls by default. Even though retail data can't make use of most of them, some mods may count on their visibility. 2021-02-07 14:06:27 -06:00
Baezon 24947b64d7 split light and collision width 2021-02-06 22:00:45 -05:00
Goober5000 61bb44d07b Merge pull request #3200 from wookieejedi/test-rotation-fix
Fix Bug with Reading Turret Rotation Axes
2021-02-06 14:44:07 -05:00
Goober5000 aa3eb4d42c Merge pull request #3199 from Goober5000/vecmat_projecc
add useful function
2021-02-06 14:19:36 -05:00
wookieejedi 2cdc74264c Fix Bug with Reading Turret Rotation Axes
Multipart turrets that have no rotation specified in PCS don't have `movement_type` assigned properly within `modelread.cpp`, which eventually leads to a fatal crash. This two line fixe properly specifies the `movement_type` and fixes the crash. Tested and confirmed. Thanks to @Goober5000 for the assistance and troubleshooting.
2021-02-06 13:59:23 -05:00
Goober5000 dd92a0f0bb add vm_vec_is_normalized and use it in several places 2021-02-06 13:46:54 -05:00
Goober5000 e699d991d1 add useful function 2021-02-06 00:19:57 -05:00
wookieejedi ede8c6a172 Merge pull request #3197 from wookieejedi/expose-countermeasure-firewait
Expose Additional Countermeasure Options to Modders
2021-02-06 00:08:36 -05:00
JohnAFernandez ba9205cd35 Make sure to pull from the bounds of the vector. 2021-02-05 23:40:24 -05:00
Baezon b7bd8d6fbb moar tweaks 2021-02-05 15:28:14 -05:00
Baezon 7015818ea5 review tweaks 2021-02-05 12:56:03 -05:00
wookieejedi c831235cd3 add warnings 2021-02-05 11:39:50 -05:00
Baezon a6b19706eb 'landmark' logging 2021-02-05 03:49:39 -05:00
wookieejedi de17df207a specify values for AI and use multipliers for fail and succeed 2021-02-04 22:38:06 -05:00
wookieejedi 5116471d8d simplify logic 2021-02-04 13:40:23 -05:00
wookieejedi e01bd28e79 Expose Additional Countermeasure Options to Modders
This PR provides modders with additional options to alter countermeasure values. Previously, countermeasures had a fixed, hardcoded fire wait time of 333 milliseconds, regardless of what `$Fire Wait:` was specified. Also, the AI would wait a fixed delay between firing of failed countermeasure launches and successful countermeasure launches. For successful launches the AI would double the fire wait. Also, Friendly ships would only use a fixed constant value for countermeasure firing chance, and not the value based on their class specific AI profile.

This PR exposes those values with the following options:
•	Add main AI table flag: `Friendly Ships Use AI Profile Countermeasures Firing Chance`. This will allow Friendly ships to use their AI class profile countermeasure firing chance instead of the default fixed value from main AI table.
•	Add value in CM section of weapons table: Countermeasures use fire wait time `+Use Fire Wait`. This is a boolean that allows the countermeasure’s fire wait to actually use what is specified in the `$Fire Wait:` section of that weapon.
•	Add value in CM section weapons table: `+Fail Delay Equals Fire Wait`. The delay between failed countermeasure launches is set to use the fire wait value.
•	Add value in CM section weapons table: `+Successful Launch Delay Multiplier`. This allows modders to set the value that is multiplied to fire wait for successful countermeasure launches.
2021-02-04 13:12:02 -05:00
Asteroth 994e42a27d Merge pull request #3175 from Baezon/trail-decay-exponent
Non-linear Trail decay and Texture stretch
2021-02-04 12:09:22 -05:00
wookieejedi 74c9139c1c Merge pull request #3195 from wookieejedi/fix-retail-cap-ship-speed
Fix speed differential for retail cap ships
2021-02-03 19:26:19 -05:00
wookieejedi 1d7070cf12 add claryifying parentheses 2021-02-03 18:18:04 -05:00
JohnAFernandez 19c19f1262 Remove the Unused Just_updated Flag
This flag is vestigal.  It was likely used in the FS1 codebase and then was not removed by the rushed FS2 multi team.  Whether or not an object uses physics_sim is determined earlier in `multi_oo_is_interp_object()`
2021-02-03 18:00:16 -05:00
wookieejedi 754f4a309c add deprecation check 2021-02-03 17:46:06 -05:00
Asteroth 83bd14586f Merge pull request #3179 from Baezon/empty-sound-fix
Don't search for empty sound names
2021-02-03 17:41:08 -05:00
wookieejedi 828a993eb6 Fix speed differential for retail cap ships
As astuetly determined by @Baezon `the speed differential for retail cap ships is caused by 'ships with no shields can manage ETS', being part of the bugfixes with target version`. This PR adds two flags per Discord suggestion, one for all ships and one for only small ships.
2021-02-03 17:14:39 -05:00
Asteroth 69b319a7d6 Merge pull request #2591 from Baezon/homing-primaries
Add homing primaries
2021-02-02 21:48:16 -05:00
Baezon 6414172898 Merge remote-tracking branch 'upstream/master' into homing-primaries 2021-02-02 21:15:05 -05:00
Baezon e78fccc294 unused variables 2021-02-02 20:49:33 -05:00
Baezon 54f1a86a5a clena up and finalization of subsys targeting 2021-02-02 20:06:40 -05:00
Baezon 8c387d7507 tentative subsys targeting 2021-02-02 11:31:05 -05:00
Baezon 476e916945 Merge remote-tracking branch 'upstream/master' into turret-forced-target 2021-02-01 22:12:50 -05:00
Asteroth 1d131403d5 Merge pull request #3176 from Baezon/damage-incidence-angle
Angle-based damage multiplier
2021-02-01 20:54:20 -05:00
Baezon e7cab7cb42 clang-tidy dont hurt me no mo 2021-02-01 14:24:44 -05:00
Baezon 7b2c8304ff typo 2021-02-01 13:25:44 -05:00
Goober5000 b6314feb29 add comment 2021-02-01 02:24:54 -05:00
Goober5000 a124722966 qtfred 2021-02-01 00:46:17 -05:00
Goober5000 47543ac7d4 implement keyboard shortcuts, implement mission saving for bg color 2021-02-01 00:46:17 -05:00
Goober5000 262b45188a resizable Event Editor 2021-02-01 00:46:17 -05:00
Goober5000 c0446cd03c color stuff works pretty well 2021-02-01 00:46:17 -05:00
Goober5000 bc37fda89e reorganize event annotations a bit
preliminary work for background color and changing indent
implement a sort-of-working background color change
2021-02-01 00:46:17 -05:00
Goober5000 275a439091 Merge pull request #3190 from Goober5000/quick_annotation_fix
mission save bugfix
2021-02-01 00:43:55 -05:00
Goober5000 f475ea4d25 mission save bugfix
Somehow during the annotation merge the save got borked.  This fixes mission saving.
2021-02-01 00:09:55 -05:00
Goober5000 72d2f9f1a1 reimplement look_at
This PR re-implements the look_at feature, which has been broken for many years.  A look-at rotation is a type of intrinsic_rotation, just like dumb-rotations. The same code handles both; the only difference is whether submodel_rotate or submodel_look_at is called to apply the actual movement.

The previous look_at parsing code has been optimized by performing the name-to-submodel resolution when the model is actually parsed, instead of when the first look-at rotation is called.  This avoids the need to store a name in the submodel struct and also avoids cluttering the look_at function.

This PR is essentially bookkeeping, except for the submodel_look_at method.  This method takes advantage of the submodel rotation upgrade and calculates angles in almost the same way as the new turret rotation code.  It's much more elegant, much less hackish, and works for all detail levels.
2021-01-31 14:31:40 -05:00
Goober5000 8ab3cf240b Merge pull request #3189 from Goober5000/fix_compilation_error
fix compilation
2021-01-31 14:30:16 -05:00
Goober5000 450900d2b5 fix compilation
Quick hotfix due to two branches being merged that were both compatible with master but not with each other.
2021-01-31 13:57:12 -05:00
Goober5000 68b6795d5a Merge pull request #3079 from Goober5000/stuff_number
convert float parsing to use strtof
2021-01-31 13:18:27 -05:00
Goober5000 868715867d Merge pull request #3056 from Goober5000/model_rotation_arbitrary_axis
Allow submodels to rotate around an arbitrary axis
2021-01-31 13:17:27 -05:00
Baezon 9b7cc77b55 revert multi compatability :( 2021-01-31 13:11:27 -05:00
Baezon d3355b0783 experimental multi compatability 2021-01-31 12:29:25 -05:00
m!m 6f382ce0d9 Merge pull request #3188 from asarium/fix/stdApiCrash
Fix crash in server REST API when omitting framecap
2021-01-31 17:02:19 +01:00
asarium dbfb5b9d34 Fix crash in server REST API when omitting framecap
Since the return value of the json library is null in that case it
crashed the server when no value was specified.
2021-01-31 16:08:33 +01:00
Allen A. Babb b3edc683fc Merge pull request #2907 from z64555/feature/controls2
Controls 0, 1, and 2 - Vectorize Controls_config, Refactor Control Presets, and Use Undosys for undo/redo actions done in the Controls configuration menu.
2021-01-30 10:04:58 -06:00
Asteroth f1ff6ebf55 Merge pull request #2870 from Baezon/armor-types-beam-weapon
Use armor/damage types for beam-weapon damage
2021-01-30 02:33:13 -05:00
Baezon f95e51b047 dont search for empty names 2021-01-30 00:05:17 -05:00
wookieejedi 213d20f7ef Merge pull request #3177 from Baezon/better-missile-avoid
Improved missile avoidance
2021-01-29 22:47:01 -05:00
Goober5000 a10e456de3 Merge pull request #3073 from Goober5000/fred_comments
Fred comments
2021-01-29 17:38:31 -05:00
Goober5000 5187ea5041 Revert "Disable Qt projects since downloads are broken"
This reverts commit 4aa33c7b3e from PR #3160.
2021-01-29 16:57:05 -05:00
z64555 9b42819dce Address Clang-Tidy issues. 2021-01-29 15:09:54 -06:00
z64555 c1d1a965c6 Think I got all of the index swapped. *Scrolls right* oh. 2021-01-29 04:40:58 -06:00
Baezon 89a8cbcbae review tweaks 2021-01-29 01:04:15 -05:00
z64555 b97e804123 Address signed/unsigned complaint. 2021-01-28 23:54:44 -06:00
Asteroth e0dd807bb4 Merge pull request #3145 from EatThePath/fix-type-d-beam-pulse-lighting
Stop including tube lights between anti-fighter beam pulses
2021-01-29 00:39:27 -05:00
Baezon 888c14aeaf flip max and min 2021-01-28 23:45:06 -05:00
Baezon ab64183981 Merge remote-tracking branch 'upstream/master' into generic-debris-enhancement 2021-01-28 22:57:42 -05:00
Baezon 055784dcff clean up swarm missiles 2021-01-28 22:33:01 -05:00
Baezon 4b3a1a8d84 unused variables 2021-01-28 20:39:29 -05:00
Baezon 91be428596 missing '$' 2021-01-28 20:27:36 -05:00
Baezon 0c0a9e4f26 typo 2021-01-28 20:24:54 -05:00
z64555 d6672d01cf Don't count an item in the reset check if the item is disabled.
* Remove errant Assert()
* Drop leading whitespace of preset $Name field
* Fix do_reset behavior due to incorrect default binding check.  Fix is possibly a backport.
* When $Text is specified for a bind item, set the XStr index to 0.
2021-01-28 19:16:07 -06:00
Goober5000 43ae0e3575 qtfred 2021-01-28 19:59:20 -05:00
Goober5000 2be4818d24 tweak parsing since we want to read annotations generally 2021-01-28 19:17:08 -05:00
Goober5000 9bebdbb575 rename event_comment to event_annotation 2021-01-28 18:56:15 -05:00
Goober5000 04cf220f2d comment capability for FRED
Add FRED comments. These aren't the typical source-code style comments that are embedded in mission or table files; these are regular strings that are stored as mission data. You might think of them as annotations. Right-click on any node in the event tree and click on Edit Comment to add one. The tree node will then show a different icon and the comment will be visible as a tooltip when you mouse over the node text.
2021-01-28 18:25:19 -05:00
Goober5000 61c7cc2856 Merge pull request #3141 from JohnAFernandez/Hud-config-screen-is-weird
Make sure the Hud_config_inited is reset when the screen is exited.
2021-01-28 14:29:29 -05:00
Baezon 824c537bd2 Merge remote-tracking branch 'upstream/master' into ai-multilock 2021-01-28 12:25:35 -05:00
Asteroth d1f0f5002f Merge pull request #2775 from Baezon/burst-seed
Implement Beam Flags and some adjustments to burst handling
2021-01-28 11:51:30 -05:00
Baezon d3d016602d rename beam_flags -> beam_info_flags 2021-01-28 02:46:40 -05:00
Baezon f9e44f545e ignore empty sounds 2021-01-27 23:31:38 -05:00
Baezon 52f57df064 NULL -> nullptr 2021-01-27 23:25:19 -05:00
Baezon 61931520d1 Merge remote-tracking branch 'upstream/master' into generic-debris-enhancement 2021-01-27 23:06:45 -05:00
Baezon 229dd4c63c clean up 2021-01-27 20:59:01 -05:00
Baezon 7515422979 clarity parentheses 2021-01-27 20:14:33 -05:00
Baezon eb1d748907 safety 2021-01-27 17:25:28 -05:00
Baezon b87d3c65a0 Merge remote-tracking branch 'upstream/master' into better-missile-avoid 2021-01-27 15:11:08 -05:00
Baezon 8d841fa1cc clean up 2021-01-27 14:48:41 -05:00
Goober5000 537c4b6f24 Merge pull request #3172 from BMagnu/hotfix_keynames
Fix special char hex codes for utf8
2021-01-27 13:52:15 -05:00
Goober5000 f9a6c86cad Merge pull request #3162 from Goober5000/ship_create_display_name
default display names for script/sexp-created ships
2021-01-27 13:40:16 -05:00
Goober5000 db466048ea Merge pull request #3168 from Goober5000/debris_colgroup_check
add collision group checks to debris
2021-01-27 13:40:05 -05:00
m!m 6952b58846 Merge pull request #3174 from asarium/build/bumpVersion
Bump version
2021-01-27 19:12:45 +01:00
Baezon 284ad2941c Merge remote-tracking branch 'upstream/master' into better-missile-avoid 2021-01-27 12:53:24 -05:00
Baezon 76d295d2bc Merge remote-tracking branch 'upstream/master' into damage-incidence-angle 2021-01-27 12:47:55 -05:00
Baezon 66c38c43c6 clean up 2021-01-27 12:43:32 -05:00
asarium 2161ab563d Bump version 2021-01-27 17:55:37 +01:00
Baezon 6cd5510bd1 clean up 2021-01-27 10:49:32 -05:00
Birk Magnussen 25cca192db Switch Key Names from internal encoding to unicode in utf8 mode 2021-01-26 19:09:20 +09:00
Birk Magnussen e6067f756a Fix special char hex codes for utf8 2021-01-26 13:53:25 +09:00
Goober5000 6d9e9a2e3d add collision group checks to debris
Collision groups were checked between ships, weapons, and beams, but not debris.  This adds debris.
2021-01-24 01:07:11 -05:00
David Gibson 373d119f1a modernize nullptr for tidy 2021-01-23 21:58:47 -06:00
David Gibson 7cb2338325 removed now-superflous element counting loop from gr_opengl_deferred_lighting_finish 2021-01-23 21:10:54 -06:00
David Gibson ddcc94b0da Extended the tube light cylinder volumes for deferred lighting to encompass the end cap spheres, removed those spheres, and adjusted the shader handling of tube lights to account for this. 2021-01-23 20:56:07 -06:00
David Gibson 9a866434b8 Removed the end light volumes from the defered lighting setup for tubelights. 2021-01-23 17:31:12 -06:00
Goober5000 37e92e01b6 default display names for script/sexp-created ships
Now that the hash truncation logic is part of the ship display name, ships created by script or sexp should check this as well.
2021-01-22 23:06:48 -05:00
m!m 60047116fd Merge pull request #3160 from asarium/ci/disableQt
Disable Qt projects since downloads are broken
2021-01-22 16:54:54 +01:00
asarium 4aa33c7b3e Disable Qt projects since downloads are broken 2021-01-22 16:26:44 +01:00
m!m 373dbeb63f Merge pull request #3159 from Baezon/previous-bank-fix
Fix a bug with previous_bank and ship class swapping
2021-01-21 22:06:30 +01:00
m!m 361cc76c30 Merge pull request #3154 from Goober5000/redo_3149
fix a rare crash in the tech room
2021-01-21 21:47:53 +01:00
Baezon 3f27183d6d also reset previous bank 2021-01-21 01:04:13 -05:00
Baezon 4e5c74d729 add trail alpha decay exponent 2021-01-19 22:44:08 -05:00
Goober5000 3d976f53b4 fix a rare crash in the tech room
The tech room loop checked that all the lines could fit in the available screen real estate, but it didn't check to see that the number of lines was less than the array capacity.  Normally this never happened, but certain mods which use smaller fonts will overflow the limit.  This adds a proper bounds check and also increases the bounds so that more of the smaller lines can be used.
2021-01-17 11:21:41 -05:00
m!m e5af389803 Merge pull request #3150 from scp-fs2open/revert-3149-fix_techroom_crash
Revert "fix a rare crash in the tech room"
2021-01-17 17:14:30 +01:00
m!m ba0f2e7f83 Revert "fix a rare crash in the tech room" 2021-01-17 11:55:59 +01:00
Goober5000 f0987a4ad1 Merge pull request #3149 from Goober5000/fix_techroom_crash
fix a rare crash in the tech room
2021-01-17 02:15:55 -05:00
Goober5000 61dd4356f0 fix a rare crash in the tech room
The tech room loop checked that all the lines could fit in the available screen real estate, but it didn't check to see that the number of lines was less than the array capacity.  Normally this never happened, but certain mods which use smaller fonts will overflow the limit.  This adds a proper bounds check and also increases the bounds so that more of the smaller lines can be used.
2021-01-17 01:21:52 -05:00
David Gibson d9895455cd Addressed feedback and tidy issues with AA beam pulse lighting fixes 2021-01-15 13:09:43 -06:00
Baezon d9a7e786b5 Merge remote-tracking branch 'upstream/master' into burst-seed 2021-01-15 12:52:25 -05:00
David Gibson 40e7ce012e =Added some important brackets I negligently omitted 2021-01-15 00:28:59 -06:00
David Gibson 31227c659a added a check in beam_move_all_post() to avoid adding tube lights when anti-fighter beams are between pulses. Also added documenting comments to beam_type_b_get_status 2021-01-14 23:59:13 -06:00
JohnAFernandez 679f7f20d7 Switch the correct ammo variable.
The previous pr was supposed to fix what ammo capacity the ship was reloaded to, but instead it was changing how much ammo was in the magazine.
2021-01-14 09:23:52 -05:00
JohnAFernandez ff9b2fd6cd Make sure the Hud_config_inited is reset when the screen is exited. 2021-01-13 21:20:27 -05:00
Fabian Woltermann a939a73c14 Merge pull request #3139 from z64555/hud_config
More safety checks for the HUD_config struct
2021-01-13 22:20:43 +01:00
Goober5000 487aad8bbe a bit of cleanup and reorganization/simplification 2021-01-13 14:01:34 -05:00
Goober5000 554bbb884d remove angles from the submodel instance 2021-01-13 14:01:34 -05:00
Goober5000 020f14fb51 allow rotating submodels to rotate around an arbitrary axis 2021-01-13 14:01:28 -05:00
Goober5000 98e501acc7 remove the orientation field for submodels
Change the `orientation` field to `frame_of_reference` and remove it from submodel instance calculations.
2021-01-13 13:52:48 -05:00
Goober5000 3f5ad1239d Merge pull request #3140 from Goober5000/techroom_update
make model_set_up_techroom_instance a bit more robust
2021-01-13 13:51:47 -05:00
z64555 4e715352c9 Increment int strikes per CSG warning, as done in PLR code
* Use ReleaseWarnring instead of Warning
* Use correct upper boundry check logic on HUD_config::mail_color
2021-01-13 12:48:24 -06:00
Goober5000 5f538fa514 make model_set_up_techroom_instance a bit more robust
Follow-up to #3137.  I missed two important details in the first implementation: the triggered animation needs to be an "initial position" type, and `model_update_instance` needs to be run on all subobjects, not just turrets.

This should really fix #3123.  I still can't see the destroyed collector, but the Rahu no longer flickers when it spins around.
2021-01-13 13:17:31 -05:00
Goober5000 506ba911d0 Merge pull request #3137 from Goober5000/tech_room_instance
properly use model instances for tech room and briefing popups
2021-01-13 11:03:25 -05:00
z64555 f44cfa06c8 Adds more safety checks for PLR and CSG reading for the HUD_config structure.
* Adds a #define for the HC_color array size
* Doxy's the HUD_config struct
2021-01-12 23:12:20 -06:00
Goober5000 eeb6f5b091 properly use model instances for tech room and briefing popups
These two situations mostly relied on the obsolete model code which didn't include model instances.  Data for submodel positions and for whether a submodel is blown off are now stored exclusively in model instances, not the model itself.

This fixes #3124.
2021-01-12 23:15:37 -05:00
Fabian Woltermann 18cb07dc72 Merge pull request #3134 from EatThePath/tube-light-attenuation-recalc
Properly recalculate tube light attenuation
2021-01-11 20:28:19 +01:00
JohnAFernandez 3a4df0d89a Send them to Github instead of Mantis 2021-01-11 14:06:03 -05:00
JohnAFernandez d33f9db1f0 Move Standalone Running statement to after the init of Debug Statements 2021-01-11 14:05:01 -05:00
JohnAFernandez 75b26ef94b Fix unfocused multi interpolation inaccuracies (#3129)
Remove One Source of Client and Server having Different Timing

Multiplayer *must not* have its time affected by being in the background, because their clocks will come out of sync and movement from an out of focus multiplayer instance will appear to move in slow motion.  This fixes the timing discrepancy by only doing os_sleep when unfocused when in single player.
2021-01-11 14:04:23 -05:00
JohnAFernandez 398f4d9053 Remove Unused ClientDamage Commandline Option (#3132)
This option was likely part of an attempt to fix multi that never went anywhere. We now have rollback, which is on by default.
2021-01-11 14:02:52 -05:00
David Gibson 069947e397 Added a recalculation of tube light attenuation in fragment shader after proper distance is determined. fixes slash beam and penetration lighting issues 2021-01-11 11:55:45 -06:00
Fabian Woltermann 580d67eca7 Merge pull request #3133 from Baezon/slow-weapon-collide-fix
Fix collision culling for slow/accelerating weapons
2021-01-11 09:15:53 +01:00
Baezon 4bf93e08df fix collision culling for slow weapons 2021-01-11 00:45:42 -05:00
Fabian Woltermann 6c475130d1 Merge pull request #3126 from The-E/fix/ambient_light_in_lab
When setting the ambient factor in the lab, recalculate ambient lighting
2021-01-10 20:11:13 +01:00
Fabian Woltermann 6f0dec4169 When setting the ambient factor in the lab, recalculate ambient lighting 2021-01-10 19:44:24 +01:00
Goober5000 3b99402a0a Merge pull request #3121 from Goober5000/background_warning
make FRED validate all backgrounds, not just the active one
2021-01-10 09:21:45 -05:00
Fabian Woltermann 6c6ade116f Merge pull request #3120 from Goober5000/fix_3101
fix 3101
2021-01-10 12:43:47 +01:00
Fabian Woltermann 4f6c834587 Merge pull request #3122 from Baezon/glowpoint-timing-fix
Fix a bug with glowpoint timing
2021-01-10 12:42:42 +01:00
Baezon c486843e5f fix a bug with glowpoint timing 2021-01-10 03:11:25 -05:00
Goober5000 ec93ac4c0e fix 3101
Always update the ship class and loadout information in a ship's parse object, even if it is present at mission start.
2021-01-10 01:53:14 -05:00
Goober5000 2307d05086 make FRED validate all backgrounds, not just the active one
The background validation checks are somewhat convoluted, and misleading with multiple backgrounds, so this PR disables the standard main-background check if FRED is running.  It then adds a new FRED-specific background check that covers all backgrounds.

Additionally, this PR fixes a bug in an error message in `stars_get_first_valid_background`.

Fixes #3116.
2021-01-10 01:48:43 -05:00
Goober5000 d3d48ee6fa Merge pull request #3093 from Baezon/script-target-bracket-fix
Fix a crash with scripted targeting brackets
2021-01-08 18:13:44 -05:00
Baezon ac7bdbf269 fix bug in scripted targeting brackets 2021-01-08 17:30:28 -05:00
Goober5000 ddf00588d6 Merge pull request #3076 from Goober5000/hash_stuff
preprocess alt names before mission start
2021-01-08 16:03:10 -05:00
Goober5000 365ba2029e remove temporary function 2021-01-08 09:53:11 -05:00
Goober5000 02cdb106ba convert number parsing to use atoi and strtof
One small detail that was overlooked in PR #3021... KeldorKatarn's old code used `strtod` while the new code used `stuff_float`.  This wouldn't be a problem except that a couple MVP models use annoyingly formatted floats like 8.9e-08.  So I decided to convert `stuff_float` to use `strtof` and do some more upgrades while I was at it.
2021-01-08 09:25:25 -05:00
m!m 85a2a8f11e Merge pull request #3092 from Goober5000/strtof_patch
interim patch for get_user_vec3d_value
2021-01-08 10:47:42 +01:00
Goober5000 e76fdea8b9 interim patch for get_user_vec3d_value
As described in #3079, the old parsing of fvec and uvec used strtod and some POFs rely on this format.  This is a quickfix that uses the new parsing method for only `get_user_vec3d_value`.
2021-01-07 18:08:27 -05:00
Goober5000 726ce953c7 Merge pull request #3089 from Goober5000/fix_submodel_debris
de-parent live debris
2021-01-07 15:24:49 -05:00
JohnAFernandez a545a4ec27 Merge pull request #3087 from Baezon/lock-restriction-safety
Safety for lock restriction handling
2021-01-07 15:01:31 -05:00
Fabian Woltermann fc0662a9c4 Merge pull request #3080 from JohnAFernandez/Vectorize-Tech-Lists
Vectorize tech lists
2021-01-07 15:16:09 +01:00
JohnAFernandez e5685ded86 Keep the lists from being cleared early by removing unneeded the loops. 2021-01-07 00:33:21 -05:00
JohnAFernandez 226cbf1204 The true fix, check the correct value 2021-01-07 00:32:52 -05:00
Goober5000 043466309a de-parent live debris
It appears that live debris is not supposed to have a parent submodel; see the retail NTF Boadicea.  This removes the parent from any live debris that might have it.

This should fix #3078.
2021-01-07 00:02:49 -05:00
Baezon 766624600d update name 2021-01-06 18:04:59 -05:00
Baezon dab9a41f45 remove redundant check 2021-01-06 17:45:32 -05:00
m!m 51d8ab13d8 Merge pull request #3088 from EatThePath/fix-empty-secondaries-locking
off-by-one fix in early exit update_aspect_lock_information()
2021-01-06 23:25:53 +01:00
Baezon b93d30e12b unused variable 2021-01-06 14:46:44 -05:00
David Gibson 945db25578 corrected off-by-one issue in the early exit condition of update_aspect_lock_information() 2021-01-06 13:46:05 -06:00
Baezon 67de007ecb lock restrictions safety 2021-01-06 14:28:27 -05:00
JohnAFernandez e9a9b3b978 Merge pull request #3085 from Baezon/docking-collision-bugfix
Safety for check_for_docking_collision
2021-01-06 14:03:00 -05:00
Baezon e10522a2c7 safety for check_for_docking_collision 2021-01-06 13:18:27 -05:00
JohnAFernandez 9f33b432fc Simply this check 2021-01-05 00:07:07 -05:00
JohnAFernandez 7a0578a797 Ok CI, I'll use nullptr 2021-01-04 22:14:36 -05:00
JohnAFernandez b81825326c Signed Vs Unsigned
AKA C'Mon CI!
2021-01-03 21:54:31 -05:00
JohnAFernandez b8c2c975c0 Change to a pointer
So that we can release bitmaps and animations properly.
2021-01-03 21:36:50 -05:00
JohnAFernandez dc0272e664 Fixes Part 1 2021-01-03 20:56:30 -05:00
JohnAFernandez 3e329d64dd Check the correct value in the animation code 2021-01-03 15:15:51 -05:00
JohnAFernandez 882ac2b1a1 Possibly Fix Memory Corruption Issue
Remove Unused Var
2021-01-03 15:14:11 -05:00
Goober5000 b3153df6be preprocess alt names before mission start
For compatibility purposes some mods want alt names to truncate at the hash symbol. But we can't actually do that at mission load,
since we have to save them again in FRED. So this commit processes the names just before the mission starts.

To further complicate things, some mods actually want the hash to be displayed. So this commit introduces the double-hash as an escape sequence for a single hash.
2021-01-02 14:31:59 -05:00
z64555 bc8e16b37b Address change requst. 2021-01-01 22:41:43 -06:00
z64555 79e4c9b4e3 Satisfy change requests 2021-01-01 19:14:20 -06:00
z64555 70969c4475 Address requests by Goober5000 2020-12-31 15:39:21 -06:00
z64555 ecbb6a12f8 update feature to use eval_ship() instead of sexp_get_ship_from_node() 2020-12-31 14:58:33 -06:00
z64555 218059ffbb Merge branch 'add_ai_seconds_to_waypoint_sexp' of https://github.com/tcrayford/fs2open.github.com into feature/time_to_goal 2020-12-31 13:15:35 -06:00
Baezon c65ae50b81 version 1 of generic debris enhancements 2020-12-17 01:58:00 -05:00
Baezon 95de0c6833 version 1 of ai multilock 2020-12-14 20:41:06 -05:00
Baezon ab2c08392e in-progress 2020-12-14 04:29:55 -05:00
z64555 89a2c4dbcb Missed another break. 2020-12-12 14:47:15 -06:00
z64555 2cd557e483 Expletives and default breaks. 2020-12-12 14:20:07 -06:00
z64555 e5df64ab75 Address uninitialized variable issue. 2020-12-12 12:20:54 -06:00
z64555 52b0b19d11 Update qtFred sexp_tree::get_listing_opf_keypress 2020-12-12 11:39:47 -06:00
z64555 36a2355e86 Address exceedingly frivolous signed/unsigned mismatch errors. 2020-12-11 17:44:45 -06:00
z64555 351e8e0c44 Address short/int size mismatches. 2020-12-11 15:59:31 -06:00
z64555 91e0d8f578 QoL: Highlight/select the found key, be it primary or secondary, should the search mode find it. 2020-12-11 12:41:46 -06:00
z64555 f8f26e3b23 Fix bug where search mode wouldn't detect joy buttons correclty.
* Fix bug where joy hats were ignored.
2020-12-11 12:41:46 -06:00
z64555 873a3c3442 Fix bug with displaying joy button text
* Fix a number of warnings
2020-12-11 12:41:46 -06:00
z64555 1318b814d3 Fix out-of-bounds error due to axis controls index. 2020-12-11 12:41:45 -06:00
z64555 4c8f5f789c Grey out empty/unbound items
* Joy axis bindings now use the same color logic as the keys and buttons
2020-12-11 12:41:45 -06:00
z64555 b9b922b235 Fix bug where int conflict wasn't incremented for unselected items.
* Fix color highlighting of mouse-over lines
* Fix color highlighting of selected bindings
* Fix bug when trying to select an item while the selected line is an axis control
* Allow user to select an empty item
* Expand hitbox of items so players aren't required to click exactly on the text to select it.
2020-12-11 12:41:45 -06:00
z64555 716b4a3205 Moves the listbox draw function out of do_frame()
* Adjusts listbox positioning and widths of the binding columns for better display.
* Adds DCF tools to adjust the text positioning in the listbox
2020-12-11 12:41:44 -06:00
z64555 3c592b799f Fix bug where the "disallowed key" popup would spam you, blocking you from doing a meaningful bind. 2020-12-11 12:41:44 -06:00
z64555 c8c8a8d896 Fix bug where unbound items were flagged as conflicted.
* Fix bug where Cc_lines was accessed after being cleared. (Incorrectly assumed control_config_cancel_exit() was an exit point)
2020-12-11 12:41:43 -06:00
z64555 12b19a32bd Fix bug where unbound joy buttons would persist as a valid binding. 2020-12-11 12:41:43 -06:00
z64555 40e114351c Miscellaneous fixes to allow building.
* declare CCB before CC_bind.
* update various functions to use new binding aggregate classes.
2020-12-11 12:41:43 -06:00
z64555 704c600ef0 update control_config_clear() 2020-12-11 12:41:42 -06:00
z64555 5dde26fc33 Update check_control_used() to use primary and secondary. 2020-12-11 12:41:42 -06:00
z64555 cb5f80b0d5 Complete refactor of control_config_do_frame()
* Add textify method to CC_bind
* Replace string printing of key and joy bindings with primary and secondary bindings.
2020-12-11 12:41:42 -06:00
z64555 32636968bd Refactor browse mode in control_config_do_frame()
* Allow joy button presses to dismiss help overlay while in browse mode
* Refactor selected item cycling
2020-12-11 12:41:41 -06:00
z64555 e546a75c6b Fix possible bug where joy btn was ignored in bind mode
* Refactor search mode in control_config_do_frame()
* Dismiss help overlay in search mode when joy button is pressed
* Fix possible bug where nav buttons were not reset in search mode
2020-12-11 12:41:41 -06:00
z64555 9b0aab3f82 replace CCI::joy_id and ::key_id with ::primary and ::secondary (through inheritance of CCB)
* Add convenience methods to CCB
* Convert CC_bind into a class and define convenience methods
* Set underlying type of enum CID to short
* controlconfigdefaults.tbl: Should the CCI be disabled by an override, clear its binding.
* Control config menu: Should the help overlay be active during bind mode, dismiss it, don't bind anything, and stay in bind mode (fixes inconstant behavior)
* Refactor bind mode handling in control_config_do_frame()
2020-12-11 12:41:40 -06:00
z64555 7f2baec387 Remove Control_config::key_default and ::joy_default, redirect calls to the default presets 2020-12-11 12:41:40 -06:00
z64555 392148f84b Fix crash in unit tests due to uninitialized Control_config vector. 2020-12-11 12:33:45 -06:00
z64555 577ae95026 Use ints instead of size_t because CI said so. 2020-12-11 07:40:42 -06:00
z64555 968d76431f Missing an amp. 2020-12-11 07:40:42 -06:00
z64555 c2408839d1 Fix out of bounds error due to dynamic containers cleared at wrong spot. 2020-12-11 07:40:41 -06:00
z64555 a03af2e4a9 Re-enables the undo feature in the controls config menu. 2020-12-11 07:40:41 -06:00
z64555 aec7589b94 Tweak Undo_item::save to correctly save a reference as a pointer
* Remove two uncessary Assets.  operator new should throw an exception should it fail.
* Move template functions into .h.  This resolves instancing problems when trying to define them in a .cpp
* Add Undo_system::empty() and ::empty_redo() for checking if an ::undo() or ::redo() is possible.
2020-12-11 07:40:41 -06:00
z64555 e1974d1b57 Fix potential issue where Undo_stacks delete tracked items when going out of scope, even after the items were passed onto an Undo_system 2020-12-11 07:40:40 -06:00
z64555 bc7809de43 Undo_system::save_stack() now ignores empty stacks passed to it. No need to check for stack size before saving.
* Implement Undo_stack::size()
* Spellcheck in undosys.h
2020-12-11 07:40:40 -06:00
z64555 f23a72e228 Minor changes 2020-12-11 07:40:40 -06:00
z64555 45a45a4eff Remove licensing. 2020-12-11 07:40:39 -06:00
z64555 7e9ce1c9f7 Initial draft of the instruction documentation
Fix two typos

Adds Undo_system::clear()

Whoops! Can't just simply clear the stacks,gotta clean stuff off the heap first.
2020-12-11 07:40:39 -06:00
z64555 dce37d529c Adds ability to save a stack of undo operations as a single undo-op within the system 2020-12-11 07:40:39 -06:00
z64555 f528b3caa5 Changes the system so that the undo() and redo() functions return references to the changed item and its container (if it was specified at launch). This should allow client code to quickly find and access it on its end by comparing pointer values.
Since the pair is returned instead of the size of the undo/redo stacks, stack size information has been moved to their own getter functions.
2020-12-11 07:40:38 -06:00
z64555 492320f8d3 z64555's Undo system! This is a generic undo system, so you can save any single item type (not C arrays) and do undo/redo stuff on them. 2020-12-11 07:40:38 -06:00
z64555 636b4b12e4 Vectorize control_config::Conflicts 2020-12-11 07:40:14 -06:00
z64555 93c96b8943 Re-enable display of current selected preset. 2020-12-11 07:40:14 -06:00
z64555 d1f94c7b92 Fix overwrite check.
Add check for cfile open correctly.
2020-12-11 07:40:13 -06:00
z64555 74ffcb2db8 Print "NONE" instead of "-1" For unbound keys. 2020-12-11 07:40:13 -06:00
z64555 c7112fd897 Adds function to write controlconfigdefaults.tbl using the default preset at time of call.
* Adds DC function 'write_ccd' to write the .tbl
* Adds DC function 'load_ccd' to reload the .tbl
2020-12-11 07:40:13 -06:00
z64555 1bb9ed8832 Remove unused variable for catch clause. 2020-12-11 07:40:13 -06:00
z64555 23f85da586 Move typedef after the declaration of the struct it uses. 2020-12-11 07:40:12 -06:00
z64555 f163f56c10 Cleanup controlsconfig.h and refactor some loops. 2020-12-11 07:40:12 -06:00
z64555 9c03e8c069 Remove dead comment. 2020-12-11 07:40:12 -06:00
z64555 92a76c05ee Adds ability for mod devs to change the naming of a control as it shows up in the config menu.
* Presets start from a clean slate, while Overrides inherite from hardcode defaults
2020-12-11 07:40:11 -06:00
z64555 730ab835a8 Add #ControlConfigPreset section to controlconfigdefault.tbl and allow multiple sections in the .tbl
* This is a section that only configures the bindings for a preset.  Allowing mod devs to add presets instead of just the overrides
* Added ability to resume parsing should a Binding not be found
2020-12-11 07:40:11 -06:00
z64555 ef89a4aa38 Refactor and cleanup control_config_common_load_overrides.
* Mod devs now have the option to override hardcoded defaults
2020-12-11 07:40:11 -06:00
z64555 f9474cf773 Refactor defaults.
* Hardcoded default bindings are now a preset
* rename controls_config_init_bindings() to control_config_common_init_bindings() for consistancy
2020-12-11 07:40:10 -06:00
z64555 96382b47e2 Initial work on presets and default keybinds. Defaults will be moved into a preset instead of lingering in the bindings vector, this may cause issues with training messages that reference controls by default keybinds. 2020-12-11 07:40:10 -06:00
z64555 99dfdf07a2 Refactor control_config_list_prepare()
Default Disable Non-retail controls
Expand CC_lines buffer to include NUM_JOY_AXIS_ACTIONS
2020-12-11 07:39:30 -06:00
z64555 62fa76d65e Fix wrong reference to array size.
Init Cc_lines, which is now dynamic
De-init Cc_lines and Control_config_backup when closing the menu.
2020-12-11 07:39:30 -06:00
z64555 1a482cab4a Remove Joy_table declaration for later PR.. 2020-12-11 07:39:30 -06:00
z64555 ec61af7e1c Revert obliteration of magic number. 2020-12-11 07:39:29 -06:00
z64555 d8d4e9ed2c Disable Presets and Undo capabilities. Only reset_all was spared.
* Revert Joy_axis_action_index changes.  Feature to be added later
* Strip out most of the preset and undo capability.  Only the backup ability survived.
2020-12-11 07:39:29 -06:00
z64555 38df849e6e Change Control_config array to an SCP_vector
* Hardcoded bindings are done at run-time instead of assignment
* Created a map that should retain backward compatibility with controlconfigdefaults.tbl and playerfiles, since a reorganization of the controls in the code is planned and would break compatibility.
2020-12-11 07:39:28 -06:00
Baezon d06eedf13c testing 2020-12-10 18:49:05 -05:00
Baezon a3d3be11fb initial testing version 2020-12-10 18:41:36 -05:00
Baezon be76cd727a implement turret-forced-target 2020-12-08 00:07:23 -05:00
Baezon 641cf48073 implement damage incidence angle 2020-12-01 12:37:22 -05:00
Baezon 2dbaf53e49 no more travis wooo 2020-11-20 14:10:27 -05:00
Baezon 849b4c57b6 no warning 2020-11-20 12:03:34 -05:00
Baezon de0933e1b9 expose targeting sizes 2020-11-20 12:03:34 -05:00
Baezon 8c9a6d049e use armor types for beam-weapon damage 2020-11-06 23:40:02 -05:00
Baezon 799fa27d36 clarity comment 2020-10-02 23:14:45 -04:00
Baezon 01cd5a34b9 travis 2020-10-02 12:04:45 -04:00
Baezon 9b3905a4bb v1 2020-10-02 02:53:13 -04:00
Shivansps 1239ec47e3 Smart pointers and disabled some messages
Added smart pointers to bsp_in, bsp_out, sldc_tree and slc2_tree as requested.

I also changed the #error to #pragma message in a attempt to remove the false positive error.

Also did minor code indent fixes-
2020-08-30 13:45:43 -03:00
Shivansps eb1814e303 SLC2 and POF version 2118 support
Changed SLDC system to SLC2, this replaced the char at the beginning of the node for an int in order for the tree to be aligned.
Added BSP_Defpoints data alignment and SLDC to SLC2 conversion for pof version < 2118.
2020-08-27 20:10:29 -03:00
Baezon b4ec1b32ba better subtype determiner 2020-08-05 01:54:47 -04:00
Baezon 27544e781a Revert "no homing when out of range"
This reverts commit eebfb7eadb.
2020-07-23 21:12:51 -04:00
Baezon eebfb7eadb no homing when out of range 2020-07-23 12:30:28 -04:00
Baezon e6938bd14d verison 1 2020-07-22 23:48:53 -04:00
Tom Crayford 6ce29b5c6a add seconds-to-goal
returns the number of seconds between a designated ship and its goal.
Uses `ship_return_seconds_to_goal`, but only returns 0 in the invalid
cases.
2019-09-23 11:12:18 +01:00
Tom Crayford bc99331d47 refactor ship_return_time_to_goal to be more general 2019-09-22 22:00:13 +01:00
650 changed files with 63189 additions and 19293 deletions

No files matched your search

+4
View File
@@ -6,3 +6,7 @@ code/executor/ @asarium
code/scpui/ @asarium
code/scripting/ @asarium
code/controlconfig/ @z64555
code/model/modelanimation*.* @bmagnu
+3 -1
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-a8ca321
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -29,6 +29,8 @@ jobs:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
+117 -27
View File
@@ -16,6 +16,17 @@ jobs:
- name: Create Release
id: create_release
uses: actions/create-release@v1
# Creates a release package page on github
# create_release.inputs: (notable inputs)
# allowUpdates=false if true, update an existing release if it exists
# artifactErrorsFailBuild=false if true, fails the build should artifact read/write errors occur
# artifacts optional set of paths to artifacts to upload to the release. comma delimited.
# removeArtifacts=false if true, remove existing artifacts
# replaceArtifacts=false if true, replace/overwrite existing artifacts
# create_release.outputs:
# id id of the created release
# html_url HTML URL of the release
# upload_url FTP URL of the release where assets are uploaded
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
@@ -28,36 +39,77 @@ jobs:
echo -n "${{ steps.create_release.outputs.upload_url }}" > upload_url
- name: Persist upload URL
uses: actions/upload-artifact@v2
# Upload the url file for use with other runners
# upload-artifact.inputs:
# if-no-files-found=warn What to do if path fails to find any files.
# warn Display a warning but do not fail the action
# error Display an error and fail the action
# ignore No display, No fail
# retention-days=0 Days to keep the artifact.
# 0 Use default retention policy of the repo
# 1~90 Min 1, Max 90 days to keep the artifact unless changed by repo settings page
with:
name: upload_url
path: ${{ github.workspace }}/upload_url
name: upload_url # name of artifact
path: ${{ github.workspace }}/upload_url # source location of artifact to upload
build_linux:
strategy:
matrix:
# Run this job for each configuration
# The current config running is accesible with `matrix.configuration`
configuration: [FastDebug, Release]
name: Linux
needs: create_release
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-a8ca321
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
# cache the Qt directory so we don't have to reinstall it every time
# cache.inputs:
# path - A list of files, directories, and wildcard patterns to cache and restore. See @actions/glob for supported patterns.
# key - An explicit key for restoring and saving the cache
# restore-keys - An ordered list of keys to use for restoring the cache if no cache hit occurred for key
# cache.outputs:
# cache-hit true when an exact match was found for the key, false otherwise.
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
# installs Qt in the action workflow
# install-qt-action.inputs:
# version desired qt version to install
# host Host platform of Qt, default to platform used by runs-on
# target target platform of Qt, default to desktop
# arch target architecture of Qt, only used for windows or android builds
# dir root dir Qt will be installed to
# install-deps if true, auto-install dependencies on linux. Default true
# modules whitespace delimited list string of additional addon modules to install
# archives whitespace delimited list string of Qt archives to install
# cached if true, Don't download Qt but set ENVARs; use with cache.outputs.cache-hit
# setup-python Set to false to skip using setup-python to find/download a valid python version
# set-env if true, set ENVARs; default = false
# aqtversion version of aqtinstall to use; default = 2.0.0
# py7zrversion version of py7zr to use; default = 0.16.1
# extra additional arguments to pass to aqinstall
# ENVARS set:
# Qt5_DIR / Qt6_DIR
# Qt bin dir appended to PATH
# QT_PLUGIN_PATH, QML2_IMPORT_PATH, PKG_CONFIG_PATH, LD_LIBRARY_PATH
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
name: Checkout
with:
submodules: true
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
@@ -95,38 +147,52 @@ jobs:
name: Checkout
with:
submodules: true
fetch-depth: '0'
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
- name: Download upload URL
uses: actions/download-artifact@v1
# Downloads and extracts uploaded artifact by name
# github_token default ${{secrets.GITHUB_TOKEN}}
# name name of artifact to download
# latest Download latest artifact (default true)
# path Where to save the artifact, (default extract_here)
# repo Source repo of artifact (default ${{github.repository}})
with:
name: upload_url
path: .
- name: Extract upload URL
# Extract the URL from file and stuff it into a shell variable
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- name: Download Release builds
uses: actions/download-artifact@v1
# Grab the release builds
uses: actions/download-artifact@v2
with:
name: linux-Release
path: builds
- name: Download FastDebug builds
# Grab the debug builds
uses: actions/download-artifact@v2
with:
name: linux-FastDebug
path: builds
- name: Create Distribution package
# Zip both builds together
id: generate_package
working-directory: ./builds
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Linux
- name: Upload result package
uses: actions/upload-release-asset@v1
# Stash the result to artifact filespace
uses: actions/upload-artifact@v2
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
- name: Publish result package
# publish the zipped result
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.extractUploadUrl.outputs.upload_url }}
asset_path: ${{ steps.generate_package.outputs.package_path }}
asset_name: ${{ steps.generate_package.outputs.package_name }}
asset_content_type: ${{ steps.generate_package.outputs.package_mime }}
files: ${{ steps.generate_package.outputs.package_path }}
build_windows:
strategy:
@@ -139,16 +205,19 @@ jobs:
runs-on: windows-2019
steps:
- uses: actions/checkout@v1
# Checkout repo
name: Checkout
with:
submodules: true
- name: Cache Qt
# Cache Qt
id: cache-qt-win
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-${{ matrix.arch }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt (32 bit)
# Install Qt 32bit if matrix.arch == Win32
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'Win32' }}
with:
@@ -158,6 +227,7 @@ jobs:
cached: ${{ steps.cache-qt-win.outputs.cache-hit }}
aqtversion: ==0.8
- name: Install Qt (64 bit)
# Install Qt 64bit if matrix.arch == x64
uses: jurplel/install-qt-action@v2
if: ${{ matrix.arch == 'x64' }}
with:
@@ -202,39 +272,47 @@ jobs:
with:
name: windows-${{ matrix.configuration }}-${{ matrix.arch }}-${{ matrix.simd }}
path: ${{ github.workspace }}/build/install/*
windows_zip:
name: Build Windows distribution zip
needs: build_windows
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/sftp_upload:sha-748b19d
strategy:
fail-fast: false # Run the other jobs in the matrix instead of failing them
matrix:
arch: [Win32, x64]
simd: [SSE2, AVX]
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: '0'
- name: Download upload URL
uses: actions/download-artifact@v1
with:
name: upload_url
path: .
- name: Extract upload URL
id: extractUploadUrl
run: echo "::set-output name=upload_url::$(cat upload_url)"
- name: Download Release builds
uses: actions/download-artifact@v1
uses: actions/download-artifact@v2
with:
name: windows-Release-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Download FastDebug builds
uses: actions/download-artifact@v2
with:
name: windows-FastDebug-${{ matrix.arch }}-${{ matrix.simd }}
path: builds
- name: Create Distribution package
id: generate_package
working-directory: ./builds
@@ -243,21 +321,33 @@ jobs:
ARCH: ${{ matrix.arch }}
SIMD: ${{ matrix.simd }}
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Windows
- name: Upload result package
uses: actions/upload-release-asset@v1
uses: actions/upload-artifact@v2
with:
name: ${{ steps.generate_package.outputs.package_name }}
path: ${{ steps.generate_package.outputs.package_path }}
- name: Upload debug package
uses: actions/upload-artifact@v2
with:
name: ${{ steps.generate_package.outputs.debug_name }}
path: ${{ steps.generate_package.outputs.debug_path }}
- name: Publish packages
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.extractUploadUrl.outputs.upload_url }}
asset_path: ${{ steps.generate_package.outputs.package_path }}
asset_name: ${{ steps.generate_package.outputs.package_name }}
asset_content_type: ${{ steps.generate_package.outputs.package_mime }}
- name: Upload debug symbols
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.extractUploadUrl.outputs.upload_url }}
asset_path: ${{ steps.generate_package.outputs.debug_path }}
asset_name: ${{ steps.generate_package.outputs.debug_name }}
asset_content_type: ${{ steps.generate_package.outputs.debug_mime }}
files: |
${{ steps.generate_package.outputs.package_path }}
${{ steps.generate_package.outputs.debug_path }}
post_build:
name: Post builds to Nebula and Forum
needs: [linux_zip, windows_zip]
uses: ./.github/workflows/post-build-release.yaml
with:
linux_result: ${{ needs.build_linux.result }}
windows_result: ${{ needs.build_windows.result }}
releaseTag: ${{ github.ref_name }}
+53
View File
@@ -0,0 +1,53 @@
name: Publish Standalone docker image
on:
push:
tags:
- 'nightly_*'
- 'release_*'
jobs:
build_images:
if: github.repository == 'scp-fs2open/fs2open.github.com'
strategy:
matrix:
configuration: [FastDebug, Release]
include:
- configuration: FastDebug
tag_suffix: -debug
- configuration: Release
tag_suffix: ""
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v1
with:
images: ghcr.io/scp-fs2open/standalone_server
tag-latest: false
- name: Login to GitHub Docker Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./docker/standalone/Dockerfile
push: true
tags: ${{ steps.docker_meta.outputs.tags }}${{ matrix.tag_suffix }}
labels: ${{ steps.docker_meta.outputs.labels }}
build-args: |
build_type=${{ matrix.configuration }}
+3 -1
View File
@@ -15,7 +15,7 @@ jobs:
configuration: [FastDebug, Release]
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-a8ca321
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -29,6 +29,8 @@ jobs:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
+62
View File
@@ -0,0 +1,62 @@
name: Build caches for master
on:
push:
branches:
- master
env:
QT_VERSION: 5.12.9
jobs:
build_linux:
strategy:
matrix:
configuration: [Debug, Release]
compiler: [gcc-5, gcc-10]
cmake_options: [""]
include:
# Also include configurations that check if the code compiles without the graphics backends
- configuration: Debug
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
- configuration: Release
compiler: gcc-10
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
uses: actions/cache@v1
with:
path: ${{ github.workspace }}/../Qt
key: ${{ runner.os }}-QtCache-${{ env.QT_VERSION }}
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
COMPILER: ${{ matrix.compiler }}
JOB_CMAKE_OPTIONS: ${{ matrix.cmake_options }}
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
- name: Compile
working-directory: ./build
run: LD_LIBRARY_PATH=$Qt5_DIR/lib:$LD_LIBRARY_PATH ninja -k 20 all
+64
View File
@@ -0,0 +1,64 @@
name: Post Release builds
on:
workflow_call:
# Trigger when called by other workflows
inputs:
linux_result: # job.result; either success, failure, canceled or skipped
required: true
type: boolean
windows_result: # job.result
required: true
type: boolean
releaseTag:
required: true
type: string
workflow_dispatch:
# Trigger manually from Github
inputs:
releaseTag:
description: Release Tag
required: true
type: string
env:
GITHUB_REPO: ${{ github.repository }} # repo this workflow was called from
INDIEGAMES_USER: ${{ secrets.INDIEGAMES_USER }}
INDIEGAMES_SSHPASS: ${{ secrets.INDIEGAMES_PASSWORD }}
NEBULA_USER: ${{ secrets.NEBULA_USER }}
NEBULA_PASSWORD: ${{ secrets.NEBULA_PASSWORD }}
HLP_API: ${{ secrets.HLP_API }}
HLP_KEY: ${{ secrets.HLP_KEY }}
RELEASE_TAG: ${{ github.event.inputs.releaseTag }}
jobs:
post_builds:
name: Post builds on Nebula and the forums
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: '0'
- name: Install Python dependencies
run: pip install -r ci/post/requirements.txt
- name: Post Builds (Auto trigger)
if: ${{ github.event_name == 'workflow_call' }}
env:
LINUX_RESULT: ${{ github.event.inputs.linux_result }}
WINDOWS_RESULT: ${{ github.event.inputs.windows_result }}
run: python ci/post/main.py release
- name: Post Builds (Manual trigger)
if: ${{ github.event_name == 'workflow_dispatch' }}
# assume user knows what they're doing...
env:
LINUX_RESULT: success
WINDOWS_RESULT: success
run: |
echo "releaseTag= ${{ github.event.inputs.releaseTag }}"
echo "repository= ${{ github.repository }}"
python ci/post/main.py release
@@ -1,48 +0,0 @@
name: Publish Standalone docker image
on:
push:
tags:
- '*'
jobs:
build_images:
strategy:
matrix:
configuration: [FastDebug, Release]
include:
- configuration: FastDebug
latest_tag: latest_debug
nightly_tag: nightly_debug
release_tag: release_debug
- configuration: Release
latest_tag: latest
nightly_tag: nightly
release_tag: release
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
- name: Docker login
run: echo ${{ secrets.DOCKER_ACCESSTOKEN }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
- name: Docker build
run: docker build --build-arg build_type=${{ matrix.configuration }} -f docker/standalone/Dockerfile -t ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }} .
- name: Push latest tag
run: |
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }}
- name: Push nightly tag
if: contains(github.ref, 'refs/tags/nightly_')
run: |
docker tag ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }} ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.nightly_tag }}
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.nightly_tag }}
- name: Push release tag
if: contains(github.ref, 'refs/tags/release_')
run: |
docker tag ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.latest_tag }} ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.release_tag }}
docker push ${{ secrets.DOCKER_REPOSITORY }}:${{ matrix.release_tag }}
@@ -8,7 +8,6 @@ env:
jobs:
build_linux:
strategy:
fail-fast: false
matrix:
configuration: [Debug, Release]
compiler: [gcc-5, gcc-10, clang-9]
@@ -23,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-e977d36
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -38,12 +37,18 @@ jobs:
dir: ${{ github.workspace }}/..
cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
setup-python: 'false'
aqtversion: ==1.1.3
- uses: actions/checkout@v1
name: Checkout
with:
submodules: true
fetch-depth: 0
- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ matrix.configuration }}-${{ matrix.compiler }}
- name: Configure CMake
env:
CONFIGURATION: ${{ matrix.configuration }}
+228
View File
@@ -0,0 +1,228 @@
import re # regex module
from ftplib import FTP, error_perm
from itertools import groupby
from typing import List, Tuple, Dict
import requests # HTTP requests module
from util import retry_multi, GLOBAL_TIMEOUT # from util.py
class ReleaseFile:
"""! Class representing a Released file on Nebula
`name`: str
Mod (or build) name,
`url`: str
Primary host URL,
`group`: str
Mod group string,
`subgroup`: str
Mod subgroup string,
`mirrors`: List[str]
List of URL's of FTP mirrors
"""
def __init__(self, name, url, group, subgroup=None, mirrors=None):
if mirrors is None:
mirrors = []
self.mirrors = mirrors
self.subgroup = subgroup
self.group = group
self.url = url
self.name = name
self.base_url = "/".join(url.split('/')[0:-1]) + "/"
self.filename = url.split('/')[-1]
# A list of tuples of (filename, hash)
self.content_hashes = None
self.hash = None
self.size = 0
def __repr__(self):
return repr((self.name))
class SourceFile:
"""! Class represeting a source file
`name`: str
File name,
`url`: str
FTP URL,
`group`
<unknown>
@details More details
"""
def __init__(self, name, url, group):
self.group = group
self.url = url
self.name = name
class FileGroup:
"""! Represents a file group
`name`: str
Name of this group
`files`: List[ReleaseFile]
List of files within this group
`mainFile`: str
If this FileGroup has a subgroup, `mainFile` is the head of that group
`subFiles`: List[ReleaseFile]
Files within a subgroup
"""
def __init__(self, name, files: List[ReleaseFile]):
self.files = files
self.name = name
if len(files) == 1:
self.mainFile = files[0]
self.subFiles = {}
else:
self.mainFile = None
subFiles = []
for file in files:
# We only have subcategories for Windows where SSE2 is the main group
if file.subgroup == "SSE2":
self.mainFile = file
else:
subFiles.append(file)
self.subFiles = dict(((x[0], next(x[1])) for x in groupby(subFiles, lambda f: f.subgroup)))
def get_release_files(tag_name, config) -> Tuple[List[ReleaseFile], Dict[str, SourceFile]]:
"""! Brief Gets the binary and source files from the Github Release server
@param[in] `tag_name` Git tag of the current release
@param[in] `config` confi metadata set in main.py
@returns `List[ReleaseFile]` List of release files
@returns `Dict[str, SourceFile]` Dictionary of source files
@details Sends an `HTTP GET` request to github using their REST API to retrieve metadata. The files are not
actually downloaded here, just their metadata is gathered and organized in their respective container for later
use.
"""
@retry_multi(5) # retry at most 5 times
def execute_request(path):
"""!
@brief Performs a GET request with the given path. To be used with Github's REST API.
@returns If successful, returns a .JSON object
"""
headers = {
"Accept": "application/vnd.github.v3+json"
}
url = "https://api.github.com" + path
# GET https://api.github.com/<path> Accept: "application/vnd.github.v3+json"
response = requests.get(url, headers=headers, timeout=GLOBAL_TIMEOUT)
response.raise_for_status() # Raise a RequestException if we failed, and trigger retry
return response.json()
build_group_regex = re.compile("fs2_open_.*-builds-([^.-]*)(-([^.]*))?.*") # regex for matching binary .zip's and .7z's
source_file_regex = re.compile("fs2_open_.*-source-([^.]*)?.*") # regex for matching source .zip's and .7z's
# Get the github release metadata of the given tag name
response = execute_request(
"/repos/{}/releases/tags/{}".format(config["github"]["repo"], tag_name))
# Extract the binary and source files from the response["asset"] metadata
binary_files = []
source_files = {}
for asset in response["assets"]:
url = asset["browser_download_url"]
name = asset["name"]
group_match = build_group_regex.match(name)
if group_match is not None:
platform = group_match.group(1)
# x64 is the Visual Studio name but for consistency we need Win64
if platform == "x64":
platform = "Win64"
binary_files.append(ReleaseFile(name, url, platform, group_match.group(3)))
else:
group_match = source_file_regex.match(name)
if group_match is None:
continue
group = group_match.group(1)
source_files[group] = SourceFile(name, url, group)
binary_files.sort(key=lambda ReleaseFile: ReleaseFile.name)
return binary_files, source_files
def get_ftp_files(build_type, tag_name, config) -> List[ReleaseFile] :
"""!
@brief Gets file metadata for nightlies hosted on FTP, as determined by config["ftp"] attributes
@param [in] `build_type` Unknown str
@param [in] `tag_name` Github tag name of the release
@param [in] `config` config metadata set in main.py
"""
tag_regex = re.compile("nightly_(.*)")
build_group_regex = re.compile("nightly_.*-builds-([^.]+).*")
files = []
try:
with FTP(config["ftp"]["host"], config["ftp"]["user"], config["ftp"]["pass"]) as ftp:
# extract version
version_str = tag_regex.match(tag_name).group(1)
# extract filepath w/ version
# then list all ftp hits with that path
path_template = config["ftp"]["path"]
path = path_template.format(type=build_type, version=version_str)
file_entries = list(ftp.mlsd(path, ["type"]))
# get all ftp hits of type file
for entry in file_entries:
if entry[1]["type"] == "file":
files.append(entry[0])
except error_perm:
print("Received permanent FTP error!")
return []
out_data = []
for file in files:
# from the file list, extract only nightly files
file_match = build_group_regex.match(file)
if file_match is None:
print("Ignoring non nightly file '{}'".format(file))
continue
group_match = file_match.group(1)
primary_url = None
mirrors = []
# x64 is the name Visual Studio uses but Win64 works better for us since that gets displayed in the nightly post
if "x64" in group_match:
group_match = group_match.replace("x64", "Win64")
# construct the download URL list for all mirrors. The first listed ftp location is taken as the Primary
for mirror in config["ftp"]["mirrors"]:
download_url = mirror.format(type=build_type, version=version_str, file=file)
if primary_url is None:
primary_url = download_url
else:
mirrors.append(download_url)
# Form the List[ReleaseFile] list with the download URL links
out_data.append(ReleaseFile(file, primary_url, group_match, None, mirrors))
return out_data
+65
View File
@@ -0,0 +1,65 @@
from typing import List
import requests
import semantic_version
from mako.template import Template
from file_list import ReleaseFile
class ForumAPI:
def __init__(self, config):
self.config = config
def create_post(self, title, content, board):
print(self.config["hlp"]["api"])
print(self.config["hlp"]["key"])
if (self.config["hlp"]["api"] == "") or (self.config["hlp"]["key"] == ""):
print("Post failed! No API or API_KEY given!")
return
resp = requests.post(self.config["hlp"]["api"], data={
"api_key": self.config["hlp"]["key"],
"board": str(board),
"subject": title,
"body": content
})
if resp.text != "OK":
print("Post failed! Response: %s" %resp.text)
def post_nightly(self, date, revision, files, log, success):
print("Posting nightly thread...")
title = "Nightly: {} - Revision {}".format(date, revision)
template = Template(filename=self.config["templates"]["nightly"])
rendered = template.render_unicode(**{
"date": date,
"revision": revision,
"files": files,
"log": log,
"success": success
})
print("Creating post...")
self.create_post(title, rendered, self.config["nightly"]["hlp_board"])
def post_release(self, date, version: semantic_version.Version, groups, sources):
print("Posting release thread...")
title = "Release: {}".format(version)
template = Template(
filename=self.config["templates"]["release"].format(major=version.major, minor=version.minor),
module_directory='/tmp/mako_modules')
rendered = template.render_unicode(**{
"date": date,
"version": version,
"groups": groups,
"sources": sources
}).strip("\n")
print("Creating post...")
self.create_post(title, rendered, self.config["release"]["hlp_board"])
+88
View File
@@ -0,0 +1,88 @@
import os
import hashlib
import tarfile
import traceback
import zipfile
from tempfile import NamedTemporaryFile
from zipfile import ZipFile
import requests
import sys
from mako.template import Template
from file_list import ReleaseFile
from util import GLOBAL_TIMEOUT
def _download_file(url, dest_file, session):
print("Downloading " + url)
# NOTE the stream=True parameter
r = session.get(url, stream=True, timeout=GLOBAL_TIMEOUT)
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
dest_file.write(chunk)
dest_file.flush()
def _gen_hash(fileobj, hash_alg):
h = hashlib.new(hash_alg)
while True:
data = fileobj.read(4096)
if not data:
break
h.update(data)
return h.hexdigest()
def get_hashed_file_list(file: ReleaseFile, session: requests.Session = None, hash_alg: str = "sha256"):
if session is None:
session = requests.Session()
with NamedTemporaryFile('w+b', suffix=file.filename) as local_file:
_download_file(file.url, local_file, session)
filename = local_file.name
hash_list = []
local_file.seek(0)
file.hash = _gen_hash(local_file, hash_alg)
file.size = os.stat(filename).st_size
try:
if tarfile.is_tarfile(filename):
with tarfile.open(filename) as archive:
for entry in archive:
if not entry.isfile():
continue
print("Computing hash for " + entry.name)
fileobj = archive.extractfile(entry)
hash_list.append((entry.path, _gen_hash(fileobj, hash_alg)))
elif zipfile.is_zipfile(filename):
with ZipFile(filename) as archive:
for entry in archive.infolist():
# Python 3.6 has is_dir but that version is relatively new so we'll use the "safe" version here
if entry.filename.endswith('/'):
continue
print("Computing hash for " + entry.filename)
with archive.open(entry) as fileobj:
hash_list.append((entry.filename, _gen_hash(fileobj, hash_alg)))
else:
raise NotImplementedError("Unsupported archive type!")
except:
traceback.print_exception(*sys.exc_info())
return
file.content_hashes = hash_list
def render_installer_config(version, groups, config):
template = Template(filename=config["templates"]["installer"], module_directory='/tmp/mako_modules')
return template.render(**{
"version": version,
"groups": groups,
}).strip("\n")
+260
View File
@@ -0,0 +1,260 @@
# Post-build python script
# Uploads build packages to Nebula and creates a forum post on https://www.hard-light.net
# Uses the following environment variables (Set by the github action workflow before execution)
# FSO versioning
# FSO_VERSION_MAJOR
# FSO_VERSION_MINOR
# FSO_VERSION_BUILD
# Credentials into IndieGames file host
# INDIEGAMES_USER:
# INDIEGAMES_SSHPASS:
# Credentials into Nebula Mod Database
# NEBULA_USER:
# NEBULA_PASSWORD:
# Credentials into hard-light.net for forum post
# HLP_API:
# HLP_KEY:
# LINUX_RESULT: bool, if the linux builds were sucessfully uploaded
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
import sys
import os
import re
from subprocess import check_output
from datetime import datetime
from itertools import groupby
import semantic_version
# local .py files
import file_list
import installer
import nebula
import forum
# Compile regexes for extracting version components
MAJOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MAJOR (\d+)\)")
MINOR_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_MINOR (\d+)\)")
BUILD_VERSION_PATTERN = re.compile("set_if_not_defined\(FSO_VERSION_BUILD (\d+)\)")
LOG_FORMAT = """
------------------------------------------------------------------------%n
commit %h%nAuthor: %an <%ad>%n
Commit: %cn <%cd>%n%n %s
"""
DATEFORMAT_VERSION = "%Y%m%d"
DATEFORMAT_FORUM = "%d %B %Y"
def _match_version_number(text, regex):
"""! Extracts the version component represented by `regex` from `text`
@param [in] `text` Filename with version string 'MAJOR.MINOR.BUILD'
@param [in] `regex` Regex pattern of component to look for
@return The version component as integer
"""
match = regex.search(text)
return int(match.group(1))
def get_source_version(date_version: datetime, tag_name: str) -> semantic_version.Version:
"""! Retrieves the build's version from `version.cmake`, forms it as a string, and appends the date
@param[in] `date_version` Date this build is published for release
@param[in] `tag_name` Tag of this release, used to determine if release, rc, or nightly
@return If release: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION` from version.cmake, or
@return If rc: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION` from tag_name, or
@return If nightly: `MAJOR_VERSION.MINOR_VERSION.BUILD_VERSION-date` from version.cmake
"""
major = minor = build = version = 0
with open(os.path.join("..", "..", "cmake", "version.cmake"), "r") as f:
filetext = f.read()
major = _match_version_number(filetext, MAJOR_VERSION_PATTERN)
minor = _match_version_number(filetext, MINOR_VERSION_PATTERN)
build = _match_version_number(filetext, BUILD_VERSION_PATTERN)
if "rc" in tag_name.lower():
# Release candidates idenfity with their unstable version (ex: 21.5.0-03052022) within the game and the logs, but
# the builds are named with the target release version (ex: 22.0.0). Since this script works on the builds we
# need to grab the target release version from tag_name
x = tag_name.upper().split("_")
# "release" = x[0], year = x[1], major = x[2], minor = x[3], build = x[4],
version = semantic_version.Version("{}.{}.{}-{}".format(x[1], x[2], x[3], x[4]))
elif "release" in tag_name.lower():
version = semantic_version.Version("{}.{}.{}".format(major, minor, build))
elif "nightly" in tag_name.lower():
version = semantic_version.Version("{}.{}.{}-{}".format(major, minor, build, date_version))
else:
print("ERROR: malformed tag_name %s" % tag_name)
sys.exit(1)
print("version: {}".format(version))
print("version.prerelease: {}".format(version.prerelease))
return version
def main():
os.chdir(os.path.dirname(__file__)) # Change working directory to this file's directory
# Aggregate configuration data in a dictionary
config = {
"github": {
"repo": os.environ["GITHUB_REPO"],
},
"ftp": {
"host": "scp.indiegames.us",
"user": os.environ["INDIEGAMES_USER"],
"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}",
),
},
"nebula": {
"user": os.environ["NEBULA_USER"],
"password": os.environ["NEBULA_PASSWORD"],
},
"hlp": {
"api": os.environ["HLP_API"],
"key": os.environ["HLP_KEY"],
},
"templates": {
"nightly": "nightly.mako",
"release": "release.mako",
},
"nightly": {
"hlp_board": 173,
},
"release": {
"hlp_board": 50,
},
}
# bail if this script is run from a workflow that doesn't identify as a release or nightly
if sys.argv[1] not in ("release", "nightly"):
print("ERROR: Invalid release mode %s passed. Expected release or nightly!" % sys.argv[1])
sys.exit(1)
tag_name = os.environ["RELEASE_TAG"] ##!< commit tag string
date = datetime.now() ##!< current date
version = get_source_version(date.strftime(DATEFORMAT_VERSION), tag_name) ##!< form full version string
success = os.environ["LINUX_RESULT"] == "success" and os.environ["WINDOWS_RESULT"] == "success" ##!< true if both linux and windows builds successful
# check that tag_name is actually in the git repo and find the previous tag release
tags = check_output(("git", "for-each-ref", "--sort=-taggerdate", "--format='%(tag)'", "refs/tags"), text=True).splitlines() # retrieve all tags in the repo by using git on the shell
# NOTE: check_output returns canonical string representation. use repr() on strings its being compared to
previous_tag = None
found = False
for tag in tags:
if found:
# Look for the "previous" tag with the same configuration ('release_' or 'nightly_')
# Assumes older tags have a higher index than newer
if tag.startswith("\'" + sys.argv[1] + "_"):
previous_tag = tag
break
elif tag == repr(tag_name):
# Ok, found the tag
found = True
if not found:
# couldn't find tag, bail
print("ERROR: Couldn't find tag %s in repo!" % tag_name)
sys.exit(1)
if not previous_tag:
# couldn't find previous tag, bail
print("ERROR: Could not find a previous tag for %s!" % tag_name)
sys.exit(1)
if sys.argv[1] == "release":
# Release specific action
if not tag_name.startswith("release_"):
# Safety check tag is from a release
print("ERROR: Invalid tag name detected. Expected release_ prefix for release builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
files, sources = file_list.get_release_files(tag_name, config)
print("Hashing files")
for file in files:
installer.get_hashed_file_list(file)
# Construct the file groups
# split the file list into a dictionary of {group: files} pairs using `groupby()`
# Since `groupby()` returns a iterator reference to the original files list, we have to do a weird hand toss
# to save it as a dictionary
## NOTE z64: files need to be sorted or else key duplication will occur!
groups = {key: file_list.FileGroup(key, list(group)) for key, group in groupby(files, lambda g: g.group)}
# Error check for all group keys and subkeys to be used in the mako. Do this here for better debugging QoL
if "Win32" in groups.keys():
if "AVX" not in groups["Win32"].subFiles.keys():
print("ERROR: No Win32-AVX builds were detected!")
sys.exit(1)
else:
print("ERROR: No Win32 builds were detected!")
sys.exit(1)
if "Win64" in groups.keys():
if "AVX" not in groups["Win64"].subFiles.keys():
print("ERROR: No x64-AVX builds were detected!")
sys.exit(1)
else:
print("ERROR: No x64 builds were detected!")
sys.exit(1)
if "Linux" not in groups.keys():
print("ERROR: No Linux builds were detected!")
sys.exit(1)
# z64: What dose this do???
# print(installer.render_installer_config(version, groups, config))
# Publish release builds to Nebula
nebula.submit_release(
nebula.render_nebula_release(version, "rc" if version.prerelease else "stable", files, config),
config)
# Publish forum post, using the release.mako template
fapi = forum.ForumAPI(config)
fapi.post_release(date.strftime(DATEFORMAT_FORUM), version, groups, sources)
else:
# Dead for now, nightly publish is done elsewhere
# Nightly specific action
if not tag_name.startswith("nightly_"):
# safety check tag is from a nightly
print("ERROR: Invalid tag name detected. Expected nightly_ prefix for nightly builds but found %s (full ref = %s)" % tag_name, os.environ["GITHUB_REF"])
sys.exit(1)
print("Retrieving file list")
files = file_list.get_ftp_files("nightly", tag_name, config)
print("Hashing files")
for file in files:
installer.get_hashed_file_list(file)
# Publish nightly builds to Nebula
nebula.submit_release(
nebula.render_nebula_release(version, "nightly", files, config),
config)
# Compile commit messages into a log with all commits between this nightly and the previous nightly
log = check_output(("git", "log", "%s^..%s^" % (previous_tag, tag_name), "--no-merges", "--stat", "--pretty=format:\"%s\"" % LOG_FORMAT.strip()))
# Publish forum post, using the nighty.mako template
fapi = forum.ForumAPI(config)
fapi.post_nightly(date.strftime(DATEFORMAT_FORUM), os.environ["GITHUB_SHA"], files, log, success)
main()
+241
View File
@@ -0,0 +1,241 @@
import os.path
import sys
import traceback
import requests
from file_list import ReleaseFile
from util import retry_multi, GLOBAL_TIMEOUT
metadata = {
'type': 'engine',
'title': 'FSO',
'notes': '',
'banner': 'https://fsnebula.org/storage/0d/e7/bf64bcdea9a9c115969cfb784e1ca457d24a7c2da4fc6f213521c3bb6abb.png',
'screenshots': [],
'videos': [],
'first_release': '2017-09-24',
'cmdline': '',
'mod_flag': ['FSO'],
'tile': 'https://fsnebula.org/storage/ec/cc/0bf23e028c26d5175ff52d003bff85b0a17b0ddfc1130d65bdf6d36f6324.png',
'logo': None,
'release_thread': None,
'description': '',
'id': 'FSO',
'packages': [],
}
platforms = {
'Linux': 'linux',
'MacOSX': 'macosx',
'Win32-SSE2': 'windows',
'Win64-SSE2': 'windows',
'Win32-AVX': 'windows',
'Win64-AVX': 'windows'
}
envs = {
'Linux': 'linux && x86_64', # Linux only has 64bit builds
'MacOSX': 'macosx',
'Win32-SSE2': 'windows',
'Win64-SSE2': 'windows && x86_64',
'Win32-AVX': 'windows && avx',
'Win64-AVX': 'windows && avx && x86_64'
}
subdirs = {
'Win32-SSE2': 'x86',
'Win64-SSE2': 'x64',
'Win32-AVX': 'x86_avx',
'Win64-AVX': 'x64_avx'
}
def render_nebula_release(version, stability, files, config):
meta = metadata.copy()
meta['version'] = str(version)
meta['stability'] = stability # This can be one of ('stable', 'rc', 'nightly')
for file in files:
if file.content_hashes is None:
# The extraction probably failed which is why we don't have any hashes
continue
group = file.group
# release.py sets subgroup but nightly.py doesn't which means we have to normalize group here.
if file.subgroup:
group += '-' + file.subgroup
pkg = {
'name': group,
'notes': '',
'is_vp': False,
'files': [{
'dest': platforms[group] + '/' + subdirs.get(group, ''),
'filesize': file.size,
'checksum': ['sha256', file.hash],
'urls': [file.url] + file.mirrors,
'filename': file.name
}],
'environment': envs.get(group),
'filelist': [],
'status': 'required',
'folder': None,
'dependencies': [],
'executables': []
}
for fn, checksum in file.content_hashes:
if group in subdirs:
dest_fn = subdirs[group] + '/' + fn
else:
dest_fn = fn
# If the group is a known platform then we put the binaries into a separate subfolder for each platform
if group in platforms:
dest_fn = platforms[group] + '/' + dest_fn
pkg['filelist'].append({
'orig_name': fn,
'checksum': ('sha256', checksum),
'archive': file.name,
'filename': dest_fn
})
if group == 'Linux' and fn.endswith('.AppImage'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
else:
label = 'QtFRED'
else:
if '-FASTDBG' in fn:
label = 'Fast Debug'
else:
label = None
props = {
"x64": True, # All Linux builds are 64-bit
"sse2": True, # Linux builds are forced to compile with SSE2 but not AVX
"avx": False,
"avx2": False,
}
pkg['executables'].append({
'file': dest_fn,
'label': label,
'properties': props,
})
elif group == 'MacOSX' and fn.startswith(os.path.basename(fn) + '.app/'):
if 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
else:
label = 'QtFRED'
else:
if '-FASTDBG' in fn:
label = 'Fast Debug'
else:
label = None
props = {
"x64": True, # All Mac builds are 64-bit
"sse2": True, # There are no forced options on mac but 64-bit always implies SSE2 so we set that here
"avx": False,
"avx2": False,
}
pkg['executables'].append({
'file': dest_fn,
'label': label,
'properties': props,
})
elif group.startswith('Win') and fn.endswith('.exe'):
if 'fred2' in fn:
if '-FASTDBG' in fn:
label = 'FRED2 Debug'
else:
label = 'FRED2'
elif 'qtfred' in fn:
if '-FASTDBG' in fn:
label = 'QtFRED Debug'
else:
label = 'QtFRED'
else:
if '-FASTDBG' in fn:
label = 'Fast Debug'
else:
label = None
props = {
"x64": "x64" in fn,
"sse2": "SSE2" in fn or "AVX" in fn, # AVX implies SSE2
"avx": "AVX" in fn, # This conveniently also covers the AVX2 case since AVX2 implies AVX
"avx2": "AVX2" in fn,
}
pkg['executables'].append({
'file': dest_fn,
'label': label,
'properties': props,
})
meta["packages"].append(pkg)
return meta
@retry_multi(5)
def nebula_request(session, kind, path, **kwargs):
uri = "https://fsnebula.org/api/1/{}".format(path)
request_args = {
"timeout": GLOBAL_TIMEOUT
}
request_args.update(kwargs)
return session.request(kind, uri, **request_args)
def submit_release(meta, config):
try:
with requests.Session() as session:
print('Logging into Nebula...')
result = nebula_request(session, 'post', 'login', data={
'user': config['nebula']['user'],
'password': config['nebula']['password']
})
if result.status_code != 200:
print('Login failed!')
return False
data = result.json()
if not data['result']:
print('Login failed!')
return False
print('Submitting release...')
result = nebula_request(session, 'post', 'mod/release', headers={
'X-KN-TOKEN': data['token']
}, json=meta)
if result.status_code != 200:
print('Request failed!')
return False
data = result.json()
if not data['result']:
print('ERROR: ' + data['reason'])
return False
print('Success!')
return True
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
return False
+27
View File
@@ -0,0 +1,27 @@
Here is the nightly for ${date} - Revision ${revision}
% if not success:
[b][color=red]At least one of the nightly builds failed![/color][/b]
% endif
% for file in files:
Group: ${file.group}
[url=${file.url}]${file.name}[/url] \
%for mirror in file.mirrors:
%if loop.first:
(\
%endif
[url=${mirror}]Mirror[/url]\
%if loop.last:
)\
%else:
, \
%endif
%endfor
% endfor
[code]
${log}
[/code]
+68
View File
@@ -0,0 +1,68 @@
<%def name="build(file)">[url=${file.url}]${file.filename}[/url]</%def>
[b]Change log:[/b] (chronologically ordered)
PLACEHOLDER
[b]Deprecations:[/b]
PLACEHOLDER
Deprecations are a mechanism in FSO where a certain feature or aspect of the engine has changed or is no longer supported. Since this would normally break existing mods we have the mod table feature "[tt]$Target Version:[/tt]" with which a mod can specify what version of FSO it was developed with. The features listed above will be removed or changed when the target version of a mod is at least the version released in this post.
[size=5pt]Previous [url=https://www.hard-light.net/forums/index.php?topic=97293.0]21.0 Release Thread[/url][/size]
Launchers, if you don't have one already:
[b]All platforms: [/b] For every day use, we recommend [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url], an integrated solution for downloading and launching mods.
[hidden=Alternative Launchers]
Cross-platform: [url=http://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/files/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=http://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
OS X: Soulstorm's [url=http://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
Linux: [url=http://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=http://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]
[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)}
[b]32-bit:[/b] ${build(groups["Win32"].mainFile)}
[size=8pt]This one is based on the SSE2 Optimizations from the MSVC Compiler.[/size]
[hidden=Alternative builds]
[b]64-bit AVX:[/b] ${build(groups["Win64"].subFiles["AVX"])}
[size=8pt]This one is based on the AVX Optimizations from the MSVC Compiler (fastest build if your CPU supports AVX instructions).[/size]
[b]32-bit AVX:[/b] ${build(groups["Win32"].subFiles["AVX"])}
[size=8pt]This one is based on the AVX Optimizations from the MSVC Compiler.[/size]
[b]What are those SSE, SSE2 and AVX builds I keep seeing everywhere?[/b]
[url=http://www.hard-light.net/forums/index.php?topic=65628.0]Your answer is in this topic.[/url]
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]
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
${build(groups["Linux"].mainFile)}
These builds use a mechanism called [url=http://appimage.org/]AppImage[/url] which should allow these builds to run on most Linux distributions. However, we recommend that you compile your own builds which will result in less issues.
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.
[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=http://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]
Known issues:
[list]
[li][url=https://github.com/scp-fs2open/fs2open.github.com/issues]Github issues[/url] and [url=https://github.com/scp-fs2open/fs2open.github.com/pulls]pending pull requests[/url][/li]
[li]See the list of [url=http://scp.indiegames.us/mantis/search.php?project_id=1&status_id%5B%5D=10&status_id%5B%5D=20&status_id%5B%5D=30&status_id%5B%5D=40&status_id%5B%5D=50&priority_id%5B%5D=40&priority_id%5B%5D=50&priority_id%5B%5D=60&sticky_issues=on&sortby=last_updated&dir=DESC&per_page=200&hide_status_id=-2]Fix for next release[/url] bugs - mark a bug as an elevated priority (high, urgent, immediate) to get it included in that filter.[/li]
[/list]
+3
View File
@@ -0,0 +1,3 @@
Mako==1.1.5
requests==2.26.0
semantic-version==2.8.5
+46
View File
@@ -0,0 +1,46 @@
# miscellaneous utilities
import os
import time
from functools import wraps
from requests import RequestException
GLOBAL_TIMEOUT = 30
def retry_multi(max_retries):
"""!
@brief Decorator - Retry a function `max_retries` times.
@param [in] `max_retries` Maximum number of times to retry the decorated function before giving up
@details Intended for use with functions from the `request` module, only catches `RequestException`'s
@note This has been copied from https://stackoverflow.com/a/23892489
"""
def retry(func):
@wraps(func)
def wrapper(*args, **kwargs):
num_retries = 0
while num_retries <= max_retries:
try:
ret = func(*args, **kwargs)
break
except RequestException:
if num_retries == max_retries:
raise
num_retries += 1
time.sleep(5)
return ret
return wrapper
return retry
def expand_config_vars(config):
"""
@brief Expands the shell variable for the repo string from `config`
"""
config["git"]["repo"] = os.path.expandvars(config["git"]["repo"])
-12
View File
@@ -1,15 +1,3 @@
include(WriteCompilerDetectionHeader)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
set(CMAKE_CXX_STANDARD 11)
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
write_compiler_detection_header(
FILE "${GENERATED_SOURCE_DIR}/scp_compiler_detection.h"
PREFIX SCP
COMPILERS AppleClang Clang GNU MSVC
FEATURES ${CMAKE_CXX_KNOWN_FEATURES}
VERSION 3.2
)
-2
View File
@@ -21,8 +21,6 @@ endif()
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES)
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
-2
View File
@@ -8,8 +8,6 @@
#cmakedefine SCP_HAVE_MAX_ALIGN_T
#cmakedefine SCP_HAVE_STD_MAX_ALIGN_T
#cmakedefine01 HAVE_STD_IS_TRIVIALLY_COPYABLE
#cmakedefine01 IS_64BIT
#cmakedefine01 SCP_HAVE_STRCASECMP
+2 -2
View File
@@ -6,8 +6,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
include("${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 20)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_MAJOR 21)
set_if_not_defined(FSO_VERSION_MINOR 5)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
+3
View File
@@ -26,6 +26,7 @@ TARGET_LINK_LIBRARIES(code PUBLIC openal)
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC lz4)
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
@@ -65,6 +66,8 @@ TARGET_LINK_LIBRARIES(code PUBLIC jansson)
target_link_libraries(code PUBLIC variant)
target_link_libraries(code PUBLIC any)
# Headers for standalone "gui" on UNIX
IF(UNIX)
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
+1
View File
@@ -7,6 +7,7 @@ ActionDefinition::ActionDefinition(SCP_string name, SCP_vector<ActionParameter>
: m_name(std::move(name)), m_parameters(std::move(parameters))
{
}
ActionDefinition::~ActionDefinition() = default;
const SCP_string& ActionDefinition::getName() const
{
+1
View File
@@ -15,6 +15,7 @@ struct ActionParameter {
class ActionDefinition {
public:
ActionDefinition(SCP_string name, SCP_vector<ActionParameter> parameters);
virtual ~ActionDefinition();
const SCP_string& getName() const;
const SCP_vector<actions::ActionParameter>& getParameters() const;
+15 -18
View File
@@ -47,24 +47,7 @@ void parseActionParameters(const SCP_vector<ActionParameter>& params,
const ActionDefinitionManager& ActionDefinitionManager::instance()
{
static const ActionDefinitionManager manager = []() {
ActionDefinitionManager newManager;
newManager.addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::MoveToSubmodel>("Move To Subobject")));
newManager.addDefinition(std::unique_ptr<ActionDefinition>(
new BuiltinActionDefinition<types::ParticleEffectAction>("Start Particle Effect")));
newManager.addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::PlaySoundAction>("Play 3D Sound")));
newManager.addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetDirectionAction>("Set Direction")));
newManager.addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetPositionAction>("Set Position")));
newManager.addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::WaitAction>("Wait")));
return newManager;
}();
static const ActionDefinitionManager manager;
return manager;
}
void ActionDefinitionManager::addDefinition(std::unique_ptr<ActionDefinition> def)
@@ -144,5 +127,19 @@ std::unique_ptr<Action> ActionDefinitionManager::parseAction(const flagset<Progr
return std::unique_ptr<Action>();
}
ActionDefinitionManager::ActionDefinitionManager()
{
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::MoveToSubmodel>("Move To Subobject")));
addDefinition(std::unique_ptr<ActionDefinition>(
new BuiltinActionDefinition<types::ParticleEffectAction>("Start Particle Effect")));
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::PlaySoundAction>("Play 3D Sound")));
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetDirectionAction>("Set Direction")));
addDefinition(
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetPositionAction>("Set Position")));
addDefinition(std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::WaitAction>("Wait")));
}
} // namespace actions
+1 -1
View File
@@ -19,7 +19,7 @@ class ActionDefinitionManager {
static const ActionDefinitionManager& instance();
private:
ActionDefinitionManager() = default;
ActionDefinitionManager();
void addDefinition(std::unique_ptr<ActionDefinition> def);
-2
View File
@@ -1,2 +0,0 @@
#include "BuiltinActionDefinition.h"
+1
View File
@@ -15,6 +15,7 @@ class BuiltinActionDefinition : public ActionDefinition {
: ActionDefinition(std::move(name), {{"parameter", expression::ValueTypeTraits<ActionValueType>::type}})
{
}
~BuiltinActionDefinition() override = default;
flagset<ProgramContextFlags> getRequiredContext() const override
{
+2 -2
View File
@@ -123,9 +123,9 @@ Program& Program::operator=(const Program& other)
Program& Program::operator=(Program&&) noexcept = default;
Program::Program(Program&&) noexcept = default;
const SCP_vector<actions::Program>& ProgramSet::getPrograms() const
bool ProgramSet::isEmpty() const
{
return _programs;
return _programs.empty();
}
ProgramSet::ProgramSet() = default;
+1 -1
View File
@@ -84,7 +84,7 @@ class ProgramSet {
ProgramSet();
explicit ProgramSet(const flagset<ProgramContextFlags>& context_flags);
const SCP_vector<actions::Program>& getPrograms() const;
bool isEmpty() const;
/**
* @brief Starts the execution of all programs within this set with the specified parameters
@@ -14,6 +14,12 @@ class AbstractExpression;
template <typename T>
class TypedActionExpression;
/**
* @brief An expression that can be executed to compute a value at runtime
*
* This is the basis of having dynamic values in actions by allowing mods to specify complex expressions that make use
* of variables and functions for computing their values at runtime.
*/
class ActionExpression {
public:
ActionExpression() = default;
@@ -36,6 +42,13 @@ class ActionExpression {
std::shared_ptr<nodes::AbstractExpression> m_expression;
};
/**
* @brief An action expression with a specific type specified at compile time
*
* This is most useful for built-in actions that have the required type fixed at compile time.
*
* @tparam T The type of the expression value.
*/
template <typename T>
class TypedActionExpression {
public:
+11 -14
View File
@@ -22,19 +22,7 @@ Value value_minus(const SCP_vector<Value>& parameters)
const FunctionManager& FunctionManager::instance()
{
static const FunctionManager manager = []() {
FunctionManager newManager;
newManager.addOperator("+", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_plus<int>);
newManager.addOperator("+", {ValueType::Float, ValueType::Float}, ValueType::Float, value_plus<float>);
newManager.addOperator("+", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_plus<vec3d>);
newManager.addOperator("-", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_minus<int>);
newManager.addOperator("-", {ValueType::Float, ValueType::Float}, ValueType::Float, value_minus<float>);
newManager.addOperator("-", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_minus<vec3d>);
return newManager;
}();
static const FunctionManager manager;
return manager;
}
void FunctionManager::addOperator(const SCP_string& name,
@@ -87,7 +75,16 @@ const FunctionDefinition* FunctionManager::findOperator(const SCP_string& name,
return nullptr;
}
FunctionManager::FunctionManager() = default;
FunctionManager::FunctionManager()
{
addOperator("+", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_plus<int>);
addOperator("+", {ValueType::Float, ValueType::Float}, ValueType::Float, value_plus<float>);
addOperator("+", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_plus<vec3d>);
addOperator("-", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_minus<int>);
addOperator("-", {ValueType::Float, ValueType::Float}, ValueType::Float, value_minus<float>);
addOperator("-", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_minus<vec3d>);
}
} // namespace expression
} // namespace actions
+4 -4
View File
@@ -43,13 +43,13 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
auto pmi = model_get_instance(instance);
auto pm = model_get(pmi->model_num);
find_submodel_instance_point_orient(&local_pos,
model_instance_local_to_global_point_orient(&local_pos,
&local_orient,
&locals.localPosition,
&locals.localOrient,
pm,
pmi,
locals.hostSubobject,
&locals.localPosition,
&locals.localOrient);
locals.hostSubobject);
} else {
local_pos = locals.localPosition;
local_orient = locals.localOrient;
+4 -4
View File
@@ -32,13 +32,13 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
auto pmi = model_get_instance(instance);
auto pm = model_get(pmi->model_num);
find_submodel_instance_point_orient(&local_pos,
model_instance_local_to_global_point_orient(&local_pos,
&local_orient,
&locals.localPosition,
&locals.localOrient,
pm,
pmi,
locals.hostSubobject,
&locals.localPosition,
&locals.localOrient);
locals.hostSubobject);
} else {
local_pos = locals.localPosition;
local_orient = locals.localOrient;
+7 -5
View File
@@ -330,7 +330,7 @@ typedef struct ai_info {
fix path_next_check_time; // Last time checked to see if would collide with model.
int path_goal_dist; // minimum distance to first path point to consider path reached
int path_subsystem_next_check; // timestamp to next check if subsystem is still visible
vec3d path_depart_orient; //Rotational orientation associated with the path
vec3d path_depart_rvec; //Rotational orientation associated with the path
int submode;
int previous_submode; // previous submode, get it?
@@ -405,7 +405,6 @@ typedef struct ai_info {
union {
float lead_scale; // Amount to lead current opponent by.
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
};
@@ -491,6 +490,9 @@ typedef struct ai_info {
int ai_override_rot_timestamp; // mark for when to end the current rotational maneuver override
int form_obj_slotnum; // for flying in formation object mode, the position in the formation
int multilock_check_timestamp; // when to check for multilock next
SCP_vector<std::pair<int, ship_subsys*>> ai_missile_locks_firing; // a list of missile locks (locked objnum, locked subsys) the ai is currently firing
} ai_info;
// Goober5000
@@ -561,7 +563,7 @@ const char *ai_get_goal_target_name(const char *name, int *index);
void ai_clear_goal_target_names();
extern void init_ai_system(void);
extern void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp, int ship_info_index = -1);
extern void ai_attack_object(object *attacker, object *attacked, int ship_info_index = -1);
extern void ai_evade_object(object *evader, object *evaded);
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
extern void ai_ignore_wing(object *ignorer, int wingnum);
@@ -605,7 +607,7 @@ extern int ai_find_goal_index( ai_goal* aigp, int mode, int submode = -1, int pr
extern void ai_do_safety(object *objp);
// used to get path info for fighter bay emerging and departing
int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int path_mask, vec3d *pos, vec3d *fvec);
int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int path_mask);
int ai_acquire_depart_path(object *pl_objp, int parent_objnum, int path_mask);
// used by AiBig.cpp
@@ -657,7 +659,7 @@ void ai_start_fly_to_ship(object *objp, int shipnum);
void ai_fly_to_ship();
//Moved declaration here for player ship -WMC
void process_subobjects(int objnum);
void ai_process_subobjects(int objnum);
//SUSHI: Setting ai_info stuff from both ai class and ai profile
void init_aip_from_class_and_profile(ai_info *aip, ai_class *aicp, ai_profile_t *profile);
+13 -2
View File
@@ -5,7 +5,7 @@
namespace AI {
FLAG_LIST(AI_Flags) {
Formation_wing, // Fly in formation as part of wing.
Formation_wing, // Fly in formation as part of wing. Also used when flying waypoints.
Awaiting_repair, // Awaiting a repair ship.
Being_repaired, // Currently docked with repair ship.
Repairing, // Repairing a ship (or going to repair a ship)
@@ -130,9 +130,20 @@ namespace AI {
Use_only_single_fov_for_turrets,
No_turning_directional_bias,
Use_axial_turnrate_differences,
nonshielded_ships_can_manage_ets,
all_nonshielded_ships_can_manage_ets,
fightercraft_nonshielded_ships_can_manage_ets,
Better_collision_avoidance,
Require_exact_los,
Improved_missile_avoidance,
Friendlies_use_countermeasure_firechance,
Improved_subsystem_attack_pathing,
Fixed_ship_weapon_collision,
No_shield_damage_from_ship_collisions,
Reset_last_hit_target_time_for_player_hits,
Fighterbay_arrivals_use_carrier_orient,
Fighterbay_departures_use_carrier_orient,
Prevent_negative_turret_ammo,
Fix_keep_safe_distance,
NUM_VALUES
};
+93 -9
View File
@@ -58,6 +58,26 @@ int ai_path_type_match(char *p)
return -1;
}
const char* AI_secondary_range_aware_select_modes[] = {
"retail",
"aware",
};
int Num_ai_secondary_range_aware_select_modes = sizeof(AI_secondary_range_aware_select_modes) / sizeof(char*);
int ai_secondary_range_select_mode_match(char* p)
{
int i;
for (i = 0; i < Num_ai_secondary_range_aware_select_modes; i++)
{
if (!stricmp(AI_secondary_range_aware_select_modes[i], p))
return i;
}
return -1;
}
void parse_ai_profiles_tbl(const char *filename)
{
int i;
@@ -448,7 +468,10 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
set_flag(profile, "$fighterbay arrivals use carrier orientation:", AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
set_flag(profile, "$fighterbay departures use carrier orientation:", AI::Profile_Flags::Fighterbay_departures_use_carrier_orient);
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -481,14 +504,12 @@ void parse_ai_profiles_tbl(const char *filename)
if (path_radii >= Minimum_subsystem_path_pt_dist) {
profile->subsystem_path_radii = path_radii;
} else {
mprintf(("Warning: \"$override radius for subsystem path points:\" should be >= %i (read %i). Value will not be used. ", Minimum_subsystem_path_pt_dist, path_radii));
mprintf(("Warning: \"$override radius for subsystem path points:\" should be >= %i (read %i). Value will not be used.\n", Minimum_subsystem_path_pt_dist, path_radii));
}
}
set_flag(profile, "$use POF radius for subsystem path points:", AI::Profile_Flags::Use_subsystem_path_point_radii);
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
if (optional_string("$bay arrive speed multiplier:")) {
stuff_float(&profile->bay_arrive_speed_mult);
}
@@ -520,15 +541,64 @@ void parse_ai_profiles_tbl(const char *filename)
profile->second_order_lead_predict_factor = 0;
}
}
if (optional_string("$ships with no shields can manage ETS:"))
{
mprintf(("Warning: \"$ships with no shields can manage ETS\" flag is deprecated in favor of \"$any ship with no shields can manage ETS\"\n"));
bool temp;
stuff_boolean(&temp);
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, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
set_flag(profile, "$ships with no shields can manage ETS:", AI::Profile_Flags::nonshielded_ships_can_manage_ets);
set_flag(profile, "$any ship with no shields can manage ETS:", AI::Profile_Flags::all_nonshielded_ships_can_manage_ets);
set_flag(profile, "$fighters/bombers with no shields can manage ETS:", AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
set_flag(profile, "$better combat collision avoidance for fightercraft:", AI::Profile_Flags::Better_collision_avoidance);
set_flag(profile, "$improved missile avoidance for fightercraft:", AI::Profile_Flags::Improved_missile_avoidance);
set_flag(profile, "$friendly ships use AI profile countermeasure chance:", AI::Profile_Flags::Friendlies_use_countermeasure_firechance);
set_flag(profile, "$improved subsystem attack pathing:", AI::Profile_Flags::Improved_subsystem_attack_pathing);
set_flag(profile, "$fixed ship-weapon collisions:", AI::Profile_Flags::Fixed_ship_weapon_collision);
//Intention is to expand this feature to include a preference for close or long range weapons
//hence using something besides a simple flag.
if (optional_string("$AI secondary range awareness:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
int j = ai_secondary_range_select_mode_match(buf);
if (j >= 0) {
profile->ai_range_aware_secondary_select_mode = j;
}
else {
Warning(LOCATION, "Invalid ai secondary range awareness mode '%s' specified", buf);
}
}
set_flag(profile, "$no shield damage from ship collisions:", AI::Profile_Flags::No_shield_damage_from_ship_collisions);
set_flag(profile, "$reset last_hit_target_time for player hits:", AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
if (optional_string("$turret target recheck time:"))
{
stuff_float(&profile->turret_target_recheck_time);
if (profile->turret_target_recheck_time < 0) {
Warning(LOCATION, "Turret target recheck time must be positive.");
profile->turret_target_recheck_time = 2000.0f;
}
}
set_flag(profile, "$prevent negative turret ammo:", AI::Profile_Flags::Prevent_negative_turret_ammo);
set_flag(profile, "$fix keep-safe-distance:", AI::Profile_Flags::Fix_keep_safe_distance);
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
{
@@ -600,11 +670,13 @@ void ai_profile_t::reset()
flags.reset();
ai_path_mode = 0;
ai_path_mode = AI_PATH_MODE_NORMAL;
subsystem_path_radii = 0;
bay_arrive_speed_mult = 0;
bay_depart_speed_mult = 0;
bay_arrive_speed_mult = 1.0f;
bay_depart_speed_mult = 1.0f;
second_order_lead_predict_factor = 0;
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
turret_target_recheck_time = 2000.0f;
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
max_incoming_asteroids[i] = 0;
@@ -676,10 +748,22 @@ void ai_profile_t::reset()
flags.set(AI::Profile_Flags::Fix_ai_path_order_bug);
flags.set(AI::Profile_Flags::Aspect_invulnerability_fix);
flags.set(AI::Profile_Flags::Use_actual_primary_range);
flags.set(AI::Profile_Flags::nonshielded_ships_can_manage_ets);
flags.set(AI::Profile_Flags::fightercraft_nonshielded_ships_can_manage_ets);
}
// this flag has been enabled ever since 3.7.2
if (mod_supports_version(3, 7, 2)) {
flags.set(AI::Profile_Flags::Fix_ramming_stationary_targets_bug);
}
// and this flag has been enabled ever since 3.6.10
if (mod_supports_version(3, 6, 10)) {
flags.set(AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits);
}
if (mod_supports_version(21, 4, 0)) {
flags.set(AI::Profile_Flags::Fixed_ship_weapon_collision);
}
if (mod_supports_version(22, 0, 0)) {
flags.set(AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
flags.set(AI::Profile_Flags::Prevent_negative_turret_ammo);
flags.set(AI::Profile_Flags::Fix_keep_safe_distance);
}
}
+9
View File
@@ -17,6 +17,9 @@
// AI Path types
#define AI_PATH_MODE_NORMAL 0
#define AI_PATH_MODE_ALT1 1
#define AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL 0
#define AI_RANGE_AWARE_SEC_SEL_MODE_AWARE 1
#define MAX_AI_PROFILES 5
@@ -107,6 +110,12 @@ public:
// How much 0-1 of a second-order lead prediction factor to add to lead indicators. Affects only the HUD indicator, and autoaim.
float second_order_lead_predict_factor;
//Controls if the AI is dumb enough to keep trying to use out-of-range secondaries.
int ai_range_aware_secondary_select_mode;
// how often turrets shoulds check for new targets, milliseconds
float turret_target_recheck_time;
void reset();
};
+160 -19
View File
@@ -17,12 +17,13 @@
#include "io/timer.h"
#include "math/staticrand.h"
#include "mission/missionparse.h"
#include "object/objcollide.h"
#include "object/object.h"
#include "ship/afterburner.h"
#include "ship/ship.h"
#include "utils/Random.h"
#include "weapon/weapon.h"
#ifdef _MSC_VER
#pragma optimize("", off)
#pragma auto_inline(off)
@@ -406,7 +407,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
// get world pos of eye (stored in geye)
ep = &(pm->view_positions[shipp->current_viewpoint]);
model_instance_find_world_point( &geye, &ep->pnt, pm, pmi, 0, &Pl_objp->orient, &Pl_objp->pos );
model_instance_local_to_global_point( &geye, &ep->pnt, pm, pmi, 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);
@@ -529,6 +530,112 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
return 0;
}
bool ai_new_maybe_reposition_attack_subsys() {
ai_info* aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
if (aip->target_objnum < 0 || aip->targeted_subsys == nullptr)
return false;
object* target_objp = &Objects[aip->target_objnum];
// dont bother with this if you're still far away
if (vm_vec_dist(&Pl_objp->pos, &target_objp->pos) > target_objp->radius * 2.0f + 2000.0f)
return false;
vec3d geye, gsubpos;
eye* ep;
polymodel* pm = model_get(Ship_info[Ships[Pl_objp->instance].ship_info_index].model_num);
// 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);
// 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);
// you're in sight! shoot it!
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
return false;
// not in sight, gotta get there
vec3d tgt2pl = Pl_objp->pos - target_objp->pos;
vec3d tgt2subsys = gsubpos - target_objp->pos;
float pl_dist = vm_vec_mag(&tgt2pl);
float subsys_dist = vm_vec_mag(&tgt2subsys) * 1.3f; // add a bit to this, we don't want to go directly at the subsys, we want to go above it
float angle2subsys = vm_vec_delta_ang(&tgt2pl, &tgt2subsys, nullptr);
float angle2goal = angle2subsys;
if (angle2goal > 1.2f) // let's not try to go more than about 70 degrees around the ship
angle2goal = 1.2f;
// we'll start by travelling along the sphere at our current distance around the ship
// remember that goal_pos will be relative to our target_ship (so we can scale in and out easily)
vec3d goal_pos, cross;
vm_vec_cross(&cross, &tgt2pl, &tgt2subsys);
vm_vec_normalize(&cross);
vm_vec_negate(&cross);
vm_rot_point_around_line(&goal_pos, &tgt2pl, angle2goal, &vmd_zero_vector, &cross);
// then scale in (or out) towards our subsys
vec3d world_goal_pos;
float new_radius = ((subsys_dist - pl_dist) * (angle2goal / angle2subsys)) + pl_dist;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, new_radius / pl_dist);
world_goal_pos += target_objp->pos;
vec3d* good_pos = nullptr;
if (pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f)) {
// ok best case won't work
if (pl_dist > subsys_dist) {
//we're farther away than the subsys, let's try at our current distance
world_goal_pos = goal_pos + target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// ok, let's start moving it away and see if that's better
for (float i = 1.0f; i < 4.0f; i += 1.0f) {
if (good_pos)
break;
vm_vec_copy_scale(&world_goal_pos, &goal_pos, (new_radius / pl_dist) * powf(1.3f,i));
world_goal_pos += target_objp->pos;
if (!pp_collide(&Pl_objp->pos, &world_goal_pos, target_objp, Pl_objp->radius * 4.0f))
good_pos = &world_goal_pos;
}
// welp this sucks, just run away i guess
if (!good_pos) {
vm_vec_copy_normalize(&world_goal_pos, &tgt2pl);
world_goal_pos *= target_objp->radius + pl_dist;
world_goal_pos += target_objp->pos;
good_pos = &world_goal_pos;
}
}
else
good_pos = &world_goal_pos;
ai_turn_towards_vector(good_pos, Pl_objp, nullptr, nullptr, 0.0f, 0);
float subsys_distance = vm_vec_dist(&Pl_objp->pos, &gsubpos);
// full speed until you're close, then slow down a bit
accelerate_ship(aip, subsys_distance > 200.0f ? 1.0f : subsys_distance / 200.0f);
if (!(Ships[Pl_objp->instance].flags[Ship::Ship_Flags::Afterburner_locked])) {
if (subsys_distance > 300.0f) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
aip->afterburner_stop_time = Missiontime + 2 * F1_0;
}
}
else
afterburners_stop(Pl_objp);
}
return true;
}
// This function is only called from ai_big_chase_attack() when a ship is flying very slowly and
// attacking a big ship. The ship should scan for enemy fighter/bombers... if any are close, then
// return 1, otherwise return 0;
@@ -637,7 +744,10 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
}
// see if Pl_objp needs to reposition to get a good shot at subsystem which is being attacked
if ( ai_big_maybe_follow_subsys_path() ) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
if (ai_new_maybe_reposition_attack_subsys())
return;
} else if ( ai_big_maybe_follow_subsys_path() ) {
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
afterburners_stop(Pl_objp);
}
@@ -667,14 +777,28 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
ai_turn_towards_vector(enemy_pos, Pl_objp, nullptr, rel_pos, 0.0f, 0, rvec);
// set an optimal range if applicable
float optimal_range = 0.0f;
ship_weapon* weapons = &Ships[Pl_objp->instance].weapons;
weapon_info* wip = nullptr;
ship* shipp = &Ships[Pl_objp->instance];
if (weapons->num_primary_banks >= 1 && weapons->current_primary_bank >= 0 && !shipp->flags[Ship::Ship_Flags::Primaries_locked]) {
wip = &Weapon_info[weapons->primary_bank_weapons[weapons->current_primary_bank]];
} else if (weapons->num_secondary_banks >= 1 && weapons->current_secondary_bank >= 0 && !shipp->flags[Ship::Ship_Flags::Secondaries_locked]) {
wip = &Weapon_info[weapons->secondary_bank_weapons[weapons->current_secondary_bank]];
}
if (wip != nullptr && wip->optimum_range > 0)
optimal_range = wip->optimum_range;
// calc range of primary weapon
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
if ( aip->targeted_subsys != NULL ) {
if (dist_to_enemy > (weapon_travel_dist-20)) {
if (dist_to_enemy > (optimal_range > 0.0f ? optimal_range : (weapon_travel_dist-20))) {
accelerate_ship(aip, 1.0f);
ship *shipp = &Ships[Pl_objp->instance];
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
@@ -699,7 +823,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
} else if (dot_to_enemy < 0.75f) {
accel = 0.75f;
} else {
if (dist_to_enemy > weapon_travel_dist/2.0f) {
if (dist_to_enemy > (optimal_range > 0.0f ? optimal_range : (weapon_travel_dist/2.0f))) {
accel = 1.0f;
} else {
accel = 1.0f - dot_to_enemy;
@@ -716,7 +840,6 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
} else {
accelerate_ship(aip, accel);
ship *shipp = &Ships[Pl_objp->instance];
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
@@ -757,7 +880,14 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
swp = &Ships[Pl_objp->instance].weapons;
if (dot_to_enemy > 0.95f - 0.5f * En_objp->radius/MAX(1.0f, En_objp->radius + dist_to_enemy)) {
float target_radius = En_objp->radius;
// normal subsystem attacking uses whether or not its on a path and skips this function entirely to stop "over-eager" firing
// since the improved method doesnt use paths, refine the target radius to stop over-eager shooting
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing] && aip->targeted_subsys != nullptr)
target_radius = aip->targeted_subsys->system_info->radius;
if (dot_to_enemy > 0.95f - 0.5f * target_radius/MAX(1.0f, target_radius + dist_to_enemy)) {
aip->time_enemy_in_range += flFrametime;
// Chance of hitting ship is based on dot product of firing ship's forward vector with vector to ship
@@ -797,7 +927,7 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
}
}
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank])) {
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank]) && weapon_target_satisfies_lock_restrictions(swip, En_objp)) {
float firing_range;
if (swip->wi_flags[Weapon::Info_Flags::Local_ssm])
firing_range=swip->lssm_lock_range;
@@ -827,10 +957,11 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
} else {
t = swip->fire_wait;
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
} else {
swp->burst_counter[current_bank_adjusted] = 0;
}
swp->burst_seed[current_bank_adjusted] = Random::next();
}
} else {
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
@@ -839,10 +970,11 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
} else {
t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
swp->burst_counter[current_bank_adjusted] = Random::next(swip->burst_shots);
} else {
swp->burst_counter[current_bank_adjusted] = 0;
}
swp->burst_seed[current_bank_adjusted] = Random::next();
}
}
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
@@ -1039,7 +1171,10 @@ void ai_big_chase()
float dist_normal_to_enemy;
if (vm_vec_mag_squared(&aip->big_attack_surface_normal) > 0.9) {
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing])
dist_normal_to_enemy = fl_abs((dist_to_enemy / vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
else // I'm fairly sure this retail code VVV meant to use / instead of *
dist_normal_to_enemy = fl_abs((dist_to_enemy * vm_vec_dot(&vec_to_enemy, &aip->big_attack_surface_normal)));
} else {
// don;t have normal so use a conservative value here
dist_normal_to_enemy = 0.3f * dist_to_enemy;
@@ -1316,13 +1451,17 @@ void ai_big_strafe_attack()
ai_info *aip;
vec3d target_pos;
vec3d rand_vec;
float target_dist, target_dot, accel, t;
float accel, t;
float target_dist = 0.0f;
float target_dot = 0.0f;
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
if ( ai_big_maybe_follow_subsys_path(0) ) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
if (ai_new_maybe_reposition_attack_subsys())
return;
} else if (ai_big_maybe_follow_subsys_path(0))
return;
}
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(&target_pos) )
@@ -1345,7 +1484,7 @@ void ai_big_strafe_attack()
if ( t > 0.0f && t < 1.5f ) {
// set up goal_point for avoid path to turn towards
aip->goal_point = Pl_objp->pos;
switch(rand()%4) {
switch(Random::next(4)) {
case 0:
vm_vec_scale_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec, 2.0f);
break;
@@ -1439,9 +1578,11 @@ void ai_big_strafe_glide_attack()
flight_dot_to_enemy = vm_vec_dot(&target_objp->pos, &norm_vel_vec); //Angle between flight path and target ship
//If we're following a path, then we shouldn't be doing glide strafe
if ( ai_big_maybe_follow_subsys_path(0) ) {
if (aip->ai_profile_flags[AI::Profile_Flags::Improved_subsystem_attack_pathing]) {
if (ai_new_maybe_reposition_attack_subsys())
return;
} else if (ai_big_maybe_follow_subsys_path(0))
return;
}
//Gets a point on the target ship to attack, as well as distance and the angle between the nose of the attacker and that point.
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
@@ -1575,7 +1716,7 @@ void ai_big_strafe_retreat1()
if (Missiontime - aip->submode_start_time > fl2f(1.50f)) {
// set up goal_point for avoid path to turn towards
aip->prev_goal_point = Pl_objp->pos;
switch(rand()%4) {
switch(Random::next(4)) {
case 0:
vm_vec_add(&rand_vec, &Pl_objp->orient.vec.fvec, &Pl_objp->orient.vec.uvec);
break;
+701 -323
View File
File diff suppressed because it is too large. Load diff
+25 -12
View File
@@ -23,6 +23,7 @@
#include "playerman/player.h"
#include "scripting/scripting.h"
#include "ship/ship.h"
#include "ship/awacs.h"
#include "weapon/weapon.h"
// Just a reference to this struct being for looking up a ship's team in TVT
@@ -187,6 +188,11 @@ void ai_post_process_mission()
object *objp;
int i;
// make sure team visibility is updated first
if ( !Fred_running ) {
awacs_process();
}
// Check ships in player starting wings. Those ships should follow these rules:
// (1) if they have no orders, they should get a form on my wing order
// (2) if they have an order, they are free to act on it.
@@ -203,7 +209,6 @@ void ai_post_process_mission()
wingp = &Wings[Starting_wings[i]];
ai_maybe_add_form_goal( wingp );
}
}
}
@@ -261,14 +266,20 @@ void ai_remove_ship_goal( ai_info *aip, int index )
// ai goal code look
Assert ( index >= 0 ); // must have a valid goal
if (index == aip->active_goal)
{
// rearm/repair needs a bit of extra cleanup
if (aip->goals[index].ai_mode == AI_GOAL_REARM_REPAIR)
ai_abort_rearm_request(&Objects[Ships[aip->shipnum].objnum]);
aip->active_goal = AI_GOAL_NONE;
}
aip->goals[index].ai_mode = AI_GOAL_NONE;
aip->goals[index].signature = -1;
aip->goals[index].priority = -1;
aip->goals[index].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
if ( index == aip->active_goal )
aip->active_goal = AI_GOAL_NONE;
// mwa -- removed this line 8/5/97. Just because we remove a goal doesn't mean to do the default
// behavior. We will make the call commented out below in a more reasonable location
//ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] );
@@ -293,9 +304,11 @@ void ai_clear_ship_goals( ai_info *aip )
}
// add scripting hook for 'On Goals Cleared' --wookieejedi
Script_system.SetHookObject("Ship", &Objects[Ships[aip->shipnum].objnum]);
Script_system.RunCondition(CHA_ONGOALSCLEARED);
Script_system.RemHookVars({"Ship"});
if (Script_system.IsActiveAction(CHA_ONGOALSCLEARED)) {
Script_system.SetHookObject("Ship", &Objects[Ships[aip->shipnum].objnum]);
Script_system.RunCondition(CHA_ONGOALSCLEARED);
Script_system.RemHookVars({"Ship"});
}
}
void ai_clear_wing_goals( wing *wingp )
@@ -2147,14 +2160,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
// Mike -- debug code!
// If a ship has a subobject on it, attack that instead of the main ship!
ai_attack_object( objp, other_obj, NULL);
ai_attack_object( objp, other_obj);
break;
case AI_GOAL_CHASE_WEAPON:
Assert( Weapons[current_goal->target_instance].objnum >= 0 );
other_obj = &Objects[Weapons[current_goal->target_instance].objnum];
Assert( other_obj->signature == current_goal->target_signature );
ai_attack_object( objp, other_obj, NULL );
ai_attack_object( objp, other_obj);
break;
case AI_GOAL_GUARD:
@@ -2279,7 +2292,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
shipnum = ship_name_lookup( current_goal->target_name );
Assert( shipnum >= 0 );
other_obj = &Objects[Ships[shipnum].objnum];
ai_attack_object( objp, other_obj, NULL);
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) {
if (aip->target_objnum != -1) {
@@ -2301,14 +2314,14 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
break;
case AI_GOAL_CHASE_ANY:
ai_attack_object( objp, NULL, NULL );
ai_attack_object( objp, nullptr);
break;
// chase-ship-class is chase-any but restricted to a subset of ships
case AI_GOAL_CHASE_SHIP_CLASS:
shipnum = ship_info_lookup( current_goal->target_name );
Assertion( shipnum >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!" );
ai_attack_object( objp, NULL, NULL, shipnum );
ai_attack_object( objp, nullptr, shipnum );
break;
case AI_GOAL_WARP: {
+1 -1
View File
@@ -32,6 +32,6 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip, int second
bool check_los(int objnum, int target_objnum, float threshold, int primary_bank, int secondary_bank, ship_subsys* turret);
//Does all the stuff needed to aim and fire a turret.
void ai_fire_from_turret(ship *shipp, ship_subsys *ss);
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss);
#endif
+201 -203
View File
@@ -18,6 +18,7 @@
#include "render/3d.h"
#include "ship/ship.h"
#include "ship/shipfx.h"
#include "utils/Random.h"
#include "weapon/beam.h"
#include "weapon/flak.h"
#include "weapon/muzzleflash.h"
@@ -87,6 +88,18 @@ typedef struct eval_enemy_obj_struct {
int nearest_objnum;
} eval_enemy_obj_struct;
// the current world orientation of the turret matrix, corresponding to its fvec and uvec defined in the model
// is NOT affected by the turret's current aiming
void turret_instance_find_world_orient(matrix* out_mat, int model_instance_num, int submodel_num, const matrix* objorient)
{
auto pmi = model_get_instance(model_instance_num);
auto pm = model_get(pmi->model_num);
vec3d fvec, uvec;
model_instance_local_to_global_dir(&fvec, &pm->submodel[submodel_num].frame_of_reference.vec.fvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
model_instance_local_to_global_dir(&uvec, &pm->submodel[submodel_num].frame_of_reference.vec.uvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
vm_vector_2_matrix_norm(out_mat, &fvec, &uvec);
}
/**
* Is object in turret field of view?
*
@@ -98,117 +111,53 @@ typedef struct eval_enemy_obj_struct {
*
* @return 1 if objp is in fov of the specified turret. Otherwise return 0.
*/
int object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
bool object_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, float dist)
{
vec3d v2e;
float size_mod;
bool in_fov;
bool in_fov = false;
if (ss->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
int model_num;
switch (objp->type) {
case OBJ_SHIP:
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
break;
case OBJ_ASTEROID:
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
break;
default:
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
size_mod = objp->radius / (dist + objp->radius);
in_fov = turret_fov_test(ss, tvec, &v2e, size_mod);
return in_fov;
}
auto pm = model_get(model_num);
for (int i = 0; i < 8; i++) {
vec3d bbox_point;
vm_vec_unrotate(&bbox_point, &pm->bounding_box[i], &objp->orient);
bbox_point += objp->pos;
vm_vec_normalized_dir(&v2e, &bbox_point, tpos);
in_fov = turret_fov_test(ss, tvec, &v2e, -0.2f);
if (in_fov)
return true;
}
}
// if the bbox points method didn't work (or fov_edge_checks isn't on)
// try the normal method
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
size_mod = objp->radius / (dist + objp->radius);
in_fov = turret_fov_test(ss, tvec, &v2e, size_mod);
if ( in_fov ) {
return 1;
}
return 0;
}
bool is_object_radius_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec, vec3d *tpos, vec3d *v2e, vec3d *predicted_pos, float distance)
{
float target_dist = distance;
if (distance == 0.0f)
target_dist = vm_vec_dist(predicted_pos,tpos);
if (object_in_turret_fov(objp, ss, tvec, tpos, target_dist + objp->radius)) {
// so the targeted spot in not in fov but the enemy + radius is
// lets align the darn gun and try shooting there
vec3d temp_vec;
float multiplier = 0;
model_subsystem *tp = ss->system_info;
// project v2e_from_turret to turret normal
// substract resultant vector from the temp_vec (v2e_from_turret)
// adjust z component as necessary
// calculate multiplier for the resultant vector
// use multiplier and the z component and compose a new vector
float dot = vm_vec_dot(v2e, tvec);
vm_vec_scale_add(&temp_vec, v2e, tvec, -dot);
if (IS_VEC_NULL_SQ_SAFE(&temp_vec)) {
// return false, target is perfectly aligned over or below the turret
// safe bet is to allow turret to reacquire better target
return false;
}
// normalize the vec, it needs to be done regardless
vm_vec_normalize(&temp_vec);
bool fix_elevation = false;
bool fix_base_rot = false;
if (dot < tp->turret_fov) {
dot = tp->turret_fov;
fix_elevation = true;
}
if (dot > tp->turret_max_fov) {
dot = tp->turret_max_fov;
fix_elevation = true;
}
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
vec3d temp_vec2;
vm_vec_rotate(&temp_vec2, &temp_vec, &ss->world_to_turret_matrix);
// now in turrets frame of reference
// check if math is actually possible
if (!((temp_vec2.xyz.x == 0) && (temp_vec2.xyz.y == 0))) {
float temp_z = temp_vec2.xyz.z;
temp_vec2.xyz.z = 0.0f;
// make sure null vecs wont happen
if (!IS_VEC_NULL_SQ_SAFE(&temp_vec2)) {
vm_vec_normalize(&temp_vec2);
// only do this if it actually is required
if (-temp_vec2.xyz.y < tp->turret_y_fov) {
float check_pos = 1;
fix_base_rot = true;
temp_vec2.xyz.y = -tp->turret_y_fov;
if (temp_vec2.xyz.x < 0)
check_pos = -1;
temp_vec2.xyz.x = check_pos * sqrtf(1 - (temp_vec2.xyz.y*temp_vec2.xyz.y));
// restore z component
float scaler = sqrtf(1 - (temp_z*temp_z));
vm_vec_scale(&temp_vec2,scaler);
temp_vec2.xyz.z = temp_z;
// back to world frame
vm_vec_unrotate(&temp_vec, &temp_vec2, &ss->world_to_turret_matrix);
}
}
}
}
if (fix_elevation || fix_base_rot) {
if (fix_elevation) {
multiplier = sqrtf(1 - (dot*dot));
// keep the temp_vec scaled with the tweaked vector
vm_vec_scale(&temp_vec, multiplier);
}
vm_vec_scale_add(v2e, &temp_vec, tvec, dot);
// and we are done with v2e...
vm_vec_scale_add(predicted_pos, tpos, v2e, target_dist);
// and we are done with predicted position
return true;
} else {
mprintf(("Warning: Function 'is_object_radius_in_turret_fov' was called\nwithout need to fix turret alignments\n"));
return false;
}
}
// outside of the expanded radii, unable to align, return false
return false;
return in_fov;
}
/**
@@ -555,6 +504,7 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
if ( objp->type == OBJ_SHIP ) {
shipp = &Ships[objp->instance];
ship_info* sip = &Ship_info[shipp->ship_info_index];
// check on enemy team
if ( !iff_matches_mask(shipp->team, eeo->enemy_team_mask) ) {
@@ -594,16 +544,18 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
}
}
// don't shoot at small ships if we shouldn't
// don't shoot at big ships with huge weapons unless they have the flag
if (eeo->eeo_flags & EEOF_BIG_ONLY) {
if (!(Ship_info[shipp->ship_info_index].is_big_or_huge())) {
if (sip->class_type == -1 || !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
return;
}
}
// ^ Note the difference between these checks
// V "small only" EXCLUDES only big ships, "huge" INCLUDES only big ships
// don't shoot at big ships if we shouldn't
// don't shoot at ships ignored by small weapons if this is a small weapon
if (eeo->eeo_flags & EEOF_SMALL_ONLY) {
if ((Ship_info[shipp->ship_info_index].is_big_or_huge())) {
if (sip->class_type >= 0 && (Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
return;
}
}
@@ -1179,23 +1131,18 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
if (!skip) {
if ( Objects[aip->target_objnum].type == OBJ_SHIP ) {
ship_info* esip = &Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index];
// check for huge weapon and huge ship
if ( !big_only_flag || (Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index].is_big_or_huge()) ) {
if ( !big_only_flag || (esip->class_type >= 0 && Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only]) ) {
// check for tagged only and tagged ship
if ( tagged_only_flag && ship_is_tagged(&Objects[aip->target_objnum]) ) {
// select new target if aip->target_objnum is out of field of view
vec3d v2e;
float dist;
bool in_fov;
dist = vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, tpos);
vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, tpos);
in_fov = turret_fov_test(turret_subsys, tvec, &v2e);
if (turret_subsys->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
if (in_fov == false)
if (object_in_turret_fov(&Objects[aip->target_objnum], turret_subsys, tvec, tpos, dist + Objects[aip->target_objnum].radius))
in_fov = true;
}
// MODIFY FOR ATTACKING BIG SHIP
// dot += (0.5f * Objects[aip->target_objnum].radius / dist);
if (in_fov) {
@@ -1230,20 +1177,22 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
* of the turret.
*
* @param objp Pointer to object
* @param tp Turrent model system on that object
* @param tp Turret model system on that object
* @param gpos [Output] Global absolute position of gun firing point
* @param gvec [Output] Global vector
*
* @note The gun normal is the unrotated gun normal, (the center of the FOV cone), not
* the actual gun normal given using the current turret heading. But it _is_ rotated into the model's orientation
* in global space.
* @note2 Because of this, both single-part and multi-part turrets are treated the same way; no need to find the multi-part's gun submodel.
*/
void ship_get_global_turret_info(object *objp, model_subsystem *tp, vec3d *gpos, vec3d *gvec)
void ship_get_global_turret_info(const object *objp, const model_subsystem *tp, vec3d *gpos, vec3d *gvec)
{
// vm_vec_unrotate(gpos, &tp->turret_avg_firing_point, &objp->orient);
vm_vec_unrotate(gpos, &tp->pnt, &objp->orient);
vm_vec_add2(gpos, &objp->pos);
vm_vec_unrotate(gvec, &tp->turret_norm, &objp->orient);
auto model_instance_num = Ships[objp->instance].model_instance_num;
if (gpos)
model_instance_local_to_global_point(gpos, &vmd_zero_vector, model_instance_num, tp->subobj_num, &objp->orient, &objp->pos);
if (gvec)
model_instance_local_to_global_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient, true);
}
void turret_ai_update_aim(ai_info *aip, object *En_Objp, ship_subsys *ss);
@@ -1271,15 +1220,15 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
gun_pos = &tp->turret_firing_point[ssp->turret_next_fire_pos % tp->turret_num_firing_points];
model_instance_find_world_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
if (use_angles) {
model_instance_find_world_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
model_instance_local_to_global_dir(gvec, &tp->turret_norm, pm, pmi, tp->turret_gun_sobj, &objp->orient);
} else if (tp->flags[Model::Subsystem_Flags::Share_fire_direction]) {
vec3d avg, tmp_pos, tmp_target, enemy_point, turret_norm;
vm_vec_avg_n(&avg, tp->turret_num_firing_points, tp->turret_firing_point);
model_instance_find_world_point(&tmp_pos, &avg, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
model_instance_local_to_global_point(&tmp_pos, &avg, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
if (targetp == nullptr) {
ship* shipp = &Ships[Objects[ssp->parent_objnum].instance];
@@ -1303,7 +1252,8 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
vm_vec_add2(&enemy_point, &ssp->last_aim_enemy_pos);
} else {
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
vm_vec_unrotate(&turret_norm, &tp->turret_norm, &objp->orient);
// the turret norm here is from the perspective of the base submodel, not the gun submodel
model_instance_local_to_global_dir(&turret_norm, &tp->turret_norm, pm, pmi, pm->submodel[tp->subobj_num].parent, &objp->orient);
ai_big_pick_attack_point_turret(lep, ssp, &tmp_pos, &turret_norm, &enemy_point, MIN(wip->max_speed * wip->lifetime, wip->weapon_range), tp->turret_fov);
}
else {
@@ -1434,18 +1384,13 @@ int aifft_rotate_turret(object *objp, ship *shipp, ship_subsys *ss, object *lep,
in_fov = turret_fov_test(ss, gvec, &v2e);
if (ss->flags[Ship::Subsystem_Flags::FOV_edge_check]) {
if (in_fov == false)
in_fov = is_object_radius_in_turret_fov(&Objects[ss->turret_enemy_objnum], ss, gvec, &gun_pos, &v2e, predicted_enemy_pos, 0.0f);
}
if (in_fov) {
ret_val = model_rotate_gun(objp, pm, pmi, tp, predicted_enemy_pos);
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos);
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(objp, pm, pmi, tp, predicted_enemy_pos, true);
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
}
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
ret_val = model_rotate_gun(objp, pm, pmi, ss->system_info, predicted_enemy_pos, true);
ret_val = model_rotate_gun(objp, pm, pmi, ss, predicted_enemy_pos, true);
}
// by default "ret_val" should be set to 1 for multi-part turrets, and 0 for single-part turrets
@@ -1477,7 +1422,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
if (ship_subsystem_in_sight(enemy_objp, enemy_subsysp, abs_gunposp, &subobj_pos, 1, &dot_out, &vector_out)) {
vec3d turret_norm;
vm_vec_unrotate(&turret_norm, &turret_subsysp->system_info->turret_norm, &objp->orient);
model_instance_local_to_global_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient, true);
float dot_return = vm_vec_dot(&turret_norm, &vector_out);
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
@@ -1547,8 +1492,7 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
// Compute absolute gun position.
vec3d abs_gun_pos;
vm_vec_unrotate(&abs_gun_pos, &ssp->system_info->pnt, &objp->orient);
vm_vec_add2(&abs_gun_pos, &objp->pos);
ship_get_global_turret_info(objp, ssp->system_info, &abs_gun_pos, nullptr);
// Only pick a turret to attack on large ships.
if (!esip->is_big_or_huge())
@@ -1661,8 +1605,10 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
{
Assert(weapon_num < MAX_SHIP_WEAPONS);
float wait = 1000.0f;
// should subtract 1 from firepoints to match behavior of wip->burst_shots
int burst_shots = (wip->burst_flags[Weapon::Burst_Flags::Num_firepoints_burst_shots] ? turret->system_info->turret_num_firing_points - 1 : wip->burst_shots);
if (wip->burst_shots > turret->weapons.burst_counter[weapon_num]) {
if (burst_shots > turret->weapons.burst_counter[weapon_num]) {
wait *= wip->burst_delay;
turret->weapons.burst_counter[weapon_num]++;
} else {
@@ -1672,10 +1618,12 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
} else {
wait *= wip->fire_wait;
}
if ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
turret->weapons.burst_counter[weapon_num] = (myrand() % wip->burst_shots);
if ((burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
turret->weapons.burst_counter[weapon_num] = Random::next(burst_shots);
turret->weapons.burst_seed[weapon_num] = Random::next();
} else {
turret->weapons.burst_counter[weapon_num] = 0;
turret->weapons.burst_seed[weapon_num] = Random::next();
}
}
@@ -1686,7 +1634,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
fs_dest = &turret->weapons.next_secondary_fire_stamp[weapon_num - MAX_SHIP_PRIMARY_BANKS];
//Check for the new cooldown flag
if(!((wip->wi_flags[Weapon::Info_Flags::Same_turret_cooldown]) || ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Fast_firing]))))
if(!((wip->wi_flags[Weapon::Info_Flags::Same_turret_cooldown]) || ((burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Fast_firing]))))
{
// make side even for team vs. team
@@ -1769,7 +1717,7 @@ void turret_update_enemy_in_range(ship_subsys *turret, float seconds)
/**
* Fire a weapon from a turret
*/
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *turret_fvec, vec3d *predicted_pos = NULL, float flak_range_override = 100.0f)
bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum, vec3d *turret_pos, vec3d *firing_vec, vec3d *predicted_pos = nullptr, float flak_range_override = 100.0f)
{
matrix turret_orient;
int weapon_objnum;
@@ -1834,8 +1782,25 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
#endif
if (check_ok_to_fire(parent_objnum, turret->turret_enemy_objnum, wip, -1, turret)) {
vm_vector_2_matrix(&turret_orient, turret_fvec, NULL, NULL);
turret->turret_last_fire_direction = *turret_fvec;
ship_weapon* swp = &turret->weapons;
turret->turret_last_fire_direction = *firing_vec;
if (turret->turret_inaccuracy > 0.0f)
vm_vec_random_cone(firing_vec, firing_vec, turret->turret_inaccuracy);
vm_vector_2_matrix(&turret_orient, firing_vec, nullptr, nullptr);
// grab and set some burst data before turret_set_next_fire_timestamp wipes it
int old_burst_seed = swp->burst_seed[weapon_num];
int old_burst_counter = swp->burst_counter[weapon_num];
// only used by type 5 beams
if (turret->weapons.burst_counter[weapon_num] == 0) {
swp->per_burst_rot += wip->b_info.t5info.per_burst_rot;
if (swp->per_burst_rot > PI2)
swp->per_burst_rot -= PI2;
else if (swp->per_burst_rot < -PI2)
swp->per_burst_rot += PI2;
}
// set next fire timestamp for the turret
if (last_shot_in_salvo)
@@ -1861,7 +1826,10 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
else
fire_info.target_subsys = NULL;
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
fire_info.burst_index = old_burst_counter;
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
@@ -1872,9 +1840,11 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = turret_weapon_class;
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
}
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
@@ -1882,12 +1852,11 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
// don't fire swam, but set up swarm info instead
else if ((wip->wi_flags[Weapon::Info_Flags::Swarm]) || (wip->wi_flags[Weapon::Info_Flags::Corkscrew])) {
ship_weapon *swp = &turret->weapons;
if (swp->current_secondary_bank < 0) {
swp->current_secondary_bank = 0;
}
int bank_to_fire = swp->current_secondary_bank;
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && !ship_secondary_has_ammo(swp, bank_to_fire)) {
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
swp->current_secondary_bank++;
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
@@ -1908,8 +1877,6 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
else {
for (int i = 0; i < wip->shots; i++) {
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
ship_weapon *swp;
swp = &turret->weapons;
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
if (wip->subtype == WP_LASER) {
int points;
@@ -1937,7 +1904,10 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
points = 1;
}
if (swp->primary_bank_ammo[bank_to_fire] >= 0) {
if (swp->primary_bank_ammo[bank_to_fire] >= points) {
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if ((swp->primary_bank_ammo[bank_to_fire] >= 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
// default behavior allowed ammo to be negative
swp->primary_bank_ammo[bank_to_fire] -= points;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
swp->current_primary_bank++;
@@ -1969,11 +1939,17 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
for (int j = start_slot; j <= end_slot; j++) {
swp->secondary_next_slot[bank_to_fire]++;
if (Weapon_info[swp->secondary_bank_weapons[bank_to_fire]].wi_flags[Weapon::Info_Flags::SecondaryNoAmmo])
continue;
if (swp->secondary_next_slot[bank_to_fire] > (num_slots - 1)){
swp->secondary_next_slot[bank_to_fire] = 0;
}
if (swp->secondary_bank_ammo[bank_to_fire] >= 0) {
if (swp->secondary_bank_ammo[bank_to_fire] > 0) {
swp->secondary_bank_ammo[bank_to_fire]--;
} else if ((swp->secondary_bank_ammo[bank_to_fire] == 0) && !(The_mission.ai_profile->flags[AI::Profile_Flags::Prevent_negative_turret_ammo])) {
// default behavior allowed ammo to be negative
swp->secondary_bank_ammo[bank_to_fire]--;
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
swp->current_secondary_bank++;
@@ -1989,7 +1965,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
// zookeeper - Firepoints should cycle normally between shots,
// so we need to get the position info separately for each shot
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, turret_pos, turret_fvec, 1, NULL);
ship_get_global_turret_gun_info(&Objects[parent_objnum], turret, turret_pos, firing_vec, 1, nullptr);
weapon_objnum = weapon_create( turret_pos, &turret_orient, turret_weapon_class, parent_objnum, -1, 1, 0,0.0f, turret);
weapon_set_tracking_info(weapon_objnum, parent_objnum, turret->turret_enemy_objnum, 1, turret->targeted_subsys);
@@ -2007,14 +1983,14 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
// AL 1-6-97: Store pointer to turret subsystem
wp->turret_subsys = turret;
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
// if the gun is a flak gun
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
// show a muzzle flash
flak_muzzle_flash(turret_pos, turret_fvec, &Objects[parent_ship->objnum].phys_info, turret_weapon_class);
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
if(predicted_pos != NULL)
{
@@ -2029,9 +2005,10 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
flak_set_range(objp, flak_range_override);
}
}
// otherwise just do mflash if the weapon has it
else if (wip->muzzle_flash >= 0) {
mflash_create(turret_pos, turret_fvec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
// do mflash if the weapon has it
if (wip->muzzle_flash >= 0) {
mflash_create(turret_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
}
// in multiplayer (and the master), then send a turret fired packet.
@@ -2073,7 +2050,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set has fired flag for scriptng - nuke
//Fire animation stuff
model_anim_start_type(turret, AnimationTriggerType::TurretFired, ANIMATION_SUBTYPE_ALL, 1);
Ship_info[parent_ship->ship_info_index].animations.start(model_get_instance(parent_ship->model_instance_num), animation::ModelAnimationTriggerType::TurretFired, animation::anim_name_from_subsys(turret->system_info), animation::ModelAnimationDirection::FWD, true);
return true;
}
@@ -2124,9 +2101,11 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
Ships[Objects[tsi->parent_objnum].instance].last_fired_turret = tsi->turret;
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
if (Script_system.IsActiveAction(CHA_ONTURRETFIRED)) {
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
Script_system.RemHookVars({"Ship", "Weapon", "Beam", "Target"});
}
// muzzle flash?
if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
@@ -2157,13 +2136,15 @@ int Num_find_turret_enemy = 0;
int Num_turrets_fired = 0;
/**
* Given a turret tp and its parent parent_objnum, fire from the turret at its enemy.
* Previously called ai_fire_from_turret()
* Given a ship and a turret subsystem, handle all its behavior, mostly targeting and shooting but also
* all turret movement and resetting when idle
*/
extern int Nebula_sec_range;
void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
void ai_turret_execute_behavior(ship *shipp, ship_subsys *ss)
{
float weapon_firing_range;
float WeaponMinRange; // *Weapon minimum firing range -Et1
float weapon_min_range; // *Weapon minimum firing range -Et1
vec3d v2e;
object *lep; // Last enemy pointer
model_subsystem *tp = ss->system_info;
@@ -2235,6 +2216,8 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
{
ss->turret_enemy_objnum = -1;
lep = nullptr;
ss->flags.remove(Ship::Subsystem_Flags::Forced_target);
ss->flags.remove(Ship::Subsystem_Flags::Forced_subsys_target);
}
Assert((shipp->objnum >= 0) && (shipp->objnum < MAX_OBJECTS));
@@ -2242,25 +2225,10 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
objp = &Objects[shipp->objnum];
Assert(objp->type == OBJ_SHIP);
// Wanderer - make sure turrets already have all the data
if ( !(tp->flags[Model::Subsystem_Flags::Turret_matrix]) )
{
if (!(tp->turret_gun_sobj == tp->subobj_num))
{
auto pmi = model_get_instance(shipp->model_instance_num);
auto pm = model_get(pmi->model_num);
model_make_turret_matrix(pm, pmi, tp);
}
}
// Use the turret info for all guns, not one gun in particular.
vec3d gvec, gpos;
ship_get_global_turret_info(objp, tp, &gpos, &gvec);
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
vm_matrix_x_matrix( &ss->world_to_turret_matrix, &objp->orient, &tp->turret_matrix );
}
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
int use_angles = aifft_rotate_turret(objp, shipp, ss, lep, &predicted_enemy_pos, &gvec);
@@ -2351,12 +2319,12 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
{
weapon_firing_range = wip->lssm_lock_range;
WeaponMinRange = 0.0f;
weapon_min_range = 0.0f;
}
else
{
weapon_firing_range = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
WeaponMinRange = wip->WeaponMinRange;
weapon_min_range = wip->weapon_min_range;
}
// if beam weapon in nebula and target not tagged, decrease firing range
@@ -2369,19 +2337,21 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
}
// Don't try to fire beyond weapon_limit_range (or within min range)
if (dist_to_enemy < WeaponMinRange || dist_to_enemy > weapon_firing_range) {
if (dist_to_enemy < weapon_min_range || dist_to_enemy > weapon_firing_range) {
// it's possible another weapon is in range, but if not,
// we will end up selecting a new target
continue;
}
ship_info* esip = lep->type != OBJ_SHIP ? nullptr : &Ship_info[Ships[lep->instance].ship_info_index];
// If targeted a small ship and have a huge weapon, don't fire. But this shouldn't happen, as a small ship should not get selected.
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
if ( lep->type != OBJ_SHIP ) {
tentative_return = true;
continue;
}
if ( !(Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge()) ) {
if ( esip->class_type >= 0 && !(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
tentative_return = true;
continue;
}
@@ -2389,7 +2359,8 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
// Similar check for small weapons
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
if ( (lep->type == OBJ_SHIP) && Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge() ) {
if ( (lep->type == OBJ_SHIP) && esip->class_type >= 0 &&
(Ship_types[esip->class_type].flags[Ship::Type_Info_Flags::Targeted_by_huge_Ignored_by_small_only])) {
tentative_return = true;
continue;
}
@@ -2433,6 +2404,11 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
tentative_return = true;
continue;
}
if (!weapon_target_satisfies_lock_restrictions(wip, lep)) {
tentative_return = true;
continue;
}
}
else {
// check tagged-only for bombs only if the flag is set; see Mantis #3114
@@ -2453,8 +2429,10 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
//none of our guns can hit the enemy, so find a new enemy
if (num_valid == 0) {
ss->turret_enemy_objnum = -1;
ss->turret_time_enemy_in_range = 0.0f;
if (!ss->flags[Ship::Subsystem_Flags::Forced_target]) {
ss->turret_enemy_objnum = -1;
ss->turret_time_enemy_in_range = 0.0f;
}
// in the original code, we returned where the "tentative return" variable was set,
// so return for real now, since we don't have a reason to remain in the function
@@ -2462,8 +2440,16 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
return;
}
// if we've got Forced_subsys_target targeted_subsys *really* shouldnt be null but just in case...
if (ss->flags[Ship::Subsystem_Flags::Forced_subsys_target] && ss->targeted_subsys != nullptr) {
if (ss->targeted_subsys->current_hits <= 0.0f) {
ss->flags.remove(Ship::Subsystem_Flags::Forced_subsys_target);
ss->flags.remove(Ship::Subsystem_Flags::Forced_target);
}
}
// Maybe pick a new enemy, unless targeting has been taken over by scripting
if ( turret_should_pick_new_target(ss) && !ss->scripting_target_override ) {
if ( turret_should_pick_new_target(ss) && !ss->scripting_target_override && !(ss->flags[Ship::Subsystem_Flags::Forced_target])) {
Num_find_turret_enemy++;
int objnum = find_turret_enemy(ss, parent_objnum, &gpos, &gvec, ss->turret_enemy_objnum);
@@ -2489,9 +2475,10 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
if (( lep->type == OBJ_SHIP ) && !(ss->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
ss->targeted_subsys = aifft_find_turret_subsys(objp, ss, lep, &dot);
}
ss->turret_next_enemy_check_stamp = timestamp((int) (MAX(dot, 0.5f)*2000.0f) + 1000);
// recheck in 2-3 seconds
ss->turret_next_enemy_check_stamp = timestamp((int)((MAX(dot, 0.5f) * The_mission.ai_profile->turret_target_recheck_time) + (The_mission.ai_profile->turret_target_recheck_time / 2.0f)));
} else {
ss->turret_next_enemy_check_stamp = timestamp((int) (2000.0f * frand_range(0.9f, 1.1f))); // Check every two seconds
ss->turret_next_enemy_check_stamp = timestamp((int)(The_mission.ai_profile->turret_target_recheck_time * frand_range(0.9f, 1.1f))); // Check every two seconds
}
}
@@ -2680,8 +2667,15 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
{
// starting animation checks
if (ss->turret_animation_position == MA_POS_NOT_SET) {
if ( model_anim_start_type(shipp, AnimationTriggerType::TurretFiring, ss->system_info->subobj_num, 1) ) {
ss->turret_animation_done_time = model_anim_get_time_type(shipp, AnimationTriggerType::TurretFiring, ss->system_info->subobj_num);
bool started = false;
//For legacy animations using subtype for turret number
started |= Ship_info[shipp->ship_info_index].animations.startAll(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::ModelAnimationDirection::FWD, false, false, false, ss->system_info->subobj_num, true);
//For modern animations using proper triggered-by-subsys name
started |= Ship_info[shipp->ship_info_index].animations.start(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::anim_name_from_subsys(ss->system_info), animation::ModelAnimationDirection::FWD);
if (started) {
int duration = Ship_info[shipp->ship_info_index].animations.getTimeAll(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, ss->system_info->subobj_num, true);
int duration2 = Ship_info[shipp->ship_info_index].animations.getTime(model_get_instance(shipp->model_instance_num), animation::ModelAnimationTriggerType::TurretFiring, animation::anim_name_from_subsys(ss->system_info));
ss->turret_animation_done_time = timestamp(duration > duration2 ? duration : duration2);
ss->turret_animation_position = MA_POS_SET;
}
}
@@ -2736,7 +2730,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
{
// If nothing is OK to fire (lost track of the target?)
// reset the target (so we don't continue to track what we can't hit)
if (tp->flags[Model::Subsystem_Flags::Turret_only_target_if_can_fire])
if (tp->flags[Model::Subsystem_Flags::Turret_only_target_if_can_fire] && !(ss->flags[Ship::Subsystem_Flags::Forced_target]))
{
ss->turret_enemy_objnum = -1; // Reset enemy objnum, find a new one next frame.
ss->turret_time_enemy_in_range = 0.0f;
@@ -2771,7 +2765,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss)
}
}
}
else
else if (!(ss->flags[Ship::Subsystem_Flags::Forced_target]))
{
// Lost him!
ss->turret_enemy_objnum = -1; // Reset enemy objnum, find a new one next frame.
@@ -2794,16 +2788,20 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
model_subsystem *tp = ss->system_info;
float dot = vm_vec_dot(v2e, gvec);
if (((dot + size_mod) >= tp->turret_fov) && ((dot - size_mod) <= tp->turret_max_fov)) {
object* objp = &Objects[ss->parent_objnum];
matrix turret_matrix;
turret_instance_find_world_orient(&turret_matrix, Ships[objp->instance].model_instance_num, tp->subobj_num, &objp->orient);
vec3d of_dst;
vm_vec_rotate( &of_dst, v2e, &ss->world_to_turret_matrix );
if ((of_dst.xyz.x == 0) && (of_dst.xyz.y == 0)) {
return true;
} else {
of_dst.xyz.z = 0;
vm_vec_rotate(&of_dst, v2e, &turret_matrix);
if ((of_dst.xyz.x == 0) && (of_dst.xyz.z == 0))
return true;
else {
of_dst.xyz.y = 0;
if (!IS_VEC_NULL_SQ_SAFE(&of_dst)) {
vm_vec_normalize(&of_dst);
// now we have 2d vector with lenght of 1 that points at the targets direction after being rotated to turrets FOR
if ((-of_dst.xyz.y + size_mod) >= tp->turret_y_fov)
if ((of_dst.xyz.z + size_mod) >= tp->turret_base_fov)
return true;
}
}
@@ -2814,7 +2812,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
{
bool in_fov = false;
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_alt_math])
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_restricted_fov])
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
else
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
+317 -267
View File
@@ -38,7 +38,6 @@
#include "ship/ship.h"
#include "ship/shipfx.h"
#include "ship/shiphit.h"
#include "species_defs/species_defs.h"
#include "stats/scoring.h"
#include "weapon/weapon.h"
@@ -50,14 +49,12 @@ asteroid_obj Asteroid_objs[MAX_ASTEROID_OBJS]; // array used to store asteroid o
asteroid_obj Asteroid_obj_list; // head of linked list of asteroid_obj structs
// used for randomly generating debris type when there are multiple sizes.
#define SMALL_DEBRIS_WEIGHT 8
#define MEDIUM_DEBRIS_WEIGHT 4
#define LARGE_DEBRIS_WEIGHT 1
const float SMALL_DEBRIS_WEIGHT = 8.0f;
const float MEDIUM_DEBRIS_WEIGHT = 4.0f;
const float LARGE_DEBRIS_WEIGHT = 1.0f;
int Asteroids_enabled = 1;
int Num_asteroids = 0;
int Asteroid_throw_objnum = -1; // Object index of ship to throw asteroids at.
int Next_asteroid_throw;
SCP_vector< asteroid_info > Asteroid_info;
asteroid Asteroids[MAX_ASTEROIDS];
@@ -74,6 +71,55 @@ float Asteroid_icon_closeup_zoom;
#define ASTEROID_UPDATE_COLLIDE_TIMESTAMP 2000 // how often asteroid is checked for impending collisions with escort ships
#define ASTEROID_MIN_COLLIDE_TIME 24 // time in seconds to check for asteroid colliding
SCP_vector<SCP_string> Asteroid_target_ships;
bool Default_asteroid_throwing_behavior = true;
typedef struct asteroid_target {
int objnum;
int signature;
int throw_stamp;
int incoming_asteroids;
} asteroid_target;
// if default throwing behavior is enabled, then this should always have at most 1 target or possibly none, determined the retail way
// if not, then this is whatever number of mission-specified ships (after they arrive, list is sanitized when they exit)
SCP_vector<asteroid_target> Asteroid_targets;
/**
* Return number of asteroids expected to collide with a ship.
*/
static int count_incident_asteroids(int target_objnum)
{
object* asteroid_objp;
int count;
count = 0;
for (asteroid_objp = GET_FIRST(&obj_used_list); asteroid_objp != END_OF_LIST(&obj_used_list); asteroid_objp = GET_NEXT(asteroid_objp)) {
if (asteroid_objp->type == OBJ_ASTEROID) {
asteroid* asp = &Asteroids[asteroid_objp->instance];
if (asp->target_objnum == target_objnum) {
count++;
}
}
}
return count;
}
// add a ship as a new asteroid target
void asteroid_add_target(object* objp) {
asteroid_target new_target;
new_target.objnum = OBJ_INDEX(objp);
new_target.signature = objp->signature;
new_target.throw_stamp = timestamp(Random::next(500, 2000));
new_target.incoming_asteroids = count_incident_asteroids(OBJ_INDEX(objp)); // this *should* normally be 0
Asteroid_targets.push_back(new_target);
}
/**
* Force updating of pair stuff for asteroid *objp.
*/
@@ -159,43 +205,28 @@ static float asteroid_cap_speed(int asteroid_info_index, float speed)
return speed;
}
/**
* Returns whether position is inside inner bounding volume
*
* Sum together the following: 1 inside x, 2 inside y, 4 inside z
* inside only when sum = 7
*/
static int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
{
Assert(asfieldp->has_inner_bound);
int rval = 0;
if ( (pos->xyz.x > asfieldp->inner_min_bound.xyz.x - delta) && (pos->xyz.x < asfieldp->inner_max_bound.xyz.x + delta) ) {
rval += 1;
}
if ( (pos->xyz.y > asfieldp->inner_min_bound.xyz.y - delta) && (pos->xyz.y < asfieldp->inner_max_bound.xyz.y + delta) ) {
rval += 2;
}
if ( (pos->xyz.z > asfieldp->inner_min_bound.xyz.z - delta) && (pos->xyz.z < asfieldp->inner_max_bound.xyz.z + delta) ) {
rval += 4;
}
return rval;
}
/**
* Check if asteroid is within inner bound
* @return 0 if not inside or no inner bound, 1 if inside inner bound
*/
static int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
static bool asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
if (!asfieldp->has_inner_bound) {
return 0;
}
if (!asfieldp->has_inner_bound)
return false;
return (asteroid_in_inner_bound_with_axes(asfieldp, pos, delta) == 7);
return (pos->xyz.x > asfieldp->inner_min_bound.xyz.x - delta) && (pos->xyz.x < asfieldp->inner_max_bound.xyz.x + delta) &&
(pos->xyz.y > asfieldp->inner_min_bound.xyz.y - delta) && (pos->xyz.y < asfieldp->inner_max_bound.xyz.y + delta) &&
(pos->xyz.z > asfieldp->inner_min_bound.xyz.z - delta) && (pos->xyz.z < asfieldp->inner_max_bound.xyz.z + delta);
}
static bool asteroid_is_ship_inside_field(asteroid_field* asfieldp, vec3d* pos, float radius) {
radius *= 2.0f;
return pos->xyz.x + radius > Asteroid_field.min_bound.xyz.x && pos->xyz.x - radius < Asteroid_field.max_bound.xyz.x &&
pos->xyz.y + radius > Asteroid_field.min_bound.xyz.y && pos->xyz.y - radius < Asteroid_field.max_bound.xyz.y &&
pos->xyz.z + radius > Asteroid_field.min_bound.xyz.z && pos->xyz.z - radius < Asteroid_field.max_bound.xyz.z &&
!asteroid_in_inner_bound(asfieldp, pos, radius);
}
/**
@@ -257,7 +288,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
return NULL;
}
if((asteroid_type < 0) || (asteroid_type >= (((int)Species_info.size() + 1) * NUM_DEBRIS_SIZES))) {
if((asteroid_type < 0) || (asteroid_type >= (int)Asteroid_info.size())) {
return NULL;
}
@@ -325,7 +356,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asteroid_default_flagset += Object::Object_Flags::Physics;
asteroid_default_flagset += Object::Object_Flags::Collides;
objnum = obj_create(OBJ_ASTEROID, -1, n, &orient, &pos, radius, asteroid_default_flagset);
objnum = obj_create(OBJ_ASTEROID, -1, n, &orient, &pos, radius, asteroid_default_flagset, false);
if ( (objnum == -1) || (objnum >= MAX_OBJECTS) ) {
mprintf(("Couldn't create asteroid -- out of object slots\n"));
@@ -335,8 +366,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asp->objnum = objnum;
asp->model_instance_num = -1;
if (model_get(asip->model_num[asteroid_subtype])->flags & PM_FLAG_HAS_INTRINSIC_ROTATE) {
asp->model_instance_num = model_create_instance(false, asip->model_num[asteroid_subtype]);
if (model_get(asip->model_num[asteroid_subtype])->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
asp->model_instance_num = model_create_instance(objnum, asip->model_num[asteroid_subtype]);
}
// Add to Asteroid_used_list
@@ -488,31 +519,6 @@ static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
}
}
/**
* Returns a weight that depends on asteroid size.
*
* The weight is then used to determine the frequencty of different sizes of ship debris
*/
static int get_debris_weight(int ship_debris_index)
{
int size = ship_debris_index % NUM_DEBRIS_SIZES;
switch (size)
{
case ASTEROID_TYPE_SMALL:
return SMALL_DEBRIS_WEIGHT;
case ASTEROID_TYPE_MEDIUM:
return MEDIUM_DEBRIS_WEIGHT;
case ASTEROID_TYPE_LARGE:
return LARGE_DEBRIS_WEIGHT;
default:
Int3();
return 1;
}
}
/**
* Create all the asteroids for the mission
*/
@@ -522,14 +528,14 @@ void asteroid_create_all()
// ship_debris_odds_table keeps track of debris type of the next debris piece
// each different type (size) of debris piece has a diffenent weight, smaller weighted more heavily than larger.
// choose next type from table ship_debris_odds_table by rand()%max_weighted_range,
// choose next type from table ship_debris_odds_table by Random::next()%max_weighted_range,
// the threshold *below* which the debris type is selected.
struct {
int random_threshold;
float random_threshold;
int debris_type;
} ship_debris_odds_table[MAX_ACTIVE_DEBRIS_TYPES];
int max_weighted_range = 0;
float max_weighted_range = 0.0f;
if (!Asteroids_enabled)
return;
@@ -538,6 +544,11 @@ void asteroid_create_all()
return;
}
if (Asteroid_field.num_used_field_debris_types <= 0) {
Warning(LOCATION, "An asteroid field is enabled, but no asteroid types were enabled.");
return;
}
int max_asteroids = Asteroid_field.num_initial_asteroids; // * (1.0f - 0.1f*(MAX_DETAIL_LEVEL-Detail.asteroid_density)));
int num_debris_types = 0;
@@ -552,7 +563,7 @@ void asteroid_create_all()
// Calculate the odds table
for (idx=0; idx<num_debris_types; idx++) {
int debris_weight = get_debris_weight(Asteroid_field.field_debris_type[idx]);
float debris_weight = Asteroid_info[Asteroid_field.field_debris_type[idx]].spawn_weight;
ship_debris_odds_table[idx].random_threshold = max_weighted_range + debris_weight;
ship_debris_odds_table[idx].debris_type = Asteroid_field.field_debris_type[idx];
max_weighted_range += debris_weight;
@@ -590,16 +601,24 @@ void asteroid_create_all()
// For asteroid, load only large asteroids
// get a valid subtype
int subtype = rand() % NUM_DEBRIS_POFS;
while (Asteroid_field.field_debris_type[subtype] == -1) {
subtype = (subtype + 1) % NUM_DEBRIS_POFS;
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
int subtype = -1;
for (int j = 0; j < NUM_DEBRIS_POFS; j++) {
if (Asteroid_field.field_debris_type[j] >= 0) {
if (counter == 0) {
subtype = j;
break;
} else
counter--;
}
}
asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
if (subtype >= 0)
asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
} else {
Assert(num_debris_types > 0);
int rand_choice = rand() % max_weighted_range;
float rand_choice = frand() * max_weighted_range;
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
// for ship debris, choose type according to odds table
@@ -619,11 +638,13 @@ void asteroid_level_init()
{
Asteroid_field.num_initial_asteroids=0;
Num_asteroids = 0;
Next_asteroid_throw = timestamp(1);
Asteroid_targets.clear();
Default_asteroid_throwing_behavior = true;
asteroid_obj_list_init();
SCP_vector<asteroid_info>::iterator ast;
for (ast = Asteroid_info.begin(); ast != Asteroid_info.end(); ++ast)
ast->damage_type_idx = ast->damage_type_idx_sav;
Asteroid_field.num_used_field_debris_types = 0;
}
/**
@@ -759,52 +780,75 @@ static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float de
}
/**
* Call once per frame to maybe throw an asteroid at a ship.
* Sanitizes the Asteroid targets list removing ships that have died/become invalid etc
*/
static void sanitize_asteroid_targets_list() {
for (size_t i = 0; i < Asteroid_targets.size();) {
object* target_objp = &Objects[Asteroid_targets[i].objnum];
if (target_objp->type != OBJ_SHIP || target_objp->signature != Asteroid_targets[i].signature) {
Asteroid_targets[i] = Asteroid_targets.back();
Asteroid_targets.pop_back();
}
else // if we needed to cull we should not advance because we just moved a new asteroid target into this spot
i++;
}
}
/**
* Call once per frame to maybe throw some asteroids at one or more ships.
*
* @param count asteroids already targeted on
*/
static void maybe_throw_asteroid(int count)
static void maybe_throw_asteroid()
{
if (!timestamp_elapsed(Next_asteroid_throw)) {
return;
}
if (Asteroid_throw_objnum == -1) {
return;
}
for (asteroid_target& target : Asteroid_targets) {
if (!timestamp_elapsed(target.throw_stamp))
continue;
nprintf(("AI", "Incoming asteroids: %i\n", count));
object* target_objp = &Objects[target.objnum];
if (!asteroid_is_ship_inside_field(&Asteroid_field, &target_objp->pos, target_objp->radius))
continue;
// This should've been greater equal, but alas...
if (target.incoming_asteroids > The_mission.ai_profile->max_incoming_asteroids[Game_skill_level])
continue;
if (count > The_mission.ai_profile->max_incoming_asteroids[Game_skill_level])
return;
nprintf(("AI", "Incoming asteroids to %s: %i\n", Ships[target_objp->instance].ship_name, target.incoming_asteroids));
Next_asteroid_throw = timestamp(1000 + 1200 * count/(Game_skill_level+1));
target.throw_stamp = timestamp(1000 + 1200 * target.incoming_asteroids /(Game_skill_level+1));
ship_obj *so;
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
object *A = &Objects[so->objnum];
if (so->objnum == Asteroid_throw_objnum) {
int subtype = rand() % NUM_DEBRIS_POFS;
while (Asteroid_field.field_debris_type[subtype] == -1) {
subtype = (subtype + 1) % NUM_DEBRIS_POFS;
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
int subtype = -1;
for (int i = 0; i < NUM_DEBRIS_POFS; i++) {
if (Asteroid_field.field_debris_type[i] >= 0) {
if (counter == 0) {
subtype = i;
break;
}
else
counter--;
}
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
if (objp != NULL) {
asteroid_aim_at_target(A, objp, ASTEROID_MIN_COLLIDE_TIME + frand() * 20.0f);
}
// if asteroid is inside inner bound, kill it
if (asteroid_in_inner_bound(&Asteroid_field, &objp->pos, 0.0f)) {
objp->flags.set(Object::Object_Flags::Should_be_dead);
} else {
Asteroids[objp->instance].target_objnum = so->objnum;
// this really shouldn't happen but just in case...
if (subtype < 0)
return;
if ( MULTIPLAYER_MASTER ) {
send_asteroid_throw( objp );
}
object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
if (objp != nullptr) {
asteroid_aim_at_target(target_objp, objp, ASTEROID_MIN_COLLIDE_TIME + frand() * 20.0f);
// if asteroid is inside inner bound, kill it
if (asteroid_in_inner_bound(&Asteroid_field, &objp->pos, 0.0f)) {
objp->flags.set(Object::Object_Flags::Should_be_dead);
} else {
Asteroids[objp->instance].target_objnum = target.objnum;
target.incoming_asteroids++;
if ( MULTIPLAYER_MASTER ) {
send_asteroid_throw( objp );
}
}
return;
}
}
@@ -826,6 +870,13 @@ void asteroid_delete( object * obj )
if (asp->model_instance_num >= 0)
model_delete_instance(asp->model_instance_num);
if (asp->target_objnum >= 0) {
for (asteroid_target& target : Asteroid_targets) {
if (asp->target_objnum == target.objnum)
target.incoming_asteroids--;
}
}
asp->flags = 0;
Num_asteroids--;
Assert(Num_asteroids >= 0);
@@ -864,7 +915,14 @@ static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
} else {
// check to ensure player won't see asteroid appear either
asteroid_wrap_pos(objp, asfieldp);
Asteroids[objp->instance].target_objnum = -1;
asteroid* astp = &Asteroids[objp->instance];
// this doesnt count as a thrown asteroid anymore
for (asteroid_target& target : Asteroid_targets)
if (target.objnum == astp->target_objnum)
target.incoming_asteroids--;
astp->target_objnum = -1;
dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
@@ -944,9 +1002,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
vec3d normal;
if (mc.model_instance_num >= 0)
model_instance_find_world_dir(&normal, &mc.hit_normal, mc.model_instance_num, mc.hit_submodel, mc.orient);
model_instance_local_to_global_dir(&normal, &mc.hit_normal, mc.model_instance_num, mc.hit_submodel, mc.orient);
else
model_find_world_dir(&normal, &mc.hit_normal, mc.model_num, mc.hit_submodel, mc.orient);
model_local_to_global_dir(&normal, &mc.hit_normal, mc.model_num, mc.hit_submodel, mc.orient);
*hitnormal = normal;
}
@@ -976,11 +1034,11 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// find the light object's position in the heavy object's reference frame at last frame and also in this frame.
vec3d p0_temp, p0_rotated;
// Collision detection from rotation enabled if at rotaion is less than 30 degree in frame
// Collision detection from rotation enabled if at rotation is less than 30 degree in frame
// This should account for all ships
if ( (vm_vec_mag_squared( &heavy->phys_info.rotvel ) * flFrametime*flFrametime) < (PI*PI/36) ) {
// collide_rotate calculate (1) start position and (2) relative velocity
asteroid_hit_info->collide_rotate = 1;
asteroid_hit_info->collide_rotate = true;
vm_vec_rotate( &p0_temp, &p0, &heavy->last_orient );
vm_vec_unrotate( &p0_rotated, &p0_temp, &heavy->orient );
mc.p0 = &p0_rotated; // Point 1 of ray to check
@@ -988,11 +1046,11 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
vm_vec_scale( &asteroid_hit_info->light_rel_vel, 1/flFrametime );
// HACK - this applies to big ships warping in/out of asteroid fields - not sure what it does
if (vm_vec_mag(&asteroid_hit_info->light_rel_vel) > 300) {
asteroid_hit_info->collide_rotate = 0;
asteroid_hit_info->collide_rotate = false;
vm_vec_sub( &asteroid_hit_info->light_rel_vel, &lighter->phys_info.vel, &heavy->phys_info.vel );
}
} else {
asteroid_hit_info->collide_rotate = 0;
asteroid_hit_info->collide_rotate = false;
vm_vec_sub( &asteroid_hit_info->light_rel_vel, &lighter->phys_info.vel, &heavy->phys_info.vel );
}
@@ -1024,18 +1082,18 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// Do collision the cool new way
if ( asteroid_hit_info->collide_rotate ) {
// We collide with the sphere, find the list of rotating submodels and test one at a time
// We collide with the sphere, find the list of moving submodels and test one at a time
SCP_vector<int> submodel_vector;
model_get_rotating_submodel_list(&submodel_vector, heavy_obj);
model_get_moving_submodel_list(submodel_vector, heavy_obj);
// turn off all rotating submodels, collide against only 1 at a time.
// turn off collision detection for all rotating submodels
// turn off all moving submodels, collide against only 1 at a time.
// turn off collision detection for all moving submodels
for (auto submodel: submodel_vector) {
pmi->submodel[submodel].collision_checked = true;
}
// reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
// Only check single submodel now, since children of moving submodels are handled as moving as well
mc.flags = copy_flags | MC_SUBMODEL;
// check each submodel in turn
for (auto submodel: submodel_vector) {
@@ -1044,15 +1102,9 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// turn on just one submodel for collision test
smi->collision_checked = false;
// set angles for last frame (need to set to prev to get p0)
angles copy_angles = smi->angs;
// find the start and end positions of the sphere in submodel RF
smi->angs = smi->prev_angs;
world_find_model_instance_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos);
smi->angs = copy_angles;
world_find_model_instance_point(&p1, &light_obj->pos, pm, pmi, submodel, &heavy_obj->orient, &heavy_obj->pos);
model_instance_global_to_local_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos, true);
model_instance_global_to_local_point(&p1, &light_obj->pos, pm, pmi, submodel, &heavy_obj->orient, &heavy_obj->pos);
mc.p0 = &p0;
mc.p1 = &p1;
@@ -1065,18 +1117,18 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
mc_ret_val = 1;
// set up asteroid_hit_info common
set_hit_struct_info(asteroid_hit_info, &mc, SUBMODEL_ROT_HIT);
set_hit_struct_info(asteroid_hit_info, &mc, true);
// set up asteroid_hit_info for rotating submodel
if (asteroid_hit_info->edge_hit == 0) {
model_instance_find_obj_dir(&asteroid_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
if (!asteroid_hit_info->edge_hit) {
model_instance_local_to_global_dir(&asteroid_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
}
// find position in submodel RF of light object at collison
vec3d int_light_pos, diff;
vm_vec_sub(&diff, mc.p1, mc.p0);
vm_vec_scale_add(&int_light_pos, mc.p0, &diff, mc.hit_dist);
model_instance_find_world_point(&asteroid_hit_info->light_collision_cm_pos, &int_light_pos, pm, pmi, mc.hit_submodel, &heavy_obj->orient, &zero);
model_instance_local_to_global_point(&asteroid_hit_info->light_collision_cm_pos, &int_light_pos, pm, pmi, mc.hit_submodel, &heavy_obj->orient, &zero);
}
}
// Don't look at this submodel again
@@ -1097,11 +1149,11 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
if (mc.hit_dist < asteroid_hit_info->hit_time) {
mc_ret_val = 1;
set_hit_struct_info(asteroid_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
set_hit_struct_info(asteroid_hit_info, &mc, false);
// get collision normal if not edge hit
if (asteroid_hit_info->edge_hit == 0) {
model_instance_find_obj_dir(&asteroid_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
if (!asteroid_hit_info->edge_hit) {
model_instance_local_to_global_dir(&asteroid_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
}
// find position in submodel RF of light object at collison
@@ -1126,7 +1178,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
mc_ret_val = model_collide(&mc);
if (mc_ret_val) {
set_hit_struct_info(asteroid_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
set_hit_struct_info(asteroid_hit_info, &mc, false);
// set normal if not edge hit
if ( !asteroid_hit_info->edge_hit ) {
@@ -1350,7 +1402,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
if ( weapon_area_calc_damage(ship_objp, &asteroid_objp->pos, asip->inner_rad, asip->outer_rad, asip->blast, asip->damage, &blast, &damage, asip->outer_rad) == -1 )
continue;
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage );
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
weapon_area_apply_blast(NULL, ship_objp, &asteroid_objp->pos, blast, 0);
} // end for
}
@@ -1458,9 +1510,14 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
if ( timestamp_elapsed(asp->final_death_time) ) {
vec3d relvec, vfh, tvec;
bool skip = false;
bool hooked = Script_system.IsActiveAction(CHA_DEATH);
Script_system.SetHookObject("Self", pasteroid_obj);
if(!Script_system.IsConditionOverride(CHA_DEATH, pasteroid_obj))
if (hooked) {
Script_system.SetHookObject("Self", pasteroid_obj);
skip = Script_system.IsConditionOverride(CHA_DEATH, pasteroid_obj);
}
if (!skip)
{
pasteroid_obj->flags.set(Object::Object_Flags::Should_be_dead);
@@ -1510,7 +1567,7 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
int num_roids_var = split->max - split->min;
if (num_roids_var > 0)
num_roids += rand() % num_roids_var;
num_roids += Random::next(num_roids_var);
if (num_roids > 0)
for (int i=0; i<num_roids; i++)
@@ -1565,8 +1622,10 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
}
asp->final_death_time = timestamp(-1);
}
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
Script_system.RemHookVar("Self");
if (hooked) {
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
Script_system.RemHookVar("Self");
}
}
}
@@ -1788,7 +1847,7 @@ static void asteroid_parse_section(asteroid_info *asip)
}
required_string("$Detail distance:");
asip->num_detail_levels = stuff_int_list(asip->detail_distance, MAX_ASTEROID_DETAIL_LEVELS, RAW_INTEGER_TYPE);
asip->num_detail_levels = (int)stuff_int_list(asip->detail_distance, MAX_ASTEROID_DETAIL_LEVELS, RAW_INTEGER_TYPE);
required_string("$Max Speed:");
stuff_float(&asip->max_speed);
@@ -1802,7 +1861,7 @@ static void asteroid_parse_section(asteroid_info *asip)
if(optional_string("$Explosion Animations:")){
int temp[MAX_FIREBALL_TYPES];
int parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
auto parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
asip->explosion_bitmap_anims.clear();
asip->explosion_bitmap_anims.insert(asip->explosion_bitmap_anims.begin(), temp, temp+parsed_ints);
}
@@ -1849,20 +1908,81 @@ static void asteroid_parse_section(asteroid_info *asip)
} else
Warning(LOCATION, "Invalid asteroid reference %i used for $Split in asteroids table, ignoring.", split_type);
}
if (optional_string("$Spawn Weight:")) {
stuff_float(&asip->spawn_weight);
if (asip->spawn_weight <= 0.0f) {
Warning(LOCATION, "Spawn weight for asteroid '%s' must be greater than 0", asip->name);
asip->spawn_weight = 1.0f;
}
} else {
switch (Asteroid_info.size() % NUM_DEBRIS_SIZES)
{
case ASTEROID_TYPE_SMALL:
asip->spawn_weight = SMALL_DEBRIS_WEIGHT;
break;
case ASTEROID_TYPE_MEDIUM:
asip->spawn_weight = MEDIUM_DEBRIS_WEIGHT;
break;
case ASTEROID_TYPE_LARGE:
asip->spawn_weight = LARGE_DEBRIS_WEIGHT;
break;
default:
UNREACHABLE("Here be dragons");
}
}
}
// changes the name to "[species] Debris" if it had a name like "[species] debris #"
void maybe_change_asteroid_name(asteroid_info* asip) {
SCP_string name = asip->name;
size_t split = std::string::npos;
for (species_info species : Species_info) {
if (name.compare(0, strlen(species.species_name), species.species_name) == 0) {
split = strlen(species.species_name);
break;
}
}
if (split == std::string::npos)
return;
SCP_string remaining_name = name.substr(split + 1, name.length());
split = remaining_name.find(' ');
if (split == std::string::npos)
return;
SCP_string debris = remaining_name.substr(0, split);
SCP_string num = remaining_name.substr(split + 1, remaining_name.length());
if (stricmp(debris.c_str(), "Debris") != 0)
return;
if (num.empty() || std::find_if(num.begin(), num.end(), [](char c) {
return !std::isdigit(c, SCP_default_locale);
}) != num.end())
return;
// make sure this asteroid would correspond the 'species section' of the old style retail asteroids
if (Asteroid_info.size() < NUM_DEBRIS_SIZES + Species_info.size() * NUM_DEBRIS_SIZES && Asteroid_info.size() >= NUM_DEBRIS_SIZES) {
int idx = (int)(Asteroid_info.size()) / NUM_DEBRIS_SIZES - 1;
strcpy_s(asip->name, Species_info[idx].species_name);
strcat(asip->name, " ");
strcat(asip->name, XSTR("debris", 348));
}
}
/**
Read in data from asteroid.tbl into Asteroid_info[] array.
After this function is completes, the Asteroid_info[] array will
contain exactly three asteroids per species plus exactly three
generic asteroids. These three asteroids are a set
of small, medium, and large asteroids in that exact order.
If asteroid.tbl contains too many or too few asteroids as per
the rules above this function will abort the engine with an
error message stating the number expected and it will write
to the debug.log how everything was parsed.
After this function is complete, the Asteroid_info[] array
will have at least 3 generic asteroids plus whatever else
special ones were added in the table. The generic asteroids are
a set of small, medium, and large asteroids in that exact order.
Note that by saying "asteroid" this code is talking about
the asteroids and the debris that make up asteroid fields
@@ -1874,12 +1994,6 @@ that is being protected.
static void asteroid_parse_tbl()
{
char impact_ani_file[MAX_FILENAME_LEN];
// How did we get here without having any species defined?
Assertion(!Species_info.empty(),
"Cannot parse asteroids/debris if there "
"are no species for them to belong to."
);
try
{
@@ -1889,8 +2003,6 @@ static void asteroid_parse_tbl()
required_string("#Asteroid Types");
size_t tally = 0;
size_t max_asteroids =
NUM_DEBRIS_SIZES + Species_info.size() * NUM_DEBRIS_SIZES;
#ifndef NDEBUG
SCP_vector<SCP_string> parsed_asteroids;
@@ -1903,82 +2015,41 @@ static void asteroid_parse_tbl()
asteroid_parse_section(&new_asteroid);
size_t species = tally / NUM_DEBRIS_SIZES;
if (tally >= max_asteroids)
{
#ifdef NDEBUG
// Bump the warning count in release so they get something
// even if the message never gets displayed.
Warning(LOCATION, "Ignoring extra asteroid/debris");
#else
SCP_string msg("Ignoring extra asteroid/debris '");
msg.append(new_asteroid.name);
msg.append("'\n");
Warning(LOCATION, "%s", msg.c_str());
parsed_asteroids.push_back(msg);
#endif
}
else
{
maybe_change_asteroid_name(&new_asteroid);
#ifndef NDEBUG
SCP_string msg;
msg.append("Parsing asteroid: '");
msg.append(new_asteroid.name);
msg.append("' as a '");
msg.append((species == 0) ? "generic" : Species_info[species - 1].species_name);
msg.append("'");
switch (tally % NUM_DEBRIS_SIZES) {
case ASTEROID_TYPE_SMALL:
msg.append(" small\n");
break;
case ASTEROID_TYPE_MEDIUM:
msg.append(" medium\n");
break;
case ASTEROID_TYPE_LARGE:
msg.append(" large\n");
break;
default:
Error(LOCATION, "Get a coder! Math has broken!\n"
"Important numbers:\n"
"\ttally: " SIZE_T_ARG "\n"
"\tNUM_DEBRIS_SIZES: %d\n",
tally, NUM_DEBRIS_SIZES
);
msg.append(" unknown\n");
}
parsed_asteroids.push_back(msg);
#endif
Asteroid_info.push_back(new_asteroid);
SCP_string msg;
msg.append("Parsing asteroid: '");
msg.append(new_asteroid.name);
msg.append("' as a '");
msg.append((tally >= NUM_DEBRIS_SIZES) ? "generic" : "special");
msg.append("'");
switch (tally % NUM_DEBRIS_SIZES) {
case ASTEROID_TYPE_SMALL:
msg.append(" small\n");
break;
case ASTEROID_TYPE_MEDIUM:
msg.append(" medium\n");
break;
case ASTEROID_TYPE_LARGE:
msg.append(" large\n");
break;
default:
Error(LOCATION, "Get a coder! Math has broken!\n"
"Important numbers:\n"
"\ttally: " SIZE_T_ARG "\n"
"\tNUM_DEBRIS_SIZES: %d\n",
tally, NUM_DEBRIS_SIZES
);
msg.append(" unknown\n");
}
parsed_asteroids.push_back(msg);
#endif
Asteroid_info.push_back(new_asteroid);
tally++;
}
required_string("#End");
if (tally != max_asteroids)
{
#ifndef NDEBUG
mprintf(("Asteroid.tbl as parsed:\n"));
for (SCP_vector<SCP_string>::iterator iter = parsed_asteroids.begin();
iter != parsed_asteroids.end(); ++iter)
{
mprintf(("%s\n", iter->c_str()));
}
#endif
Error(LOCATION,
"Found " SIZE_T_ARG " asteroids/debris when " SIZE_T_ARG " expected\n\n"
"<Number expected> = <Number of species> * %d + %d generic asteroids\n"
SIZE_T_ARG " = " SIZE_T_ARG "*%d + %d\n\n"
#ifdef NDEBUG
"Run a debug build to see a list of all parsed asteroids\n",
#else
"See the debug.log for a listing of all parsed asteroids\n",
#endif
tally, max_asteroids,
NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES,
max_asteroids, Species_info.size(), NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES
);
}
Asteroid_impact_explosion_ani = -1;
required_string("$Impact Explosion:");
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
@@ -2019,29 +2090,6 @@ static void asteroid_parse_tbl()
}
}
/**
* Return number of asteroids expected to collide with a ship.
*/
static int count_incident_asteroids()
{
object *asteroid_objp;
int count;
count = 0;
for ( asteroid_objp = GET_FIRST(&obj_used_list); asteroid_objp !=END_OF_LIST(&obj_used_list); asteroid_objp = GET_NEXT(asteroid_objp) ) {
if (asteroid_objp->type == OBJ_ASTEROID ) {
asteroid *asp = &Asteroids[asteroid_objp->instance];
if ( asp->target_objnum >= 0 ) {
count++;
}
}
}
return count;
}
/**
* Pick object to throw asteroids at.
* Pick any capital or big ship inside the bounds of the asteroid field.
@@ -2056,17 +2104,10 @@ static int set_asteroid_throw_objnum()
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
ship_objp = &Objects[so->objnum];
float radius = ship_objp->radius*2.0f;
if (Ship_info[Ships[ship_objp->instance].ship_info_index].is_big_or_huge()) {
if (ship_objp->pos.xyz.x + radius > Asteroid_field.min_bound.xyz.x)
if (ship_objp->pos.xyz.y + radius > Asteroid_field.min_bound.xyz.y)
if (ship_objp->pos.xyz.z + radius > Asteroid_field.min_bound.xyz.z)
if (ship_objp->pos.xyz.x - radius < Asteroid_field.max_bound.xyz.x)
if (ship_objp->pos.xyz.y - radius < Asteroid_field.max_bound.xyz.y)
if (ship_objp->pos.xyz.z - radius < Asteroid_field.max_bound.xyz.z)
if (!asteroid_in_inner_bound(&Asteroid_field, &ship_objp->pos, radius))
return so->objnum;
if (asteroid_is_ship_inside_field(&Asteroid_field, &ship_objp->pos, ship_objp->radius))
return so->objnum;
}
}
return -1;
@@ -2083,9 +2124,18 @@ void asteroid_frame()
return;
}
Asteroid_throw_objnum = set_asteroid_throw_objnum();
if (Default_asteroid_throwing_behavior) {
int objnum = set_asteroid_throw_objnum();
if (Asteroid_targets.empty() || Asteroid_targets[0].objnum != objnum) {
Asteroid_targets.clear();
if (objnum >= 0)
asteroid_add_target(&Objects[objnum]);
}
}
maybe_throw_asteroid(count_incident_asteroids());
sanitize_asteroid_targets_list();
maybe_throw_asteroid();
}
/**
+9
View File
@@ -36,6 +36,11 @@ class model_draw_list;
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
#define MAX_ASTEROID_DETAIL_LEVELS 5
// whether to do retail behavior, just throw at the first big ship in the field
// must be explicitly opted out of by the mission
extern bool Default_asteroid_throwing_behavior;
extern SCP_vector<SCP_string> Asteroid_target_ships;
// Data structure to track the active asteroids
typedef struct asteroid_obj {
@@ -73,6 +78,8 @@ public:
int model_num[NUM_DEBRIS_POFS];
SCP_vector<int> explosion_bitmap_anims;
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
asteroid_info( )
: num_detail_levels( 0 ), max_speed( 0 ), damage_type_idx( 0 ),
@@ -136,6 +143,7 @@ typedef struct asteroid_field {
field_type_t field_type; // active throws and wraps, passive does not
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
int num_used_field_debris_types; // how many of the above are used
} asteroid_field;
extern SCP_vector< asteroid_info > Asteroid_info;
@@ -163,6 +171,7 @@ int asteroid_collide_objnum(object *asteroid_objp);
float asteroid_time_to_impact(object *asteroid_objp);
void asteroid_show_brackets();
void asteroid_target_closest_danger();
void asteroid_add_target(object* objp);
// need to extern for multiplayer
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
+3 -2
View File
@@ -716,7 +716,7 @@ bool StartAutopilot()
vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead)
vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship
switch (myrand()%24)
switch (Random::next(24))
// 8 different ways of getting perp points
// 4 of which will not be used when capships are present (anything below, or straight above)
{
@@ -795,7 +795,8 @@ bool StartAutopilot()
vm_vec_scale(&perp, Autopilot_flight_leader->radius+radius);
// randomly scale up/down by up to 20%
j = 20-myrand()%40; // [-20,20]
// jg18 - original comment said [-20,20] but preserving existing behavior
j = Random::next(-19, 20);
vm_vec_scale(&perp, 1.0f+(float(j)/100.0f));
vm_vec_add(&cameraPos, &pos, &perp);
+17 -10
View File
@@ -1120,7 +1120,7 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
return 0;
}
int bm_load(const char *real_filename) {
int bm_load(const char *real_filename, int dir_type) {
int free_slot = -1;
int w, h, bpp = 8;
int rc = 0;
@@ -1152,6 +1152,7 @@ int bm_load(const char *real_filename) {
if (Is_standalone) {
char standalone_filename[MAX_FILENAME_LEN] = "right_bracket";
strcpy_s(filename, standalone_filename);
dir_type = CF_TYPE_INTERFACE;
}
// safety catch for strcat...
@@ -1164,11 +1165,11 @@ int bm_load(const char *real_filename) {
// Lets find out what type it is
{
// see if it's already loaded (checks for any type with filename)
if (bm_load_sub_fast(filename, &handle))
if (bm_load_sub_fast(filename, &handle, dir_type))
return handle;
// if we are still here then we need to fall back to a file-based search
int rval = bm_load_sub_slow(filename, BM_NUM_TYPES, bm_ext_list, &img_cfp);
int rval = bm_load_sub_slow(filename, BM_NUM_TYPES, bm_ext_list, &img_cfp, dir_type);
if (rval < 0)
return -1;
@@ -1224,7 +1225,7 @@ int bm_load(const char *real_filename) {
entry->bm.palette = nullptr;
entry->num_mipmaps = mm_lvl;
entry->mem_taken = (size_t)bm_size;
entry->dir_type = CF_TYPE_ANY;
entry->dir_type = dir_type;
entry->handle = handle;
entry->load_count++;
@@ -1235,8 +1236,8 @@ int bm_load(const char *real_filename) {
return handle;
}
int bm_load(const SCP_string& filename) {
return bm_load(filename.c_str());
int bm_load(const SCP_string& filename, int dir_type) {
return bm_load(filename.c_str(), dir_type);
}
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type) {
@@ -1424,7 +1425,7 @@ static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug)
return 0;
}
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, float *total_time, bool can_drop_frames, int dir_type) {
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, float *total_time, bool can_drop_frames, int dir_type, bool rethrow_exceptions) {
int i, n;
anim the_anim;
CFILE *img_cfp = nullptr;
@@ -1466,6 +1467,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
if (Is_standalone) {
char standalone_filename[MAX_FILENAME_LEN] = "cursorweb";
strcpy_s(filename, standalone_filename);
dir_type = CF_TYPE_INTERFACE;
}
// safety catch for strcat...
@@ -1594,10 +1596,15 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
img_size = the_apng.imgsize();
}
catch (const apng::ApngException& e) {
mprintf(("Failed to load apng: %s\n", e.what() ));
if (img_cfp != nullptr)
cfclose(img_cfp);
return -1;
if (rethrow_exceptions) {
throw e;
}
else {
mprintf(("Failed to load apng: %s\n", e.what()));
return -1;
}
}
}
else {
@@ -1789,7 +1796,7 @@ int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe,
*fps = 0;
int tidx = bm_load_animation(filename, nframes, fps, keyframe, nullptr, can_drop_frames, dir_type);
if (tidx == -1) {
tidx = bm_load(filename);
tidx = bm_load(filename, dir_type);
if (tidx != -1 && nframes != NULL)
*nframes = 1;
}
+10 -3
View File
@@ -177,7 +177,7 @@ void clear_bm_lookup_cache();
* @returns The bitmap number if successful, else
* @returns a negative value if not
*/
int bm_load(const char* filename);
int bm_load(const char* filename, int dir_type = CF_TYPE_ANY);
/**
* @brief Loads a bitmap so we can draw with it later. (Preferred version)
@@ -187,7 +187,7 @@ int bm_load(const char* filename);
* @returns The bitmap number if successful, else
* @returns a negative value if not
*/
int bm_load(const SCP_string& filename);
int bm_load(const SCP_string& filename, int dir_type = CF_TYPE_ANY);
/**
* @brief Reloads a bitmap as a duplicate.
@@ -289,7 +289,14 @@ bool bm_release_rendertarget(int handle);
* @returns The bm number of the first bitmap in the sequence if successful, or
* @returns A negative value if unsuccessful
*/
int bm_load_animation(const char *filename, int *nframes = nullptr, int *fps = nullptr, int *keyframe = nullptr, float *total_time = nullptr, bool can_drop_frames = 0, int dir_type = CF_TYPE_ANY);
int bm_load_animation(const char *filename,
int *nframes = nullptr,
int *fps = nullptr,
int *keyframe = nullptr,
float *total_time = nullptr,
bool can_drop_frames = false,
int dir_type = CF_TYPE_ANY,
bool rethrow_exceptions = false);
/**
* @brief Loads either animation (bm_load_animation) or still image (bm_load)
+81 -44
View File
@@ -43,7 +43,7 @@ auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View",
.finish();
//*************************CLASS: camera*************************
//This is where the camera class beings! :D
//This is where the camera class begins! :D
camera::camera(const char *in_name, int in_signature)
{
set_name(in_name);
@@ -237,12 +237,15 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
{
matrix temp_matrix = IDENTITY_MATRIX;
if(in_target != NULL)
if (in_target != nullptr)
{
vec3d position = vmd_zero_vector;
this->get_info(&position, NULL);
vec3d position;
matrix orient_buf;
auto orient = Use_host_orientation_for_set_camera_facing ? &orient_buf : nullptr;
if(in_target->xyz.x == position.xyz.x && in_target->xyz.y == position.xyz.y && in_target->xyz.z == position.xyz.z)
this->get_info(&position, orient, false);
if (vm_vec_same(in_target, &position))
{
Warning(LOCATION, "Camera tried to point to self");
return;
@@ -250,7 +253,25 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
vec3d targetvec;
vm_vec_normalized_dir(&targetvec, in_target, &position);
vm_vector_2_matrix(&temp_matrix, &targetvec, NULL, NULL);
if (Use_host_orientation_for_set_camera_facing)
{
// point along the target vector, but using the host orient's roll
vm_vector_2_matrix(&temp_matrix, &targetvec, &orient->vec.uvec, nullptr);
// if we have a host, we need the difference between the camera's current orient and the orient we want
// if not, we will later set the absolute orientation, rather than the orientation relative to the host
if (object_host.IsValid())
{
vm_transpose(orient);
temp_matrix = temp_matrix * *orient;
}
}
else
{
// point directly along the target vector
vm_vector_2_matrix(&temp_matrix, &targetvec, nullptr, nullptr);
}
}
set_rotation(&temp_matrix, in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time);
@@ -298,13 +319,16 @@ float camera::get_fov()
}
eye* get_submodel_eye(polymodel *pm, int submodel_num);
void camera::get_info(vec3d *position, matrix *orientation)
void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation)
{
if(position == NULL && orientation == NULL)
return;
eye* eyep = NULL;
vec3d host_normal;
matrix host_orient = vmd_identity_matrix;
bool use_host_orient = false;
//POSITION
if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid())
{
@@ -342,16 +366,19 @@ void camera::get_info(vec3d *position, matrix *orientation)
Assertion(objp->type == OBJ_SHIP, "This part of the code expects the object to be a ship");
vec3d c_pos_in;
find_submodel_instance_point_normal(&c_pos_in, &host_normal, pm, pmi, eyep->parent, &eyep->pnt, &eyep->norm);
model_instance_local_to_global_point_dir(&c_pos_in, &host_normal, &eyep->pnt, &eyep->norm, pm, pmi, eyep->parent);
vm_vec_unrotate(&c_pos, &c_pos_in, &objp->orient);
vm_vec_add2(&c_pos, &objp->pos);
}
else
{
if (pmi != nullptr)
model_instance_find_world_point(&c_pos, &pt, pm, pmi, object_host_submodel, &objp->orient, &objp->pos);
{
model_instance_local_to_global_point_orient(&c_pos, &host_orient, &pt, &vmd_identity_matrix, pm, pmi, object_host_submodel, &objp->orient, &objp->pos);
use_host_orient = true;
}
else
model_find_world_point( &c_pos, &pt, pm, object_host_submodel, &objp->orient, &objp->pos );
model_local_to_global_point( &c_pos, &pt, pm, object_host_submodel, &objp->orient, &objp->pos );
}
}
}
@@ -367,7 +394,7 @@ void camera::get_info(vec3d *position, matrix *orientation)
}
}
if(position != NULL)
if (position != nullptr)
*position = c_pos;
//ORIENTATION
@@ -378,32 +405,32 @@ void camera::get_info(vec3d *position, matrix *orientation)
{
if(object_target.IsValid())
{
object *objp = object_target.objp;
int model_num = object_get_model(objp);
polymodel *pm = nullptr;
polymodel_instance *pmi = nullptr;
object *target_objp = object_target.objp;
int model_num = object_get_model(target_objp);
polymodel *target_pm = nullptr;
polymodel_instance *target_pmi = nullptr;
vec3d target_pos = vmd_zero_vector;
//See if we can get the model
if(model_num >= 0)
{
pm = model_get(model_num);
if (objp->type == OBJ_SHIP)
pmi = model_get_instance(Ships[objp->instance].model_instance_num);
target_pm = model_get(model_num);
if (target_objp->type == OBJ_SHIP)
target_pmi = model_get_instance(Ships[target_objp->instance].model_instance_num);
}
//If we don't have a submodel or don't have the model use object pos
//Otherwise, find the submodel pos as it is rotated
if(object_target_submodel < 0 || pm == NULL)
if (object_target_submodel < 0 || target_pm == nullptr)
{
target_pos = objp->pos;
target_pos = target_objp->pos;
}
else
{
if (pmi != nullptr)
model_instance_find_world_point(&target_pos, &vmd_zero_vector, pm, pmi, object_target_submodel, &objp->orient, &objp->pos);
if (target_pmi != nullptr)
model_instance_local_to_global_point(&target_pos, &vmd_zero_vector, target_pm, target_pmi, object_target_submodel, &target_objp->orient, &target_objp->pos);
else
model_find_world_point( &target_pos, &vmd_zero_vector, pm, object_target_submodel, &objp->orient, &objp->pos );
model_local_to_global_point( &target_pos, &vmd_zero_vector, target_pm, object_target_submodel, &target_objp->orient, &target_objp->pos );
}
vec3d targetvec;
@@ -418,6 +445,10 @@ void camera::get_info(vec3d *position, matrix *orientation)
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL);
target_set = true;
}
else if (use_host_orient)
{
c_ori = host_orient;
}
else
{
c_ori = object_host.objp->orient;
@@ -428,23 +459,30 @@ void camera::get_info(vec3d *position, matrix *orientation)
c_ori = vmd_identity_matrix;
}
matrix mtxA = c_ori;
matrix mtxB = IDENTITY_MATRIX;
float pos = 0.0f;
for(int i = 0; i < 9; i++)
//Do custom orientation stuff, if needed
if (func_custom_orientation != nullptr && !target_set)
{
ori[i].get(&pos, NULL);
mtxB.a1d[i] = pos;
func_custom_orientation(this, &c_ori);
}
vm_matrix_x_matrix(&c_ori, &mtxA, &mtxB);
vm_orthogonalize_matrix(&c_ori);
}
//Do custom orientation stuff, if needed
if(func_custom_orientation != NULL && !target_set)
{
func_custom_orientation(this, &c_ori);
// only do this if we want to find where the camera is actually pointing;
// skip this if we just want the orientation of the host
if (apply_camera_orientation)
{
matrix mtxA = c_ori;
matrix mtxB = IDENTITY_MATRIX;
float pos = 0.0f;
for (int i = 0; i < 9; i++)
{
ori[i].get(&pos, nullptr);
mtxB.a1d[i] = pos;
}
vm_matrix_x_matrix(&c_ori, &mtxA, &mtxB);
vm_orthogonalize_matrix(&c_ori);
}
}
*orientation = c_ori;
}
}
@@ -560,9 +598,9 @@ void warp_camera::get_info(vec3d *position, matrix *orientation)
#define MAX_SUBTITLE_LINES 64
subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char* in_imageanim, float in_display_time,
float in_fade_time, const color *in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width,
int in_height, bool in_post_shaded)
:display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), time_displayed(-1.0f), time_displayed_end(-1.0f),
post_shaded(false)
int in_height, bool in_post_shaded, float in_line_height_factor)
: display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), line_height_factor(1.0f),
image_id(-1), time_displayed(-1.0f), time_displayed_end(-1.0f), post_shaded(false)
{
// Initialize color
gr_init_color(&text_color, 0, 0, 0);
@@ -573,7 +611,6 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
memset( imageanim, 0, sizeof(imageanim) );
memset( &text_pos, 0, 2*sizeof(int) );
memset( &image_pos, 0, 4*sizeof(int) );
image_id = -1;
if ( ((in_text != NULL) && (strlen(in_text) <= 0)) && ((in_imageanim != NULL) && (strlen(in_imageanim) <= 0)) )
return;
@@ -585,7 +622,6 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
in_text = text_buf.c_str();
}
int num_text_lines = 0;
const char *text_line_ptrs[MAX_SUBTITLE_LINES];
int text_line_lens[MAX_SUBTITLE_LINES];
@@ -608,6 +644,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
else
gr_init_alphacolor(&text_color, 255, 255, 255, 255);
text_fontnum = in_text_fontnum;
line_height_factor = in_line_height_factor;
//Setup display and fade time
display_time = fl_abs(in_display_time);
@@ -646,7 +683,7 @@ subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char*
if(w > tw)
tw = w;
th += h;
th += fl2i(line_height_factor * h);
}
// restore old font
@@ -744,7 +781,7 @@ void subtitle::do_frame(float frametime)
for(SCP_vector<SCP_string>::iterator line = text_lines.begin(); line != text_lines.end(); ++line)
{
gr_string(x, y, (char*)line->c_str(), GR_RESIZE_NONE);
y += font_height;
y += fl2i(line_height_factor * font_height);
}
// restore old font
@@ -793,9 +830,9 @@ subtitle::~subtitle()
void subtitle::clone(const subtitle &sub)
{
text_lines = sub.text_lines;
text_fontnum = sub.text_fontnum;
line_height_factor = sub.line_height_factor;
// copy the structs
text_pos = sub.text_pos;
+4 -2
View File
@@ -75,7 +75,7 @@ public:
object *get_object_target();
int get_object_target_submodel();
float get_fov();
void get_info(vec3d *position, matrix *orientation);
void get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation = true);
//Is
bool is_empty(){return sig < 0;}
@@ -123,6 +123,7 @@ private:
float fade_time;
color text_color;
int text_fontnum;
float line_height_factor;
//Done with set
char imageanim[MAX_FILENAME_LEN];
@@ -139,7 +140,8 @@ private:
public:
subtitle(int in_x_pos, int in_y_pos, const char* in_text = NULL, const char* in_imageanim = NULL,
float in_display_time = 0, float in_fade_time = 0.0f, const color *in_text_color = NULL, int in_text_fontnum = -1,
bool center_x = false, bool center_y = false, int in_width = 0, int in_height = 0, bool post_shaded=false);
bool center_x = false, bool center_y = false, int in_width = 0, int in_height = 0, bool post_shaded = false,
float in_line_height_factor = 1.0f);
~subtitle();
subtitle(const subtitle &sub) { clone(sub); }
+9 -6
View File
@@ -80,7 +80,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA },
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt", CF_TYPE_DATA },
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
@@ -91,6 +91,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
{ CF_TYPE_INTERFACE_MARKUP, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "markup", ".rml", CF_TYPE_INTERFACE },
{ CF_TYPE_INTERFACE_CSS, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "css", ".rcss", CF_TYPE_INTERFACE },
{ CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS },
};
// clang-format on
@@ -287,7 +288,7 @@ static int _cfile_chdir(const char *new_dir, const char *cur_dir __UNUSED)
const char *colon = strchr(new_dir, ':');
if (colon) {
if (!cfile_chdrive(tolower(*(colon - 1)) - 'a' + 1, 1))
if (!cfile_chdrive(SCP_tolower(*(colon - 1)) - 'a' + 1, 1))
return 1;
path = colon + 1;
@@ -305,7 +306,7 @@ static int _cfile_chdir(const char *new_dir, const char *cur_dir __UNUSED)
status = _chdir(path);
if (status != 0) {
#ifdef _WIN32
cfile_chdrive(tolower(cur_dir[0]) - 'a' + 1, 1);
cfile_chdrive(SCP_tolower(cur_dir[0]) - 'a' + 1, 1);
#endif /* _WIN32 */
return 2;
}
@@ -866,6 +867,7 @@ static int cfget_cfile_block()
cfile->data = nullptr;
cfile->fp = nullptr;
cfile->type = CFILE_BLOCK_USED;
cf_clear_compression_info(cfile);
return i;
}
}
@@ -921,7 +923,7 @@ int cfclose( CFILE * cfile )
} else {
// VP do nothing
}
cf_clear_compression_info(cfile);
cfile->type = CFILE_BLOCK_UNUSED;
return result;
}
@@ -973,7 +975,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, const char* ori
if(pos == -1L)
pos = 0;
cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)), 0 );
cf_check_compression(cfp);
return cfp;
}
}
@@ -1008,7 +1010,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, const char* o
cfp->line_num = line;
cf_init_lowlevel_read_code(cfp,offset, size, 0 );
cf_check_compression(cfp);
return cfp;
}
@@ -1052,6 +1054,7 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, const ch
cfp->line_num = line;
cf_init_lowlevel_read_code(cfp, 0, 0, 0 );
#if defined _WIN32
cfp->hMapFile = CreateFileMapping(cfp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (cfp->hMapFile == NULL) {
+2 -1
View File
@@ -81,9 +81,10 @@ typedef struct {
#define CF_TYPE_FREDDOCS 37
#define CF_TYPE_INTERFACE_MARKUP 38
#define CF_TYPE_INTERFACE_CSS 39
#define CF_TYPE_PLAYER_BINDS 40
#define CF_MAX_PATH_TYPES \
40 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
41 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
// TRUE if type is specified and valid
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
+47 -8
View File
@@ -24,6 +24,7 @@
#include "cfile/cfile.h"
#include "cfile/cfilearchive.h"
#include "cfile/cfilecompression.h"
#include "luaconf.h"
#include <sstream>
@@ -33,7 +34,6 @@
#define CHECK_POSITION
// Called once to setup the low-level reading code.
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos )
{
Assert(cfile != nullptr);
@@ -54,6 +54,33 @@ void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size,
}
}
//This function checks the file header to see if the file is compressed, if so it fills the correct compression info.
void cf_check_compression(CFILE* cfile)
{
if (cfile->size <= 16)
return;
int header=cfread_int(cfile);
cfseek(cfile, 0, SEEK_SET);
if (comp_check_header(header) == COMP_HEADER_MATCH)
comp_create_ci(cfile, header);
}
//This function is called to cleanup compression info when the cfile handle is reused.
void cf_clear_compression_info(CFILE* cfile)
{
if (cfile->compression_info.header != 0)
{
free(cfile->compression_info.offsets);
free(cfile->compression_info.decoder_buffer);
cfile->compression_info.offsets = nullptr;
cfile->compression_info.decoder_buffer = nullptr;
cfile->compression_info.header = 0;
cfile->compression_info.block_size = 0;
cfile->compression_info.last_decoded_block_pos = 0;
cfile->compression_info.last_decoded_block_bytes = 0;
cfile->compression_info.num_offsets = 0;
}
}
// cfeof() Tests for end-of-file on a stream
@@ -61,11 +88,11 @@ void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size,
// returns a nonzero value after the first read operation that attempts to read
// past the end of the file. It returns 0 if the current position is not end of file.
// There is no error return.
int cfeof(CFILE *cfile)
{
Assert(cfile != NULL);
if (cfile->compression_info.header != 0)
return comp_feof(cfile);
int result = 0;
#if defined(CHECK_POSITION) && !defined(NDEBUG)
@@ -92,6 +119,8 @@ int cfeof(CFILE *cfile)
int cftell( CFILE * cfile )
{
Assert(cfile != NULL);
if (cfile->compression_info.header != 0)
return (int)comp_ftell(cfile);
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
@@ -117,6 +146,9 @@ int cfseek( CFILE *cfile, int offset, int where )
Assert(cfile != NULL);
if (cfile->compression_info.header != 0)
return comp_fseek(cfile, offset, where);
// TODO: seek to offset in memory mapped file
Assert( !cfile->mem_mapped );
@@ -202,23 +234,31 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
// This is a file from memory
bytes_read = size;
memcpy(buf, reinterpret_cast<const char*>(cfile->data) + cfile->raw_position, size);
} else if (cfile->compression_info.header != 0) {
bytes_read = comp_fread(cfile, reinterpret_cast<char*>(buf),size);
if (bytes_read != size)
{
mprintf(("\nFile: %s decompression error. Result was: %d expected: %d\n", cfile->original_filename.c_str(), (int)bytes_read, (int)size));
Assertion(bytes_read == size, "File decompression error!");
}
} else {
bytes_read = fread( buf, 1, size, cfile->fp );
bytes_read = fread(buf, 1, size, cfile->fp);
}
if ( bytes_read > 0 ) {
cfile->raw_position += bytes_read;
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
}
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
//Raw position is not the fp position with compressed files
if (cfile->fp && cfile->compression_info.header == 0) {
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
Assert(tmp_offset==cfile->raw_position);
Assert(tmp_offset == cfile->raw_position);
}
#endif
return (int)(bytes_read / elsize);
}
int cfread_lua_number(double *buf, CFILE *cfile)
@@ -266,4 +306,3 @@ int cfread_lua_number(double *buf, CFILE *cfile)
return items_read;
}
+19 -2
View File
@@ -7,7 +7,6 @@
*
*/
#ifndef _CFILEARCHIVE_H
#define _CFILEARCHIVE_H
@@ -23,6 +22,17 @@
#define CFILE_BLOCK_UNUSED 0
#define CFILE_BLOCK_USED 1
struct COMPRESSION_INFO {
int header = 0;
size_t compressed_size = 0;
int block_size = 0;
int num_offsets = 0;
int* offsets = nullptr;
char* decoder_buffer = nullptr;
int last_decoded_block_pos = 0;
int last_decoded_block_bytes = 0;
};
struct CFILE {
int type = CFILE_BLOCK_UNUSED; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
int dir_type; // directory location
@@ -44,12 +54,19 @@ struct CFILE {
SCP_string original_filename;
const char* source_file;
int line_num;
COMPRESSION_INFO compression_info;
};
#define MAX_CFILE_BLOCKS 64
extern std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
// Called once to setup the low-level reading code.
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos );
void cf_init_lowlevel_read_code(CFILE* cfile, size_t lib_offset, size_t size, size_t pos);
// This checks if the file is compressed or not, and creates the proper compression info if so.
void cf_check_compression(CFILE* cfile);
// Used to clear compression info data and free dynamic memory used by compression
void cf_clear_compression_info(CFILE* cfile);
#endif
+206
View File
@@ -0,0 +1,206 @@
#define _CFILE_INTERNAL
#include <cstdlib>
#include <cstring>
#include <cstdio>
#ifdef _WIN32
#include <io.h>
#include <direct.h>
#include <windows.h>
#include <winbase.h>
#endif
#include "lz4.h"
#include "cfilecompression.h"
#include "cfilearchive.h"
/*INTERNAL FUNCTIONS*/
/*LZ41*/
void lz41_load_offsets(CFILE* cf);
size_t lz41_stream_random_access(CFILE* cf, char* bytes_out, size_t offset, size_t length);
void lz41_create_ci(CFILE* cf, int header);
/*MISC*/
int fso_fseek(CFILE* cfile, int offset, int where);
/*END OF INTERNAL FUNCTIONS*/
int comp_check_header(int header)
{
if (LZ41_FILE_HEADER == header)
return COMP_HEADER_MATCH;
return COMP_HEADER_MISMATCH;
}
void comp_create_ci(CFILE* cf, int header)
{
//mprintf(("(CI)Compressed File Opened: %s \n", cf->original_filename.c_str()));
if (LZ41_FILE_HEADER == header)
lz41_create_ci(cf, header);
//mprintf(("(CI)Uncompressed FileSize: %d \n", cf->size));
//mprintf(("(CI)Compressed FileSize: %d \n", cf->compression_info.compressed_size));
//mprintf(("(CI)Block Size: %d \n", cf->compression_info.block_size));
}
size_t comp_fread(CFILE* cf, char* buffer, size_t length)
{
/* Check the request to be at least 1 byte */
Assertion(length > 0, "Invalid length requested.");
/* Check that we are not requesting to read beyond end of file */
Assertion(cf->raw_position + length <= cf->size, "Invalid length requested.");
if (LZ41_FILE_HEADER == cf->compression_info.header)
return lz41_stream_random_access(cf, buffer, cf->raw_position, length);
return 0;
}
size_t comp_ftell(CFILE* cf)
{
return cf->raw_position;
}
int comp_feof(CFILE* cf)
{
if (cf->raw_position >= cf->size)
return 1;
else
return 0;
}
int comp_fseek(CFILE* cf, int offset, int where)
{
size_t goal_position;
switch (where) {
case SEEK_SET: goal_position = offset; break;
case SEEK_CUR: goal_position = cf->raw_position + offset; break;
case SEEK_END: goal_position = cf->size + offset; break;
default: return 1;
}
// Make sure we don't seek beyond the end of the file
CAP(goal_position,(size_t)0, cf->size);
cf->raw_position = goal_position;
return 0;
}
//Special fseek for compressed files handled by FSO, only SEEK_SET and SEEK_END is supported.
int fso_fseek(CFILE* cfile, int offset, int where)
{
size_t goal_position;
switch (where) {
case SEEK_SET: goal_position = offset + cfile->lib_offset; break;
case SEEK_END: goal_position = cfile->compression_info.compressed_size + offset + cfile->lib_offset; break;
default: return 0;
}
// Make sure we don't seek beyond the end of the file
CAP(goal_position, cfile->lib_offset, cfile->lib_offset + cfile->compression_info.compressed_size);
int result = 0;
if (cfile->fp)
{
result = fseek(cfile->fp, (long)goal_position, SEEK_SET);
Assertion(goal_position >= cfile->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cfile->lib_offset);
}
return result;
}
void lz41_create_ci(CFILE* cf, int header)
{
cf->compression_info.header = header;
cf->compression_info.compressed_size = cf->size;
fso_fseek(cf, (int)sizeof(int)*-3, SEEK_END);
auto fNumoffsets = fread(&cf->compression_info.num_offsets, sizeof(int), 1, cf->fp);
auto fSize = fread(&cf->size, sizeof(int), 1, cf->fp);
auto fBsize = fread(&cf->compression_info.block_size, sizeof(int), 1, cf->fp);
Assertion(cf->compression_info.num_offsets > 0, "Invalid number of offsets, compressed file is possibly in the wrong format or corrupted.");
#if !defined(NDEBUG)
Assertion(cf->size > 4, "Invalid filesize, compressed file is possibly in the wrong format or corrupted.");
Assertion(cf->compression_info.block_size > 16, "Invalid block size, compressed file is possibly in the wrong format or corrupted.");
Assertion(fNumoffsets == 1, "Error while reading the number of offsets, compressed file is possibly in the wrong format or corrupted.");
Assertion(fSize == 1, "Error while reading original filesize, compressed file is possibly in the wrong format or corrupted.");
Assertion(fBsize == 1, "Error while reading block size, compressed file is possibly in the wrong format or corrupted.");
#endif
cf->compression_info.decoder_buffer = (char*)malloc(LZ4_compressBound(cf->compression_info.block_size));
cf->compression_info.last_decoded_block_pos = 0;
cf->compression_info.last_decoded_block_bytes = 0;
lz41_load_offsets(cf);
}
void lz41_load_offsets(CFILE* cf)
{
cf->compression_info.offsets = (int*)malloc(cf->compression_info.num_offsets * sizeof(int));
int block;
int* offsets_ptr = cf->compression_info.offsets;
/* Seek to the first offset position, remember to consider the trailing ints */
fso_fseek(cf, ( ( sizeof(int) * cf->compression_info.num_offsets ) * -1 ) - (sizeof(int)*3 ), SEEK_END);
for (block = 0; block < cf->compression_info.num_offsets; ++block)
{
auto bytes_read = fread(offsets_ptr++, sizeof(int), 1, cf->fp);
Assertion(bytes_read == 1, "Error reading offset list.");
}
}
size_t lz41_stream_random_access(CFILE* cf, char* bytes_out, size_t offset, size_t length)
{
LZ4_streamDecode_t lz4_stream_decode_body;
LZ4_streamDecode_t* lz4_stream_decode = &lz4_stream_decode_body;
/* The blocks (current_block to end_block) contain the data we want */
size_t current_block = offset / cf->compression_info.block_size;
size_t end_block = ((offset + length - 1) / cf->compression_info.block_size) + 1;
size_t written_bytes = 0;
if (cf->compression_info.num_offsets <= (int)end_block)
return (size_t)LZ41_OFFSETS_MISMATCH;
/* Seek to the first block to read, if it matches the cached block, search the next one instead */
if (cf->compression_info.last_decoded_block_pos == cf->compression_info.offsets[current_block] && current_block + 1 <= end_block)
fso_fseek(cf, cf->compression_info.offsets[current_block+1], SEEK_SET);
else
fso_fseek(cf, cf->compression_info.offsets[current_block], SEEK_SET);
offset = offset % cf->compression_info.block_size;
char* cmp_buf = (char*)malloc(LZ4_compressBound(cf->compression_info.block_size));
/* Start decoding */
for (; current_block < end_block; ++current_block)
{
/* Only read and decode if the requested block is not the cached one */
if (cf->compression_info.last_decoded_block_pos != cf->compression_info.offsets[current_block])
{
cf->compression_info.last_decoded_block_pos = cf->compression_info.offsets[current_block];
/* The difference in offsets is the size of the block */
int cmp_bytes = cf->compression_info.offsets[current_block + 1] - cf->compression_info.offsets[current_block];
auto bytes_read = fread(cmp_buf, cmp_bytes, 1, cf->fp);
Assertion(bytes_read == 1, "Error reading from compressed file.");
cf->compression_info.last_decoded_block_bytes = LZ4_decompress_safe_continue(lz4_stream_decode, cmp_buf, cf->compression_info.decoder_buffer, cmp_bytes, cf->compression_info.block_size);
if (cf->compression_info.last_decoded_block_bytes <= 0)
{
free(cmp_buf);
return (size_t)LZ41_DECOMPRESSION_ERROR;
}
}
/* Write out the part of the data we care about from buffer */
size_t block_length = (length < (cf->compression_info.last_decoded_block_bytes - offset) ? length : (cf->compression_info.last_decoded_block_bytes - offset));
memcpy(bytes_out + written_bytes, cf->compression_info.decoder_buffer + offset, (size_t)block_length);
written_bytes += block_length;
offset = 0;
length -= block_length;
}
free(cmp_buf);
return written_bytes;
}
+66
View File
@@ -0,0 +1,66 @@
/*
ShivanSpS - Compressed files support for FSO. Many thanks to ngld, taylor and everyone elsewho helped me in getting this done.
-The file header is a version, this is used to tell FSO how to decompress that file, always use 4 chars to mantain alignment.
-The header ID can be used to add diferent revisions to LZ41 decompression system or to add other compression format supports whiout breaking compatibility.
-The system uses a offset list to record the position of every block in file, this list, along with the number of offsets, original filesize,
and block size, must be written by the compressor app.
-A decoder cache is used to store the last decoded block, this ensures each block is read and decoded only once in sequential reads. This cache
is a little bit bigger than the block size, a higher block size means less overhead added to the file, but it also means a little more ram will
be used during decompression.
-All this dynamic memory is assigned at cfopen() and it is cleared on cfclose().
................................char[4]..........(n ints)...(int)..........(int)..........(int)
-COMPRESSED FILE DATA STUCTURE: HEADER|N BLOCKS|N OFFSETS|NUM_OFFSETS|ORIGINAL_FILESIZE|BLOCK_SIZE
*/
#ifndef _CFILECOMPRESSION_H
#define _CFILECOMPRESSION_H
struct CFILE;
/*LZ41*/
#define LZ41_FILE_HEADER 0x31345A4C // "14ZL" -> "LZ41", inverted
#define LZ41_DECOMPRESSION_ERROR -1
#define LZ41_MAX_BLOCKS_OVERFLOW -2
#define LZ41_HEADER_MISMATCH -3
#define LZ41_OFFSETS_MISMATCH -4
/******/
#define COMP_HEADER_MATCH 1
#define COMP_HEADER_MISMATCH 0
/*
Returns COMP_HEADER_MATCH if header is a valid compressed file header,
returns COMP_HEADER_MISMATCH if it dosent.
*/
int comp_check_header(int header);
/*
This is called to generate the correct compression_info data
after the file has been indentified as a compressed file.
This must be done before calling any other function.
*/
void comp_create_ci(CFILE* cf, int header);
/*
Read X bytes from the uncompressed file starting from X offset.
Returns the amount of bytes read, and 0 or lower to indicate errors.
*/
size_t comp_fread(CFILE* cf, char* buffer, size_t length);
/*
Returns the current uncompressed file position.
*/
size_t comp_ftell(CFILE* cf);
/*
Returns 1 of the uncompressed file has been completely read, otherwise it returns a 0.
*/
int comp_feof(CFILE* cf);
/*
Used to move the uncompressed file current position.
*/
int comp_fseek(CFILE* cf, int offset, int where);
#endif
+469 -760
View File
File diff suppressed because it is too large. Load diff
+59 -39
View File
@@ -220,6 +220,8 @@ Flag exe_params[] =
{ "-set_cpu_affinity", "Sets processor affinity to config value", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-set_cpu_affinity", },
{ "-nograb", "Disables mouse grabbing", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nograb", },
{ "-noshadercache", "Disables the shader cache", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noshadercache", },
{ "-prefer_ipv4", "Prefer IPv4 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv4", },
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
#ifdef WIN32
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
#endif
@@ -246,11 +248,13 @@ Flag exe_params[] =
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
{ "-profile_frame_time","Profile frame time", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_time", },
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
{ "-json_profiling", "Generate JSON profiling output", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
{ "-debug_window", "Enable the debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
{ "-gr_debug", "Output graphics debug information", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gr_debug", },
{ "-stdout_log", "Output log file to stdout", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stdout_log", },
{ "-slow_frames_ok", "Don't adjust timestamps for slow frames", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-slow_frames_ok", },
};
// clang-format on
@@ -274,7 +278,6 @@ cmdline_parm gameclosed_arg("-closed", NULL, AT_NONE); // Cmdline_closed_game
cmdline_parm gamerestricted_arg("-restricted", NULL, AT_NONE); // Cmdline_restricted_game
cmdline_parm port_arg("-port", "Multiplayer network port", AT_INT);
cmdline_parm multilog_arg("-multilog", NULL, AT_NONE); // Cmdline_multi_log
cmdline_parm client_dodamage("-clientdamage", NULL, AT_NONE); // Cmdline_client_dodamage
cmdline_parm pof_spew("-pofspew", NULL, AT_NONE); // Cmdline_spew_pof_info
cmdline_parm weapon_spew("-weaponspew", nullptr, AT_STRING); // Cmdline_spew_weapon_stats
cmdline_parm mouse_coords("-coords", NULL, AT_NONE); // Cmdline_mouse_coords
@@ -287,7 +290,6 @@ char *Cmdline_game_password = NULL;
char *Cmdline_rank_above = NULL;
char *Cmdline_rank_below = NULL;
int Cmdline_cd_check = 1;
int Cmdline_client_dodamage = 0;
int Cmdline_closed_game = 0;
int Cmdline_freespace_no_music = 0;
int Cmdline_freespace_no_sound = 0;
@@ -377,21 +379,23 @@ int Cmdline_rearm_timer = 0;
int Cmdline_targetinfo = 0;
// Gameplay related
cmdline_parm use_3dwarp("-3dwarp", NULL, AT_NONE); // Cmdline_3dwarp
cmdline_parm ship_choice_3d_arg("-ship_choice_3d", NULL, AT_NONE); // Cmdline_ship_choice_3d
cmdline_parm weapon_choice_3d_arg("-weapon_choice_3d", NULL, AT_NONE); // Cmdline_weapon_choice_3d
cmdline_parm use_warp_flash("-warp_flash", NULL, AT_NONE); // Cmdline_warp_flash
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", NULL, AT_NONE);
cmdline_parm stretch_menu("-stretch_menu", NULL, AT_NONE); // Cmdline_stretch_menu
cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3d_warp
cmdline_parm ship_choice_3d_arg("-ship_choice_3d", nullptr, AT_NONE); // Cmdline_ship_choice_3d
cmdline_parm weapon_choice_3d_arg("-weapon_choice_3d", nullptr, AT_NONE); // Cmdline_weapon_choice_3d
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 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
int Cmdline_3dwarp = 0;
int Cmdline_ship_choice_3d = 0;
int Cmdline_weapon_choice_3d = 0;
int Cmdline_warp_flash = 0;
int Cmdline_autopilot_interruptable = 1;
int Cmdline_stretch_menu = 0;
int Cmdline_no_screenshake = 0;
int Cmdline_deadzone = -1;
// Audio related
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
@@ -438,6 +442,8 @@ cmdline_parm no_geo_sdr_effects("-no_geo_effects", NULL, AT_NONE);
cmdline_parm set_cpu_affinity("-set_cpu_affinity", NULL, AT_NONE);
cmdline_parm nograb_arg("-nograb", NULL, AT_NONE);
cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -456,6 +462,8 @@ bool Cmdline_no_geo_sdr_effects = false;
bool Cmdline_set_cpu_affinity = false;
bool Cmdline_nograb = false;
bool Cmdline_noshadercache = false;
bool Cmdline_prefer_ipv4 = false;
bool Cmdline_prefer_ipv6 = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -481,6 +489,7 @@ cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
@@ -488,6 +497,7 @@ cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_
cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_window
cmdline_parm graphics_debug_output_arg("-gr_debug", nullptr, AT_NONE); // Cmdline_graphics_debug_output
cmdline_parm log_to_stdout_arg("-stdout_log", nullptr, AT_NONE); // Cmdline_log_to_stdout
cmdline_parm slow_frames_ok_arg("-slow_frames_ok", nullptr, AT_NONE); // Cmdline_slow_frames_ok
char *Cmdline_start_mission = NULL;
@@ -512,6 +522,7 @@ int Cmdline_reparse_mainhall = 0;
bool Cmdline_profile_write_file = false;
bool Cmdline_no_unfocus_pause = false;
bool Cmdline_benchmark_mode = false;
const char *Cmdline_pilot = nullptr;
bool Cmdline_noninteractive = false;
bool Cmdline_json_profiling = false;
bool Cmdline_frame_profile = false;
@@ -519,6 +530,7 @@ bool Cmdline_show_video_info = false;
bool Cmdline_debug_window = false;
bool Cmdline_graphics_debug_output = false;
bool Cmdline_log_to_stdout = false;
bool Cmdline_slow_frames_ok = false;
// Other
cmdline_parm get_flags_arg(GET_FLAGS_STRING, "Output the launcher flags file", AT_STRING);
@@ -812,7 +824,7 @@ void os_validate_parms(int argc, char *argv[])
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("Mantis (bug reporting): http://scp.indiegames.us/mantis/\n\n");
printf("Github (bug reporting): https://github.com/scp-fs2open/fs2open.github.com/issues\n\n");
printf("Usage: fs2_open [options]\n");
// not the prettiest thing but the job gets done
@@ -1319,6 +1331,7 @@ static json_t* json_get_v1() {
json_array_append_new(caps_array, json_string("No D3D"));
json_array_append_new(caps_array, json_string("New Sound"));
json_array_append_new(caps_array, json_string("SDL"));
json_array_append_new(caps_array, json_string("Multijoy"));
json_object_set_new(root, "caps", caps_array);
}
@@ -1410,24 +1423,7 @@ static json_t* json_get_v1() {
json_object_set_new(root, "openal", openal_obj);
}
{
auto joystick_array = json_array();
auto joysticks = io::joystick::getJoystickInformations();
for (auto& info : joysticks) {
auto joystick_obj = json_object();
json_object_set_new(joystick_obj, "name", json_string(info.name.c_str()));
json_object_set_new(joystick_obj, "guid", json_string(info.guid.c_str()));
json_object_set_new(joystick_obj, "num_axes", json_integer(info.num_axes));
json_object_set_new(joystick_obj, "num_balls", json_integer(info.num_balls));
json_object_set_new(joystick_obj, "num_buttons", json_integer(info.num_buttons));
json_object_set_new(joystick_obj, "num_hats", json_integer(info.num_hats));
json_object_set_new(joystick_obj, "is_haptic", json_boolean(info.is_haptic));
json_array_append_new(joystick_array, joystick_obj);
}
auto joystick_array = io::joystick::getJsonArray();
json_object_set_new(root, "joysticks", joystick_array);
}
@@ -1619,7 +1615,7 @@ bool SetCmdlineParams()
Cmdline_game_name = gamename_arg.str();
// be sure that this string fits in our limits
if ( strlen(Cmdline_game_name) > MAX_GAMENAME_LEN ) {
if ( strlen(Cmdline_game_name) >= MAX_GAMENAME_LEN ) {
Cmdline_game_name[MAX_GAMENAME_LEN-1] = '\0';
}
}
@@ -1629,8 +1625,9 @@ bool SetCmdlineParams()
Cmdline_game_password = gamepassword_arg.str();
// be sure that this string fits in our limits
if ( strlen(Cmdline_game_name) > MAX_PASSWD_LEN ) {
Cmdline_game_name[MAX_PASSWD_LEN-1] = '\0';
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);
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
}
}
@@ -1663,12 +1660,6 @@ bool SetCmdlineParams()
Cmdline_multi_log = 1;
}
// maybe use old-school client damage
if(client_dodamage.found()){
Cmdline_client_dodamage = 1;
}
// spew pof info
if(pof_spew.found()){
Cmdline_spew_pof_info = 1;
@@ -1721,7 +1712,7 @@ bool SetCmdlineParams()
sprintf(override, "{\"width\":%d,\"height\":%d}", width, height);
options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
} else {
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".", Cmdline_res));
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".\n", Cmdline_res));
}
}
if(center_res_arg.found()){
@@ -1847,6 +1838,10 @@ bool SetCmdlineParams()
Cmdline_no_screenshake = 1;
}
if ( deadzone.found() ) {
Cmdline_deadzone = deadzone.get_int();
}
if ( stretch_menu.found() ) {
Cmdline_stretch_menu = 1;
}
@@ -2131,6 +2126,11 @@ bool SetCmdlineParams()
Cmdline_benchmark_mode = true;
}
if (pilot_arg.found())
{
Cmdline_pilot = pilot_arg.str();
}
if (noninteractive_arg.found())
{
Cmdline_noninteractive = true;
@@ -2158,6 +2158,10 @@ bool SetCmdlineParams()
Cmdline_log_to_stdout = true;
}
if (slow_frames_ok_arg.found()) {
Cmdline_slow_frames_ok = true;
}
if (show_video_info.found())
{
Cmdline_show_video_info = true;
@@ -2259,6 +2263,22 @@ bool SetCmdlineParams()
}
}
}
if (prefer_ipv4_arg.found()) {
Cmdline_prefer_ipv4 = true;
}
if (prefer_ipv6_arg.found()) {
Cmdline_prefer_ipv6 = true;
// Rule 2: Not both
if (Cmdline_prefer_ipv4) {
ReleaseWarning(LOCATION, "Cannot set preference for both IPv4 and IPv6! Reverting to default behavior...\n");
Cmdline_prefer_ipv4 = false;
Cmdline_prefer_ipv6 = false;
}
}
return true;
}
+5 -2
View File
@@ -30,7 +30,6 @@ extern char *Cmdline_game_password;
extern char *Cmdline_rank_above;
extern char *Cmdline_rank_below;
extern int Cmdline_cd_check;
extern int Cmdline_client_dodamage;
extern int Cmdline_closed_game;
extern int Cmdline_freespace_no_music;
extern int Cmdline_freespace_no_sound;
@@ -84,13 +83,13 @@ extern int Cmdline_rearm_timer;
extern int Cmdline_targetinfo;
// Gameplay related
extern int Cmdline_3dwarp;
extern int Cmdline_ship_choice_3d;
extern int Cmdline_weapon_choice_3d;
extern int Cmdline_warp_flash;
extern int Cmdline_autopilot_interruptable;
extern int Cmdline_stretch_menu;
extern int Cmdline_no_screenshake;
extern int Cmdline_deadzone;
// Audio related
extern int Cmdline_voice_recognition;
@@ -124,6 +123,8 @@ extern bool Cmdline_no_geo_sdr_effects;
extern bool Cmdline_set_cpu_affinity;
extern bool Cmdline_nograb;
extern bool Cmdline_noshadercache;
extern bool Cmdline_prefer_ipv4;
extern bool Cmdline_prefer_ipv6;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
@@ -144,6 +145,7 @@ extern int Cmdline_reparse_mainhall;
extern bool Cmdline_profile_write_file;
extern bool Cmdline_no_unfocus_pause;
extern bool Cmdline_benchmark_mode;
extern const char *Cmdline_pilot;
extern bool Cmdline_noninteractive;
extern bool Cmdline_json_profiling;
extern bool Cmdline_frame_profile;
@@ -151,6 +153,7 @@ extern bool Cmdline_show_video_info;
extern bool Cmdline_debug_window;
extern bool Cmdline_graphics_debug_output;
extern bool Cmdline_log_to_stdout;
extern bool Cmdline_slow_frames_ok;
enum class WeaponSpewType { NONE = 0, STANDARD, ALL };
extern WeaponSpewType Cmdline_spew_weapon_stats;
File diff suppressed because it is too large. Load diff
+642 -64
View File
@@ -15,69 +15,72 @@
#define CONTROL_CONFIG_XSTR 507
#define CCF_AXIS_BTN 0x40 //!< axis is a button on positive side. If also inverted, is on negative side instead
#define CCF_RELATIVE 0x20 //!< axis is relative
#define CCF_INVERTED 0x10 //!< axis is inverted
#define CCF_AXIS 0x08 //!< btn is an axis
#define CCF_HAT 0x04 //!< btn is a hat
#define CCF_BALL 0x02 //!< btn is a ball
/*!
* These are used to index a corresponding joystick axis value from an array.
* These are used to index a corresponding axis value from an array.
* Currently only used by ::Axis_map_to[] and ::Axis_map_to_defaults[]
*/
enum Joy_axis_index {
enum Joy_axis_index : short {
JOY_X_AXIS =0,
JOY_Y_AXIS,
JOY_Z_AXIS,
JOY_RX_AXIS,
JOY_RY_AXIS,
JOY_RZ_AXIS
JOY_RZ_AXIS,
JOY_NUM_AXES // Number of axes a joystick may have. Must be last enum in Joy_axis_index.
};
// Aliases for mouse axes. Really should unify this...
const short MOUSE_X_AXIS = JOY_X_AXIS;
const short MOUSE_Y_AXIS = JOY_Y_AXIS;
const short MOUSE_Z_AXIS = JOY_Z_AXIS;
const short MOUSE_NUM_AXES = 3;
const short MOUSE_NUM_BUTTONS = 9; // Keep this up to date with mouse.h until z64555 stops being lazy and does it right
/*!
* These are used to index a corresponding (analog) action, namely controlling the orientation angles and throttle.
* Controller index enumeration
* @details For use with hardcoded bindings and scripting API to allow human-readable translation
* @note These enums are hardcoded so that an int value of 0 would be JOY0
*/
enum Joy_axis_action_index {
JOY_HEADING_AXIS =0,
JOY_PITCH_AXIS,
JOY_BANK_AXIS,
JOY_ABS_THROTTLE_AXIS,
JOY_REL_THROTTLE_AXIS,
/*!
* This must always be below the last defined item
*/
NUM_JOY_AXIS_ACTIONS //!< The total number of actions an axis may map to
enum CID : int8_t {
CID_NONE = -3, //!< No device bound
CID_KEYBOARD = -2, //!< belongs to keyboard
CID_MOUSE = -1, //!< to mouse
CID_JOY0 = 0, //!< to Joy0
CID_JOY1 = 1, //!< to Joy1 (Throttle?)
CID_JOY2 = 2, //!< to Joy2 (Pedals?)
CID_JOY3 = 3, //!< to Joy3 (Head tracker?)
CID_JOY_MAX //!< Maximum supported joysticks, must be last in the enum definition
};
/*!
* Control Configuration Types. Namely differ in how the control is activated
*/
enum CC_type {
CC_TYPE_TRIGGER =0, //!< A normal, one-shot type control that is activated when a key is or button is pressed
CC_TYPE_CONTINUOUS //!< A continous control that is activated as long as the key or button is held down
CC_TYPE_TRIGGER = 0, //!< A normal, one-shot type control that is activated when a key is or button is pressed
CC_TYPE_CONTINUOUS, //!< A continous control that is activated as long as the key or button is held down
CC_TYPE_AXIS_ABS, //!< Absolute Axis mode. Axis position = output value
CC_TYPE_AXIS_REL, //!< Relative Axis mode. Axis postion away from its center adds or subtracts an output value register
CC_TYPE_AXIS_BTN_NEG, //!< Axis Button mode, negative side. Axis position in the negative side will trigger a button action
CC_TYPE_AXIS_BTN_POS //!< Axis Button mode, positive side. Axis position in the positive side will trigger a button action
};
/*!
* Control configuration item type.
*/
typedef struct config_item {
short key_default; //!< default key bound to action
short joy_default; //!< default joystick button bound to action
char tab; //!< what tab (category) it belongs in
int indexXSTR; //!< what string index we should use to translate this with an XSTR
const char *text; //!< describes the action in the config screen
char type; //!< manner control should be checked in
short key_id; //!< actual key bound to action
short joy_id; //!< joystick button bound to action
int used; //!< has control been used yet in mission? If so, this is the timestamp
bool disabled; //!< whether this action should be available at all
bool continuous_ongoing;//!< whether this action is a continuous one and is currently ongoing
} config_item;
/*!
* All available actions
* This is the value of the id field in config_item
* The first group of items are ship targeting.
*
* Note: Do not adjust the order or numeric value
*/
enum IoActionId {
enum IoActionId : int {
TARGET_NEXT =0, //!< target next
TARGET_PREV =1, //!< target previous
TARGET_NEXT_CLOSEST_HOSTILE =2, //!< target the next hostile target
@@ -252,7 +255,7 @@ enum IoActionId {
DOWN_SLIDE_THRUST =111, //!< DOWN_SLIDE_THRUST
HUD_TARGETBOX_TOGGLE_WIREFRAME =112, //!< HUD_TARGETBOX_TOGGLE_WIREFRAME
VIEW_TOPDOWN =113, //!< VIEW_TOPDOWN
VIEW_TRACK_TARGET =114, //!< VIEW_TRACK_TARGET
VIEW_TRACK_TARGET =114, //!< VIEW_TRACK_TARGET (Switfty) Toggle for VM_Track
//!< @n
//!< AutoPilot - Kazan
@@ -279,69 +282,644 @@ enum IoActionId {
CUSTOM_CONTROL_4 = 122,
CUSTOM_CONTROL_5 = 123,
//!< @n
//!< Analog controls
//!<-----------------------------
//!< All axis actions must be kept together
JOY_HEADING_AXIS = 124,
JOY_PITCH_AXIS = 125,
JOY_BANK_AXIS = 126,
JOY_ABS_THROTTLE_AXIS = 127,
JOY_REL_THROTTLE_AXIS = 128,
/*!
* This must always be below the last defined item
*/
CCFG_MAX //!< The total number of defined control actions (or last define + 1)
};
extern int Failed_key_index;
// Constants for array-based checking (within Control_config) for the axis actions.
// z64: Yes, this is hackish. No I don't really like it.
const int JOY_AXIS_BEGIN = JOY_HEADING_AXIS;
const int JOY_AXIS_END = JOY_REL_THROTTLE_AXIS + 1;
const int NUM_JOY_AXIS_ACTIONS = JOY_AXIS_END - JOY_AXIS_BEGIN;
extern int Axis_map_to[];
extern int Invert_axis[];
extern int Invert_axis_defaults[];
/*!
* @brief Enum for indexing into axis action arrays.
* @note Keep this up to date with JOY_HEADING_AXIS and friends. Pay attention to their order and copy to here
*/
namespace Action {
enum {
HEADING = 0,
PITCH,
BANK,
ABS_THROTTLE,
REL_THROTTLE,
NUM_VALUES
};
}
class CCB;
/*!
* A singular button binding
*/
class CC_bind {
public:
CC_bind() = default;
CC_bind(CID _cid, short _btn) : cid(_cid), btn(_btn) { validate(); };
CC_bind(CID _cid, short _btn, char _flags) : cid(_cid), flags(_flags), btn(_btn) { validate(); };
CC_bind(const CC_bind &A) = default;
CC_bind& operator=(const CC_bind &A) = default;
/*!
* Checks if this CC_bind is equal to the given CC_bind
*
* @note EQUAL means EQUAL, this will return FALSE if the flags differ by a single bit
*/
bool operator==(const CC_bind &B) const;
/*!
* Checks if this CC_bind is not equal to the given CC_bind
*/
bool operator!=(const CC_bind &B) const;
/*!
* Checks if this CC_bind is equal to the given CC_bind, disregarding the inversion flag
*/
bool invert_agnostic_equals(const CC_bind &B) const;
/*!
* Clears the binding and flags. Some flags are retained.
*/
void clear();
/*!
* True if not bound
*/
bool empty() const;
/*!
* Returns a copy of ::btn
*/
short get_btn() const;
/*!
* Returns a copy of ::cid
*/
CID get_cid() const;
/*!
* Returns a copy of ::flags
*/
char get_flags() const;
/**
* Takes the given binding.
*/
void take(CID _cid, short _btn, char _flags = 0);
/**
* Validates the binding, clearing it if necassary
*/
void validate();
/*!
* Returns a human-readable string of this binding
*/
SCP_string textify() const;
/*!
* Sets the inversion state of this binding according to the passed bool. True = inverted, false = normal
*/
void invert(bool);
/*!
* Toggles the inversion state
*/
void invert_toggle();
/*!
* Is true if inverted, false otherwise
*/
bool is_inverted() const;
/*!
* Checks if this CC_bind conflicts with the given argument
*
* @note Similar to operator==, but ignores certain combinations of flags.
*/
bool conflicts_with(const CC_bind&) const;
private:
CID cid = CID_NONE; //!< Which controller this belongs to
char flags = 0; //!< mask to determine various additional attributes of btn
short btn = -1; //!< The button, key combo, or axis that's bound.
};
/*!
* A pair of bindings.
* @note Please don't set the bindings directly, use ::take() instead.
*/
class CCB {
public:
CC_bind first; // The primary binding
CC_bind second; // The secondary binding
public:
CCB() = default;
CCB(const CCB& A) = default;
/*!
* Returns true if nothing is bound
*/
bool empty() const;
/*!
* Takes a given binding
*
* @param[in] A The bind to take
* @param[in] order 0 is primary, 1 is secondary, -1 is overwrite existing bind (if any)
*
* @note Should there be a binding to the same controller as the given binding, it is cleared
*/
void take(CC_bind A, int order);
/*!
* Clears both bindings
*/
void clear();
/*!
* Gets the value of btn if either CC_bind has the given CID
*
* @returns the btn of the bound controller, or
* @returns -1 if that controller is not bound
*/
short get_btn(CID) const;
/*!
* Assigns the contents of the given CCB to this CCB
*/
CCB& operator=(const CCB&) = default;
/*!
* Checks if the given CCB is exactly equal to this
*/
bool operator==(const CCB&);
/*!
* Checks if the given CCB differs from this
*/
bool operator!=(const CCB&);
/*!
* Returns True if this CCB's first isn't empty and the given CCB has a binding that can conflict with it
*/
bool has_first_conflict(const CCB&) const;
/*!
* Returns True if this CCB's second isn't empty and the given CCB has a binding that can conflict with it
*/
bool has_second_conflict(const CCB&) const;
/*!
* Returns a pointer to first, or second, whichever has a binding equal to the given CC_bind, or nullptr if neither
*/
CC_bind* find(const CC_bind&);
/*!
* Returns a pointer to first, or second, whichever has a CID equal to the given CID, or nullptr if neither
*/
CC_bind* find(CID);
/*!
* Returns a pointer to first, or second, whichever has *all* flags in the given mask
*/
CC_bind* find_flags(const char);
};
/*!
* A preset, a collection of bindings for use in Control_config with an associated name
*/
class CC_preset {
public:
SCP_vector<CCB> bindings;
SCP_string name;
public:
/*!
* Checks if the given preset is a duplicate of this one
*/
bool is_duplicate_of(CC_preset&);
};
/*!
* Control configuration item type.
* @detail Contains binding info, documentation, behavior, etc. for a single control
*/
class CCI : public CCB {
public:
// Inherited from CCB
// CC_bind first;
// CC_bind second;
// Items Set in menu
char tab; //!< what tab (category) it belongs in
int indexXSTR; //!< what string index we should use to translate this with an XSTR 0 = None, 1= Use item index + CONTROL_CONFIG_XSTR, 2 <= use CCI::indexXSTR directly
SCP_string text; //!< describes the action in the config screen
CC_type type; //!< manner control should be checked in
// Items used during gameplay
int used; //!< has control been used yet in mission? If so, this is the timestamp
bool disabled = true; //!< whether this action should be available at all
bool continuous_ongoing; //!< whether this action is a continuous one and is currently ongoing
public:
CCI() = default;
CCI(const CCI& A) = default;
/*!
* Assigns the contents of the given CCI to this CCI
*/
CCI& operator=(const CCI&);
/*!
* @brief Takes the bindings of the given CCB, but leaves all other members alone
*/
CCI& operator=(const CCB&);
/*!
* Returns true if this item is analogue or an axis
*/
bool is_axis();
};
/*!
* Builder predicate to populate a ControlConfig vector with hardcoded default bindings.
*/
class CCI_builder {
public:
/*!
* Initilizes the given ControlConfig vector
*/
CCI_builder(SCP_vector<CCI>& _ControlConfig);
/*!
* Start a chain of factory methods. If there are any pre-init work to be done, that's done here.
*/
CCI_builder& start();
/*!
* End a chain of factory methods. If there any post-init work to be done, that's done here.
*/
void end();
/*!
* Assigns the hardcoded binding to the given action
*
* @note This differs from the original hardcode from :V: in the hopes of it being more intuitive to future IoAction additions
*
* param[in] action_id The IoActionId enum associated with the control
* param[in] primary The btn, key combo, or axis for the default primary binding
* param[in] secondary The btn, key combo, or axis for the default secondary binding
* param[in] tab Category tab this control should show up under on the config menu
* param[in] indexXSTR ID for the XSTR localization utility. 0 for no localization, 1 for automatic lookup, all other values are index for item in strings.tbl
* param[in] text Label text displayed in the config menu.
* param[in] type How the control should be treated. see doxy on CC_type for details
* param[in] disabled If true, this control will not be available in the game. Controlsconfigdefaults.tbl may override this. Don't use this to temporarily disable controls in mission.
*
* @details The CID for the default primary and secondary is determined by the type parameter.
* If the type is CC_TYPE_TRIGGER or CC_TYPE_CONTINOUS, the primary is assumed to be a key combo and secondary is assumed to be a joy button.
* If the type is CC_TYPE_AXIS_ABS, CC_TYPE_AXIS_REL, CC_TYPE_AXIS_BTN_POS, or CC_TYPE_AXIS_BTN_NEG, the primary is a Joy0 axis and the secondary is a Mouse axis
*/
CCI_builder& operator()(IoActionId action_id, short primary, short secondary, char tab, int indexXSTR, const char *text, CC_type type, bool disabled = false);
private:
CCI_builder(); // Only one builder per Control Config, so a default constructor is useless
SCP_vector<CCI>& ControlConfig;
};
extern int Failed_key_index;
extern int Joy_dead_zone_size;
extern int Joy_sensitivity;
extern int Control_config_overlay_id;
extern config_item Control_config[]; //!< Stores the keyboard configuration
extern SCP_vector<config_item*> Control_config_presets; // tabled control presets; pointers to config_item arrays
extern SCP_vector<SCP_string> Control_config_preset_names; // names for Control_config_presets (identical order of items)
extern SCP_vector<CCI> Control_config; //!< Stores the keyboard configuration
extern SCP_vector<CC_preset> Control_config_presets; // tabled control presets; pointers to config_item arrays
extern const char **Scan_code_text;
extern const char **Joy_button_text;
extern const char **Joy_button_text; // String table of button labels. XSTR'd on init.
void control_config_common_init(); //!< initialize common control config stuff - call at game startup after localization has been initialized
void control_config_common_close(); //!< close common control config stuff - call at game shutdown
// string table constants for labels and stuff.
#define NUM_AXIS_TEXT JOY_NUM_AXES
#define NUM_MOUSE_TEXT MOUSE_NUM_BUTTONS
extern char *Axis_text[NUM_AXIS_TEXT]; // String table of axis labels (joystick and mice). XSTR'd on init.
extern char *Mouse_button_text[NUM_MOUSE_TEXT]; // String table of mouse button labels. XSTR'd on init.
/*!
* @brief Checks if either binding in the CCB has the given cid
*
* @returns 0 if its the first element, or
* @returns 1 if its the second element, or
* @returns -1 if neither
*/
int is_cid_either(CID, const CCB);
/*!
* Allows CID to be assigned by a short. Has Assert to check values
*/
void cid_assign(CID&, const short);
/*!
* @brief initialize common control config stuff - call at game startup after localization has been initialized
*/
void control_config_common_init();
/*!
* @brief close common control config stuff - call at game shutdown
*/
void control_config_common_close();
/*!
* @brief init config menu
*/
void control_config_init();
/*!
* @brief do a frame of the config menu
*/
void control_config_do_frame(float frametime);
/*!
* @brief close config menu
*/
void control_config_close();
/*!
* @brief Cancel configuration of controls, revert any changes, return to previous menu/game state
*/
void control_config_cancel_exit();
void control_config_reset_defaults(int presetnum=-1);
/*!
* @brief Copies all bindings within preset into Control_config
*/
void control_config_use_preset(CC_preset &preset);
/*!
* @brief Search for a given preset by name and use it, if it exists.
*
* @returns TRUE if the preset was found and selected
* @returns FALSE if the preset was not found, and the defaults were selected
*
* @details If the preset does not exist, then defaults are used instead.
* @see control_config_use_preset()
*/
bool control_config_use_preset_by_name(const SCP_string &name);
/**
* @brief Gets the currently used preset
*
* @param[in] invert_agnostic If true, check the bindings in Control_config against the preset, ignoring inversion flags
*
* @returns an iterator to the current preset, or
* @returns ::iterator Control_config_presets.end() if current bindings are not in a preset
*/
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic = false);
/*!
* Returns the IoActionId (index within Control_config[]) of a control bound to the given key
*
* @param[in] key The key combo to look for
* @param[in] find_override If true, return the IoActionId of a control that has this key as its default
*
* @return -1 if the given key is NULL or not bound.
*
* @details If find_override is set to true, then this returns the index of the action
*/
int translate_key_to_index(const char *key, bool find_override=true);
char *translate_key(char *key);
/*!
* @brief Given the system default key 'key', return the current control input(s) that is bound to that function.
*
* @param[in] key The default key combo (as cstring) to a certain control
*
* @return The key combo (as cstring) currently bound to the control, or
* @return nullptr if the given key is not a system default key, or
* @return "None" if there is nothing bound to the control
*
* @details Both the 'key' and the return value are descriptive strings that can be displayed
* directly to the user. If 'key' isn't a real key, is not normally bound to anything,
* or there is no key currently bound to the function, nullptr is returned.
*
* @note Not thread safe. Has an internal buffer for the return value which is overwritten on each call.
*
* @note Uses CC_bind::textify for translations
*/
const char *translate_key(char *key);
/**
* @brief Converts the specified key code to a human readable string
* @brief Converts the specified key code to a human readable string, according to the selected locale
*
* @note The returned value is localized to the current language
* @param[in] code The key code to convert
* @param[in] use_default_locale If true, return the default locale (English) translation of the key
*
* @param code The key code to convert
* @return The text representation of the code. The returned value is stored in a temporary location, copy it to your
* own buffer if you want to continue using it.
* @return The text representation of the code.
*
* @note Not thread safe. Has an internal buffer for the return value which is overwritten on each call.
*
* @note The return value is translated according to localization settings
*/
const char *textify_scancode(int code);
const char *textify_scancode(int code, bool use_default_locale = false);
/**
* @note Same as textify_scancode but always returns the same value regardless of current language
* @param code The key code to convert
* @return The name of the key
* @see textify_scancode
/*!
* @brief Checks how long a control has been active
*
* @param[in] id The IoActionId of the control to check
*
* @returns Time, in milliseconds, that the control has been active.
*
* @note This function is only to be used on CC_CONTINOUS type controls, or it will trigger an assertion
*/
const char *textify_scancode_universal(int code);
float check_control_timef(int id);
/**
* @brief Wrapper for check_control_used. Allows the game to ignore the key if told to do so by the ignore-key SEXP.
*
* @param[in] id The IoActionId of the control to check
* @param[in] key The key combo to check against the control. If -1, re-check the last key passed to this function
*
* @returns 0 If the control wasn't used, or
* @returns 1 If the control was used
*
* @details If the given control is CC_CONTINOUS, param key is effectively ignored and instead keyd_press[] is checked.
* This function also checks against joy and mouse presses.
*/
int check_control(int id, int key = -1);
void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr);
/**
* @brief Gets the scaled reading for all control axes.
*
* @param[in] frametime Frametime used to scale the mouse axes
* @param[out] axis_v Output array of all control axes, must have size of JOY_NUM_AXIS_ACTIONS
*
* @details
* * Clamps output to stay within +/-JOY_AXIS_RANGE.
* * Should multiple axes be bound to a control, their values are blended with a simple sum. This is to save a bit of
* processing for speed.
*/
void control_get_axes_readings(int *axis_v, float frame_time);
/**
* @brief Markes the given control (by IoActionId) as used
*
* @details Updates the ::used timestamp, triggers a script hook, and marks ::continous_ongoing as true
*/
void control_used(int id);
/**
* @brief Clears the bindings of all controls
*/
void control_config_clear();
/**
* @brief debug function used to indicate number of controls checked
*/
void control_check_indicate();
/**
* @brief Clears the used timestamp of all controls
*/
void control_config_clear_used_status();
/**
* @brief Applies sensitivity multiplier and deadzone histerisis to the raw axis value
*
* @param[in] raw The raw axis value to transform
*
* @return The transformed value
*/
int joy_get_scaled_reading(int raw);
/**
* Lookups the given stringified enum to find its value
* @return -1 if not found, or
* @return IoActionId if found
*/
int ActionToVal(const char * str);
/**
* Reverse lookups the IoActionId to get its stringified name
* @return Pointer to the stringified name of the action, or
* @return nullptr if not found
*/
const char * ValToAction(IoActionId id);
/**
* Reverse lookups the IoActionId to get its stringified name
* @return Pointer to the stringified name of the action, or
* @return nullptr if not found, or invalid id
*/
const char * ValToAction(int id);
/**
* Lookups the given stringified enum to find its value
*/
CID CIDToVal(const char * str);
/**
* Reverse lookups the CID to get its stringified name
* @return Pointer to the stringified name of the CID, or
* @return nullptr if not found
*/
const char * ValToCID(CID id);
/**
* Reverse lookups the CID to get its stringified name
* @return Pointer to the stringified name of the CID, or
* @return nullptr if not found, or invalid id
*/
const char * ValToCID(int id);
/**
* Lookups the given stringified enum to find its value
*/
char CCFToVal(const char * str);
/**
* Constructs a enum string from the CCF_FLAGS
* @return Pointer to the stringified name of the CCF, or
* @return nullptr if not found, or invalid id
*/
SCP_string ValToCCF(char id);
/**
* Lookups the given stringified enum to find its value
*/
short InputToVal(CID cid, const char * str);
/**
* Constructs a enumstring from the input binding, depending on the CID
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
*/
SCP_string ValToInput(const CC_bind &bind);
/**
* Lookups the given stringified enum to find its btn value
*/
short MouseToVal(const char * str);
/**
* Constructs a enum string from the mouse input
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
* TODO XSTR
*
* @note This requires a CCB due to the way things are encoded
*/
SCP_string ValToMouse(const CC_bind &bind);
/**
* Lookups the given stringified enum to find its btn value
*/
short KeyboardToVal(const char * str);
/**
* Constructs an enum string from the key binding
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
* TODO XSTR
*/
SCP_string ValToKeyboard(const CC_bind &bind);
/**
* Lookups the given stringified enum to find its value
*/
short JoyToVal(const char * str);
/**
* Constructs a enum string from the Joystick input
*
* @return Pointer to the stringified name of the input, or
* @return nullptr if not found, or invalid CC_bind
*
* @note This requires a CCB due to the way things are encoded
* TODO XSTR
*/
SCP_string ValToJoy(const CC_bind &bind);
#endif
File diff suppressed because it is too large. Load diff
+481
View File
@@ -0,0 +1,481 @@
#include "controlconfig/controlsconfig.h"
#include "controlconfig/presets.h"
#include "libs/jansson.h"
#include "parse/parselo.h"
#include <jansson.h>
using namespace io::presets;
const SCP_vector<std::pair<Section, const char*>> SectionMapping {
std::pair<Section, const char*>(Section::Unnamed, nullptr),
std::pair<Section, const char*>(Section::Actions, "actions"),
std::pair<Section, const char*>(Section::Primary, "primary"),
std::pair<Section, const char*>(Section::Secondary, "secondary"),
};
const char * lookupSectionName(Section id) {
for (const auto& pair: SectionMapping) {
if (pair.first == id) {
return pair.second;
}
}
return nullptr;
}
Section lookupSectionValue(const char* name) {
Assertion(name != nullptr, "Key name must be a valid pointer!");
for (auto& pair : SectionMapping) {
if (!strcmp(pair.second, name)) {
return pair.first;
}
}
return Section::Invalid;
}
void load_preset_files() {
SCP_vector<SCP_string> filelist;
cf_get_file_list(filelist, CF_TYPE_PLAYER_BINDS, NOX("*.json"), CF_SORT_NAME, nullptr,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
std::unique_ptr<PresetFileHandler> handler = nullptr;
for (const auto &file : filelist) {
CFILE* fp = cfopen((file + ".json").c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!fp) {
mprintf(("PLR => Unable to open '%s' for loading!\n", file.c_str()));
// try next
continue;
}
try {
handler.reset(new PresetFileHandler(fp, true));
} catch (const std::exception& e) {
mprintf(("PLR => Failed to open JSON: `%s`\n", e.what()));
continue;
}
// Check the signature
int pst_id = handler->readInt("signature");
if (pst_id != PST_FILE_ID) {
mprintf(("PST => Invalid header id for `%s`, skipping...\n", file.c_str()));
continue;
}
// Version
int version = handler->readInt("version");
mprintf(("PST => Loading `%s` with version %i\n", file.c_str(), version));
// Start reading in data
CC_preset preset;
preset.name = file;
preset.bindings.resize(Control_config.size());
size_t size;
handler->beginArrayRead(Section::Actions, size);
for (size_t i = 0; i < size; ++i, handler->nextArrayElement()) {
SCP_string str;
int id;
//handler->beginSectionRead(Section::Unnamed);
str = handler->readString("bind");
id = ActionToVal(str.c_str());
if (id < 0) {
// Unknown bind, possibly custom. Ignore for now
handler->endSectionRead(); // Unnamed
continue;
}
auto &item = preset.bindings[id];
handler->beginSectionRead(Section::Primary);
str = handler->readString("cid");
auto cid = CIDToVal(str.c_str());
str = handler->readString("flags");
auto flags = CCFToVal(str.c_str());
str = handler->readString("input");
auto btn = InputToVal(cid, str.c_str());
item.first.take(cid, btn, flags);
handler->endSectionRead(); // Primary
handler->beginSectionRead(Section::Secondary);
str = handler->readString("cid");
cid = CIDToVal(str.c_str());
str = handler->readString("flags");
flags = CCFToVal(str.c_str());
str = handler->readString("input");
btn = InputToVal(cid, str.c_str());
item.second.take(cid, btn, flags);
handler->endSectionRead(); // Secondary
//handler->endSectionRead(); // Unnamed
}
handler->endArrayRead(); // Actions
// Done with the file
bool unique = true;
auto it = Control_config_presets.begin();
for (; it != Control_config_presets.end(); ++it) {
if (preset.is_duplicate_of(*it)) {
unique = false;
break;
}
}
if (unique) {
Control_config_presets.push_back(preset);
} else {
Warning(LOCATION, "Preset '%s' is a duplicate of '%s', ignoring", preset.name.c_str(), it->name.c_str());
}
}
}
bool preset_file_exists(SCP_string name) {
if (name.find(".json") == std::string::npos) {
name.append(".json");
}
return cf_exists(name.c_str(), CF_TYPE_PLAYER_BINDS) != 0;
}
bool save_preset_file(CC_preset preset, bool overwrite) {
// Must have a name
if (preset.name.empty()) {
mprintf(("PST => Unable to save preset, missing name!\n"));
return false;
}
SCP_string filename = preset.name + ".json";
std::unique_ptr<PresetFileHandler> handler = nullptr;
// Check if there's a file already
CFILE* fp = cfopen(filename.c_str(), "r", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if ((fp != nullptr) && !overwrite) {
mprintf(("PST => Unable to save '%s', file already exists!\n", filename.c_str()));
return false;
}
// Try opening file for write
fp = cfopen(filename.c_str(), "w", CFILE_NORMAL, CF_TYPE_PLAYER_BINDS, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!fp) {
mprintf(("PST => Unable to save '%s', unknown error!\n", filename.c_str()));
}
try {
handler.reset(new PresetFileHandler(fp, false));
} catch (const std::exception& e) {
mprintf(("PST => Failed to open JSON: %s\n", e.what()));
return false;
}
// Write header and version
handler->writeInt("signature", PST_FILE_ID);
handler->writeInt("version", PST_VERSION);
mprintf(("PST => Saving %s with version %d...\n", filename.c_str(), (int)PST_VERSION));
handler->beginArrayWrite(Section::Actions);
for (int i = 0; static_cast<size_t>(i) < preset.bindings.size(); ++i) {
const auto& item = preset.bindings[i];
const auto& first = item.first;
const auto& second = item.second;
handler->beginSectionWrite(Section::Unnamed);
handler->writeString("bind", ValToAction(i));
handler->beginSectionWrite(Section::Primary);
handler->writeString("cid", ValToCID(first.get_cid()));
handler->writeString("flags", ValToCCF(first.get_flags()));
handler->writeString("input", ValToInput(first));
handler->endSectionWrite(); // Primary
handler->beginSectionWrite(Section::Secondary);
handler->writeString("cid", ValToCID(second.get_cid()));
handler->writeString("flags", ValToCCF(second.get_flags()));
handler->writeString("input", ValToInput(second));
handler->endSectionWrite(); // Secondary
handler->endSectionWrite(); // Control_config[i]
}
handler->endArrayWrite(); // Actions
handler->flush();
return true;
}
PresetFileHandler::PresetFileHandler(CFILE* cfp, bool reading) : _cfp(cfp) {
Assertion(cfp != nullptr, "File pointer must be valid!");
if (reading) {
json_error_t error;
_rootObj = json_load_cfile(cfp, 0, &error);
if (!_rootObj) {
SCP_string errorStr;
sprintf(errorStr, "Error while reading pilot file! %d: %s", error.line, error.text);
throw std::runtime_error(errorStr);
}
} else {
_rootObj = json_object();
}
_currentEl = _rootObj;
_elementStack.push_back(_currentEl);
};
PresetFileHandler::~PresetFileHandler() {
json_decref(_rootObj);
cfclose(_cfp);
_cfp = nullptr;
};
bool PresetFileHandler::beginSectionRead(Section s) {
const char * sectionName = lookupSectionName(s);
ensureExists(sectionName);
auto section = json_object_get(_currentEl, sectionName);
if (json_typeof(section) != JSON_OBJECT) {
Error(LOCATION, "Section must be a JSON object!");
return false;
}
pushElement(section);
return true;
};
void PresetFileHandler::beginSectionWrite(Section s) {
auto key_name = lookupSectionName(s);
json_t* obj = json_object();
if (json_is_array(_currentEl)) {
// Currently in an array, section must be unnamed
Assertion(key_name == nullptr, "Elements of array may not be named sections!");
json_array_append_new(_currentEl, obj);
} else {
Assertion(key_name != nullptr, "Section outside of arrays must be named!");
json_object_set_new(_currentEl, key_name, obj);
}
pushElement(obj);
};
bool PresetFileHandler::beginArrayRead(Section s, size_t &size) {
Assertion(_arrayIndex == INVALID_SIZE, "Array nesting is not supported yet!");
const char * name = lookupSectionName(s);
ensureExists(name);
auto array = json_object_get(_currentEl, name);
if (json_typeof(array) != JSON_ARRAY) {
Error(LOCATION, "Expected an array for '%s' but it was a different type!", name);
return false;
}
pushElement(array);
size = json_array_size(array);
if (size == 0) {
// Nothing to do here, avoid calling nextArraySection since that assumes that there is at least one element
return true;
} // Else, advance to the first element in the array
_arrayIndex = 0;
nextArrayElement();
return true;
}
void PresetFileHandler::beginArrayWrite(Section s) {
const char * name = lookupSectionName(s);
auto array = json_array();
if (json_is_array(_currentEl)) {
// We are in an array, section must be unnamed
Assertion(name == nullptr, "Inside an array there can be no named section!");
json_array_append_new(_currentEl, array);
} else {
Assertion(name != nullptr, "Section outside of arrays must be named!");
json_object_set_new(_currentEl, name, array);
}
pushElement(array);
}
void PresetFileHandler::endSectionRead() {
Assertion(json_typeof(_currentEl) == JSON_OBJECT, "Current element for section reading is not an object!");
popElement();
};
void PresetFileHandler::endSectionWrite() {
Assertion(json_is_object(_currentEl), "Section ended while not in a section!");
popElement();
};
void PresetFileHandler::endArrayRead() {
// First, remove the element we are currently in if it exists
if (json_typeof(_currentEl) != JSON_ARRAY) {
popElement();
}
Assertion(json_typeof(_currentEl) == JSON_ARRAY, "Current element must be an array!");
// TODO Sections are straightforward, but Arrays may need special consideration re: index.
popElement();
_arrayIndex = INVALID_SIZE;
};
void PresetFileHandler::endArrayWrite() {
Assertion(json_is_array(_currentEl), "Array ended while not in an array!");
popElement();
};
void PresetFileHandler::ensureExists(const char* name) {
if (json_typeof(_currentEl) != JSON_OBJECT) {
Error(LOCATION, "JSON reading requires a value with name '%s' but the current element is not an object!", name);
}
if (json_object_get(_currentEl, name) == nullptr) {
Error(LOCATION, "JSON reading requires a value with name '%s' but there is no such value!", name);
}
}
void PresetFileHandler::ensureNotExists(const char* name) {
// Stuff debug checks into booleans, otherwise clang will trigger a false positive for static method with just the asserts
// Make sure we're in an element that can support keys
bool supports_keys = json_is_object(_currentEl);
// Make sure we don't overwrite previous values
bool element_is_unique = json_object_get(_currentEl, name) == nullptr;
Assertion(supports_keys, "Currently not in an element that supports keys!");
Assertion(element_is_unique, "Entry with name %s already exists!", name);
}
bool PresetFileHandler::exists(const char* name) {
if (json_typeof(_currentEl) != JSON_OBJECT) {
return false;
}
if (json_object_get(_currentEl, name) == nullptr) {
return false;
}
return true;
}
void PresetFileHandler::flush() {
Assertion(_elementStack.size() == 1, "Not all sections or arrays have been ended!");
json_dump_cfile(_rootObj, _cfp, JSON_INDENT(4) | JSON_PRESERVE_ORDER);
}
void PresetFileHandler::nextArrayElement() {
Assertion(_arrayIndex != INVALID_SIZE, "Array index must be valid for this function!");
bool in_section = json_is_object(_currentEl);
if (in_section) {
// We have to pop the previous section first
popElement();
Assertion(json_typeof(_currentEl) == JSON_ARRAY, "The previous element should have been an array!");
}
auto max = json_array_size(_currentEl);
Assertion(_arrayIndex <= max, "Invalid array index detected!");
// Silently ignore if we are one past the last element since this function is used in a for loop where this function
// is executed one time after the index is incremented past the last element
if (_arrayIndex == max) {
// Increment the index so we catch usage errors the next time someone tries to call this function
++_arrayIndex;
return;
}
// We use the current array index and then increment it to avoid skipping the first element
auto el = json_array_get(_currentEl, _arrayIndex);
++_arrayIndex;
pushElement(el);
}
json_t * PresetFileHandler::popElement() {
Assertion(_elementStack.size() > 1, "Element stack may not get smaller than one element!");
_elementStack.pop_back();
_currentEl = _elementStack.back();
return _currentEl;
}
void PresetFileHandler::pushElement(json_t* el) {
Assertion(el != nullptr, "Invalid JSON element pointer passed!");
_currentEl = el;
_elementStack.push_back(_currentEl);
}
SCP_string PresetFileHandler::readString(const char* key) {
auto el = json_object_get(_currentEl, key);
if (el == nullptr || json_typeof(el) != JSON_STRING) {
Error(LOCATION, "JSON element %s must be a string but it is not valid!", key);
return SCP_string();
}
auto json_str = json_string_value(el);
SCP_string val;
val.assign(json_str, json_str + json_string_length(el));
return val;
}
int PresetFileHandler::readInt(const char* key) {
auto el = json_object_get(_currentEl, key);
if (el == nullptr || json_typeof(el) != JSON_INTEGER) {
Error(LOCATION, "JSON element %s must be an integer but it is not valid!", key);
return 0;
}
return static_cast<int>(json_integer_value(el));
}
void PresetFileHandler::writeString(const char* key, SCP_string s) {
ensureNotExists(key);
json_t *jstr = nullptr;
if (!s.empty()) {
// if this string isn't proper UTF-8, try to convert it
if (utf8::find_invalid(s.begin(), s.end()) != s.end()) {
SCP_string buffer;
coerce_to_utf8(buffer, s.c_str());
jstr = json_string(buffer.c_str());
} else {
jstr = json_string(s.c_str());
}
}
json_object_set_new(_currentEl, key, jstr);
};
void PresetFileHandler::writeInt(const char* key, int val) {
ensureNotExists(key);
json_object_set_new(_currentEl, key, json_integer(val));
}
+222
View File
@@ -0,0 +1,222 @@
#pragma once
#include "cfile/cfile.h"
#include "controlconfig/controlsconfig.h"
#include "globalincs/pstypes.h"
#include "globalincs/vmallocator.h"
#include <jansson.h>
/** API for saving and loading player custom bindings, known as Presets
Init. If the player/preset dir doesn't exist. Create it, and print a help.txt with all enums (as strings) to label
the button names and action names.
Example output:
{
"actions": {
"TARGET_NEXT": {
"first": {
"cid": 0,
"flags": 0,
"btn": 0
},
"second": {
"cid": 0,
"flags": 0,
"btn": 0
}
},
"TARGET_PREV" : {
"first": {
"cid": 0,
"flags": 0,
"btn": 0
},
"second": {
"cid": 0,
"flags": 0,
"btn": 0
}
},
},
"version": 0
}
*/
namespace io {
namespace presets {
static const unsigned int PST_VERSION = 0;
static const unsigned int PST_FILE_ID = 0x5f545350; // "PST_" in file
enum class Section {
Invalid = -1,
Unnamed = 0,
// arrays
Actions,
// subsections
Primary,
Secondary
};
class PresetFileHandler {
public:
PresetFileHandler(CFILE* cfp, bool reading);
~PresetFileHandler();
/**
* begins writing to a section using the presets::Section as its name
* @param[in] s id of the section
*/
void beginSectionWrite(presets::Section s);
/**
* begins reading a section, if it exists
* @param[in] s id of the section
*/
bool beginSectionRead(presets::Section s);
/**
* Begins writing to an array using the presets::Section as its name
*
* @param[in] s id of the array
*/
void beginArrayWrite(presets::Section s);
/**
* Begins reading from an array
* @param[int] s id of the array
* @param[out] size the size of the array
*/
bool beginArrayRead(presets::Section s, size_t &size);
/**
* ends writing to a section
*/
void endSectionWrite();
/**
* ends reading a section
*/
void endSectionRead();
/**
* ends writing to an array.
*/
void endArrayWrite();
/**
* ends reading from an array
*/
void endArrayRead();
/**
* Writes a string with the given key name
*/
void writeString(const char* key, SCP_string s);
/**
* Reads a string with the given key name
*/
SCP_string readString(const char* key);
/**
* Writes an int with the given key name
*/
void writeInt(const char* key, int val);
/**
* Reads an int with the given key name
*/
int readInt(const char* key);
/**
* For writing, Flushes the buffers and dumps to file
*/
void flush();
/**
* Advances the array parser to the next element
*/
void nextArrayElement();
private:
CFILE* _cfp = nullptr;
json_t* _rootObj = nullptr;
json_t* _currentEl = nullptr;
/**
* BufferStack of all json elements being read/written
*/
SCP_vector<json_t*> _elementStack;
/**
* Stack to keep track of the heirachy/nesting. Back is immediate parent, Front is root
*/
SCP_vector<void*> _parentStack;
size_t _arrayIndex = INVALID_SIZE;
//void* _sectionIterator = nullptr; //!< Pointer to the current section/array we're in
private:
/**
* Pushes an element onto the elementStack
*/
void pushElement(json_t* el);
/**
* Pops an element off the elementStack
*/
json_t * popElement();
/**
* Used for optionals, checks if an element exists with the given name
* @return True if the element exists
* @return False otherwise
*/
bool exists(const char* name);
/**
* Throws an error if an element with the given name does not exist
*/
void ensureExists(const char* name);
/**
* Throws an error if an element with the given name exists
*/
void ensureNotExists(const char* name);
};
} // namespace presets
} // namespace io
/**
* @brief Saves the given preset to file.
* @param[in] preset The preset to save
* @param[in] overwrite If true, overwrite existing preset file which have the same name as the given preset
*
* @returns True if successful, or
* @returns False Preset does not have a name, or
* @returns False Preset file exists and overwrite == false, or
* @returns False Preset file .JSON could not be written
*/
bool save_preset_file(CC_preset preset, bool overwrite);
/**
* @brief Loads in all preset .json files from 'players/presets'
* @details If a preset file is unique, it is loaded into the game and available for use by the player. However, if
* a preset is a duplicate of another preset, it is ignored, and the player is warned of it
*/
void load_preset_files();
/**
* @brief Returns true if a preset file with the given name exists.
*/
bool preset_file_exists(SCP_string name);
+2 -3
View File
@@ -93,13 +93,12 @@ class Decoder {
bool m_decoding;
size_t m_queueSize = 0;
Decoder(const Decoder&) SCP_DELETED_FUNCTION;
Decoder& operator=(const Decoder&) SCP_DELETED_FUNCTION;
protected:
Decoder();
public:
Decoder(const Decoder&) = delete;
Decoder& operator=(const Decoder&) = delete;
virtual ~Decoder();
+1 -1
View File
@@ -613,7 +613,7 @@ void cutscenes_screen_do_frame()
if (src)
{
Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines,
Cutscene_max_text_lines[gr_screen.res]);
Cutscene_max_text_lines[gr_screen.res], MAX_TEXT_LINE_LEN);
Assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
}
}
+38 -28
View File
@@ -229,7 +229,7 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
auto ctx = stream->m_ctx->ctx();
auto videoStream = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &status->videoCodec, 0);
auto videoStream = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (videoStream < 0) {
if (videoStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No video stream found in file!\n"));
@@ -242,10 +242,26 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
return nullptr;
}
status->videoStreamIndex = videoStream;
status->videoStream = ctx->streams[videoStream];
status->videoCodecPars = getCodecParameters(status->videoStream);
status->videoCodec = avcodec_find_decoder(status->videoCodecPars.codec_id);
if ( !status->videoCodec ) {
mprintf(("FFmpeg: Cannot find decoder for video stream!\n"));
return nullptr;
}
if (properties.looping && status->videoCodecPars.codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) {
mprintf(("FFmpeg: Looping is not supported for inteplay (MVE) movies!\n"));
return nullptr;
}
int audioStream = -1;
if (properties.with_audio) {
audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, &status->audioCodec, 0);
audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, nullptr, 0);
if (audioStream < 0) {
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No audio stream found in file!\n"));
@@ -254,17 +270,21 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
} else {
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
}
} else {
status->audioStreamIndex = audioStream;
status->audioStream = ctx->streams[audioStream];
status->audioCodecPars = getCodecParameters(status->audioStream);
status->audioCodec = avcodec_find_decoder(status->audioCodecPars.codec_id);
if ( !status->audioCodec ) {
mprintf(("FFmpeg: Cannot find decoder for audio stream!\n"));
status->audioStreamIndex = -1;
audioStream = -1;
}
}
}
status->videoStreamIndex = videoStream;
status->videoStream = ctx->streams[videoStream];
if (audioStream >= 0) {
status->audioStreamIndex = audioStream;
status->audioStream = ctx->streams[audioStream];
}
if (subt) {
auto subtCtx = subt->m_ctx->ctx();
@@ -278,15 +298,19 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
mprintf(("FFmpeg: Unknown error while finding subtitle stream!\n"));
}
} else {
status->subtitleStreamIndex = subtStream;
status->subtitleStream = subtCtx->streams[subtStream];
status->externalSubtitles = true;
status->subtitleStreamIndex = subtStream;
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
}
}
if (status->subtitleStream == nullptr) {
// We don't have an external subtitle stream or loading from that file has failed
auto& current_language = Lcl_languages[Lcl_current_lang == LCL_UNTRANSLATED ? LCL_DEFAULT : Lcl_current_lang];
auto& current_language = Lcl_languages[lcl_get_current_lang_index()];
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
auto test_stream = ctx->streams[i];
@@ -312,13 +336,6 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
}
}
status->videoCodecPars = getCodecParameters(status->videoStream);
if (properties.looping && status->videoCodecPars.codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) {
mprintf(("FFmpeg: Looping is not supported for inteplay (MVE) movies!\n"));
return nullptr;
}
int err;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->videoCodecCtx = avcodec_alloc_context3(status->videoCodec);
@@ -348,8 +365,6 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
// Now initialize audio, if this fails it's not a fatal error
if (audioStream >= 0) {
status->audioCodecPars = getCodecParameters(status->audioStream);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->audioCodecCtx = avcodec_alloc_context3(status->audioCodec);
@@ -376,11 +391,6 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
}
if (status->subtitleStream != nullptr) {
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->subtitleCodecCtx = avcodec_alloc_context3(status->subtitleCodec);
@@ -428,7 +438,7 @@ std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string& name)
{
auto& current_language = Lcl_languages[Lcl_current_lang == LCL_UNTRANSLATED ? LCL_DEFAULT : Lcl_current_lang];
auto& current_language = Lcl_languages[lcl_get_current_lang_index()];
for (auto ext : CHECKED_SUBT_EXTENSIONS) {
SCP_string fileName;
@@ -453,7 +463,7 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName, const PlaybackPropert
{
SCP_string movieName = fileName;
// First make the file name lower case
std::transform(movieName.begin(), movieName.end(), movieName.begin(), [](char c) { return (char)::tolower(c); });
SCP_tolower(movieName);
// Then remove the extension
size_t dotPos = movieName.find('.');
+7 -9
View File
@@ -24,13 +24,13 @@ struct DecoderStatus {
int videoStreamIndex = -1;
AVStream* videoStream = nullptr;
CodecContextParameters videoCodecPars;
AVCodec* videoCodec = nullptr;
const AVCodec* videoCodec = nullptr;
AVCodecContext* videoCodecCtx = nullptr;
int audioStreamIndex = -1;
AVStream* audioStream = nullptr;
CodecContextParameters audioCodecPars;
AVCodec* audioCodec = nullptr;
const AVCodec* audioCodec = nullptr;
AVCodecContext* audioCodecCtx = nullptr;
// Subtitles are a bit different since they max come from a different file
@@ -38,17 +38,15 @@ struct DecoderStatus {
int subtitleStreamIndex = -1;
AVStream* subtitleStream = nullptr;
CodecContextParameters subtitleCodecPars;
AVCodec* subtitleCodec = nullptr;
const AVCodec* subtitleCodec = nullptr;
AVCodecContext* subtitleCodecCtx = nullptr;
DecoderStatus();
~DecoderStatus();
private:
DecoderStatus(const DecoderStatus&) SCP_DELETED_FUNCTION;
DecoderStatus& operator=(const DecoderStatus&) SCP_DELETED_FUNCTION;
DecoderStatus(const DecoderStatus&) = delete;
DecoderStatus& operator=(const DecoderStatus&) = delete;
};
template<typename Frame>
@@ -67,8 +65,8 @@ class FFMPEGStreamDecoder {
explicit FFMPEGStreamDecoder(DecoderStatus* status);
virtual ~FFMPEGStreamDecoder();
FFMPEGStreamDecoder(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
FFMPEGStreamDecoder& operator=(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
FFMPEGStreamDecoder(const FFMPEGStreamDecoder&) = delete;
FFMPEGStreamDecoder& operator=(const FFMPEGStreamDecoder&) = delete;
virtual void decodePacket(AVPacket* packet) = 0;
+4 -4
View File
@@ -205,14 +205,14 @@ void movie_display_loop(Player* player, PlaybackState* state) {
auto fpsCapSave = Cmdline_NoFPSCap;
Cmdline_NoFPSCap = 1;
auto lastDisplayTimestamp = timer_get_microseconds();
auto lastDisplayTime = timer_get_microseconds();
while (state->playing) {
TRACE_SCOPE(tracing::CutsceneStep);
auto timestamp = timer_get_microseconds();
auto now = timer_get_microseconds();
auto passed = timestamp - lastDisplayTimestamp;
lastDisplayTimestamp = timestamp;
auto passed = now - lastDisplayTime;
lastDisplayTime = now;
if (player->isPlaybackReady()) {
// Play as long as the player reports that there is more to display
+103 -113
View File
@@ -30,8 +30,9 @@
#include "ship/ship.h"
#include "ship/shipfx.h"
#include "species_defs/species_defs.h"
#include "weapon/weapon.h"
#include "tracing/Monitor.h"
#include "utils/Random.h"
#include "weapon/weapon.h"
#define MIN_RADIUS_FOR_PERSISTANT_DEBRIS 50 // ship radius at which debris from it becomes persistant
#define DEBRIS_SOUND_DELAY 2000 // time to start debris sound after created
@@ -51,8 +52,6 @@ int Debris_model = -1;
int Debris_vaporize_model = -1;
int Debris_num_submodels = 0;
#define MAX_DEBRIS_DIST 10000.0f // Debris goes away if it's this far away.
#define DEBRIS_DISTANCE_CHECK_TIME (10*1000) // Check every 10 seconds.
#define DEBRIS_INDEX(dp) (int)(dp-Debris.data())
const auto OnDebrisCreatedHook = scripting::Hook::Factory(
@@ -75,7 +74,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
int fireball_type = fireball_ship_explosion_type(&Ship_info[debris_p->ship_info_index]);
if(fireball_type < 0) {
fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
fireball_type = FIREBALL_EXPLOSION_LARGE1 + Random::next(FIREBALL_NUM_LARGE_EXPLOSIONS);
}
fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);
@@ -196,34 +195,6 @@ void debris_delete( object * obj )
db->objnum = -1;
}
/**
* If debris piece *db is far away from all players, make it go away very soon.
* In single player game, delete if MAX_DEBRIS_DIST from player.
* In multiplayer game, delete if MAX_DEBRIS_DIST from all players.
*/
void maybe_delete_debris(debris *db)
{
object *objp;
if (Player_obj != nullptr && timestamp_elapsed(db->next_distance_check) && timestamp_elapsed(db->must_survive_until)) {
if (!(Game_mode & GM_MULTIPLAYER)) { // In single player game, just check against player.
if (vm_vec_dist_quick(&Player_obj->pos, &Objects[db->objnum].pos) > MAX_DEBRIS_DIST)
db->lifeleft = 0.1f;
else
db->next_distance_check = timestamp(DEBRIS_DISTANCE_CHECK_TIME);
} else {
for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
if (objp->flags[Object::Object_Flags::Player_ship]) {
if (vm_vec_dist_quick(&objp->pos, &Objects[db->objnum].pos) < MAX_DEBRIS_DIST) {
db->next_distance_check = timestamp(DEBRIS_DISTANCE_CHECK_TIME);
return;
}
}
}
db->lifeleft = 0.1f;
}
}
}
/**
* Do various updates to debris: check if time to die, start fireballs
@@ -246,7 +217,7 @@ void debris_process_post(object * obj, float frame_time)
radar_plot_object( obj );
if ( timestamp_elapsed(db->sound_delay) ) {
obj_snd_assign(objnum, db->ambient_sound, &vmd_zero_vector, 0);
obj_snd_assign(objnum, db->ambient_sound, &vmd_zero_vector);
db->sound_delay = 0;
}
}
@@ -260,8 +231,6 @@ void debris_process_post(object * obj, float frame_time)
}
}
maybe_delete_debris(db); // Make this debris go away if it's very far away.
// ================== DO THE ELECTRIC ARCING STUFF =====================
if ( db->arc_frequency <= 0 ) {
return; // If arc_frequency <= 0, this piece has no arcs on it
@@ -274,7 +243,7 @@ void debris_process_post(object * obj, float frame_time)
if (db->is_hull) {
int n, n_arcs = ((rand()>>5) % 3)+1; // Create 1-3 sparks
int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks
vec3d v1, v2, v3, v4;
@@ -283,8 +252,7 @@ void debris_process_post(object * obj, float frame_time)
n = 0;
int a = 100, b = 1000;
int lifetime = (myrand()%((b)-(a)+1))+(a);
int lifetime = Random::next(100, 1000);
// Create the spark effects
for (int i=0; i<MAX_DEBRIS_ARCS; ++i) {
@@ -351,8 +319,8 @@ void debris_process_post(object * obj, float frame_time)
db->arc_timestamp[i] = timestamp(-1);
} else {
// Maybe move a vertex.... 20% of the time maybe?
int mr = myrand();
if ( mr < RAND_MAX/5 ) {
int mr = Random::next();
if ( mr < Random::MAX_VALUE/5 ) {
vec3d v1, v2;
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
@@ -424,17 +392,6 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
sip = &Ship_info[shipp->ship_info_index];
vaporize = (shipp->flags[Ship::Ship_Flags::Vaporize]);
if ( !hull_flag ) {
// Make vaporize debris seen from farther away
float dist = vm_vec_dist_quick( pos, &Eye_position );
if (vaporize) {
dist /= 2.0f;
}
if ( dist > 200.0f ) {
return NULL;
}
}
// try to maintain our soft limit
if (hull_flag && (Num_hull_pieces >= SOFT_LIMIT_DEBRIS_PIECES)) {
// cause oldest hull debris chunk to blow up
@@ -457,8 +414,38 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
db = &Debris[n];
//WMC - We must survive until now, at least.
db->must_survive_until = timestamp();
if (!hull_flag) {
if (model_num >= 0) {
db->model_num = model_num;
db->submodel_num = Random::next(sip->generic_debris_num_submodels);
}
else if (vaporize) {
db->model_num = Debris_vaporize_model;
db->submodel_num = Random::next(Debris_num_submodels);
}
else {
db->model_num = Debris_model;
db->submodel_num = Random::next(Debris_num_submodels);
}
}
else {
db->model_num = model_num;
db->submodel_num = submodel_num;
}
float radius = submodel_get_radius(db->model_num, db->submodel_num);
// if its generic, maybe cull it if its too small and far
if (!hull_flag) {
float dist = vm_vec_dist_quick(pos, &Eye_position);
// Make vaporize debris seen from farther away
if (vaporize) {
dist /= 2.0f;
}
if (dist > radius * 200.0f) {
return nullptr;
}
}
if(hull_flag && sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
{
@@ -468,14 +455,16 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
{
// Create Debris piece n!
if ( hull_flag ) {
if (rand() < RAND_MAX/6) // Make some pieces blow up shortly after explosion.
db->lifeleft = 2.0f * (myrand() * RAND_MAX_1f) + 0.5f;
if (Random::next() < (Random::MAX_VALUE/6)) // Make some pieces blow up shortly after explosion.
db->lifeleft = 2.0f * (frand()) + 0.5f;
else {
db->flags.set(Debris_Flags::DoNotExpire);
db->lifeleft = -1.0f; // large hull pieces stay around forever
}
} else {
db->lifeleft = (myrand() * RAND_MAX_1f) * 2.0f + 0.1f;
} else {
// small non-hull pieces should stick around longer the larger they are
// sqrtf should make sure its never too crazy long
db->lifeleft = (frand() * 2.0f + 0.1f) * sqrtf(radius);
}
}
@@ -484,12 +473,10 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
{
if(sip->debris_min_lifetime >= 0.0f && sip->debris_max_lifetime >= 0.0f)
{
db->must_survive_until = timestamp(fl2i(sip->debris_min_lifetime * 1000.0f));
db->lifeleft = (( sip->debris_max_lifetime - sip->debris_min_lifetime ) * frand()) + sip->debris_min_lifetime;
}
else if(sip->debris_min_lifetime >= 0.0f)
{
db->must_survive_until = timestamp(fl2i(sip->debris_min_lifetime * 1000.0f));
if(db->lifeleft < sip->debris_min_lifetime)
db->lifeleft = sip->debris_min_lifetime;
}
@@ -514,7 +501,6 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
db->fire_timeout = 0; // if not changed, timestamp_elapsed() will return false
db->time_started = Missiontime;
db->species = Ship_info[shipp->ship_info_index].species;
db->next_distance_check = (myrand() % 2000) + 4*DEBRIS_DISTANCE_CHECK_TIME;
db->parent_alt_name = shipp->alt_type_index;
db->damage_mult = 1.0f;
@@ -533,25 +519,9 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
db->arc_frequency = 0;
}
if ( model_num < 0 ) {
if (vaporize) {
db->model_num = Debris_vaporize_model;
} else {
db->model_num = Debris_model;
}
db->submodel_num = (myrand()>>4) % Debris_num_submodels;
} else {
db->model_num = model_num;
db->submodel_num = submodel_num;
}
db->model_instance_num = model_create_instance(false, db->model_num);
float radius = submodel_get_radius( db->model_num, db->submodel_num );
db->next_fireball = timestamp_rand(500,2000); //start one 1/2 - 2 secs later
if ( pos == NULL )
if ( pos == nullptr )
pos = &source_obj->pos;
flagset<Object::Object_Flags> default_flags;
@@ -559,10 +529,18 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
default_flags.set(Object::Object_Flags::Physics);
default_flags.set(Object::Object_Flags::Collides, hull_flag != 0);
objnum = obj_create( OBJ_DEBRIS, parent_objnum, n, &source_obj->orient, pos, radius, default_flags);
matrix orient = source_obj->orient;
if (!db->is_hull) {
// non-hull debris has no relation to its parent orientation
vec3d rand;
vm_vec_rand_vec(&rand);
vm_vector_2_matrix(&orient, &rand);
}
objnum = obj_create(OBJ_DEBRIS, parent_objnum, n, &orient, pos, radius, default_flags, false);
if ( objnum == -1 ) {
mprintf(("Couldn't create debris object -- out of object slots\n"));
return NULL;
return nullptr;
}
db->objnum = objnum;
@@ -570,6 +548,8 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
obj = &Objects[objnum];
pi = &obj->phys_info;
db->model_instance_num = model_create_instance(objnum, db->model_num);
// assign the network signature. The signature will be 0 for non-hull pieces, but since that
// is our invalid signature, it should be okay.
obj->net_signature = 0;
@@ -612,7 +592,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
if ( hull_flag ) {
float t;
scale = exp_force * i2fl((myrand()%20) + 10); // for radial_vel away from location of blast center
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from location of blast center
db->sound_delay = timestamp(DEBRIS_SOUND_DELAY);
// set up physics mass and I_inv for hull debris pieces
@@ -624,7 +604,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
// limit the amount of time that fireballs appear
// let fireball length be linked to radius of ship. Range is .33 radius => 3.33 radius seconds.
t = 1000*Objects[db->source_objnum].radius/3 + myrand()%(fl2i(1000*3*Objects[db->source_objnum].radius));
t = 1000*Objects[db->source_objnum].radius/3 + Random::next(fl2i(1000*3*Objects[db->source_objnum].radius));
db->fire_timeout = timestamp(fl2i(t)); // fireballs last from 5 - 30 seconds
if ( Objects[db->source_objnum].radius < MIN_RADIUS_FOR_PERSISTANT_DEBRIS ) {
@@ -635,7 +615,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
}
}
else {
scale = exp_force * i2fl((myrand()%20) + 10); // for radial_vel away from blast center (non-hull)
scale = exp_force * i2fl(Random::next(10, 29)); // for radial_vel away from blast center (non-hull)
}
if ( vm_vec_mag_squared( &to_center ) < 0.1f ) {
@@ -662,7 +642,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
radius = 1.0f;
}
scale = ( 6.0f + i2fl(myrand()%4) ) / radius;
scale = (6.0f + i2fl(Random::next(4))) / radius;
vm_vec_rand_vec_quick(&rotvel);
vm_vec_scale(&rotvel, scale);
@@ -795,9 +775,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
vec3d normal;
if (mc.model_instance_num >= 0)
model_instance_find_world_dir(&normal, &mc.hit_normal, mc.model_instance_num, mc.hit_submodel, mc.orient);
model_instance_local_to_global_dir(&normal, &mc.hit_normal, mc.model_instance_num, mc.hit_submodel, mc.orient);
else
model_find_world_dir(&normal, &mc.hit_normal, mc.model_num, mc.hit_submodel, mc.orient);
model_local_to_global_dir(&normal, &mc.hit_normal, mc.model_num, mc.hit_submodel, mc.orient);
*hitNormal = normal;
}
@@ -831,18 +811,18 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
// find the light object's position in the heavy object's reference frame at last frame and also in this frame.
vec3d p0_temp, p0_rotated;
// Collision detection from rotation enabled if at rotaion is less than 30 degree in frame
// Collision detection from rotation enabled if at rotation is less than 30 degree in frame
// This should account for all ships
if ( (vm_vec_mag_squared(&heavy->phys_info.rotvel) * flFrametime*flFrametime) < (PI*PI/36) ) {
// collide_rotate calculate (1) start position and (2) relative velocity
debris_hit_info->collide_rotate = 1;
debris_hit_info->collide_rotate = true;
vm_vec_rotate(&p0_temp, &p0, &heavy->last_orient);
vm_vec_unrotate(&p0_rotated, &p0_temp, &heavy->orient);
mc.p0 = &p0_rotated; // Point 1 of ray to check
vm_vec_sub(&debris_hit_info->light_rel_vel, &p1, &p0_rotated);
vm_vec_scale(&debris_hit_info->light_rel_vel, 1/flFrametime);
} else {
debris_hit_info->collide_rotate = 0;
debris_hit_info->collide_rotate = false;
vm_vec_sub(&debris_hit_info->light_rel_vel, &lighter->phys_info.vel, &heavy->phys_info.vel);
}
@@ -874,18 +854,18 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
// Do collision the cool new way
if ( debris_hit_info->collide_rotate ) {
// We collide with the sphere, find the list of rotating submodels and test one at a time
// We collide with the sphere, find the list of moving submodels and test one at a time
SCP_vector<int> submodel_vector;
model_get_rotating_submodel_list(&submodel_vector, heavy_obj);
model_get_moving_submodel_list(submodel_vector, heavy_obj);
// turn off all rotating submodels, collide against only 1 at a time.
// turn off collision detection for all rotating submodels
// turn off all moving submodels, collide against only 1 at a time.
// turn off collision detection for all moving submodels
for (auto submodel : submodel_vector) {
pmi->submodel[submodel].collision_checked = true;
}
// reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
// Only check single submodel now, since children of moving submodels are handled as moving as well
mc.flags = copy_flags | MC_SUBMODEL;
if (Ship_info[Ships[pship_obj->instance].ship_info_index].collision_lod > -1) {
mc.lod = Ship_info[Ships[pship_obj->instance].ship_info_index].collision_lod;
@@ -898,15 +878,9 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
// turn on just one submodel for collision test
smi->collision_checked = false;
// set angles for last frame (need to set to prev to get p0)
angles copy_angles = smi->angs;
// find the start and end positions of the sphere in submodel RF
smi->angs = smi->prev_angs;
world_find_model_instance_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos);
smi->angs = copy_angles;
world_find_model_instance_point(&p1, &light_obj->pos, pm, pmi, submodel, &heavy_obj->orient, &heavy_obj->pos);
model_instance_global_to_local_point(&p0, &light_obj->last_pos, pm, pmi, submodel, &heavy_obj->last_orient, &heavy_obj->last_pos, true);
model_instance_global_to_local_point(&p1, &light_obj->pos, pm, pmi, submodel, &heavy_obj->orient, &heavy_obj->pos);
mc.p0 = &p0;
mc.p1 = &p1;
@@ -919,19 +893,19 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
mc_ret_val = 1;
// set up debris_hit_info common
set_hit_struct_info(debris_hit_info, &mc, SUBMODEL_ROT_HIT);
model_instance_find_world_point(&debris_hit_info->hit_pos, &mc.hit_point, pm, pmi, mc.hit_submodel, &heavy_obj->orient, &zero);
set_hit_struct_info(debris_hit_info, &mc, true);
model_instance_local_to_global_point(&debris_hit_info->hit_pos, &mc.hit_point, pm, pmi, mc.hit_submodel, &heavy_obj->orient, &zero);
// set up debris_hit_info for rotating submodel
if (debris_hit_info->edge_hit == 0) {
model_instance_find_obj_dir(&debris_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
if (!debris_hit_info->edge_hit) {
model_instance_local_to_global_dir(&debris_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
}
// find position in submodel RF of light object at collison
vec3d int_light_pos, diff;
vm_vec_sub(&diff, mc.p1, mc.p0);
vm_vec_scale_add(&int_light_pos, mc.p0, &diff, mc.hit_dist);
model_instance_find_world_point(&debris_hit_info->light_collision_cm_pos, &int_light_pos, pm, pmi, mc.hit_submodel, &heavy_obj->orient, &zero);
model_instance_local_to_global_point(&debris_hit_info->light_collision_cm_pos, &int_light_pos, pm, pmi, mc.hit_submodel, &heavy_obj->orient, &zero);
}
}
@@ -952,11 +926,11 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
if (mc.hit_dist < debris_hit_info->hit_time) {
mc_ret_val = 1;
set_hit_struct_info(debris_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
set_hit_struct_info(debris_hit_info, &mc, false);
// get collision normal if not edge hit
if (debris_hit_info->edge_hit == 0) {
model_instance_find_obj_dir(&debris_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
if (!debris_hit_info->edge_hit) {
model_instance_local_to_global_dir(&debris_hit_info->collision_normal, &mc.hit_normal, pm, pmi, mc.hit_submodel, &heavy_obj->orient);
}
// find position in submodel RF of light object at collison
@@ -982,7 +956,7 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
mc_ret_val = model_collide(&mc);
if (mc_ret_val) {
set_hit_struct_info(debris_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
set_hit_struct_info(debris_hit_info, &mc, false);
// set normal if not edge hit
if ( !debris_hit_info->edge_hit ) {
@@ -1116,7 +1090,7 @@ void debris_render(object * obj, model_draw_list *scene)
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) {
for (i=0; i<MAX_DEBRIS_ARCS; i++ ) {
if ( timestamp_valid( db->arc_timestamp[i] ) ) {
model_instance_add_arc( pm, pmi, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_NORMAL );
model_instance_add_arc( pm, pmi, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_DAMAGED );
}
}
}
@@ -1127,7 +1101,7 @@ void debris_render(object * obj, model_draw_list *scene)
MONITOR_INC(NumHullDebrisRend, 1);
} else {
MONITOR_INC(NumSmallDebrisRend, 1);
render_info.set_flags(MR_NO_LIGHTING);
// render_info.set_flags(MR_NO_LIGHTING);
}
submodel_render_queue( &render_info, scene, pm, pmi, db->submodel_num, &obj->orient, &obj->pos );
@@ -1146,3 +1120,19 @@ bool debris_is_vaporized(debris *db)
{
return db->model_num == Debris_vaporize_model;
}
void create_generic_debris(object* ship_objp, vec3d* pos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris) {
Assertion(ship_objp->type == OBJ_SHIP, "create_generic_debris called for a non-ship, only ships can spew debris!");
if (ship_objp->type != OBJ_SHIP)
return;
float num_debris = frand_range(min_num_debris, max_num_debris);
num_debris *= (Detail.num_small_debris + 0.5f) / 4.5f;
vec3d create_pos = *pos;
for (int i = 0; i < num_debris; i++) {
int model_num = use_ship_debris ? Ship_info[Ships[ship_objp->instance].ship_info_index].generic_debris_model_num : -1;
debris_create(ship_objp, model_num, -1, &create_pos, pos, 0, speed_mult);
}
}
+5 -3
View File
@@ -40,17 +40,15 @@ typedef struct debris {
gamesnd_id ambient_sound; // Ambient looping sound
int objnum = -1; // What object this is linked to
float lifeleft; // When 0 or less object dies
int must_survive_until; //WMC - timestamp of earliest point that it can be murthered.
int model_num; // What model this uses
int model_instance_num; // What model instance this uses - needed for arcs
int submodel_num; // What submodel this uses
int next_fireball; // When to start a fireball
int is_hull; // indicates a large hull chunk of debris
int is_hull; // indicates whether this is a collideable, destructable piece of debris from the model, or just a generic debris fragment
int species; // What species this is from. -1 if don't care.
int fire_timeout; // timestamp that holds time for fireballs to stop appearing
int sound_delay; // timestamp to signal when sound should start
fix time_started; // time when debris was created
int next_distance_check; // timestamp to determine whether to delete this piece of debris.
vec3d arc_pts[MAX_DEBRIS_ARCS][2]; // The endpoints of each arc
int arc_timestamp[MAX_DEBRIS_ARCS]; // When this times out, the spark goes away. -1 is not used
@@ -82,4 +80,8 @@ void debris_remove_from_hull_list(debris *db);
bool debris_is_generic(debris *db);
bool debris_is_vaporized(debris *db);
// creates a burst of generic debris at hitpos from ship_objp, with a random number between min and max
// use_ship_debris is for whether the ship's generic debris should be used, or simply debris01.pof
void create_generic_debris(object* ship_objp, vec3d* hitpos, float min_num_debris, float max_num_debris, float speed_mult, bool use_ship_debris);
#endif // _DEBRIS_H
+15 -4
View File
@@ -244,6 +244,9 @@ struct Decal {
if (!object.IsValid()) {
return false;
}
if (object.objp->flags[Object::Object_Flags::Should_be_dead]) {
return false;
}
if (orig_obj_type != object.objp->type) {
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
@@ -270,6 +273,9 @@ struct Decal {
if (smi->blown_off) {
return false;
}
} else {
Assertion(false, "Only ships are currently supported for decals!");
return false;
}
return true;
@@ -405,7 +411,7 @@ matrix4 getDecalTransform(Decal& decal) {
auto pm = model_get(pmi->model_num);
vec3d worldPos;
model_instance_find_world_point(&worldPos,
model_instance_local_to_global_point(&worldPos,
&decal.position,
pm,
pmi,
@@ -414,16 +420,21 @@ matrix4 getDecalTransform(Decal& decal) {
&objp->pos);
vec3d worldDir;
model_instance_find_world_dir(&worldDir,
model_instance_local_to_global_dir(&worldDir,
&decal.orientation.vec.fvec,
pm,
pmi,
decal.submodel,
&objp->orient);
// The decal API sees the "direction" of a decal to be along the normal of the surface it is attached to. However,
// this will lead to a situation where we would look at the decal texture "from behind" causing the texture to
// appear flipped. We fix that here for the graphics transform.
vm_vec_scale(&worldDir, -1.0f);
vec3d worldUp;
model_instance_find_world_dir(&worldUp,
&decal.orientation.vec.fvec,
model_instance_local_to_global_dir(&worldUp,
&decal.orientation.vec.uvec,
pm,
pmi,
decal.submodel,
+9 -1
View File
@@ -65,15 +65,23 @@ void GetLightInfo(vec3 position, out vec3 lightDir, out float attenuation)
if (lightType == LT_TUBE) { // Tube light
float beamLength = length(beamVec);
vec3 beamDir = beamVec / beamLength;
//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
//this allows room for clean falloff of the light past the ends of beams.
vec3 adjustedLightPos = lightPosition - (beamDir * lightRadius);
beamLength = beamLength - (lightRadius * 2.0);
//adjustments having been made, lightdir needs recalculating
lightDir = adjustedLightPos - position.xyz;
// Get nearest point on line
float neardist = clamp(dot(lightDir, beamDir), 0.0, beamLength);
// Move back from the endpoint of the beam along the beam by the distance we calculated
vec3 nearest = lightPosition - beamDir * neardist;
vec3 nearest = adjustedLightPos - beamDir * neardist;
lightDir = nearest - position.xyz;
dist = length(lightDir);
if(dist > lightRadius) {
discard;
}
attenuation = 1.0 - clamp(dist / lightRadius, 0.0, 1.0);
} else if (lightType == LT_CONE) {
float coneDot = dot(normalize(-lightDir), coneDir);
if(dualCone) {
+4 -6
View File
@@ -12,7 +12,7 @@ layout (std140) uniform genericData {
vec3 fog_color;
float fog_start;
float fog_scale;
float fog_density;
float zNear;
float zFar;
};
@@ -23,17 +23,15 @@ void main()
// If the scene is in fog then we change the color we operate on based on the depth of the pixel
float depth_val = texture(depth_tex, fragTexCoord.xy).x;
// Transform depth value from [-1, 1] to [0, 1]
float depth_normalized = fma(depth_val, 0.5, 0.5);
// Transform depth value from [0, 1] to [-1, 1]
float depth_normalized = 2 * depth_val - 1;
// Now we compute the depth value in projection space using the clipping plane information
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
if (isinf(view_depth)) {
fragOut0.rgb = color_in.rgb;
} else {
// This is the same formula that is also used by the main shader
float fog_dist = clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
float fog_dist = clamp(1 - pow(fog_density, view_depth - fog_start) , 0.0, 1.0);
vec3 finalFogColor = srgb_to_linear(fog_color);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
-6
View File
@@ -4,14 +4,8 @@ const int LT_POINT = 1; // A point light, like an explosion
const int LT_TUBE = 2; // A tube light, like a fluorescent light
const int LT_CONE = 3; // A cone light, like a flood light
const float SPEC_INTENSITY_POINT = 5.3 ;// Point light
const float SPEC_INTENSITY_DIRECTIONAL = 3.0 ;// Directional light
const float SPECULAR_FACTOR = 1.75;
const float SPECULAR_ALPHA = 0.1;
const float SPEC_FACTOR_NO_SPEC_MAP = 0.1;
const float ENV_ALPHA_FACTOR = 0.3;
const float GLOW_MAP_INTENSITY = 1.5;
const float AMBIENT_LIGHT_BOOST = 1.0;
const float GLOW_MAP_SRGB_MULTIPLIER = 3.0;
vec3 FresnelSchlick(vec3 specColor, vec3 light, vec3 halfVec)
+16 -1
View File
@@ -94,6 +94,8 @@ layout (std140) uniform modelData {
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
float alphaMult;
};
in VertexOutput {
@@ -261,6 +263,11 @@ void main()
}
#endif
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
#ifdef FLAG_ALPHA_MULT
baseColor.a *= alphaMult;
#endif
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
// if blend_alpha is 2, assume blend func is additive and don't modify color
@@ -429,7 +436,15 @@ void main()
fragOut0 = baseColor;
#ifdef FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
fragOut2 = vec4(normal, glossData);
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
// basically make surfaces rougher if local normals change too fast in screenspace
vec2 normDx = dFdx(normal.xy);
vec2 normDy = dFdy(normal.xy);
float glossGeo = 1.0f - pow(clamp(max(dot(normDx,normDx), dot(normDy,normDy)),0.0,1.0),0.33);
fragOut2 = vec4(normal, min(glossData, glossGeo));
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
#endif
+2
View File
@@ -103,6 +103,8 @@ layout (std140) uniform modelData {
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
float alphaMult;
};
in VertexOutput {
+2
View File
@@ -97,6 +97,8 @@ layout (std140) uniform modelData {
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
float alphaMult;
};
#ifdef FLAG_TRANSFORM
+193 -7
View File
@@ -7,9 +7,25 @@ uniform sampler2D tex;
layout (std140) uniform genericData {
float exposure;
};
int tonemapper;
float x0; //from here on these are for the PPC tonemappers
float y0;
vec3 Uncharted2Tonemapping(vec3 hdr_color)
float x1;
float toe_B;
float toe_lnA;
float sh_B;
float sh_lnA;
float sh_offsetX;
float sh_offsetY;
};
//Tonemapping options, aside from the previous standard UC2, pulled from wookiejedi and qazwsxal's
//work on testing them for FSO, which itself was based on these references:
//https://64.github.io/tonemapping/ Delta - Blog by 64: Tone Mapping
//http://filmicworlds.com/blog/filmic-tonemapping-operators/ Filmic Worlds: Filmic Tonemapping Operators by John Hable
vec3 Uncharted2ToneMapping(vec3 hdr_color) // John Hable's filmic
{
float A = 0.15;
float B = 0.50;
@@ -17,15 +33,185 @@ vec3 Uncharted2Tonemapping(vec3 hdr_color)
float D = 0.20;
float E = 0.02;
float F = 0.30;
return ((hdr_color*(A*hdr_color+C*B)+D*E)/(hdr_color*(A*hdr_color+B)+D*F))-E/F;
float W = 11.2;
hdr_color = ((hdr_color * (A * hdr_color + C * B) + D * E) / (hdr_color * (A * hdr_color + B) + D * F)) - E / F;
float white = ((W * (A * W + C * B) + D * E) / (W * (A * W + B) + D * F)) - E / F;
hdr_color /= white;
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
return hdr_color;
}
vec3 rtt_and_odt_fit(vec3 v)
{
vec3 a = v * (v + 0.0245786f) - 0.000090537f;
vec3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f;
return a / b;
}
const mat3 aces_input = mat3(vec3(0.59719, 0.07600, 0.02840),
vec3(0.35458, 0.90834, 0.13383),
vec3(0.04823, 0.01566, 0.83777)
);
const mat3 aces_output = mat3(vec3( 1.60475, -0.10208, -0.00327),
vec3(-0.53108, 1.10813, -0.07276),
vec3(-0.07367, -0.00605, 1.07602)
);
vec3 aces(vec3 hdr_color)
{
hdr_color = aces_input * hdr_color;
hdr_color = rtt_and_odt_fit(hdr_color);
hdr_color = aces_output * hdr_color;
hdr_color = linear_to_srgb(hdr_color);
return hdr_color;
}
vec3 aces_approx(vec3 hdr_color) // also filmic, higher contrast then Uncharted2ToneMapping
{
const float a = 2.51f;
const float b = 0.03f;
const float c = 2.43f;
const float d = 0.59f;
const float e = 0.14f;
hdr_color *= 0.6f;
hdr_color = clamp((hdr_color*(a*hdr_color+b))/(hdr_color*(c*hdr_color+d)+e), 0.0f, 1.0f);
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
return hdr_color;
}
vec3 OptimizedCineonToneMapping( vec3 color ) {
// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson
color = max( vec3( 0.0 ), color - 0.004 );
color = (color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 );
// linear to sRGB conversion embedded in shader
return color;
}
vec3 rhj_lumaToneMapping(vec3 hdr_color) // reinhard_jodie
{
float luma = dot(hdr_color, vec3(0.2126, 0.7152, 0.0722)); //dot products are a bit more expensive
float toneMappedLuma = luma / (1.0 + luma);
hdr_color *= toneMappedLuma / luma;
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
return hdr_color;
}
vec3 reinhard_extended(vec3 hdr_color)
{
float max_white = 1.0;
vec3 numerator = hdr_color * (1.0f + (hdr_color / vec3(max_white * max_white)));
hdr_color = numerator / (1.0f + hdr_color);
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
return hdr_color;
}
vec3 linearToneMapping(vec3 hdr_color)
{
hdr_color = clamp(hdr_color, 0., 1.);
hdr_color = linear_to_srgb(hdr_color); // return from linear color space to SRGB color space
return hdr_color;
}
float toe( float x ) {
return exp(toe_lnA + toe_B * log(x));
}
float linear( float x ) {
// Slope is 1 by definition
return y0 + (x - x0);
}
float shoulder ( float x ) {
// Scale is -1 so reverse subtraction to save a mult
x = sh_offsetX - x;
x = exp(sh_lnA + sh_B * log(x));
x = sh_offsetY - x;
return x;
}
float funswitch (float x) {
float x_tone;
if (x <= x0) {
x_tone = toe(x);
}
else if (x <= x1) {
x_tone = linear(x);
}
else if ( x < sh_offsetX ){
x_tone = shoulder(x);
}
else {
x_tone = sh_offsetY;
}
return x_tone;
}
vec3 PPC_RGB( vec3 color ) {
color = vec3( funswitch(color.r),
funswitch(color.g),
funswitch(color.b));
return linear_to_srgb(color);
}
vec3 PPC( vec3 color ) {
float luma = dot(color, vec3(0.2126, 0.7152, 0.0722));
float luma_tone;
if ( luma <= x0 ) {
luma_tone = toe(luma);
}
else if ( luma <= x1 ) {
luma_tone = linear(luma);
}
else if ( luma < sh_offsetX ){
luma_tone = shoulder(luma);
}
else {
luma_tone = sh_offsetY;
}
return linear_to_srgb(color * luma_tone / luma);
}
void main()
{
vec4 color = texture(tex, fragTexCoord.xy);
// Tone mapping using John Hable's Uncharted 2 tonemapping algorithm.
float whitepoint = 11.2f; // hardcoded whitepoint value from Hable's algo
color.rgb = Uncharted2Tonemapping(color.rgb * exposure) / Uncharted2Tonemapping(vec3(whitepoint));
color.rgb = linear_to_srgb(color.rgb); // return from linear color space to SRGB color space
color *= exposure;
switch(tonemapper){
case 0:
color.rgb = linearToneMapping(color.rgb);
break;
case 1:
color.rgb = Uncharted2ToneMapping(color.rgb);
break;
case 2:
color.rgb = aces(color.rgb);
break;
case 3:
color.rgb = aces_approx(color.rgb);
break;
case 4:
color.rgb = OptimizedCineonToneMapping(color.rgb);
break;
case 5:
color.rgb = rhj_lumaToneMapping(color.rgb);
break;
case 6:
color.rgb = reinhard_extended(color.rgb);
break;
case 7:
color.rgb = PPC(color.rgb);
break;
case 8:
color.rgb = PPC_RGB(color.rgb);
break;
}
fragOut0 = vec4(color.rgb, 1.0);
}
@@ -221,6 +221,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Freighter
$Counts for Alone: YES
@@ -250,6 +251,7 @@ $AI:
+Active docks: ( "cargo" )
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: AWACS
$Counts for Alone: YES
@@ -277,6 +279,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Gas Miner
$Counts for Alone: YES
@@ -304,6 +307,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Cruiser
$Counts for Alone: YES
@@ -331,6 +335,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Corvette
$Counts for Alone: YES
@@ -358,6 +363,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Capital
$Counts for Alone: YES
@@ -386,6 +392,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Super Cap
$Counts for Alone: YES
@@ -412,6 +419,7 @@ $AI:
+Can Form Wing: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Drydock
$Counts for Alone: YES
@@ -436,6 +444,7 @@ $AI:
+Turrets attack this: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
$Name: Knossos Device
$Counts for Alone: YES
@@ -458,5 +467,6 @@ $AI:
+Turrets attack this: YES
+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" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Vaporize Percent Chance: 0.0
#End
+118 -109
View File
@@ -14,6 +14,7 @@
#include "graphics/tmapper.h"
#include "localization/localize.h"
#include "model/model.h"
#include "nebula/neb.h"
#include "object/object.h"
#include "options/Option.h"
#include "parse/parselo.h"
@@ -25,19 +26,21 @@
#include <cstdlib>
int Knossos_warp_ani_used;
bool Knossos_warp_ani_used;
#define WARPHOLE_GROW_TIME (2.35f) // time for warphole to reach max size (also time to shrink to nothing once it begins to shrink)
#define MAX_WARP_LOD 0
fireball Fireballs[MAX_FIREBALLS];
constexpr int INTITIAL_FIREBALL_CONTAINTER_SIZE = 256;
SCP_vector<fireball> Fireballs;
SCP_vector<int> Unused_fireball_indices;
fireball_info Fireball_info[MAX_FIREBALL_TYPES];
int fireball_used[MAX_FIREBALL_TYPES];
int Num_fireballs = 0;
int Num_fireball_types = 0;
bool fireballs_inited = false;
@@ -200,6 +203,10 @@ static void fireball_set_default_warp_attributes(int idx)
strcpy_s(Fireball_info[idx].warp_glow, "warpglow01");
strcpy_s(Fireball_info[idx].warp_ball, "warpball01");
strcpy_s(Fireball_info[idx].warp_model, "warp.pof");
if (Fireball_use_3d_warp)
Fireball_info[idx].use_3d_warp = true;
break;
}
}
@@ -284,11 +291,13 @@ static void parse_fireball_tbl(const char *table_filename)
}
}
bool first_time;
// now select our entry accordingly...
// are we using a previous entry?
if (existing_idx >= 0)
{
fi = &Fireball_info[existing_idx];
first_time = false;
}
// we are creating a new entry, so set some defaults
else
@@ -312,6 +321,7 @@ static void parse_fireball_tbl(const char *table_filename)
fireball_set_default_warp_attributes(Num_fireball_types);
Num_fireball_types++;
first_time = true;
}
// copy over what we already parsed
@@ -319,6 +329,7 @@ static void parse_fireball_tbl(const char *table_filename)
strcpy_s(fi->unique_id, unique_id);
strcpy_s(fi->lod[0].filename, fireball_filename);
// Do we have a LOD num?
if (optional_string("$LOD:"))
{
@@ -326,6 +337,9 @@ static void parse_fireball_tbl(const char *table_filename)
if (fi->lod_count > MAX_FIREBALL_LOD)
fi->lod_count = MAX_FIREBALL_LOD;
} else if (first_time) {
//assume a LOD of at least 1
fi->lod_count = 1;
}
// check for particular lighting color
@@ -356,7 +370,13 @@ static void parse_fireball_tbl(const char *table_filename)
// check for custom warp model
if (optional_string("$Warp model:"))
{
stuff_string(fi->warp_model, F_NAME, NAME_LENGTH);
// if we are explicitly specifying a model, then we'll want to use it,
// rather than just having the default model that might or might not be used
fi->use_3d_warp = true;
}
}
required_string("#End");
@@ -435,8 +455,6 @@ void fireball_load_data()
// This will get called at the start of each level.
void fireball_init()
{
int i;
if ( !fireballs_inited ) {
// Do all the processing that happens only once
fireball_parse_tbl();
@@ -446,13 +464,13 @@ void fireball_init()
}
// Reset everything between levels
Num_fireballs = 0;
for (i=0; i<MAX_FIREBALLS; i++ ) {
Fireballs[i].objnum = -1;
}
Fireballs.clear();
Fireballs.reserve(INTITIAL_FIREBALL_CONTAINTER_SIZE);
Unused_fireball_indices.clear();
Unused_fireball_indices.reserve(INTITIAL_FIREBALL_CONTAINTER_SIZE);
// Goober5000 - reset Knossos warp flag
Knossos_warp_ani_used = 0;
Knossos_warp_ani_used = false;
}
MONITOR( NumFireballsRend )
@@ -467,13 +485,15 @@ void fireball_delete( object * obj )
fireball *fb;
num = obj->instance;
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
fb = &Fireballs[num];
Assert( fb->objnum == OBJ_INDEX(obj));
Fireballs[num].objnum = -1;
Num_fireballs--;
Assert( Num_fireballs >= 0 );
Unused_fireball_indices.push_back(num);
}
/**
@@ -481,13 +501,9 @@ void fireball_delete( object * obj )
*/
void fireball_delete_all()
{
fireball *fb;
int i;
for ( i = 0; i < MAX_FIREBALLS; i++ ) {
fb = &Fireballs[i];
if ( fb->objnum != -1 ) {
obj_delete(fb->objnum);
for (auto& current_fireball : Fireballs) {
if ( current_fireball.objnum != -1 ) {
obj_delete(current_fireball.objnum);
}
}
}
@@ -499,6 +515,8 @@ void fireball_set_framenum(int num)
fireball_info *fd;
fireball_lod *fl;
Assert(static_cast<int>(Fireballs.size()) > num);
fb = &Fireballs[num];
fd = &Fireball_info[Fireballs[num].fireball_info_index];
@@ -537,6 +555,9 @@ int fireball_is_perishable(object * obj)
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert((int)Fireballs.size() > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -553,43 +574,6 @@ int fireball_is_perishable(object * obj)
return 0;
}
/**
* There are too many fireballs, so delete the oldest small one
* to free up a slot.
*
* @return The fireball slot freed.
*/
int fireball_free_one()
{
fireball *fb;
int i;
int oldest_objnum = -1, oldest_slotnum = -1;
float lifeleft, oldest_lifeleft = 0.0f;
for ( i = 0; i < MAX_FIREBALLS; i++ ) {
fb = &Fireballs[i];
// only remove the ones that aren't warp effects
if ( (fb->objnum >= 0) && fireball_is_perishable(&Objects[fb->objnum]) ) {
lifeleft = fb->total_time - fb->time_elapsed;
if ( (oldest_objnum < 0) || (lifeleft < oldest_lifeleft) ) {
oldest_slotnum = i;
oldest_lifeleft = lifeleft;
oldest_objnum = fb->objnum;
}
break;
}
}
if ( oldest_objnum > -1 ) {
obj_delete(oldest_objnum);
}
return oldest_slotnum;
}
int fireball_is_warp(object * obj)
{
int num, objnum;
@@ -597,6 +581,9 @@ int fireball_is_warp(object * obj)
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -641,6 +628,9 @@ void fireball_process_post(object * obj, float frame_time)
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -665,6 +655,10 @@ float fireball_lifeleft( object *obj )
num = obj->instance;
objnum = OBJ_INDEX(obj);
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
Assert( Fireballs[num].objnum == objnum );
fb = &Fireballs[num];
@@ -680,6 +674,10 @@ float fireball_lifeleft_percent( object *obj )
int num, objnum;
fireball *fb;
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
num = obj->instance;
objnum = OBJ_INDEX(obj);
Assert( Fireballs[num].objnum == objnum );
@@ -781,10 +779,8 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
{
int n, objnum, fb_lod;
object *obj;
fireball *fb;
fireball_info *fd;
fireball_lod *fl;
Assert( fireball_type > -1 );
Assert( fireball_type < Num_fireball_types );
@@ -800,23 +796,21 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
}
}
if ( (Num_fireballs >= MAX_FIREBALLS) || (Num_objects >= MAX_OBJECTS) ) {
// out of slots, so free one up.
n = fireball_free_one();
if ( n < 0 ) {
return -1;
}
} else {
for ( n = 0; n < MAX_FIREBALLS; n++ ) {
if ( Fireballs[n].objnum < 0 ) {
break;
}
}
Assert( n != MAX_FIREBALLS );
if (Num_objects >= MAX_OBJECTS) {
return -1;
}
fb = &Fireballs[n];
if (!Unused_fireball_indices.empty()) {
n = Unused_fireball_indices.back();
Unused_fireball_indices.pop_back();
}
else {
n = static_cast<int>(Fireballs.size());
Fireballs.emplace_back();
}
fireball* new_fireball = &Fireballs[n];
// get an lod to use
fb_lod = fireball_get_lod(pos, fd, size);
@@ -833,13 +827,13 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
}
fl = &fd->lod[fb_lod];
fb->lod = (char)fb_lod;
new_fireball->lod = (char)fb_lod;
fb->flags = extra_flags;
fb->warp_open_sound_index = warp_open_sound;
fb->warp_close_sound_index = warp_close_sound;
fb->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
fb->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
new_fireball->flags = extra_flags;
new_fireball->warp_open_sound_index = warp_open_sound;
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;
matrix orient;
if(orient_override != NULL){
@@ -854,60 +848,55 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
flagset<Object::Object_Flags> default_flags;
default_flags.set(Object::Object_Flags::Renders);
objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags);
if (objnum < 0) {
Int3(); // Get John, we ran out of objects for fireballs
return objnum;
}
objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags, false);
obj = &Objects[objnum];
fb->fireball_info_index = fireball_type;
fb->fireball_render_type = render_type;
fb->time_elapsed = 0.0f;
fb->objnum = objnum;
fb->current_bitmap = -1;
new_fireball->fireball_info_index = fireball_type;
new_fireball->fireball_render_type = render_type;
new_fireball->time_elapsed = 0.0f;
new_fireball->objnum = objnum;
new_fireball->current_bitmap = -1;
switch( fb->fireball_render_type ) {
switch( new_fireball->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION:
fb->orient = (myrand()>>8) & 7; // 0 - 7
new_fireball->orient = Random::next() & 7; // 0 - 7
break;
case FIREBALL_LARGE_EXPLOSION:
fb->orient = (myrand()>>8) % 360; // 0 - 359
new_fireball->orient = Random::next(360); // 0 - 359
break;
case FIREBALL_WARP_EFFECT:
// Play sound effect for warp hole opening up
fireball_play_warphole_open_sound(ship_class, fb);
fireball_play_warphole_open_sound(ship_class, new_fireball);
// warp in type
if (reverse) {
fb->orient = 1;
new_fireball->orient = 1;
// if warp out, then reverse the orientation
vm_vec_scale( &obj->orient.vec.fvec, -1.0f ); // Reverse the forward vector
vm_vec_scale( &obj->orient.vec.rvec, -1.0f ); // Reverse the right vector
} else {
fb->orient = 0;
new_fireball->orient = 0;
}
break;
default:
Int3();
UNREACHABLE("Bad type set in fireball_create");
break;
}
if ( fb->fireball_render_type == FIREBALL_WARP_EFFECT ) {
if ( new_fireball->fireball_render_type == FIREBALL_WARP_EFFECT ) {
Assert( warp_lifetime >= 4.0f ); // Warp lifetime must be at least 4 seconds!
if ( warp_lifetime < 4.0f )
warp_lifetime = 4.0f;
fb->total_time = warp_lifetime; // in seconds
new_fireball->total_time = warp_lifetime; // in seconds
} else {
fb->total_time = i2fl(fl->num_frames) / fl->fps; // in seconds
new_fireball->total_time = i2fl(fl->num_frames) / fl->fps; // in seconds
}
fireball_set_framenum(n);
if ( velocity ) {
@@ -923,7 +912,6 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
vm_vec_zero(&obj->phys_info.max_rotvel);
}
Num_fireballs++;
return objnum;
}
@@ -1008,9 +996,9 @@ int fireball_ship_explosion_type(ship_info *sip)
}
if(ship_fireballs > 0){
index = sip->explosion_bitmap_anims[rand()%ship_fireballs];
index = sip->explosion_bitmap_anims[Random::next(ship_fireballs)];
} else if(objecttype_fireballs > 0){
index = Ship_types[sip->class_type].explosion_bitmap_anims[rand()%objecttype_fireballs];
index = Ship_types[sip->class_type].explosion_bitmap_anims[Random::next(objecttype_fireballs)];
}
return index;
@@ -1027,7 +1015,7 @@ int fireball_asteroid_explosion_type(asteroid_info *aip)
int roid_fireballs = (int)aip->explosion_bitmap_anims.size();
if (roid_fireballs > 0) {
index = aip->explosion_bitmap_anims[rand()%roid_fireballs];
index = aip->explosion_bitmap_anims[Random::next(roid_fireballs)];
}
return index;
@@ -1058,24 +1046,34 @@ void fireball_render(object* obj, model_draw_list *scene)
MONITOR_INC( NumFireballsRend, 1 );
// Make sure the new system works fine.
Assert(obj->instance > -1);
Assert(static_cast<int>(Fireballs.size()) > obj->instance);
num = obj->instance;
fb = &Fireballs[num];
if ( Fireballs[num].current_bitmap < 0 )
if ( fb->current_bitmap < 0 )
return;
float alpha = 1.0f;
if (The_mission.flags[Mission::Mission_Flags::Fullneb] && Neb_affects_fireballs)
alpha *= neb2_get_fog_visibility(&obj->pos,
Neb2_fog_visibility_fireball_const + (obj->radius * Neb2_fog_visibility_fireball_scaled_factor));
g3_transfer_vertex(&p, &obj->pos);
switch ( fb->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION: {
batching_add_volume_bitmap(Fireballs[num].current_bitmap, &p, fb->orient, obj->radius);
batching_add_volume_bitmap(fb->current_bitmap, &p, fb->orient, obj->radius, alpha);
}
break;
case FIREBALL_LARGE_EXPLOSION: {
// Make the big explosions rotate with the viewer.
batching_add_volume_bitmap_rotated(Fireballs[num].current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius);
batching_add_volume_bitmap_rotated(fb->current_bitmap, &p, (i2fl(fb->orient)*PI) / 180.0f, obj->radius, alpha);
}
break;
@@ -1084,7 +1082,7 @@ void fireball_render(object* obj, model_draw_list *scene)
float rad = obj->radius * fireball_wormhole_intensity(fb);
fireball_info *fi = &Fireball_info[fb->fireball_info_index];
warpin_queue_render(scene, obj, &obj->orient, &obj->pos, fb->current_bitmap, rad, percent_life, obj->radius, (fb->flags & FBF_WARP_3D) != 0, fi->warp_glow_bitmap, fi->warp_ball_bitmap, fi->warp_model_id);
warpin_queue_render(scene, obj, &obj->orient, &obj->pos, fb->current_bitmap, rad, percent_life, obj->radius, fi->use_3d_warp || (fb->flags & FBF_WARP_3D) != 0, fi->warp_glow_bitmap, fi->warp_ball_bitmap, fi->warp_model_id);
}
break;
@@ -1093,3 +1091,14 @@ void fireball_render(object* obj, model_draw_list *scene)
Int3();
}
}
// Because fireballs are only added and removed in two places, and Unused_fireball_indices is always updated in those places to contain unused indices,
// this very simple code will give you the correct count of currently existing fireballs in use.
int fireball_get_count()
{
int count = static_cast<int>(Fireballs.size()) - static_cast<int>(Unused_fireball_indices.size());
Assert (count >= 0);
return count;
}
+7 -3
View File
@@ -58,6 +58,8 @@ typedef struct fireball_info {
fireball_lod lod[MAX_FIREBALL_LOD];
float exp_color[3]; // red, green, blue
bool use_3d_warp;
char warp_glow[NAME_LENGTH];
int warp_glow_bitmap;
char warp_ball[NAME_LENGTH];
@@ -95,8 +97,7 @@ typedef struct fireball {
} fireball;
// end move
extern fireball Fireballs[MAX_FIREBALLS];
extern int Num_fireballs;
extern SCP_vector<fireball> Fireballs;
extern bool fireballs_inited;
@@ -142,8 +143,11 @@ int fireball_asteroid_explosion_type(asteroid_info *aip);
float fireball_wormhole_intensity( fireball *fb );
// Goober5000
extern int Knossos_warp_ani_used;
extern bool Knossos_warp_ani_used;
extern bool Fireball_use_3d_warp;
// Cyborg - get a count of how many valid fireballs are in the mission.
int fireball_get_count();
#endif /* _FIREBALLS_H */
+2 -2
View File
@@ -91,14 +91,14 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
g3_transfer_vertex( &verts[4], &vecs[4] );
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f;
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? neb2_get_fog_visibility(&obj->pos, 1.0f) : 1.0f;
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
}
}
if ( (warp_model_id >= 0) && (warp_3d || Fireball_use_3d_warp) ) {
if ( (warp_model_id >= 0) && (warp_3d) ) {
model_render_params render_info;
float scale = radius / 25.0f;
+8 -16
View File
@@ -112,35 +112,27 @@ static int Current_help_page;
void gameplay_help_blit_control_line(int x, int y, int id)
{
int has_key=0, has_joy=0;
char buf[256];
config_item *ci;
ci = &Control_config[id];
auto ci = &Control_config[id];
buf[0] = 0;
if ( ci->key_id >= 0 ) {
strcpy_s(buf, textify_scancode(ci->key_id));
has_key=1;
strcpy_s(buf, ci->first.textify().c_str());
if (!ci->second.empty()) {
strcat_s(buf, XSTR( ", ", 129));
strcat_s(buf, ci->second.textify().c_str());
}
if ( ci->joy_id >= 0 ) {
if ( has_key ) {
strcat_s(buf, XSTR( ", ", 129));
}
strcat_s(buf, Joy_button_text[ci->joy_id]);
has_joy=1;
}
if ( !has_key && !has_joy ) {
if (ci->empty()) {
strcpy_s(buf, XSTR( "no binding", 130));
}
gr_string(x,y,buf,GR_RESIZE_MENU);
// gr_string(x+KEY_DESCRIPTION_OFFSET,y,ci->text,GR_RESIZE_MENU);
gr_string(x+KEY_DESCRIPTION_OFFSET, y, XSTR(ci->text, CONTROL_CONFIG_XSTR + id), GR_RESIZE_MENU);
gr_string(x+KEY_DESCRIPTION_OFFSET, y, XSTR(ci->text.c_str(), CONTROL_CONFIG_XSTR + id), GR_RESIZE_MENU);
}
void gameplay_help_blit_control_line_raw(int x, int y, const char *control_text, const char *control_description)
+4 -1
View File
@@ -239,7 +239,10 @@ bool GameState_Stack_Valid()
// returns one of the GS_STATE_ macros
int gameseq_get_state(int depth)
{
{
if (!GameState_Stack_Valid())
return GS_STATE_INVALID;
Assert(depth <= gs_current_stack);
return gs[gs_current_stack - depth].current_state;
+13 -1
View File
@@ -659,7 +659,12 @@ void event_music_first_pattern()
audiostream_stop( Patterns[Current_pattern].handle );
}
Pattern_timer_id = 2000; // start music delay
// if we really are initializing the level
if (Missiontime == 0) {
Pattern_timer_id = timestamp(-1); // don't let this start quite yet; see event_music_set_start_delay()
} else {
Pattern_timer_id = timestamp(0); // start immediately
}
Event_music_begun = FALSE;
if ( Event_Music_battle_started == TRUE ) {
@@ -670,6 +675,13 @@ void event_music_first_pattern()
}
}
// Event music was originally hard-coded to start at 2 seconds, regardless of the timestamp. Since the default player entry delay is 1 second,
// this yields a relative start time of 1 second. Mission start will now use relative rather than absolute delay.
void event_music_set_start_delay()
{
Pattern_timer_id = timestamp(1000);
}
// -------------------------------------------------------------------------------------------------
// event_music_level_close()
//
+1
View File
@@ -107,6 +107,7 @@ void event_music_parse_musictbl(const char *filename);
void event_music_change_pattern(int new_pattern);
int event_music_return_current_pattern();
void event_music_first_pattern();
void event_music_set_start_delay();
int event_music_battle_start();
int event_music_enemy_arrival();
int event_music_friendly_arrival();
+50 -29
View File
@@ -304,6 +304,10 @@ gamesnd_id gamesnd_get_by_name(const char* name)
{
Assert( Snds.size() <= INT_MAX );
// empty name is not valid!
if (name == nullptr || name[0] == '\0')
return gamesnd_id(-1);
int index = gamesnd_lookup_name(name, Snds);
if (index < 0)
@@ -522,7 +526,7 @@ void parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& desti
//if we're using the old format, double check the size)
if(!scp_list && (destination.size() != (unsigned)check))
{
mprintf(("%s in '%s' has " SIZE_T_ARG " entries. This does not match entered size of %i.", tag, object_name, destination.size(), check));
mprintf(("%s in '%s' has " SIZE_T_ARG " entries. This does not match entered size of %i.\n", tag, object_name, destination.size(), check));
}
}
}
@@ -540,12 +544,12 @@ void gamesnd_preload_common_sounds()
return;
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( gs->preload ) {
for (auto& entry : gs->sound_entries) {
for (auto& gs: Snds) {
if ( gs.preload ) {
for (auto& entry : gs.sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0 ) {
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
entry.id = snd_load(&entry, gs->flags);
entry.id = snd_load(&entry, &gs.flags);
}
}
}
@@ -561,12 +565,12 @@ void gamesnd_load_gameplay_sounds()
return;
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( !gs->preload ) { // don't try to load anything that's already preloaded
for (auto& entry : gs->sound_entries) {
for (auto& gs: Snds) {
if ( !gs.preload ) { // don't try to load anything that's already preloaded
for (auto& entry : gs.sound_entries) {
if (entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0) {
game_busy(NOX("** preloading gameplay sounds **")); // Animate loading cursor... does nothing if loading screen not active.
entry.id = snd_load(&entry, gs->flags);
entry.id = snd_load(&entry, &gs.flags);
}
}
}
@@ -579,8 +583,8 @@ void gamesnd_load_gameplay_sounds()
void gamesnd_unload_gameplay_sounds()
{
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
for (auto& entry : gs->sound_entries) {
for (auto& gs: Snds) {
for (auto& entry : gs.sound_entries) {
if (entry.id.isValid()) {
snd_unload(entry.id);
entry.id = sound_load_id::invalid();
@@ -598,10 +602,10 @@ void gamesnd_load_interface_sounds()
return;
Assert( Snds_iface.size() < INT_MAX );
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
for (auto& entry : si->sound_entries) {
for (auto& gs: Snds) {
for (auto& entry : gs.sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0 ) {
entry.id = snd_load(&entry, si->flags);
entry.id = snd_load(&entry, &gs.flags);
}
}
}
@@ -638,10 +642,11 @@ void parse_gamesnd_old(game_snd* gs)
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN, ",");
if (!stricmp(entry.filename, NOX("empty")))
if (!stricmp(entry.filename, NOX("empty")) || !stricmp(entry.filename, NOX("none")))
{
entry.filename[0] = 0;
advance_to_eoln(NULL);
advance_to_eoln(nullptr);
gs->flags |= GAME_SND_NOT_VALID;
return;
}
Mp++;
@@ -675,11 +680,9 @@ void parse_gamesnd_old(game_snd* gs)
{
int temp_min, temp_max;
ignore_gray_space();
if (stuff_int_optional(&temp_min, true) == 2)
if (stuff_int_optional(&temp_min) == 2)
{
ignore_gray_space();
if (stuff_int_optional(&temp_max, true) == 2)
if (stuff_int_optional(&temp_max) == 2)
{
mprintf(("Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), entry.filename));
is_3d = 1;
@@ -693,8 +696,7 @@ void parse_gamesnd_old(game_snd* gs)
}
// check for extra values per Mantis #2408
ignore_gray_space();
if (stuff_int_optional(&temp, true) == 2)
if (stuff_int_optional(&temp) == 2)
{
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
}
@@ -750,14 +752,14 @@ bool required_string_no_create(const char* token, bool no_create)
static GameSoundCycleType parse_cycle_type() {
if (optional_string("Sequential")) {
return GameSoundCycleType::Sequential;
return GameSoundCycleType::SequentialCycle;
} else if (optional_string("Random")) {
return GameSoundCycleType::Random;
return GameSoundCycleType::RandomCycle;
} else {
error_display(0, "Failed to parse sound cycle type. Expected 'sequential' or 'random'. Got [%.32s]", next_tokens());
// Ignore everything until the end of the line. That should hopefully skip the bad token.
advance_to_eoln(nullptr);
return GameSoundCycleType::Sequential;
return GameSoundCycleType::SequentialCycle;
}
}
@@ -859,9 +861,10 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
// Default pitch is 1.0. This is set here in case we don't have a valid file name
gs->pitch_range = util::UniformFloatRange(1.0f);
if (!stricmp(name, NOX("empty")))
if (!stricmp(name, NOX("empty")) || !stricmp(name, NOX("none")))
{
entry->filename[0] = 0;
gs->flags |= GAME_SND_NOT_VALID;
return;
}
@@ -1342,13 +1345,31 @@ bool gamesnd_interface_sound_valid(interface_snd_id sound) {
return sound.isValid() && sound.value() < (int) Snds_iface.size();
}
bool gamesnd_game_sound_try_load(gamesnd_id sound)
{
if (!gamesnd_game_sound_valid(sound)) {
return false;
}
auto gs = gamesnd_get_game_sound(sound);
for (auto& entry : gs->sound_entries) {
if (!entry.id.isValid()) {
// Lazily load unloaded sound entries when required
entry.id = snd_load(&entry, &gs->flags);
}
}
// check flag
return (gs->flags & GAME_SND_NOT_VALID) == 0;
}
float gamesnd_get_max_duration(game_snd* gs) {
int max_length = 0;
for (auto& entry : gs->sound_entries) {
if (!entry.id.isValid()) {
// Lazily load unloaded sound entries when required
entry.id = snd_load(&entry, gs->flags);
entry.id = snd_load(&entry, &gs->flags);
}
max_length = std::max(max_length, snd_get_duration(entry.id));
@@ -1361,14 +1382,14 @@ game_snd_entry* gamesnd_choose_entry(game_snd* gs) {
size_t index = 0;
switch(gs->cycle_type) {
case GameSoundCycleType::Random:
case GameSoundCycleType::RandomCycle:
if (gs->sound_entries.size() == 1) {
index = 0;
} else {
index = util::UniformRange<size_t>(0, gs->sound_entries.size() - 1).next();
}
break;
case GameSoundCycleType::Sequential:
case GameSoundCycleType::SequentialCycle:
if (gs->last_entry_index == std::numeric_limits<size_t>::max()) {
// If this is the first time we must return the first sound to keep everything consistent
index = 0;
+5
View File
@@ -401,6 +401,11 @@ game_snd* gamesnd_get_interface_sound(interface_snd_id handle);
*/
bool gamesnd_game_sound_valid(gamesnd_id sound);
/**
* @brief Checks if the given sound handle can be loaded
*/
bool gamesnd_game_sound_try_load(gamesnd_id sound);
/**
* @brief Checks if the given sound handle is a valid interface sound handle
* @param sound The handle to check
-2
View File
@@ -31,8 +31,6 @@
#define CALLSIGN_LEN (MAX_FILENAME_LEN - 4 - 1) // shortened from 32 to allow .json to be attached without exceeding MAX_FILENAME_LEN
#define SHORT_CALLSIGN_PIXEL_W 80 // max width of short_callsign[] in pixels
#define MAX_IFFS 10
// from ship.h
#define MAX_SHIPS 400 // max number of ship instances there can be.DTP; bumped from 200 to 400
#define SHIPS_LIMIT 400 // what MAX_SHIPS will be at release time (for error checking in debug mode); dtp Bumped from 200 to 400
+4 -13
View File
@@ -113,6 +113,8 @@ typedef struct vec2d {
float x, y;
} vec2d;
// Euler angles for a rotation: h=heading, b=bank and p=pitch; angles are around the y, z and x axes
// respectively and are performed in that order.
typedef struct angles {
float p, b, h;
} angles_t;
@@ -128,6 +130,7 @@ typedef struct matrix {
};
} matrix;
// You might think this is also row-major. You fool! It is actually column-major.
typedef struct matrix4 {
union {
struct {
@@ -303,8 +306,6 @@ constexpr bool LoggingEnabled = false;
const float PI2 = (PI*2.0f);
// half values
const float PI_2 = (PI/2.0f);
const int RAND_MAX_2 = (RAND_MAX/2);
const float RAND_MAX_1f = (1.0f / RAND_MAX);
extern int Fred_running; // Is Fred running, or FreeSpace?
@@ -350,14 +351,6 @@ const size_t INVALID_SIZE = static_cast<size_t>(-1);
#define TRUE 1
#define FALSE 0
int myrand();
// Returns a random number between 0 and 0x7fffffff
int rand32();
// Returns a random integer from low to high, inclusive
int rand32(int low, int high);
// lod checker for (modular) table parsing
typedef struct lod_checker {
@@ -463,7 +456,6 @@ SCP_string dump_stacktrace();
// DEBUG compile time catch for dangerous uses of memset/memcpy/memmove
// This is disabled for VS2013 and lower since that doesn't support the necessary features
#if !defined(NDEBUG) && !defined(USING_THIRD_PARTY_LIBS) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
#if SCP_COMPILER_CXX_AUTO_TYPE && SCP_COMPILER_CXX_STATIC_ASSERT && HAVE_STD_IS_TRIVIALLY_COPYABLE
// feature support seems to be: gcc clang msvc
// auto 4.4 2.9 2010
// std::is_trivial 4.5 ? 2012 (2010 only duplicates std::is_pod)
@@ -563,7 +555,6 @@ using std::memcpy_if_trivial_else_error;
using std::memmove_if_trivial_else_error;
using std::memset_if_trivial_else_error;
#endif // HAVE_CXX11
#endif // NDEBUG
#endif // PS_TYPES_H
#endif // _PSTYPES_H
-2
View File
@@ -3,8 +3,6 @@
#define SCP_DEFINES_H
#pragma once
#include "scp_compiler_detection.h"
#define SCP_TOKEN_CONCAT1(x, y) x ## y
#define SCP_TOKEN_CONCAT(x, y) SCP_TOKEN_CONCAT1(x, y)
+18 -47
View File
@@ -57,7 +57,6 @@ vci Viewer_chase_info; // View chase camera information
vec3d leaning_position;
int Is_standalone;
int Rand_count;
int Interface_last_tick = -1; // last timer tick on flip
@@ -109,47 +108,6 @@ float Noise[NOISE_NUM_FRAMES] = {
0.000000f
};
int myrand()
{
int rval;
rval = rand();
Rand_count++;
// nprintf(("Alan","RAND: %d\n", rval));
return rval;
}
// returns a random number between 0 and 0x7fffffff, or something close to it.
int rand32()
{
if (RAND_MAX == 0x7fff) {
int random32;
// this gets two random 16 bit numbers and stuffs them into a 32 bit number
random32 = (rand() << 16) | rand();
//since rand() returns between 0 and 0x7fff, there needs to be a thing to randomly generate the 16th bit
random32 |= ((rand() & 1) << 15);
return random32;
}
else {
return rand();
}
}
int rand32(int low, int high)
{
int diff;
// get diff - don't allow negative or zero
diff = high - low;
if (diff < 0)
diff = 0;
// To get a range of values between min and max, inclusive:
// random value = min + random number % (max - min + 1)
return (low + rand32() % (diff + 1));
}
// Variables for the loading callback hooks
static int cf_timestamp = -1;
static void (*cf_callback)(int count) = NULL;
@@ -285,8 +243,8 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
{ // Highest level
3, // setting
// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
3, // nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
3, // detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
4, // nebula_detail; // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
4, // detail_distance; // 0=lowest MAX_DETAIL_LEVEL=highest
4, // hardware_textures; // 0=max culling, MAX_DETAIL_LEVEL=no culling
4, // num_small_debris; // 0=min number, MAX_DETAIL_LEVEL=max number
4, // num_particles; // 0=min number, MAX_DETAIL_LEVEL=max number
@@ -370,9 +328,6 @@ void detail_level_set(int level)
Assert( level < NUM_DEFAULT_DETAIL_LEVELS );
Detail = Detail_defaults[level];
// reset nebula stuff
neb2_set_detail_level(level);
}
// Returns the current detail level or -1 if custom.
@@ -511,3 +466,19 @@ void insertion_sort(void *array_base, size_t array_size, size_t element_size, in
// free the allocated space
free(current);
}
// Stuff that can't be included in vmallocator.h
std::locale SCP_default_locale("");
void SCP_tolower(char *str)
{
for (; *str != '\0'; ++str)
*str = SCP_tolower(*str);
}
void SCP_toupper(char *str)
{
for (; *str != '\0'; ++str)
*str = SCP_toupper(*str);
}
-1
View File
@@ -94,7 +94,6 @@ extern int Game_mode;
#define SINGLEPLAYER !(Game_mode & GM_MULTIPLAYER)
extern int Viewer_mode;
extern int Rand_count;
extern int Game_restoring; // If set, this means we are restoring data from disk
+1 -1
View File
@@ -67,7 +67,7 @@
#define USED_VARIABLE __attribute__((used))
#if SCP_COMPILER_VERSION_MAJOR >= 7
#if __GNUC__ >= 7
#define FALLTHROUGH [[fallthrough]]
#else
#define FALLTHROUGH
+1 -1
View File
@@ -64,7 +64,7 @@
#define USED_VARIABLE __attribute__((used))
#if SCP_COMPILER_VERSION_MAJOR >= 7
#if __GNUC__ >= 7
#define FALLTHROUGH __attribute__((fallthrough))
#else
#define FALLTHROUGH
+166
View File
@@ -0,0 +1,166 @@
/*
* z64555's Undo system, created for the FreeSpace Source Code project
*/
#include "globalincs/pstypes.h"
#include "globalincs/undosys.h"
#include "globalincs/vmallocator.h"
// Pure virtual deconstructors must be defined.
Undo_item_base::~Undo_item_base() = default;
Undo_system::Undo_system()
: max_undos(10) {};
Undo_system::Undo_system(size_t _undos)
: max_undos(_undos) {};
void Undo_system::clamp_stacks() {
while (undo_stack.size() > max_undos) {
// If we're past the stack limit, de-construct and remove until we're in the limit
// If max_undos is held constant (as it should be), the loop isn't necassary.
// But, it also isn't that much different from an if{} when assembled, so there's no harm in using it
delete undo_stack.front();
undo_stack.pop_front();
}
// This while() shouldn't ever be triggered, but this is a safety to prevent any weird edge-cases.
while (redo_stack.size() > max_undos) {
delete redo_stack.front();
undo_stack.pop_front();
}
}
void Undo_system::clear() {
clear_redo();
for (auto &element : undo_stack) {
delete element;
}
undo_stack.clear();
}
void Undo_system::clear_redo() {
for (auto &element : redo_stack) {
delete element;
}
redo_stack.clear();
}
size_t Undo_system::save_stack(Undo_stack& stack) {
if (stack.size() == 0) {
return 0;
}
clear_redo();
// Copy the stack onto the heap, and push it into our undo_stack as a single item
Undo_item_base *new_item = new Undo_stack(stack);
Assert(new_item != nullptr);
undo_stack.push_back(new_item);
// Input stack is told to untrack the items, so that there's only one deletion handler for them
stack.untrack();
clamp_stacks();
return undo_stack.size();
}
std::pair<const void*, const void*> Undo_system::redo() {
std::pair<const void*, const void*> retval;
if (redo_stack.empty()) {
// Nothing to redo
return {nullptr, nullptr};
}
auto &item = redo_stack.back();
retval = item->restore();
undo_stack.push_back(item);
redo_stack.pop_back();
return retval;
};
std::pair<const void*, const void*> Undo_system::undo() {
std::pair<const void*, const void*> retval;
if (undo_stack.empty()) {
// Nothing to undo
return {nullptr, nullptr};
}
auto &item = undo_stack.back();
retval = item->restore();
redo_stack.push_back(item);
undo_stack.pop_back();
return retval;
};
bool Undo_system::empty() {
return undo_stack.empty();
}
bool Undo_system::empty_redo() {
return redo_stack.empty();
}
size_t Undo_system::size() {
return undo_stack.size();
}
size_t Undo_system::size_redo() {
return redo_stack.size();
}
Undo_stack::Undo_stack()
: reverse(false) {
}
Undo_stack::Undo_stack(size_t size)
: reverse(false) {
stack.reserve(size);
}
Undo_stack::~Undo_stack() {
clear();
}
void Undo_stack::reserve(size_t size) {
stack.reserve(size);
}
std::pair<const void*, const void*> Undo_stack::restore() {
std::pair<const void*, const void*> retval;
if (reverse) {
for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
retval = (*it)->restore();
}
} else {
for (auto &element : stack) {
retval = element->restore();
}
}
reverse = !reverse;
return retval;
}
size_t Undo_stack::size() {
return stack.size();
}
void Undo_stack::untrack() {
stack.clear();
}
void Undo_stack::clear() {
for (auto &element : stack) {
delete element;
}
stack.clear();
}
+326
View File
@@ -0,0 +1,326 @@
/*
* z64555's Undo system, created for the FreeSpace Source Code project
*/
#include "globalincs/pstypes.h"
#include "globalincs/vmallocator.h"
#include <utility>
/**********************************************************
Usage:
First, you need an instance of the Undo_system within your module:
{
Undo_styem Undo_controls;
}
From now on, you can save and restore items. (Just be sure to save them before you change them!)
{
Undo_controls.save(Control_config[z]); // 1. Save the item!!
Control_config[z].bind(cid(CID_KEYBOARD, KEY_UP)); // 2. Make changes to the item!!
Undo_controls.undo(); // 3. Undo's the changes you did in step 2!
Undo_controls.redo(); // 4. Redo's the changes you did in step 2!
}
The undo system can save any type of data, you don't have to have an instance of a system per data type.
!!NOTE!! C style arrays and strings should be wrapped in a std::array when saving. Simply passing the array/string's head won't save the entire array.
{
Undo_controls.save(std::array<int, JOY_AXIS_ACTIONS>(Axis_map_to));
}
In several cases, the client code would like to know exactly what was changed. The undo system provides a mechanism for doing this:
{
Undo_controls.save(Control_config[z], &Control_config[0]); // Save the item, and a reference to its container. Here, we use the location of the first item in Control_config as our reference
Undo_controls.save(Axis_map_to[z], Axis_map_to); // Saves an axis mapping, here, we use the array's head pointer as our reference (since a int[] is the same as a int*)
std::pair<const void*, const void*> ref = Undo_controls.undo(); // ::undo() returns a std::pair<const void*, const void*>, the first member referencing the item that changed, and the second referencing the item's container (if we provided it)
// Once we've stored the return value from ::undo, we can found out what the item is by comparing the second member with containers that we've been saving
if (ref.second == &Control_config[0]) {
cout << "I'm a button!";
Tab = static_cast<Config_item>(ref.first).tab; // Sets the selected tab within the Controls Config menu. We do a static cast here so we can access the Config_item::tab member
} else if (ref.second == Axis_map_to) {
cout << "I'm an axis!";
Tab = SHIP_TAB; // Sets the selected tab within the Controls config menu. Can't do a cast on this one, since it's a simple C array. But we already know where the axes are kept (on the ship tab)
} else {
cout << "I don't know what I am!!! D:"; // Usually an error condition. Depending on the client code this can be fatal or just a minor setback
}
}
Lastly, you can make stacks of undo operations, so that a single op in the system can undo/redo multiple item changes.
{
Undo_stack stack; // We'll want to save multiple changes as a single operation. So we have to make a stack.
for (int i = 0; i < JOY_AXIS_ACTIONS; ++i) {
stack.save(Axis_map_to[i], Axis_map_to); // This example saves a C style array. Does the same thing without a wrapper, but wasteful
Undo_controls.save_stack(stack) // Save the stack as a single item!
}
std::pair<const void*, const void*> ref = Undo_controls.undo();
// Undo rolls through the items as they were saved, should your data operate on the same location, this will apply the changes in the correct sequence
ref.second == Axis_map_to;
ref.first == &Axis_map_to[0]; // ::first references the _last_ item that the undo stack changed
//Also, performing an undo reverses the stack. So when you do a system undo, the changes are applied in reverse
ref = Undo_controls.redo();
ref.second == Axis_map_to;
ref.first == &Axis_map_to[JOY_AXIS_ACTIONS - 1]; // ::first references the _last_ item that the undo stack changed
***********************************************************/
/*!
* @brief Base class of Undo_item. Use this when making an undo stack!
* @sa Undo_item
*/
class Undo_item_base
{
public:
virtual ~Undo_item_base() = 0;
virtual std::pair<const void*, const void*> restore() = 0;
};
/*!
* @brief Class which handles undo operations.
* @details This class works with a single data item, to make a undo or redo stack you'd use something like a
* std::vector or a std::deque of this class. Undo and Redo stacks would be separate. Before restoring data from
* either, you'd save a copy of the item in the opposite stack.
*
* For example, if you're about to restore from the undo stack, you'd first save a copy of the current data to the
* redo stack, then do the undo. The Undo_item in the undo stack can then be popped off the stack.
*
* @note If you want to save changes to an entire C-style array (such as 'int array[]'), try wrapping it in a std::array first.
*
* @sa Undo_item_base
*/
template<typename T> class Undo_item : public Undo_item_base
{
public:
Undo_item()
: dest(nullptr), data(nullptr) {};
Undo_item(T& _data) {
save(_data);
};
Undo_item(T& _data, T* _cont) {
save(_data, _cont);
};
~Undo_item() override {
if (data != nullptr) {
delete data;
}
};
/**
* @brief Restores the saved data
*
* @returns A pair of const void* referencing the affected item and its container (if it was provided)
* @details swaps the data with the destination's, effectively making an undo item into a redo item, and vice versa
*/
std::pair<const void*, const void*> restore() override {
Assert((dest != nullptr) && (data != nullptr));
std::swap(*static_cast<T*>(dest),*static_cast<T*>(data));
return std::pair<const void*, const void*>(dest, container);
};
/*!
* @brief Saves data and its destination as an undo item
*
* @param[in] _data The data to save
* @param[in] _cont The container this data is originally found in
* @details The explicit definition is here to ensure type safety
*/
void save(T& _data, T* _cont = nullptr) {
dest = &_data;
data = new T(_data);
container = _cont;
};
private:
T* dest; //!< Destination of the data
T* data; //!< Reference to a copy of data on the heap
T* container; //!< Optional reference to this item's container
};
/*!
* @brief Class which handles multiple undo operations as a single op within the Undo_system
* @note Caution: Upon deconstruction the tracked Undo_items are deleted.
*/
class Undo_stack : public Undo_item_base
{
public:
Undo_stack();
Undo_stack(size_t size);
~Undo_stack() override;
/*!
* @brief Restores all items within the undo stack
*
* @details Maintains an internal flag which will reverse direction on the next call, thereby re-doing
*
* @returns A pair of references to the last item restored
*/
std::pair<const void*, const void*> restore() override;
/*!
* @brief Saves the item onto the undo stack
*
* @param[in] item The item to save
* @param[in] container (Optional) The container wherein this item is located
* @note Call this _before_ you do your operation on the item
*/
template<typename T>
size_t save(T& item, T* container = nullptr) {
// Create a new instance of Undo_tem, with the correct type reference
Undo_item_base *new_item = new Undo_item<T>(item, container);
stack.push_back(new_item);
return stack.size();
};
/*!
* @brief Calls ::reserve() on the internal vector
*/
void reserve(size_t size);
/*!
* @brief Returns the size of the stack
*/
size_t size();
/*!
* @brief Deletes all tracked items in the internal vector
*/
void clear();
protected:
friend class Undo_system;
/*!
* @brief Calls ::clear() on the internal vector
* @note Caution: This does not delete the tracked Undo_items
*/
void untrack();
private:
bool reverse; // Direction to walk the stack. forward = false, reverse = True
std::vector<Undo_item_base*> stack;
};
/*!
* @brief Generic Undo/Redo system. Save whatever, restore whatever!
*
* @details Currently uses a pair of deques. Would ideally use a ring container so that the actual Undo_item instances don't go anywhere.
*/
class Undo_system
{
public:
Undo_system();
Undo_system(size_t _undos);
/*!
* @brief Deletes all undo and redo data
*/
void clear();
/*!
* @brief Saves the item onto the undo stack
*
* @param[in] item The item to save
* @param[in] container (Optional) The container wherein this item is located
* @note Call this _before_ you do your operation on the item
*/
template<typename T>
size_t save(T& item, T* container = nullptr) {
// De-construct all intances of Undo_item on the redo stack, then clear the stack
clear_redo();
// Create a new instance of Undo_tem, with the correct type reference
Undo_item_base *new_item = new Undo_item<T>(item, container);
undo_stack.push_back(new_item);
clamp_stacks();
return undo_stack.size();
};
/*!
* @brief Saves a stack of undo-items as a single undo-item within the system
*
* @param[in,out] stack The undo stack to save to the undo system. Data in the stack is "unspecified" after this operation
*
* @details The undo system effectively moves the stack into its internal containers, claiming ownership of the
* Undo_items and deleting them upon going out of scope. The input stack is told to untrack the Undo_items in
* the process, so that there is only ever one reference to the Undo_item like a std::unique_ptr
*/
size_t save_stack(Undo_stack& stack);
/*!
* @brief Undo's the last changed item and save the changes into the Redo stack
*
* @returns A pair of const void* which reference the affected item, and its container (if it was provided)
*/
std::pair<const void*, const void*> undo();
/*!
* @brief Redo's the last changed item and save the changes into the undo
*
* @returns A pair of const void* which reference the affected item, and its container (if it was provided)
*/
std::pair<const void*, const void*> redo();
/*!
* @brief Returns the size of the undo stack
*/
size_t size();
/*!
* @brief Returns the size of the redo stack
*/
size_t size_redo();
/*!
* @brief True if undo stack size = 0
*/
bool empty();
/*!
* @brief True if redo stack size = 0
*/
bool empty_redo();
protected:
/*!
* @brief Deletes all redo data
*/
void clear_redo();
/*!
* @brief Clamp the stack sizes to be <= max_undos, deleting data as needed
*/
void clamp_stacks();
private:
size_t max_undos; //!< Max number of Undo's available
/*!
* @brief The undo and redo stacks. These are containers of pointers, because we can't simply store the base class.
* If we did, then the data of the Undo_item instances would be sliced out.
* @{
*/
SCP_deque<Undo_item_base*> undo_stack;
SCP_deque<Undo_item_base*> redo_stack;
//! @}
};
+76 -2
View File
@@ -1,10 +1,10 @@
#ifndef _VMALLOCATOR_H_INCLUDED_
#define _VMALLOCATOR_H_INCLUDED_
/* SCP_vm_allocator - maintained by portej05 (i.e. please don't patch this one yourself!) */
#include <deque>
#include <iterator>
#include <list>
#include <locale>
#include <map>
#include <queue>
#include <sstream>
@@ -25,10 +25,31 @@ bool SCP_vector_contains(SCP_vector<T>& vector, T item) {
template< typename T >
using SCP_list = std::list< T, std::allocator< T > >;
extern std::locale SCP_default_locale;
template< class charT >
charT SCP_toupper(charT ch) { return std::toupper(ch, SCP_default_locale); }
template< class charT >
charT SCP_tolower(charT ch) { return std::tolower(ch, SCP_default_locale); }
typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > SCP_string;
typedef std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> > SCP_stringstream;
inline void SCP_tolower(SCP_string &str) {
std::transform(str.begin(), str.end(), str.begin(), [](char c) { return SCP_tolower(c); });
}
inline void SCP_toupper(SCP_string &str) {
std::transform(str.begin(), str.end(), str.begin(), [](char c) { return SCP_toupper(c); });
}
extern void SCP_tolower(char *str);
extern void SCP_toupper(char *str);
template< typename T, typename U >
using SCP_map = std::map<T, U, std::less<T>, std::allocator<std::pair<const T, U> > >;
@@ -75,6 +96,59 @@ template <typename T>
using SCP_hash = std::hash<T>;
#endif
struct SCP_string_lcase_hash {
size_t operator()(const SCP_string& elem) const {
SCP_string lcase_copy;
std::transform(elem.begin(), elem.end(), std::back_inserter(lcase_copy),
[](char c) {
return SCP_tolower(c);
});
return SCP_hash<SCP_string>()(lcase_copy);
}
};
struct SCP_string_lcase_equal_to {
bool operator()(const SCP_string& _Left, const SCP_string& _Right) const {
if (_Left.size() != _Right.size()) {
return false;
}
auto l_it = _Left.cbegin();
auto r_it = _Right.cbegin();
while (l_it != _Left.cend()) {
if (SCP_tolower(*l_it) != SCP_tolower(*r_it)) {
return false;
}
++l_it;
++r_it;
}
return true;
}
};
struct SCP_string_lcase_less_than {
bool operator()(const SCP_string& _Left, const SCP_string& _Right) const {
auto l_it = _Left.cbegin();
auto r_it = _Right.cbegin();
while (true) {
if (l_it == _Left.cend()) {
return (r_it != _Right.cend());
} else if (r_it == _Right.cend()) {
return false;
}
auto lch = SCP_tolower(*l_it);
auto rch = SCP_tolower(*r_it);
if (lch < rch) {
return true;
} else if (lch > rch) {
return false;
}
++l_it;
++r_it;
}
return true;
}
};
template <typename Key, typename T, typename Hash = SCP_hash<Key>, typename KeyEqual = std::equal_to<Key>>
using SCP_unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, std::allocator<std::pair<const Key, T>>>;
Loaded 100 of 650 files, more files were not shown because too many files have changed in this diff. Show more