Compare commits

...

280 commits

Author SHA1 Message Date
Anonimus
8f198aeff8 Make the Bubble Shield reflect powered-up players 2025-09-28 14:05:10 -04:00
NepDisk
97b34e3e7c Merge pull request '[BUGFIX] Fix issues with CSS scroll when changing to other options on the menu' (#139) from minenice55/blankart:css-scrollreset-fix into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/139
2025-09-28 18:57:13 +02:00
minenice55
46bb9e41ee fix issues with CSS scroll when changing to other options on the menu 2025-09-28 12:54:44 -04:00
GenericHeroGuy
0d2f2e106c Fix driftgauge flipcam logic (closes #130) 2025-09-28 18:54:25 +02:00
NepDisk
1e01b387df Change sort default to name 2025-09-28 12:31:49 -04:00
GenericHeroGuy
d3b8f9f3a6 Fix positions changing after finish with legacy checkpoints (closes #136) 2025-09-28 18:13:03 +02:00
NepDisk
1e1404162e Try making random item more accurate for battle (#135 point 1, still needs testing) 2025-09-28 11:13:49 -04:00
GenericHeroGuy
df819b303d Fix orbi/jawz/thwomp/player hits not resetting sneakertimer (closes #134) 2025-09-28 17:01:58 +02:00
GenericHeroGuy
671b4e1f3d Fix orbinauts getting deleted by players in flashtics (closes #92 point 1) 2025-09-28 16:58:40 +02:00
NepDisk
169ddc1533 Fix lack of camera death tilt 2025-09-28 10:04:29 -04:00
NepDisk
93e679298e Fix being awarded bumpers erroneously (#135 point 2) 2025-09-28 09:58:58 -04:00
NepDisk
ee9579b950 Fix Karma SPB getting hit not putting you into WAIT (#135 point 3) 2025-09-28 09:40:46 -04:00
NepDisk
75d232e9b3 Default to openGL again 2025-09-27 23:46:32 -04:00
NepDisk
d56031e657 Make Airdrop feel better to use and tweak ring usage numbers 2025-09-27 23:46:32 -04:00
NepDisk
62fab4b7b2 Merge pull request 'Continue to attempt to make legacy odds bearable' (#138) from ledamagecontrol into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/138
2025-09-28 04:59:22 +02:00
Anonimus
d75402b37e Attempt to remedy fixed-point math problems by using a 64-bit integer 2025-09-27 22:02:08 -04:00
Anonimus
3cfca7dbf8 Make odds distances cvars so we're not constantly recompiling 2025-09-27 20:32:21 -04:00
Anonimus
b749cc117d Attempt to remedy odds issues 2025-09-27 16:54:59 -04:00
NepDisk
35bbf39f47 aaaa 2025-09-27 15:28:57 -04:00
NepDisk
2430bc7e50 Revert "Oh look at the little scringly dingly"
This reverts commit 95d032889f.
2025-09-27 15:28:11 -04:00
GenericHeroGuy
e266fb723a oops 2025-09-27 21:12:13 +02:00
Anonimus
95d032889f Oh look at the little scringly dingly 2025-09-27 14:50:51 -04:00
GenericHeroGuy
0cffa16a45 Fix assert when entering splitscreen on replays (closes #94)
The problem is quite simple: G_LeaveParty is called for the old value of
displayplayers[1] which is 0, and this triggers the assert for replays from
dedi servers where player 0 doesn't exist.
No idea if the fix is correct but I assume making a non-existent player
leave their party is nonsense
2025-09-27 19:21:27 +02:00
NepDisk
28c4ebd968 agagaga 2025-09-27 13:17:57 -04:00
NepDisk
b2d3da4aa2 Update code karma stuff to be more accurate
Turns out you can still drive even with karma off in v1 so lets repat this here
2025-09-27 12:19:36 -04:00
NepDisk
44ec1d9ef5 Don't calculate battle wanted in p_ticker if wanted isn't on 2025-09-27 09:50:00 -04:00
NepDisk
e4a9561261 Make usage of battlespeed cvar a gametyperule 2025-09-27 09:06:36 -04:00
NepDisk
99a6d1aefa Add a small speed bonus for wall transfering
One part MKWii brainrot, one part making this less ass
2025-09-27 00:12:00 -04:00
NepDisk
6c26d96910 Don't set default time limit for battle 2025-09-26 23:04:38 -04:00
NepDisk
37012cfc60 Draw karma points display in 4p like bumpers 2025-09-26 22:51:59 -04:00
NepDisk
f551718fd2 hash 2025-09-26 21:51:55 -04:00
NepDisk
74973764e2 Update Draft and Timers to support offsets and use stplyrnum more 2025-09-26 21:31:44 -04:00
NepDisk
0c2d8eefc2 Basic Slip stream indicator for now
splitscreen for this hud element is broken and needs to be fixed
2025-09-26 18:22:17 -04:00
GenericHeroGuy
a08c097a20 Fix VID_BlitLinearScreen's SSE version ignoring width (closes #128) 2025-09-26 23:59:53 +02:00
NepDisk
f60e499f91 Implement Worst mode for lagless (for #129) 2025-09-26 15:05:28 -04:00
NepDisk
db315f72ac Comment out all stuff for big mode icons
We don't use this stuff currently so lets comment it out so its not compiled
2025-09-26 14:39:46 -04:00
NepDisk
e098598a3d Renable item timers and adjust for new assets 2025-09-26 14:16:10 -04:00
Anonimus
eade241d3b Add SPBs to battle mode
The ultimate means against camping
2025-09-26 00:05:06 -04:00
Gustaf Alhäll
003bef11ae Fix compiler warning 2025-09-25 21:42:09 -04:00
Gustaf Alhäll
31ac81fe93 Fix edge case when checking line in P_PathTraverse
Ported from 31e8ba9238
2025-09-25 21:40:09 -04:00
NepDisk
3778520ee6 Unhardcode more behaviour as gametyperules 2025-09-25 21:28:00 -04:00
NepDisk
1f2cc02db4 Fix unused flag 2025-09-25 19:39:54 -04:00
NepDisk
179db51639 Battlemode fix ups 2025-09-25 19:37:20 -04:00
NepDisk
8340be41a1 Use a different distvar for legacy maps 2025-09-25 14:41:04 -04:00
NepDisk
602a6d5e3f Mr SPB makes his return 2025-09-25 14:30:46 -04:00
NepDisk
10671fff5a Reallow doomednum overriding
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2740
2025-09-25 13:00:03 -04:00
Anonimus
29ca3d2ecd Fix shitty maxodds assert
Why aren't we just clamping this?
2025-09-25 02:38:27 -04:00
NepDisk
318ae2ef6b Attempt to fix SPB logic for legacy 2025-09-25 02:26:30 -04:00
Anonimus
023f75097f Some more AltInvinc loose ends
Prevent it from appearing as a "homestretch" item in non-legacy distancing
Fix the visual inconsistencies between it and Software
2025-09-25 01:45:56 -04:00
NepDisk
eab3a88d2a Do 1.4x scaling instead 3.5x scaling when under player cap
Yes really its 3.5 not 2.5 like the comment says :p
2025-09-25 00:45:41 -04:00
NepDisk
aaf91e38cb Further refactor odds stuff and prevent overflows 2025-09-25 00:29:30 -04:00
NepDisk
87300944fa Refactor legacy odds code to generate pdis instead of duping multiple legacy functions
Why did I ever do it like that before when it was this easy....
2025-09-24 22:55:38 -04:00
NepDisk
dcc5b41075 Update debugger to display pdis using correct units 2025-09-24 20:25:51 -04:00
NepDisk
2780d33436 Just give everyone bonus draft accel 2025-09-24 19:09:42 -04:00
Anonimus
5ea5b11902 Bandaid: exaggerate AltInvinc legacy cluster distance checks
Closes #89; this (hopefully) brings it more in line with the DtF checks
Bagging may be a concern, not too sure yet
2025-09-24 18:26:24 -04:00
NepDisk
87337da97c Don't use nghttp2 on windows 2025-09-24 18:03:37 -04:00
NepDisk
83bc2dc9fb Add support for parsing follower icons 2025-09-24 16:42:22 -04:00
NepDisk
5babac8249 Remove init as well 2025-09-24 16:25:32 -04:00
NepDisk
35292fca34 Fix duped patch 2025-09-24 16:24:24 -04:00
NepDisk
61bb7c8013 Add number display to player select 2025-09-24 16:23:19 -04:00
NepDisk
f46382f902 Merge pull request '[Enhancement] Implement Superjustinbros' new stat bar assets' (#126) from minenice55/blankart:sjb-statbars into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/126
2025-09-24 21:02:47 +02:00
minenice55
797c708262 tweaks from feedback (UNTESTED)
make "sub" stats use a dark non-color
split out the icons and draw em separately
TODO: numerical stats
2025-09-24 14:50:32 -04:00
NepDisk
a437e70376 Fix alot of rings lagging the game 2025-09-24 13:58:00 -04:00
NepDisk
922db84289 whoops 2025-09-24 12:39:00 -04:00
NepDisk
c3bf7e643d Revert "try Netsyncing this stuff"
This reverts commit 2f337ee3d6.
2025-09-24 12:37:24 -04:00
NepDisk
c5a2ae1431 Revert "Make this a 3"
This reverts commit 2e588d3516.
2025-09-24 12:37:17 -04:00
NepDisk
bc4fb8a9c6 Merge pull request '[FEAT] Vectors matrices quaternions' (#117) from vectors-matrices-quaternions into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/117
2025-09-24 18:28:38 +02:00
minenice55
eea55ee9a1 implement superustinbros' new stat bar assets 2025-09-24 11:26:54 -04:00
NepDisk
c427ef90fa Fix gravfix (fixes #124) 2025-09-24 09:53:34 -04:00
NepDisk
1cc556ade9 Add flipcam support to nametags 2025-09-23 18:59:43 -04:00
GenericHeroGuy
88f275879d Clean up and fix segfault in demo error code
Forgot to actually return at lumperror lmao
2025-09-23 21:59:16 +02:00
GenericHeroGuy
4efb810721 Revert "You don't need to increment demoversion for a flags change"
This reverts commit f523c2f069.
2025-09-23 18:53:04 +02:00
GenericHeroGuy
f523c2f069 You don't need to increment demoversion for a flags change 2025-09-23 17:43:20 +02:00
Anonimus
855d25ae13 Better bumpspark bitmask reading (thanks GHG) 2025-09-23 11:31:59 -04:00
NepDisk
e5d866eb6f e 2025-09-23 11:30:13 -04:00
NepDisk
3d8d167cf4 Add flipcam support to object tracking 2025-09-23 10:25:32 -04:00
NepDisk
85817c57d3 Forgot to add previous versions to this list 2025-09-23 08:26:21 -04:00
NepDisk
f68f5dd7fd Make sure NextmapOnchage is updated when quiting or ending ta 2025-09-22 20:41:09 -04:00
NepDisk
2cbfd46ddd Update hash 2025-09-22 20:18:53 -04:00
NepDisk
01d2c486d1 Impact added to purple and rainbow drift sounds 2025-09-22 20:12:48 -04:00
Anonimus
6bc4e4f63a Remembering G_AddGhost's existence 2025-09-22 17:47:15 -04:00
Anonimus
321f6c9e1b Bumpspark cvar consistency 2025-09-22 17:47:15 -04:00
Anonimus
3f39e18456 Add Reset to Blue bumpspark, Clang-format the cvar for my sanity 2025-09-22 17:47:06 -04:00
NepDisk
41188a66e4 Update hash 2025-09-22 17:39:45 -04:00
NepDisk
093b17987f Merge pull request 'Air Drop' (#125) from AirDrop into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/125
2025-09-22 23:25:34 +02:00
NepDisk
474e613354 Fix bumpspark merge conflict 2025-09-22 17:20:49 -04:00
NepDisk
9dc0bdc31e Merge branch 'blankart-dev' into AirDrop 2025-09-22 17:05:58 -04:00
GenericHeroGuy
5d419b48bb Fix TA menu face using incorrect coordinates 2025-09-22 23:00:50 +02:00
NepDisk
9df538fe32 Merge branch 'blankart-dev' into AirDrop 2025-09-22 15:35:20 -04:00
NepDisk
5beb1619d5 Update some loops stuff to be more up to date 2025-09-22 15:16:27 -04:00
Anonimus
fb5b72a600 Add bumpspark as a TA modifier
Also a bunch of other things in relation to that
Kart mode has bumpspark off, Blan mode uses "keep drift, lose charge", and Tech has bumpspark enabled
2025-09-22 02:04:03 -04:00
NepDisk
17e92d25f1 Merge branch 'blankart-dev' into AirDrop 2025-09-21 22:25:19 -04:00
NepDisk
0a74900e19 Don't kick bots with antigrief 2025-09-21 22:24:31 -04:00
NepDisk
6d20c8fcbf Merge branch 'blankart-dev' into AirDrop 2025-09-21 20:53:34 -04:00
NepDisk
7a86b59fc8 Update in-game server browser
Based on https://git.do.srb2.org/KartKrew/Kart-Public/-/merge_requests/313 with some tweaks to match our codebase. No page switch animation cus lazy and don't feel like adpating it to cvars
2025-09-21 20:51:30 -04:00
Anonimus
76c17ec7b9 Default bumpspark to removing only charge
Doesn't cancel drifts entirely, but completely resets a player's driftcharge.
2025-09-21 20:42:53 -04:00
Anonimus
5f9406cca0 Fix erroneous facepatch assign (fixes #122) 2025-09-21 18:02:54 -04:00
Anonimus
5c6da29657 Auto-center ALL rank and minimap patches, make offsets relative to center
The current system ended up loading to a lot of visual jank with certain addon characters
Most if not all vanilla characters have null offsets, and the edgecase icons should not necessitate using absolute offsets
2025-09-21 18:02:54 -04:00
Anonimus
0b1f458fb9 I'm just going to say stupid shit for these hash commits
🥹
2025-09-21 18:02:53 -04:00
NepDisk
eff9283bef Merge branch 'blankart-dev' into AirDrop 2025-09-21 17:34:54 -04:00
NepDisk
4553420b71 Use srb2 classic as the MS 2025-09-21 17:32:50 -04:00
NepDisk
9acbd66a9e Don't add ghosts that don't match our current record attack mode 2025-09-21 16:17:38 -04:00
NepDisk
0d87f8a662 Merge branch 'blankart-dev' into AirDrop 2025-09-21 15:28:58 -04:00
NepDisk
91f71a3cf5 Fix menu preset for airdrop 2025-09-21 15:27:22 -04:00
NepDisk
b769bcd295 Adjust for our needs 2025-09-21 15:21:36 -04:00
JugadorXEI
eb4d4717e5 Move cv_showgremlins code to P_SweepTestLines so it can still fire 2025-09-21 15:08:36 -04:00
JugadorXEI
01b2f9d5b0 Add workaround for gremlin'd wall collisions 2025-09-21 15:06:29 -04:00
NepDisk
4495ae6b4c Merge branch 'blankart-dev' into AirDrop 2025-09-20 19:33:10 -04:00
NepDisk
703afe7992 Merge pull request 'Bot improvement changes' (#120) from bothandlechanges into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/120
2025-09-21 00:39:14 +02:00
NepDisk
4cebf26be3 Merge branch 'blankart-dev' into AirDrop 2025-09-20 18:18:07 -04:00
NepDisk
fbe224bce3 Merge pull request '[ENHANCEMENT] Color-code and angle bananas' (#119) from bananablind into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/119
2025-09-20 23:26:38 +02:00
Anonimus
31aea3cd97 Color-code and angle bananas
* Bananas, similar to Orbinauts, now preserve the user's color
* They also preserve the last angle they had within the drag chain; if they're thrown forwards, the angle matches the player's
2025-09-20 16:40:55 -04:00
NepDisk
78a9947662 Merge branch 'blankart-dev' into AirDrop 2025-09-20 14:01:38 -04:00
Lactozilla
3b489df3db Fix SRB2 1393 (Nep: also flats and brightmap support Thx lug) (Closes #115) 2025-09-20 13:43:35 -04:00
NepDisk
e2fba0195c Merge branch 'blankart-dev' into AirDrop 2025-09-20 13:21:46 -04:00
NepDisk
de3a843974 unleash the blananas 2025-09-20 13:20:07 -04:00
James R
fba66c4084 Do not disable and reenable sounds entirely when window focus changes
Sounds are not started if the window is unfocused,
regardless of sound_disabled.

Fixes -nosound not working (sounds would always be
reenabled if window comes into focus).
2025-09-20 17:45:38 +02:00
GenericHeroGuy
e5c97ca233 Introducing: __attribute__((__cleanup__))
I don't wanna hear about MSVC... or C++...
This fixes NUMEROUS memory leaks introduced by G_ReadDemoHeader,
which I was utterly oblivious to up until an hour ago
2025-09-20 16:52:44 +02:00
NepDisk
49c0b2c00e Make Airdrop drop lines only turn yellow when you have ringboost 2025-09-20 10:23:15 -04:00
NepDisk
de5a8594b9 Add more conditions here 2025-09-20 09:43:32 -04:00
NepDisk
aba9e23a0d Readd bot airbrake logic for bot controllers 2025-09-20 09:40:27 -04:00
NepDisk
ca3d533771 Don't break the airdrop toggle, you BAKA! 2025-09-20 01:00:23 -04:00
NepDisk
7de3cc3b25 Add toggle logic for Air Drop 2025-09-20 00:42:47 -04:00
NepDisk
ffa7850bb6 AirDrop Starting Commit
This introduces a new optional feature called Airdropping. When holding brake in the air you will start to fall faster. If you have rings active and have rings on you, you Ring Drop to fall even faster and with less delay. The ringboost output from this move is weaker then using rings normally making it so always using ring drop isn't the best play
2025-09-20 00:41:08 -04:00
NepDisk
dbabd84715 Don't use map modifier 2025-09-19 22:41:00 -04:00
NepDisk
044e8c6ec1 Remove sclar on driftskill, make small grip lock out after drifts and make bots go neutral faster at high speeds 2025-09-18 16:53:08 -04:00
NepDisk
4a1618829b Merge branch 'blankart-dev' into bothandlechanges 2025-09-18 16:27:17 -04:00
Anonimus
b36b327a00 UPDAYTE DE GOT TAMN HAYSH
Maybe we should move hashes to a header that's easy to drop in from asset compiling?
Maybe? ...please?
2025-09-18 16:11:49 -04:00
Anonimus
b6c34067bb Universal scale for cluster distancing
Should hopefully make gradienting less punishing on maps like Green Cave
2025-09-18 16:11:49 -04:00
NepDisk
6512d71e4e Try to improve regular turns and drifts 2025-09-18 15:59:45 -04:00
GenericHeroGuy
fd65151d50 Fix ghost hitlist causing zone errors (closes #118)
Beware the wrath of PU_LEVEL
2025-09-18 21:19:06 +02:00
NepDisk
2e588d3516 Make this a 3 2025-09-18 10:45:17 -04:00
NepDisk
2f337ee3d6 try Netsyncing this stuff 2025-09-18 10:31:53 -04:00
GenericHeroGuy
0362a0dff4 Add debugmappatch, for hot-reloading map patches 2025-09-18 16:30:37 +02:00
Anonimus
bb1f65fcc1 Fix compiler/linker fussing and inconsistencies
Some things got lost in translation in the revert
2025-09-18 04:10:34 -04:00
NepDisk
7c7368fe93 Sunbeam hashes 2025-09-18 01:16:08 -04:00
Gustaf Alhäll
d0ab031a71 Remove redundant vertex, matrix and quaternion code 2025-09-18 00:59:35 -04:00
LJ Sonic
bfc55ed016 Allow passing a vector to Matrix.translation/scaling() 2025-09-18 00:20:47 -04:00
LJ Sonic
2f69f46a0a Rename Matrix.fromTranslation/Scaling() 2025-09-18 00:20:18 -04:00
LJ Sonic
96c1fc4bd1 Fix name of matrix.get() and matrix.set() 2025-09-17 22:35:05 -04:00
LJ Sonic
7ee04cdaaa Fix bruh moment 2025-09-17 22:30:45 -04:00
LJ Sonic
e180d7720e Add missing include directive 2025-09-17 22:29:50 -04:00
LJ Sonic
18d54fc07b Implement vectors, matrices and quaternions 2025-09-17 22:27:36 -04:00
LJ Sonic
8b2626165b Add lua_tofixed() and luaL_optfixed() 2025-09-17 22:13:35 -04:00
NepDisk
9c30e7a422 Fix some compiler warnings AGAIN 2025-09-17 20:56:29 -04:00
NepDisk
d3bad05bf9 Let you open the console in RA replays 2025-09-17 19:49:28 -04:00
NepDisk
869f0f8256 Do local camera turns here and always set player_t->angleturn 2025-09-17 17:36:16 -04:00
NepDisk
7871bab697 Fix T_Pusher player turn 2025-09-17 17:29:08 -04:00
GenericHeroGuy
b2595045fc Remove leftover P_CheckGravity call in ceiling bonk code 2025-09-17 22:46:40 +02:00
GenericHeroGuy
1c33caa84e Attempt number two at fixing ACS unarchiving
Can't use map numbers, can't use lump numbers... so don't use numbers!
2025-09-17 18:31:10 +02:00
GenericHeroGuy
858162f333 Revert "Fix the ACS unarchival crash (closes #97)"
This reverts commit 8348ed1c05.
2025-09-17 18:31:10 +02:00
GenericHeroGuy
c8c2d828de brap 2025-09-17 18:31:10 +02:00
James R
ea54e3f08a Fix instances of lump searching not being case insensitive 2025-09-17 18:31:10 +02:00
NepDisk
9568ff843b Merge pull request '[FEAT] Implement configurable starting rings' (#116) from minenice55/blankart:start-rings-cvar into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/116
2025-09-17 18:30:59 +02:00
minenice55
a0cd60b9a2 implement configurable starting rings 2025-09-17 12:12:23 -04:00
Alug
693374c5c1 ensure deterministic order for P_Random stuff passed as arguments
the evaluation order of arguments passed to functions is undefined in C/C++, so its up to the compiler in which order to evaluate these

P_Random functions modify the randomseed each time theyre called, which can lead to different outcomes (thus desynchs) on different platforms, compilers,

compiler versions etc.

so match up with the most common which is last to first (seemingly the order gcc on nix and windows handle it)

common case are mine/eggbomb explosions hitting the smk ice blocks causing desynchs when either server or client were clang compiled
2025-09-17 18:08:06 +02:00
Anonimus
3be59c8100 ACTUALLY fix the small icon misalignment
This time for sure, haha...
2025-09-17 07:17:05 -04:00
Anonimus
43732fe21d PINGAS 2025-09-16 18:09:45 -04:00
NepDisk
bb3e543fb7 Change the backgroundpatch for wifi based if purple drift isn't on 2025-09-16 17:39:12 -04:00
GenericHeroGuy
8a6a2b5bf3 Fix Sryder's Pleasure Castle ghost segfaulting... again (closes #114) 2025-09-16 22:39:48 +02:00
NepDisk
77e1e3fe38 Use a cliprect on the player square so the player doesn't overlap the menu 2025-09-16 15:47:01 -04:00
GenericHeroGuy
33348e7c92 Refactor and tweak afterimages, clean up drift release (closes #98)
I pinky promise I did NOT break drifting
2025-09-16 21:08:32 +02:00
GenericHeroGuy
6b6594e430 Refactor driftgauge and fix the bar colors (closes #95)
Bar colors based on sglua (with new colors for purple)
2025-09-16 18:23:48 +02:00
NepDisk
4dc40f0256 Remove maxsend limit, default to 200MB maxsend
https://gitlab.com/kart-krew-dev/ring-racers/-/merge_requests/14
2025-09-16 10:36:45 -04:00
LJ Sonic
12dc3798a7 Rename matrix_t to oldmatrix_t 2025-09-16 09:39:44 -04:00
NepDisk
3f611cf6d2 Raise demo version 2025-09-15 12:50:56 -04:00
NepDisk
c204314ae9 Shut up GCC 2025-09-15 12:01:09 -04:00
NepDisk
9109ce58cc Default bumpspark and BumpSpring on 2025-09-15 11:39:50 -04:00
NepDisk
24bceed8f1 Add backwards compat for older demos regarding ez start and bumpspark 2025-09-15 11:38:23 -04:00
NepDisk
93896b5e68 Test 2025-09-15 03:49:08 -04:00
NepDisk
14fb1048fe QOL for RA
Having to time the input everytime makes attempts annoying to attempt since you often have to restart if you fail. Bumpspark and Bumpspring are also enabled for ease of play as well since vanilla bumps are generally unliked
2025-09-15 03:16:09 -04:00
NepDisk
f517163a77 Update le hashes 2025-09-15 00:04:37 -04:00
NepDisk
0e0964dd18 Merge pull request '[ENHANCEMENT] Add option to show lap split on race timer' (#112) from minenice55/blankart:timer-lap-splits into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/112
2025-09-15 05:56:09 +02:00
Anonimus
3ab2e769c5 Fix misalignment for smaller minimap icons 2025-09-14 22:05:23 -04:00
NepDisk
990390fd5c Add for floorClip support to 3D models 2025-09-14 21:20:14 -04:00
minenice55
7197c2e3de Merge branch 'blankart-dev' into timer-lap-splits 2025-09-14 19:08:32 -04:00
minenice55
e39d1ecfaf add option to show lap split on race timer
also adds hud offset support to the "centred" lap split display
2025-09-14 18:29:43 -04:00
NepDisk
f359a53756 Fix gremlins on Abstration minecart map 2025-09-14 17:47:39 -04:00
NepDisk
4917fcde50 Revert 'Use Path traversal if sweep lines fail'
This reverts commit 89f0ef836b.
2025-09-14 15:39:42 -04:00
NepDisk
7c7f5ac1d0 Revert "Only run fallback traversal for bounce and slide for gameplay important objects"
This reverts commit 15b83e9fc3.
2025-09-14 15:38:12 -04:00
NepDisk
8b9bead8ba Revert "Replace assert with return in slidemove old"
This reverts commit 95eea4d1af.
2025-09-14 15:35:49 -04:00
NepDisk
9541e4fb52 Merge pull request 'Consolevar that enables icon spinouts' (#111) from minimapspin into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/111
2025-09-14 20:52:52 +02:00
Anonimus
a4d89f3083 Spinout rotations 2025-09-14 14:24:22 -04:00
NepDisk
4a79ad337b Properly use menu_text_input boolean 2025-09-14 11:53:08 -04:00
NepDisk
ef481b936f Use US default as default... Crazy 2025-09-14 10:55:12 -04:00
NepDisk
5f97577561 Add cvar for keyboard layout 2025-09-14 10:52:38 -04:00
NepDisk
95eea4d1af Replace assert with return in slidemove old 2025-09-14 01:43:30 -04:00
NepDisk
72596e8d03 Port addfilelocal from saturn
Modified to turn off features we don't have / prevent resyncs
2025-09-14 01:06:05 -04:00
NepDisk
2a669a665e Merge pull request 'Add lap splits during races, from RR 2.4' (#110) from rrlapsplits into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/110
2025-09-14 05:17:07 +02:00
Anonimus
c906ccc7a1 Add race lap splits display from Ring Racers
Very neat feature
2025-09-13 23:07:52 -04:00
Anonimus
ab5ded6ae9 Praying there are no more hash inconsistencies... 2025-09-13 23:07:52 -04:00
NepDisk
d00e674088 Port Native keyboard 2025-09-13 22:41:48 -04:00
GenericHeroGuy
8348ed1c05 Fix the ACS unarchival crash (closes #97)
Map numbers are consistent between server and client, wadnums are not
2025-09-14 01:36:22 +02:00
GenericHeroGuy
ecefb06069 Fix negative refcount warnings when joining servers 2025-09-13 22:14:16 +02:00
NepDisk
ea1426b947 Merge pull request 'Gif recording improvements' (#109) from gifhell into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/109
2025-09-13 21:01:27 +02:00
NepDisk
30fbf1c4c8 Don't draw most of thinker stats when level is not running.
This crashes, why did it ever do this.
2025-09-13 14:58:31 -04:00
NepDisk
dd1790749e Remove unused var 2025-09-13 14:19:17 -04:00
NepDisk
14052daede Improve step up accuracy to v1
So it turns out Theres no 'maxstep > 0' check in v1
2025-09-13 13:40:20 -04:00
NepDisk
1aed9067bb remove avgheight as its no longer needed 2025-09-13 10:35:33 -04:00
NepDisk
7cdb502874 Add safety to K_PlayerWeight 2025-09-13 08:51:07 -04:00
NepDisk
2acf3725e3 Fix Bubble and Flame activating instatly when holding item down
You know have to let go once after rolling to use it.
2025-09-13 00:55:18 -04:00
NepDisk
3aa7217155 Fix bubble getting stuck large on exiting 2025-09-12 23:44:25 -04:00
NepDisk
c3eeffc95c Fix typing indicator being tied to nametags (Fixes #90) 2025-09-12 23:26:48 -04:00
NepDisk
02212a9974 Fix spectator reentry not being reset between maps. (Fixes #96) 2025-09-12 23:20:16 -04:00
Anonimus
fa1b3b9431 SRB2 rendering code is very good yes indeed 2025-09-12 21:11:38 -04:00
Anonimus
93a4824549 Fix mis-scaling of rolling offsets 2025-09-12 20:21:57 -04:00
NepDisk
462d18186c Renable hasing 2025-09-12 19:49:16 -04:00
NepDisk
50c7019f44 Add KZ speedometer and fix many compiler warnings 2025-09-12 19:43:43 -04:00
NepDisk
51ccb74a12 Merge pull request 'Option for Ring Racers skins to imitate SRB2Kart drifts' (#108) from v1driftjitter into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/108
2025-09-12 23:16:31 +02:00
Anonimus
4cd813575c Move driftjitter cvars to weaponpref 2025-09-12 17:13:21 -04:00
Anonimus
12be394af2 Remove duplicated baked offset read 2025-09-12 15:56:43 -04:00
Anonimus
9136d1da75 Hash-slinging slasher 2025-09-12 15:14:10 -04:00
Anonimus
04dd587ef4 Add legacy drifting for RR characters
Imitates V1 drifts using baked offsets; perfectly netsafe
2025-09-12 15:01:45 -04:00
Anonimus
b702e17547 Rolling offsets, add interp to offset rotation code 2025-09-12 14:56:39 -04:00
Chearii
dc99014d2a Add baked offset parameters 2025-09-12 14:55:31 -04:00
NepDisk
a77f95dabc E 2025-09-12 14:05:26 -04:00
NepDisk
a02fbacf01 Fix resync crash 2025-09-12 12:39:48 -04:00
Sal
b87868d07e Merge branch 'more-saveg-fixes' into 'master'
Several netsave fixes / improvements

See merge request KartKrew/Kart!2475
2025-09-12 12:27:40 -04:00
NepDisk
0911633728 Add Chearii under Ring Racers programming as well 2025-09-12 11:51:19 -04:00
NepDisk
d98dd3e2dd Add variables that bake 3D offsets into a sprite
https://git.do.srb2.org/KartKrew/RingRacers/-/merge_requests/63
2025-09-12 11:50:24 -04:00
Oni
4a5c7fcae2 Merge branch 'speedy-savestate' into 'master'
Don't reload level on gamestate resend

See merge request KartKrew/Kart!2225
2025-09-12 01:35:16 -04:00
NepDisk
9352d77c92 'Increment move resolution increase' cherry-pick
adbdc63895
2025-09-12 01:29:08 -04:00
Sally Coolatta
659777a974 Fix UnArchiveSectors not actually adding tags
It was removing tags and then also removing the new ones, instead of removing tags and adding the new ones. Netsaves are so fucking scuffed.
2025-09-12 01:25:08 -04:00
Sally Coolatta
59872a8181 mobj->terrain archive imrpovements
- TERRAIN index is +1 (it can write terrainOverlay at the same time, so there is the possibility of needing to archive NULL terrain).
-TERRAIN lookup is done immediately instead of at P_RelinkPointers (dunno why I did this, TERRAIN doesn't do mobjnum crap).
2025-09-12 01:23:26 -04:00
Eidolon
6461678967 Merge branch 'bheapPushWrongRealloc' into 'master'
Fix wrong size in K_BHeapPush Z_Realloc

See merge request KartKrew/RingRacers!83
2025-09-12 01:21:11 -04:00
Antonio Martinez
7a27d853f9 Always omit unimportant files from fileneeded (fixes rejoining modded always failing in DEVELOP) 2025-09-12 01:03:55 -04:00
toaster
2686503602 r_things.cpp: Fix highresscale for custom skins interacting badly with Linkdraw on the player (bubble shield, etc) 2025-09-12 00:41:55 -04:00
toaster
2baf834265 Threaded HTTP downloader
Composite of the work of:
- Hacinef (SRB2 repository, https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2322 )
- alufolie91 (SRB2Kart-Saturn repository, 84bfb3991e )
This advancement made possible by Indev in the KKD discord

Untested because I don't know how to set up a HTTP download server
2025-09-12 00:33:26 -04:00
NepDisk
e1f6fb1b68 AllocateMobj RR port 2025-09-12 00:24:18 -04:00
Oni
0bbc485f3e Merge branch 'acs-archive-fixes' into 'master'
ACS archival fixes

See merge request KartKrew/Kart!2480
2025-09-12 00:24:18 -04:00
NepDisk
3b475919d8 Update README.md 2025-09-11 23:40:05 +02:00
NepDisk
da3fe6f48a Update README.md 2025-09-11 23:21:48 +02:00
NepDisk
c8d3a223d8 Update README.md 2025-09-11 23:20:34 +02:00
NepDisk
d210c8b6bd Update hash for skincolors 2025-09-11 16:59:40 -04:00
NepDisk
bba37cf709 Merge pull request 'New Skincolors' (#107) from newcolors into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/107
2025-09-11 22:25:56 +02:00
NepDisk
6acd057189 SuperJustinBros New Skincolors 2025-09-11 16:21:12 -04:00
NepDisk
77d3e020cd Merge pull request 'Fix some oversights with kartbot_cap' (#105) from Wumbo/blankart:fixbotcap into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/105
2025-09-11 18:42:39 +02:00
GenericHeroGuy
aa71181c5a Fix GIF recording at 1x resolution, and stop recording on resolution change
Simplifies the framebuffer management and eliminates the memcpy per frame
2025-09-11 17:52:27 +02:00
NepDisk
1c52947194 Small Cleanup
Make itemodds compile as C, remove .vscode
2025-09-11 11:16:13 -04:00
Wumbo
9ab3987e0d Fix some oversights with kartbot_cap 2025-09-11 11:05:55 -04:00
NepDisk
7b58b8b488 Hashbrown 2025-09-11 10:55:58 -04:00
GenericHeroGuy
54bb823b31 Remove GetTexImage stuff 2025-09-11 16:46:23 +02:00
NepDisk
12b56701aa Fix balance changes display for drafting 2025-09-11 10:41:09 -04:00
NepDisk
9c361fe3ff Add qs22j header to r_skins 2025-09-11 10:38:43 -04:00
NepDisk
0ce6a91b6d Merge pull request '[FEAT] Grid Interface for Character Select Screen' (#102) from minenice55/blankart:mine-grid-css-2021 into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/102
2025-09-11 16:34:54 +02:00
NepDisk
d8a9f516f4 Merge pull request '16-tier useodds, increased odds precision' (#104) from nu_useodds into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/104
2025-09-11 16:34:08 +02:00
NepDisk
1edc6b736d Fix Colormap compat 2025-09-11 10:33:13 -04:00
Anonimus
ce19f740f8 Adjust odds 2025-09-11 10:22:23 -04:00
NepDisk
e4ef793be4 Use qs22j instead of qsort 2025-09-11 16:00:50 +02:00
NepDisk
1a9dfea86d Compat for Kart v1 TC modes 2025-09-11 09:46:18 -04:00
minenice55
51a4be0a3f Merge branch 'blankart-dev' into mine-grid-css-2021 2025-09-11 07:52:01 +02:00
minenice55
af2bc96101 implement stat bars for grid style 2025-09-10 23:17:26 -04:00
Anonimus
a8dc5774e2 Refactor odds and move them to their own file
* Race odds now use 16 tiers and are intended to be balanced around 16 players
* DISTVAR has been increased to 2048 to match the new tier capacity
* Race odds now use a max-75 scale, with the x4 multiplier in calcs being used only in a battle odds context
2025-09-10 16:45:40 -04:00
NepDisk
5082c343c8 Merge pull request 'Add kartbot_cap cvar' (#103) from Wumbo/blankart:betteroffline into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/103
2025-09-10 22:43:30 +02:00
Wumbo
9874a36f91 Add kartbot_cap cvar 2025-09-10 16:09:59 -04:00
NepDisk
8340e170a8 Update README.md 2025-09-10 21:53:30 +02:00
minenice55
7c4d9f7dc8 Merge branch 'blankart-dev' into mine-grid-css-2021 2025-09-10 14:54:21 -04:00
GenericHeroGuy
e92362f36c (WIP) Rewrite screen capture code for GIFs
Downscaling is now performed during screen capture instead of GIF writing
This may or may not make GIF recording faster?
Maybe it would be faster if I knew how OpenGL worked...
Regardless, the m*th in the GIF code is gone, fixing the high/odd res issues

Also includes a little deduped hardware code, and GL 4.3 debugging code
2025-09-09 23:09:51 +02:00
minenice55
31cca408a2 fix scroll clamping 2025-09-09 15:31:52 -04:00
minenice55
c82557529e hide bar-style stat backer in grid mode 2025-09-09 14:04:00 -04:00
minenice55
1ef672ab9c disable scrollbar when skins take up less than one complete page 2025-09-08 19:03:46 -04:00
NepDisk
15b83e9fc3 Only run fallback traversal for bounce and slide for gameplay important objects
Mostly to prevent issues with objects such as mine explosion particles and other visual effects from spamming traversals
2025-09-08 17:19:33 -04:00
NepDisk
89f0ef836b Use Path traversal if sweep lines fail
Not very pretty with lots of duped code but it works?
Designed to handle collision line sweep miss edgecases as they occur until line sweeps can be improved
2025-09-08 16:33:06 -04:00
minenice55
874687e9c7 don't draw scrollbar if no need to scroll 2025-09-08 14:40:03 -04:00
minenice55
5b18297c68 prefcolor sorting 2025-09-08 13:21:10 -04:00
minenice55
7f12437c76 implement sorting for grid CSS 2025-09-08 13:15:33 -04:00
NepDisk
4192ca3da6 Merge pull request 'Unify death animations and make more accurate to SRB2Kart' (#101) from Wumbo/blankart:simpledeath into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/101
2025-09-08 17:20:24 +02:00
minenice55
be8e46506a cvar to swap css styles
need to check this still
2025-09-08 08:50:17 -04:00
minenice55
779fcde3f4 reword this note 2025-09-07 22:32:14 -04:00
minenice55
306f66e09c Merge branch 'blankart-dev' into mine-grid-css-2021 2025-09-07 22:15:11 -04:00
minenice55
7b5a4c5529 remove commented code 2025-09-07 22:10:04 -04:00
minenice55
8c480f9606 tweak colours, tab fast-exit 2025-09-07 22:09:17 -04:00
minenice55
e1db6d59cd fix inaccurate scroll bar 2025-09-07 21:52:59 -04:00
minenice55
35483ccd84 get controls working 2025-09-07 21:20:18 -04:00
Wumbo
b0e25dcc9c Unify death animations and make more accurate to SRB2Kart 2025-09-07 19:06:37 -04:00
Gustaf Alhäll
9986f9aaef Fix OS-specific behavior caused by integer overflow on Lua numbers 2025-09-07 11:50:10 -04:00
NepDisk
41c584638e Nerf drafting a small bit and give higher speeds an accel bonus 2025-09-07 11:24:44 -04:00
minenice55
9ee41124c1 start porting my wip grid css from 2021 2025-09-07 00:20:41 -04:00
GenericHeroGuy
1eabec187a Fix gamestate reloads 2025-09-07 01:49:09 +02:00
StarManiaKG
a2ecd5dbdd Set maximum window size for SDL 2025-09-06 15:45:09 -04:00
134 changed files with 8441 additions and 3940 deletions

1
.gitignore vendored
View file

@ -19,6 +19,7 @@ Win32_LIB_ASM_Release
*.opendb
*.kate-swp
/.vs
/.vscode
/debian
/assets/debian
/make

View file

@ -86,6 +86,7 @@ option(SRB2_CONFIG_TRACY "Compile with Tracy profiling enabled" OFF)
option(SRB2_CONFIG_ASAN "Compile with AddressSanitizer (libasan)." OFF)
set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.")
option(SRB2_CONFIG_LTO "Enable link time optimizations, improves performance at the cost of longer link times." ON)
option(SRB2_CONFIG_TIDY "Enable clang tiny, checks compiled code for issues at the cost of longer compile times." OFF)
if(SRB2_CONFIG_ENABLE_TESTS)
# https://github.com/catchorg/Catch2

View file

@ -2,6 +2,8 @@
BlanKart is a modification of SRB2Kart v2 Indev to make it closer to SRB2Kart gameplay while adding new features, and techincal improvements.
If you're interested in helping out, theres a matrix room located [here](https://matrix.to/#/#blankart:matrix.org)!
# Notice
This is still in active development and things are going to change. If you find any bugs besure to report to the [issue tracker](https://codeberg.org/NepDisk/blankart/issues)!
@ -9,6 +11,7 @@ This is still in active development and things are going to change. If you find
## Techincal Features
- Full Support for UDMF, Terrain, Bots, ACS, New Waypoints and many other technical features backported from Ring Racers. Also includes some extensions to these features such as bot drifting, new terrain effects and map header toggles.
- Ring Racers' software renderer and its multithreading.
- Native support for both SRB2Kart and Ring Racers custom skins.
- Backwards compatiblity with most SRB2Kart maps, assets* and scripts\*.
- A map patching system to allow custom map things to be patched onto maps. Useful for adding rings, waypoints and other objects to existing maps.
- Support for many SRB2Kart v1 custom client extensions from Saturn and other clients such as vote themes.
@ -54,7 +57,7 @@ git clone https://codeberg.org/NepDisk/blankart.git
cd blankart
mkdir build
cd build
cmake -G "MSYS Makefiles" ..
cmake -G "MSYS Makefiles" .. -DCMAKE_POLICY_VERSION_MINIMUM=3.5
make -j$(nproc)
```

View file

@ -64,6 +64,10 @@ if(SRB2_CONFIG_ASAN)
target_link_options(SRB2SDL2 PRIVATE -fsanitize=address)
endif()
if(SRB2_CONFIG_TIDY)
set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*")
endif()
add_subdirectory(blua)
add_subdirectory(blan)
add_subdirectory(sdl)

View file

@ -64,6 +64,7 @@ p_user.c
p_slopes.c
p_sweep.cpp
p_test.cpp
p_deepcopy.cpp
tables.c
r_bsp.cpp
r_data.c
@ -116,6 +117,9 @@ lua_hudlib_drawlist.c
lua_followerlib.c
lua_terrainlib.c
lua_waypointslib.c
lua_vectorlib.c
lua_matrixlib.c
lua_quaternionlib.c
k_kart.c
k_collide.c
k_color.c
@ -128,6 +132,7 @@ k_bot.cpp
k_botitem.cpp
k_botsearch.cpp
k_cluster.cpp
k_odds.c
k_grandprix.c
k_boss.c
k_hud.c

View file

@ -10,8 +10,10 @@
//
//-----------------------------------------------------------------------------
#ifdef __GNUC__
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#endif
#include "Thread.hpp"
#include "Array.hpp"

View file

@ -10,8 +10,10 @@
//
//-----------------------------------------------------------------------------
#ifdef __GNUC__
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#endif
#include "Thread.hpp"
#include "Array.hpp"

View file

@ -4310,6 +4310,12 @@ enum
THING_PROP_HNEXT,
THING_PROP_HPREV,
THING_PROP_ITNEXT,
THING_PROP_BAKEDXOFFSET,
THING_PROP_BAKEDYOFFSET,
THING_PROP_BAKEDZOFFSET,
THING_PROP_BAKEDXPIVOT,
THING_PROP_BAKEDYPIVOT,
THING_PROP_BAKEDZPIVOT,
THING_PROP__MAX
};
@ -4479,6 +4485,12 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A
PROP_MOBJ(THING_PROP_HNEXT, hnext)
PROP_MOBJ(THING_PROP_HPREV, hprev)
PROP_MOBJ(THING_PROP_ITNEXT, itnext)
PROP_INT(THING_PROP_BAKEDXOFFSET, bakexoff)
PROP_INT(THING_PROP_BAKEDYOFFSET, bakeyoff)
PROP_INT(THING_PROP_BAKEDZOFFSET, bakezoff)
PROP_INT(THING_PROP_BAKEDXPIVOT, bakexpiv)
PROP_INT(THING_PROP_BAKEDYPIVOT, bakeypiv)
PROP_INT(THING_PROP_BAKEDZPIVOT, bakezpiv)
default:
{
CONS_Alert(CONS_WARNING, "GetThingProperty type %d out of range (expected 0 - %d).\n", property, THING_PROP__MAX-1);

View file

@ -260,9 +260,8 @@ ACSVM::Thread *Environment::allocThread()
ACSVM::ModuleName Environment::getModuleName(char const *str, size_t len)
{
ACSVM::String *name = getString(str, len);
lumpnum_t lump = W_CheckNumForNameInFolder(str, "ACS/");
return { name, nullptr, static_cast<size_t>(lump) };
return { name, nullptr, static_cast<size_t>(false) };
}
void Environment::loadModule(ACSVM::Module *module)
@ -272,22 +271,34 @@ void Environment::loadModule(ACSVM::Module *module)
size_t lumpLen = 0;
std::vector<ACSVM::Byte> data;
if (name->i == (size_t)LUMPERROR)
lumpnum_t lumpnum = LUMPERROR;
if (name->i) // this module is from a map!
{
// No lump given for module.
CONS_Alert(CONS_WARNING, "Could not find ACS module \"%s\"; scripts will not function properly!\n", name->s->str);
return; //throw ACSVM::ReadError("file open failure");
INT32 mapnum = G_MapNumber(name->s->str);
if (mapnum < NEXTMAP_INVALID)
lumpnum = mapheaderinfo[mapnum]->lumpnum;
}
else // just a lump
{
lumpnum = W_CheckNumForNameInFolder(name->s->str, "ACS/");
}
lumpLen = W_LumpLength(name->i);
if (lumpnum == LUMPERROR)
{
// No lump given for module.
throw ACSVM::ReadError("invalid lump");
}
if (W_IsLumpWad(name->i) == true || lumpLen == 0)
lumpLen = W_LumpLength(lumpnum);
if (W_IsLumpWad(lumpnum) == true || lumpLen == 0)
{
CONS_Debug(DBG_SETUP, "Attempting to load ACS module from the BEHAVIOR lump of map '%s'...\n", name->s->str);
// The lump given is a virtual resource.
// Try to grab a BEHAVIOR lump from inside of it.
virtres_t *vRes = vres_GetMap(name->i);
virtres_t *vRes = vres_GetMap(lumpnum);
auto _ = srb2::finally([vRes]() { vres_Free(vRes); });
virtlump_t *vLump = vres_Find(vRes, "BEHAVIOR");
@ -309,7 +320,7 @@ void Environment::loadModule(ACSVM::Module *module)
ACSVM::Byte *lump = static_cast<ACSVM::Byte *>(Z_Calloc(lumpLen, PU_STATIC, nullptr));
auto _ = srb2::finally([lump]() { Z_Free(lump); });
W_ReadLump(name->i, lump);
W_ReadLump(lumpnum, lump);
data.insert(data.begin(), lump, lump + lumpLen);
}
@ -327,9 +338,7 @@ void Environment::loadModule(ACSVM::Module *module)
}
else
{
// Unlike Hexen, a BEHAVIOR lump is not required.
// Simply ignore in this instance.
CONS_Debug(DBG_SETUP, "ACS module has no data, ignoring...\n");
throw ACSVM::ReadError("file empty");
}
}

View file

@ -143,14 +143,22 @@ void ACS_LoadLevelScripts(size_t mapID)
map->active = true;
// Insert BEHAVIOR lump into the list.
virtres_t *vRes = vres_GetMap(mapheaderinfo[mapID]->lumpnum);
auto _ = srb2::finally([vRes]() { vres_Free(vRes); });
// Unlike Hexen, a BEHAVIOR lump is not required.
// Simply ignore in this instance.
virtlump_t *vLump = vres_Find(vRes, "BEHAVIOR");
if (vLump != nullptr && vLump->size > 0)
{
ACSVM::ModuleName name = ACSVM::ModuleName(
env->getString( mapheaderinfo[mapID]->lumpname ),
nullptr,
mapheaderinfo[mapID]->lumpnum
static_cast<size_t>(true)
);
modules.push_back(env->getModule(name));
CONS_Debug(DBG_SETUP, "Found BEHAVIOR lump.\n");
}
if (modules.empty() == false)
@ -517,8 +525,10 @@ void ACS_Archive(savebuffer_t *save)
std::ostream stream{&buffer};
ACSVM::Serial serial{stream};
#if 0
// Enable debug signatures.
serial.signs = true;
#endif
try
{

View file

@ -89,8 +89,12 @@ int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
int luaO_str2d (const char *s, lua_Number *result) {
char *endptr;
double r = lua_str2number(s, &endptr);
*result = (lua_Number)r;
long r = lua_str2number(s, &endptr);
if (r > INT32_MAX)
r = INT32_MAX;
else if (r < INT32_MIN)
r = INT32_MIN;
*result = (lua_Number)r;
if (endptr == s) return 0; /* conversion failed */
if (*endptr == 'x' || *endptr == 'X') /* maybe an hexadecimal constant? */
*result = cast_num(strtoul(s, &endptr, 16));

View file

@ -677,6 +677,9 @@ static void CON_MoveConsole(void)
INT32 CON_ShiftChar(INT32 ch)
{
if (I_UseNativeKeyboard())
return ch;
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
{
if (shiftdown ^ capslock)
@ -838,7 +841,7 @@ boolean CON_Responder(event_t *ev)
// check for console toggle key
if (ev->type != ev_console)
{
if (modeattacking || metalrecording || marathonmode)
if ((modeattacking && !demo.playback) || metalrecording || marathonmode)
return false;
if (ev->data1 >= NUMKEYS) // See also: HUD_Responder

View file

@ -117,7 +117,7 @@ UINT32 playerpacketlosstable[MAXPLAYERS];
UINT32 playerdelaytable[MAXPLAYERS]; // mindelay values.
static tic_t lowest_lag;
boolean server_lagless;
SINT8 server_lagless;
SINT8 nodetoplayer[MAXNETNODES];
SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
@ -1424,6 +1424,10 @@ static void SendAskInfo(INT32 node)
serverelem_t serverlist[MAXSERVERLIST];
UINT32 serverlistcount = 0;
UINT32 serverlistultimatecount = 0;
static boolean resendserverlistnode[MAXNETNODES];
static tic_t serverlistepoch;
static void SL_ClearServerList(INT32 connectedserver)
{
@ -1436,6 +1440,7 @@ static void SL_ClearServerList(INT32 connectedserver)
serverlist[i].node = 0;
}
serverlistcount = 0;
memset(resendserverlistnode, 0, sizeof resendserverlistnode);
M_UpdateNumServerPages();
}
@ -1453,6 +1458,8 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
{
UINT32 i;
resendserverlistnode[node] = false;
// search if not already on it
i = SL_SearchServer(node);
if (i == UINT32_MAX)
@ -1493,6 +1500,8 @@ void CL_QueryServerList (msg_server_t *server_list)
CL_UpdateServerList();
serverlistepoch = I_GetTime();
for (i = 0; server_list[i].header.buffer[0]; i++)
{
// Make sure MS version matches our own, to
@ -1505,19 +1514,42 @@ void CL_QueryServerList (msg_server_t *server_list)
if (node == -1)
break; // no more node free
SendAskInfo(node);
// Force close the connection so that servers can't eat
// up nodes forever if we never get a reply back from them
// (usually when they've not forwarded their ports).
//
// Don't worry, we'll get in contact with the working
// servers again when they send SERVERINFO to us later!
//
// (Note: as a side effect this probably means every
// server in the list will probably be using the same node (e.g. node 1),
// not that it matters which nodes they use when
// the connections are closed afterwards anyway)
// -- Monster Iestyn 12/11/18
Net_CloseConnection(node|FORCECLOSE);
resendserverlistnode[node] = true;
// Leave this node open. It'll be closed if the
// request times out (CL_TimeoutServerList).
}
}
serverlistultimatecount = i;
}
#define SERVERLISTRESENDRATE NEWTICRATE
void CL_TimeoutServerList(void)
{
if (netgame && serverlistultimatecount > serverlistcount)
{
const tic_t timediff = I_GetTime() - serverlistepoch;
const tic_t timetoresend = timediff % SERVERLISTRESENDRATE;
const boolean timedout = timediff > connectiontimeout;
if (timedout || (timediff > 0 && timetoresend == 0))
{
INT32 node;
for (node = 1; node < MAXNETNODES; ++node)
{
if (resendserverlistnode[node])
{
if (timedout)
Net_CloseConnection(node|FORCECLOSE);
else
SendAskInfo(node);
}
}
if (timedout)
serverlistultimatecount = serverlistcount;
}
}
}
@ -1887,8 +1919,10 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
break;
}
#ifndef HAVE_THREADS
if (curl_running)
CURLGetFile();
#endif
if (waitmore)
break; // exit the case
@ -3387,8 +3421,8 @@ consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "2", CV_SAVE, resyn
consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE, CV_OnOff, NULL);
// max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "51200", CV_SAVE, maxsend_cons_t, NULL);
static CV_PossibleValue_t maxsend_cons_t[] = {{-1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "204800", CV_SAVE, maxsend_cons_t, NULL);
consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE, CV_OnOff, NULL);
// Speed of file downloading (in packets per tic)
@ -5741,6 +5775,17 @@ boolean TryRunTics(tic_t realtics)
COM_BufTicker();
if (mapchangepending)
D_MapChange(-1, 0, encoremode, false, 2, false, fromlevelselect); // finish the map change
// fun fact: this used to be located in NetUpdate!
// as it turns out, reloading the level in rendering code is a very bad idea!
if (client)
{
// If the client just finished redownloading the game state, load it
if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND)
CL_ReloadReceivedSavegame();
hu_redownloadinggamestate = cl_redownloadinggamestate;
}
}
NetUpdate();
@ -5944,6 +5989,7 @@ static tic_t gametime = 0;
static void UpdatePingTable(void)
{
tic_t fastest;
tic_t slowest;
tic_t lag;
INT32 i;
@ -5954,6 +6000,7 @@ static void UpdatePingTable(void)
PingUpdate();
fastest = 0;
slowest = 0;
// update node latency values so we can take an average later.
for (i = 0; i < MAXPLAYERS; i++)
@ -5968,14 +6015,19 @@ static void UpdatePingTable(void)
lag = playerpingtable[i];
if (! fastest || lag < fastest)
fastest = lag;
if (! slowest || lag > slowest)
slowest = lag;
}
}
}
if (server_lagless)
if (server_lagless == 1)
lowest_lag = 0;
else
else if (server_lagless == 0)
lowest_lag = fastest;
else if (server_lagless == -1)
lowest_lag = slowest;
// Don't gentleman below your mindelay
if (lowest_lag < (tic_t)cv_mindelay.value)
@ -6184,12 +6236,7 @@ void NetUpdate(void)
if (client)
{
// If the client just finished redownloading the game state, load it
if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND)
CL_ReloadReceivedSavegame();
CL_SendClientCmd(); // Send tic cmd
hu_redownloadinggamestate = cl_redownloadinggamestate;
}
else
{

View file

@ -425,6 +425,7 @@ struct serverelem_t
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern UINT32 serverlistultimatecount;
extern INT32 mapchangepending;
// Points inside doomcom
@ -488,7 +489,7 @@ extern UINT32 playerpacketlosstable[MAXPLAYERS];
extern UINT32 playerdelaytable[MAXPLAYERS];
extern tic_t servermaxping;
extern boolean server_lagless;
extern SINT8 server_lagless;
extern consvar_t cv_mindelay;
extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_joindelay;
@ -569,6 +570,7 @@ void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(void);
void CL_TimeoutServerList(void);
// Is there a game running
boolean Playing(void);

View file

@ -35,6 +35,7 @@
#include "am_map.h"
#include "console.h"
#include "d_net.h"
#include "d_netfil.h"
#include "f_finale.h"
#include "f_dscredits.hpp"
#include "g_game.h"
@ -89,8 +90,8 @@
#define ASSET_HASH_TEXTURES_KART 0xb4211b2f32b6a291
#define ASSET_HASH_CHARS_KART 0x1e68a3e01aa5c68b
#define ASSET_HASH_MAPS_KART 0x38558ed00da41ce9
#define ASSET_HASH_MAIN_PK3 0xd9cf115699dc58c4
#define ASSET_HASH_MAPPATCH_PK3 0xf1c7678ded3a2d1b
#define ASSET_HASH_MAIN_PK3 0xd0bf225260f749ed
#define ASSET_HASH_MAPPATCH_PK3 0xefe28bb9de73a31c
#define ASSET_HASH_BONUSCHARS_KART 0x60e6f13d822a7461
#ifdef USE_PATCH_FILE
#define ASSET_HASH_PATCH_PK3 0x0000000000000000
@ -1187,6 +1188,7 @@ void D_StartTitle(void)
// okay, stop now
// (otherwise the game still thinks we're playing!)
CURLAbortFile();
SV_StopServer();
SV_ResetServer();
@ -1704,8 +1706,6 @@ void D_SRB2Main(void)
memset(timelimits, 0, sizeof(timelimits));
memset(pointlimits, 0, sizeof(pointlimits));
timelimits[GT_BATTLE] = 2;
CON_SetLoadingProgress(LOADED_HUINIT);
if (modifiedgame)

View file

@ -1006,7 +1006,7 @@ static boolean ShouldDropPacket(void)
{
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100))) || packetdroprate == 100;
}
#endif

View file

@ -160,8 +160,10 @@ static void KartChaining_OnChange(void);
static void KartSlipdash_OnChange(void);
static void KartSlopeBoost_OnChange(void);
static void KartDrafting_OnChange(void);
static void KartAirDrop_OnChange(void);
static void KartItemBreaker_OnChange(void);
static void KartInvinType_OnChange(void);
static void KartBumpSpark_OnChange(void);
static void Schedule_OnChange(void);
@ -184,6 +186,7 @@ static void Command_AcceptInvite_f(void);
static void Command_RejectInvite_f(void);
static void Command_LeaveParty_f(void);
static void Command_Addfilelocal(void);
static void Command_Addfile(void);
static void Command_ListWADS_f(void);
static void Command_ListDoomednums_f(void);
@ -444,7 +447,9 @@ static CV_PossibleValue_t kartbot_cons_t[] = {
{13,"Lv.MAX"},
{0, NULL}
};
static CV_PossibleValue_t kartbot_cap_cons_t[] = {{0, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}};
consvar_t cv_kartbot = CVAR_INIT ("kartbot", "0", CV_NETVAR, kartbot_cons_t, NULL);
consvar_t cv_kartbot_cap = CVAR_INIT ("kartbot_cap", "0", CV_NETVAR, kartbot_cap_cons_t, NULL);
consvar_t cv_kartbot_modifiermax = CVAR_INIT ("kartbot_modifiermax", "1.0", CV_NETVAR|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartbot_basetrackcomplexity = CVAR_INIT ("kartbot_basetrackcomplexity", "-7000", CV_NETVAR, CV_Signed, NULL);
@ -455,9 +460,13 @@ consvar_t cv_kartrings = CVAR_INIT ("kartrings", "No", CV_NETVAR|CV_CALL|CV_NOIN
static CV_PossibleValue_t ringsmin_cons_t[] = {{INT8_MIN, "MIN"}, {0, "MAX"}, {0, NULL}};
static CV_PossibleValue_t ringsmax_cons_t[] = {{0, "MIN"}, {INT8_MAX, "MAX"}, {0, NULL}};
consvar_t cv_kartringsmin = CVAR_INIT ("kartringsmin", "-20", CV_NETVAR, ringsmin_cons_t, NULL);
consvar_t cv_kartringsmax = CVAR_INIT ("kartringsmax", "20", CV_NETVAR, ringsmax_cons_t, NULL);
static CV_PossibleValue_t ringsstart_cons_t[] = {{INT8_MIN, "MIN"}, {INT8_MAX, "MAX"}, {0, NULL}};
consvar_t cv_kartringsstart = CVAR_INIT ("kartringsstart", "5", CV_NETVAR, ringsstart_cons_t, NULL);
// Stacking related
consvar_t cv_kartstacking = CVAR_INIT ("kartstacking", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartStacking_OnChange);
consvar_t cv_kartstacking_diminishparam = CVAR_INIT ("kartstacking_diminishparam", "0.32", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
@ -494,6 +503,10 @@ consvar_t cv_kartstacking_start_speedboost = CVAR_INIT ("vanillaboost_start_spee
consvar_t cv_kartstacking_start_accelboost = CVAR_INIT ("vanillaboost_start_accelboost", "6.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_start_stackable = CVAR_INIT ("vanillaboost_start_stackable", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_kartstacking_walltransfer_speedboost = CVAR_INIT ("vanillaboost_walltransfer_speedboost", "0.10", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_walltransfer_accelboost = CVAR_INIT ("vanillaboost_walltransfer_accelboost", "5.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_walltransfer_stackable = CVAR_INIT ("vanillaboost_walltransfer_stackable", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_kartstacking_drift_speedboost = CVAR_INIT ("vanillaboost_drift_speedboost", "0.25", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_drift_accelboost = CVAR_INIT ("vanillaboost_drift_accelboost", "4.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_drift_stackable = CVAR_INIT ("vanillaboost_drift_stackable", "On", CV_NETVAR, CV_OnOff, NULL);
@ -510,10 +523,10 @@ consvar_t cv_kartstacking_slope_accelboost = CVAR_INIT ("vanillaboost_slope_acce
consvar_t cv_kartstacking_slope_stackable = CVAR_INIT ("vanillaboost_slope_stackable", "On", CV_NETVAR, CV_OnOff, NULL);
// Max speed for high speeds
consvar_t cv_kartstacking_drafting_minspeed = CVAR_INIT ("vanillaboost_draft_minspeed", "0.22", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_drafting_minspeed = CVAR_INIT ("vanillaboost_draft_minspeed", "0.16", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
// Max speed for low speeds
consvar_t cv_kartstacking_drafting_maxspeed = CVAR_INIT ("vanillaboost_draft_maxspeed", "0.32", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartstacking_drafting_maxspeed = CVAR_INIT ("vanillaboost_draft_maxspeed", "0.26", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL);
consvar_t cv_kartchaining = CVAR_INIT ("kartchaining", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartChaining_OnChange);
consvar_t cv_kartchainingoffroad = CVAR_INIT ("kartchaining_chainoffroad", "No", CV_NETVAR, CV_YesNo, NULL);
@ -526,9 +539,19 @@ consvar_t cv_kartusepwrlv = CVAR_INIT ("kartusepwrlv", "Yes", CV_NETVAR, CV_YesN
consvar_t cv_kartpurpledrift = CVAR_INIT ("kartpurpledrift", "No", CV_NETVAR, CV_YesNo, KartPurpleDrift_OnChange);
consvar_t cv_kartbumpspark = CVAR_INIT ("kartbumpspark", "No", CV_NETVAR, CV_YesNo, NULL);
static CV_PossibleValue_t bumpspark_cons_t[] = {{BUMPSPARK_NONE, "Off"},
{BUMPSPARK_NOCHARGE, "Remove Charge Only"},
{BUMPSPARK_RESET100, "Reset to Blue"},
{BUMPSPARK_ALL, "On"},
{0, NULL}};
consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_kartbumpspark = CVAR_INIT("kartbumpspark",
"Remove Charge Only",
CV_NETVAR | CV_CALL,
bumpspark_cons_t,
KartBumpSpark_OnChange);
consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "Yes", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_kartslipdash = CVAR_INIT ("kartslipdash", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartSlipdash_OnChange);
@ -539,6 +562,19 @@ consvar_t cv_kartdrafting_closedraft = CVAR_INIT ("kartdrafting_closedraft", "Of
consvar_t cv_kartdrafting_closedeadzone = CVAR_INIT ("kartdrafting_closedeadzone", "640", CV_NETVAR|CV_CHEAT, CV_Unsigned, NULL);
consvar_t cv_kartdrafting_basedistance = CVAR_INIT ("kartdrafting_basedistance", "2560", CV_NETVAR|CV_CHEAT, CV_Unsigned, NULL);
consvar_t cv_kartairdrop = CVAR_INIT ("kartairdrop", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartAirDrop_OnChange);
// Odds distancing
#define MAXODDSDIST ((INT32_MAX / FRACUNIT) / 2)
static CV_PossibleValue_t distvar_cons_t[] = {{1, "MIN"}, {MAXODDSDIST, "MAX"}, {0, NULL}};
consvar_t cv_kartoddsdist = CVAR_INIT ("kartoddsdist", "2048", CV_NETVAR|CV_CHEAT, distvar_cons_t, NULL);
consvar_t cv_kartlegacyoddsdist = CVAR_INIT ("kartlegacyoddsdist", "2048", CV_NETVAR|CV_CHEAT, distvar_cons_t, NULL);
// SPB distance; no legacy modifiers currently (lazy)
static CV_PossibleValue_t spbdist_cons_t[] = {{1, "MIN"}, {32000, "MAX"}, {0, NULL}};
consvar_t cv_kartspbdist = CVAR_INIT ("kartspbdist", "8192", CV_NETVAR|CV_CHEAT, spbdist_cons_t, NULL);
#undef MAXODDSDIST
// Invincibility modifiers
static CV_PossibleValue_t invintype_cons_t[] = {{0, "Legacy"}, {1, "Alternative"}, {0, NULL}};
consvar_t cv_kartinvintype = CVAR_INIT ("kartinvintype", "Legacy", CV_NETVAR|CV_CALL, invintype_cons_t, KartInvinType_OnChange);
@ -609,7 +645,7 @@ consvar_t cv_rollingdemos = CVAR_INIT ("rollingdemos", "On", CV_SAVE, CV_OnOff,
static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, {0, "None"}, {0, NULL}};
consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange);
static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}};
static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {99999, "MAX"}, {0, "None"}, {0, NULL}};
consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange);
static CV_PossibleValue_t numlaps_cons_t[] = {{0, "MIN"}, {MAX_LAPS, "MAX"}, {-1, "Map default"}, {0, NULL}};
@ -634,7 +670,8 @@ consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "210", CV_CALL|CV_SAVE, netti
consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "210", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange);
consvar_t cv_maxping = CVAR_INIT ("maxdelay", "20", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_lagless = CVAR_INIT ("lagless", "On", CV_SAVE|CV_NETVAR|CV_CALL, CV_OnOff, Lagless_OnChange);
static CV_PossibleValue_t lagless_cons_t[] = {{-1, "Worst"}, {0, "Best"}, {1, "Lagless"}, {0, NULL}};
consvar_t cv_lagless = CVAR_INIT ("lagless", "Lagless", CV_SAVE|CV_NETVAR|CV_CALL, lagless_cons_t, Lagless_OnChange);
static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
consvar_t cv_pingtimeout = CVAR_INIT ("maxdelaytimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL);
@ -646,13 +683,24 @@ consvar_t cv_showping = CVAR_INIT ("showping", "Always", CV_SAVE, showping_cons_
static CV_PossibleValue_t pingmeasurement_cons_t[] = {{0, "Frames"}, {1, "Milliseconds"}, {0, NULL}};
consvar_t cv_pingmeasurement = CVAR_INIT ("pingmeasurement", "Frames", CV_SAVE, pingmeasurement_cons_t, NULL);
consvar_t cv_showlapemblem = CVAR_INIT ("showlapemblem", "On", CV_SAVE, CV_OnOff, NULL);
static CV_PossibleValue_t showlapemblem_cons_t[] = {{0, "Off"}, {1, "Emblem Only"}, {2, "Splits Only"}, {3, "All"}, {0, NULL}};
consvar_t cv_showlapemblem = CVAR_INIT ("showlapemblem", "All", CV_SAVE, showlapemblem_cons_t, NULL);
static CV_PossibleValue_t lapemblemmode_cons_t[] = {{0, "Centre"}, {1, "Race Timer"}, {0, NULL}};
consvar_t cv_lapemblemmode = CVAR_INIT ("lapemblemmode", "Centre", CV_SAVE, lapemblemmode_cons_t, NULL);
// Race splits rely on showlapemblem, so toggling them off isn't really necessary.
static CV_PossibleValue_t racesplits_cons_t[] = {{1, "Next"}, {2, "Leader"}, {0, NULL}};
consvar_t cv_racesplits = CVAR_INIT ("racesplits", "Leader", CV_SAVE, racesplits_cons_t, NULL);
consvar_t cv_showminimapnames = CVAR_INIT ("showminimapnames", "Off", CV_SAVE, CV_OnOff, NULL);
static CV_PossibleValue_t minimapdot_cons_t[] = {{0, "Off"}, {1, "Dot"}, {2, "Headlight"}, {0, NULL}};
consvar_t cv_showminimapangle = CVAR_INIT ("showminimapangle", "Dot", CV_SAVE, minimapdot_cons_t, NULL);
consvar_t cv_minihead = CVAR_INIT ("smallminimapplayers", "Off", CV_SAVE, CV_OnOff, NULL);
static CV_PossibleValue_t spinoutroll_cons_t[] = {{0, "Off"}, {1, "Minimap Only"}, {2, "Rankings Only"}, {3, "Minimap+Rankings"}, {0, NULL}};
consvar_t cv_spinoutroll = CVAR_INIT ("spinoutroll", "Minimap+Rankings", CV_SAVE, spinoutroll_cons_t, NULL);
consvar_t cv_showviewpointtext = CVAR_INIT ("showviewpointtext", "On", CV_SAVE, CV_OnOff, NULL);
// Intermission time Tails 04-19-2002
@ -688,6 +736,8 @@ consvar_t cv_schedule = CVAR_INIT ("schedule", "On", CV_NETVAR|CV_CALL, CV_OnOff
consvar_t cv_automate = CVAR_INIT ("automate", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_debugmappatch = CVAR_INIT ("debugmappatch", "", 0, NULL, NULL);
char timedemo_name[256];
boolean timedemo_csv;
char timedemo_csv_id[256];
@ -851,6 +901,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("showmap", Command_Showmap_f);
COM_AddCommand("maphash", Command_Maphash_f);
COM_AddCommand("addfilelocal", Command_Addfilelocal);
COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("listwad", Command_ListWADS_f);
COM_AddCommand("listmapthings", Command_ListDoomednums_f);
@ -964,7 +1015,10 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_showminimapnames);
CV_RegisterVar(&cv_showminimapangle);
CV_RegisterVar(&cv_minihead);
CV_RegisterVar(&cv_spinoutroll);
CV_RegisterVar(&cv_showlapemblem);
CV_RegisterVar(&cv_lapemblemmode);
CV_RegisterVar(&cv_racesplits);
CV_RegisterVar(&cv_showviewpointtext);
CV_RegisterVar(&cv_schedule);
@ -997,6 +1051,8 @@ void D_RegisterServerCommands(void)
#ifdef LUA_ALLOW_BYTECODE
COM_AddCommand("dumplua", Command_Dumplua_f);
#endif
CV_RegisterVar(&cv_debugmappatch);
}
// =========================================================================
@ -1113,6 +1169,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_skin[i]);
CV_RegisterVar(&cv_follower[i]);
CV_RegisterVar(&cv_followercolor[i]);
CV_RegisterVar(&cv_jitterlegacy[i]);
}
// preferred number of players
@ -1288,7 +1345,6 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_connectawaittime);
CV_RegisterVar(&cv_serverinfoscreen);
}
/**
@ -1930,6 +1986,7 @@ enum {
WP_KICKSTARTACCEL = 1<<0,
WP_SHRINKME = 1<<1,
WP_FLIPCAM = 1<<2,
WP_LEGACYJITTER = 1<<3
};
void WeaponPref_Send(UINT8 ssplayer)
@ -1945,6 +2002,9 @@ void WeaponPref_Send(UINT8 ssplayer)
if (cv_flipcam[ssplayer].value)
prefs |= WP_FLIPCAM;
if (!(cv_jitterlegacy[ssplayer].value))
prefs |= WP_LEGACYJITTER;
UINT8 buf[2];
buf[0] = prefs;
buf[1] = cv_mindelay.value;
@ -1967,6 +2027,9 @@ void WeaponPref_Save(UINT8 **cp, INT32 playernum)
if (player->pflags & PF_FLIPCAM)
prefs |= WP_FLIPCAM;
if (player->jitterlegacy)
prefs |= WP_LEGACYJITTER;
WRITEUINT8(*cp, prefs);
}
@ -1977,6 +2040,7 @@ void WeaponPref_Parse(UINT8 **cp, INT32 playernum)
UINT8 prefs = READUINT8(*cp);
player->pflags &= ~(PF_KICKSTARTACCEL|PF_SHRINKME|PF_FLIPCAM);
player->jitterlegacy = false;
if (prefs & WP_KICKSTARTACCEL)
player->pflags |= PF_KICKSTARTACCEL;
@ -1987,6 +2051,9 @@ void WeaponPref_Parse(UINT8 **cp, INT32 playernum)
if (prefs & WP_FLIPCAM)
player->pflags |= PF_FLIPCAM;
if (prefs & WP_LEGACYJITTER)
player->jitterlegacy = true;
if (leveltime < 2)
{
// BAD HACK: No other place I tried to slot this in
@ -4743,6 +4810,44 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
G_SetGameModified(true, false);
}
static void Command_Addfilelocal(void)
{
const char *fn;
INT32 i;
size_t docompat = COM_CheckPartialParm("-c");
size_t nocompat = COM_CheckPartialParm("-n");
wadcompat_t compat = WC_AUTO;
if (docompat && nocompat)
{
CONS_Printf(M_GetText("Please specify only one of -c or -n\n"));
return;
}
else if (docompat)
compat = WC_ON;
else if (nocompat)
compat = WC_OFF;
if (COM_Argc() != 2 + (docompat || nocompat))
{
CONS_Printf(M_GetText("addfilelocal [-c|-n] <filename.pk3/wad/lua/soc>: Load local add-on\n"
"-c forces compatmode, -n disables it.\n"));
return;
}
else
fn = COM_Argv(1);
// Disallow non-printing characters and semicolons.
for (i = 0; fn[i] != '\0'; i++)
if (!isprint(fn[i]) || fn[i] == ';')
return;
// Add any wad file, ignoring checks for if it contains complex things like
// lua. Great for complex but client-side customizations, like different
// level cards or anything like that.
P_AddWadFile(fn, compat, true);
}
/** Adds a pwad at runtime.
* Searches for sounds, maps, music, new images.
*/
@ -4836,7 +4941,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)
{
P_AddWadFile(fn, compat);
P_AddWadFile(fn, compat, false);
addedfiles[numfilesadded++] = fn;
continue;
}
@ -4976,7 +5081,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename, filehash, true);
if (ncs != FS_FOUND || !P_AddWadFile(filename, compat))
if (ncs != FS_FOUND || !P_AddWadFile(filename, compat, false))
{
Command_ExitGame_f();
if (ncs == FS_FOUND)
@ -5319,9 +5424,8 @@ static void JoinTimeout_OnChange(void)
static void
Lagless_OnChange (void)
{
/* don't back out of dishonesty, or go lagless after playing honestly */
if (cv_lagless.value && gamestate == GS_LEVEL)
server_lagless = true;
if (gamestate == GS_LEVEL)
server_lagless = cv_lagless.value;
}
UINT32 timelimitintics = 0;
@ -7518,6 +7622,40 @@ static void KartDrafting_OnChange(void)
}
}
static void KartAirDrop_OnChange(void)
{
if (K_CanChangeRules() == false)
{
return;
}
if (!K_AirDropActive() && cv_kartairdrop.value)
{
if (leveltime < starttime)
{
airdropactive = true;
CONS_Printf(M_GetText("Air Drop has been turned \"On\".\n"));
}
else
{
CONS_Printf(M_GetText("Air Drop will be turned \"On\" Next Round.\n"));
}
}
else if (K_AirDropActive() && !cv_kartairdrop.value)
{
if (leveltime < starttime)
{
airdropactive = false;
CONS_Printf(M_GetText("Drafting has been turned \"Off\".\n"));
}
else
{
CONS_Printf(M_GetText("Drafting will be turned \"Off\" next round.\n"));
}
}
}
static void KartItemBreaker_OnChange(void)
{
if (K_CanChangeRules() == false)
@ -7558,6 +7696,24 @@ static void KartInvinType_OnChange(void)
}
}
static void KartBumpSpark_OnChange(void)
{
if (K_CanChangeRules() == false)
{
return;
}
if (leveltime < starttime)
{
CONS_Printf(M_GetText("Bump spark type has been changed to \"%s\".\n"), cv_kartbumpspark.string);
bumpsparkactive = (UINT8)cv_kartbumpspark.value;
}
else
{
CONS_Printf(M_GetText("Bump spark type will be changed to \"%s\" next round.\n"), cv_kartbumpspark.string);
}
}
static void Schedule_OnChange(void)
{
size_t i;

View file

@ -117,6 +117,7 @@ extern consvar_t cv_kartgametypepreference;
extern consvar_t cv_kartspeedometer;
extern consvar_t cv_kartvoices;
extern consvar_t cv_kartbot;
extern consvar_t cv_kartbot_cap;
extern consvar_t cv_kartbot_modifiermax;
extern consvar_t cv_kartbot_basetrackcomplexity;
extern consvar_t cv_karteliminatelast;
@ -124,6 +125,7 @@ extern consvar_t cv_kartusepwrlv;
extern consvar_t cv_kartrings;
extern consvar_t cv_kartringsmin;
extern consvar_t cv_kartringsmax;
extern consvar_t cv_kartringsstart;
extern consvar_t cv_kartstacking;
extern consvar_t cv_kartstacking_diminishparam;
@ -158,6 +160,10 @@ extern consvar_t cv_kartstacking_start_speedboost;
extern consvar_t cv_kartstacking_start_accelboost;
extern consvar_t cv_kartstacking_start_stackable;
extern consvar_t cv_kartstacking_walltransfer_speedboost;
extern consvar_t cv_kartstacking_walltransfer_accelboost;
extern consvar_t cv_kartstacking_walltransfer_stackable;
extern consvar_t cv_kartstacking_drift_speedboost;
extern consvar_t cv_kartstacking_drift_accelboost;
extern consvar_t cv_kartstacking_drift_stackable;
@ -196,6 +202,12 @@ extern consvar_t cv_kartinvindistmul;
extern consvar_t cv_kartinvin_maxtime;
extern consvar_t cv_kartinvin_midtime;
extern consvar_t cv_kartairdrop;
extern consvar_t cv_kartoddsdist;
extern consvar_t cv_kartlegacyoddsdist;
extern consvar_t cv_kartspbdist;
extern consvar_t cv_encorevotes;
extern consvar_t cv_votetime;
@ -225,8 +237,11 @@ extern consvar_t cv_pingmeasurement;
extern consvar_t cv_showminimapnames;
extern consvar_t cv_showminimapangle;
extern consvar_t cv_minihead;
extern consvar_t cv_spinoutroll;
extern consvar_t cv_showlapemblem;
extern consvar_t cv_lapemblemmode;
extern consvar_t cv_racesplits;
extern consvar_t cv_showviewpointtext;
extern consvar_t cv_skipmapcheck;
@ -239,6 +254,8 @@ extern consvar_t cv_director;
extern consvar_t cv_schedule;
extern consvar_t cv_debugmappatch;
extern char timedemo_name[256];
extern boolean timedemo_csv;
extern char timedemo_csv_id[256];

View file

@ -98,6 +98,9 @@ static filetran_t transfer[MAXNETNODES];
INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
static tic_t lasttimeackpacketsent = 0;
#ifdef HAVE_THREADS
static I_mutex downloadmutex;
#endif
// For resuming failed downloads
typedef struct
@ -164,7 +167,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
for (; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
{
// If it has only music/sound lumps, don't put it in the list
if (i >= NUMMAINWADS && !wadfiles[i]->important)
if (!wadfiles[i]->important)
continue;
if (firstfile)
@ -173,6 +176,8 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
continue;
}
// CONS_Printf("putting %d (%s) - mw %d\n", i, wadfiles[i]->filename, mainwads);
nameonly(strcpy(wadfilename, wadfiles[i]->filename));
// Look below at the WRITE macros to understand what these numbers mean.
@ -197,7 +202,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
// Store in the upper four bits
if (!cv_downloading.value)
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
else if (cv_maxsend.value == -1 || (wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
// else
// filestatus += (0 << 4); -- Won't send, too big
@ -555,7 +560,10 @@ INT32 CL_CheckFiles(void)
#endif
for (i = 0; i < fileneedednum || j < numwadfiles;)
{
if (j < numwadfiles && !wadfiles[j]->important)
// CONS_Printf("checking %d of %d / %d of %d?\n", i, fileneedednum, j, numwadfiles);
// CONS_Printf("i: %s / j: %s \n", fileneeded[i].filename, wadfiles[j]->filename);
if (j < numwadfiles && !wadfiles[j]->important && !wadfiles[j]->localfile)
{
// Unimportant on our side.
++j;
@ -565,7 +573,9 @@ INT32 CL_CheckFiles(void)
// If this test is true, we've reached the end of one file list
// and the other still has a file that's important
if (i >= fileneedednum || j >= numwadfiles)
{
return 2;
}
// For the sake of speed, only bother with a hash check
if (wadfiles[j]->hash != fileneeded[i].hash)
@ -646,7 +656,7 @@ boolean CL_LoadServerFiles(void)
continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_PartialAddWadFile(fileneeded[i].filename, fileneeded[i].compatmode ? WC_ON : WC_OFF);
P_PartialAddWadFile(fileneeded[i].filename, fileneeded[i].compatmode ? WC_ON : WC_OFF, false);
G_SetGameModified(true, false);
fileneeded[i].status = FS_OPEN;
return false;
@ -947,7 +957,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid
}
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
if (cv_maxsend.value != -1 && wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{
// Too big
// Don't inform client (client sucks, man)
@ -1793,10 +1803,13 @@ void CURLPrepareFile(const char* url, int dfilenum)
I_Error("Attempted to download files in -nodownload mode");
#endif
curl_global_init(CURL_GLOBAL_ALL);
if (!multi_handle)
{
curl_global_init(CURL_GLOBAL_ALL);
multi_handle = curl_multi_init();
}
http_handle = curl_easy_init();
multi_handle = curl_multi_init();
if (http_handle && multi_handle)
{
@ -1847,99 +1860,134 @@ void CURLPrepareFile(const char* url, int dfilenum)
curl_multi_add_handle(multi_handle, http_handle);
curl_multi_perform(multi_handle, &curl_runninghandles);
curl_starttime = time(NULL);
curl_running = true;
#ifdef HAVE_THREADS
I_spawn_thread("http-download", (I_thread_fn)CURLGetFile, NULL);
#endif
}
}
void CURLAbortFile(void)
{
curl_running = false;
#ifdef HAVE_THREADS
// lock and unlock to wait for the download thread to exit
I_lock_mutex(&downloadmutex);
I_unlock_mutex(downloadmutex);
#endif
}
void CURLGetFile(void)
{
CURLMcode mc; /* return code used by curl_multi_wait() */
CURLcode easyres; /* Return from easy interface */
int numfds;
CURLMsg *m; /* for picking up messages with the transfer status */
CURL *e;
int msgs_left; /* how many messages are left */
const char *easy_handle_error;
long response_code = 0;
static char *filename;
if (curl_runninghandles)
{
curl_multi_perform(multi_handle, &curl_runninghandles);
#ifdef HAVE_THREADS
boolean running = true;
/* wait for activity, timeout or "nothing" */
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
if (mc != CURLM_OK)
{
CONS_Alert(CONS_WARNING, "curl_multi_wait() failed, code %d.\n", mc);
return;
}
curl_curfile->currentsize = curl_dlnow;
curl_curfile->totalsize = curl_dltotal;
}
/* See how the transfers went */
while ((m = curl_multi_info_read(multi_handle, &msgs_left)))
I_lock_mutex(&downloadmutex);
while (running && curl_running)
#endif
{
if (m && (m->msg == CURLMSG_DONE))
if (curl_runninghandles)
{
e = m->easy_handle;
easyres = m->data.result;
filename = Z_StrDup(curl_realname);
nameonly(filename);
if (easyres != CURLE_OK)
{
if (easyres == CURLE_HTTP_RETURNED_ERROR)
curl_easy_getinfo(e, CURLINFO_RESPONSE_CODE, &response_code);
curl_multi_perform(multi_handle, &curl_runninghandles);
easy_handle_error = (response_code) ? va("HTTP reponse code %ld", response_code) : curl_easy_strerror(easyres);
curl_curfile->status = FS_FALLBACK;
curl_curfile->currentsize = curl_origfilesize;
curl_curfile->totalsize = curl_origtotalfilesize;
curl_failedwebdownload = true;
fclose(curl_curfile->file);
remove(curl_curfile->filename);
CONS_Printf(M_GetText("Failed to download %s (%s)\n"), filename, easy_handle_error);
/* wait for activity, timeout or "nothing" */
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, NULL);
if (mc != CURLM_OK)
{
CONS_Alert(CONS_WARNING, "curl_multi_wait() failed, code %d.\n", mc);
continue;
}
else
{
fclose(curl_curfile->file);
curl_curfile->currentsize = curl_dlnow;
curl_curfile->totalsize = curl_dltotal;
}
if (checkfilehash(curl_curfile->filename, curl_curfile->hash) == FS_BADHASH)
/* See how the transfers went */
while ((m = curl_multi_info_read(multi_handle, &msgs_left)))
{
if (m && (m->msg == CURLMSG_DONE))
{
#ifdef HAVE_THREADS
running = false;
#endif
e = m->easy_handle;
easyres = m->data.result;
char *filename = Z_StrDup(curl_realname);
nameonly(filename);
if (easyres != CURLE_OK)
{
CONS_Alert(CONS_ERROR, M_GetText("HTTP Download of %s finished but is corrupt or has been modified\n"), filename);
long response_code = 0;
if (easyres == CURLE_HTTP_RETURNED_ERROR)
curl_easy_getinfo(e, CURLINFO_RESPONSE_CODE, &response_code);
easy_handle_error = (response_code) ? va("HTTP response code %ld", response_code) : curl_easy_strerror(easyres);
curl_curfile->status = FS_FALLBACK;
curl_curfile->currentsize = curl_origfilesize;
curl_curfile->totalsize = curl_origtotalfilesize;
curl_failedwebdownload = true;
fclose(curl_curfile->file);
remove(curl_curfile->filename);
CONS_Printf(M_GetText("Failed to download %s (%s)\n"), filename, easy_handle_error);
}
else
{
CONS_Printf(M_GetText("Finished HTTP download of %s\n"), filename);
downloadcompletednum++;
downloadcompletedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
fclose(curl_curfile->file);
if (checkfilehash(curl_curfile->filename, curl_curfile->hash) == FS_BADHASH)
{
CONS_Alert(CONS_ERROR, M_GetText("HTTP Download of %s finished but is corrupt or has been modified\n"), filename);
curl_curfile->status = FS_FALLBACK;
curl_failedwebdownload = true;
}
else
{
CONS_Printf(M_GetText("Finished HTTP download of %s\n"), filename);
downloadcompletednum++;
downloadcompletedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
}
}
Z_Free(filename);
curl_curfile->file = NULL;
#ifndef HAVE_THREADS
curl_running = false;
#endif
curl_transfers--;
curl_multi_remove_handle(multi_handle, e);
curl_easy_cleanup(e);
if (!curl_transfers)
break;
}
Z_Free(filename);
curl_curfile->file = NULL;
curl_running = false;
curl_transfers--;
curl_multi_remove_handle(multi_handle, e);
curl_easy_cleanup(e);
if (!curl_transfers)
break;
}
}
if (!curl_transfers)
if (!curl_transfers || !curl_running)
{
curl_multi_cleanup(multi_handle);
curl_global_cleanup();
multi_handle = NULL;
}
#ifdef HAVE_THREADS
curl_running = false;
I_unlock_mutex(downloadmutex);
#endif
}
HTTP_login *

View file

@ -164,6 +164,7 @@ size_t nameonlylength(const char *s);
#ifdef HAVE_CURL
void CURLPrepareFile(const char* url, int dfilenum);
void CURLAbortFile(void);
void CURLGetFile(void);
HTTP_login * CURLGetLogin (const char *url, HTTP_login ***return_prev_next);
#endif

View file

@ -40,11 +40,14 @@ extern "C" {
typedef enum
{
SF_MACHINE = 1, // Beep boop. Are you a robot?
SF_NOGIBS = 1<<1, // Does this kart smash into pieces?
SF_OLDDEATH = 1<<2, // Kart V1 styled death animation
SF_OLDDEATH = 1<<1, // Kart V1 styled death animation
// free up to and including 1<<31
} skinflags_t;
// Splits are per-lap in Blankart, but let's keep this as-is.
// mine: pedantic; isn't MAX_LAPS = 99 here?
#define MAXRACESPLITS 32
//
// Player states.
//
@ -269,6 +272,18 @@ typedef enum
khud_cardanimation, // Used to determine the position of some full-screen Battle Mode graphics
khud_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly
// Splits
khud_splittime, // Delta between you and highest split
khud_splitwin, // How to color/flag the split based on gaining/losing | ahead/behind
khud_splittimer, // How long to show splits HUD
khud_splitskin, // Skin index of the leading player
khud_splitcolor, // Skincolor of the leading player
khud_splitposition, // Who are we comparing to?
// Drifting
khud_afterimagetime, // tics left for displaying afterimage
khud_afterimagevalue, // what value the drift ended at
NUMKARTHUD
} karthudtype_t;
@ -481,6 +496,15 @@ struct saltyhop_t
fixed_t momz, zoffset; // erm... the mechanism....
};
// enum for saved lap times
typedef enum
{
LAP_CUR,
LAP_BEST,
LAP_LAST,
LAP__MAX
} laptime_e;
// ========================================================================
// PLAYER STRUCTURE
// ========================================================================
@ -566,6 +590,9 @@ struct player_t
// SRB2kart stuff
INT32 kartstuff[NUMKARTSTUFF];
INT32 karthud[NUMKARTHUD];
boolean jitterlegacy; // If true, makes Ring Racers characters jitter during drifts like
// SRB2Kart.
// Basic gameplay things
UINT8 position; // Used for Kart positions, mostly for deterministic stuff
@ -601,6 +628,9 @@ struct player_t
fixed_t driftcharge; // Charge your drift so you can release a burst of speed
UINT8 driftboost; // (0 to 125) - Boost you get from drifting
tic_t driftsparkGrowTimer;
tic_t driftelapsed; // Elapsed time spent during a drift.
fixed_t spinoutrot; // When a player spins out, this value increments modulus 360.
SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked
INT32 aizdrifttilt;
@ -653,12 +683,16 @@ struct player_t
SINT8 ringmax; // maximum rings
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
UINT8 ringlock; // Timer for automatic handeling of ringlock
UINT16 ringboost; // Ring boost timer
UINT16 ringtime; // The current Ring boost timer if it wasn't capped. Used for spam prevention measures.
UINT16 superring; // Spawn rings on top of you every tic!
UINT8 nextringaward; // When should we spawn our next superring ring?
UINT8 ringvolume; // When consuming lots of rings, lower the sound a little.
UINT8 ringtransparency; // When consuming lots of rings, fade out the rings again.
UINT8 ringtransparency; // When consuming lots of rings, fade out the rings again.
UINT8 airdroptime; // Tracks how long airdrop has been active, used for delay before airdrop kicks in.
boolean ringdrop; // Set when having ringdrop applied.
UINT8 curshield; // see kartshields_t
UINT8 bubblecool; // Bubble Shield use cooldown
@ -721,6 +755,9 @@ struct player_t
UINT8 lastsafelap;
UINT8 lastsafestarpost;
tic_t splits[MAXRACESPLITS]; // Times we crossed checkpoint
INT32 pace; // Last split delta, used for checking whether gaining or losing time
//
SINT8 lives;
@ -743,6 +780,7 @@ struct player_t
INT16 totalring; // Total number of rings obtained for GP
tic_t realtime; // integer replacement for leveltime
tic_t laptime[LAP__MAX];
UINT8 laps; // Number of laps (optional)
UINT8 latestlap;
@ -808,6 +846,9 @@ struct player_t
boolean prevonground;
boolean walltransfered;
UINT8 walltransferboost;
#ifdef HWRENDER
fixed_t fovadd; // adjust FOV for hw rendering
#endif

View file

@ -1859,6 +1859,8 @@ static struct { const char *name; consvar_t *var; } HIDDENVARS[] = {
{ "DUMMYATTACKINGSLIPDASH", &cv_dummyattackingslipdash },
{ "DUMMYATTACKINGPURPLEDRIFT", &cv_dummyattackingpurpledrift },
{ "DUMMYATTACKINGSLOPEBOOST", &cv_dummyattackingslopeboost },
{ "DUMMYATTACKINGAIRDROP", &cv_dummyattackingairdrop },
{ "DUMMYATTACKINGBUMPSPARK", &cv_dummyattackingbumpspark },
{ "DUMMYSTAFF", &cv_dummystaff },
{ "DUMMYMULTIPLAYER", &cv_dummymultiplayer },
{ "DUMMYIP", &cv_dummyip },
@ -3711,10 +3713,11 @@ void readfollower(MYFILE *f)
followers[numfollowers].horzlag = 3*FRACUNIT;
followers[numfollowers].vertlag = 6*FRACUNIT;
followers[numfollowers].anglelag = 8*FRACUNIT;
followers[numfollowers].bobspeed = (TICRATE*2)*FRACUNIT;
followers[numfollowers].bobspeed = TICRATE*2;
followers[numfollowers].bobamp = 4*FRACUNIT;
followers[numfollowers].hitconfirmtime = TICRATE;
followers[numfollowers].defaultcolor = SKINCOLOR_GREEN;
followers[numfollowers].defaultcolor = FOLLOWERCOLOR_MATCH;
strcpy(followers[numfollowers].icon, "MISSING");
do
{
@ -3748,6 +3751,11 @@ void readfollower(MYFILE *f)
strcpy(followers[numfollowers].name, word2);
nameset = true;
}
else if (fastcmp(word, "ICON"))
{
strlcpy(followers[numfollowers].icon, word2, 8+1);
nameset = true;
}
else if (fastcmp(word, "MODE"))
{
if (word2)

View file

@ -379,13 +379,18 @@ const char *const GAMETYPERULE_LIST[] = {
"BOTS",
"RINGS",
"BUMPERS",
"POINTS",
"BATTLEODDS",
"PAPERITEMS",
"WANTED",
"WANTEDSPB",
"KARMA",
"ITEMARROWS",
"ITEMBREAKER",
"BATTLESTARTS",
"CLOSERPLAYERS",
"BATTLEBOXES",
"BATTLESPEED",
"POINTLIMIT",
"TIMELIMIT",
"OVERTIME",
@ -755,6 +760,8 @@ struct menu_routine_s const MENU_ROUTINES[] = {
{ "QUITVIEWSERVER", &MR_QuitViewServer },
{ "HANDLEVIEWSERVER", &MR_HandleViewServer },
{ "CAMERASETUP", &MR_CameraSetup },
// { "BARCSS", &MR_HandleBarCss },
{ "HANDLESETUPMULTIPLAYERMENU", &MR_HandleSetupMultiPlayerMenu },
#ifdef HAVE_DISCORDRPC
{ "HANDLEDISCORDREQUESTS", &MR_HandleDiscordRequests },
#endif
@ -769,6 +776,9 @@ struct menu_drawer_s const MENU_DRAWERS[] = {
{ "DRAWTIMEATTACKMENU", &MD_DrawTimeAttackMenu },
{ "DRAWMPMAINMENU", &MD_DrawMPMainMenu },
{ "DRAWSETUPMULTIPLAYERMENU", &MD_DrawSetupMultiPlayerMenu },
// { "DRAWCSSCHARACTER", &MD_DrawCssCharacter },
// { "DRAWBARCSSSELECTOR", &MD_DrawBarCssSelector },
// { "DRAWGRIDCSSSELECTOR", &MD_DrawGridCssSelector },
{ "DRAWVIDEOMODE", &MD_DrawVideoMode },
{ "DRAWADDONS", &MD_DrawAddons },
{ "DRAWREPLAYSTARTMENU", &MD_DrawReplayStartMenu },
@ -1000,7 +1010,6 @@ struct int_const_s const INT_CONST[] = {
// Character flags (skinflags_t)
{"SF_HIRES",0},
{"SF_MACHINE",SF_MACHINE},
{"SF_NOGIBS",SF_NOGIBS},
{"SF_OLDDEATH",SF_OLDDEATH},
// Sound flags
@ -1083,6 +1092,7 @@ struct int_const_s const INT_CONST[] = {
{"OV_DONT3DOFFSET", OV_DONT3DOFFSET},
{"OV_DONTXYSCALE", OV_DONTXYSCALE},
{"OV_DONTROLL", OV_DONTROLL},
{"OV_DONTBAKEOFFSET", OV_DONTBAKEOFFSET},
// Player state (playerstate_t)
{"PST_LIVE",PST_LIVE}, // Playing or camping.
@ -1592,7 +1602,8 @@ struct int_const_s const INT_CONST[] = {
{"TMBOT_NORUBBERBAND",TMBOT_NORUBBERBAND},
{"TMBOT_NOCONTROL",TMBOT_NOCONTROL},
{"TMBOT_FORCEDIR",TMBOT_FORCEDIR},
//{"TMBOT_FASTFALL",TMBOT_FASTFALL},
{"TMBOT_AIRDROP",TMBOT_AIRDROP},
{"TMBOT_FASTFALL",TMBOT_AIRDROP},
// textmapbottrick_t
/*

View file

@ -475,6 +475,12 @@ UINT32 quickncasehash (const char *p, size_t n)
#endif
#endif
// the GNU cleanup attribute: plugging memory leaks since 2003!
// on scope exit, the cleanup function is called with a pointer to the declared variable,
// essentially behaving like a C++ destructor
// NOTE: you WILL have nasal troubles if the variable is not initialized
#define CLEANUP(f) __attribute__((__cleanup__(f)))
// An assert-type mechanism.
// NOTE: USE SRB2_ASSERT FOR C++ CODE INSTEAD
#ifdef PARANOIA

View file

@ -479,37 +479,42 @@ enum GameTypeRules
{
// Race rules
GTR_CIRCUIT = 1, // Enables the finish line, laps, and the waypoint system.
GTR_RACEODDS = 1<<2, // ItemOdds used in this mode are for racing.
GTR_BOTS = 1<<3, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype.
GTR_RINGS = 1<<4, // Allow Rings in this gametype.
GTR_RACEODDS = 1<<1, // ItemOdds used in this mode are for racing.
GTR_BOTS = 1<<2, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype.
GTR_RINGS = 1<<3, // Allow Rings in this gametype.
// Battle gametype rules
GTR_BUMPERS = 1<<5, // Enables the bumper health system
GTR_BATTLEODDS = 1<<6, // ItemOdds used in this mode are for battling.
GTR_PAPERITEMS = 1<<7, // Replaces item boxes with paper item spawners
GTR_WANTED = 1<<8, // Enables the wanted anti-camping system
GTR_KARMA = 1<<9, // Enables the Karma system if you're out of bumpers
GTR_ITEMARROWS = 1<<10, // Show item box arrows above players
GTR_ITEMBREAKER = 1<<11, // Enables the use of Item Breaker in this Gamemode
GTR_BATTLESTARTS = 1<<12, // Use Battle Mode start positions.
GTR_BUMPERS = 1<<4, // Enables the bumper health system.
GTR_POINTS = 1<<5, // Get awarded score when hitting people.
GTR_BATTLEODDS = 1<<6, // ItemOdds used in this mode are for battling.
GTR_PAPERITEMS = 1<<7, // Replaces item boxes with paper item spawners.
GTR_WANTED = 1<<8, // Enables the wanted anti-camping system.
GTR_WANTEDSPB = 1<<9, // Unleash Self-Propelled Bombs on Wanted players.
GTR_KARMA = 1<<10, // Enables the Karma system if you're out of bumpers.
GTR_ITEMARROWS = 1<<11, // Show item box arrows above players.
GTR_ITEMBREAKER = 1<<12, // Enables the use of Item Breaker in this Gamemode.
GTR_BATTLESTARTS = 1<<13, // Use Battle Mode start positions.
GTR_CLOSERPLAYERS = 1<<14, // Enables specfic gameplay tweaks with closer players.
GTR_BATTLEBOXES = 1<<15, // Itemboxes respawn differently.
GTR_BATTLESPEED = 1<<16, // Use battle gamespeed cvar.
GTR_POINTLIMIT = 1<<13, // Reaching point limit ends the round
GTR_TIMELIMIT = 1<<14, // Reaching time limit ends the round
GTR_OVERTIME = 1<<15, // Allow overtime behavior
GTR_POINTLIMIT = 1<<17, // Reaching point limit ends the round.
GTR_TIMELIMIT = 1<<18, // Reaching time limit ends the round.
GTR_OVERTIME = 1<<19, // Allow overtime behavior.
// Custom gametype rules
GTR_TEAMS = 1<<16, // Teams are forced on
GTR_NOTEAMS = 1<<17, // Teams are forced off
GTR_TEAMSTARTS = 1<<18, // Use team-based start positions
GTR_TEAMS = 1<<20, // Teams are forced on.
GTR_NOTEAMS = 1<<21, // Teams are forced off.
GTR_TEAMSTARTS = 1<<22, // Use team-based start positions.
// Grand Prix rules
//Free = 1<<19,
GTR_LIVES = 1<<20, // Lives system, players are forced to spectate during Game Over.
GTR_SPECIALBOTS = 1<<21, // Bot difficulty gets stronger between rounds, and the rival system is enabled.
//Free = 1<<23,
GTR_LIVES = 1<<24, // Lives system, players are forced to spectate during Game Over.
GTR_SPECIALBOTS = 1<<25, // Bot difficulty gets stronger between rounds, and the rival system is enabled.
// Misc
GTR_NOCOUNTDOWN = 1<<22, // Disables Countdown timer and control lock at the start of levels.
GTR_ENCORE = 1<<23, // Enable Encore mode.
GTR_NOCOUNTDOWN = 1<<26, // Disables Countdown timer and control lock at the start of levels.
GTR_ENCORE = 1<<27, // Enable Encore mode.
// free: to and including 1<<31
};
@ -667,6 +672,7 @@ extern boolean franticitems;
extern boolean encoremode, prevencoremode;
extern boolean comeback;
extern SINT8 mostwanted;
extern SINT8 battlewanted[4];
extern tic_t wantedcalcdelay;
extern tic_t indirectitemcooldown;

View file

@ -68,7 +68,7 @@ void I_WaitVBL(INT32 count)
(void)count;
}
void I_ReadScreen(UINT8 *scr)
void I_ReadScreen(UINT8 * restrict scr, INT32 scale)
{
(void)scr;
}

View file

@ -972,7 +972,7 @@ void F_SecretCreditsTicker(void)
finalescene = elapsed;
}
if ((((elapsed - finalescene) / FINALESECDELAY) != finalesecs))
if ((((elapsed - finalescene) / FINALESECDELAY) != (longtic_t)finalesecs))
{
finalesecs = ((elapsed - finalescene) / FINALESECDELAY);

View file

@ -911,17 +911,16 @@ const char *blancredits[] = {
"Kart Krew Dev",
"\"JugadorXEI\"",
"\"Kimberly\"",
"\"Chearii\"",
"",
"\1Item Design",
"\"NepDisk\"",
"\"Anonimus\"",
"\"Denny\" aka \"shephoron\"",
"",
"\1Design Support",
"\"Rim Jobless\"",
"\"JonUD\"",
"\"luna\"",
"\"Denny\" aka \"shephoron\"",
"\"White Mage (guy who picked up controller)\"",
"",
"\1New Item Art",
@ -948,6 +947,16 @@ const char *blancredits[] = {
"\"Mayo\"",
"\"ArcadeStriker\"",
"",
// Anyone who's been directly involved with getting rid of SIGSEGV
// culprits gets credited here.
"\1Super Special SIGSEGV Search and Smash Squad",
"\"NepDisk\"",
"\"GenericHeroGuy\"",
"\"Anonimus\"",
"\"MotoBugger\"",
"\"Rim Jobless\"",
"\"Toad The Fungus\"",
"",
"\1Testing",
"\"NepDisk\"",
"\"Alug\"",
@ -960,8 +969,6 @@ const char *blancredits[] = {
"\"Anonimus\"",
"\"luna\"",
"\"swift\"",
"\"Astronight\"",
"\"Denny\" aka \"shephoron\"",
"\"Rim Jobless\"",
"\"White Mage (guy who picked up controller)\"",
"\"Mayo\"",

View file

@ -316,7 +316,7 @@ void F_WipeStartScreen(void)
}
#endif
wipe_scr_start = screens[3];
I_ReadScreen(wipe_scr_start);
I_ReadScreen(wipe_scr_start, 1);
#endif
}
@ -333,7 +333,7 @@ void F_WipeEndScreen(void)
}
#endif
wipe_scr_end = screens[4];
I_ReadScreen(wipe_scr_end);
I_ReadScreen(wipe_scr_end, 1);
V_DrawBlock(0, 0, 0, vid.width, vid.height, wipe_scr_start);
#endif
}

View file

@ -112,7 +112,7 @@ demoghost *ghosts = NULL;
// DEMO RECORDING
//
#define DEMOVERSION 0x000A
#define DEMOVERSION 0x000C
#define DEMOHEADER "\xF0" "BlanReplay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too!
@ -399,9 +399,9 @@ static UINT8 *G_ReadZipTic(ticcmd_t *cmd, UINT8 *dp, UINT16 version)
if (version < 0x000a && ziptic & 0x8000) // ZT_BOT
{
UINT16 botziptic = READUINT16(dp);
if (botziptic & 1) READSINT8(dp);
if (botziptic & 2) READSINT8(dp);
if (botziptic & 4) READSINT8(dp);
if (botziptic & 1) (void)READSINT8(dp);
if (botziptic & 2) (void)READSINT8(dp);
if (botziptic & 4) (void)READSINT8(dp);
}
return dp;
}
@ -649,7 +649,7 @@ static UINT8 *G_ReadRawExtraData(extradata_t *extra, UINT8 *dp, UINT16 version)
}
// parses a demo header from the given byte pointer
// remember to call G_FreeDemoHeader! (unless an error occurs)
// remember to call G_FreeDemoHeader!
static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header)
{
UINT8 *startdp = dp;
@ -683,6 +683,11 @@ static headerstatus_e G_ReadDemoHeader(UINT8 *dp, demoheader_t *header)
case DEMOVERSION: // latest always supported
break;
case 0x000B:
break;
case 0x000A:
break;
case 0x0009:
serverinfo = false;
break;
@ -1463,7 +1468,7 @@ void G_GhostAddHit(INT32 playernum, mobj_t *victim)
return;
ghostext[playernum].flags |= EZT_HIT;
ghostext[playernum].hits++;
ghostext[playernum].hitlist = Z_Realloc(ghostext[playernum].hitlist, ghostext[playernum].hits * sizeof(mobj_t *), PU_LEVEL, &ghostext[playernum].hitlist);
Z_Realloc(ghostext[playernum].hitlist, ghostext[playernum].hits * sizeof(mobj_t *), PU_STATIC, &ghostext[playernum].hitlist);
P_SetTarget(ghostext[playernum].hitlist + (ghostext[playernum].hits-1), victim);
}
@ -1645,6 +1650,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
WRITEANGLE(demobuf.p,mo->angle);
P_SetTarget(ghostext[playernum].hitlist+i, NULL);
}
Z_Free(ghostext[playernum].hitlist);
ghostext[playernum].hits = 0;
}
if (ghostext[playernum].flags & EZT_SPRITE)
@ -1818,7 +1824,7 @@ void G_ConsGhostTic(INT32 playernum)
gy = oldghost[playernum].y;
gz = oldghost[playernum].z;
if (abs(px-gx) > syncleeway || abs(py-gy) > syncleeway || abs(pz-gz) > syncleeway)
if ((UINT32)abs(px-gx) > syncleeway || (UINT32)abs(py-gy) > syncleeway || (UINT32)abs(pz-gz) > syncleeway)
{
ghostext[playernum].desyncframes++;
@ -2001,8 +2007,8 @@ void G_GhostTicker(void)
for (UINT16 i = 0; i < zt.damagecount; i++)
{
zipticdamage_t *damage = &zt.damage[i];
if (!(mobjinfo[damage->type].flags & MF_SHOOTABLE)
|| !(mobjinfo[damage->type].flags & (MF_ENEMY|MF_MONITOR))
// MAP15S03 has a broken EZT_HIT at leveltime 3455 which is all 0xff... so bounds check damage->type
if ((damage->type < nummobjtypes && !(mobjinfo[damage->type].flags & (MF_SHOOTABLE|MF_ENEMY|MF_MONITOR)))
|| damage->health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad.
continue;
mobj_t *poof = P_SpawnMobj(damage->x, damage->y, damage->z, MT_GHOST);
@ -2736,6 +2742,20 @@ void G_BeginRecording(void)
raflags |= RAF_PURPLEDRIFT;
if (cv_dummyattackingslopeboost.value)
raflags |= RAF_SLOPEBOOST;
if (cv_dummyattackingairdrop.value)
raflags |= RAF_AIRDROP;
switch (cv_dummyattackingbumpspark.value)
{
case BUMPSPARK_ALL:
raflags |= RAF_BUMPSPARK;
break;
case BUMPSPARK_RESET100:
raflags |= RAF_BS_RESET100;
break;
case BUMPSPARK_NOCHARGE:
raflags |= RAF_BUMPDRIFT;
break;
}
}
else
{
@ -3082,7 +3102,7 @@ static void G_LoadDemoExtraFiles(demoheader_t *header)
}
else
{
P_PartialAddWadFile(file->filename, file->compatmode ? WC_ON : WC_OFF);
P_PartialAddWadFile(file->filename, file->compatmode ? WC_ON : WC_OFF, false);
}
}
}
@ -3178,13 +3198,11 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
I_Assert(bufsize != 0);
// read demo header
demoheader_t header;
CLEANUP(G_FreeDemoHeader) demoheader_t header;
headerstatus_e status = G_ReadDemoHeader(buffer, &header);
(void)status;
I_Assert(status == HEADER_OK);
I_Assert(header.version == VERSION);
I_Assert(header.subversion == SUBVERSION);
I_Assert(header.demoversion == DEMOVERSION);
I_Assert(status == HEADER_OK && header.version == VERSION
&& header.subversion == SUBVERSION && header.demoversion == DEMOVERSION);
Z_Free(buffer);
@ -3200,8 +3218,6 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
else
newlap = UINT32_MAX;
G_FreeDemoHeader(&header);
// load old file
FIL_DefaultExtension(oldname, ".lmp");
if (!FIL_ReadFile(oldname, &buffer))
@ -3211,7 +3227,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
}
// read demo header
demoheader_t oldheader;
CLEANUP(G_FreeDemoHeader) demoheader_t oldheader;
if (G_ReadDemoHeader(buffer, &oldheader) != HEADER_OK)
{
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname);
@ -3224,7 +3240,6 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
if (!(oldheader.demoflags & aflags))
{
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname);
G_FreeDemoHeader(&oldheader);
return UINT8_MAX;
}
@ -3234,8 +3249,6 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
else
oldlap = 0;
G_FreeDemoHeader(&oldheader);
c = 0;
if (uselaps)
@ -3258,20 +3271,20 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
void G_LoadDemoInfo(menudemo_t *pdemo)
{
UINT8 *infobuffer, *extrainfo_p;
CLEANUP(Z_Pfree) UINT8 *infobuffer = NULL;
const UINT8 *extrainfo_p;
if (!FIL_ReadFile(pdemo->filepath, &infobuffer))
{
CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
return;
}
pdemo->type = MD_LOADED;
demoheader_t header;
CLEANUP(G_FreeDemoHeader) demoheader_t header;
switch (G_ReadDemoHeader(infobuffer, &header))
{
case HEADER_OK:
@ -3281,21 +3294,18 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
CONS_Alert(CONS_ERROR, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
case HEADER_BADVERSION:
CONS_Alert(CONS_ERROR, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
case HEADER_BADFORMAT:
CONS_Alert(CONS_ERROR, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
}
@ -3310,7 +3320,6 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
if (!(header.demoflags & DF_MULTIPLAYER))
{
CONS_Alert(CONS_ERROR, M_GetText("%s is not a multiplayer replay and can't be listed on this menu fully yet.\n"), pdemo->filepath);
Z_Free(infobuffer);
return;
}
@ -3383,10 +3392,6 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
if (count >= MAXPLAYERS)
break; //@TODO still cycle through the rest of these if extra demo data is ever used
}
// I think that's everything we need?
Z_Free(infobuffer);
G_FreeDemoHeader(&header);
}
//
@ -3405,18 +3410,38 @@ void G_DeferedPlayDemo(const char *name)
#define SKIPERRORS
static void PrintDemoError(const char (*msg)[1024])
{
if (*msg[0] == '\0')
return;
CONS_Alert(CONS_ERROR, "%s", *msg);
demo.playback = false;
demo.title = false;
if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out.
M_StartMessage(*msg, NULL, MM_NOTHING);
}
static void FreeDemoBuffer(savebuffer_t **freebuffer)
{
if (*freebuffer != NULL)
P_SaveBufferFree(*freebuffer);
}
void G_DoPlayDemo(char *defdemoname)
{
UINT16 i, j;
lumpnum_t l;
char *n,*pdemoname;
char msg[1024];
UINT8 pnum;
CLEANUP(Z_Pfree) char *pdemoname = NULL;
const char *n;
CLEANUP(PrintDemoError) char msg[1024];
CLEANUP(FreeDemoBuffer) savebuffer_t *freebuffer = NULL;
#if defined(SKIPERRORS) && !defined(DEVELOP)
boolean skiperrors = false;
#endif
msg[0] = '\0';
M_ClearMenus(true);
G_InitDemoRewind();
gameaction = ga_nothing;
@ -3446,7 +3471,7 @@ void G_DoPlayDemo(char *defdemoname)
if (P_SaveBufferFromFile(&demobuf, defdemoname) == false)
{
snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname);
goto lumperror;
return;
}
}
// load demo resource from WAD
@ -3458,7 +3483,7 @@ void G_DoPlayDemo(char *defdemoname)
if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR)
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname);
goto lumperror;
return;
}
P_SaveBufferFromLump(&demobuf, l);
@ -3484,7 +3509,7 @@ void G_DoPlayDemo(char *defdemoname)
if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find map %s)'.\n"), defdemoname, mapname);
goto lumperror;
return;
}
vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum);
@ -3493,7 +3518,7 @@ void G_DoPlayDemo(char *defdemoname)
if (vLump == NULL)
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname);
goto lumperror;
return;
}
P_SaveBufferAlloc(&demobuf, vLump->size);
@ -3509,10 +3534,9 @@ void G_DoPlayDemo(char *defdemoname)
// read demo header
demo.playback = true;
demo.buffer = &demobuf;
demoheader_t header;
demo.buffer = freebuffer = &demobuf;
CLEANUP(G_FreeDemoHeader) demoheader_t header;
switch (G_ReadDemoHeader(demobuf.p, &header))
{
case HEADER_OK:
@ -3521,15 +3545,15 @@ void G_DoPlayDemo(char *defdemoname)
case HEADER_BADMAGIC:
snprintf(msg, 1024, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemoname);
goto headererror;
return;
case HEADER_BADVERSION:
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
goto headererror;
return;
case HEADER_BADFORMAT:
snprintf(msg, 1024, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemoname);
goto headererror;
return;
}
demo.version = header.demoversion;
@ -3561,31 +3585,31 @@ void G_DoPlayDemo(char *defdemoname)
snprintf(msg, 1024,
M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"),
pdemoname);
goto error;
return;
case DFILE_ERROR_OUTOFORDER:
snprintf(msg, 1024,
M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
pdemoname);
goto error;
return;
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
snprintf(msg, 1024,
M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"),
pdemoname);
goto error;
return;
case DFILE_ERROR_CANNOTLOAD:
snprintf(msg, 1024,
M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
pdemoname);
goto error;
return;
case DFILE_ERROR_EXTRAFILES:
snprintf(msg, 1024,
M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"),
pdemoname);
goto error;
return;
}
// Moved here so these init properly.
@ -3601,14 +3625,14 @@ void G_DoPlayDemo(char *defdemoname)
if (!gamemap || (gamemap > nummapheaders) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR)
{
snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname);
goto error;
return;
}
// Sigh ... it's an empty demo.
if (header.empty)
{
snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname);
goto error;
return;
}
// extra checks for RA replays
@ -3625,10 +3649,13 @@ void G_DoPlayDemo(char *defdemoname)
if (reason)
{
snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with %s, and is thus invalid.\n"), pdemoname, reason);
goto error;
return;
}
}
// no more error checks at this point, don't free demobuf
freebuffer = NULL;
modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT;
multiplayer = !!(demoflags & DF_MULTIPLAYER);
@ -3656,8 +3683,6 @@ void G_DoPlayDemo(char *defdemoname)
// Load "mapmusrng" used for altmusic selection
mapmusrng = header.mapmusrng;
Z_Free(pdemoname);
memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost));
memset(&ghostext,0,sizeof(ghostext));
@ -3685,7 +3710,7 @@ void G_DoPlayDemo(char *defdemoname)
memset(camera,0,sizeof(camera)); // reset freecam
// Load players that were in-game when the map started
for (pnum = 0; pnum < header.numplayers; pnum++)
for (UINT8 pnum = 0; pnum < header.numplayers; pnum++)
{
demoplayer_t *plr = &header.playerdata[pnum];
UINT8 p = plr->playernum;
@ -3792,33 +3817,19 @@ void G_DoPlayDemo(char *defdemoname)
CopyCaretColors(connectedservercontact, header.servercontact, MAXSERVERCONTACT);
strncpy(connectedserverdescription, header.serverdescription, MAXSERVERDESCRIPTION);
for (pnum = 0; pnum < header.numplayers; pnum++)
for (i = 0; i < header.numplayers; i++)
{
// oldghost init doesn't work here, players aren't immediately spawned anymore
// Set saved attribute values
// No cheat checking here, because even if they ARE wrong...
// it would only break the replay if we clipped them.
demoplayer_t *plr = &header.playerdata[pnum];
demoplayer_t *plr = &header.playerdata[i];
players[plr->playernum].kartspeed = plr->kartspeed;
players[plr->playernum].kartweight = plr->kartweight;
}
demo.deferstart = true;
G_FreeDemoHeader(&header);
return;
error:
G_FreeDemoHeader(&header);
headererror:
P_SaveBufferFree(&demobuf);
lumperror:
CONS_Alert(CONS_ERROR, "%s", msg);
Z_Free(pdemoname);
demo.playback = false;
demo.title = false;
if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out.
M_StartMessage(msg, NULL, MM_NOTHING);
}
void G_SetupDemoPlayer(INT32 i)
@ -3833,11 +3844,13 @@ void G_AddGhost(char *defdemoname)
{
INT32 i;
lumpnum_t l;
char *n,*pdemoname;
CLEANUP(Z_Pfree) char *pdemoname = NULL;
const char *n;
UINT64 demohash;
UINT32 raflags;
demoghost *gh;
UINT8 flags;
UINT8 *buffer;
CLEANUP(Z_Pfree) UINT8 *buffer = NULL;
mapthing_t *mthing;
skin_t *ghskin = &skins[0];
@ -3856,7 +3869,6 @@ void G_AddGhost(char *defdemoname)
if (!FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL))
{
CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname);
Z_Free(pdemoname);
return;
}
}
@ -3864,13 +3876,12 @@ void G_AddGhost(char *defdemoname)
else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR)
{
CONS_Alert(CONS_ERROR, M_GetText("Failed to read lump '%s'.\n"), defdemoname);
Z_Free(pdemoname);
return;
}
else // it's an internal demo
buffer = W_CacheLumpNum(l, PU_LEVEL);
demoheader_t header;
CLEANUP(G_FreeDemoHeader) demoheader_t header;
switch (G_ReadDemoHeader(buffer, &header))
{
case HEADER_OK:
@ -3878,20 +3889,14 @@ void G_AddGhost(char *defdemoname)
case HEADER_BADMAGIC:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
return;
case HEADER_BADVERSION:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
return;
case HEADER_BADFORMAT:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
return;
}
@ -3901,50 +3906,82 @@ void G_AddGhost(char *defdemoname)
if (demohash == gh->checksum) // another ghost in the game already has this checksum?
{ // Don't add another one, then!
CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (hash was matched)\n", pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
G_FreeDemoHeader(&header);
return;
}
flags = header.demoflags;
raflags = header.raflags;
if (!(flags & DF_GHOST))
{
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
G_FreeDemoHeader(&header);
return;
}
if (flags & DF_LUAVARS) // can't be arsed to add support for grinding away ported lua material
{
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
G_FreeDemoHeader(&header);
return;
}
if (header.empty)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
G_FreeDemoHeader(&header);
return;
}
// Check RA flags.
{
UINT32 ourraflags = 0;
UINT16 demoversion = header.demoversion;
if (cv_dummyattackingrings.value)
ourraflags |= RAF_RINGS;
if (cv_dummyattackingstacking.value)
ourraflags |= RAF_STACKING;
if (cv_dummyattackingchaining.value)
ourraflags |= RAF_CHAINING;
if (cv_dummyattackingslipdash.value)
ourraflags |= RAF_SLIPDASH;
if (cv_dummyattackingpurpledrift.value)
ourraflags |= RAF_PURPLEDRIFT;
if (cv_dummyattackingslopeboost.value)
ourraflags |= RAF_SLOPEBOOST;
if (cv_dummyattackingairdrop.value)
ourraflags |= RAF_AIRDROP;
switch (cv_dummyattackingbumpspark.value)
{
case BUMPSPARK_ALL:
raflags |= RAF_BUMPSPARK;
break;
case BUMPSPARK_RESET100:
raflags |= RAF_BS_RESET100;
break;
case BUMPSPARK_NOCHARGE:
raflags |= RAF_BUMPDRIFT;
break;
}
if (demoversion <= 0x000B)
{
ourraflags &= ~RAF_AIRDROP;
ourraflags &= ~RAF_BUMPSPARKMASK;
}
if (ourraflags != raflags)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay doesn't match current RA mode.\n"), pdemoname);
return;
}
}
demoplayer_t *plr = &header.playerdata[0];
// any invalidating flags?
if ((plr->flags & (DEMO_SPECTATOR|DEMO_BOT)) != 0)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), defdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
G_FreeDemoHeader(&header);
return;
}
@ -3968,6 +4005,7 @@ void G_AddGhost(char *defdemoname)
gh->buffer = buffer;
gh->checksum = demohash;
gh->p = buffer + header.endofs;
buffer = NULL; // buffer can't be freed now!
ghosts = gh;
@ -4022,8 +4060,6 @@ void G_AddGhost(char *defdemoname)
gh->oldmo.color = gh->mo->color;
CONS_Printf(M_GetText("Added ghost %s from %s\n"), plr->name, pdemoname);
G_FreeDemoHeader(&header);
Z_Free(pdemoname);
}
// Clean up all ghosts
@ -4041,26 +4077,21 @@ void G_FreeGhosts(void)
// A simplified version of G_AddGhost...
void G_UpdateStaffGhostName(lumpnum_t l)
{
UINT8 *buffer = W_CacheLumpNum(l, PU_CACHE);
CLEANUP(Z_Pfree) UINT8 *buffer = W_CacheLumpNum(l, PU_CACHE);
demoheader_t header;
CLEANUP(G_FreeDemoHeader) demoheader_t header;
if (G_ReadDemoHeader(buffer, &header) != HEADER_OK)
goto fail;
return;
if (!(header.demoflags & DF_GHOST))
goto fail; // we don't NEED to do it here, but whatever
return; // we don't NEED to do it here, but whatever
if (header.numplayers == 0 || header.playerdata[0].playernum != 0)
goto fail;
return;
if (header.playerdata[0].flags & (DEMO_SPECTATOR|DEMO_BOT))
goto fail;
strcpy(dummystaffname, header.playerdata[0].name);
return;
// Ok, no longer any reason to care, bye
fail:
G_FreeDemoHeader(&header);
Z_Free(buffer);
return;
strcpy(dummystaffname, header.playerdata[0].name);
}
//
@ -4454,7 +4485,8 @@ void G_SyncDemoParty(INT32 rem, INT32 newsplitscreen)
// viewports.
// Remove this player
G_LeaveParty(rem);
if (playeringame[rem])
G_LeaveParty(rem);
// And reset the rest of the party
for (int i = 0; i <= r_splitscreen_copy; ++i)

View file

@ -41,6 +41,12 @@ typedef enum
RAF_SLIPDASH = 1<<3,
RAF_PURPLEDRIFT = 1<<4,
RAF_SLOPEBOOST = 1<<5,
RAF_AIRDROP = 1<<6,
RAF_BUMPDRIFT = 1<<7,
RAF_BUMPSPARK = 2<<7,
RAF_BS_RESET100 = 3<<7,
RAF_BUMPSPARKMASK = 0x3<<7,
// up to 1<<31 is free
} raflags_t;

View file

@ -296,6 +296,7 @@ SINT8 pickedvote; // What vote the host rolls
// Server-sided, synched variables
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
SINT8 mostwanted; // The "most wanted" (first in line) player.
tic_t wantedcalcdelay; // Time before it recalculates WANTED
tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded
tic_t hyubgone; // Cooldown before hyudoro is allowed to be rerolled
@ -442,6 +443,17 @@ consvar_t cv_shrinkme[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("shrinkme4", "Off", CV_CALL, CV_OnOff, weaponPrefChange4)
};
// Jon's lament
static CV_PossibleValue_t driftjitter_cons_t[] = {{0, "SRB2Kart"}, {1, "Ring Racers"}, {0, NULL}};
// Drift jitter settings.
consvar_t cv_jitterlegacy[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("driftjitter", "Ring Racers", CV_SAVE|CV_CALL|CV_NOINIT, driftjitter_cons_t, weaponPrefChange),
CVAR_INIT ("driftjitter2", "Ring Racers", CV_SAVE|CV_CALL|CV_NOINIT, driftjitter_cons_t, weaponPrefChange),
CVAR_INIT ("driftjitter3", "Ring Racers", CV_SAVE|CV_CALL|CV_NOINIT, driftjitter_cons_t, weaponPrefChange),
CVAR_INIT ("driftjitter4", "Ring Racers", CV_SAVE|CV_CALL|CV_NOINIT, driftjitter_cons_t, weaponPrefChange)
};
static CV_PossibleValue_t zerotoone_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}};
consvar_t cv_deadzone[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("deadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
@ -472,14 +484,16 @@ SINT8 G_RecordPresetIndex(void)
boolean slipdash = cv_dummyattackingslipdash.value;
boolean purpledrift = cv_dummyattackingpurpledrift.value;
boolean slopeboost = cv_dummyattackingslopeboost.value;
boolean airdrop = cv_dummyattackingairdrop.value;
UINT8 bumpspark = cv_dummyattackingbumpspark.value;
if (!rings && !stacking && !chaining && !slipdash && !purpledrift && !slopeboost)
if (!rings && !stacking && !chaining && !slipdash && !purpledrift && !slopeboost && !airdrop && (bumpspark == BUMPSPARK_NONE))
return RP_KART;
if (stacking && chaining && slopeboost && !rings && !slipdash && !purpledrift)
if (stacking && chaining && slopeboost && airdrop && !rings && !slipdash && !purpledrift && (bumpspark == BUMPSPARK_ALL))
return RP_TECH;
if (rings && stacking && chaining && slipdash && purpledrift && slopeboost)
if (rings && stacking && chaining && slipdash && purpledrift && slopeboost && (bumpspark == BUMPSPARK_NOCHARGE))
return RP_BLAN;
return RP_CUST;
@ -2391,6 +2405,8 @@ static inline void G_PlayerFinishLevel(INT32 player)
void G_PlayerReborn(INT32 player, boolean betweenmaps)
{
player_t *p;
UINT8 i;
INT32 score, roundscore;
INT32 lives;
@ -2467,6 +2483,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT8 lastsafelap;
UINT8 lastsafestarpost;
UINT16 bigwaypointgap;
boolean jitterlegacy = false;
tic_t laptime[LAP__MAX];
score = players[player].score;
lives = players[player].lives;
@ -2490,6 +2509,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
followercolor = players[player].followercolor;
followerskin = players[player].followerskin;
jitterlegacy = players[player].jitterlegacy;
availabilities = players[player].availabilities;
charflags = players[player].charflags;
@ -2520,7 +2541,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0);
karmapoints = 0;
wanted = 0;
rings = 5;
rings = cv_kartringsstart.value;
minrings = cv_kartringsmin.value;
maxrings = cv_kartringsmax.value;
kickstartaccel = 0;
@ -2544,6 +2565,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
nextcheck = 0;
xtralife = 0;
for (i = 0; i < LAP__MAX; i++)
{
laptime[i] = 0;
}
}
else
{
@ -2600,6 +2625,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
lastsafelap = players[player].lastsafelap;
lastsafestarpost = players[player].lastsafestarpost;
bigwaypointgap = players[player].bigwaypointgap;
for (i = 0; i < LAP__MAX; i++)
{
laptime[i] = players[player].laptime[i];
}
}
if (!betweenmaps)
@ -2615,7 +2645,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
follower = NULL;
}
spectatorreentry = players[player].spectatorreentry;
spectatorreentry = (betweenmaps ? 0 : players[player].spectatorreentry);
grieftime = players[player].grieftime;
griefstrikes = players[player].griefstrikes;
@ -2665,6 +2695,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->latestlap = latestlap;
p->totalring = totalring;
for (i = 0; i < LAP__MAX; i++)
{
p->laptime[i] = laptime[i];
}
p->bot = bot;
p->botvars.style = style;
p->botvars.difficulty = botdifficulty;
@ -2689,9 +2724,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->eggmanblame = -1;
p->nocontrol = nocontrol;
p->kickstartaccel = kickstartaccel;
p->jitterlegacy = jitterlegacy;
p->ringvolume = 255;
p->ringtransparency = 255;
p->spinoutrot = 0;
p->spectatorreentry = spectatorreentry;
p->grieftime = grieftime;
@ -2718,8 +2755,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
// Check to make sure their color didn't change somehow...
if (G_GametypeHasTeams())
{
UINT8 i;
if (p->ctfteam == 1 && p->skincolor != skincolor_redteam)
{
for (i = 0; i <= splitscreen; i++)
@ -3339,7 +3374,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] =
// Race
GTR_CIRCUIT|GTR_BOTS|GTR_RINGS|GTR_ENCORE|GTR_RACEODDS,
// Battle
GTR_BUMPERS|GTR_RINGS|GTR_KARMA|GTR_WANTED|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT|GTR_BATTLEODDS
GTR_BUMPERS|GTR_POINTS|GTR_RINGS|GTR_KARMA|GTR_WANTED|GTR_WANTEDSPB|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT|GTR_POINTLIMIT|GTR_BATTLEODDS|GTR_CLOSERPLAYERS|GTR_BATTLEBOXES|GTR_BATTLESPEED
};
//

View file

@ -78,6 +78,8 @@ extern consvar_t cv_invertmouse;
extern consvar_t cv_kickstartaccel[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_shrinkme[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_jitterlegacy[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_deadzone[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_deadzonestyle[MAXSPLITSCREENPLAYERS];

View file

@ -42,10 +42,10 @@ typedef struct itimer_s
{
const char* name; // name of timer
INT32 timer; // current time
std::vector<patch_t*> patches; // timer graphics (big/freeplay)
//std::vector<patch_t*> patches; // timer graphics (big/freeplay)
std::vector<patch_t*> patches_small; // timer graphics (small)
INT32 anim_frames; // tic duration for each graphic
INT32 xoffs = 0, yoffs = 0; // offsets for freeplay mode
//INT32 xoffs = 0, yoffs = 0; // offsets for freeplay mode
INT32 xoffs_small = 0, yoffs_small = 0; // offsets for normal mode
boolean counter; // not a timer, show a counter instead
boolean badtimer; // timer is colored red
@ -143,8 +143,8 @@ static std::vector<itimer_t> addTimers_unsorted;
void K_AddItemTimerEx(
const char *name,
INT32 *timer,
char **patches, char **patches_small,
INT32 patches_size, INT32 patches_small_size,
/*char **patches,*/ char **patches_small,
/*INT32 patches_size,*/ INT32 patches_small_size,
INT32 anim_duration,
INT32 xoffs, INT32 yoffs,
INT32 xoffs_small, INT32 yoffs_small,
@ -156,13 +156,13 @@ void K_AddItemTimerEx(
t.timer_p = timer;
INT32 i;
for (i = 0; i < patches_size; i++)
t.patches.push_back(qche(patches[i]));
//for (i = 0; i < patches_size; i++)
//t.patches.push_back(qche(patches[i]));
for (i = 0; i < patches_small_size; i++)
t.patches_small.push_back(qche(patches[i]));
t.patches_small.push_back(qche(patches_small[i]));
t.anim_frames = anim_duration;
t.xoffs = xoffs; t.yoffs = yoffs;
//t.xoffs = xoffs; t.yoffs = yoffs;
t.xoffs_small = xoffs_small; t.yoffs_small = yoffs_small;
t.counter = counter;
@ -173,6 +173,37 @@ void K_AddItemTimerEx(
addTimers.push_back(t);
}
void K_getTimersDrawinfo(drawinfo_t *out)
{
INT32 fx, fy, flags = V_HUDTRANS|V_SNAPTOBOTTOM|V_SPLITSCREEN;
fx = 160 + cv_timers_xoffset.value;
fy = 170 + cv_timers_yoffset.value;
if (r_splitscreen == 1)
{
flags &= ~V_SNAPTOBOTTOM;
fx = 160;
fy = 75;
}
else if (r_splitscreen > 1)
{
flags &= ~V_SNAPTOBOTTOM;
fy = 75;
fx = 80;
}
if (r_splitscreen > 0)
{
flags &= ~V_HUDTRANS;
flags |= V_30TRANS;
}
out->x = fx;
out->y = fy;
out->flags = flags;
}
void K_DisplayItemTimers(void)
{
if (!cv_itemtimers.value) return;
@ -184,58 +215,65 @@ void K_DisplayItemTimers(void)
{ // sneaker
"shoe",
stplyr->sneakertimer,
{qche("K_ISSHOE")},
{qche("HL_SNKR")},
1, -15, -15, -4, -2,
//{qche("K_ISSHOE")},
{qche("K_TISHOE")},
1, /*-15, -15,*/ -4, -2,
},
{ // invinc
"invincible",
stplyr->invincibilitytimer,
{qche("K_ISINV1"), qche("K_ISINV2"), qche("K_ISINV3"), qche("K_ISINV4"), qche("K_ISINV5"), qche("K_ISINV6")},
{qche("HL_INVNC")},
3, -15, -15, -4, -2,
//{qche("K_ISINV1"), qche("K_ISINV2"), qche("K_ISINV3"), qche("K_ISINV4"), qche("K_ISINV5"), qche("K_ISINV6")},
{qche("K_TIINV1"), qche("K_TIINV2"), qche("K_TIINV3"), qche("K_TIINV4"), qche("K_TIINV5"), qche("K_TIINV6")},
3, /*-15, -15,*/ -4, -2,
},
{ // grow
"grow",
std::max<INT16>(0, stplyr->growshrinktimer),
{qche("K_ISGROW")},
{qche("HL_GROW")},
1, -15, -15, -4, -2,
//{qche("K_ISGROW")},
{qche("K_TIGROW")},
1, /*-15, -15,*/ -4, -2,
},
{ // rocket sneakers
"rocketsneakers",
stplyr->rocketsneakertimer,
{qche("K_ISRSHE")},
{qche("ISPYRSHE")},
1, -15, -15, -4, -2,
//{qche("K_ISRSHE")},
{qche("K_TIRSHE")},
1, /*-15, -15,*/ -4, -2,
},
{ // hyudoro
"hyudoro",
stplyr->hyudorotimer,
{qche("K_ISHYUD")},
{qche("HL_HYU")},
1, -15, -15, -4, -2,
//{qche("K_ISHYUD")},
{qche("K_TIHYUD")},
1, /*-15, -15,*/ -4, -2,
},
{ // drift boost
"driftsparkboost",
stplyr->driftboost,
{qche("IT_ORB0"), qche("IT_ORB1"), qche("IT_ORB2"), qche("IT_ORB3"), qche("IT_ORB4"), qche("IT_ORB3"), qche("IT_ORB2"), qche("IT_ORB1")},
{qche("MSO_SPH1"), qche("MSO_SPH2"), qche("MSO_SPH3"), qche("MSO_SPH4")},
3,
//{qche("K_DRSP1"), qche("K_DRSP2")},
{qche("K_TISRK1"), qche("K_TISRK2")},
2, /*-15, -15,*/ -4, -2,
},
{ // start boost
"startboost",
stplyr->startboost,
{qche("K_ISSTB")},
{qche("K_SSSTB")},
1,
//{qche("K_ISSTB")},
{qche("K_TISTB")},
1, /*-15, -15,*/ -4, -2,
},
{ // ring boost
"ringboost",
stplyr->ringboost,
{qche("IT_RING")},
{qche("MSO_RNG")},
1,
//{qche("K_ISRING")},
{qche("K_TIRING")},
1, /*-15, -15,*/ -4, -2,
},
{ // flameshield
"flameshield",
stplyr->flametimer,
//{qche("K_ISFLMS")},
{qche("K_TIFLMS")},
1, /*-15, -15,*/ -4, -2,
},
};
@ -250,27 +288,41 @@ void K_DisplayItemTimers(void)
{ // spinout
"spinout",
std::max<UINT16>(stplyr->spinouttimer, stplyr->wipeoutslow),
{qche("K_DIZZ1"), qche("K_DIZZ2"), qche("K_DIZZ3"), qche("K_DIZZ4")},
{qche("MSO_HRT1"), qche("MSO_HRT2"), qche("MSO_HRT3"), qche("MSO_HRT4")},
3, .badtimer = true,
//{qche("K_DIZZ1"), qche("K_DIZZ2"), qche("K_DIZZ3"), qche("K_DIZZ4")},
{qche("K_TISPN1"), qche("K_TISPN2"), qche("K_TISPN3"), qche("K_TISPN4")},
3, /*-15, -15,*/ -4, -2,
false,
true,
}
);
timers.push_back(
{ // shrink
"shrink",
std::max<INT16>(0, -stplyr->growshrinktimer),
{qche("K_ISSHRK")},
{qche("HL_SHRNK")},
3, -15, -15, -4, -3, .badtimer = true,
//{qche("K_ISSHRK")},
{qche("K_TISHRK")},
1,
//-15,
//-15,
-4,
-2,
false,
true,
}
);
timers.push_back(
{ // spb
"blueshell",
"spb",
(INT32)spbTimers[stplyr-players],
{qche("IT_SPB1"), qche("IT_SPB2")},
{qche("IT_SPBS1"), qche("IT_SPBS2")},
1, .badtimer = (stplyr->position == K_GetBestRank()),
//{qche("K_ISSPB")},
{qche("K_TISPB")},
1,
//-15,
//-15,
-4,
-2,
false,
(stplyr->position == K_GetBestRank())
}
);
// Same with boost stacks
@ -278,46 +330,44 @@ void K_DisplayItemTimers(void)
{ // boosts
"boosts",
K_StackingActive() ? stplyr->numboosts : 0,
{qche("IT_BOOST0"), qche("IT_BOOST1"), qche("IT_BOOST2"), qche("IT_BOOST3"), qche("IT_BOOST4"), qche("IT_BOOST3"), qche("IT_BOOST2"), qche("IT_BOOST1")},
{qche("MSO_SPD1"), qche("MSO_SPD2"), qche("MSO_SPD3"), qche("MSO_SPD4"), qche("MSO_SPD3"), qche("MSO_SPD2")},
3, .counter = true,
//{qche("K_DRSP1"), qche("K_DRSP2")},
{qche("K_TISRK1"), qche("K_TISRK2")},
2, /*-15, -15,*/ -3, -2,
true,
}
);
timers.push_back(
/*timers.push_back(
{ // dead
"spr_realisticexplosion",
stplyr->deadtimer ? std::max<INT32>(0, TICRATE - stplyr->deadtimer) : 0,
{qche("IT_DED1"), qche("IT_DED2"), qche("IT_DED3"), qche("IT_DED4"), qche("IT_DED5"), qche("IT_DED6"), qche("IT_DED7"), qche("IT_DED8")},
//{qche("IT_DED1"), qche("IT_DED2"), qche("IT_DED3"), qche("IT_DED4"), qche("IT_DED5"), qche("IT_DED6"), qche("IT_DED7"), qche("IT_DED8")},
{qche("IT_DEAD1"), qche("IT_DEAD2"), qche("IT_DEAD3"), qche("IT_DEAD4"), qche("IT_DEAD5"), qche("IT_DEAD6"), qche("IT_DEAD7"), qche("IT_DEAD8")},
1, .yoffs = -4, .badtimer = true,
1,
//0,
//-4,
0,
0,
false,
true,
}
);
);*/
// insert unsortable timers
timers.insert(timers.end(), addTimers_unsorted.begin(), addTimers_unsorted.end());
if ((K_NotFreePlay() && !modeattacking) || r_splitscreen > 0) // "HOME" style, with icons at the bottom
if (!modeattacking) // "HOME" style, with icons at the bottom
{
INT32 itemx = 160, itemy = 160;
INT32 flags = V_SNAPTOBOTTOM|V_SLIDEIN|V_SPLITSCREEN;
INT32 itemx = 0, itemy = 0;
INT32 flags = 0;
INT32 stepx = 25;
INT32 viewnum = R_GetViewNumber();
if (r_splitscreen == 1)
{
flags &= ~V_SNAPTOBOTTOM;
itemy = 75;
}
else if (r_splitscreen > 1)
{
flags &= ~V_SNAPTOBOTTOM;
itemy = 75;
itemx = 80;
}
if (r_splitscreen > 0)
flags |= V_30TRANS;
drawinfo_t info;
K_getTimersDrawinfo(&info);
itemx = info.x;
itemy = info.y;
flags = info.flags;
// Move it up to account for viewpoint text
if (cv_showviewpointtext.value && !demo.title && !P_IsLocalPlayer(stplyr) && !camera[viewnum].freecam && !r_splitscreen)
@ -368,9 +418,9 @@ void K_DisplayItemTimers(void)
textcmap = cmap;
}
if (fastcmp(t.name, "invincibilitytimer"))
if (fastcmp(t.name, "boosts"))
{
cmap = R_GetTranslationColormap(TC_RAINBOW, (skincolornum_t)K_RainbowColor(leveltime), GTC_CACHE);
flags |= V_GREENMAP;
}
if (t.counter) // don't show up as time
@ -382,7 +432,10 @@ void K_DisplayItemTimers(void)
// very bad!
if (t.badtimer)
textcmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
{
flags |= V_REDMAP;
//textcmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
}
patch_t *item = t.patches_small[patchnum];
V_DrawFixedPatch((itemx - (item->width/2))<<FRACBITS, (itemy + t.yoffs_small)<<FRACBITS, FRACUNIT, flags, t.patches_small[patchnum], cmap);
@ -402,7 +455,7 @@ void K_DisplayItemTimers(void)
itemx += stepx;
}
}
else // FREEPLAY - Move these to the left side, where the rankings usually are
/*else // FREEPLAY - Move these to the left side, where the rankings usually are
{
if (r_splitscreen) // How?
return;
@ -483,4 +536,5 @@ void K_DisplayItemTimers(void)
fy += step;
}
}
*/
}

View file

@ -18,6 +18,7 @@ extern "C" {
#include "command.h"
#include "d_player.h"
#include "k_hud.h"
extern consvar_t cv_itemtimers;
extern tic_t spbTimers[MAXPLAYERS];
@ -34,6 +35,7 @@ void K_AddItemTimerEx(
INT32 xoffs_small, INT32 yoffs_small,
boolean counter, boolean unsorted);
void K_DisplayItemTimers(void);
void K_getTimersDrawinfo(drawinfo_t *out);
#ifdef __cplusplus
} // extern "C"

View file

@ -21,7 +21,6 @@
#include "hw_glob.h"
#include "hw_drv.h"
#include "../m_misc.h" //FIL_WriteFile()
#include "../r_draw.h" //viewborderlump
#include "../r_main.h"
#include "../w_wad.h"
@ -1252,41 +1251,18 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
// screen shot
// --------------------------------------------------------------------------
UINT8 *HWR_GetScreenshot(void)
UINT8 *HWR_GetScreenshot(INT32 scale)
{
static UINT8 *buf = NULL;
buf = realloc(buf, vid.width * vid.height * 3);
buf = realloc(buf, (vid.width/scale)*(vid.height/scale)*3);
if (!buf)
return NULL;
// returns 24bit 888 RGB
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
HWD.pfnReadScreenFinalTexture(buf, scale);
return buf;
}
boolean HWR_Screenshot(const char *pathname)
{
boolean ret;
UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
if (!buf)
{
CONS_Debug(DBG_RENDER, "HWR_Screenshot: Failed to allocate memory\n");
return false;
}
// returns 24bit 888 RGB
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
#ifdef USE_PNG
ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL);
#else
ret = saveTGA(pathname, buf, vid.width, vid.height);
#endif
free(buf);
return ret;
}
#endif //HWRENDER

View file

@ -44,7 +44,7 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFl
EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo);
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data);
EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale);
EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip);
EXPORT void HWRAPI(ClearMipMapCache) (void);
@ -99,7 +99,7 @@ struct hwdriver_s
SetTexture pfnSetTexture;
UpdateTexture pfnUpdateTexture;
DeleteTexture pfnDeleteTexture;
ReadRect pfnReadRect;
ReadScreenFinalTexture pfnReadScreenFinalTexture;
GClipRect pfnGClipRect;
ClearMipMapCache pfnClearMipMapCache;
SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility

View file

@ -4712,15 +4712,25 @@ static void HWR_ProjectSprite(mobj_t *thing)
patch_t *rotsprite = NULL;
INT32 rollangle = 0;
angle_t spriterotangle = 0;
vector2_t visoffs, rotoffset;
#endif
// uncapped/interpolation
interpmobjstate_t interp = {0};
mobj_t *interptarg;
if (!thing)
return;
R_InterpolateMobjState(thing, R_GetTimeFrac(RTF_LEVEL), &interp);
interptarg = thing;
if (R_IsOverlayingInvinciblePlayer(thing))
{
// Kill overlay misalignment
interptarg = thing->target;
}
R_InterpolateMobjState(interptarg, R_GetTimeFrac(RTF_LEVEL), &interp);
dispoffset = thing->dispoffset;
@ -4877,12 +4887,36 @@ static void HWR_ProjectSprite(mobj_t *thing)
flip = 0;
}
}
// initialize and rotate pitch/roll vectors
visoffs.x = 0;
visoffs.y = 0;
rotoffset.x = 0;
rotoffset.y = 0;
const fixed_t visoffymul = (vflip ? -FRACUNIT : FRACUNIT);
if (R_ThingIsUsingBakedOffsets(thing))
{
R_RotateSpriteOffsetsByPitchRoll(thing,
vflip,
hflip,
&interp,
&visoffs,
&rotoffset);
rotoffset.x *= FRACUNIT;
}
#endif
if (thing->renderflags & RF_ABSOLUTEOFFSETS)
{
spr_offset = interp.spritexoffset;
#ifdef ROTSPRITE
spr_topoffset = (interp.spriteyoffset + FixedDiv((visoffs.y * visoffymul), mapobjectscale) + (rotoffset.y * visoffymul));
#else
spr_topoffset = interp.spriteyoffset;
#endif
}
else
{
@ -4892,7 +4926,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
flipoffset = -1;
spr_offset += interp.spritexoffset * flipoffset;
#ifdef ROTSPRITE
spr_topoffset += (interp.spriteyoffset + FixedDiv((visoffs.y * visoffymul),
mapobjectscale) + (rotoffset.y * visoffymul)) * flipoffset;
#else
spr_topoffset += interp.spriteyoffset * flipoffset;
#endif
}
if (papersprite)
@ -4943,17 +4982,30 @@ static void HWR_ProjectSprite(mobj_t *thing)
}
else
{
#ifdef ROTSPRITE
if (visoffs.x)
{
visoffs.x = (FixedDiv((visoffs.x * FRACUNIT), mapobjectscale));
}
#endif
if (flip)
{
x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale);
#ifdef ROTSPRITE
spr_offset -= visoffs.x;
spr_offset -= rotoffset.x;
#endif
x1 = (FIXED_TO_FLOAT((spr_width - spr_offset)) * this_xscale);
x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale);
}
else
{
#ifdef ROTSPRITE
spr_offset += visoffs.x;
spr_offset += rotoffset.x;
#endif
x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale);
x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale);
}
// test if too close
/*
if (papersprite)
@ -5095,7 +5147,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
// New colormap stuff for skins Tails 06-07-2002
if (thing->colorized)
{
vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
vis->colormap = R_GetTranslationColormap(
R_IsOverlayingInvinciblePlayer(thing) ? TC_BLINK : TC_RAINBOW,
thing->color,
GTC_CACHE);
}
else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
{
@ -5538,7 +5593,7 @@ static void HWR_DrawSkyBackground(player_t *player)
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
v[0].s = v[3].s = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left
v[0].s = v[3].s = (-1.0f * angle) / (((float)ANGLE_90-1.0f)*dimensionmultiply); // left
v[2].s = v[1].s = v[0].s + (1.0f/dimensionmultiply); // right (or left + 1.0f)
// use +angle and -1.0f above instead if you wanted old backwards behavior

View file

@ -54,8 +54,7 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32
void HWR_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 color);
void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum);
UINT8 *HWR_GetScreenshot(void);
boolean HWR_Screenshot(const char *pathname);
UINT8 *HWR_GetScreenshot(INT32 scale);
void HWR_AddCommands(void);
void HWR_AddSessionCommands(void);

View file

@ -1685,18 +1685,27 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.angley = FIXED_TO_FLOAT(anglef);
}
angle_t pitchR, rollR, fixedAngY;
// drift frame unrotation hack...
if (modeltype == MODELTYPE_OLDPLAYER && (spr2 == SPR2_DRRN || spr2 == SPR2_DRLN))
p.angley += spr2 == SPR2_DRRN ? 45.0f : -45.0f;
pitchR = 0;
rollR = 0;
fixedAngY = 0;
{
fixed_t anglef = AngleFixed(R_SpriteRotationAngle(spr->mobj, NULL, &interp));
p.rollangle = 0.0f;
// make fixedAngY a disguised fixed_t first
fixedAngY = FLOAT_TO_FIXED(p.angley);
if (anglef)
{
fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know
fixed_t camAngleDiff = AngleFixed(viewangle) - (fixed_t)(fixedAngY); // dumb reconversion back, I know
anglef *= flip ? -1 : 1; // Adjust for flipping
@ -1708,9 +1717,19 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2);
// rotation axes relative to camera
p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
pitchR = FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT);
rollR = FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT);
p.rollx = FIXED_TO_FLOAT((fixed_t)rollR);
p.rollz = FIXED_TO_FLOAT((fixed_t)pitchR);
// convert to angles
pitchR = FixedAngle((fixed_t)pitchR);
rollR = FixedAngle((fixed_t)rollR);
}
// make this a proper angle now
fixedAngY = FixedAngle(fixedAngY);
}
p.anglez = FIXED_TO_FLOAT(AngleFixed(R_InterpolateAngle(spr->mobj->old_pitch, spr->mobj->pitch)));
@ -1722,6 +1741,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
HWD.pfnSetShader(SHADER_MODEL); // model shader
{
float this_scale = FIXED_TO_FLOAT(interp.scale);
fixed_t floorClip = spr->mobj->terrain ? spr->mobj->terrain->floorClip : 0;
float finalfloorClip = FIXED_TO_FLOAT(FixedMul(floorClip, mapobjectscale)*P_MobjFlip(spr->mobj));
float xs = this_scale * FIXED_TO_FLOAT(interp.spritexscale);
float ys = this_scale * FIXED_TO_FLOAT(interp.spriteyscale);
@ -1742,7 +1763,89 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
// offset perpendicular to the camera angle
p.x -= ox * gl_viewsin;
p.y += ox * gl_viewcos;
p.z += oy;
p.z += oy - finalfloorClip;
if (R_ThingIsUsingBakedOffsets(spr->mobj))
{
// visoffset stuff
float xx, xy, yx, yy;
float zx, zy, zz;
float xpiv, ypiv, zpiv;
fixed_t zh;
fixed_t xoffs, yoffs;
// xoffs = (cos(xoff) + sin(yoff))
xoffs =
FixedMul(spr->mobj->bakeyoff, -FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)) +
FixedMul(spr->mobj->bakexoff, FINESINE(fixedAngY >> ANGLETOFINESHIFT));
// yoffs = (-sin(xoff) + cos(yoff))
yoffs =
FixedMul(spr->mobj->bakeyoff, -FINESINE(fixedAngY >> ANGLETOFINESHIFT)) +
FixedMul(spr->mobj->bakexoff, FINECOSINE(fixedAngY >> ANGLETOFINESHIFT));
const fixed_t hflipmul = hflip ? -FRACUNIT : FRACUNIT;
xpiv = FIXED_TO_FLOAT(
FixedMul(
FixedMul(spr->mobj->bakeypiv,
-FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)) +
FixedMul(spr->mobj->bakexpiv,
FINESINE(fixedAngY >> ANGLETOFINESHIFT)),
hflipmul));
ypiv = FIXED_TO_FLOAT(
FixedMul(
FixedMul(spr->mobj->bakeypiv,
-FINESINE(fixedAngY >> ANGLETOFINESHIFT)) +
FixedMul(spr->mobj->bakexpiv,
FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)),
hflipmul));
zpiv = FIXED_TO_FLOAT(spr->mobj->bakezpiv * ((flip) ? -1 : 1));
pitchR = ((pitchR + spr->mobj->pitch) * ((flip) ? -1 : 1));
rollR = ((rollR + spr->mobj->roll) * ((flip) ? -1 : 1));
// x offset
xx = FIXED_TO_FLOAT(FixedMul(FixedMul(
FixedMul(xoffs,spr->mobj->spritexscale),
hflipmul),
FINECOSINE(pitchR >> ANGLETOFINESHIFT)
));
xy = FIXED_TO_FLOAT(FixedMul(FixedMul(
FixedMul(xoffs,spr->mobj->spritexscale),
hflipmul),
-FINESINE(pitchR >> ANGLETOFINESHIFT)
));
// y offset
yx = FIXED_TO_FLOAT(FixedMul(FixedMul(
FixedMul(yoffs,spr->mobj->spritexscale),
hflipmul),
FINECOSINE(rollR >> ANGLETOFINESHIFT)
));
yy = FIXED_TO_FLOAT(FixedMul(FixedMul(
FixedMul(yoffs,spr->mobj->spritexscale),
hflipmul),
-FINESINE(rollR >> ANGLETOFINESHIFT)
));
// z offset
zh = FixedMul(FixedMul(spr->mobj->bakezoff,spr->mobj->spriteyscale),
FINECOSINE(rollR >> ANGLETOFINESHIFT));
zz = FIXED_TO_FLOAT(FixedMul(zh,
FINECOSINE(pitchR >> ANGLETOFINESHIFT)));
zx = FIXED_TO_FLOAT(FixedMul(zh,
FINESINE(pitchR >> ANGLETOFINESHIFT)));
zy = FIXED_TO_FLOAT(FixedMul(zh,
FINESINE(rollR >> ANGLETOFINESHIFT)));
// do these namings even make sense at this point?
p.x += xx + zx + xpiv;
p.z += (xy + yy + zz * (flip ? -1 : 1)) + zpiv;
p.y += yx + zy + ypiv;
}
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf);
}

View file

@ -25,6 +25,9 @@
#include "r_opengl.h"
#include "r_vbo.h"
// requires GL 4.3
//#define GLDEBUGMESSAGE
#if defined (HWRENDER) && !defined (NOROPENGL)
struct GLRGBAFloat
@ -281,6 +284,10 @@ static void GL_MSG_Error(const char *format, ...)
#define pglCopyTexImage2D glCopyTexImage2D
#define pglCopyTexSubImage2D glCopyTexSubImage2D
#ifdef GLDEBUGMESSAGE
#define pglDebugMessageCallback glDebugMessageCallback
#endif
#else //!STATIC_OPENGL
/* 1.0 functions */
@ -423,6 +430,11 @@ static PFNglDeleteBuffers pglDeleteBuffers;
typedef void (APIENTRY * PFNglBlendEquation) (GLenum mode);
static PFNglBlendEquation pglBlendEquation;
#ifdef GLDEBUGMESSAGE
typedef void (APIENTRY * PFNglDebugMessageCallback) (void (APIENTRY *DEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam), const void *userParam);
static PFNglDebugMessageCallback pglDebugMessageCallback;
#endif
/* 1.2 Parms */
/* GL_CLAMP_TO_EDGE_EXT */
@ -983,6 +995,10 @@ void SetupGLFunc4(void)
*(void**)&pglUniform3fv = GetGLFunc("glUniform3fv");
*(void**)&pglGetUniformLocation = GetGLFunc("glGetUniformLocation");
#endif
#ifdef GLDEBUGMESSAGE
*(void**)&pglDebugMessageCallback = GetGLFunc("glDebugMessageCallback");
#endif
}
EXPORT boolean HWRAPI(CompileShaders) (void)
@ -1335,6 +1351,50 @@ void SetModelView(GLint w, GLint h)
pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
}
#ifdef GLDEBUGMESSAGE
static void APIENTRY DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
{
const char *debugsource, *debugtype;
switch (source)
{
#define S(s) case GL_DEBUG_SOURCE_##s: debugsource = #s; break
S(API);
S(WINDOW_SYSTEM);
S(SHADER_COMPILER);
S(THIRD_PARTY);
S(APPLICATION);
S(OTHER);
#undef S
default:
debugsource = "unknown";
break;
}
switch (type)
{
#define S(s) case GL_DEBUG_TYPE_##s: debugtype = #s; break
S(ERROR);
S(DEPRECATED_BEHAVIOR);
S(UNDEFINED_BEHAVIOR);
S(PORTABILITY);
S(PERFORMANCE);
S(MARKER);
S(PUSH_GROUP);
S(POP_GROUP);
S(OTHER);
#undef S
default:
debugtype = "unknown";
break;
}
alerttype_t level = severity == GL_DEBUG_SEVERITY_HIGH ? CONS_ERROR
: severity == GL_DEBUG_SEVERITY_MEDIUM ? CONS_WARNING
: CONS_NOTICE;
CONS_Alert(level, "OpenGL (%s) (%s): %s\n", debugsource, debugtype, message);
}
#endif
// -----------------+
// SetStates : Set permanent states
@ -1395,6 +1455,12 @@ void SetStates(void)
pglLoadIdentity();
pglScalef(1.0f, 1.0f, -1.0f);
pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
#ifdef GLDEBUGMESSAGE
pglEnable(GL_DEBUG_OUTPUT);
pglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
pglDebugMessageCallback(&DebugMessage, NULL);
#endif
}
@ -1514,58 +1580,37 @@ EXPORT void HWRAPI(ClearMipMapCache) (void)
Flush();
}
// -----------------+
// ReadRect : Read a rectangle region of the truecolor framebuffer
// : store pixels as 16bit 565 RGB
// Returns : 16bit 565 RGB pixel array stored in dst_data
// -----------------+
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
INT32 dst_stride, UINT16 * dst_data)
// -----------------------+
// ReadScreenFinalTexture : Reads out the final screen texture
// Returns : 24bit RGB pixel array stored in dest
// -----------------------+
EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale)
{
INT32 i;
// GL_DBG_Printf ("ReadRect()\n");
if (dst_stride == width*3)
{
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
GLubyte *row = malloc(dst_stride);
if (!row) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(i = 0; i < height/2; i++)
{
memcpy(row, top, dst_stride);
memcpy(top, bottom, dst_stride);
memcpy(bottom, row, dst_stride);
top += dst_stride;
bottom -= dst_stride;
}
free(row);
}
else
{
INT32 j;
GLubyte *image = malloc(width*height*3*sizeof (*image));
if (!image) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = height-1; i >= 0; i--)
{
for (j = 0; j < width; j++)
{
dst_data[(height-1-i)*width+j] =
(UINT16)(
((image[(i*width+j)*3]>>3)<<11) |
((image[(i*width+j)*3+1]>>2)<<5) |
((image[(i*width+j)*3+2]>>3)));
}
}
free(image);
}
}
const INT32 stride = (screen_width/scale)*3;
INT32 scanlines = screen_height;
GLubyte * restrict image;
image = malloc(screen_width*screen_height*3);
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, image);
// TODO the downscaling happens in the screen capture code now,
// yet we're still doing this on the CPU? sheesh...
// this is where actual knowledge of OpenGL would've come in handy
image += scanlines*screen_width*3;
while ((scanlines -= scale) >= 0)
{
image -= screen_width*scale*3;
if (scale == 1)
memcpy(dest, image, stride);
else for (INT32 i = 0; i < stride; i += 3)
memcpy(dest + i, image + i*scale, 3);
dest += stride;
}
// ...yet still, restrict doesn't make the inner loop any faster
free(image - ((screen_height % scale) * screen_width*3));
}
// -----------------+
// GClipRect : Defines the 2D hardware clipping window

View file

@ -2058,7 +2058,7 @@ static void HU_DrawDemoInfo(void)
void HU_DrawSongCredits(void)
{
fixed_t x;
fixed_t y = (r_splitscreen ? (BASEVIDHEIGHT/2)-4 : 32) * FRACUNIT;
fixed_t y = ((r_splitscreen && G_GamestateUsesLevel()) ? (BASEVIDHEIGHT/2)-4 : 32) * FRACUNIT;
INT32 snapflags = cursongcredit.snapflags;
INT32 bgt;
@ -2592,7 +2592,7 @@ static void HU_DrawRankings(void)
tab[scorelines].name = player_names[i];
if ((gametyperules & GTR_CIRCUIT))
if (gametyperules & GTR_CIRCUIT)
{
if (!players[i].exiting)
sprintf(tab[scorelines].string, "Lap %d", players[i].laps);
@ -2605,7 +2605,7 @@ static void HU_DrawRankings(void)
sprintf(tab[scorelines].string, "%i'%02i\"%02i", min, sec, cen);
}
}
else
else if (gametyperules & GTR_POINTS)
sprintf(tab[scorelines].string, "%d", players[i].roundscore);
scorelines++;

View file

@ -141,7 +141,7 @@ void I_WaitVBL(INT32 count);
\return void
*/
void I_ReadScreen(UINT8 *scr);
void I_ReadScreen(UINT8 * restrict scr, INT32 scale);
/** \brief Start disk icon
*/
@ -153,6 +153,10 @@ void I_EndRead(void);
UINT32 I_GetRefreshRate(void);
boolean I_UseNativeKeyboard(void);
extern consvar_t cv_keyboardlayout;
void I_SetBorderlessWindow(void);
#ifdef __cplusplus

View file

@ -158,7 +158,7 @@ void P_ResetData(INT32 flags)
if (!init)
{
lumpnum = W_CheckNumForLongNamePwadNoUpper("states", MAINWAD_MAIN, 0);
lumpnum = W_CheckNumForLongNamePwad("states", MAINWAD_MAIN, 0);
DEH_LoadDehackedLumpPwad(MAINWAD_MAIN, lumpnum, true);
}
}
@ -183,7 +183,7 @@ void P_ResetData(INT32 flags)
if (!init)
{
lumpnum = W_CheckNumForLongNamePwadNoUpper("mobjs", MAINWAD_MAIN, 0);
lumpnum = W_CheckNumForLongNamePwad("mobjs", MAINWAD_MAIN, 0);
DEH_LoadDehackedLumpPwad(MAINWAD_MAIN, lumpnum, true);
}
}
@ -211,7 +211,7 @@ void P_ResetData(INT32 flags)
if (!init)
{
lumpnum = W_CheckNumForLongNamePwadNoUpper("skincolors", MAINWAD_MAIN, 0);
lumpnum = W_CheckNumForLongNamePwad("skincolors", MAINWAD_MAIN, 0);
DEH_LoadDehackedLumpPwad(MAINWAD_MAIN, lumpnum, true);
}
}

View file

@ -222,4 +222,3 @@ _(A_RoamingShadowThinker, ROAMINGSHADOWTHINKER)
_(A_MayonakaArrow, MAYONAKAARROW)
_(A_MementosTPParticles, MEMENTOSTPPARTICLES)
_(A_ReaperThinker, REAPERTHINKER)
_(A_DeathSpin, DEATHSPIN)

View file

@ -5,8 +5,6 @@ _(UNKNOWN)
_(THOK) // Thok! mobj
_(SHADOW) // Linkdraw Shadow (for invisible objects)
_(PLAYER)
_(KART_LEFTOVER)
_(KART_TIRE)
// Enemies
_(BLUECRAWLA) // Crawla (Blue)

View file

@ -1,6 +1,7 @@
// SRB2K colors
_(NONE)
_(WHITE) // kart colors
_(WHITE)
_(SILVER)
_(GREY)
_(NICKEL)
@ -62,7 +63,7 @@ _(ROBOHOOD)
_(MINT)
_(GREEN)
_(PINETREE)
_(EMERALD)
_(TURTLE)
_(SWAMP)
_(DREAM)
_(PLAGUE)
@ -82,10 +83,10 @@ _(THUNDER)
_(RUST)
_(WRISTWATCH)
_(JET)
_(SAPPHIRE) // sweet mother, i cannot weave - slender aphrodite has overcome me with longing for a girl
_(SAPPHIRE)
_(PERIWINKLE)
_(BLUE)
_(BLUEBERRY)
_(MIDNIGHT)
_(NOVA)
_(PASTEL)
_(MOONSLAM)
@ -101,170 +102,268 @@ _(BYZANTIUM)
_(POMEGRANATE)
_(LILAC)
_(TAN) // v2 colors, i think? separated from the rest (yay compatmode!)
// Ring Racers New Colors
// These are listed after the Kart colors for backwards compatability
_(SUNSLAM)
_(TAN)
_(BANANA)
_(PERIDOT)
_(TURTLE)
_(EMERALD)
_(AQUAMARINE)
_(TURQUOISE)
_(ROBIN)
_(ULTRAMARINE)
_(MIDNIGHT)
_(BLUEBERRY)
_(THISTLE)
_(MOONSET)
_(VIOLET)
_(MAGENTA)
_(BLOSSOM)
_(TAFFY)
_(BONE) // vanilla colors - shoutouts to Sonic Team Jr.
// SRB2 Vanilla 2.2 Ports
// featuring Viv's vivid colours (toast 21/07/17)
// Tweaks & additions (Lach, Chrispy, sphere, Alice, MotorRoach & Saneko 26/10/22)
// Conversion to Kart/Ring Racers style (BlanKart 21/04/25)
_(BONE)
_(CARBON)
_(INK)
_(GHOST)
_(AETHER)
_(MARBLE)
_(MOONSTONE)
_(BLUEBELL)
_(CHOCOLATE)
_(CHESTNUT)
_(LATTE)
_(BOULDER)
_(BRASS)
_(VINTAGE)
_(ECRU)
_(SANDSTORM)
_(ROSEBUSH)
_(LEEK)
_(EGGPLANT)
_(CERISE)
_(CRANBERRY)
_(PEPPER)
_(MAHOGANY)
_(BLAZING)
_(GARNET)
_(PEACHY)
_(QUAIL)
_(LANTERN)
_(FOUNDATION)
_(BURNING)
_(APRICOT)
_(SANDY)
_(SUNFLOWER)
_(OLIVINE)
_(APPLE)
_(SEAFOAM)
_(FOREST)
_(TOPAZ)
_(FROST)
_(WAVE)
_(ICY)
_(PEACOCK)
_(VAPOR)
_(GEMSTONE)
_(NEON)
_(PLUM)
_(DIAMOND) // custom color expansion begins here
_(RAVEN)
_(MUD)
_(EARTHWORM)
_(YOGURT)
_(PEARL)
_(STRAWBERRY)
_(SODA)
_(BLOODCELL)
_(MAHOGANY)
_(FIERY)
_(SPICE)
_(KING)
_(HOTDOG)
_(CARNATION)
_(CANDY)
_(NEBULA)
_(STEAMPUNK)
_(AMBER)
_(CARROT)
_(CHEESE)
_(DUNE)
_(BRASS)
_(CITRINE)
_(SANDY)
_(LEMON)
_(CASKET)
_(PEAR)
_(GECKO)
_(VENOM)
_(APPLE)
_(HEADLIGHT)
_(CHARTREUSE)
_(FOREST)
_(JADE)
_(MASTER)
_(HARLEQUIN)
_(SEAFOAM)
_(ISLAND)
_(BOTTLE)
_(OCEAN)
_(WAVE)
_(FROST)
_(VACATION)
_(HYDRO)
_(SKY)
_(MARINE)
_(DEPTHS)
_(FANTASY)
_(ICY)
_(DAYBREAK)
_(ARCTIC)
_(CORNFLOWER)
_(COBALT)
_(NIGHTFALL)
_(GALAXY)
_(VAPOR)
_(MAJESTY)
_(NOBLE)
_(BERRY)
_(SIBERITE)
_(NEON)
_(GRAPE)
_(ARISTOCRAT)
_(BLOOM)
_(MALLOW)
_(EVENTIDE)
_(PLUM)
_(PUNCH)
_(FLAMINGO)
_(FANCY)
_(SANGRIA)
_(VOLCANIC)
// Custom Color Expansion
// Featuring all new colors to best match Kart and Ring Racers
_(IVORY)
_(ABYSS)
_(DIAMOND)
_(RAVEN)
_(NOIR)
_(VANILLA)
_(FIREFLY)
_(COFFEE)
_(CHOCOLATE)
_(DUST)
_(HICKORY)
_(PEARL)
_(ROSEGOLD)
_(DRAGONFRUIT)
_(STRAWBERRY)
_(AMARANTH)
_(PARROT)
_(SODA)
_(VERMILLION)
_(WINE)
_(BLOODCELL)
_(SYRUP)
_(SUNBURST)
_(GRAPEFRUIT)
_(DEEPFRY)
_(SENTINEL)
_(FIERY)
_(AUTUMN)
_(SPICE)
_(SUMMER)
_(HALLOWEEN)
_(DUNE)
_(CHEESE)
_(CARROT)
_(TIGER)
_(SIENNA)
_(AMBER)
_(STEAMPUNK)
_(BLONDE)
_(DRAVITE)
_(CANARY)
_(HORNET)
_(MOON)
_(KHAKI)
_(LIGHT)
_(PEPPERMINT)
_(PYRAMID)
_(LASER)
_(ASPARAGUS)
_(DANDELION)
_(SAGE)
_(JUNGLE)
_(PLANTATION)
_(SCIENCE)
_(WILD)
_(JUNIPER)
_(PEPPERMINT)
_(SPRING)
_(IGUANA)
_(AVOCADO)
_(ARMY)
_(CROW)
_(CHARTEUSE)
_(SLIME)
_(DIANNE)
_(BEAN)
_(CLOVER)
_(LEAF)
_(JUNGLE)
_(EVERGREEN)
_(TROPIC)
_(IGUANA)
_(SOUR)
_(SLIME)
_(WATERMELON)
_(MIAMI)
_(SPEARMINT)
_(PATINA)
_(LAKESIDE)
_(CAPRI)
_(ELECTRIC)
_(PEGASUS)
_(PLASMA)
_(COMET)
_(LIGHTNING)
_(VACATION)
_(DEPTHS)
_(DIANNE)
_(EXOTIC)
_(SNOW)
_(MOON)
_(PIPEWORK)
_(SACRAMENTO)
_(EVERGREEN)
_(CHILL)
_(PEACOCK)
_(WINTER)
_(MECHA)
_(POLAR)
_(COTTONCANDY)
_(SNOWMAN)
_(CRYSTAL)
_(WATERSTONE)
_(LUNAR)
_(ONYX)
_(ASTRONAUT)
_(COMET)
_(MINSK)
_(LAPIS)
_(ORCA)
_(STORM)
_(COTTONCANDY) // this color was a pain to get right
_(CYBER) // this one too
_(GROWTH)
_(NOCTURNE)
_(ZIRCON)
_(ORCHID)
_(EMPERESS)
_(NIGHTWALK)
_(AMETHYST)
_(IRIS)
_(GOTHIC)
_(GRAPE)
_(INDIGO)
_(CORDOVAN)
_(SAKURA)
_(DISCO)
_(MULBERRY)
_(BOYSENBERRY)
_(MYSTIC)
_(VELOUR)
_(WICKED)
_(GLAMOUR)
_(UNICORN)
_(SUPER1) // Super Sonic Yellow
// Super Colors
// Currently not implemented, using SRB2K's as a placeholder
_(SUPER1)
_(SUPER2)
_(SUPER3)
_(SUPER4)
_(SUPER5)
_(TSUPER1) // Super Tails Orange
_(TSUPER1)
_(TSUPER2)
_(TSUPER3)
_(TSUPER4)
_(TSUPER5)
_(KSUPER1) // Super Knuckles Red
_(KSUPER1)
_(KSUPER2)
_(KSUPER3)
_(KSUPER4)
_(KSUPER5)
_(PSUPER1) // Hyper Sonic Pink
_(PSUPER1)
_(PSUPER2)
_(PSUPER3)
_(PSUPER4)
_(PSUPER5)
_(BSUPER1) // Hyper Sonic Blue
_(BSUPER1)
_(BSUPER2)
_(BSUPER3)
_(BSUPER4)
_(BSUPER5)
_(ASUPER1) // Aqua Super
_(ASUPER1)
_(ASUPER2)
_(ASUPER3)
_(ASUPER4)
_(ASUPER5)
_(GSUPER1) // Hyper Sonic Green
_(GSUPER1)
_(GSUPER2)
_(GSUPER3)
_(GSUPER4)
_(GSUPER5)
_(WSUPER1) // Hyper Sonic White
_(WSUPER1)
_(WSUPER2)
_(WSUPER3)
_(WSUPER4)
_(WSUPER5)
_(CSUPER1) // Creamy Super (Shadow?)
_(CSUPER1)
_(CSUPER2)
_(CSUPER3)
_(CSUPER4)

View file

@ -7,8 +7,6 @@ _(UNKN)
_(THOK) // Thok! mobj
_(PLAY)
_(KART)
_(TIRE)
// Enemies
_(POSS) // Crawla (Blue)

View file

@ -48,9 +48,6 @@ _(KART_SIGN)
// technically the player goes here but it's an infinite tic state
_(OBJPLACE_DUMMY)
_(KART_LEFTOVER)
_(KART_TIRE)
// Blue Crawla
_(POSS_STND)
_(POSS_RUN1)

View file

@ -55,6 +55,20 @@ boolean K_IsPlayerWanted(player_t *player)
return false;
}
boolean K_IsPlayerMostWanted(player_t *player)
{
if (mostwanted == -1)
return false;
if (!(gametyperules & GTR_WANTEDSPB))
return false;
if (player == &players[mostwanted])
return true;
return false;
}
void K_CalculateBattleWanted(void)
{
UINT8 numingame = 0, numwanted = 0;
@ -62,6 +76,8 @@ void K_CalculateBattleWanted(void)
UINT8 ties = 0, nextcamppos = 0;
UINT8 i, j;
mostwanted = -1;
if (!(gametyperules & GTR_WANTED))
{
memset(battlewanted, -1, sizeof (battlewanted));
@ -162,6 +178,10 @@ void K_CalculateBattleWanted(void)
if (ties < (numwanted-i)) // Is it still low enough after counting?
{
battlewanted[i] = camppos[nextcamppos];
if (!nextcamppos)
mostwanted = battlewanted[i];
nextcamppos++;
}
else

View file

@ -14,6 +14,7 @@ extern UINT8 numtargets;
INT32 K_StartingBumperCount(void);
boolean K_IsPlayerWanted(player_t *player);
boolean K_IsPlayerMostWanted(player_t *player);
void K_CalculateBattleWanted(void);
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount);
void K_CheckBumpers(void);

View file

@ -394,7 +394,7 @@ boolean K_BHeapPush(bheap_t *const heap, void *const item, UINT32 value, updatei
if (heap->count >= heap->capacity)
{
size_t newarraycapacity = heap->capacity * 2;
heap->array = Z_Realloc(heap->array, newarraycapacity, PU_STATIC, NULL);
heap->array = Z_Realloc(heap->array, newarraycapacity * sizeof(bheapitem_t), PU_STATIC, NULL);
if (heap->array == NULL)
{

View file

@ -80,6 +80,8 @@ void K_DrawBotDebugger(const player_t *player)
V_DrawThinString(x2, y+32, vflags|(bd->driftlockout ? V_ORANGEMAP : 0), va("driftlockout: %d", bd->driftlockout));
V_DrawThinString(x1, y+40, vflags, va("driftturn: %d", bd->driftturn));
V_DrawThinString(x2, y+40, vflags, va("drifttime: %d", bd->drifttime));
V_DrawThinString(x1, y+48, vflags, va("preditionerror: %d", bd->predictionerror));
V_DrawThinString(x2, y+48, vflags|(bd->griplockout ? V_ORANGEMAP : 0), va("griplockout: %d", bd->griplockout));
}
/*--------------------------------------------------
@ -257,14 +259,7 @@ void K_UpdateMatchRaceBots(void)
else
{
difficulty = cv_kartbot.value;
if (netgame)
{
pmax = std::min<UINT8>(pmax, static_cast<UINT8>(cv_maxplayers.value));
}
if (cv_ingamecap.value > 0)
{
pmax = std::min<UINT8>(pmax, static_cast<UINT8>(cv_ingamecap.value));
}
pmax = std::min<UINT8>(pmax, static_cast<UINT8>(cv_kartbot_cap.value));
}
for (i = 0; i < MAXPLAYERS; i++)
@ -362,7 +357,7 @@ void K_UpdateMatchRaceBots(void)
{
UINT16 index = P_RandomKey(usableskins);
skinnum = grabskins[index];
if (((cv_ingamecap.value > 0) && (usableskins+1 >= cv_ingamecap.value)) || (usableskins+1 >= cv_maxplayers.value))
if (((cv_kartbot_cap.value > 0) && (usableskins+1 >= cv_kartbot_cap.value)) || (usableskins+1 >= cv_maxplayers.value))
{
grabskins[index] = grabskins[--usableskins];
}
@ -555,6 +550,9 @@ botcontroller_t *K_GetBotController(const mobj_t *mobj)
--------------------------------------------------*/
fixed_t K_BotMapModifier(void)
{
// fuck it we ball
return 5*FRACUNIT/10;
constexpr INT32 complexity_scale = 10000;
fixed_t modifier_max = K_TrackModifierMax();
@ -1231,6 +1229,8 @@ static INT32 K_HandleBotTrack(botdata_t *bd, const player_t *player, angle_t des
moveangle = player->mo->angle;
anglediff = AngleDeltaSigned(moveangle, destangle);
bd->predictionerror = std::min(destangle - moveangle, moveangle - destangle);
// line up for an incoming drift
if (bd->driftstate == DRIFTSTATE_STARTING)
{
@ -1300,6 +1300,26 @@ static INT32 K_HandleBotTrack(botdata_t *bd, const player_t *player, angle_t des
bd->acceldown = true;
bd->brakedown = false;
// Additional grip for turns.
if ((player->speed > K_GetKartSpeed(player, false, false)/2) && !bd->griplockout)//35*FRACUNIT
{
const angle_t MAXERROR = ANGLE_45;
const angle_t MIDERROR = ANGLE_22h;
if (bd->predictionerror > MAXERROR && bd->driftstate == DRIFTSTATE_AUTO)
{
bd->acceldown = false;
bd->brakedown = true;
}
else if (bd->predictionerror > MIDERROR && bd->driftstate == DRIFTSTATE_AUTO)
{
bd->brakedown = true;
}
}
if (bd->griplockout > 0)
bd->griplockout--;
if (dirdist <= rad
&& bd->driftstate != DRIFTSTATE_STARTING) // steer towards waypoints when starting drift
{
@ -1334,6 +1354,8 @@ static INT32 K_HandleBotTrack(botdata_t *bd, const player_t *player, angle_t des
turnvalue = 541 - (turnvalue - 541); // weight 5 = 541
turnamt = std::clamp(FixedMul(driftpower, turnvalue), -KART_FULLTURN, KART_FULLTURN);
bd->griplockout = 6;
}
/*
else if ((turnamt) && (bd->driftstate == DRIFTSTATE_AUTO) &&
@ -1618,6 +1640,26 @@ void K_BotTicker(const player_t *player)
forcedDir = true;
}
if (P_IsObjectOnGround(player->mo) == false)
{
if (player->airdroptime == 0
&& K_AirDropActive()
&& !P_PlayerInPain(player)
&& !player->loop.radius
&& !(player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT)
&& !player->respawn)
{
if (botController != nullptr && (botController->flags & TMBOT_AIRDROP) == TMBOT_AIRDROP)
{
// Air Drop!
bd->brakedown = true;
return;
}
}
//return; // Don't allow bots to turn in the air.
}
if (forcedDir == true)
{
destangle = R_PointToAngle2(player->mo->x, player->mo->y, bd->predict.x, bd->predict.y);
@ -1663,12 +1705,15 @@ void K_BotTicker(const player_t *player)
ps_bots[player - players].item = I_GetPreciseTime() - t;
}
// Update turning quicker if we're moving at high speeds.
UINT8 turndelta = (player->speed > (7 * K_GetKartSpeed(player, false, false) / 4)) ? 2 : 1;
if (turnamt > 0)
{
// Count up
if (bd->turnconfirm < BOTTURNCONFIRM)
{
bd->turnconfirm++;
bd->turnconfirm += turndelta;
}
}
else if (turnamt < 0)
@ -1676,7 +1721,7 @@ void K_BotTicker(const player_t *player)
// Count down
if (bd->turnconfirm > -BOTTURNCONFIRM)
{
bd->turnconfirm--;
bd->turnconfirm -= turndelta;
}
}
else
@ -1684,11 +1729,11 @@ void K_BotTicker(const player_t *player)
// Back to neutral
if (bd->turnconfirm < 0)
{
bd->turnconfirm++;
bd->turnconfirm += turndelta;
}
else if (bd->turnconfirm > 0)
{
bd->turnconfirm--;
bd->turnconfirm -= turndelta;
}
}
@ -1777,7 +1822,10 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
}
// BOT_STYLE_NORMAL is the only other style, so...
cmd->forwardmove = !!bd->acceldown * MAXPLMOVE - !!bd->brakedown * MAXPLMOVE/2;
SINT8 maxacceldown = (!!bd->acceldown * MAXPLMOVE);
SINT8 maxbrakedown = !!bd->brakedown * MAXPLMOVE/2;
cmd->forwardmove = maxacceldown - maxbrakedown;
if (bd->itemthrow != 0)
{
cmd->throwdir = bd->itemthrow * KART_FULLTURN;

View file

@ -98,6 +98,9 @@ struct botdata_t
boolean itemwasdown; // last tic's item button
SINT8 itemthrow; // throwdir
INT16 turnamt; // turning
angle_t predictionerror; // How bad is our momentum angle relative to where we're trying to go?
angle_t griplockout; // When you need to prevent grip braking, use this.
};
// AVAILABLE FOR LUA

View file

@ -29,6 +29,7 @@
#include "m_random.h"
#include "r_things.h" // numskins
#include "m_easing.h"
#include "k_odds.h"
// Looks for players around the bot, and presses the item button
// if there is one in range.
@ -960,6 +961,11 @@ static void K_BotItemFlame(botdata_t *bd, const player_t *player)
{
ZoneScoped;
if (player->flametimer >= (itemtime*3)-5)
{
bd->itemdelay = 5;
}
if (P_IsObjectOnGround(player->mo) == false)
{
// Drain itemdelay as needed so theres no delay when landing.

View file

@ -233,10 +233,22 @@ void K_InitBrightmapsPwad(INT32 wadNum)
break;
}
texNum = R_CheckTextureNumForName(bms->textureName);
texNum = R_CheckTextureNumForName(bms->textureName, TEXTURETYPE_TEXTURE);
if (texNum == -1)
{
texNum = R_CheckTextureNumForName(bms->textureName, TEXTURETYPE_FLAT);
}
if (texNum != -1)
{
bmNum = R_CheckTextureNumForName(bms->brightmapName);
bmNum = R_CheckTextureNumForName(bms->brightmapName, TEXTURETYPE_TEXTURE);
if (bmNum == -1)
{
bmNum = R_CheckTextureNumForName(bms->brightmapName, TEXTURETYPE_FLAT);
}
R_UpdateTextureBrightmap(texNum, (bmNum == -1 ? 0 : bmNum));
}
}

View file

@ -7,6 +7,7 @@
#include "doomtype.h"
#include "p_mobj.h"
#include "k_kart.h"
#include "k_odds.h"
#include "p_local.h"
#include "s_sound.h"
#include "r_main.h" // R_PointToAngle2, R_PointToDist2
@ -56,6 +57,8 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
if (t2->player)
{
if (t2->player->flashing && !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ))
return true;
if (t2->player->hyudorotimer)
return true; // no interaction
@ -542,11 +545,17 @@ static void K_BubbleShieldCollideDrain(player_t *player, mobj_t *bubble)
}
}
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2, boolean isplayer)
{
mobj_t *owner = t1->player ? t1 : t1->target;
INT32 div = 2;
if (!t2->threshold)
if (isplayer)
{
div = 1;
}
if ((!t2->threshold)||(isplayer))
{
if (!t2->momx && !t2->momy)
{
@ -554,15 +563,23 @@ boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
}
else
{
t2->momx = (-1*t2->momx)/2;
t2->momy = (-1*t2->momy)/2;
t2->momz = (-1*t2->momz)/2;
t2->angle += ANGLE_180;
t2->momx = (-1*t2->momx)/div;
t2->momy = (-1*t2->momy)/div;
t2->momz = (-1*t2->momz)/div;
if (!isplayer)
{
t2->angle += ANGLE_180;
}
}
if (!isplayer)
{
if (t2->type == MT_JAWZ)
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
P_SetTarget(&t2->target, owner); // Let the source reflect it back again!
t2->threshold = 10;
}
if (t2->type == MT_JAWZ)
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
P_SetTarget(&t2->target, owner); // Let the source reflect it back again!
t2->threshold = 10;
S_StartSound(t1, sfx_s3k44);
}
@ -574,26 +591,37 @@ boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2)
return (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD
|| t2->type == MT_BANANA || t2->type == MT_EGGMANITEM || t2->type == MT_BALLHOG
|| t2->type == MT_SSMINE || t2->type == MT_LANDMINE || t2->type == MT_SINK
|| t2->type == MT_KART_LEFTOVER
|| (t2->type == MT_PLAYER && t1->target != t2));
}
static boolean K_PlayerCanBeBubbleBumped(player_t *player)
{
return (((K_GetKartInvinType() == KARTINVIN_LEGACY) && (player->invincibilitytimer))
|| (player->growshrinktimer > 0));
}
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
{
if (t2->type == MT_PLAYER)
{
// Ignore players.
return true;
boolean bumpme = ((t2->player) && (K_PlayerCanBeBubbleBumped(t2->player)));
if (!bumpme)
{
// Ignore non-bumpable players.
return true;
}
}
if (K_BubbleShieldCanReflect(t1, t2))
{
if (!t2->threshold)
if ((!t2->threshold)||(t2->player))
{
// Drain my stuff please.
K_BubbleShieldCollideDrain(t1->target->player, t1);
}
return K_BubbleShieldReflect(t1, t2);
return K_BubbleShieldReflect(t1, t2, (t2->player) ? true : false);
}
if (t2->flags & MF_SHOOTABLE)

View file

@ -17,7 +17,7 @@ boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2);
boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2);
void K_ThunderShieldAttack(mobj_t *actor, fixed_t size);
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2);
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2, boolean isplayer);
boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2);
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);

View file

@ -20,12 +20,12 @@
UINT16 altinvinccolors[16] = {
SKINCOLOR_BLOODCELL, // 0
SKINCOLOR_FUCHSIA, // 1
SKINCOLOR_LANTERN, // 2
SKINCOLOR_MOON, // 2
SKINCOLOR_FIERY, // 3
SKINCOLOR_FLAME, // 4
SKINCOLOR_APRICOT, // 5
SKINCOLOR_GARDEN, // 6
SKINCOLOR_OLIVINE, // 7
SKINCOLOR_OLIVE, // 7
SKINCOLOR_LIME, // 8
SKINCOLOR_EMERALD, // 9
SKINCOLOR_NAVY, // 10

View file

@ -53,6 +53,8 @@ struct follower_t
{
char skinname[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything.
char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this.
char icon[8+1]; // Lump names are only 8 characters. (+1 for \0)
skincolornum_t defaultcolor; // default color for menus.
followermode_t mode; // Follower behavior modifier.

File diff suppressed because it is too large Load diff

View file

@ -41,6 +41,8 @@ IMPL_HUD_OFFSET(rings); // Number of rings
IMPL_HUD_OFFSET(dnft); // Countdown (did not finish timer)
IMPL_HUD_OFFSET(speed); // Speedometer
IMPL_HUD_OFFSET(acce); // Accessibility
IMPL_HUD_OFFSET(timers); // Drafting
IMPL_HUD_OFFSET(draft); // Drafting
IMPL_HUD_OFFSET(posi); // Position in race
IMPL_HUD_OFFSET(face); // Mini rankings
IMPL_HUD_OFFSET(stcd); // Starting countdown
@ -91,6 +93,7 @@ void K_getItemBoxDrawinfo(drawinfo_t *out);
void K_getLapsDrawinfo(drawinfo_t *out);
void K_getRingsDrawinfo(drawinfo_t *out);
void K_getMinimapDrawinfo(drawinfo_t *out);
void K_getSlipstreamDrawinfo(drawinfo_t *out);
const char *K_GetItemPatch(UINT8 item, boolean tiny);
void K_ReloadHUDColorCvar(void);
boolean K_UseColorHud(void);
@ -103,7 +106,7 @@ INT32 K_DrawNeoTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines
void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol);
#define MAXSERVERMODS 255
#define MAXSERVERMODNAME 13
#define MAXSERVERMODNAME 14
struct servermods_t
{

File diff suppressed because it is too large Load diff

View file

@ -68,9 +68,6 @@ extern boolean clusterplayer[MAXPLAYERS];
extern UINT32 clusterid; // ID of the "cluster player", the one closest to the cluster point.
extern vector3_t clusterpoint, clusterdtf;
// :)
#define MAXODDS 8
// Bubble Shield's maximum health
#define MAXBUBBLEHEALTH 6
@ -125,6 +122,10 @@ extern vector3_t clusterpoint, clusterdtf;
#define STARTACCELBOOST K_RAGuard(cv_kartstacking_start_accelboost)
#define STARTSTACKABLE K_RAGuard(cv_kartstacking_start_stackable)
#define WALLTRANSFERSPEEDBOOST K_RAGuard(cv_kartstacking_walltransfer_speedboost)
#define WALLTRANSFERACCELBOOST K_RAGuard(cv_kartstacking_walltransfer_accelboost)
#define WALLTRANSFERSTACKABLE K_RAGuard(cv_kartstacking_walltransfer_stackable)
#define DRIFTSPEEDBOOST K_RAGuard(cv_kartstacking_drift_speedboost)
#define DRIFTACCELBOOST K_RAGuard(cv_kartstacking_drift_accelboost)
#define DRIFTSTACKABLE K_RAGuard(cv_kartstacking_drift_stackable)
@ -189,19 +190,6 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player);
boolean K_IsPlayerLosing(player_t *player);
fixed_t K_GetKartGameSpeedScalar(SINT8 value);
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb);
fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, UINT32 clusterDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival);
INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t clusterDist, fixed_t mashed, boolean spbrush);
INT32 K_GetRollingRouletteItem(player_t *player);
INT32 K_GetShieldFromPlayer(player_t *player);
INT32 K_GetShieldFromItem(INT32 item);
SINT8 K_ItemResultToType(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem);
fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against);
boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid);
void K_KartPainEnergyFling(player_t *player);
@ -209,7 +197,6 @@ void K_FlipFromObject(mobj_t *mo, mobj_t *master);
void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master);
void K_GenericExtraFlagsNoZAdjust(mobj_t *mo, mobj_t *master);
void K_SpawnDashDustRelease(player_t *player);
void K_SpawnDriftBoostClip(player_t *player);
void K_SpawnNormalSpeedLines(player_t *player);
void K_SpawnDraftSpeedLines(player_t *player, fixed_t scale, skincolornum_t color, boolean translucent);
void K_SpawnInvincibilitySpeedLines(mobj_t *mo);
@ -222,6 +209,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);
void K_KartPlayerAfterThink(player_t *player);
angle_t K_MomentumAngle(mobj_t *mo);
void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload);
void K_HandleRaceSplits(player_t *player, tic_t time, UINT8 checkpoint);
void K_DoInstashield(player_t *player);
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved);
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type);
@ -270,8 +258,7 @@ void K_SetRespawnAtNextWaypoint(player_t * player);
INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue);
INT32 K_GetKartDriftSparkValue(const player_t *player);
INT32 K_GetKartDriftSparkValueForStage(const player_t *player, UINT8 stage);
void K_SpawnDriftBoostExplosion(player_t *player, int stage);
void K_SpawnDriftElectricSparks(player_t *player);
UINT8 K_GetKartDriftSparkStageForValue(const player_t *player, INT32 value);
INT32 K_GetDriftAngleOffset(player_t *player);
void K_KartUpdatePosition(player_t *player);
void K_KartLegacyUpdatePosition(player_t *player);
@ -324,6 +311,9 @@ void K_PlayHitEmSound(mobj_t *source, mobj_t *other);
void K_TryHurtSoundExchange(mobj_t *victim, mobj_t *attacker);
void K_PlayPowerGloatSound(mobj_t *source);
INT32 K_GetShieldFromPlayer(player_t *player);
INT32 K_GetShieldFromItem(INT32 item);
void K_SetItemOut(player_t *player);
void K_UnsetItemOut(player_t *player);
@ -336,7 +326,9 @@ boolean K_ChainingActive(void);
boolean K_SlipdashActive(void);
boolean K_SlopeBoostActive(void);
boolean K_DraftingActive(void);
boolean K_AirDropActive(void);
boolean K_GetKartInvinType(void);
INT32 K_GetBumpSpark(void);
boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound);
INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound);
boolean K_UsingLegacyCheckpoints(void);
@ -345,6 +337,7 @@ INT32 K_CheckpointThreshold(boolean roundup);
void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount);
fixed_t K_BoostRescale(fixed_t value,fixed_t oldmin,fixed_t oldmax,fixed_t newmin,fixed_t newmax);
void K_DoBoost(player_t *player, fixed_t speedboost, fixed_t accelboost, boolean stack, boolean visible);
void K_ClearBoost(player_t *player);
@ -359,6 +352,14 @@ void K_AwardScaledPlayerRings(player_t *player, SINT8 mode);
void K_QuiteSaltyHop(player_t *player);
typedef enum
{
BUMPSPARK_NONE = 0,
BUMPSPARK_NOCHARGE,
BUMPSPARK_RESET100, // Reset to 100 (blue); the Sunflower's Garden system
BUMPSPARK_ALL
} bumpsparktype_t;
#ifdef __cplusplus
} // extern "C"
#endif

1283
src/k_odds.c Normal file

File diff suppressed because it is too large Load diff

53
src/k_odds.h Normal file
View file

@ -0,0 +1,53 @@
// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2025 by Kart Krew.
// Copyright (C) 2025 by "Anonimus".
// Copyright (C) 2025 Blankart Team.
//
// 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 k_odds.hpp
/// \brief Kart item odds systems.
#ifndef __K_ODDS__
#define __K_ODDS__
#include "command.h" // Need for player_t
#include "doomdef.h"
#include "doomtype.h"
#include "d_player.h" // Need for player_t
#include "d_ticcmd.h"
#include "m_fixed.h"
#include "k_kart.h" // K_RAGuard
#ifdef __cplusplus
extern "C" {
#endif
// Max odds count
#define MAXODDS 16
// Distance variables
#define DISTVAR K_RAGuard(cv_kartoddsdist)
#define DISTVAR_LEGACY K_RAGuard(cv_kartlegacyoddsdist)
#define SPBDISTVAR K_RAGuard(cv_kartspbdist)
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame);
UINT32 K_CalculatePDIS(const player_t *player, UINT8 numPlayers, boolean *spbrush);
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, UINT32 clusterDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival);
INT32 K_GetRollingRouletteItem(player_t *player);
SINT8 K_ItemResultToType(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem);
void K_KartItemRoulette(player_t *player, ticcmd_t *cmd);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __K_ODDS__

View file

@ -956,7 +956,7 @@ static void K_SpawnFootstepParticle(mobj_t *mo, t_footstep_t *fs, tic_t timer)
if (mo->player != NULL)
{
boolean karmabomb = ((gametyperules & GTR_KARMA) && mo->player->bumper <= 0);
boolean karmabomb = ((gametyperules & GTR_BUMPERS) && mo->player->bumper <= 0);
tireAngle = (mo->player->drawangle + ANGLE_180);
speedValue = K_GetKartSpeedFromStat(mo->player->kartspeed, karmabomb);
}
@ -2136,7 +2136,13 @@ static boolean K_TERRAINLumpParser(char *data, size_t size)
f->terrainID = K_GetTerrainHeapIndex(t);
CONS_Printf("Texture '%s' set to Terrain '%s'\n", f->textureName, tkn);
INT32 tex = R_CheckTextureNumForName(f->textureName);
INT32 tex = R_CheckTextureNumForName(f->textureName, TEXTURETYPE_TEXTURE);
if (tex == -1)
{
R_CheckTextureNumForName(f->textureName, TEXTURETYPE_FLAT);
}
if (tex != -1)
{
textures[tex]->terrainID = f->terrainID;

View file

@ -191,8 +191,6 @@ static const struct {
{META_NODE, "node_t"},
#endif
{META_SLOPE, "slope_t"},
{META_VECTOR2, "vector2_t"},
{META_VECTOR3, "vector3_t"},
{META_MAPHEADER, "mapheader_t"},
{META_POLYOBJ, "polyobj_t"},
@ -245,6 +243,11 @@ static const struct {
{META_OVERLAY, "t_overlay_t"},
{META_TERRAIN, "terrain_t"},
{META_VECTOR2, "vector2_t"},
{META_VECTOR3, "vector3_t"},
{META_MATRIX, "matrix_t"},
{META_QUATERNION, "quaternion_t"},
{NULL, NULL}
};
@ -2552,7 +2555,10 @@ static int lib_rCheckTextureNumForName(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_CheckTextureNumForName(name));
INT32 num = R_CheckTextureNumForName(name, TEXTURETYPE_TEXTURE);
if (num == -1)
num = R_CheckTextureNumForName(name, TEXTURETYPE_FLAT);
lua_pushinteger(L, num);
return 1;
}
@ -4167,6 +4173,13 @@ static int lib_kDraftingActive(lua_State *L)
return 1;
}
// Checks if Air Drop is active.
static int lib_kAirDropActive(lua_State *L)
{
lua_pushboolean(L, K_AirDropActive());
return 1;
}
// Grabs the currently active invintype.
static int lib_kGetKartInvinType(lua_State *L)
{
@ -4174,6 +4187,13 @@ static int lib_kGetKartInvinType(lua_State *L)
return 1;
}
// Gets the currently active bumpspark type.
static int lib_kGetBumpSpark(lua_State *L)
{
lua_pushinteger(L, K_GetBumpSpark());
return 1;
}
// Checks if current map is using legacy boss3 bassed checkpoints. Useful for map compat.
static int lib_kUsingLegacyCheckpoints(lua_State *L)
{
@ -5263,6 +5283,8 @@ static luaL_Reg lib[] = {
{"K_SlipdashActive",lib_kSlipdashActive},
{"K_SlopeBoostActive",lib_kSlopeBoostActive},
{"K_DraftingActive",lib_kDraftingActive},
{"K_AirDropActive",lib_kAirDropActive},
{"K_GetBumpSpark",lib_kGetBumpSpark},
{"K_GetKartInvinType",lib_kGetKartInvinType},
{"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints},
{"K_DoBoost",lib_kDoBoost},

View file

@ -169,68 +169,70 @@ static int botdata_get(lua_State *L)
{
case botdata_valid:
lua_pushboolean(L, botdata != NULL);
return 1;
break;
case botdata_itemdelay:
lua_pushinteger(L, botdata->itemdelay);
return 1;
break;
case botdata_itemconfirm:
lua_pushinteger(L, botdata->itemconfirm);
return 1;
break;
case botdata_turnconfirm:
lua_pushinteger(L, botdata->turnconfirm);
return 1;
break;
case botdata_respawnconfirm:
lua_pushinteger(L, botdata->respawnconfirm);
return 1;
break;
case botdata_driftstate:
lua_pushinteger(L, botdata->driftstate);
return 1;
break;
case botdata_driftturn:
lua_pushinteger(L, botdata->driftturn);
return 1;
break;
case botdata_drifttime:
lua_pushinteger(L, botdata->drifttime);
return 1;
break;
case botdata_driftlockout:
lua_pushinteger(L, botdata->driftlockout);
return 1;
break;
case botdata_driftmaxdist:
lua_pushinteger(L, botdata->driftmaxdist);
return 1;
break;
case botdata_driftpowerdiv:
lua_pushinteger(L, botdata->driftpowerdiv);
return 1;
break;
case botdata_driftstatedelay:
lua_pushinteger(L, botdata->driftstatedelay);
return 1;
break;
case botdata_driftskill:
lua_pushfixed(L, botdata->driftskill);
return 1;
break;
case botdata_acceldown:
lua_pushboolean(L, botdata->acceldown);
return 1;
break;
case botdata_brakedown:
lua_pushboolean(L, botdata->brakedown);
return 1;
break;
case botdata_driftdown:
lua_pushboolean(L, botdata->driftdown);
return 1;
break;
case botdata_itemdown:
lua_pushboolean(L, botdata->itemdown);
return 1;
break;
case botdata_dolookback:
lua_pushboolean(L, botdata->dolookback);
return 1;
break;
case botdata_itemwasdown:
lua_pushboolean(L, botdata->itemwasdown);
return 1;
break;
case botdata_itemthrow:
lua_pushinteger(L, botdata->itemthrow);
return 1;
break;
case botdata_turnamt:
lua_pushinteger(L, botdata->turnamt);
return 1;
break;
}
return 1;
}
#define NOSET luaL_error(L, LUA_QL("botdata_t") " field " LUA_QS " should not be set directly.", botdata_opt[field])
@ -248,65 +250,67 @@ static int botdata_set(lua_State *L)
return NOSET;
case botdata_itemdelay:
botdata->itemdelay = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_itemconfirm:
botdata->itemconfirm = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_turnconfirm:
botdata->turnconfirm = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_respawnconfirm:
botdata->respawnconfirm = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftstate:
botdata->driftstate = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftturn:
botdata->driftturn = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_drifttime:
botdata->drifttime = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftlockout:
botdata->driftlockout = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftmaxdist:
botdata->driftmaxdist = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftpowerdiv:
botdata->driftpowerdiv = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftstatedelay:
botdata->driftstatedelay = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_driftskill:
botdata->driftskill = luaL_checkfixed(L, 3);
return 0;
break;
case botdata_acceldown:
botdata->acceldown = luaL_checkboolean(L, 3);
return 0;
break;
case botdata_brakedown:
botdata->brakedown = luaL_checkboolean(L, 3);
return 0;
break;
case botdata_driftdown:
botdata->driftdown = luaL_checkboolean(L, 3);
return 0;
break;
case botdata_itemdown:
botdata->itemdown = luaL_checkboolean(L, 3);
return 0;
break;
case botdata_dolookback:
botdata->dolookback = luaL_checkboolean(L, 3);
return 0;
break;
case botdata_itemwasdown:
botdata->itemwasdown = luaL_checkboolean(L, 3);
return 0;
break;
case botdata_itemthrow:
botdata->itemthrow = luaL_checkinteger(L, 3);
return 0;
break;
case botdata_turnamt:
botdata->turnamt = luaL_checkinteger(L, 3);
return 0;
break;
}
return 0;
}
#undef NOSET

View file

@ -34,6 +34,7 @@
#include "lua_hook.h"
#include "k_hud.h"
#include "h_timers.h"
#define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!");
@ -749,7 +750,7 @@ static int libd_drawOnMinimap(lua_State *L)
if (gamestate != GS_LEVEL)
return 0;
if (stplyr != &players[displayplayers[0]])
if (stplyrnum != 0)
return 0;
if (minimapinfo.minimap_pic == NULL)
@ -1128,9 +1129,29 @@ static int libd_getColormap(lua_State *L)
{
if (skinnum >= MAXSKINS)
return luaL_error(L, "skin number %d is out of range (>%d)", skinnum, MAXSKINS-1);
else if (skinnum < 0 && skinnum > TC_DEFAULT)
else if (skinnum < -6 && !(skinnum >= TC_BOSS && skinnum <= TC_DEFAULT))
return luaL_error(L, "translation colormap index is out of range");
switch(skinnum)
{
skinnum = TC_DEFAULT;
case -6:
skinnum = TC_BLINK;
break;
case -5:
skinnum = TC_RAINBOW;
break;
case -4:
skinnum = TC_ALLWHITE;
break;
case -3:
skinnum = TC_METALSONIC;
break;
case -2:
skinnum = TC_BOSS;
break;
case -1:
skinnum = TC_DEFAULT;
break;
}
}
else
@ -1367,7 +1388,9 @@ enum huddrawinfo {
huddrawinfo_item = 0,
huddrawinfo_gametypeinfo,
huddrawinfo_rings,
huddrawinfo_minimap
huddrawinfo_minimap,
huddrawinfo_timers,
huddrawinfo_drafting,
};
static const char *const hud_drawinfo_options[] = {
@ -1375,6 +1398,8 @@ static const char *const hud_drawinfo_options[] = {
"gametypeinfo",
"rings",
"minimap",
"timers",
"drafting",
NULL};
static int libd_getDrawInfo(lua_State *L)
@ -1384,10 +1409,12 @@ static int libd_getDrawInfo(lua_State *L)
drawinfo_t info;
switch(option) {
case huddrawinfo_item: K_getItemBoxDrawinfo(&info); break;
case huddrawinfo_gametypeinfo: K_getLapsDrawinfo(&info); break;
case huddrawinfo_rings: K_getRingsDrawinfo(&info); break;
case huddrawinfo_minimap: K_getMinimapDrawinfo(&info); break;
case huddrawinfo_item: K_getItemBoxDrawinfo(&info); break;
case huddrawinfo_gametypeinfo: K_getLapsDrawinfo(&info); break;
case huddrawinfo_rings: K_getRingsDrawinfo(&info); break;
case huddrawinfo_minimap: K_getMinimapDrawinfo(&info); break;
case huddrawinfo_timers: K_getSlipstreamDrawinfo(&info); break;
case huddrawinfo_drafting: K_getTimersDrawinfo(&info); break;
default:
return 0; // unreachable
}
@ -1395,7 +1422,8 @@ static int libd_getDrawInfo(lua_State *L)
lua_pushinteger(L, info.x);
lua_pushinteger(L, info.y);
lua_pushinteger(L, info.flags);
return 3;
lua_pushinteger(L, info.flipamount);
return 4;
}
// Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int

View file

@ -65,8 +65,6 @@ extern lua_State *gL;
#define META_NODE "NODE_T*"
#endif
#define META_SLOPE "PSLOPE_T*"
#define META_VECTOR2 "VECTOR2_T"
#define META_VECTOR3 "VECTOR3_T"
#define META_MAPHEADER "MAPHEADER_T*"
#define META_POLYOBJ "POLYOBJ_T*"
@ -119,6 +117,11 @@ extern lua_State *gL;
#define META_OVERLAY "T_OVERLAY_T*"
#define META_TERRAIN "TERRAIN_T*"
#define META_VECTOR2 "VECTOR2_T"
#define META_VECTOR3 "VECTOR3_T"
#define META_MATRIX "MATRIX_T"
#define META_QUATERNION "QUATERNION_T"
boolean luaL_checkboolean(lua_State *L, int narg);
int LUA_EnumLib(lua_State *L);
@ -141,6 +144,9 @@ int LUA_FollowerLib(lua_State *L);
int LUA_BotVarsLib(lua_State *L);
int LUA_TerrainLib(lua_State *L);
int LUA_WaypointLib(lua_State *L);
int LUA_MatrixLib(lua_State *L);
int LUA_QuaternionLib(lua_State *L);
int LUA_VectorLib(lua_State *L);
#ifdef __cplusplus
} // extern "C"

View file

@ -381,19 +381,6 @@ static const char *const slope_opt[] = {
"flags",
NULL};
// shared by both vector2_t and vector3_t
enum vector_e {
vector_x = 0,
vector_y,
vector_z
};
static const char *const vector_opt[] = {
"x",
"y",
"z",
NULL};
enum activator_e {
activator_valid = 0,
activator_mo,
@ -2375,17 +2362,32 @@ static int slope_get(lua_State *L)
lua_pushboolean(L, 1);
return 1;
case slope_o: // o
LUA_PushUserdata(L, &slope->o, META_VECTOR3);
{
vector3_t *vec = lua_newuserdata(L, sizeof(vector3_t));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
FV3_Load(vec, slope->o.x, slope->o.y, slope->o.z);
return 1;
}
case slope_d: // d
LUA_PushUserdata(L, &slope->d, META_VECTOR2);
{
vector2_t *vec = lua_newuserdata(L, sizeof(vector2_t));
luaL_getmetatable(L, META_VECTOR2);
lua_setmetatable(L, -2);
FV2_Load(vec, slope->d.x, slope->d.y);
return 1;
}
case slope_zdelta: // zdelta
lua_pushfixed(L, slope->zdelta);
return 1;
case slope_normal: // normal
LUA_PushUserdata(L, &slope->normal, META_VECTOR3);
{
vector3_t *vec = lua_newuserdata(L, sizeof(vector3_t));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
FV3_Load(vec, slope->normal.x, slope->normal.y, slope->normal.z);
return 1;
}
case slope_zangle: // zangle
lua_pushangle(L, slope->zangle);
return 1;
@ -2486,47 +2488,6 @@ static int slope_set(lua_State *L)
return 0;
}
///////////////
// vector*_t //
///////////////
static int vector2_get(lua_State *L)
{
vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector2_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
static int vector3_get(lua_State *L)
{
vector3_t *vec = *((vector3_t **)luaL_checkudata(L, 1, META_VECTOR3));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
case vector_z: lua_pushfixed(L, vec->z); return 1;
default: break;
}
return 0;
}
/////////////////////
// mapheaderinfo[] //
/////////////////////
@ -2896,16 +2857,6 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
luaL_newmetatable(L, META_VECTOR2);
lua_pushcfunction(L, vector2_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_newmetatable(L, META_VECTOR3);
lua_pushcfunction(L, vector3_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_newmetatable(L, META_MAPHEADER);
lua_pushcfunction(L, mapheaderinfo_get);
lua_setfield(L, -2, "__index");

220
src/lua_matrixlib.c Normal file
View file

@ -0,0 +1,220 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// 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_matrixlib.c
/// \brief matrix library for Lua scripting
#include "m_fixed.h"
#include "lua_script.h"
#include "lua_libs.h"
static vector3_t *GetVector(lua_State *L, int index)
{
vector3_t *vec = lua_touserdata(L, index);
if (!vec)
return NULL;
if (!lua_getmetatable(L, index))
return NULL;
lua_getfield(L, LUA_REGISTRYINDEX, META_VECTOR3);
if (!lua_rawequal(L, -1, -2))
return NULL;
lua_pop(L, 2);
return vec;
}
static void GetVectorOrXYZ(lua_State *L, int index, vector3_t *result)
{
vector3_t *vec = GetVector(L, index);
if (vec)
{
*result = *vec;
}
else
{
result->x = luaL_checkfixed(L, 1);
result->y = luaL_checkfixed(L, 2);
result->z = luaL_checkfixed(L, 3);
}
}
static matrix_t *NewMatrix(lua_State *L)
{
matrix_t *mat = lua_newuserdata(L, sizeof(*mat));
luaL_getmetatable(L, META_MATRIX);
lua_setmetatable(L, -2);
return mat;
}
////////////////////
// STATIC MEMBERS //
////////////////////
static int matrix_new(lua_State *L)
{
FM_LoadIdentity(NewMatrix(L));
return 1;
}
static int matrix_translation(lua_State *L)
{
vector3_t translation;
GetVectorOrXYZ(L, 1, &translation);
matrix_t *mat = NewMatrix(L);
FM_LoadIdentity(mat);
FM_Translate(mat, translation.x, translation.y, translation.z);
return 1;
}
static int matrix_scaling(lua_State *L)
{
vector3_t scaling;
GetVectorOrXYZ(L, 1, &scaling);
FM_Scale(NewMatrix(L), scaling.x, scaling.y, scaling.z);
return 1;
}
static luaL_Reg matrix[] = {
{"new", matrix_new},
{"translation", matrix_translation},
{"scaling", matrix_scaling},
{NULL, NULL}
};
/////////////
// MEMBERS //
/////////////
enum matrixfield_e {
matrixfield_clone = 0,
matrixfield_getvalue,
matrixfield_setvalue,
matrixfield_mulXYZ,
};
static const char *const matrixfield_opt[] = {
"clone",
"get",
"set",
"mulXYZ",
NULL};
static int matrix_clone(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
memcpy(NewMatrix(L), mat, sizeof(matrix_t));
return 1;
}
static int matrix_getvalue(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
INT32 row = luaL_checkinteger(L, 2);
INT32 col = luaL_checkinteger(L, 3);
if (row < 1 || row > 4)
return luaL_error(L, "matrix row %d out of range (1 - 4)", row);
if (col < 1 || col > 4)
return luaL_error(L, "matrix column %d out of range (1 - 4)", col);
lua_pushfixed(L, mat->m[(col - 1) * 4 + row - 1]);
return 1;
}
static int matrix_setvalue(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
INT32 row = luaL_checkinteger(L, 2);
INT32 col = luaL_checkinteger(L, 3);
fixed_t value = luaL_checkfixed(L, 4);
if (row < 1 || row > 4)
return luaL_error(L, "matrix row %d out of range (1 - 4)", row);
if (col < 1 || col > 4)
return luaL_error(L, "matrix column %d out of range (1 - 4)", col);
mat->m[(col - 1) * 4 + row - 1] = value;
return 0;
}
static int matrix_mulXYZ(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
vector3_t vec;
vector3_t result;
FV3_Load(&vec, x, y, z);
FM_MultMatrixVec3(mat, &vec, &result);
lua_pushfixed(L, result.x);
lua_pushfixed(L, result.y);
lua_pushfixed(L, result.z);
return 3;
}
static int matrix_get(lua_State *L)
{
enum matrixfield_e field = luaL_checkoption(L, 2, matrixfield_opt[0], matrixfield_opt);
switch(field)
{
case matrixfield_clone: lua_pushcfunction(L, matrix_clone); return 1;
case matrixfield_getvalue: lua_pushcfunction(L, matrix_getvalue); return 1;
case matrixfield_setvalue: lua_pushcfunction(L, matrix_setvalue); return 1;
case matrixfield_mulXYZ: lua_pushcfunction(L, matrix_mulXYZ); return 1;
default: break;
}
return 0;
}
///////////////
// OPERATORS //
///////////////
static int matrix_mul(lua_State *L)
{
matrix_t *mat1 = luaL_checkudata(L, 1, META_MATRIX);
vector3_t *vec2 = GetVector(L, 2);
if (vec2)
{
vector3_t *result = lua_newuserdata(L, sizeof(*result));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
FM_MultMatrixVec3(mat1, vec2, result);
}
else
{
matrix_t *mat2 = luaL_checkudata(L, 2, META_MATRIX);
FM_MultMatrixEx(mat1, mat2, NewMatrix(L));
}
return 1;
}
int LUA_MatrixLib(lua_State *L)
{
luaL_newmetatable(L, META_MATRIX);
LUA_SetCFunctionField(L, "__index", matrix_get);
LUA_SetCFunctionField(L, "__mul", matrix_mul);
lua_pop(L, 1);
luaL_register(L, "Matrix", matrix);
return 0;
}

View file

@ -103,6 +103,12 @@ enum mobj_e {
mobj_sprxoff,
mobj_spryoff,
mobj_sprzoff,
mobj_bakexoff,
mobj_bakeyoff,
mobj_bakezoff,
mobj_bakexpiv,
mobj_bakeypiv,
mobj_bakezpiv,
mobj_terrain,
mobj_dispoffset,
mobj_tid,
@ -192,6 +198,12 @@ static const char *const mobj_opt[] = {
"sprxoff",
"spryoff",
"sprzoff",
"bakexoff",
"bakeyoff",
"bakezoff",
"bakexpiv",
"bakeypiv",
"bakezpiv",
"terrain",
"dispoffset",
"tid",
@ -542,6 +554,24 @@ static int mobj_get(lua_State *L)
case mobj_sprzoff:
lua_pushfixed(L, mo->sprzoff);
break;
case mobj_bakexoff:
lua_pushfixed(L, mo->bakexoff);
break;
case mobj_bakeyoff:
lua_pushfixed(L, mo->bakeyoff);
break;
case mobj_bakezoff:
lua_pushfixed(L, mo->bakezoff);
break;
case mobj_bakexpiv:
lua_pushfixed(L, mo->bakexpiv);
break;
case mobj_bakeypiv:
lua_pushfixed(L, mo->bakeypiv);
break;
case mobj_bakezpiv:
lua_pushfixed(L, mo->bakezpiv);
break;
case mobj_terrain:
LUA_PushUserdata(L, mo->terrain, META_TERRAIN);
break;
@ -982,6 +1012,24 @@ static int mobj_set(lua_State *L)
case mobj_sprzoff:
mo->sprzoff = luaL_checkfixed(L, 3);
break;
case mobj_bakexoff:
mo->bakexoff = luaL_checkfixed(L, 3);
break;
case mobj_bakeyoff:
mo->bakeyoff = luaL_checkfixed(L, 3);
break;
case mobj_bakezoff:
mo->bakezoff = luaL_checkfixed(L, 3);
break;
case mobj_bakexpiv:
mo->bakexpiv = luaL_checkfixed(L, 3);
break;
case mobj_bakeypiv:
mo->bakeypiv = luaL_checkfixed(L, 3);
break;
case mobj_bakezpiv:
mo->bakezpiv = luaL_checkfixed(L, 3);
break;
case mobj_terrain:
mo->terrain = *((terrain_t **)luaL_checkudata(L, 3, META_TERRAIN));
break;

View file

@ -256,12 +256,15 @@ enum player_e
player_ringmax,
player_pickuprings,
player_ringdelay,
player_ringlock,
player_ringboost,
player_ringtime,
player_superring,
player_nextringaward,
player_ringvolume,
player_ringtransparency,
player_airdroptime,
player_ringdrop,
player_curshield,
player_bubblecool,
player_bubbleblowup,
@ -357,6 +360,9 @@ enum player_e
player_ping,
player_packetloss,
player_loop,
player_prevonground,
player_walltransfered,
player_walltransferboost,
#ifdef HWRENDER
player_fovadd,
#endif
@ -453,12 +459,15 @@ static const char *const player_opt[] = {
"ringmax",
"pickuprings",
"ringdelay",
"ringlock",
"ringboost",
"ringtime",
"superring",
"nextringaward",
"ringvolume",
"ringtransparency",
"airdroptime",
"ringdrop",
"curshield",
"bubblecool",
"bubbleblowup",
@ -554,6 +563,9 @@ static const char *const player_opt[] = {
"ping",
"packetloss",
"loop",
"prevonground",
"walltransfered",
"walltransfeboost",
#ifdef HWRENDER
"fovadd",
#endif
@ -854,6 +866,9 @@ static int player_get(lua_State *L)
case player_ringdelay:
lua_pushinteger(L, plr->ringdelay);
break;
case player_ringlock:
lua_pushinteger(L, plr->ringlock);
break;
case player_ringboost:
lua_pushinteger(L, plr->ringboost);
break;
@ -872,6 +887,12 @@ static int player_get(lua_State *L)
case player_ringtransparency:
lua_pushinteger(L, plr->ringtransparency);
break;
case player_airdroptime:
lua_pushinteger(L, plr->airdroptime);
break;
case player_ringdrop:
lua_pushinteger(L, plr->ringdrop);
break;
case player_curshield:
lua_pushinteger(L, plr->curshield);
break;
@ -1177,6 +1198,15 @@ static int player_get(lua_State *L)
case player_loop:
LUA_PushUserdata(L, &plr->loop, META_SONICLOOPVARS);
break;
case player_prevonground:
lua_pushboolean(L, plr->prevonground);
break;
case player_walltransfered:
lua_pushboolean(L, plr->walltransfered);
break;
case player_walltransferboost:
lua_pushinteger(L, plr->walltransferboost);
break;
#ifdef HWRENDER
case player_fovadd:
lua_pushfixed(L, plr->fovadd);
@ -1534,6 +1564,9 @@ static int player_set(lua_State *L)
case player_ringdelay:
plr->ringdelay = luaL_checkinteger(L, 3);
break;
case player_ringlock:
plr->ringlock = luaL_checkinteger(L, 3);
break;
case player_ringboost:
plr->ringboost = luaL_checkinteger(L, 3);
break;
@ -1552,6 +1585,12 @@ static int player_set(lua_State *L)
case player_ringtransparency:
plr->ringtransparency = luaL_checkinteger(L, 3);
break;
case player_airdroptime:
plr->airdroptime = luaL_checkinteger(L, 3);
break;
case player_ringdrop:
plr->ringdrop = luaL_checkinteger(L, 3);
break;
case player_curshield:
plr->curshield = luaL_checkinteger(L, 3);
break;
@ -1839,6 +1878,12 @@ static int player_set(lua_State *L)
return NOSET;
case player_loop:
return NOSET;
case player_prevonground:
return NOSET;
case player_walltransfered:
plr->walltransfered = lua_toboolean(L, 3);
case player_walltransferboost:
plr->walltransferboost= lua_tointeger(L, 3);
#ifdef HWRENDER
case player_fovadd:
plr->fovadd = luaL_checkfixed(L, 3);

192
src/lua_quaternionlib.c Normal file
View file

@ -0,0 +1,192 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// 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_quaternionlib.c
/// \brief quaternion library for Lua scripting
#include "m_fixed.h"
#include "lua_script.h"
#include "lua_libs.h"
static vector4_t *NewQuaternion(lua_State *L)
{
vector4_t *quat = lua_newuserdata(L, sizeof(*quat));
luaL_getmetatable(L, META_QUATERNION);
lua_setmetatable(L, -2);
return quat;
}
////////////////////
// STATIC MEMBERS //
////////////////////
static int quaternion_new(lua_State *L)
{
vector4_t *q = NewQuaternion(L);
q->x = 0;
q->y = 0;
q->z = 0;
q->a = FRACUNIT;
return 1;
}
static int quaternion_fromAxisRotation(lua_State *L)
{
vector3_t *axis = luaL_checkudata(L, 1, META_VECTOR3);
fixed_t angle = luaL_checkfixed(L, 2);
fixed_t cosangle = FINECOSINE(((angle / 2) >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t sinangle = FINESINE(((angle / 2) >> ANGLETOFINESHIFT) & FINEMASK);
vector3_t normaxis;
FV3_NormalizeEx(axis, &normaxis);
FV4_Load(NewQuaternion(L),
FixedMul(normaxis.x, sinangle),
FixedMul(normaxis.y, sinangle),
FixedMul(normaxis.z, sinangle),
cosangle
);
return 1;
}
static luaL_Reg quaternion[] = {
{"new", quaternion_new},
{"fromAxisRotation", quaternion_fromAxisRotation},
{NULL, NULL}
};
/////////////
// MEMBERS //
/////////////
static int quaternion_clone(lua_State *L)
{
vector4_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
FV4_Copy(NewQuaternion(L), quat);
return 1;
}
static int vector4_toMatrix(lua_State *L)
{
vector4_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
matrix_t *mat = lua_newuserdata(L, sizeof(*mat));
luaL_getmetatable(L, META_MATRIX);
lua_setmetatable(L, -2);
fixed_t x = quat->x, y = quat->y, z = quat->z, w = quat->a;
fixed_t xx2 = 2 * FixedMul(x, x);
fixed_t xy2 = 2 * FixedMul(x, y);
fixed_t xz2 = 2 * FixedMul(x, z);
fixed_t xw2 = 2 * FixedMul(x, w);
fixed_t yy2 = 2 * FixedMul(y, y);
fixed_t yz2 = 2 * FixedMul(y, z);
fixed_t yw2 = 2 * FixedMul(y, w);
fixed_t zz2 = 2 * FixedMul(z, z);
fixed_t zw2 = 2 * FixedMul(z, w);
FM_LoadIdentity(mat);
mat->m[0 + 0*4] = FRACUNIT - yy2 - zz2;
mat->m[0 + 1*4] = xy2 - zw2;
mat->m[0 + 2*4] = xz2 + yw2;
mat->m[1 + 0*4] = xy2 + zw2;
mat->m[1 + 1*4] = FRACUNIT - xx2 - zz2;
mat->m[1 + 2*4] = yz2 - xw2;
mat->m[2 + 0*4] = xz2 - yw2;
mat->m[2 + 1*4] = yz2 + xw2;
mat->m[2 + 2*4] = FRACUNIT - xx2 - yy2;
mat->m[3 + 3*4] = FRACUNIT;
return 1;
}
enum quaternionfield_e {
quaternionfield_clone = 0,
quaternionfield_toMatrix,
quaternionfield_x,
quaternionfield_y,
quaternionfield_z,
quaternionfield_w,
};
static const char *const quaternionfield_opt[] = {
"clone",
"toMatrix",
"x",
"y",
"z",
"w",
NULL};
static int quaternion_get(lua_State *L)
{
vector4_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
enum quaternionfield_e field = luaL_checkoption(L, 2, quaternionfield_opt[0], quaternionfield_opt);
switch(field)
{
case quaternionfield_clone: lua_pushcfunction(L, quaternion_clone); return 1;
case quaternionfield_toMatrix: lua_pushcfunction(L, vector4_toMatrix); return 1;
case quaternionfield_x: lua_pushfixed(L, quat->x); return 1;
case quaternionfield_y: lua_pushfixed(L, quat->y); return 1;
case quaternionfield_z: lua_pushfixed(L, quat->z); return 1;
case quaternionfield_w: lua_pushfixed(L, quat->a); return 1;
default: break;
}
return 0;
}
///////////////
// OPERATORS //
///////////////
// FV4_Mul isn't an accurate multiplication, so let's silently use LJ Sonic's multiplication
// function.
static vector4_t *QuaternionMul(vector4_t *out, vector4_t *a, vector4_t *b)
{
fixed_t ax = a->x, ay = a->y, az = a->z, aw = a->a;
fixed_t bx = b->x, by = b->y, bz = b->z, bw = b->a;
FV4_NormalizeEx(out, FV4_Load(out,
FixedMul(aw, bx) + FixedMul(ax, bw) + FixedMul(ay, bz) - FixedMul(az, by),
FixedMul(aw, by) - FixedMul(ax, bz) + FixedMul(ay, bw) + FixedMul(az, bx),
FixedMul(aw, bz) + FixedMul(ax, by) - FixedMul(ay, bx) + FixedMul(az, bw),
FixedMul(aw, bw) - FixedMul(ax, bx) - FixedMul(ay, by) - FixedMul(az, bz)
));
return out;
}
static int quaternion_mul(lua_State *L)
{
vector4_t *quat1 = luaL_checkudata(L, 1, META_QUATERNION);
vector4_t *quat2 = luaL_checkudata(L, 2, META_QUATERNION);
QuaternionMul(NewQuaternion(L), quat1, quat2);
return 1;
}
int LUA_QuaternionLib(lua_State *L)
{
luaL_newmetatable(L, META_QUATERNION);
LUA_SetCFunctionField(L, "__index", quaternion_get);
LUA_SetCFunctionField(L, "__mul", quaternion_mul);
lua_pop(L, 1);
luaL_register(L, "Quaternion", quaternion);
return 0;
}

View file

@ -63,6 +63,9 @@ static lua_CFunction liblist[] = {
LUA_BotVarsLib, // botvars_t
LUA_TerrainLib, // t_splash_t, t_footstep_t, t_overlay_t, terrain_t
LUA_WaypointLib, // waypoint_t
LUA_VectorLib, // vectors
LUA_MatrixLib, // matrices
LUA_QuaternionLib, // quaternions
NULL
};
@ -397,6 +400,11 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"draftingactive")) {
lua_pushinteger(L, draftingactive);
return 1;
} else if (fastcmp(word,"airdropactive")) {
lua_pushinteger(L, airdropactive);
} else if (fastcmp(word,"bumpsparkactive")) {
lua_pushinteger(L, bumpsparkactive);
return 1;
} else if (fastcmp(word,"purpledriftactive")) {
lua_pushinteger(L, purpledriftactive);
return 1;
@ -1919,6 +1927,40 @@ void LUA_UnArchive(savebuffer_t *save, boolean network, boolean compat)
lua_pop(gL, 1); // pop tables
}
static void SetBasicMetamethods(
lua_State *L,
lua_CFunction get,
lua_CFunction set,
lua_CFunction len
)
{
if (get)
LUA_SetCFunctionField(L, "__index", get);
if (set)
LUA_SetCFunctionField(L, "__newindex", set);
if (len)
LUA_SetCFunctionField(L, "__len", len);
}
void LUA_SetCFunctionField(lua_State *L, const char *name, lua_CFunction value)
{
lua_pushcfunction(L, value);
lua_setfield(L, -2, name);
}
void LUA_RegisterUserdataMetatable(
lua_State *L,
const char *name,
lua_CFunction get,
lua_CFunction set,
lua_CFunction len
)
{
luaL_newmetatable(L, name);
SetBasicMetamethods(L, get, set, len);
lua_pop(L, 1);
}
// For mobj_t, player_t, etc. to take custom variables.
int Lua_optoption(lua_State *L, int narg,
const char *def, const char *const lst[])

View file

@ -34,7 +34,9 @@ extern "C" {
// fixed_t casting
// TODO add some distinction between fixed numbers and integer numbers
// for at least the purpose of printing and maybe math.
#define lua_tofixed(L, i) lua_tointeger(L, i)
#define luaL_checkfixed(L, i) luaL_checkinteger(L, i)
#define luaL_optfixed(L, i, d) luaL_optinteger(L, i, d)
#define lua_pushfixed(L, f) lua_pushinteger(L, f)
// angle_t casting
@ -62,6 +64,16 @@ void LUA_Step(void);
void LUA_Archive(savebuffer_t *save, boolean network);
void LUA_UnArchive(savebuffer_t *save, boolean network, boolean compat);
void LUA_SetCFunctionField(lua_State *L, const char *name, lua_CFunction value);
void LUA_RegisterUserdataMetatable(
lua_State *L,
const char *name,
lua_CFunction get,
lua_CFunction set,
lua_CFunction len
);
int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_WriteGlobals(lua_State *L, const char *word);

219
src/lua_vectorlib.c Normal file
View file

@ -0,0 +1,219 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// 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_vectorlib.c
/// \brief vector library for Lua scripting
#include "m_fixed.h"
#include "lua_script.h"
#include "lua_libs.h"
// shared by both Vector2D and Vector3D
enum vectorfield_e {
vectorfield_clone = 0,
vectorfield_opposite,
vectorfield_x,
vectorfield_y,
vectorfield_z,
vectorfield_length,
vectorfield_normalized,
};
static const char *const vectorfield_opt[] = {
"vector_clone",
"vector_opposite",
"x",
"y",
"z",
"vector_length",
"vector_normalized",
NULL};
////////////////////////////
// VECTOR2 STATIC MEMBERS //
////////////////////////////
/////////////////////
// VECTOR2 MEMBERS //
/////////////////////
static int vector2d_get(lua_State *L)
{
vector2_t *vec = luaL_checkudata(L, 1, META_VECTOR2);
enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt);
switch(field)
{
case vectorfield_x: lua_pushfixed(L, vec->x); return 1;
case vectorfield_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
/////////////
// VECTOR3 //
/////////////
static vector3_t *NewVector3(lua_State *L)
{
vector3_t *vec = lua_newuserdata(L, sizeof(*vec));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
return vec;
}
////////////////////////////
// VECTOR3 STATIC MEMBERS //
////////////////////////////
static int vector3d_new(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_optfixed(L, 3, 0);
FV3_Load(NewVector3(L), x, y, z);
return 1;
}
static luaL_Reg vector3d[] = {
{"new", vector3d_new},
{NULL, NULL}
};
/////////////////////
// VECTOR3 MEMBERS //
/////////////////////
static int vector3d_clone(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
FV3_Copy(NewVector3(L), vec);
return 1;
}
static int vector3d_opposite(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
FV3_NegateEx(vec, NewVector3(L));
return 1;
}
static int vector3d_get(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
vector3_t unit = { 0, 0, 0 };
switch(field)
{
case vectorfield_clone: lua_pushcfunction(L, vector3d_clone); return 1;
case vectorfield_opposite: lua_pushcfunction(L, vector3d_opposite); return 1;
case vectorfield_x: lua_pushfixed(L, vec->x); return 1;
case vectorfield_y: lua_pushfixed(L, vec->y); return 1;
case vectorfield_z: lua_pushfixed(L, vec->z); return 1;
case vectorfield_length: lua_pushfixed(L, FV3_Distance(&unit, vec)); return 1;
case vectorfield_normalized: FV3_NormalizeEx(vec, NewVector3(L)); return 1;
default: break;
}
return 0;
}
///////////////////////
// VECTOR3 OPERATORS //
///////////////////////
static int vector3d_eq(lua_State *L)
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
lua_pushboolean(L, FV3_Equal(vec1, vec2));
return 1;
}
static int vector3d_op(
lua_State *L,
vector3_t *(*opvector)(const vector3_t*, const vector3_t*, vector3_t*)
)
{
if (lua_isnumber(L, 1) && (opvector == FV3_AddEx || opvector == FV3_MulEx))
{
fixed_t n1 = lua_tofixed(L, 1);
vector3_t vec1 = { n1, n1, n1 };
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
opvector(NewVector3(L), vec2, &vec1);
}
else if (lua_isnumber(L, 2))
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
fixed_t n2 = lua_tofixed(L, 2);
vector3_t vec2 = { n2, n2, n2 };
opvector(NewVector3(L), vec1, &vec2);
}
else
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
opvector(NewVector3(L), vec1, vec2);
}
return 1;
}
static int vector3d_add(lua_State *L)
{
return vector3d_op(L, FV3_AddEx);
}
static int vector3d_sub(lua_State *L)
{
return vector3d_op(L, FV3_SubEx);
}
static int vector3d_mul(lua_State *L)
{
return vector3d_op(L, FV3_MulEx);
}
static int vector3d_div(lua_State *L)
{
return vector3d_op(L, FV3_DivideEx);
}
static int vector3d_unm(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
FV3_NegateEx(vec, NewVector3(L));
return 1;
}
int LUA_VectorLib(lua_State *L)
{
LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2d_get, NULL, NULL);
luaL_newmetatable(L, META_VECTOR3);
LUA_SetCFunctionField(L, "__index", vector3d_get);
LUA_SetCFunctionField(L, "__eq", vector3d_eq);
LUA_SetCFunctionField(L, "__add", vector3d_add);
LUA_SetCFunctionField(L, "__sub", vector3d_sub);
LUA_SetCFunctionField(L, "__mul", vector3d_mul);
LUA_SetCFunctionField(L, "__div", vector3d_div);
LUA_SetCFunctionField(L, "__unm", vector3d_unm);
lua_pop(L, 1);
luaL_register(L, "Vector3D", vector3d);
return 0;
}

View file

@ -57,14 +57,15 @@ static precise_t gif_prevframetime = 0;
static UINT32 gif_delayus = 0; // "us" is microseconds
static UINT8 gif_writeover = 0;
typedef struct
{
void *pixels;
size_t size;
boolean owns_pixels;
} gif_screen_t;
static gif_screen_t gif_screens[2];
// SCReen BUFfer (obviously)
// ---
static UINT8 *scrbuf_pos;
static UINT8 *scrbuf_linebegin;
static UINT8 *scrbuf_lineend;
static UINT8 *scrbuf_writeend;
static INT16 scrbuf_downscaleamt = 1;
static UINT16 scrbuf_width, scrbuf_height;
static UINT8 *scrbuf_screens;
// OPTIMIZE gif output
// ---
@ -79,13 +80,13 @@ static gif_screen_t gif_screens[2];
static UINT8 GIF_optimizecmprow(const UINT8 *dst, const UINT8 *src, INT32 row,
INT32 *last, INT32 *left, INT32 *right)
{
const UINT8 *dp = dst + (vid.width * row);
const UINT8 *sp = src + (vid.width * row);
const UINT8 *dp = dst + (scrbuf_width * row);
const UINT8 *sp = src + (scrbuf_width * row);
const UINT8 *dtmp, *stmp;
UINT8 doleft = 1, doright = 1;
INT32 i = 0;
if (!memcmp(sp, dp, vid.width))
if (!memcmp(sp, dp, scrbuf_width))
return 0; // unchanged.
*last = row;
@ -112,14 +113,14 @@ static UINT8 GIF_optimizecmprow(const UINT8 *dst, const UINT8 *src, INT32 row,
}
// right side
i = vid.width - 1;
if (*right == vid.width - 1) // edge reached
i = scrbuf_width - 1;
if (*right == scrbuf_width - 1) // edge reached
doright = 0;
else if (*right >= 0) // right set, non-end-of-width
{
dtmp = dp + *right + 1;
stmp = sp + *right + 1;
if (!memcmp(stmp, dtmp, vid.width - (*right + 1)))
if (!memcmp(stmp, dtmp, scrbuf_width - (*right + 1)))
doright = 0; // right side not changed
}
while (doright)
@ -149,7 +150,7 @@ static UINT8 GIF_optimizecmprow(const UINT8 *dst, const UINT8 *src, INT32 row,
static void GIF_optimizeregion(const UINT8 *dst, const UINT8 *src,
INT32 *x, INT32 *y, INT32 *w, INT32 *h)
{
INT32 st = 0, sb = vid.height - 1; // work from both directions
INT32 st = 0, sb = scrbuf_height - 1; // work from both directions
INT32 firstchg_t = -1, firstchg_b = -1; // store first changed row.
INT32 lastchg_t = -1, lastchg_b = -1; // Store last row... just in case
INT32 lmpix = -1, rmpix = -1; // store left and rightmost change
@ -160,7 +161,7 @@ static void GIF_optimizeregion(const UINT8 *dst, const UINT8 *src,
if (!stopt)
{
if (GIF_optimizecmprow(dst, src, st++, &lastchg_t, &lmpix, &rmpix)
&& lmpix == 0 && rmpix == vid.width - 1)
&& lmpix == 0 && rmpix == scrbuf_width - 1)
stopt = 1;
if (firstchg_t < 0 && lastchg_t >= 0)
firstchg_t = lastchg_t;
@ -168,7 +169,7 @@ static void GIF_optimizeregion(const UINT8 *dst, const UINT8 *src,
if (!stopb)
{
if (GIF_optimizecmprow(dst, src, sb--, &lastchg_b, &lmpix, &rmpix)
&& lmpix == 0 && rmpix == vid.width - 1)
&& lmpix == 0 && rmpix == scrbuf_width - 1)
stopb = 1;
if (firstchg_b < 0 && lastchg_b >= 0)
firstchg_b = lastchg_b;
@ -238,18 +239,6 @@ static void GIF_bwrwrite(UINT32 idata)
}
}
// SCReen BUFfer (obviously)
// ---
static UINT8 *scrbuf_pos;
static UINT8 *scrbuf_linebegin;
static UINT8 *scrbuf_lineend;
static UINT8 *scrbuf_writeend;
static INT16 scrbuf_downscaleamt = 1;
// GIF LZW algorithm
// ---
#define GIFLZW_TABLECLR 0x100
@ -375,10 +364,10 @@ static void GIF_lzw(void)
GIF_bwrwrite(GIFLZW_TABLECLR);
GIF_prepareLZW();
}
if ((scrbuf_pos += scrbuf_downscaleamt) >= scrbuf_lineend)
if (++scrbuf_pos >= scrbuf_lineend)
{
scrbuf_lineend += (vid.width * scrbuf_downscaleamt);
scrbuf_linebegin += (vid.width * scrbuf_downscaleamt);
scrbuf_lineend += scrbuf_width;
scrbuf_linebegin += scrbuf_width;
scrbuf_pos = scrbuf_linebegin;
}
// Just a bit of overflow prevention
@ -459,7 +448,6 @@ static void GIF_headwrite(void)
{
UINT8 *gifhead = Z_Malloc(800, PU_STATIC, NULL);
UINT8 *p = gifhead;
UINT16 rwidth, rheight;
if (!gif_out)
return;
@ -470,18 +458,18 @@ static void GIF_headwrite(void)
if (gif_downscale)
{
scrbuf_downscaleamt = vid.dupx;
rwidth = (vid.width / scrbuf_downscaleamt);
rheight = (vid.height / scrbuf_downscaleamt);
scrbuf_width = (vid.width / scrbuf_downscaleamt);
scrbuf_height = (vid.height / scrbuf_downscaleamt);
}
else
{
scrbuf_downscaleamt = 1;
rwidth = vid.width;
rheight = vid.height;
scrbuf_width = vid.width;
scrbuf_height = vid.height;
}
WRITEUINT16(p, rwidth);
WRITEUINT16(p, rheight);
WRITEUINT16(p, scrbuf_width);
WRITEUINT16(p, scrbuf_height);
// colors, aspect, etc
WRITEUINT8(p, 0xF7); // (0xF7 = 1111 0111)
@ -515,28 +503,16 @@ static size_t gifframe_size = 8192;
#ifdef HWRENDER
static colorlookup_t gif_colorlookup;
static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
static void GIF_rgbconvert(UINT8 * restrict linear, UINT8 * restrict scr)
{
UINT8 r, g, b;
size_t src, dest;
int x, y;
InitColorLUT(&gif_colorlookup, (gif_localcolortable) ? gif_framepalette : gif_headerpalette, true);
for (x = 0; x < vid.width; x += scrbuf_downscaleamt)
for (INT32 i = 0; i < scrbuf_width*scrbuf_height; i++)
{
for (y = 0; y < vid.height; y += scrbuf_downscaleamt)
{
dest = y*vid.width + x;
src = dest*3;
r = (UINT8)linear[src];
g = (UINT8)linear[src + 1];
b = (UINT8)linear[src + 2];
scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b);
src += (3 * scrbuf_downscaleamt);
dest += scrbuf_downscaleamt;
}
UINT8 r = *linear++;
UINT8 g = *linear++;
UINT8 b = *linear++;
*scr++ = GetColorLUTDirect(&gif_colorlookup, r, g, b);
}
}
#endif
@ -548,8 +524,8 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
static void GIF_framewrite(void)
{
UINT8 *p;
UINT8 *base_screen = gif_screens[0].pixels;
UINT8 *movie_screen = gif_screens[1].pixels;
UINT8 *base_screen = scrbuf_screens;
UINT8 *movie_screen = scrbuf_screens;
INT32 blitx, blity, blitw, blith;
boolean palchanged;
@ -569,48 +545,35 @@ static void GIF_framewrite(void)
else
palchanged = false;
// select your framebuffer
if (gif_frames & 1)
base_screen += scrbuf_width*scrbuf_height;
else
movie_screen += scrbuf_width*scrbuf_height;
// blit to temp screen
if (rendermode == render_soft)
I_ReadScreen(movie_screen, scrbuf_downscaleamt);
#ifdef HWRENDER
else if (rendermode == render_opengl)
{
UINT8 *linear = HWR_GetScreenshot(scrbuf_downscaleamt);
GIF_rgbconvert(linear, movie_screen);
//free(linear); // Allocated 'statically', no need to free now
}
#endif
// Compare image data (for optimizing GIF)
// If the palette has changed, the entire frame is considered to be different.
if (gif_optimize && gif_frames > 0 && (!palchanged))
{
// before blit movie_screen points to last frame, cur_screen points to this frame
UINT8 *cur_screen = base_screen;
GIF_optimizeregion(cur_screen, movie_screen, &blitx, &blity, &blitw, &blith);
// blit to temp screen
if (rendermode == render_soft)
I_ReadScreen(movie_screen);
#ifdef HWRENDER
else if (rendermode == render_opengl)
{
UINT8 *linear = HWR_GetScreenshot();
GIF_rgbconvert(linear, movie_screen);
//free(linear); // Allocated 'statically', no need to free now
}
#endif
GIF_optimizeregion(base_screen, movie_screen, &blitx, &blity, &blitw, &blith);
}
else
{
blitx = blity = 0;
blitw = vid.width;
blith = vid.height;
#ifdef HWRENDER
// Copy the current OpenGL frame into the base screen
if (rendermode == render_opengl)
{
UINT8 *linear = HWR_GetScreenshot();
GIF_rgbconvert(linear, base_screen);
//free(linear); // Allocated 'statically', no need to free now
}
#endif
// Copy the first frame into the movie screen
// OpenGL already does the same above.
if (gif_frames == 0 && rendermode == render_soft)
I_ReadScreen(movie_screen);
movie_screen = base_screen;
blitw = scrbuf_width;
blith = scrbuf_height;
}
// screen regions are handled in GIF_lzw
@ -654,20 +617,11 @@ static void GIF_framewrite(void)
WRITEUINT8(p, 0);
WRITEUINT8(p, 0); // end of GCE
if (scrbuf_downscaleamt > 1)
{
// Ensure our downscaled blitx/y starts and ends on a pixel.
blitx -= (blitx % scrbuf_downscaleamt);
blity -= (blity % scrbuf_downscaleamt);
blitw = ((blitw + (scrbuf_downscaleamt - 1)) / scrbuf_downscaleamt) * scrbuf_downscaleamt;
blith = ((blith + (scrbuf_downscaleamt - 1)) / scrbuf_downscaleamt) * scrbuf_downscaleamt;
}
WRITEUINT8(p, 0x2C);
WRITEUINT16(p, (UINT16)(blitx / scrbuf_downscaleamt));
WRITEUINT16(p, (UINT16)(blity / scrbuf_downscaleamt));
WRITEUINT16(p, (UINT16)(blitw / scrbuf_downscaleamt));
WRITEUINT16(p, (UINT16)(blith / scrbuf_downscaleamt));
WRITEUINT16(p, (UINT16)blitx);
WRITEUINT16(p, (UINT16)blity);
WRITEUINT16(p, (UINT16)blitw);
WRITEUINT16(p, (UINT16)blith);
if (!gif_localcolortable)
WRITEUINT8(p, 0); // no local table of colors
@ -683,8 +637,8 @@ static void GIF_framewrite(void)
WRITEUINT8(p, 0); // They are equal, no Local Color Table needed.
}
scrbuf_pos = movie_screen + blitx + (blity * vid.width);
scrbuf_writeend = scrbuf_pos + (blitw - 1) + ((blith - 1) * vid.width);
scrbuf_pos = movie_screen + blitx + (blity * scrbuf_width);
scrbuf_writeend = scrbuf_pos + (blitw - 1) + ((blith - 1) * scrbuf_width);
if (!gifbwr_buf)
gifbwr_buf = Z_Malloc(256, PU_STATIC, NULL);
@ -694,8 +648,8 @@ static void GIF_framewrite(void)
giflzw_workingCode = UINT16_MAX;
WRITEUINT8(p, gifbwr_bits_min - 1);
startline = (scrbuf_pos - movie_screen) / vid.width;
scrbuf_linebegin = movie_screen + (startline * vid.width) + blitx;
startline = (scrbuf_pos - movie_screen) / scrbuf_width;
scrbuf_linebegin = movie_screen + (startline * scrbuf_width) + blitx;
scrbuf_lineend = scrbuf_linebegin + blitw;
//prewrite a table clear
@ -760,55 +714,11 @@ INT32 GIF_open(const char *filename)
static void GIF_checkscreens(void)
{
for (size_t i = 0; i < sizeof(gif_screens) / sizeof(gif_screens[0]); i++)
{
if (rendermode == render_soft)
{
if (gif_screens[i].owns_pixels)
{
Z_Free(gif_screens[i].pixels);
gif_screens[i].owns_pixels = false;
}
if (scrbuf_screens == NULL)
Z_Malloc(scrbuf_width * scrbuf_height * 2, PU_STATIC, &scrbuf_screens);
gif_screens[i].size = 0;
if (i == 1)
gif_screens[i].pixels = screens[2];
else
gif_screens[i].pixels = screens[0];
}
else
{
size_t sz = vid.width * vid.height * vid.bpp;
if (!gif_screens[i].owns_pixels)
{
gif_screens[i].size = sz;
gif_screens[i].pixels = Z_Malloc(gif_screens[i].size, PU_STATIC, NULL);
gif_screens[i].owns_pixels = true;
}
else if (gif_screens[i].size != sz)
{
gif_screens[i].size = sz;
gif_screens[i].pixels = Z_Realloc(gif_screens[i].pixels, gif_screens[i].size, PU_STATIC, NULL);
}
}
}
}
static void GIF_freescreens(void)
{
for (size_t i = 0; i < sizeof(gif_screens) / sizeof(gif_screens[0]); i++)
{
if (gif_screens[i].owns_pixels)
{
Z_Free(gif_screens[i].pixels);
gif_screens[i].owns_pixels = false;
}
gif_screens[i].size = 0;
gif_screens[i].pixels = NULL;
}
I_Assert(scrbuf_width == vid.width / scrbuf_downscaleamt);
I_Assert(scrbuf_height == vid.height / scrbuf_downscaleamt);
}
//
@ -847,7 +757,7 @@ INT32 GIF_close(void)
Z_Free(giflzw_hashTable);
giflzw_hashTable = NULL;
GIF_freescreens();
Z_Free(scrbuf_screens);
CONS_Printf(M_GetText("Animated gif closed; wrote %d frames\n"), gif_frames);
return 1;

View file

@ -248,6 +248,15 @@ vector3_t *FV3_Load(vector3_t *vec, fixed_t x, fixed_t y, fixed_t z)
return vec;
}
vector4_t *FV4_Load(vector4_t *vec, fixed_t x, fixed_t y, fixed_t z, fixed_t a)
{
vec->x = x;
vec->y = y;
vec->z = z;
vec->a = a;
return vec;
}
vector3_t *FV3_UnLoad(vector3_t *vec, fixed_t *x, fixed_t *y, fixed_t *z)
{
*x = vec->x;
@ -256,11 +265,25 @@ vector3_t *FV3_UnLoad(vector3_t *vec, fixed_t *x, fixed_t *y, fixed_t *z)
return vec;
}
vector4_t *FV4_UnLoad(vector4_t *vec, fixed_t *x, fixed_t *y, fixed_t *z, fixed_t *a)
{
*x = vec->x;
*y = vec->y;
*z = vec->z;
*a = vec->a;
return vec;
}
vector3_t *FV3_Copy(vector3_t *a_o, const vector3_t *a_i)
{
return M_Memcpy(a_o, a_i, sizeof(vector3_t));
}
vector4_t *FV4_Copy(vector4_t *a_o, const vector4_t *a_i)
{
return M_Memcpy(a_o, a_i, sizeof(vector4_t));
}
vector3_t *FV3_AddEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
{
a_o->x = a_i->x + a_c->x;
@ -269,11 +292,25 @@ vector3_t *FV3_AddEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
return a_o;
}
vector4_t *FV4_AddEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o)
{
a_o->x = a_i->x + a_c->x;
a_o->y = a_i->y + a_c->y;
a_o->z = a_i->z + a_c->z;
a_o->a = a_i->a + a_c->a;
return a_o;
}
vector3_t *FV3_Add(vector3_t *a_i, const vector3_t *a_c)
{
return FV3_AddEx(a_i, a_c, a_i);
}
vector4_t *FV4_Add(vector4_t *a_i, const vector4_t *a_c)
{
return FV4_AddEx(a_i, a_c, a_i);
}
vector3_t *FV3_SubEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
{
a_o->x = a_i->x - a_c->x;
@ -282,37 +319,79 @@ vector3_t *FV3_SubEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
return a_o;
}
vector4_t *FV4_SubEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o)
{
a_o->x = a_i->x - a_c->x;
a_o->y = a_i->y - a_c->y;
a_o->z = a_i->z - a_c->z;
a_o->a = a_i->a - a_c->a;
return a_o;
}
vector3_t *FV3_Sub(vector3_t *a_i, const vector3_t *a_c)
{
return FV3_SubEx(a_i, a_c, a_i);
}
vector3_t *FV3_MulEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o)
vector4_t *FV4_Sub(vector4_t *a_i, const vector4_t *a_c)
{
a_o->x = FixedMul(a_i->x, a_c);
a_o->y = FixedMul(a_i->y, a_c);
a_o->z = FixedMul(a_i->z, a_c);
return FV4_SubEx(a_i, a_c, a_i);
}
vector3_t *FV3_MulEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
{
a_o->x = FixedMul(a_i->x, a_c->x);
a_o->y = FixedMul(a_i->y, a_c->y);
a_o->z = FixedMul(a_i->z, a_c->z);
return a_o;
}
vector3_t *FV3_Mul(vector3_t *a_i, fixed_t a_c)
vector4_t *FV4_MulEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o)
{
a_o->x = FixedMul(a_i->x, a_c->x);
a_o->y = FixedMul(a_i->y, a_c->y);
a_o->z = FixedMul(a_i->z, a_c->z);
a_o->a = FixedMul(a_i->a, a_c->a);
return a_o;
}
vector3_t *FV3_Mul(vector3_t *a_i, const vector3_t *a_c)
{
return FV3_MulEx(a_i, a_c, a_i);
}
vector3_t *FV3_DivideEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o)
vector4_t *FV4_Mul(vector4_t *a_i, const vector4_t *a_c)
{
a_o->x = FixedDiv(a_i->x, a_c);
a_o->y = FixedDiv(a_i->y, a_c);
a_o->z = FixedDiv(a_i->z, a_c);
return FV4_MulEx(a_i, a_c, a_i);
}
vector3_t *FV3_DivideEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
{
a_o->x = FixedDiv(a_i->x, a_c->x);
a_o->y = FixedDiv(a_i->y, a_c->y);
a_o->z = FixedDiv(a_i->z, a_c->z);
return a_o;
}
vector3_t *FV3_Divide(vector3_t *a_i, fixed_t a_c)
vector4_t *FV4_DivideEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o)
{
a_o->x = FixedDiv(a_i->x, a_c->x);
a_o->y = FixedDiv(a_i->y, a_c->y);
a_o->z = FixedDiv(a_i->z, a_c->z);
a_o->a = FixedDiv(a_i->a, a_c->a);
return a_o;
}
vector3_t *FV3_Divide(vector3_t *a_i, const vector3_t *a_c)
{
return FV3_DivideEx(a_i, a_c, a_i);
}
vector4_t *FV4_Divide(vector4_t *a_i, const vector4_t *a_c)
{
return FV4_DivideEx(a_i, a_c, a_i);
}
// Vector Complex Math
vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o)
{
@ -325,6 +404,19 @@ vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a
return a_o;
}
vector4_t *FV4_Midpoint(const vector4_t *a_1, const vector4_t *a_2, vector4_t *a_o)
{
a_o->x = FixedDiv(a_2->x - a_1->x, 2 * FRACUNIT);
a_o->y = FixedDiv(a_2->y - a_1->y, 2 * FRACUNIT);
a_o->z = FixedDiv(a_2->z - a_1->z, 2 * FRACUNIT);
a_o->a = FixedDiv(a_2->a - a_1->a, 2 * FRACUNIT);
a_o->x = a_1->x + a_o->x;
a_o->y = a_1->y + a_o->y;
a_o->z = a_1->z + a_o->z;
a_o->a = a_1->z + a_o->a;
return a_o;
}
fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2)
{
fixed_t xs = FixedMul(p2->x - p1->x, p2->x - p1->x);
@ -333,6 +425,15 @@ fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2)
return FixedSqrt(xs + ys + zs);
}
fixed_t FV4_Distance(const vector4_t *p1, const vector4_t *p2)
{
fixed_t xs = FixedMul(p2->x - p1->x, p2->x - p1->x);
fixed_t ys = FixedMul(p2->y - p1->y, p2->y - p1->y);
fixed_t zs = FixedMul(p2->z - p1->z, p2->z - p1->z);
fixed_t za = FixedMul(p2->a - p1->a, p2->a - p1->a);
return FixedSqrt(xs + ys + zs + za);
}
fixed_t FV3_Magnitude(const vector3_t *a_normal)
{
fixed_t xs = FixedMul(a_normal->x, a_normal->x);
@ -341,6 +442,15 @@ fixed_t FV3_Magnitude(const vector3_t *a_normal)
return FixedSqrt(xs + ys + zs);
}
fixed_t FV4_Magnitude(const vector4_t *a_normal)
{
fixed_t xs = FixedMul(a_normal->x, a_normal->x);
fixed_t ys = FixedMul(a_normal->y, a_normal->y);
fixed_t zs = FixedMul(a_normal->z, a_normal->z);
fixed_t as = FixedMul(a_normal->a, a_normal->a);
return FixedSqrt(xs + ys + zs + as);
}
// Also returns the magnitude
fixed_t FV3_NormalizeEx(const vector3_t *a_normal, vector3_t *a_o)
{
@ -351,11 +461,26 @@ fixed_t FV3_NormalizeEx(const vector3_t *a_normal, vector3_t *a_o)
return magnitude;
}
fixed_t FV4_NormalizeEx(const vector4_t *a_normal, vector4_t *a_o)
{
fixed_t magnitude = FV4_Magnitude(a_normal);
a_o->x = FixedDiv(a_normal->x, magnitude);
a_o->y = FixedDiv(a_normal->y, magnitude);
a_o->z = FixedDiv(a_normal->z, magnitude);
a_o->a = FixedDiv(a_normal->a, magnitude);
return magnitude;
}
fixed_t FV3_Normalize(vector3_t *a_normal)
{
return FV3_NormalizeEx(a_normal, a_normal);
}
fixed_t FV4_Normalize(vector4_t *a_normal)
{
return FV4_NormalizeEx(a_normal, a_normal);
}
vector3_t *FV3_NegateEx(const vector3_t *a_1, vector3_t *a_o)
{
a_o->x = -a_1->x;
@ -364,11 +489,25 @@ vector3_t *FV3_NegateEx(const vector3_t *a_1, vector3_t *a_o)
return a_o;
}
vector4_t *FV4_NegateEx(const vector4_t *a_1, vector4_t *a_o)
{
a_o->x = -a_1->x;
a_o->y = -a_1->y;
a_o->z = -a_1->z;
a_o->a = -a_1->a;
return a_o;
}
vector3_t *FV3_Negate(vector3_t *a_1)
{
return FV3_NegateEx(a_1, a_1);
}
vector4_t *FV4_Negate(vector4_t *a_1)
{
return FV4_NegateEx(a_1, a_1);
}
boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2)
{
fixed_t Epsilon = FRACUNIT / FRACUNIT;
@ -383,11 +522,31 @@ boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2)
return false;
}
boolean FV4_Equal(const vector4_t *a_1, const vector4_t *a_2)
{
fixed_t Epsilon = FRACUNIT / FRACUNIT;
if ((abs(a_2->x - a_1->x) > Epsilon) ||
(abs(a_2->y - a_1->y) > Epsilon) ||
(abs(a_2->z - a_1->z) > Epsilon) ||
(abs(a_2->a - a_1->a) > Epsilon))
{
return true;
}
return false;
}
fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2)
{
return (FixedMul(a_1->x, a_2->x) + FixedMul(a_1->y, a_2->y) + FixedMul(a_1->z, a_2->z));
}
fixed_t FV4_Dot(const vector4_t *a_1, const vector4_t *a_2)
{
return (FixedMul(a_1->x, a_2->x) + FixedMul(a_1->y, a_2->y) + FixedMul(a_1->z, a_2->z) + FixedMul(a_1->a, a_2->a));
}
vector3_t *FV3_Cross(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o)
{
a_o->x = FixedMul(a_1->y, a_2->z) - FixedMul(a_1->z, a_2->y);
@ -424,8 +583,9 @@ vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vec
return FV3_Copy(out, &Line[1]);
}
// Return the point between <20>Line[0]<5D> and <20>Line[1]<5D>
FV3_Mul(&V, t);
// Return the point between "Line[0]" and "Line[1]"
vector3_t T = { t, t, t };
FV3_Mul(&V, &T);
return FV3_AddEx(&Line[0], &V, out);
}
@ -440,7 +600,8 @@ void FV3_ClosestPointOnVector(const vector3_t *dir, const vector3_t *p, vector3_
fixed_t t = FV3_Dot(dir, p);
// Return the point on the line closest
FV3_MulEx(dir, t, out);
vector3_t T = { t, t, t };
FV3_MulEx(dir, &T, out);
return;
}
@ -782,7 +943,7 @@ void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fi
//
// Multiplies a vector by the specified matrix
//
void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out)
const vector3_t *FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out)
{
#define M(row,col) matrix->m[col * 4 + row]
out->x = FixedMul(vec->x, M(0, 0))
@ -800,6 +961,34 @@ void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *
+ FixedMul(vec->z, M(2, 2))
+ M(2, 3);
#undef M
return out;
}
const vector4_t *FM_MultMatrixVec4(const matrix_t *matrix, const vector4_t *vec, vector4_t *out)
{
#define M(row,col) matrix->m[col * 4 + row]
out->x = FixedMul(vec->x, M(0, 0))
+ FixedMul(vec->y, M(0, 1))
+ FixedMul(vec->z, M(0, 2))
+ FixedMul(vec->a, M(0, 3));
out->y = FixedMul(vec->x, M(1, 0))
+ FixedMul(vec->y, M(1, 1))
+ FixedMul(vec->z, M(1, 2))
+ FixedMul(vec->a, M(1, 3));
out->z = FixedMul(vec->x, M(2, 0))
+ FixedMul(vec->y, M(2, 1))
+ FixedMul(vec->z, M(2, 2))
+ FixedMul(vec->a, M(2, 3));
out->a = FixedMul(vec->x, M(3, 0))
+ FixedMul(vec->y, M(3, 1))
+ FixedMul(vec->z, M(3, 2))
+ FixedMul(vec->a, M(3, 3));
#undef M
return out;
}
//
@ -807,13 +996,12 @@ void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *
//
// Multiples one matrix into another
//
void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
void FM_MultMatrixEx(const matrix_t *m1, const matrix_t *m2, matrix_t *dest)
{
matrix_t result;
UINT8 i, j;
#define M(row,col) multme->m[col * 4 + row]
#define D(row,col) dest->m[col * 4 + row]
#define R(row,col) result.m[col * 4 + row]
#define M(row,col) m1->m[col * 4 + row]
#define D(row,col) m2->m[col * 4 + row]
#define R(row,col) dest->m[col * 4 + row]
for (i = 0; i < 4; i++)
{
@ -821,13 +1009,16 @@ void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
R(i, j) = FixedMul(D(i, 0), M(0, j)) + FixedMul(D(i, 1), M(1, j)) + FixedMul(D(i, 2), M(2, j)) + FixedMul(D(i, 3), M(3, j));
}
M_Memcpy(dest, &result, sizeof(matrix_t));
#undef R
#undef D
#undef M
}
void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
{
FM_MultMatrixEx(dest, multme, dest);
}
//
// Translate
//

View file

@ -299,10 +299,10 @@ vector3_t *FV3_AddEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o)
vector3_t *FV3_Add(vector3_t *a_i, const vector3_t *a_c);
vector3_t *FV3_SubEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o);
vector3_t *FV3_Sub(vector3_t *a_i, const vector3_t *a_c);
vector3_t *FV3_MulEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o);
vector3_t *FV3_Mul(vector3_t *a_i, fixed_t a_c);
vector3_t *FV3_DivideEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o);
vector3_t *FV3_Divide(vector3_t *a_i, fixed_t a_c);
vector3_t *FV3_MulEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o);
vector3_t *FV3_Mul(vector3_t *a_i, const vector3_t *a_c);
vector3_t *FV3_DivideEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o);
vector3_t *FV3_Divide(vector3_t *a_i, const vector3_t *a_c);
vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o);
fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2);
fixed_t FV3_Magnitude(const vector3_t *a_normal);
@ -327,6 +327,32 @@ vector3_t *FV3_IntersectionPoint(const vector3_t *vNormal, const vector3_t *vLin
UINT8 FV3_PointOnLineSide(const vector3_t *point, const vector3_t *line);
boolean FV3_PointInsideBox(const vector3_t *point, const vector3_t *box);
struct vector4_t
{
fixed_t x, y, z, a;
};
vector4_t *FV4_Load(vector4_t *vec, fixed_t x, fixed_t y, fixed_t z, fixed_t a);
vector4_t *FV4_UnLoad(vector4_t *vec, fixed_t *x, fixed_t *y, fixed_t *z, fixed_t *a);
vector4_t *FV4_Copy(vector4_t *a_o, const vector4_t *a_i);
vector4_t *FV4_AddEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o);
vector4_t *FV4_Add(vector4_t *a_i, const vector4_t *a_c);
vector4_t *FV4_SubEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o);
vector4_t *FV4_Sub(vector4_t *a_i, const vector4_t *a_c);
vector4_t *FV4_MulEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o);
vector4_t *FV4_Mul(vector4_t *a_i, const vector4_t *a_c);
vector4_t *FV4_DivideEx(const vector4_t *a_i, const vector4_t *a_c, vector4_t *a_o);
vector4_t *FV4_Divide(vector4_t *a_i, const vector4_t *a_c);
vector4_t *FV4_Midpoint(const vector4_t *a_1, const vector4_t *a_2, vector4_t *a_o);
fixed_t FV4_Distance(const vector4_t *p1, const vector4_t *p2);
fixed_t FV4_Magnitude(const vector4_t *a_normal);
fixed_t FV4_NormalizeEx(const vector4_t *a_normal, vector4_t *a_o);
fixed_t FV4_Normalize(vector4_t *a_normal);
vector4_t *FV4_NegateEx(const vector4_t *a_1, vector4_t *a_o);
vector4_t *FV4_Negate(vector4_t *a_1);
boolean FV4_Equal(const vector4_t *a_1, const vector4_t *a_2);
fixed_t FV4_Dot(const vector4_t *a_1, const vector4_t *a_2);
struct matrix_t
{
fixed_t m[16];
@ -334,8 +360,10 @@ struct matrix_t
void FM_LoadIdentity(matrix_t* matrix);
void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius);
void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out);
const vector3_t *FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out);
const vector4_t *FM_MultMatrixVec4(const matrix_t *matrix, const vector4_t *vec, vector4_t *out);
void FM_MultMatrix(matrix_t *dest, const matrix_t *multme);
void FM_MultMatrixEx(const matrix_t *m1, const matrix_t *m2, matrix_t *dest);
void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);

File diff suppressed because it is too large Load diff

View file

@ -302,6 +302,7 @@ INT32 MR_Retry(INT32 choice);
INT32 MR_EndGame(INT32 choice);
INT32 MR_MapChange(INT32 choice);
INT32 MR_SetupMultiPlayer(INT32 choice);
INT32 MR_HandleSetupMultiPlayerMenu(INT32 choice);
INT32 MR_ConfirmSpectate(INT32 choice);
INT32 MR_ConfirmEnterGame(INT32 choice);
INT32 MR_ConfirmTeamScramble(INT32 choice);
@ -339,6 +340,12 @@ void MD_DrawReplayHut(void);
void MD_DrawTimeAttackMenu(void);
void MD_DrawMPMainMenu(void);
void MD_DrawSetupMultiPlayerMenu(void);
void MD_DrawCssStatBacker(void);
void MD_DrawCssStatBars(void);
void MD_DrawCssColourBar(void);
void MD_DrawCssCharacter(void);
void MD_DrawBarCssSelector(void);
void MD_DrawGridCssSelector(void);
void MD_DrawConnectMenu(void);
void MD_DrawVideoMode(void);
void MD_DrawAddons(void);
@ -353,6 +360,8 @@ void MD_DrawViewServer(void);
void MD_DrawDiscordRequests(void);
#endif
INT32 MapGridSelectToSkin(INT32 column, INT32 row);
// Maybe this goes here????? Who knows.
boolean M_MouseNeeded(void);
@ -413,6 +422,7 @@ extern consvar_t cv_dummygpdifficulty, cv_dummygpencore, cv_dummygpcup;
extern consvar_t cv_dummymenuplayer, cv_dummyteam, cv_dummyspectate, cv_dummyscramble;
extern consvar_t cv_dummyattackingrings, cv_dummyattackingstacking, cv_dummyattackingchaining;
extern consvar_t cv_dummyattackingslipdash, cv_dummyattackingpurpledrift, cv_dummyattackingslopeboost;
extern consvar_t cv_dummyattackingairdrop, cv_dummyattackingbumpspark;
extern consvar_t cv_dummystaff;
extern consvar_t cv_dummymultiplayer, cv_dummyip, cv_dummyname, cv_dummyfollower, cv_dummycolor;
extern consvar_t cv_dummyserverpage;
@ -461,6 +471,9 @@ fixed_t M_GetMapThumbnail(INT16 mapnum, patch_t **out);
// Moviemode menu updating
void Moviemode_option_Onchange(void);
void Skinsort_option_Onchange(void);
void Skinselectstyle_option_Onchange(void);
// Player Setup menu colors linked list
struct menucolor_t {
menucolor_t *next;
@ -478,6 +491,8 @@ UINT16 M_GetColorAfter(UINT16 color);
void M_InitPlayerSetupColors(void);
void M_FreePlayerSetupColors(void);
extern boolean menu_text_input;
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -1303,7 +1303,7 @@ void M_SaveFrame(void)
{
// munge planar buffer to linear
linear = screens[2];
I_ReadScreen(linear);
I_ReadScreen(linear, 1);
}
#ifdef HWRENDER
else
@ -1576,6 +1576,7 @@ void M_DoScreenShot(void)
char pathname[MAX_WADPATH];
boolean ret = false;
UINT8 *linear = NULL;
UINT8 *palette;
// Don't take multiple screenshots, obviously
takescreenshot = false;
@ -1608,30 +1609,30 @@ void M_DoScreenShot(void)
freename = Newsnapshotfile(pathname,"tga");
#endif
if (!freename)
goto failure;
if (rendermode == render_soft)
{
// munge planar buffer to linear
linear = screens[2];
I_ReadScreen(linear);
}
if (!freename)
goto failure;
// save the pcx file
#ifdef HWRENDER
if (rendermode == render_opengl)
ret = HWR_Screenshot(va(pandf,pathname,freename));
else
#endif
{
I_ReadScreen(linear, 1);
M_CreateScreenShotPalette();
#ifdef USE_PNG
ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
#else
ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
#endif
palette = screenshot_palette;
}
#ifdef HWRENDER
else if (rendermode == render_opengl)
{
linear = HWR_GetScreenshot(1);
palette = nullptr;
}
#endif
#ifdef USE_PNG
ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, palette);
#else
ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, palette);
#endif
failure:
if (ret)

View file

@ -431,68 +431,75 @@ static void M_DrawTickStats(void)
perfstatcol_t detailed_thinkercount_col2 = {94, 119, V_BLUEMAP, detailed_thinkercount_row2};
perfstatcol_t misc_calls_col = {170, 216, V_PURPLEMAP, misc_calls_row};
for (i = 0; i < NUM_THINKERLISTS; i++)
if (G_GamestateUsesLevel())
{
for (thinker = thlist[i].next; thinker != &thlist[i]; thinker = thinker->next)
for (i = 0; i < NUM_THINKERLISTS; i++)
{
thinkercount++;
if (thinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
removecount++;
else if (i == THINK_POLYOBJ)
polythcount++;
else if (i == THINK_MAIN)
mainthcount++;
else if (i == THINK_MOBJ)
for (thinker = thlist[i].next; thinker != &thlist[i]; thinker = thinker->next)
{
if (thinker->function.acp1 == (actionf_p1)P_MobjThinker)
thinkercount++;
if (thinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
removecount++;
else if (i == THINK_POLYOBJ)
polythcount++;
else if (i == THINK_MAIN)
mainthcount++;
else if (i == THINK_MOBJ)
{
mobj_t *mobj = (mobj_t*)thinker;
mobjcount++;
if (mobj->flags & MF_NOTHINK)
nothinkcount++;
else if (mobj->flags & MF_SCENERY)
scenerycount++;
else
regularcount++;
if (thinker->function.acp1 == (actionf_p1)P_MobjThinker)
{
mobj_t *mobj = (mobj_t*)thinker;
mobjcount++;
if (mobj->flags & MF_NOTHINK)
nothinkcount++;
else if (mobj->flags & MF_SCENERY)
scenerycount++;
else
regularcount++;
}
}
else if (i == THINK_DYNSLOPE)
dynslopethcount++;
else if (i == THINK_PRECIP)
precipcount++;
}
else if (i == THINK_DYNSLOPE)
dynslopethcount++;
else if (i == THINK_PRECIP)
precipcount++;
}
}
draw_row = 10;
M_DrawPerfTiming(&tictime_col);
M_DrawPerfTiming(&thinker_time_col);
M_DrawPerfTiming(&detailed_thinker_time_col);
if (server)
M_DrawPerfTiming(&bot_time_col);
M_DrawPerfTiming(&extra_thinker_time_col);
draw_row = 10;
M_DrawPerfCount(&thinkercount_col);
M_DrawPerfCount(&detailed_thinkercount_col);
M_DrawPerfCount(&mobjthinkercount_col);
if (nothinkcount)
M_DrawPerfCount(&nothinkcount_col);
M_DrawPerfCount(&detailed_thinkercount_col2);
if (M_HighResolution())
if (G_GamestateUsesLevel())
{
V_DrawSmallString(212, 10, V_MONOSPACE | V_ALLOWLOWERCASE | V_PURPLEMAP, "Calls:");
M_DrawPerfTiming(&thinker_time_col);
M_DrawPerfTiming(&detailed_thinker_time_col);
if (server)
M_DrawPerfTiming(&bot_time_col);
M_DrawPerfTiming(&extra_thinker_time_col);
draw_row = 15;
}
else
{
draw_row = 10;
}
M_DrawPerfCount(&thinkercount_col);
M_DrawPerfCount(&detailed_thinkercount_col);
M_DrawPerfCount(&mobjthinkercount_col);
M_DrawPerfCount(&misc_calls_col);
if (nothinkcount)
M_DrawPerfCount(&nothinkcount_col);
M_DrawPerfCount(&detailed_thinkercount_col2);
if (M_HighResolution())
{
V_DrawSmallString(212, 10, V_MONOSPACE | V_ALLOWLOWERCASE | V_PURPLEMAP, "Calls:");
draw_row = 15;
}
else
{
draw_row = 10;
}
M_DrawPerfCount(&misc_calls_col);
}
}
void M_DrawPerfStats(void)

View file

@ -382,7 +382,7 @@ static boolean M_TextInputHandleBase(textinput_t *input, INT32 key, boolean emot
key = '/';
// same capslock code as hu_stuff.c's HU_responder. Check there for details.
key = /*cv_keyboardlayout.value == 3 ? CON_ShitAndAltGrChar(key) : */CON_ShiftChar(key);
key = CON_ShiftChar(key);
// enter a char into the command prompt
if (key < 32 || key > 127)

View file

@ -67,7 +67,8 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
{0, NULL}
};
consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://ms.kartkrew.org/ms/api", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange);
//https://ms.kartkrew.org/ms/api
consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://ms.srb2classic.net/MS/1", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange);
consvar_t cv_rendezvousserver = CVAR_INIT ("holepunchserver", "relay.kartkrew.org", CV_SAVE, NULL, NULL);
consvar_t cv_servername = CVAR_INIT ("servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);
consvar_t cv_server_contact = CVAR_INIT ("server_contact", "", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);

View file

@ -1,7 +1,7 @@
// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James R.
// Copyright (C) 2023 by Kart Krew
// Copyright (C) 2025 by James Robert Roman
// Copyright (C) 2025 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -180,10 +180,8 @@ Obj_InitLoopEndpoint
void
Obj_InitLoopCenter (mobj_t *center)
{
const mapthing_t *mt = center->spawnpoint;
center_max_revolution(center) = mt->args[1] * FRACUNIT / 360;
center_set_flip(center, mt->args[0]);
center_max_revolution(center) = center->args[1] * FRACUNIT / 360;
center_set_flip(center, center->args[0]);
}
void
@ -260,7 +258,7 @@ Obj_LoopEndpointCollide
const fixed_t magnitude = R_PointToDist2(0, 0, px, py);
const fixed_t newX = FixedDiv(px, magnitude);
const fixed_t newY = FixedDiv(py, magnitude);
s->origin_shift = {FixedMul(newX, FCOS(anchor->angle)),
FixedMul(newY, FSIN(anchor->angle))};
}
@ -285,15 +283,15 @@ Obj_LoopEndpointCollide
cam->enter_tic = leveltime;
cam->exit_tic = INFTICS;
if (center->spawnpoint->args[4]) // is camera distance set?
if (center->args[4]) // is camera distance set?
{
cam->zoom_out_speed = center->spawnpoint->args[2];
cam->zoom_in_speed = center->spawnpoint->args[3];
cam->dist = center->spawnpoint->args[4] * FRACUNIT;
cam->pan = FixedAngle(center->spawnpoint->args[5] * FRACUNIT);
cam->pan_speed = center->spawnpoint->args[6] * FRACUNIT;
cam->pan_accel = center->spawnpoint->args[7];
cam->pan_back = center->spawnpoint->args[8];
cam->zoom_out_speed = center->args[2];
cam->zoom_in_speed = center->args[3];
cam->dist = center->args[4] * FRACUNIT;
cam->pan = FixedAngle(center->args[5] * FRACUNIT);
cam->pan_speed = center->args[6] * FRACUNIT;
cam->pan_accel = center->args[7];
cam->pan_back = center->args[8];
}
else
{

229
src/p_deepcopy.cpp Normal file
View file

@ -0,0 +1,229 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2024 by Kart Krew
//
// 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 p_deepcopy.cpp
/// \brief Methods for deep copying
#include "p_deepcopy.h"
#include "typedef.h"
#include "z_zone.h"
#include "taglist.h"
#include "r_defs.h"
/*--------------------------------------------------
static void P_DeepCopy(Type *target, Type *source, void (*callback)(Type *, Type *))
Make a deep copy of a struct, by using memcpy
for an initial shallow copy, and a callback
function to handle any memory addresses.
Input Arguments:-
Type: The type of the structs.
target: The struct to copy into.
source: The struct to copy from.
callback: A callback function, intended to replace
pointers after the initial shallow copy.
Return:-
N/A
--------------------------------------------------*/
template <typename Type>
static void P_DeepCopy(Type *target, Type *source, void (*callback)(Type *, Type *))
{
memcpy(target, source, sizeof(Type));
if (callback != nullptr)
{
callback(target, source);
}
}
/*--------------------------------------------------
static void P_DeepCopyArray(Type **target_array, Type **source_array, size_t source_len, void (*callback)(Type *, Type *))
Make a deep copy of an array of structs, by using
memcpy for an initial shallow copy, and a callback
function to handle any memory addresses for each
individual struct.
Input Arguments:-
Type: The type of the structs.
target_array: The start of the array to copy into.
This will be allocated by this function, so
it should be freed beforehand.
source_array: The start of the array to copy from.
source_len: The length of the array to copy from.
callback: A callback function, intended to replace
pointers after the initial shallow copy.
Return:-
N/A
--------------------------------------------------*/
template <typename Type>
static void P_DeepCopyArray(Type **target_array, Type **source_array, size_t source_len, void (*callback)(Type *, Type *))
{
const size_t source_total = source_len * sizeof(Type);
*target_array = static_cast<Type *>(Z_Calloc(source_total, PU_LEVEL, nullptr));
memcpy(*target_array, *source_array, source_total);
if (callback != nullptr)
{
for (size_t i = 0; i < source_len; i++)
{
Type *target = &(*target_array)[i];
Type *source = &(*source_array)[i];
callback(target, source);
}
}
}
/*--------------------------------------------------
static void copy_taglist_tags(taglist_t *target, taglist_t *source)
Make a deep copy of taglist's tags fields.
Used as a helper function for other callbacks,
does not work as a full deep copy of taglist_t
on its own.
Input Arguments:-
target: The struct to copy into.
source: The struct to copy from.
Return:-
N/A
--------------------------------------------------*/
static void copy_taglist_tags(taglist_t *target, taglist_t *source)
{
if (source->count)
{
target->tags = static_cast<mtag_t *>(
memcpy(
Z_Malloc(
source->count * sizeof(mtag_t),
PU_LEVEL,
nullptr
),
source->tags,
source->count * sizeof(mtag_t)
)
);
}
}
/*--------------------------------------------------
static void copy_sector_callback(sector_t *target, sector_t *source)
Handles memory addresses after creating a shallow copy
of a sector_t, to turn it into a deep copy.
Input Arguments:-
target: The struct to copy into.
source: The struct to copy from.
Return:-
N/A
--------------------------------------------------*/
static void copy_sector_callback(sector_t *target, sector_t *source)
{
// (Not a true deep copy until all of the memory addresses are accounted for.)
copy_taglist_tags(&target->tags, &source->tags);
}
/*--------------------------------------------------
void P_DeepCopySector(sector_t *target, sector_t *source)
See header file for description.
--------------------------------------------------*/
void P_DeepCopySector(sector_t *target, sector_t *source)
{
P_DeepCopy<sector_t>(target, source, copy_sector_callback);
}
/*--------------------------------------------------
void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len)
See header file for description.
--------------------------------------------------*/
void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len)
{
P_DeepCopyArray<sector_t>(target_array, source_array, source_len, copy_sector_callback);
}
/*--------------------------------------------------
static void copy_line_callback(line_t *target, line_t *source)
Handles memory addresses after creating a shallow copy
of a line_t, to turn it into a deep copy.
Input Arguments:-
target: The struct to copy into.
source: The struct to copy from.
Return:-
N/A
--------------------------------------------------*/
static void copy_line_callback(line_t *target, line_t *source)
{
// (Not a true deep copy until all of the memory addresses are accounted for.)
copy_taglist_tags(&target->tags, &source->tags);
}
/*--------------------------------------------------
void P_DeepCopyLine(line_t *target, line_t *source)
See header file for description.
--------------------------------------------------*/
void P_DeepCopyLine(line_t *target, line_t *source)
{
P_DeepCopy<line_t>(target, source, copy_line_callback);
}
/*--------------------------------------------------
void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len)
See header file for description.
--------------------------------------------------*/
void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len)
{
P_DeepCopyArray<line_t>(target_array, source_array, source_len, copy_line_callback);
}
/*--------------------------------------------------
void P_DeepCopySide(line_t *target, line_t *source)
See header file for description.
--------------------------------------------------*/
void P_DeepCopySide(side_t *target, side_t *source)
{
P_DeepCopy<side_t>(target, source, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.)
}
/*--------------------------------------------------
void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len)
See header file for description.
--------------------------------------------------*/
void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len)
{
P_DeepCopyArray<side_t>(target_array, source_array, source_len, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.)
}

131
src/p_deepcopy.h Normal file
View file

@ -0,0 +1,131 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2024 by Kart Krew
//
// 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 p_deepcopy.h
/// \brief Methods for deep copying
#ifndef __P_DEEPCOPY__
#define __P_DEEPCOPY__
#include "doomdef.h"
#ifdef __cplusplus
extern "C" {
#endif
/*--------------------------------------------------
void P_DeepCopySector(sector_t *target, sector_t *source);
Make a deep copy of a single sector_t.
Input Arguments:-
target: The struct to copy into.
source: The struct to copy from.
Return:-
N/A
--------------------------------------------------*/
void P_DeepCopySector(sector_t *target, sector_t *source);
/*--------------------------------------------------
void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len);
Make a deep copy of an array of sector_t.
Input Arguments:-
target_array: The start of the array to copy into.
This will be allocated by this function, so
it should be freed beforehand.
source_array: The start of the array to copy from.
source_len: The length of the array to copy from.
Return:-
N/A
--------------------------------------------------*/
void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len);
/*--------------------------------------------------
void P_DeepCopyLine(line_t *target, line_t *source)
Make a deep copy of a single line_t.
Input Arguments:-
target: The struct to copy into.
source: The struct to copy from.
Return:-
N/A
--------------------------------------------------*/
void P_DeepCopyLine(line_t *target, line_t *source);
/*--------------------------------------------------
void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len)
Make a deep copy of an array of line_t.
Input Arguments:-
target_array: The start of the array to copy into.
This will be allocated by this function, so
it should be freed beforehand.
source_array: The start of the array to copy from.
source_len: The length of the array to copy from.
Return:-
N/A
--------------------------------------------------*/
void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len);
/*--------------------------------------------------
void P_DeepCopySide(line_t *target, line_t *source)
Make a deep copy of a single side_t.
Input Arguments:-
target: The struct to copy into.
source: The struct to copy from.
Return:-
N/A
--------------------------------------------------*/
void P_DeepCopySide(side_t *target, side_t *source);
/*--------------------------------------------------
void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len)
Make a deep copy of an array of side_t.
Input Arguments:-
target_array: The start of the array to copy into.
This will be allocated by this function, so
it should be freed beforehand.
source_array: The start of the array to copy from.
source_len: The length of the array to copy from.
Return:-
N/A
--------------------------------------------------*/
void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __P_DEEPCOPY__

View file

@ -3170,11 +3170,27 @@ void A_AttractChase(mobj_t *actor)
if (actor->extravalue1 >= 21)
{
// Base add is 4 tics for 9,9, adds 1 tic for each point closer to the 1,1 end
actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true);
actor->target->player->ringtime += K_GetKartRingPower(actor->target->player, true);
if (actor->extravalue3 && !P_IsObjectOnGround(actor->target))
{
actor->target->momz -= (FixedMul(gravity, mapobjectscale))*P_MobjFlip(actor->target);
actor->target->player->ringboost += 7;
actor->target->player->ringtime += 7;
actor->target->player->ringdrop = true;
}
else
{
// Base add is 4 tics for 9,9, adds 1 tic for each point closer to the 1,1 end
actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true);
actor->target->player->ringtime += K_GetKartRingPower(actor->target->player, true);
}
S_StartSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume);
if (actor->extravalue3 && !P_IsObjectOnGround(actor->target))
{
actor->target->momz -= (FixedMul(gravity, mapobjectscale)/2 + FixedMul(gravity, mapobjectscale)/4)*P_MobjFlip(actor->target);
}
if (actor->target->player->rings <= 10)
{
S_StartSoundAtVolume(actor->target, sfx_ringlw, 255 - actor->target->player->rings*10);
@ -3199,6 +3215,7 @@ void A_AttractChase(mobj_t *actor)
( actor->target->height + offz )* P_MobjFlip(actor));
actor->extravalue1++;
}
}
else // Collecting
{
@ -3424,7 +3441,14 @@ void A_FishJump(mobj_t *actor)
if (i < MAXPLAYERS)
{
fixed_t rad = actor->radius>>FRACBITS;
P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<<FRACBITS, P_RandomRange(rad, -rad)<<FRACBITS, 0, (mobjtype_t)locvar2);
fixed_t rand_x;
fixed_t rand_y;
rand_y = P_RandomRange(rad, -rad)<<FRACBITS;
rand_x = P_RandomRange(rad, -rad)<<FRACBITS;
P_SpawnMobjFromMobj(actor, rand_x, rand_y, 0, (mobjtype_t)locvar2);
}
}
@ -3516,7 +3540,7 @@ void A_SignPlayer(mobj_t *actor)
if (!actor->target->player)
return;
// Set the sign to be an appropriate background color for this player's skincolor.
actor->color = skincolors[actor->target->player->skincolor].invcolor;
actor->frame += skincolors[actor->target->player->skincolor].invshade;
@ -7230,7 +7254,7 @@ void A_StateRangeByParameter(mobj_t *actor)
if (locvar2 - locvar1 < 0)
return; // invalid range
if (udmf)
{
parameter = actor->args[0];
@ -9673,7 +9697,7 @@ void A_FlickyCenter(mobj_t *actor)
return;
homeRadius = locvar2 ? FixedMul(abs(locvar2), actor->scale) : 384*actor->scale;
if (!actor->tracer)
{
mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false, 0);
@ -10118,11 +10142,16 @@ void A_FlameParticle(mobj_t *actor)
rad = actor->radius>>FRACBITS;
hei = actor->height>>FRACBITS;
particle = P_SpawnMobjFromMobj(actor,
P_RandomRange(rad, -rad)<<FRACBITS,
P_RandomRange(rad, -rad)<<FRACBITS,
P_RandomRange(hei/2, hei)<<FRACBITS,
type);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = P_RandomRange(hei/2, hei)<<FRACBITS;
rand_y = P_RandomRange(rad, -rad)<<FRACBITS;
rand_x = P_RandomRange(rad, -rad)<<FRACBITS;
particle = P_SpawnMobjFromMobj(actor, rand_x, rand_y, rand_z, type);
P_SetObjectMomZ(particle, 2<<FRACBITS, false);
}
@ -10595,16 +10624,11 @@ void A_ItemPop(mobj_t *actor)
remains->flags2 = actor->flags2; // Transfer flags2
remains->fuse = actor->fuse; // Transfer respawn timer
remains->cvmem = leveltime;
remains->threshold = actor->threshold;
if (remains->threshold != 69 && remains->threshold != 70)
{
remains->threshold = 68;
}
remains->threshold = (actor->threshold == 69 ? 69 : 68);
// To insure this information doesn't have to be rediscovered every time you look at this function...
// A threshold of 0 is for a "living", ordinary random item.
// 68 means regular popped random item debris.
// 69 used to mean old Karma Item behaviour (now you can replicate this with MF2_DONTRESPAWN).
// 70 is a powered up Overtime item.
// 69 means Karmabomb dropped Item behaviour
remains->skin = NULL;
remains->spawnpoint = actor->spawnpoint;
@ -10612,7 +10636,7 @@ void A_ItemPop(mobj_t *actor)
//if (actor->info->deathsound)
//S_StartSound(remains, actor->info->deathsound);
if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumper <= 0) && !itembreaker)
{
actor->target->player->itemroulette = KROULETTE_ACTIVE;
@ -10621,7 +10645,7 @@ void A_ItemPop(mobj_t *actor)
{
K_AwardScaledPlayerRings(actor->target->player, ASR_ITEMBOX);
if (numgotboxes < 3)
if (numtargets < 4)
{
actor->target->player->itemtype = KITEM_POGOSPRING;
actor->target->player->itemamount += 1;
@ -10631,7 +10655,7 @@ void A_ItemPop(mobj_t *actor)
remains->flags2 &= ~MF2_AMBUSH;
// Here at mapload in battle?
if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP))
if (gametyperules & GTR_BUMPERS && actor->threshold != 69)
numgotboxes++;
P_RemoveMobj(actor);
@ -10695,8 +10719,15 @@ void A_JawzExplode(mobj_t *actor)
{
INT32 speed, speed2;
truc = P_SpawnMobj(actor->x + P_RandomRange(-8, 8)*FRACUNIT, actor->y + P_RandomRange(-8, 8)*FRACUNIT,
actor->z + P_RandomRange(0, 8)*FRACUNIT, MT_BOOMPARTICLE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = actor->z + P_RandomRange(0, 8)*FRACUNIT;
rand_y = actor->y + P_RandomRange(-8, 8)*FRACUNIT;
rand_x = actor->x + P_RandomRange(-8, 8)*FRACUNIT;
truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMPARTICLE);
truc->scale = actor->scale*2;
speed = FixedMul(7*FRACUNIT, actor->scale)>>FRACBITS;
@ -10739,7 +10770,8 @@ void A_SPBChase(mobj_t *actor)
return;
}
// Find the player with the best rank
// Find the player with the best rank. In gametypes with SPB forcing on WANTED
// players, find our most-wanted player.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].exiting)
@ -10754,7 +10786,15 @@ void A_SPBChase(mobj_t *actor)
if (players[i].kartstuff[k_respawn])
continue;*/ // respawning
if (players[i].position < bestrank)
if ((gametyperules & GTR_WANTED) && (gametyperules & GTR_WANTEDSPB))
{
if (K_IsPlayerMostWanted(&players[i]))
{
player = &players[i];
break;
}
}
else if (players[i].position < bestrank)
{
bestrank = players[i].position;
player = &players[i];
@ -10807,7 +10847,14 @@ void A_SPBChase(mobj_t *actor)
else if (actor->extravalue2-- <= 0)
actor->extravalue1 = 0; // back to SEEKING
spbplace = actor->tracer->player->position;
if ((gametyperules & GTR_WANTED) && (gametyperules & GTR_WANTEDSPB))
{
spbplace = (actor->tracer->player - players);
}
else
{
spbplace = actor->tracer->player->position;
}
}
if ((K_RingsActive() == true) ) // Spawn rings to make up for the fact first has ring grabbing
@ -10885,10 +10932,15 @@ void A_SPBChase(mobj_t *actor)
: (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target
&& xyspeed > K_GetKartSpeed(actor->tracer->player, false, false)/4) // Don't display speedup lines at pitifully low speeds
{
mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale),
actor->y + (P_RandomRange(-24,24) * actor->scale),
actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale),
MT_FASTLINE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale);
rand_y = actor->y + (P_RandomRange(-24,24) * actor->scale);
rand_x = actor->x + (P_RandomRange(-24,24) * actor->scale);
mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE);
fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
//fast->momx = (3*actor->momx)/4;
//fast->momy = (3*actor->momy)/4;
@ -10921,7 +10973,15 @@ void A_SPBChase(mobj_t *actor)
&& !players[actor->lastlook].spectator
&& !players[actor->lastlook].exiting)
{
spbplace = players[actor->lastlook].position;
if ((gametyperules & GTR_WANTED) && (gametyperules & GTR_WANTEDSPB))
{
spbplace = actor->lastlook;
}
else
{
spbplace = players[actor->lastlook].position;
}
if (actor->extravalue2-- <= 0 && players[actor->lastlook].mo)
{
P_SetTarget(&actor->tracer, players[actor->lastlook].mo);
@ -11283,8 +11343,15 @@ void A_FZBoomSmoke(mobj_t *actor)
for (i = 0; i < 8+(4*var1); i++)
{
mobj_t *smoke = P_SpawnMobj(actor->x + (P_RandomRange(-rad, rad)*actor->scale), actor->y + (P_RandomRange(-rad, rad)*actor->scale),
actor->z + (P_RandomRange(0, 72)*actor->scale), MT_THOK);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = actor->z + (P_RandomRange(0, 72)*actor->scale);
rand_y = actor->y + (P_RandomRange(-rad, rad)*actor->scale);
rand_x = actor->x + (P_RandomRange(-rad, rad)*actor->scale);
mobj_t *smoke = P_SpawnMobj(rand_x, rand_y, rand_z, MT_THOK);
P_SetMobjState(smoke, S_FZEROSMOKE1);
smoke->tics += P_RandomRange(-3, 4);
@ -11445,13 +11512,20 @@ void A_MementosTPParticles(mobj_t *actor)
mobj_t *mo2;
int i = 0;
thinker_t *th;
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
if (LUA_CallAction(A_MEMENTOSTPPARTICLES, (actor)))
return;
for (; i<4; i++)
{
particle = P_SpawnMobj(actor->x + (P_RandomRange(-256, 256)<<FRACBITS), actor->y + (P_RandomRange(-256, 256)<<FRACBITS), actor->z + (P_RandomRange(48, 256)<<FRACBITS), MT_MEMENTOSPARTICLE);
rand_z = actor->z + (P_RandomRange(48, 256)<<FRACBITS);
rand_y = actor->y + (P_RandomRange(-256, 256)<<FRACBITS);
rand_x = actor->x + (P_RandomRange(-256, 256)<<FRACBITS);
particle = P_SpawnMobj(rand_x, rand_y, rand_z, MT_MEMENTOSPARTICLE);
particle->frame = 0;
particle->color = ((i%2) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK));
particle->destscale = 1;
@ -11512,9 +11586,15 @@ void A_ReaperThinker(mobj_t *actor)
if (actor->scale < 2<<FRACBITS) // we haven't finished growing YET.
{
// Spawn particles as we grow out of the floor, ゴ ゴ ゴ ゴ
for (; i<16; i++)
for (; i < 16; i++)
{
particle = P_SpawnMobj(actor->x + (P_RandomRange(-60, 60)<<FRACBITS), actor->y + (P_RandomRange(-60, 60)<<FRACBITS), actor->z, MT_THOK);
fixed_t rand_x;
fixed_t rand_y;
rand_y = actor->y + (P_RandomRange(-60, 60)<<FRACBITS);
rand_x = actor->x + (P_RandomRange(-60, 60)<<FRACBITS);
particle = P_SpawnMobj(rand_x, rand_y, actor->z, MT_THOK);
particle->momz = 20<<FRACBITS;
particle->color = ((i%2 !=0) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK));
particle->frame = 0;
@ -11659,9 +11739,3 @@ void A_ReaperThinker(mobj_t *actor)
}
}
}
void A_DeathSpin(mobj_t *actor)
{
INT32 locvar1 = var1;
actor->angle += locvar1;
}

View file

@ -39,6 +39,7 @@
#include "k_boss.h"
#include "p_spec.h"
#include "k_objects.h"
#include "k_odds.h"
#include "acs/interface.h"
// CTF player names
@ -943,12 +944,16 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost)
(void)snaptopost;
// SRB2kart - 150117
if (K_UsingLegacyCheckpoints() && player->exiting) //STOP MESSING UP MY STATS FASDFASDF
return;
// Going backwards triggers sound
if (K_CheckpointThreshold(false) == numstarposts
? post->health - player->starpostnum > 1
: post->health >= player->starpostnum + K_CheckpointThreshold(false))
{
if (!player->checkskip)
if (!player->checkskip && !player->bot)
{
S_StartSound(toucher, sfx_s26d);
if (netgame && cv_antigrief.value)
@ -1565,88 +1570,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
case MT_PLAYER:
if (damagetype != DMG_SPECTATOR)
{
target->fuse = 2*TICRATE; // timer before mobj disappears from view (even if not an actual player)
target->fuse = TICRATE;
target->momx = target->momy = target->momz = 0;
if (target->player && !(skins[target->player->skin].flags & SF_NOGIBS))
{
angle_t playerFlingAngle;
angle_t kartFlingAngle;
if (source && !P_MobjWasRemoved(source))
{
playerFlingAngle = kartFlingAngle = R_PointToAngle2(
source->x - source->momx, source->y - source->momy,
target->x, target->y
);
}
else
{
kartFlingAngle = target->angle;
if (P_RandomByte() & 1)
{
kartFlingAngle -= ANGLE_45;
}
else
{
kartFlingAngle += ANGLE_45;
}
playerFlingAngle = kartFlingAngle + ANGLE_180;
}
// Spawn kart frame
mobj_t *kart = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_KART_LEFTOVER);
if (kart && !P_MobjWasRemoved(kart))
{
kart->angle = target->angle;
kart->color = target->color;
kart->extravalue1 = target->player->kartweight;
kart->fuse = 2*TICRATE;
// Copy interp data
kart->old_angle = target->old_angle;
kart->old_x = target->old_x;
kart->old_y = target->old_y;
kart->old_z = target->old_z;
P_InstaThrust(kart, kartFlingAngle, 1 * kart->scale);
P_SetObjectMomZ(kart, 10*FRACUNIT, false);
const angle_t aOffset = ANGLE_22h;
UINT8 i;
angle_t tireAngle;
mobj_t *tire;
// Spawn tires
tireAngle = kartFlingAngle - ANGLE_90 - ANGLE_22h;
for (i = 0; i < 4; i++)
{
if (i == 2) tireAngle += ANGLE_90;
tire = P_SpawnMobjFromMobj(kart, 0, 0, 0, MT_KART_TIRE);
tire->fuse = 2*TICRATE;
tire->angle = tireAngle;
P_InstaThrust(tire, tireAngle, 3 * tire->scale);
P_SetObjectMomZ(tire, 10*FRACUNIT, false);
tireAngle += (aOffset * 2);
}
}
P_InstaThrust(target, playerFlingAngle, 4 * target->scale);
P_SetObjectMomZ(target, 14*FRACUNIT, false);
}
if (target->player && (skins[target->player->skin].flags & SF_OLDDEATH))
{
P_SetObjectMomZ(target, 14*FRACUNIT, false);
}
P_SetObjectMomZ(target, 14*FRACUNIT, false);
P_PlayDeathSound(target);
}
break;
@ -2220,15 +2146,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false;
}
// Check if we should allow explosion combos.
if ((explosioncombo == false) && (player->flashing > 0 || player->squishedtimer > 0))
{
// Check if we should allow explosion combos.
if ((explosioncombo == false) && (player->flashing > 0 || player->squishedtimer > 0))
{
// Post-hit invincibility
K_DoInstashield(player);
return false;
}
// Post-hit invincibility
K_DoInstashield(player);
return false;
}
}
@ -2243,7 +2166,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{
K_TakeBumpersFromPlayer(source->player, player, 1);
}
else if (damage & DMG_KARMA)
else if (damage & DMG_KARMA && source->player->bumper <= 0)
{
source->player->karmapoints++;
if (source->player->karmapoints >= 2)
@ -2268,11 +2191,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
K_DestroyBumpers(player, 1);
}
if (!(type == DMG_NORMAL || type == DMG_WIPEOUT || type == DMG_VOLTAGE || type == DMG_FLIPOVER))
if (inflictor && (inflictor->type == MT_ORBINAUT || inflictor->type == MT_ORBINAUT_SHIELD
|| inflictor->type == MT_JAWZ || inflictor->type == MT_JAWZ_SHIELD || inflictor->type == MT_JAWZ_DUD
|| inflictor->type == MT_SMK_THWOMP || inflictor->player))
{
player->sneakertimer = 0;
player->sneakertimer = player->numsneakers = 0;
player->mo->flags2 &= ~MF2_WATERRUN;
}
player->driftboost = 0;
@ -2280,6 +2204,20 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->glanceDir = 0;
player->pflags &= ~PF_GAINAX;
if (gametyperules & GTR_BUMPERS)
{
if (player->bumper <= 0)
{
player->karmadelay = comebacktime;
if ((gametyperules & GTR_KARMA) && player->karmamode == 2 )
{
mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE);
S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound);
player->karmamode = 0;
}
}
}
INT16 ringburst = 3;
// Handle ringloss based on hittype.

View file

@ -303,6 +303,8 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype);
void P_RespawnSpecials(void);
mobj_t *P_AllocateMobj(void);
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
void P_CalculatePrecipFloor(precipmobj_t *mobj);
@ -319,6 +321,7 @@ void P_RunOverlays(void);
#define OV_DONT3DOFFSET 1<<1
#define OV_DONTXYSCALE 1<<2
#define OV_DONTROLL 1<<3
#define OV_DONTBAKEOFFSET 1<<4
void P_HandleMinecartSegments(mobj_t *mobj);
void P_MobjThinker(mobj_t *mobj);

View file

@ -1,6 +1,7 @@
// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by Kart Krew
// Copyright (C) 2025 by James Robert Roman.
// Copyright (C) 2025 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -11,7 +12,6 @@
#include "doomdef.h"
#include "d_player.h"
#include "doomstat.h"
#include "k_kart.h"
#include "p_local.h"
#include "p_setup.h"

View file

@ -1290,21 +1290,6 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
return BMIT_CONTINUE;
}
else if (thing->type == MT_KART_LEFTOVER)
{
// see if it went over / under
if (g_tm.thing->z > thing->z + thing->height)
return BMIT_CONTINUE; // overhead
if (g_tm.thing->z + g_tm.thing->height < thing->z)
return BMIT_CONTINUE; // underneath
if (P_IsObjectOnGround(thing) && g_tm.thing->momz < 0)
K_KartBouncing(g_tm.thing, thing, true, false);
else
K_KartBouncing(g_tm.thing, thing, false, false);
return BMIT_CONTINUE;
}
else if (thing->flags & MF_SOLID)
{
// see if it went over / under
@ -1650,7 +1635,7 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld)
{
P_TestLine(ld);
}
else if (g_tm.maxstep > 0)
else
{
if (g_tm.thing->z < open.floor)
{
@ -2522,20 +2507,6 @@ fixed_t P_GetThingStepUp(mobj_t *thing, fixed_t destX, fixed_t destY)
return maxstep;
}
// Used for averging height values for step up.
static fixed_t avgheight(fixed_t a, fixed_t b)
{
if (((b > 0) && (a > (INT32_MAX - b))) ||
((b < 0) && (a < (INT32_MIN - b))))
{
return b + (a - b) / 2;
}
else
{
return (a + b) / 2;
}
}
static boolean
increment_move
( mobj_t * thing,
@ -2558,7 +2529,7 @@ increment_move
radius = max(radius, mapobjectscale);
// And Big Large (tm) movements can skip over slopes.
radius = min(radius, 16*mapobjectscale);
radius = min(radius, 8*mapobjectscale);
// (This whole "step" system is flawed; it was OK before, but the addition of slopes has
// exposed the problems with doing it like this. The right thing to do would be to use
@ -2621,8 +2592,7 @@ increment_move
if (P_UsingStepUp(thing))
{
//All things are affected by their scale.
fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy);
fixed_t stepheight = 0;
fixed_t maxstep = g_tm.maxstep;
if (thing->type == MT_SKIM)
maxstep = 0;
@ -2644,9 +2614,7 @@ increment_move
// Step up
if (thing->z < g_tm.floorz)
{
stepheight = avgheight(g_tm.floorz - thing->z, g_tm.floorstep);
if (stepheight <= maxstep)
if (g_tm.floorz - thing->z <= maxstep)
{
thing->z = thing->floorz = g_tm.floorz;
thing->floorrover = g_tm.floorrover;
@ -2659,9 +2627,7 @@ increment_move
}
else if (g_tm.ceilingz < thingtop)
{
stepheight = avgheight(thingtop - g_tm.ceilingz, g_tm.ceilingstep);
if (stepheight <= maxstep)
if (thingtop - g_tm.ceilingz <= maxstep)
{
thing->z = ( thing->ceilingz = g_tm.ceilingz ) - thing->height;
thing->ceilingrover = g_tm.ceilingrover;
@ -3513,16 +3479,31 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
mmomx = mo->player->rmomx;
mmomy = mo->player->rmomy;
if (!cv_kartbumpspark.value || modeattacking != ATTACKING_NONE)
UINT32 bumpspark = K_GetBumpSpark();
// The easy solution is to do this :^)
UINT32 basecharge = min(mo->player->driftcharge, K_GetKartDriftSparkValue(mo->player));
if ((bumpspark < BUMPSPARK_ALL) ||
(modeattacking != ATTACKING_NONE && G_CompatLevel(0x0009)))
{
mo->player->drift = 0;
mo->player->driftcharge = 0;
if (!bumpspark)
{
// Bumps removing spark would be less frustrating if you didn't get your drift
// removed too. Losing sparks is a fair punishment, drifting RIGHT for
// daring to scrape a wall for a wide LEFT turn is horrendous and leads to
// awful gluewalling.
// TL;DR: I hate wrongdrifts and hopefully this is an okay middle ground.
mo->player->drift = 0;
}
mo->player->driftcharge = (bumpspark == BUMPSPARK_RESET100) ? basecharge : 0;
}
// Regardless of bumpspark, tell bots to stop drifting if they bonk a wall.
K_BotSetDriftState(mo->player, DRIFTSTATE_AUTO, TICRATE);
if (!cv_kartbumpspring.value || modeattacking != ATTACKING_NONE)
if ((!cv_kartbumpspring.value && modeattacking == ATTACKING_NONE) || (modeattacking != ATTACKING_NONE && G_CompatLevel(0x0009)))
{
mo->player->pogospring = 0;
}
@ -3530,24 +3511,12 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
slidemo = mo;
bestslideline = result->line;
if (bestslideline == NULL && cv_showgremlins.value)
/*if (mo->health <= 0)
{
// debug
mobj_t*x = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK);
x->frame = FF_FULLBRIGHT | FF_ADD;
x->renderflags = RF_ALWAYSONTOP;
x->color = SKINCOLOR_RED;
CONS_Printf(
"GREMLIN: leveltime=%u x=%f y=%f z=%f angle=%f\n",
leveltime,
FixedToFloat(mo->x),
FixedToFloat(mo->y),
FixedToFloat(mo->z),
AngleToFloat(R_PointToAngle2(0, 0, oldmomx, oldmomy))
);
tmxmove = mo->momx;
tmymove = mo->momy;
}
else if*/
if (mo->eflags & MFE_JUSTBOUNCEDWALL) // Stronger push-out
{
tmxmove = mmomx;

View file

@ -78,8 +78,9 @@ void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *Line, vector3_t
FV3_SubEx(p, v1, &c);
d = R_PointToDist2(0, v2->z, R_PointToDist2(v2->x, v2->y, v1->x, v1->y), v1->z);
vector3_t vd = { d, d, d };
FV3_Copy(&n, &V);
FV3_Divide(&n, d);
FV3_Divide(&n, &vd);
t = FV3_Dot(&n, &c);
@ -95,7 +96,8 @@ void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *Line, vector3_t
return;
}
FV3_Mul(&n, t);
vector3_t tv = { t, t, t };
FV3_Mul(&n, &tv);
FV3_AddEx(v1, &n, result);
return;
@ -1800,12 +1802,32 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
pos_x += hity_x;
pos_y += hity_y;
}
else
else if (FixedMul(hitx_x, hitx_x) + FixedMul(hitx_y, hitx_y) < FixedMul(hity_x, hity_x) + FixedMul(hity_y, hity_y))
{
gridpos_x += dir_x;
pos_x += hitx_x;
pos_y += hitx_y;
}
else
{
// we hit a corner, round down towards south-east
if (dir_x < 0 && dir_y > 0)
{
gridpos_y += dir_y;
}
else if (dir_x > 0 && dir_y < 0)
{
gridpos_x += dir_x;
}
else
{
gridpos_x += dir_x;
gridpos_y += dir_y;
}
pos_x += hitx_x;
pos_y += hitx_y;
}
if (flags & PT_ADDLINES)
if (!P_BlockLinesIterator(gridpos_x, gridpos_y, PIT_AddLineIntercepts))

View file

@ -50,6 +50,7 @@
#include "k_terrain.h"
#include "k_collide.h"
#include "k_objects.h"
#include "k_odds.h"
// BlanKart
#include "blan/b_soc.h"
@ -1159,6 +1160,13 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (mo->player)
{
// MF2_OBJECTFLIP is relative -- flips sector reverse gravity back to normal
if (mo->flags2 & MF2_OBJECTFLIP)
{
gravityadd = -gravityadd;
mo->eflags ^= MFE_VERTICALFLIP;
}
if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way
P_PlayerFlip(mo);
@ -1732,6 +1740,12 @@ void P_XYMovement(mobj_t *mo)
mo->momz = transfermomz;
mo->standingslope = NULL;
mo->terrain = NULL;
if (mo->player)
{
S_StartSound(mo, sfx_kc5e);
mo->player->walltransfered = true;
}
}
}
}
@ -2844,7 +2858,6 @@ void P_PlayerZMovement(mobj_t *mo)
P_CheckMarioBlocks(mo);
mo->momz = 0;
P_CheckGravity(mo, true);
}
}
@ -6616,17 +6629,19 @@ static boolean P_IsMiscCapObject(INT32 type)
{
switch (type)
{
case MT_RING:
case MT_FLINGRING:
return true;
if (cv_kartdebugrings.value)
return true;
break;
case MT_RANDOMITEM:
return true;
if (itembreaker)
return true;
break;
default:
return false;
break;
}
@ -6739,6 +6754,18 @@ void P_RunOverlays(void)
mo->roll = mo->target->roll;
}
if (!(mo->threshold & OV_DONTBAKEOFFSET))
{
// offsets
mo->bakexoff = mo->target->bakexoff;
mo->bakeyoff = mo->target->bakeyoff;
mo->bakezoff = mo->target->bakezoff;
// pivots
mo->bakexpiv = mo->target->bakexpiv;
mo->bakeypiv = mo->target->bakeypiv;
mo->bakezpiv = mo->target->bakezpiv;
}
if ((mo->flags & MF_DONTENCOREMAP) != (mo->target->flags & MF_DONTENCOREMAP))
mo->flags ^= MF_DONTENCOREMAP;
@ -6834,7 +6861,7 @@ static void P_PlayerInvincibilityOverlay(mobj_t *thing)
{
I_Assert(thing->target != NULL);
I_Assert(thing->target->player != NULL);
if (!thing->target->player->invincibilitytimer)
{
P_SetTarget(&thing->target, NULL);
@ -7521,14 +7548,13 @@ static void P_MobjSceneryThink(mobj_t *mobj)
case MT_PLAYERARROW:
if (mobj->target && mobj->target->health
&& mobj->target->player && !mobj->target->player->spectator
&& mobj->target->health && mobj->target->player->playerstate != PST_DEAD
/*&& players[displayplayers[0]].mo && !players[displayplayers[0]].spectator*/)
&& mobj->target->health && mobj->target->player->playerstate != PST_DEAD)
{
fixed_t scale = 3*mobj->target->scale;
mobj->color = mobj->target->color;
K_MatchGenericExtraFlags(mobj, mobj->target);
if ((gametype == GT_RACE || mobj->target->player->bumper <= 0)
if ((!(gametyperules & GTR_ITEMARROWS) || (gametyperules & GTR_BUMPERS && mobj->target->player->bumper <= 0))
#if 1 // Set to 0 to test without needing to host
|| (P_IsDisplayPlayer(mobj->target->player))
#endif
@ -7633,6 +7659,17 @@ static void P_MobjSceneryThink(mobj_t *mobj)
else
mobj->tracer->renderflags |= RF_DONTDRAW;
}
else if (mobj->target->player->flametimer > 1)
{
//itembar = mobj->target->player->flametimer; -- not today satan
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_FLAMESHIELD;
if (leveltime & 1)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
}
else if (mobj->target->player->growshrinktimer > 0)
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
@ -7940,7 +7977,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
}
else // Apply gravity to fall downwards.
{
P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true);
P_SetObjectMomZ(mobj, -3*FRACUNIT/2, true);
if (mobj->player && (skins[mobj->player->skin].flags & SF_OLDDEATH))
{
@ -7953,11 +7990,16 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
if (!(mobj->fuse % 8))
{
fixed_t r = mobj->radius >> FRACBITS;
mobj_t *explosion = P_SpawnMobj(
mobj->x + (P_RandomRange(r, -r) << FRACBITS),
mobj->y + (P_RandomRange(r, -r) << FRACBITS),
mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS),
MT_SONIC3KBOSSEXPLODE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS);
rand_y = mobj->y + (P_RandomRange(r, -r) << FRACBITS);
rand_x = mobj->x + (P_RandomRange(r, -r) << FRACBITS);
mobj_t *explosion = P_SpawnMobj(rand_x, rand_y, rand_z, MT_SONIC3KBOSSEXPLODE);
S_StartSound(explosion, sfx_s3kb4);
}
P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true);
@ -8341,7 +8383,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
// No need to check water. Who cares?
P_RingThinker(mobj);
P_AddMiscCap(mobj);
if (cv_kartdebugrings.value)
P_AddMiscCap(mobj);
A_AttractChase(mobj);
return false;
@ -8917,7 +8960,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
smoke->momy = mobj->target->momy/2;
smoke->momz = mobj->target->momz/2;
P_Thrust(smoke, mobj->angle+FixedAngle(P_RandomRange(135, 225)<<FRACBITS), P_RandomRange(0, 8) * mobj->target->scale);
fixed_t rand_angle;
fixed_t rand_move;
rand_move = P_RandomRange(0, 8) * mobj->target->scale;
rand_angle = mobj->angle+FixedAngle(P_RandomRange(135, 225)<<FRACBITS);
P_Thrust(smoke, rand_angle, rand_move);
}
break;
case MT_SPARKLETRAIL:
@ -9291,7 +9340,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
statenum_t state = (mobj->state-states);
if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator
|| (gametyperules & GTR_CIRCUIT || mobj->target->player->bumper))
|| mobj->target->player->bumper || !(gametyperules & GTR_KARMA))
{
P_RemoveMobj(mobj);
return false;
@ -9391,11 +9440,18 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
else
{
P_SpawnMobj(mobj->x + (P_RandomRange(-48,48)*mobj->scale),
mobj->y + (P_RandomRange(-48,48)*mobj->scale),
mobj->z + (24*mobj->scale) + (P_RandomRange(-8,8)*mobj->scale),
MT_SIGNSPARKLE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = mobj->z + (24*mobj->scale) + (P_RandomRange(-8,8)*mobj->scale);
rand_y = mobj->y + (P_RandomRange(-48,48)*mobj->scale);
rand_x = mobj->x + (P_RandomRange(-48,48)*mobj->scale);
P_SpawnMobj(rand_x, rand_y, rand_z, MT_SIGNSPARKLE);
mobj->flags &= ~MF_NOGRAVITY;
if (abs(mobj->z - mobj->movefactor) <= (512*mobj->scale) && !mobj->cvmem)
{
if (mobj->info->seesound)
@ -9453,7 +9509,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
else // fire + smoke pillar
{
UINT8 i;
mobj_t *fire = P_SpawnMobj(mobj->x + (P_RandomRange(-32, 32)*mobj->scale), mobj->y + (P_RandomRange(-32, 32)*mobj->scale), mobj->z, MT_THOK);
fixed_t rand_x;
fixed_t rand_y;
rand_y = mobj->y + (P_RandomRange(-32, 32)*mobj->scale);
rand_x = mobj->x + (P_RandomRange(-32, 32)*mobj->scale);
mobj_t *fire = P_SpawnMobj(rand_x, rand_y, mobj->z, MT_THOK);
fire->sprite = SPR_FPRT;
fire->frame = FF_FULLBRIGHT|FF_TRANS30;
@ -9465,7 +9528,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
for (i = 0; i < 2; i++)
{
mobj_t *smoke = P_SpawnMobj(mobj->x + (P_RandomRange(-16, 16)*mobj->scale), mobj->y + (P_RandomRange(-16, 16)*mobj->scale), mobj->z, MT_SMOKE);
rand_y = mobj->y + (P_RandomRange(-16, 16)*mobj->scale);
rand_x = mobj->x + (P_RandomRange(-16, 16)*mobj->scale);
mobj_t *smoke = P_SpawnMobj(rand_x, rand_y, mobj->z, MT_SMOKE);
P_SetMobjState(smoke, S_FZSLOWSMOKE1);
smoke->scale = mobj->scale;
@ -9689,9 +9755,15 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if ((mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) && !(leveltime % 10))
{
mobj_t *dust = P_SpawnMobj(mobj->x + (P_RandomRange(-4, 4)<<FRACBITS),
mobj->y + (P_RandomRange(-4, 4)<<FRACBITS),
mobj->z + (P_RandomRange(0, 2)<<FRACBITS), MT_BBZDUST);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = mobj->z + (P_RandomRange(0, 2)<<FRACBITS);
rand_y = mobj->y + (P_RandomRange(-4, 4)<<FRACBITS);
rand_x = mobj->x + (P_RandomRange(-4, 4)<<FRACBITS);
mobj_t *dust = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BBZDUST);
P_SetScale(dust, mobj->scale/2);
P_InstaThrust(dust, FixedAngle(P_RandomRange(0,359)<<FRACBITS), abs(mobj->tracer->momz)/2);
@ -10196,7 +10268,7 @@ static void P_MonitorFuseThink(mobj_t *mobj)
static boolean P_FuseThink(mobj_t *mobj)
{
if (mobj->fuse <= TICRATE && (mobj->type == MT_RANDOMITEM || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK))
if (mobj->fuse <= TICRATE && ((mobj->type == MT_RANDOMITEM && mobj->threshold == 69) || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK))
mobj->renderflags ^= RF_DONTDRAW;
mobj->fuse--;
@ -10224,7 +10296,7 @@ static boolean P_FuseThink(mobj_t *mobj)
{
;
}
else if (gametype == GT_BATTLE)
else if (gametyperules & GTR_BATTLEBOXES)
{
if (mobj->threshold != 69)
break;
@ -10243,7 +10315,7 @@ static boolean P_FuseThink(mobj_t *mobj)
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type);
// Transfer flags2 (strongbox, objectflip, bossnotrap)
newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW;
newmobj->flags2 = mobj->flags2;
}
P_RemoveMobj(mobj); // make sure they disappear
@ -10925,6 +10997,24 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
}
}
mobj_t *P_AllocateMobj(void)
{
mobj_t *mobj;
if (mobjcache != NULL)
{
mobj = mobjcache;
mobjcache = mobjcache->hnext;
memset(mobj, 0, sizeof(*mobj));
}
else
{
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
}
return mobj;
}
//
// P_SpawnMobj
//
@ -10950,16 +11040,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
type = MT_RAY;
}
if (mobjcache != NULL)
{
mobj = mobjcache;
mobjcache = mobjcache->hnext;
memset(mobj, 0, sizeof(*mobj));
}
else
{
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
}
mobj = P_AllocateMobj();
// this is officially a mobj, declared as soon as possible.
mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
@ -11171,9 +11252,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->color = BALLOONCOLORS[P_RandomKey(sizeof(BALLOONCOLORS))];
}
break;
case MT_KART_LEFTOVER:
mobj->color = SKINCOLOR_RED;
break;
case MT_REDRING: // Make MT_REDRING red by default
mobj->color = skincolor_redring;
break;
@ -11713,9 +11791,9 @@ void P_FreePrecipMobj(precipmobj_t *mobj)
// Clearing out stuff for savegames
void P_RemoveSavegameMobj(mobj_t *mobj)
{
// unlink from sector and block lists
if (((thinker_t *)mobj)->function.acp1 == (actionf_p1)P_NullPrecipThinker)
{
// unlink from sector and block lists
P_UnsetPrecipThingPosition((precipmobj_t *)mobj);
if (precipsector_list)
@ -11738,20 +11816,18 @@ void P_RemoveSavegameMobj(mobj_t *mobj)
P_DelSeclist(sector_list);
sector_list = NULL;
}
P_DeleteMobjStringArgs(mobj);
}
// stop any playing sound
S_StopSound(mobj);
R_RemoveMobjInterpolator(mobj);
P_DeleteMobjStringArgs(mobj);
R_RemoveMobjInterpolator(mobj);
// free block
// Here we use the same code as R_RemoveThinkerDelayed, but without reference counting (we're removing everything so it shouldn't matter) and without touching currentthinker since we aren't in P_RunThinkers
{
thinker_t *thinker = (thinker_t *)mobj;
thinker_t *next = thinker->next;
(next->prev = thinker->prev)->next = next;
Z_Free(thinker);
}
P_UnlinkThinker((thinker_t*)mobj);
}
static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
@ -12039,8 +12115,8 @@ void P_PrecipitationEffects(void)
*/
mobjtype_t P_GetMobjtype(UINT16 mthingtype)
{
mobjtype_t i;
for (i = 0; i < NUMMOBJTYPES; i++)
INT32 i;
for (i = NUMMOBJTYPES-1; i >= 0; i--)
if (mthingtype == mobjinfo[i].doomednum)
return i;
return MT_UNKNOWN;
@ -12055,7 +12131,7 @@ void P_RespawnSpecials(void)
INT32 time = 30*TICRATE; // Respawn things in empty dedicated servers
mapthing_t *mthing = NULL;
if (gametype == GT_BATTLE && numgotboxes >= (4*nummapboxes/5) && !itembreaker) // Battle Mode respawns all boxes in a different way
if ((gametyperules & GTR_BATTLEBOXES) && !itembreaker && numgotboxes >= (4*nummapboxes/5)) // Battle Mode respawns all boxes in a different way
{
thinker_t *th;
@ -12308,14 +12384,18 @@ void P_SpawnPlayer(INT32 playernum)
P_FlashPal(p, 0, 0); // Resets
p->grieftime = 0;
p->spinoutrot = 0;
if (gametyperules & GTR_BUMPERS)
if (gametyperules & GTR_ITEMARROWS)
{
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW);
P_SetTarget(&overheadarrow->target, mobj);
overheadarrow->renderflags |= RF_DONTDRAW;
P_SetScale(overheadarrow, mobj->destscale);
}
if (gametyperules & GTR_BUMPERS)
{
if (p->spectator)
{
// HEY! No being cheap...
@ -12330,7 +12410,7 @@ void P_SpawnPlayer(INT32 playernum)
K_SpawnPlayerBattleBumpers(p);
}
else if (p->bumper <= 0)
else if (p->bumper <= 0 && (gametyperules & GTR_KARMA))
{
mobj_t *karmahitbox = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_KARMAHITBOX); // Player hitbox is too small!!
P_SetTarget(&karmahitbox->target, mobj);
@ -13510,10 +13590,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
}
case MT_RANDOMITEM:
{
if (leveltime < 3)
{
mobj->flags2 |= MF2_BOSSNOTRAP; // mark as here on map start
}
mobj->flags2 |= MF2_BOSSNOTRAP; // mark as here on map start
nummapboxes++;
break;
}

View file

@ -312,6 +312,9 @@ struct mobj_t
fixed_t old_spritexscale2, old_spriteyscale2;
fixed_t old_spritexoffset, old_spriteyoffset;
fixed_t old_spritexoffset2, old_spriteyoffset2;
// X and Y offsets that rotate alongside the sprite.
INT16 rollingxoffset, rollingyoffset;
pslope_t *floorspriteslope; // The slope that the floorsprite is rotated by
INT16 lightlevel; // Add to sector lightlevel, -255 - 255
@ -404,6 +407,7 @@ struct mobj_t
// Extra values are for internal use for whatever you want
INT32 extravalue1;
INT32 extravalue2;
INT32 extravalue3;
// Custom values are not to be altered by us!
// They are for SOCs to store things in.
@ -421,6 +425,8 @@ struct mobj_t
UINT8 shadowcolor; // Palette index to use for rendering the shadow
fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision
fixed_t bakexoff, bakeyoff, bakezoff; // BAKED sprite offsets. Simulates visuals in real space, and rotates along the object's sprite
fixed_t bakexpiv, bakeypiv, bakezpiv; // Pivot points for baked offsets. These are *not* rotated with a sprite
terrain_t *terrain; // Terrain definition of the floor this object last hit. NULL when in the air.
mobj_t *terrainOverlay; // Overlay sprite object for terrain
@ -485,6 +491,10 @@ struct precipmobj_t
fixed_t old_spritexscale2, old_spriteyscale2;
fixed_t old_spritexoffset, old_spriteyoffset;
fixed_t old_spritexoffset2, old_spriteyoffset2;
// X and Y offsets that rotate alongside the sprite.
INT16 rollingxoffset, rollingyoffset;
pslope_t *floorspriteslope; // The slope that the floorsprite is rotated by
INT16 lightlevel; // Add to sector lightlevel, -255 - 255
@ -597,6 +607,8 @@ extern boolean slipdashactive;
extern boolean purpledriftactive;
extern boolean slopeboostactive;
extern boolean draftingactive;
extern boolean airdropactive;
extern UINT8 bumpsparkactive;
extern UINT16 bossdisabled;
extern boolean stoppedclock;

View file

@ -162,6 +162,10 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEINT16(save->p, players[i].totalring);
WRITEUINT32(save->p, players[i].realtime);
for (j = 0; j < LAP__MAX; j++)
{
WRITEUINT32(save->p, players[i].laptime[j]);
}
WRITEUINT8(save->p, players[i].laps);
WRITEUINT8(save->p, players[i].latestlap);
@ -254,6 +258,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT16(save->p, players[i].flashing);
WRITEUINT16(save->p, players[i].spinouttimer);
WRITEINT32(save->p, players[i].spinoutrot);
WRITEUINT8(save->p, players[i].spinouttype);
WRITEUINT16(save->p, players[i].flipovertimer);
WRITEANGLE(save->p, players[i].flipoverangle);
@ -322,6 +327,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITESINT8(save->p, players[i].ringmax);
WRITEUINT8(save->p, players[i].pickuprings);
WRITEUINT8(save->p, players[i].ringdelay);
WRITEUINT8(save->p, players[i].ringlock);
WRITEUINT16(save->p, players[i].ringboost);
WRITEUINT16(save->p, players[i].ringtime);
WRITEUINT16(save->p, players[i].superring);
@ -329,6 +335,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT8(save->p, players[i].ringvolume);
WRITEUINT8(save->p, players[i].ringtransparency);
WRITEUINT8(save->p, players[i].airdroptime);
WRITEUINT8(save->p, players[i].ringdrop);
WRITEUINT8(save->p, players[i].curshield);
WRITEUINT8(save->p, players[i].bubblecool);
WRITEUINT8(save->p, players[i].bubbleblowup);
@ -442,6 +451,10 @@ static void P_NetArchivePlayers(savebuffer_t *save)
// Fix janky landing particle
WRITEUINT8(save->p, players[i].prevonground);
// Wall Transfer bonus
WRITEUINT8(save->p, players[i].walltransfered);
WRITEUINT8(save->p, players[i].walltransferboost);
}
TracyCZoneEnd(__zone);
}
@ -517,6 +530,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].totalring = READINT16(save->p); // Total number of rings obtained for GP
players[i].realtime = READUINT32(save->p); // integer replacement for leveltime
for (j = 0; j < LAP__MAX; j++)
{
players[i].laptime[j] = READUINT32(save->p);
}
players[i].laps = READUINT8(save->p); // Number of laps (optional)
players[i].latestlap = READUINT8(save->p);
@ -602,6 +619,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].flashing = READUINT16(save->p);
players[i].spinouttimer = READUINT16(save->p);
players[i].spinoutrot = READINT32(save->p);
players[i].spinouttype = READUINT8(save->p);
players[i].flipoverangle = READUINT16(save->p);
players[i].flipovertimer = READANGLE(save->p);
@ -670,6 +688,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].ringmax = READSINT8(save->p);
players[i].pickuprings = READUINT8(save->p);
players[i].ringdelay = READUINT8(save->p);
players[i].ringlock = READUINT8(save->p);
players[i].ringboost = READUINT16(save->p);
players[i].ringtime = READUINT16(save->p);;
players[i].superring = READUINT16(save->p);
@ -677,6 +696,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].ringvolume = READUINT8(save->p);
players[i].ringtransparency = READUINT8(save->p);
players[i].airdroptime = READUINT8(save->p);
players[i].ringdrop = READUINT8(save->p);
players[i].curshield = READUINT8(save->p);
players[i].bubblecool = READUINT8(save->p);
players[i].bubbleblowup = READUINT8(save->p);
@ -789,7 +811,11 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].maxlink = READINT32(save->p);
// Fix janky landing particle
players[i].prevonground = READUINT8(save->p);
players[i].prevonground = (boolean)READUINT8(save->p);
// Wall Transfer bonus
players[i].walltransfered = (boolean)READUINT8(save->p);
players[i].walltransferboost = READUINT8(save->p);
//players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point
}
@ -1123,7 +1149,7 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save)
#define SD_DIFF3 0x80
// diff3 flags
#define SD_TAGLIST 0x01
#define SD__UNUSED 0x01
#define SD_COLORMAP 0x02
#define SD_CRUMBLESTATE 0x04
#define SD_FLOORLIGHT 0x08
@ -1173,7 +1199,7 @@ static boolean P_SectorStringArgsEqual(const sector_t *sc, const sector_t *spawn
#define LD_FLAG 0x01
#define LD_SPECIAL 0x02
#define LD_CLLCOUNT 0x04
#define LD_TAG 0x04
#define LD_S1TEXOFF 0x08
#define LD_S1TOPTEX 0x10
#define LD_S1BOTTEX 0x20
@ -1187,7 +1213,7 @@ static boolean P_SectorStringArgsEqual(const sector_t *sc, const sector_t *spawn
#define LD_S2MIDTEX 0x08
#define LD_ARGS 0x10
#define LD_STRINGARGS 0x20
#define LD_EXECUTORDELAY 0x40
#define LD__UNUSED 0x40
#define LD_DIFF3 0x80
// diff3 flags
@ -1600,7 +1626,7 @@ static void UnArchiveSectors(savebuffer_t *save)
// Add new entries.
for (j = 0; j < sectors[i].tags.count; j++)
Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i);
Taggroup_Add(tags_sectors, sectors[i].tags.tags[j], i);
}
@ -1678,7 +1704,7 @@ static void UnArchiveSectors(savebuffer_t *save)
static void ArchiveLines(savebuffer_t *save)
{
size_t i;
size_t i, j;
const line_t *li = lines;
const line_t *spawnli = spawnlines;
const side_t *si;
@ -1695,8 +1721,8 @@ static void ArchiveLines(savebuffer_t *save)
if (li->special != spawnli->special)
diff |= LD_SPECIAL;
if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved
diff |= LD_CLLCOUNT;
if (!Tag_Compare(&li->tags, &spawnli->tags))
diff |= LD_TAG;
if (!P_LineArgsEqual(li, spawnli))
diff2 |= LD_ARGS;
@ -1704,9 +1730,6 @@ static void ArchiveLines(savebuffer_t *save)
if (!P_LineStringArgsEqual(li, spawnli))
diff2 |= LD_STRINGARGS;
if (li->executordelay != spawnli->executordelay)
diff2 |= LD_EXECUTORDELAY;
if (li->activation != spawnli->activation)
diff3 |= LD_ACTIVATION;
@ -1756,8 +1779,12 @@ static void ArchiveLines(savebuffer_t *save)
WRITEUINT32(save->p, li->flags);
if (diff & LD_SPECIAL)
WRITEINT16(save->p, li->special);
if (diff & LD_CLLCOUNT)
WRITEINT16(save->p, li->callcount);
if (diff & LD_TAG)
{
WRITEUINT32(save->p, li->tags.count);
for (j = 0; j < li->tags.count; j++)
WRITEINT16(save->p, li->tags.tags[j]);
}
si = &sides[li->sidenum[0]];
if (diff & LD_S1TEXOFF)
@ -1780,13 +1807,11 @@ static void ArchiveLines(savebuffer_t *save)
WRITEINT32(save->p, si->midtexture);
if (diff2 & LD_ARGS)
{
UINT8 j;
for (j = 0; j < NUM_SCRIPT_ARGS; j++)
WRITEINT32(save->p, li->args[j]);
}
if (diff2 & LD_STRINGARGS)
{
UINT8 j;
for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++)
{
size_t len, k;
@ -1803,8 +1828,6 @@ static void ArchiveLines(savebuffer_t *save)
WRITECHAR(save->p, li->stringargs[j][k]);
}
}
if (diff2 & LD_EXECUTORDELAY)
WRITEINT32(save->p, li->executordelay);
if (diff3 & LD_ACTIVATION)
WRITEUINT32(save->p, li->activation);
}
@ -1814,7 +1837,7 @@ static void ArchiveLines(savebuffer_t *save)
static void UnArchiveLines(savebuffer_t *save)
{
UINT16 i;
UINT16 i, j;
line_t *li;
side_t *si;
UINT8 diff, diff2, diff3;
@ -1845,8 +1868,28 @@ static void UnArchiveLines(savebuffer_t *save)
li->flags = READUINT32(save->p);
if (diff & LD_SPECIAL)
li->special = READINT16(save->p);
if (diff & LD_CLLCOUNT)
li->callcount = READINT16(save->p);
if (diff & LD_TAG)
{
size_t ncount = READUINT32(save->p);
// Remove entries from global lists.
for (j = 0; j < lines[i].tags.count; j++)
Taggroup_Remove(tags_lines, lines[i].tags.tags[j], i);
// Reallocate if size differs.
if (ncount != lines[i].tags.count)
{
lines[i].tags.count = ncount;
lines[i].tags.tags = (mtag_t*)Z_Realloc(lines[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL);
}
for (j = 0; j < ncount; j++)
lines[i].tags.tags[j] = READINT16(save->p);
// Add new entries.
for (j = 0; j < lines[i].tags.count; j++)
Taggroup_Add(tags_lines, lines[i].tags.tags[j], i);
}
si = &sides[li->sidenum[0]];
if (diff & LD_S1TEXOFF)
@ -1869,13 +1912,11 @@ static void UnArchiveLines(savebuffer_t *save)
si->midtexture = READINT32(save->p);
if (diff2 & LD_ARGS)
{
UINT8 j;
for (j = 0; j < NUM_SCRIPT_ARGS; j++)
li->args[j] = READINT32(save->p);
}
if (diff2 & LD_STRINGARGS)
{
UINT8 j;
for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++)
{
size_t len = READINT32(save->p);
@ -1894,8 +1935,6 @@ static void UnArchiveLines(savebuffer_t *save)
li->stringargs[j][len] = '\0';
}
}
if (diff2 & LD_EXECUTORDELAY)
li->executordelay = READINT32(save->p);
if (diff3 & LD_ACTIVATION)
li->activation = READUINT32(save->p);
@ -2071,7 +2110,8 @@ typedef enum
{
MD3_GRAVITY = 1,
MD3_MISCCAP = 1<<1,
MD3_BAKEDOFFSET = 1<<2,
MD3_EXTVAL3 = 1<<3,
} mobj_diff3_t;
typedef enum
@ -2254,9 +2294,9 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
// not the default but the most probable
if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0)
diff |= MD_MOM;
if (mobj->radius != mobj->info->radius)
if (mobj->radius != FixedMul(mapobjectscale, mobj->info->radius))
diff |= MD_RADIUS;
if (mobj->height != mobj->info->height)
if (mobj->height != FixedMul(mapobjectscale, mobj->info->height))
diff |= MD_HEIGHT;
if (mobj->flags != mobj->info->flags)
diff |= MD_FLAGS;
@ -2301,11 +2341,11 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
diff |= MD_MOVEFACTOR;
if (mobj->fuse)
diff |= MD_FUSE;
if (mobj->watertop)
if (mobj->watertop != INT32_MAX)
diff |= MD_WATERTOP;
if (mobj->waterbottom)
diff |= MD_WATERBOTTOM;
if (mobj->scale != FRACUNIT)
if (mobj->scale != mapobjectscale)
diff |= MD_SCALE;
if (mobj->destscale != mobj->scale)
diff |= MD_DSCALE;
@ -2348,7 +2388,8 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
diff2 |= MD2_TID;
if (mobj->spritexscale != FRACUNIT || mobj->spriteyscale != FRACUNIT)
diff2 |= MD2_SPRITESCALE;
if (mobj->spritexoffset || mobj->spriteyoffset)
if (mobj->spritexoffset || mobj->spriteyoffset ||
mobj->rollingxoffset || mobj->rollingyoffset)
diff2 |= MD2_SPRITEOFFSET;
if (mobj->sprxoff || mobj->spryoff || mobj->sprzoff)
diff2 |= MD2_WORLDOFFSET;
@ -2383,6 +2424,11 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
diff3 |= MD3_GRAVITY;
if (mobj == misccap)
diff3 |= MD3_MISCCAP;
if (mobj->bakexoff || mobj->bakeyoff || mobj->bakezoff || mobj->bakexpiv ||
mobj->bakeypiv || mobj->bakezpiv)
diff3 |= MD3_BAKEDOFFSET;
if (mobj->extravalue3)
diff3 |= MD3_EXTVAL3;
if (diff3 != 0)
diff2 |= MD2_MORE;
@ -2587,6 +2633,8 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
{
WRITEFIXED(save->p, mobj->spritexoffset);
WRITEFIXED(save->p, mobj->spriteyoffset);
WRITEINT16(save->p, mobj->rollingxoffset);
WRITEINT16(save->p, mobj->rollingyoffset);
}
if (diff2 & MD2_WORLDOFFSET)
{
@ -2651,13 +2699,26 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
}
if (diff2 & MD2_TERRAIN)
{
WRITEUINT32(save->p, K_GetTerrainHeapIndex(mobj->terrain));
WRITEUINT32(save->p, K_GetTerrainHeapIndex(mobj->terrain) + 1);
WRITEUINT32(save->p, SaveMobjnum(mobj->terrainOverlay));
}
if (diff3 & MD3_GRAVITY)
{
WRITEFIXED(save->p, mobj->gravity);
}
if (diff3 & MD3_BAKEDOFFSET)
{
WRITEFIXED(save->p, mobj->bakexoff);
WRITEFIXED(save->p, mobj->bakeyoff);
WRITEFIXED(save->p, mobj->bakezoff);
WRITEFIXED(save->p, mobj->bakexpiv);
WRITEFIXED(save->p, mobj->bakeypiv);
WRITEFIXED(save->p, mobj->bakezpiv);
}
if (diff3 & MD3_EXTVAL3)
{
WRITEINT32(save->p, mobj->extravalue3);
}
WRITEUINT32(save->p, mobj->mobjnum);
}
@ -3540,7 +3601,22 @@ static inline pslope_t *LoadSlope(UINT32 slopeid)
return NULL;
}
static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
static mobjtype_t g_doomednum_to_mobjtype[UINT16_MAX];
static void CalculateDoomednumToMobjtype(void)
{
memset(g_doomednum_to_mobjtype, MT_NULL, sizeof(g_doomednum_to_mobjtype));
for (size_t i = MT_NULL+1; i < NUMMOBJTYPES; i++)
{
if (mobjinfo[i].doomednum > 0 && mobjinfo[i].doomednum <= UINT16_MAX)
{
g_doomednum_to_mobjtype[ mobjinfo[i].doomednum ] = i;
}
}
}
static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker, UINT8 tclass)
{
mobj_t *mobj;
UINT32 diff;
@ -3590,17 +3666,20 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
return NULL;
}
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
mobj = P_AllocateMobj();
mobj->spawnpoint = &mapthings[spawnpointnum];
mapthings[spawnpointnum].mobj = mobj;
}
else
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
mobj = P_AllocateMobj();
// declare this as a valid mobj as soon as possible.
mobj->thinker.function.acp1 = thinker;
// manually link to thinkerlist, since the thinker isn't returned anymore
P_AddThinker(tclass, &mobj->thinker);
mobj->z = z;
mobj->floorz = floorz;
mobj->ceilingz = ceilingz;
@ -3611,20 +3690,26 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
mobj->type = READUINT32(save->p);
else
{
for (i = 0; i < NUMMOBJTYPES; i++)
if (mobj->spawnpoint && mobj->spawnpoint->type == mobjinfo[i].doomednum)
break;
if (i == NUMMOBJTYPES)
mobjtype_t new_type = MT_NULL;
if (mobj->spawnpoint)
{
new_type = g_doomednum_to_mobjtype[mobj->spawnpoint->type];
}
if (new_type <= MT_NULL || new_type >= NUMMOBJTYPES)
{
if (mobj->spawnpoint)
CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type %d\n", mobj->spawnpoint->type);
CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum %d\n", mobj->spawnpoint->type);
else
CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type NULL\n");
CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum NULL\n");
I_Error("Netsave corrupted");
}
mobj->type = i;
mobj->type = new_type;
}
mobj->info = &mobjinfo[mobj->type];
if (diff & MD_POS)
{
mobj->x = mobj->old_x = READFIXED(save->p);
@ -3652,11 +3737,11 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
if (diff & MD_RADIUS)
mobj->radius = READFIXED(save->p);
else
mobj->radius = mobj->info->radius;
mobj->radius = FixedMul(mobj->info->radius, mapobjectscale);
if (diff & MD_HEIGHT)
mobj->height = READFIXED(save->p);
else
mobj->height = mobj->info->height;
mobj->height = FixedMul(mobj->info->height, mapobjectscale);
if (diff & MD_FLAGS)
mobj->flags = READUINT32(save->p);
else
@ -3734,12 +3819,14 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
mobj->fuse = READINT32(save->p);
if (diff & MD_WATERTOP)
mobj->watertop = READFIXED(save->p);
else
mobj->watertop = INT32_MAX;
if (diff & MD_WATERBOTTOM)
mobj->waterbottom = READFIXED(save->p);
if (diff & MD_SCALE)
mobj->scale = READFIXED(save->p);
else
mobj->scale = FRACUNIT;
mobj->scale = mapobjectscale;
if (diff & MD_DSCALE)
mobj->destscale = READFIXED(save->p);
else
@ -3822,10 +3909,13 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
{
mobj->spritexoffset = READFIXED(save->p);
mobj->spriteyoffset = READFIXED(save->p);
mobj->rollingxoffset = READINT16(save->p);
mobj->rollingyoffset = READINT16(save->p);
}
else
{
mobj->spritexoffset = mobj->spriteyoffset = 0;
mobj->rollingxoffset = mobj->rollingyoffset = 0;
}
if (diff2 & MD2_WORLDOFFSET)
{
@ -3897,7 +3987,9 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
}
if (diff2 & MD2_TERRAIN)
{
mobj->terrain = (terrain_t *)(size_t)READUINT32(save->p);
UINT32 terrain_index = READUINT32(save->p);
if (terrain_index > 0)
mobj->terrain = K_GetTerrainByIndex(terrain_index - 1);
mobj->terrainOverlay = (mobj_t *)(size_t)READUINT32(save->p);
}
else
@ -3912,6 +4004,24 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
{
mobj->gravity = FRACUNIT;
}
if (diff3 & MD3_BAKEDOFFSET)
{
mobj->bakexoff = READFIXED(save->p);
mobj->bakeyoff = READFIXED(save->p);
mobj->bakezoff = READFIXED(save->p);
mobj->bakexpiv = READFIXED(save->p);
mobj->bakeypiv = READFIXED(save->p);
mobj->bakezpiv = READFIXED(save->p);
}
else
{
mobj->bakexoff = mobj->bakeyoff = mobj->bakezoff = 0;
mobj->bakexpiv = mobj->bakeypiv = mobj->bakezpiv = 0;
}
if (diff3 & MD3_EXTVAL3)
{
mobj->extravalue3 = READINT32(save->p);
}
// Reset some non-synch values
mobj->sloperoll = 0;
@ -3952,7 +4062,9 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
R_AddMobjInterpolator(mobj);
return &mobj->thinker;
// don't allow the mobj's refcount to be reset by P_AddThinker
// we might've already called P_SetTarget!
return NULL;//&mobj->thinker;
}
static thinker_t* LoadNoEnemiesThinker(savebuffer_t *save, actionf_p1 thinker)
@ -4571,6 +4683,10 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save)
if (READUINT32(save->p) != ARCHIVEBLOCK_THINKERS)
I_Error("Bad $$$.sav at archive block Thinkers");
// Pre-calculate this lookup, because it was wasting
// a shit ton of time loading mobj thinkers.
CalculateDoomednumToMobjtype();
// remove all the current thinkers
for (i = 0; i < NUM_THINKERLISTS; i++)
{
@ -4615,7 +4731,7 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save)
switch (tclass)
{
case tc_mobj:
th = LoadMobjThinker(save, (actionf_p1)P_MobjThinker);
th = LoadMobjThinker(save, (actionf_p1)P_MobjThinker, i);
break;
case tc_ceiling:
@ -4970,15 +5086,6 @@ static void P_RelinkPointers(void)
if (!RelinkMobj(&mobj->itnext))
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
}
if (mobj->terrain)
{
temp = (UINT32)(size_t)mobj->terrain;
mobj->terrain = K_GetTerrainByIndex(temp);
if (mobj->terrain == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "terrain not found on %d\n", mobj->type);
}
}
if (mobj->terrainOverlay)
{
if (!RelinkMobj(&mobj->terrainOverlay))
@ -5218,6 +5325,8 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
WRITEUINT8(save->p, purpledriftactive);
WRITEUINT8(save->p, slopeboostactive);
WRITEUINT8(save->p, draftingactive);
WRITEUINT8(save->p, airdropactive);
WRITEUINT8(save->p, bumpsparkactive);
for (i = 0; i < 12; i++)
{
@ -5287,6 +5396,9 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
WRITESINT8(save->p, speedscramble);
WRITESINT8(save->p, encorescramble);
// WANTED system
WRITESINT8(save->p, mostwanted);
for (i = 0; i < 4; i++)
WRITESINT8(save->p, battlewanted[i]);
@ -5348,9 +5460,11 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
{
TracyCZone(__zone, true);
size_t i;
size_t i, j;
size_t numTasks;
const INT16 prevgamemap = gamemap;
if (READUINT32(save->p) != ARCHIVEBLOCK_MISC)
I_Error("Bad $$$.sav at archive block Misc");
@ -5390,10 +5504,206 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
mapmusrng = READUINT8(save->p);
if (!P_LoadLevel(true, reloading))
// Only reload the level during a gamestate reload
// if the map is horribly mismatched somehow. Minor
// differences in level state are already handled
// by other parts of the reload, so doing this
// on *every* reload wastes lots of time that we
// will need for rollback down the road.
if (!reloading || prevgamemap != gamemap)
{
CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n"));
return false;
if (!P_LoadLevel(true, reloading))
{
CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n"));
return false;
}
}
else
{
// Only reload stuff that can we modify in the save states themselves.
// This is still orders of magnitude faster than a full level reload.
// Considered memcpy, but it's complicated -- save that for local saves.
sector_t *ss = sectors;
sector_t *spawnss = spawnsectors;
for (i = 0; i < numsectors; i++, ss++, spawnss++)
{
ss->floorheight = spawnss->floorheight;
ss->ceilingheight = spawnss->ceilingheight;
ss->floorpic = spawnss->floorpic;
ss->ceilingpic = spawnss->ceilingpic;
ss->lightlevel = spawnss->lightlevel;
ss->special = spawnss->special;
ss->floor_xoffs = spawnss->floor_xoffs;
ss->floor_yoffs = spawnss->floor_yoffs;
ss->ceiling_xoffs = spawnss->ceiling_xoffs;
ss->ceiling_yoffs = spawnss->ceiling_yoffs;
ss->floorpic_angle = spawnss->floorpic_angle;
ss->ceilingpic_angle = spawnss->ceilingpic_angle;
if (Tag_Compare(&ss->tags, &spawnss->tags) == false)
{
if (spawnss->tags.count)
{
ss->tags.count = spawnss->tags.count;
ss->tags.tags =
memcpy(
Z_Realloc(
ss->tags.tags,
spawnss->tags.count * sizeof(mtag_t),
PU_LEVEL,
NULL
),
spawnss->tags.tags,
spawnss->tags.count * sizeof(mtag_t)
);
}
else
{
ss->tags.count = 0;
Z_Free(ss->tags.tags);
}
}
ss->extra_colormap = ss->spawn_extra_colormap;
ss->crumblestate = CRUMBLE_NONE;
ss->floorlightlevel = spawnss->floorlightlevel;
ss->floorlightabsolute = spawnss->floorlightabsolute;
ss->ceilinglightlevel = spawnss->ceilinglightlevel;
ss->ceilinglightabsolute = spawnss->ceilinglightabsolute;
ss->flags = spawnss->flags;
ss->specialflags = spawnss->specialflags;
ss->damagetype = spawnss->damagetype;
ss->triggertag = spawnss->triggertag;
ss->triggerer = spawnss->triggerer;
ss->gravity = spawnss->gravity;
ss->action = spawnss->action;
memcpy(ss->args, spawnss->args, NUM_SCRIPT_ARGS * sizeof(*ss->args));
for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++)
{
size_t len = 0;
if (spawnss->stringargs[j])
{
len = strlen(spawnss->stringargs[j]);
}
if (!len)
{
Z_Free(ss->stringargs[j]);
ss->stringargs[j] = NULL;
}
else
{
ss->stringargs[j] = Z_Realloc(ss->stringargs[j], len + 1, PU_LEVEL, NULL);
M_Memcpy(ss->stringargs[j], spawnss->stringargs[j], len);
ss->stringargs[j][len] = '\0';
}
}
ss->activation = spawnss->activation;
ss->botController.flags = spawnss->botController.flags;
ss->botController.forceAngle = spawnss->botController.forceAngle;
if (ss->ffloors)
{
ffloor_t *rover;
for (rover = ss->ffloors; rover; rover = rover->next)
{
rover->fofflags = rover->spawnflags;
rover->alpha = rover->spawnalpha;
}
}
}
line_t *li = lines;
line_t *spawnli = spawnlines;
side_t *si = NULL;
side_t *spawnsi = NULL;
for (i = 0; i < numlines; i++, spawnli++, li++)
{
li->flags = spawnli->flags;
li->special = spawnli->special;
li->callcount = 0;
if (Tag_Compare(&li->tags, &spawnli->tags) == false)
{
if (spawnli->tags.count)
{
li->tags.count = spawnli->tags.count;
li->tags.tags =
memcpy(
Z_Realloc(
li->tags.tags,
spawnli->tags.count * sizeof(mtag_t),
PU_LEVEL,
NULL
),
spawnli->tags.tags,
spawnli->tags.count * sizeof(mtag_t)
);
}
else
{
li->tags.count = 0;
Z_Free(li->tags.tags);
}
}
memcpy(li->args, spawnli->args, NUM_SCRIPT_ARGS * sizeof(*li->args));
for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++)
{
size_t len = 0;
if (spawnli->stringargs[j])
{
len = strlen(spawnli->stringargs[j]);
}
if (!len)
{
Z_Free(li->stringargs[j]);
li->stringargs[j] = NULL;
}
else
{
li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL);
M_Memcpy(li->stringargs[j], spawnli->stringargs[j], len);
li->stringargs[j][len] = '\0';
}
}
li->executordelay = spawnli->executordelay;
li->activation = spawnli->activation;
if (li->sidenum[0] != 0xffff)
{
si = &sides[li->sidenum[0]];
spawnsi = &spawnsides[li->sidenum[0]];
si->textureoffset = spawnsi->textureoffset;
si->toptexture = spawnsi->toptexture;
si->bottomtexture = spawnsi->bottomtexture;
si->midtexture = spawnsi->midtexture;
}
if (li->sidenum[1] != 0xffff)
{
si = &sides[li->sidenum[1]];
spawnsi = &spawnsides[li->sidenum[1]];
si->textureoffset = spawnsi->textureoffset;
si->toptexture = spawnsi->toptexture;
si->bottomtexture = spawnsi->bottomtexture;
si->midtexture = spawnsi->midtexture;
}
}
Taglist_InitGlobalTables();
}
// get the time
@ -5407,6 +5717,8 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
purpledriftactive = READUINT8(save->p);
slopeboostactive = READUINT8(save->p);
draftingactive = READUINT8(save->p);
airdropactive = READUINT8(save->p);
bumpsparkactive = READUINT8(save->p);
for (i = 0; i < 12; i++)
{
@ -5473,6 +5785,7 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
speedscramble = READSINT8(save->p);
encorescramble = READSINT8(save->p);
mostwanted = READSINT8(save->p);
for (i = 0; i < 4; i++)
battlewanted[i] = READSINT8(save->p);

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