Compare commits

..
Author SHA1 Message Date
SirKnightly 7bb0c77bb5 Automated build commit 2021-09-27 00:17:41 +00: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
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
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
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
Birk Magnussen 011f7e4d6c Change flag to Table entry 2021-03-19 18:30:39 +09:00
Baezon eb538ffba8 update turret_alt_math for moving subsystems 2021-03-19 02:13:20 -04: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
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
Shivansps d5feddfb8a fixed comp_fseek return 2021-03-15 20:08:58 -03: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
Shivansps ba6a471054 comment debug statements 2021-03-14 14:55:20 -03:00
Shivansps ce44e3522b updated header 2021-03-14 14:35:04 -03: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
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
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
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
Shivansps 8292d8c44a Revert "Merge branch 'arm_fixes'"
This reverts commit 2ee128cd88, reversing
changes made to a2b349855e.
2021-03-09 20:44:43 -03: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 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
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
Baezon 5004f6ab32 Merge remote-tracking branch 'upstream/master' into ai-multilock 2021-02-21 22:15:31 -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 4b3a1a8d84 unused variables 2021-01-28 20:39:29 -05:00
Baezon 824c537bd2 Merge remote-tracking branch 'upstream/master' into ai-multilock 2021-01-28 12:25:35 -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 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
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
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
345 changed files with 22687 additions and 5453 deletions

No files matched your search

