Compare commits

...

391 commits

Author SHA1 Message Date
Eidolon
c2c3ae63a7 Merge branch 'wallspike-crash-fix' into 'master'
Add player pointer check in wall spike bounce

Closes #397

See merge request kart-krew-dev/ring-racers!78
2025-10-26 20:59:39 -05:00
Eidolon
721d5630a1 Add player pointer check in wall spike bounce 2025-10-26 20:37:51 -05:00
Eidolon
200e7b4014 Update modversion for RC9/final just in case 2025-10-26 19:48:56 -05:00
Eidolon
d4c2235e92 Update hashes 2025-10-26 19:26:36 -05:00
Ashnal
b9df8963cd Merge branch 'tally-idle-exp-grade-fix' into 'master'
Fixes grading for 0 EXP finishes

See merge request kart-krew-dev/ring-racers-internal!2973
2025-10-27 00:20:23 +00:00
Ashnal
719923e0cf Fixes grading for 0 EXP finishes 2025-10-27 00:20:22 +00:00
Eidolon
e864ba5255 Merge branch 'team-assist' into 'master'
Significantly more active Speed Assist in teamplay

See merge request kart-krew-dev/ring-racers-internal!2969
2025-10-26 18:51:49 -05:00
Eidolon
b0e1b14c9b Merge remote-tracking branch 'public/master' 2025-10-26 18:07:56 -05:00
Eidolon
15f66de4af Merge branch 'battle-exp-queue' into 'master'
Implement score-to-EXP scaling for Battle and Duel Race when Mobiums are not enabled.

See merge request kart-krew-dev/ring-racers!69
2025-10-26 18:00:03 -05:00
Freaky Mutant Man
6d344ad118 Implement score-to-EXP scaling for Battle and Duel Race when Mobiums are not enabled. 2025-10-26 18:00:03 -05:00
Eidolon
5f0121cca8 Merge branch 'eid-sonic-boom-color' into 'master'
Fix sonic boom colorization

Closes ring-racers#378

See merge request kart-krew-dev/ring-racers-internal!2971
2025-10-26 16:50:22 -05:00
Eidolon
36de3285bd Merge branch 'eid-battle-crash-fix' into 'master'
Use a different patch for striking levels in duel vote

Closes ring-racers#388

See merge request kart-krew-dev/ring-racers-internal!2972
2025-10-26 16:50:16 -05:00
Eidolon
ecb1927cf8 Merge branch 'shorter-caltrops' into 'master'
Set short fuse on "ring burn" caltrops

See merge request kart-krew-dev/ring-racers-internal!2970
2025-10-26 15:11:04 -05:00
Antonio Martinez
c28733f2f5 Speed Assist: Store team multiplier up front 2025-10-26 15:57:23 -04:00
Eidolon
e63ad4a681 Use a different patch for striking levels in duel vote 2025-10-26 14:17:38 -05:00
Eidolon
c087c8bacc Fix sonic boom colorization 2025-10-25 21:08:23 -05:00
Eidolon
8ce90ff211 Merge public master 2025-10-25 20:43:09 -05:00
Eidolon
b4c597161b Merge branch 'node0Bot' into 'master'
Fix node 0 being occupied by a bot in dedicated servers for clients

Closes #385

See merge request kart-krew-dev/ring-racers!77
2025-10-25 20:40:00 -05:00
JugadorXEI
2b7e1384ed Fix node 0 being occupied by a bot in dedicated servers for clients 2025-10-25 20:39:59 -05:00
Eidolon
176713d243 Merge branch 'cachedlevels-lua-why-broke' into 'master'
Fix cup->cachedlevels Lua getter to return entire cachedlevels list.

See merge request kart-krew-dev/ring-racers!73
2025-10-25 20:26:31 -05:00
Freaky Mutant Man
d363c71007 Fix cup->cachedlevels Lua getter to return entire cachedlevels list. 2025-10-25 20:26:31 -05:00
Eidolon
fd27994c48 Merge branch 'unarchiveLuaVarsAfterMapLoad' into 'master'
Unarchive Lua variables *after* loading a level in a demo (fixes #284)

Closes #284

See merge request kart-krew-dev/ring-racers!72
2025-10-25 20:16:52 -05:00
JugadorXEI
9244b9148e Unarchive Lua variables *after* loading a level in a demo (fixes #284) 2025-10-25 20:16:52 -05:00
Eidolon
5d697e378f Merge branch 'fix-long-message-crash' into 'master'
Fixed crash when sending a max character message

See merge request kart-krew-dev/ring-racers!68
2025-10-25 20:01:35 -05:00
Eidolon
0e431cd334 Merge branch 'reducevfx-battle' into 'master'
Disable overtime barrier animation/flashing when reducevfx is enabled.

See merge request kart-krew-dev/ring-racers!74
2025-10-25 19:57:12 -05:00
Eidolon
21a3489bcb Merge branch 'jesus-christ-music-remap-still-broke' into 'master'
Fix anti-Stereo Mode remap check in Lua music remapping function.

See merge request kart-krew-dev/ring-racers!75
2025-10-25 19:46:00 -05:00
Freaky Mutant Man
039ba6c3dc Fix anti-Stereo Mode remap check in Lua music remapping function. 2025-10-25 19:46:00 -05:00
Eidolon
de0fc7d3be Merge branch 'ring-bail-gp-life-loss' into 'master'
Fix unintended life loss in GP when finishing a race with -20 rings.

See merge request kart-krew-dev/ring-racers!76
2025-10-25 19:38:14 -05:00
Freaky Mutant Man
fcb7d38dce Fix unintended life loss in GP when finishing a race with -20 rings. 2025-10-25 19:38:13 -05:00
Eidolon
f984ecc5d7 Merge branch 'queue-cup-crash-fix-please' into 'master'
Fix crash when trying to queue cup while highlighting an empty square.

Closes #377

See merge request kart-krew-dev/ring-racers!71
2025-10-25 19:07:30 -05:00
Eidolon
4c2e540451 Merge branch 'chatclosefix' into 'master'
Fix softlocks surrounding chat input changes

Closes #373

See merge request kart-krew-dev/ring-racers!70
2025-10-25 19:06:27 -05:00
zander3312
59830a4ff0 Fix softlocks surrounding chat input changes 2025-10-25 19:06:26 -05:00
Antonio Martinez
af61408029 Set short fuse on "ring burn" caltrops 2025-10-25 20:03:56 -04:00
Antonio Martinez
668072c285 Significantly more active Speed Assist in teamplay 2025-10-25 19:56:38 -04:00
FreakyMutantMan
687bfb0e1d Disable overtime barrier animation/flashing when reducevfx is enabled. 2025-10-23 23:12:36 -07:00
Oni VelocitOni
121ac80b43 Merge branch 'fix-eggmark-burst' into 'master'
Fix eggmark bail occuring when last roulette was eggmark

Closes ring-racers#379 and ring-racers#384

See merge request kart-krew-dev/ring-racers-internal!2968
2025-10-24 04:11:58 +00:00
Oni VelocitOni
c9dce813e3 Merge branch 'tripwire-speed-reflect' into 'master'
Lower tripwire unstuck threshold (faster)

See merge request kart-krew-dev/ring-racers-internal!2967
2025-10-24 04:11:23 +00:00
Antonio Martinez
e6b21388bd Fix eggmark bail occuring when last roulette was eggmark 2025-10-22 18:35:31 -04:00
Antonio Martinez
7ac5a45979 Lower tripwire unstuck threshold (faster) 2025-10-22 17:52:13 -04:00
FreakyMutantMan
ea8acf33aa Fix crash when trying to queue cup while highlighting an empty square. 2025-10-22 11:20:32 -07:00
Eidolon
add76b17aa Update modversion for rc8/2.4 final 2025-10-21 20:47:53 -05:00
Eidolon
ba8bbc643c Update hashes 2025-10-21 20:09:21 -05:00
Eidolon
9087914dca Update hashes 2025-10-21 19:55:49 -05:00
Eidolon
f0f14ae91e Add 2x tripwire texture 2025-10-21 19:54:24 -05:00
Gunla
b10b845a05 RC7 Asset Hashes 2025-10-22 00:51:54 +00:00
Eidolon
8a55463587 Merge branch 'real-shorter-shoe' into 'master'
Actually shorten Stone Shoe

See merge request kart-krew-dev/ring-racers-internal!2965
2025-10-21 19:45:23 -05:00
Eidolon
c2f68ba92b Merge branch 'no-bungee-items' into 'master'
No item usage on bungees

See merge request kart-krew-dev/ring-racers-internal!2964
2025-10-21 19:44:57 -05:00
Eidolon
5b0351524f Merge branch 'addons-repair' into 'master'
Addons repair

Closes ring-racers#177 and ring-racers#172

See merge request kart-krew-dev/ring-racers-internal!2966
2025-10-21 19:39:47 -05:00
Eidolon
3e058ed7cf Merge branch 'retune-amps' into 'master'
Retune stat-based amp gains

See merge request kart-krew-dev/ring-racers-internal!2961
2025-10-21 19:34:59 -05:00
Eidolon
c42de4ec8c in lieu of a case-insensitive startswith 2025-10-21 19:31:12 -05:00
Antonio Martinez
046afb223d Actually shorten Stone Shoe 2025-10-21 16:17:16 -04:00
toaster
35da317d62 Don't send a netxcmd when using addfile outside of netgame
Was supposed to be happening already, but `multiplayer` is a useless variable...
2025-10-21 20:48:22 +01:00
toaster
2f189ca6f0 Rewind W_VerifyNMUSlumps file handle for PK3, too (resolves kart-krew-dev/ring-racers#177) 2025-10-21 20:46:00 +01:00
toaster
5a622e6ce0 Single period for tooltip for Addons case sensitivity (resolves kart-krew-dev/ring-racers#172) 2025-10-21 20:22:30 +01:00
Eidolon
3d5639c864 Merge public master 2025-10-21 12:06:48 -05:00
Eidolon
7491e40e0f Merge branch 'acs-playerrealname' into 'master'
Add PlayerSkinRealName as an ACS function

See merge request kart-krew-dev/ring-racers!13
2025-10-21 11:53:39 -05:00
Frivolous Aqua
aef864345f Add PlayerSkinRealName as an ACS function 2025-10-21 11:53:39 -05:00
Antonio Martinez
07f80f05df No item usage on bungees 2025-10-21 00:20:29 -04:00
Eidolon
c73c02aac9 Merge branch 'tripwire-texture-swap' into 'master'
Tripwire texture swap

See merge request kart-krew-dev/ring-racers-internal!2950
2025-10-20 18:33:28 -05:00
Ashnal
f09950ddd5 Tripwire texture swap 2025-10-20 18:33:28 -05:00
Eidolon
70675476e5 Merge branch 'fix-defensive-overdrive' into 'master'
Don't unset Overdrive leniency after auto Overdrive

See merge request kart-krew-dev/ring-racers-internal!2963
2025-10-20 18:24:33 -05:00
Eidolon
68413fde44 Merge branch 'rewind-double' into 'master'
Demo rewind doubled to 10s

See merge request kart-krew-dev/ring-racers-internal!2960
2025-10-20 18:23:06 -05:00
Eidolon
0b841b486f Merge branch 'hyuu-ritalin' into 'master'
Leader-penalty counter

See merge request kart-krew-dev/ring-racers-internal!2958
2025-10-20 18:22:54 -05:00
Eidolon
c009236107 Merge branch 'bot-turns' into 'master'
IMMEDIATELY reduce bot rubberbanding when cornering

See merge request kart-krew-dev/ring-racers-internal!2955
2025-10-20 18:20:34 -05:00
Eidolon
2928f84d9a Merge branch 'replay-prefix-cleanup' into 'master'
M_GetRecordMode

See merge request kart-krew-dev/ring-racers-internal!2959
2025-10-20 18:19:47 -05:00
Eidolon
09c6ee99f2 Merge branch 'fix-botscanvote' into 'master'
Fix map voting/striking for bots

Closes ring-racers#333

See merge request kart-krew-dev/ring-racers-internal!2949
2025-10-20 18:18:06 -05:00
Eidolon
3244e42177 Merge branch 'attenuating-spikes' into 'master'
Less spike softlock (resolves ring-racers#65)

Closes ring-racers#65

See merge request kart-krew-dev/ring-racers-internal!2953
2025-10-20 18:15:22 -05:00
Eidolon
a1e903fc72 Merge public master 2025-10-20 16:59:53 -05:00
Eidolon
fa8c2aac86 Fix incorrect ACS MusicRemap tune check 2025-10-20 16:57:02 -05:00
Antonio Martinez
d0938e1dc9 Don't unset Overdrive leniency after auto Overdrive 2025-10-20 16:46:09 -04:00
AJ Martinez
537a44871a Revert "Don't unset Overdrive leniency after auto Overdrive"
This reverts commit 71a1252ec5.
2025-10-20 16:45:35 -04:00
Antonio Martinez
71a1252ec5 Don't unset Overdrive leniency after auto Overdrive 2025-10-20 16:44:54 -04:00
Skirlez
4bb035c7a5 Fixed crash when sending a max character message 2025-10-20 22:54:26 +03:00
Eidolon
131ce41657 Merge public master 2025-10-20 14:36:42 -05:00
Eidolon
f7afea7abb Merge branch 'queue-cup' into 'master'
Add ability to queue all maps in a cup for netgames and local matches by pressing Action on cup select.

See merge request kart-krew-dev/ring-racers!11
2025-10-20 14:24:16 -05:00
Freaky Mutant Man
188d168ace Add ability to queue all maps in a cup for netgames and local matches by pressing Action on cup select. 2025-10-20 14:24:16 -05:00
Eidolon
66a7f40800 Merge branch 'expAmpLuaFuncs' into 'master'
Expose Exp/Amp-related functions to Lua

See merge request kart-krew-dev/ring-racers!66
2025-10-20 14:09:54 -05:00
JugadorXEI
114b01a516 Expose Exp/Amp-related functions to Lua 2025-10-20 14:09:54 -05:00
Eidolon
17ff0fea89 Merge branch 'profiledefault' into 'master'
Add profile color and followercolor to Default color rotation on character select screen

See merge request kart-krew-dev/ring-racers!34
2025-10-20 14:04:06 -05:00
zander3312
17556495f6 Add profile color and followercolor to Default color rotation on character select screen 2025-10-20 14:04:05 -05:00
Eidolon
93918b7bf2 Merge branch 'grandprixinfo-lua' into 'master'
Expose multiple Grand Prix, cup and round queue related structs to Lua.

See merge request kart-krew-dev/ring-racers!39
2025-10-20 14:01:27 -05:00
Freaky Mutant Man
3dc57d5908 Expose multiple Grand Prix, cup and round queue related structs to Lua. 2025-10-20 14:01:27 -05:00
Eidolon
303401aea5 Merge branch 'allow-replay-saving-map-change' into 'master'
Save replay if map abruptly changes

Closes #316, #276, and #242

See merge request kart-krew-dev/ring-racers!63
2025-10-20 13:55:23 -05:00
skirlez
fda4e6542e Save replay if map abruptly changes 2025-10-20 13:55:23 -05:00
Eidolon
f67c53e130 Merge branch 'me-when-i-am-string-and-dancing' into 'master'
Fix inline `V_STRINGDANCE` (hex 0x02) in strings not resetting y offset

See merge request kart-krew-dev/ring-racers!65
2025-10-20 13:50:31 -05:00
Eidolon
2a7b4c1396 Merge branch 'eid-hyudoro-sonicboom' into 'master'
Don't play sonic boom sounds in hyudoro either

See merge request kart-krew-dev/ring-racers-internal!2962
2025-10-19 20:35:45 -05:00
Eidolon
feb9787187 Don't play sonic boom sounds in hyudoro either 2025-10-19 18:57:48 -05:00
Antonio Martinez
8194b0ee8d Amp stat stuff closer to old values in most cases 2025-10-19 19:05:00 -04:00
Antonio Martinez
653393e5a9 Retune stat-based amp gains 2025-10-19 19:03:05 -04:00
toaster
b7a50f1123 Demo rewind doubled to 10s
Got a lot of feedback over time that 5s was too little for how frequently you need to rewind to go back through an extended interaction. Probably a better minimum
2025-10-19 23:40:25 +01:00
Gunla
54e9534615 Merge branch 'eggmark-bail' into 'master'
No bailing Eggmark, 30% speed -> 45%

See merge request kart-krew-dev/ring-racers-internal!2957
2025-10-19 18:28:59 +00:00
toaster
151b91f204 M_GetRecordMode
Simplifies a lot of copypasted "modeprefix" evaluations into one simple call.
Only G_UpdateRecordReplays is seperate.
Resolves two issues:
- Guest replay ghosts have been broken for a while and nobody noticed (untracked)
- Cannot watch back hivolt replays (#1656)
In addition, makes it way easier to add new modeprefixes later.
2025-10-19 17:58:18 +01:00
toaster
cb48d53f02 Leader-penalty counter
Allows for penalising 1st in a positiondelay-friendly way.
Does not increment outside of circuit, with only one player, in Sealed Stars or Cooperative contexts.
Currently applies to Hyudoro only, since that one's *really* instant in terms of giving the frontrunner an inadvisable tool for single-tic position flickers.
2025-10-19 16:34:03 +01:00
Antonio Martinez
c224b38685 Instaexplode bail if eggmark is rolling OR counting 2025-10-18 18:22:52 -04:00
Eidolon
19600c2589 Merge branch 'encore-demap' into 'master'
More encore/tweak remapping limits

Closes #1520 and #1284

See merge request kart-krew-dev/ring-racers-internal!2954
2025-10-18 10:11:13 -05:00
Eidolon
f59dc1e3a2 Merge branch 'seperate-best-times' into 'master'
Resolve ring-racers#112

Closes ring-racers#112

See merge request kart-krew-dev/ring-racers-internal!2952
2025-10-18 10:10:47 -05:00
Eidolon
b8769f14de Merge branch 'eid-more-reducevfx' into 'master'
More reducevfx

See merge request kart-krew-dev/ring-racers-internal!2951
2025-10-18 10:10:05 -05:00
Antonio Martinez
725882ab76 No bailing Eggmark, 30% speed -> 45% 2025-10-18 06:12:22 -04:00
haya
5019203872 fix: inline string dance not resetting y offset 2025-10-18 10:46:55 +08:00
Antonio Martinez
773736da46 IMMEDIATELY reduce bot rubberbanding when cornering 2025-10-17 19:23:17 -04:00
Eidolon
b7437a6565 Merge public master 2025-10-17 15:50:53 -05:00
Eidolon
6fcfd452aa Merge branch 'chatclose' into 'master'
Improved netgame chat input eating

See merge request kart-krew-dev/ring-racers!40
2025-10-17 15:46:10 -05:00
zander3312
3e1311473d Improved netgame chat input eating 2025-10-17 15:46:09 -05:00
toaster
1737db47db Prevent encore/tweak remapping of:
- Flybot 767 (resolves #1520)
- Trick Charge (resolves #1284)
- MT_BLOCKRING, MT_BLOCKBODY
- Amps and EXP
- MT_AMPRING, MT_AMPBODY, MT_AMPAURA, MT_AMPBURST
- Sonic Boom
- MT_TRIPWIREOK, MT_TRIPWIRELOCKOUT
- GOT IT!
- Rainbow Dash Ring
- Adventure Air Booster
- CDSS1 UFO
- Follower Bubble overlay
- Powerup Aura
- Script Question-Mark (from hint ring)
- Ball Switch
2025-10-17 18:59:29 +01:00
toaster
65f388de3a Less spike softlock (resolves ring-racers#65)
- Less strength in the first place
- Attenuates strength on repeated pokes
- Always stumbles since that seemed to be what was happening previously
2025-10-17 18:18:05 +01:00
toaster
e11751ddf7 Resolve ring-racers#112 2025-10-17 12:53:17 +01:00
toaster
4faf85eab4 Fix code provided by ring-racers!51
It just straight up wasn't functional, and ERRORMODE pointed me to it
Make the provideable amount use INT32 so the max/min macros actually do something
(but also don't use nested min-maxes just to reduce reliance on macros)
2025-10-17 11:25:04 +01:00
AJ Martinez
d3163d73cf Edit Default.md 2025-10-17 10:05:32 +00:00
Eidolon
06cf1b914a Merge public master 2025-10-16 21:22:21 -05:00
Eidolon
3e185efa44 Don't flicker drift electricity with reducevfx 2025-10-16 20:54:25 -05:00
Eidolon
56533a1876 Use std::string_view::npos in EggTVData 2025-10-16 20:06:57 -05:00
Eidolon
d37590f84c Merge branch 'fix-eggtv-names-and-crash' into 'master'
Fix Egg TV replay names being wrong, fix crash if your replay name was 1 character

Closes #267 and #110

See merge request kart-krew-dev/ring-racers!64
2025-10-16 20:01:21 -05:00
skirlez
c40c9a87d3 Fix Egg TV replay names being wrong, fix crash if your replay name was 1 character 2025-10-16 20:01:21 -05:00
Eidolon
eaf2e34efb Make <150% sonic boom flash transparent instead in reducevfx 2025-10-16 17:45:37 -05:00
Eidolon
99542a5b00 Disable invinc sprite flicker, MT_INVULNFLASH in reducevfx 2025-10-16 16:44:12 -05:00
SteelT
7e618b888e Fix bot voting being done under the context of human players 2025-10-15 23:52:20 -04:00
Eidolon
507a4b6c91 Fix unintended ternary bad parse 2025-10-15 22:11:30 -05:00
Eidolon
fd248e7e58 Merge public master 2025-10-15 22:10:08 -05:00
Ashnal
2fe37dc996 Merge branch 'insecticide' into 'master'
Immediately disable tether when holding completed Insta-Whip charge

See merge request kart-krew-dev/ring-racers-internal!2942
2025-10-16 03:00:09 +00:00
Ashnal
bfa4b11b6d Merge branch 'eid-more-vfx-reductions' into 'master'
Reduce invinc rainbow, grow/shrink, ring boost, countdown flashing in reducevfx

See merge request kart-krew-dev/ring-racers-internal!2944
2025-10-16 02:58:40 +00:00
Eidolon
1d3eda5926 Merge branch '309-fix' into 'master'
Resolved Issue #309 by Detecting Overflows & Underflows in Set Instructions to p->itemAmount and p->backupItemAmount

Closes #309

See merge request kart-krew-dev/ring-racers!51
2025-10-15 21:58:08 -05:00
SpringEThing
2ddc4c4867 Resolved Issue #309 by Detecting Overflows & Underflows in Set Instructions to p->itemAmount and p->backupItemAmount 2025-10-15 21:58:08 -05:00
Ashnal
e6da621dec Merge branch 'no-startline-in-special' into 'master'
No start awards in Special

See merge request kart-krew-dev/ring-racers-internal!2941
2025-10-16 02:56:44 +00:00
Ashnal
7f568779d8 Merge branch 'fix-tox-bot-amps' into 'master'
PvPAmpReward: always award at least 1 amp

See merge request kart-krew-dev/ring-racers-internal!2945
2025-10-16 02:55:38 +00:00
Ashnal
3befb83abf Merge branch 'amp-sound' into 'master'
Play amp sounds at player mo

Closes ring-racers#317

See merge request kart-krew-dev/ring-racers-internal!2946
2025-10-16 02:54:57 +00:00
Ashnal
d5154314e5 Merge branch 'goner-photosensitivity-brake' into 'master'
Photosensitivity warning is just informational now

See merge request kart-krew-dev/ring-racers-internal!2943
2025-10-16 02:53:36 +00:00
Ashnal
bbe55cda4b Photosensitivity warning is just informational now 2025-10-16 02:53:35 +00:00
Ashnal
3b0e3ec75c Merge branch 'orbinaut-waterski-new' into 'master'
orbinaut waterski is now based on owner waterski at the time of throw

See merge request kart-krew-dev/ring-racers-internal!2940
2025-10-16 02:53:18 +00:00
Ashnal
3cadaf70cc Merge branch 'no-hyu-clash' into 'master'
Hyudoro doesn't clash

Closes ring-racers#357

See merge request kart-krew-dev/ring-racers-internal!2947
2025-10-16 02:48:17 +00:00
Ashnal
3150c1f62e Merge branch 'reflected-item-fix' into 'master'
droptarget reflected items are dangerous to the thower again

See merge request kart-krew-dev/ring-racers-internal!2948
2025-10-16 02:47:28 +00:00
Eidolon
15413bf6d0 Merge branch 'fix-snatch-deployed-edgecase' into 'master'
Don't move backup item into main slot if player has item deployed

See merge request kart-krew-dev/ring-racers!59
2025-10-15 21:39:10 -05:00
skirlez
90ec96a2b0 Don't move backup item into main slot if player has item deployed 2025-10-15 21:39:10 -05:00
Eidolon
50d83e4b6d Merge branch 'fix-bot-replacement-negative-points' into 'master'
Fix replacement bot in last place keeping negative points from previous bot

See merge request kart-krew-dev/ring-racers!61
2025-10-15 21:36:12 -05:00
Superstarxalien
6182b83518 Fix replacement bot in last place keeping negative points from previous bot 2025-10-15 21:36:12 -05:00
Eidolon
6fa09928c8 Merge branch 'tune-reset' into 'master'
Prevent non-dynamic tunes remapped by ACS from remaining remapped after map ends.

See merge request kart-krew-dev/ring-racers!24
2025-10-15 21:28:49 -05:00
Freaky Mutant Man
9fb3719a8d Prevent non-dynamic tunes remapped by ACS from remaining remapped after map ends. 2025-10-15 21:28:48 -05:00
Eidolon
a02f1f7506 Merge branch 'fixMapDementia' into 'master'
Fix map vote dementia

See merge request kart-krew-dev/ring-racers!60
2025-10-15 21:19:41 -05:00
JugadorXEI
3425727ca6 Fix map vote dementia 2025-10-15 21:19:41 -05:00
Ashnal
0aad29ff68 droptarget reflected items are dangerous to the thower again 2025-10-15 20:07:47 -04:00
Antonio Martinez
83a0ca6a1f Hyudoro doesn't clash 2025-10-15 02:01:12 -04:00
Antonio Martinez
c7d137de5c Play amp sounds at player mo 2025-10-14 06:13:03 -04:00
Antonio Martinez
78e4724e2d PvPAmpReward: always award at least 1 amp 2025-10-14 03:31:31 -04:00
Eidolon
7e0fa35b7f Reduce invinc rainbow, grow/shrink, ring boost flashing 2025-10-13 21:13:29 -05:00
Antonio Martinez
71dc52d732 Immediately cut tether when completing Insta-Whip charge 2025-10-13 06:11:50 -04:00
Antonio Martinez
14c82a9f5a No start awards in Special 2025-10-13 01:36:42 -04:00
Ashnal
d782a6fdb7 orbinaut waterski is now based on owner waterski at the time of throw 2025-10-13 01:26:38 -04:00
Eidolon
2270813eee Bump modversion for 2.4 rc7 2025-10-12 19:28:24 -05:00
Eidolon
7a40d3b79f Merge branch 'jawz-adjustments' into 'master'
Jawz backthrow is viable

See merge request kart-krew-dev/ring-racers-internal!2939
2025-10-12 19:01:18 -05:00
Oni VelocitOni
a9fdc85b00 Jawz backthrow is viable 2025-10-12 19:01:18 -05:00
Eidolon
c24588a593 Fix indentation of src/objects/exp.c 2025-10-12 18:36:20 -05:00
Oni VelocitOni
a91e62029a Merge branch 'exp-local-only-sfx' into 'master'
Only play EXP sound for yourself

See merge request kart-krew-dev/ring-racers-internal!2936
2025-10-12 23:31:30 +00:00
Eidolon
1f3eef72c7 Merge branch 'fix-subsonic-proration-flash' into 'master'
Subsonic's red flashing matches new default race threshold

See merge request kart-krew-dev/ring-racers-internal!2934
2025-10-12 18:29:24 -05:00
Eidolon
2769037787 Merge branch 'spb-starts-closerange-chase-from-further-away' into 'master'
SPB Activation Range is doubled

See merge request kart-krew-dev/ring-racers-internal!2935
2025-10-12 18:28:36 -05:00
Eidolon
9ecde56ca4 Merge branch 'visual-burn' into 'master'
Ring burn conveyance

See merge request kart-krew-dev/ring-racers-internal!2937
2025-10-12 18:27:40 -05:00
Eidolon
781b1a07a8 Revert "Merge branch 'jawz-adjustments' into 'master'"
This reverts commit 73ff24ff1b, reversing
changes made to 40968abdc3.
2025-10-12 18:25:16 -05:00
Eidolon
73ff24ff1b Merge branch 'jawz-adjustments' into 'master'
Jawz Target Speed Adjustments

See merge request kart-krew-dev/ring-racers-internal!2938
2025-10-12 18:23:34 -05:00
Gunla
40968abdc3 2.4 RC6 Asset Hashes 2025-10-12 22:58:02 +00:00
VelocitOni
c48500e453 Minimum backthrow speed + Slows down half as much when in range
Will be 120% of owner's speed @ minimum during backthrow; and now jawz slows down more when in range (healthier chases)
2025-10-12 18:51:52 -04:00
Antonio Martinez
a35121716f Ring burn conveyance 2025-10-12 18:35:01 -04:00
VelocitOni
e15ab7ab0b Move local display player check
Oops, make sure EXP obj is actually removed again.
2025-10-12 18:16:30 -04:00
VelocitOni
a4c7faf34a Backthrown Jawz now keeps up
Returns at 120% of owner's speed
2025-10-12 18:12:54 -04:00
VelocitOni
9080d932f5 Only play EXP sound for yourself 2025-10-12 16:59:40 -04:00
VelocitOni
fc8e1f5f0c SPB Activation Range is doubled
Accounts for moving twice as fast, should no longer smack 1st with sliptide dust from activation before on-screen
2025-10-12 16:32:56 -04:00
VelocitOni
4f5e9dbaa3 Sonic Boom floor is now 175%
This might've got missed when it was raised, the floor was meant to be 175%, not 180%. Just a bit easier for drowners.
2025-10-12 16:24:11 -04:00
VelocitOni
6fb3de555d Subsonic flashing matches new default race threshold
Noticed in all videos of RC5 that it was flashing at above 200%, when Sonic Boom was raised to 225% in race
2025-10-12 16:23:17 -04:00
Eidolon
5284dba540 Merge branch 'no-respawn-sonicboom-fx' into 'master'
Don't do sonicboom fx during respawn/lightsnake

See merge request kart-krew-dev/ring-racers-internal!2932
2025-10-12 15:06:58 -05:00
Eidolon
02a1a5576a Merge remote-tracking branch 'public/master' 2025-10-12 14:48:16 -05:00
Eidolon
1584e8a134 Merge branch 'shrink-patchcvt-alloc' into 'master'
Calculate staging buffer maximum size in Picture_Convert

See merge request kart-krew-dev/ring-racers-internal!2933
2025-10-12 14:45:58 -05:00
Eidolon
5834f45678 Fix typo in Accessibility menu description 2025-10-12 14:40:52 -05:00
Eidolon
a28fd6c3dd Calculate staging buffer maximum size in Picture_Convert 2025-10-12 14:28:06 -05:00
Eidolon
44ebf73464 Don't do sonicboom fx during respawn/lightsnake 2025-10-12 13:15:39 -05:00
Eidolon
36a0331c8b Merge branch 'no-sonicboom-sounds-invinc-grow' into 'master'
Don't play sonic boom sounds in invinc or grow state

See merge request kart-krew-dev/ring-racers-internal!2931
2025-10-12 13:11:13 -05:00
Eidolon
9a2b054ca9 Don't play sonic boom sounds in invinc or grow state 2025-10-12 12:56:21 -05:00
Eidolon
4d5099070b Merge remote-tracking branch 'public/master' 2025-10-12 12:26:11 -05:00
Eidolon
1c8bf6987d Merge branch 'versus-hidden-rank' into 'master'
Make hidden rank system compatible with any gametype in the special stage slot.

See merge request kart-krew-dev/ring-racers!31
2025-10-12 12:23:20 -05:00
Freaky Mutant Man
02a889c265 Make hidden rank system compatible with any gametype in the special stage slot. 2025-10-12 12:23:20 -05:00
Eidolon
2f19edabec Merge remote-tracking branch 'public/master' 2025-10-12 11:30:42 -05:00
Eidolon
81f54b2ef3 Merge branch 'fixSetNameForBot' into 'master'
Clamp and validate names in K_SetNameForBot correctly for Lua (fixes #238)

Closes #238

See merge request kart-krew-dev/ring-racers!38
2025-10-12 11:27:19 -05:00
AJ Martinez
6cd9746c4b Merge branch 'no-neostart-in-duel' into 'master'
Whoops, use the right boost type (and not in Duel)

See merge request kart-krew-dev/ring-racers-internal!2930
2025-10-11 07:38:58 +00:00
Antonio Martinez
2c4c94d80d Whoops, use the right boost type (and not in Duel) 2025-10-11 03:38:33 -04:00
AJ Martinez
c8c56acd65 Merge branch 'start-award' into 'master'
Start reward rework

See merge request kart-krew-dev/ring-racers-internal!2925
2025-10-11 07:32:37 +00:00
AJ Martinez
58b158ffab Merge branch 'better-burn' into 'master'
Improve burning rings from payout

See merge request kart-krew-dev/ring-racers-internal!2919
2025-10-11 07:32:23 +00:00
Antonio Martinez
4ea782c493 Add momentboost instantly (are we seriously out of mobj properties?) 2025-10-11 02:46:54 -04:00
AJ Martinez
0bcadb7ffe Merge branch 'whip-warning' into 'master'
Whip awareness

See merge request kart-krew-dev/ring-racers-internal!2929
2025-10-11 06:46:03 +00:00
AJ Martinez
45a2470479 Merge branch 'm30-profile' into 'master'
Add 8BitDo vanilla M30 control layout

See merge request kart-krew-dev/ring-racers-internal!2928
2025-10-10 22:38:06 +00:00
AJ Martinez
3f4476ea77 Merge branch 'fix-lonely-weakitem-rejection' into 'master'
Roulette: fix lonely weakitem rejection when near leader

See merge request kart-krew-dev/ring-racers-internal!2927
2025-10-10 22:37:49 +00:00
AJ Martinez
22c145ac28 Merge branch 'fast-rc6-balance' into 'master'
Fast rc6 balance

See merge request kart-krew-dev/ring-racers-internal!2926
2025-10-10 22:37:37 +00:00
Eidolon
0414617e92 Merge branch 'luaPlayerLibNonsense' into 'master'
Lua: expose various members from player_t and others into Lua

See merge request kart-krew-dev/ring-racers!4
2025-10-10 16:51:35 -05:00
JugadorXEI
c79b8ea9ba Lua: expose various members from player_t and others into Lua 2025-10-10 16:51:34 -05:00
Antonio Martinez
d143128305 Whip awareness 2025-10-10 16:33:21 -04:00
Antonio Martinez
a3c64581cf Add 8BitDo vanilla M30 control layout 2025-10-09 20:11:38 -04:00
Antonio Martinez
a081f72f6d Roulette: fix lonely weakitem rejection when near leader 2025-10-09 14:34:28 -04:00
Antonio Martinez
5f76a74c37 Small nudge down 2025-10-09 03:56:16 -04:00
Antonio Martinez
78e4943ff9 Change momentboost to a ringboost base speed modifier, explicitly drains ringboost while active 2025-10-09 03:50:54 -04:00
Antonio Martinez
fb63ce7304 Fuck it, use a boost type 2025-10-08 22:22:03 -04:00
AJ Martinez
98d90e3501 Merge branch 'no-contest-exp' into 'master'
No contest exp fixes

See merge request kart-krew-dev/ring-racers-internal!2924
2025-10-09 01:40:22 +00:00
Antonio Martinez
225c34d2dc Toxomister triggers defensive Overdrive 2025-10-07 01:08:16 -04:00
Antonio Martinez
5b1e7197c2 Toxomister amps 3 -> 2 2025-10-07 01:01:09 -04:00
Antonio Martinez
61d9722214 Stone Shoe links 8 -> 5 2025-10-07 00:59:01 -04:00
Antonio Martinez
668a2d8d31 WIP: Start reward rework 2025-10-07 00:54:35 -04:00
Gunla
ee8ec81da4 Merge branch 'fix-waterskii' into 'master'
Waterskii fixes

See merge request kart-krew-dev/ring-racers-internal!2918
2025-10-07 01:38:31 +00:00
Gunla
81135614ff Merge branch 'bubble-fuck-off' into 'master'
Bubble Shield pings off walls

See merge request kart-krew-dev/ring-racers-internal!2922
2025-10-07 01:35:15 +00:00
Gunla
0996610995 Merge branch 'frantic-crystal' into 'master'
franticitems now has a purple crystal

See merge request kart-krew-dev/ring-racers-internal!2923
2025-10-07 01:26:25 +00:00
Eidolon
9e73292a67 Remove debug print 2025-10-06 19:15:05 -05:00
Ashnal
644ead272b lets not do that actually, as a penalty 2025-10-06 18:48:50 -04:00
Ashnal
9e0920f45e properly calculate exp for remaining grading points when a player no contests 2025-10-06 18:36:33 -04:00
Ashnal
0da0cf4909 last place can get points now 2025-10-06 18:16:03 -04:00
Eidolon
8ed4c1c081 Don't show prerelease message when taking thumbnails 2025-10-06 16:11:59 -05:00
Eidolon
d883e54886 Merge remote-tracking branch 'public/master' 2025-10-06 15:58:23 -05:00
Eidolon
f7e819079c Merge branch 'frantic-pause-display' into 'master'
Display whether Frantic Items is on alongside Gear speed on pause menu.

See merge request kart-krew-dev/ring-racers!55
2025-10-06 15:54:22 -05:00
Freaky Mutant Man
f18022e9c8 Display whether Frantic Items is on alongside Gear speed on pause menu. 2025-10-06 15:54:22 -05:00
Eidolon
f5e8f24a3c Merge remote-tracking branch 'public/master' 2025-10-06 15:48:25 -05:00
Eidolon
499fccf061 Merge branch 'reducevfx-characterselect' into 'master'
Disable character select cursor flashing when reducevfx is on.

See merge request kart-krew-dev/ring-racers!50
2025-10-06 15:47:27 -05:00
Freaky Mutant Man
89df4da48c Disable character select cursor flashing when reducevfx is on. 2025-10-06 15:47:27 -05:00
Eidolon
c90947e3ce Merge remote-tracking branch 'public/master' 2025-10-06 15:14:47 -05:00
Eidolon
7f8b5ec43e Merge branch 'focusvoice' into 'master'
Include voice in tabbed out audio settings (fixes #37)

Closes #37

See merge request kart-krew-dev/ring-racers!44
2025-10-06 15:12:59 -05:00
zander3312
e134b6609f Include voice in tabbed out audio settings (fixes #37) 2025-10-06 15:12:59 -05:00
Eidolon
6b95e3e218 Merge branch 'fix-shuffleloser-spec' into 'master'
Don't spectate player with shuffleloser on if a player spectated mid-race

Closes #310

See merge request kart-krew-dev/ring-racers!52
2025-10-06 14:49:35 -05:00
Eidolon
cb9e074bda Merge remote-tracking branch 'public/master' 2025-10-06 14:46:30 -05:00
Eidolon
1b3012604c Merge branch 'gp-race-or-battle-decider' into 'master'
Add check to G_GPCupIntoRoundQueue to ensure bonus game maps with both Race and Battle TOLs are treated as Battle.

See merge request kart-krew-dev/ring-racers!49
2025-10-06 14:42:11 -05:00
Eidolon
4d4738487a Merge branch 'ground-follower-fix' into 'master'
Fix ground followers phasing through FOFs

See merge request kart-krew-dev/ring-racers!56
2025-10-06 14:13:15 -05:00
Wumbo
7d6289817d Fix ground followers phasing through FOFs 2025-10-06 11:43:59 -04:00
Ashnal
43b5117416 add comment 2025-10-05 23:16:27 -04:00
Ashnal
b2d668f015 Add half sec tiregrease to zippers to facilitate waterski at high tripwire speed thresholds 2025-10-05 23:14:55 -04:00
Ashnal
2551fd3751 use base speed instead of triupwire speed for pre-boost waterskii cutoff 2025-10-05 22:42:42 -04:00
Ashnal
f692f5f9e7 formatting cleanup 2025-10-05 22:04:23 -04:00
Ashnal
ca68ddd35b fix incorrect dereference 2025-10-05 21:59:43 -04:00
Skirlez
3802f61dc1 Don't spectate player with shuffleloser on if the other player spectated 2025-10-04 23:21:52 +03:00
Ashnal
1d19eb7210 franticitems now has a purple crystal 2025-10-03 19:26:05 -04:00
JugadorXEI
9921d0b427 Ensure bot names set by Lua's K_SetNameForBot are good 2025-10-03 21:19:25 +02:00
FreakyMutantMan
6780b5f607 Add checks to G_GPCupIntoRoundQueue to account for potential multi-gametype special stage maps (in order of Special>Versus>guess). 2025-10-02 16:28:59 -07:00
Oni VelocitOni
0369bc01fd Merge branch 'midtexinviswall' into 'master'
Adds ML_MIDTEXINVISWALL linedef flag

See merge request kart-krew-dev/ring-racers-internal!2921
2025-10-02 22:37:54 +00:00
Eidolon
494f4c1641 and this whitespace 2025-10-02 12:33:43 -05:00
Eidolon
48e60648f6 Fix clang-cl compilation from showgremlins patch 2025-10-02 12:33:24 -05:00
VelocitOni
e64ff44a39 Air failsafe boost prevention
AiAi burned to ash
2025-10-02 00:56:39 -04:00
VelocitOni
5c9730bec8 Make it work
Decided to put it in P_BouncePlayerMove, + some flourish
2025-10-02 00:44:52 -04:00
VelocitOni
cb3c370e33 Bubble wall bounce tumble
(does nothing yet)
2025-10-01 22:44:56 -04:00
Ashnal
2b075407a2 Merge branch 'fix-final-check-fuckery' into 'master'
Fix final checkpoint granting way too much EXP, especially in low placements

See merge request kart-krew-dev/ring-racers-internal!2920
2025-10-02 01:44:16 +00:00
Ashnal
0418507f5a Adds ML_MIDTEXINVISWALL linedef flag
A linedef with a midtexture and the flag set will have its collision extended to the ceiling, invisible wall style
Tripwires have this behavior by default, and the flag inverts it
2025-10-01 20:46:41 -04:00
Antonio Martinez
6c980807c3 Sony Releases Stupid Piece Of Shit That Doesn't Fucking Work 2025-10-01 19:35:32 -04:00
Antonio Martinez
975b2cce98 Improve burning rings from payout 2025-10-01 17:57:08 -04:00
Eidolon
8744023a87 annoying 2025-10-01 16:35:48 -05:00
Eidolon
6aee524ace sse2 again? earth to CI 2025-10-01 16:26:50 -05:00
Eidolon
046564eece Enable sse2 (as was intended) on IA-32 2025-10-01 15:52:48 -05:00
VelocitOni
c7c8ee3c7a Demo compatability for waterskiing
Updated DEMOVERSION
2025-10-01 15:36:13 -04:00
Eidolon
341c62cc07 Merge branch 'denormals-are-a-fuck' into 'master'
Ignore float denormals on ia32/64 for voice and sound

Closes ring-racers#283

See merge request kart-krew-dev/ring-racers-internal!2917
2025-10-01 14:25:16 -05:00
VelocitOni
f0df4990ae Waterskii fixes
Check for if you're at half sonic boom later (order of operations), make sure sonic boom is always assumed to be 200% max to just make the game continue to work
2025-10-01 15:10:03 -04:00
Eidolon
9ba4cccc5a Ignore float denormals on ia32/64 for voice and sound 2025-10-01 13:01:08 -05:00
FreakyMutantMan
2989d3564e Add check to GP_GPCupIntoRoundQueue to ensure maps with both Race and Battle TOL flags are properly accounted for in bonus game queue. 2025-09-30 21:22:57 -07:00
Eidolon
92c117d186 remove more g++ warning flags 2025-09-30 21:09:10 -05:00
Eidolon
c8f986db4d Remove unintended g++ warnings 2025-09-30 20:18:47 -05:00
Eidolon
0734ffc201 Start MODVERSION 9 RC6 2025-09-30 20:12:04 -05:00
Eidolon
fa787c4e8f Merge remote-tracking branch 'public/master' 2025-09-30 17:37:01 -05:00
Gunla
511d9b083b 2.4 RC5 Hashes 2025-09-30 22:36:34 +00:00
Eidolon
6f61cfaefa Merge branch 'shitty-sign-markedfordeath' into 'master'
Add ability for shitty signs to display when 1st place finishes while markedfordeath

See merge request kart-krew-dev/ring-racers!28
2025-09-30 17:16:26 -05:00
Freaky Mutant Man
932deb0b3f Add ability for shitty signs to display when 1st place finishes while markedfordeath 2025-09-30 17:16:26 -05:00
Eidolon
2309d11274 Merge branch 'fixUnfrozenTickers' into 'master'
Freeze finish line when level is frozen (fixes #237)

Closes #237

See merge request kart-krew-dev/ring-racers!37
2025-09-30 17:13:43 -05:00
JugadorXEI
a9fe850eda Freeze finish line when level is frozen (fixes #237) 2025-09-30 17:13:43 -05:00
Eidolon
210ec5ee63 Merge branch 'classrnochal' into 'master'
Remove ability for Class R to clear Time Attack challenges

See merge request kart-krew-dev/ring-racers!41
2025-09-30 17:11:29 -05:00
Eidolon
cbb99ca79b Merge branch 'reducevfx-checkwarning' into 'master'
Disable flashing of CHECK warnings when reducevfx is on.

See merge request kart-krew-dev/ring-racers!43
2025-09-30 17:09:47 -05:00
Freaky Mutant Man
4ff1f38877 Disable flashing of CHECK warnings when reducevfx is on. 2025-09-30 17:09:46 -05:00
Eidolon
78b11e8306 Merge branch 'bailhornset' into 'master'
Bail horn respects follower horn settings (fixes #251)

Closes #251

See merge request kart-krew-dev/ring-racers!45
2025-09-30 17:06:27 -05:00
zander3312
eb90b28c12 Bail horn respects follower horn settings (fixes #251) 2025-09-30 17:06:27 -05:00
Eidolon
8bf15ef6f1 Merge branch 'insaneAsylumGremlin' into 'master'
Add workaround for gremlin'd wall collisions

See merge request kart-krew-dev/ring-racers!35
2025-09-30 17:05:35 -05:00
JugadorXEI
ef4ef91fed Add workaround for gremlin'd wall collisions 2025-09-30 17:05:35 -05:00
Eidolon
abbc6b03d4 Merge branch 'creditsmusic' into 'master'
Menu music plays after credits (fixes #189)

Closes #189

See merge request kart-krew-dev/ring-racers!48
2025-09-30 17:03:22 -05:00
zander3312
50f007b653 Menu music plays after credits (fixes #189) 2025-09-30 17:03:22 -05:00
Eidolon
11acb78875 Merge branch 'nogravbulbturbine' into 'master'
Removed nogravity flag on touching bulbs/turbines (fixes #245)

Closes #245

See merge request kart-krew-dev/ring-racers!46
2025-09-30 17:02:54 -05:00
zander3312
8363ead346 Removed nogravity flag on touching bulbs/turbines (fixes #245) 2025-09-30 17:02:54 -05:00
Antonio Martinez
32d03ccb1e go go gadget gameplay constants 2025-09-29 23:00:59 -04:00
Antonio Martinez
d5c4534d31 Marginal item power nudge 2025-09-29 18:26:46 -04:00
AJ Martinez
2d3e7ce049 Merge branch 'fix-rocket-bail' into 'master'
Really remove rocketsneaker while bailing

See merge request kart-krew-dev/ring-racers-internal!2914
2025-09-29 22:23:49 +00:00
AJ Martinez
14201c65aa Merge branch 'fix-damage-floor-invinc' into 'master'
Fix stumble behavior being used on non-stumble terrain

See merge request kart-krew-dev/ring-racers-internal!2913
2025-09-29 22:23:43 +00:00
AJ Martinez
093cdb1043 Merge branch 'slower-stone' into 'master'
Stone Shoe 80% -> 70% boostpower

See merge request kart-krew-dev/ring-racers-internal!2915
2025-09-29 22:23:36 +00:00
AJ Martinez
350cd423e4 Merge branch 'fix-debugitemodds' into 'master'
Fix debugitemodds displaying wrong odds

Closes ring-racers#227

See merge request kart-krew-dev/ring-racers-internal!2887
2025-09-29 22:23:29 +00:00
AJ Martinez
1d1e7d1741 Merge branch 'tripwire-deux' into 'master'
Race Tripwire 200% -> 250%, check larger scam window in larger games

See merge request kart-krew-dev/ring-racers-internal!2916
2025-09-29 22:23:22 +00:00
Antonio Martinez
59c4cfb2be Class R tripwire oopsie 2025-09-29 01:54:30 -04:00
Antonio Martinez
d3ac1a6c5e 200% tripwire in Tutorial / Easy 2025-09-29 01:19:56 -04:00
Antonio Martinez
60e65133e6 Race Tripwire 200% -> 250%, check larger scam window in larger games 2025-09-28 20:53:57 -04:00
Antonio Martinez
0badaed11d Stone Shoe 80% -> 70% boostpower 2025-09-28 20:33:55 -04:00
Antonio Martinez
53d71225b8 Really remove rocketsneaker while bailing 2025-09-28 20:24:41 -04:00
Antonio Martinez
80c0db9546 Fix stumble behavior being used on non-stumble terrain 2025-09-28 20:16:56 -04:00
AJ Martinez
06626c9b0d Merge branch 'staffsync-triage' into 'master'
Extended staffsync RNG/resync reporting

See merge request kart-krew-dev/ring-racers-internal!2912
2025-09-28 05:40:46 +00:00
Eidolon
0e46138a14 Fix ABI issue with skiprender 2025-09-28 00:00:21 -05:00
Antonio Martinez
ae0100ba05 Extended staffsync RNG/resync reporting 2025-09-27 23:09:52 -04:00
AJ Martinez
ab39175430 Merge branch 'fix-item-ties' into 'master'
Use cusval instead of cvmem to track item box break type (cvmem is used for VFX!)

Closes ring-racers#252

See merge request kart-krew-dev/ring-racers-internal!2910
2025-09-28 01:02:07 +00:00
AJ Martinez
9bdd01f5a6 Merge branch 'damaging-sector-stumble' into 'master'
Use damage stumble for stumble sectors / terrain again (allows DI)

See merge request kart-krew-dev/ring-racers-internal!2911
2025-09-28 01:02:00 +00:00
AJ Martinez
69e23ad50a Merge branch 'fix-lagless-sting' into 'master'
Fix hitlag from Ring Sting being zero

Closes #1666

See merge request kart-krew-dev/ring-racers-internal!2908
2025-09-28 01:01:48 +00:00
AJ Martinez
e3067e8a09 Merge branch 'staffsync-bodge' into 'master'
Disable PR_ITEM_DEBRIS detections in staffsync

See merge request kart-krew-dev/ring-racers-internal!2909
2025-09-28 00:38:57 +00:00
Antonio Martinez
3d16ecd7e9 Staffsync excludes many RNG classes 2025-09-27 20:38:42 -04:00
Antonio Martinez
bf901fddb3 Actually check the correct momentum, idiot 2025-09-27 06:11:34 -04:00
Antonio Martinez
140f9846aa Use damage stumble for stumble sectors / terrain again (allows DI) 2025-09-27 05:58:50 -04:00
Antonio Martinez
9297e3cdcb Use cusval instead of cvmem to track item box break type (cvmem is used for VFX!) 2025-09-27 02:58:22 -04:00
Antonio Martinez
7b10e4e2bd Largegamescaler slightly up 2025-09-26 23:40:16 -04:00
Antonio Martinez
667ad18339 Disable PR_ITEM_DEBRIS detections in staffsync 2025-09-26 23:35:31 -04:00
Antonio Martinez
5e44040ae8 Fix hitlag from Ring Sting being zero 2025-09-26 23:28:39 -04:00
AJ Martinez
55192eaf39 Merge branch 'fast-tripwire-entry' into 'master'
Fast Tripwire entry

See merge request kart-krew-dev/ring-racers-internal!2907
2025-09-26 22:42:52 +00:00
Antonio Martinez
d157076326 Fast Tripwire entry 2025-09-26 18:09:22 -04:00
AJ Martinez
8b86622218 Merge branch 'pain-with-gain' into 'master'
Remove ringboost only when taking non-stumble damage

Closes #1664

See merge request kart-krew-dev/ring-racers-internal!2903
2025-09-26 21:59:13 +00:00
AJ Martinez
5ead1e5964 Merge branch 'better-lightning-shield' into 'master'
Lightningcharge can punt, blocks

See merge request kart-krew-dev/ring-racers-internal!2906
2025-09-26 21:59:07 +00:00
AJ Martinez
d5fc805cbd Merge branch 'further-sting-leniency' into 'master'
Don't sting just after using rings

See merge request kart-krew-dev/ring-racers-internal!2905
2025-09-26 21:29:21 +00:00
Antonio Martinez
fbe2f9fd56 Lightningcharge can punt, blocks 2025-09-26 17:26:09 -04:00
AJ Martinez
7b4cf9a07c Merge branch 'no-fucking-mutibail-for-real' into 'master'
Cannot bail while bailing

Closes ring-racers#236

See merge request kart-krew-dev/ring-racers-internal!2896
2025-09-26 17:58:25 +00:00
AJ Martinez
d060df9bfe Merge branch 'clash-hitlag-deux' into 'master'
Reduce hitlag when punting hazards etc

Closes ring-racers#256

See merge request kart-krew-dev/ring-racers-internal!2898
2025-09-26 17:58:17 +00:00
AJ Martinez
a05a82de7b Merge branch 'skiprender' into 'master'
"skiprender" cvar (performance increase when fuzzing)

See merge request kart-krew-dev/ring-racers-internal!2901
2025-09-26 17:58:09 +00:00
AJ Martinez
cd038addd5 Merge branch 'proration-polish' into 'master'
Subsonic Adjustments

See merge request kart-krew-dev/ring-racers-internal!2886
2025-09-26 17:58:02 +00:00
Oni VelocitOni
8f4a698a35 Subsonic Adjustments 2025-09-26 17:58:02 +00:00
AJ Martinez
e7ee7ec9ce Merge branch 'allow-hitlag-explode' into 'master'
Fix Eggmark not activating on players in precisely timed hitlag

Closes ring-racers#259

See merge request kart-krew-dev/ring-racers-internal!2899
2025-09-26 17:57:53 +00:00
AJ Martinez
8b71cd9e82 Merge branch 'tutorial-password' into 'master'
Added password for unlocking all tutorials early

See merge request kart-krew-dev/ring-racers-internal!2880
2025-09-26 17:57:46 +00:00
AJ Martinez
3f8ee05db8 Merge branch 'acs-netlumps' into 'master'
ACS netlumps

See merge request kart-krew-dev/ring-racers-internal!2876
2025-09-26 17:57:39 +00:00
AJ Martinez
d55eab9748 Merge branch '99-laps' into 'master'
Duels end at 99 laps, high lapcount HUD safety

Closes ring-racers#107

See merge request kart-krew-dev/ring-racers-internal!2892
2025-09-26 17:57:29 +00:00
AJ Martinez
997f995ce9 Merge branch 'fix-mindelay-send' into 'master'
Fix mindelay wpnpref not being applied on join

Closes ring-racers#149

See merge request kart-krew-dev/ring-racers-internal!2890
2025-09-26 17:57:22 +00:00
AJ Martinez
bd4b3336bf Merge branch 'hell-respawn' into 'master'
Kill players who respawn at lethal threshold

Closes #1663

See merge request kart-krew-dev/ring-racers-internal!2900
2025-09-26 17:57:10 +00:00
AJ Martinez
a428811884 Merge branch 'acid-cancel-kickstart' into 'master'
Fix Acid Drop irregularities (multi-input, Kickstart, etc)

Closes ring-racers#181

See merge request kart-krew-dev/ring-racers-internal!2894
2025-09-26 17:57:04 +00:00
AJ Martinez
74ae7abd4c Merge branch 'eid-dumbass-titlescreen' into 'master'
Prevent 1-frame title screen when playing demos

Closes #1665

See merge request kart-krew-dev/ring-racers-internal!2904
2025-09-26 17:56:53 +00:00
Antonio Martinez
8649a66e08 Don't sting just after using rings 2025-09-26 13:52:42 -04:00
Eidolon
0c3906690d Merge branch 'eid-teamplay-demos-workaround' into 'master'
Workaround g_teamplay assigning teams erroneously in demos

Closes ring-racers#210

See merge request kart-krew-dev/ring-racers-internal!2902
2025-09-26 08:42:59 -05:00
Eidolon
8e4b690387 Prevent 1-frame title screen when playing demos
Nothing makes sense anymore

Fixes https://gitlab.com/kart-krew-dev/ring-racers-internal/-/issues/1665
2025-09-25 23:02:39 -05:00
Antonio Martinez
cfd8260762 Remove ringboost only when taking non-stumble damage 2025-09-25 23:17:19 -04:00
Eidolon
f2ab528062 Workaround g_teamplay assigning teams erroneously in demos
Fixes https://gitlab.com/kart-krew-dev/ring-racers/-/issues/210
2025-09-25 22:09:48 -05:00
Antonio Martinez
bf330bafcc Fix ringshooter death check to only activate if you are USING your ringshooter 2025-09-25 22:56:16 -04:00
Antonio Martinez
48e1ed5779 Don't die from Ring Shooter at -20 2025-09-25 21:58:45 -04:00
Antonio Martinez
5950298ac6 "skiprender" cvar (performance incerase when fuzzing) 2025-09-25 19:57:21 -04:00
Antonio Martinez
77768b5a68 Acid cancel last call 2025-09-25 19:47:36 -04:00
Antonio Martinez
c1a80e4b1b Kill players who die at lethal threshold 2025-09-25 19:15:46 -04:00
Antonio Martinez
65cf6edb93 Fix acid cancel oldbutton check 2025-09-25 18:45:11 -04:00
Eidolon
b746b1a0e4 Merge branch 'eid-battle-team-elim' into 'master'
Allow team victory by opposing team elimination in battle overtime

Closes ring-racers#204

See merge request kart-krew-dev/ring-racers-internal!2895
2025-09-25 17:04:06 -05:00
Antonio Martinez
b587b4b574 Fix Eggmark not activating on players in precisely timed hitlag 2025-09-25 18:02:19 -04:00
Eidolon
ddd48b72d7 Merge branch 'more-msvc' into 'master'
Add cpptrace in I_Error on windows, minidumps, stricter warnings, optimized drawers in debug

See merge request kart-krew-dev/ring-racers-internal!2881
2025-09-25 16:25:00 -05:00
Eidolon
94ef03dcd2 Add cpptrace in I_Error on windows, minidumps, stricter warnings, optimized drawers in debug 2025-09-25 16:08:09 -05:00
Antonio Martinez
a6f27a39e3 Overshield can punt 2025-09-25 16:49:11 -04:00
Antonio Martinez
22e7b5e8ad Reduce hitlag when punting hazards etc 2025-09-25 04:33:35 -04:00
Antonio Martinez
a31b4a2682 Cannot bail while bailing 2025-09-24 22:53:16 -04:00
Eidolon
c96e3b3cca Allow team victory by opposing team elimination in battle overtime 2025-09-24 21:49:19 -05:00
Antonio Martinez
766f34d4f5 Fix Kickstart being unable to Acid Drop with Strict Fastfall off 2025-09-24 22:41:42 -04:00
Eidolon
b7f8afd5ef Merge branch 'teamplay-monitor-items' into 'master'
Teamplay: Allow allies to pick up monitor paperitems

Closes ring-racers#217

See merge request kart-krew-dev/ring-racers-internal!2893
2025-09-24 21:36:15 -05:00
Antonio Martinez
6507984c22 Teamplay: Allow allies to pick up monitor paperitems 2025-09-24 22:25:20 -04:00
Antonio Martinez
3cc58d93f2 Whoops that's a testing define 2025-09-24 22:10:52 -04:00
Antonio Martinez
39c2779fb2 Duels end at 99 laps, high lapcount HUD safety 2025-09-24 22:09:43 -04:00
Eidolon
c1b22c0c73 Revert "Update vcpkg baseline"
This reverts commit b3a2cc2ea9.
2025-09-24 20:06:44 -05:00
Eidolon
dc1c3bec0f Merge branch 'eid-dequeue-once' into 'master'
Dequeue audio only once per frame, improve quality

Closes ring-racers#234

See merge request kart-krew-dev/ring-racers-internal!2889
2025-09-24 20:05:43 -05:00
Eidolon
e9906915b0 Calculate podium position for PODIUMCUP condition instead of using current player position
Fixes https://gitlab.com/kart-krew-dev/ring-racers/-/issues/253
2025-09-24 19:58:53 -05:00
AJ Martinez
8f213c7e1b Merge branch 'minor-stun-reduce' into 'master'
Min weight stun 10 sec -> 8 sec

See merge request kart-krew-dev/ring-racers-internal!2891
2025-09-24 21:34:35 +00:00
Antonio Martinez
cef307816d Min weight stun 10 sec -> 8 sec 2025-09-24 16:58:14 -04:00
Antonio Martinez
d69e667835 Fix mindelay wpnpref not being applied on join 2025-09-24 16:54:22 -04:00
Eidolon
b52e1cb61f Dequeue audio only once per frame, improve quality 2025-09-24 13:19:49 -05:00
AJ Martinez
fc4a2e9f80 Merge branch 'final-check-exp' into 'master'
"Final checkpoint" EXP bonus

See merge request kart-krew-dev/ring-racers-internal!2878
2025-09-24 04:25:59 +00:00
Antonio Martinez
01bcf6116e Copy-paste final lap PWR error 2025-09-24 00:10:36 -04:00
Antonio Martinez
15bac24b8d Fix deflated final checkpoint scoring 2025-09-23 22:47:40 -04:00
Antonio Martinez
c7fcf34a8a Vibetweaking 2025-09-23 22:12:38 -04:00
Antonio Martinez
d5f131dcc2 Convert displayexp math to fixed, use autocalibrated final checkpoint power 2025-09-23 21:26:51 -04:00
Ashnal
2be14316cf Finish position is now factored into exp 2025-09-23 21:26:51 -04:00
Antonio Martinez
60fca5210d "Final checkpoint" EXP bonus 2025-09-23 21:26:51 -04:00
AJ Martinez
7109cd8c13 Merge branch 'close-to-leader-items' into 'master'
Fewer speed items when crowding 1st

See merge request kart-krew-dev/ring-racers-internal!2888
2025-09-24 01:26:06 +00:00
Antonio Martinez
e0fd5b43c5 grug tweak exp influence 2025-09-23 21:25:08 -04:00
Antonio Martinez
51cc299e40 I guess we're just doing everything on vibes now huh 2025-09-23 21:17:19 -04:00
Antonio Martinez
84917e36f1 Not unused anymore, idiot 2025-09-23 21:10:07 -04:00
Antonio Martinez
5d30a46728 EXP softening, large game softening 2025-09-23 21:04:36 -04:00
Antonio Martinez
d0ef4cdfaf Grow stacking gives a maximum of 5 seconds grow time 2025-09-23 20:44:02 -04:00
Antonio Martinez
220f8b035d Fewer speed items when crowding 1st 2025-09-23 19:52:46 -04:00
Zander
51e22892ac removed ability for class r to clear ta challenges 2025-09-23 13:58:43 -04:00
Antonio Martinez
eb90dcd047 Fix debugitemodds displaying wrong odds 2025-09-23 06:53:02 -04:00
AJ Martinez
4337618342 Merge branch 'backline-exp-roundup' into 'master'
EXP adjustments

See merge request kart-krew-dev/ring-racers-internal!2879
2025-09-23 09:46:05 +00:00
AJ Martinez
2a72e0a855 Merge branch 'fix-ringboost-crack' into 'master'
Fix Ring payout rate getting stuck fast until interacting with aother Ring Box

Closes ring-racers#225

See merge request kart-krew-dev/ring-racers-internal!2884
2025-09-23 09:45:41 +00:00
AJ Martinez
6bd6c91077 Merge branch 'tutorial-flame' into 'master'
Max Flame Shield in Catcher/Tutorial

Closes ring-racers#219

See merge request kart-krew-dev/ring-racers-internal!2882
2025-09-23 09:44:59 +00:00
AJ Martinez
aee332fa9b Merge branch 'botslow-takeover-fix' into 'master'
Fix staff ghost desyncs when bots takeover

See merge request kart-krew-dev/ring-racers-internal!2885
2025-09-23 09:44:48 +00:00
AJ Martinez
f7bc6e303e Merge branch 'damage-fixes' into 'master'
Various damage fixes

Closes ring-racers#191, ring-racers#116, and ring-racers#197

See merge request kart-krew-dev/ring-racers-internal!2883
2025-09-23 09:44:36 +00:00
Antonio Martinez
4aa3309885 Oops deleted staffsync 2025-09-23 03:22:15 -04:00
Antonio Martinez
595874f4e5 CompatLevel fixes 2025-09-23 03:18:14 -04:00
Antonio Martinez
3f5f9825a8 Compatlevel for bumpslow fixes 2025-09-23 01:25:50 -04:00
Antonio Martinez
4478fce917 P_DamageMobjCompat 2025-09-23 01:25:32 -04:00
Antonio Martinez
f78ae582d4 Compatlevel for bumpslow fixes 2025-09-22 19:55:40 -04:00
Antonio Martinez
55b333e01f Remove sector damage stumble AND terrain damage stumble from damage system 2025-09-22 17:11:14 -04:00
Antonio Martinez
867dfb49f2 Stumble floors are not damage, we use this to control area access! 2025-09-22 15:56:32 -04:00
Antonio Martinez
3d5f0e9d73 Fix Ring payout rate getting stuck fast until interacting with aother Ring Box 2025-09-22 08:23:22 -04:00
Antonio Martinez
587eddeb70 Orbital/backspam downgrade cleanup 2025-09-22 04:41:42 -04:00
Antonio Martinez
4b94f06186 Various damage fixes 2025-09-22 04:19:30 -04:00
Antonio Martinez
38be6953e7 Max Flame Shield in Catcher/Tutorial 2025-09-22 01:15:03 -04:00
toaster
a13735822e Added password for unlocking all tutorials early 2025-09-21 12:11:01 +01:00
Eidolon
b3a2cc2ea9 Update vcpkg baseline 2025-09-20 20:39:09 -05:00
Antonio Martinez
0373a23d72 2 second FAULT 2025-09-20 19:18:24 -04:00
Antonio Martinez
27b9a46f0c Disable large game scaling in Frantic 2025-09-20 17:02:38 -04:00
Antonio Martinez
944c13993b EXP adjustments 2025-09-20 16:11:23 -04:00
Antonio Martinez
0dad1aa918 me sweepy 2025-09-19 23:51:39 -04:00
Antonio Martinez
f674778097 Super Ring is a speed item 2025-09-19 23:50:31 -04:00
toaster
9411ce5387 Environment::read/writeModuleName: Convert lumpnums to a netsafe form for transit
- Introduces new functions
    - W_LumpIntoNetSave
    - W_LumpFromNetSave
- Essentially shims the upper 16 bits to account for unimportant files
2025-09-19 16:22:06 +01:00
toaster
a01300cd54 w_wad for lumpnums: Use bitwise and instead of addition
Makes the mathematical logic of what's being done clearer
2025-09-19 16:12:59 +01:00
toaster
1517ba4d89 Fix mainwads-dependent calculations
- sounds.pk3 was being considered a mainwad in some spots due to use of <= instead of <
- fileneeded material was manually skipping over base musicwads when it didn't have to
2025-09-19 16:12:59 +01:00
AJ Martinez
4b81be037a Revert "Why no one noticed this I will never fully understand"
This reverts commit 75fe652dd5.
2025-09-18 23:12:17 -04:00
Antonio Martinez
75fe652dd5 Why no one noticed this I will never fully understand 2025-09-18 23:10:54 -04:00
Eidolon
daa6dbd667 Start rc5/modversion 8 2025-09-18 21:01:51 -05:00
133 changed files with 6004 additions and 1079 deletions

View file

@ -1,3 +1,7 @@
# Have you already searched the issue tracker for issues similar to yours?
(Use the search bar on https://gitlab.com/kart-krew-dev/ring-racers/-/issues - duplicate reports make it tough for us to keep track of things.)
# What version of Ring Racers are you playing?
(Replace this text with the version number. You can see this on the title screen at the bottom-left corner.)

View file

@ -125,6 +125,9 @@ find_package(PNG REQUIRED)
find_package(SDL2 CONFIG REQUIRED)
find_package(CURL REQUIRED)
find_package(Opus REQUIRED)
if(WIN32 AND NOT MINGW)
find_package(cpptrace CONFIG REQUIRED)
endif()
# Use the one in thirdparty/fmt to guarantee a minimum version
#find_package(FMT CONFIG REQUIRED)

View file

@ -54,8 +54,8 @@
"name": "__develop-cl",
"hidden": true,
"cacheVariables": {
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"SRB2_CONFIG_DEV_BUILD": "ON",
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
@ -64,8 +64,8 @@
"name": "__release-cl",
"hidden": true,
"cacheVariables": {
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
"SRB2_CONFIG_DEV_BUILD": "OFF",
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}

View file

@ -1,3 +1,5 @@
include(CheckCXXCompilerFlag)
add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
comptime.c
cxxutil.hpp
@ -128,6 +130,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
lua_itemroulettelib.c
lua_respawnvarslib.c
lua_waypointslib.c
lua_grandprixlib.c
lua_profile.cpp
k_kart.c
k_respawn.c
@ -176,6 +179,41 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
p_deepcopy.cpp
)
# Always compile some files with optimizations in Debug config.
# This is to make the debugging experience less slow for the majority of cases.
set(always_optimize_options "")
if(MSVC)
set(always_optimize_options "$<$<CONFIG:Debug>:/O2;/Ob2>")
else()
set(always_optimize_options "$<$<CONFIG:Debug>:-O3>")
endif()
set_source_files_properties(
r_bsp.cpp
r_data.c
r_debug.cpp
r_debug_parser.cpp
r_debug_printer.cpp
r_draw.cpp
r_fps.cpp
r_main.cpp
r_plane.cpp
r_segs.cpp
r_skins.c
r_sky.c
r_splats.c
r_spritefx.cpp
r_things.cpp
r_bbox.c
r_textures.cpp
r_textures_dups.cpp
r_patch.cpp
r_patchrotation.c
r_picformats.c
r_portal.c
PROPERTIES
COMPILE_OPTIONS "${always_optimize_options}"
)
set_target_properties(SRB2SDL2 PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/sdl/macosx/MacOSXBundleInfo.plist.in")
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
@ -210,7 +248,7 @@ add_custom_target(_SRB2_reconf ALL
)
add_dependencies(SRB2SDL2 _SRB2_reconf)
if(("${CMAKE_COMPILER_IS_GNUCC}" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
if(("${CMAKE_COMPILER_IS_GNUCC}") AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase")
if("${SRB2_CONFIG_STATIC_STDLIB}")
# On MinGW with internal libraries, link the standard library statically
@ -224,8 +262,19 @@ if(("${CMAKE_COMPILER_IS_GNUCC}" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND
endif()
endif()
if(MSVC OR CMAKE_CXX_LINK_EXECUTABLE MATCHES "lld-link.exe")
if(MSVC OR CMAKE_CXX_LINK_EXECUTABLE MATCHES "lld-link\\.exe")
target_link_options(SRB2SDL2 PRIVATE /MANIFEST:NO)
target_link_libraries(SRB2SDL2 PRIVATE "dbghelp")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
# Stuff to make paths not include the builder's file system paths on clang-cl
string(REPLACE "/" "\\" backslashes_cmake_source_dir "${CMAKE_SOURCE_DIR}")
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=X:/ringracers>")
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-prefix-map=${backslashes_cmake_source_dir}=X:/ringracers>")
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-compilation-dir=${CMAKE_SOURCE_DIR}>")
target_link_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/pdbaltpath:%_PDB%>")
endif()
target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
@ -279,10 +328,35 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
target_compile_definitions(SRB2SDL2 PRIVATE -DMACOSX)
endif()
# Enable SSE2 for IA-32.
if(SRB2_SYSTEM_BITS EQUAL 32)
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang|AppleClang)")
check_cxx_compiler_flag("-msse2" has_sse2)
if(has_sse2)
message(STATUS "Using SSE2 on IA-32")
target_compile_options(SRB2SDL2 PRIVATE "-msse2")
else()
message(FATAL_ERROR "Needs -msse2 compiler support")
endif()
elseif(MSVC)
check_cxx_compiler_flag("/arch:sse2" has_sse2)
if(has_sse2)
message(STATUS "Using SSE2 on IA-32")
target_compile_options(SRB2SDL2 PRIVATE "/arch:SSE2")
else()
message(FATAL_ERROR "Needs /arch:SSE2 compiler support")
endif()
endif()
endif()
target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB)
target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG)
target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl)
target_link_libraries(SRB2SDL2 PRIVATE Opus::opus)
if(WIN32 AND NOT MINGW)
target_link_libraries(SRB2SDL2 PRIVATE cpptrace::cpptrace)
target_compile_definitions(SRB2SDL2 PRIVATE HAVE_CPPTRACE)
endif()
target_link_libraries(SRB2SDL2 PRIVATE ReNameNoise::renamenoise)
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
target_link_libraries(SRB2SDL2 PRIVATE -lexecinfo)
@ -461,6 +535,7 @@ target_compile_options(SRB2SDL2 PRIVATE
# This is a direct translation from versions.mk
$<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>:
-Wall
-Werror-implicit-function-declaration
-Wno-trigraphs
-W # Was controlled by RELAXWARNINGS
-pedantic
@ -545,6 +620,7 @@ target_compile_options(SRB2SDL2 PRIVATE
$<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
#-Wall
-Werror=microsoft
-Werror=implicit-function-declaration
-Wreturn-type # Missing returns in non-void function
-Wduplicate-decl-specifier
-Wsometimes-uninitialized
@ -570,9 +646,11 @@ target_compile_options(SRB2SDL2 PRIVATE
# C++, GNU
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:GNU>>:
-Wall
-Wno-c++11-compat
-Wno-c++14-compat # No C++14 compat needed
>
# C++, GNU, Clang and Apple Clang
# C++, Clang and Apple Clang
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>>:
#-Wall
-Werror=microsoft
@ -584,6 +662,8 @@ target_compile_options(SRB2SDL2 PRIVATE
-Wno-c++98-compat
-Wno-c++11-compat
-Wno-c++14-compat # No C++14 compat needed
-Werror=c++20-extensions
-Werror=c++23-extensions # Disallow newer language features entirely
-Wno-unused-but-set-variable # Setting unread variables is fine (nontrivial C++ types issue)
-Wno-misleading-indentation # Some cases in code currently
-Wno-deprecated-non-prototype # We have no intention of using C23 yet.
@ -594,6 +674,8 @@ target_compile_options(SRB2SDL2 PRIVATE
-Wno-unused-function
>
# C++, Clang and Apple Clang
# C++, MSVC
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:
/Wv:19.20.27004.0

View file

@ -1654,6 +1654,32 @@ bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerSkinRealName(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's skin real name.
--------------------------------------------------*/
bool CallFunc_PlayerSkinRealName(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
Environment *env = &ACSEnv;
auto info = &static_cast<Thread *>(thread)->info;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
UINT16 skin = info->mo->player->skin;
thread->dataStk.push(~env->getString( skins[skin]->realname )->idx);
return false;
}
thread->dataStk.push(0);
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -2409,6 +2435,8 @@ bool CallFunc_MusicStopAll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM
bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
ACSVM::MapScope *map = thread->scopeMap;
ACSVM::String *tuneStr = nullptr;
const char *tune = nullptr;
// 0: str tune - id for the tune to play
// 1: str song - lump name for the song to map to
@ -2419,6 +2447,16 @@ bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
return false;
}
tuneStr = map->getString(argV[0]);
tune = tuneStr->str;
// Do not allow ACS to remap Stereo Mode tunes.
if (strlen(tune) > 5
&& toupper(tune[0]) == 'S' && toupper(tune[1]) == 'T' && toupper(tune[2]) == 'E' && toupper(tune[3]) == 'R' && toupper(tune[4]) == 'E')
{
return false;
}
Music_Remap(map->getString(argV[0])->str, map->getString(argV[1])->str);
return false;

View file

@ -76,6 +76,7 @@ bool CallFunc_CountPushables(ACSVM::Thread *thread, const ACSVM::Word *argV, ACS
bool CallFunc_HaveUnlockableTrigger(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_HaveUnlockable(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerSkinRealName(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerLosing(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);

View file

@ -177,6 +177,7 @@ Environment::Environment()
addFuncDataACS0( 318, addCallFunc(CallFunc_CheckTutorialChallenge));
addFuncDataACS0( 319, addCallFunc(CallFunc_PlayerLosing));
addFuncDataACS0( 320, addCallFunc(CallFunc_PlayerExiting));
addFuncDataACS0( 321, addCallFunc(CallFunc_PlayerSkinRealName));
addFuncDataACS0( 500, addCallFunc(CallFunc_CameraWait));
addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition));

View file

@ -25,6 +25,7 @@
#include "Script.hpp"
#include "Serial.hpp"
#include "Thread.hpp"
#include "../../../w_wad.h"
#include <iostream>
#include <list>
@ -596,7 +597,12 @@ namespace ACSVM
ModuleName Environment::readModuleName(Serial &in) const
{
auto s = readString(in);
auto i = ReadVLN<std::size_t>(in);
size_t i = ReadVLN<std::size_t>(in);
if ((i = W_LumpFromNetSave(i)) == LUMPERROR)
{
CONS_Debug(DBG_GAMELOGIC, "lumpnum not found for ACS module '%s'\n", s->str);
}
return {s, nullptr, i};
}
@ -768,7 +774,7 @@ namespace ACSVM
void Environment::writeModuleName(Serial &out, ModuleName const &in) const
{
writeString(out, in.s);
WriteVLN(out, in.i);
WriteVLN<std::size_t>(out, W_LumpIntoNetSave(in.i));
}
//

View file

@ -113,6 +113,7 @@ CV_PossibleValue_t descriptiveinput_cons_t[] = {
{7, "6Bt. (D)"},
{8, "6Bt. (E)"},
{9, "6Bt. (F)"},
{10, "6Bt. (G)"},
{0, NULL}
};

View file

@ -420,7 +420,11 @@ consvar_t cv_bgaudio = Player("bgaudio", "Nothing").onchange_noinit(BGAudio_OnCh
{0, "Nothing"},
{1, "Music"},
{2, "Sounds"},
{4, "Voices"},
{3, "Music&Sounds"},
{5, "Music&Voices"},
{6, "Sounds&Voices"},
{7, "MusicSounds&Voices"}
});
// Pause game upon window losing focus
@ -829,6 +833,7 @@ void ForceSkin_OnChange(void);
consvar_t cv_forceskin = OnlineCheat("forcecharacter", "None").onchange(ForceSkin_OnChange).description("Force all players to use one character");
consvar_t cv_fuzz = OnlineCheat("fuzz", "Off").on_off().description("Human players spam random inputs, get random items");
consvar_t cv_skiprender = OnlineCheat("skiprender", "1").values(CV_Natural).description("Only render every X frames");
consvar_t cv_kartdebugamount = OnlineCheat("debugitemamount", "1").min_max(1, 255).description("If debugitem, give multiple copies of an item");
consvar_t cv_kartdebugbots = OnlineCheat("debugbots", "Off").on_off().description("Bot AI debugger");
@ -1003,7 +1008,7 @@ consvar_t cv_dummyprofilerumble = MenuDummy("dummyprofilerumble", "On").on_off()
consvar_t cv_dummyscramble = MenuDummy("dummyscramble", "Random").values({{0, "Random"}, {1, "Points"}});
void CV_SPBAttackChanged(void);
consvar_t cv_dummyspbattack = MenuDummy("dummyspbattack", "Off").on_off().onchange(CV_SPBAttackChanged);
consvar_t cv_dummyspbattack = MenuDummy("dummyspbattack", "Off").on_off().onchange_noinit(CV_SPBAttackChanged);
consvar_t cv_dummyspectate = MenuDummy("dummyspectate", "Spectator").values({{0, "Spectator"}, {1, "Playing"}});

View file

@ -105,6 +105,7 @@ boolean server = true; // true or false but !server == client
#define client (!server)
boolean nodownload = false;
boolean serverrunning = false;
boolean connectedtodedicated = false;
INT32 serverplayer = 0;
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
@ -206,8 +207,11 @@ static UINT32 g_player_voice_frames_this_tic[MAXPLAYERS];
static OpusEncoder *g_local_opus_encoder;
static ReNameNoiseDenoiseState *g_local_renamenoise_state;
static UINT64 g_local_opus_frame = 0;
#define SRB2_VOICE_OPUS_FRAME_SIZE 960
static float g_local_voice_buffer[SRB2_VOICE_OPUS_FRAME_SIZE];
#define SRB2_VOICE_OPUS_FRAME_SIZE (20 * 48)
#define SRB2_VOICE_MAX_FRAMES 8
#define SRB2_VOICE_MAX_DEQUEUE_SAMPLES (SRB2_VOICE_MAX_FRAMES * SRB2_VOICE_OPUS_FRAME_SIZE)
#define SRB2_VOICE_MAX_DEQUEUE_BYTES (SRB2_VOICE_MAX_DEQUEUE_SAMPLES * sizeof(float))
static float g_local_voice_buffer[SRB2_VOICE_MAX_DEQUEUE_SAMPLES];
static INT32 g_local_voice_buffer_len = 0;
static INT32 g_local_voice_threshold_time = 0;
float g_local_voice_last_peak = 0;
@ -1268,6 +1272,7 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.dedicated = (boolean)dedicated;
netbuffer->u.servercfg.maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value));
netbuffer->u.servercfg.allownewplayer = cv_allownewplayer.value;
@ -2244,7 +2249,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
#ifdef HAVE_THREADS
I_lock_mutex(&k_menu_mutex);
#endif
M_UpdateMenuCMD(0, true);
M_UpdateMenuCMD(0, true, false);
if (cl_mode == CL_CONFIRMCONNECT)
{
@ -2499,6 +2504,7 @@ static void Command_connect(void)
// we don't request a restart unless the filelist differs
server = false;
connectedtodedicated = false;
// Get the server node.
if (netgame)
@ -2726,6 +2732,19 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
K_CheckBumpers();
P_CheckRacers();
// Reset map headers' justPlayed and anger records
// when there are no players in a dedicated server.
// Otherwise maps get angry at newly-joined players
// that don't deserve it.
if (dedicated && D_NumPlayers() == 0)
{
for (INT32 i = 0; i < nummapheaders; i++)
{
mapheaderinfo[i]->justPlayed = 0;
mapheaderinfo[i]->anger = 0;
}
}
}
void CL_Reset(void)
@ -2745,6 +2764,7 @@ void CL_Reset(void)
multiplayer = false;
servernode = 0;
server = true;
connectedtodedicated = false;
doomcom->numnodes = 1;
doomcom->numslots = 1;
SV_StopServer();
@ -3742,8 +3762,6 @@ static void InitializeLocalVoiceEncoder(void)
CONS_Alert(CONS_WARNING, "Failed to create Opus voice encoder: opus error %d\n", error);
encoder = NULL;
}
opus_encoder_ctl(encoder, OPUS_SET_VBR(0));
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(28000));
g_local_opus_encoder = encoder;
g_local_opus_frame = 0;
}
@ -3811,6 +3829,12 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum)
newplayer->availabilities[i] = READUINT8(*p);
}
if (server)
{
for (i = 0; i < G_LocalSplitscreenPartySize(newplayernum); ++i)
playerdelaytable[G_LocalSplitscreenPartyMember(newplayernum, i)] = mindelay;
}
// the server is creating my player
if (node == mynode)
{
@ -3838,12 +3862,6 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum)
P_ForceLocalAngle(newplayer, newplayer->angleturn);
addedtogame = true;
if (server)
{
for (i = 0; i < G_LocalSplitscreenPartySize(newplayernum); ++i)
playerdelaytable[G_LocalSplitscreenPartyMember(newplayernum, i)] = mindelay;
}
}
newplayer->splitscreenindex = splitscreenplayer;
@ -4260,6 +4278,11 @@ boolean Playing(void)
return (server && serverrunning) || (client && cl_mode == CL_CONNECTED);
}
boolean InADedicatedServer(void)
{
return Playing() && (dedicated || connectedtodedicated);
}
boolean SV_SpawnServer(void)
{
#ifdef TESTERS
@ -4362,6 +4385,7 @@ void SV_StartSinglePlayerServer(INT32 dogametype, boolean donetgame)
{
INT32 lastgametype = gametype;
server = true;
connectedtodedicated = false;
multiplayer = (modeattacking == ATTACKING_NONE);
joinedIP[0] = '\0'; // Make sure to empty this so that we don't save garbage when we start our own game. (because yes we use this for netgames too....)
@ -4988,6 +5012,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
G_SetGametype(netbuffer->u.servercfg.gametype);
modifiedgame = netbuffer->u.servercfg.modifiedgame;
connectedtodedicated = netbuffer->u.servercfg.dedicated;
memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
@ -5379,7 +5404,7 @@ static void PT_HandleVoiceClient(SINT8 node, boolean isserver)
{
return;
}
float *decoded_out = Z_Malloc(sizeof(float) * SRB2_VOICE_OPUS_FRAME_SIZE, PU_STATIC, NULL);
float *decoded_out = Z_Malloc(sizeof(float) * 1920, PU_STATIC, NULL);
INT32 decoded_samples = 0;
UINT64 missedframes = 0;
@ -5390,26 +5415,26 @@ static void PT_HandleVoiceClient(SINT8 node, boolean isserver)
for (UINT64 i = 0; i < missedframes; i++)
{
decoded_samples = opus_decode_float(decoder, NULL, 0, decoded_out, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
decoded_samples = opus_decode_float(decoder, NULL, 0, decoded_out, 1920, 0);
if (decoded_samples < 0)
{
continue;
}
if (cv_voice_selfdeafen.value != 1 && playernum != g_localplayers[0])
if (cv_voice_selfdeafen.value != 1 && playernum != g_localplayers[0] && !g_voice_disabled)
{
S_QueueVoiceFrameFromPlayer(playernum, (void*)decoded_out, decoded_samples * sizeof(float), false);
}
}
g_player_opus_lastframe[playernum] = framenum;
decoded_samples = opus_decode_float(decoder, frame, framesize, decoded_out, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
decoded_samples = opus_decode_float(decoder, frame, framesize, decoded_out, 1920, 0);
if (decoded_samples < 0)
{
Z_Free(decoded_out);
return;
}
if (cv_voice_selfdeafen.value != 1 && playernum != g_localplayers[0])
if (cv_voice_selfdeafen.value != 1 && playernum != g_localplayers[0] && !g_voice_disabled)
{
S_QueueVoiceFrameFromPlayer(playernum, (void*)decoded_out, decoded_samples * sizeof(float), terminal);
}
@ -7378,7 +7403,9 @@ void NetKeepAlive(void)
FileSendTicker();
// Update voice whenever possible.
NetVoiceUpdate();
{
NetVoiceUpdate();
}
}
// If a tree falls in the forest but nobody is around to hear it, does it make a tic?
@ -7566,52 +7593,49 @@ void NetUpdate(void)
FileSendTicker();
}
static INT32 BiggestOpusFrameLength(INT32 samples)
{
if (samples >= 1920) return 1920;
if (samples >= 960) return 960;
if (samples >= 480) return 480;
return 0;
}
void NetVoiceUpdate(void)
{
UINT8 *encoded = NULL;
float *subframe_buffer = NULL;
float *denoise_buffer = NULL;
ps_voiceupdatetime = I_GetPreciseTime();
if (dedicated)
{
ps_voiceupdatetime = I_GetPreciseTime() - ps_voiceupdatetime;
return;
}
floatdenormalstate_t dnzstate = M_EnterFloatDenormalToZero();
UINT32 bytes_dequed = 0;
do
bytes_dequed = S_SoundInputDequeueSamples((void*)(g_local_voice_buffer + g_local_voice_buffer_len), SRB2_VOICE_MAX_DEQUEUE_BYTES - (g_local_voice_buffer_len * sizeof(float)));
g_local_voice_buffer_len += bytes_dequed / 4;
INT32 buffer_offset = 0;
INT32 frame_length = 0;
for (
;
(frame_length = BiggestOpusFrameLength(g_local_voice_buffer_len - buffer_offset)) > 0 && (buffer_offset + frame_length) < g_local_voice_buffer_len;
buffer_offset += frame_length
)
{
// We need to drain the input queue completely, so do this in a full loop
UINT32 to_read = (SRB2_VOICE_OPUS_FRAME_SIZE - g_local_voice_buffer_len) * sizeof(float);
if (to_read > 0)
{
// Attempt to fill the voice frame buffer
bytes_dequed = S_SoundInputDequeueSamples((void*)(g_local_voice_buffer + g_local_voice_buffer_len), to_read);
g_local_voice_buffer_len += bytes_dequed / 4;
}
else
{
bytes_dequed = 0;
}
if (g_local_voice_buffer_len < SRB2_VOICE_OPUS_FRAME_SIZE)
{
continue;
}
if (S_SoundInputRemainingSamples() > 5 * SRB2_VOICE_OPUS_FRAME_SIZE)
{
// If there are too many frames worth of samples to dequeue (100ms), skip this frame instead of encoding.
// This is so we drain the queue without sending too many packets that might queue up on the network driver.
g_local_voice_buffer_len = 0;
continue;
}
float *frame_buffer = g_local_voice_buffer + buffer_offset;
// Amp of +10 dB is appromiately "twice as loud"
float ampfactor = powf(10, (float) cv_voice_inputamp.value / 20.f);
for (int i = 0; i < g_local_voice_buffer_len; i++)
for (int i = 0; i < frame_length; i++)
{
g_local_voice_buffer[i] *= ampfactor;
frame_buffer[i] *= ampfactor;
}
if (cv_voice_denoise.value)
@ -7620,30 +7644,34 @@ void NetVoiceUpdate(void)
{
InitializeLocalVoiceDenoiser();
}
int rnnoise_size = renamenoise_get_frame_size();
float *subframe_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
float *denoise_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
int rnnoise_size = renamenoise_get_frame_size(); // this is always 480
if (subframe_buffer == NULL)
{
subframe_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
}
if (denoise_buffer == NULL)
{
denoise_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
}
// rnnoise frames are smaller than opus, but we should not expect the opus frame to be an exact multiple of rnnoise
for (int denoise_position = 0; denoise_position < SRB2_VOICE_OPUS_FRAME_SIZE; denoise_position += rnnoise_size)
for (int denoise_position = 0; denoise_position < frame_length; denoise_position += rnnoise_size)
{
memset(subframe_buffer, 0, rnnoise_size * sizeof(float));
memcpy(subframe_buffer, g_local_voice_buffer + denoise_position, min(rnnoise_size * sizeof(float), (SRB2_VOICE_OPUS_FRAME_SIZE - denoise_position) * sizeof(float)));
memcpy(subframe_buffer, frame_buffer + denoise_position, min(rnnoise_size * sizeof(float), (frame_length - denoise_position) * sizeof(float)));
renamenoise_process_frame(g_local_renamenoise_state, denoise_buffer, subframe_buffer);
memcpy(g_local_voice_buffer + denoise_position, denoise_buffer, min(rnnoise_size * sizeof(float), (SRB2_VOICE_OPUS_FRAME_SIZE - denoise_position) * sizeof(float)));
memcpy(frame_buffer + denoise_position, denoise_buffer, min(rnnoise_size * sizeof(float), (frame_length - denoise_position) * sizeof(float)));
}
Z_Free(denoise_buffer);
Z_Free(subframe_buffer);
}
float softmem = 0.f;
opus_pcm_soft_clip(g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, 1, &softmem);
opus_pcm_soft_clip(frame_buffer, frame_length, 1, &softmem);
// Voice detection gate open/close
float maxamplitude = 0.f;
for (int i = 0; i < g_local_voice_buffer_len; i++)
for (int i = 0; i < frame_length; i++)
{
maxamplitude = max(fabsf(g_local_voice_buffer[i]), maxamplitude);
maxamplitude = max(fabsf(frame_buffer[i]), maxamplitude);
}
// 20. * log_10(amplitude) -> decibels (up to 0)
// lower than -30 dB is usually inaudible
@ -7660,7 +7688,6 @@ void NetVoiceUpdate(void)
case 0:
if (I_GetTime() - g_local_voice_threshold_time > 15)
{
g_local_voice_buffer_len = 0;
g_local_voice_detected = false;
continue;
}
@ -7668,20 +7695,17 @@ void NetVoiceUpdate(void)
case 1:
if (!g_voicepushtotalk_on)
{
g_local_voice_buffer_len = 0;
g_local_voice_detected = false;
continue;
}
g_local_voice_detected = true;
break;
default:
g_local_voice_buffer_len = 0;
continue;
}
if (cv_voice_selfdeafen.value == 1)
if (cv_voice_selfdeafen.value == 1 || g_voice_disabled)
{
g_local_voice_buffer_len = 0;
continue;
}
@ -7696,7 +7720,7 @@ void NetVoiceUpdate(void)
}
OpusEncoder *encoder = g_local_opus_encoder;
INT32 result = opus_encode_float(encoder, g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, encoded, 1400);
INT32 result = opus_encode_float(encoder, frame_buffer, frame_length, encoded, 1400);
if (result < 0)
{
continue;
@ -7718,15 +7742,24 @@ void NetVoiceUpdate(void)
{
RecreatePlayerOpusDecoder(consoleplayer);
}
result = opus_decode_float(g_player_opus_decoders[consoleplayer], encoded, result, g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
S_QueueVoiceFrameFromPlayer(consoleplayer, g_local_voice_buffer, result * sizeof(float), false);
result = opus_decode_float(g_player_opus_decoders[consoleplayer], encoded, result, frame_buffer, frame_length, 0);
S_QueueVoiceFrameFromPlayer(consoleplayer, frame_buffer, result * sizeof(float), false);
}
g_local_voice_buffer_len = 0;
g_local_opus_frame += 1;
} while (bytes_dequed > 0);
}
if (buffer_offset > 0)
{
memmove(g_local_voice_buffer, g_local_voice_buffer + buffer_offset, (g_local_voice_buffer_len - buffer_offset) * sizeof(float));
g_local_voice_buffer_len -= buffer_offset;
}
M_ExitFloatDenormalToZero(dnzstate);
if (denoise_buffer) Z_Free(denoise_buffer);
if (subframe_buffer) Z_Free(subframe_buffer);
if (encoded) Z_Free(encoded);
ps_voiceupdatetime = I_GetPreciseTime() - ps_voiceupdatetime;
return;
}

View file

@ -231,6 +231,7 @@ struct serverconfig_pak
UINT8 gametype;
UINT8 modifiedgame;
boolean dedicated;
char server_context[8]; // Unique context id, generated at server startup.
@ -407,7 +408,7 @@ struct resultsall_pak
struct say_pak
{
char message[HU_MAXMSGLEN];
char message[HU_MAXMSGLEN + 1];
UINT8 target;
UINT8 flags;
UINT8 source;
@ -465,7 +466,7 @@ struct doomdata_t
client3cmd_pak client3pak; // 264 bytes(?)
client4cmd_pak client4pak; // 324 bytes(?)
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
serverconfig_pak servercfg; // 777 bytes
UINT8 textcmd[MAXTEXTCMD+2]; // 66049 bytes (wut??? 64k??? More like 258 bytes...)
char filetxpak[sizeof (filetx_pak)];// 139 bytes
char fileack[sizeof (fileack_pak)];
@ -558,6 +559,7 @@ extern boolean server;
extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern boolean connectedtodedicated; // Client that is connected to a dedicated server.
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
extern SINT8 servernode;
@ -670,6 +672,7 @@ void CL_UpdateServerList(void);
void CL_TimeoutServerList(void);
// Is there a game running
boolean Playing(void);
boolean InADedicatedServer(void);
// Advance client-to-client pubkey verification flow
void UpdateChallenges(void);

View file

@ -107,17 +107,17 @@ extern "C" consvar_t cv_lua_profile, cv_menuframeskip;
/* Manually defined asset hashes
*/
#define ASSET_HASH_BIOS_PK3 "70ad11d77048078ee0adb7891068bf38"
#define ASSET_HASH_SCRIPTS_PK3 "c3440a9ee57b4d9a81145a09afa0c0d6"
#define ASSET_HASH_GFX_PK3 "314e88e73c0a629df9c2851dd7c21baf"
#define ASSET_HASH_TEXTURES_GENERAL_PK3 "609b683d3efc291ea28dd4e50d731f34"
#define ASSET_HASH_TEXTURES_SEGAZONES_PK3 "61a19cb324e66b84e0fbc07abb659c64"
#define ASSET_HASH_TEXTURES_ORIGINALZONES_PK3 "2f3aa120be2dfb1f4fe3e7090fbb0948"
#define ASSET_HASH_BIOS_PK3 "36201c4690256d133dff7d3879436dff"
#define ASSET_HASH_SCRIPTS_PK3 "56be3c47192870c3265f19cf024e860e"
#define ASSET_HASH_GFX_PK3 "9e91306851cb6619124b37533cfbf029"
#define ASSET_HASH_TEXTURES_GENERAL_PK3 "3b81c0645b9e0580c1675f2eb70c4250"
#define ASSET_HASH_TEXTURES_SEGAZONES_PK3 "2e87cb9dddae7d32656932fdad32b22f"
#define ASSET_HASH_TEXTURES_ORIGINALZONES_PK3 "f15f974dbd17c9ce1b60bf31cf12d246"
#define ASSET_HASH_CHARS_PK3 "5c8c34c5623acf984e3f654da4509126"
#define ASSET_HASH_FOLLOWERS_PK3 "4b61428e5f2ec806de398de8a5fba5f0"
#define ASSET_HASH_MAPS_PK3 "84503a914248842b3e88db4f1080b8e6"
#define ASSET_HASH_MAPS_PK3 "d744ac9747e078220a986ab295721182"
#define ASSET_HASH_UNLOCKS_PK3 "a4de35ba9f83829ced44dfc1316ba33e"
#define ASSET_HASH_STAFFGHOSTS_PK3 "f2ea75218c9b8ef479a75f287cc32d11"
#define ASSET_HASH_STAFFGHOSTS_PK3 "4248d1fb6eb14c6b359f739c118249cc"
#define ASSET_HASH_SHADERS_PK3 "bc0b47744d457956db2ee9ea00f59eff"
#ifdef USE_PATCH_FILE
#define ASSET_HASH_PATCH_PK3 "00000000000000000000000000000000"
@ -343,7 +343,7 @@ void D_ProcessEvents(boolean callresponders)
// Update menu CMD
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
M_UpdateMenuCMD(i, false);
M_UpdateMenuCMD(i, false, chat_keydown);
}
}
@ -843,6 +843,8 @@ static bool D_Display(bool world)
tic_t rendergametic;
extern "C" consvar_t cv_skiprender;
void D_SRB2Loop(void)
{
tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS;
@ -862,6 +864,7 @@ void D_SRB2Loop(void)
if (dedicated)
server = true;
connectedtodedicated = dedicated;
// Pushing of + parameters is now done back in D_SRB2Main, not here.
@ -1123,6 +1126,13 @@ void D_SRB2Loop(void)
else
frameskip = 0;
}
else if (cv_skiprender.value > 1)
{
if (frameskip < cv_skiprender.value)
frameskip++;
else
frameskip = 0;
}
else
{
if (!ranwipe && frameskip < 3 && deltatics > 1.0)
@ -1588,6 +1598,7 @@ void D_SRB2Main(void)
// for dedicated server
dedicated = M_CheckParm("-dedicated") != 0;
connectedtodedicated = dedicated;
if (dedicated)
{
usedTourney = true;
@ -2405,5 +2416,6 @@ void D_TakeMapSnapshots(void)
setmodeneeded = old_mode + 1;
D_Display(true);
}
g_takemapthumbnail = TMT_NO;
}

View file

@ -618,7 +618,23 @@ static boolean AllowedPlayerNameChar(char ch)
return true;
}
boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
boolean IsPlayerNameUnique(const char *name, INT32 playernum)
{
// Check if a player is currently using the name, case-insensitively.
for (INT32 ix = 0; ix < MAXPLAYERS; ix++)
{
if (ix == playernum) // Don't compare with themself.
continue;
if (playeringame[ix] == false) // This player is not ingame.
continue;
if (strcasecmp(name, player_names[ix]) == 0) // Are usernames equal?
return false;
}
return true;
}
boolean IsPlayerNameGood(char *name)
{
size_t ix, len = strlen(name);
@ -650,36 +666,43 @@ boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
for (ix = 0; ix < len; ix++)
if (!AllowedPlayerNameChar(name[ix]))
return false;
return true;
}
// Check if a player is currently using the name, case-insensitively.
for (ix = 0; ix < MAXPLAYERS; ix++)
boolean EnsurePlayerNameIsGood(char *name, INT32 playernum)
{
size_t len = strlen(name);
// Check if a player is using a valid name.
if (!IsPlayerNameGood(name))
return false;
// Check if another player is currently using the name, case-insensitively.
if (!IsPlayerNameUnique(name, playernum))
{
if (ix != (size_t)playernum && playeringame[ix]
&& strcasecmp(name, player_names[ix]) == 0)
{
// We shouldn't kick people out just because
// they joined the game with the same name
// as someone else -- modify the name instead.
// We shouldn't kick people out just because
// they joined the game with the same name
// as someone else -- modify the name instead.
// Recursion!
// Slowly strip characters off the end of the
// name until we no longer have a duplicate.
if (len > 1)
{
name[len-1] = '\0';
if (!EnsurePlayerNameIsGood (name, playernum))
return false;
}
else if (len == 1) // Agh!
{
// Last ditch effort...
sprintf(name, "%d", 'A' + M_RandomKey(26));
if (!EnsurePlayerNameIsGood (name, playernum))
return false;
}
else
// Recursion!
// Slowly strip characters off the end of the
// name until we no longer have a duplicate.
if (len > 1)
{
name[len-1] = '\0';
if (!EnsurePlayerNameIsGood (name, playernum))
return false;
}
else if (len == 1) // Agh!
{
// Last ditch effort...
sprintf(name, "%d", 'A' + M_RandomKey(26));
if (!EnsurePlayerNameIsGood (name, playernum))
return false;
}
else
return false;
}
return true;
@ -2992,9 +3015,19 @@ static void Got_Mapcmd(const UINT8 **cp, INT32 playernum)
CON_LogMessage(M_GetText("Speeding off to level...\n"));
}
if (demo.playback && !demo.timing)
precache = false;
// Save demo in case map change happened after level finish
// (either manually with the map command, or with a redo vote)
// Isn't needed for time attack (and would also cause issues, as there
// G_RecordDemo (which sets demo.recording to true) is called before this runs)
if (demo.recording && modeattacking == ATTACKING_NONE)
G_CheckDemoStatus();
demo.willsave = (cv_recordmultiplayerdemos.value == 2);
demo.savebutton = 0;
@ -4451,7 +4484,7 @@ static void Command_Addfile(void)
}
// Add file on your client directly if it is trivial, or you aren't in a netgame.
if (!(netgame || multiplayer) || musiconly)
if (!netgame || musiconly)
{
P_AddWadFile(fn);
addedfiles[numfilesadded++] = fn;
@ -4639,10 +4672,10 @@ static void Command_ListWADS_f(void)
nameonly(tempname = va("%s", wadfiles[i]->filename));
if (!i)
CONS_Printf("\x82 IWAD\x80: %s\n", tempname);
else if (i <= mainwads)
else if (i < mainwads)
CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname);
else if (!wadfiles[i]->important)
CONS_Printf("\x86 %c %.2d: %s\n", ((i <= mainwads + musicwads) ? '*' : ' '), i, tempname);
CONS_Printf("\x86 %c %.2d: %s\n", ((i < mainwads + musicwads) ? '*' : ' '), i, tempname);
else
CONS_Printf(" %.2d: %s\n", i, tempname);
}
@ -5696,6 +5729,11 @@ static void Got_SetupVotecmd(const UINT8 **cp, INT32 playernum)
memcpy(g_voteLevels, tempVoteLevels, sizeof(g_voteLevels));
// admin can force vote state whenever
// so we have to save this replay if it needs to be saved
if (demo.recording)
G_CheckDemoStatus();
G_SetGamestate(GS_VOTING);
Y_StartVote();
}
@ -6067,7 +6105,7 @@ static void Got_Cheat(const UINT8 **cp, INT32 playernum)
K_StopRoulette(&player->itemRoulette);
player->itemtype = item;
player->itemamount = amt;
K_SetPlayerItemAmount(player, amt);
if (amt == 0)
{
@ -6876,6 +6914,7 @@ static void Command_Staffsync(void)
demostarttime = I_GetTime();
staffbrief = mapheader->ghostBrief[staffsync_ghost];
G_DoPlayDemoEx("", (staffbrief->wad << 16) | staffbrief->lump);
staffsync_ghost++;
@ -6923,6 +6962,28 @@ static void Command_Staffsync(void)
CONS_Printf("\n");
CONS_Printf(" %d syncs (%d error)\n", result->numerror, result->totalerror/FRACUNIT);
CONS_Printf(" presync: ");
for (UINT32 j = 0; j < PRNUMSYNCED; j++)
{
if (result->rngerror_presync[j] > 0)
CONS_Printf("%s %d ", rng_class_names[j], result->rngerror_presync[j]);
}
CONS_Printf("\n");
CONS_Printf(" postsync: ");
for (UINT32 j = 0; j < PRNUMSYNCED; j++)
{
if (result->rngerror_postsync[j] > 0)
CONS_Printf("%s %d ", rng_class_names[j], result->rngerror_postsync[j]);
}
CONS_Printf("\n");
i++;
}

View file

@ -200,6 +200,8 @@ extern const char *netxcmdnames[MAXNETXCMD - 1];
void D_RegisterServerCommands(void);
void D_RegisterClientCommands(void);
void CleanupPlayerName(INT32 playernum, const char *newname);
boolean IsPlayerNameUnique(const char *name, INT32 playernum);
boolean IsPlayerNameGood(char *name);
boolean EnsurePlayerNameIsGood(char *name, INT32 playernum);
void D_FillPlayerSkinAndColor(const UINT8 n, const player_t *player, player_config_t *config);
void D_PlayerChangeSkinAndColor(player_t *player, UINT16 skin, UINT16 color, INT16 follower, UINT16 followercolor);

View file

@ -163,10 +163,10 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
#ifdef DEVELOP
i = 0;
#else
i = mainwads + 1;
i = mainwads + musicwads;
#endif
for (; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
for (; i < numwadfiles; i++) //mainwads+musicwads, otherwise we start on the first mainwad
{
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
@ -197,7 +197,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
/* don't send mainwads!! */
#ifdef DEVELOP
if (i <= mainwads)
if (i < mainwads)
filestatus += (2 << 4);
#endif
@ -565,7 +565,7 @@ INT32 CL_CheckFiles(void)
#ifdef DEVELOP
j = 0;
#else
j = mainwads + 1;
j = mainwads + musicwads;
#endif
for (i = 0; i < fileneedednum || j < numwadfiles;)
{

View file

@ -154,6 +154,8 @@ typedef enum
PF2_SERVERTEMPMUTE = 1<<10, // Haven't met gamestochat requirement
PF2_SAMEFRAMESTUNG = 1<<11, // Goofy bullshit for tracking mutual ring sting
PF2_UNSTINGABLE = 1<<12, // Was bumped out of spindash
PF2_GIMMESTARTAWARDS = 1<<13, // Need to apply non-first start awards on a 1 tic delay to prevent port priority
PF2_GIMMEFIRSTBLOOD = 1<<14, // And need to differentiate between First Blood and everything else!
} pflags2_t;
typedef enum
@ -383,7 +385,7 @@ typedef enum
#define TUMBLEBOUNCES 3
#define TUMBLEGRAVITY (4*FRACUNIT)
#define TRIPWIRETIME (15)
#define TRIPWIRETIME (50)
#define BALLHOGINCREMENT (7)
@ -736,6 +738,7 @@ struct player_t
UINT8 position; // Used for Kart positions, mostly for deterministic stuff
UINT8 oldposition; // Used for taunting when you pass someone
UINT8 positiondelay; // Used for position number, so it can grow when passing
UINT8 leaderpenalty; // Used for penalising 1st in a positiondelay-friendly way
UINT8 teamposition; // Position, but only against other teams -- not your own.
UINT8 teamimportance; // Opposite of team position x2, with +1 for being in 1st.
@ -755,6 +758,7 @@ struct player_t
tic_t lastairtime;
UINT16 bigwaypointgap; // timer counts down if finish line distance gap is too big to update waypoint
UINT8 startboost; // (0 to 125) - Boost you get from start of race
UINT8 neostartboost; // Weaker partial startboost
UINT8 dropdashboost; // Boost you get when holding A while respawning
UINT8 aciddropdashboost; // acid dropdash
@ -766,6 +770,7 @@ struct player_t
UINT8 wipeoutslow; // Timer before you slowdown when getting wiped out
UINT8 justbumped; // Prevent players from endlessly bumping into each other
UINT8 noEbrakeMagnet; // Briefly disable 2.2 responsive ebrake if you're bumped by another player.
UINT8 wallSpikeDampen; // 2.4 wallspikes can softlock in closed quarters... attenuate their violence
UINT8 tumbleBounces;
UINT16 tumbleHeight; // In *mobjscaled* fracunits, or mfu, not raw fu
UINT16 stunned; // Number of tics during which rings cannot be picked up
@ -801,6 +806,8 @@ struct player_t
fixed_t spindashspeed; // Spindash release speed
UINT8 spindashboost; // Spindash release boost timer
UINT8 ringboostinprogress; // Ring overhead, don't sting!
fixed_t fastfall; // Fast fall momentum
fixed_t fastfallBase; // Fast fall base speed multiplier
@ -821,6 +828,7 @@ struct player_t
UINT16 tripwireLeniency; // When reaching a state that lets you go thru tripwire, you get an extra second leniency after it ends to still go through it.
UINT8 tripwireAirLeniency; // Timer that elongates tripwire leniency when in midair.
UINT8 fakeBoost; // Some items need to grant tripwire pass briefly, even when their effect is thrust/instathrust. This is a fake boost type to control that.
UINT16 subsonicleniency; // Keep the subsonic visual for just a little bit when your sonic boom is visible
itemroulette_t itemRoulette; // Item roulette data
@ -840,6 +848,7 @@ struct player_t
UINT8 pickuprings; // Number of rings being picked up before added to the counter (prevents rings from being deleted forever over 20)
UINT8 ringdelay; // (0 to 3) - 3 tic delay between every ring usage
UINT16 ringboost; // Ring boost timer
UINT16 momentboost; // Sigh
UINT8 sparkleanim; // (0 to 19) - Angle offset for ring sparkle animation
UINT16 superring; // You were awarded rings, and have this many of them left to spawn on yourself.
UINT16 superringdisplay; // For HUD countup when awarded superring
@ -1071,8 +1080,6 @@ struct player_t
UINT16 wavedashboost; // The actual boost granted from wavedash.
fixed_t wavedashpower; // Is this a bullshit "tap" wavedash? Weaken lower-charge wavedashes while keeping long sliptides fully rewarding.
UINT16 speedpunt;
UINT16 trickcharge; // Landed normally from a trick panel? Get the benefits package!
UINT16 infinitether; // Generic infinitether time, used for infinitether leniency.
@ -1129,6 +1136,8 @@ struct player_t
boolean stingfx;
UINT8 bumperinflate;
boolean mfdfinish; // Did you cross the finish line while just about to explode?
UINT8 ringboxdelay; // Delay until Ring Box auto-activates
UINT8 ringboxaward; // Where did we stop?
UINT32 lastringboost; // What was our accumulated boost when locking the award?

View file

@ -314,6 +314,16 @@ static inline int lib_getenum(lua_State *L)
if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("PF2_", word, 4)) {
p = word+4;
for (i = 0; PLAYERFLAG2_LIST[i]; i++)
if (fastcmp(p, PLAYERFLAG2_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i));
return 1;
}
if (mathlib) return luaL_error(L, "playerflag2 '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("GT_", word, 3)) {
p = word;
i = 0;
@ -382,6 +392,11 @@ static inline int lib_getenum(lua_State *L)
lua_pushinteger(L, (lua_Integer)ML_WRAPMIDTEX);
return 1;
}
if (fastcmp(p, "EFFECT6"))
{
lua_pushinteger(L, (lua_Integer)ML_MIDTEXINVISWALL);
return 1;
}
if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word);
return 0;
}

View file

@ -1599,6 +1599,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_AMPBURST",
// Tripwire VFX on player for bumping it or passing it
"S_SONICBOOM",
"S_TRIPWIREOK",
"S_TRIPWIRELOCKOUT",
@ -3597,6 +3599,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_AMPAURA",
"MT_AMPBURST",
"MT_SONICBOOM",
"MT_TRIPWIREOK",
"MT_TRIPWIRELOCKOUT",
@ -4212,6 +4215,25 @@ const char *const PLAYERFLAG_LIST[] = {
NULL // stop loop here.
};
const char *const PLAYERFLAG2_LIST[] = {
"SELFMUTE",
"SELFDEAFEN",
"SERVERMUTE",
"SERVERDEAFEN",
"STRICTFASTFALL", // Fastfall only with C, never with A+X. Profile preference.
"ALWAYSDAMAGED", // Ignore invulnerability or clash conditions when evaulating damage (P_DamageMobj). Unset after use!
"BUBBLECONTACT", // ACHTUNG VERY BAD HACK - Don't allow Bubble Shield to contact certain objects unless this is a fresh blowup.
"SUPERTRANSFERVFX", // Don't respawn the "super transfer available" VFX.
"FASTTUMBLEBOUNCE", // Don't lose speed when tumblebouncing.
"SERVERTEMPMUTE", // Haven't met gamestochat requirement
"SAMEFRAMESTUNG", // Goofy bullshit for tracking mutual ring sting
"UNSTINGABLE", // Was bumped out of spindash
NULL
};
const char *const GAMETYPERULE_LIST[] = {
"CIRCUIT",
"BOTS",

View file

@ -65,6 +65,7 @@ extern const char *const MOBJFLAG2_LIST[]; // \tMF2_(\S+).*// (.+) --> \t"\1", /
extern const char *const MOBJEFLAG_LIST[];
extern const char *const MAPTHINGFLAG_LIST[4];
extern const char *const PLAYERFLAG_LIST[];
extern const char *const PLAYERFLAG2_LIST[];
extern const char *const GAMETYPERULE_LIST[];
extern const char *const ML_LIST[]; // Linedef flags
extern const char *const MSF_LIST[]; // Sector flags

View file

@ -159,6 +159,9 @@ enum
// Transfers FOF properties.
ML_TFERLINE = 0x00008000,
// Like ML_WRAPMIDTEX, but invisible wall style instead
ML_MIDTEXINVISWALL = 0x00010000,
};
enum

View file

@ -457,7 +457,7 @@ enum {
*/
void I_Error(const char *error, ...) FUNCIERROR;
FUNCIERROR void ATTRNORETURN I_Error(const char *error, ...);
/** \brief write a message to stderr (use before I_Quit) for when you need to quit with a msg, but need
the return code 0 of I_Quit();
@ -757,8 +757,8 @@ extern int
#define EXP_STABLERATE 3*FRACUNIT/10 // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain
#define EXP_POWER 3*FRACUNIT/100 // adjust to change overall xp volatility
#define EXP_MIN 25 // The min value target
#define EXP_TARGET 120 // Used for grading ...
#define EXP_MAX 120 // The max value displayed by the hud and in the tally screen and GP results screen
#define EXP_TARGET 150 // Used for grading ...
#define EXP_MAX 150 // The max value displayed by the hud and in the tally screen and GP results screen
#ifdef __cplusplus
} // extern "C"

View file

@ -220,6 +220,7 @@ extern boolean imcontinuing; // Temporary flag while continuing
#define ATTACKING_LAP (1<<1)
#define ATTACKING_SPB (1<<2)
extern UINT8 modeattacking;
const char *M_GetRecordMode(void);
// menu demo things
extern UINT8 numDemos;
@ -245,6 +246,10 @@ struct staffsync_t
char name[MAXPLAYERNAME+1];
UINT32 reason;
UINT32 extra;
fixed_t totalerror;
UINT32 numerror;
UINT32 rngerror_presync[32];
UINT32 rngerror_postsync[32];
};
extern staffsync_t staffsync_results[1024];

View file

@ -239,6 +239,7 @@ enum {false = 0, true = 1};
#endif
#define ATTRUNUSED __attribute__((unused))
#define ATTRUNOPTIMIZE __attribute__((optimize("O0")))
#elif defined (_MSC_VER)
#define ATTRNORETURN __declspec(noreturn)
#define ATTRINLINE __forceinline

View file

@ -1593,6 +1593,7 @@ void F_StartGameEnd(void)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeEndScreen();
F_RunWipe(wipe_level_toblack, wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
Music_Stop("credits");
nextmap = NEXTMAP_TITLE;
G_EndGame();

View file

@ -182,9 +182,10 @@ demoghost *ghosts = NULL;
// - 0x000F -- RR 2.4 indev (staff ghosts part 2 - dynslopes thinker fix)
// - 0x0010 -- RR 2.4 rc1 (staff ghosts part 3 - skinlimit raise. don't say we never did anythin for 'ya)
// - 0x0011 -- RR 2.4 rc2 (K_FlipFromObject oversight)
// - 0x0012 -- RR 2.4 rc6 (Waterskii regression from 2.3)
#define MINDEMOVERSION 0x000E
#define DEMOVERSION 0x0011
#define DEMOVERSION 0x0012
boolean G_CompatLevel(UINT16 level)
{
@ -303,18 +304,39 @@ boolean G_ConsiderEndingDemoRead(void)
}
// Demo failed sync during a sync test! Log the failure to be reported later.
static void G_FailStaffSync(staffsync_reason_t reason, UINT32 extra)
static boolean G_FailStaffSync(staffsync_reason_t reason, UINT32 extra)
{
if (demo.attract != DEMO_ATTRACT_OFF) // Don't shout about RNG desyncs in titledemos
return false;
if (!staffsync)
return;
return true;
if (staffsync_results[staffsync_failed].reason != 0)
return;
return false;
if (reason == SYNC_RNG)
{
switch (extra)
{
case PR_ITEM_DEBRIS:
case PR_RANDOMAUDIENCE:
case PR_VOICES:
case PR_DECORATION:
case PR_RANDOMANIM:
CONS_Printf("[!] Ignored desync from RNG class %d\n", extra);
return false;
default:
break;
}
}
staffsync_results[staffsync_failed].map = gamemap;
memcpy(&staffsync_results[staffsync_failed].name, player_names[consoleplayer], sizeof(player_names[consoleplayer]));
staffsync_results[staffsync_failed].reason = reason;
staffsync_results[staffsync_failed].extra = extra;
return true;
}
void G_ReadDemoExtraData(void)
@ -484,13 +506,26 @@ void G_ReadDemoExtraData(void)
{
P_SetRandSeed(static_cast<pr_class_t>(i), rng);
if (demosynced)
if (staffsync)
{
CONS_Alert(CONS_WARNING, "Demo playback has desynced (RNG class %d)!\n", i);
G_FailStaffSync(SYNC_RNG, i);
if (demosynced)
staffsync_results[staffsync_failed].rngerror_presync[i]++;
else
staffsync_results[staffsync_failed].rngerror_postsync[i]++;
}
storesynced = false;
if (demosynced)
{
if (G_FailStaffSync(SYNC_RNG, i))
{
CONS_Alert(CONS_WARNING, "Demo playback has desynced (RNG class %d - %s)!\n", i, rng_class_names[i]);
storesynced = false;
}
}
else
{
storesynced = false;
}
}
}
demosynced = storesynced;
@ -1242,6 +1277,12 @@ void G_ConsGhostTic(INT32 playernum)
}
demosynced = false;
if (staffsync)
{
staffsync_results[staffsync_failed].numerror++;
staffsync_results[staffsync_failed].totalerror += abs(testmo->x - oldghost[playernum].x) + abs(testmo->y - oldghost[playernum].y) + abs(testmo->z - oldghost[playernum].z);
}
P_UnsetThingPosition(testmo);
testmo->x = oldghost[playernum].x;
testmo->y = oldghost[playernum].y;
@ -3269,6 +3310,8 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
// net var data
demobuf.p += CV_LoadDemoVars(demobuf.p);
// Dumb hack for team play desyncs - https://gitlab.com/kart-krew-dev/ring-racers/-/issues/210
g_teamplay = cv_teamplay.value ? 1 : 0;
memset(&grandprixinfo, 0, sizeof grandprixinfo);
if ((demoflags & DF_GRANDPRIX))
@ -3474,15 +3517,7 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
}
// end of player read (the 0xFF marker)
// so this is where we are to read our lua variables (if possible!)
if (demoflags & DF_LUAVARS) // again, used for compability, lua shit will be saved to replays regardless of if it's even been loaded
{
if (!gL) // No Lua state! ...I guess we'll just start one...
LUA_ClearState();
// No modeattacking check, DF_LUAVARS won't be present here.
LUA_UnArchive(&demobuf, false);
}
// see the DF_LUAVARS if later, though.
splitscreen = 0;
@ -3504,6 +3539,18 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
G_InitNew((demoflags & DF_ENCORE) != 0, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
// so this is where we are to read our lua variables (if possible!)
// we read it here because Lua player variables can have mobj references,
// and not having the map loaded causes crashes if that's the case.
if (demoflags & DF_LUAVARS) // again, used for compability, lua shit will be saved to replays regardless of if it's even been loaded
{
if (!gL) // No Lua state! ...I guess we'll just start one...
LUA_ClearState();
// No modeattacking check, DF_LUAVARS won't be present here.
LUA_UnArchive(&demobuf, false);
}
for (i = 0; i < numslots; i++)
{
UINT8 j;
@ -4169,6 +4216,7 @@ boolean G_CheckDemoStatus(void)
if (modeattacking || demo.willsave)
{
demo.willsave = false;
if (demobuf.p)
{
G_SaveDemo();

View file

@ -496,7 +496,11 @@ bademblem:
if (!gonnadrawtime && showownrecord)
{
stickermedalinfo.timetoreach = G_GetBestTime(map);
stickermedalinfo.timetoreach = (encoremode == true)
? mapheaderinfo[map]->records.spbattack.time
: mapheaderinfo[map]->records.timeattack.time;
if (!stickermedalinfo.timetoreach)
stickermedalinfo.timetoreach = UINT32_MAX;
}
if (stickermedalinfo.timetoreach != UINT32_MAX)
@ -584,6 +588,7 @@ static void G_UpdateRecordReplays(void)
char lastdemo[256], bestdemo[256];
const char *modeprefix = "";
// See also M_GetRecordMode
if (encoremode)
{
modeprefix = "spb-";
@ -1413,6 +1418,7 @@ boolean G_Responder(event_t *ev)
if (HU_Responder(ev))
{
hu_keystrokes = true;
chat_keydown = true;
return true; // chat ate the event
}
}
@ -1522,6 +1528,7 @@ boolean G_Responder(event_t *ev)
return true;
case ev_keyup:
chat_keydown = false; // prevents repeat inputs from inputs made with chat open
return false; // always let key up events filter down
case ev_mouse:
@ -1885,7 +1892,7 @@ void G_Ticker(boolean run)
P_MapStart();
if (demo.playback && staffsync && !demosynced)
if (demo.playback && staffsync && !demosynced && false) // We want to assess the magnitude of position desync, don't bail early!
{
G_ClearRetryFlag();
G_StopDemo();
@ -2312,6 +2319,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT16 bigwaypointgap;
INT16 duelscore;
boolean mfdfinish;
roundconditions_t roundconditions;
boolean saveroundconditions;
@ -2406,6 +2415,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
totalring = players[player].totalring;
xtralife = players[player].xtralife;
mfdfinish = players[player].mfdfinish;
pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE|PF_AUTOROULETTE|PF_ANALOGSTICK|PF_AUTORING));
pflags2 = (players[player].pflags2 & (PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERTEMPMUTE | PF2_SERVERMUTE | PF2_SERVERDEAFEN | PF2_STRICTFASTFALL));
@ -2483,6 +2494,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
lastsafecheatcheck = 0;
bigwaypointgap = 0;
duelscore = 0;
mfdfinish = 0;
finalized = false;
@ -2675,10 +2687,12 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->xtralife = xtralife;
p->finalized = finalized;
p->mfdfinish = mfdfinish;
// SRB2kart
p->itemtype = itemtype;
p->itemamount = itemamount;
K_SetPlayerItemAmount(p, itemamount);
p->growshrinktimer = growshrinktimer;
p->karmadelay = 0;
p->eggmanblame = -1;
@ -4057,12 +4071,91 @@ UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolea
void G_AddMapToBuffer(UINT16 map)
{
#if 0
// DEBUG: make nearly everything but four race levels full justPlayed
// to look into what happens when a dedicated runs for seven million years.
INT32 justplayedvalue = TOLMaps(gametype) - VOTE_NUM_LEVELS;
UINT32 tolflag = G_TOLFlag(gametype);
// Find all the maps that are ok
INT32 i;
for (i = 0; i < nummapheaders; i++)
{
if (mapheaderinfo[i] == NULL)
{
continue;
}
if (mapheaderinfo[i]->lumpnum == LUMPERROR)
{
continue;
}
if ((mapheaderinfo[i]->typeoflevel & tolflag) == 0)
{
continue;
}
if (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU)
{
// Don't include hidden
continue;
}
// Only care about restrictions if the host is a listen server.
if (!dedicated)
{
if (!(mapheaderinfo[i]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_VISITED)
&& !(
mapheaderinfo[i]->cup
&& mapheaderinfo[i]->cup->cachedlevels[0] == i
))
{
// Not visited OR head of cup
continue;
}
if ((mapheaderinfo[i]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_BEATEN))
{
// Not completed
continue;
}
}
if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
continue;
}
mapheaderinfo[i]->justPlayed = justplayedvalue;
justplayedvalue -= 1;
if (justplayedvalue <= 0)
break;
}
#else
if (dedicated && D_NumPlayers() == 0)
return;
const size_t upperJustPlayedLimit = TOLMaps(gametype) - VOTE_NUM_LEVELS - 1;
if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map.
{
// Decrement every maps' justPlayed value.
INT32 i;
for (i = 0; i < nummapheaders; i++)
{
// If the map's justPlayed value is higher
// than what it should be, clamp it.
// (Usually a result of SOC files
// manipulating which levels are hidden.)
if (mapheaderinfo[i]->justPlayed > upperJustPlayedLimit)
{
mapheaderinfo[i]->justPlayed = upperJustPlayedLimit;
}
if (mapheaderinfo[i]->justPlayed > 0)
{
mapheaderinfo[i]->justPlayed--;
@ -4071,8 +4164,9 @@ void G_AddMapToBuffer(UINT16 map)
}
// Set our map's justPlayed value.
mapheaderinfo[map]->justPlayed = TOLMaps(gametype) - VOTE_NUM_LEVELS;
mapheaderinfo[map]->justPlayed = upperJustPlayedLimit;
mapheaderinfo[map]->anger = 0; // Reset voting anger now that we're playing it
#endif
}
//
@ -4195,6 +4289,7 @@ void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencor
UINT8 i, levelindex = 0, bonusindex = 0;
UINT8 bonusmodulo = max(1, (cup->numlevels+1)/(cup->numbonus+1));
UINT16 cupLevelNum;
INT32 bonusgt;
// Levels are added to the queue in the following pattern.
// For 5 Race rounds and 2 Bonus rounds, the most common case:
@ -4236,9 +4331,17 @@ void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencor
if (cupLevelNum < nummapheaders)
{
// In the case of Bonus rounds, we simply skip invalid maps.
if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_BATTLE) == TOL_BATTLE)
{
bonusgt = GT_BATTLE;
}
else
{
bonusgt = G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel);
}
G_MapIntoRoundQueue(
cupLevelNum,
G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel),
bonusgt,
setencore, // if this isn't correct, Got_Mapcmd will fix it
false
);
@ -4306,9 +4409,22 @@ void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencor
cupLevelNum = emeraldcup->cachedlevels[CUPCACHE_SPECIAL];
if (cupLevelNum < nummapheaders)
{
// In case of multiple TOLs, prioritize Special, then Versus, then guess.
if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_SPECIAL) == TOL_SPECIAL)
{
bonusgt = GT_SPECIAL;
}
else if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_VERSUS) == TOL_VERSUS)
{
bonusgt = GT_VERSUS;
}
else
{
bonusgt = G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel);
}
G_MapIntoRoundQueue(
cupLevelNum,
G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel),
bonusgt,
setencore, // if this isn't correct, Got_Mapcmd will fix it
true // Rank-restricted!
);
@ -4968,7 +5084,10 @@ void G_AfterIntermission(void)
return;
}
else if (demo.recording && (modeattacking || demo.willsave))
{
demo.willsave = false;
G_SaveDemo();
}
else if (demo.recording)
G_ResetDemoRecording();
@ -5106,6 +5225,9 @@ static void G_DoContinued(void)
// when something new is added.
void G_EndGame(void)
{
// Clean up ACS music remaps.
Music_TuneReset();
// Handle voting
if (nextmap == NEXTMAP_VOTING)
{
@ -5910,7 +6032,7 @@ void G_SetRetryFlag(void)
{
if (retrying == false && grandprixinfo.gp)
{
if (!specialstageinfo.valid)
if (grandprixinfo.eventmode != GPEVENT_SPECIAL)
grandprixinfo.rank.continuesUsed++;
grandprixinfo.rank.levels[grandprixinfo.rank.numLevels].continues++;
}

View file

@ -81,6 +81,8 @@ extern struct menuqueue
UINT8 size;
UINT8 sending;
UINT8 anchor;
boolean clearing;
boolean cupqueue;
roundentry_t entries[ROUNDQUEUE_MAX];
} menuqueue;

View file

@ -1386,8 +1386,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
grTex = HWR_GetTexture(gl_midtexture, gl_sidedef->midtexture);
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
// Check if we should flip tripwire texture vertically for unpegged tripwires
if (R_ShouldFlipTripWire(gl_linedef))
{
// Flip texture coordinates vertically
wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
wallVerts[3].t = wallVerts[2].t = (h - l + texturevpeg) * grTex->scaleY;
}
else
{
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
}
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;
}
@ -1433,8 +1443,19 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
texturevpeg = textureheight[gl_sidedef->midtexture]*repeats - h + polybottom;
else
texturevpeg = polytop - h;
wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
// Apply tripwire flipping for slope correction as well
if (R_ShouldFlipTripWire(gl_linedef))
{
// Flip texture coordinates vertically
wallVerts[1].t = texturevpeg * grTex->scaleY;
wallVerts[2].t = (h - l + texturevpeg) * grTex->scaleY;
}
else
{
wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY;
}
}
wallVerts[2].y = FIXED_TO_FLOAT(h);
@ -1531,8 +1552,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
grTex = HWR_GetTexture(gl_midtexture, gl_sidedef->midtexture);
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
// Check if we should flip tripwire texture vertically for single-sided lines too
if (R_ShouldFlipTripWire(gl_linedef))
{
// Flip texture coordinates vertically
wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
wallVerts[3].t = wallVerts[2].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
}
else
{
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
}
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX;

View file

@ -85,6 +85,7 @@ patch_t *frameslash; // framerate stuff. Used in screen.c
static player_t *plr;
boolean hu_keystrokes; // :)
boolean chat_keydown;
boolean chat_on; // entering a chat message?
boolean g_voicepushtotalk_on; // holding PTT?
static char w_chat[HU_MAXMSGLEN + 1];

View file

@ -124,6 +124,9 @@ typedef enum
// some functions
void HU_AddChatText(const char *text, boolean playsound);
// set true when key is pressed while chat is open
extern boolean chat_keydown;
// set true when entering a chat message
extern boolean chat_on;

View file

@ -92,7 +92,7 @@ void I_OsPolling(void);
/** \brief Called by M_Responder when quit is selected, return exit code 0
*/
void I_Quit(void) FUNCNORETURN;
FUNCNORETURN void ATTRNORETURN I_Quit(void);
typedef enum
{

View file

@ -1229,6 +1229,7 @@ boolean I_InitTcpNetwork(void)
if (M_CheckParm("-server") || dedicated)
{
server = true;
connectedtodedicated = dedicated;
// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
// to connect before starting.

View file

@ -614,6 +614,7 @@ char sprnames[NUMSPRITES + 1][5] =
"EXPC",
"TWBB",
"TWOK",
"TW_L",
@ -2225,6 +2226,7 @@ state_t states[NUMSTATES] =
{SPR_AMPD, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_AMPAURA
{SPR_AMPB, FF_FULLBRIGHT|FF_ADD|FF_PAPERSPRITE|2, -1, {NULL}, 4, 2, S_NULL}, // S_AMPBURST
{SPR_TWBB, FF_ADD|FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SONICBOOM
{SPR_TWOK, FF_FULLBRIGHT|FF_ANIMATE|0, 56, {NULL}, 55, 1, S_NULL}, // S_TRIPWIREOK
{SPR_TW_L, FF_FULLBRIGHT|FF_ANIMATE|0, 56, {NULL}, 55, 1, S_NULL}, // S_TRIPWIRELOCKOUT
@ -13778,7 +13780,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -13805,7 +13807,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -13913,7 +13915,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -13940,7 +13942,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -13967,7 +13969,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -13994,7 +13996,34 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_SONICBOOM
-1, // doomednum
S_SONICBOOM, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
67*FRACUNIT, // radius
67*FRACUNIT, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14021,7 +14050,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14048,7 +14077,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14075,7 +14104,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14102,7 +14131,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14129,7 +14158,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14156,7 +14185,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14183,7 +14212,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14210,7 +14239,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -14237,7 +14266,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -17532,7 +17561,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -17559,7 +17588,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
MF_NOGRAVITY|MF_SPECIAL|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -17586,7 +17615,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_supert, // activesound
MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -17613,7 +17642,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPHEIGHT|MF_SPECIAL|MF_NOGRAVITY, // flags
MF_NOCLIPHEIGHT|MF_SPECIAL|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -17640,7 +17669,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -17829,7 +17858,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SPECIAL|MF_SHOOTABLE, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SPECIAL|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -18991,7 +19020,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL, // raisestate
},
@ -19019,7 +19048,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL, // raisestate
},
@ -19047,7 +19076,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL, // raisestate
},
@ -19452,7 +19481,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTPUNT, // flags
MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTPUNT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -19479,7 +19508,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -19614,7 +19643,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -19668,7 +19697,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -19695,7 +19724,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -20100,7 +20129,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags
MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -20127,7 +20156,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -22735,7 +22764,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_EXP
@ -22761,7 +22790,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_FLYBOT767
@ -22787,7 +22816,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_STONESHOE

View file

@ -1155,6 +1155,7 @@ typedef enum sprite
SPR_EXPC,
SPR_TWBB, // Sonic Boom
SPR_TWOK, // Tripwire OK
SPR_TW_L, // Tripwire Lockout
@ -2681,6 +2682,7 @@ typedef enum state
S_AMPAURA,
S_AMPBURST,
S_SONICBOOM,
S_TRIPWIREOK,
S_TRIPWIRELOCKOUT,
@ -4706,6 +4708,7 @@ typedef enum mobj_type
MT_AMPAURA,
MT_AMPBURST,
MT_SONICBOOM,
MT_TRIPWIREOK,
MT_TRIPWIRELOCKOUT,

View file

@ -133,8 +133,12 @@ void K_CheckBumpers(void)
{
UINT8 i;
UINT8 numingame = 0;
UINT8 rednumingame = 0;
UINT8 bluenumingame = 0;
UINT8 nobumpers = 0;
UINT8 eliminated = 0;
UINT8 redeliminated = 0;
UINT8 blueeliminated = 0;
SINT8 kingofthehill = -1;
if (!(gametyperules & GTR_BUMPERS))
@ -143,6 +147,8 @@ void K_CheckBumpers(void)
if (gameaction == ga_completed)
return;
boolean team = G_GametypeHasTeams();
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator) // not even in-game
@ -152,6 +158,11 @@ void K_CheckBumpers(void)
return;
numingame++;
if (team)
{
if (players[i].team == 1) rednumingame++;
if (players[i].team == 2) bluenumingame++;
}
if (!P_MobjWasRemoved(players[i].mo) && players[i].mo->health <= 0) // if you don't have any bumpers, you're probably not a winner
{
@ -161,6 +172,11 @@ void K_CheckBumpers(void)
if (players[i].pflags & PF_ELIMINATED)
{
eliminated++;
if (team)
{
if (players[i].team == 1) redeliminated++;
else if (players[i].team == 2) blueeliminated++;
}
}
else
{
@ -168,6 +184,12 @@ void K_CheckBumpers(void)
}
}
boolean teamwin = false;
if (team && (rednumingame - redeliminated == 0 || bluenumingame - blueeliminated == 0))
{
teamwin = true;
}
if (numingame - eliminated == 2 && battleovertime.enabled && battleovertime.radius <= BARRIER_MIN_RADIUS)
{
Music_Stop("battle_overtime");
@ -186,9 +208,28 @@ void K_CheckBumpers(void)
{
// If every other player is eliminated, the
// last player standing wins by default.
if (eliminated >= numingame - 1)
// Or, if an entire team is eliminated.
if (eliminated >= numingame - 1 || teamwin)
{
K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL);
if (teamwin)
{
// Find the player with the highest individual score
UINT32 highestscore = 0;
UINT32 highestplayer = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].score > highestscore)
{
highestplayer = i;
highestscore = players[i].score;
}
}
K_EndBattleRound(&players[highestplayer]);
}
else
{
K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL);
}
return;
}
}
@ -699,8 +740,11 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
case 0:
P_SetMobjState(mo, S_OVERTIME_BULB1);
if (leveltime & 1)
mo->frame += 1;
if (!cv_reducevfx.value)
{
if (leveltime & 1)
mo->frame += 1;
}
//P_SetScale(mo, mapobjectscale);
zpos += 35 * mo->scale * flip;
@ -708,10 +752,13 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
case 1:
P_SetMobjState(mo, S_OVERTIME_LASER);
if (leveltime & 1)
mo->frame += 3;
else
mo->frame += (leveltime / 2) % 3;
if (!cv_reducevfx.value)
{
if (leveltime & 1)
mo->frame += 3;
else
mo->frame += (leveltime / 2) % 3;
}
//P_SetScale(mo, scale);
zpos += 346 * mo->scale * flip;
@ -722,8 +769,11 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
case 2:
P_SetMobjState(mo, S_OVERTIME_BULB2);
if (leveltime & 1)
mo->frame += 1;
if (!cv_reducevfx.value)
{
if (leveltime & 1)
mo->frame += 1;
}
//P_SetScale(mo, mapobjectscale);
break;
@ -988,6 +1038,8 @@ boolean K_EndBattleRound(player_t *victor)
// exiting, the round has already ended.
return false;
}
UINT32 topscore = 0;
if (gametyperules & GTR_POINTLIMIT)
{
@ -996,7 +1048,27 @@ boolean K_EndBattleRound(player_t *victor)
// TODO: a "won the round" bool used for sorting
// position / intermission, so we aren't completely
// clobbering the individual scoring.
victor->roundscore = 100;
// This isn't quite the above TODO but it's something?
// For purposes of score-to-EXP conversion, we need to not lock the winner to an arbitrarily high score.
// Instead, let's find the highest score, and if they're not the highest scoring player,
// give them a bump so they *are* the highest scoring player.
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
if ((&players[i])->roundscore > topscore)
{
topscore = (&players[i])->roundscore;
}
}
if (victor->roundscore <= topscore)
{
victor->roundscore = topscore + 3;
}
if (G_GametypeHasTeams() == true && victor->team != TEAM_UNASSIGNED)
{

View file

@ -55,30 +55,16 @@ extern "C" consvar_t cv_forcebots;
--------------------------------------------------*/
void K_SetNameForBot(UINT8 newplayernum, const char *realname)
{
UINT8 ix = MAXPLAYERS;
// These names are generally sourced from skins.
I_Assert(MAXPLAYERNAME >= SKINNAMESIZE+2);
boolean canApplyNameChange = true;
if (netgame == true)
{
// Check if a player is currently using the name, case-insensitively.
// We only do this if online, because it doesn't matter if there are multiple Eggrobo *off*line.
// See also EnsurePlayerNameIsGood
for (ix = 0; ix < MAXPLAYERS; ix++)
{
if (ix == newplayernum)
continue;
if (playeringame[ix] == false)
continue;
if (strcasecmp(realname, player_names[ix]) != 0)
continue;
break;
}
canApplyNameChange = IsPlayerNameUnique(realname, newplayernum);
}
if (ix == MAXPLAYERS)
if (canApplyNameChange)
{
// No conflict detected!
sprintf(player_names[newplayernum], "%s", realname);
@ -241,7 +227,7 @@ void K_UpdateMatchRaceBots(void)
{
const UINT16 defaultbotskin = R_BotDefaultSkin();
UINT8 difficulty;
UINT8 pmax = (dedicated ? MAXPLAYERS-1 : MAXPLAYERS);
UINT8 pmax = (InADedicatedServer() ? MAXPLAYERS-1 : MAXPLAYERS);
UINT8 numplayers = 0;
UINT8 numbots = 0;
UINT8 numwaiting = 0;
@ -357,12 +343,7 @@ void K_UpdateMatchRaceBots(void)
if (numbots < wantedbots)
{
// We require MORE bots!
UINT8 newplayernum = 0;
if (dedicated)
{
newplayernum = 1;
}
UINT8 newplayernum = InADedicatedServer() ? 1 : 0;
// Rearrange usable bot skins list to prevent gaps for randomised selection
if (tutorialchallenge == TUTORIALSKIP_INPROGRESS)

View file

@ -721,6 +721,11 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2)
t2->angle += ANGLE_180;
if (t2->type == MT_JAWZ)
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
// Reflected item becomes owned by the DT owner, so it becomes dangerous the the thrower
if (t1->target && !P_MobjWasRemoved(t1->target))
P_SetTarget(&t2->target, t1->target);
t2->threshold = 10;
}
@ -1034,10 +1039,6 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
}
// if you're here, you're getting hit
// Damage is a bit hacky, we want only a small loss-of-control
// while still behaving as if it's a "real" hit.
P_PlayRinglossSound(victim);
P_PlayerRingBurst(victimPlayer, 5);
P_DamageMobj(victim, shield, attacker, 1, DMG_WHUMBLE);
K_DropPowerUps(victimPlayer);
@ -1293,8 +1294,15 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
auto doStumble = [](mobj_t *t1, mobj_t *t2)
{
K_StumblePlayer(t2->player);
K_SpawnAmps(t1->player, K_PvPAmpReward(20, t1->player, t2->player), t2);
if (gametyperules & GTR_BUMPERS)
{
K_StumblePlayer(t2->player);
K_SpawnAmps(t1->player, K_PvPAmpReward(20, t1->player, t2->player), t2);
}
else
{
P_DamageMobj(t2, t1, t1, 1, DMG_WHUMBLE);
}
};
if (forEither(shouldStumble, doStumble))
@ -1325,7 +1333,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
bool stung = false;
if (RINGTOTAL(t2->player) <= 0 && t2->health == 1 && !(t2->player->pflags2 & PF2_UNSTINGABLE))
if (RINGTOTAL(t2->player) <= 0 && t2->player->ringboostinprogress == 0 && t2->health == 1 && !(t2->player->pflags2 & PF2_UNSTINGABLE))
{
P_DamageMobj(t2, t1, t1, 1, DMG_STING|DMG_WOMBO);
// CONS_Printf("T2 stung\n");

View file

@ -477,10 +477,8 @@ void K_HandleFollower(player_t *player)
if (fl->mode == FOLLOWERMODE_GROUND)
{
sector_t *sec = R_PointInSubsector(sx, sy)->sector;
fh = min(fh, P_GetFloorZ(player->follower, sec, sx, sy, NULL));
ch = max(ch, P_GetCeilingZ(player->follower, sec, sx, sy, NULL) - ourheight);
fh = min(fh, P_FloorzAtPos(sx, sy, player->follower->z, ourheight));
ch = max(ch, P_CeilingzAtPos(sx, sy, player->follower->z, ourheight) - ourheight);
if (P_IsObjectOnGround(player->mo) == false)
{

View file

@ -60,7 +60,7 @@ INT16 K_CalculateGPRankPoints(UINT16 exp, UINT8 position, UINT8 numplayers)
{
INT16 points;
if (position >= numplayers || position == 0)
if (position > numplayers || position == 0)
{
// Invalid position, no points
return 0;
@ -858,7 +858,12 @@ void K_RetireBots(void)
std::stable_sort(humans.begin(), humans.end(), CompareReplacements);
std::stable_sort(bots.begin(), bots.end(), CompareReplacements);
if (G_GametypeHasSpectators() == true && grandprixinfo.gp == false && cv_shuffleloser.value != 0)
// If a player spectated mid-race or mid-duel, they will be placed in-game by K_CheckSpectateStatus,
// and their position will be set to 0. Since we're only replacing one player as of now, there's no need
// to do anything; a player has already been replaced.
bool player_already_joined = (!humans.empty() && humans[0]->position == 0);
if (G_GametypeHasSpectators() == true && grandprixinfo.gp == false && !player_already_joined && cv_shuffleloser.value != 0)
{
// While joiners and players still exist, insert joiners.

View file

@ -22,6 +22,26 @@
#include "s_sound.h"
#include "m_easing.h"
// Use for adding hitlag that should be mostly ignored by impervious players.
// (Currently only called in power clash, but in the future...?)
void K_AddHitLagFromCollision(mobj_t *mo, INT32 tics)
{
boolean doAnything = true;
if (mo->player == NULL || mo->type != MT_PLAYER)
doAnything = false;
else if (!K_PlayerCanPunt(mo->player))
doAnything = false;
if (!doAnything)
{
K_AddHitLag(mo, tics, false);
return;
}
K_AddHitLag(mo, min(tics, 2), false);
}
/*--------------------------------------------------
void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage)
@ -34,9 +54,6 @@ void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage)
return;
}
if (mo->player && mo->player->overshield)
tics = min(tics, 3);
mo->hitlag += tics;
mo->hitlag = min(mo->hitlag, MAXHITLAGTICS);

View file

@ -26,6 +26,8 @@ extern "C" {
#define NUM_HITLAG_STATES (9)
#define NUM_HITLAG_SOUNDS (4)
void K_AddHitLagFromCollision(mobj_t *mo, INT32 tics);
/*--------------------------------------------------
void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage);

View file

@ -3307,19 +3307,13 @@ static void K_drawKartEmeralds(void)
INT32 K_GetTransFlagFromFixed(fixed_t value, boolean midrace)
{
fixed_t base = midrace ? GRADINGFACTORSOFTCAP : FRACUNIT;
fixed_t base = FRACUNIT;
value = std::clamp(value, base - FRACUNIT/2, base + FRACUNIT/2);
// Calculate distance from "base""
fixed_t distance = abs(base - value);
if (midrace)
{
if (value > base)
distance = FixedMul(distance, GRADINGFACTORCAPSTRENGTH);
}
distance = std::clamp(distance, 0, FRACUNIT/2);
// Map the distance to 0-10 range (10 = closest to 1.0, 0 = farthest from 1.0)
@ -4241,11 +4235,20 @@ static boolean K_drawKartLaps(void)
K_DrawMarginSticker(fr-1+(flipflag ? 2 : 0), fy+1, 25+bump, V_HUDTRANS|V_SLIDEIN|splitflags, true, flipflag);
// WHAT IS THIS?
// WHAT ARE YOU FUCKING TALKING ABOUT?
V_DrawMappedPatch(fr, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[1], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE));
auto transflag = K_GetTransFlagFromFixed(K_EffectiveGradingFactor(stplyr), true);
skincolornum_t overlaycolor = K_EffectiveGradingFactor(stplyr) < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE);
V_DrawMappedPatch(fr, fy, transflag|V_SLIDEIN|splitflags, kp_exp[1], colormap);
if (franticitems)
{
V_DrawMappedPatch(fr, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[1], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PURPLE, GTC_CACHE));
}
else
{
V_DrawMappedPatch(fr, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[1], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE));
auto transflag = K_GetTransFlagFromFixed(K_EffectiveGradingFactor(stplyr), true);
skincolornum_t overlaycolor = K_EffectiveGradingFactor(stplyr) < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE);
V_DrawMappedPatch(fr, fy, transflag|V_SLIDEIN|splitflags, kp_exp[1], colormap);
}
// EXP
@ -4263,12 +4266,19 @@ static boolean K_drawKartLaps(void)
if (!drewsticker)
K_DrawSticker(LAPS_X+13, LAPS_Y+5, 25+bump, V_HUDTRANS|V_SLIDEIN|splitflags, false);
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[0], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE));
auto transflag = K_GetTransFlagFromFixed(K_EffectiveGradingFactor(stplyr), true);
skincolornum_t overlaycolor = K_EffectiveGradingFactor(stplyr) < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE);
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, transflag|V_SLIDEIN|splitflags, kp_exp[0], colormap);
if (franticitems)
{
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[0], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PURPLE, GTC_CACHE));
}
else
{
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[0], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE));
auto transflag = K_GetTransFlagFromFixed(K_EffectiveGradingFactor(stplyr), true);
skincolornum_t overlaycolor = K_EffectiveGradingFactor(stplyr) < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE);
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, transflag|V_SLIDEIN|splitflags, kp_exp[0], colormap);
}
using srb2::Draw;
Draw row = Draw(LAPS_X+23+bump, LAPS_Y+3).flags(V_HUDTRANS|V_SLIDEIN|splitflags|danceflag).font(Draw::Font::kThinTimer).colorize(dancecolor);
@ -4304,6 +4314,20 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
boolean colorring = false;
INT32 ringx = 0, fy = 0;
UINT16 superringcolor = SKINCOLOR_SAPPHIRE;
if (stplyr->momentboost)
{
if (!cv_reducevfx.value)
{
if (leveltime % 2)
superringcolor = SKINCOLOR_GOLD;
}
else
{
superringcolor = SKINCOLOR_GOLD;
}
}
rn[0] = ((abs(stplyr->hudrings) / 10) % 10);
rn[1] = (abs(stplyr->hudrings) % 10);
@ -4456,7 +4480,7 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
if (stplyr->superringdisplay && !(stplyr->superringalert % 2))
{
using srb2::Draw;
Draw row = Draw(fr+19+superoffset, fy).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kPing).colorize(SKINCOLOR_SAPPHIRE);
Draw row = Draw(fr+19+superoffset, fy).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kPing).colorize(superringcolor);
row.text("+{:01}", abs(stplyr->superringdisplay));
}
}
@ -4563,7 +4587,7 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
if (stplyr->superringdisplay && !(stplyr->superringalert % 2))
{
using srb2::Draw;
Draw row = Draw(LAPS_X+23+3+15, fy-4).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer).colorize(SKINCOLOR_SAPPHIRE);
Draw row = Draw(LAPS_X+23+3+15, fy-4).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer).colorize(superringcolor);
row.text("+{:01}", abs(stplyr->superringdisplay));
}
}
@ -5125,7 +5149,7 @@ static void K_drawKartWanted(void)
static void K_drawKartPlayerCheck(void)
{
const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
const fixed_t maxdistance = FixedMul(2000 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
UINT8 i;
INT32 splitflags = V_SNAPTOBOTTOM|V_SPLITSCREEN;
fixed_t y = CHEK_Y * FRACUNIT;
@ -5183,13 +5207,15 @@ static void K_drawKartPlayerCheck(void)
distance = R_PointToDist2(pPos.x, pPos.y, v.x, v.y);
colormap = R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(checkplayer->mo->color), GTC_CACHE);
if (distance > maxdistance)
{
// Too far away
continue;
}
if ((checkplayer->invincibilitytimer <= 0) && (leveltime & 2))
if ((checkplayer->invincibilitytimer <= 0) && (leveltime & 2) && !(cv_reducevfx.value))
{
pnum++; // white frames
}
@ -5202,12 +5228,18 @@ static void K_drawKartPlayerCheck(void)
{
pnum += 2;
}
else if ((checkplayer->instaWhipCharge) && !(cv_reducevfx.value))
{
if (leveltime & 2)
R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(SKINCOLOR_WHITE), GTC_CACHE);
else
R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(SKINCOLOR_BLACK), GTC_CACHE);
}
K_ObjectTracking(&result, &v, true);
if (result.onScreen == true)
{
colormap = R_GetTranslationColormap(TC_DEFAULT, static_cast<skincolornum_t>(checkplayer->mo->color), GTC_CACHE);
V_DrawFixedPatch(result.x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN|splitflags, kp_check[pnum], colormap);
}
}
@ -6833,7 +6865,13 @@ static void K_drawKartStartCountdown(void)
}
}
if ((leveltime % (2*5)) / 5) // blink
int flashrate = 5;
if (cv_reducevfx.value)
{
flashrate = 35;
}
if ((leveltime % (2*flashrate)) / flashrate) // blink
pnum += 5;
if (r_splitscreen) // splitscreen
pnum += 10;
@ -7172,11 +7210,13 @@ static void K_drawLapStartAnim(void)
oldval = (188 + (32 * std::max(0, progressOld - 76))) * FRACUNIT;
interpx = R_InterpolateFixed(oldval, newval);
UINT32 sanitizedlaps = std::min((UINT32)99, (UINT32)stplyr->latestlap);
V_DrawFixedPatch(
interpx, // 194
30*FRACUNIT, // 24
FRACUNIT, V_SNAPTOTOP|hudtransflags,
kp_lapanim_number[(((UINT32)stplyr->latestlap) / 10)][std::min(progress/2-8, 2)], NULL);
kp_lapanim_number[(sanitizedlaps / 10)][std::min(progress/2-8, 2)], NULL);
if (progress/2-10 >= 0)
{
@ -7188,7 +7228,7 @@ static void K_drawLapStartAnim(void)
interpx, // 221
30*FRACUNIT, // 24
FRACUNIT, V_SNAPTOTOP|hudtransflags,
kp_lapanim_number[(((UINT32)stplyr->latestlap) % 10)][std::min(progress/2-10, 2)], NULL);
kp_lapanim_number[(sanitizedlaps % 10)][std::min(progress/2-10, 2)], NULL);
}
}
}
@ -7311,7 +7351,21 @@ static void K_drawDistributionDebugger(void)
return;
}
K_FillItemRouletteData(stplyr, &rouletteData, false, true);
{
// GROSS GROSS GROSS GROSS copypaste from K_FillItemRoulette
// but without the potential for Lua side-effects etc.
// This sucks the ass.
K_InitRoulette(&rouletteData);
rouletteData.baseDist = K_UndoMapScaling(stplyr->distancetofinish);
if (stplyr->pflags & PF_AUTOROULETTE)
rouletteData.autoroulette = true;
K_CalculateRouletteSpeed(&rouletteData);
K_FillItemRouletteData(stplyr, &rouletteData, false, true);
}
if (cv_kartdebugdistribution.value <= 1)
return;
@ -7772,7 +7826,7 @@ void K_drawKartHUD(void)
return;
}
if (staffsync)
if (staffsync && staffsync_total)
{
V_DrawFadeScreen(31, 8);
V_DrawCenteredGamemodeString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 - 30, 0, 0, "Staff Ghost Sync Test");
@ -7970,8 +8024,16 @@ void K_drawKartHUD(void)
std::string arrow = (ahead == 1 || ahead == -2) ? "(" : ")";
// vibes offset
row.x(-35).colormap(skincolor).patch(R_CanShowSkinInDemo(skin) ? faceprefix[skin][FACE_MINIMAP] : kp_unknownminimap);
if (skin != -1)
{
// vibes offset
row.x(-35).colormap(skincolor).patch(R_CanShowSkinInDemo(skin) ? faceprefix[skin][FACE_MINIMAP] : kp_unknownminimap);
}
else
{
ahead = -1;
}
if (pos > 1)
row.x(-35).font(Draw::Font::kPing).text(va("%d", pos));

File diff suppressed because it is too large Load diff

View file

@ -41,8 +41,8 @@ Make sure this matches the actual number of states
#define INSTAWHIP_RINGDRAINEVERY (TICRATE/2)
#define INSTAWHIP_HOLD_DELAY (TICRATE*2)
// MUST be longer or equal to INSTAWHIP_CHARGETIME.
#define INSTAWHIP_TETHERBLOCK (TICRATE*4)
#define PUNISHWINDOW (10*TICRATE/10)
#define INSTAWHIP_TETHERBLOCK (3*TICRATE/4)
#define PUNISHWINDOW (G_CompatLevel(0x0010) ? 7*TICRATE/10 : 10*TICRATE/10)
#define BAIL_MAXCHARGE (84) // tics to bail when in painstate nad in air, on ground is half, if you touch this, also update Obj_BailChargeThink synced animation logic
#define BAIL_DROP (FRACUNIT) // How many rings it has to drop before stun starts
@ -57,6 +57,8 @@ Make sure this matches the actual number of states
#define MINCOMBOFLOAT (mapobjectscale*1)
#define MAXCOMBOTIME (TICRATE*4)
#define STARTBOOST_DURATION (125)
#define TIMEATTACK_START (TICRATE*10)
#define LIGHTNING_CHARGE (TICRATE*2)
@ -76,7 +78,7 @@ Make sure this matches the actual number of states
#define EARLY_ITEM_FLICKER (NUMTRANSMAPS)
#define TRIPWIRE_OK_SOUND (sfx_s3k40)
#define TRIPWIRE_OK_SOUND (sfx_sonbo2)
#define TRIPWIRE_NG_SOUND (sfx_gshaf)
// 2023-08-26 +ang20 to Sal's OG values to make them friendlier - Tyron
@ -105,7 +107,7 @@ Make sure this matches the actual number of states
#define MAXTOPACCEL (12*FRACUNIT)
#define TOPACCELREGEN (FRACUNIT/16)
#define BUBBLESCAM (4)
#define BUBBLESCAM (4*FRACUNIT)
// Handling boosts and sliptide conditions got weird.
// You must be under a handling boost of at least SLIPTIDEHANDLING to sliptide.
@ -123,6 +125,11 @@ Make sure this matches the actual number of states
#define AUTORESPAWN_TIME (10*TICRATE)
#define AUTORESPAWN_THRESHOLD (7*TICRATE)
UINT8 K_SetPlayerItemAmount(player_t *player, INT32 amount);
UINT8 K_SetPlayerBackupItemAmount(player_t *player, INT32 amount);
UINT8 K_AdjustPlayerItemAmount(player_t *player, INT32 amount);
UINT8 K_AdjustPlayerBackupItemAmount(player_t *player, INT32 amount);
angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed);
void K_PopBubbleShield(player_t *player);
@ -132,11 +139,10 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt);
boolean K_InRaceDuel(void);
player_t *K_DuelOpponent(player_t *player);
fixed_t K_FinalCheckpointPower(void);
fixed_t K_EffectiveGradingFactor(const player_t *player);
#define MINGRADINGFACTOR (FRACUNIT/2)
#define MINFRANTICFACTOR (8*FRACUNIT/10)
#define GRADINGFACTORSOFTCAP (FRACUNIT)
#define GRADINGFACTORCAPSTRENGTH (3*FRACUNIT)
void K_TimerReset(void);
void K_TimerInit(void);
@ -145,7 +151,7 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player);
void K_ReduceVFXForEveryone(mobj_t *mo);
boolean K_IsPlayerLosing(player_t *player);
fixed_t K_PlayerScamPercentage(const player_t *player, UINT8 mult);
fixed_t K_PlayerScamPercentage(const player_t *player, fixed_t mult);
fixed_t K_GetKartGameSpeedScalar(SINT8 value);
INT32 K_GetShieldFromItem(INT32 item);
@ -296,6 +302,7 @@ boolean K_PlayerEBrake(const player_t *player);
boolean K_PlayerGuard(const player_t *player);
SINT8 K_Sliptiding(const player_t *player);
boolean K_FastFallBounce(player_t *player);
void K_DappleEmployment(player_t *player);
fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original);
void K_AdjustPlayerFriction(player_t *player);
void K_MoveKartPlayer(player_t *player, boolean onground);
@ -347,7 +354,7 @@ boolean K_ThunderDome(void);
boolean K_PlayerCanUseItem(player_t *player);
fixed_t K_GetGradingFactorAdjustment(player_t *player);
fixed_t K_GetGradingFactorAdjustment(player_t *player, UINT32 gradingpoint);
fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max);
UINT16 K_GetEXP(player_t *player);

View file

@ -661,7 +661,7 @@ typedef enum
MA_NO
} manswer_e;
#define MAXMENUMESSAGE 256
#define MAXMENUMESSAGE 448
#define MENUMESSAGECLOSE 2
extern struct menumessage_s
{
@ -748,7 +748,7 @@ void M_SetMenuDelay(UINT8 i);
void M_SortServerList(void);
void M_UpdateMenuCMD(UINT8 i, boolean bailrequired);
void M_UpdateMenuCMD(UINT8 i, boolean bailrequired, boolean chat_open);
boolean M_Responder(event_t *ev);
boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt);
boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt);
@ -769,6 +769,7 @@ void M_StartControlPanel(void);
void M_ValidateRestoreMenu(void);
menu_t *M_SpecificMenuRestore(menu_t *torestore);
void M_ClearMenus(boolean callexitmenufunc);
void M_ClearMenusNoTitle(boolean callexitmenufunc);
void M_SelectableClearMenus(INT32 choice);
void M_SetupNextMenu(menu_t *menudef, boolean nofade);
void M_GoBack(INT32 choice);
@ -960,6 +961,10 @@ void M_MenuToLevelPreamble(UINT8 ssplayers, boolean nowipe);
void M_LevelSelected(INT16 add, boolean menuupdate);
boolean M_LevelSelectCupSwitch(boolean next, boolean skipones);
void M_LevelConfirmHandler(void);
void M_ClearQueueHandler(void);
void M_CupQueueHandler(cupheader_t *cup);
// dummy consvars for GP & match race setup
extern consvar_t cv_dummygpdifficulty;
extern consvar_t cv_dummykartspeed;

View file

@ -2315,13 +2315,24 @@ static void M_DrawCharSelectCursor(UINT8 num)
}
else if (p->mdepth > CSSTEP_CHARS)
{
V_DrawMappedPatch(x, y, 0, W_CachePatchName(selectframesa[setup_animcounter % SELECTLEN], PU_CACHE), colormap);
if (selectframesb[(setup_animcounter-1) % SELECTLEN] != NULL)
V_DrawMappedPatch(x, y, V_TRANSLUCENT, W_CachePatchName(selectframesb[(setup_animcounter-1) % SELECTLEN], PU_CACHE), colormap);
if (cv_reducevfx.value)
{
V_DrawMappedPatch(x, y, 0, W_CachePatchName(selectframesa[0], PU_CACHE), colormap);
}
else
{
V_DrawMappedPatch(x, y, 0, W_CachePatchName(selectframesa[setup_animcounter % SELECTLEN], PU_CACHE), colormap);
if (selectframesb[(setup_animcounter-1) % SELECTLEN] != NULL)
V_DrawMappedPatch(x, y, V_TRANSLUCENT, W_CachePatchName(selectframesb[(setup_animcounter-1) % SELECTLEN], PU_CACHE), colormap);
}
}
else
{
V_DrawMappedPatch(x, y, 0, W_CachePatchName(idleframes[setup_animcounter % IDLELEN], PU_CACHE), colormap);
if (cv_reducevfx.value)
V_DrawMappedPatch(x, y, 0, W_CachePatchName(idleframes[0], PU_CACHE), colormap);
else
V_DrawMappedPatch(x, y, 0, W_CachePatchName(idleframes[setup_animcounter % IDLELEN], PU_CACHE), colormap);
}
if (p->mdepth < CSSTEP_READY)
@ -3329,6 +3340,21 @@ void M_DrawCupSelect(void)
M_DrawCupPreview(y, &templevelsearch);
M_DrawCupTitle(120 - ty, &templevelsearch);
const char *worktext = "Undo";
if (menuqueue.size)
worktext = "Undo";
else if (roundqueue.size)
worktext = "Clear Queue";
if (levellist.canqueue)
{
K_DrawGameControl(BASEVIDWIDTH/2, 6-ty, 0, va("%s Queue Cup<white> %s %s",
(templevelsearch.cup && templevelsearch.cup != &dummy_lostandfound && !roundqueue.size) ? "<z_animated>" : "<z_pressed><gray>",
(roundqueue.size || menuqueue.size) ? "<c_animated>" : "<c_pressed><gray>",
worktext), 1, TINY_FONT, 0);
}
if (templevelsearch.grandprix == false && templevelsearch.cup != NULL)
{
@ -5659,22 +5685,25 @@ void M_DrawProfileControls(void)
help = va("6Bt. (Auto): Tries to guess your 6-button pad's layout.");
break;
case 4:
help = va("6Bt. (A): Saturn buttons, Retro-Bit Wired DInput layout.");
help = va("6Bt. (A): Saturn (Retro-Bit Wired DInput) - C/Z = RB/RT");
break;
case 5:
help = va("6Bt. (B): Saturn buttons, Retro-Bit Wireless DInput layout.");
help = va("6Bt. (B): Saturn (Retro-Bit Wireless DInput) - C/Z = LB/RB");
break;
case 6:
help = va("6Bt. (C): Saturn buttons, Retro-Bit XInput layout.");
help = va("6Bt. (C): Saturn (Retro-Bit XInput) - C/Z = RT/LT");
break;
case 7:
help = va("6Bt. (D): Saturn buttons, arcade/8BitDo layout. (C/Z = RT/RB)");
help = va("6Bt. (D): Saturn (arcade / 8BitDo) - C/Z = RT/RB");
break;
case 8:
help = va("6Bt. (E): Saturn buttons, Hori/M30X layout. (LB/LT = LS/RS)");
help = va("6Bt. (E): Saturn (Hori/M30X) - C/Z = RT/RB, LB/LT = LS/RS");
break;
case 9:
help = va("6Bt. (F): Saturn buttons, Mayflash layout. (C/Z = RS/LS)");
help = va("6Bt. (F): Saturn (Mayflash) - C/Z = RS/LS");
break;
case 10:
help = va("6Bt. (G): Saturn (orig M30) - C/Z = RB/LB");
break;
}
@ -6092,6 +6121,14 @@ static char *M_GetGameplayMode(void)
return va("Relaxed");
}
if (franticitems)
{
if (cv_4thgear.value)
return va("4th Gear! Frantic!");
else
return va("Gear %d - Frantic\n", gamespeed+1);
}
if (cv_4thgear.value)
return va("4th Gear!");

View file

@ -912,10 +912,6 @@ void M_ClearMenus(boolean callexitmenufunc)
if (currentMenu->quitroutine && callexitmenufunc && !currentMenu->quitroutine())
return; // we can't quit this menu (also used to set parameter from the menu)
#ifndef DC // Save the config file. I'm sick of crashing the game later and losing all my changes!
COM_BufAddText(va("saveconfig \"%s\" -silent\n", configfile));
#endif //Alam: But not on the Dreamcast's VMUs
currentMenu->lastOn = itemOn;
if (gamestate == GS_MENU) // Back to title screen
@ -934,6 +930,24 @@ void M_ClearMenus(boolean callexitmenufunc)
menuactive = false;
}
void M_ClearMenusNoTitle(boolean callexitmenufunc)
{
if (!menuactive)
return;
CON_ClearHUD();
if (currentMenu->quitroutine && callexitmenufunc && !currentMenu->quitroutine())
return; // we can't quit this menu (also used to set parameter from the menu)
currentMenu->lastOn = itemOn;
M_AbortVirtualKeyboard();
menumessage.active = false;
menuactive = false;
}
void M_SelectableClearMenus(INT32 choice)
{
(void)choice;
@ -1070,7 +1084,7 @@ void M_SetMenuDelay(UINT8 i)
}
}
void M_UpdateMenuCMD(UINT8 i, boolean bailrequired)
void M_UpdateMenuCMD(UINT8 i, boolean bailrequired, boolean chat_open)
{
UINT8 mp = max(1, setup_numplayers);
@ -1083,6 +1097,10 @@ void M_UpdateMenuCMD(UINT8 i, boolean bailrequired)
menucmd[i].buttonsHeld = menucmd[i].buttons;
menucmd[i].buttons = 0;
// Eat inputs made when chat is open
if (chat_open && pausemenu.closing)
return;
if (G_PlayerInputDown(i, gc_screenshot, mp)) { menucmd[i].buttons |= MBT_SCREENSHOT; }
if (G_PlayerInputDown(i, gc_startmovie, mp)) { menucmd[i].buttons |= MBT_STARTMOVIE; }
if (G_PlayerInputDown(i, gc_startlossless, mp)) { menucmd[i].buttons |= MBT_STARTLOSSLESS; }

View file

@ -384,14 +384,20 @@ void K_UpdatePowerLevels(player_t *player, UINT8 gradingpoint, boolean forfeit)
}
else
{
if (exitBonus == false)
fixed_t prevInc = ourinc;
INT16 dvs = max(K_GetNumGradingPoints(), 1);
ourinc = FixedDiv(ourinc, dvs*FRACUNIT);
theirinc = FixedDiv(theirinc, dvs*FRACUNIT);
if (exitBonus)
{
ourinc = FixedMul(ourinc, FRACUNIT + K_FinalCheckpointPower());
theirinc = FixedMul(theirinc, FRACUNIT + K_FinalCheckpointPower());
CONS_Debug(DBG_PWRLV, "Final check bonus (%d / %d * %d = %d)\n", prevInc/FRACUNIT, dvs, K_FinalCheckpointPower(), ourinc/FRACUNIT);
}
else
{
fixed_t prevInc = ourinc;
INT16 dvs = max(K_GetNumGradingPoints(), 1);
ourinc = FixedDiv(ourinc, dvs*FRACUNIT);
theirinc = FixedDiv(theirinc, dvs*FRACUNIT);
CONS_Debug(DBG_PWRLV, "Reduced (%d / %d = %d) because it's not the end of the race\n", prevInc/FRACUNIT, dvs, ourinc/FRACUNIT);
}
}
@ -432,6 +438,8 @@ void K_UpdatePowerLevelsFinalize(player_t *player, boolean onForfeit)
if (checksleft <= 0)
{
if (!(gametyperules & GTR_CHECKPOINTS)) // We should probably do at least _one_ PWR update.
K_UpdatePowerLevels(player, player->gradingpointnum, onForfeit);
// We've done every checkpoint already.
return;
}

View file

@ -423,8 +423,8 @@ static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *
--------------------------------------------------*/
void K_RunFinishLineBeam(void)
{
if ((gametyperules & GTR_ROLLINGSTART) || !(leveltime < starttime || rainbowstartavailable == true))
{
if ((gametyperules & GTR_ROLLINGSTART) || !(leveltime < starttime || rainbowstartavailable == true) || P_LevelIsFrozen())
{
return;
}

View file

@ -577,9 +577,8 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
// If our last map was Special, check for "uncredited" continues to offset the rank bump.
fixed_t hiddenpercent = percent;
gpRank_level_t *lastgrade = &rankData->levels[rankData->numLevels - 1];
UINT32 id = lastgrade->id;
if (rankData->specialWon && (mapheaderinfo[id-1]->typeoflevel & G_TOLFlag(GT_SPECIAL)))
if (rankData->specialWon)
{
hiddenpercent -= FRACUNIT / RANK_CONTINUE_PENALTY_DIV * lastgrade->continues;
}

View file

@ -176,6 +176,12 @@ void K_DoIngameRespawn(player_t *player)
K_DoFault(player);
}
if (player->rings <= -20 && !player->respawn.fromRingShooter)
{
P_KillMobj(player->mo, NULL, NULL, DMG_INSTAKILL);
return;
}
player->ringboost = 0;
player->driftboost = player->strongdriftboost = 0;
player->gateBoost = 0;
@ -740,7 +746,7 @@ static void K_DropDashWait(player_t *player)
player->respawn.timer--;
if (player->pflags & PF_FAULT)
return;
return;
if (leveltime % 8 == 0)
{

View file

@ -80,7 +80,7 @@
static UINT32 K_DynamicItemOddsRace[NUMKARTRESULTS-1][2] =
{
// distance, duplication tolerance
{20, 10}, // sneaker
{25, 10}, // sneaker
{63, 12}, // rocketsneaker
{60, 19}, // invincibility
{8, 4}, // banana
@ -491,12 +491,7 @@ UINT32 K_ScaleItemDistance(INT32 distance, UINT8 numPlayers)
return distance;
}
/*--------------------------------------------------
static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
See header file for description.
--------------------------------------------------*/
UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
static UINT32 K_GetUnscaledFirstDistance(const player_t *player)
{
UINT32 pdis = 0;
@ -546,6 +541,19 @@ UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
}
pdis = K_UndoMapScaling(pdis);
return pdis;
}
/*--------------------------------------------------
static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
See header file for description.
--------------------------------------------------*/
UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
{
UINT32 pdis = K_GetUnscaledFirstDistance(player);
pdis = K_ScaleItemDistance(pdis, numPlayers);
if (player->bot && (player->botvars.rival || cv_levelskull.value))
@ -735,7 +743,7 @@ boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette)
Return:-
N/A
--------------------------------------------------*/
static void K_InitRoulette(itemroulette_t *const roulette)
void K_InitRoulette(itemroulette_t *const roulette)
{
size_t i;
@ -1047,7 +1055,7 @@ ATTRUNUSED static boolean K_IsItemUselessAlone(kartitems_t item)
}
}
ATTRUNUSED static boolean K_IsItemSpeed(kartitems_t item)
static boolean K_IsItemSpeed(kartitems_t item)
{
switch (item)
{
@ -1059,6 +1067,7 @@ ATTRUNUSED static boolean K_IsItemSpeed(kartitems_t item)
case KRITEM_TRIPLESNEAKER:
case KITEM_FLAMESHIELD:
case KITEM_SHRINK:
case KITEM_SUPERRING:
return true;
default:
return false;
@ -1411,11 +1420,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
roulette->preexpdist = K_GetItemRouletteDistance(player, roulette->playing);
roulette->dist = roulette->preexpdist;
if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative())
{
roulette->dist = FixedMul(roulette->preexpdist, K_EffectiveGradingFactor(player));
}
// ===============================================================================
// Dynamic Roulette. Oh boy!
// Alright, here's the broad plan:
@ -1426,15 +1430,41 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
// 5: Skim any items that are much weaker than the reel's average out of the roulette
// 6: Cram it all in
fixed_t largegamescaler = roulette->playing * 14 + 100; // Spread out item odds in large games for a less insane experience.
UINT32 targetpower = 100 * roulette->dist / largegamescaler; // fill roulette with items around this value!
UINT32 powers[NUMKARTRESULTS]; // how strong is each item? think of this as a "target distance" for this item to spawn at
UINT32 deltas[NUMKARTRESULTS]; // how different is that strength from target?
UINT32 candidates[NUMKARTRESULTS]; // how many of this item should we try to insert?
UINT32 dupetolerance[NUMKARTRESULTS]; // how willing are we to select this item after already selecting it? higher values = lower dupe penalty
boolean permit[NUMKARTRESULTS]; // is this item allowed?
UINT32 lonelinessSuppressor = DISTVAR; // This close to 1st? Dampen loneliness (you have a target!)
UINT32 maxEXPDistanceCut = 3*DISTVAR; // The maximum amount you can be displaced by EXP
// If we're too close to 1st in absolute units, crush our top-end item odds down.
fixed_t crowdingFirst = 0;
if (player->position != 1)
crowdingFirst = FixedRescale(K_GetUnscaledFirstDistance(player), 0, 4*DISTVAR, Easing_InCubic, FRACUNIT, 0);
if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative())
{
roulette->dist = FixedMul(roulette->preexpdist, K_EffectiveGradingFactor(player));
if (roulette->dist < roulette->preexpdist)
{
if (roulette->preexpdist - roulette->dist > maxEXPDistanceCut)
{
roulette->dist = roulette->preexpdist - maxEXPDistanceCut;
}
}
}
fixed_t largegamescaler = roulette->playing * 11 + 115; // Spread out item odds in large games for a less insane experience.
if (franticitems)
largegamescaler = 100; // Except in Frantic, where you know what you're getting
UINT32 targetpower = 100 * roulette->dist / largegamescaler; // fill roulette with items around this value!
if (!(specialstageinfo.valid))
targetpower = Easing_Linear(crowdingFirst, targetpower, targetpower/2);
boolean rival = (player->bot && (player->botvars.rival || cv_levelskull.value));
boolean filterweakitems = true; // strip unusually weak items from reel?
UINT8 reelsize = 15; // How many items to attempt to add in prepass?
@ -1488,6 +1518,10 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
{
powers[i] = humanscaler * K_DynamicItemOddsRace[i-1][0];
dupetolerance[i] = K_DynamicItemOddsRace[i-1][1];
// Bias towards attack items when close to the leader, gotta work for the slingshot pass!
if (K_IsItemSpeed(i) && i != KITEM_SUPERRING)
powers[i] = Easing_Linear(crowdingFirst, powers[i], 2*powers[i]);
}
maxpower = max(maxpower, powers[i]);
@ -1586,6 +1620,12 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
loneliness = Easing_InCubic(loneliness, 0, FRACUNIT);
// You are not lonely if you're super close to 1st, even if 3nd is far away.
if (roulette->preexpdist < lonelinessSuppressor)
{
loneliness = FixedRescale(roulette->preexpdist, 0, lonelinessSuppressor, Easing_InCubic, 0, loneliness);
}
// Give interaction items a nudge against initial selection if you're lonely..
for (i = 1; i < NUMKARTRESULTS; i++)
{
@ -1621,6 +1661,13 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
UINT8 added = 0; // How many items added so far?
UINT32 totalreelpower = 0; // How much total item power in the reel? Used for an average later.
UINT32 basepenalty = 4*DISTVAR; // How much to penalize repicked items, to ensure item variety.
// BUT, keep the item distribution tighter if we're close to the frontrunner...
UINT32 penalty = Easing_Linear(crowdingFirst, basepenalty, basepenalty/2);
if (player->position == 1) // ...unless we ARE the frontrunner.
penalty = basepenalty;
for (i = 0; i < reelsize; i++)
{
UINT32 lowestdelta = INT32_MAX;
@ -1647,7 +1694,7 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
// Impose a penalty to this item's delta, to bias against selecting it again.
// This is naively slashed by an item's "duplicate tolerance":
// lower tolerance means that an item is less likely to be reselected (it's "rarer").
UINT32 deltapenalty = 4*DISTVAR*(1+candidates[bestitem])/dupetolerance[bestitem];
UINT32 deltapenalty = penalty*(1+candidates[bestitem])/dupetolerance[bestitem];
// Power items get better odds in frantic, or if you're the rival.
// (For the rival, this is way more likely to matter at lower skills, where they're
@ -1703,6 +1750,7 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
UINT8 debugcount = 0; // For the "simple" odds debugger.
UINT32 meanreelpower = totalreelpower/max(added, 1); // Average power for the "moth filter".
UINT32 maxreduction = -1 * min(2 * DISTVAR, meanreelpower/2);
// == PREP FOR ADDING TO THE ROULETTE REEL
// Sal's prior work for this is rock-solid.
@ -1718,7 +1766,7 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
// If we're far away from interactions, be extra aggressive about tossing attack items.
if (filterweakitems && !reject && !K_IsItemSpeed(i))
reject = (powers[i] + Easing_Linear(loneliness, DISTVAR, -2 * DISTVAR) < meanreelpower);
reject = (powers[i] + Easing_Linear(loneliness, DISTVAR, maxreduction) < meanreelpower);
// Popcorn Super Ring is always strong enough, we put it there on purpose.
if (i == KITEM_SUPERRING && !canfiltersuperring)
@ -1731,10 +1779,13 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
UINT16 BASE_X = 280;
UINT16 BASE_Y = 5+12*debugcount;
INT32 FLAGS = V_SNAPTOTOP|V_SNAPTORIGHT;
V_DrawRightAlignedThinString(BASE_X - 12, 5, FLAGS, va("%d", targetpower/humanscaler));
V_DrawRightAlignedThinString(BASE_X - 12, 5+12, FLAGS, va("%d", toFront));
V_DrawRightAlignedThinString(BASE_X - 12, 5+24, FLAGS, va("%d", toBack));
V_DrawRightAlignedThinString(BASE_X - 12, 5+36, FLAGS, va("%d", loneliness));
if (reject)
FLAGS |= V_TRANSLUCENT;
V_DrawRightAlignedThinString(BASE_X - 12, 5, FLAGS, va("TP %d", targetpower/humanscaler));
V_DrawRightAlignedThinString(BASE_X - 12, 5+12, FLAGS, va("FB %d / %d", toFront, toBack));
V_DrawRightAlignedThinString(BASE_X - 12, 5+24, FLAGS, va("L %d / CF %d", loneliness, crowdingFirst));
V_DrawRightAlignedThinString(BASE_X - 12, 5+36, FLAGS, va("D %d / %d", roulette->preexpdist, roulette->dist));
for(UINT8 k = 0; k < candidates[i]; k++)
V_DrawFixedPatch((BASE_X + 3*k)*FRACUNIT, (BASE_Y-7)*FRACUNIT, (FRACUNIT >> 1), FLAGS, K_GetSmallStaticCachedItemPatch(i), NULL);
UINT8 amount = K_ItemResultToAmount(i, roulette);
@ -1905,7 +1956,8 @@ void K_KartGetItemResult(player_t *const player, kartitems_t getitem)
UINT8 itemamount = K_ItemResultToAmount(getitem, &player->itemRoulette);
if (cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == player->itemtype && cv_kartdebugamount.value > 1)
itemamount = cv_kartdebugamount.value;
player->itemamount = itemamount;
K_SetPlayerItemAmount(player, itemamount);
if (player->itemtype == KITEM_SPB)
Obj_SPBEradicateCapsules();

View file

@ -138,6 +138,19 @@ UINT32 K_UndoMapScaling(UINT32 distance);
N/A
--------------------------------------------------*/
void K_InitRoulette(itemroulette_t *const roulette);
/*--------------------------------------------------
static void K_InitRoulette(itemroulette_t *const roulette)
Initializes the data for a new item roulette.
Input Arguments:-
roulette - The item roulette data to initialize.
Return:-
N/A
--------------------------------------------------*/
void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item);
/*--------------------------------------------------

View file

@ -225,7 +225,7 @@ INT32 level_tally_t::CalculateGrade(void)
}
}
const INT32 positionWeight = (position > 0 && numPlayers > 2) ? 50 : 0;
const INT32 positionWeight = 0; // (position > 0 && numPlayers > 2) ? 50 : 0;
const INT32 total = positionWeight + bonusWeights[0] + bonusWeights[1];
INT32 ours = 0;
@ -345,13 +345,10 @@ void level_tally_t::Init(player_t *player)
}
}
if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT)
if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT && K_GetNumGradingPoints() > 0) // EXP should be a rule type, but here we are
{
if (player->exp)
{
exp = player->exp;
totalExp = EXP_TARGET;
}
exp = static_cast<UINT16>(std::max<fixed_t>(player->exp, 0)); // The scoring calc doesn't subtract anymore, so using 0 is okay and will not wrap
totalExp = EXP_TARGET;
}
if (battleprisons)

View file

@ -501,7 +501,21 @@ void K_ProcessTerrainEffect(mobj_t *mo)
if (terrain->damageType > 0)
{
UINT8 dmg = (terrain->damageType & 0xFF);
P_DamageMobj(mo, NULL, NULL, 1, dmg);
if ((dmg == DMG_STUMBLE) && !G_CompatLevel(0x0010))
{
if (player->mo->hitlag == 0 &&
(player->mo->momz == 0 || (player->mo->momz > 0) != (P_MobjFlip(player->mo) > 0)))
{
player->pflags2 |= PF2_ALWAYSDAMAGED;
P_DamageMobj(mo, NULL, NULL, 1, dmg);
player->pflags2 &= ~PF2_ALWAYSDAMAGED;
}
}
else
{
P_DamageMobj(mo, NULL, NULL, 1, dmg);
}
}
// Sneaker panel
@ -589,6 +603,15 @@ void K_ProcessTerrainEffect(mobj_t *mo)
player->dashpadcooldown = TICRATE/3;
player->trickpanel = TRICKSTATE_NONE;
player->floorboost = 2;
if (G_CompatLevel(0x0011))
{
// Old behavior, no grease
}
else
{
player->tiregrease = TICRATE/2;
}
S_StartSound(player->mo, sfx_cdfm62);
}
@ -2011,7 +2034,7 @@ static boolean K_TERRAINLumpParser(char *data, size_t size)
Z_Free(tkn);
tkn = M_GetToken(NULL);
pos = M_GetTokenPos();
if (tkn && pos <= size)
{
if (stricmp(tkn, "optional") == 0)

View file

@ -1845,7 +1845,7 @@ static void Y_TickVoteStageStrike(void)
static void Y_TickVoteSelection(void)
{
boolean everyone_voted = true;/* the default condition */
INT32 i;
INT32 i, j;
if (vote.tic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V
{
@ -1872,7 +1872,6 @@ static void Y_TickVoteSelection(void)
if (vote.players[i].sentTimeOutVote == false)
{
// Move off of striked stages for the timeout vote.
INT32 j;
for (j = 0; j < VOTE_NUM_LEVELS; j++)
{
if (g_votes_striked[vote.players[i].selection] == false)
@ -1944,9 +1943,9 @@ static void Y_TickVoteSelection(void)
{
// bots vote randomly
INT32 rng = M_RandomKey(VOTE_NUM_LEVELS);
for (i = 0; i < VOTE_NUM_LEVELS; i++)
for (j = 0; j < VOTE_NUM_LEVELS; j++)
{
if (g_votes_striked[i] == false)
if (g_votes_striked[j] == false)
{
break;
}
@ -2095,7 +2094,7 @@ static void Y_InitVoteDrawing(void)
INT32 i = 0, j = 0;
vote_draw.ruby_icon = W_CachePatchName("RUBYICON", PU_STATIC);
vote_draw.strike_icon = W_CachePatchName("K_NOBLNS", PU_STATIC);
vote_draw.strike_icon = W_CachePatchName("VT_LSTRK", PU_STATIC);
for (i = 0; i < PLANET_FRAMES; i++)
{

View file

@ -46,6 +46,7 @@
#include "k_hitlag.h"
#include "music.h" // music functions necessary for lua integration
#include "k_terrain.h"
#include "k_grandprix.h"
#include "lua_script.h"
#include "lua_libs.h"
@ -252,6 +253,16 @@ static const struct {
{META_FOOTSTEP, "t_footstep_t"},
{META_OVERLAY, "t_overlay_t"},
{META_TERRAIN, "terrain_t"},
{META_POWERUPVARS, "powerupvars_t"},
{META_ICECUBEVARS, "icecubevars_t"},
{META_SKYBOX, "skybox_t"},
{META_CUP, "cupheader_t"},
{META_GPRANK, "gprank_t"},
{META_GPRANKLEVEL, "gprank_level_t"},
{META_GPRANKLEVELPERPLAYER, "gprank_level_perplayer_t"},
{META_ROUNDENTRY, "roundentry_t"},
{NULL, NULL}
};
@ -476,6 +487,13 @@ static int lib_mMusicRemap(lua_State *L)
{
return LUA_ErrNoTune(L, tune_id);
}
// Do not allow Lua to remap Stereo Mode tunes.
if (strlen(tune_id) > 5
&& toupper(tune_id[0]) == 'S' && toupper(tune_id[1]) == 'T' && toupper(tune_id[2]) == 'E' && toupper(tune_id[3]) == 'R' && toupper(tune_id[4]) == 'E')
{
return LUA_ErrStereo(L, tune_id);
}
Music_Remap(tune_id, music_name);
@ -3987,6 +4005,84 @@ static int lib_kMomentumAngle(lua_State *L)
return 1;
}
static int lib_kPvPAmpReward(lua_State *L)
{
UINT32 award = luaL_checkinteger(L, 1);
player_t *attacker = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
player_t *defender = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
NOHUD
INLEVEL
if (!attacker || !defender)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_PvPAmpReward(award, attacker, defender));
return 1;
}
static int lib_kSpawnAmps(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT8 amps = luaL_checkinteger(L, 2);
mobj_t *impact = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!impact)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnAmps(player, amps, impact);
return 0;
}
static int lib_kSpawnEXP(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT8 exp = luaL_checkinteger(L, 2);
mobj_t *impact = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!impact)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnEXP(player, exp, impact);
return 0;
}
static int lib_kAwardPlayerAmps(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT8 amps = luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_AwardPlayerAmps(player, amps);
return 0;
}
static int lib_kOverdrive(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_Overdrive(player));
return 1;
}
static int lib_kDefensiveOverdrive(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_DefensiveOverdrive(player));
return 1;
}
static int lib_kDoInstashield(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -5266,6 +5362,48 @@ static int lib_kPlayerCanUseItem(lua_State *L)
return 1;
}
static int lib_kGetGradingFactorAdjustment(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT32 gradingpoint = luaL_checkinteger(L, 2);
INLEVEL
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetGradingFactorAdjustment(player, gradingpoint));
return 1;
}
static int lib_kGetGradingFactorMinMax(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean max = luaL_checkboolean(L, 2);
INLEVEL
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetGradingFactorMinMax(player, max));
return 1;
}
static int lib_kGetEXP(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_GetEXP(player));
return 1;
}
static int lib_kGetNumGradingPoints(lua_State *L)
{
INLEVEL
lua_pushinteger(L, K_GetNumGradingPoints());
return 1;
}
static int lib_kEggmanTransfer(lua_State *L)
{
player_t *source = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -5290,6 +5428,31 @@ static int lib_kSetTireGrease(lua_State *L)
return 0;
}
static int lib_kApplyStun(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *inflictor = NULL;
mobj_t *source = NULL;
INT32 damage = luaL_optinteger(L, 4, 0);
UINT8 damagetype = luaL_optinteger(L, 5, 0);
INLEVEL
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnil(L, 2) && lua_isuserdata(L, 2)) {
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!inflictor)
return LUA_ErrInvalid(L, "mobj_t");
}
if (!lua_isnil(L, 3) && lua_isuserdata(L, 3)) {
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
}
K_ApplyStun(player, inflictor, source, damage, damagetype);
return 0;
}
static int lib_kGetCollideAngle(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -5986,7 +6149,15 @@ static int lib_kSetNameForBot(lua_State *L)
if (!player->bot)
return luaL_error(L, "You may only change bot names.");
K_SetNameForBot(player-players, realname);
// Doing this to avoid a discarded const warning:
char modifiedname[MAXPLAYERNAME+1] = "";
strcpy(modifiedname, realname);
if (!IsPlayerNameGood(modifiedname))
return luaL_error(L, "Invalid bot name - it must be between %d and %d characters of length, "
"not start with a space, @ or ~ characters, and it must be composed of valid ASCII characters.", 1, MAXPLAYERNAME);
K_SetNameForBot(player-players, modifiedname);
return 0;
}
@ -6774,7 +6945,13 @@ static luaL_Reg lib[] = {
{"K_MomentumAngleEx",lib_kMomentumAngleEx},
{"K_MomentumAngleReal",lib_kMomentumAngleReal},
{"K_MomentumAngle",lib_kMomentumAngle},
{"K_PvPAmpReward",lib_kPvPAmpReward},
{"K_SpawnAmps",lib_kSpawnAmps},
{"K_SpawnEXP",lib_kSpawnEXP},
{"K_AwardPlayerAmps",lib_kAwardPlayerAmps},
{"K_AwardPlayerRings",lib_kAwardPlayerRings},
{"K_Overdrive",lib_kOverdrive},
{"K_DefensiveOverdrive",lib_kDefensiveOverdrive},
{"K_DoInstashield",lib_kDoInstashield},
{"K_DoPowerClash",lib_kDoPowerClash},
{"K_DoGuardBreak",lib_kDoGuardBreak},
@ -6883,10 +7060,15 @@ static luaL_Reg lib[] = {
{"K_BumperInflate",lib_kBumperInflate},
{"K_ThunderDome",lib_kThunderDome},
{"K_PlayerCanUseItem",lib_kPlayerCanUseItem},
{"K_GetGradingFactorAdjustment",lib_kGetGradingFactorAdjustment},
{"K_GetGradingFactorMinMax",lib_kGetGradingFactorMinMax},
{"K_GetEXP",lib_kGetEXP},
{"K_GetNumGradingPoints",lib_kGetNumGradingPoints},
{"K_PlayerGuard",lib_kPlayerGuard},
{"K_FastFallBounce",lib_kFastFallBounce},
{"K_EggmanTransfer",lib_kEggmanTransfer},
{"K_SetTireGrease",lib_kSetTireGrease},
{"K_ApplyStun",lib_kApplyStun},
{"K_GetCollideAngle",lib_kGetCollideAngle},

View file

@ -23,7 +23,9 @@ enum botvars {
botvars_difficulty,
botvars_diffincrease,
botvars_rival,
botvars_foe,
botvars_rubberband,
botvars_bumpslow,
botvars_itemdelay,
botvars_itemconfirm,
botvars_turnconfirm,
@ -31,6 +33,9 @@ enum botvars {
botvars_respawnconfirm,
botvars_roulettepriority,
botvars_roulettetimeout,
botvars_predictionerror,
botvars_recentdeflection,
botvars_lastangle
};
static const char *const botvars_opt[] = {
@ -39,7 +44,9 @@ static const char *const botvars_opt[] = {
"difficulty",
"diffincrease",
"rival",
"foe",
"rubberband",
"bumpslow",
"itemdelay",
"itemconfirm",
"turnconfirm",
@ -47,6 +54,9 @@ static const char *const botvars_opt[] = {
"respawnconfirm",
"roulettepriority",
"roulettetimeout",
"predictionerror",
"recentdeflection",
"lastangle",
NULL
};
@ -77,9 +87,15 @@ static int botvars_get(lua_State *L)
case botvars_rival:
lua_pushboolean(L, botvars->rival);
break;
case botvars_foe:
lua_pushboolean(L, botvars->foe);
break;
case botvars_rubberband:
lua_pushfixed(L, botvars->rubberband);
break;
case botvars_bumpslow:
lua_pushinteger(L, botvars->bumpslow);
break;
case botvars_itemdelay:
lua_pushinteger(L, botvars->itemdelay);
break;
@ -101,6 +117,15 @@ static int botvars_get(lua_State *L)
case botvars_roulettetimeout:
lua_pushinteger(L, botvars->rouletteTimeout);
break;
case botvars_predictionerror:
lua_pushinteger(L, botvars->predictionError);
break;
case botvars_recentdeflection:
lua_pushinteger(L, botvars->recentDeflection);
break;
case botvars_lastangle:
lua_pushinteger(L, botvars->lastAngle);
break;
}
return 1;
}
@ -133,9 +158,15 @@ static int botvars_set(lua_State *L)
case botvars_rival:
botvars->rival = luaL_checkboolean(L, 3);
break;
case botvars_foe:
botvars->foe = luaL_checkboolean(L, 3);
break;
case botvars_rubberband:
botvars->rubberband = luaL_checkfixed(L, 3);
break;
case botvars_bumpslow:
botvars->bumpslow = luaL_checkinteger(L, 3);
break;
case botvars_itemdelay:
botvars->itemdelay = luaL_checkinteger(L, 3);
break;
@ -157,6 +188,15 @@ static int botvars_set(lua_State *L)
case botvars_roulettetimeout:
botvars->rouletteTimeout = luaL_checkinteger(L, 3);
break;
case botvars_predictionerror:
botvars->predictionError = luaL_checkangle(L, 3);
break;
case botvars_recentdeflection:
botvars->recentDeflection = luaL_checkangle(L, 3);
break;
case botvars_lastangle:
botvars->lastAngle = luaL_checkangle(L, 3);
break;
}
return 0;
}

968
src/lua_grandprixlib.c Normal file
View file

@ -0,0 +1,968 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Freaky Mutant Man.
// Copyright (C) 2025 by Kart Krew.
// Copyright (C) 2020 by Sonic Team Junior.
// Copyright (C) 2016 by John "JTE" Muniz.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_grandprixlib.c
/// \brief Grand Prix, cup and rank info for Lua scripting.
#include "doomdef.h"
#include "fastcmp.h"
#include "doomstat.h"
#include "k_grandprix.h"
#include "k_rank.h"
#include "g_game.h"
#include "lua_script.h"
#include "lua_libs.h"
#define UNIMPLEMENTED luaL_error(L, LUA_QL("cupheader_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", cup_opt[field])
#define RNOFIELDGP luaL_error(L, LUA_QL("grandprixinfo") " has no field named " LUA_QS, field)
#define RNOFIELDCH luaL_error(L, LUA_QL("cupheader_t") " has no field named " LUA_QS, field)
#define RNOFIELDGR luaL_error(L, LUA_QL("gprank_t") " has no field named " LUA_QS, field)
#define RNOFIELDGRL luaL_error(L, LUA_QL("gprank_level_t") " has no field named " LUA_QS, field)
#define RNOFIELDGRLP luaL_error(L, LUA_QL("gprank_level_perplayer_t") " has no field named " LUA_QS, field)
#define RNOFIELDRQ luaL_error(L, LUA_QL("roundqueue") " has no field named " LUA_QS, field)
#define RNOFIELDRE luaL_error(L, LUA_QL("roundentry_t") " has no field named " LUA_QS, field)
#define GPERR luaL_error(L, LUA_QL("grandprixinfo") " field " LUA_QS " cannot be accessed while grandprixinfo.gp is false.", grandprix_opt[field])
#define ROUNDCUEERR luaL_error(L, LUA_QL("roundqueue") " field " LUA_QS " cannot be accessed while roundqueue.size is 0.", grandprix_opt[field])
enum grandprix {
grandprix_gp = 0,
grandprix_cup,
grandprix_gamespeed,
grandprix_encore,
grandprix_masterbots,
grandprix_initialize,
grandprix_initalize,
grandprix_wonround,
grandprix_eventmode,
grandprix_specialdamage,
grandprix_rank,
};
enum cup {
cup_valid = 0,
cup_id,
cup_monitor,
cup_name,
cup_namehash,
cup_realname,
cup_icon,
cup_levellist,
cup_cachedlevels,
cup_numlevels,
cup_numbonus,
cup_emeraldnum,
cup_playcredits,
cup_hintcondition,
cup_cache_cuplock,
cup_windata,
cup_next,
};
enum gprank {
gprank_valid = 0,
gprank_numplayers,
gprank_totalplayers,
gprank_position,
gprank_skin,
gprank_winpoints,
gprank_totalpoints,
gprank_exp,
gprank_totalexp,
gprank_continuesused,
gprank_prisons,
gprank_totalprisons,
gprank_rings,
gprank_totalrings,
gprank_specialwon,
gprank_scoreposition,
gprank_scoregppoints,
gprank_scoreexp,
gprank_scoreprisons,
gprank_scorerings,
gprank_scorecontinues,
gprank_scoretotal,
gprank_numlevels,
gprank_levels,
};
enum gprank_level {
gprank_level_valid = 0,
gprank_level_id,
gprank_level_event,
gprank_level_time,
gprank_level_totalexp,
gprank_level_totalprisons,
gprank_level_continues,
gprank_level_perplayer,
};
enum gprank_level_perplayer {
gprank_level_perplayer_valid = 0,
gprank_level_perplayer_position,
gprank_level_perplayer_rings,
gprank_level_perplayer_exp,
gprank_level_perplayer_prisons,
gprank_level_perplayer_gotspecialprize,
gprank_level_perplayer_grade,
};
enum roundcue { // named "roundcue" to avoid overlap with actual roundqueue struct
roundcue_size = 0, // placed first since we'll be checking this to see if the roundqueue is currently in use
roundcue_roundnum,
roundcue_position,
roundcue_netcommunicate,
roundcue_writetextmap,
roundcue_snapshotmaps,
roundcue_entries,
};
enum roundentry {
roundentry_valid = 0,
roundentry_mapnum,
roundentry_gametype,
roundentry_encore,
roundentry_rankrestricted,
roundentry_overridden,
};
static const char *const grandprix_opt[] = {
"gp",
"cup",
"gamespeed",
"encore",
"masterbots",
"initialize",
"initalize",
"wonround",
"eventmode",
"specialdamage",
"rank",
NULL
};
static const char *const cup_opt[] = {
"valid",
"id",
"monitor",
"name",
"namehash",
"realname",
"icon",
"levellist",
"cachedlevels",
"numlevels",
"numbonus",
"emeraldnum",
"playcredits",
"hintcondition",
"cache_cuplock",
"windata",
"next",
NULL
};
static const char *const gprank_opt[] = {
"valid",
"numplayers",
"totalplayers",
"position",
"skin",
"winpoints",
"totalpoints",
"exp",
"totalexp",
"continuesused",
"prisons",
"totalprisons",
"rings",
"totalrings",
"specialwon",
"scoreposition",
"scoregppoints",
"scoreexp",
"scoreprisons",
"scorerings",
"scorecontinues",
"scoretotal",
"numlevels",
"levels",
NULL
};
static const char *const gprank_level_opt[] = {
"valid",
"id",
"event",
"time",
"totalexp",
"totalprisons",
"continues",
"perplayer",
NULL
};
static const char *const gprank_level_perplayer_opt[] = {
"valid",
"position",
"rings",
"exp",
"prisons",
"gotspecialprize",
"grade",
NULL
};
static const char *const roundcue_opt[] = {
"size",
"roundnum",
"position",
"netcommunicate",
"writetextmap",
"snapshotmaps",
"entries",
NULL
};
static const char *const roundentry_opt[] = {
"valid",
"mapnum",
"gametype",
"encore",
"rankrestricted",
"overridden",
NULL
};
static int grandprix_get(lua_State *L)
{
enum grandprix field = luaL_checkoption(L, 2, grandprix_opt[0], grandprix_opt);
// Don't return any grandprixinfo values while not in a GP.
if (!grandprixinfo.gp)
{
switch (field)
{
case grandprix_gp:
lua_pushboolean(L, false);
return 1;
default:
return GPERR;
}
}
switch (field)
{
case grandprix_gp:
lua_pushboolean(L, grandprixinfo.gp);
break;
case grandprix_cup:
LUA_PushUserdata(L, grandprixinfo.cup, META_CUP);
break;
case grandprix_gamespeed:
lua_pushnumber(L, grandprixinfo.gamespeed);
break;
case grandprix_encore:
lua_pushboolean(L, grandprixinfo.encore);
break;
case grandprix_masterbots:
lua_pushboolean(L, grandprixinfo.masterbots);
break;
case grandprix_initialize:
case grandprix_initalize: // when the struct misspelled the variable...
lua_pushboolean(L, grandprixinfo.initalize);
break;
case grandprix_wonround:
lua_pushboolean(L, grandprixinfo.wonround);
break;
case grandprix_eventmode:
lua_pushnumber(L, grandprixinfo.eventmode);
break;
case grandprix_specialdamage:
lua_pushnumber(L, grandprixinfo.specialDamage);
break;
case grandprix_rank:
LUA_PushUserdata(L, &grandprixinfo.rank, META_GPRANK);
break;
default:
return RNOFIELDGP;
}
return 1;
}
static int grandprix_set(lua_State *L)
{
return luaL_error(L, LUA_QL("grandprixinfo") " struct cannot be edited by Lua.");
}
static int cup_get(lua_State *L)
{
cupheader_t *cup = *((cupheader_t **)luaL_checkudata(L, 1, META_CUP));
enum cup field = luaL_checkoption(L, 2, cup_opt[0], cup_opt);
if (!cup)
{
switch (field)
{
case cup_valid:
lua_pushboolean(L, false);
return 1;
default:
return LUA_ErrInvalid(L, "cupheader_t");
}
}
switch (field)
{
case cup_valid:
lua_pushboolean(L, true);
break;
case cup_id:
lua_pushnumber(L, cup->id);
break;
case cup_monitor:
lua_pushnumber(L, cup->monitor);
break;
case cup_name:
lua_pushstring(L, cup->name);
break;
case cup_namehash:
return UNIMPLEMENTED;
break;
case cup_realname:
lua_pushstring(L, cup->realname);
break;
case cup_icon:
lua_pushstring(L, cup->icon);
break;
case cup_levellist:
lua_createtable(L, ((cup->numlevels) + (cup->numbonus)), 0);
for (size_t i = 0; i < ((cup->numlevels) + (cup->numbonus)); i++)
{
lua_pushstring(L, cup->levellist[i]);
lua_rawseti(L, -2, 1 + i);
}
break;
case cup_cachedlevels:
lua_createtable(L, ((cup->numlevels) + (cup->numbonus)), 0);
for (size_t i = 0; i < CUPCACHE_MAX; i++)
{
lua_pushnumber(L, (cup->cachedlevels[i])+1);
lua_rawseti(L, -2, 1 + i);
}
break;
case cup_numlevels:
lua_pushnumber(L, cup->numlevels);
break;
case cup_numbonus:
lua_pushnumber(L, cup->numbonus);
break;
case cup_emeraldnum:
lua_pushnumber(L, cup->emeraldnum);
break;
case cup_playcredits:
lua_pushboolean(L, cup->playcredits);
break;
case cup_hintcondition:
lua_pushnumber(L, cup->hintcondition);
break;
case cup_cache_cuplock:
return UNIMPLEMENTED;
break;
case cup_windata:
return UNIMPLEMENTED;
break;
case cup_next:
return UNIMPLEMENTED;
break;
default:
return RNOFIELDCH;
}
return 1;
}
static int cup_set(lua_State *L)
{
return luaL_error(L, LUA_QL("cupheader_t") " struct cannot be edited by Lua.");
}
static int gprank_get(lua_State *L)
{
gpRank_t *gprank = *((gpRank_t **)luaL_checkudata(L, 1, META_GPRANK));
enum gprank field = luaL_checkoption(L, 2, gprank_opt[0], gprank_opt);
if (!gprank)
{
switch (field)
{
case gprank_valid:
lua_pushboolean(L, false);
return 1;
default:
return LUA_ErrInvalid(L, "gprank_t");
}
}
switch (field)
{
case gprank_valid:
lua_pushboolean(L, true);
break;
case gprank_numplayers:
lua_pushnumber(L, gprank->numPlayers);
break;
case gprank_totalplayers:
lua_pushnumber(L, gprank->totalPlayers);
break;
case gprank_position:
lua_pushnumber(L, gprank->position);
break;
case gprank_skin:
lua_pushnumber(L, gprank->skin);
break;
case gprank_winpoints:
lua_pushnumber(L, gprank->winPoints);
break;
case gprank_totalpoints:
lua_pushnumber(L, gprank->totalPoints);
break;
case gprank_exp:
lua_pushnumber(L, gprank->exp);
break;
case gprank_totalexp:
lua_pushnumber(L, gprank->totalExp);
break;
case gprank_continuesused:
lua_pushnumber(L, gprank->continuesUsed);
break;
case gprank_prisons:
lua_pushnumber(L, gprank->prisons);
break;
case gprank_totalprisons:
lua_pushnumber(L, gprank->totalPrisons);
break;
case gprank_rings:
lua_pushnumber(L, gprank->rings);
break;
case gprank_totalrings:
lua_pushnumber(L, gprank->totalRings);
break;
case gprank_specialwon:
lua_pushboolean(L, gprank->specialWon);
break;
case gprank_scoreposition:
lua_pushnumber(L, gprank->scorePosition);
break;
case gprank_scoregppoints:
lua_pushnumber(L, gprank->scoreGPPoints);
break;
case gprank_scoreexp:
lua_pushnumber(L, gprank->scoreExp);
break;
case gprank_scoreprisons:
lua_pushnumber(L, gprank->scorePrisons);
break;
case gprank_scorerings:
lua_pushnumber(L, gprank->scoreRings);
break;
case gprank_scorecontinues:
lua_pushnumber(L, gprank->scoreContinues);
break;
case gprank_scoretotal:
lua_pushnumber(L, gprank->scoreTotal);
break;
case gprank_numlevels:
lua_pushnumber(L, gprank->numLevels);
break;
case gprank_levels:
lua_createtable(L, ((grandprixinfo.cup->numlevels) + (grandprixinfo.cup->numbonus)), 0);
for (size_t i = 0; i < ((grandprixinfo.cup->numlevels) + (grandprixinfo.cup->numbonus)); i++)
{
LUA_PushUserdata(L, &gprank->levels[i], META_GPRANKLEVEL);
lua_rawseti(L, -2, 1 + i);
}
break;
default:
return RNOFIELDGR;
}
return 1;
}
static int gprank_set(lua_State *L)
{
return luaL_error(L, LUA_QL("gprank_t") " struct cannot be edited by Lua.");
}
static int gprank_level_get(lua_State *L)
{
gpRank_level_t *gprank_level = *((gpRank_level_t **)luaL_checkudata(L, 1, META_GPRANKLEVEL));
enum gprank_level field = luaL_checkoption(L, 2, gprank_level_opt[0], gprank_level_opt);
if (!gprank_level)
{
switch (field)
{
case gprank_level_valid:
lua_pushboolean(L, false);
return 1;
default:
return LUA_ErrInvalid(L, "gprank_level_t");
}
}
switch (field)
{
case gprank_level_valid:
lua_pushboolean(L, true);
break;
case gprank_level_id:
lua_pushnumber(L, gprank_level->id);
break;
case gprank_level_event:
lua_pushnumber(L, gprank_level->event);
break;
case gprank_level_time:
lua_pushnumber(L, gprank_level->time);
break;
case gprank_level_totalexp:
lua_pushnumber(L, gprank_level->totalExp);
break;
case gprank_level_totalprisons:
lua_pushnumber(L, gprank_level->totalPrisons);
break;
case gprank_level_continues:
lua_pushnumber(L, gprank_level->continues);
break;
case gprank_level_perplayer:
lua_createtable(L, grandprixinfo.rank.numPlayers, 0);
for (size_t i = 0; i < grandprixinfo.rank.numPlayers; i++)
{
LUA_PushUserdata(L, &gprank_level->perPlayer[i], META_GPRANKLEVELPERPLAYER);
lua_rawseti(L, -2, 1 + i);
}
break;
default:
return RNOFIELDGRL;
}
return 1;
}
static int gprank_level_set(lua_State *L)
{
return luaL_error(L, LUA_QL("gprank_level_t") " struct cannot be edited by Lua.");
}
static int gprank_level_perplayer_get(lua_State *L)
{
// "perplaya" to avoid shadowed declaration
gpRank_level_perplayer_t *gprank_level_perplaya = *((gpRank_level_perplayer_t **)luaL_checkudata(L, 1, META_GPRANKLEVELPERPLAYER));
enum gprank_level_perplayer field = luaL_checkoption(L, 2, gprank_level_perplayer_opt[0], gprank_level_perplayer_opt);
if (!gprank_level_perplaya)
{
switch (field)
{
case gprank_level_perplayer_valid:
lua_pushboolean(L, false);
return 1;
default:
return LUA_ErrInvalid(L, "gprank_level_perplayer_t");
}
}
switch (field)
{
case gprank_level_perplayer_valid:
lua_pushboolean(L, true);
break;
case gprank_level_perplayer_position:
lua_pushnumber(L, gprank_level_perplaya->position);
break;
case gprank_level_perplayer_rings:
lua_pushnumber(L, gprank_level_perplaya->rings);
break;
case gprank_level_perplayer_exp:
lua_pushnumber(L, gprank_level_perplaya->exp);
break;
case gprank_level_perplayer_prisons:
lua_pushnumber(L, gprank_level_perplaya->prisons);
break;
case gprank_level_perplayer_gotspecialprize:
lua_pushboolean(L, gprank_level_perplaya->gotSpecialPrize);
break;
case gprank_level_perplayer_grade:
lua_pushnumber(L, gprank_level_perplaya->grade);
break;
default:
return RNOFIELDGRLP;
}
return 1;
}
static int gprank_level_perplayer_set(lua_State *L)
{
return luaL_error(L, LUA_QL("gprank_level_perplayer") " struct cannot be edited by Lua.");
}
static int roundcue_get(lua_State *L)
{
enum roundcue field = luaL_checkoption(L, 2, roundcue_opt[0], roundcue_opt);
// Don't return any grandprixinfo values while not in a GP.
if (!roundqueue.size)
{
switch (field)
{
case roundcue_size:
lua_pushboolean(L, false);
return 1;
default:
return ROUNDCUEERR;
}
}
switch (field)
{
case roundcue_size:
lua_pushnumber(L, roundqueue.size);
break;
case roundcue_roundnum:
lua_pushnumber(L, roundqueue.roundnum);
break;
case roundcue_position:
lua_pushnumber(L, roundqueue.position);
break;
case roundcue_netcommunicate:
return UNIMPLEMENTED;
break;
case roundcue_writetextmap:
return UNIMPLEMENTED;
break;
case roundcue_snapshotmaps:
lua_pushboolean(L, roundqueue.snapshotmaps);
break;
case roundcue_entries:
lua_createtable(L, roundqueue.size, 0);
for (size_t i = 0; i < roundqueue.size; i++)
{
LUA_PushUserdata(L, &roundqueue.entries[i], META_ROUNDENTRY);
lua_rawseti(L, -2, 1 + i);
}
break;
default:
return RNOFIELDRQ;
}
return 1;
}
static int roundcue_set(lua_State *L)
{
return luaL_error(L, LUA_QL("roundqueue") " struct cannot be edited by Lua.");
}
static int roundentry_get(lua_State *L)
{
roundentry_t *roundentry = *((roundentry_t **)luaL_checkudata(L, 1, META_ROUNDENTRY));
enum roundentry field = luaL_checkoption(L, 2, roundentry_opt[0], roundentry_opt);
if (!roundentry)
{
switch (field)
{
case roundentry_valid:
lua_pushboolean(L, false);
return 1;
default:
return LUA_ErrInvalid(L, "roundentry_t");
}
}
switch (field)
{
case roundentry_valid:
lua_pushboolean(L, true);
break;
case roundentry_mapnum:
lua_pushnumber(L, roundentry->mapnum);
break;
case roundentry_gametype:
lua_pushnumber(L, roundentry->gametype);
break;
case roundentry_encore:
lua_pushboolean(L, roundentry->encore);
break;
case roundentry_rankrestricted:
lua_pushboolean(L, roundentry->rankrestricted);
break;
case roundentry_overridden:
lua_pushboolean(L, roundentry->overridden);
break;
default:
return RNOFIELDRE;
}
return 1;
}
static int roundentry_set(lua_State *L)
{
return luaL_error(L, LUA_QL("roundentry_t") " struct cannot be edited by Lua.");
}
#undef UNIMPLEMENTED
#undef RNOFIELDGP
#undef RNOFIELDCH
#undef RNOFIELDGR
#undef RNOFIELDGRL
#undef RNOFIELDGRLP
#undef RNOFIELDRQ
#undef RNOFIELDRE
#undef GPERR
#undef ROUNDCUEERR
static int lib_numCupheaders(lua_State *L)
{
lua_pushinteger(L, numkartcupheaders);
return 1;
}
// There was, in fact, a better thing to do here - thanks toaster
#define GETCUPERR UINT16_MAX
// copied and edited from G_MapNumber
static UINT16 LUA_GetCupByNum(UINT16 cupnum)
{
cupheader_t *checkcup;
// find by cup id
if (cupnum != GETCUPERR)
{
if (cupnum >= numkartcupheaders)
return GETCUPERR; // id outta range
for (checkcup = kartcupheaders; checkcup->id <= numkartcupheaders; checkcup = checkcup->next)
{
if (checkcup->id != cupnum)
continue;
else
break;
return GETCUPERR; // id invalid
}
return checkcup->id;
}
return GETCUPERR;
}
// copied and edited from G_MapNumber
static UINT16 LUA_GetCupByName(const char * name)
{
cupheader_t *checkcup;
UINT32 hash = quickncasehash(name, MAXCUPNAME);
// find by cup name/realname
for (checkcup = kartcupheaders; checkcup != NULL; checkcup = checkcup->next)
{
if (hash != checkcup->namehash)
continue;
if (strcasecmp(checkcup->name, name) != 0)
continue;
return checkcup->id;
}
return GETCUPERR;
}
static int lib_iterateCups(lua_State *L)
{
INT32 i = -1;
cupheader_t *tempcup = kartcupheaders;
if (lua_gettop(L) < 2)
{
lua_pushcfunction(L, lib_iterateCups);
return 1;
}
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
{
i = ((*((cupheader_t **)luaL_checkudata(L, 1, META_CUP)))->id) + 1;
}
else
i = 0;
for (tempcup = kartcupheaders; tempcup->id < numkartcupheaders; tempcup = tempcup->next)
{
if (tempcup->next == NULL)
break;
if (tempcup->id >= i)
break;
}
// cups are always valid, only added, never removed
if (i < numkartcupheaders)
{
LUA_PushUserdata(L, tempcup, META_CUP);
return 1;
}
return 0;
}
// Shamelessly copied and edited from lua_waypointslib.c (with thanks to JugadorXEI)
static int lib_getCupheader(lua_State *L)
{
const char *field;
size_t i;
cupheader_t *checkcup;
UINT16 getResult = GETCUPERR;
// find cup by id number
if (lua_type(L, 2) == LUA_TNUMBER)
{
i = luaL_checkinteger(L, 2);
if (i > numkartcupheaders)
return luaL_error(L, "cupheader_t id %d out of loaded range (0 - %d)", i, numkartcupheaders);
getResult = LUA_GetCupByNum(i);
if (getResult == GETCUPERR)
return luaL_error(L, "cupheader_t id %d invalid", i);
for (checkcup = kartcupheaders; checkcup->id < numkartcupheaders; checkcup = checkcup->next)
{
if (checkcup->id != getResult)
continue;
else
break;
return luaL_error(L, "cupheader_t id %d invalid (LUA_GetCupByNum failed?)", i);
}
LUA_PushUserdata(L, checkcup, META_CUP);
return 1;
}
field = luaL_checkstring(L, 2);
// special function iterate
if (fastcmp(field,"iterate"))
{
lua_pushcfunction(L, lib_iterateCups);
return 1;
}
if (lua_type(L, 2) == LUA_TSTRING)
{
getResult = LUA_GetCupByName(field);
if (getResult == GETCUPERR)
return luaL_error(L, "no cupheader_t with name %s", field);
}
// If, after all this...
if (getResult == GETCUPERR)
return luaL_error(L, "internal failure in lua_grandprixlib.c???");
for (checkcup = kartcupheaders; checkcup->id < numkartcupheaders; checkcup = checkcup->next)
{
if (checkcup->id != getResult)
continue;
else
break;
return luaL_error(L, "cupheader_t id %d invalid (LUA_GetCupByName failed?)", i);
}
LUA_PushUserdata(L, checkcup, META_CUP);
return 1;
}
int LUA_GrandPrixLib(lua_State *L)
{
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, grandprix_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, grandprix_set);
lua_setfield(L, -2, "__newindex");
lua_setmetatable(L, -2);
lua_setglobal(L, "grandprixinfo");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, roundcue_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, roundcue_set);
lua_setfield(L, -2, "__newindex");
lua_setmetatable(L, -2);
lua_setglobal(L, "roundqueue");
luaL_newmetatable(L, META_CUP);
lua_pushcfunction(L, cup_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, cup_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
luaL_newmetatable(L, META_GPRANK);
lua_pushcfunction(L, gprank_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, gprank_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
luaL_newmetatable(L, META_GPRANKLEVEL);
lua_pushcfunction(L, gprank_level_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, gprank_level_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
luaL_newmetatable(L, META_GPRANKLEVELPERPLAYER);
lua_pushcfunction(L, gprank_level_perplayer_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, gprank_level_perplayer_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
luaL_newmetatable(L, META_ROUNDENTRY);
lua_pushcfunction(L, roundentry_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, roundentry_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getCupheader);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_numCupheaders);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "cups");
return 0;
}

View file

@ -28,6 +28,7 @@ enum itemroulette {
itemroulette_itemlist,
itemroulette_playing,
itemroulette_exiting,
itemroulette_preexpdist,
itemroulette_dist,
itemroulette_basedist,
itemroulette_firstdist,
@ -41,7 +42,8 @@ enum itemroulette {
itemroulette_eggman,
itemroulette_ringbox,
itemroulette_autoroulette,
itemroulette_reserved
itemroulette_reserved,
itemroulette_popcorn
};
static const char *const itemroulette_opt[] = {
"valid",
@ -49,6 +51,7 @@ static const char *const itemroulette_opt[] = {
"itemlist",
"playing",
"exiting",
"preexpdist",
"dist",
"basedist",
"firstdist",
@ -63,6 +66,7 @@ static const char *const itemroulette_opt[] = {
"ringbox",
"autoroulette",
"reserved",
"popcorn",
NULL
};
@ -91,6 +95,9 @@ static int itemroulette_get(lua_State *L)
case itemroulette_exiting:
lua_pushinteger(L, itemroulette->exiting);
break;
case itemroulette_preexpdist:
lua_pushinteger(L, itemroulette->preexpdist);
break;
case itemroulette_dist:
lua_pushinteger(L, itemroulette->dist);
break;
@ -133,6 +140,9 @@ static int itemroulette_get(lua_State *L)
case itemroulette_reserved:
lua_pushinteger(L, itemroulette->reserved);
break;
case itemroulette_popcorn:
lua_pushinteger(L, itemroulette->popcorn);
break;
}
return 1;
@ -172,6 +182,9 @@ static int itemroulette_set(lua_State *L)
case itemroulette_exiting:
itemroulette->exiting = luaL_checkinteger(L, 3);
break;
case itemroulette_preexpdist:
itemroulette->preexpdist = luaL_checkinteger(L, 3);
break;
case itemroulette_dist:
itemroulette->dist = luaL_checkinteger(L, 3);
break;
@ -214,6 +227,9 @@ static int itemroulette_set(lua_State *L)
case itemroulette_reserved:
itemroulette->reserved = luaL_checkinteger(L, 3);
break;
case itemroulette_popcorn:
itemroulette->popcorn = luaL_checkinteger(L, 3);
break;
}
return 0;
}

View file

@ -118,6 +118,16 @@ extern lua_State *gL;
#define META_OVERLAY "T_OVERLAY_T*"
#define META_TERRAIN "TERRAIN_T*"
#define META_POWERUPVARS "POWERUPVARS_T*"
#define META_ICECUBEVARS "ICECUBEVARS_T*"
#define META_SKYBOX "SKYBOX_T*"
#define META_CUP "CUPHEADER_T*"
#define META_GPRANK "GPRANK_T*"
#define META_GPRANKLEVEL "GPRANK_LEVEL_T*"
#define META_GPRANKLEVELPERPLAYER "GPRANK_LEVEL_PERPLAYER_T*"
#define META_ROUNDENTRY "ROUNDENTRY_T*"
boolean luaL_checkboolean(lua_State *L, int narg);
int LUA_EnumLib(lua_State *L);
@ -142,6 +152,7 @@ int LUA_BotVarsLib(lua_State *L);
int LUA_TerrainLib(lua_State *L);
int LUA_RespawnVarsLib(lua_State *L);
int LUA_WaypointLib(lua_State *L);
int LUA_GrandPrixLib(lua_State *L);
#ifdef __cplusplus
} // extern "C"

File diff suppressed because it is too large Load diff

View file

@ -66,6 +66,7 @@ static lua_CFunction liblist[] = {
LUA_TerrainLib, // t_splash_t, t_footstep_t, t_overlay_t, terrain_t
LUA_RespawnVarsLib, // respawnvars_t
LUA_WaypointLib, // waypoint_t
LUA_GrandPrixLib, // grandprixinfo, cupheader_t, gprank_t, skinrecord_t, etc.
NULL
};

View file

@ -117,6 +117,9 @@ void COM_Lua_f(void);
// Music: "No tune" error.
#define LUA_ErrNoTune(L, tune) luaL_error(L, "tune \"%s\" does not exist", tune)
// Music: "Stereo Mode" error.
#define LUA_ErrStereo(L, tune) luaL_error(L, "tune \"%s\" cannot be remapped (stereo mode)", tune)
// Deprecation warnings
// Shows once upon use. Then doesn't show again.
#define LUA_Deprecated(L,this_func,use_instead)\

View file

@ -113,8 +113,13 @@ static int skin_get(lua_State *L)
lua_pushinteger(L, skin->highresscale);
break;
case skin_rivals:
// This would be pretty cool to push
return UNIMPLEMENTED;
lua_createtable(L, SKINRIVALS, 0);
for (size_t i = 0; i < SKINRIVALS; i++)
{
lua_pushstring(L, skin->rivals[i]);
lua_rawseti(L, -2, 1 + i);
}
break;
case skin_soundsid:
LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID);
break;

View file

@ -1797,7 +1797,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
case UCRP_PREFIX_BONUSROUND:
return ((grandprixinfo.gp == true) && (grandprixinfo.eventmode == GPEVENT_BONUS));
case UCRP_PREFIX_TIMEATTACK:
return (modeattacking != ATTACKING_NONE);
return (modeattacking != ATTACKING_NONE && !(skins[player->skin]->flags & SF_HIVOLT));
case UCRP_PREFIX_PRISONBREAK:
return ((gametyperules & GTR_PRISONS) && battleprisons);
case UCRP_PREFIX_SEALEDSTAR:
@ -1843,8 +1843,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
if (cn->extrainfo2 != 0)
return (K_PodiumGrade() >= cn->extrainfo1);
if (cn->extrainfo1 != 0)
return (player->position != 0
&& player->position <= cn->extrainfo1);
return K_GetPodiumPosition(player) <= cn->extrainfo1;
return true;
case UCRP_PODIUMEMERALD:
case UCRP_PODIUMPRIZE:

View file

@ -32,6 +32,11 @@
// Extended map support.
#include <ctype.h>
#if defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
#include <immintrin.h>
#define NEED_INTEL_DENORMAL_BIT 1
#endif
#include "doomdef.h"
#include "g_game.h"
#include "m_misc.h"
@ -2805,3 +2810,44 @@ const char * M_Ftrim (double f)
return &dig[1];/* skip the 0 */
}
}
/** Enable floating point denormal-to-zero section, if necessary */
floatdenormalstate_t M_EnterFloatDenormalToZero(void)
{
#ifdef NEED_INTEL_DENORMAL_BIT
floatdenormalstate_t state = 0;
state |= _MM_GET_FLUSH_ZERO_MODE() == _MM_FLUSH_ZERO_ON ? 1 : 0;
state |= _MM_GET_DENORMALS_ZERO_MODE() == _MM_DENORMALS_ZERO_ON ? 2 : 0;
if ((state & 1) == 0)
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
}
if ((state & 2) == 0)
{
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
}
return state;
#else
return 0;
#endif
}
/** Exit floating point denormal-to-zero section, if necessary, restoring previous state */
void M_ExitFloatDenormalToZero(floatdenormalstate_t previous)
{
#ifdef NEED_INTEL_DENORMAL_BIT
if ((previous & 1) == 0)
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
}
if ((previous & 2) == 0)
{
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
}
return;
#else
(void)previous;
return;
#endif
}

View file

@ -167,6 +167,13 @@ FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
extern char configfile[MAX_WADPATH];
typedef INT32 floatdenormalstate_t;
/** Enable floating point denormal-to-zero section, if necessary */
floatdenormalstate_t M_EnterFloatDenormalToZero(void);
/** Exit floating point denormal-to-zero section, if necessary, restoring previous state */
void M_ExitFloatDenormalToZero(floatdenormalstate_t previous);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -61,6 +61,8 @@ int ps_checkposition_calls = 0;
precise_t ps_lua_thinkframe_time = 0;
int ps_lua_mobjhooks = 0;
precise_t ps_voiceupdatetime = 0;
// dynamically allocated resizeable array for thinkframe hook stats
ps_hookinfo_t *thinkframe_hooks = NULL;
int thinkframe_hooks_length = 0;
@ -208,6 +210,7 @@ static void M_DrawRenderStats(void)
perfstatrow_t tictime_row[] = {
{"logic ", "Game logic: ", &ps_tictime},
{"voice ", "Voice update: ", &ps_voiceupdatetime},
{0}
};

View file

@ -45,6 +45,8 @@ extern int ps_checkposition_calls;
extern precise_t ps_lua_thinkframe_time;
extern int ps_lua_mobjhooks;
extern precise_t ps_voiceupdatetime;
struct ps_hookinfo_t
{
precise_t time_taken;

View file

@ -32,6 +32,7 @@
#include "g_game.h"
#include "k_menu.h"
#include "m_cheat.h"
#include "m_random.h"
#include "m_cond.h"
#include "m_pw.h"
#include "m_pw_hash.h"
@ -364,6 +365,111 @@ void f_maps()
}
}
void f_tutorials()
{
UINT16 i;
boolean success = false;
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (!unlockables[i].conditionset)
continue;
if (unlockables[i].conditionset == CH_FURYBIKE)
continue;
if (gamedata->unlocked[i])
continue;
if (unlockables[i].type != SECRET_MAP)
continue;
UINT16 mapnum = M_UnlockableMapNum(&unlockables[i]);
if (mapnum >= nummapheaders || !mapheaderinfo[mapnum])
continue;
if (G_GuessGametypeByTOL(mapheaderinfo[mapnum]->typeoflevel) != GT_TUTORIAL)
continue;
gamedata->unlocked[i] = true;
success = true;
}
if (success)
{
S_StartSound(0, sfx_kc42);
G_SaveGameData();
}
const char *knucklesrap;
const UINT8 numsections = 5;
static UINT8 section = numsections;
if (section == numsections)
section = M_RandomKey(numsections);
switch (section)
{
default:
knucklesrap =
"\x85""So here's what I'm thinkin', \n"
"\x85"" last time smart guys got together,\n"
"\x85""In a tough sandy place \n"
"\x85"" with a lot of hot weather,\n"
"\x85""Playin' fundamental forces \n"
"\x85"" at the top of their class,\n"
"\x85""They made the sky so much hotter \n"
"\x85"" and that sand into glass!\x80";
break;
case 1:
knucklesrap =
"\x85""But somethin's different, see? \n"
"\x85""My homie right there, I trust him trustin'\n"
"\x85"" the Eggman like it's nothin',\n"
"\x85""A smart little guy \n"
"\x85"" with a brother I like fightin',\n"
"\x85""If there's somethin' cooking \n"
"\x85"" I'm sure he'll do the right thing.\x80";
break;
case 2:
knucklesrap =
"\x85""I watched a space station fall, \n"
"\x85"" straight down, fast fall, into the ground,\n"
"\x85""Pieces of fire, shooting stars, \n"
"\x85"" don't make a wish, kids\n"
"\x85""Last second it's, gone, I ask how, \n"
"\x85"" behold, they call it chaos control,\n"
"\x85""I don't know it, never heard it, seen it, felt it, \n"
"\x85"" sensed it. Even to me, these powers are a mystery.\x80";
break;
case 3:
knucklesrap =
"\x85""The tide goes out, it carries time away, \n"
"\x85"" we call it yesterday,\n"
"\x85""The tide comes in, it rings, it sings, \n"
"\x85"" it brings a new age,\n"
"\x85""But right now it's just me and the water, \n"
"\x85"" thoughts clear, future lookin' hotter,\n"
"\x85""I let myself sink in, feel the waves, \n"
"\x85"" feel my body get lighter.\x80";
break;
case 4:
knucklesrap =
"\x85""Somethin' brewin' at the edges, \n"
"\x85"" that's what a ring is, nothin' but edges,\n"
"\x85""Circled light in a band, \n"
"\x85"" hold 'em in in your hand,\n"
"\x85""But it's a miracle a thousand times over,\n"
"\x85""Small gasps of potential\n"
"\x85"" floatin' over the sand.\x80";
break;
}
section = (section + 1) % numsections;
M_StartMessage("\"Broken Arrow\" ...for Sunbeam Paradise",
va("\"%s\"\n\n%s",
knucklesrap,
(success ? "Unlocked all Tutorials." : "There are no more Tutorials to unlock.")),
NULL, MM_NOTHING, NULL, NULL);
}
void f_characters()
{
UINT16 i;
@ -779,6 +885,7 @@ void M_PasswordInit(void)
passwords.emplace_back(f_colors, "aSk8dw6FzJtTEmovh8fVEtUBpu6lj3QlRT/B5lwiEhAw8dAhRBQLdvtYlPaQcZISWI4wneAfAo6w5d6uf5r++g==");
passwords.emplace_back(f_followers, "zYCIZw2qcnUbtF0P2ybLNHajdl8zrje0hzGex7yuMFe7fj4mvx4AegoMmvir28YvAbfAqkz/ekQRzr+RhrycHw==");
passwords.emplace_back(f_maps, "u/Svaf+DCnCpJ8xmP3AVP4CK6X6X4O3fY73cmIq88ZJEygwz+n+L66q4Vhlv13vWgld1PEyRszFErzflQt9WZw==");
passwords.emplace_back(f_tutorials, "G2FMttJpJ+lI/DeQu8tthL5i7AB4dk8uuksZR1c2N08Zrmpj3vTqWpbhxuSzSrhH10wJfWahR7QOgQdBkDbTdQ==");
passwords.emplace_back(f_characters, "MohmPqpaGSd3MEHLfQKUFl/Yg8pHE+12X1LHEP59Gs/5w1u8mPtGUXNv1GYTF+c8gQqT5hXpZ3FeZ/EfCxo34g==");
passwords.emplace_back(f_altmusic, "dZgxKNagOtB9F7wXqUUPzsuq4tfQlfK8ZqEeFXdI3Hd+k5tYfRm3ToLgbqawaNmwuLVrJ8PB+QnH4gT3ojnTMw==");
passwords.emplace_back(f_timeattack, "mFu5OB9d6jnc2kth7HE66wJ42F/GHDzSvuciK1Qw++6iGnpBccxcKjpoxgOvD3eIoqR606ruBINuXi23proXHQ==");

View file

@ -21,7 +21,42 @@
#include "m_random.h"
#include "m_fixed.h"
char rng_class_names[34][30] = {
"UNDEFINED",
"EXECUTOR",
"ACS",
"DECORATION",
"TERRAIN",
"BUBBLE",
"RANDOMANIM",
"PLAYERSTARTS",
"VOICES",
"RANDOMSKIN",
"RANDOMAUDIENCE",
"RULESCRAMBLE",
"MUSICSELECT",
"ITEM_ROULETTE",
"ITEM_RINGS",
"ITEM_SHRINK",
"ITEM_BUBBLE",
"ITEM_DEBRIS",
"ITEM_BOOST",
"EXPLOSION",
"SMOLDERING",
"SPARKLE",
"MOVINGTARGET",
"TRACKHAZARDD",
"BATTLEUFO",
"BOTS",
"AUTOROULETTE",
"FUZZ",
"FROSTTHROWERS",
"ITEM_SPAWNER",
"TEAMS",
"DUMMY",
"INTERPHUDRANDOM",
"NUISANCE"
};
// ---------------------------
// RNG functions (not synched)

View file

@ -103,6 +103,7 @@ typedef enum
PRNUMCLASS
} pr_class_t;
extern char rng_class_names[34][30];
// M_Random functions pull random numbers of various types that aren't network synced.
// P_Random functions pulls random bytes from a PRNG that is network synced.

View file

@ -438,7 +438,7 @@ void EggTV::watch() const
{
restoreMenu = currentMenu;
M_ClearMenus(false);
M_ClearMenusNoTitle(false);
demo.loadfiles = true;
demo.ignorefiles = false;

View file

@ -229,7 +229,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
const std::string_view str = info.title;
const std::size_t mid = str.find(kDelimiter);
title_ = Title(str.substr(0, mid), mid == srb2::String::npos ? "" : str.substr(mid + kDelimiter.size()));
title_ = Title(str.substr(0, mid), mid == std::string_view::npos ? "" : str.substr(mid + kDelimiter.size()));
//title_ = Title("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "WWWWWWWWWWWWWWWWWWWWWWWWWWW");
}

View file

@ -57,12 +57,12 @@ static void M_GonerHandStrain(INT32 ch)
static void M_GonerPhotosensitivity(INT32 ch)
{
if (ch == MA_YES)
{
CV_StealthSet(&cv_reducevfx, "Yes");
CV_StealthSet(&cv_screenshake, "Off");
CV_StealthSet(&cv_tilting, "Off");
}
// if (ch == MA_YES)
// {
// CV_StealthSet(&cv_reducevfx, "Yes");
// CV_StealthSet(&cv_screenshake, "Off");
// CV_StealthSet(&cv_tilting, "Off");
// }
#ifdef HANDSTRAIN
M_StartMessage("Hand strain warning",
@ -96,9 +96,12 @@ static void M_GonerAccessibilityTick(void)
"patterns.""\x80"" Listen to your body, and\n"
"stop playing if you feel unwell.\n"
"\n"
"There is a ""\x88""special mode""\x80"" to reduce some\n"
"visual effects. Would you like to turn it on?\n"
, &M_GonerPhotosensitivity, MM_YESNO, "Yes, reduce effects", "No thanks");
"There is a ""\x88""special mode""\x80""\n"
"to reduce some visual effects.\n"
"\n"
"You can turn it on within the\n"
"Profile Setup > Accessibility menu.\n"
, &M_GonerPhotosensitivity, MM_NOTHING, NULL, NULL);
return;
}

View file

@ -28,7 +28,7 @@ menuitem_t OPTIONS_DataAdvancedAddon[] =
{IT_STRING | IT_CVAR, "Matching", "Set where to check for the text pattern when looking up addons via name.",
NULL, {.cvar = &cv_addons_search_type}, 0, 0},
{IT_STRING | IT_CVAR, "Case Sensitivity", "Set whether to consider the case when searching for addons..",
{IT_STRING | IT_CVAR, "Case Sensitivity", "Set whether to consider the case when searching for addons.",
NULL, {.cvar = &cv_addons_search_case}, 0, 0},
};

View file

@ -27,7 +27,7 @@ menuitem_t OPTIONS_EditProfile[] = {
{IT_STRING | IT_CALL, "Controls", "Change the button mappings.",
NULL, {.routine = M_ProfileDeviceSelect}, 0, 91},
{IT_STRING | IT_SUBMENU, "Accessibility", "Acccessibility and quality of life options.",
{IT_STRING | IT_SUBMENU, "Accessibility", "Accessibility and quality of life options.",
NULL, {.submenu = &OPTIONS_ProfileAccessibilityDef}, 0, 111},
{IT_STRING | IT_CALL, "Character", NULL, // tooltip set in M_StartEditProfile

View file

@ -29,7 +29,7 @@ menuitem_t OPTIONS_Voice[] =
NULL, srb2::itemaction(&cv_voice_inputamp), 0, 0},
{IT_STRING | IT_CVAR, "Input Noise Suppression", "Suppress background noise from your voice.",
NULL, {.cvar = &cv_voice_denoise}, 0, 0},
NULL, srb2::itemaction(&cv_voice_denoise), 0, 0},
{IT_STRING | IT_CVAR, "Input Sensitivity", "Voice higher than this threshold will transmit, in decibels.",
NULL, srb2::itemaction(&cv_voice_activationthreshold), 0, 0 },

View file

@ -1019,7 +1019,10 @@ static void M_HandleColorRotate(setup_player_t *p, UINT8 num)
{
if (p->skin >= 0)
{
p->color = SKINCOLOR_NONE;
if (p->color == SKINCOLOR_NONE)
p->color = PR_GetProfile(p->profilen)->color;
else
p->color = SKINCOLOR_NONE;
p->rotate = CSROTATETICS;
p->hitlag = true;
S_StartSound(NULL, sfx_s3k7b); //sfx_s3kc3s
@ -1252,8 +1255,11 @@ static void M_HandleFollowerColorRotate(setup_player_t *p, UINT8 num)
}
else if (M_MenuExtraPressed(num))
{
UINT16 profile_followercolor = PR_GetProfile(p->profilen)->followercolor;
if (p->followercolor == FOLLOWERCOLOR_MATCH)
p->followercolor = FOLLOWERCOLOR_OPPOSITE;
else if (p->followercolor == FOLLOWERCOLOR_OPPOSITE && profile_followercolor != FOLLOWERCOLOR_OPPOSITE && profile_followercolor != FOLLOWERCOLOR_MATCH)
p->followercolor = profile_followercolor;
else if (p->followercolor == SKINCOLOR_NONE)
p->followercolor = FOLLOWERCOLOR_MATCH;
else

View file

@ -266,6 +266,23 @@ menu_t PLAY_TAGhostsDef = {
NULL
};
// See also G_UpdateRecordReplays
const char *M_GetRecordMode(void)
{
if (cv_dummyspbattack.value)
{
return "spb-";
}
const INT32 skinid = R_SkinAvailableEx(cv_skin[0].string, false);
if (skinid >= 0 && (skins[skinid]->flags & SF_HIVOLT))
{
return "hivolt-";
}
return "";
}
void CV_SPBAttackChanged(void);
void CV_SPBAttackChanged(void)
{
@ -275,14 +292,12 @@ void CV_SPBAttackChanged(void)
{
// see also p_setup.c's P_LoadRecordGhosts
char *gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1)));
const char *modeprefix = "";
const char *modeprefix = M_GetRecordMode();
UINT8 active;
if (!gpath)
return;
if (cv_dummyspbattack.value)
modeprefix = "spb-";
active = false;
PLAY_TimeAttack[ta_guest].status = IT_DISABLED;
@ -440,7 +455,7 @@ void M_HandleStaffReplay(INT32 choice)
staffbrief_t *staffbrief;
restoreMenu = &PLAY_TAReplayDef;
M_ClearMenus(true);
M_ClearMenusNoTitle(true);
demo.loadfiles = false;
demo.ignorefiles = true; // Just assume that record attack replays have the files needed
@ -458,20 +473,7 @@ void M_ReplayTimeAttack(INT32 choice)
{
menudemo_t menudemo = {0};
const char *which = NULL;
const char *modeprefix = "";
if (cv_dummyspbattack.value)
{
modeprefix = "spb-";
}
else
{
const INT32 skinid = R_SkinAvailableEx(cv_skin[0].string, false);
if (skinid >= 0 && (skins[skinid]->flags & SF_HIVOLT))
{
modeprefix = "hivolt-";
}
}
const char *modeprefix = M_GetRecordMode();
switch (choice)
{
@ -507,7 +509,7 @@ void M_ReplayTimeAttack(INT32 choice)
restoreMenu = &PLAY_TAReplayDef;
M_ClearMenus(true);
M_ClearMenusNoTitle(true);
demo.loadfiles = false;
demo.ignorefiles = true; // Just assume that record attack replays have the files needed
@ -528,20 +530,7 @@ static void M_WriteGuestReplay(INT32 ch)
gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1)));
const char *modeprefix = "";
if (cv_dummyspbattack.value)
{
modeprefix = "spb-";
}
else
{
const INT32 skinid = R_SkinAvailableEx(cv_skin[0].string, false);
if (skinid >= 0 && (skins[skinid]->flags & SF_HIVOLT))
{
modeprefix = "hivolt-";
}
}
const char *modeprefix = M_GetRecordMode();
if (TA_GuestReplay_Str != NULL)
{
@ -597,20 +586,7 @@ void M_SetGuestReplay(INT32 choice)
break;
}
const char *modeprefix = "";
if (cv_dummyspbattack.value)
{
modeprefix = "spb-";
}
else
{
const INT32 skinid = R_SkinAvailableEx(cv_skin[0].string, false);
if (skinid >= 0 && (skins[skinid]->flags & SF_HIVOLT))
{
modeprefix = "hivolt-";
}
}
const char *modeprefix = M_GetRecordMode();
if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%sguest.lmp", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1), modeprefix)))
{
@ -626,7 +602,7 @@ void M_StartTimeAttack(INT32 choice)
{
char *gpath;
char nameofdemo[256];
const char *modeprefix = "";
const char *modeprefix = M_GetRecordMode();
(void)choice;
@ -649,16 +625,6 @@ void M_StartTimeAttack(INT32 choice)
{
encoremode = true; // guarantees short wipe
}
modeprefix = "spb-";
}
else
{
const INT32 skinid = R_SkinAvailableEx(cv_skin[0].string, false);
if (skinid >= 0 && (skins[skinid]->flags & SF_HIVOLT))
{
modeprefix = "hivolt-";
}
}
// DON'T SOFTLOCK
@ -692,7 +658,7 @@ void M_StartTimeAttack(INT32 choice)
false
);
M_ClearMenus(true);
M_ClearMenusNoTitle(true);
G_UpdateTimeStickerMedals(levellist.choosemap, true);
}

View file

@ -287,6 +287,97 @@ static void M_GPBackup(INT32 choice)
M_StartCup(UINT8_MAX);
}
static boolean M_IsCupQueueable(cupheader_t *cup)
{
levelsearch_t templevelsearch = levellist.levelsearch; // copy levellist so we don't mess with stuff I think
UINT16 ShownCount = 0;
UINT16 CupCount = 0;
UINT32 CheckGametype[2] = {TOL_RACE,TOL_BATTLE};
templevelsearch.cup = cup;
UINT8 e, i = 0;
for (e = 0; e < 2; e++)
{
templevelsearch.typeoflevel = CheckGametype[e];
ShownCount += M_CountLevelsToShowInList(&templevelsearch);
}
//CONS_Printf(M_GetText("ShownCount: %d\n"), ShownCount);
UINT16 checkmap = NEXTMAP_INVALID;
for (i = 0; i < CUPCACHE_SPECIAL; i++)
{
checkmap = templevelsearch.cup->cachedlevels[i];
if (checkmap == NEXTMAP_INVALID)
{
continue;
}
CupCount++;
}
//CONS_Printf(M_GetText("CupCount: %d\n"), CupCount);
if (ShownCount >= CupCount) // greater than is used to ensure multi-gametype maps don't accidentally cause this to return false.
return true;
return false;
}
static void M_CupStartResponse(INT32 ch)
{
if (ch != MA_YES)
return;
if (!(server || (IsPlayerAdmin(consoleplayer))))
return;
M_LevelConfirmHandler();
}
static void M_CupQueueResponse(INT32 ch)
{
if (ch != MA_YES)
return;
if (!(server || (IsPlayerAdmin(consoleplayer))))
return;
cupheader_t *queuedcup = cupgrid.builtgrid[CUPMENU_CURSORID];
M_CupQueueHandler(queuedcup);
S_StartSound(NULL, sfx_gshe2);
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (!netgame)
{
M_StartMessage("Cup Queue",
va(M_GetText(
"You just queued %s CUP.\n"
"\n"
"Do you want to start the\n"
"cup immediately?\n"
), queuedcup->realname
), &M_CupStartResponse, MM_YESNO,
"Here we go!",
"On second thought..."
);
}
else
{
M_StartMessage("Cup Queue",
va(M_GetText(
"You just queued %s CUP.\n"
"\n"
"Do you want to queue it\n"
"for everyone?\n"
), queuedcup->realname
), &M_CupStartResponse, MM_YESNO,
"Queue em up!",
"Not yet"
);
}
}
void M_CupSelectHandler(INT32 choice)
{
const UINT8 pid = 0;
@ -429,6 +520,63 @@ void M_CupSelectHandler(INT32 choice)
S_StartSound(NULL, sfx_s3k63);
}
}
// Queue a cup for match race and netgames. See levelselect.c for most of how this actually works.
else if (levellist.canqueue && M_MenuButtonPressed(pid, MBT_Z))
{
M_SetMenuDelay(pid);
if ((cupgrid.builtgrid[CUPMENU_CURSORID] == &dummy_lostandfound) || (cupgrid.builtgrid[CUPMENU_CURSORID] == NULL))
S_StartSound(NULL, sfx_gshe7);
else if (!M_IsCupQueueable(cupgrid.builtgrid[CUPMENU_CURSORID]))
{
S_StartSound(NULL, sfx_s3kb2);
M_StartMessage("Back to the Grand Prix!", "Can't queue a cup you haven't fully unlocked!", NULL, MM_NOTHING, NULL, NULL);
}
// Better to avoid any headaches here - pass the buck to the Extra button.
else if (roundqueue.size)
{
S_StartSound(NULL, sfx_s3kb2);
M_StartMessage("Queue is not empty!", "Clear the queue before trying to queue a cup!", NULL, MM_NOTHING, NULL, NULL);
return;
}
else
{
// We're not queueing Battle maps if we're in single-player Match Race.
if (!levellist.netgame && (cv_splitplayers.value == 1) && !netgame)
{
M_StartMessage("Cup Queue",
va(M_GetText(
"This will queue all Race courses in this cup.\n"
"\n"
"Any rounds already in the queue will be cleared out.\n"
"\n"
"Do you want to queue the cup?\n"
)), &M_CupQueueResponse, MM_YESNO,
"Let's do it!",
"Nah.");
}
else
{
M_StartMessage("Cup Queue",
va(M_GetText(
"This will queue the entire cup, including both Race and Battle courses.\n"
"\n"
"Any rounds already in the queue will be cleared out.\n"
"\n"
"Do you want to queue the cup?\n"
)), &M_CupQueueResponse, MM_YESNO,
"Let's do it!",
"Nah.");
}
}
}
else if (levellist.canqueue && M_MenuExtraPressed(pid))
{
M_ClearQueueHandler();
}
else if (M_MenuBackPressed(pid))
{
M_SetMenuDelay(pid);
@ -443,4 +591,6 @@ void M_CupSelectHandler(INT32 choice)
void M_CupSelectTick(void)
{
cupgrid.previewanim++;
// Shoving this here for cup queue purposes.
M_LevelSelectTick();
}

View file

@ -832,8 +832,10 @@ void M_LevelSelected(INT16 add, boolean menuupdate)
static void M_MenuQueueStopSend(INT32 ch)
{
(void)ch;
memset(&menuqueue, 0, sizeof(struct menuqueue));
menuqueue.clearing = false;
}
static void M_MenuQueueSelectedLocal(void)
@ -905,6 +907,92 @@ static void M_MenuQueueSelectedLocal(void)
}
}
// Copy-pasted and edited from G_GPCupIntoRoundQueue
void M_CupQueueHandler(cupheader_t *cup)
{
UINT8 i, levelindex = 0, bonusindex = 0;
UINT8 bonusmodulo = max(1, (cup->numlevels+1)/(cup->numbonus+1));
UINT16 cupLevelNum;
INT32 gtcheck;
// We shouldn't get to this point while there's rounds queued, but if we do, get outta there.
if (roundqueue.size)
{
return;
}
menuqueue.size = 0;
// Levels are added to the queue in the following pattern.
// For 5 Race rounds and 2 Bonus rounds, the most common case:
// race - race - BONUS - race - race - BONUS - race
// The system is flexible enough to permit other arrangements.
// However, we just want to keep the pacing even & consistent.
while (levelindex < cup->numlevels)
{
memset(menuqueue.entries+menuqueue.size, 0, sizeof(roundentry_t));
// Fill like two or three Race maps.
for (i = 0; i < bonusmodulo; i++)
{
cupLevelNum = cup->cachedlevels[levelindex];
if (cupLevelNum >= nummapheaders)
{
// Just skip the map if it's invalid.
continue;
}
if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_RACE) == TOL_RACE)
{
gtcheck = GT_RACE;
}
else
{
gtcheck = mapheaderinfo[cupLevelNum]->typeoflevel;
}
menuqueue.entries[menuqueue.size].mapnum = cupLevelNum;
menuqueue.entries[menuqueue.size].gametype = gtcheck;
menuqueue.entries[menuqueue.size].encore = (cv_kartencore.value == 1);
menuqueue.size++;
levelindex++;
if (levelindex >= cup->numlevels)
break;
}
// Attempt to add an interstitial Battle round.
// If we're in singleplayer Match Race, just skip this.
if ((levelindex < cup->numlevels
&& bonusindex < cup->numbonus) && (levellist.netgame || (cv_splitplayers.value > 1) || netgame))
{
cupLevelNum = cup->cachedlevels[CUPCACHE_BONUS + bonusindex];
if (cupLevelNum < nummapheaders)
{
if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_BATTLE) == TOL_BATTLE)
{
gtcheck = GT_BATTLE;
}
else
{
gtcheck = mapheaderinfo[cupLevelNum]->typeoflevel;
}
// In the case of Bonus rounds, we simply skip invalid maps.
menuqueue.entries[menuqueue.size].mapnum = cupLevelNum;
menuqueue.entries[menuqueue.size].gametype = gtcheck;
menuqueue.entries[menuqueue.size].encore = (cv_kartencore.value == 1);
menuqueue.size++;
}
bonusindex++;
}
}
}
boolean M_LevelSelectCupSwitch(boolean next, boolean skipones)
{
levelsearch_t templevelsearch = levellist.levelsearch;
@ -1002,6 +1090,40 @@ static void M_MenuQueueResponse(INT32 ch)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
// Ripped out of LevelSelectHandler for use in cup queueing from cupselect.c
void M_LevelConfirmHandler(void)
{
// Starting immediately OR importing queue
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (!levellist.canqueue || !menuqueue.size)
{
M_LevelSelected(levellist.cursor, true);
}
else if (netgame)
{
menuqueue.anchor = roundqueue.size;
menuqueue.sending = 1;
M_StartMessage("Queueing Rounds",
va(M_GetText(
"Attempting to send %d Round%s...\n"
"\n"
"If this is taking longer than you\n"
"expect, exit out of this message.\n"
), menuqueue.size, (menuqueue.size == 1 ? "" : "s")
), &M_MenuQueueStopSend, MM_NOTHING,
NULL,
"This is taking too long..."
);
}
else
{
M_MenuQueueSelectedLocal();
}
}
static void M_ClearQueueResponse(INT32 ch)
{
@ -1012,18 +1134,56 @@ static void M_ClearQueueResponse(INT32 ch)
return;
S_StartSound(NULL, sfx_slip);
if (netgame)
if (!netgame)
memset(&roundqueue, 0, sizeof(struct roundqueue));
if (netgame && (roundqueue.size != 0))
{
if (roundqueue.size)
{
Handle_MapQueueSend(0, ROUNDQUEUE_CMD_CLEAR, false);
}
return;
menuqueue.clearing = true;
Handle_MapQueueSend(0, ROUNDQUEUE_CMD_CLEAR, false);
M_StartMessage("Clearing Rounds",
va(M_GetText(
"Attempting to clear %d Round%s...\n"
"\n"
"If this is taking longer than you\n"
"expect, exit out of this message.\n"
), roundqueue.size, (roundqueue.size == 1 ? "" : "s")
), &M_MenuQueueStopSend, MM_NOTHING,
NULL,
"This is taking too long..."
);
}
memset(&roundqueue, 0, sizeof(struct roundqueue));
}
// Ripped out of LevelSelectHandler for use in queue clearing from cupselect.c
void M_ClearQueueHandler(void)
{
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (menuqueue.size)
{
S_StartSound(NULL, sfx_shldls);
menuqueue.size--;
}
else if (roundqueue.size)
{
M_StartMessage("Queue Clearing",
va(M_GetText(
"There %s %d Round%s of play queued.\n"
"\n"
"Do you want to empty the queue?\n"
),
(roundqueue.size == 1 ? "is" : "are"),
roundqueue.size,
(roundqueue.size == 1 ? "" : "s")
), &M_ClearQueueResponse, MM_YESNO,
"Time to start fresh",
"Not right now"
);
}
}
void M_LevelSelectHandler(INT32 choice)
{
const UINT8 pid = 0;
@ -1074,38 +1234,9 @@ void M_LevelSelectHandler(INT32 choice)
if (M_MenuConfirmPressed(pid))
{
// Starting immediately OR importing queue
M_SetMenuDelay(pid);
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (!levellist.canqueue || !menuqueue.size)
{
M_LevelSelected(levellist.cursor, true);
}
else if (netgame)
{
menuqueue.anchor = roundqueue.size;
menuqueue.sending = 1;
M_StartMessage("Queueing Rounds",
va(M_GetText(
"Attempting to send %d Round%s...\n"
"\n"
"If this is taking longer than you\n"
"expect, exit out of this message.\n"
), menuqueue.size, (menuqueue.size == 1 ? "" : "s")
), &M_MenuQueueStopSend, MM_NOTHING,
NULL,
"This is taking too long..."
);
}
else
{
M_MenuQueueSelectedLocal();
}
M_LevelConfirmHandler();
}
else if (levellist.canqueue && M_MenuButtonPressed(pid, MBT_Z))
{
@ -1138,30 +1269,7 @@ void M_LevelSelectHandler(INT32 choice)
}
else if (levellist.canqueue && M_MenuExtraPressed(pid))
{
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (menuqueue.size)
{
S_StartSound(NULL, sfx_shldls);
menuqueue.size--;
}
else if (roundqueue.size)
{
M_StartMessage("Queue Clearing",
va(M_GetText(
"There %s %d Round%s of play queued.\n"
"\n"
"Do you want to empty the queue?\n"
),
(roundqueue.size == 1 ? "is" : "are"),
roundqueue.size,
(roundqueue.size == 1 ? "" : "s")
), &M_ClearQueueResponse, MM_YESNO,
"Time to start fresh",
"Not right now"
);
}
M_ClearQueueHandler();
}
else if (M_MenuBackPressed(pid))
{
@ -1176,9 +1284,20 @@ void M_LevelSelectHandler(INT32 choice)
void M_LevelSelectTick(void)
{
if (menuqueue.clearing)
{
if (roundqueue.size != 0)
return;
menuqueue.clearing = false;
if (!menuqueue.cupqueue)
M_StopMessage(MA_NONE);
else
menuqueue.cupqueue = false;
}
if (!menuqueue.sending)
return;
if ((menuqueue.sending <= menuqueue.size) // Sending
&& (roundqueue.size >= menuqueue.anchor)) // Didn't get it wiped
{

View file

@ -15,6 +15,7 @@
#include "../../d_netcmd.h"
#include "../../i_time.h"
#include "../../k_menu.h"
#include "../../hu_stuff.h"
#include "../../k_grandprix.h" // K_CanChangeRules
#include "../../m_cond.h"
#include "../../s_sound.h"
@ -125,6 +126,9 @@ void M_OpenPauseMenu(void)
pausemenu.openoffset.dist = 0;
pausemenu.closing = false;
// Fix specific input error regarding closing netgame chat with escape while a controller is connected (only on Windows?)
chat_keydown = false;
itemOn = currentMenu->lastOn = mpause_continue; // Make sure we select "RESUME GAME" by default
// Now the hilarious balancing act of deciding what options should be enabled and which ones shouldn't be!

View file

@ -39,7 +39,7 @@ menuitem_t PAUSE_PlaybackMenu[] =
{IT_CALL | IT_STRING, "Hide Menu", NULL, "M_PHIDE", {.routine = M_SelectableClearMenus}, 0, 0},
{IT_CALL | IT_STRING, "Restart", NULL, "M_PRSTRT", {.routine = M_PlaybackRewind}, 20, 0},
{IT_CALL | IT_STRING, "Rewind 5 seconds", NULL, "M_PREW", {.routine = M_PlaybackRewind}, 36, 0},
{IT_CALL | IT_STRING, "Rewind 10 seconds", NULL, "M_PREW", {.routine = M_PlaybackRewind}, 36, 0},
{IT_CALL | IT_STRING, "Pause", NULL, "M_PPAUSE", {.routine = M_PlaybackPause}, 52, 0},
{IT_CALL | IT_STRING, "Fast-Forward", NULL, "M_PFFWD", {.routine = M_PlaybackFastForward}, 68, 0},
{IT_CALL | IT_STRING, "Resume", NULL, "M_PRESUM", {.routine = M_PlaybackPause}, 52, 0},
@ -220,9 +220,9 @@ void M_PlaybackRewind(INT32 choice)
if (demo.simplerewind)
{
if (curleveltime > 5*TICRATE)
if (curleveltime > 10*TICRATE)
{
g_fast_forward = curleveltime - (5 * TICRATE);
g_fast_forward = curleveltime - (10 * TICRATE);
g_fast_forward_clock_stop = INFTICS; //I_GetTime() + 2 * TICRATE; -- maybe?
}
else

View file

@ -25,6 +25,7 @@ TuneManager g_tunes;
void Music_Init(void)
{
// Many tunes below now have their default songs set in Music_TuneReset. Check there first for changing those.
{
Tune& tune = g_tunes.insert("level");
@ -55,21 +56,21 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("battle_overtime", g_tunes.find("level"));
tune.song = "shwdwn";
tune.song = ""; // Music_TuneReset
tune.priority = 11;
}
{
Tune& tune = g_tunes.insert("battle_overtime_stress", g_tunes.find("battle_overtime"));
tune.song = "shwdn2";
tune.song = ""; // Music_TuneReset
tune.priority = 10;
}
{
Tune& tune = g_tunes.insert("grow");
tune.song = "kgrow";
tune.song = ""; // Music_TuneReset
tune.priority = 20;
tune.resume_fade_in = 200;
tune.use_level_volume = true;
@ -78,7 +79,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("invinc");
tune.song = "kinvnc";
tune.song = ""; // Music_TuneReset
tune.priority = 21;
tune.use_level_volume = true;
}
@ -86,7 +87,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("finish_silence");
tune.song = "";
tune.song = ""; // Music_TuneReset
tune.priority = 30;
}
@ -100,7 +101,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("comeon");
tune.song = "chalng";
tune.song = ""; // Music_TuneReset
tune.priority = 35;
tune.loop = false;
}
@ -116,7 +117,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("vote");
tune.song = "vote";
tune.song = ""; // Music_TuneReset
tune.priority = 50;
tune.credit = true;
}
@ -124,14 +125,14 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("vote_suspense");
tune.song = "voteea";
tune.song = ""; // Music_TuneReset
tune.priority = 51;
}
{
Tune& tune = g_tunes.insert("vote_end");
tune.song = "voteeb";
tune.song = ""; // Music_TuneReset
tune.priority = 52;
tune.loop = false;
}
@ -139,14 +140,14 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("wait");
tune.song = "WAIT2J";
tune.song = ""; // Music_TuneReset
tune.priority = 60;
}
{
Tune& tune = g_tunes.insert("title");
tune.song = "_title";
tune.song = ""; // Music_TuneReset
tune.priority = 100;
tune.resist = true;
}
@ -167,7 +168,7 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("credits_silence");
tune.song = "";
tune.song = ""; // Music_TuneReset
tune.priority = 100;
}
@ -175,7 +176,7 @@ void Music_Init(void)
Tune& tune = g_tunes.insert("credits");
tune.priority = 101;
tune.song = "_creds";
tune.song = ""; // Music_TuneReset
tune.credit = true;
}
@ -213,10 +214,12 @@ void Music_Init(void)
{
Tune& tune = g_tunes.insert("lawyer");
tune.song = "lawyer";
tune.song = ""; // Music_TuneReset
tune.priority = 35;
tune.loop = false;
}
Music_TuneReset();
}
@ -522,3 +525,21 @@ void Music_ResetLevelVolume(void)
{
g_tunes.level_volume(100, true);
}
void Music_TuneReset(void)
{
Music_Remap("battle_overtime", "shwdwn");
Music_Remap("battle_overtime_stress", "shwdn2");
Music_Remap("grow", "kgrow");
Music_Remap("invinc", "kinvnc");
Music_Remap("finish_silence", "");
Music_Remap("comeon", "chalng");
Music_Remap("vote", "vote");
Music_Remap("vote_suspense", "voteea");
Music_Remap("vote_end", "voteeb");
Music_Remap("wait", "WAIT2J");
Music_Remap("title", "_title");
Music_Remap("credits_silence", "");
Music_Remap("credits", "_creds");
Music_Remap("lawyer", "lawyer");
}

View file

@ -207,6 +207,10 @@ void Music_Tick(void);
// the music plays again when re-enabled.
void Music_Flip(void);
// Resets all non-dynamic tunes to default values.
// Keeps ACS music remapping from playing havoc after a map.
void Music_TuneReset(void);
#ifdef __cplusplus
} // extern "C"