+1 -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-e29f882
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
name: Linux
needs: create_release
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-e29f882
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
+1 -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-e29f882
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
+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
+6 -1
View File
@@ -22,7 +22,7 @@ jobs:
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
name: Linux
runs-on: ubuntu-latest
container: ghcr.io/scp-fs2open/linux_build:sha-e29f882
container: ghcr.io/scp-fs2open/linux_build:sha-11e553c
steps:
- name: Cache Qt
id: cache-qt-lin
@@ -44,6 +44,11 @@ jobs:
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 }}
-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
+1 -1
View File
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 21)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
+1
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)
+3
View File
@@ -491,6 +491,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
+4 -1
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)
@@ -137,6 +137,9 @@ namespace AI {
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,
NUM_VALUES
};
+52 -7
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,6 @@ 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;
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -481,14 +500,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);
}
@@ -544,6 +561,26 @@ void parse_ai_profiles_tbl(const char *filename)
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 we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
{
@@ -615,11 +652,12 @@ 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;
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
max_incoming_asteroids[i] = 0;
@@ -697,4 +735,11 @@ void ai_profile_t::reset()
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);
}
}
+6
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,9 @@ 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;
void reset();
};
+26 -12
View File
@@ -17,12 +17,12 @@
#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"
#include "object/objcollide.h"
#ifdef _MSC_VER
#pragma optimize("", off)
@@ -777,11 +777,25 @@ 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;
if (weapons->num_primary_banks >= 1 && weapons->current_primary_bank >= 0) {
wip = &Weapon_info[weapons->primary_bank_weapons[weapons->current_primary_bank]];
} else if (weapons->num_secondary_banks >= 1 && weapons->current_secondary_bank >= 0) {
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];
@@ -809,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;
@@ -914,7 +928,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;
@@ -944,11 +958,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] = rand32();
swp->burst_seed[current_bank_adjusted] = Random::next();
}
} else {
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
@@ -957,11 +971,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] = rand32();
swp->burst_seed[current_bank_adjusted] = Random::next();
}
}
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
@@ -1448,7 +1462,7 @@ void ai_big_strafe_attack()
if (ai_new_maybe_reposition_attack_subsys())
return;
} else if (ai_big_maybe_follow_subsys_path(0))
return
return;
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(&target_pos) )
@@ -1471,7 +1485,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;
@@ -1703,7 +1717,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;
+249 -77
View File
@@ -68,6 +68,7 @@
#include "ship/shipfx.h"
#include "ship/shiphit.h"
#include "ship/subsysdamage.h"
#include "utils/Random.h"
#include "weapon/beam.h"
#include "weapon/flak.h"
#include "weapon/swarm.h"
@@ -1077,7 +1078,8 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
float old_dot, new_dot;
object *old_weapon_objp = NULL;
if ((attacked_objnum == -1) || (weapon_objnum == -1)) {
// any object number less than 0 is invalid
if ((attacked_objnum < 0) || (weapon_objnum < 0)) {
return;
}
@@ -2287,7 +2289,7 @@ int num_turrets_attacking(object *turret_parent, int target_objnum)
*/
int get_enemy_timestamp()
{
return (NUM_SKILL_LEVELS - Game_skill_level) * ( (myrand() % 500) + 500);
return (NUM_SKILL_LEVELS - Game_skill_level) * Random::next(500, 999);
}
/**
@@ -2348,8 +2350,9 @@ void ai_set_goal_abort_support_call(object *objp, ai_info *aip)
object *repair_obj;
if (aip->support_ship_objnum == -1) {
repair_obj = NULL;
repair_obj = nullptr;
} else {
Assertion(aip->support_ship_objnum >= 0, "%s has a nonsense support_ship_objnum of %d, please report!", Ships[aip->shipnum].ship_name, aip->support_ship_objnum);
repair_obj = &Objects[aip->support_ship_objnum];
}
ai_do_objects_repairing_stuff( objp, repair_obj, REPAIR_INFO_ABORT );
@@ -2376,7 +2379,7 @@ void ai_attack_object(object* attacker, object* attacked, int ship_info_index)
ai_info* aip;
Assert(attacker != nullptr);
Assert(attacker->instance != -1);
Assert(attacker->instance >= 0);
Assert(Ships[attacker->instance].ai_index != -1);
// Bogus! Who tried to get me to attack myself!
if (attacker == attacked) {
@@ -4417,6 +4420,13 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
bool carry_flag = ((shipp->flags[Ship::Ship_Flags::Navpoint_carry]) || ((shipp->wingnum >= 0) && (Wings[shipp->wingnum].flags[Ship::Wing_Flags::Nav_carry])));
float waypoint_turnrate = 1 / (3.0f * scale);
// for retail compatability reasons, have to take into account rotdamp so that ships with less than 1 rotdamp have increased waypoint turnrate
// please see PR #2740 and #3494 for more information
if (Pl_objp->phys_info.rotdamp < 1.0f )
// start increasing the turnrate to 2x at 0.5 rotdamp and 3x at 0
waypoint_turnrate *= (3 - 2 * Pl_objp->phys_info.rotdamp);
vec3d turnrate_mod;
vm_vec_make(&turnrate_mod, waypoint_turnrate, waypoint_turnrate, waypoint_turnrate);
@@ -4697,11 +4707,13 @@ void ai_waypoints()
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, aip->wp_list->get_name(), -1 );
}
// adds scripting hook for 'On Waypoints Done' --wookieejedi
Script_system.SetHookObject("Ship", &Objects[Ships[Pl_objp->instance].objnum]);
Script_system.SetHookVar("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum));
Script_system.SetHookVar("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(aip->wp_list)));
Script_system.RunCondition(CHA_ONWAYPOINTSDONE);
Script_system.RemHookVars({"Ship", "Wing", "Waypointlist"});
if (Script_system.IsActiveAction(CHA_ONWAYPOINTSDONE)) {
Script_system.SetHookObject("Ship", &Objects[Ships[Pl_objp->instance].objnum]);
Script_system.SetHookVar("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum));
Script_system.SetHookVar("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(aip->wp_list)));
Script_system.RunCondition(CHA_ONWAYPOINTSDONE);
Script_system.RemHookVars({"Ship", "Wing", "Waypointlist"});
}
}
}
}
@@ -5285,7 +5297,7 @@ void evade_ship()
}
} else {
evade_ship_l1: ;
if (aip->ai_evasion > myrand()*100.0f/32767.0f) {
if (aip->ai_evasion > Random::next()*Random::INV_F_MAX_VALUE*100.0f) {
int temp;
float scale;
float psrandval; // some value close to zero to choose whether to turn right or left.
@@ -5755,6 +5767,140 @@ void set_primary_weapon_linkage(object *objp)
}
}
const int MULTILOCK_CHECK_INTERVAL = 250; // every quarter of a second
// This function returns if the ship could theoretically have fully locked all available targets
// given the current time it's been locking on its primary target
// If so, it cheats a little bit and assumes that's what it has done, and fills
// the ai's missile_locks_firing vector, and to be fired at those targets
bool ai_do_multilock(ai_info* aip, weapon_info* wip) {
if (!timestamp_elapsed(aip->multilock_check_timestamp))
return false;
object* primary_target = &Objects[aip->target_objnum];
struct multilock_target {
object* objp;
ship_subsys* subsys;
float dot;
};
// First we accrue all available targets into this vector which we will later sort by dot
SCP_vector<multilock_target> multilock_targets;
if (wip->target_restrict == LR_CURRENT_TARGET)
multilock_targets.push_back(multilock_target{ primary_target, aip->targeted_subsys, 1.0f });
else if (wip->target_restrict == LR_CURRENT_TARGET_SUBSYS) {
if (primary_target->type != OBJ_SHIP)
multilock_targets.push_back(multilock_target{ primary_target, nullptr, 1.0f });
else {
ship* sp = &Ships[primary_target->instance];
ship_subsys* ss;
if (Ship_info[sp->ship_info_index].is_big_or_huge()) {
for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss)) {
float dot;
if (!weapon_multilock_can_lock_on_subsys(Pl_objp, primary_target, ss, wip, &dot))
continue;
// this will guarantee the ship will send always send some missiles at its actual target
if (aip->targeted_subsys == ss)
dot = 1.0f;
multilock_targets.push_back(multilock_target{ primary_target, ss, dot });
}
} else
multilock_targets.push_back(multilock_target{ primary_target, nullptr, 1.0f });
}
} else { // any target
for (ship_obj* so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so)) {
object* target_objp = &Objects[so->objnum];
ship* target_ship = &Ships[target_objp->instance];
float dot;
if (!weapon_multilock_can_lock_on_target(Pl_objp, target_objp, wip, &dot))
continue;
if (Ship_info[target_ship->ship_info_index].is_big_or_huge()) {
// add ALL the valid subsystems as possible targets
// dont check range or lock fov, the sub function will do that for subsystems
ship_subsys* ss;
for (ss = GET_FIRST(&target_ship->subsys_list); ss != END_OF_LIST(&target_ship->subsys_list); ss = GET_NEXT(ss)) {
if (!weapon_multilock_can_lock_on_subsys(Pl_objp, target_objp, ss, wip, &dot))
continue;
// this will guarantee the ship will send always send some missiles at its actual target
if (aip->targeted_subsys == ss)
dot = 1.0f;
multilock_targets.push_back(multilock_target{ target_objp, ss, dot });
}
} else {
// just a small target, now we check range and fov
if (!weapon_secondary_world_pos_in_range(Player_obj, wip, &target_objp->pos))
continue;
if (dot < wip->lock_fov)
continue;
// this will guarantee the ship will send always send some missiles at its actual target
if (primary_target == target_objp)
dot = 1.0f;
multilock_targets.push_back(multilock_target{ target_objp, nullptr, dot });
}
}
}
// before any sorting let's first determine if we're maximally locked
int allocatable_missiles = MIN(weapon_get_max_missile_seekers(wip), (int)multilock_targets.size() * wip->max_seekers_per_target);
float missiles_allocated = wip->max_seeking * (aip->aspect_locked_time / wip->min_lock_time);
// we could still lock more missiles! wait for it (or couldn't find any targets??)
if (missiles_allocated < allocatable_missiles || allocatable_missiles == 0) {
aip->multilock_check_timestamp = timestamp(MULTILOCK_CHECK_INTERVAL);
return false;
}
// we're fully locked! sort by dot and let them fly!
std::sort(multilock_targets.begin(), multilock_targets.end(), [](multilock_target &a, multilock_target &b)
{ return a.dot < b.dot; });
aip->ai_missile_locks_firing.clear();
int missiles = weapon_get_max_missile_seekers(wip);
int remaining_seekers_per_target = wip->max_seekers_per_target;
for (size_t i = multilock_targets.size() - 1;; i--) {
std::pair<int, ship_subsys*> lock;
lock.first = OBJ_INDEX(multilock_targets.at(i).objp);
lock.second = multilock_targets.at(i).subsys;
aip->ai_missile_locks_firing.push_back(lock);
missiles--;
// out of missiles, we're done
if (missiles == 0)
break;
// still more missiles, but exhausted our targets, time to loop over them all again
// and start double-locking triple-locking etc
if (i == 0) {
remaining_seekers_per_target--;
// exhausted our seekers per target, we're done
if (remaining_seekers_per_target == 0)
break;
// reset i and go through the whole list again
i = multilock_targets.size();
}
}
return true;
}
// --------------------------------------------------------------------------
// Fire the current primary weapon.
// *objp is the object to fire from.
@@ -6396,9 +6542,18 @@ int ai_fire_secondary_weapon(object *objp)
// Note, maybe don't fire if firing at player and any homers yet fired.
// Decreasing chance to fire the more homers are incoming on player.
if (check_ok_to_fire(OBJ_INDEX(objp), aip->target_objnum, wip, current_bank, nullptr)) {
if (wip->multi_lock && !ai_do_multilock(aip, wip))
return rval;
if (ship_fire_secondary(objp)) {
rval = 1;
swp->next_secondary_fire_stamp[current_bank] = timestamp(500);
if (wip->multi_lock && wip->launch_reset_locks) {
aip->aspect_locked_time = 0.0f;
aip->current_target_is_locked = 0;
}
}
} else {
@@ -6606,6 +6761,8 @@ float ai_get_weapon_dist(ship_weapon *swp)
return 1000.0f;
}
Assertion(weapon_num >= 0, "A ship's weapon has a nonsense index of %d, but the ship's name is not accessible from this function. Please report!", weapon_num);
return MIN((Weapon_info[weapon_num].max_speed * Weapon_info[weapon_num].lifetime), Weapon_info[weapon_num].weapon_range);
}
@@ -6623,6 +6780,8 @@ float ai_get_weapon_speed(ship_weapon *swp)
return 100.0f;
}
Assertion(weapon_num >= 0, "A ship's weapon has a nonsense index of %d, but the ship's name is not accessible from this function. Please report!", weapon_num);
return Weapon_info[weapon_num].max_speed;
}
@@ -6632,14 +6791,16 @@ weapon_info* ai_get_weapon(ship_weapon *swp)
bank_num = swp->current_primary_bank;
if (bank_num < 0)
return NULL;
return nullptr;
weapon_num = swp->primary_bank_weapons[bank_num];
if (weapon_num == -1) {
return NULL;
return nullptr;
}
Assertion(weapon_num >= 0, "A ship's weapon has a nonsense index of %d, but the ship's name is not accessible from this function. Please report!", weapon_num);
return &Weapon_info[weapon_num];
}
@@ -6894,6 +7055,8 @@ float ai_endangered_by_weapon(ai_info *aip)
return -1.0f;
}
Assertion(aip->danger_weapon_objnum >= 0, "%s has a nonsense danger_weapon_objnum of %d. Please report!", Ships[aip->shipnum].ship_name, aip->danger_weapon_objnum);\
weapon_objp = &Objects[aip->danger_weapon_objnum];
if (weapon_objp->signature != aip->danger_weapon_signature) {
@@ -6935,6 +7098,8 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip)
AI_ci.sideways = side_vec.x;
AI_ci.vertical = side_vec.y;
}
const float AI_DEFAULT_ATTACK_APPROACH_DIST = 200.0f;
/**
* Set acceleration while in attack mode.
@@ -6987,10 +7152,24 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
return;
}
// assume the original retail value of a 200m range
float optimal_range = AI_DEFAULT_ATTACK_APPROACH_DIST;
ship_weapon* weapons = &Ships[Pl_objp->instance].weapons;
weapon_info* wip = nullptr;
if (dist_to_enemy > 200.0f + vm_vec_mag_quick(&En_objp->phys_info.vel) * dot_from_enemy + Pl_objp->phys_info.speed * speed_ratio) {
// see if we can get a better one
if (weapons->num_primary_banks >= 1 && weapons->current_primary_bank >= 0) {
wip = &Weapon_info[weapons->primary_bank_weapons[weapons->current_primary_bank]];
} else if (weapons->num_secondary_banks >= 1 && weapons->current_secondary_bank >= 0) {
wip = &Weapon_info[weapons->secondary_bank_weapons[weapons->current_secondary_bank]];
}
if (wip != nullptr && wip->optimum_range > 0)
optimal_range = wip->optimum_range;
if (dist_to_enemy > optimal_range + vm_vec_mag_quick(&En_objp->phys_info.vel) * dot_from_enemy + Pl_objp->phys_info.speed * speed_ratio) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
if (dist_to_enemy > 800.0f) {
if (dist_to_enemy > optimal_range + 600.0f) {
if (!( Pl_objp->phys_info.flags & PF_AFTERBURNER_ON )) {
float percent_left;
ship *shipp;
@@ -7543,7 +7722,7 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
vec3d new_pos;
start_bank = Ships[aip->shipnum].weapons.current_primary_bank;
if (po->n_guns && start_bank != -1 ) {
if (po->n_guns && start_bank != -1 && !(The_mission.ai_profile->flags[AI::Profile_Flags::Ai_aims_from_ship_center])) {
rel_pos = &po->gun_banks[start_bank].pnt[0];
} else
rel_pos = NULL;
@@ -7677,6 +7856,8 @@ int ai_set_attack_subsystem(object *objp, int subnum)
if ( aip->target_objnum == -1 )
return 0;
Assertion(aip->target_objnum >= 0, "The target_objnum for %s has become a nonsense value of %d. Please report!",attacker_shipp->ship_name ,aip->target_objnum);
attacked_objp = &Objects[aip->target_objnum];
shipp = &Ships[attacked_objp->instance]; // need to get our target's ship pointer!!!
@@ -7891,11 +8072,13 @@ void update_aspect_lock_information(ai_info *aip, vec3d *vec_to_enemy, float dis
(tshpp == NULL ||
ship_get_closest_subsys_in_sight(tshpp, SUBSYSTEM_ENGINE, &aiobjp->pos))))) {
aip->aspect_locked_time += flFrametime;
if (aip->aspect_locked_time >= wip->min_lock_time) {
aip->aspect_locked_time = wip->min_lock_time;
if (aip->aspect_locked_time >= wip->min_lock_time) {
aip->current_target_is_locked = 1;
}
} else {
if (aip->aspect_locked_time > wip->min_lock_time)
aip->aspect_locked_time = wip->min_lock_time;
aip->aspect_locked_time -= flFrametime*2;
if (aip->aspect_locked_time < 0.0f)
aip->aspect_locked_time = 0.0f;
@@ -7932,6 +8115,8 @@ void ai_chase_fly_away(object *objp, ai_info *aip)
} else {
vec3d v2e;
float dot;
Assertion(aip->target_objnum >= 0, "This ship's target objnum is nonsense. It is %d instead of a positive number or -1.", aip->target_objnum);
vm_vec_normalized_dir(&v2e, &Objects[aip->target_objnum].pos, &objp->pos);
@@ -8776,7 +8961,7 @@ void ai_chase()
if (frand() > 0.5f) {
aip->submode = SM_CONTINUOUS_TURN;
aip->submode_start_time = Missiontime;
aip->submode_parm0 = myrand() & 0x0f;
aip->submode_parm0 = Random::next() & 0x0f;
} else {
aip->submode = SM_EVADE;
aip->submode_start_time = Missiontime;
@@ -8859,7 +9044,7 @@ void ai_chase()
? (float)(aip->ai_class + Game_skill_level)/(Num_ai_classes + NUM_SKILL_LEVELS)
: aip->ai_get_away_chance;
switch (myrand() % 5) {
switch (Random::next(5)) {
case 0:
aip->submode = SM_CONTINUOUS_TURN;
aip->submode_start_time = Missiontime;
@@ -9064,7 +9249,7 @@ void ai_chase()
float range_max = pwip->max_speed * (1.0f + scale);
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
range_max = std::min({range_max, pwip->max_speed * pwip->lifetime, pwip->weapon_range});
range_min = pwip->WeaponMinRange;
range_min = pwip->weapon_min_range;
}
if ((dist_to_enemy < range_max) && (dist_to_enemy >= range_min)) {
if(ai_fire_primary_weapon(Pl_objp) == 1){
@@ -9148,11 +9333,11 @@ void ai_chase()
} 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] = rand32();
swp->burst_seed[current_bank_adjusted] = Random::next();
}
} else {
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
@@ -9161,11 +9346,11 @@ void ai_chase()
} 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] = rand32();
swp->burst_seed[current_bank_adjusted] = Random::next();
}
}
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (t*1000.0f));
@@ -9756,7 +9941,7 @@ void remove_farthest_attacker(int objnum)
aip->ignore_objnum = aip->target_objnum;
aip->ignore_signature = Objects[aip->target_objnum].signature;
aip->ai_flags.set(AI::AI_Flags::Temporary_ignore);
aip->ignore_expire_timestamp = timestamp(((myrand() % 10) + 20) * 1000); // OK to attack again in 20 to 24 seconds.
aip->ignore_expire_timestamp = timestamp(Random::next(20, 29) * 1000); // OK to attack again in 20 to 29 seconds.
}
aip->target_objnum = -1;
ai_do_default_behavior(farthest_objp);
@@ -11463,9 +11648,6 @@ void process_subobjects(int objnum)
ai_info *aip = &Ai_info[shipp->ai_index];
ship_info *sip = &Ship_info[shipp->ship_info_index];
//Look for enemies. If none are present, we don't have to move turrets
int enemies_present = -1;
model_subsystem *psub;
for ( pss = GET_FIRST(&shipp->subsys_list); pss !=END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
psub = pss->system_info;
@@ -11485,34 +11667,7 @@ void process_subobjects(int objnum)
if ( psub->turret_num_firing_points > 0 )
{
if(enemies_present == -1)
{
enemies_present = 0;
for(unsigned int i = 0; i < MAX_OBJECTS; i++)
{
objp = &Objects[i];
switch(objp->type)
{
case OBJ_SHIP:
case OBJ_DEBRIS:
case OBJ_WEAPON:
if(obj_team(objp) != shipp->team)
enemies_present = 1;
break;
case OBJ_ASTEROID:
enemies_present = 1;
break;
}
if(enemies_present==1)
break;
}
//Reset objp
objp = &Objects[objnum];
}
//Only move turrets if enemies are present
if(enemies_present == 1 || pss->turret_enemy_objnum >= 0)
ai_fire_from_turret(shipp, pss);
ai_turret_execute_behavior(shipp, pss);
} else {
Warning( LOCATION, "Turret %s on ship %s has no firing points assigned to it.\nThis needs to be fixed in the model.\n", psub->name, shipp->ship_name );
}
@@ -12294,6 +12449,8 @@ void ai_do_repair_frame(object *objp, ai_info *aip, float frametime)
if (support_objnum == -1)
return;
Assertion(support_objnum >= 0, "The support ship objnum is nonsense. It is %d instead of a positive number or -1.", support_objnum);
// Curious -- object numbers match, but signatures do not.
// Must mean original repair ship died and was replaced by current ship.
Assert(Objects[support_objnum].signature == aip->support_ship_signature);
@@ -12893,7 +13050,9 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
pnode *pnp;
vec3d *next_point;
Assertion(pl_objp->instance >= 0, "Arriving ship does not have a valid ship number. Has %d instead. Please report!", pl_objp->instance);
ship *shipp = &Ships[pl_objp->instance];
Assertion(shipp->ai_index >= 0, "Arriving ship does not have a valid ai index. Has %d instead. Please report!", shipp->ai_index);
ai_info *aip = &Ai_info[shipp->ai_index];
if ( parent_objnum == -1 ) {
@@ -12901,6 +13060,7 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
return -1;
}
Assertion(parent_objnum >= 0, "Arriving ship does not have a parent object number. Has %d instead. Please report!", parent_objnum);
object *parent_objp = &Objects[parent_objnum];
ship *parent_shipp = &Ships[parent_objp->instance];
@@ -13609,7 +13769,7 @@ void ai_maybe_depart(object *objp)
if (sip->is_fighter_bomber()) {
if (aip->warp_out_timestamp == 0) {
//if (ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS) == 0.0f) {
// aip->warp_out_timestamp = timestamp(((myrand() % 10) + 10) * 1000);
// aip->warp_out_timestamp = timestamp(Random::next(10, 19) * 1000);
//}
} else if (timestamp_elapsed(aip->warp_out_timestamp)) {
mission_do_departure(objp);
@@ -14096,7 +14256,7 @@ void ai_maybe_self_destruct(object *objp, ai_info *aip)
}
if (timestamp_elapsed(aip->self_destruct_timestamp)) {
ship_apply_local_damage( objp, objp, &objp->pos, objp->hull_strength*flFrametime + 1.0f, MISS_SHIELDS);
ship_apply_local_damage( objp, objp, &objp->pos, objp->hull_strength*flFrametime + 1.0f, -1, MISS_SHIELDS);
}
}
}
@@ -14765,6 +14925,9 @@ void init_ai_object(int objnum)
memset(&aip->ai_override_ci,0,sizeof(control_info));
aip->form_obj_slotnum = -1;
aip->multilock_check_timestamp = timestamp(1);
aip->ai_missile_locks_firing.clear();
}
void init_ai_system()
@@ -15225,7 +15388,7 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
{
int hitter_objnum = -2;
object *objp_hitter = NULL;
object *objp_hitter = nullptr;
ship *shipp;
ai_info *aip, *hitter_aip;
@@ -15233,25 +15396,29 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
aip = &Ai_info[shipp->ai_index];
if (objp_ship->flags[Object::Object_Flags::Player_ship]) {
//SUSHI: So that hitting a player ship actually resets the last_hit_target_time counter for whoever hit the player.
//This is all copypasted from code below
// Added OBJ_BEAM for traitor detection - FUBAR
if ((hit_objp->type == OBJ_WEAPON) || (hit_objp->type == OBJ_BEAM)) {
hitter_objnum = hit_objp->parent;
Assert((hitter_objnum < MAX_OBJECTS));
if (hitter_objnum == -1) {
return; // Possible SSM, bail while we still can.
if (The_mission.ai_profile->flags[AI::Profile_Flags::Reset_last_hit_target_time_for_player_hits]) {
//SUSHI: So that hitting a player ship actually resets the last_hit_target_time counter for whoever hit the player.
//This is all copypasted from code below
// Added OBJ_BEAM for traitor detection - FUBAR
if ((hit_objp->type == OBJ_WEAPON) || (hit_objp->type == OBJ_BEAM)) {
hitter_objnum = hit_objp->parent;
Assert((hitter_objnum < MAX_OBJECTS));
if (hitter_objnum == -1) {
return; // Possible SSM, bail while we still can.
}
objp_hitter = &Objects[hitter_objnum];
} else if (hit_objp->type == OBJ_SHIP) {
objp_hitter = hit_objp;
} else {
UNREACHABLE("Should never happen.");
return;
}
objp_hitter = &Objects[hitter_objnum];
} else if (hit_objp->type == OBJ_SHIP) {
objp_hitter = hit_objp;
} else {
Int3(); // Should never happen.
return;
Assert(objp_hitter != nullptr);
hitter_aip = &Ai_info[Ships[objp_hitter->instance].ai_index];
hitter_aip->last_hit_target_time = Missiontime;
aip->last_hit_time = Missiontime;
}
Assert(objp_hitter != NULL);
hitter_aip = &Ai_info[Ships[objp_hitter->instance].ai_index];
hitter_aip->last_hit_target_time = Missiontime;
return;
}
@@ -15277,6 +15444,11 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
if ( hit_objp->parent_sig != Objects[hit_objp->parent].signature ){
return;
}
weapon_info* wip = hit_objp->type == OBJ_WEAPON ? &Weapon_info[Weapons[hit_objp->instance].weapon_info_index] :
&Weapon_info[Beams[hit_objp->instance].weapon_info_index];
if (wip->wi_flags[Weapon::Info_Flags::Heals])
return;
hitter_objnum = hit_objp->parent;
Assert((hitter_objnum >= 0) && (hitter_objnum < MAX_OBJECTS));
@@ -15332,7 +15504,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
if (hit_objp->flags[Object::Object_Flags::Protected])
return;
Assert(objp_hitter != NULL);
Assert(objp_hitter != nullptr);
hitter_aip = &Ai_info[Ships[objp_hitter->instance].ai_index];
hitter_aip->last_hit_target_time = Missiontime;
+5 -3
View File
@@ -293,9 +293,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 )
+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
+117 -163
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_find_world_dir(&fvec, &pm->submodel[submodel_num].frame_of_reference.vec.fvec, pm, pmi, pm->submodel[submodel_num].parent, objorient);
model_instance_find_world_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,124 +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]) {
// Since we no longer maintain world_to_turret_matrix, regenerate it here.
vec3d turret_norm;
matrix turret_matrix, world_to_turret_matrix;
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->subobj_num, &vmd_identity_matrix);
vm_vector_2_matrix(&turret_matrix, &turret_norm, nullptr, nullptr);
vm_matrix_x_matrix(&world_to_turret_matrix, &objp->orient, &turret_matrix);
vec3d temp_vec2;
vm_vec_rotate(&temp_vec2, &temp_vec, &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, &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;
}
/**
@@ -1196,17 +1138,11 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
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) {
@@ -1256,7 +1192,7 @@ void ship_get_global_turret_info(const object *objp, const model_subsystem *tp,
if (gpos)
model_instance_find_world_point(gpos, &vmd_zero_vector, model_instance_num, tp->subobj_num, &objp->orient, &objp->pos);
if (gvec)
model_instance_find_world_dir(gvec, &tp->turret_norm, model_instance_num, tp->subobj_num, &objp->orient);
model_instance_find_world_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);
@@ -1317,7 +1253,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
} else {
if ((lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge())) {
// the turret norm here is from the perspective of the base submodel, not the gun submodel
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, pm, pmi, tp->subobj_num, &objp->orient);
model_instance_find_world_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 {
@@ -1448,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
@@ -1491,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;
model_instance_find_world_dir(&turret_norm, &turret_subsysp->system_info->turret_norm, Ships[objp->instance].model_instance_num, turret_subsysp->system_info->subobj_num, &objp->orient);
model_instance_find_world_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]) {
@@ -1674,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 {
@@ -1685,12 +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);
turret->weapons.burst_seed[weapon_num] = rand32();
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] = rand32();
turret->weapons.burst_seed[weapon_num] = Random::next();
}
}
@@ -1701,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
@@ -1857,8 +1790,19 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
vm_vector_2_matrix(&turret_orient, firing_vec, nullptr, nullptr);
// set next fire timestamp for the turret
// 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)
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
@@ -1884,6 +1828,8 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
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);
@@ -1894,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
@@ -2026,9 +1974,11 @@ 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]) {
@@ -2142,9 +2092,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) {
@@ -2175,13 +2127,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;
@@ -2356,12 +2310,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
@@ -2374,7 +2328,7 @@ 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;
@@ -2441,6 +2395,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
@@ -2812,25 +2771,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)) {
// Since we no longer maintain world_to_turret_matrix, regenerate it here.
object *objp = &Objects[ss->parent_objnum];
vec3d turret_norm;
matrix turret_matrix, world_to_turret_matrix;
model_instance_find_world_dir(&turret_norm, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->subobj_num, &vmd_identity_matrix);
vm_vector_2_matrix(&turret_matrix, &turret_norm, nullptr, nullptr);
vm_matrix_x_matrix(&world_to_turret_matrix, &objp->orient, &turret_matrix);
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, &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;
}
}
@@ -2841,7 +2795,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);
+17 -10
View File
@@ -324,7 +324,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"));
@@ -496,7 +496,7 @@ 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 {
float random_threshold;
@@ -564,7 +564,7 @@ void asteroid_create_all()
// For asteroid, load only large asteroids
// get a valid subtype
int subtype = rand() % NUM_DEBRIS_POFS;
int subtype = Random::next(NUM_DEBRIS_POFS);
while (Asteroid_field.field_debris_type[subtype] == -1) {
subtype = (subtype + 1) % NUM_DEBRIS_POFS;
}
@@ -758,7 +758,7 @@ static void maybe_throw_asteroid(int count)
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;
int subtype = Random::next(NUM_DEBRIS_POFS);
while (Asteroid_field.field_debris_type[subtype] == -1) {
subtype = (subtype + 1) % NUM_DEBRIS_POFS;
}
@@ -1324,7 +1324,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
}
@@ -1432,9 +1432,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);
@@ -1484,7 +1489,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++)
@@ -1539,8 +1544,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");
}
}
}
+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);
+5 -3
View File
@@ -866,6 +866,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 +922,7 @@ int cfclose( CFILE * cfile )
} else {
// VP do nothing
}
cf_clear_compression_info(cfile);
cfile->type = CFILE_BLOCK_UNUSED;
return result;
}
@@ -973,7 +974,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 +1009,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 +1053,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) {
+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
+13 -5
View File
@@ -246,7 +246,7 @@ 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", },
@@ -479,6 +479,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
@@ -510,6 +511,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;
@@ -1617,7 +1619,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';
}
}
@@ -1627,8 +1629,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';
}
}
@@ -1713,7 +1716,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()){
@@ -2123,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;
+1
View File
@@ -143,6 +143,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;
+13 -9
View File
@@ -115,10 +115,10 @@ int Conflict_wnd_coords[GR_NUM_RESOLUTIONS][4] = {
// conflict warning anim coords
int Conflict_warning_coords[GR_NUM_RESOLUTIONS][2] = {
{
-1, 420 // GR_640
320, 420 // GR_640
},
{
-1, 669 // GR_1024
512, 669 // GR_1024
}
};
@@ -1288,7 +1288,7 @@ void control_config_cancel_exit()
{
// Restore all bindings with the backup
std::move(Control_config_backup.begin(), Control_config_backup.end(), Control_config.begin());
std::move(Axis_map_to_backup, Axis_map_to_backup + JOY_NUM_AXES, Axis_map_to);
std::move(Axis_map_to_backup, Axis_map_to_backup + NUM_JOY_AXIS_ACTIONS, Axis_map_to);
std::move(Invert_axis_backup, Invert_axis_backup + JOY_NUM_AXES, Invert_axis);
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
@@ -1934,7 +1934,7 @@ void control_config_do_frame(float frametime)
for (i=0; i<MOUSE_NUM_BUTTONS; i++) {
if (mouse_down(1 << i)) {
Assert(!(z & JOY_AXIS));
control_config_bind_btn(z, CC_bind(CID_MOUSE, static_cast<short>(i)), 1);
control_config_bind_btn(z, CC_bind(CID_JOY0, static_cast<short>(i)), 1);
strcpy_s(bound_string, Joy_button_text[i]);
done = true;
@@ -2295,7 +2295,9 @@ void control_config_do_frame(float frametime)
int sw, sh;
gr_get_string_size(&sw, &sh, conflict_str);
gr_string((gr_screen.max_w / 2) - (sw / 2), Conflict_warning_coords[gr_screen.res][1], conflict_str, GR_RESIZE_MENU);
x = Conflict_warning_coords[gr_screen.res][CONTROL_X_COORD] - (sw / 2);
y = Conflict_warning_coords[gr_screen.res][CONTROL_Y_COORD];
gr_printf_menu(x, y, "%s", conflict_str);
font::set_font(font::FONT1);
} else {
@@ -2550,9 +2552,11 @@ int check_control(int id, int key)
// If we reach this point, then it means this is a continuous control
// which has just been released
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
Script_system.RemHookVar("Action");
if (Script_system.IsActiveAction(CHA_ONACTIONSTOPPED)) {
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
Script_system.RemHookVar("Action");
}
Control_config[id].continuous_ongoing = false;
}
@@ -2647,4 +2651,4 @@ void control_config_clear()
for (auto &item : Control_config) {
item.clear();
}
}
}
+2 -2
View File
@@ -1516,9 +1516,9 @@ void control_config_common_read_section(int s, bool first_override) {
// Assign the various attributes to this control
int iTemp;
short key = 0;
auto item = &Control_config[item_id];
auto& new_binding = new_preset.bindings[item_id];
short key = new_binding.get_btn(CID_KEYBOARD);
// Key assignment and modifiers
if (optional_string("$Key Default:")) {
@@ -1987,7 +1987,7 @@ CCI_builder& CCI_builder::operator()(IoActionId action_id, short key_default, sh
item.type = type;
if (tab == NO_TAB) {
mprintf(("Control item defined without a valid tab. Disabling: %s", item.text.c_str()));
mprintf(("Control item defined without a valid tab. Disabling: %s\n", item.text.c_str()));
}
// Assign disabled state
+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]);
}
}
+4 -6
View File
@@ -45,10 +45,8 @@ struct 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;
+30 -67
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 > source_obj->radius * 20.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
@@ -460,15 +417,15 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
if (!hull_flag) {
if (model_num >= 0) {
db->model_num = model_num;
db->submodel_num = (myrand() >> 4) % sip->generic_debris_num_submodels;
db->submodel_num = Random::next(sip->generic_debris_num_submodels);
}
else if (vaporize) {
db->model_num = Debris_vaporize_model;
db->submodel_num = (myrand() >> 4) % Debris_num_submodels;
db->submodel_num = Random::next(Debris_num_submodels);
}
else {
db->model_num = Debris_model;
db->submodel_num = (myrand() >> 4) % Debris_num_submodels;
db->submodel_num = Random::next(Debris_num_submodels);
}
}
else {
@@ -480,8 +437,17 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
float radius = submodel_get_radius(db->model_num, db->submodel_num);
//WMC - We must survive until now, at least.
db->must_survive_until = timestamp();
// 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)
{
@@ -491,7 +457,7 @@ 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.
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);
@@ -509,12 +475,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;
}
@@ -539,7 +503,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;
@@ -560,7 +523,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
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;
@@ -576,10 +539,10 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
vm_vector_2_matrix(&orient, &rand);
}
objnum = obj_create( OBJ_DEBRIS, parent_objnum, n, &orient, pos, radius, default_flags);
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;
@@ -629,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
@@ -641,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 ) {
@@ -652,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 ) {
@@ -679,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);
-2
View File
@@ -40,7 +40,6 @@ 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
@@ -50,7 +49,6 @@ typedef struct debris {
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
+2 -4
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;
};
@@ -31,9 +31,7 @@ void main()
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);
+9 -1
View File
@@ -429,7 +429,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
+21 -8
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"
@@ -286,11 +287,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
@@ -314,6 +317,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
@@ -321,6 +325,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:"))
{
@@ -328,6 +333,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
@@ -830,7 +838,7 @@ 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);
objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, default_flags, false);
obj = &Objects[objnum];
@@ -843,11 +851,11 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
switch( new_fireball->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION:
new_fireball->orient = (myrand()>>8) & 7; // 0 - 7
new_fireball->orient = Random::next() & 7; // 0 - 7
break;
case FIREBALL_LARGE_EXPLOSION:
new_fireball->orient = (myrand()>>8) % 360; // 0 - 359
new_fireball->orient = Random::next(360); // 0 - 359
break;
case FIREBALL_WARP_EFFECT:
@@ -978,9 +986,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;
@@ -997,7 +1005,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;
@@ -1037,19 +1045,24 @@ void fireball_render(object* obj, model_draw_list *scene)
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, NEB_FOG_VISIBILITY_MULT_FIREBALL(obj->radius));
g3_transfer_vertex(&p, &obj->pos);
switch ( fb->fireball_render_type ) {
case FIREBALL_MEDIUM_EXPLOSION: {
batching_add_volume_bitmap(fb->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(fb->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;
+1 -1
View File
@@ -91,7 +91,7 @@ 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);
+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;
+20 -20
View File
@@ -526,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));
}
}
}
@@ -544,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);
}
}
}
@@ -565,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);
}
}
}
@@ -583,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();
@@ -602,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);
}
}
}
@@ -751,14 +751,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;
}
}
@@ -1349,7 +1349,7 @@ float gamesnd_get_max_duration(game_snd* gs) {
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));
@@ -1362,14 +1362,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;
+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)
-45
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;
@@ -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.
-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
+3 -1
View File
@@ -41,6 +41,7 @@
#include "scripting/scripting.h"
#include "tracing/tracing.h"
#include "utils/boost/hash_combine.h"
#include "gamesequence/gamesequence.h"
#ifdef WITH_OPENGL
#include "graphics/opengl/gropengl.h"
@@ -2547,7 +2548,8 @@ void gr_flip(bool execute_scripting)
executor::OnFrameExecutor->process();
// m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
if (execute_scripting && !popup_active()) {
// Cyborg - A similar bug will occur when a mission is restarted so check for that, too.
if (execute_scripting && !popup_active() && !((gameseq_get_state() == GS_STATE_GAME_PLAY) && !(Game_mode & GM_IN_MISSION))) {
TRACE_SCOPE(tracing::LuaOnFrame);
// WMC - Do conditional hooks. Yippee!
+1 -1
View File
@@ -808,7 +808,7 @@ typedef struct screen {
std::function<void(int bitmap_handle, int bpp, const ubyte* data, int width, int height)> gf_update_texture;
std::function<void(void* data_out, int bitmap_num)> gf_get_bitmap_from_texture;
std::function<void(matrix4* shadow_view_matrix, const matrix* light_matrix)> gf_shadow_map_start;
std::function<void(matrix4* shadow_view_matrix, const matrix* light_matrix, vec3d* eye_pos)> gf_shadow_map_start;
std::function<void()> gf_shadow_map_end;
std::function<void()> gf_start_decal_pass;
+16 -2
View File
@@ -630,7 +630,7 @@ void generic_anim_render_variable_frame_delay(generic_anim* ga, float frametime,
else {
// playing forwards
ga->anim_time += frametime;
if(ga->anim_time >= ga->total_time && ga->png.anim->current_frame >= ga->png.anim->nframes-1) {
if(ga->anim_time >= ga->total_time && ga->png.anim->current_frame >= ga->png.anim->nframes) {
if(ga->direction & GENERIC_ANIM_DIRECTION_NOLOOP) {
ga->anim_time = ga->total_time; // stop on last frame when playing
}
@@ -660,7 +660,7 @@ void generic_anim_render_variable_frame_delay(generic_anim* ga, float frametime,
}
else {
if (ga->anim_time >= ga->png.previous_frame_time + ga->png.anim->frame.delay &&
ga->png.anim->current_frame < ga->png.anim->nframes-1) {
ga->png.anim->current_frame < ga->png.anim->nframes) {
ga->png.previous_frame_time += ga->png.anim->frame.delay;
ga->current_frame++;
}
@@ -725,3 +725,17 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
}
}
}
/*
* @brief reset an animation back to the start
*
* @param [in] *ga animation data
*/
void generic_anim_reset(generic_anim *ga) {
ga->anim_time = 0.0f;
ga->current_frame = 0;
if (ga->type == BM_TYPE_PNG) {
ga->png.previous_frame_time = 0.0f;
ga->png.anim->goto_start();
}
}
+1 -1
View File
@@ -89,5 +89,5 @@ int generic_anim_stream(generic_anim *ga, const bool cache = true);
int generic_bitmap_load(generic_bitmap *gb);
void generic_anim_unload(generic_anim *ga);
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr);
void generic_anim_reset(generic_anim *ga);
#endif
+1 -1
View File
@@ -285,7 +285,7 @@ int gr_stub_maybe_create_shader(shader_type /*shader_t*/, unsigned int /*flags
return -1;
}
void gr_stub_shadow_map_start(matrix4 * /*shadow_view_matrix*/, const matrix* /*light_matrix*/)
void gr_stub_shadow_map_start(matrix4 * /*shadow_view_matrix*/, const matrix* /*light_matrix*/, vec3d* /*eye_pos*/)
{
}
+2 -2
View File
@@ -55,8 +55,8 @@ class ShaderProgram {
ShaderUniforms Uniforms;
ShaderProgram(const ShaderProgram&) SCP_DELETED_FUNCTION;
ShaderProgram& operator=(const ShaderProgram&) SCP_DELETED_FUNCTION;
ShaderProgram(const ShaderProgram&) = delete;
ShaderProgram& operator=(const ShaderProgram&) = delete;
ShaderProgram(ShaderProgram&& other) noexcept;
ShaderProgram& operator=(ShaderProgram&& other) noexcept;
+3 -3
View File
@@ -301,8 +301,8 @@ void gr_opengl_deferred_lighting_finish()
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_emissive_texture);
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_depth_texture);
float fog_near, fog_far;
neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr);
float fog_near, fog_far, fog_density;
neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density);
unsigned char r, g, b;
neb2_get_fog_color(&r, &g, &b);
@@ -311,7 +311,7 @@ void gr_opengl_deferred_lighting_finish()
opengl_set_generic_uniform_data<graphics::generic_data::fog_data>([&](graphics::generic_data::fog_data* data) {
data->fog_start = fog_near;
data->fog_scale = 1.0f / (fog_far - fog_near);
data->fog_density = fog_density;
data->fog_color.xyz.x = r / 255.f;
data->fog_color.xyz.y = g / 255.f;
data->fog_color.xyz.z = b / 255.f;
+2 -2
View File
@@ -706,8 +706,8 @@ void gr_opengl_update_distortion()
for(int i = 0; i < 33; i++)
{
distortion_verts[i].r = (ubyte)rand() % 256;
distortion_verts[i].g = (ubyte)rand() % 256;
distortion_verts[i].r = (ubyte)Random::next(256);
distortion_verts[i].g = (ubyte)Random::next(256);
distortion_verts[i].b = 255;
distortion_verts[i].a = 255;
+1 -1
View File
@@ -34,7 +34,7 @@ void gr_opengl_update_distortion();
void gr_opengl_sphere(material *material_def, float rad);
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient);
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient, vec3d* eye_pos);
void gr_opengl_shadow_map_end();
void gr_opengl_render_shield_impact(shield_material* material_info,
@@ -170,7 +170,7 @@ void opengl_post_pass_bloom()
opengl_set_generic_uniform_data<graphics::generic_data::bloom_composition_data>(
[](graphics::generic_data::bloom_composition_data* data) {
data->levels = MAX_MIP_BLUR_LEVELS;
data->bloom_intensity = Cmdline_bloom_intensity / 100.0f;
data->bloom_intensity = gr_bloom_intensity() / 100.0f;
});
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Bloom_textures[0]);
@@ -442,9 +442,9 @@ void opengl_post_lightshafts()
float dot;
if ( (dot = vm_vec_dot(&light_dir, &Eye_matrix.vec.fvec)) > 0.7f ) {
x = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI * 1.5f +
x = asinf_safe(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI * 1.5f +
0.5f; // cant get the coordinates right but this works for the limited glare fov
y = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI * 1.5f * gr_screen.clip_aspect + 0.5f;
y = asinf_safe(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI * 1.5f * gr_screen.clip_aspect + 0.5f;
opengl_set_generic_uniform_data<graphics::generic_data::lightshaft_data>(
[&](graphics::generic_data::lightshaft_data* data) {
@@ -871,7 +871,7 @@ bool opengl_post_init_shaders()
gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLUR, SDR_FLAG_BLUR_VERTICAL) < 0 ||
gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLOOM_COMP, 0) < 0) {
// disable bloom if we don't have those shaders available
Cmdline_bloom_intensity = 0;
graphics::Post_processing_manager->setBloomShadersOk(false);
}
if (gr_is_fxaa_mode(Gr_aa_mode))
+3 -2
View File
@@ -679,7 +679,7 @@ bool Glowpoint_override_save;
extern bool gr_htl_projection_matrix_set;
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient)
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient, vec3d* eye_pos)
{
if (Shadow_quality == ShadowQuality::Disabled)
return;
@@ -701,7 +701,8 @@ void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light
Glowpoint_override = true;
gr_htl_projection_matrix_set = true;
gr_set_view_matrix(&Eye_position, light_orient);
gr_set_view_matrix(eye_pos, light_orient);
*shadow_view_matrix = gr_view_matrix;
+67 -1
View File
@@ -2,6 +2,7 @@
#include "post_processing.h"
#include "graphics/grinternal.h"
#include "options/Option.h"
#include "parse/parselo.h"
#include "ship/ship.h"
@@ -34,6 +35,31 @@ PostEffectUniformType mapUniformNameToType(const SCP_string& uniform_name)
}
}
// used by In-Game Options menu
bool Post_processing_enable_lightshafts = true;
auto LightshaftsOption =
options::OptionBuilder<bool>("Graphics.Lightshafts", "Lightshafts", "Enable lightshafts (requires post-processing)")
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Post_processing_enable_lightshafts)
.importance(60)
.finish();
int Post_processing_bloom_intensity = 25; // using default value of Cmdline_bloom_intensity
auto BloomIntensityOption = options::OptionBuilder<int>("Graphics.BloomIntensity",
"Bloom intensity",
"Set bloom intensity (requires post-processing)")
.category("Graphics")
.range(0, 200)
.level(options::ExpertLevel::Advanced)
.default_val(25)
.bind_to(&Post_processing_bloom_intensity)
.importance(55)
.finish();
} // namespace
bool PostProcessingManager::parse_table()
@@ -169,9 +195,49 @@ SCP_vector<graphics::post_effect_t>& PostProcessingManager::getPostEffects() { r
const lightshaft_parameters& PostProcessingManager::getLightshaftParams() const { return m_lightshaftParams; }
lightshaft_parameters& PostProcessingManager::getLightshaftParams() { return m_lightshaftParams; }
bool PostProcessingManager::bloomShadersOk() const
{
return m_bloomShadersOk;
}
void PostProcessingManager::setBloomShadersOk(bool ok)
{
m_bloomShadersOk = ok;
}
} // namespace graphics
bool gr_lightshafts_enabled()
{
return graphics::Post_processing_manager->getLightshaftParams().on && !Cmdline_force_lightshaft_off;
if (!graphics::Post_processing_manager->getLightshaftParams().on) {
return false;
}
if (Using_in_game_options) {
return graphics::Post_processing_enable_lightshafts;
} else {
return !Cmdline_force_lightshaft_off;
}
}
int gr_bloom_intensity()
{
if (graphics::Post_processing_manager == nullptr || !graphics::Post_processing_manager->bloomShadersOk()) {
return 0;
}
if (Using_in_game_options) {
return graphics::Post_processing_bloom_intensity;
} else {
return Cmdline_bloom_intensity;
}
}
void gr_set_bloom_intensity(int intensity)
{
if (Using_in_game_options) {
graphics::Post_processing_bloom_intensity = intensity;
} else {
Cmdline_bloom_intensity = intensity;
}
}
+8 -1
View File
@@ -35,7 +35,7 @@ struct post_effect_t {
};
struct lightshaft_parameters {
bool on = false;
bool on = true; // enabled by default
float density = 0.5f;
float weight = 0.02f;
float falloff = 1.0f;
@@ -56,12 +56,19 @@ class PostProcessingManager {
const lightshaft_parameters& getLightshaftParams() const;
lightshaft_parameters& getLightshaftParams();
bool bloomShadersOk() const;
void setBloomShadersOk(bool ok);
private:
SCP_vector<post_effect_t> m_postEffects;
lightshaft_parameters m_lightshaftParams;
bool m_bloomShadersOk = true;
};
} // namespace graphics
bool gr_lightshafts_enabled();
int gr_bloom_intensity();
// used by lab
void gr_set_bloom_intensity(int intensity);
+4 -3
View File
@@ -14,6 +14,7 @@
#include "graphics/matrix.h"
#include "lighting/lighting.h"
#include "math/vecmat.h"
#include "mod_table/mod_table.h"
#include "model/model.h"
#include "model/modelrender.h"
#include "options/Option.h"
@@ -405,7 +406,7 @@ matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float
Shadow_proj_matrix[2] = Shadow_frustums[2].proj_matrix;
Shadow_proj_matrix[3] = Shadow_frustums[3].proj_matrix;
gr_shadow_map_start(&Shadow_view_matrix, &light_matrix);
gr_shadow_map_start(&Shadow_view_matrix, &light_matrix, eye_pos);
return light_matrix;
}
@@ -433,9 +434,9 @@ void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
gr_end_proj_matrix();
gr_end_view_matrix();
// these cascade distances are a result of some arbitrary tuning to give a good balance of quality and banding.
// the default cascade distances are a result of some arbitrary tuning to give a good balance of quality and banding.
// maybe we could use a more programmatic algorithim?
matrix light_matrix = shadows_start_render(eye_orient, eye_pos, fov, gr_screen.clip_aspect, 200.0f, 600.0f, 2500.0f, 8000.0f);
matrix light_matrix = shadows_start_render(eye_orient, eye_pos, fov, gr_screen.clip_aspect, std::get<0>(Shadow_distances), std::get<1>(Shadow_distances), std::get<2>(Shadow_distances), std::get<3>(Shadow_distances));
model_draw_list scene;
object *objp = Objects;
+6 -6
View File
@@ -120,14 +120,14 @@ namespace font
CFILE* fp = cfopen(typeface.c_str(), "rb", CFILE_NORMAL, CF_TYPE_ANY, localize);
if (fp == NULL)
{
mprintf(("Unable to find font file \"%s\".", typeface.c_str()));
mprintf(("Unable to find font file \"%s\"\n", typeface.c_str()));
return NULL;
}
std::unique_ptr<font> fnt(new font());
if (!fnt)
{
mprintf(("Unable to allocate memory for \"%s\"", typeface.c_str()));
mprintf(("Unable to allocate memory for \"%s\"\n", typeface.c_str()));
return NULL;
}
@@ -283,7 +283,7 @@ namespace font
if (fontFile == NULL)
{
mprintf(("Couldn't open font file \"%s\"", fileName.c_str()));
mprintf(("Couldn't open font file \"%s\"\n", fileName.c_str()));
return NULL;
}
@@ -293,14 +293,14 @@ namespace font
if (!fontData)
{
mprintf(("Couldn't allocate " SIZE_T_ARG " bytes for reading font file \"%s\"!", size, fileName.c_str()));
mprintf(("Couldn't allocate " SIZE_T_ARG " bytes for reading font file \"%s\"!\n", size, fileName.c_str()));
cfclose(fontFile);
return NULL;
}
if (!cfread(fontData.get(), (int)size, 1, fontFile))
{
mprintf(("Error while reading font data from \"%s\"", fileName.c_str()));
mprintf(("Error while reading font data from \"%s\"\n", fileName.c_str()));
cfclose(fontFile);
return NULL;
}
@@ -323,7 +323,7 @@ namespace font
if (handle < 0)
{
mprintf(("Couldn't couldn't create font for file \"%s\"", fileName.c_str()));
mprintf(("Couldn't couldn't create font for file \"%s\"\n", fileName.c_str()));
return NULL;
}
+2 -4
View File
@@ -33,10 +33,8 @@ namespace font {
return *this;
}
private:
TrueTypeFontData(const TrueTypeFontData &) SCP_DELETED_FUNCTION;
TrueTypeFontData &operator=(const TrueTypeFontData &) SCP_DELETED_FUNCTION;
TrueTypeFontData(const TrueTypeFontData &) = delete;
TrueTypeFontData &operator=(const TrueTypeFontData &) = delete;
};
// Forward declarations
-8
View File
@@ -40,9 +40,7 @@ class UniformAligner {
{
Assertion(sizeof(T) == _dataSize,
"Sizes of template parameter and runtime size do not match! This probably uses the wrong type.");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<T>::value, "Element type must be trivially copyable!");
#endif
return reinterpret_cast<T*>(addElement());
}
@@ -50,9 +48,7 @@ class UniformAligner {
template<typename THeader>
THeader* getHeader() {
Assertion(sizeof(THeader) == _headerSize, "Header size does not match requested header type!");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<THeader>::value, "Header type must be trivially copyable!");
#endif
return reinterpret_cast<THeader*>(_buffer);
}
@@ -63,9 +59,7 @@ class UniformAligner {
T* getTypedElement(size_t index) {
Assertion(sizeof(T) == _dataSize,
"Sizes of template parameter and runtime size do not match! This probably uses the wrong type.");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<T>::value, "Element type must be trivially copyable!");
#endif
return reinterpret_cast<T*>(getElement(index));
}
@@ -82,9 +76,7 @@ class UniformAligner {
T* nextTypedElement(T* currentEl) {
Assertion(sizeof(T) == _dataSize,
"Sizes of template parameter and runtime size do not match! This probably uses the wrong type.");
#if HAVE_STD_IS_TRIVIALLY_COPYABLE
static_assert(std::is_trivially_copyable<T>::value, "Element type must be trivially copyable!");
#endif
return reinterpret_cast<T*>(nextElement(reinterpret_cast<void*>(currentEl)));
}
+1 -1
View File
@@ -284,7 +284,7 @@ struct fog_data {
vec3d fog_color;
float fog_start;
float fog_scale;
float fog_density;
float zNear;
float zFar;
+1 -1
View File
@@ -121,7 +121,7 @@ bool stub_bm_data(int /*n*/, bitmap* /*bm*/) { return true; }
int stub_maybe_create_shader(shader_type /*shader_t*/, unsigned int /*flags*/) { return -1; }
void stub_shadow_map_start(matrix4* /*shadow_view_matrix*/, const matrix* /*light_matrix*/) {}
void stub_shadow_map_start(matrix4* /*shadow_view_matrix*/, const matrix* /*light_matrix*/, vec3d* /*eye_pos*/) {}
void stub_shadow_map_end() {}
Executable → Regular
+35 -24
View File
@@ -23,6 +23,7 @@
#include "object/object.h"
#include "parse/parselo.h"
#include "sound/sound.h"
#include "utils/Random.h"
#include "weapon/beam.h"
#include "weapon/weapon.h"
@@ -302,7 +303,7 @@ void ssm_create(object *target, vec3d *start, size_t ssm_index, ssm_firing_info
count = Ssm_info[ssm_index].count;
if (Ssm_info[ssm_index].max_count != -1) {
count += rand32(count, Ssm_info[ssm_index].max_count);
count += Random::next(count, Ssm_info[ssm_index].max_count);
}
// override in multiplayer
@@ -399,35 +400,45 @@ void ssm_process()
if(moveup->fireballs[idx] >= 0){
if ((1.0f - fireball_lifeleft_percent(&Objects[moveup->fireballs[idx]])) >= moveup->sinfo.duration) {
weapon_info *wip = &Weapon_info[si->weapon_info_index];
// get an orientation
vec3d temp;
matrix orient;
vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
vm_vec_normalize(&temp);
vm_vector_2_matrix(&orient, &temp, nullptr, nullptr);
// are we a beam? -MageKing17
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
beam_fire_info fire_info;
memset(&fire_info, 0, sizeof(beam_fire_info));
int num_beams = wip->b_info.beam_type == 5 && (int)wip->b_info.t5info.burst_rot_pattern.size() > 1 ?
(int)wip->b_info.t5info.burst_rot_pattern.size() : 1;
for (int i = 0; i < num_beams; i++) {
beam_fire_info fire_info;
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 0.000001f; // this will guarantee a hit
fire_info.shooter = NULL;
fire_info.turret = NULL;
fire_info.target = moveup->sinfo.target;
fire_info.target_subsys = NULL;
fire_info.bfi_flags |= BFIF_FLOATING_BEAM;
fire_info.starting_pos = moveup->sinfo.start_pos[idx];
fire_info.beam_info_index = si->weapon_info_index;
fire_info.team = static_cast<char>(moveup->sinfo.ssm_team);
fire_info.fire_method = BFM_SUBSPACE_STRIKE;
fire_info.accuracy = 0.000001f; // this will guarantee a hit
fire_info.shooter = nullptr;
fire_info.turret = nullptr;
fire_info.target = moveup->sinfo.target;
fire_info.target_subsys = nullptr;
fire_info.bfi_flags |= BFIF_FLOATING_BEAM;
fire_info.starting_pos = moveup->sinfo.start_pos[idx];
fire_info.beam_info_index = si->weapon_info_index;
fire_info.team = static_cast<char>(moveup->sinfo.ssm_team);
fire_info.fire_method = BFM_SUBSPACE_STRIKE;
fire_info.burst_index = i;
// fire the beam
beam_fire(&fire_info);
// Fill target_pos but DONT turn on BFIF_TARGETING_COORDS
// It would mess up normal beams but type 5s can still make use of this
fire_info.target_pos1 = orient.vec.fvec + fire_info.starting_pos;
moveup->done_flags[idx] = true;
// fire the beam
beam_fire(&fire_info);
moveup->done_flags[idx] = true;
}
} else {
// get an orientation
vec3d temp;
matrix orient;
vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
vm_vec_normalize(&temp);
vm_vector_2_matrix(&orient, &temp, NULL, NULL);
// fire the missile and flash the screen
weapon_objnum = weapon_create(&moveup->sinfo.start_pos[idx], &orient, si->weapon_info_index, -1, -1, 1);
+329 -344
View File
@@ -31,7 +31,7 @@
#include "weapon/emp.h"
int Show_escort_view;
static int Show_escort_view;
typedef struct escort_info
{
@@ -45,14 +45,31 @@ typedef struct escort_info
int escort_hit_timer;
int escort_hit_next_flash;
bool escort_show_bright;
escort_info() : objnum(-1), obj_signature(-1), priority(-1), np_id(-1),
escort_hit_timer(0), escort_hit_next_flash(0), escort_show_bright(false) {}
} escort_info;
escort_info Escort_ships[MAX_COMPLETE_ESCORT_LIST];
int Num_escort_ships;
int Max_escort_ships = 3;
static SCP_list<escort_info> Escort_ships;
int Max_escort_ships = 3;
static int Last_target_index; // index into Escort_gauges for last targeted via 'Next Escort Target' key
static SCP_list<escort_info>::iterator get_escort_entry_from_index(int index)
{
int e_idx = 0;
auto it = Escort_ships.begin();
while ( (e_idx != index) && (it != Escort_ships.end()) ) {
++it;
++e_idx;
}
return it;
}
HudGaugeEscort::HudGaugeEscort():
HudGauge(HUD_OBJECT_ESCORT, HUD_ESCORT_VIEW, false, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_OTHER_SHIP), 255, 255, 255)
{
@@ -153,6 +170,7 @@ int HudGaugeEscort::setGaugeColorEscort(int index, int team)
int is_flashing = 0;
int is_bright = 0;
int seen_from_team = (Player_ship != NULL) ? Player_ship->team : -1;
int objnum = -1;
// multiplayer dogfight
if(MULTI_DOGFIGHT)
@@ -160,19 +178,39 @@ int HudGaugeEscort::setGaugeColorEscort(int index, int team)
setGaugeColor();
return 0;
}
auto eship = get_escort_entry_from_index(index);
if (eship == Escort_ships.end()) {
return 0;
}
if ( (Game_mode & GM_MULTIPLAYER) && (eship->np_id >= 0) ) {
int np_index = find_player_index(eship->np_id);
if ( (np_index >= 0) && (Net_players[np_index].m_player != nullptr) ) {
objnum = Net_players[np_index].m_player->objnum;
}
} else {
objnum = eship->objnum;
}
if (objnum < 0) {
return 0;
}
// set flashing color
if (!timestamp_elapsed(Escort_ships[index].escort_hit_timer))
if (!timestamp_elapsed(eship->escort_hit_timer))
{
is_flashing = 1;
if (Escort_ships[index].escort_show_bright)
if (eship->escort_show_bright)
{
is_bright = 1;
}
}
// Goober5000 - now base this on team color
gr_set_color_fast(iff_get_color_by_team_and_object(team, seen_from_team, is_bright, &Objects[Escort_ships[index].objnum]));
gr_set_color_fast(iff_get_color_by_team_and_object(team, seen_from_team, is_bright, &Objects[objnum]));
// Goober5000 - an alternative; same as original but incorporating teams for non-friendlies
@@ -204,7 +242,7 @@ void HudGaugeEscort::render(float /*frametime*/)
return;
}
if ( !Num_escort_ships ) {
if ( Escort_ships.empty() ) {
return;
}
@@ -219,12 +257,12 @@ void HudGaugeEscort::render(float /*frametime*/)
int y = position[1] + list_start_offsets[1];
//This is temporary
Num_escort_ships--;
int num_escort_ships = std::min(hud_escort_num_ships_on_list(), Max_escort_ships) - 1;
i=0;
if(Num_escort_ships)
if(num_escort_ships > 0)
{
for(; i < Num_escort_ships; i++)
for(; i < num_escort_ships; i++)
{
if(i != 0)
{
@@ -242,9 +280,6 @@ void HudGaugeEscort::render(float /*frametime*/)
y += entry_h;
}
//Back to right #
Num_escort_ships++;
//Show the last escort entry
renderBitmap(Escort_gauges[2].first_frame, x, y + bottom_bg_offset);
renderIcon(x, y, i);
@@ -260,10 +295,32 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
}
float shields, integrity;
int screen_integrity, offset;
int screen_integrity, offset, objnum = -1;
char buf[255];
const player *pl = nullptr;
object *objp = &Objects[Escort_ships[index].objnum];
auto eship = get_escort_entry_from_index(index);
if (eship == Escort_ships.end()) {
return;
}
if ( (Game_mode & GM_MULTIPLAYER) && (eship->np_id >= 0) ) {
int np_index = find_player_index(eship->np_id);
if (np_index >= 0) {
pl = Net_players[np_index].m_player;
objnum = pl->objnum;
}
} else {
objnum = eship->objnum;
}
if (objnum < 0) {
return;
}
object *objp = &Objects[objnum];
ship *sp = &Ships[objp->instance];
// determine if its "friendly" or not
@@ -284,6 +341,20 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
// print out ship name
strcpy_s(buf, sp->get_display_name());
// maybe add callsign if multi and player ship
if (pl) {
SCP_string callsign;
callsign.reserve(32);
callsign += " (";
callsign += pl->short_callsign;
callsign += ")";
strcat_s(buf, callsign.c_str());
}
const int w = font::force_fit_string(buf, 255, ship_name_max_width);
if (right_align_names) {
@@ -323,8 +394,15 @@ void HudGaugeEscort::renderIconDogfight(int x, int y, int index)
// always use the standard color to avoid confusion
setGaugeColor();
auto eship = get_escort_entry_from_index(index);
if (eship == Escort_ships.end()) {
return;
}
// netplayer index
np_index = find_player_id(Escort_ships[index].np_id);
np_index = find_player_index(eship->np_id);
if((np_index < 0) || (np_index >= MAX_PLAYERS) || (Net_players[np_index].m_player == NULL)){
return;
}
@@ -360,17 +438,11 @@ void HudGaugeEscort::renderIconDogfight(int x, int y, int index)
void hud_escort_update_list()
{
if(Num_escort_ships)
{
for(int i = 0; i < Num_escort_ships; i++)
{
if (!timestamp_elapsed(Escort_ships[i].escort_hit_timer))
{
if (timestamp_elapsed(Escort_ships[i].escort_hit_next_flash))
{
Escort_ships[i].escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
Escort_ships[i].escort_show_bright = !Escort_ships[i].escort_show_bright; // toggle between default and bright frames
}
for (auto &es : Escort_ships) {
if ( !timestamp_elapsed(es.escort_hit_timer) ) {
if (timestamp_elapsed(es.escort_hit_next_flash)) {
es.escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
es.escort_show_bright = !es.escort_show_bright; // toggle between default and bright frames
}
}
}
@@ -391,99 +463,75 @@ void hud_escort_init()
//
void hud_escort_clear_all(bool clear_flags)
{
int i;
Num_escort_ships = 0;
for ( i = 0; i < Max_escort_ships; i++ ) {
if(clear_flags && (Escort_ships[i].objnum >= 0) && (Objects[Escort_ships[i].objnum].type == OBJ_SHIP) && (Objects[Escort_ships[i].objnum].instance >= 0)){
Ships[Objects[Escort_ships[i].objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
if (clear_flags) {
for (auto &es : Escort_ships) {
if ( (es.objnum >= 0) && (Objects[es.objnum].type == OBJ_SHIP) && (Objects[es.objnum].instance >= 0) ) {
Ships[Objects[es.objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
}
Escort_ships[i].obj_signature = -99;
Escort_ships[i].np_id = -1;
Escort_ships[i].escort_hit_timer = 0;
Escort_ships[i].escort_hit_next_flash = 0;
Escort_ships[i].escort_show_bright = false;
}
Escort_ships.clear();
}
// internal helper function for sort.
// sorts first by priority number and then alphabetically
int escort_compare_func(const void *e1, const void *e2)
static bool escort_compare(const escort_info &escort1, const escort_info &escort2)
{
escort_info *escort1, *escort2;
int diff;
int ret;
if (MULTI_DOGFIGHT) {
int n1 = find_player_index(escort1.np_id);
int n2 = find_player_index(escort2.np_id);
escort1 = (escort_info*) e1;
escort2 = (escort_info*) e2;
if ( (n1 < 0) || (n2 < 0) || (Net_players[n1].m_player == nullptr) || (Net_players[n2].m_player == nullptr) ) {
return false;
}
// multiplayer dogfight
if(MULTI_DOGFIGHT){
int n1, n2;
n1 = find_player_id(escort1->np_id);
n2 = find_player_id(escort2->np_id);
if((n1 < 0) || (n2 < 0) || (Net_players[n1].m_player == NULL) || (Net_players[n2].m_player == NULL)){
ret = 0;
} else {
// player 1 is higher than player 2
if(Net_players[n1].m_player->stats.m_kill_count_ok >= Net_players[n2].m_player->stats.m_kill_count_ok){
ret = -1;
} else {
ret = 1;
return (Net_players[n1].m_player->stats.m_kill_count_ok >= Net_players[n2].m_player->stats.m_kill_count_ok);
} else {
// in multi, players go to the top
if (Game_mode & GM_MULTIPLAYER) {
if ( (escort1.np_id >= 0) && (escort2.np_id < 0) ) {
return true;
} else if ( (escort1.np_id < 0) && (escort2.np_id >= 0) ) {
return false;
}
}
} else {
diff = escort2->priority - escort1->priority;
if (diff != 0) {
ret = diff;
} else {
char *name1, *name2;
name1 = Ships[Objects[escort1->objnum].instance].ship_name;
name2 = Ships[Objects[escort2->objnum].instance].ship_name;
if (escort1.priority != escort2.priority) {
return (escort1.priority > escort2.priority);
} else if ( (escort1.objnum >= 0) && (Objects[escort1.objnum].instance >= 0) &&
(escort2.objnum >= 0) && (Objects[escort2.objnum].instance >= 0) )
{
const char *name1 = Ships[Objects[escort1.objnum].instance].ship_name;
const char *name2 = Ships[Objects[escort2.objnum].instance].ship_name;
ret = stricmp(name1, name2);
return (stricmp(name1, name2) > 0);
}
}
return ret;
return false;
}
// create complete priority sorted escort list for all active ships
// escorts - array of escort info
// num_escorts - number of escorts requests in field of active ships
// This will be culled to MAX_ESCORTS, selecting the top set from escorts
void hud_create_complete_escort_list(escort_info *escorts, int *num_escorts)
void hud_create_complete_escort_list()
{
ship_obj *so;
object *objp;
// start with none on list
*num_escorts = 0;
object *objp;
int idx;
// multiplayer dogfight
if(MULTI_DOGFIGHT){
for(idx=0; idx<MAX_PLAYERS; idx++){
// break out of the loop when we have reached our max
if ( *num_escorts == MAX_COMPLETE_ESCORT_LIST ) {
mprintf(("exceeded max ships in big escort list\n"));
break;
}
// is this a valid player
if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
if (MULTI_DOGFIGHT) {
for (idx = 0; idx < MAX_PLAYERS; idx++) {
// is this a valid player
if ( MULTI_CONNECTED(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) ) {
// add the ship
escorts[*num_escorts].objnum = -1;
escorts[*num_escorts].obj_signature = -1;
escorts[*num_escorts].priority = -1;
escorts[*num_escorts].np_id = Net_players[idx].player_id;
escorts[*num_escorts].escort_hit_timer = 0;
escorts[*num_escorts].escort_hit_next_flash = 0;
escorts[*num_escorts].escort_show_bright = false;
(*num_escorts)++;
escort_info einfo;
einfo.np_id = Net_players[idx].player_id;
Escort_ships.push_back(einfo);
}
}
}
@@ -500,19 +548,13 @@ void hud_create_complete_escort_list(escort_info *escorts, int *num_escorts)
continue;
}
// break out of the loop when we have reached our max
if ( *num_escorts == MAX_COMPLETE_ESCORT_LIST ) {
mprintf(("exceeded max ships in big escort list\n"));
break;
}
// only process ships that might be on the list
if ( !(Ships[objp->instance].flags[Ship::Ship_Flags::Escort]) ){
if ( !(Ships[objp->instance].flags[Ship::Ship_Flags::Escort]) ) {
continue;
}
// only process ships that can be seen by sensors
if ( (Ships[objp->instance].flags[Ship::Ship_Flags::Hidden_from_sensors]) ){
if ( (Ships[objp->instance].flags[Ship::Ship_Flags::Hidden_from_sensors]) ) {
continue;
}
@@ -540,14 +582,12 @@ void hud_create_complete_escort_list(escort_info *escorts, int *num_escorts)
}
// add the ship
escorts[*num_escorts].objnum = so->objnum;
escorts[*num_escorts].obj_signature = objp->signature;
escorts[*num_escorts].priority = Ships[objp->instance].escort_priority;
escorts[*num_escorts].np_id = -1;
escorts[*num_escorts].escort_hit_timer = 0;
escorts[*num_escorts].escort_hit_next_flash = 0;
escorts[*num_escorts].escort_show_bright = false;
(*num_escorts)++;
escort_info einfo;
einfo.objnum = so->objnum;
einfo.obj_signature = objp->signature;
einfo.priority = Ships[objp->instance].escort_priority;
Escort_ships.push_back(einfo);
}
}
}
@@ -556,36 +596,26 @@ void hud_create_complete_escort_list(escort_info *escorts, int *num_escorts)
// ----------------------------------------------------------------------
// hud_init_escort_info()
//
// Set up the escort list
// Set up the initial escort list
//
void hud_setup_escort_list(int level)
{
int num_escorts, num_complete_escorts;
escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
hud_escort_clear_all();
// get complete escort list
hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
// sort escort list by priority
insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
// set number in escort list
num_escorts = num_complete_escorts;
if (num_escorts > Max_escort_ships) {
num_escorts = Max_escort_ships;
// this should never be called while in a mission
if (Game_mode & GM_IN_MISSION) {
return;
}
// add ships to escort list
for (Num_escort_ships=0; Num_escort_ships<num_escorts; Num_escort_ships++) {
Escort_ships[Num_escort_ships].obj_signature = complete_escorts[Num_escort_ships].obj_signature;
Escort_ships[Num_escort_ships].priority = complete_escorts[Num_escort_ships].priority;
Escort_ships[Num_escort_ships].objnum = complete_escorts[Num_escort_ships].objnum;
Escort_ships[Num_escort_ships].np_id = complete_escorts[Num_escort_ships].np_id;
Escort_ships[Num_escort_ships].escort_hit_timer = 0;
Escort_ships[Num_escort_ships].escort_hit_next_flash = 0;
Escort_ships[Num_escort_ships].escort_show_bright = false;
Escort_ships.clear();
// build escort list
hud_create_complete_escort_list();
// and sort it by priority
Escort_ships.sort(escort_compare);
// then resize the list to fit max
if (hud_escort_num_ships_on_list() > MAX_COMPLETE_ESCORT_LIST) {
Escort_ships.resize(MAX_COMPLETE_ESCORT_LIST);
}
if(level){
@@ -593,151 +623,81 @@ void hud_setup_escort_list(int level)
}
}
// combine complete escort list with Escort_ships, keeping valid hit info
void merge_escort_lists(escort_info *complete_escorts, int num_complete_escorts)
// re-sort the escort list
void hud_resort_escort_list()
{
int i, j, top_complete_escorts;
int valid_hit_info[MAX_COMPLETE_ESCORT_LIST];
// may be > 1 ship change to list (ie, 2 or 3 culled during same frame)
// set Num_escort_ships and cap
Num_escort_ships = num_complete_escorts;
if (Num_escort_ships > Max_escort_ships) {
Num_escort_ships = Max_escort_ships;
}
// nothing to do
if (Num_escort_ships == 0) {
return;
}
// check used as a flag whether top slots in complete_escorts were copied
// this is important re. hit info
for (i=0; i<Max_escort_ships; i++) {
valid_hit_info[i] = 0;
}
// get the top slots in complete escort list that will be copied onto Escort_ships
top_complete_escorts = num_complete_escorts;
if (top_complete_escorts > Max_escort_ships) {
top_complete_escorts = Max_escort_ships;
}
// copy for Escort_ships to complete_escorts to retain hit_info
if(!MULTI_DOGFIGHT) {
for (i=0; i<top_complete_escorts; i++) {
for (j=0; j<Num_escort_ships; j++) {
if (Escort_ships[j].obj_signature == complete_escorts[i].obj_signature) {
complete_escorts[i] = Escort_ships[j];
valid_hit_info[i] = 1;
break;
}
}
}
// copy top slots to Escort_ships
for (i=0; i<top_complete_escorts; i++) {
Escort_ships[i] = complete_escorts[i];
// check all ships are valid
int objnum = Escort_ships[i].objnum;
Assert( objnum >=0 && objnum < MAX_OBJECTS );
if((objnum < 0) || (objnum >= MAX_OBJECTS)){
continue;
}
if ( !valid_hit_info[i] ) {
Escort_ships[i].escort_hit_timer = 0;
Escort_ships[i].escort_hit_next_flash = 0;
Escort_ships[i].escort_show_bright = false;
}
}
}
// reset Num_escort_ships
Num_escort_ships = top_complete_escorts;
}
// ----------------------------------------------------------------------
// hud_remove_ship_from_escort_index()
//
// Take a ship out of the escort list
void hud_remove_ship_from_escort_index(int dead_index, int objnum)
{
int i, count, num_complete_escorts;
escort_info bakup_arr[MAX_COMPLETE_ESCORT_LIST], complete_escorts[MAX_COMPLETE_ESCORT_LIST];
// remove him from escort list
if((objnum >= 0) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0)){
Ships[Objects[objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
count = 0;
for ( i = 0; i < Num_escort_ships; i++ ) {
if ( i != dead_index ) {
bakup_arr[count++] = Escort_ships[i];
}
}
for ( i = 0; i < count; i++ ) {
Escort_ships[i] = bakup_arr[i];
}
Num_escort_ships--;
Assert(Num_escort_ships >= 0);
// get complete escort list
hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
// sort escort list by priority
insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
// merge list
merge_escort_lists(complete_escorts, num_complete_escorts);
hud_gauge_popup_start(HUD_ESCORT_VIEW);
Escort_ships.sort(escort_compare);
}
// called once per frame to refresh the escort list if important flags changed
void hud_escort_cull_list()
{
int i;
if ( Escort_ships.empty() ) {
return;
}
int np_index;
auto it = Escort_ships.begin();
// multiplayer dogfight
if(MULTI_DOGFIGHT){
for ( i = 0; i < Num_escort_ships; i++ ) {
np_index = find_player_id(Escort_ships[i].np_id);
while (it != Escort_ships.end()) {
np_index = find_player_index(it->np_id);
// maybe remove him if he left
if ( np_index < 0 ) {
hud_setup_escort_list(0);
break;
if (np_index < 0) {
it = Escort_ships.erase(it);
} else {
++it;
}
}
}
}
// everything else
else {
for ( i = 0; i < Num_escort_ships; i++ ) {
int objnum = Escort_ships[i].objnum;
Assert( objnum >=0 && objnum < MAX_OBJECTS );
int objnum;
bool remove;
if ( Objects[objnum].flags[Object::Object_Flags::Should_be_dead] ) {
hud_setup_escort_list(0);
break;
} else if ( Objects[objnum].type == OBJ_SHIP ) {
while (it != Escort_ships.end()) {
remove = false;
objnum = it->objnum;
// player ships should stay so long as they are valid
if ( (Game_mode & GM_MULTIPLAYER) && (it->np_id >= 0) ) {
np_index = find_player_index(it->np_id);
// maybe remove him if he left
if (np_index < 0) {
remove = true;
}
} else if (Objects[objnum].flags[Object::Object_Flags::Should_be_dead]) {
remove = true;
} else if (Objects[objnum].type == OBJ_SHIP) {
int shipnum = Objects[objnum].instance;
Assert( shipnum >= 0 && shipnum < MAX_SHIPS );
if ( (Ships[shipnum].flags[Ship::Ship_Flags::Hidden_from_sensors])
|| ((Ships[shipnum].flags[Ship::Ship_Flags::Stealth]) && ((Ships[shipnum].team != Player_ship->team) || (Ships[shipnum].flags[Ship::Ship_Flags::Friendly_stealth_invis])))
) {
hud_setup_escort_list(0);
break;
if ( !(Ships[shipnum].flags[Ship::Ship_Flags::Escort]) ) {
remove = true;
} else if (Ships[shipnum].flags[Ship::Ship_Flags::Hidden_from_sensors]) {
remove = true;
} else if (Ships[shipnum].flags[Ship::Ship_Flags::Stealth]) {
if (Ships[shipnum].team != Player_ship->team) {
// friendly stealths are only not seen when explicitly specified
if ( Ships[shipnum].flags[Ship::Ship_Flags::Friendly_stealth_invis]) {
remove = true;
}
}
// non-friendly stealths are never seen
else {
remove = true;
}
}
}
if (remove) {
it = Escort_ships.erase(it);
} else {
++it;
}
}
}
}
@@ -758,62 +718,68 @@ void hud_escort_view_toggle()
// try to add a ship to the escort list, if slot available
void hud_add_ship_to_escort(int objnum, int supress_feedback)
{
escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
int num_complete_escorts, idx, found;
// no ships on the escort list in multiplayer dogfight
if (MULTI_DOGFIGHT) {
return;
}
// get complete escort list
hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);
if (objnum < 0) {
UNREACHABLE("Invalid objnum passed to hud_add_ship_to_escort()!");
return;
}
// ensure the complete escort list is not full already
if (num_complete_escorts == MAX_COMPLETE_ESCORT_LIST)
{
return;
}
if (Objects[objnum].type != OBJ_SHIP) {
if ( !supress_feedback ) {
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
}
return;
}
// check if ship is already on complete escort list
found = 0;
for (idx=0; idx<num_complete_escorts; idx++) {
if (complete_escorts[idx].obj_signature == Objects[objnum].signature) {
found = 1;
bool found = false;
for (auto &es : Escort_ships) {
if (es.obj_signature == Objects[objnum].signature) {
found = true;
break;
}
}
// add new ship into complete list
if ( !found ) {
complete_escorts[num_complete_escorts].objnum = objnum;
complete_escorts[num_complete_escorts].obj_signature = Objects[objnum].signature;
complete_escorts[num_complete_escorts].priority = Ships[Objects[objnum].instance].escort_priority;
complete_escorts[num_complete_escorts].escort_hit_timer = 0;
complete_escorts[num_complete_escorts].escort_hit_next_flash = 0;
complete_escorts[num_complete_escorts].escort_show_bright = false;
escort_info einfo;
// add him to escort list
Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort);
einfo.objnum = objnum;
einfo.obj_signature = Objects[objnum].signature;
einfo.priority = Ships[Objects[objnum].instance].escort_priority;
num_complete_escorts++;
// add him to escort list and re-sort
Escort_ships.push_back(einfo);
Escort_ships.sort(escort_compare);
Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort);
}
// sort escort list by priority
insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);
if (hud_escort_num_ships_on_list() > MAX_COMPLETE_ESCORT_LIST) {
Escort_ships.resize(MAX_COMPLETE_ESCORT_LIST);
// merge list
merge_escort_lists(complete_escorts, num_complete_escorts);
// maybe do feedback
if ( !supress_feedback ) {
found = false;
// maybe do feedback
if ( (Num_escort_ships == Max_escort_ships) && !supress_feedback) {
found = 0;
// search thru list for objnum
for (idx=0; idx<Num_escort_ships; idx++) {
if (Escort_ships[idx].objnum == objnum) {
found = 1;
break;
// search thru list for objnum
for (auto &es : Escort_ships) {
if (es.objnum == objnum) {
found = true;
break;
}
}
}
if (!found) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), Num_escort_ships);
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
if ( !found ) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), hud_escort_num_ships_on_list());
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
}
}
}
@@ -826,8 +792,6 @@ void hud_add_ship_to_escort(int objnum, int supress_feedback)
//
void hud_add_remove_ship_escort(int objnum, int supress_feedback)
{
int in_escort, i;
// no ships on the escort list in multiplayer dogfight
if(MULTI_DOGFIGHT){
return;
@@ -845,26 +809,27 @@ void hud_add_remove_ship_escort(int objnum, int supress_feedback)
return;
}
in_escort = 0;
for ( i = 0; i < Num_escort_ships; i++ ) {
if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
in_escort = 1;
break;
// if it's in the list already just remove it
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->obj_signature == Objects[objnum].signature) {
if ( (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) ) {
Ships[Objects[objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
Escort_ships.erase(it);
hud_gauge_popup_start(HUD_ESCORT_VIEW);
return;
}
}
if ( in_escort ) {
hud_remove_ship_from_escort_index(i, objnum);
return;
}
// otherwise add ship to list
hud_add_ship_to_escort(objnum, supress_feedback);
}
void hud_remove_ship_from_escort(int objnum)
{
int in_escort, i;
// no ships on the escort list in multiplayer dogfight
if(MULTI_DOGFIGHT){
return;
@@ -875,18 +840,19 @@ void hud_remove_ship_from_escort(int objnum)
return;
}
in_escort = 0;
for ( i = 0; i < Num_escort_ships; i++ ) {
if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
in_escort = 1;
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->obj_signature == Objects[objnum].signature) {
if ( (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0) ) {
Ships[Objects[objnum].instance].flags.remove(Ship::Ship_Flags::Escort);
}
Escort_ships.erase(it);
hud_gauge_popup_start(HUD_ESCORT_VIEW);
break;
}
}
if ( in_escort ) {
hud_remove_ship_from_escort_index(i, objnum);
return;
}
}
/**
@@ -903,11 +869,14 @@ void hud_escort_ship_hit(object *objp, int /*quadrant*/)
return;
}
for ( int i = 0; i < Num_escort_ships; i++ ) {
if ( Escort_ships[i].objnum == OBJ_INDEX(objp) ) {
int objnum = OBJ_INDEX(objp);
for (auto &es : Escort_ships) {
if (es.objnum == objnum) {
hud_gauge_popup_start(HUD_ESCORT_VIEW);
Escort_ships[i].escort_hit_timer = timestamp(SHIELD_HIT_DURATION);
Escort_ships[i].escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
es.escort_hit_timer = timestamp(SHIELD_HIT_DURATION);
es.escort_hit_next_flash = timestamp(SHIELD_FLASH_INTERVAL);
break;
}
}
}
@@ -917,17 +886,24 @@ void hud_escort_target_next()
{
int objnum;
if ( Num_escort_ships == 0 ) {
if ( Escort_ships.empty() ) {
snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL), 0.0f );
return;
}
Last_target_index++;
if ( Last_target_index >= Num_escort_ships ) {
if ( Last_target_index >= hud_escort_num_ships_on_list() ) {
Last_target_index = 0;
}
objnum = Escort_ships[Last_target_index].objnum;
auto eship = get_escort_entry_from_index(Last_target_index);
if ( (eship == Escort_ships.end()) || (eship->objnum < 0) ) {
return;
}
objnum = eship->objnum;
set_target_objnum( Player_ai, objnum);
hud_restore_subsystem_target(&Ships[Objects[objnum].instance]);
}
@@ -935,30 +911,33 @@ void hud_escort_target_next()
// return the number of ships currently on the escort list
int hud_escort_num_ships_on_list()
{
return Num_escort_ships;
return static_cast<int>(Escort_ships.size());
}
// Return the object number for the ship at index position in the escort list
int hud_escort_return_objnum(int index)
{
int escort_objnum, escort_sig;
if ( index >= Num_escort_ships || index >= MAX_COMPLETE_ESCORT_LIST) {
if (index < 0) {
return -1;
}
escort_objnum = Escort_ships[index].objnum;
escort_sig = Escort_ships[index].obj_signature;
auto eship = get_escort_entry_from_index(index);
if ( escort_objnum < 0 ) {
if ( (eship == Escort_ships.end()) || (eship->objnum < 0) ) {
return -1;
}
escort_objnum = eship->objnum;
escort_sig = eship->obj_signature;
// ensure this is still a valid index
if ( Objects[escort_objnum].signature != escort_sig ) {
if (Objects[escort_objnum].signature != escort_sig) {
return -1;
}
return Escort_ships[index].objnum;
return escort_objnum;
}
void hud_escort_add_player(short id)
@@ -968,17 +947,24 @@ void hud_escort_add_player(short id)
return;
}
int idx;
// just go through and add as long as its not a duplicate
for(idx=0; idx<Num_escort_ships; idx++){
if(Escort_ships[idx].np_id == id){
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->np_id == id) {
return;
}
}
// re-setup the escort list
hud_setup_escort_list(0);
escort_info einfo;
einfo.np_id = id;
Escort_ships.push_back(einfo);
Escort_ships.sort(escort_compare);
// resize the list to fit
if (hud_escort_num_ships_on_list() > MAX_COMPLETE_ESCORT_LIST) {
Escort_ships.resize(MAX_COMPLETE_ESCORT_LIST);
}
}
void hud_escort_remove_player(short id)
@@ -988,12 +974,11 @@ void hud_escort_remove_player(short id)
return;
}
int idx;
// find the instance and remove it if possible
for(idx=0; idx<Num_escort_ships; idx++){
if(Escort_ships[idx].np_id == id){
hud_remove_ship_from_escort_index(idx, -1);
for (auto it = Escort_ships.begin(); it != Escort_ships.end(); ++it) {
if (it->np_id == id) {
Escort_ships.erase(it);
return;
}
}
+1
View File
@@ -24,6 +24,7 @@ class object;
void hud_escort_update_list();
void hud_escort_init();
void hud_setup_escort_list(int level = 1);
void hud_resort_escort_list();
void hud_add_remove_ship_escort(int objnum, int supress_feedback = 0);
void hud_escort_clear_all(bool clear_flags = false);
void hud_escort_ship_hit(object *objp, int quadrant);
+3
View File
@@ -103,6 +103,9 @@ void update_ets(object* objp, float fl_frametime)
shield_delta = Energy_levels[ship_p->shield_recharge_index] * max_new_shield_energy;
}
if (Missiontime - Ai_info[ship_p->ai_index].last_hit_time < fl2f(sinfo_p->shield_regen_hit_delay))
shield_delta = 0.0f;
shield_add_strength(objp, shield_delta);
// if strength now exceeds max, scale back segments proportionally
+7 -1
View File
@@ -55,7 +55,13 @@
#define HUD_SUPPORT_GAUGE 37
#define HUD_LAG_GAUGE 38
extern const char *HUD_gauge_text[NUM_HUD_GAUGES]; // defined in sexp.cpp!!!!
struct Legacy_HUD_gauge_pair
{
const char *hud_gauge_text;
int hud_gauge_type;
};
extern Legacy_HUD_gauge_pair Legacy_HUD_gauges[NUM_HUD_GAUGES]; // defined in hudparse.cpp!!!!
#endif /* __HUD_COMMON_H__ */
+32 -112
View File
@@ -12,6 +12,7 @@
#include "ai/ai.h"
#include "debugconsole/console.h"
#include "gamesequence/gamesequence.h"
#include "gamesnd/gamesnd.h"
#include "globalincs/linklist.h"
#include "hud/hudlock.h"
@@ -404,46 +405,10 @@ int hud_lock_has_homing_point()
int Nebula_sec_range = 0;
DCF_BOOL(nebula_sec_range, Nebula_sec_range);
int hud_lock_world_pos_in_range(vec3d *target_world_pos, vec3d *vec_to_target)
{
float dist_to_target, weapon_range;
weapon_info *wip;
ship_weapon *swp;
int target_in_range=1;
swp = &Player_ship->weapons;
wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
vm_vec_sub(vec_to_target, target_world_pos, &Player_obj->pos);
dist_to_target = vm_vec_mag(vec_to_target);
//local ssms are always in range :)
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
weapon_range=wip->lssm_lock_range;
else
// calculate the range of the weapon, and only display the lead target indicator when
// if the weapon can actually hit the target
weapon_range = MIN((wip->max_speed * wip->lifetime), wip->weapon_range);
// reduce firing range in nebula
if ((The_mission.flags[Mission::Mission_Flags::Fullneb]) && Nebula_sec_range) {
weapon_range *= 0.8f;
}
if (dist_to_target > weapon_range) {
target_in_range=0;
}
return target_in_range;
}
// Determine if point to lock on is in range
int hud_lock_target_in_range()
{
vec3d target_world_pos, vec_to_target;
vec3d target_world_pos;
object *targetp;
if ( !hud_lock_has_homing_point() ) {
@@ -464,8 +429,10 @@ int hud_lock_target_in_range()
target_world_pos = targetp->pos;
}
}
ship_weapon* swp = &Player_ship->weapons;
weapon_info* wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
return hud_lock_world_pos_in_range(&target_world_pos, &vec_to_target);
return weapon_secondary_world_pos_in_range(Player_obj, wip, &target_world_pos);
}
int hud_abort_lock()
@@ -763,6 +730,9 @@ void hud_lock_acquire_current_target(object *target_objp, ship_subsys *target_su
target_shipp = &Ships[target_objp->instance];
}
ship_weapon* swp = &Player_ship->weapons;
weapon_info* wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
// Reset target subsys in case it isn't needed
if (target_subsys != nullptr) target_subsys = nullptr;
@@ -771,8 +741,8 @@ void hud_lock_acquire_current_target(object *target_objp, ship_subsys *target_su
// check all the subsystems and the center of the ship
// assume best lock pos is the center of the ship
lock_in_range = hud_lock_world_pos_in_range(&target_objp->pos, &vec_to_lock);
vm_vec_normalize(&vec_to_lock);
lock_in_range = weapon_secondary_world_pos_in_range(Player_obj, wip, &target_objp->pos);
vm_vec_normalized_dir(&vec_to_lock, &target_objp->pos, &Player_obj->pos);
if ( lock_in_range ) {
best_lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
}
@@ -788,8 +758,8 @@ void hud_lock_acquire_current_target(object *target_objp, ship_subsys *target_su
// get world pos of subsystem
get_subsystem_world_pos(target_objp, ss, &subsys_world_pos);
if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) {
vm_vec_normalize(&vec_to_lock);
if ( weapon_secondary_world_pos_in_range(Player_obj, wip, &subsys_world_pos) ) {
vm_vec_normalized_dir(&vec_to_lock, &subsys_world_pos, &Player_obj->pos);
lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
if ( lock_dot > best_lock_dot ) {
best_lock_dot=lock_dot;
@@ -807,36 +777,16 @@ void hud_lock_acquire_uncaged_subsystem(weapon_info *wip, lock_info *lock, float
Assert( lock->obj->type == OBJ_SHIP );
ship *sp = &Ships[lock->obj->instance];
ship_subsys *ss;
float ss_dot;
vec3d ss_pos;
vec3d vec_to_target;
int current_num_locks = 0;
if ( Ship_info[sp->ship_info_index].is_big_or_huge() ) {
for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
if (ss->flags[Ship::Subsystem_Flags::Untargetable]) {
for (ship_subsys* ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
if (!weapon_multilock_can_lock_on_subsys(Player_obj, lock->obj, ss, wip, &ss_dot))
continue;
}
get_subsystem_world_pos(lock->obj, ss, &ss_pos);
if ( !hud_lock_world_pos_in_range(&ss_pos, &vec_to_target) ) {
continue;
}
vm_vec_normalize(&vec_to_target);
ss_dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
if ( ss_dot < wip->lock_fov ) {
continue;
}
if ( !ship_subsystem_in_sight(lock->obj, ss, &Eye_position, &ss_pos) ) {
continue;
}
// check for existing locks
current_num_locks = 0;
@@ -871,11 +821,8 @@ void hud_lock_acquire_uncaged_subsystem(weapon_info *wip, lock_info *lock, float
void hud_lock_acquire_uncaged_target(lock_info *current_lock, weapon_info *wip)
{
object *A;
vec3d vec_to_target;
float dot;
ship *sp;
size_t i = 0;
object* best_obj = nullptr;
@@ -888,45 +835,12 @@ void hud_lock_acquire_uncaged_target(lock_info *current_lock, weapon_info *wip)
bool actively_locking = false;
for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
if ( A->type != OBJ_SHIP ) {
ship* sp = &Ships[A->instance];
if (!weapon_multilock_can_lock_on_target(Player_obj, A, wip, &dot))
continue;
}
if ( hud_target_invalid_awacs(A) ) {
continue;
}
sp = &Ships[A->instance];
if ( A->flags[Object::Object_Flags::Should_be_dead] ) {
continue;
}
if ( sp->flags[Ship::Ship_Flags::Dying] ) {
continue;
}
if ( should_be_ignored(sp) ) {
continue;
}
// if this is part of the same team and doesn't have any iff restrictions, reject lock
if ( !weapon_has_iff_restrictions(wip) && Player_ship->team == obj_team(A) ) {
continue;
}
int in_range = hud_lock_world_pos_in_range(&A->pos, &vec_to_target);
vm_vec_normalize(&vec_to_target);
dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
/*if ( dot < 0.95f ) {
// broad test to see if we should bother to even check
continue;
}*/
if (!weapon_target_satisfies_lock_restrictions(wip, A)) {
continue;
}
bool in_range = weapon_secondary_world_pos_in_range(Player_obj, wip, &A->pos);
if ( Ship_info[sp->ship_info_index].is_big_or_huge() ) {
lock_info temp_lock;
@@ -1013,7 +927,7 @@ void hud_lock_determine_lock_target(lock_info *lock_slot, weapon_info *wip)
vm_vec_normalized_dir(&vec_to_target, &target_pos, &Eye_position);
dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
if ( !hud_lock_world_pos_in_range(&target_pos, &vec_to_target) || dot < wip->lock_fov) {
if ( !weapon_secondary_world_pos_in_range(Player_obj, wip, &lock_slot->obj->pos) || dot < wip->lock_fov) {
// set this lock slot to empty
ship_clear_lock(lock_slot);
hud_lock_acquire_uncaged_target(lock_slot, wip);
@@ -1459,7 +1373,7 @@ void hud_calculate_lock_slot_position(lock_info *current_lock, float frametime)
// Determine if point to lock on is in range
int hud_lock_target_in_range(lock_info *lock_slot)
{
vec3d target_world_pos, vec_to_target;
vec3d target_world_pos;
if ( lock_slot == nullptr || lock_slot->obj == nullptr) {
return 0;
@@ -1476,8 +1390,9 @@ int hud_lock_target_in_range(lock_info *lock_slot)
target_world_pos = lock_slot->obj->pos;
}
}
ship_weapon* swp = &Player_ship->weapons;
return hud_lock_world_pos_in_range(&target_world_pos, &vec_to_target);
return weapon_secondary_world_pos_in_range(Player_obj, &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]], &target_world_pos);
}
void hud_do_lock_indicators(float frametime)
@@ -1490,6 +1405,11 @@ void hud_do_lock_indicators(float frametime)
return;
}
// do not continue locking if the game is paused (viewer pause still has hud on)
if (gameseq_get_state() == GS_STATE_GAME_PAUSED) {
return;
}
// be sure to unset this flag, then possibly set later in this function so that
// threat indicators work properly.
Player_ai->ai_flags.remove(AI::AI_Flags::Seek_lock);
@@ -2103,8 +2023,8 @@ void hud_lock_get_new_lock_pos(object *target_objp)
Player->locking_on_center=1;
Player->locking_subsys=NULL;
Player->locking_subsys_parent=-1;
lock_in_range = hud_lock_world_pos_in_range(&lock_world_pos, &vec_to_lock);
vm_vec_normalize(&vec_to_lock);
lock_in_range = weapon_secondary_world_pos_in_range(Player_obj, wip, &lock_world_pos);
vm_vec_normalized_dir(&vec_to_lock, &lock_world_pos, &Player_obj->pos);
if ( lock_in_range ) {
best_lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
}
@@ -2120,8 +2040,8 @@ void hud_lock_get_new_lock_pos(object *target_objp)
// get world pos of subsystem
get_subsystem_world_pos(target_objp, ss, &subsys_world_pos);
if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) {
vm_vec_normalize(&vec_to_lock);
if ( weapon_secondary_world_pos_in_range(Player_obj, wip, &subsys_world_pos) ) {
vm_vec_normalized_dir(&vec_to_lock, &subsys_world_pos, &Player_obj->pos);
lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
if ( lock_dot > best_lock_dot ) {
best_lock_dot=lock_dot;
+65 -24
View File
@@ -53,9 +53,9 @@ int Hud_font = -1;
bool Chase_view_only_ex = false;
//WARNING: If you add gauges to this array, make sure to bump num_default_gauges!
int num_default_gauges = 42;
static int retail_gauges[] = {
//WARNING: If you add gauges to this array, make sure to bump Num_builtin_gauges!
const int Num_builtin_gauges = 42;
static int Builtin_gauges[Num_builtin_gauges] = {
HUD_OBJECT_MESSAGES,
HUD_OBJECT_TRAINING_MESSAGES,
HUD_OBJECT_SUPPORT,
@@ -100,9 +100,52 @@ static int retail_gauges[] = {
HUD_OBJECT_ETS_RETAIL
};
Legacy_HUD_gauge_pair Legacy_HUD_gauges[NUM_HUD_GAUGES] =
{
{ "LEAD_INDICATOR", HUD_OBJECT_LEAD },
{ "ORIENTATION_TEE", HUD_OBJECT_ORIENTATION_TEE },
{ "HOSTILE_TRIANGLE", HUD_OBJECT_HOSTILE_TRI },
{ "TARGET_TRIANGLE", HUD_OBJECT_TARGET_TRI },
{ "MISSION_TIME", HUD_OBJECT_MISSION_TIME },
{ "RETICLE_CIRCLE", -1 },
{ "THROTTLE_GAUGE", HUD_OBJECT_THROTTLE },
{ "RADAR", HUD_OBJECT_RADAR_STD },
{ "TARGET_MONITOR", HUD_OBJECT_TARGET_MONITOR },
{ "CENTER_RETICLE", HUD_OBJECT_CENTER_RETICLE },
{ "TARGET_MONITOR_EXTRA_DATA", HUD_OBJECT_EXTRA_TARGET_DATA },
{ "TARGET_SHIELD_ICON", HUD_OBJECT_TARGET_SHIELD },
{ "PLAYER_SHIELD_ICON", HUD_OBJECT_PLAYER_SHIELD },
{ "ETS_GAUGE", HUD_OBJECT_ETS_RETAIL },
{ "AUTO_TARGET", HUD_OBJECT_AUTO_TARGET },
{ "AUTO_SPEED", HUD_OBJECT_AUTO_SPEED },
{ "WEAPONS_GAUGE", HUD_OBJECT_WEAPONS },
{ "ESCORT_VIEW", HUD_OBJECT_ESCORT },
{ "DIRECTIVES_VIEW", HUD_OBJECT_DIRECTIVES },
{ "THREAT_GAUGE", HUD_OBJECT_THREAT },
{ "AFTERBURNER_ENERGY", HUD_OBJECT_AFTERBURNER },
{ "WEAPONS_ENERGY", HUD_OBJECT_WEAPON_ENERGY },
{ "WEAPON_LINKING_GAUGE", HUD_OBJECT_WEAPON_LINKING },
{ "TARGER_MINI_ICON", HUD_OBJECT_MINI_SHIELD },
{ "OFFSCREEN_INDICATOR", HUD_OBJECT_OFFSCREEN },
{ "TALKING_HEAD", HUD_OBJECT_TALKING_HEAD },
{ "DAMAGE_GAUGE", HUD_OBJECT_DAMAGE },
{ "MESSAGE_LINES", HUD_OBJECT_MESSAGES },
{ "MISSILE_WARNING_ARROW", HUD_OBJECT_MISSILE_TRI },
{ "CMEASURE_GAUGE", HUD_OBJECT_CMEASURES },
{ "OBJECTIVES_NOTIFY_GAUGE", HUD_OBJECT_OBJ_NOTIFY },
{ "WINGMEN_STATUS", HUD_OBJECT_WINGMAN_STATUS },
{ "OFFSCREEN RANGE", -1 },
{ "KILLS GAUGE", HUD_OBJECT_KILLS },
{ "ATTACKING TARGET COUNT", -1 },
{ "TEXT FLASH", HUD_OBJECT_TEXT_WARNINGS },
{ "MESSAGE BOX", HUD_OBJECT_SQUAD_MSG },
{ "SUPPORT GUAGE", HUD_OBJECT_SUPPORT },
{ "LAG GUAGE", HUD_OBJECT_LAG },
};
flag_def_list Hud_gauge_types[] = {
{ "Messages", HUD_OBJECT_MESSAGES, 0},
{ "Training messages", HUD_OBJECT_TRAINING_MESSAGES, 0},
{ "Training messages", HUD_OBJECT_TRAINING_MESSAGES, 0}, // Not in legacy list
{ "Support", HUD_OBJECT_SUPPORT, 0},
{ "Damage", HUD_OBJECT_DAMAGE, 0},
{ "Wingman status", HUD_OBJECT_WINGMAN_STATUS, 0},
@@ -120,14 +163,14 @@ flag_def_list Hud_gauge_types[] = {
{ "Target shield", HUD_OBJECT_TARGET_SHIELD, 0},
{ "Escort list", HUD_OBJECT_ESCORT, 0},
{ "Mission time", HUD_OBJECT_MISSION_TIME, 0},
{ "Ets weapons", HUD_OBJECT_ETS_WEAPONS, 0},
{ "Ets shields", HUD_OBJECT_ETS_SHIELDS, 0},
{ "Ets engines", HUD_OBJECT_ETS_ENGINES, 0},
{ "Ets weapons", HUD_OBJECT_ETS_WEAPONS, 0}, // Not in legacy list
{ "Ets shields", HUD_OBJECT_ETS_SHIELDS, 0}, // Not in legacy list
{ "Ets engines", HUD_OBJECT_ETS_ENGINES, 0}, // Not in legacy list
{ "Target monitor", HUD_OBJECT_TARGET_MONITOR, 0},
{ "Extra target data", HUD_OBJECT_EXTRA_TARGET_DATA, 0},
{ "Radar", HUD_OBJECT_RADAR_STD, 0},
{ "Radar orb", HUD_OBJECT_RADAR_ORB, 0},
{ "Radar BSG", HUD_OBJECT_RADAR_BSG, 0},
{ "Radar orb", HUD_OBJECT_RADAR_ORB, 0}, // Not in legacy list
{ "Radar BSG", HUD_OBJECT_RADAR_BSG, 0}, // Not in legacy list
{ "Afterburner energy", HUD_OBJECT_AFTERBURNER, 0},
{ "Weapon energy", HUD_OBJECT_WEAPON_ENERGY, 0},
{ "Text warnings", HUD_OBJECT_TEXT_WARNINGS, 0},
@@ -136,12 +179,12 @@ flag_def_list Hud_gauge_types[] = {
{ "Threat indicator", HUD_OBJECT_THREAT, 0},
{ "Lead indicator", HUD_OBJECT_LEAD, 0},
{ "Lead sight", HUD_OBJECT_LEAD_SIGHT, 0},
{ "Lock indicator", HUD_OBJECT_LOCK, 0},
{ "Lock indicator", HUD_OBJECT_LOCK, 0}, // Not in legacy list
{ "Weapon linking", HUD_OBJECT_WEAPON_LINKING, 0},
{ "Multiplayer messages", HUD_OBJECT_MULTI_MSG, 0},
{ "Voice status", HUD_OBJECT_VOICE_STATUS, 0},
{ "Ping", HUD_OBJECT_PING, 0},
{ "Supernova", HUD_OBJECT_SUPERNOVA, 0},
{ "Multiplayer messages", HUD_OBJECT_MULTI_MSG, 0}, // Not in legacy list
{ "Voice status", HUD_OBJECT_VOICE_STATUS, 0}, // Not in legacy list
{ "Ping", HUD_OBJECT_PING, 0}, // Not in legacy list
{ "Supernova", HUD_OBJECT_SUPERNOVA, 0}, // Not in legacy list
{ "Offscreen indicator", HUD_OBJECT_OFFSCREEN, 0},
{ "Targeting brackets", HUD_OBJECT_BRACKETS, 0},
{ "Orientation", HUD_OBJECT_ORIENTATION_TEE, 0},
@@ -149,10 +192,9 @@ flag_def_list Hud_gauge_types[] = {
{ "Target direction", HUD_OBJECT_TARGET_TRI, 0},
{ "Missile indicator", HUD_OBJECT_MISSILE_TRI, 0},
{ "Kills", HUD_OBJECT_KILLS, 0},
{ "Fixed messages", HUD_OBJECT_FIXED_MESSAGES, 0},
{ "Fixed messages", HUD_OBJECT_FIXED_MESSAGES, 0}, // Not in legacy list
{ "Ets retail", HUD_OBJECT_ETS_RETAIL, 0}
};
int Num_hud_gauge_types = sizeof(Hud_gauge_types)/sizeof(flag_def_list);
int parse_ship_start()
@@ -522,7 +564,6 @@ void hud_positions_init()
// load missing retail gauges for the default and ship-specific HUDs
load_missing_retail_gauges();
}
void load_missing_retail_gauges()
@@ -533,11 +574,11 @@ void load_missing_retail_gauges()
if(Hud_retail) {
int num_loaded_gauges = (int)default_hud_gauges.size();
for(int i = 0; i < num_default_gauges; i++) {
for(int i = 0; i < Num_builtin_gauges; i++) {
retail_gauge_loaded = false;
for(int j = 0; j < num_loaded_gauges; j++) {
if(retail_gauges[i] == default_hud_gauges[j]->getObjectType()) {
if(Builtin_gauges[i] == default_hud_gauges[j]->getObjectType()) {
retail_gauge_loaded = true;
break;
}
@@ -545,7 +586,7 @@ void load_missing_retail_gauges()
if(!retail_gauge_loaded) {
gauge_settings settings;
load_gauge(retail_gauges[i], &settings);
load_gauge(Builtin_gauges[i], &settings);
}
}
@@ -589,9 +630,9 @@ void load_missing_retail_gauges()
if(it->hud_enabled && it->hud_retail) {
int num_loaded_gauges = (int)it->hud_gauges.size();
for(int i = 0; i < num_default_gauges; i++) {
for(int i = 0; i < Num_builtin_gauges; i++) {
for(int j = 0; j < num_loaded_gauges; j++) {
if(retail_gauges[i] == it->hud_gauges[j]->getObjectType()) {
if(Builtin_gauges[i] == it->hud_gauges[j]->getObjectType()) {
retail_gauge_loaded = true;
}
}
@@ -599,7 +640,7 @@ void load_missing_retail_gauges()
if(!retail_gauge_loaded) {
gauge_settings settings;
settings.ship_idx = &sindex;
load_gauge(retail_gauges[i], &settings);
load_gauge(Builtin_gauges[i], &settings);
}
}
@@ -1452,7 +1493,7 @@ void load_gauge_custom(gauge_settings* settings)
stuff_string(gauge_string, F_NAME, MAX_FILENAME_LEN);
for(i = 0; i < NUM_HUD_GAUGES; i++) {
if(!strcmp(HUD_gauge_text[i], gauge_string)) {
if(!strcmp(Legacy_HUD_gauges[i].hud_gauge_text, gauge_string)) {
gauge_type = i;
break;
}
+5 -5
View File
@@ -236,7 +236,7 @@ void HudGaugeReticle::initBitmaps(char *fname)
{
crosshair.first_frame = bm_load_animation(fname, &crosshair.num_frames);
if (crosshair.first_frame < 0) {
mprintf(("Cannot load hud ani: %s\n", fname));
Warning(LOCATION, "Cannot load hud ani: %s\n", fname);
}
}
@@ -495,7 +495,7 @@ void HudGaugeThrottle::initBitmaps(char *fname)
throttle_frames.first_frame = bm_load_animation(fname, &throttle_frames.num_frames);
if (throttle_frames.first_frame < 0) {
mprintf(("Cannot load hud ani: %s\n", fname));
Warning(LOCATION, "Cannot load hud ani: %s\n", fname);
}
}
@@ -748,17 +748,17 @@ void HudGaugeThreatIndicator::initBitmaps(char *fname_arc, char *fname_laser, ch
{
threat_arc.first_frame = bm_load_animation(fname_arc, &threat_arc.num_frames);
if (threat_arc.first_frame < 0) {
mprintf(("Cannot load hud ani: %s\n", fname_arc));
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_arc);
}
laser_warn.first_frame = bm_load_animation(fname_laser, &laser_warn.num_frames);
if (laser_warn.first_frame < 0) {
mprintf(("Cannot load hud ani: %s\n", fname_laser));
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_laser);
}
lock_warn.first_frame = bm_load_animation(fname_lock, &lock_warn.num_frames);
if (lock_warn.first_frame < 0) {
mprintf(("Cannot load hud ani: %s\n", fname_lock));
Warning(LOCATION, "Cannot load hud ani: %s\n", fname_lock);
}
}
+16 -4
View File
@@ -378,7 +378,13 @@ void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_off
break;
}
if (objp->shield_quadrant[Quadrant_xlate[i]] < 0.1f ) {
int num;
if (!(Ship_info[Ships[objp->instance].ship_info_index].flags[Ship::Info_Flags::Model_point_shields]))
num = Quadrant_xlate[i];
else
num = i;
if (objp->shield_quadrant[num] < 0.1f ) {
continue;
}
@@ -389,7 +395,7 @@ void hud_shield_show_mini(object *objp, int x_force, int y_force, int x_hull_off
}
range = HUD_color_alpha;
hud_color_index = (int)std::lround((objp->shield_quadrant[Quadrant_xlate[i]] / max_shield) * range);
hud_color_index = (int)std::lround((objp->shield_quadrant[num] / max_shield) * range);
Assert(hud_color_index >= 0 && hud_color_index <= range);
if ( hud_color_index < 0 ) {
@@ -975,7 +981,13 @@ void HudGaugeShieldMini::showMiniShields(object *objp)
break;
}
if ( objp->shield_quadrant[Quadrant_xlate[i]] < 0.1f ) {
int num;
if (!(Ship_info[Ships[objp->instance].ship_info_index].flags[Ship::Info_Flags::Model_point_shields]))
num = Quadrant_xlate[i];
else
num = i;
if (objp->shield_quadrant[num] < 0.1f ) {
continue;
}
@@ -986,7 +998,7 @@ void HudGaugeShieldMini::showMiniShields(object *objp)
}
range = HUD_color_alpha;
hud_color_index = (int)std::lround((objp->shield_quadrant[Quadrant_xlate[i]] / max_shield) * range);
hud_color_index = (int)std::lround((objp->shield_quadrant[num] / max_shield) * range);
Assert(hud_color_index >= 0 && hud_color_index <= range);
if ( hud_color_index < 0 ) {
+1 -1
View File
@@ -1823,7 +1823,7 @@ void hud_squadmsg_call_reinforcement(int reinforcement_num, int /*player_num*/)
break;
//if ( i > 0 )
// message_send_to_player( rp->yes_messages[myrand() % i], rp->name, MESSAGE_PRIORITY_NORMAL, HUD_SOURCE_FRIENDLY );
// message_send_to_player( rp->yes_messages[Random::next(i)], rp->name, MESSAGE_PRIORITY_NORMAL, HUD_SOURCE_FRIENDLY );
*/
mission_log_add_entry(LOG_PLAYER_CALLED_FOR_REINFORCEMENT, rp->name, NULL);
+30 -9
View File
@@ -7185,13 +7185,17 @@ void HudGaugeHardpoints::render(float /*frametime*/)
//secondary weapons
int num_secondaries_rendered = 0;
if ( draw_secondary_models ) {
auto ship_pm = model_get(sip->model_num);
for (i = 0; i < swp->num_secondary_banks; i++) {
if (Weapon_info[swp->secondary_bank_weapons[i]].external_model_num == -1 || !sip->draw_secondary_models[i])
auto wip = &Weapon_info[swp->secondary_bank_weapons[i]];
if (wip->external_model_num == -1 || !sip->draw_secondary_models[i])
continue;
auto bank = &(model_get(sip->model_num))->missile_banks[i];
auto bank = &ship_pm->missile_banks[i];
if (Weapon_info[swp->secondary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::External_weapon_lnch]) {
if (wip->wi_flags[Weapon::Info_Flags::External_weapon_lnch]) {
for(k = 0; k < bank->num_slots; k++) {
model_render_params weapon_render_info;
@@ -7202,7 +7206,12 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vec3d world_position;
vm_vec_unrotate(&world_position, &bank->pnt[k], &object_orient);
model_render_immediate(&weapon_render_info, Weapon_info[swp->secondary_bank_weapons[i]].external_model_num, &object_orient, &bank->pnt[k]);
// "Bank" the external model by the angle offset
angles angs = { 0.0f, bank->external_model_angle_offset[k], 0.0f };
matrix model_orient = object_orient;
vm_rotate_matrix_by_angles(&model_orient, &angs);
model_render_immediate(&weapon_render_info, wip->external_model_num, &model_orient, &bank->pnt[k]);
}
} else {
num_secondaries_rendered = 0;
@@ -7214,7 +7223,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
if (num_secondaries_rendered >= sp->weapons.secondary_bank_ammo[i])
break;
if(sp->secondary_point_reload_pct[i][k] <= 0.0)
if(sp->secondary_point_reload_pct.get(i, k) <= 0.0)
continue;
model_render_params weapon_render_info;
@@ -7227,7 +7236,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
num_secondaries_rendered++;
vm_vec_scale_add2(&secondary_weapon_pos, &vmd_z_vector, -(1.0f-sp->secondary_point_reload_pct[i][k]) * model_get(Weapon_info[swp->secondary_bank_weapons[i]].external_model_num)->rad);
vm_vec_scale_add2(&secondary_weapon_pos, &vmd_z_vector, -(1.0f-sp->secondary_point_reload_pct.get(i, k)) * model_get(wip->external_model_num)->rad);
weapon_render_info.set_detail_level_lock(detail_level_lock);
weapon_render_info.set_flags(render_flags);
@@ -7236,7 +7245,12 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vec3d world_position;
vm_vec_unrotate(&world_position, &secondary_weapon_pos, &object_orient);
model_render_immediate(&weapon_render_info, Weapon_info[swp->secondary_bank_weapons[i]].external_model_num, &object_orient, &world_position);
// "Bank" the external model by the angle offset
angles angs = { 0.0f, bank->external_model_angle_offset[k], 0.0f };
matrix model_orient = object_orient;
vm_rotate_matrix_by_angles(&model_orient, &angs);
model_render_immediate(&weapon_render_info, wip->external_model_num, &model_orient, &world_position);
}
}
}
@@ -7248,9 +7262,11 @@ void HudGaugeHardpoints::render(float /*frametime*/)
//primary weapons
if ( draw_primary_models ) {
auto ship_pm = model_get(sip->model_num);
for ( i = 0; i < swp->num_primary_banks; i++ ) {
auto wip = &Weapon_info[swp->primary_bank_weapons[i]];
auto bank = &model_get(sip->model_num)->gun_banks[i];
auto bank = &ship_pm->gun_banks[i];
for ( k = 0; k < bank->num_slots; k++ ) {
if ( wip->external_model_num < 0 || !sip->draw_primary_models[i] ) {
@@ -7278,7 +7294,12 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vec3d world_position;
vm_vec_unrotate(&world_position, &bank->pnt[k], &object_orient);
model_render_immediate(&weapon_render_info, wip->external_model_num, swp->primary_bank_external_model_instance[i], &object_orient, &world_position);
// "Bank" the external model by the angle offset
angles angs = { 0.0f, bank->external_model_angle_offset[k], 0.0f };
matrix model_orient = object_orient;
vm_rotate_matrix_by_angles(&model_orient, &angs);
model_render_immediate(&weapon_render_info, wip->external_model_num, swp->primary_bank_external_model_instance[i], &model_orient, &world_position);
}
}
}
-19
View File
@@ -99,24 +99,6 @@ void hud_set_wingman_status_alive( int wing_index, int wing_pos)
HUD_wingman_status[wing_index].status[wing_pos] = HUD_WINGMAN_STATUS_ALIVE;
}
void hud_wingman_status_init_late_wings()
{
/*
int i, j, wing_index;
for ( i = 0; i < Num_wings; i++ ) {
wing_index = ship_squadron_wing_lookup(Wings[i].name);
if ( (wing_index >= 0) && (Wings[i].total_arrived_count == 0) ) {
HUD_wingman_status[wing_index].used = 1;
for (j = 0; j < Wings[i].wave_count; j++) {
HUD_wingman_status[wing_index].status[j] = HUD_WINGMAN_STATUS_NOT_HERE;
}
}
}
*/
}
// function which marks the other team wing as not used for the wingman status gauge
void hud_wingman_kill_multi_teams()
{
@@ -161,7 +143,6 @@ void hud_init_wingman_status_gauge()
}
}
hud_wingman_status_init_late_wings();
hud_wingman_kill_multi_teams();
hud_wingman_status_update();
}
+11 -7
View File
@@ -542,9 +542,11 @@ void key_mark( uint code, int state, uint latency )
Current_key_down |= KEY_CTRLED;
}
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYRELEASED);
Script_system.RemHookVar("Key");
if (Script_system.IsActiveAction(CHA_KEYRELEASED)) {
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYRELEASED);
Script_system.RemHookVar("Key");
}
} else {
// Key going down
keyd_last_pressed = scancode;
@@ -570,10 +572,12 @@ void key_mark( uint code, int state, uint latency )
Current_key_down |= KEY_CTRLED;
}
// We use the universal value here to keep the scripting interface consistent regardless of the current language
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYPRESSED);
Script_system.RemHookVar("Key");
if (Script_system.IsActiveAction(CHA_KEYPRESSED)) {
// We use the universal value here to keep the scripting interface consistent regardless of the current language
Script_system.SetHookVar("Key", 's', textify_scancode_universal(Current_key_down));
Script_system.RunCondition(CHA_KEYPRESSED);
Script_system.RemHookVar("Key");
}
} else if (!keyd_repeat) {
// Don't buffer repeating key if repeat mode is off
scancode = 0xAA;
+4 -13
View File
@@ -692,15 +692,6 @@ void process_debug_keys(int k)
case KEY_DEBUGGED + KEY_H:
hud_target_toggle_hidden_from_sensors();
break;
case KEY_DEBUGGED + KEY_F:
extern int wacky_scheme;
if(wacky_scheme == 3){
wacky_scheme = 0;
} else {
wacky_scheme++;
}
break;
case KEY_DEBUGGED + KEY_ALTED + KEY_F:
Framerate_delay += 10;
@@ -785,8 +776,8 @@ void process_debug_keys(int k)
// remove guardian flag -- kazan
Ships[objp->instance].ship_guardian_threshold = 0;
ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
break;
case OBJ_WEAPON:
Weapons[objp->instance].lifeleft = 0.01f;
@@ -856,7 +847,7 @@ void process_debug_keys(int k)
object *objp = &Objects[Player_ai->target_objnum];
if (objp->type == OBJ_SHIP) {
ship_apply_local_damage( objp, Player_obj, &objp->pos, Ships[objp->instance].ship_max_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage( objp, Player_obj, &objp->pos, Ships[objp->instance].ship_max_hull_strength * 0.1f + 10.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
}
}
break;
@@ -894,7 +885,7 @@ void process_debug_keys(int k)
vm_vec_rand_vec_quick(&randvec);
vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, -1, MISS_SHIELDS, CREATE_SPARKS);
hud_get_target_strength(Player_obj, &shield, &integrity);
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You whacked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
break;
+9 -10
View File
@@ -99,7 +99,7 @@ namespace
break;
default:
// SDL gave us an unknown button. Just log it
mprintf(("Unknown SDL button %i", e.button.button));
mprintf(("Unknown SDL button %i\n", e.button.button));
}
return true;
@@ -270,14 +270,13 @@ void mouse_mark_button( uint flags, int set)
Script_system.SetHookVar("MouseButton", 'i', flags);
//WMC - On Mouse Pressed and On Mouse Released hooks
if (set == 1)
{
Script_system.RunCondition(CHA_MOUSEPRESSED);
}
else if (set == 0)
{
Script_system.RunCondition(CHA_MOUSERELEASED);
if (Script_system.IsActiveAction(CHA_MOUSEPRESSED) || Script_system.IsActiveAction(CHA_MOUSERELEASED)) {
//WMC - On Mouse Pressed and On Mouse Released hooks
if (set == 1) {
Script_system.RunCondition(CHA_MOUSEPRESSED);
} else if (set == 0) {
Script_system.RunCondition(CHA_MOUSERELEASED);
}
}
Script_system.RemHookVar("MouseButton");
@@ -464,7 +463,7 @@ void mouse_event(int x, int y, int dx, int dy)
Mouse_dx += dx;
Mouse_dy += dy;
if(Mouse_dx != 0 || Mouse_dy != 0)
if (Script_system.IsActiveAction(CHA_MOUSEMOVED) && (Mouse_dx != 0 || Mouse_dy != 0))
{
Script_system.RunCondition(CHA_MOUSEMOVED);
}
+5 -1
View File
@@ -14,8 +14,12 @@
#include "globalincs/pstypes.h"
#include "utils/Random.h"
#include <cstdint>
using Random = util::Random;
//==========================================================================
// This installs the timer services and interrupts at the rate specified by
// count_val. If 'function' isn't 0, the function pointed to by function will
@@ -96,7 +100,7 @@ int timestamp();
// gets a timestamp randomly between a and b milliseconds in
// the future.
inline int timestamp_rand(int a, int b) {
return timestamp(myrand() % (b - a + 1) + a);
return timestamp(Random::next(a, b));
}
// Example that makes a ship fire in 1/2 second
+18 -10
View File
@@ -2,6 +2,8 @@
#include "lab/labv2_internal.h"
#include "ship/shiphit.h"
#include <array>
/**********************Click event handlers********************************************/
void destroy_subsystem(Tree* caller) {
@@ -62,8 +64,8 @@ void destroy_ship(Button* /*caller*/) {
std::map<AnimationTriggerType, std::map<int, bool>> manual_animation_triggers = {};
std::map<AnimationTriggerType, bool> manual_animations = {};
bool triggered_primary_banks[MAX_SHIP_PRIMARY_BANKS];
bool triggered_secondary_banks[MAX_SHIP_SECONDARY_BANKS];
std::array<bool, MAX_SHIP_PRIMARY_BANKS> triggered_primary_banks;
std::array<bool, MAX_SHIP_SECONDARY_BANKS> triggered_secondary_banks;
void reset_animations(Tree*) {
if (getLabManager()->isSafeForShips()) {
@@ -176,7 +178,8 @@ void Actions::open(Button* /*caller*/) {
getLabManager()->loadWeapons();
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Actions", gr_screen.center_offset_x + 250, gr_screen.center_offset_y + 50));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
int y = 0;
@@ -184,8 +187,9 @@ void Actions::open(Button* /*caller*/) {
dialogWindow->AddChild(btn);
y += btn->GetHeight();
for (auto dialog : subDialogs) {
auto dgo = new DialogOpener(dialog, 0, y);
for (auto &dialog : subDialogs) {
auto *dgo = new DialogOpener(dialog, 0, y);
dialog->setOpener(dgo);
dialogWindow->AddChild(dgo);
y += dgo->GetHeight();
}
@@ -194,7 +198,7 @@ void Actions::open(Button* /*caller*/) {
}
void Actions::update(LabMode newLabMode, int classIndex) {
for (auto dialog : subDialogs) {
for (auto &dialog : subDialogs) {
dialog->update(newLabMode, classIndex);
}
}
@@ -204,7 +208,8 @@ void DestroySubsystems::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Destroy Subsystems", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -234,7 +239,8 @@ void ChangeLoadout::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Change Loadout", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -349,7 +355,8 @@ void WeaponFire::open(Button* /*caller*/) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(
new DialogWindow("Fire weapons", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50)
);
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -387,7 +394,8 @@ void AnimationTrigger::open(Button* /*caller*/) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(
new DialogWindow("Trigger animations", gr_screen.center_offset_x + 400, gr_screen.center_offset_y + 50)
);
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
+20 -5
View File
@@ -5,7 +5,10 @@
class DestroySubsystems : public LabDialog {
public:
~DestroySubsystems() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -31,7 +34,10 @@ private:
};
class ChangeLoadout : public LabDialog {
public:
~ChangeLoadout() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -57,7 +63,10 @@ private:
};
class WeaponFire : public LabDialog {
public:
~WeaponFire() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -83,6 +92,10 @@ private:
};
class AnimationTrigger : public LabDialog {
public:
~AnimationTrigger() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -105,12 +118,14 @@ private:
class Actions : public LabDialog {
public:
Actions() {
subDialogs.push_back(new DestroySubsystems());
subDialogs.push_back(new ChangeLoadout());
subDialogs.push_back(new WeaponFire());
subDialogs.push_back(new AnimationTrigger());
subDialogs.emplace_back(std::make_shared<DestroySubsystems>());
subDialogs.emplace_back(std::make_shared<ChangeLoadout>());
subDialogs.emplace_back(std::make_shared<WeaponFire>());
subDialogs.emplace_back(std::make_shared<AnimationTrigger>());
}
~Actions() override = default;
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
@@ -133,5 +148,5 @@ public:
private:
DialogWindow* dialogWindow = nullptr;
SCP_vector<LabDialog*> subDialogs;
SCP_vector<std::shared_ptr<LabDialog>> subDialogs;
};
+2 -1
View File
@@ -36,7 +36,8 @@ void BackgroundDialog::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Mission Backgrounds", gr_screen.center_offset_x + 250, gr_screen.center_offset_y + 50));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
SCP_vector<SCP_string> missions;
+4
View File
@@ -4,6 +4,10 @@
class BackgroundDialog : public LabDialog {
public:
~BackgroundDialog() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
+2 -1
View File
@@ -8,7 +8,8 @@ void Descriptions::open(Button* /*caller*/) {
gr_screen.center_offset_y + gr_screen.center_h - gr_screen.center_h / 6 - 50, gr_screen.center_w / 3,
gr_screen.center_h / 6)
);
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
}
dialogWindow->DeleteChildren();
+4
View File
@@ -3,6 +3,10 @@
#include "lab/dialogs/lab_dialog.h"
class Descriptions : public LabDialog {
public:
~Descriptions() override = default;
private:
void open(Button* caller) override;
void close() override {
+2 -1
View File
@@ -7,7 +7,8 @@ void Options::open(Button* /*caller*/) {
if (dialogWindow == nullptr) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow(
"Flags Window", gr_screen.center_offset_x + gr_screen.center_w - 205, gr_screen.center_offset_y + 200));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
}
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
+4
View File
@@ -9,6 +9,10 @@ struct lab_flag {
};
class Options : public LabDialog {
public:
~Options() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
+5 -4
View File
@@ -8,7 +8,8 @@ void Variables::open(Button* /*caller*/) {
if (dialogWindow == nullptr) {
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Class Variables", gr_screen.center_offset_x + gr_screen.center_w - 285,
gr_screen.center_offset_y + 200));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
}
update(getLabManager()->CurrentMode, getLabManager()->CurrentClass);
}
@@ -74,8 +75,8 @@ void Variables::update(LabMode newLabMode, int classIndex) {
addHeader(y, "Techroom");
addVariable(&y, "Closeup zoom", sip->closeup_zoom);
addVariable(&y, "Closeup pos (x)", sip->closeup_pos.xyz.x);
addVariable(&y, "Closeup pos (y)", sip->closeup_pos.xyz.x);
addVariable(&y, "Closeup pos (z)", sip->closeup_pos.xyz.x);
addVariable(&y, "Closeup pos (y)", sip->closeup_pos.xyz.y);
addVariable(&y, "Closeup pos (z)", sip->closeup_pos.xyz.z);
break;
case LabMode::Weapon:
wip = &Weapon_info[classIndex];
@@ -89,7 +90,7 @@ void Variables::update(LabMode newLabMode, int classIndex) {
addVariable(&y, "Max speed", wip->max_speed);
addVariable(&y, "Lifetime", wip->lifetime);
addVariable(&y, "Range", wip->weapon_range);
addVariable(&y, "Min Range", wip->WeaponMinRange);
addVariable(&y, "Min Range", wip->weapon_min_range);
addHeader(y, "Damage");
addVariable(&y, "Fire wait", wip->fire_wait);
+4
View File
@@ -3,6 +3,10 @@
#include "lab/dialogs/lab_dialog.h"
class Variables : public LabDialog {
public:
~Variables() override = default;
private:
void open(Button* caller) override;
void close() override {
+15 -2
View File
@@ -3,8 +3,12 @@
#include "lab/wmcgui.h"
#include "lab/labv2.h"
class DialogOpener;
class LabDialog {
public:
virtual ~LabDialog() = default;
// Called when this dialog is opened via the top toolbar
virtual void open(Button* caller) = 0;
@@ -19,13 +23,16 @@ public:
// Returns true if it is safe to open this dialog
virtual bool safeToOpen(LabMode labMode) = 0;
void setOpener(const DialogOpener* opener) { Opener = opener; }
protected:
const DialogOpener *Opener = nullptr;
};
// This is a base class for Windows opened by the various dialogs. Since dialogs exist even when their Windows are closed,
// this introduces the concept of an "Owner", who gets notified when the DialogWindow is closed.
class DialogWindow : public Window {
public:
void SetOwner(LabDialog* owner) { Owner = owner; }
DialogWindow(const SCP_string& in_caption, int x_coord, int y_coord, int x_width = -1, int y_height = -1, int in_style = 0) :
Window(in_caption, x_coord, y_coord, x_width, y_height, in_style) {
}
@@ -34,6 +41,12 @@ public:
if (Owner != nullptr)
Owner->close();
}
void SetOwner(std::shared_ptr<LabDialog> owner)
{
Owner = std::move(owner);
}
private:
LabDialog* Owner = nullptr;
std::shared_ptr<LabDialog> Owner;
};
+12 -2
View File
@@ -49,6 +49,12 @@ void set_spec_flag(Checkbox* caller) {
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoSpecularMap, !value);
}
void set_reflect_flag(Checkbox* caller) {
auto value = caller->GetChecked();
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoReflectMap, !value);
}
void set_env_flag(Checkbox* caller) {
auto value = caller->GetChecked();
@@ -164,7 +170,8 @@ void RenderOptions::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Render Options", gr_screen.center_offset_x + gr_screen.center_w - 300, gr_screen.center_offset_y + 200));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
dialogWindow->DeleteChildren();
@@ -193,6 +200,9 @@ void RenderOptions::open(Button* /*caller*/) {
cbp = (Checkbox*)dialogWindow->AddChild(new Checkbox("No Specular Map", 2, y, set_spec_flag));
y += cbp->GetHeight() + 2;
cbp = (Checkbox*)dialogWindow->AddChild(new Checkbox("No Reflection Map", 2, y, set_reflect_flag));
y += cbp->GetHeight() + 2;
cbp = (Checkbox*)dialogWindow->AddChild(new Checkbox("No Environment Map", 2, y, set_env_flag));
y += cbp->GetHeight() + 2;
@@ -243,7 +253,7 @@ void RenderOptions::open(Button* /*caller*/) {
y += direct_sldr->GetHeight() + 2;
auto bloom_sldr = new Slider("Bloom", 0, 200, 0, y + 2, set_bloom, dialogWindow->GetWidth());
bloom_sldr->SetSliderValue((float)Cmdline_bloom_intensity);
bloom_sldr->SetSliderValue((float)gr_bloom_intensity());
dialogWindow->AddChild(bloom_sldr);
y += bloom_sldr->GetHeight() + 2;
+4
View File
@@ -4,6 +4,10 @@
class RenderOptions : public LabDialog {
public:
~RenderOptions() override = default;
private:
// Called when this dialog is opened via the top toolbar
void open(Button* /*caller*/) override;
+8 -4
View File
@@ -12,7 +12,8 @@ void ShipClasses::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Ship Classes", gr_screen.center_offset_x + 50, gr_screen.center_offset_y + 50));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
auto tree = (Tree*)dialogWindow->AddChild(new Tree("Ship Tree", 0, 0));
/* Ship tree layout
@@ -49,13 +50,16 @@ void ShipClasses::update(LabMode newLabMode, int classIndex) {
if (Class_toolbar == nullptr) {
Class_toolbar = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Class Toolbar", gr_screen.center_offset_x + 0,
gr_screen.center_offset_y + getLabManager()->Toolbar->GetHeight(), -1, -1, WS_NOTITLEBAR | WS_NONMOVEABLE));
Class_toolbar->SetOwner(this);
Assert(Opener != nullptr);
Class_toolbar->SetOwner(Opener->getDialog());
}
Class_toolbar->DeleteChildren();
auto x = 0;
for (auto subdialog : Subdialogs) {
auto cbp = Class_toolbar->AddChild(new DialogOpener(subdialog, x, 0));
for (auto &subdialog : Subdialogs) {
auto *dgo = new DialogOpener(subdialog, x, 0);
subdialog->setOpener(dgo);
auto *cbp = Class_toolbar->AddChild(dgo);
x += cbp->GetWidth();
subdialog->update(newLabMode, classIndex);
+6 -4
View File
@@ -12,14 +12,16 @@
class ShipClasses : public LabDialog {
public:
ShipClasses() {
Subdialogs.push_back(new Descriptions());
Subdialogs.push_back(new Options());
Subdialogs.push_back(new Variables());
Subdialogs.emplace_back(std::make_shared<Descriptions>());
Subdialogs.emplace_back(std::make_shared<Options>());
Subdialogs.emplace_back(std::make_shared<Variables>());
dialogWindow = nullptr;
Class_toolbar = nullptr;
}
~ShipClasses() override = default;
SCP_string getTitle() override { return "Ship Classes"; }
bool safeToOpen(LabMode /*labMode*/) override { return true; }
@@ -43,5 +45,5 @@ public:
private:
DialogWindow* dialogWindow = nullptr;
DialogWindow* Class_toolbar = nullptr;
SCP_vector<LabDialog*> Subdialogs;
SCP_vector<std::shared_ptr<LabDialog>> Subdialogs;
};
+8 -4
View File
@@ -13,7 +13,8 @@ void WeaponClasses::open(Button* /*caller*/) {
return;
dialogWindow = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Weapon Classes", gr_screen.center_offset_x + 50, gr_screen.center_offset_y + 50));
dialogWindow->SetOwner(this);
Assert(Opener != nullptr);
dialogWindow->SetOwner(Opener->getDialog());
auto tree = (Tree*)dialogWindow->AddChild(new Tree("Weapon Tree", 0, 0));
SCP_vector<TreeItem*> typeHeaders;
@@ -52,13 +53,16 @@ void WeaponClasses::update(LabMode newLabMode, int classIndex) {
if (Class_toolbar == nullptr) {
Class_toolbar = (DialogWindow*)getLabManager()->Screen->Add(new DialogWindow("Class Toolbar", gr_screen.center_offset_x + 0,
gr_screen.center_offset_y + getLabManager()->Toolbar->GetHeight(), -1, -1, WS_NOTITLEBAR | WS_NONMOVEABLE));
Class_toolbar->SetOwner(this);
Assert(Opener != nullptr);
Class_toolbar->SetOwner(Opener->getDialog());
}
Class_toolbar->DeleteChildren();
auto x = 0;
for (auto subdialog : Subdialogs) {
auto cbp = Class_toolbar->AddChild(new DialogOpener(subdialog, x, 0));
for (auto &subdialog : Subdialogs) {
auto *dgo = new DialogOpener(subdialog, x, 0);
subdialog->setOpener(dgo);
auto *cbp = Class_toolbar->AddChild(dgo);
x += cbp->GetWidth();
subdialog->update(newLabMode, classIndex);
+6 -4
View File
@@ -8,14 +8,16 @@
class WeaponClasses : public LabDialog {
public:
WeaponClasses() {
Subdialogs.push_back(new Descriptions());
Subdialogs.push_back(new Options());
Subdialogs.push_back(new Variables());
Subdialogs.emplace_back(std::make_shared<Descriptions>());
Subdialogs.emplace_back(std::make_shared<Options>());
Subdialogs.emplace_back(std::make_shared<Variables>());
dialogWindow = nullptr;
Class_toolbar = nullptr;
}
~WeaponClasses() override = default;
SCP_string getTitle() override { return "Weapon Classes"; }
bool safeToOpen(LabMode /*labMode*/) override { return true; }
@@ -39,5 +41,5 @@ public:
private:
DialogWindow* dialogWindow = nullptr;
DialogWindow* Class_toolbar = nullptr;
SCP_vector<LabDialog*> Subdialogs;
SCP_vector<std::shared_ptr<LabDialog>> Subdialogs;
};
+4 -5
View File
@@ -3,11 +3,11 @@
#include "lab/manager/lab_manager.h"
#include "gamesequence/gamesequence.h"
LabManager* LMGR = nullptr;
static std::unique_ptr<LabManager> LMGR;
LabManager* getLabManager() {
const std::unique_ptr<LabManager> &getLabManager() {
if (LMGR == nullptr) {
LMGR = new LabManager();
LMGR.reset(new LabManager());
}
return LMGR;
@@ -18,8 +18,7 @@ void lab_init() {
}
void lab_close() {
delete LMGR;
LMGR = nullptr;
LMGR.reset();
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
}
Loaded 100 of 345 files, more files were not shown because too many files have changed in this diff. Show more