View file

@ -292,7 +292,7 @@ void Obj_BulbTouched(mobj_t *special, mobj_t *toucher)
P_MoveOrigin(toucher, special->x, special->y, special->z);
toucher->player->nocontrol = 1;
P_SetTarget(&toucher->tracer, special);
toucher->flags &= ~MF_SHOOTABLE;
toucher->flags &= ~(MF_SHOOTABLE|MF_NOGRAVITY);
toucher->renderflags |= RF_DONTDRAW;
P_SetTarget(&special->target, toucher);
special->extravalue1 = spd;

View file

@ -27,122 +27,125 @@
static void ghostme(mobj_t *exp, player_t *player)
{
if (exp->cusval%2)
return;
if (exp->cusval%2)
return;
mobj_t *ghost = P_SpawnGhostMobj(exp);
ghost->colorized = true;
ghost->color = player->skincolor;
ghost->renderflags |= RF_ADD;
ghost->fuse = 2;
mobj_t *ghost = P_SpawnGhostMobj(exp);
ghost->colorized = true;
ghost->color = player->skincolor;
ghost->renderflags |= RF_ADD;
ghost->fuse = 2;
}
void Obj_ExpThink (mobj_t *exp)
{
if (P_MobjWasRemoved(exp->target)
if (P_MobjWasRemoved(exp->target)
|| exp->target->health == 0
|| exp->target->destscale <= 1 // sealed star fall out
|| !exp->target->player)
{
P_RemoveMobj(exp);
}
else
{
mobj_t *mo = exp->target;
player_t *player = mo->player;
{
P_RemoveMobj(exp);
}
else
{
mobj_t *mo = exp->target;
player_t *player = mo->player;
fixed_t dist, fakez;
angle_t hang, vang;
fixed_t dist, fakez;
angle_t hang, vang;
dist = P_AproxDistance(P_AproxDistance(exp->x - mo->x, exp->y - mo->y), exp->z - mo->z);
dist = P_AproxDistance(P_AproxDistance(exp->x - mo->x, exp->y - mo->y), exp->z - mo->z);
exp->renderflags |= RF_DONTDRAW;
exp->renderflags &= ~K_GetPlayerDontDrawFlag(player);
exp->renderflags |= RF_DONTDRAW;
exp->renderflags &= ~K_GetPlayerDontDrawFlag(player);
// K_MatchGenericExtraFlags(exp, mo);
// K_MatchGenericExtraFlags(exp, mo);
exp->cusval++;
exp->cusval++;
// bullshit copypaste orbit behavior
if (exp->threshold)
{
fixed_t orbit = (4*mo->scale) * (16 - exp->extravalue1);
// bullshit copypaste orbit behavior
if (exp->threshold)
{
fixed_t orbit = (4*mo->scale) * (16 - exp->extravalue1);
P_SetScale(exp, (exp->destscale = mapobjectscale - ((mapobjectscale/28) * exp->extravalue1)));
exp->z = exp->target->z;
P_MoveOrigin(exp,
mo->x + FixedMul(orbit, FINECOSINE(exp->angle >> ANGLETOFINESHIFT)),
mo->y + FixedMul(orbit, FINESINE(exp->angle >> ANGLETOFINESHIFT)),
exp->z + mo->scale * 24 * P_MobjFlip(exp));
P_SetScale(exp, (exp->destscale = mapobjectscale - ((mapobjectscale/28) * exp->extravalue1)));
exp->z = exp->target->z;
P_MoveOrigin(exp,
mo->x + FixedMul(orbit, FINECOSINE(exp->angle >> ANGLETOFINESHIFT)),
mo->y + FixedMul(orbit, FINESINE(exp->angle >> ANGLETOFINESHIFT)),
exp->z + mo->scale * 24 * P_MobjFlip(exp));
exp->momx = 0;
exp->momy = 0;
exp->momz = 0;
exp->momx = 0;
exp->momy = 0;
exp->momz = 0;
ghostme(exp, player);
ghostme(exp, player);
exp->angle += ANG30;
exp->extravalue1++;
exp->angle += ANG30;
exp->extravalue1++;
if (exp->extravalue1 >= 16)
if (exp->extravalue1 >= 16)
{
if(P_IsDisplayPlayer(player)) // As you know Kris, I am FUCKING your EXP.
{
S_StopSoundByID(exp->target, sfx_exp);
S_StartSound(exp->target, sfx_exp);
P_RemoveMobj(exp);
}
P_RemoveMobj(exp);
}
return;
}
return;
}
exp->angle += ANGLE_45/2;
exp->angle += ANGLE_45/2;
UINT8 damper = 3;
UINT8 damper = 3;
fixed_t vert = dist/3;
fixed_t speed = 60*exp->scale;
fixed_t vert = dist/3;
fixed_t speed = 60*exp->scale;
if (exp->extravalue2) // Mode: going down, aim at the player and speed up / dampen stray movement
{
if (exp->extravalue1)
exp->extravalue1--;
if (exp->extravalue2) // Mode: going down, aim at the player and speed up / dampen stray movement
{
if (exp->extravalue1)
exp->extravalue1--;
exp->extravalue2++;
exp->extravalue2++;
speed += exp->extravalue2 * exp->scale/2;
speed += exp->extravalue2 * exp->scale/2;
fakez = mo->z + (vert * exp->extravalue1 / EXP_ARCTIME);
damper = 1;
}
else // Mode: going up, aim above the player
{
exp->extravalue1++;
if (exp->extravalue1 >= EXP_ARCTIME)
exp->extravalue2 = 1;
fakez = mo->z + (vert * exp->extravalue1 / EXP_ARCTIME);
damper = 1;
}
else // Mode: going up, aim above the player
{
exp->extravalue1++;
if (exp->extravalue1 >= EXP_ARCTIME)
exp->extravalue2 = 1;
fakez = mo->z + vert;
}
fakez = mo->z + vert;
}
if (mo->flags & MFE_VERTICALFLIP)
fakez -= mo->height/2;
else
fakez += mo->height/2;
if (mo->flags & MFE_VERTICALFLIP)
fakez -= mo->height/2;
else
fakez += mo->height/2;
hang = R_PointToAngle2(exp->x, exp->y, mo->x, mo->y);
vang = R_PointToAngle2(exp->z, 0, fakez, dist);
hang = R_PointToAngle2(exp->x, exp->y, mo->x, mo->y);
vang = R_PointToAngle2(exp->z, 0, fakez, dist);
exp->momx -= exp->momx>>(damper), exp->momy -= exp->momy>>(damper), exp->momz -= exp->momz>>(damper);
exp->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), speed));
exp->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), speed));
exp->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), speed);
exp->momx -= exp->momx>>(damper), exp->momy -= exp->momy>>(damper), exp->momz -= exp->momz>>(damper);
exp->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), speed));
exp->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), speed));
exp->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), speed);
ghostme(exp, player);
ghostme(exp, player);
if (dist < (EXP_ORBIT * exp->scale) && exp->extravalue2)
{
exp->threshold = TICRATE;
exp->extravalue1 = 0;
exp->extravalue2 = 0;
}
}
if (dist < (EXP_ORBIT * exp->scale) && exp->extravalue2)
{
exp->threshold = TICRATE;
exp->extravalue1 = 0;
exp->extravalue2 = 0;
}
}
}

View file

@ -19,6 +19,7 @@
#include "../r_main.h"
#include "../tables.h"
#include "../s_sound.h"
#include "../k_kart.h"
/* An object may not be visible on the same tic:
1) that it spawned
@ -85,7 +86,7 @@ bool award_target(mobj_t* mobj)
if (rebound_timer(mobj) < 1)
{
player->itemtype = KITEM_GACHABOM;
player->itemamount++;
K_AdjustPlayerItemAmount(player, 1);
if (player->roundconditions.gachabom_miser == 1)
player->roundconditions.gachabom_miser = 0;

View file

@ -612,7 +612,7 @@ Obj_GardenTopThrow (player_t *player)
}
if (player->itemamount > 0)
player->itemamount--;
K_AdjustPlayerItemAmount(player, -1);
if (player->itemamount <= 0)
player->itemtype = KITEM_NONE;

View file

@ -325,7 +325,7 @@ move_to_player (mobj_t *hyu)
// For first place only: cap hyudoro speed at 50%
// target player's kart speed
if (target->player && target->player->position == 1)
if (target->player && target->player->leaderpenalty)
{
const fixed_t normalspeed =
K_GetKartSpeed(target->player, false, false) / 2;
@ -582,7 +582,7 @@ hyudoro_patrol_hit_player
S_StartSound(toucher, sfx_s3k92);
/* do not make 1st place invisible */
if (player->position != 1)
if (player->leaderpenalty == 0)
{
player->hyudorotimer = hyudorotime;
}
@ -625,7 +625,7 @@ award_immediately (mobj_t *hyu)
if (player)
{
if (player->position == 1)
if (player->leaderpenalty)
{
return false;
}
@ -742,7 +742,7 @@ blend_hover_hyudoro (mobj_t *hyu)
/* 1st place: Hyudoro stack is unusable, so make a visual
indication */
if (player->position == 1)
if (player->leaderpenalty)
{
hyu->renderflags |= RF_MODULATE;
trail_glow(hyu);

View file

@ -279,8 +279,16 @@ void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir)
th->momx = 0;
th->momy = 0;
// Slow down the top speed.
finalSpeed = FixedMul(finalSpeed, 4*FRACUNIT/5);
// Return at absolutely 120% of the owner's speed if it's any less than that.
fixed_t min_backthrowspeed = 6*(K_GetKartSpeed(owner, false, false))/5;
if (owner->speed >= min_backthrowspeed)
{
finalSpeed = 6*(owner->speed)/5;
}
else
{
finalSpeed = min_backthrowspeed;
}
// Set a fuse.
th->fuse = RR_PROJECTILE_FUSE;

View file

@ -11,6 +11,7 @@
#include "../doomdef.h"
#include "../doomstat.h"
#include "../info.h"
#include "../g_game.h"
#include "../k_objects.h"
#include "../p_local.h"
#include "../r_state.h"

View file

@ -215,18 +215,12 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
else
{
// Player Damage
if ((t1->type == MT_ORBINAUT_SHIELD || t1->type == MT_JAWZ_SHIELD)
&& !t2->player->invincibilitytimer && !K_IsBigger(t2, t1)) // UGH. Stumble ignores invinc. Fix this damage type someday.
{
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO | DMG_STUMBLE);
}
else
{
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO |
(tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT));
if (tumbleitem || (gametyperules & GTR_SPHERES) || !t2->player->tripwireLeniency)
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO |
(tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT));
if (tumbleitem || !t2->player->tripwireLeniency)
if ((gametyperules & GTR_SPHERES) || (t1->type != MT_ORBINAUT_SHIELD && t1->type != MT_JAWZ_SHIELD))
K_KartBouncing(t2, t1);
}
S_StartSound(t2, sfx_s3k7b);
}
@ -331,10 +325,9 @@ void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir)
{
th->color = orbinaut_owner(th)->player->skincolor;
const mobj_t *owner = orbinaut_owner(th);
const ffloor_t *rover = P_IsObjectFlipped(owner) ? owner->ceilingrover : owner->floorrover;
const boolean ownerwaterrun = K_WaterRun(orbinaut_owner(th));
if (dir >= 0 && rover && (rover->fofflags & FOF_SWIMMABLE))
if (dir >= 0 && ownerwaterrun)
{
// The owner can run on water, so we should too!
orbinaut_flags(th) |= ORBI_WATERSKI;

View file

@ -28,7 +28,7 @@
#define SPB_SLIPTIDEDELTA (ANG1 * 3)
#define SPB_STEERDELTA (ANGLE_90 - ANG10)
#define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(9) * 2))
#define SPB_ACTIVEDIST (1024 * FRACUNIT)
#define SPB_ACTIVEDIST (2048 * FRACUNIT)
#define SPB_HOTPOTATO (2*TICRATE)
#define SPB_MAXSWAPS (2)

View file

@ -88,7 +88,7 @@ struct Shoe : Mobj
bool valid() const { return Mobj::valid(follow()) && follow()->valid() && Mobj::valid(chain()); }
Fixed minDist() const { return 200 * mapobjectscale; }
Fixed maxDist() const { return 800 * mapobjectscale; }
Fixed maxDist() const { return 500 * mapobjectscale; }
angle_t followAngle() const { return R_PointToAngle2(x, y, follow()->x, follow()->y); }
Fixed followDistance() const { return FixedHypot(x - follow()->x, y - follow()->y); }
@ -115,7 +115,7 @@ struct Shoe : Mobj
shoe->dir(0);
shoe->fuse = 15 * TICRATE;
INT32 numLinks = 8;
INT32 numLinks = 5;
Chain* link = nullptr;
for (INT32 i = 0; i < numLinks; ++i)
@ -237,7 +237,7 @@ private:
}
}
thrust(a, 8 * mapobjectscale);
thrust(a, 10 * mapobjectscale);
Fixed maxSpeed = 32 * mapobjectscale;
Fixed speed = FixedHypot(momx, momy);

View file

@ -311,6 +311,7 @@ struct Cloud : Mobj
if (leveltime % (TICRATE/3) == 0 && follow()->player->rings > -20) // toxomister ring drain
{
follow()->player->rings--;
K_DefensiveOverdrive(follow()->player);
S_StartSound(follow()->player->mo, sfx_antiri);
}
@ -321,7 +322,7 @@ struct Cloud : Mobj
if (fuse < kMaxFuse && (kMaxFuse - fuse) % 20 == 0 && Mobj::valid(target()) && target()->player && follow()->player)
{
K_SpawnAmps(target()->player, K_PvPAmpReward(3, target()->player, follow()->player), this);
K_SpawnAmps(target()->player, K_PvPAmpReward(2, target()->player, follow()->player), this);
}
follow()->player->stunned = fuse; // stunned as long as cloud is here

View file

@ -220,6 +220,7 @@ void Obj_playerWPZTurbine(player_t *p)
}
mt = t->spawnpoint;
pmo->flags &= ~MF_NOGRAVITY;
opt1 = (mt->thing_args[0] != 0);

Some files were not shown because too many files have changed in this diff Show more