802 Commits
Author SHA1 Message Date
fgsfds 9625cd7d28 Merge branch 'port' into port-net 2024-05-14 11:37:47 +02:00
fgsfds 32c5d2c742 Merge pull request #411 from jonaeru/port-friendly-fire
port: add friendly fire mp option
2024-05-14 11:35:08 +02:00
fgsfds 3199f99fbd Merge branch 'port' into port-friendly-fire 2024-05-14 11:32:21 +02:00
fgsfds 0e2de3b746 Merge branch 'port' into port-net 2024-05-14 11:29:28 +02:00
fgsfds 51d842f516 Merge pull request #412 from jonaeru/port-autorandom
port: add auto random mp weapon option
2024-05-14 11:21:22 +02:00
fgsfds 4e7e61c207 Merge branch 'port' into port-autorandom 2024-05-14 11:20:29 +02:00
fgsfds 32417c164c Merge branch 'port' into port-net 2024-05-14 11:12:56 +02:00
fgsfds 70b02da163 port: fix long option names and whitespace 2024-05-14 11:12:49 +02:00
fgsfds 1a3f36f626 Merge pull request #420 from throwaway29292/port
Add an option in Combat Simulator to disable the blur effect from melee damage
2024-05-14 11:02:28 +02:00
fgsfds 1db33f278b Merge branch 'port' into port-net 2024-05-14 10:56:58 +02:00
fgsfds d8a26fa221 port: clean up whitespace 2024-05-14 10:56:50 +02:00
fgsfds 28d6c5b827 Merge pull request #426 from throwaway29292/dualwieldallguns
Add a cheat to allow dual-wielding all weapons
2024-05-14 10:35:57 +02:00
fgsfds abc6612641 Merge branch 'port' into port-net 2024-05-14 10:35:06 +02:00
fgsfds fef8985b6b port: fix whitespace and scope in bgunConsiderToggleGunFunction 2024-05-14 10:34:16 +02:00
fgsfds fd8718f7b1 Merge pull request #416 from NeonNyan/fix-rcp120alt
fix for rcp120 alt button behavior
2024-05-14 10:25:21 +02:00
fgsfds 57b1e37397 Merge branch 'port' into port-net 2024-05-14 10:15:19 +02:00
fgsfds 197208b951 port: add detail textures toggle 2024-05-14 10:13:50 +02:00
fgsfds 3f3c091289 Merge branch 'port' into port-net 2024-05-13 22:23:16 +02:00
fgsfds 4bd314f60b port: add exclusive fullscreen and hidpi settings
for now config only

exclusive fullscreen uses DefaultWidth/DefaultHeight for resolution

hidpi defaults to off
2024-05-13 22:23:04 +02:00
fgsfds 41ddcc7822 Merge branch 'port' into port-net 2024-05-13 18:49:16 +02:00
fgsfds 95b43b3f7b port: remove sprintf redeclaration 2024-05-13 18:48:35 +02:00
fgsfds 6708bf2aa6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 15:27:06 +02:00
fgsfds 62a55a3d6e port: don't force libc++, fix system.c on clang16+ 2024-05-13 15:24:45 +02:00
fgsfds 12cf9df01b port: allow overriding CC and CXX 2024-05-13 12:55:29 +02:00
fgsfds c16aa70a66 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 12:20:12 +02:00
fgsfds c5c1ef1d4e port: ask for high performance GPU on windows 2024-05-13 12:19:34 +02:00
fgsfds f3c1242858 port: more detail texture adjustment 2024-05-13 12:15:42 +02:00
fgsfds 60c30e9b67 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 01:15:50 +02:00
fgsfds ef3d53b9f7 port: make detail textures less intense 2024-05-13 01:15:30 +02:00
fgsfds bc01ff558f Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 00:30:42 +02:00
fgsfds 1d040b1ccc port: hackfix detail textures
this might have broken something else
2024-05-13 00:30:21 +02:00
fgsfds 9755f3ab41 port: even more gfx_pc cleanup 2024-05-13 00:28:19 +02:00
fgsfds f86746364f port: no need to explicitly disable player collision when tracing light glares 2024-05-12 17:12:37 +02:00
fgsfds 536c766793 port: more gfx_pc cleanup 2024-05-12 17:09:50 +02:00
fgsfds dca1e1752b port: remove remnants of masked/blended texture support 2024-05-12 16:48:33 +02:00
fgsfds 8c844874e7 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-12 16:32:16 +02:00
fgsfds ce6424117e port: re-disable glare calculation in multiplayer
they don't render anyway
2024-05-12 16:31:45 +02:00
fgsfds 15c0327592 port: better light glare hit detection 2024-05-12 16:22:34 +02:00
fgsfds 2e18ffdad9 update branch name in build instructions 2024-05-11 15:58:56 +02:00
fgsfds b2ea9aa5f2 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-11 15:57:20 +02:00
fgsfds 13003121ea Update README.md 2024-05-11 15:54:52 +02:00
fgsfds ba56947457 clarify build instructions a bit 2024-05-11 15:53:34 +02:00
fgsfds b9a51e4a62 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-11 14:14:15 +02:00
fgsfds 27faaecda2 gcc14 fixes 2024-05-11 14:13:51 +02:00
Not actually throwaway 798fbf7b90 Add a cheat to allow dual-wielding all guns. The cheat's name is "Gameplay/(Two-Handed)" 2024-05-01 17:55:22 +02:00
fgsfds a0f8550034 Merge pull request #422 from PaulGrandperrin/patch-1
Makefile.port: fix dependencies for parallel compilation
2024-04-25 17:33:29 +02:00
Paul Grandperrin 73dc52cfd6 Makefile.port: fix dependencies for parallel compilation 2024-04-25 12:49:36 +02:00
Not actually throwaway 5b1d03cbbb Add an option in Combat Simulator to disable the blur effect from melee damage
This effect might be annoyning or eye straining for some people so i believe it's a good idea to implement this option. There is still some free space in the MP Options bitfield for future expansion.
2024-04-24 22:54:15 +02:00
Catherine Reprobate 68aee1d2f2 fix for rcp120 alt button behavior 2024-04-14 14:49:32 -07:00
Jonaeru 7580ebcaf9 port: rename constants 2024-03-26 23:45:55 +09:00
Jonaeru c9a14f090b port: add constants 2024-03-26 23:41:57 +09:00
Jonaeru 2483d4fc35 port: add auto random mp weapon option 2024-03-26 00:53:57 +09:00
Jonaeru 501ab95b00 port: fix texts 2024-03-20 11:19:06 +09:00
Jonaeru 0b61ec9641 port: add friendly fire mp option 2024-03-20 01:53:50 +09:00
fgsfds b4f7f467c0 Merge pull request #406 from jonaeru/port-perfectdarkness
Give Night Vision at respawn in Perfect Darkness Combat
2024-03-17 13:38:42 +01:00
fgsfds 894ccfabf3 Merge pull request #408 from jonaeru/port-fix-xrayscanner
Fix X-Ray Scanner model in Combat Simulator
2024-03-17 13:38:01 +01:00
Jonaeru ec8310e4a1 port: fix X-Ray Scanner model in Combat Simulator 2024-03-17 15:42:53 +09:00
Jonaeru 80faefbaf6 port: give Night Vision at respawn in Perfect Darkness Combat 2024-03-17 15:12:26 +09:00
fgsfds b72d7f54e1 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-03-09 22:38:35 +01:00
fgsfds c9f880e427 port: fix #224, allow combat knife in jpn 2024-03-09 22:38:11 +01:00
fgsfds d8b21f78e0 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-03-09 17:45:41 +01:00
fgsfds 92a9ac43fc port: fix linux build 2024-03-09 17:45:27 +01:00
fgsfds 0d0de5b0d4 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-03-09 17:43:11 +01:00
fgsfds 4baae8de0b port: add extra sleep calls to busy loops; separate sleep into system.c 2024-03-09 17:39:41 +01:00
fgsfds d11b5705a2 port: add missing configRegisterUInt decl 2024-03-09 17:03:06 +01:00
fgsfds 7667d37ff0 Merge pull request #388 from iamgreaser/gm/net/counterop-4player
port-net: Extend counter-op mode to 4 players
2024-03-09 16:58:31 +01:00
fgsfds cf7c4d4239 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-02-13 01:17:45 +01:00
fgsfds 839143550f port: fix potential crash in handInflictMeleeDamage
pointers can be little endian, so there might be a problem
2024-02-13 01:16:57 +01:00
GreaseMonkey adcf56ed34 Handle cases for Counter-Op where certain local players can be missing; Don't support 2.x controls for Counter-Op
I'm not sure if this happens in practice in the port itself, but with a bit of temporary hackery one can force certain players to be absent.
This handles that case cleanly.
2024-02-11 13:25:35 +13:00
fgsfds 5e65e84210 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-02-11 00:59:18 +01:00
fgsfds fe0d9b3cfd port: fix blur shader on some older cards 2024-02-10 16:56:54 +01:00
fgsfds 935cd1faa9 port: gl: dump shader source when compilation fails 2024-02-10 14:07:20 +01:00
GreaseMonkey 63a9a26908 set_chr_team(CHR_ANTI, *) now sets all counter-op player teams
The easiest-to-test effect of this is that counter-op players will no longer attempt to auto-aim against one another (p2 vs any other).

Maps where this was necessary: Villa, Chicago, Rescue, Air Base, Air Force One
(Other maps stick to the default of `TEAM_ENEMY`, and so this doesn't really affect it.)
2024-02-10 14:17:22 +13:00
GreaseMonkey f4530633d6 Replace "Counter-Operative" player selection with "Main Player" + extend to 4 entries 2024-02-10 11:20:01 +13:00
GreaseMonkey 94e244a236 Report correct ending success/failure when any counter-op player aborts 2024-02-09 16:15:09 +13:00
GreaseMonkey 92d3a9f564 Add macros for counter-op player determination; Handle some missing checks 2024-02-09 13:44:04 +13:00
GreaseMonkey 44a67e60e8 net: Use LOCALPLAYERCOUNT() for UI size determination 2024-02-09 09:10:33 +13:00
GreaseMonkey 634eecb35d Use vertical-split versions of menus in 3+-player main missions
These work fine in the 2x2 split arrangement.
2024-02-09 08:40:02 +13:00
GreaseMonkey a0db91a0c9 Preliminary 4-player counter-op mode
Here's some things that will be needed off the top of my head:

- Handling the half-screen-width case for the pause menus
- Changing the player select menu to select the not-counter-op player instead, then extending that to 4 players
- Thorough testing of each level for any weird counter-op-specific features
2024-02-09 08:40:02 +13:00
fgsfds 6b105d0be0 Merge pull request #381 from iamgreaser/gm/net/broadcast-queries-001
query.py: Allow broadcast queries and wait for all replies
2024-02-06 10:49:58 +01:00
GreaseMonkey 11febd7ace port-net: query.py: Print reply source addresses 2024-02-06 12:16:05 +13:00
GreaseMonkey dface4696c port-net: query.py: List all server query replies
This is for when one provides a broadcast address to query.
2024-02-06 12:14:20 +13:00
GreaseMonkey 0669ce5668 port-net: query.py: Allow querying broadcast
This waits for the first reply and then exits.
2024-02-06 12:05:17 +13:00
fgsfds 6d3ea5b0fd Update README.md 2024-01-29 22:14:06 +01:00
fgsfds 36f8494ebf Update README.md 2024-01-29 22:11:34 +01:00
fgsfds fcb1dbb298 Merge pull request #375 from abgrac/readme-links-netplay
Add port-net/netplay build links to default README
2024-01-29 22:10:14 +01:00
fgsfds 409e955883 Merge pull request #376 from abgrac/readme-links-titles
Updated title & links titles for consistency with Master
2024-01-29 22:10:06 +01:00
Adriano Bini f006f9ba7b Updated title/link titles for consistency with MST
Some people are not being able to properly download/play because of Github's always defaulting to master's README.MD. This includes netplay links in the master branchg README as well.
2024-01-29 17:16:07 -03:00
Adriano Bini 815c75c6a8 Add port-net/netplay build links to default README
Some people are not being able to properly download/play because of Github's always defaulting to master's README.MD. This includes netplay links in the master branchg README as well.
2024-01-29 17:08:27 -03:00
fgsfds 6a03e8d9cf port: net: unify console and join address input routines 2024-01-28 19:28:51 +01:00
fgsfds a1af5b655a Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-28 18:46:13 +01:00
fgsfds 33cc89e8fd Merge pull request #371 from Calinou/add-crosshair-health-option
Add an option to color crosshair according to player health + shield
2024-01-28 18:39:05 +01:00
fgsfds cc6df47eed Merge pull request #372 from Calinou/crosshair-hide-when-dead
Always hide crosshair when dead
2024-01-28 18:37:50 +01:00
Hugo Locurcio 02d7efb87f Add an option to color crosshair according to player health + shield
Shield is taken into account and is added to health for the calculation,
as the vast majority of damage types are fully blocked by a shield.

3 modes are available:

- Off (default)
- On (Green): Goes through a red-yellow-green-cyan gradient,
  closer to vanilla.
- On (White): Goes through a red-yellow-white-green gradient,
  closer to games like Xonotic.

When set to either of the On modes, the crosshair color setting
is ignored but the crosshair alpha setting is still used.
2024-01-27 19:21:05 +01:00
Hugo Locurcio 1f4d9c8cdc Always hide crosshair when dead
Previously, the crosshair would show up during the death animation
if Always Show Target is enabled or if aiming just before dying.
2024-01-27 19:19:06 +01:00
fgsfds edeafa596d Merge pull request #373 from abgrac/port-net
Changed server footer color to more readable green
2024-01-27 14:51:30 +01:00
Adriano Bini b954e3ce80 Changed server footer color to more readable green 2024-01-27 02:17:48 -03:00
fgsfds bfa4035642 port: net: bump protocol version 2024-01-16 01:59:01 +01:00
fgsfds 35be4d589e Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-16 01:57:15 +01:00
fgsfds 474a6df3d4 port: add spawn with weapon mp option
unfortunately it does not fit in the save buffer and won't save
2024-01-16 01:56:30 +01:00
fgsfds 884a30f970 port: net: bump protocol version 2024-01-16 01:27:22 +01:00
fgsfds 7288947390 port: net: handle UCMD_ACTIVATE as a press 2024-01-16 01:27:03 +01:00
fgsfds c444e76ecb port: net: skip intro cutscene if netgame requested on command line 2024-01-15 13:10:57 +01:00
fgsfds c4b1a8d4a2 port: net: fix --maxclients 2024-01-15 13:01:13 +01:00
fgsfds 7c8b1176c7 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-15 12:58:35 +01:00
fgsfds 9cde121b52 port: don't call rumble function if rumble strength is 0 2024-01-15 12:58:00 +01:00
fgsfds c5a088e7b8 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-15 11:40:30 +01:00
fgsfds e53f26f3eb port: fix #347
patch submitted by Ryan Dwyer

The patch allows all humans/bots to be selected regardless of team. It also adds a check to make sure a bot is not given a command to attack itself.
2024-01-15 09:47:52 +01:00
fgsfds 81313f0c4e port: ifdef around sight scale changes 2024-01-14 21:21:19 +01:00
fgsfds cf5588478b Merge pull request #332 from Calinou/add-crosshair-size-option
Add a crosshair size option
2024-01-14 21:21:03 +01:00
fgsfds d9cb850848 Merge pull request #333 from AXDOOMER/port
Always use high detail weapon models
2024-01-14 21:20:36 +01:00
fgsfds 8e443d4830 port: ifdef around sight scale changes 2024-01-14 21:13:31 +01:00
fgsfds 2cb52b749c Merge pull request #332 from Calinou/add-crosshair-size-option
Add a crosshair size option
2024-01-14 21:11:58 +01:00
fgsfds de14f90daf Merge branch 'port-net' into add-crosshair-size-option 2024-01-14 21:11:44 +01:00
fgsfds 9afc7e113e Merge pull request #333 from AXDOOMER/port
Always use high detail weapon models
2024-01-14 20:49:20 +01:00
fgsfds fbfe4b4564 port: net: allow up to 120fps in netgames 2024-01-14 20:48:22 +01:00
fgsfds 4cb99506cb port: net: replace useless checksum with slightly more useful crc16 2024-01-14 20:36:03 +01:00
fgsfds 562e763fbd tools: add server query client example 2024-01-14 20:03:16 +01:00
fgsfds 952de6e82b port: net: allow connectionless server info queries 2024-01-14 19:59:00 +01:00
fgsfds 7ec54e6d0b port: net: fix team/handicap menus with 5+ players 2024-01-14 17:54:16 +01:00
fgsfds e6df6014c7 port: net: bump protocol version 2024-01-14 17:40:02 +01:00
fgsfds e688a1c6e6 port: net: do not assume contiguous player slots 2024-01-14 17:36:19 +01:00
fgsfds e44298d0c2 port: net: fix player options not working in SP 2024-01-14 17:15:43 +01:00
fgsfds 31cd8fc28a port: net: fix #328 2024-01-14 15:49:18 +01:00
fgsfds a46ce32ad4 port: net: don't crash if there aren't any player props
although I still don't know what actually leads to this situation
2024-01-14 15:38:05 +01:00
fgsfds 31d8aae704 port: net: move the rest of the IP logging to log only 2024-01-08 12:31:42 +01:00
fgsfds 4b30f52b32 port: net: cap --maxclients 2024-01-07 22:20:46 +01:00
fgsfds c8d42bbf20 port: net: if going into netgame from command line, skip intro and default to profile 0 2024-01-07 22:14:59 +01:00
fgsfds 511d6ca299 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-07 22:06:47 +01:00
fgsfds b9db86f89b port: add command line parameter to select player file 2024-01-07 22:05:31 +01:00
fgsfds 33f6d643be port: net: add command line arguments for quick hosting and joining 2024-01-07 22:01:20 +01:00
fgsfds c2d09135f7 port: net: probably fix ipv6 address parsing 2024-01-07 21:17:59 +01:00
fgsfds 9f6b21e870 port: net: fix main menu lockup after playing a 5+ player game 2024-01-07 20:52:31 +01:00
fgsfds 4eca4a1f07 port: net: fix a bunch of access violations 2024-01-07 19:54:27 +01:00
fgsfds 4439fdf411 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-07 19:10:21 +01:00
fgsfds 6bd3597ff6 port: fix optionsmenu.c warnings 2024-01-07 18:40:32 +01:00
fgsfds 6ac8a1a0f6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-07 17:08:44 +01:00
fgsfds 8645d0a82a port: don't use the existing log system in crashlog in case it crashes 2024-01-07 17:07:12 +01:00
fgsfds ba52580e0c port: display module offsets in the windows crashlog 2024-01-07 16:43:20 +01:00
fgsfds d1d288b96a port: don't use cv2pdb by default if it exists 2024-01-07 16:43:02 +01:00
fgsfds 06f2283180 port: use cv2pdb on windows executables if present 2024-01-07 16:09:04 +01:00
fgsfds b1b17e21c1 port: write crash info to log file even without --log 2024-01-07 15:40:30 +01:00
Alexandre-Xavier Labonté-Lamoureux f4ec781b8e port: always use high detail weapon models 2024-01-06 02:58:54 -05:00
Hugo Locurcio 5e256ea406 Add a crosshair size option
5 sizes are available (from 0 to 4), with 2 being the default vanilla-like
value.

Size 0 is a dot with alpha adjusted to match the crosshair color
settings.
2024-01-05 20:21:44 +01:00
fgsfds 5abb0e484e port: net: fix maxplayers cap 2024-01-05 00:33:51 +01:00
fgsfds 16c247a24e port: net: change default LerpTicks to 3 2024-01-04 19:27:14 +01:00
fgsfds 0737c688d7 port: net: don't explode in menu code with > 4 players 2024-01-04 00:00:14 +01:00
fgsfds 9de245eab6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-03 21:56:28 +01:00
fgsfds c487e423b1 port: fix blur-related crash on Intel GPUs 2024-01-03 21:55:07 +01:00
fgsfds a3cc54d33a port: net: bump protocol version 2024-01-02 19:03:11 +01:00
fgsfds a261246e64 port: net: move clsettings to a separate message; add join notifications 2024-01-02 19:02:23 +01:00
fgsfds 2e195fe21a port: net: bump protocol version 2024-01-02 00:44:40 +01:00
fgsfds 36a692991f port: net: transmit more player options; allow headroll death in netgames 2024-01-02 00:44:08 +01:00
fgsfds ca0e3c3060 port: net: disable headroll in netgames 2024-01-01 21:25:36 +01:00
fgsfds 39474e97a7 port: net: bump protocol version 2024-01-01 20:26:52 +01:00
fgsfds b74cd095a1 port: net: better gun and crosshair position sync; fix zooming guns 2024-01-01 20:18:32 +01:00
fgsfds 96e1c57f61 port: net: carry some of the client inputs over to server-sent moves 2023-12-31 21:00:54 +01:00
fgsfds f6ee8bbf71 port: net: don't die when there's a % in a chat message 2023-12-31 20:31:37 +01:00
fgsfds 188faeecf6 port: net: update netplay.md 2023-12-31 19:51:13 +01:00
fgsfds 2c0a0a1337 port: net: don't play death music, pain and pickup sounds from other players 2023-12-30 14:32:35 +01:00
fgsfds 7f92551d5a port: net: don't create hudmsgs for other players 2023-12-30 13:21:36 +01:00
fgsfds f54dbb596e Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-30 12:20:03 +01:00
fgsfds 49f607dd79 port: fix pal and jpn builds 2023-12-30 12:19:36 +01:00
fgsfds aa3c5a85b7 port: net: make team sync slightly less insane 2023-12-29 11:56:54 +01:00
fgsfds f46e112c3d port: net: fix dualwielding, probably; bump protocol version 2023-12-29 02:06:12 +01:00
fgsfds bcb5b3f5c1 port: net: fix uninitialized tickop in SVC_PROP_USE 2023-12-28 22:49:39 +01:00
fgsfds 65589e2fd2 port: net: sort of sync lifts; bump protocol version 2023-12-28 22:43:27 +01:00
fgsfds 787758c038 port: log branch name 2023-12-28 21:48:05 +01:00
fgsfds 54fbd8ba54 port: net: log protocol name 2023-12-28 21:41:27 +01:00
fgsfds 49129dd3e7 port: log branch name 2023-12-28 21:41:20 +01:00
fgsfds 7bfa2b9425 port: net: bump protocol number 2023-12-28 21:38:33 +01:00
fgsfds 53fbbb8a10 port: net: fix teams in netgames 2023-12-28 21:38:17 +01:00
fgsfds 7bee9cdcfc port: net: sync instant environmental death 2023-12-28 12:45:18 +01:00
fgsfds 928544ae5f port: net: bump protocol version just in case 2023-12-28 12:11:43 +01:00
fgsfds 312c752205 port: net: set client rng at the same time the server sends it 2023-12-28 12:10:43 +01:00
fgsfds a5d1c25fea port: net: set g_NumReasonsToEndMatch when server ends the match
just in case
2023-12-28 12:00:21 +01:00
fgsfds 7abebe7405 port: net: don't end match locally on the client 2023-12-28 11:58:38 +01:00
fgsfds ebc126f837 port: net: disable pause in netgames 2023-12-27 19:30:29 +01:00
fgsfds 67bc9c4858 port: net: ignore handicap in netgames 2023-12-27 16:08:49 +01:00
fgsfds c4a3c18208 port: net: clarify chrslots 2023-12-27 16:08:41 +01:00
fgsfds cf1b87a833 port: net: discard game-related messages on client if not in CLSTATE_GAME 2023-12-27 01:51:44 +01:00
fgsfds fb123603ca port: net: put SVC_STAGE_START/END back in the default channel 2023-12-27 01:40:05 +01:00
fgsfds b3ab58da3b Update netplay.md 2023-12-27 01:15:23 +01:00
fgsfds 6374fc834c Update README.md 2023-12-27 01:03:04 +01:00
fgsfds 6df31649f5 Update README.md 2023-12-27 00:38:05 +01:00
fgsfds 9de6b580ba port: net: document netplay status 2023-12-27 00:37:19 +01:00
fgsfds 8eb6880694 port: net: fix linux builds probably 2023-12-26 23:15:05 +01:00
fgsfds fe4d86fae1 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-26 22:58:20 +01:00
fgsfds 3c62a967a2 port: display branch name in legal screen 2023-12-26 22:58:08 +01:00
fgsfds 8492670bad ci: build port-net branch 2023-12-26 22:49:18 +01:00
fgsfds 04f95ed1d1 port: net: experimental 8 player support 2023-12-26 22:48:28 +01:00
fgsfds ee037c10ce port: net: ignore UpdateFrames when reliable move is required 2023-12-26 22:40:33 +01:00
fgsfds cbf65e53b9 port: net: only send player moves when needed; add stuff to net debug 2023-12-26 22:33:57 +01:00
fgsfds 8c2b15d649 port: on-screen messages include all rows of the message 2023-12-26 16:55:39 +01:00
fgsfds 2134571b9a port: net: check clients for matching mods; bump protocol version 2023-12-26 16:51:55 +01:00
fgsfds a541c79eda port: net: add movement update rate to ini 2023-12-26 16:21:07 +01:00
fgsfds 454086be6b port: net: separate control msgs into another channel; add bandwidth settings 2023-12-26 16:18:20 +01:00
fgsfds 6bd5997059 port: net: don't draw console or net debug when the font is unloaded 2023-12-25 18:25:07 +01:00
fgsfds 99911b2290 port: net: domain names can in fact start with a digit 2023-12-25 13:10:07 +01:00
fgsfds 95d8b0692f port: net: add some config vars 2023-12-24 17:31:57 +01:00
fgsfds e85cc3b309 port: net: hardcap fps to 60 if in network game 2023-12-24 17:14:19 +01:00
fgsfds 2a01d562c3 Update README.md 2023-12-24 17:07:24 +01:00
fgsfds 51daf45c19 Update README.md 2023-12-24 17:06:29 +01:00
fgsfds c9bd2bfd54 port: net: clarify what this is 2023-12-24 17:01:40 +01:00
fgsfds 6225f62412 port: net: partially fix rockets 2023-12-24 16:56:05 +01:00
fgsfds d2ffd73dea port: net: add net debug info, add copypaste support to IP input 2023-12-24 00:39:36 +01:00
fgsfds 02329b64a1 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-23 22:09:43 +01:00
fgsfds aae0f70dd3 port: net: sync some projectiles, doors, parts of bgun, etc 2023-12-23 22:09:37 +01:00
fgsfds 41d9cb4578 port: add console for chat and log messages 2023-12-23 22:09:02 +01:00
fgsfds f2a2458795 port: fix typo 2023-12-22 12:33:34 +01:00
fgsfds a7ab358b43 port: simplify sight color code a bit 2023-12-22 12:32:13 +01:00
fgsfds a82ac025da Merge pull request #300 from Bobbar/port_crosshair_alpha
Crosshair Alpha Proof of Concept
2023-12-22 12:25:36 +01:00
fgsfds 461bf8d49b Merge pull request #314 from kronflux/port
port: add "Skedar Leader" track to Soundtrack menu
2023-12-22 12:24:46 +01:00
fgsfds 370047b1b0 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-18 16:34:58 +01:00
Richard M db1d00a9b0 port: add "Skedar Leader" track
Add the "Skedar Leader" track to the Combat Simulator Soundtrack selection menu as "Skedar Warrior" as we do not currently have the ability to use the official track name
2023-12-17 11:50:16 -07:00
fgsfds 6fc99e4c23 port: net: basic networking with barely working position sync 2023-12-17 12:54:48 +01:00
fgsfds 92c66c93dc port: correct HUD aspect in horizontal 2-player splitscreen too 2023-12-17 12:52:11 +01:00
fgsfds 94df3fc58c Merge pull request #309 from djdv/feat/win-max
port: add maximize window option to extended menu
2023-12-17 12:30:25 +01:00
fgsfds f2545b4e53 port: fix GE muzzleflashes on single-shot guns 2023-12-17 12:28:47 +01:00
Dominic Della Valle 0221839699 port: add maximize window option to extended menu 2023-12-16 11:56:39 -05:00
Bobby Lovell 1698f53728 Update main.c to use new UInt config for crosshair color 2023-12-16 10:20:32 -05:00
Bobby Lovell 7ac734fc81 Merge branch 'fgsfdsfgs:port' into port_crosshair_alpha 2023-12-16 10:18:34 -05:00
fgsfds 28218b26c2 port: add setting for GE muzzle flashes and disable it by default 2023-12-16 15:22:23 +01:00
fgsfds 4233e5e066 Merge pull request #293 from Nyxem64/muzzleflash
GE Muzzle flash addition
2023-12-16 15:08:22 +01:00
fgsfds cdd7d6edac port: use strto* when parsing config instead of ato*
allows hex values
2023-12-16 15:08:14 +01:00
fgsfds 581c63fc27 Merge pull request #308 from djdv/feat/win-max
port: add start window maximized flag to config
2023-12-16 15:03:04 +01:00
fgsfds dee7ab7b54 Merge pull request #306 from Bobbar/port_u32_config_support
Add config support for unsigned integers.
2023-12-16 15:02:37 +01:00
Dominic Della Valle 8c509db888 port: add start window maximized flag to config 2023-12-16 07:04:52 -05:00
Bobby Lovell 5aa799718a Add support for unsigned integers. 2023-12-15 10:17:15 -05:00
Bobby Lovell 880a7a0971 Add back line inadvertently removed in 342e186f79 2023-12-15 08:10:31 -05:00
Bobby Lovell e84d83e404 Add missing ndef. 2023-12-14 16:08:53 -05:00
Bobby Lovell 79fb976bcf Implement a simple colored box menu item type and use that for the preview. 2023-12-14 16:03:29 -05:00
Bobby Lovell 519bd95a75 Center preview text. 2023-12-14 14:49:13 -05:00
Bobby Lovell 8421140e3f Remove comment. 2023-12-14 10:31:47 -05:00
Bobby Lovell 894ea53b29 Spell out colors... 2023-12-14 10:18:43 -05:00
Bobby Lovell fb05725c34 - Implement RGBA.
- Add preview label.
2023-12-14 10:13:27 -05:00
Bobby Lovell 2a6625278a - Fix RGB defines
- Just store the colour and parse RGBA values when modifying.
2023-12-13 13:48:06 -05:00
Bobby Lovell 342e186f79 Add option to change crosshair alpha, and could provide fully custom colors. Proof of concept. 2023-12-13 13:06:48 -05:00
J cabd40f898 GE Muzzle flash addition 2023-12-11 00:49:09 +00:00
fgsfds 0a7faf2409 port: add file patching system; add patch for #286
patch submitted by Ryan Dwyer
2023-12-07 17:20:34 +01:00
fgsfds 03324c0823 port: use correct aspect instead of 4:3 when scaling crosshair 2023-12-07 16:46:32 +01:00
fgsfds aeb6851606 port: change FPS hard cap to 240 on NTSC, 200 on PAL 2023-12-06 17:16:34 +01:00
fgsfds 26da2aa5e6 Update README.md 2023-12-06 17:12:13 +01:00
fgsfds 7647062619 port: hard cap FPS to 200 for now 2023-12-06 17:11:21 +01:00
fgsfds 3a313287bb port: fix config ints not clamping properly 2023-12-06 17:10:48 +01:00
fgsfds 42af4d4604 port: approximately normalize eyespy bob 2023-12-06 16:53:46 +01:00
fgsfds 3118d01921 port: don't render garbage in the first blur frame (fixes #287) 2023-12-06 14:57:21 +01:00
fgsfds f46359b307 Update README.md 2023-12-05 16:27:09 +01:00
fgsfds 00297f6d0d Merge pull request #276 from hyh19962008/port
Add the minimal required gcc and sdl2 version in README.md
2023-12-05 16:23:47 +01:00
Demon 39d5b57ccb Update README.md, change minimal SDL2 version to 2.0.12 2023-12-05 23:00:56 +08:00
fgsfds d1be171939 port: only use SDL_CONTROLLER_TYPE_VIRTUAL when available 2023-12-04 18:22:37 +01:00
fgsfds 6f206345a1 Merge pull request #282 from JAMoreno-Larios/port
Changed 'codeclean' so that it doesn't try to delete inexistent directories.
2023-12-03 23:08:25 +01:00
José Agustín Moreno Larios 13b23de6d3 Simplified the 'codeclean' rule to find all *.o files and delete them 2023-12-03 16:38:18 -05:00
José Agustín Moreno Larios d897356029 Changed 'codeclean' so that it doesn't try to delete inexistent directories. 2023-12-03 16:28:02 -05:00
fgsfds f96e7da00f port: use proper aspect for 2D elements
this means that now scaling at most 4:3 resolutions will be a bit mangled, since the real base resolution is 320x220
2023-12-03 21:10:41 +01:00
Demon 1fb16b3bfd Update README.md, add the minimal required gcc and sdl2 version 2023-12-03 13:18:27 +08:00
fgsfds 2c20a0487e port: better menu blur
TODO: make it render the blurred texture to the fb once instead of rendering it blurred every frame
2023-12-02 19:18:47 +01:00
fgsfds aef2463361 port: alternative fix for the classic sight 2023-12-02 14:04:33 +01:00
fgsfds 2b8d5d4f75 port: fix crosshair aspect and make sights centered 4:3 2023-12-02 13:48:24 +01:00
fgsfds ef83f23200 port: fix sun aspect ratio 2023-12-01 19:35:04 +01:00
fgsfds 75133acbbd port: alternate squished aspect fix
by just changing the actual aspect instead of fucking around with the resolution
2023-12-01 17:31:42 +01:00
fgsfds 1aea68b89a Revert "port: unsquish the aspect ratio"
This reverts commit af34015562.

I'll have to come up with a better way to do this
2023-12-01 17:21:27 +01:00
fgsfds af34015562 port: unsquish the aspect ratio
this might break something but I haven't noticed anything bad yet
2023-11-30 10:51:21 +01:00
fgsfds 7cd3dafaa4 port: add wide HUD centering option for ultrawide displays 2023-11-27 11:52:53 +01:00
fgsfds e0249067b9 port: reset the controller LEDs on unassign 2023-11-27 01:26:45 +01:00
fgsfds 31ad9351f5 port: load gamecontrollerdb if available 2023-11-27 01:20:09 +01:00
fgsfds 116dc7e8b6 port: allow assigning controllers manually 2023-11-27 00:57:52 +01:00
fgsfds aced07f356 Merge pull request #253 from NeonNyan/fix-camspy
fixup: PC controls camspy instant abort
2023-11-26 23:59:35 +01:00
Catherine Reprobate 8d99ac92a0 fixup: PC controls camspy instant abort
only consider first controller for camspy input
2023-11-26 14:54:12 -08:00
fgsfds 4a3c3a29b7 port: measure nbomb age based on timestamps
makes them last the same amount of time regardless of fps
2023-11-26 21:15:47 +01:00
fgsfds 523e6ba9d9 port: don't randomly close radial menu at 240fps 2023-11-26 20:45:54 +01:00
fgsfds c6a36633f5 port: untie radial menu open delay from framerate 2023-11-26 20:43:31 +01:00
fgsfds 626b5937ce port: possibly fix reloading and some altmodes in N64 schemes 2023-11-26 20:32:46 +01:00
fgsfds 228851f867 port: add c-buttons to bind menu 2023-11-26 20:27:22 +01:00
fgsfds 1c72b3022e port: prevent extended options from cutting off 2023-11-26 19:46:06 +01:00
fgsfds 5d7b7adb57 port: expose FirstGamepadNum as checkbox in ext options menu 2023-11-26 19:26:07 +01:00
fgsfds 2d3e3d1aaf port: add option to disable death music in MP 2023-11-26 19:10:19 +01:00
fgsfds 94e8e1b5e7 port: don't nuke all binds when resetting one player 2023-11-26 19:05:13 +01:00
fgsfds d3a2ed216a port: add a second set of default bindings for N64 controls 2023-11-26 18:40:06 +01:00
fgsfds 600dae58e2 port: allow using N64 control schemes
change from Ext to another control scheme to activate

note that this will require rebinding keys, as the default config is for the Ext scheme
2023-11-26 18:07:35 +01:00
fgsfds 3a1d08509b port: unlock all challenges properly 2023-11-26 13:40:15 +01:00
fgsfds 45a44cd37e port: move unlock everything option to cheats 2023-11-24 22:40:02 +01:00
fgsfds 5a68daf18c Merge pull request #243 from Bobbar/unlock_everything_gamesave
Option to unlock everything.
2023-11-24 22:31:40 +01:00
fgsfds e43d29f357 port: add hold crouch 2023-11-24 22:30:52 +01:00
fgsfds 3328e147eb port: hackfix some more RGBA32 textures 2023-11-22 22:19:54 +01:00
fgsfds 7e929c2432 Update README.md 2023-11-18 12:05:21 +01:00
fgsfds b88690e8df port: add easier ways to skip the intro
--skip-intro on command line or Game.SkipIntro in the config
2023-11-18 11:56:19 +01:00
fgsfds 305e64a263 port: restore glReadBuffer value after changing it
this might fix reshade
2023-11-18 00:43:22 +01:00
fgsfds b618c99abd Merge pull request #245 from Bobbar/port_add_VS_ignore
Update gitignore for Visual Studio.
2023-11-17 20:48:47 +01:00
Bobby Lovell 58d815f1ec Update gitignore for Visual Studio. 2023-11-17 12:20:35 -05:00
Bobby Lovell 99da0586ea Add menu and confirmation prompt. 2023-11-17 09:28:43 -05:00
Bobby Lovell 27e36ca24e Add prototype. 2023-11-17 09:23:00 -05:00
Bobby Lovell 9dfd0ec905 Add the main unlock hacks 2023-11-16 21:11:31 -05:00
fgsfds 6f55843f30 port: backport better SDL framepacing from LUS 2023-11-15 13:53:18 +01:00
fgsfds 4a16f27abd port: don't slow down the mouse at exactly 240 fps 2023-11-15 12:13:13 +01:00
fgsfds 11e318b70f port: mouselook speed now independent of framerate 2023-11-15 10:32:54 +01:00
fgsfds 5bb4f1d193 port: fix (?) slomo at high framerates 2023-11-15 00:25:10 +01:00
fgsfds f394f209b2 port: fix npc footsteps at high framerates 2023-11-15 00:25:01 +01:00
fgsfds 9c7f348652 port: use the 240hz timer in activemenu 2023-11-15 00:24:38 +01:00
fgsfds 32b2e9c28e port: fix sliding doors exploding at non-60fps framerates 2023-11-14 23:58:40 +01:00
fgsfds 72e9e2af95 port: very experimental uncapped framerate support
set Game.TickRateDivisor in pd.ini to 0

this still has many issues, such as combat boost not working
2023-11-14 23:29:44 +01:00
fgsfds 8a348ab1b5 port: fix bullet casings going behind the world 2023-11-13 21:07:53 +01:00
fgsfds 28b172f5c7 port: make autoguns fire only on even frames at 60+ fps 2023-11-12 16:09:58 +01:00
fgsfds ef511d5889 port: fix #231 2023-11-12 15:48:41 +01:00
fgsfds 83a155fa49 port: fix #210
by using a separate fullscreen fb for blur effects
2023-11-12 15:05:21 +01:00
fgsfds eecee9d940 port: fix #55
patch submitted by Ryan Dwyer
2023-11-12 13:56:50 +01:00
fgsfds cd19c07810 port: fix player model flinching at the start of a cutscene
patch contributed by Ryan Dwyer
2023-11-11 17:42:39 +01:00
fgsfds f1edc91fd8 port: fix whitespace 2023-11-11 17:41:19 +01:00
fgsfds 5df6d2fdfb port: slightly simpler fix for bgTestHitOnObj 2023-11-11 17:41:10 +01:00
fgsfds 83c5b4980b Merge pull request #230 from NeonNyan/port
Remote mine fixes
2023-11-11 17:31:52 +01:00
Catherine Reprobate 0e043f24b5 Remote mine fixes
- N64 fix: fixes issue where selecting the remote mine from the active menu
  or the inventory menu when Jo already has a remote mine equipped
  causes the player to unequip the detonator

Confirmed this issue presents on ntsc-final on 1964GEPD.

- port fix: fixes issue with remote mine input handler where the
  previous active menu slotnum would be activeated. The slotnum is
  unconditionally set to 4 (the "resting no-op" slotnum) to prevent this
2023-11-06 22:09:48 -08:00
fgsfds 828776e272 port: account for non-segmented addresses in bgTestHitOnObj 2023-11-05 23:08:34 +01:00
fgsfds 407d4724a7 port: use mpindex to index player specific settings 2023-11-04 02:39:16 +01:00
fgsfds d75adeb0c8 port: per-player settings
NOTE: this will reset big parts of your config
2023-11-04 02:08:45 +01:00
fgsfds dc6e6a507c port: slightly more helpful rom error messages 2023-11-04 02:08:44 +01:00
fgsfds fbae610a3b port: rework config system a bit 2023-11-04 02:08:44 +01:00
fgsfds 479c0335f3 Update README.md 2023-11-02 00:24:49 +01:00
fgsfds d021e95d70 port: add exe region to legal screen 2023-11-02 00:20:35 +01:00
fgsfds 3ac194f9ee port: pal: fix (?) audio stutter 2023-11-02 00:20:18 +01:00
fgsfds fea0a1e4ca port: pal: swap all the characters in extended fonts 2023-11-01 23:46:39 +01:00
fgsfds a802d2db06 port: allow pressing DEL to delete the binding 2023-11-01 17:46:24 +01:00
fgsfds 4a0296d1a4 port: fix radial menu bind in extended options 2023-11-01 16:36:07 +01:00
fgsfds c040c17b49 port: fix whitespace 2023-11-01 16:35:48 +01:00
fgsfds 4eaaae91a6 Merge pull request #215 from SilentException/feat-grab-mouse-default
Allow mouse input by default
2023-11-01 16:30:25 +01:00
SilentException 83d22c3b70 Allow mouse input by default 2023-11-01 04:23:34 +01:00
fgsfds 4914aa335b fix README typo 2023-10-30 19:01:52 +01:00
fgsfds afb91ab9e9 port: add radial menu sensitivity slider 2023-10-30 19:00:26 +01:00
fgsfds ed65f7971a Merge pull request #206 from NeonNyan/port
Input fixups for quick-detonate and radial menu navigation
2023-10-30 11:14:33 +01:00
Catherine Reprobate 3feddd8c64 port: fixes #205 radial movement issue 2023-10-29 16:13:04 -07:00
Catherine Reprobate 9b65199d3d fix: port: xbla-style quick detonate fix
- adds A + X to list of quick-detonate keybinds: correct xbla behavior for quick detonating per the xbox
implementation
2023-10-29 15:48:50 -07:00
fgsfds 50b74e4280 port: fix #204; allow players 2-4 to use lstick in radial menu 2023-10-29 18:28:04 +01:00
fgsfds c8db5fa106 port: add keybind menu 2023-10-28 18:17:35 +02:00
fgsfds cea9527936 port: add controller axis settings
also make sliders look nicer and save some input settings on quit
2023-10-28 14:36:00 +02:00
fgsfds 2813ecedeb port: fix some sliders in extended options 2023-10-28 13:45:12 +02:00
fgsfds 015817f204 port: add extended options menu
as well as support for string literals in the menu system
2023-10-28 05:33:09 +02:00
fgsfds da7e1493a5 port: extend sky slightly beyond screen
to push glitchy corners out of view
2023-10-25 12:54:47 +02:00
fgsfds 368021201b Update README.md 2023-10-24 15:55:04 +02:00
fgsfds 30b8400d86 port: fix drug blur not resetting on respawn
fix taken from Graslu's decomp fork
2023-10-24 11:14:33 +02:00
fgsfds 77fcac4912 port: remove static decls from bondmove.h 2023-10-23 20:34:51 +02:00
fgsfds 790d44afb0 Merge pull request #203 from NeonNyan/port
fixup: quick detonate
2023-10-23 20:33:23 +02:00
Catherine Reprobate 0ea3bea096 port: put instant detonate flow in own function 2023-10-22 16:35:30 -07:00
Catherine Reprobate 05c108a950 fixup: quick detonate 2023-10-22 16:23:25 -07:00
fgsfds 6957c1540d port: fix digital grab movement 2023-10-22 18:49:48 +02:00
fgsfds be689a0495 port: add forgotten DPAD_RIGHT setting 2023-10-22 15:29:36 +02:00
fgsfds 0b9f99a084 port: only allow crouch cycling when crouching is allowed 2023-10-22 15:22:01 +02:00
fgsfds 4c1076080d port: allow user to go back to the original crouch controls
set Game.ClassicCrouch=1
2023-10-22 15:17:47 +02:00
fgsfds 8347900d33 port: expand config size 2023-10-22 15:07:47 +02:00
fgsfds f638d49693 port: fit the CK_ enum back into 32 bits 2023-10-22 14:45:58 +02:00
fgsfds d1817aaea6 port: cleanup; camspy and slayer respect invert pitch option
note: dual analog mode now only works if you set StickCButtons=0 in pd.ini
2023-10-22 14:38:44 +02:00
fgsfds e2b1cdce86 Merge pull request #196 from NeonNyan/1.2_analog
1.2 + 1 Analog Controls
2023-10-22 13:29:42 +02:00
fgsfds 81a5e971ef port: finish drawing before copying the backbuffer 2023-10-21 14:24:36 +02:00
fgsfds 6f0cb752aa port: gl: allow user to override context version 2023-10-19 13:36:40 +02:00
fgsfds abf5703036 port: only disable crash handlers if they were installed 2023-10-19 12:32:57 +02:00
fgsfds b8e6e19ef5 port: allow running without a crash handler
--no-crash-handler
2023-10-19 12:30:50 +02:00
fgsfds ba51e9d5d1 port: don't autoturn when looking too far to the side in horizon scanner mode 2023-10-18 16:17:26 +02:00
fgsfds 8bf14c4044 port: implement horizon scan effect 2023-10-18 16:12:25 +02:00
Catherine Reprobate b650c820e0 Readme update 2023-10-17 18:28:18 -07:00
Catherine Reprobate 80d787caf9 Support for two-sticks, one controller
port: implements analog movement for pc controllers

port: Implement menu movement with the C stick

port: Implement analog leaning

port: Implement 1.2 + 1 analog zooming

port: pd input lib now handles 32 buttons

port: modern crouch implementation

port: implement analog slayer airbraking

port: xbla farsight strafing

Map crouch buttons

- map cycle crouch to L3
- sensible 1964-style crouch bindings
2023-10-17 18:28:18 -07:00
fgsfds 1eb1e9686a port: allow user to disable framebuffer use 2023-10-16 23:19:18 +02:00
fgsfds dbebe7e626 port: fix new fb effects when MSAA is on 2023-10-16 23:06:00 +02:00
fgsfds 79f8a35c33 port: implement fisheye 2023-10-16 22:38:44 +02:00
fgsfds b78a5ee064 port: implement motion blur and zoom blur 2023-10-16 22:07:41 +02:00
fgsfds ed3bd97dd7 port: when loading GL try 3.0 and 3.2 core as well 2023-10-05 18:20:37 +02:00
fgsfds d3d313c9e8 Merge pull request #194 from rafccq/port
bug fix: incorrect RGBA values for some embedded textures
2023-10-04 10:53:40 +02:00
Raf 8bb847508f Merge remote-tracking branch 'base/port' into port 2023-10-03 21:14:48 +08:00
fgsfds 63b38e48ba port: actually use RumbleScale 2023-10-03 11:03:27 +02:00
Raf e8cb7e4136 Merge remote-tracking branch 'base/port' into port 2023-10-02 01:48:49 +08:00
fgsfds 8a71ff651a port: correct aspect ratio of combat scenario-specific timers 2023-10-01 17:33:37 +02:00
Raf 4c201ef3ff Merge remote-tracking branch 'base/port' into port 2023-10-01 23:05:07 +08:00
fgsfds 0278458a28 port: fix #193 2023-10-01 16:22:51 +02:00
Raf 3b4600d0af bug fix: incorrect RGBA values for some embedded textures
fixes blue muzzle flash from Investigation and Crash Site drone guns
2023-10-01 21:58:27 +08:00
fgsfds 50e3393951 Update README.md 2023-09-30 19:09:12 +02:00
fgsfds 72fa10634f Merge pull request #191 from TwitchBronBron/patch-1
Improve windows build instructions
2023-09-30 19:08:13 +02:00
Bronley Plumb e6a852ea8b Update README.md
fix numbers in list
2023-09-30 12:37:41 -04:00
Bronley Plumb 603a879bdf Update README.md
Add a note.
Remove lots of stuff that wasn't actually necessary.
2023-09-30 12:36:55 -04:00
Bronley Plumb 94221e2c62 Improve windows build instructions 2023-09-30 12:13:49 -04:00
fgsfds 28837dd034 port: different fix for chrAlertOthersOfInjury crash 2023-09-30 14:17:47 +02:00
fgsfds 9a7e9c9ee3 port: small fixes for previous commit 2023-09-30 14:05:53 +02:00
fgsfds 608b02d363 Merge pull request #188 from NeonNyan/ammenu-abs
hack: cp `inputMouseGetScaled -> inputMouseGetScaledDeltaAbsSens` for intuitive amenu UX while using aim inversion
2023-09-30 12:41:49 +02:00
Catherine Reprobate 940ba8c4c0 fixup: Use the float abs function 2023-09-29 17:29:08 -07:00
Catherine Reprobate b0c6e79329 hack: cp inputMouseGetScaledDeltaAbsSens for ammenu 2023-09-28 23:00:07 -07:00
fgsfds 86ed199054 port: fix external seg loading 2023-09-28 09:05:11 +02:00
fgsfds 466c77362e port: mod: add support for sequence replacements 2023-09-28 00:55:14 +02:00
fgsfds 8a342a0698 port: mod: add a dumb replacement system for individual textures and animations 2023-09-27 23:42:47 +02:00
fgsfds 75b0d2dd29 port: modconfig: allow defining the alarm sound and extra gunmem size 2023-09-27 20:19:09 +02:00
fgsfds 704015deac port: modconfig: add user defined extended weather config
includes a way to specify weatherproof rooms and other hardcoded stuff

this might break something, as it removes some hardcoded checks
2023-09-27 19:44:51 +02:00
fgsfds d98575d77b port: add basic mod directory support with config files for custom stages
select mod directory with --moddir whatever

these should contain a modconfig.txt that can specify replacements for some stage table fields, etc
2023-09-26 23:05:07 +02:00
fgsfds 9b17aaf258 port: gl: add ARB_vertex_array_object
for those #ifdef APPLE parts
2023-09-26 15:29:59 +02:00
fgsfds 4638af52e2 port: gl: don't die without fbo support 2023-09-26 15:28:43 +02:00
fgsfds 8aa1e6b9c9 port: gl: check for GL_MIRROR_CLAMP_TO_EDGE; cleanup 2023-09-26 15:01:49 +02:00
fgsfds c4e0e4f868 port: more GL error checking 2023-09-26 14:49:14 +02:00
fgsfds 85b2ba5f77 port: cap pad size
this is required for some custom levels that have pads with wrong flags
2023-09-25 01:39:01 +02:00
fgsfds ef090a2b8f port: properly get size from external files 2023-09-25 01:39:01 +02:00
fgsfds d1d11b9362 port: fix alreadySwapped
how the fuck did this work fine before?
2023-09-25 01:39:00 +02:00
fgsfds ee4434eb6c Merge pull request #181 from jonaeru/enable-combatknife-jp
Add the combat knife in jpn-final
2023-09-24 19:40:10 +02:00
Jonaeru 9d2957c419 Add the combat knife in jpn-final, fix conditions 2023-09-24 22:07:53 +09:00
Jonaeru e606a58515 Add the combat knife in jpn-final, fix #if 2023-09-24 21:58:08 +09:00
fgsfds d303971c2d Revert "port: use system trig functions"
apparently this only causes issues, though it might be possible to use SOME trig functions from libc
2023-09-24 11:47:14 +02:00
fgsfds bd113a5b44 port: nicer GL debug output
now only enabled if you pass --debug-gl
2023-09-24 00:41:57 +02:00
Jonaeru 99337e8157 Add the combat knife in jpn-final 2023-09-24 01:30:11 +09:00
fgsfds dad5b3c074 port: use system trig functions
this might cause different behavior from the N64 version or it might fix some issues, who knows
2023-09-23 13:18:51 +02:00
fgsfds 7d5f33d033 port: fix surfacetypes in g_Textures 2023-09-22 21:26:02 +02:00
fgsfds 54842f50db port: another UB fix in bg.c 2023-09-22 21:06:32 +02:00
fgsfds 5ae29afdeb port: fix some pointer ub in bg.c 2023-09-22 20:52:31 +02:00
fgsfds 8a62b884cc port: make crosshair sway resolution independent
this might suck
2023-09-22 20:37:52 +02:00
fgsfds ca8851789a port: add centered HUD mode
set Game.CenterHUD=1 in pd.ini to enable
2023-09-22 20:26:32 +02:00
fgsfds 205032c626 Merge pull request #176 from rafccq/port
bug fix: hoverbike jittering
2023-09-22 20:13:59 +02:00
Raf f0842337e1 Merge remote-tracking branch 'base/port' into port 2023-09-20 18:37:36 +08:00
fgsfds b2cb5c1737 tools: assetmgr: move --raw-out into a separate function 2023-09-20 11:19:36 +02:00
fgsfds eef42a1e3e tools: assetmgr: allow writing raw binary instead of ELF; fix zip() on windows
use --raw-out filename to get the raw output (zipped if applicable)
2023-09-20 10:58:19 +02:00
fgsfds 53ff42836c tools: rarezip: use system gzip on non-linux 2023-09-20 10:36:21 +02:00
Raf e92f556cf9 bug fix: hoverbike jittering - also remove redundant condition from hovUpdateGround() 2023-09-19 04:07:28 +08:00
Raf 13a6cc1c28 bug fix: hoverbike jittering - revert changes to frametimeCalculate() 2023-09-19 03:12:30 +08:00
Raf 89a3377456 bug fix: hoverbike jittering - forgot to remove a term from the expression 2023-09-19 01:13:29 +08:00
Raf 053d6172e5 bug fix: hoverbike jittering 2023-09-19 00:59:09 +08:00
fgsfds 31bb7c62ad port: add scanline effects for NV and IR goggles and slayer 2023-09-17 23:53:12 +02:00
fgsfds c3f572f016 port: recreate infiltration camera effects
using newly added modulation blending and noise
2023-09-17 23:34:02 +02:00
fgsfds 309aff78fe Merge pull request #171 from Phnod/enhancement/auto-switch-classic-weapons
Add classic weapons to auto-switch list
2023-09-16 12:41:44 +02:00
fgsfds 8553c788ab port: disable reverse pitch and lookahead by default 2023-09-15 21:08:04 +02:00
fgsfds d567f707cb port: fix #170 2023-09-15 20:59:48 +02:00
fgsfds 6686221029 port: fix #169 2023-09-15 20:53:06 +02:00
fgsfds 3ee473d909 Revert "port: fall back to copy if a zipped file is not zipped"
This reverts commit 233f4b7514.
2023-09-15 20:38:58 +02:00
fgsfds 2010d31f6b Revert "port: fix error message in previous commit"
This reverts commit ae2d463d7e.
2023-09-15 20:38:37 +02:00
fgsfds ae2d463d7e port: fix error message in previous commit 2023-09-15 20:32:31 +02:00
fgsfds 233f4b7514 port: fall back to copy if a zipped file is not zipped 2023-09-15 20:31:24 +02:00
fgsfds 6a1b0a474c port: allow specifying path to eeprom file
--eeprom-file file.bin
2023-09-14 21:35:05 +02:00
fgsfds 78ff5683ce port: make the reverse pitch option affect mouselook 2023-09-14 20:41:19 +02:00
fgsfds 53e881b75e port: support loading/saving from/to a directory in HOME or APPDATA
~/.local/share/perfectdark on Linux

AppData/Roaming/perfectdark on Windows

on Windows if the game has write access to the working directory it will save there by default, otherwise it will save to AppData

on Linux the game will save to the working directory if there is already a config there, otherwise it will save to ~

additionally the ROM/data files will be loaded from wherever they're found, working directory taking priority
2023-09-13 20:36:42 +02:00
fgsfds fff2fcae21 port: don't increment module refcount when getting base address 2023-09-12 23:28:30 +02:00
fgsfds a68a23d1cb port: print module base in crash message 2023-09-12 23:24:23 +02:00
fgsfds cb1e1e5dca port: fix #163 2023-09-12 17:34:34 +02:00
Phnod 3b09cb3fae Add classic weapons to auto-switch list 2023-09-11 18:45:33 -04:00
fgsfds c10050a14c port: jpn-final: possibly fix japanese characters 2023-09-11 18:32:09 +02:00
fgsfds f8ef6939b0 port: roll back to old variant of #76 2023-09-08 22:28:19 +02:00
fgsfds 52854b6502 port: fix #139 2023-09-08 15:47:24 +02:00
fgsfds fe5d1dd152 port: fix #158 2023-09-08 15:09:05 +02:00
fgsfds 180e62d597 port: cosmetics 2023-09-08 14:37:44 +02:00
fgsfds 4870641d38 Merge pull request #126 from Phnod/zoom-hud-fov
Zoom HUD fov fix and zoom fov config option
2023-09-08 13:00:14 +02:00
fgsfds 33e2f15f49 Merge pull request #121 from rafccq/port
Bug fix: double reload
2023-09-08 12:59:32 +02:00
fgsfds cf51f09826 Merge pull request #160 from tmyqlfpir/port
Fix random five scenario using classic weapons for last slot
2023-09-08 12:59:21 +02:00
tmyqlfpir 8a75774506 Fix comment typo
Introduced in commit 920c0eada5
2023-09-08 20:40:58 +10:00
tmyqlfpir 7e8c57ee4d Fix random five scenario using classic weapons for last slot 2023-09-08 20:25:30 +10:00
Raf 84331c4d08 Bug fix: double reload, new approach
Reverted the previous changes, no longer necessary
2023-09-05 22:27:24 +08:00
Raf ceac1be026 Merge remote-tracking branch 'base/port' into port 2023-09-05 21:44:26 +08:00
fgsfds 892d50ba7c port: revert #134 for now
there must be a different solution for that problem
2023-09-05 11:45:12 +02:00
Raf c08d8b6bcb Merge remote-tracking branch 'base/port' into port 2023-09-05 04:40:45 +08:00
fgsfds dde656c4c3 port: fix typo 2023-09-04 21:47:42 +02:00
fgsfds 2d628e2b5a Merge pull request #134 from Phnod/fix/guard-line-of-sight
fix: return false in chrHasLosToPosWasteful if outside FOV check
2023-09-04 21:46:52 +02:00
fgsfds d7652a6db6 port: remove stray field in TextureCacheKey 2023-09-04 21:10:20 +02:00
fgsfds 491d3521f7 port: different names for pal and jpn EXEs 2023-09-04 21:06:49 +02:00
fgsfds d6854c412c port: allow building with pal-final and jpn-final
this will produce a separate executable that will load pd.pal-final.z64 or pd.jpn-final.z64, respectively

japanese characters are broken in jpn and pal crashes when you try to select language, so no autobuilds yet
2023-09-04 21:06:10 +02:00
fgsfds 110386a3dd tools: mklang: explicitly specify utf-8 2023-09-04 21:02:50 +02:00
Phnod 7d96cd8fbd Merge branch 'port' of https://github.com/Phnod/perfect_dark into zoom-hud-fov
# Conflicts:
#	port/src/main.c
#	src/include/data.h
2023-09-03 15:39:46 -04:00
fgsfds 840a2e73a5 port: implement screen shake 2023-09-03 19:12:29 +02:00
Phnod d033a7fa02 Merge branch 'port' of https://github.com/Phnod/perfect_dark into zoom-hud-fov
# Conflicts:
#	src/include/data.h
2023-09-02 19:05:12 -04:00
fgsfds 07c3a513ef port: generalize the texture font filter a bit
now called TextureFilter2D; although for now I couldn't find anything other than fonts to use it on
2023-09-03 00:36:27 +02:00
fgsfds 18b467a4d8 Merge pull request #127 from Phnod/font-filtering
port: add a config option to disable texture filtering on fonts
2023-09-03 00:22:06 +02:00
fgsfds ff8505c013 Merge pull request #130 from Phnod/rotated-text-cutoff-fix
fix: remove height trim on rotated text
2023-09-03 00:19:06 +02:00
fgsfds 7207bb6293 Merge pull request #137 from NeonNyan/pc-ab
Use XBox / PC Menu A/B semantics
2023-09-02 23:21:30 +02:00
Catherine Reprobate 0d6a62ada0 Use XBox / PC Menu A/B semantics
Fixes #110
2023-09-02 13:28:21 -07:00
fgsfds 721c27c329 port: add exit option to 4mb menu 2023-09-02 22:05:33 +02:00
Raf 488198b7da Merge remote-tracking branch 'base/port' into port 2023-09-03 02:45:19 +08:00
fgsfds 702db43590 port: workarounds for some sky issues 2023-09-02 19:35:04 +02:00
Raf d8c5960c80 Merge remote-tracking branch 'base/port' into port 2023-09-02 23:13:48 +08:00
fgsfds 0942f61aff port: possibly fix skyboxes
by just rendering them with normal triangles
2023-09-02 16:18:06 +02:00
Phnod b83604a677 fix: return false in chrHasLosToPosWasteful if outside FOV check 2023-09-02 02:45:40 -04:00
fgsfds 56df5b4054 port: ignore invert pitch setting when mouse aiming 2023-09-01 23:08:52 +02:00
fgsfds cc079e842b port: small crashhandler fix 2 2023-09-01 22:58:45 +02:00
fgsfds 37907dccfc port: small crashhandler fix 2023-09-01 22:49:45 +02:00
fgsfds 701193e71a port: add crash handler
you probably won't get symbol names, but you can still use addr2line
2023-09-01 22:42:44 +02:00
Phnod eff475c498 fix: nudge menu left side text a pixel to the left to counteract extra pixel column 2023-09-01 14:38:17 -04:00
Phnod 5235581e33 fix: remove height trim on rotated text 2023-09-01 13:49:50 -04:00
Raf ec6b6b25a4 Merge remote-tracking branch 'base/port' into port 2023-09-02 00:20:29 +08:00
fgsfds e5e685902c port: don't use G_RM_NOOP2 with non-noop 1cyc modes
this ALMOST fixes sparks and blood splatter
2023-09-01 17:56:00 +02:00
fgsfds b0d97bde89 port: possibly fixed a bunch of textures
at the cost of about 22kb extra memory, how horrifying
2023-09-01 17:55:07 +02:00
Phnod 810db26bf4 fix: undo regression with previous cleanup, horizon scanner previously showed the wrong zoom level relative to FOV change 2023-09-01 10:07:15 -04:00
Phnod 5033c096a2 cleanup: move PLATFORM_N64 preprocessor checks for fov zoom into a separate macro to reduce clutter 2023-09-01 09:48:53 -04:00
Raf 83cfaa5e77 Merge remote-tracking branch 'base/port' into port 2023-09-01 20:44:50 +08:00
fgsfds 29dae044cc port: also disable hi-res and aspect options in 2p pause menu 2023-09-01 12:45:05 +02:00
Raf 7e83207444 Merge remote-tracking branch 'base/port' into port 2023-09-01 15:59:51 +08:00
fgsfds 9744b2266f port: dummy out hi-res and screen ratio options 2023-09-01 09:22:09 +02:00
Phnod 9eb3ffcc30 port: add a config option to disable texture filtering on fonts 2023-09-01 00:02:47 -04:00
Phnod 917209cb65 fix: remove +1 from horizon scanner's displayed zoom level to show the accurate zoom level
Previously the display would instantly jump from 1.00x to 2.01x, and show 31.00x instead of 30.00 at the max zoom level
2023-08-31 21:31:31 -04:00
Phnod 0bf57ddd48 fix: apply FovAffectsZoom to horizon scanner zoom 2023-08-31 21:26:00 -04:00
Phnod fb009ae52f fix: allow dynamic zoom weapons to fully zoom out to 1x zoom 2023-08-31 20:58:33 -04:00
Phnod 2a5160c519 cleanup: move repetitive zoom fov logic to single multiplier value 2023-08-31 20:39:30 -04:00
Phnod 349b502149 port: apply FovAffectsZoom to Farsight's secondary fire mode 2023-08-31 20:39:30 -04:00
Phnod 1c1164d9e8 port: apply FovAffectsZoom changes to max zoom level for sniper, farsight and horizon scanner 2023-08-31 20:39:29 -04:00
Phnod 35386bbd2c port: modify default zoom level for dynamic zoom weapons if fovzoom ini option is enabled
This affects the Sniper Rifle, Farsight, and Horizon Scanner
2023-08-31 20:39:29 -04:00
Phnod 96bd8e05aa port: add ini config parameter to control whether ini FOV change should affect the max zoom of weapons 2023-08-31 20:39:29 -04:00
Phnod 85c1adb258 port: adjust max zoom range by FOV ini value 2023-08-31 20:39:29 -04:00
Phnod e540a42c9c port: modify zoom range hud to use player FOV 2023-08-31 20:39:29 -04:00
Raf 93ff313237 Merge remote-tracking branch 'base/port' into port 2023-09-01 01:05:42 +08:00
fgsfds 60e2118001 Merge pull request #114 from iamgreaser/gm/ubfix-0001
Fix a few cases of UB incl. OoB
2023-08-31 18:29:38 +02:00
Raf 49963c2e47 Merge remote-tracking branch 'base/port' into port 2023-08-31 20:07:43 +08:00
fgsfds e883144a76 port: fix texformat errors 2023-08-31 13:00:04 +02:00
fgsfds b6a3aef345 port: add logging and some command line args
--log: logs messages to pd.log

--boot-stage N: sets initial stage number to N (MP stages will crash or hang if booted like this)

--no-sound: disable sound

--rom-file S: set ROM filename
2023-08-31 12:54:18 +02:00
Raf b49cc250e0 Merge remote-tracking branch 'base/port' into port 2023-08-31 17:53:17 +08:00
fgsfds 2e49ba10dd port: aspect correct radial menu 2023-08-31 10:36:21 +02:00
Raf 4042fb3a62 Bug fix: double reload 2023-08-31 14:29:29 +08:00
fgsfds 24ced381de port: add separate mouse aim sensitivity
Game.MouseAimSpeedX and Game.MouseAimSpeedY
2023-08-31 01:21:33 +02:00
fgsfds e265482cb4 port: more widescreen HUD hacks 2023-08-31 00:55:17 +02:00
fgsfds ba8346edb7 port: experimental hack for proper 16:9 HUD
might or might not be more convenient than editing all offsets
2023-08-31 00:45:18 +02:00
fgsfds 600f261dcb port: don't crash silently on GL errors 2023-08-30 18:19:54 +02:00
fgsfds 14efaee388 port: add wide rect commands; fix crosshair spazzing out on screen borders
if you're building manually, this change requires a clean rebuild
2023-08-30 17:21:13 +02:00
fgsfds 687682cab0 port: fix gamepad aiming with MOUSEAIM_CLASSIC
also uninvert Y when moving the camera with it
2023-08-30 16:10:42 +02:00
fgsfds c3b4d59168 port: add 1964GEPD-like mouse aim mode
you can switch to the old variant by setting Game.MouseAimMode to 1 in pd.ini
2023-08-30 15:28:33 +02:00
fgsfds 970e13773d port: remove unused fileSlots array 2023-08-30 12:45:39 +02:00
fgsfds af1422a1de port: move CrosshairSway and FovY to the [Game] ini section
fov doesn't really belong in the video functions either
2023-08-30 12:31:27 +02:00
fgsfds 4947350230 Merge pull request #70 from squiddingme/crosshair
Config option to control crosshair/gun sway
2023-08-30 12:15:57 +02:00
fgsfds e29e20e779 port: small cleanup; decrease bigfont height to 26
this avoids scrolling in the main menu; will probably also help with the extended options later
2023-08-30 12:14:18 +02:00
fgsfds 3490f1d7ae Merge pull request #104 from kronflux/port
Add an exit option to main menu
2023-08-30 12:03:20 +02:00
fgsfds d39d7fb1f5 port: small cleanup 2023-08-30 12:02:24 +02:00
fgsfds 8b3b684675 Merge pull request #108 from rafccq/port
enable using mouse on the radial menu
2023-08-30 12:00:27 +02:00
Richard M 630b236ac0 Merge branch 'fgsfdsfgs:port' into port 2023-08-30 01:10:15 -06:00
Raf 5bb7cb47aa Merge remote-tracking branch 'base/port' into port 2023-08-29 20:07:59 +08:00
fgsfds 7d152b37ad Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-29 14:00:48 +02:00
Ryan Dwyer 0235a971d6 Fix bot name array overflow 2023-08-29 21:36:58 +10:00
Raf bb9bb83202 Merge remote-tracking branch 'base/port' into port 2023-08-29 19:33:51 +08:00
Raf 1a7458a290 fix whitespace issues 2023-08-29 16:26:33 +08:00
fgsfds 00decf3347 port: wrap previous change in #ifdef AVOID_UB 2023-08-29 10:16:51 +02:00
fgsfds 6e1df743d0 Merge pull request #116 from AXDOOMER/port
Fix buffer overflow in creditsResetSlides
2023-08-29 10:15:02 +02:00
fgsfds c54a768b19 port: fix #117 and other related OOB writes 2023-08-29 10:09:46 +02:00
Richard M 250e9b1805 Merge branch 'fgsfdsfgs:port' into port 2023-08-29 00:44:46 -06:00
GreaseMonkey 43a91b2b4b Fix "mpindex=4" UB cases for various view gadgets 2023-08-29 13:15:42 +12:00
Alexandre-Xavier e4742bcafb Fix array out of bound in decoder.c 2023-08-29 01:07:44 +00:00
Alexandre-Xavier Labonté-Lamoureux 21f3dee554 Fix buffer overflow in creditsResetSlides 2023-08-28 19:45:50 -04:00
GreaseMonkey 889ae950fe Fix a few cases of UB incl. OoB
Behaviour should be mostly the same but there are some OoB accesses in the menu code where I've had to assume things.

Tests for each OoB case:

- Accessing of layer -1: Select a game file in the "Choose Your Reality" screen.
- Accessing of menu for the 5th player: Die in a mission.
2023-08-29 10:23:14 +12:00
Raf 272b28b6a9 attempt to fix whitespace issues 2023-08-29 02:53:17 +08:00
Raf 9a259acefa enable using mouse on the radial menu: removed unused constants 2023-08-29 02:41:11 +08:00
Raf 92392da6fe enable using mouse on the radial menu: reworked
mouse+kb and other input devices are no longer exclusive when using the radial menu
2023-08-29 02:39:16 +08:00
Raf 0f6920a3f1 Merge branch 'base-port' into port 2023-08-28 23:55:15 +08:00
fgsfds d2574c4b49 port: fix RGB555 textures in Grid
fix submitted by Ryan
2023-08-28 16:02:37 +02:00
fgsfds 0e5b4bde62 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-28 15:55:54 +02:00
fgsfds 916d147619 port: skip detail textures
this fixes the carpet in Defection and maybe other places, but means that detail textures are broken for now
2023-08-28 15:03:51 +02:00
Ryan Dwyer 4f56cd4c09 Set names for symbols relating to the gfx C0 command 2023-08-28 22:18:05 +10:00
Raf ab17a995a4 enable using mouse on the radial menu 2023-08-28 04:50:26 +08:00
squiddingme 3f562c3009 Add config option to control crosshair/gun sway 2023-08-28 02:40:50 +08:00
fgsfds 66443dd2c2 port: don't explode when EEPROM can't be saved or loaded 2023-08-27 17:49:27 +02:00
fgsfds 89849bc805 port: read keybinds from config file 2023-08-27 17:26:57 +02:00
fgsfds 4fef14f9fc port: rework config system
it is no longer required to specify all possible config keys in config.c, you can just use configGet/Set
2023-08-27 17:26:46 +02:00
fgsfds dce1f5492f Update README.md 2023-08-27 13:33:41 +02:00
Ryan Dwyer 0b1aabf345 Set names for a heap of shotdata symbols 2023-08-27 21:27:53 +10:00
fgsfds 57b6247a65 Update README.md 2023-08-27 13:22:59 +02:00
fgsfds 9529a991ef Merge pull request #68 from NeonNyan/controller-buttons
Multiple input updates
2023-08-27 13:06:16 +02:00
fgsfds 1f49665c05 Merge pull request #103 from iamgreaser/gm/fix-choppy-audio-at-non-60fps
Fix choppy audio at sub-60fps framerates
2023-08-27 12:49:54 +02:00
Richard M 0f73ab889f port: add an exit option to main menu
In Fullscreen there is currently no way to close the game without using Alt+F4. This adds an option "Exit" to the Main Menu, which asks to confirm before performing exit.
2023-08-27 04:16:51 -06:00
Catherine Reprobate aa8e08e4d0 Update readme 2023-08-26 18:35:07 -07:00
Catherine Reprobate 2a78f6902d handle b button differently if N64 platform 2023-08-26 17:56:36 -07:00
fgsfds 558875c91c port: fix the RGBA4/8 hack
this fixes the door hinge thing textures in CI
2023-08-27 02:17:30 +02:00
Catherine Reprobate 8ec0feb49b fix: grabbable 2023-08-26 17:16:41 -07:00
GreaseMonkey 5b0874daef Fix choppy audio at sub-60fps framerates 2023-08-27 12:12:21 +12:00
Catherine Reprobate df8c1139a1 fix: sniper crouching 2023-08-26 16:27:41 -07:00
Catherine Reprobate 0d7bd746ac move abstracted n64 buttons to contants.h 2023-08-26 16:17:54 -07:00
Catherine Reprobate e95c7f144e fixes AB remote detonation 2023-08-26 16:14:43 -07:00
Catherine Reprobate 10844e7a52 fixup controller use buttons 2023-08-26 16:14:43 -07:00
Catherine Reprobate 077a091f7d fixup camspy bindings 2023-08-26 16:14:43 -07:00
Catherine Reprobate f88493870a Address multiple extended input nits
- Q for radial menu
- mapped remaining xbla buttons, but the menus follow switch controller handfeel
- based on @Phnod's switch-weapons PR: https://github.com/fgsfdsfgs/perfect_dark/pull/57
2023-08-26 16:14:43 -07:00
Catherine Reprobate 3f6f0b3f9c map sensible xbox inputs
xbox A is mapped to n64 B for using items
n64 A is unmapped for controller.

When radial / weapon switching is mapped way from n64 A n64 A can be
remapped as a cancel button .
Trigger will need to be used for the menus until
2023-08-26 16:14:43 -07:00
Phnod 5a0580005f Added scrollwheel weapon swapping 2023-08-26 16:14:43 -07:00
fgsfds 1439f8bbeb Merge pull request #76 from tmyqlfpir/mp-classic-weapons
Allow classic weapons to be used in multiplayer
2023-08-26 20:49:44 +02:00
fgsfds bf8277fb2c port: re-disable GBI_FLOATS
some more matrices need fixing I guess
2023-08-26 15:59:43 +02:00
fgsfds d9c974fc00 port: set default optimization level to -Og 2023-08-26 14:49:37 +02:00
fgsfds 23dfc05511 port: enable GBI_FLOATS by default
seems like it works fine
2023-08-26 14:49:07 +02:00
fgsfds 4d9a41bc76 port: (possibly) make the laser scale better with the bigger distance 2023-08-26 14:23:22 +02:00
fgsfds db0059e0f0 port: infinitely shooting guard fix from 1964GEPD 2023-08-26 14:08:20 +02:00
fgsfds 2b27c2dc6a port: make matrices work with GBI_FLOATS
add GBI_FLOATS=1 to DEFINES to enable it

not enabling by default yet because not sure if it'll break anything
2023-08-26 13:49:23 +02:00
fgsfds 85e914c129 Merge pull request #94 from MaikelChan/credits_texts
Fixed credits texts with wrong UVs.
2023-08-26 13:31:20 +02:00
MaikelChan 5710b2a7dd Fixed credits texts with wrong UVs. 2023-08-26 13:24:42 +02:00
fgsfds 844139b339 port: restart currently playing MP3 when needed
there's probably a way to determine reset condition without adding an extra field to g_Mp3Vars, but I can't be arsed to figure it out
2023-08-26 10:34:35 +02:00
Ryan Dwyer 79a94b29ce Name some texture symbols, mostly relating to LODs 2023-08-26 12:20:04 +10:00
tmyqlfpir d03617d682 Add classic weapons to multiplayer 2023-08-26 11:09:58 +10:00
fgsfds 8494e29075 Merge pull request #90 from Phnod/laser-sight-distance
Increase Falcon laser fade out distance
2023-08-25 20:59:20 +02:00
fgsfds d229ba2405 port: somewhat fix the health display at different FOVs 2023-08-25 20:56:17 +02:00
fgsfds 4ab1e08129 port: make sun and light glares use LOS checks
this partially fixes them, but there are still problems to iron out
2023-08-25 17:18:02 +02:00
Phnod 4255867f29 Increase laser fade out distance 2023-08-25 00:39:20 -04:00
fgsfds 87529f37c8 port: use gettimeofday() as timing source; use smaller tick multiplier to avoid overflows 2023-08-24 18:11:14 +02:00
fgsfds caaf82385b port: disable color modulation effects when none are active 2023-08-24 17:53:13 +02:00
fgsfds ffdcdeee9f port: increase slayer sensitivity a bit more 2023-08-23 23:02:56 +02:00
fgsfds 0db9e84b58 port: cap slayer rocket sensitivity and make it a bit bigger 2023-08-23 22:47:06 +02:00
fgsfds 82f647299c port: link with -ldl on linux regardless of arch 2023-08-23 22:36:47 +02:00
fgsfds a85a18774f port: implement NVG/IRG color modulation using the grayscale command
still missing the funky overlays
2023-08-22 23:21:55 +02:00
fgsfds 143d2a107a port: save config on exit 2023-08-22 20:37:18 +02:00
fgsfds 47258ebd7f Merge pull request #53 from tmyqlfpir/fix-footsteps-slomo
Fix spamming footsteps for slow mode
2023-08-22 20:30:55 +02:00
fgsfds 095b7540d5 port: fix aspect on menu models 2023-08-22 20:22:25 +02:00
fgsfds e871156301 port: reduce or eliminate portal seams
by slightly extending the portal scissor boxes
2023-08-22 20:09:14 +02:00
fgsfds 35da8e2e67 port: fix animated textures in Attack Ship
patch submitted by Ryan
2023-08-22 19:48:22 +02:00
fgsfds 5d4606d0f6 port: fix #73
patch submitted by Ryan
2023-08-22 19:47:50 +02:00
fgsfds 2533a844a7 port: fix use-after-free when invalidating texcache 2023-08-22 01:35:13 +02:00
fgsfds 62ea74f332 port: turns out rodata comes after texture data 2023-08-22 00:57:27 +02:00
Ryan Dwyer 38345c1672 Set names for menumodel symbols 2023-08-22 08:48:32 +10:00
fgsfds 3a10d47903 port: fix normals 2023-08-22 00:42:36 +02:00
fgsfds 12eeb97e71 port: don't go out of bounds when unswizzling textures
this might still break though, god knows what else is there in the texconfigs
2023-08-22 00:30:41 +02:00
fgsfds 4b1dc93792 Merge pull request #69 from tmyqlfpir/fov-speed-adjustment
Adjust FOV zoom speed when using non-default FOV
2023-08-21 17:11:54 +02:00
tmyqlfpir 5aa8474d2b Adjust FOV zoom speed when using non-default FOV 2023-08-21 18:23:40 +10:00
fgsfds 58e13db613 Update README.md 2023-08-21 01:14:45 +02:00
fgsfds 9e3dd9b6d4 Merge pull request #61 from tmyqlfpir/eyespy-clamp
Limit eyespy range to 75 degrees
2023-08-21 01:12:52 +02:00
fgsfds 81902e1b96 Merge pull request #63 from tmyqlfpir/tweak-pickup-threshold-degrees
Adjust pickup degrees threshold
2023-08-21 00:55:52 +02:00
fgsfds 2670db7ca1 port: add rstick fields to OSContPad 2023-08-21 00:29:51 +02:00
tmyqlfpir bf43f32946 Adjust pickup degrees threshold 2023-08-21 07:45:38 +10:00
tmyqlfpir 4455cfcde1 Limit eyespy range to 75 degrees
Needed due to lack of lookahead
2023-08-21 07:26:01 +10:00
tmyqlfpir 682c0c83a1 Expose LV_SLOMO_TICK_CAP macro in lv.h
Needed for slomo footsteps fix
2023-08-21 06:24:08 +10:00
fgsfds b9944e8669 port: don't crash when swapping empty rooms 2023-08-20 22:20:12 +02:00
fgsfds b4207b3fd9 port: allow theoretical ARM builds
this requires your device to support desktop GL3+ and might require manual setting of the TOOLCHAIN variable
2023-08-20 21:41:04 +02:00
fgsfds 2b6b205a78 port: min supported SDL version should now be 2.0.12 2023-08-20 21:25:06 +02:00
fgsfds 8c6d6df5fc port: be a bit more standard compliant 2023-08-20 19:59:07 +02:00
tmyqlfpir 18ae54f656 Fix footsteps with combat boost 2023-08-21 02:33:11 +10:00
tmyqlfpir f6fb534035 Fix spamming footsteps for slow mode 2023-08-21 01:49:59 +10:00
fgsfds 4b0f2ea439 port: unswizzle pre-swizzled textures 2023-08-20 17:26:11 +02:00
fgsfds 45a81e92f4 Update README.md 2023-08-20 16:51:21 +02:00
fgsfds e0ced73d8a port: fix model lighting 2023-08-20 16:26:21 +02:00
fgsfds f1186a35d8 port: forgot this 2023-08-20 15:48:46 +02:00
fgsfds 933ba8a708 port: swap all portal vertex batches
actually fixes #43

credit to Ryan for the patch
2023-08-20 15:44:01 +02:00
fgsfds bd5d613a24 port: whitespace cleanup 2023-08-20 15:42:40 +02:00
fgsfds 3da1fd4372 Merge pull request #28 from NeonNyan/port
Implement some dedicated buttons for mouse+kb / gamepad
2023-08-20 15:30:39 +02:00
fgsfds d007550adb Merge branch 'port' into port 2023-08-20 15:30:19 +02:00
fgsfds 170f2646e1 Merge pull request #48 from tmyqlfpir/fix-ai-menu-mp
Fix menu crash when issuing order to all bots
2023-08-20 15:28:14 +02:00
fgsfds 207f97a0eb Update README.md 2023-08-20 15:27:34 +02:00
fgsfds 577de9683b Update README.md 2023-08-20 15:26:31 +02:00
tmyqlfpir ec09d4a6ca Use already existing JPN fix 2023-08-20 23:19:59 +10:00
fgsfds 1b04dd8032 Merge pull request #45 from tmyqlfpir/port
Adjust spark scale depending on output resolution
2023-08-20 15:15:43 +02:00
fgsfds 24bfac89ae Merge pull request #46 from tmyqlfpir/force-anim-lerp
Always interpolate character animations
2023-08-20 15:15:00 +02:00
fgsfds 2a5594d7d5 Merge pull request #47 from tmyqlfpir/no-lods
Don't draw LODs for port
2023-08-20 15:14:33 +02:00
fgsfds 44c8b024b0 Merge pull request #49 from tmyqlfpir/skedar-door-rate-limit
Rate limit stuckage RNG for skedar doors
2023-08-20 15:13:40 +02:00
fgsfds 9acd05f16c port: allocate room data from system heap
props to Ryan for the patch
2023-08-20 15:12:09 +02:00
fgsfds 7e71450a76 port: wrap malloc & co
in case we'll need allocation stats or something later
2023-08-20 14:56:07 +02:00
fgsfds 6fbb7e39ec Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-20 14:41:57 +02:00
tmyqlfpir 920c0eada5 Rate limit stuckage RNG for skedar doors
Limits calculation to 15 times per second, close to that to how fast this would execute on original hardware
2023-08-20 21:38:38 +10:00
tmyqlfpir 97c1b13370 Decrease spark scale
Uses hires resolution as multiplication factor
2023-08-20 20:58:16 +10:00
tmyqlfpir 47d4e4f659 Fix menu crash when issuing order to all bots 2023-08-20 20:33:52 +10:00
tmyqlfpir 97258542be Don't draw LODs for port 2023-08-20 20:08:19 +10:00
tmyqlfpir 908aa3556e Always interpolate chr animation
Ignores distance check for pc port
2023-08-20 17:33:17 +10:00
Catherine Reprobate 93679e62e8 tested with xbox one controller
map implemented buttons to xbla positions

map radial menu to middle the mouse button
2023-08-20 00:00:00 -07:00
Ryan Dwyer 09edfb8545 Fix some global data placement issues 2023-08-20 16:48:35 +10:00
Ryan Dwyer d7926f12ad Fix incorrect rounding in C version of sinf 2023-08-20 16:34:38 +10:00
Ryan Dwyer e18167d8ae Fix C version of portalConvertCoordinates 2023-08-20 12:49:21 +10:00
Catherine Reprobate c3dc838acb F to crouch w/ sniper
F to crouch with sniper
F + Z to crouch with sniper
2023-08-19 14:47:43 -07:00
fgsfds 7e26e6eac0 port: disable zbufClear to prevent white flashing in splitscreen 2023-08-19 18:24:33 +02:00
fgsfds 0c80abf5b9 port: ignore scissor test in resolve_msaa_color_buffer 2023-08-19 18:02:24 +02:00
fgsfds a7692fe4ef port: add MSAA setting 2023-08-19 17:50:31 +02:00
fgsfds 05233ef853 port: fix slomo
for different framerates hopefully we'll just have to redefine TICKS
2023-08-19 16:13:02 +02:00
fgsfds 8232d4a3f2 port: fix #23
credit to Ryan for figuring this out
2023-08-19 15:45:16 +02:00
fgsfds e6a4b9f2fe port: small clean up in gfx_pc 2023-08-19 15:38:16 +02:00
fgsfds 67c4531771 port: add stick scale config setting; better (?) deadzone 2023-08-19 15:18:15 +02:00
fgsfds 6f3f48d1e9 port: disable camspy lookahead 2023-08-19 14:21:33 +02:00
fgsfds b7f77498b3 port: disable height-based sensitivity multipliers 2023-08-19 14:17:53 +02:00
fgsfds 8d26944642 port: three-point does not need GL_LINEAR 2023-08-19 13:57:44 +02:00
fgsfds 2f54ceb96e port: add texture filter setting 2023-08-19 13:56:15 +02:00
fgsfds 63a5701906 port: fix mouse sensitivity at different FOVs/in zoom 2023-08-19 13:36:58 +02:00
fgsfds 41cdef055e port: allow keyboard to act as a separate controller
also add a way to fake controller connection status for testing
2023-08-19 12:13:23 +02:00
fgsfds 420053178e Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-19 11:45:17 +02:00
fgsfds 412dcd7736 port: fix blur in hires mode 2023-08-19 11:43:18 +02:00
Ryan Dwyer d7c94b4d04 Fix UB in modelasm chrinfo handler 2023-08-19 19:14:10 +10:00
Ryan Dwyer 032c5166f4 Fix improper casting of model rwdata 2023-08-19 19:01:00 +10:00
fgsfds 4e42e3ef82 port: mouse wheel binds; handle adding and removing controllers 2023-08-19 02:16:58 +02:00
Catherine Reprobate a71c7cbba2 Merge branch 'fgsfdsfgs:port' into port 2023-08-18 16:39:44 -07:00
Catherine Reprobate 781fbcddd4 fixup bindings:
F and G will switch modes and bringup the radial menu
2023-08-18 16:37:41 -07:00
fgsfds 1d151f2864 port: implement some framebuffer effects
cloaking and menu blur

in a likely extremely slow way
2023-08-19 00:48:09 +02:00
Catherine Reprobate ffae4540f9 dedicated radial menu mapped to D_JPAD 2023-08-18 14:34:58 -07:00
Catherine Reprobate 25b5f66e6b map L_TRIG to alt button
- switches immediately when releases L
- or whenevever L+Z is pressed. Will switch back when L is released.
2023-08-18 14:32:08 -07:00
Catherine Reprobate 68c00af44e Mapped reload to X_BUTTON.
Introduce `JO_ACTION*` constants to use `player.bondreloadoractivate` as a bit
field.

Deviation from vanilla Mouse Injector behavior: hard seperation between
reload and activate. `B` will not reload just as `ALT1` will not
activate.
2023-08-18 14:09:45 -07:00
Catherine Reprobate 12571746d7 Unmap L_TRIG and *_JPAD 2023-08-18 13:59:13 -07:00
fgsfds d90504675f port: this is not necessary at all 2023-08-18 17:24:18 +02:00
fgsfds 249041764b port: add adjustable fov 2023-08-18 17:18:56 +02:00
fgsfds 554fde7a9d port: fix rumble 2023-08-18 15:34:13 +02:00
fgsfds a49bfd00a4 port: add mouse controls to eyespy and slayer 2023-08-18 14:47:08 +02:00
fgsfds bc4c08fe2f port: only player 1 gets mouselook and only when aiming is allowed 2023-08-18 13:58:33 +02:00
fgsfds b906f77b37 port: added rumble scale and support for 2 extra buttons
also fixed some warnings
2023-08-18 12:26:55 +02:00
fgsfds e1f6e167fb Update README.md 2023-08-16 15:43:19 +02:00
fgsfds 034ff984cc port: fix s32 pointer in bgRenderRoomPass 2023-08-16 14:52:25 +02:00
fgsfds fedcbb8917 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-16 10:53:02 +02:00
Ryan Dwyer fb5b505bab Untangle menuitemdata structs 2023-08-16 18:34:08 +10:00
Ryan Dwyer f020543599 Use sizeof for setup prop sizes instead of literals 2023-08-16 14:36:34 +10:00
fgsfds 7a4edd6ef7 port: fix SHADE_ALPHA with fog again 2023-08-16 02:15:04 +02:00
fgsfds 2b5e136cc0 port: fix #15 and menu sliders in general 2023-08-16 02:13:58 +02:00
fgsfds ab4d595904 port: fix #14
patch courtesy of Ryan
2023-08-16 00:28:20 +02:00
fgsfds b1247b5eac port: purge texcache when gunmem is released as well 2023-08-16 00:19:53 +02:00
fgsfds bed505fd91 port: get rid of __builtin_trap 2023-08-15 23:33:55 +02:00
fgsfds ffea7cd65a port: reset texcache on level change 2023-08-15 23:33:25 +02:00
fgsfds 8600aead20 port: close config after reading it 2023-08-15 22:00:39 +02:00
fgsfds f48879653a port: forgot this 2023-08-15 21:57:34 +02:00
fgsfds 0c01ab76cf port: add simple config file
includes an option to disable vsync and enable cpu-side frame limiter
2023-08-15 21:45:23 +02:00
fgsfds 1eb30b28e1 port: don't shove headers into the link command line 2023-08-15 21:35:09 +02:00
fgsfds 6a749bdae5 port: temporary fix for explosion texture colors 2023-08-15 17:49:09 +02:00
fgsfds 9aa15c6fbb Merge pull request #12 from MaikelChan/menu_rendering
Fixed flipped texts and menu elements that were beyond the near clip plane
2023-08-15 16:43:31 +02:00
fgsfds 8aa8d61bb8 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port
this fixes collision bugs related to moving objects and rotation of a lot of stuff
2023-08-15 16:16:18 +02:00
Ryan Dwyer 24657743ff Fix mtx3Copy in C translation 2023-08-15 22:28:11 +10:00
MaikelChan 6f35e00c16 Fixed flipped texts and menu elements that were beyond the near clip plane. 2023-08-15 05:05:53 +02:00
fgsfds 20fd3a8f67 port: make alt-enter go into fullscreen 2023-08-15 01:06:14 +02:00
fgsfds 7666ccf2c7 port: fix muzzle flashes on some guns 2023-08-15 00:49:35 +02:00
fgsfds 0cc29d2c99 port: fix healthbar rendering 2023-08-15 00:16:25 +02:00
fgsfds 1b1222494e port: move game viewport init to gfx_init() 2023-08-14 22:07:36 +02:00
fgsfds 94c3dfe51e port: fixup aspect ratio on the 3d parts of the title sequence 2023-08-14 22:07:16 +02:00
fgsfds 58d93cb083 port: hackfix psychosis gun crash 2023-08-14 19:43:05 +02:00
fgsfds f5bcc25e10 port: fix textureconfig-related texture corruption
explosions are still miscolored, but no longer garbage
2023-08-14 18:30:02 +02:00
fgsfds a31e2209c5 port: fix firing range
props to Ryan again
2023-08-14 17:53:08 +02:00
fgsfds 4d52a8e476 port: scale gun swivel only when mouse aiming 2023-08-14 17:42:48 +02:00
fgsfds c3fb50c358 port; refactor widescreen PR a bit
abstract aspect into a video* function

re-add gun swivel, but make it slower on hi res
2023-08-14 17:39:02 +02:00
fgsfds 65115089af Merge pull request #4 from MaikelChan/aspect_ratio
Sort of implemented arbitrary aspect ratio and mouse movement improvements
2023-08-14 17:24:57 +02:00
fgsfds 48bac90a7b Merge pull request #5 from babbygremlin/port
Fix default control scheme for combat sim
2023-08-14 17:18:35 +02:00
babbygremlin 93a38649f3 Fix default control scheme for combat sim
the default control scheme for new profiles in combat simulations was being set to 1.1 instead of 1.2 this just changes the number, its very tiny
2023-08-14 00:30:30 -07:00
MaikelChan 89c5cfb46b Sort of implemented arbitrary aspect ratio and mouse movement improvements. 2023-08-14 07:20:05 +02:00
fgsfds 51808cd1f8 port: fix a bunch of controller-related bugs
don't completely override kb+m input when a controller is connected (fixes #3)

handle controller disconnection

add adequate default controller binds

add deadzone
2023-08-13 23:18:24 +02:00
fgsfds 758eb77578 port: fix credits crash
campaign is now more or less completable, other than the pushbox collision bug
2023-08-13 22:49:00 +02:00
fgsfds 358f788b61 port: read gbi command id correctly in gfxReplaceGbiCommands 2023-08-13 21:09:04 +02:00
fgsfds e0d4bf44b8 port: read command ids correctly when rendering in xray mode 2023-08-13 21:04:00 +02:00
fgsfds 7ec10febae port: swap intro commands properly 2023-08-13 20:30:28 +02:00
fgsfds 8acd495e91 port: revert the loaded_texture changes
they broke more than they fixed
2023-08-13 20:05:26 +02:00
fgsfds 5f11dd48a2 Revert "port: make the tmem_index allocation a little bit more sane"
This reverts commit 0f0e674f71.
2023-08-13 20:02:33 +02:00
fgsfds 38343bfbf1 Revert "port: change the loaded_texture system yet again; fix a couple crashes"
This reverts commit 6750bd9422.
2023-08-13 20:02:16 +02:00
fgsfds 76ed7f180e port: padoffsets are actually u16 2023-08-13 19:42:51 +02:00
fgsfds 6750bd9422 port: change the loaded_texture system yet again; fix a couple crashes
in combat sim once in a million years, in G5 and Villa
2023-08-13 18:52:15 +02:00
fgsfds d51a7bc9d6 port: rename some math functions to avoid conflicts with libc 2023-08-13 17:13:08 +02:00
fgsfds 6cb545aaf0 port: swap more cctv and linkliftdoorobj fields
props to Ryan for noticing
2023-08-13 16:48:21 +02:00
fgsfds 4b8c4a5bcd port: saner bg portal swapping 2023-08-13 15:52:43 +02:00
fgsfds 0a9a191f27 Update README.md 2023-08-13 12:05:59 +02:00
fgsfds 83c1bd3ffd ci: bundle DLL hell with windows builds 2023-08-13 11:56:54 +02:00
fgsfds 23c57ad033 ci: add placeholder file to data directory so it gets packaged 2023-08-13 11:45:42 +02:00
fgsfds cf1594bcbb ci: forgot to --add-architecture 2023-08-13 11:39:05 +02:00
fgsfds 10caa91099 ci: add even more missing deps 2023-08-13 11:37:19 +02:00
fgsfds 6f209d26d8 ci: add missing deps 2023-08-13 11:29:16 +02:00
fgsfds 6d777fb18f ci: start setting up CI 2023-08-13 11:24:24 +02:00
fgsfds c007bee536 port: don't use s32s for texture pointers 2023-08-13 01:13:03 +02:00
fgsfds 0f0e674f71 port: make the tmem_index allocation a little bit more sane 2023-08-12 22:42:38 +02:00
fgsfds 56ab86cddc port: support linear texgen without lookat set; set default values for lookat 2023-08-12 21:41:28 +02:00
fgsfds 8c9c0abee6 port: use uname -m instead of -p for machine arch 2023-08-11 23:43:31 +02:00
fgsfds ae01850ce1 Update README.md
clarify what 32-bit platforms means
2023-08-11 22:23:18 +02:00
fgsfds 319aaaa81d Update README.md 2023-08-11 22:13:20 +02:00
fgsfds 4f4280de58 port: on linux, default to host gcc with -m32
as suggested in #1

also do not abort clean on unsupported target arch
2023-08-11 22:06:39 +02:00
fgsfds dbd2da4923 port: LoadTLUT should probably mark textures for reload as well 2023-08-11 20:55:38 +02:00
fgsfds 16fcca7a2f port: hackfix incorrect size for RGBA textures; mark all textures as changed on load
this fixes the menu font, but it's probably a better idea to fix the whole loaded_texture system
2023-08-11 20:44:24 +02:00
fgsfds a803d5a4ec port: stub out G_RDPHALF_ commands
this will temporarily prevent crashing in combat sim but will result in black skies on maps that use this
2023-08-11 18:18:16 +02:00
fgsfds d888e82de6 port: fix vertex count in G_VTX 2023-08-11 15:19:17 +02:00
fgsfds 07adda3fa6 port: more reasonable mouse sensitivity
what the fuck was I trying to do here?
2023-08-11 00:03:37 +02:00
fgsfds 3416e0632d port: fix byteswapping the waypoint data 2023-08-11 00:03:16 +02:00
fgsfds 6396b38a6f port: fix (?) crash related to knocking out the secretary in defection 2023-08-11 00:02:59 +02:00
fgsfds 25d9e4a195 Update README.md 2023-08-09 23:02:24 +02:00
fgsfds b109d866dd port: fix linux build 2023-08-09 23:00:57 +02:00
fgsfds 075b7f9bd7 port: make the legal screen display the commit hash and platform 2023-08-09 22:54:42 +02:00
fgsfds fc16dc1330 port: nuke unused env var 2023-08-09 22:33:25 +02:00
fgsfds 28282f1c35 port: auto-generate headers like the decomp does
this does not require the ROM
2023-08-09 22:32:26 +02:00
fgsfds 67492e744d Update README.md 2023-08-09 22:09:53 +02:00
fgsfds 288b37a1b3 port: fix aEnvMixer; fix some misc warnings
hopefully that was the last of the big audio issues
2023-08-09 21:18:36 +02:00
fgsfds 60e64e1a1d port: don't doubleswap envelope data
this fixes music running out of free channels
2023-08-09 19:08:48 +02:00
fgsfds 18bab30c59 port: more UB/bug fixes 2023-08-09 13:07:02 +02:00
fgsfds a37441b221 port: hackfix a bunch of UB and seg-related issues
game now runs with -O2
2023-08-08 16:38:45 +02:00
fgsfds 245d5095b5 port: remove hacks from makefile 2023-08-08 14:31:30 +02:00
fgsfds 62f3007d2a port: halfassed solution for segmented addresses; fix some dyntex related stuff 2023-08-08 14:30:59 +02:00
fgsfds f9b27d7d01 port: match rendering resolution to window resolution, but keep 4:3 for now
16:9 requires some work
2023-08-06 22:04:22 +02:00
fgsfds 885bfeaf38 port: disable indefinite wait in aiIfMusicEventQueueIsEmpty for now
might have to actually run audio in a different thread
2023-08-06 21:38:07 +02:00
fgsfds 2d6e6c887e port: add mp3 decoding via lieff/minimp3 2023-08-06 21:24:38 +02:00
fgsfds afae1a3aae port: fix chraction crash
bug?
2023-08-06 21:24:04 +02:00
fgsfds 9081421eba port: add stupid hack to avoid double-swapping audio data 2023-08-06 21:23:47 +02:00
fgsfds eb8c4e9ee9 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-06 18:52:09 +02:00
fgsfds 81c1c206d4 port: make audio run at 60hz again but with smaller frames
this is required to tick music events correctly
2023-08-06 18:20:37 +02:00
fgsfds 063df3243d port: make audio tick at 30hz, add hack to prevent popping
this is a shit solution, but it'll do for now
2023-08-06 18:08:21 +02:00
fgsfds af3e235348 port: reenable SSE/NEON checks in mixer 2023-08-06 15:52:54 +02:00
fgsfds ffb5ca4b5b port: begin implementing audio
mixer taken from sm64-port and modified to fit PD's naudio thing

MP3 playback not supported yet

audio buffering sucks
2023-08-06 15:51:07 +02:00
fgsfds 866be01860 port: swap ADPCM books and loop states 2023-08-06 15:50:07 +02:00
fgsfds 32c05e6a3d port: swap sequence headers 2023-08-06 01:18:07 +02:00
Ryan Dwyer f1e1e6b204 Set names for headanim symbols 2023-08-05 18:16:16 +10:00
fgsfds e1b892e8b4 port: hack in mouselook 2023-08-05 03:13:56 +02:00
fgsfds da9046f745 port: swap RGBA color literals 2023-08-05 01:57:26 +02:00
fgsfds 51a27cba75 port: disable windows imagebase hack
that makes windows put the heap at a lower address instead
2023-08-05 01:13:40 +02:00
fgsfds 0e931b0be0 port: add gSPPerspNormalize support
this fixes the viewmodel
2023-08-05 01:12:47 +02:00
fgsfds ea8e49c870 port: linux support; horrible hack to avoid segmented address funny moments
linux support only tested a little bit in a VM
2023-08-04 23:44:20 +02:00
fgsfds 172f943891 port: remove GetModuleHandleA call 2023-08-04 21:49:22 +02:00
fgsfds e6965580a0 port: mostly unfuck texture loader 2023-08-04 21:47:54 +02:00
fgsfds a9b772ef99 port: fix hitscans and other uses of Gtri 2023-08-04 16:46:05 +02:00
fgsfds c2d1d9b4bf port: don't crash when reading briefing in the mission screen 2023-08-04 01:25:18 +02:00
fgsfds d6ee4f49d2 port: flesh out the input system a bit 2023-08-04 01:11:50 +02:00
fgsfds 05889b54cb port: partially unfuck menus 2023-08-04 01:11:19 +02:00
fgsfds 952d23de08 port: fix gun file swapping 2023-08-03 21:54:34 +02:00
fgsfds c8e3641bbc port: fix colors when both fog and SHADE_ALPHA are enabled 2023-08-03 18:26:59 +02:00
fgsfds a12d756d79 port: detect fog alpha usage 2023-08-03 16:58:52 +02:00
fgsfds 406900e253 port: detect fog color usage 2023-08-03 16:50:24 +02:00
fgsfds ff9030f5fb port: swap light bboxes properly 2023-08-03 16:50:14 +02:00
fgsfds 316516422b port: fix lookat loading; allow for multiple mipped textures 2023-08-03 16:17:31 +02:00
fgsfds 58120e299e port: fix (?) texture alignment, ignore LOD levels > 0 for now 2023-08-03 16:01:12 +02:00
fgsfds 46a9888647 port: hackfix modeswitching 2023-08-02 20:32:21 +02:00
fgsfds a542e93fe7 port: temporarily disable sleep timer 2023-08-02 19:45:49 +02:00
fgsfds 03ea57dab8 port: disable zbufDrawArtifactsOffscreen for now 2023-08-02 19:45:11 +02:00
fgsfds 9d1e40c5f7 port: unfuck font palettes 2023-08-02 19:44:41 +02:00
fgsfds a3c3f8df72 port: fix LOD textures exploding, fix palette loading 2023-08-02 19:44:13 +02:00
fgsfds 4fa7deed5a port: swap more modeldef nodes 2023-08-02 02:30:02 +02:00
fgsfds c0e73091f5 port: check GL attrib and uniform indices before using them 2023-08-02 02:29:38 +02:00
fgsfds c449a687cf port: fix vertex color indexing 2023-08-02 01:04:15 +02:00
fgsfds 23f5b72943 port: swap room verts 2023-08-02 00:11:51 +02:00
fgsfds 9ec6fa06f8 port: oops, forgot Makefile this whole time 2023-08-01 23:39:14 +02:00
fgsfds 9433dc7769 port: make it not crash on the intro sequence and render SOME geometry 2023-08-01 23:38:06 +02:00
fgsfds 9508b136ff port: replace old fast3d with libultraship-fast3d 2023-08-01 23:37:49 +02:00
fgsfds 157d46b73a port: fix tahoma 2023-08-01 01:28:08 +02:00
fgsfds a37bb4c3be port: fix REORDER model node byteswapping and gundl.numvertices 2023-07-31 22:36:26 +02:00
fgsfds 5c9a502657 port: fix Gfx being 16 bytes 2023-07-31 22:34:54 +02:00
fgsfds 2331b0911d port: always report at least one controller connected 2023-07-30 21:25:01 +02:00
fgsfds f91401cb95 port: make the legal screen render correctly
also, total errno death in the same commit because I am dumb
2023-07-30 21:24:39 +02:00
fgsfds da94644c38 port: make it link and load
nothing happens after loading though
2023-07-29 23:21:35 +02:00
Ryan Dwyer aeca25d984 Fix arguments for if_chr_same_floor_distance_to_pad_lt 2023-07-21 00:03:01 +10:00
Ryan Dwyer cef885db72 Replace a heap of literals, mostly in sound code 2023-07-07 22:10:48 +10:00
Ryan Dwyer a780b5f179 Identify hov and hovtype properties 2023-06-28 23:37:39 +10:00
Ryan Dwyer 3b4451a2d1 Name more pak symbols 2023-06-25 22:33:57 +10:00
Ryan Dwyer 83e8265d5b Introduce RoomNum typedef 2023-06-20 19:14:13 +10:00
309 changed files with 43972 additions and 5033 deletions

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
name: C/C++ CI
on:
push:
branches: [ "port", "port-net" ]
pull_request:
branches: [ "port" ]
workflow_dispatch:
jobs:
build-i686-windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW32
update: true
install: >-
git
make
mingw-w64-i686-toolchain
mingw-w64-i686-SDL2
mingw-w64-i686-zlib
- name: Checkout repository
uses: actions/checkout@v3
- name: Build pd.exe
run: make -f Makefile.port -j
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/ntsc-final-port/pd.exe bin/
cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: pd-i686-windows
path: bin/
retention-days: 0
build-i686-linux:
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386
- name: Checkout repository
uses: actions/checkout@v3
- name: Build pd.exe
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/ntsc-final-port/pd.exe bin/pd
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: pd-i686-linux
path: bin/
retention-days: 0
+3
View File
@@ -1,5 +1,7 @@
*.o *.o
*.pyc *.pyc
*.dll
*.exe
pd.*.z64 pd.*.z64
build build
extracted extracted
@@ -19,3 +21,4 @@ src/assets/*/sequences/*.seq
src/assets/*/textures/*.bin src/assets/*/textures/*.bin
src/generated src/generated
tools/mkrom/mkrom tools/mkrom/mkrom
/.vs
+6 -2
View File
@@ -169,7 +169,8 @@ DEFINES := \
MATCHING=$(MATCHING) \ MATCHING=$(MATCHING) \
PAL=$(PAL) \ PAL=$(PAL) \
PIRACYCHECKS=$(PIRACYCHECKS) \ PIRACYCHECKS=$(PIRACYCHECKS) \
ROM_SIZE=$(ROM_SIZE) ROM_SIZE=$(ROM_SIZE) \
PLATFORM_N64=1
ifeq ($(DEBUG),1) ifeq ($(DEBUG),1)
DEFINES := $(DEFINES) DEBUG=1 DEFINES := $(DEFINES) DEBUG=1
@@ -296,6 +297,7 @@ INCLUDES = \
-I include \ -I include \
-I include/PR \ -I include/PR \
-I src/include \ -I src/include \
-I src/include/lib/libc \
-I src/generated/$(ROMID) \ -I src/generated/$(ROMID) \
-I src/lib/ultra/audio \ -I src/lib/ultra/audio \
@@ -461,7 +463,9 @@ else ifeq ($(COMPILER), gcc)
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL) $(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) \ C_DEFINES += -DAVOID_UB
CFLAGS := $(C_DEFINES) $(INCLUDES) \
-EB \ -EB \
-march=vr4300 \ -march=vr4300 \
-mabi=32 \ -mabi=32 \
+336
View File
@@ -0,0 +1,336 @@
# Options.
# HOST_PLATFORM - Which platform we're building on.
#
# Determined automatically if not specified on command line.
#
# Supported values:
# * i686-windows
# * i686-linux
HOST_PLATFORM ?=
# TARGET_PLATFORM - Which platform to build for.
#
# Determined from HOST_PLATFORM if not specified on command line.
#
# Supported values:
# * i686-windows
# * i686-linux
TARGET_PLATFORM ?=
# ROMID - The ROM version to use.
#
# Can be set in your environment using
# $ export ROMID=...
#
# Supported values:
# * ntsc-final
# * pal-final
# * jpn-final
ROMID ?= ntsc-final
# GCC_OPT_LVL - the optimisation level if building with gcc.
#
# Supported values: -O0, -O1, -O2, -O3, -Os, -Og
GCC_OPT_LVL = -Og
# ROM_SIZE - The desired ROM size in megabytes.
#
# All versions of the retail ROM are 32MB.
#
# If this is too low you might get this error from ld:
# "final link failed: memory exhausted"
ROM_SIZE := 32
# DEBUG - Enable (1) or disable (0) the debug menu and crash screen.
#
# When enabled, press C-up and C-down simultaneously to toggle the debug menu.
# Note that some emulators have problems displaying the crash screen text.
DEBUG = 0
################################################################################
# Detect host platform if not specified.
ifeq ($(HOST_PLATFORM),)
ifeq ($(OS),Windows_NT)
# assume msys for now
UNAME_OS := $(shell uname -s)
ifneq (,$(findstring MINGW64,$(UNAME_OS)))
HOST_PLATFORM := x86_64-windows
else
HOST_PLATFORM := i686-windows
endif
else # TODO
UNAME_ARCH := $(shell uname -m)
UNAME_OS := $(shell uname -s)
UNAME_OS := $(shell echo $(UNAME_OS) | tr A-Z a-z)
HOST_PLATFORM := $(UNAME_ARCH)-$(UNAME_OS)
endif
endif
# Set target platform to host platform if not specified.
ifeq ($(TARGET_PLATFORM),)
TARGET_PLATFORM := $(HOST_PLATFORM)
endif
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
$(info Host platform: $(HOST_PLATFORM))
$(info Target platform: $(TARGET_PLATFORM))
endif
# Set whether the target arch is 64- or 32-bit.
ifneq (,$(findstring 64,$(TARGET_PLATFORM))$(findstring armv8,$(TARGET_PLATFORM)))
# TODO: we're not 64-bit compatible yet, error out if building the actual game
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
$(error 64-bit target platforms are not supported yet)
endif
TARGET_64BIT = 1
else # TODO
TARGET_64BIT = 0
endif
# Set whether the target is big-endian or little-endian.
TARGET_BIG_ENDIAN = 0 # TODO
# The VERSION constant is used in the source to handle version-specific code.
ifeq ($(ROMID),ntsc-final)
BIN_NAME = pd.exe
VERSION = 2
IS_PAL = 0
else ifeq ($(ROMID),pal-final)
BIN_NAME = pd.pal.exe
VERSION = 4
IS_PAL = 1
else ifeq ($(ROMID),jpn-final)
BIN_NAME = pd.jpn.exe
VERSION = 5
IS_PAL = 0
else
$(error ROM version $(VERSION) is not supported)
endif
VERSION_HASH := $(shell git rev-parse --short HEAD)
VERSION_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
VERSION_TARGET := $(TARGET_PLATFORM)
VERSION_ROMID := $(ROMID)
ifeq ($(VERSION_BRANCH),)
VERSION_BRANCH := port-custom
endif
ifeq ($(VERSION_BRANCH),HEAD)
VERSION_BRANCH := port-custom
endif
DEFINES := \
VERSION=$(VERSION) \
VERSION_HASH=\"$(VERSION_HASH)\" \
VERSION_TARGET=\"$(VERSION_TARGET)\" \
VERSION_ROMID=\"$(VERSION_ROMID)\" \
VERSION_BRANCH=\"$(VERSION_BRANCH)\" \
MATCHING=0 \
PAL=$(IS_PAL) \
PIRACYCHECKS=0 \
ROM_SIZE=$(ROM_SIZE) \
_LANGUAGE_C=1
ifeq ($(DEBUG),1)
DEFINES := $(DEFINES) DEBUG=1
endif
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
A_DIR := src/assets/$(ROMID)
B_DIR := build/$(ROMID)-port
G_DIR := src/generated/$(ROMID)
ifneq (,$(findstring windows,$(TARGET_PLATFORM)))
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -lws2_32 -lwinmm -ldbghelp
# on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs
TOOLCHAIN ?= i686-w64-mingw32-
# on GCC link libstdc++ statically
ifeq (,$(findstring clang,$(CC))$(findstring clang,$(CXX)))
TARGET_LDFLAGS += -static-libstdc++
else
TARGET_LDFLAGS += -lstdc++
endif
else # assume *nix
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl
ifneq (,$(findstring arm,$(TARGET_PLATFORM))$(findstring aarch,$(TARGET_PLATFORM)))
# linux on arm or aarch64
# TODO: detect soft/hardfloat abi
TOOLCHAIN ?= arm-linux-gnueabihf-
endif
endif
# On x86_64 gcc add -m32 to CFLAGS if building a 32-bit executable.
ifneq (,$(findstring x86_64,$(HOST_PLATFORM))$(findstring x86_64,$(TOOLCHAIN)))
ifneq (1,$(TARGET_64BIT))
TARGET_CFLAGS += -m32
endif
endif
# These are still used in the port, but only to generate headers.
JSON_FILES := $(shell find $(A_DIR) -path '*/lang/*.json')
JSON_FILES += $(shell find $(A_DIR) -path '*/pads/*.json')
JSON_FILES += $(shell find $(A_DIR) -path '*/tiles/*.json')
JSON_FILES += $(wildcard $(A_DIR)/*.json)
JSON_HEADERS := $(patsubst $(A_DIR)/%.json, $(G_DIR)/%.h, $(JSON_FILES))
C_FILES := $(shell find src/game port -name '*.c')
C_FILES := $(C_FILES) \
$(wildcard src/lib/mp3/*.c) \
$(wildcard src/lib/naudio/*.c) \
$(wildcard src/lib/ultra/audio/*.c) \
$(wildcard src/lib/ultra/gu/*.c) \
src/lib/ultra/io/vimodentsclan1.c \
src/lib/ultra/io/vimodepallan1.c \
src/lib/ultra/io/vimodempallan1.c \
src/lib/ultra/io/vitbl.c \
$(wildcard src/lib/a*.c) \
src/lib/base.c \
src/lib/collision.c \
src/lib/debughud.c \
src/lib/dma.c \
src/lib/fault.c \
src/lib/joy.c \
$(wildcard src/lib/lib_*.c) \
src/lib/mema.c \
src/lib/memp.c \
src/lib/model.c \
src/lib/modelasm_c.c \
src/lib/mp3.c \
src/lib/mtx_c.c \
src/lib/mtx.c \
src/lib/music.c \
src/lib/path.c \
src/lib/profile.c \
src/lib/rdp.c \
src/lib/rmon.c \
src/lib/rng_c.c \
src/lib/rzip_c.c \
src/lib/snd.c \
src/lib/speaker.c \
src/lib/varsinit.c \
src/lib/vi.c \
src/textureconfig.c
CXX_FILES :=$(shell find port -name '*.cpp')
C_O_FILES := $(patsubst %.c, $(B_DIR)/%.o, $(C_FILES))
CXX_O_FILES := $(patsubst %.cpp, $(B_DIR)/%.o, $(CXX_FILES))
O_FILES := $(C_O_FILES) $(CXX_O_FILES)
INCLUDES = \
-I include \
-I include/PR \
-I src/include \
-I src/generated/$(ROMID) \
-I src/lib/ultra/audio \
-I port/include
TOOLCHAIN ?=
CC ?= $(TOOLCHAIN)gcc
CXX ?= $(TOOLCHAIN)g++
ifneq (,$(CXX_O_FILES))
LD := $(CXX)
else
LD := $(CC)
endif
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \
-fno-inline-functions \
-fno-strict-aliasing \
-funsigned-char \
-fwrapv \
-Wall \
-Wno-address \
-Wno-int-in-bool-context \
-Wno-misleading-indentation \
-Wno-missing-braces \
-Wno-multichar \
-Wno-tautological-compare \
-Wno-unused-but-set-variable \
-Wno-unused-value \
-Wno-unused-variable \
-Wno-format-truncation
CFLAGS := -std=c11 $(COMMON_CFLAGS) -Wno-pointer-sign
CXXFLAGS := -std=c++20 $(COMMON_CFLAGS) -Wno-unused-function
LDFLAGS := $(TARGET_LDFLAGS)
# Make ROMID available as an environment variable to all tooling.
# (We use this a lot)
export ROMID
BIN := $(B_DIR)/$(BIN_NAME)
default: $(BIN)
################################################################################
# Asset Manager header generation
# Anims
$(G_DIR)/animations.h: $(A_DIR)/animations.json
tools/assetmgr/mkanims --headers-only
# Lang
$(G_DIR)/lang/%.h: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< en --headers-only
# Pads
$(G_DIR)/pads/%.h: $(A_DIR)/pads/%.json
tools/assetmgr/mkpads $< --headers-only
# Sequences
$(G_DIR)/sequences.h: $(A_DIR)/sequences.json
tools/assetmgr/mksequences --headers-only
# Textures
$(G_DIR)/textures.h: $(A_DIR)/textures.json
tools/assetmgr/mktextures --headers-only
# Tiles
$(G_DIR)/tiles/%.h: $(A_DIR)/tiles/%.json
tools/assetmgr/mktiles $< --headers-only
################################################################################
# Generic compilation rules
$(BIN): $(O_FILES)
$(LD) $(COMMON_CFLAGS) $(OPT_LVL) -o $(BIN) $^ $(LDFLAGS)
ifneq ($(CV2PDB),)
$(CV2PDB) $(BIN)
endif
$(B_DIR)/%.o: %.c $(JSON_HEADERS)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
$(B_DIR)/%.o: %.cpp $(JSON_HEADERS)
@mkdir -p $(dir $@)
$(CXX) -c $(CXXFLAGS) $(OPT_LVL) -o $@ $<
################################################################################
# Clean rules
clean:
rm -rf build/$(ROMID)-port
allclean:
rm -rf build/*
rm -rf src/generated
codeclean:
find $(B_DIR)/ -name '*.o' -delete
+119 -37
View File
@@ -1,62 +1,144 @@
# Perfect Dark Decompilation # Perfect Dark port (`port-net`)
This repository contains a complete decompilation of Perfect Dark for the Nintendo 64. ## Experimental netplay branch
The project aims to be a matching decompilation. When a matching decompilation is compiled with the same compiler that the original developers used, the output will be exactly the same as the retail game, byte for byte. This branch of the port contains an **extremely** early and experimental implementation of network play.
**DISCLAIMER:** This is **NOT READY** for prime time. Use at your own risk if you are not a developer.
**Do not create issues about problems in this branch until this disclaimer is gone.**
To build the project, you must already have a Perfect Dark ROM. The project can build the exact same ROM from decomp's source code combined with assets that it extracts from your base ROM. See [this file](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/docs/netplay.md) for more information on how this works.
## Original description
This repository contains a work-in-progress port of the [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) to modern platforms.
To run the port, you must already have a Perfect Dark ROM, specifically one of the following:
* `ntsc-final`/`US V1.1`/`US Rev 1` (md5 `e03b088b6ac9e0080440efed07c1e40f`).
**This is the recommended version to use**.
Called `NTSC version 8.7 final` on the boot screen.
* `ntsc-1.0`/`US V1.0` (md5 `7f4171b0c8d17815be37913f535e4e93`).
Technically supported, but not recommended.
Called `NTSC version 8.7 final` on the boot screen as well.
* `jpn-final` (md5 `538d2b75945eae069b29c46193e74790`).
Technically supported, but requires a separate custom-built executable.
Called `JPN version 8.9 final` on the boot screen.
* `pal-final` (md5 `d9b5cd305d228424891ce38e71bc9213`).
Technically supported, but requires a separate custom-built executable.
Called `PAL 8.7 final` on the boot screen.
## Status ## Status
See the [Perfect Dark Decompilation Status Page](https://ryandwyer.gitlab.io/pdstatus/). The game is in a mostly functional state, with both singleplayer and split-screen multiplayer modes fully working.
There are minor graphics- and gameplay-related issues, and possibly occasional crashes.
All versions of the game are fully decompiled but a small handful of functions are not yet byte-matching even though they are functionally the same. The status page doesn't show these as 100% because it counts matching functions only. **The following extra features are implemented:**
* mouselook;
* dual analog controller support;
* widescreen resolution support;
* configurable field of view;
* 60 FPS support, including fixes for some framerate-related issues;
* fixes for a couple original bugs and crashes;
* basic mod support, currently enough to load a few custom levels;
* slightly expanded memory heap size;
* experimental high framerate support (up to 240 FPS):
* set `Game.TickRateDivisor` to `0` in `pd.ini` to activate;
* in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it.
## Installation Requirements Currently only 32-bit platforms are supported, namely x86 Windows and Linux.
Note that 32-bit binaries will still work on 64-bit versions of those platforms,
though you might have to install some additional libraries.
For Arch Linux: ## Download
* Install these packages: `binutils fakeroot gcc make python vim` Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) of the netplay branch for supported platforms:
* Install from AUR: `armips` * [i686-windows (`port-net`)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip)
* Install from AUR: a MIPS binutils package of your choice (eg. `mips-elf-binutils`) * [i686-linux (`port-net`)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip)
* Install from AUR: a MIPS gcc package of your choice (eg. `mips-elf-gcc`)
For Debian and Ubuntu: If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download).
* Install these packages: `binutils-mips-linux-gnu build-essential gcc-mips-linux-gnu libc6-dev-i386 libcapstone-dev make` ## Running
* Compile and install `armips`
## ROM Versions You must already have a Perfect Dark ROM to run the game, as specified above.
Perfect Dark has six known versions: 1. Create a directory named `data` next to `pd.exe`.
2. Put your Perfect Dark ROM named `pd.ntsc-final.z64` into it.
3. Run `pd.exe`.
| ROM ID | Description | MD5 Checksum | Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki).
|------------|---------------------------------------------|----------------------------------|
| ntsc-beta | NTSC 6.4 beta | aa93f4df16fceada399a749f5ad2f273 |
| ntsc-1.0 | NTSC 8.7 final (the initial, buggy release) | 7f4171b0c8d17815be37913f535e4e93 |
| ntsc-final | NTSC 8.7 final | e03b088b6ac9e0080440efed07c1e40f |
| pal-beta | PAL 28.7 beta | ad2de210a3455ba5ec541f0c78d91444 |
| pal-final | PAL 8.7 final | d9b5cd305d228424891ce38e71bc9213 |
| jpn-final | JPN 8.9 final | 538d2b75945eae069b29c46193e74790 |
The project uses the `$ROMID` environment variable to know which version to work with. If not set, it defaults to `ntsc-final`. You can change it by running something like `export ROMID=ntsc-1.0`. A GPU supporting OpenGL 3.0 or above is required to run the port.
## Extracting the base ROM ## Controls
1. Save your existing ROM file into the root of the repository with the name `pd.ntsc-final.z64`. It should not be byteswapped (the first four bytes should be `0x80371240`). 1964GEPD-style and Xbox-style bindings are implemented.
2. Run `make extract`.
This will extract assets to `src/assets`. If any asset already exists then it will not be overwritten. This means you can modify assets as desired, and your changes will not be overwritten if you run the extract command again. N64 pad buttons X and Y (or `X_BUTTON`, `Y_BUTTON` in the code) refer to the reserved buttons `0x40` and `0x80`, which are also leveraged by 1964GEPD.
The extract command will also create an `extracted/ntsc-final` directory. This directory contains some compiled code segments from the ROM and is only used for comparison purposes. Support for one controller, two-stick configurations are enabled for 1.2.
## Compiling Note that the mouse only controls player 1.
* Run `git submodule update --init --recursive`. You only have to do this once. Controls can be rebound in `pd.ini`. Default control scheme is as follows:
* Run `make -j` to build the ROM. The ROM will be written to `build/ntsc-final/pd.z64`.
## How do I know the built files are matching? | Action | Keyboard and mouse | Xbox pad | N64 pad |
| - | - | - | - |
| Fire / Accept | LMB/Space | RT | Z Trigger |
| Aim mode | RMB/Z | LT | R Trigger |
| Use / Cancel | E | N/A | B |
| Use / Accept | N/A | A | A |
| Crouch cycle | N/A | L3 | `0x80000000` (Extra) |
| Half-Crouch | Shift | N/A | `0x40000000` (Extra) |
| Full-Crouch | Control | N/A | `0x20000000` (Extra) |
| Reload | R | X | X `(0x40)` |
| Previous weapon | Mousewheel forward | B | D-Left |
| Next weapon | Mousewheel back | Y | Y `(0x80)` |
| Radial menu | Q | LB | D-Down |
| Alt fire mode | F | RB | L Trigger |
| Alt-fire oneshot | `F + LMB` or `E + LMB` | `A + RT` or `RB + RT` | `A + Z` or `L + Z` |
| Quick-detonate | `E + Q` or `E + R` | `A + B` or `A + X` | `A + D-Left`or `A + X` |
Run `make` followed by `make test`. If `make test` produces no output then the compiled project is matching. ## Building
You can also md5sum your base ROM with the built ROM and check they have the same hash: `md5sum pd.ntsc-final.z64 build/ntsc-final/pd.z64`. ### Windows
1. Install [MSYS2](https://www.msys2.org).
2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt)
3. Install dependencies:
`pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git`
4. Get the source code:
`git clone -b port-net --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
5. Run `make -f Makefile.port`.
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
6. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
7. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory.
### Linux
1. Ensure you have gcc, g++ (version 10.0+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
* On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed.
2. Get the source code:
`git clone -b port-net --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
3. Run the following command:
* On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux```
* On a 32-bit system: ```make -f Makefile.port```
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
4. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
Currently only `i686-linux` and `i686-windows` are supported, using `gcc -m32` and `i686-w64-mingw32-gcc` as compilers, respectively.
Alternate compilers can be specified by passing `TOOLCHAIN=i686-whatever-` as a command line argument.
You can build an executable with PAL or JPN ROM support by adding `ROMID=pal-final` or `ROMID=jpn-final` to the `make` command.
You will need to provide a `jpn-final` or `pal-final` ROM to run those, named `pd.jpn-final.z64` or `pd.pal-final.z64`.
It might be possible to build a 32-bit ARM executable, but this has not been tested.
## Credits
* the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors;
* doomhack for the only other publicly available [PD porting effort](https://github.com/doomhack/perfect_dark) I could find;
* [sm64-port](https://github.com/sm64-port/sm64-port) authors for the audio mixer and some other changes;
* [Ship of Harkinian team](https://github.com/Kenix3/libultraship/tree/main/src/graphic/Fast3D), Emill and MaikelChan for the libultraship version of fast3d that this port uses;
* lieff for [minimp3](https://github.com/lieff/minimp3);
* Mouse Injector and 1964GEPD authors for some of the 60FPS- and mouselook-related fixes;
* everyone who has submitted pull requests and issues to this repository and tested the port;
* probably more I'm forgetting.
+47
View File
@@ -0,0 +1,47 @@
## Experimental netplay branch
This branch contains a **highly experimental** implementation of network play.
Currently only Combat Sim is partially working with experimental 8 player support and really bad netcode.
Expect nothing to work right.
### Hosting
1. Forward the server port (`27100` by default, can be changed in `pd.ini`).
* You can also use something like ZeroTier or Hamachi if you can't port forward.
3. Choose `Network Game` -> `Host Game`, configure the player cap, press `Start Game`.
4. Configure Combat Sim as desired, but do not start it yet. Keep in mind:
* You can save and load the settings as normal.
* Your player will have the config of Combat Sim player 1.
5. Wait for everyone to join. You can use the console (press `~`) to chat in the meantime.
6. Hit Enter/Start. During the game no more players will be able to join.
7. After game is over, you will be kicked back to Combat Sim settings, at which point people can join again and the process repeats from step 3.
### Joining
1. Your player will have the config of Combat Sim player 1, so set that up beforehand in the Combat Sim menu.
2. Choose `Network Game` -> `Join Game`, enter the address (and port if it's not 27100), press `Start Game`.
3. If the message says `Waiting for host`, wait until the host configures the game. You can use the console (press `~`) to chat in the meantime or `ESC` to disconnect.
4. The game will start automatically.
5. After the game is over, press Enter/Start on the stats screen and you will be kicked back to the `Waiting for host` screen, at which point the process repeats from step 3.
### Misc
* Everyone has to have the same ROM. The game only compares the file name, but different regions in one game will definitely break everything.
* Press `~` to bring up the console, press `F9` for network stats.
* You can chat at any time during a net game by entering messages in the console and hitting Enter.
* Server port and other network settings can be configured in `pd.ini`.
* For a 4+ player game I would recommend changing `Net.Server.UpdateFrames` to `2` in `pd.ini` on the server to lower the bandwidth usage.
* You can paste stuff into the `Enter Address` prompt by hitting `CTRL+V`.
* Expect nothing to work right.
### Known issues
* Clients can't throw laptop guns.
* Clients see rocket rotation incorrectly.
* Clients can't use Slayer fly-by-wire rockets and they will not correctly sync if the server uses them.
* Clients can't use the alt fire mode on the FarSight and probably a couple other guns.
* Cloaking device is not synced.
* Most likely only Combat works properly.
* Sims don't work in netgames.
* Bandwidth consumption on the server is pretty large on the default settings, especially with 8 players.
+20
View File
@@ -60,6 +60,8 @@
#else /* _LANGUAGE_C */ #else /* _LANGUAGE_C */
#ifdef PLATFORM_N64
#define K0_TO_K1(x) ((u32)(x)|0xA0000000) /* kseg0 to kseg1 */ #define K0_TO_K1(x) ((u32)(x)|0xA0000000) /* kseg0 to kseg1 */
#define K1_TO_K0(x) ((u32)(x)&0x9FFFFFFF) /* kseg1 to kseg0 */ #define K1_TO_K0(x) ((u32)(x)&0x9FFFFFFF) /* kseg1 to kseg0 */
#define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */ #define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */
@@ -68,6 +70,24 @@
#define PHYS_TO_K0(x) ((u32)(x)|0x80000000) /* physical to kseg0 */ #define PHYS_TO_K0(x) ((u32)(x)|0x80000000) /* physical to kseg0 */
#define PHYS_TO_K1(x) ((u32)(x)|0xA0000000) /* physical to kseg1 */ #define PHYS_TO_K1(x) ((u32)(x)|0xA0000000) /* physical to kseg1 */
#else /* PLATFORM_N64 */
#ifdef PLATFORM_64BIT
typedef u64 k_ptr_t;
#else
typedef u32 k_ptr_t;
#endif
#define K0_TO_K1(x) ((k_ptr_t)(x)) /* kseg0 to kseg1 */
#define K1_TO_K0(x) ((k_ptr_t)(x)) /* kseg1 to kseg0 */
#define K0_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg0 to physical */
#define K1_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg1 to physical */
#define KDM_TO_PHYS(x) ((k_ptr_t)(x)) /* direct mapped to physical */
#define PHYS_TO_K0(x) ((k_ptr_t)(x)) /* physical to kseg0 */
#define PHYS_TO_K1(x) ((k_ptr_t)(x)) /* physical to kseg1 */
#endif /* PLATFORM_N64 */
#endif /* _LANGUAGE_ASSEMBLY */ #endif /* _LANGUAGE_ASSEMBLY */
/* /*
+8
View File
@@ -265,6 +265,8 @@ typedef short RESAMPLE_STATE[16];
*/ */
typedef short ENVMIX_STATE[40]; typedef short ENVMIX_STATE[40];
#ifdef PLATFORM_N64
/* /*
* Macros to assemble the audio command list * Macros to assemble the audio command list
*/ */
@@ -402,6 +404,12 @@ typedef short ENVMIX_STATE[40];
_a->words.w1 = (unsigned int) d; \ _a->words.w1 = (unsigned int) d; \
} }
#else // PLATFORM_N64
#include "mixer.h"
#endif
#endif /* _LANGUAGE_C */ #endif /* _LANGUAGE_C */
#endif /* !_ABI_H_ */ #endif /* !_ABI_H_ */
+97 -1
View File
@@ -1029,16 +1029,32 @@ typedef union {
* Triangle face * Triangle face
*/ */
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned char flag; unsigned char flag;
unsigned char v[3]; unsigned char v[3];
#else
unsigned char v[3]; // reverse order
unsigned char flag;
#endif
} Tri; } Tri;
#ifdef PLATFORM_BIG_ENDIAN
#define GFX_TRI_VTX(i) (i)
#else
#define GFX_TRI_VTX(i) (2 - i)
#endif
/* /*
* 4x4 matrix, fixed point s15.16 format. * 4x4 matrix, fixed point s15.16 format.
* First 8 words are integer portion of the 4x4 matrix * First 8 words are integer portion of the 4x4 matrix
* Last 8 words are the fraction portion of the 4x4 matrix * Last 8 words are the fraction portion of the 4x4 matrix
*/ */
#ifdef GBI_FLOATS
// 4x4 float matrix
typedef float Mtx_t[4][4];
#else
typedef long Mtx_t[4][4]; typedef long Mtx_t[4][4];
#endif
typedef union { typedef union {
Mtx_t m; Mtx_t m;
@@ -1291,22 +1307,35 @@ typedef union {
* Graphics DMA Packet * Graphics DMA Packet
*/ */
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
int cmd:8; int cmd:8;
unsigned int par:8; unsigned int par:8;
unsigned int len:16; unsigned int len:16;
unsigned int addr; unsigned int addr;
#else // NOTE: changing signedness mid int will break up the bitfield on normal platforms, even BE
int len:16;
int par:8;
int cmd:8;
unsigned int addr;
#endif
} Gdma; } Gdma;
/* /*
* Graphics Immediate Mode Packet types * Graphics Immediate Mode Packet types
*/ */
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
int cmd:8; int cmd:8;
int pad:24; int pad:24;
#else
int pad:24;
int cmd:8;
#endif
Tri tri; Tri tri;
} Gtri; } Gtri;
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned char cmd:8; unsigned char cmd:8;
unsigned char pad:8; unsigned char pad:8;
unsigned char z4:4; unsigned char z4:4;
@@ -1321,6 +1350,22 @@ typedef struct {
unsigned char x2:4; unsigned char x2:4;
unsigned char y1:4; unsigned char y1:4;
unsigned char x1:4; unsigned char x1:4;
#else
unsigned char z1:4;
unsigned char z2:4;
unsigned char z3:4;
unsigned char z4:4;
unsigned char pad:8;
unsigned char cmd:8;
unsigned char x1:4;
unsigned char y1:4;
unsigned char x2:4;
unsigned char y2:4;
unsigned char x3:4;
unsigned char y3:4;
unsigned char x4:4;
unsigned char y4:4;
#endif
} Gtri4; } Gtri4;
typedef struct { typedef struct {
@@ -1356,12 +1401,21 @@ typedef struct {
} GsetothermodeH; } GsetothermodeH;
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned char cmd; unsigned char cmd;
unsigned char lodscale; unsigned char lodscale;
unsigned char tile; unsigned char tile;
unsigned char on; unsigned char on;
unsigned short s; unsigned short s;
unsigned short t; unsigned short t;
#else
unsigned char on;
unsigned char tile;
unsigned char lodscale;
unsigned char cmd;
unsigned short t;
unsigned short s;
#endif
} Gtexture; } Gtexture;
typedef struct { typedef struct {
@@ -1491,6 +1545,7 @@ typedef struct {
// xxxxxxxx 11223344 44555566 66666777 // xxxxxxxx 11223344 44555566 66666777
// 88888888 99999999 9999aaaa aaaaaaaa // 88888888 99999999 9999aaaa aaaaaaaa
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned int cmd:8; unsigned int cmd:8;
unsigned int unk08:2; unsigned int unk08:2;
unsigned int unk0a:2; unsigned int unk0a:2;
@@ -1502,15 +1557,37 @@ typedef struct {
unsigned int unk20:8; unsigned int unk20:8;
unsigned int tile1:12; unsigned int tile1:12;
unsigned int tile2:12; unsigned int tile2:12;
#else
unsigned int subcmd:3;
unsigned int flags:7;
unsigned int unk12:4;
unsigned int unk0e:4;
unsigned int unk0c:2;
unsigned int unk0a:2;
unsigned int unk08:2;
unsigned int cmd:8;
unsigned int tile2:12;
unsigned int tile1:12;
unsigned int unk20:8;
#endif
} GunkC0; } GunkC0;
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned int cmd:8; unsigned int cmd:8;
unsigned int unk08:4; unsigned int unk08:4;
unsigned int unk0c:4; unsigned int unk0c:4;
unsigned int unk10:16; unsigned int unk10:16;
unsigned int seg:8; unsigned int seg:8;
unsigned int offset:24; unsigned int offset:24;
#else
unsigned int unk10:16;
unsigned int unk0c:4;
unsigned int unk08:4;
unsigned int cmd:8;
unsigned int offset:24;
unsigned int seg:8;
#endif
} Gvtx; } Gvtx;
/* /*
@@ -1525,11 +1602,12 @@ typedef union {
Gtri tri; Gtri tri;
Gtri4 tri4; Gtri4 tri4;
Gline3D line; Gline3D line;
Gtexture texture;
#ifdef PLATFORM_N64 /* the rest is not needed on other platforms and some of em screw up the size */
Gpopmtx popmtx; Gpopmtx popmtx;
Gsegment segment; Gsegment segment;
GsetothermodeH setothermodeH; GsetothermodeH setothermodeH;
GsetothermodeL setothermodeL; GsetothermodeL setothermodeL;
Gtexture texture;
Gperspnorm perspnorm; Gperspnorm perspnorm;
Gsetimg setimg; Gsetimg setimg;
Gsetcombine setcombine; Gsetcombine setcombine;
@@ -1539,10 +1617,19 @@ typedef union {
Gloadtile loadtile; /* use for loadblock also, th is dxt */ Gloadtile loadtile; /* use for loadblock also, th is dxt */
Gsettilesize settilesize; Gsettilesize settilesize;
Gloadtlut loadtlut; Gloadtlut loadtlut;
#endif
GunkC0 unkc0; GunkC0 unkc0;
long long int force_structure_alignment; long long int force_structure_alignment;
} Gfx; } Gfx;
#ifdef PLATFORM_BIG_ENDIAN
#define GFX_W0_BYTE(i) (i)
#define GFX_W1_BYTE(i) (4 + (i))
#else
#define GFX_W0_BYTE(i) (3 - (i))
#define GFX_W1_BYTE(i) (7 - (i))
#endif
/* /*
* Macros to assemble the graphics display list * Macros to assemble the graphics display list
*/ */
@@ -1847,6 +1934,15 @@ typedef union {
#define gsSPSegment(segment, base) \ #define gsSPSegment(segment, base) \
gsMoveWd(G_MW_SEGMENT, (segment)*4, base) gsMoveWd(G_MW_SEGMENT, (segment)*4, base)
#ifdef PLATFORM_N64
#define SEGADDR(x) x
#define UNSEGADDR(x) x
#else
// we mark all segmented addresses so that it'll be easier to recognize them later
#define SEGADDR(x) ((void *)((uintptr_t)(x) | 1))
#define UNSEGADDR(x) ((uintptr_t)(x) & ~1)
#endif
/* /*
* Clipping Macros * Clipping Macros
*/ */
+4
View File
@@ -120,7 +120,11 @@ typedef struct ALLink_s {
void alUnlink(ALLink *element); void alUnlink(ALLink *element);
void alLink(ALLink *element, ALLink *after); void alLink(ALLink *element, ALLink *after);
#ifdef PLATFORM_N64
typedef s32 (*ALDMAproc)(s32 addr, s32 len, void *state); typedef s32 (*ALDMAproc)(s32 addr, s32 len, void *state);
#else
typedef uintptr_t (*ALDMAproc)(uintptr_t addr, s32 len, void *state);
#endif
typedef ALDMAproc (*ALDMANew)(void *state); typedef ALDMAproc (*ALDMANew)(void *state);
void alCopy(void *src, void *dest, s32 len); void alCopy(void *src, void *dest, s32 len);
+2 -2
View File
@@ -71,7 +71,7 @@ typedef struct {
s32 maxAuxBusses; s32 maxAuxBusses;
s32 outputRate; s32 outputRate;
s32 maxOutSamples; s32 maxOutSamples;
s32 sv_dramout; uintptr_t sv_dramout;
s32 sv_first; s32 sv_first;
} N_ALSynth; } N_ALSynth;
@@ -208,7 +208,7 @@ struct fx {
s16 unk00; s16 unk00;
s16 unk02; s16 unk02;
s32 unk04; s32 unk04;
s16 unk08[8]; s16 unk08[16];
}; };
typedef struct N_ALVoiceState_s { typedef struct N_ALVoiceState_s {
+42 -18
View File
@@ -53,14 +53,18 @@ extern "C" {
typedef struct { typedef struct {
u16 type; /* Controller Type */ u16 type; /* Controller Type */
u8 status; /* Controller status */ u8 status; /* Controller status */
u8 errno; u8 errnum;
}OSContStatus; }OSContStatus;
typedef struct { typedef struct {
u16 button; u32 button;
s8 stick_x; /* -80 <= stick_x <= 80 */ s8 stick_x; /* -80 <= stick_x <= 80 */
s8 stick_y; /* -80 <= stick_y <= 80 */ s8 stick_y; /* -80 <= stick_y <= 80 */
u8 errno; u8 errnum;
#ifndef PLATFORM_N64
s8 rstick_x;
s8 rstick_y;
#endif
} OSContPad; } OSContPad;
typedef struct { typedef struct {
@@ -68,7 +72,7 @@ typedef struct {
u8 databuffer[32]; /* address of the data buffer */ u8 databuffer[32]; /* address of the data buffer */
u8 addressCrc; /* CRC code for address */ u8 addressCrc; /* CRC code for address */
u8 dataCrc; /* CRC code for data */ u8 dataCrc; /* CRC code for data */
u8 errno; u8 errnum;
} OSContRamIo; } OSContRamIo;
@@ -118,21 +122,39 @@ typedef struct {
#define CONT_EEPROM_BUSY 0x80 #define CONT_EEPROM_BUSY 0x80
/* Buttons */ /* Buttons */
#define CONT_8000 0x80000000
#define CONT_4000 0x40000000
#define CONT_2000 0x20000000
#define CONT_1000 0x10000000
#define CONT_0800 0x08000000
#define CONT_0400 0x04000000
#define CONT_0200 0x02000000
#define CONT_0100 0x01000000
#define CONT_0080 0x00800000
#define CONT_0040 0x00400000
#define CONT_0020 0x00200000
#define CONT_0010 0x00100000
#define CONT_0008 0x00080000
#define CONT_0004 0x00040000
#define CONT_0002 0x00020000
#define CONT_0001 0x00010000
#define CONT_A 0x8000 #define CONT_A 0x00008000
#define CONT_B 0x4000 #define CONT_B 0x00004000
#define CONT_G 0x2000 #define CONT_G 0x00002000
#define CONT_START 0x1000 #define CONT_START 0x00001000
#define CONT_UP 0x0800 #define CONT_UP 0x00000800
#define CONT_DOWN 0x0400 #define CONT_DOWN 0x00000400
#define CONT_LEFT 0x0200 #define CONT_LEFT 0x00000200
#define CONT_RIGHT 0x0100 #define CONT_RIGHT 0x00000100
#define CONT_L 0x0020 #define CONT_EXTRA1 0x00000080
#define CONT_R 0x0010 #define CONT_EXTRA0 0x00000040
#define CONT_E 0x0008 #define CONT_L 0x00000020
#define CONT_D 0x0004 #define CONT_R 0x00000010
#define CONT_C 0x0002 #define CONT_E 0x00000008
#define CONT_F 0x0001 #define CONT_D 0x00000004
#define CONT_C 0x00000002
#define CONT_F 0x00000001
/* Nintendo's official button names */ /* Nintendo's official button names */
@@ -150,6 +172,8 @@ typedef struct {
#define L_CBUTTONS CONT_C #define L_CBUTTONS CONT_C
#define R_CBUTTONS CONT_F #define R_CBUTTONS CONT_F
#define D_CBUTTONS CONT_D #define D_CBUTTONS CONT_D
#define X_BUTTON CONT_EXTRA0
#define Y_BUTTON CONT_EXTRA1
/* Controller error number */ /* Controller error number */
+15 -3
View File
@@ -35,6 +35,9 @@ extern "C" {
#endif #endif
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#ifndef PLATFORM_N64
#include <stdint.h>
#endif
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
@@ -70,12 +73,17 @@ extern "C" {
#define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL)) #define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL))
#define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL)) #define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL))
#ifdef PLATFORM_N64
#define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000)) #define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000))
#define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000)) #define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000))
#define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000)) #define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000))
#define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000)) #define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000))
#else
#define OS_K0_TO_PHYSICAL(x) (uintptr_t)(x)
#define OS_K1_TO_PHYSICAL(x) (uintptr_t)(x)
#define OS_PHYSICAL_TO_K0(x) (void *)(x)
#define OS_PHYSICAL_TO_K1(x) (void *)(x)
#endif
/************************************************************************** /**************************************************************************
* *
@@ -92,9 +100,13 @@ extern "C" {
/* Address translation routines and macros */ /* Address translation routines and macros */
#ifdef PLATFORM_N64
extern u32 osVirtualToPhysical(void *); extern u32 osVirtualToPhysical(void *);
extern void * osPhysicalToVirtual(u32); extern void * osPhysicalToVirtual(u32);
#else
extern uintptr_t osVirtualToPhysical(void *);
extern void * osPhysicalToVirtual(uintptr_t);
#endif
#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */ #endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */
+9 -3
View File
@@ -32,6 +32,10 @@
#include "os_pfs.h" #include "os_pfs.h"
#ifndef PLATFORM_N64
#include <stdio.h>
#endif
#ifdef _LANGUAGE_C_PLUS_PLUS #ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" { extern "C" {
#endif #endif
@@ -80,13 +84,15 @@ extern "C" {
/* byte string operations */ /* byte string operations */
extern void bcopy(const void *, void *, int); extern void bcopy(const void *, void *, size_t);
extern int bcmp(const void *, const void *, int); extern int bcmp(const void *, const void *, size_t);
extern void bzero(void *, int); extern void bzero(void *, size_t);
/* Printf */ /* Printf */
#ifdef PLATFORM_N64
extern int sprintf(char *s, const char *fmt, ...); extern int sprintf(char *s, const char *fmt, ...);
#endif
extern void osSyncPrintf(const char *fmt, ...); extern void osSyncPrintf(const char *fmt, ...);
File renamed without changes.
+8
View File
@@ -57,6 +57,8 @@ typedef volatile long long vs64; /* signed 64-bit */
typedef float f32; /* single prec floating point */ typedef float f32; /* single prec floating point */
typedef double f64; /* double prec floating point */ typedef double f64; /* double prec floating point */
#ifdef PLATFORM_N64
#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEF) #if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEF)
#define _SIZE_T #define _SIZE_T
#define _SIZE_T_DEF /* exeGCC size_t define label */ #define _SIZE_T_DEF /* exeGCC size_t define label */
@@ -68,6 +70,12 @@ typedef unsigned long size_t;
#endif #endif
#endif #endif
#else
#include <stddef.h>
#endif
#endif /* _LANGUAGE_C */ #endif /* _LANGUAGE_C */
+10
View File
@@ -0,0 +1,10 @@
#ifndef _WIN32
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#endif
#define ENET_IMPLEMENTATION 1
#define ENET_NO_PRAGMA_LINK 1
#include "external/enet.h"
+2
View File
@@ -0,0 +1,2 @@
#define MINIMP3_IMPLEMENTATION
#include "external/minimp3.h"
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Emill, MaikelChan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+58
View File
@@ -0,0 +1,58 @@
#ifndef GFX_API_H
#define GFX_API_H
#ifndef __cplusplus
#include <stdint.h>
#include <stdbool.h>
#endif
#include "gfx_rendering_api.h"
#include "gfx_window_manager_api.h"
struct XYWidthHeight {
int16_t x, y;
uint32_t width, height;
};
struct GfxDimensions {
float internal_mul;
uint32_t width, height;
float aspect_ratio;
};
struct GfxInitSettings {
struct GfxWindowManagerAPI *wapi;
struct GfxRenderingAPI *rapi;
struct GfxWindowInitSettings window_settings;
};
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions
gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
extern struct XYWidthHeight
gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
extern uint32_t gfx_msaa_level;
extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game
extern float gfx_current_native_aspect; // The aspect ratio of the above mode
extern bool gfx_framebuffers_enabled;
extern bool gfx_detail_textures_enabled;
void gfx_init(const struct GfxInitSettings *settings);
void gfx_destroy(void);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
void gfx_start_frame(void);
void gfx_run(Gfx* commands);
void gfx_end_frame(void);
void gfx_set_target_fps(int);
void gfx_set_maximum_frame_latency(int latency);
void gfx_texture_cache_clear(void);
void gfx_texture_cache_delete(const uint8_t *orig_addr);
int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize);
void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale, int autoresize);
void gfx_set_framebuffer(int fb, float noise_scale) ;
void gfx_reset_framebuffer(void);
void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back);
void gfx_get_pixel_depth_prepare(float x, float y);
uint16_t gfx_get_pixel_depth(float x, float y);
#endif
+59
View File
@@ -0,0 +1,59 @@
#include "gfx_cc.h"
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 4; k++) {
cc_features->c[i][j][k] = (shader_id0 >> (i * 32 + j * 16 + k * 4)) & 0xf;
}
}
}
cc_features->opt_alpha = (shader_id1 & SHADER_OPT_ALPHA) != 0;
cc_features->opt_fog = (shader_id1 & SHADER_OPT_FOG) != 0;
cc_features->opt_texture_edge = (shader_id1 & SHADER_OPT_TEXTURE_EDGE) != 0;
cc_features->opt_noise = (shader_id1 & SHADER_OPT_NOISE) != 0;
cc_features->opt_2cyc = (shader_id1 & SHADER_OPT_2CYC) != 0;
cc_features->opt_alpha_threshold = (shader_id1 & SHADER_OPT_ALPHA_THRESHOLD) != 0;
cc_features->opt_invisible = (shader_id1 & SHADER_OPT_INVISIBLE) != 0;
cc_features->opt_grayscale = (shader_id1 & SHADER_OPT_GRAYSCALE) != 0;
cc_features->opt_blur = (shader_id1 & SHADER_OPT_BLUR) != 0;
cc_features->clamp[0][0] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_S);
cc_features->clamp[0][1] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_T);
cc_features->clamp[1][0] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_S);
cc_features->clamp[1][1] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_T);
cc_features->used_textures[0] = false;
cc_features->used_textures[1] = false;
cc_features->num_inputs = 0;
for (int c = 0; c < 2; c++) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
if (cc_features->c[c][i][j] >= SHADER_INPUT_1 && cc_features->c[c][i][j] <= SHADER_INPUT_7) {
if (cc_features->c[c][i][j] > cc_features->num_inputs) {
cc_features->num_inputs = cc_features->c[c][i][j];
}
}
if (cc_features->c[c][i][j] == SHADER_TEXEL0 || cc_features->c[c][i][j] == SHADER_TEXEL0A) {
cc_features->used_textures[0] = true;
}
if (cc_features->c[c][i][j] == SHADER_TEXEL1 || cc_features->c[c][i][j] == SHADER_TEXEL1A) {
cc_features->used_textures[1] = true;
}
}
}
}
for (int c = 0; c < 2; c++) {
cc_features->do_single[c][0] = cc_features->c[c][0][2] == SHADER_0;
cc_features->do_single[c][1] = cc_features->c[c][1][2] == SHADER_0;
cc_features->do_multiply[c][0] = cc_features->c[c][0][1] == SHADER_0 && cc_features->c[c][0][3] == SHADER_0;
cc_features->do_multiply[c][1] = cc_features->c[c][1][1] == SHADER_0 && cc_features->c[c][1][3] == SHADER_0;
cc_features->do_mix[c][0] = cc_features->c[c][0][1] == cc_features->c[c][0][3];
cc_features->do_mix[c][1] = cc_features->c[c][1][1] == cc_features->c[c][1][3];
cc_features->color_alpha_same[c] =
((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff);
}
}
+75
View File
@@ -0,0 +1,75 @@
#ifndef GFX_CC_H
#define GFX_CC_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
#include <compare>
#endif
enum {
SHADER_0,
SHADER_INPUT_1,
SHADER_INPUT_2,
SHADER_INPUT_3,
SHADER_INPUT_4,
SHADER_INPUT_5,
SHADER_INPUT_6,
SHADER_INPUT_7,
SHADER_TEXEL0,
SHADER_TEXEL0A,
SHADER_TEXEL1,
SHADER_TEXEL1A,
SHADER_1,
SHADER_COMBINED,
SHADER_NOISE,
SHADER_LOD_FRAC,
};
#define SHADER_OPT_ALPHA (1 << 0)
#define SHADER_OPT_FOG (1 << 1)
#define SHADER_OPT_TEXTURE_EDGE (1 << 2)
#define SHADER_OPT_NOISE (1 << 3)
#define SHADER_OPT_2CYC (1 << 4)
#define SHADER_OPT_ALPHA_THRESHOLD (1 << 5)
#define SHADER_OPT_INVISIBLE (1 << 6)
#define SHADER_OPT_GRAYSCALE (1 << 7)
#define SHADER_OPT_TEXEL0_CLAMP_S (1 << 8)
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9)
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10)
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11)
#define SHADER_OPT_BLUR (1 << 12)
struct ColorCombinerKey {
uint64_t combine_mode;
uint64_t options;
auto operator<=>(const ColorCombinerKey&) const = default;
};
#define SHADER_MAX_TEXTURES 2
#define SHADER_FIRST_TEXTURE 0
struct CCFeatures {
uint8_t c[2][2][4];
bool opt_alpha;
bool opt_fog;
bool opt_texture_edge;
bool opt_noise;
bool opt_2cyc;
bool opt_alpha_threshold;
bool opt_invisible;
bool opt_grayscale;
bool opt_blur;
bool used_textures[2];
bool clamp[2][2];
int num_inputs;
bool do_single[2][2];
bool do_multiply[2][2];
bool do_mix[2][2];
bool color_alpha_same[2];
};
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features);
#endif
File diff suppressed because it is too large. Load diff
+8
View File
@@ -0,0 +1,8 @@
#ifndef GFX_OPENGL_H
#define GFX_OPENGL_H
#include "gfx_rendering_api.h"
extern struct GfxRenderingAPI gfx_opengl_api;
#endif
File diff suppressed because it is too large. Load diff
+60
View File
@@ -0,0 +1,60 @@
#ifndef GFX_PC_H
#define GFX_PC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <unordered_map>
#include <list>
#include <cstddef>
#include <PR/gbi.h>
#include "system.h"
#define SCREEN_WIDTH ((int32_t)gfx_current_native_viewport.width)
#define SCREEN_HEIGHT ((int32_t)gfx_current_native_viewport.height)
extern uintptr_t gfxFramebuffer;
struct GfxRenderingAPI;
struct GfxWindowManagerAPI;
struct TextureCacheKey {
const uint8_t* texture_addr;
const uint8_t* palette_addrs[2];
uint8_t fmt, siz;
uint8_t palette_index;
bool operator==(const TextureCacheKey&) const noexcept = default;
struct Hasher {
size_t operator()(const TextureCacheKey& key) const noexcept {
uintptr_t addr = (uintptr_t)key.texture_addr;
return (size_t)(addr ^ (addr >> 5));
}
};
};
typedef std::unordered_map<TextureCacheKey, struct TextureCacheValue, TextureCacheKey::Hasher> TextureCacheMap;
typedef std::pair<const TextureCacheKey, struct TextureCacheValue> TextureCacheNode;
struct TextureCacheValue {
uint32_t texture_id;
uint8_t cms, cmt;
bool linear_filter;
std::list<struct TextureCacheMapIter>::iterator lru_location;
};
struct TextureCacheMapIter {
TextureCacheMap::iterator it;
};
extern "C" {
#include "gfx_api.h"
}
#endif
+57
View File
@@ -0,0 +1,57 @@
#ifndef GFX_RENDERING_API_H
#define GFX_RENDERING_API_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
struct ShaderProgram;
struct GfxClipParameters {
bool z_is_from_0_to_1;
bool invert_y;
};
enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT };
struct GfxRenderingAPI {
const char* (*get_name)(void);
int (*get_max_texture_size)(void);
struct GfxClipParameters (*get_clip_parameters)(void);
void (*unload_shader)(struct ShaderProgram* old_prg);
void (*load_shader)(struct ShaderProgram* new_prg);
struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1);
struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1);
void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]);
uint32_t (*new_texture)(void);
void (*select_texture)(int tile, uint32_t texture_id);
void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height);
void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt);
void (*set_depth_test_and_mask)(bool depth_test, bool z_upd);
void (*set_depth_range)(float znear, float zfar);
void (*set_zmode_decal)(bool zmode_decal);
void (*set_viewport)(int x, int y, int width, int height);
void (*set_scissor)(int x, int y, int width, int height);
void (*set_use_alpha)(bool use_alpha, bool modulate);
void (*draw_triangles)(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris);
void (*init)(void);
void (*on_resize)(void);
void (*start_frame)(void);
void (*end_frame)(void);
void (*finish_render)(void);
int (*create_framebuffer)();
void (*update_framebuffer_parameters)(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level,
bool opengl_invert_y, bool render_target, bool has_depth_buffer,
bool can_extract_depth);
bool (*start_draw_to_framebuffer)(int fb_id, float noise_scale);
void (*copy_framebuffer)(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back);
void (*clear_framebuffer)(void);
void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
void* (*get_framebuffer_texture_id)(int fb_id);
void (*select_texture_fb)(int fb_id);
void (*delete_texture)(uint32_t texID);
void (*set_texture_filter)(enum FilteringMode mode);
enum FilteringMode (*get_texture_filter)(void);
};
#endif
+7
View File
@@ -0,0 +1,7 @@
#ifndef GFX_SCREEN_CONFIG_H
#define GFX_SCREEN_CONFIG_H
#define DESIRED_SCREEN_WIDTH 640
#define DESIRED_SCREEN_HEIGHT 480
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef GFX_SDL_H
#define GFX_SDL_H
#include "gfx_window_manager_api.h"
extern struct GfxWindowManagerAPI gfx_sdl;
#endif
+342
View File
@@ -0,0 +1,342 @@
#include <stdio.h>
#include <SDL.h>
#include <unistd.h>
#include <time.h>
#include "platform.h"
#include "system.h"
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
static SDL_Window* wnd;
static SDL_GLContext ctx;
static SDL_Renderer* renderer;
static int sdl_to_lus_table[512];
static bool vsync_enabled = true;
// OTRTODO: These are redundant. Info can be queried from SDL.
static int window_width = DESIRED_SCREEN_WIDTH;
static int window_height = DESIRED_SCREEN_HEIGHT;
static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
static bool fullscreen_state;
static bool maximized_state;
static bool is_running = true;
static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen);
static int target_fps = 120; // above 60 since vsync is enabled by default
static uint64_t previous_time;
static uint64_t qpc_freq;
#define FRAME_INTERVAL_US_NUMERATOR 1000000
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
static void set_fullscreen(bool on, bool call_callback) {
if (fullscreen_state == on) {
return;
}
fullscreen_state = on;
SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0);
if (call_callback && on_fullscreen_changed_callback) {
on_fullscreen_changed_callback(on);
}
}
static void set_maximize_window(bool on) {
if (maximized_state == on) {
return;
}
maximized_state = on;
if (on) {
SDL_MaximizeWindow(wnd);
} else {
SDL_RestoreWindow (wnd);
}
}
static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(display_in_use, &mode);
*refresh_rate = mode.refresh_rate;
}
static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
window_width = set->width;
window_height = set->height;
#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED
if (!set->allow_hidpi) {
// HiDPI control, if available
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS)
// if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor");
#endif
}
#endif
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
sysFatalError("Could not init SDL:\n%s", SDL_GetError());
}
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
if (sysArgCheck("--debug-gl")) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
}
int posX = set->x;
int posY = set->y;
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
if (display_in_use < 0) { // Fallback to default if out of bounds
posX = 100;
posY = 100;
}
if (set->fullscreen_is_exclusive) {
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
}
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
// if fullscreen was requested, start the window in fullscreen right away
if (set->fullscreen) {
flags |= fullscreen_flag;
fullscreen_state = true;
}
if (set->maximized) {
flags |= SDL_WINDOW_MAXIMIZED;
maximized_state = true;
}
#ifdef SDL_WINDOW_ALLOW_HIGHDPI
if (set->allow_hidpi) {
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
}
#endif
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
if (!wnd) {
sysFatalError("Could not open SDL window:\n%s", SDL_GetError());
}
// ideally we need 3.0 compat
// if that doesn't work, try 3.2 core in case we're on mac, 2.1 compat as a last resort
static u32 glver[][3] = {
{ 0, 0, 0 }, // for command line override
{ 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY },
{ 3, 2, SDL_GL_CONTEXT_PROFILE_CORE },
{ 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY },
};
u32 glcore = false;
u32 verstart = 1;
const u32 verend = sizeof(glver) / sizeof(*glver);
const char *verstr = sysArgGetString("--gl-version");
if (verstr && *verstr) {
// user override
glver[0][2] = strstr(verstr, "core") ? SDL_GL_CONTEXT_PROFILE_CORE :
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]);
if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) {
verstart = 0;
}
}
ctx = NULL;
u32 vmin = 0, vmaj = 0;
for (u32 i = verstart; i < verend; ++i) {
vmaj = glver[i][0];
vmin = glver[i][1];
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, vmaj);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, vmin);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, glver[i][2]);
ctx = SDL_GL_CreateContext(wnd);
if (!ctx) {
sysLogPrintf(LOG_WARNING, "GL: could not create GL%d.%d context: %s", vmaj, vmin, SDL_GetError());
} else {
glcore = (glver[i][2] == SDL_GL_CONTEXT_PROFILE_CORE);
break;
}
}
if (!ctx) {
sysFatalError("Could not create an OpenGL context of any supported version.\nSDL error: %s", SDL_GetError());
} else {
sysLogPrintf(LOG_NOTE, "GL: created GL%d.%d%s context", vmaj, vmin, glcore ? "core" : "");
}
SDL_GL_MakeCurrent(wnd, ctx);
SDL_GL_SetSwapInterval(1);
qpc_freq = SDL_GetPerformanceFrequency();
}
static void gfx_sdl_close(void) {
is_running = false;
}
static void gfx_sdl_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) {
on_fullscreen_changed_callback = on_fullscreen_changed;
}
static void gfx_sdl_set_fullscreen(bool enable) {
set_fullscreen(enable, true);
}
static void gfx_sdl_set_fullscreen_exclusive(bool enable) {
const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP;
if (fullscreen_flag != newflag) {
fullscreen_flag = newflag;
// reset fullscreen to take new value into account if it already is in fullscreen
if (fullscreen_state) {
fullscreen_state = false;
set_fullscreen(enable, true);
}
}
}
static void gfx_sdl_set_maximize_window(bool enable) {
set_maximize_window(enable);
}
static void gfx_sdl_set_cursor_visibility(bool visible) {
if (visible) {
SDL_ShowCursor(SDL_ENABLE);
} else {
SDL_ShowCursor(SDL_DISABLE);
}
}
static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) {
SDL_GL_GetDrawableSize(wnd, static_cast<int*>((void*)width), static_cast<int*>((void*)height));
SDL_GetWindowPosition(wnd, static_cast<int*>(posX), static_cast<int*>(posY));
}
static void gfx_sdl_handle_events(void) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT)) {
// alt-enter received, switch fullscreen state
set_fullscreen(!fullscreen_state, true);
}
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
SDL_GL_GetDrawableSize(wnd, &window_width, &window_height);
} else if (event.window.event == SDL_WINDOWEVENT_CLOSE &&
event.window.windowID == SDL_GetWindowID(wnd)) {
// We listen specifically for main window close because closing main window
// on macOS does not trigger SDL_Quit.
exit(0);
}
break;
case SDL_QUIT:
exit(0);
break;
}
}
}
static bool gfx_sdl_start_frame(void) {
return true;
}
static uint64_t qpc_to_100ns(uint64_t qpc) {
return qpc / qpc_freq * 10000000 + qpc % qpc_freq * 10000000 / qpc_freq;
}
static inline void sync_framerate_with_timer(void) {
uint64_t t;
t = qpc_to_100ns(SDL_GetPerformanceCounter());
const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
int64_t left = next - t;
// We want to exit a bit early, so we can busy-wait the rest to never miss the deadline
left -= 15000UL;
if (left > 0) {
sysSleep(left);
}
do {
sysCpuRelax();
t = qpc_to_100ns(SDL_GetPerformanceCounter());
} while ((int64_t)t < next);
t = qpc_to_100ns(SDL_GetPerformanceCounter());
if (left > 0 && t - next < 10000) {
// In case it takes some time for the application to wake up after sleep,
// or inaccurate timer,
// don't let that slow down the framerate.
t = next;
}
previous_time = t;
}
static void gfx_sdl_swap_buffers_begin(void) {
if (target_fps) {
sync_framerate_with_timer();
}
SDL_GL_SwapWindow(wnd);
}
static void gfx_sdl_swap_buffers_end(void) {
}
static double gfx_sdl_get_time(void) {
return SDL_GetPerformanceCounter() / (double)qpc_freq;
}
static void gfx_sdl_set_target_fps(int fps) {
target_fps = fps;
}
static bool gfx_sdl_can_disable_vsync(void) {
return true;
}
static void *gfx_sdl_get_window_handle(void) {
return (void *)wnd;
}
static void gfx_sdl_set_window_title(const char *title) {
SDL_SetWindowTitle(wnd, title);
}
static bool gfx_sdl_set_swap_interval(int interval) {
const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
vsync_enabled = success && (interval != 0);
if (!success) {
sysLogPrintf(LOG_WARNING, "SDL: failed to set vsync %d: %s", interval, SDL_GetError());
}
return success;
}
struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_init,
gfx_sdl_close,
gfx_sdl_set_fullscreen_changed_callback,
gfx_sdl_set_fullscreen,
gfx_sdl_set_fullscreen_exclusive,
gfx_sdl_set_maximize_window,
gfx_sdl_get_active_window_refresh_rate,
gfx_sdl_set_cursor_visibility,
gfx_sdl_get_dimensions,
gfx_sdl_handle_events,
gfx_sdl_start_frame,
gfx_sdl_swap_buffers_begin,
gfx_sdl_swap_buffers_end,
gfx_sdl_get_time,
gfx_sdl_set_target_fps,
gfx_sdl_can_disable_vsync,
gfx_sdl_get_window_handle,
gfx_sdl_set_window_title,
gfx_sdl_set_swap_interval,
};
+41
View File
@@ -0,0 +1,41 @@
#ifndef GFX_WINDOW_MANAGER_API_H
#define GFX_WINDOW_MANAGER_API_H
#include <stdint.h>
#include <stdbool.h>
struct GfxWindowInitSettings {
const char *title;
uint32_t width;
uint32_t height;
int32_t x;
int32_t y;
bool fullscreen;
bool fullscreen_is_exclusive;
bool maximized;
bool allow_hidpi;
};
struct GfxWindowManagerAPI {
void (*init)(const struct GfxWindowInitSettings *settings);
void (*close)(void);
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
void (*set_fullscreen)(bool enable);
void (*set_fullscreen_exclusive)(bool exc);
void (*set_maximize)(bool enable);
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
void (*set_cursor_visibility)(bool visible);
void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY);
void (*handle_events)(void);
bool (*start_frame)(void);
void (*swap_buffers_begin)(void);
void (*swap_buffers_end)(void);
double (*get_time)(void); // For debug
void (*set_target_fps)(int fps);
bool (*can_disable_vsync)(void);
void *(*get_window_handle)(void);
void (*set_window_title)(const char *);
bool (*set_swap_interval)(int);
};
#endif
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+311
View File
@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */
+12
View File
@@ -0,0 +1,12 @@
#ifndef _IN_AUDIO_H
#define _IN_AUDIO_H
#include <PR/ultratypes.h>
s32 audioInit(void);
s32 audioGetBytesBuffered(void);
s32 audioGetSamplesBuffered(void);
void audioSetNextBuffer(const s16 *buf, u32 len);
void audioEndFrame(void);
#endif
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <PR/ultratypes.h>
#define CONFIG_FNAME "pd.ini"
#define CONFIG_PATH "$S/" CONFIG_FNAME
void configInit(void);
// loads config from file (path extensions such as ! apply)
s32 configLoad(const char *fname);
// saves config to file (path extensions such as ! apply)
s32 configSave(const char *fname);
// registers a variable in the config file
// this should be done before configInit() is called, preferably in a module constructor
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max);
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max);
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max);
void configRegisterString(const char *key, char *var, u32 maxstr);
+14
View File
@@ -0,0 +1,14 @@
#ifndef _IN_CONSOLE_H
#define _IN_CONSOLE_H
#include <PR/ultratypes.h>
#include "types.h"
void conInit(void);
Gfx *conRender(Gfx *gdl);
void conTick(void);
void conPrint(s32 showmsg, const char *s);
void conPrintf(s32 showmsg, const char *fmt, ...);
void conPrintLn(s32 showmsg, const char *s);
#endif
+5098
View File
File diff suppressed because it is too large. Load diff
+1865
View File
File diff suppressed because it is too large. Load diff
+26
View File
@@ -0,0 +1,26 @@
#ifndef _IN_FS_H
#define _IN_FS_H
#include <stdio.h>
#include <PR/ultratypes.h>
#define FS_MAXPATH 1024
s32 fsInit(void);
const char *fsFullPath(const char *relPath);
s32 fsPathIsAbsolute(const char *path);
s32 fsPathIsCwdRelative(const char *path);
void *fsFileLoad(const char *name, u32 *outSize);
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize);
s32 fsFileSize(const char *name);
FILE *fsFileOpenWrite(const char *name);
FILE *fsFileOpenRead(const char *name);
void fsFileClose(FILE *f);
const char *fsGetModDir(void);
#endif
+237
View File
@@ -0,0 +1,237 @@
#ifndef _IN_INPUT_H
#define _IN_INPUT_H
#include <PR/ultratypes.h>
#include <PR/os_cont.h>
#define INPUT_MAX_CONTROLLERS MAXCONTROLLERS
#define INPUT_MAX_CONNECTED_CONTROLLERS 8
#define INPUT_MAX_CONTROLLER_BUTTONS 32
#define INPUT_MAX_BINDS 4
#define CONT_STICK_XNEG 0x10000
#define CONT_STICK_XPOS 0x20000
#define CONT_STICK_YNEG 0x40000
#define CONT_STICK_YPOS 0x80000
#define CONT_NUM_BUTTONS 32 // not including the stick axes
enum virtkey {
/* same order as SDL scancodes */
VK_KEYBOARD_BEGIN = 0,
VK_A = 4,
VK_Z = 29,
VK_1 = 30,
VK_9 = 38,
VK_0 = 39,
VK_RETURN = 40,
VK_ESCAPE = 41,
VK_BACKSPACE = 42,
VK_SPACE = 44,
VK_MINUS = 45,
VK_LEFTBRACKET = 47,
VK_RIGHTBRACKET = 48,
VK_SEMICOLON = 51,
VK_GRAVE = 53,
VK_COMMA = 54,
VK_PERIOD = 55,
VK_F1 = 58,
VK_F9 = 66,
VK_DELETE = 76,
VK_LCTRL = 224,
VK_LSHIFT = 225,
VK_RCTRL = 228,
VK_RSHIFT = 229,
/* same order as SDL mouse buttons */
VK_MOUSE_BEGIN = 512,
VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
VK_MOUSE_MIDDLE,
VK_MOUSE_RIGHT,
VK_MOUSE_X1,
VK_MOUSE_X2,
VK_MOUSE_WHEEL_UP,
VK_MOUSE_WHEEL_DN,
/* same order as SDL gamecontroller buttons plus two buttons for triggers */
VK_JOY_BEGIN,
VK_JOY1_BEGIN = VK_JOY_BEGIN,
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
};
enum contkey {
CK_C_R,
CK_C_L,
CK_C_D,
CK_C_U,
CK_RTRIG,
CK_LTRIG,
CK_X, // gap in CONT_
CK_Y, // gap in CONT_
CK_DPAD_R,
CK_DPAD_L,
CK_DPAD_D,
CK_DPAD_U,
CK_START,
CK_ZTRIG,
CK_B,
CK_A,
CK_STICK_XNEG,
CK_STICK_XPOS,
CK_STICK_YNEG,
CK_STICK_YPOS,
CK_0010,
CK_0020,
CK_0040,
CK_0080,
CK_0100,
CK_0200,
CK_0400,
CK_0800,
CK_1000,
CK_2000,
CK_4000,
CK_8000,
CK_TOTAL_COUNT
};
// returns bitmask of connected controllers or -1 if failed
s32 inputInit(void);
// read the specified player's inputs into the N64 pad struct
// returns 0 if read, non-0 if failed
s32 inputReadController(s32 idx, OSContPad *npad);
// returns 1 if rumble is supported for specified player's controller
s32 inputRumbleSupported(s32 idx);
// returns 1 if specified player has a live controller assigned
s32 inputControllerConnected(s32 idx);
// returns bitmask of players with assigned controllers
s32 inputControllerMask(void);
// get/set Input.Player%d.SwapSticks
s32 inputControllerGetSticksSwapped(s32 cidx);
void inputControllerSetSticksSwapped(s32 cidx, s32 swapped);
// get/set Input.Player%d.StickCButtons (DualAnalog is 1 if StickCButtons is 0)
s32 inputControllerGetDualAnalog(s32 cidx);
void inputControllerSetDualAnalog(s32 cidx, s32 enable);
// get/set sensitivity for a given player
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value);
// get/set deadzone for a given player
f32 inputControllerGetAxisDeadzone(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisDeadzone(s32 cidx, s32 stick, s32 axis, f32 value);
// writes array of up to INPUT_MAX_CONNECTED_CONTROLLERS controller IDs
// for all the controllers available on this machine into out if it's not NULL
// returns number of IDs that would've been written (or were written if out is not NULL)
s32 inputGetConnectedControllers(s32 *out);
// get name of connected controller id
// returns "Invalid" on failure
const char *inputGetConnectedControllerName(s32 id);
// get id of the controller currently assigned to player cidx or -1 if none
s32 inputGetAssignedControllerId(s32 cidx);
// assign connected controller id to player cidx
// if id is -1, unassigns controller from player, if any
// returns true on success, false on failure
s32 inputAssignController(s32 cidx, s32 id);
// vk is a value from the virtkey enum above
s32 inputKeyPressed(u32 vk);
// idx is controller index, contbtn is one of the CONT_ constants
s32 inputButtonPressed(s32 idx, u32 contbtn);
// bind virtkey vk to n64 pad #idx's button/axis ck as represented by its contkey value
// if bind is -1, picks a bind slot automatically
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk);
const u32 *inputKeyGetBinds(s32 idx, u32 ck);
// get VK_ value from human-readable name
s32 inputGetKeyByName(const char *name);
// get human-readable name from VK_ value
const char *inputGetKeyName(s32 vk);
// get CK_ value from human-readable name
s32 inputGetContKeyByName(const char *name);
// get human-readable name from CK_ value
const char *inputGetContKeyName(u32 ck);
// strength is 0 .. 1; 0 strength turns it off
void inputRumble(s32 idx, f32 strength, f32 time);
f32 inputRumbleGetStrength(s32 cidx);
void inputRumbleSetStrength(s32 cidx, f32 val);
// locks the mouse cursor in the window and makes it invisible if argument is true
void inputLockMouse(s32 lock);
// returns the current state of the above
s32 inputMouseIsLocked(void);
// returns mouse position in native viewport coordinates (ie, 320x240 most of the time)
void inputMouseGetPosition(s32 *x, s32 *y);
// returns changes in mouse position since last frame, in window coordinates
void inputMouseGetRawDelta(s32 *dx, s32 *dy);
// returns changes in mouse position since last frame, scaled by sensitivity
// returns 0, 0 when the mouse is not locked into the window
void inputMouseGetScaledDelta(f32 *dx, f32 *dy);
// returns changes in mouse position since last frame, scaled by absolute sensitivity
// returns 0, 0 when the mouse is not locked into the window
void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy);
void inputMouseGetSpeed(f32 *x, f32 *y);
void inputMouseSetSpeed(f32 x, f32 y);
s32 inputMouseIsEnabled(void);
void inputMouseEnable(s32 enabled);
// call this every frame
void inputUpdate(void);
// call this before configSave()
void inputSaveBinds(void);
// reset given player's binds to either PC or N64 defaults
void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode);
// clear or get the last pressed button
void inputClearLastKey(void);
s32 inputGetLastKey(void);
void inputStartTextInput(void);
void inputStopTextInput(void);
void inputClearLastTextChar(void);
char inputGetLastTextChar(void);
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol);
void inputClearClipboard(void);
const char *inputGetClipboard(void);
// get/set Input.MouseDefaultLocked
s32 inputGetMouseDefaultLocked(void);
void inputSetMouseDefaultLocked(s32 defaultLocked);
#endif
+55
View File
@@ -0,0 +1,55 @@
#ifndef MIXER_H
#define MIXER_H
#include <stdint.h>
#include <ultra64.h>
#undef aSegment
#undef aClearBuffer
#undef aSetBuffer
#undef aLoadBuffer
#undef aSaveBuffer
#undef aDMEMMove
#undef aMix
#undef aEnvMixer
#undef aResample
#undef aInterleave
#undef aSetVolume
#undef aSetVolume32
#undef aSetLoop
#undef aLoadADPCM
#undef aADPCMdec
void aClearBufferImpl(uint16_t addr, int nbytes);
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr);
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes);
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state);
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state, int nbytes, uint16_t inofs, uint16_t outofs);
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state, uint16_t inofs, uint8_t outflag);
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes);
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes);
void aInterleaveImpl(void);
void aMixImpl(uint8_t flags, int16_t gain, uint16_t in_addr, uint16_t out_addr);
void aEnvMixerImpl(uint8_t flags, ENVMIX_STATE state, int16_t some_vol);
void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r);
void aPoleFilterImpl(uint8_t flags, int16_t gain, uint32_t t, uint32_t addr);
void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c);
void aPlayMP3Impl(const void *mp3file, u32 mp3size, void *out, int reset);
#define aDisable(pkt, o, b, c) aDisableImpl(o, b, c)
#define aClearBuffer(pkt, d, c) aClearBufferImpl(d, c)
#define aLoadBuffer(pkt, c, d, s) aLoadBufferImpl((void *)(s), d, c)
#define aSaveBuffer(pkt, c, s, d) aSaveBufferImpl(s, (int16_t *)(d), c)
#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, (int16_t *)(d))
#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c)
#define aSetLoop(pkt, a) aSetLoopImpl((void *)(a))
#define aADPCMdec(pkt, s, f, c, i, o) aADPCMdecImpl(f, (void *)(s), c, i, o)
#define aResample(pkt, s, f, p, i, o) aResampleImpl(f, p, (void *)(s), i, o)
#define aInterleave(pkt) aInterleaveImpl()
#define aMix(pkt, f, g, i, o) aMixImpl(f, g, i, o)
#define aEnvMixer(pkt, f, t, s) aEnvMixerImpl(f, (void *)(s), t)
#define aSetVolume(pkt, f, v, t, r) aSetVolumeImpl(f, v, t, r)
#define aPoleFilter(pkt, f, g, t, s) aPoleFilterImpl(f, g, t, s)
#define aPlayMP3(pkt, a, b, c, r) aPlayMP3Impl((void *)(a), b, (void *)(c), r)
#endif
+19
View File
@@ -0,0 +1,19 @@
#ifndef _IN_MOD_H
#define _IN_MOD_H
#include <PR/ultratypes.h>
#define MOD_CONFIG_FNAME "modconfig.txt"
struct animtableentry;
s32 modConfigLoad(const char *path);
s32 modTextureLoad(u16 num, void *dst, u32 dstSize);
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim);
void *modAnimationLoadData(u16 num);
void *modSequenceLoad(u16 num, u32 *outSize);
#endif
+163
View File
@@ -0,0 +1,163 @@
#ifndef _IN_NET_H
#define _IN_NET_H
#include "types.h"
#include "constants.h"
#include "net/netbuf.h"
#define NET_PROTOCOL_VER 12
#define NET_QUERY_MAGIC "PDQM\x01"
#define NET_MAX_CLIENTS MAX_PLAYERS
#define NET_MAX_NAME MAX_PLAYERNAME
#define NET_MAX_ADDR 256
#define NET_BUFSIZE 1440
#define NET_DEFAULT_PORT 27100
#define NET_NULL_CLIENT 0xFF
#define NET_NULL_PROP 0
#define NETCHAN_DEFAULT 0
#define NETCHAN_CONTROL 1
#define NETCHAN_COUNT 2
#define DISCONNECT_UNKNOWN 0
#define DISCONNECT_SHUTDOWN 1
#define DISCONNECT_VERSION 2
#define DISCONNECT_KICKED 3
#define DISCONNECT_BANNED 4
#define DISCONNECT_TIMEOUT 5
#define DISCONNECT_FULL 6
#define DISCONNECT_LATE 7
#define DISCONNECT_FILES 8
#define CLSTATE_DISCONNECTED 0
#define CLSTATE_CONNECTING 1
#define CLSTATE_AUTH 2
#define CLSTATE_LOBBY 3
#define CLSTATE_GAME 4
#define UCMD_FIRE (1 << 0)
#define UCMD_ACTIVATE (1 << 1)
#define UCMD_RELOAD (1 << 2)
#define UCMD_AIMMODE (1 << 3)
#define UCMD_DUCK (1 << 4)
#define UCMD_SQUAT (1 << 5)
#define UCMD_ZOOMIN (1 << 6)
#define UCMD_SELECT (1 << 7)
#define UCMD_SELECT_DUAL (1 << 8)
#define UCMD_EYESSHUT (1 << 9)
#define UCMD_SECONDARY (1 << 10)
#define UCMD_RESPAWN (1 << 27)
#define UCMD_CHAT (1 << 28)
#define UCMD_IMPORTANT_MASK (UCMD_FIRE | UCMD_ACTIVATE | UCMD_RELOAD | UCMD_AIMMODE | UCMD_SELECT | UCMD_SELECT_DUAL)
#define UCMD_FL_FORCEPOS (1 << 29)
#define UCMD_FL_FORCEANGLE (1 << 30)
#define UCMD_FL_FORCEGROUND (1 << 31)
#define UCMD_FL_FORCEMASK (UCMD_FL_FORCEPOS | UCMD_FL_FORCEANGLE | UCMD_FL_FORCEGROUND)
struct netplayermove {
u32 tick; // g_NetTIck value when this struct was written; if 0, this struct is invalid
u32 ucmd; // player commands (UCMD_)
f32 leanofs; // analog lean value (-1 .. 1; equal to player->swaytarget / 75.f)
f32 crouchofs; // analog crouch value (-90 for SQUAT, 0 for STAND; player->crouchofs)
f32 zoomfov; // manual zoom fov for the current gun; synced only if UCMD_AIMING is set
f32 movespeed[2]; // move inputs, [0] is forward, [1] is sideways; used mostly for animation
f32 angles[2]; // view angles, [0] is theta, [1] is verta
f32 crosspos[2]; // crosshair position in aiming mode; normalized to default aspect ratio
s8 weaponnum; // switch to this weapon if UCMD_SELECT is set
struct coord pos; // player position at g_NetTick == tick
};
struct netclient {
struct _ENetPeer *peer;
u32 id; // remote client number, server is always 0, even on clients
u32 state; // CLSTATE_
u32 flags; // CLFLAG_
struct {
char name[NET_MAX_NAME];
u16 options;
u8 headnum;
u8 bodynum;
u8 team;
f32 fovy;
f32 fovzoommult;
} settings;
struct mpplayerconfig *config;
struct player *player;
u8 playernum;
struct netplayermove outmove[2]; // last 2 outgoing player inputs, newest one first
struct netplayermove inmove[2]; // last 2 incoming player inputs, newest one first
u32 inmovetick; // last inmove tick which was applied to the player
u32 outmoveack; // last acked outmove tick
u32 forcetick; // tick on which the client's position was forced, or 0 if not forcing
u32 lerpticks; // how many ticks we've been lerping the position
struct netbuf out; // outbound messages are written here, except broadcasts
struct netbuf in; // incoming packets are fed here
u8 out_data[NET_BUFSIZE]; // buffer for out
};
extern s32 g_NetMode;
extern s32 g_NetJoinLatch;
extern s32 g_NetHostLatch;
// net frame, ticks at 60 fps, starts at 0 when the server is started
extern u32 g_NetTick;
extern u32 g_NetNextSyncId;
extern u64 g_NetRngSeeds[2];
extern u32 g_NetRngLatch;
extern u32 g_NetInterpTicks;
extern u32 g_NetServerPort;
extern char g_NetLastJoinAddr[NET_MAX_ADDR + 1];
extern s32 g_NetDebugDraw;
extern s32 g_NetMaxClients;
extern s32 g_NetNumClients;
extern struct netclient g_NetClients[NET_MAX_CLIENTS + 1]; // last is an extra temporary client
extern struct netclient *g_NetLocalClient;
extern struct netbuf g_NetMsg;
extern struct netbuf g_NetMsgRel;
const char *netFormatClientAddr(const struct netclient *cl);
void netInit(void);
s32 netDisconnect(void);
void netStartFrame(void);
void netEndFrame(void);
s32 netStartServer(u16 port, s32 maxclients);
s32 netStartClient(const char *addr);
u32 netSend(struct netclient *dstcl, struct netbuf *buf, const s32 reliable, const s32 chan);
void netChat(struct netclient *dst, const char *text);
void netChatPrintf(struct netclient *dst, const char *fmt, ...);
void netServerStageStart(void);
void netServerStageEnd(void);
void netServerKick(struct netclient *cl, const u32 reason);
struct netclient *netClientForPlayerNum(s32 playernum);
void netClientSyncRng(void);
void netClientSettingsChanged(void);
void netPlayersAllocate(void);
void netSyncIdsAllocate(void);
Gfx *netDebugRender(Gfx *gdl);
#endif // _IN_NET_H
+50
View File
@@ -0,0 +1,50 @@
#ifndef _IN_NETBUF_H
#define _IN_NETBUF_H
#include "types.h"
struct netbuf {
u8 *data;
u32 size;
u32 rp;
u32 wp;
u32 error;
};
void netbufStartRead(struct netbuf *buf);
void netbufStartReadData(struct netbuf *buf, const void *data, u32 size);
s32 netbufReadLeft(const struct netbuf *buf);
u32 netbufReadData(struct netbuf *buf, void *out, u32 num);
u8 netbufReadU8(struct netbuf *buf);
u16 netbufReadU16(struct netbuf *buf);
u32 netbufReadU32(struct netbuf *buf);
u64 netbufReadU64(struct netbuf *buf);
s8 netbufReadS8(struct netbuf *buf);
s16 netbufReadS16(struct netbuf *buf);
s32 netbufReadS32(struct netbuf *buf);
s64 netbufReadS64(struct netbuf *buf);
f32 netbufReadF32(struct netbuf *buf);
char *netbufReadStr(struct netbuf *buf);
u32 netbufReadCoord(struct netbuf *buf, struct coord *out);
u32 netbufReadMtxf(struct netbuf *buf, Mtxf *out);
u32 netbufReadSkip(struct netbuf *buf, u32 count);
void netbufStartWrite(struct netbuf *buf);
s32 netbufWriteLeft(const struct netbuf *buf);
u32 netbufWriteData(struct netbuf *buf, const void *data, u32 num);
u32 netbufWriteU8(struct netbuf *buf, const u8 v);
u32 netbufWriteU16(struct netbuf *buf, const u16 v);
u32 netbufWriteU32(struct netbuf *buf, const u32 v);
u32 netbufWriteU64(struct netbuf *buf, const u64 v);
u32 netbufWriteS8(struct netbuf *buf, const s8 v);
u32 netbufWriteS16(struct netbuf *buf, const s16 v);
u32 netbufWriteS32(struct netbuf *buf, const s32 v);
u32 netbufWriteS64(struct netbuf *buf, const s64 v);
u32 netbufWriteF32(struct netbuf *buf, const f32 v);
u32 netbufWriteStr(struct netbuf *buf, const char *v);
u32 netbufWriteCoord(struct netbuf *buf, const struct coord *v);
u32 netbufWriteMtxf(struct netbuf *buf, const Mtxf *in);
void netbufReset(struct netbuf *buf);
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef _IN_NETENET_H
#define _IN_NETENET_H
#define ENET_NO_PRAGMA_LINK 1
#include "external/enet.h"
#undef bool
#undef near
#undef far
#endif
+74
View File
@@ -0,0 +1,74 @@
#ifndef _IN_NETMSG_H
#define _IN_NETMSG_H
#include <PR/ultratypes.h>
#include "net/net.h"
#include "net/netbuf.h"
#define SVC_BAD 0x00 // trash
#define SVC_NOP 0x01 // does nothing
#define SVC_AUTH 0x02 // auth response, sent in response to CLC_AUTH
#define SVC_CHAT 0x03 // chat message
#define SVC_STAGE_START 0x10 // start level
#define SVC_STAGE_END 0x11 // end level
#define SVC_PLAYER_MOVE 0x20 // player movement and inputs
#define SVC_PLAYER_GUNS 0x21 // player gun state
#define SVC_PLAYER_STATS 0x22 // player stats (health etc)
#define SVC_PROP_MOVE 0x30 // prop movement
#define SVC_PROP_SPAWN 0x31 // new prop spawned
#define SVC_PROP_DAMAGE 0x32 // prop was damaged
#define SVC_PROP_PICKUP 0x33 // prop was picked up
#define SVC_PROP_USE 0x34 // door/lift/etc was used
#define SVC_PROP_DOOR 0x35 // door state changed
#define SVC_PROP_LIFT 0x36 // lift state changed
#define SVC_CHR_DAMAGE 0x42 // chr was damaged
#define SVC_CHR_DISARM 0x43 // chr's weapons were dropped
#define CLC_BAD 0x00 // trash
#define CLC_NOP 0x01 // does nothing
#define CLC_AUTH 0x02 // auth request, sent immediately after connecting
#define CLC_CHAT 0x03 // chat message
#define CLC_MOVE 0x04 // player input
#define CLC_SETTINGS 0x05 // player settings changed
u32 netmsgClcAuthWrite(struct netbuf *dst);
u32 netmsgClcAuthRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgClcChatWrite(struct netbuf *dst, const char *str);
u32 netmsgClcChatRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgClcMoveWrite(struct netbuf *dst);
u32 netmsgClcMoveRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgClcSettingsWrite(struct netbuf *dst);
u32 netmsgClcSettingsRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcAuthWrite(struct netbuf *dst, struct netclient *authcl);
u32 netmsgSvcAuthRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcChatWrite(struct netbuf *dst, const char *str);
u32 netmsgSvcChatRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcStageStartWrite(struct netbuf *dst);
u32 netmsgSvcStageStartRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcStageEndWrite(struct netbuf *dst);
u32 netmsgSvcStageEndRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPlayerMoveWrite(struct netbuf *dst, struct netclient *movecl);
u32 netmsgSvcPlayerMoveRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPlayerStatsWrite(struct netbuf *dst, struct netclient *actcl);
u32 netmsgSvcPlayerStatsRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropSpawnWrite(struct netbuf *dst, struct prop *prop);
u32 netmsgSvcPropSpawnRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropMoveWrite(struct netbuf *dst, struct prop *prop, struct coord *initrot);
u32 netmsgSvcPropMoveRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropDamageWrite(struct netbuf *dst, struct prop *prop, f32 damage, struct coord *pos, s32 weaponnum, s32 playernum);
u32 netmsgSvcPropDamageRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropPickupWrite(struct netbuf *dst, struct netclient *actcl, struct prop *prop, const s32 tickop);
u32 netmsgSvcPropPickupRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropUseWrite(struct netbuf *dst, struct prop *prop, struct netclient *usercl, const s32 tickop);
u32 netmsgSvcPropUseRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropDoorWrite(struct netbuf *dst, struct prop *prop, struct netclient *usercl);
u32 netmsgSvcPropDoorRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropLiftWrite(struct netbuf *dst, struct prop *prop);
u32 netmsgSvcPropLiftRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcChrDamageWrite(struct netbuf *dst, struct chrdata *chr, f32 damage, struct coord *vector, struct gset *gset, struct prop *aprop, s32 hitpart, bool damageshield, struct prop *prop2, s32 side, s16 *arg11, bool explosion, struct coord *explosionpos);
u32 netmsgSvcChrDamageRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcChrDisarmWrite(struct netbuf *dst, struct chrdata *chr, struct prop *attacker, u8 weaponnum, f32 wpndamage, struct coord *wpnpos);
u32 netmsgSvcChrDisarmRead(struct netbuf *src, struct netclient *srccl);
#endif
+34
View File
@@ -0,0 +1,34 @@
#ifndef _IN_PREPROCESS_H
#define _IN_PREPROCESS_H
#include <PR/ultratypes.h>
typedef void (*preprocessfunc)(u8 *data, u32 size);
void preprocessAnimations(u8 *data, u32 size);
void preprocessMpConfigs(u8 *data, u32 size);
void preprocessFont(u8 *data, u32 size);
void preprocessJpnFont(u8 *data, u32 size);
void preprocessALBankFile(u8 *data, u32 size);
void preprocessALCMidiHdr(u8 *data, u32 size);
void preprocessSequences(u8 *data, u32 size);
void preprocessFiringRange(u8 *data, u32 size);
void preprocessTexturesList(u8 *data, u32 size);
void preprocessBgSection1Header(u8 *data, u32 size);
void preprocessBgSection1(u8 *data, u32 size);
void preprocessBgSection2Header(u8 *data, u32 size);
void preprocessBgSection2(u8 *data, u32 size);
void preprocessBgSection3Header(u8 *data, u32 size);
void preprocessBgSection3(u8 *data, u32 size);
void preprocessBgRoom(u8 *data, u32 ofs);
void preprocessBgLights(u8 *data, u32 ofs);
void preprocessLangFile(u8 *data, u32 size);
void preprocessPadsFile(u8 *data, u32 size);
void preprocessTilesFile(u8 *data, u32 size);
void preprocessSetupFile(u8 *data, u32 size);
void preprocessModelFile(u8 *data, u32 size);
void preprocessGunFile(u8 *data, u32 size);
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef _IN_ROMDATA_H
#define _IN_ROMDATA_H
#include <PR/ultratypes.h>
extern u8 *g_RomFile;
extern u32 g_RomFileSize;
extern const char *g_RomName;
s32 romdataInit(void);
u8 *romdataFileLoad(s32 fileNum, u32 *outSize);
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size);
void romdataFileFree(s32 fileNum);
const char *romdataFileGetName(s32 fileNum);
u8 *romdataFileGetData(s32 fileNum);
s32 romdataFileGetSize(s32 fileNum);
s32 romdataFileGetNumForName(const char *name);
u8 *romdataSegGetData(const char *segName);
u8 *romdataSegGetDataEnd(const char *segName);
u32 romdataSegGetSize(const char *segName);
#endif
+55
View File
@@ -0,0 +1,55 @@
#ifndef _IN_SYSTEM_H
#define _IN_SYSTEM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <PR/ultratypes.h>
#define LOGFLAG_NOCON (1 << 6)
#define LOGFLAG_SHOWMSG (1 << 7)
enum loglevel {
LOG_NOTE = 0,
LOG_CHAT = 0 | LOGFLAG_SHOWMSG,
LOG_WARNING = 1 | LOGFLAG_SHOWMSG,
LOG_ERROR = 2 | LOGFLAG_SHOWMSG,
};
void sysInitArgs(s32 argc, const char **argv);
void sysInit(void);
s32 sysArgCheck(const char *arg);
const char *sysArgGetString(const char *arg);
s32 sysArgGetInt(const char *arg, s32 defval);
u64 sysGetMicroseconds(void);
f32 sysGetSeconds(void);
void sysFatalError(const char *fmt, ...) __attribute__((noreturn));
s32 sysLogIsOpen(void);
void sysLogPrintf(s32 level, const char *fmt, ...);
void sysGetExecutablePath(char *outPath, const u32 outLen);
void sysGetHomePath(char *outPath, const u32 outLen);
void *sysMemAlloc(const u32 size);
void *sysMemZeroAlloc(const u32 size);
void sysMemFree(void *ptr);
// hns is specified in 100ns units
void sysSleep(const s64 hns);
// yield CPU if supported (e.g. during a busy loop)
void sysCpuRelax(void);
void crashInit(void);
void crashShutdown(void);
#ifdef __cplusplus
}
#endif
#endif
+29
View File
@@ -0,0 +1,29 @@
#ifndef _IN_UTILS_H
#define _IN_UTILS_H
#define UTIL_MAX_TOKEN 1024
#include <PR/ultratypes.h>
char *strRightTrim(char *str);
char *strTrim(char *str);
char *strUnquote(char *str);
char *strParseToken(char *str, char *out, s32 *outCount);
char *strFmt(const char *fmt, ...);
char *strDuplicate(const char *str);
static inline f32 lerpf(const f32 a, const f32 b, const f32 t) {
return a + (b - a) * t;
}
static inline f32 lerpanglef(const f32 a, const f32 b, const f32 t) {
f32 d = b - a;
if (d > 180.f) {
d -= 360.f;
} else if (d < -180.f) {
d += 360.f;
}
return a + d * t;
}
#endif
+53
View File
@@ -0,0 +1,53 @@
#ifndef _IN_VIDEO_H
#define _IN_VIDEO_H
#include <PR/ultratypes.h>
#include <PR/gbi.h>
// maximum framerate; if the game runs faster than this, things will break
#if PAL
#define VIDEO_MAX_FPS 200
#else
#define VIDEO_MAX_FPS 240
#endif
s32 videoInit(void);
void videoStartFrame(void);
void videoSubmitCommands(Gfx *cmds);
void videoClearScreen(void);
void videoEndFrame(void);
void *videoGetWindowHandle(void);
void videoUpdateNativeResolution(s32 w, s32 h);
s32 videoGetNativeWidth(void);
s32 videoGetNativeHeight(void);
s32 videoGetWidth(void);
s32 videoGetHeight(void);
f32 videoGetAspect(void);
s32 videoGetFullscreen(void);
s32 videoGetMaximizeWindow(void);
void videoSetMaximizeWindow(s32 fs);
u32 videoGetTextureFilter(void);
s32 videoGetTextureFilter2D(void);
s32 videoGetDetailTextures(void);
void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs);
void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(s32 filter);
void videoSetDetailTextures(s32 detail);
void videoCapFramerate(s32 limit);
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target);
void videoResetFramebuffer(void);
void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top);
void videoResizeFramebuffer(s32 target, u32 w, u32 h, s32 upscale, s32 autoresize);
s32 videoFramebuffersSupported(void);
void videoResetTextureCache(void);
void videoFreeCachedTexture(const void *texptr);
#endif
+75
View File
@@ -0,0 +1,75 @@
#include <PR/ultratypes.h>
#include <stdio.h>
#include <SDL.h>
#include "platform.h"
#include "config.h"
#include "audio.h"
#include "system.h"
static SDL_AudioDeviceID dev;
static const s16 *nextBuf;
static u32 nextSize = 0;
static s32 bufferSize = 512;
static s32 queueLimit = 8192;
s32 audioInit(void)
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
sysLogPrintf(LOG_ERROR, "SDL audio init error: %s", SDL_GetError());
return -1;
}
SDL_AudioSpec want, have;
SDL_zero(want);
want.freq = 22020; // TODO: this might cause trouble for some platforms
want.format = AUDIO_S16SYS;
want.channels = 2;
want.samples = bufferSize;
want.callback = NULL;
nextBuf = NULL;
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
if (dev == 0) {
sysLogPrintf(LOG_ERROR, "SDL_OpenAudio error: %s", SDL_GetError());
return -1;
}
SDL_PauseAudioDevice(dev, 0);
return 0;
}
s32 audioGetBytesBuffered(void)
{
return SDL_GetQueuedAudioSize(dev);
}
s32 audioGetSamplesBuffered(void)
{
return audioGetBytesBuffered() / 4;
}
void audioSetNextBuffer(const s16 *buf, u32 len)
{
nextBuf = buf;
nextSize = len;
}
void audioEndFrame(void)
{
if (nextBuf && nextSize) {
if (audioGetSamplesBuffered() < queueLimit) {
SDL_QueueAudio(dev, nextBuf, nextSize);
}
nextBuf = NULL;
nextSize = 0;
}
}
PD_CONSTRUCTOR static void audioConfigInit(void)
{
configRegisterInt("Audio.BufferSize", &bufferSize, 0, 1 * 1024 * 1024);
configRegisterInt("Audio.QueueLimit", &queueLimit, 0, 1 * 1024 * 1024);
}
+295
View File
@@ -0,0 +1,295 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <PR/ultratypes.h>
#include "fs.h"
#include "config.h"
#include "system.h"
#include "utils.h"
#define CONFIG_MAX_SECNAME 128
#define CONFIG_MAX_KEYNAME 256
#define CONFIG_MAX_SETTINGS 256
typedef enum {
CFG_NONE,
CFG_S32,
CFG_F32,
CFG_U32,
CFG_STR
} configtype;
struct configentry {
char key[CONFIG_MAX_KEYNAME + 1];
s32 seclen;
configtype type;
void *ptr;
union {
struct { f32 min_f32, max_f32; };
struct { s32 min_s32, max_s32; };
struct { u32 min_u32, max_u32; };
u32 max_str;
};
} settings[CONFIG_MAX_SETTINGS];
static s32 numSettings = 0;
static inline s32 configClampInt(s32 val, s32 min, s32 max)
{
return (val < min) ? min : ((val > max) ? max : val);
}
static inline u32 configClampUInt(u32 val, u32 min, u32 max)
{
return (val < min) ? min : ((val > max) ? max : val);
}
static inline f32 configClampFloat(f32 val, f32 min, f32 max)
{
return (val < min) ? min : ((val > max) ? max : val);
}
static inline struct configentry *configFindEntry(const char *key)
{
for (s32 i = 0; i < numSettings; ++i) {
if (!strncasecmp(settings[i].key, key, CONFIG_MAX_KEYNAME)) {
return &settings[i];
}
}
return NULL;
}
static inline struct configentry *configAddEntry(const char *key)
{
if (numSettings < CONFIG_MAX_SETTINGS) {
struct configentry *cfg = &settings[numSettings++];
strncpy(cfg->key, key, CONFIG_MAX_KEYNAME);
const char *delim = strrchr(cfg->key, '.');
cfg->seclen = delim ? (delim - cfg->key) : 0;
return cfg;
}
return NULL;
}
static inline struct configentry *configFindOrAddEntry(const char *key)
{
for (s32 i = 0; i < numSettings; ++i) {
if (!strncasecmp(settings[i].key, key, CONFIG_MAX_KEYNAME)) {
return &settings[i];
}
}
return configAddEntry(key);
}
static inline const char *configGetSection(char *sec, const struct configentry *cfg)
{
if (!cfg->seclen || cfg->seclen > CONFIG_MAX_SECNAME) {
strncpy(sec, cfg->key, CONFIG_MAX_SECNAME);
sec[CONFIG_MAX_SECNAME] = '\0';
return sec;
}
memcpy(sec, cfg->key, cfg->seclen);
sec[cfg->seclen] = '\0';
return sec;
}
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max)
{
struct configentry *cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_S32;
cfg->ptr = var;
cfg->min_s32 = min;
cfg->max_s32 = max;
}
}
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max)
{
struct configentry* cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_U32;
cfg->ptr = var;
cfg->min_u32 = min;
cfg->max_u32 = max;
}
}
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max)
{
struct configentry *cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_F32;
cfg->ptr = var;
cfg->min_f32 = min;
cfg->max_f32 = max;
}
}
void configRegisterString(const char *key, char *var, u32 maxstr)
{
struct configentry *cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_STR;
cfg->ptr = var;
cfg->max_str = maxstr;
}
}
static void configSetFromString(const char *key, const char *val)
{
struct configentry *cfg = configFindEntry(key);
if (!cfg) return;
s32 tmp_s32;
f32 tmp_f32;
u32 tmp_u32;
switch (cfg->type) {
case CFG_S32:
tmp_s32 = strtol(val, NULL, 0);
if (cfg->min_s32 < cfg->max_s32) {
tmp_s32 = configClampInt(tmp_s32, cfg->min_s32, cfg->max_s32);
}
*(s32 *)cfg->ptr = tmp_s32;
break;
case CFG_F32:
tmp_f32 = strtof(val, NULL);
if (cfg->min_f32 < cfg->max_f32) {
tmp_f32 = configClampFloat(tmp_f32, cfg->min_f32, cfg->max_f32);
}
*(f32 *)cfg->ptr = tmp_f32;
break;
case CFG_U32:
tmp_u32 = strtoul(val, NULL, 0);
if (cfg->min_u32 < cfg->max_u32) {
tmp_u32 = configClampUInt(tmp_u32, cfg->min_u32, cfg->max_u32);
}
*(u32*)cfg->ptr = tmp_u32;
break;
case CFG_STR:
strncpy(cfg->ptr, val, cfg->max_str ? cfg->max_str - 1 : 4096);
break;
default:
break;
}
}
static void configSaveEntry(struct configentry *cfg, FILE *f)
{
switch (cfg->type) {
case CFG_S32:
if (cfg->min_s32 < cfg->max_s32) {
*(s32 *)cfg->ptr = configClampInt(*(s32 *)cfg->ptr, cfg->min_s32, cfg->max_s32);
}
fprintf(f, "%s=%d\n", cfg->key + cfg->seclen + 1, *(s32 *)cfg->ptr);
break;
case CFG_F32:
if (cfg->min_f32 < cfg->max_f32) {
*(f32 *)cfg->ptr = configClampFloat(*(f32 *)cfg->ptr, cfg->min_f32, cfg->max_f32);
}
fprintf(f, "%s=%f\n", cfg->key + cfg->seclen + 1, *(f32 *)cfg->ptr);
break;
case CFG_U32:
if (cfg->min_u32 < cfg->max_u32) {
*(u32*)cfg->ptr = configClampUInt(*(u32*)cfg->ptr, cfg->min_u32, cfg->max_u32);
}
fprintf(f, "%s=%u\n", cfg->key + cfg->seclen + 1, *(u32 *)cfg->ptr);
break;
case CFG_STR:
fprintf(f, "%s=%s\n", cfg->key + cfg->seclen + 1, (char *)cfg->ptr);
break;
default:
break;
}
}
s32 configSave(const char *fname)
{
FILE *f = fsFileOpenWrite(fname);
if (!f) {
return 0;
}
char tmpSec[CONFIG_MAX_SECNAME + 1] = { 0 };
char curSec[CONFIG_MAX_SECNAME + 1] = { 0 };
configGetSection(curSec, &settings[0]);
fprintf(f, "[%s]\n", curSec);
for (s32 i = 0; i < numSettings; ++i) {
struct configentry *cfg = &settings[i];
configGetSection(tmpSec, cfg);
if (strncmp(curSec, tmpSec, CONFIG_MAX_SECNAME) != 0) {
fprintf(f, "\n[%s]\n", tmpSec);
strncpy(curSec, tmpSec, CONFIG_MAX_SECNAME);
}
configSaveEntry(cfg, f);
}
fsFileClose(f);
return 1;
}
s32 configLoad(const char *fname)
{
FILE *f = fsFileOpenRead(fname);
if (!f) {
return 0;
}
char curSec[CONFIG_MAX_SECNAME + 1] = { 0 };
char keyBuf[CONFIG_MAX_SECNAME * 2 + 2] = { 0 }; // SECTION + . + KEY + \0
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char lineBuf[2048] = { 0 };
char *line = lineBuf;
s32 lineLen = 0;
while (fgets(lineBuf, sizeof(lineBuf), f)) {
line = lineBuf;
line = strParseToken(line, token, NULL);
if (token[0] == '[' && token[1] == '\0') {
// section; get name
line = strParseToken(line, token, NULL);
if (!token[0]) {
sysLogPrintf(LOG_ERROR, "configLoad: malformed section line: %s", lineBuf);
continue;
}
strncpy(curSec, token, CONFIG_MAX_SECNAME);
// eat ]
line = strParseToken(line, token, NULL);
if (token[0] != ']' || token[1] != '\0') {
sysLogPrintf(LOG_ERROR, "configLoad: malformed section line: %s", lineBuf);
}
} else if (token[0]) {
// probably a key=value pair; append key name to section name
snprintf(keyBuf, sizeof(keyBuf) - 1, "%s.%s", curSec, token);
// eat =
line = strParseToken(line, token, NULL);
if (token[0] != '=' || token[1] != '\0') {
sysLogPrintf(LOG_ERROR, "configLoad: malformed keyvalue line: %s", lineBuf);
continue;
}
// the rest of the line is the value
line = strTrim(line);
if (line[0] == '"') {
line = strUnquote(line);
}
configSetFromString(keyBuf, line);
}
}
fsFileClose(f);
return 1;
}
void configInit(void)
{
if (fsFileSize(CONFIG_PATH) > 0) {
configLoad(CONFIG_PATH);
}
}
+213
View File
@@ -0,0 +1,213 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "platform.h"
#include "types.h"
#include "constants.h"
#include "data.h"
#include "bss.h"
#include "config.h"
#include "video.h"
#include "input.h"
#include "console.h"
#include "system.h"
#include "utils.h"
#include "net/net.h"
#include "game/hudmsg.h"
#include "game/game_1531a0.h"
#include "lib/vi.h"
#define CON_ROWS 80
#define CON_COLS 56
#define CON_VISROWS 10
#define CON_MSGROWS 4
#define CON_MSGTIMER 3.f
static char conBuf[CON_ROWS][CON_COLS + 1];
static char conInput[CON_COLS + 1];
static char *conVisRows[CON_VISROWS];
static s32 conPrintRow = 0;
static s32 conPrintCol = 0;
static s32 conMsgRows = 0;
static f32 conMsgTimer = 0.f;
static s32 conInputCol = 0;
static u32 conTextColour = 0x00ff00ff;
static s32 conOpen = 0;
static s32 conButton = 0;
void conInit(void)
{
memset(conBuf, 0, sizeof(conBuf));
memset(conInput, 0, sizeof(conInput));
memset(conVisRows, 0, sizeof(conVisRows));
conPrintRow = conPrintCol = 0;
conOpen = 0;
conMsgRows = 0;
conMsgTimer = 0.0f;
conInputCol = 0;
}
void conPrint(s32 showmsg, const char *str)
{
if (!str || !*str) {
return;
}
const s32 oldRow = conPrintRow;
for (const char *s = str; *s; ++s) {
char ch = *s;
switch (ch) {
case '\n':
if (conPrintCol) {
conPrintCol = 0;
conPrintRow = (conPrintRow + 1) % CON_ROWS;
}
break;
case '\r':
break;
case '\t':
ch = ' ';
/* fallthrough */
default:
conBuf[conPrintRow][conPrintCol++] = ch;
if (conPrintCol == CON_COLS) {
conPrintCol = 0;
conPrintRow = (conPrintRow + 1) % CON_ROWS;
}
break;
}
conBuf[conPrintRow][conPrintCol] = '\0';
}
if (conPrintRow != oldRow) {
// scroll time
for (s32 i = 0; i < ARRAYCOUNT(conVisRows); ++i) {
s32 row = conPrintRow - i - 1;
if (row < 0) {
row = CON_ROWS + row;
}
conVisRows[i] = &conBuf[row][0];
}
if (showmsg) {
if (conMsgRows < CON_MSGROWS) {
if (conPrintRow > oldRow) {
conMsgRows += conPrintRow - oldRow;
} else {
conMsgRows += conPrintRow + (CON_ROWS - oldRow);
}
}
conMsgTimer = sysGetSeconds() + CON_MSGTIMER;
}
}
}
void conPrintLn(s32 showmsg, const char *s)
{
char tmp[4096];
snprintf(tmp, sizeof(tmp), "%s\n", s);
conPrint(showmsg, tmp);
}
void conPrintf(s32 showmsg, const char *fmt, ...)
{
char tmp[4096];
tmp[sizeof(tmp) - 1] = '\0';
tmp[0] = '\0';
va_list args;
va_start(args, fmt);
vsnprintf(tmp, sizeof(tmp), fmt, args);
va_end(args);
conPrint(showmsg, tmp);
}
static inline Gfx *conRenderMsgs(Gfx *gdl)
{
if (conMsgRows) {
s32 x, y;
const u32 c = (conTextColour & 0xffffff00) | 0xa0;
for (s32 i = 0; i < conMsgRows; ++i) {
char *s = conVisRows[i];
if (s) {
x = 4;
y = 4 + 8 * (conMsgRows - i - 1);
gdl = textRenderProjected(gdl, &x, &y, s, g_CharsHandelGothicXs, g_FontHandelGothicXs, c, viGetWidth(), viGetHeight(), 0, 0);
}
}
const f32 t = sysGetSeconds();
if (conMsgTimer <= t) {
conMsgTimer = t + CON_MSGTIMER;
--conMsgRows;
}
} else {
conMsgTimer = 0;
}
return gdl;
}
Gfx *conRender(Gfx *gdl)
{
if (!g_CharsHandelGothicXs || !g_FontHandelGothicXs) {
return gdl;
}
gdl = text0f153628(gdl);
if (!conOpen) {
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_LEFT_EXT);
gdl = conRenderMsgs(gdl);
} else {
s32 x, y;
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_CENTER_EXT);
gdl = hudmsgRenderBox(gdl, 16, 0, SCREEN_WIDTH_LO - 16, 4 + 8 * (CON_VISROWS + 1), 1.f, conTextColour, 0.9f);
for (s32 i = 0; i < CON_VISROWS; ++i) {
char *s = conVisRows[i];
if (s) {
x = 18;
y = 4 + 8 * (CON_VISROWS - i - 1);
gdl = textRenderProjected(gdl, &x, &y, s, g_CharsHandelGothicXs, g_FontHandelGothicXs, conTextColour, viGetWidth(), viGetHeight(), 0, 0);
}
}
char tmp[CON_COLS + 3];
snprintf(tmp, sizeof(tmp), "> %s", conInput);
x = 18;
y = 4 + 8 * CON_VISROWS;
gdl = textRenderProjected(gdl, &x, &y, tmp, g_CharsHandelGothicXs, g_FontHandelGothicXs, conTextColour, viGetWidth(), viGetHeight(), 0, 0);
}
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
gdl = text0f153780(gdl);
return gdl;
}
void conTick(void)
{
const s32 button = inputKeyPressed(VK_GRAVE);
if (button && !conButton) {
conOpen = !conOpen;
if (conOpen) {
inputStartTextInput();
} else {
inputStopTextInput();
}
}
conButton = button;
if (conOpen) {
if (inputTextHandler(conInput, CON_COLS, &conInputCol)) {
if (g_NetMode) {
netChat(NULL, conInput);
}
conInput[0] = '\0';
conInputCol = 0;
}
}
}
+361
View File
@@ -0,0 +1,361 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SDL.h>
#include <PR/ultratypes.h>
#include "system.h"
#include "platform.h"
#define CRASH_LOG_FNAME "pd.crash.log"
#define CRASH_MAX_MSG 8192
#define CRASH_MAX_SYM 256
#define CRASH_MAX_FRAMES 32
#define CRASH_MSG(...) \
if (msglen < CRASH_MAX_MSG) msglen += snprintf(msg + msglen, CRASH_MAX_MSG - msglen, __VA_ARGS__)
#if defined(PLATFORM_WIN32)
#include <windows.h>
#include <dbghelp.h>
#include <inttypes.h>
#include <excpt.h>
// NOTE: game builds with gcc, which means we have no PDBs for the windows version
// this means that you generally won't get any symbol names in the main executable
static LPTOP_LEVEL_EXCEPTION_FILTER prevExFilter;
static void *crashGetModuleBase(const void *addr)
{
HMODULE h = NULL;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &h);
return (void *)h;
}
static void crashStackTrace(char *msg, PEXCEPTION_POINTERS exinfo)
{
CONTEXT context = *exinfo->ContextRecord;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
SymSetOptions(SymGetOptions() | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
SymInitialize(process, NULL, TRUE);
STACKFRAME64 stackframe;
memset(&stackframe, 0, sizeof(stackframe));
DWORD image;
#ifdef PLATFORM_X86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif defined(PLATFORM_X86_64)
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#else
snprintf(msg, CRASH_MAX_MSG, "no stack trace available on this arch\n");
return;
#endif
DWORD disp = 0;
DWORD64 disp64 = 0;
IMAGEHLP_LINE64 line;
DWORD msglen = 0;
CRASH_MSG("EXCEPTION: 0x%08lx\n", exinfo->ExceptionRecord->ExceptionCode);
CRASH_MSG("PC: %p", exinfo->ExceptionRecord->ExceptionAddress);
if (SymGetLineFromAddr64(process, (uintptr_t)exinfo->ExceptionRecord->ExceptionAddress, &disp, &line)) {
CRASH_MSG(": %s:%lu+%lu", line.FileName, line.LineNumber, disp);
}
CRASH_MSG("\nMODULE: [%p]\n", crashGetModuleBase(exinfo->ExceptionRecord->ExceptionAddress));
CRASH_MSG("MAIN MODULE: [%p]\n", crashGetModuleBase(crashInit));
CRASH_MSG("\nBACKTRACE:\n");
char symbuf[sizeof(SYMBOL_INFO) + CRASH_MAX_SYM * sizeof(TCHAR)];
PSYMBOL_INFO sym = (PSYMBOL_INFO)symbuf;
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLen = CRASH_MAX_SYM;
s32 i;
for (i = 0; i < CRASH_MAX_FRAMES; ++i) {
const BOOL res = StackWalk64(image, process, thread, &stackframe, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
if (!res) {
break;
}
CRASH_MSG("#%02d: %p", i, (void *)(uintptr_t)stackframe.AddrPC.Offset);
if (SymFromAddr(process, stackframe.AddrPC.Offset, &disp64, sym)) {
CRASH_MSG(": %s+%llu", sym->Name, disp64);
} else if (process, stackframe.AddrPC.Offset) {
const uintptr_t modbase = (uintptr_t)crashGetModuleBase((void *)(uintptr_t)stackframe.AddrPC.Offset);
const uintptr_t modofs = (uintptr_t)stackframe.AddrPC.Offset - modbase;
CRASH_MSG(": [%p]+%p", (void *)modbase, (void *)modofs);
}
if(SymGetLineFromAddr64(process, stackframe.AddrPC.Offset, &disp, &line)) {
CRASH_MSG(" (%s:%lu+%lu)", line.FileName, line.LineNumber, disp);
}
CRASH_MSG("\n");
}
if (i <= 1) {
CRASH_MSG("no information\n");
} else if (i == CRASH_MAX_FRAMES) {
CRASH_MSG("...\n");
}
SymCleanup(process);
}
static long __stdcall crashHandler(PEXCEPTION_POINTERS exinfo)
{
char msg[CRASH_MAX_MSG + 1] = { 0 };
if (IsDebuggerPresent()) {
if (prevExFilter) {
return prevExFilter(exinfo);
}
return EXCEPTION_CONTINUE_EXECUTION;
}
sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p CODE=0x%08lx", exinfo->ExceptionRecord->ExceptionAddress, exinfo->ExceptionRecord->ExceptionCode);
fflush(stderr);
fflush(stdout);
crashStackTrace(msg, exinfo);
// open log file for the crash dump if one hasn't been opened yet
if (!sysLogIsOpen()) {
FILE *f = fopen(CRASH_LOG_FNAME, "wb");
if (f) {
fprintf(f, "Crash!\n\n%s", msg);
fclose(f);
}
}
sysFatalError("Crash!\n\n%s", msg);
return EXCEPTION_CONTINUE_EXECUTION;
}
#elif defined(PLATFORM_LINUX)
#include <ucontext.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
#include <ctype.h>
#include <dlfcn.h>
#include <sys/fcntl.h>
static struct sigaction prevSigAction;
static s32 crashIsDebuggerPresent(void)
{
static s32 result = -1;
if (result >= 0) {
return result;
}
char buf[4096] = { 0 };
int fd = open("/proc/self/status", O_RDONLY);
if (fd < 0) {
result = 0;
return 0;
}
int rx = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (rx <= 0) {
result = 0;
return 0;
}
buf[rx] = 0;
char *str = strstr(buf, "TracerPid:");
if (!str) {
result = 0;
return 0;
}
str += 10;
while (*str && !isdigit(*str)) {
if (*str == '\n') {
result = 0;
return 0;
}
++str;
}
result = (atoi(str) != 0);
return result;
}
static void *crashGetModuleBase(const void *addr)
{
Dl_info info;
if (dladdr(addr, &info)) {
return info.dli_fbase;
}
return NULL;
}
static void crashStackTrace(char *msg, s32 sig, void *pc)
{
u32 msglen = 0;
void *frames[CRASH_MAX_FRAMES] = { NULL };
const s32 nframes = backtrace(frames, CRASH_MAX_FRAMES);
if (nframes <= 0) {
CRASH_MSG("no information\n");
return;
}
char **strings = backtrace_symbols(frames, nframes);
CRASH_MSG("SIGNAL: %d\n", sig);
CRASH_MSG("PC: ");
if (pc) {
CRASH_MSG("%p\n", pc);
} else if (strings) {
CRASH_MSG("%s\n", strings[0]);
} else {
CRASH_MSG("%p\n", frames[0]);
}
CRASH_MSG("MODULE: %p\n", crashGetModuleBase(frames[0]));
CRASH_MSG("MAIN MODULE: %p\n", crashGetModuleBase(crashInit));
CRASH_MSG("\nBACKTRACE:\n");
s32 i;
for (i = 0; i < nframes; ++i) {
CRASH_MSG("#%02d: ", i);
if (strings && strings[i]) {
CRASH_MSG("%s\n", strings[i]);
} else {
CRASH_MSG("%p\n", frames[i]);
}
}
if (i == CRASH_MAX_FRAMES) {
CRASH_MSG("...\n");
} else if (i <= 1) {
CRASH_MSG("no information\n");
}
free(strings);
}
static void crashHandler(s32 sig, siginfo_t *siginfo, void *ctx)
{
char msg[CRASH_MAX_MSG + 1] = { 0 };
if (crashIsDebuggerPresent()) {
return;
}
void *pc = NULL;
if (ctx) {
ucontext_t *ucontext = (ucontext_t *)ctx;
#ifdef PLATFORM_X86
pc = (void *)ucontext->uc_mcontext.gregs[REG_EIP];
#elif defined(PLATFORM_X86_64)
pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP];
#elif defined(PLATFORM_ARM) && defined(PLATFORM_64BIT)
pc = (void *)ucontext->uc_mcontext.pc;
#elif defined(PLATFORM_ARM)
pc = (void *)ucontext->uc_mcontext.arm_pc;
#endif
}
sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p SIGNAL=%d", pc, sig);
fflush(stderr);
fflush(stdout);
crashStackTrace(msg, sig, pc);
sysFatalError("Crash!\n\n%s", msg);
}
#endif
s32 g_CrashEnabled = 0;
static char crashMsg[1024];
void crashInit(void)
{
#ifdef PLATFORM_WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
prevExFilter = SetUnhandledExceptionFilter(crashHandler);
g_CrashEnabled = 1;
#elif defined(PLATFORM_LINUX)
struct sigaction sigact = { 0 };
sigact.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigact.sa_sigaction = crashHandler;
sigaction(SIGSEGV, &sigact, &prevSigAction);
sigaction(SIGABRT, &sigact, &prevSigAction);
sigaction(SIGBUS, &sigact, &prevSigAction);
sigaction(SIGILL, &sigact, &prevSigAction);
g_CrashEnabled = 1;
#endif
}
void crashShutdown(void)
{
if (!g_CrashEnabled) {
return;
}
#ifdef PLATFORM_WIN32
if (prevExFilter) {
SetUnhandledExceptionFilter(prevExFilter);
}
#elif defined(PLATFORM_LINUX)
sigaction(SIGSEGV, &prevSigAction, NULL);
sigaction(SIGABRT, &prevSigAction, NULL);
sigaction(SIGBUS, &prevSigAction, NULL);
sigaction(SIGILL, &prevSigAction, NULL);
#endif
g_CrashEnabled = 0;
}
void crashCreateThread(void)
{
}
void crashSetMessage(char *string)
{
}
void crashReset(void)
{
}
void crashAppendChar(char c)
{
}
+282
View File
@@ -0,0 +1,282 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>
#include <PR/ultratypes.h>
#include "config.h"
#include "system.h"
#include "platform.h"
#include "utils.h"
#include "fs.h"
#define DEFAULT_BASEDIR_NAME "data"
static char baseDir[FS_MAXPATH + 1]; // replaces $B
static char modDir[FS_MAXPATH + 1]; // replaces $M
static char saveDir[FS_MAXPATH + 1]; // replaces $S
static char homeDir[FS_MAXPATH + 1]; // replaces $H
static char exeDir[FS_MAXPATH + 1]; // replaces $E
static s32 fsPathIsWritable(const char *path)
{
#ifdef PLATFORM_WIN32
// on windows access() on directories will only check if the directory exists, so
char tmp[FS_MAXPATH + 1] = { 0 };
snprintf(tmp, sizeof(tmp), "%s/.tmp", path);
FILE *f = fopen(tmp, "wb");
if (f) {
fclose(f);
remove(tmp);
return 1;
}
return 0;
#else
return (access(path, W_OK) == 0);
#endif
}
s32 fsPathIsAbsolute(const char *path)
{
return (path[0] == '/' || (isalpha(path[0]) && path[1] == ':'));
}
s32 fsPathIsCwdRelative(const char *path)
{
// ., .., ./, ../
return (path[0] == '.' && (path[1] == '.' || path[1] == '/' || path[1] == '\\' || path[1] == '\0'));
}
const char *fsFullPath(const char *relPath)
{
static char pathBuf[FS_MAXPATH + 1];
if (relPath[0] == '$') {
// expandable placeholder $X; will be replaced with the corresponding path, if any
const char *expStr = NULL;
switch (relPath[1]) {
case 'E': expStr = exeDir; break;
case 'H': expStr = homeDir; break;
case 'M': expStr = modDir; break;
case 'B': expStr = baseDir; break;
case 'S': expStr = saveDir; break;
default: break;
}
if (expStr) {
const u32 len = strlen(expStr);
if (len > 0) {
memcpy(pathBuf, expStr, len);
strncpy(pathBuf + len, relPath + 2, FS_MAXPATH - len);
return pathBuf;
}
}
// couldn't expand anything, return as is
return relPath;
} else if (!baseDir[0] || fsPathIsAbsolute(relPath) || fsPathIsCwdRelative(relPath)) {
// user explicitly wants working directory or this is an absolute path or we have no baseDir set up yet
return relPath;
}
// path relative to mod or base dir; this will be a read request, so check where the file actually is
if (modDir[0]) {
snprintf(pathBuf, FS_MAXPATH, "%s/%s", modDir, relPath);
if (fsFileSize(pathBuf) >= 0) {
return pathBuf;
}
}
// fall back to basedir
snprintf(pathBuf, FS_MAXPATH, "%s/%s", baseDir, relPath);
return pathBuf;
}
s32 fsInit(void)
{
sysGetExecutablePath(exeDir, FS_MAXPATH);
// if this is set, default to exe path for everything
const s32 portable = sysArgCheck("--portable");
if (portable) {
strcpy(homeDir, exeDir);
} else {
sysGetHomePath(homeDir, FS_MAXPATH);
}
// get path to base dir and expand it if needed
const char *path = sysArgGetString("--basedir");
if (!path) {
// check if there's a `data` directory in working directory or homeDir, otherwise default to exe directory
path = "$E/" DEFAULT_BASEDIR_NAME;
if (!portable) {
if (fsFileSize("./" DEFAULT_BASEDIR_NAME) >= 0) {
path = "./" DEFAULT_BASEDIR_NAME;
} else if (fsFileSize("$H/" DEFAULT_BASEDIR_NAME)) {
path = "$H/" DEFAULT_BASEDIR_NAME;
}
}
}
strncpy(baseDir, fsFullPath(path), FS_MAXPATH);
// get path to mod dir and expand it if needed
// mod directory is overlaid on top of base directory
path = sysArgGetString("--moddir");
if (path) {
if (fsPathIsAbsolute(path) || fsPathIsCwdRelative(path) || path[0] == '$') {
// path is explicit; check as-is
if (fsFileSize(path) >= 0) {
strncpy(modDir, fsFullPath(path), FS_MAXPATH);
}
} else {
// path is relative to workdir; try to find it
const char *priority[] = { ".", "$E", "$H" };
for (s32 i = 0; i < 2 + (portable != 0); ++i) {
char *tmp = strFmt("%s/%s", priority[i], path);
if (fsFileSize(tmp) >= 0) {
strncpy(modDir, fsFullPath(tmp), FS_MAXPATH);
break;
}
}
}
if (!modDir[0]) {
sysLogPrintf(LOG_WARNING, "could not find specified moddir `%s`", path);
}
}
// get path to save dir and expand it if needed
path = sysArgGetString("--savedir");
if (!path) {
if (portable) {
path = "$E";
} else {
#ifdef PLATFORM_LINUX
// check if there's a config in the working directory, otherwise default to homeDir
if (fsFileSize("./" CONFIG_FNAME) >= 0) {
path = ".";
} else {
path = "$H";
}
#else
// check if working directory is writable, otherwise default to homeDir
if (fsPathIsWritable("./")) {
path = ".";
} else {
sysLogPrintf(LOG_WARNING, "cannot write to working directory, will use %s for saves instead", homeDir);
path = "$H";
}
#endif
}
}
strncpy(saveDir, fsFullPath(path), FS_MAXPATH);
if (modDir[0]) {
sysLogPrintf(LOG_NOTE, " mod dir: %s", modDir);
}
sysLogPrintf(LOG_NOTE, "base dir: %s", baseDir);
sysLogPrintf(LOG_NOTE, "save dir: %s", saveDir);
return 0;
}
const char *fsGetModDir(void)
{
return modDir[0] ? modDir : NULL;
}
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize)
{
const char *fullName = fsFullPath(name);
FILE *f = fopen(fullName, "rb");
if (!f) {
return -1;
}
fseek(f, 0, SEEK_END);
const s32 size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 0) {
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: empty file or invalid size (%d): %s", size, fullName);
fclose(f);
return -1;
}
if ((u32)size > dstSize) {
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: file too big for buffer (%u > %u): %s", size, dstSize, fullName);
fclose(f);
return -1;
}
fread(dst, 1, size, f);
fclose(f);
return size;
}
void *fsFileLoad(const char *name, u32 *outSize)
{
const char *fullName = fsFullPath(name);
FILE *f = fopen(fullName, "rb");
if (!f) {
sysLogPrintf(LOG_ERROR, "fsFileLoad: could not find file: %s", fullName);
return NULL;
}
fseek(f, 0, SEEK_END);
const s32 size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 0) {
sysLogPrintf(LOG_ERROR, "fsFileLoad: empty file or invalid size (%d): %s", size, fullName);
fclose(f);
return NULL;
}
void *buf = NULL;
if (size) {
buf = sysMemZeroAlloc(size + 1); // sick hack for a free null terminator
if (!buf) {
sysLogPrintf(LOG_ERROR, "fsFileLoad: could not alloc %d bytes for file: %s", size, fullName);
fclose(f);
return NULL;
}
fread(buf, 1, size, f);
}
fclose(f);
if (outSize) {
*outSize = size;
}
return buf;
}
s32 fsFileSize(const char *name)
{
const char *fullName = fsFullPath(name);
struct stat st;
if (stat(fullName, &st) < 0) {
return -1;
} else {
return st.st_size;
}
}
FILE *fsFileOpenWrite(const char *name)
{
return fopen(fsFullPath(name), "wb");
}
FILE *fsFileOpenRead(const char *name)
{
return fopen(fsFullPath(name), "rb");
}
void fsFileClose(FILE *f)
{
fclose(f);
}
+1398
View File
File diff suppressed because it is too large. Load diff
+488
View File
@@ -0,0 +1,488 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <PR/os_internal.h>
#include <PR/rcp.h>
#include "system.h"
#include "input.h"
#include "video.h"
#include "audio.h"
#include "fs.h"
#define EEPROM_SIZE (EEP16K_MAXBLOCKS * 8)
#define EEPROM_FNAME "eeprom.bin"
#define EEPROM_PATH "$S/" EEPROM_FNAME
#define OS_COUNTER_RATE 46875000ULL
#define OS_COUNTER_NUM (OS_COUNTER_RATE / 1000ULL)
#define OS_COUNTER_DEN (1000000ULL / 1000ULL)
u64 osClockRate = OS_CLOCK_RATE;
u32 osMemSize = 16 * 1024 * 1024; /* expansion pak installed plus some extra */
s32 osTvType = OS_TV_NTSC; /* 0 = PAL, 1 = NTSC, 2 = MPAL */
s32 osResetType = 0; /* 0 = cold reset */
s32 osViClock = VI_NTSC_CLOCK;
static u8 eeprom[EEPROM_SIZE];
static char eepromPath[FS_MAXPATH + 1];
static s32 eepromLoaded = 0;
/* Time */
OSTime osGetTime(void)
{
// u64 should be enough to last a while
return (sysGetMicroseconds() * OS_COUNTER_NUM) / OS_COUNTER_DEN;
}
u32 osGetCount(void)
{
return (u32)osGetTime();
}
/* Thread */
void osCreateThread(OSThread *thrd, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri p)
{
thrd->id = id;
thrd->state = OS_STATE_STOPPED;
}
void osDestroyThread(OSThread *thrd)
{
thrd->id = 0;
thrd->state = 0;
}
void osYieldThread(void)
{
}
void osStartThread(OSThread *thrd)
{
thrd->state = OS_STATE_RUNNING;
}
void osStopThread(OSThread *thrd)
{
thrd->state = OS_STATE_STOPPED;
}
OSPri osGetThreadPri(OSThread *thrd)
{
return 0;
}
void osSetThreadPri(OSThread *thrd, OSPri pri)
{
}
/* Mesg */
void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *msgBuf, s32 count)
{
mq->validCount = 0;
mq->first = 0;
mq->msgCount = count;
mq->msg = msgBuf;
}
void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg)
{
}
s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flag)
{
return 0;
}
s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flag)
{
return 0;
}
/* Vi */
void osCreateViManager(OSPri pri)
{
}
void osViSetMode(OSViMode *mode)
{
}
void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount)
{
}
void osViBlack(u8 active)
{
if (active) {
videoClearScreen();
}
}
void osViSetSpecialFeatures(u32 func)
{
}
void osViSwapBuffer(void *vaddr)
{
}
void osViSetXScale(f32 value)
{
}
void osViSetYScale(f32 value)
{
}
/* Ai */
s32 osAiSetFrequency(u32 frequency)
{
// we can allow for any freq
return (s32)frequency;
}
u32 osAiGetLength(void)
{
return audioGetBytesBuffered();
}
s32 osAiSetNextBuffer(void *bufPtr, u32 size)
{
audioSetNextBuffer(bufPtr, size);
return 0;
}
/* Cont */
s32 osContInit(OSMesgQueue *mesgq, u8 *bitpattern, OSContStatus *data)
{
if (bitpattern) {
*bitpattern = inputControllerMask();
}
if (data) {
osContGetQuery(data);
}
return 0;
}
s32 osContStartReadData(OSMesgQueue *mesgq)
{
osSendMesg(mesgq, (OSMesg)0, OS_MESG_NOBLOCK);
return 0;
}
void osContGetReadData(OSContPad *pad)
{
// game always passes in an array of 4 OSContPads
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++pad) {
pad->button = 0;
pad->stick_x = 0;
pad->stick_y = 0;
pad->rstick_x = 0;
pad->rstick_y = 0;
if (inputReadController(i, pad) < 0) {
pad->errnum = CONT_NO_RESPONSE_ERROR;
} else {
pad->errnum = 0;
}
}
}
s32 osContStartQuery(OSMesgQueue *mq)
{
return 0;
}
void osContGetQuery(OSContStatus *status)
{
// also always 4 status structs here
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++status) {
if (inputControllerConnected(i)) {
status->errnum = 0;
status->type = CONT_ABSOLUTE;
status->status = CONT_CARD_ON;
} else {
status->errnum = CONT_NO_RESPONSE_ERROR;
status->type = 0;
status->status = 0;
}
}
}
/* Motor */
s32 osMotorProbe(OSMesgQueue *ctrlrqueue, OSPfs* pfs, s32 channel)
{
if (pfs && inputRumbleSupported(channel)) {
pfs->queue = ctrlrqueue;
pfs->channel = channel;
pfs->activebank = 0xff;
pfs->status = PFS_MOTOR_INITIALIZED;
return 0;
}
return PFS_ERR_NOPACK;
}
s32 __osMotorAccess(OSPfs *pfs, s32 cmd)
{
if (!pfs || pfs->channel < 0 || pfs->channel >= INPUT_MAX_CONTROLLERS) {
return PFS_ERR_NOPACK;
}
const f32 strength = (f32)(cmd == MOTOR_START);
inputRumble(pfs->channel, strength, 5.f); // hope someone turns it off in those 5 seconds
return 0;
}
/* Eeprom */
static inline void osEepromSetPath(void)
{
const char *extPath = sysArgGetString("--eeprom-file");
if (extPath && extPath[0]) {
if (extPath[0] == '$' || fsPathIsAbsolute(extPath) || fsPathIsCwdRelative(extPath)) {
strncpy(eepromPath, extPath, FS_MAXPATH);
} else {
// just a filename, look for it in the save dir
snprintf(eepromPath, FS_MAXPATH, "$S/%s", extPath);
}
} else {
strncpy(eepromPath, EEPROM_PATH, FS_MAXPATH);
}
}
static inline void osEeepromLoad(const char *fname)
{
if (!eepromLoaded) {
eepromLoaded = 1;
FILE *fp = fsFileOpenRead(fname);
if (fp) {
fread(eeprom, 1, EEPROM_SIZE, fp);
fsFileClose(fp);
} else {
sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno));
}
}
}
static inline void osEeepromSave(const char *fname)
{
FILE* fp = fsFileOpenWrite(fname);
if (fp) {
fwrite(eeprom, 1, EEPROM_SIZE, fp);
fsFileClose(fp);
} else {
sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno));
}
}
s32 osEepromProbe(OSMesgQueue *mq)
{
return EEPROM_TYPE_16K;
}
s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
{
if (!eepromPath[0]) {
osEepromSetPath();
}
osEeepromLoad(eepromPath);
memcpy(buffer, eeprom + address * 8, nbytes);
return 0;
}
s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
{
if (!eepromPath[0]) {
osEepromSetPath();
}
osEeepromLoad(eepromPath);
memcpy(eeprom + address * 8, buffer, nbytes);
osEeepromSave(eepromPath);
return 0;
}
/* Pfs */
s32 osPfsIsPlug(OSMesgQueue *queue, u8 *pattern)
{
if (pattern) {
*pattern = 0;
for (s32 i = 0; i < MAXCONTROLLERS; ++i) {
if (inputRumbleSupported(i)) {
*pattern |= 1 << i;
}
}
}
return 0;
}
s32 osPfsInitPak(OSMesgQueue *queue, OSPfs *pfs, s32 channel, s32 *arg3)
{
// if rumble is supported, indicate that we have a rumble pak instead
return inputRumbleSupported(channel) ? PFS_ERR_DEVICE : PFS_ERR_NOPACK;
}
s32 osPfsChecker(OSPfs *pfs)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFreeBlocks(OSPfs *pfs, s32 *remaining)
{
return PFS_ERR_NOPACK;
}
s32 osPfsNumFiles(OSPfs *pfs, s32 *max_files, s32 *files_used)
{
return PFS_ERR_NOPACK;
}
s32 osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int num_bytes, s32 *file_no)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFindFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, s32 *file_no)
{
return PFS_ERR_NOPACK;
}
s32 osPfsDeleteFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name)
{
return PFS_ERR_NOPACK;
}
s32 osPfsReSizeFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int length)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFileState(OSPfs *pfs, s32 fileNo, OSPfsState *state)
{
return PFS_ERR_NOPACK;
}
s32 osPfsReadWriteFile(OSPfs* pfs, s32 fileNo, u8 flag, int offset, int size, u8* data)
{
return PFS_ERR_NOPACK;
}
/* Gbpak */
s32 osGbpakInit(OSMesgQueue *queue, OSPfs *pfs, s32 ch)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakPower(OSPfs *pfs, s32 flag)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakReadWrite(OSPfs *pfs, u16 flag, u16 addr, u8 *buf, u16 size)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakReadId(OSPfs *pfs, OSGbpakId *id, u8 *status)
{
return PFS_ERR_NOPACK;
}
/* Misc */
void osWritebackDCacheAll(void)
{
}
void osWritebackDCache(void *a, s32 b)
{
}
void osInvalDCache(void *a, s32 b)
{
}
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, size_t nbytes, OSMesgQueue *mq)
{
memcpy(vAddr, (const void *)devAddr, nbytes);
return 0;
}
s32 osPiReadIo(u32 devaddr, u32 *data)
{
return 0;
}
uintptr_t osVirtualToPhysical(void *addr)
{
return (uintptr_t)addr;
}
u32 osGetMemSize(void)
{
return osMemSize;
}
OSIntMask osGetIntMask(void)
{
return 0;
}
OSIntMask osSetIntMask(OSIntMask mask)
{
return 0;
}
/* libc compatibility wrappers */
#ifndef HAVE_BZERO
void bzero(void *ptr, size_t size)
{
memset(ptr, 0, size);
}
#endif
#ifndef HAVE_BCOPY
void bcopy(const void *src, void *dst, size_t n)
{
memcpy(dst, src, n);
}
#endif
#ifndef HAVE_BCMP
s32 bcmp(const void *s1, const void *s2, size_t n)
{
return memcmp(s1, s2, n);
}
#endif
+198
View File
@@ -0,0 +1,198 @@
#include <stdlib.h>
#include <stdio.h>
#include <PR/ultratypes.h>
#include <PR/ultrasched.h>
#include <PR/os_message.h>
#include "lib/main.h"
#include "bss.h"
#include "data.h"
#include "video.h"
#include "audio.h"
#include "input.h"
#include "fs.h"
#include "romdata.h"
#include "config.h"
#include "mod.h"
#include "system.h"
#include "console.h"
#include "utils.h"
#include "net/net.h"
u32 g_OsMemSize = 0;
s32 g_OsMemSizeMb = 16;
u8 g_Is4Mb = 0;
s8 g_Resetting = false;
OSSched g_Sched;
OSMesgQueue g_MainMesgQueue;
OSMesg g_MainMesgBuf[32];
u8 *g_MempHeap = NULL;
u32 g_MempHeapSize = 0;
u32 g_VmNumTlbMisses = 0;
u32 g_VmNumPageMisses = 0;
u32 g_VmNumPageReplaces = 0;
u8 g_VmShowStats = 0;
s32 g_TickRateDiv = 1;
s32 g_TickExtraSleep = true;
s32 g_SkipIntro = false;
s32 g_FileAutoSelect = -1;
extern s32 g_StageNum;
s32 bootGetMemSize(void)
{
return (s32)g_OsMemSize;
}
void *bootAllocateStack(s32 threadid, s32 size)
{
static u8 bruh[0x1000];
return bruh;
}
void bootCreateSched(void)
{
osCreateMesgQueue(&g_MainMesgQueue, g_MainMesgBuf, ARRAYCOUNT(g_MainMesgBuf));
if (osTvType == OS_TV_MPAL) {
osCreateScheduler(&g_Sched, NULL, OS_VI_MPAL_LAN1, 1);
} else {
osCreateScheduler(&g_Sched, NULL, OS_VI_NTSC_LAN1, 1);
}
}
static void gameInit(void)
{
osMemSize = g_OsMemSizeMb * 1024 * 1024;
for (s32 i = 0; i < MAX_LOCAL_PLAYERS; ++i) {
struct extplayerconfig *cfg = g_PlayerExtCfg + i;
cfg->fovzoommult = cfg->fovzoom ? cfg->fovy / 60.0f : 1.0f;
}
if (g_HudCenter == HUDCENTER_NORMAL) {
g_HudAlignModeL = G_ASPECT_CENTER_EXT;
g_HudAlignModeR = G_ASPECT_CENTER_EXT;
} else if (g_HudCenter == HUDCENTER_WIDE) {
g_HudAlignModeL = G_ASPECT_LEFT_EXT | G_ASPECT_WIDE_EXT;
g_HudAlignModeR = G_ASPECT_RIGHT_EXT | G_ASPECT_WIDE_EXT;
}
}
static void cleanup(void)
{
sysLogPrintf(LOG_NOTE, "shutdown");
netDisconnect();
inputSaveBinds();
configSave(CONFIG_PATH);
crashShutdown();
// TODO: actually shut down all subsystems
}
int main(int argc, const char **argv)
{
sysInitArgs(argc, argv);
if (!sysArgCheck("--no-crash-handler")) {
crashInit();
}
conInit();
sysInit();
fsInit();
configInit();
videoInit();
inputInit();
audioInit();
romdataInit();
netInit();
gameInit();
if (fsGetModDir()) {
modConfigLoad(MOD_CONFIG_FNAME);
}
atexit(cleanup);
bootCreateSched();
g_OsMemSize = osGetMemSize();
g_MempHeapSize = g_OsMemSize;
g_MempHeap = sysMemZeroAlloc(g_MempHeapSize);
if (!g_MempHeap) {
sysFatalError("Could not alloc %u bytes for memp heap.", g_MempHeapSize);
}
sysLogPrintf(LOG_NOTE, "memp heap at %p - %p", g_MempHeap, g_MempHeap + g_MempHeapSize);
sysLogPrintf(LOG_NOTE, "rom file at %p - %p", g_RomFile, g_RomFile + g_RomFileSize);
g_SndDisabled = sysArgCheck("--no-sound");
g_StageNum = sysArgGetInt("--boot-stage", STAGE_TITLE);
g_FileAutoSelect = sysArgGetInt("--profile", -1);
if (g_StageNum == STAGE_TITLE && (sysArgCheck("--skip-intro") || g_SkipIntro)) {
// shorthand for --boot-stage 0x26
g_StageNum = STAGE_CITRAINING;
} else if (g_StageNum < 0x01 || g_StageNum > 0x5d) {
// stage num out of range
g_StageNum = STAGE_TITLE;
}
if (g_NetJoinLatch || g_NetHostLatch) {
if (g_FileAutoSelect < 0) {
// default to profile 0 if going into a net game
g_FileAutoSelect = 0;
}
// skip the intro if going into a net game
g_StageNum = STAGE_CITRAINING;
}
if (g_StageNum != STAGE_TITLE) {
sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum);
}
if (g_FileAutoSelect >= 0) {
sysLogPrintf(LOG_NOTE, "player profile set to %d", g_FileAutoSelect);
}
mainProc();
return 0;
}
PD_CONSTRUCTOR static void gameConfigInit(void)
{
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2);
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1);
configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1);
configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1);
configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1);
for (s32 j = 0; j < MAX_LOCAL_PLAYERS; ++j) {
const s32 i = j + 1;
configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f);
configRegisterInt(strFmt("Game.Player%d.FovAffectsZoom", i), &g_PlayerExtCfg[j].fovzoom, 0, 1);
configRegisterInt(strFmt("Game.Player%d.MouseAimMode", i), &g_PlayerExtCfg[j].mouseaimmode, 0, 1);
configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedX", i), &g_PlayerExtCfg[j].mouseaimspeedx, 0.f, 10.f);
configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedY", i), &g_PlayerExtCfg[j].mouseaimspeedy, 0.f, 10.f);
configRegisterFloat(strFmt("Game.Player%d.RadialMenuSpeed", i), &g_PlayerExtCfg[j].radialmenuspeed, 0.f, 10.f);
configRegisterFloat(strFmt("Game.Player%d.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f);
configRegisterInt(strFmt("Game.Player%d.CrouchMode", i), &g_PlayerExtCfg[j].crouchmode, 0, CROUCHMODE_TOGGLE_ANALOG);
configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1);
configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF);
configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4);
configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE);
}
}
+721
View File
@@ -0,0 +1,721 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <ultra64.h>
#include "mixer.h"
#include "platform.h"
#include "external/minimp3.h"
#ifdef __SSE4_1__
#include <immintrin.h>
#define HAS_SSE41 1
#define HAS_NEON 0
#elif __ARM_NEON
#include <arm_neon.h>
#define HAS_SSE41 0
#define HAS_NEON 1
#else
#define HAS_SSE41 0
#define HAS_NEON 0
#endif
#pragma GCC optimize ("unroll-loops")
#if HAS_SSE41
#define LOADLH(l, h) _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd((const double *)(l)), (const double *)(h)))
#endif
#define ROUND_UP_64(v) (((v) + 63) & ~63)
#define ROUND_UP_32(v) (((v) + 31) & ~31)
#define ROUND_UP_16(v) (((v) + 15) & ~15)
#define ROUND_UP_8(v) (((v) + 7) & ~7)
#define ROUND_DOWN_16(v) ((v) & ~0xf)
#define BUF_SIZE 3072 // 2720 + slack
#define BUF_U8(a) (rspa.buf.as_u8 + (a))
#define BUF_S16(a) (rspa.buf.as_s16 + (a) / sizeof(int16_t))
#define NUM_SAMPLES 0xB8
#define NUM_BYTES 0x170
#define OFS_BASE 0
#define OFS_TEMP1 0x170
#define OFS_MAIN_L 0x4E0
#define OFS_MAIN_R 0x650
#define OFS_AUX_L 0x7C0
#define OFS_AUX_R 0x930
static struct {
int16_t vol[2];
int16_t target[2];
int32_t rate[2];
int16_t vol_dry;
int16_t vol_wet;
ADPCM_STATE *adpcm_loop_state;
int16_t adpcm_table[8][2][8];
union {
int16_t as_s16[BUF_SIZE / sizeof(int16_t)];
uint8_t as_u8[BUF_SIZE];
} buf;
} rspa;
static int16_t resample_table[64][4] = {
{0x0c39, 0x66ad, 0x0d46, 0xffdf}, {0x0b39, 0x6696, 0x0e5f, 0xffd8},
{0x0a44, 0x6669, 0x0f83, 0xffd0}, {0x095a, 0x6626, 0x10b4, 0xffc8},
{0x087d, 0x65cd, 0x11f0, 0xffbf}, {0x07ab, 0x655e, 0x1338, 0xffb6},
{0x06e4, 0x64d9, 0x148c, 0xffac}, {0x0628, 0x643f, 0x15eb, 0xffa1},
{0x0577, 0x638f, 0x1756, 0xff96}, {0x04d1, 0x62cb, 0x18cb, 0xff8a},
{0x0435, 0x61f3, 0x1a4c, 0xff7e}, {0x03a4, 0x6106, 0x1bd7, 0xff71},
{0x031c, 0x6007, 0x1d6c, 0xff64}, {0x029f, 0x5ef5, 0x1f0b, 0xff56},
{0x022a, 0x5dd0, 0x20b3, 0xff48}, {0x01be, 0x5c9a, 0x2264, 0xff3a},
{0x015b, 0x5b53, 0x241e, 0xff2c}, {0x0101, 0x59fc, 0x25e0, 0xff1e},
{0x00ae, 0x5896, 0x27a9, 0xff10}, {0x0063, 0x5720, 0x297a, 0xff02},
{0x001f, 0x559d, 0x2b50, 0xfef4}, {0xffe2, 0x540d, 0x2d2c, 0xfee8},
{0xffac, 0x5270, 0x2f0d, 0xfedb}, {0xff7c, 0x50c7, 0x30f3, 0xfed0},
{0xff53, 0x4f14, 0x32dc, 0xfec6}, {0xff2e, 0x4d57, 0x34c8, 0xfebd},
{0xff0f, 0x4b91, 0x36b6, 0xfeb6}, {0xfef5, 0x49c2, 0x38a5, 0xfeb0},
{0xfedf, 0x47ed, 0x3a95, 0xfeac}, {0xfece, 0x4611, 0x3c85, 0xfeab},
{0xfec0, 0x4430, 0x3e74, 0xfeac}, {0xfeb6, 0x424a, 0x4060, 0xfeaf},
{0xfeaf, 0x4060, 0x424a, 0xfeb6}, {0xfeac, 0x3e74, 0x4430, 0xfec0},
{0xfeab, 0x3c85, 0x4611, 0xfece}, {0xfeac, 0x3a95, 0x47ed, 0xfedf},
{0xfeb0, 0x38a5, 0x49c2, 0xfef5}, {0xfeb6, 0x36b6, 0x4b91, 0xff0f},
{0xfebd, 0x34c8, 0x4d57, 0xff2e}, {0xfec6, 0x32dc, 0x4f14, 0xff53},
{0xfed0, 0x30f3, 0x50c7, 0xff7c}, {0xfedb, 0x2f0d, 0x5270, 0xffac},
{0xfee8, 0x2d2c, 0x540d, 0xffe2}, {0xfef4, 0x2b50, 0x559d, 0x001f},
{0xff02, 0x297a, 0x5720, 0x0063}, {0xff10, 0x27a9, 0x5896, 0x00ae},
{0xff1e, 0x25e0, 0x59fc, 0x0101}, {0xff2c, 0x241e, 0x5b53, 0x015b},
{0xff3a, 0x2264, 0x5c9a, 0x01be}, {0xff48, 0x20b3, 0x5dd0, 0x022a},
{0xff56, 0x1f0b, 0x5ef5, 0x029f}, {0xff64, 0x1d6c, 0x6007, 0x031c},
{0xff71, 0x1bd7, 0x6106, 0x03a4}, {0xff7e, 0x1a4c, 0x61f3, 0x0435},
{0xff8a, 0x18cb, 0x62cb, 0x04d1}, {0xff96, 0x1756, 0x638f, 0x0577},
{0xffa1, 0x15eb, 0x643f, 0x0628}, {0xffac, 0x148c, 0x64d9, 0x06e4},
{0xffb6, 0x1338, 0x655e, 0x07ab}, {0xffbf, 0x11f0, 0x65cd, 0x087d},
{0xffc8, 0x10b4, 0x6626, 0x095a}, {0xffd0, 0x0f83, 0x6669, 0x0a44},
{0xffd8, 0x0e5f, 0x6696, 0x0b39}, {0xffdf, 0x0d46, 0x66ad, 0x0c39}
};
static inline int16_t clamp16(int32_t v) {
if (v < -0x8000) {
return -0x8000;
} else if (v > 0x7fff) {
return 0x7fff;
}
return (int16_t)v;
}
static inline int32_t clamp32(int64_t v) {
if (v < -0x7fffffff - 1) {
return -0x7fffffff - 1;
} else if (v > 0x7fffffff) {
return 0x7fffffff;
}
return (int32_t)v;
}
void aClearBufferImpl(uint16_t addr, int nbytes) {
nbytes = ROUND_UP_16(nbytes);
memset(BUF_U8(addr), 0, nbytes);
}
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) {
memcpy(BUF_U8(dest_addr), source_addr, ROUND_UP_8(nbytes));
}
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
memcpy(dest_addr, BUF_S16(source_addr), ROUND_UP_8(nbytes));
}
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr) {
memcpy(rspa.adpcm_table, book_source_addr, num_entries_times_16);
}
void aInterleaveImpl(void) {
const int16_t *l = BUF_S16(OFS_MAIN_L);
const int16_t *r = BUF_S16(OFS_MAIN_R);
int count = ROUND_UP_16(NUM_SAMPLES) / 8;
int16_t *d = BUF_S16(OFS_BASE);
while (count > 0) {
int16_t l0 = *l++;
int16_t l1 = *l++;
int16_t l2 = *l++;
int16_t l3 = *l++;
int16_t l4 = *l++;
int16_t l5 = *l++;
int16_t l6 = *l++;
int16_t l7 = *l++;
int16_t r0 = *r++;
int16_t r1 = *r++;
int16_t r2 = *r++;
int16_t r3 = *r++;
int16_t r4 = *r++;
int16_t r5 = *r++;
int16_t r6 = *r++;
int16_t r7 = *r++;
*d++ = l0;
*d++ = r0;
*d++ = l1;
*d++ = r1;
*d++ = l2;
*d++ = r2;
*d++ = l3;
*d++ = r3;
*d++ = l4;
*d++ = r4;
*d++ = l5;
*d++ = r5;
*d++ = l6;
*d++ = r6;
*d++ = l7;
*d++ = r7;
--count;
}
}
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes) {
memmove(BUF_U8(out_addr), BUF_U8(in_addr), ROUND_UP_16(nbytes));
}
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state) {
rspa.adpcm_loop_state = adpcm_loop_state;
}
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state, int nbytes, uint16_t inofs, uint16_t outofs) {
#if HAS_SSE41
const __m128i tblrev = _mm_setr_epi8(12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, -1, -1);
const __m128i pos0 = _mm_set_epi8(3, -1, 3, -1, 2, -1, 2, -1, 1, -1, 1, -1, 0, -1, 0, -1);
const __m128i pos1 = _mm_set_epi8(7, -1, 7, -1, 6, -1, 6, -1, 5, -1, 5, -1, 4, -1, 4, -1);
const __m128i mult = _mm_set_epi16(0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01);
const __m128i mask = _mm_set1_epi16((int16_t)0xf000);
#elif HAS_NEON
static const int8_t pos0_data[] = {-1, 0, -1, 0, -1, 1, -1, 1, -1, 2, -1, 2, -1, 3, -1, 3};
static const int8_t pos1_data[] = {-1, 4, -1, 4, -1, 5, -1, 5, -1, 6, -1, 6, -1, 7, -1, 7};
static const int16_t mult_data[] = {0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10};
static const int16_t table_prefix_data[] = {0, 0, 0, 0, 0, 0, 0, 1 << 11};
const int8x16_t pos0 = vld1q_s8(pos0_data);
const int8x16_t pos1 = vld1q_s8(pos1_data);
const int16x8_t mult = vld1q_s16(mult_data);
const int16x8_t mask = vdupq_n_s16((int16_t)0xf000);
const int16x8_t table_prefix = vld1q_s16(table_prefix_data);
#endif
uint8_t *in = BUF_U8(inofs);
int16_t *out = BUF_S16(outofs);
nbytes = ROUND_UP_32(nbytes);
if (flags & A_INIT) {
memset(out, 0, 16 * sizeof(int16_t));
} else if (flags & A_LOOP) {
memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t));
} else {
memcpy(out, state, 16 * sizeof(int16_t));
}
out += 16;
#if HAS_SSE41
__m128i prev_interleaved = _mm_set1_epi32((uint16_t)out[-2] | ((uint16_t)out[-1] << 16));
//__m128i prev_interleaved = _mm_shuffle_epi32(_mm_loadu_si32(out - 2), 0); // GCC misses this?
#elif HAS_NEON
int16x8_t result = vld1q_s16(out - 8);
#endif
while (nbytes > 0) {
int shift = *in >> 4; // should be in 0..12
int table_index = *in++ & 0xf; // should be in 0..7
int16_t (*tbl)[8] = rspa.adpcm_table[table_index];
int i;
#if HAS_SSE41
// The _mm_loadu_si64 instruction was added in GCC 9, and results in the same
// asm as the following instructions, so better be compatible with old GCC.
//__m128i inv = _mm_loadu_si64(in);
uint64_t v; memcpy(&v, in, 8);
__m128i inv = _mm_set_epi64x(0, v);
__m128i invec[2] = {_mm_shuffle_epi8(inv, pos0), _mm_shuffle_epi8(inv, pos1)};
__m128i tblvec0 = _mm_loadu_si128((const __m128i *)tbl[0]);
__m128i tblvec1 = _mm_loadu_si128((const __m128i *)(tbl[1]));
__m128i tbllo = _mm_unpacklo_epi16(tblvec0, tblvec1);
__m128i tblhi = _mm_unpackhi_epi16(tblvec0, tblvec1);
__m128i shiftcount = _mm_set_epi64x(0, 12 - shift); // _mm_cvtsi64_si128 does not exist on 32-bit x86
__m128i tblvec1_rev[8];
tblvec1_rev[0] = _mm_insert_epi16(_mm_shuffle_epi8(tblvec1, tblrev), 1 << 11, 7);
tblvec1_rev[1] = _mm_bsrli_si128(tblvec1_rev[0], 2);
tblvec1_rev[2] = _mm_bsrli_si128(tblvec1_rev[0], 4);
tblvec1_rev[3] = _mm_bsrli_si128(tblvec1_rev[0], 6);
tblvec1_rev[4] = _mm_bsrli_si128(tblvec1_rev[0], 8);
tblvec1_rev[5] = _mm_bsrli_si128(tblvec1_rev[0], 10);
tblvec1_rev[6] = _mm_bsrli_si128(tblvec1_rev[0], 12);
tblvec1_rev[7] = _mm_bsrli_si128(tblvec1_rev[0], 14);
in += 8;
for (i = 0; i < 2; i++) {
__m128i acc0 = _mm_madd_epi16(prev_interleaved, tbllo);
__m128i acc1 = _mm_madd_epi16(prev_interleaved, tblhi);
__m128i muls[8];
__m128i result;
invec[i] = _mm_sra_epi16(_mm_and_si128(_mm_mullo_epi16(invec[i], mult), mask), shiftcount);
muls[7] = _mm_madd_epi16(tblvec1_rev[0], invec[i]);
muls[6] = _mm_madd_epi16(tblvec1_rev[1], invec[i]);
muls[5] = _mm_madd_epi16(tblvec1_rev[2], invec[i]);
muls[4] = _mm_madd_epi16(tblvec1_rev[3], invec[i]);
muls[3] = _mm_madd_epi16(tblvec1_rev[4], invec[i]);
muls[2] = _mm_madd_epi16(tblvec1_rev[5], invec[i]);
muls[1] = _mm_madd_epi16(tblvec1_rev[6], invec[i]);
muls[0] = _mm_madd_epi16(tblvec1_rev[7], invec[i]);
acc0 = _mm_add_epi32(acc0, _mm_hadd_epi32(_mm_hadd_epi32(muls[0], muls[1]), _mm_hadd_epi32(muls[2], muls[3])));
acc1 = _mm_add_epi32(acc1, _mm_hadd_epi32(_mm_hadd_epi32(muls[4], muls[5]), _mm_hadd_epi32(muls[6], muls[7])));
acc0 = _mm_srai_epi32(acc0, 11);
acc1 = _mm_srai_epi32(acc1, 11);
result = _mm_packs_epi32(acc0, acc1);
_mm_storeu_si128((__m128i *)out, result);
out += 8;
prev_interleaved = _mm_shuffle_epi32(result, _MM_SHUFFLE(3, 3, 3, 3));
}
#elif HAS_NEON
int8x8_t inv = vld1_s8((int8_t *)in);
int16x8_t tblvec[2] = {vld1q_s16(tbl[0]), vld1q_s16(tbl[1])};
int16x8_t invec[2] = {vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(inv, vget_low_s8(pos0)),
vtbl1_s8(inv, vget_high_s8(pos0)))),
vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(inv, vget_low_s8(pos1)),
vtbl1_s8(inv, vget_high_s8(pos1))))};
int16x8_t shiftcount = vdupq_n_s16(shift - 12); // negative means right shift
int16x8_t tblvec1[8];
in += 8;
tblvec1[0] = vextq_s16(table_prefix, tblvec[1], 7);
invec[0] = vmulq_s16(invec[0], mult);
tblvec1[1] = vextq_s16(table_prefix, tblvec[1], 6);
invec[1] = vmulq_s16(invec[1], mult);
tblvec1[2] = vextq_s16(table_prefix, tblvec[1], 5);
tblvec1[3] = vextq_s16(table_prefix, tblvec[1], 4);
invec[0] = vandq_s16(invec[0], mask);
tblvec1[4] = vextq_s16(table_prefix, tblvec[1], 3);
invec[1] = vandq_s16(invec[1], mask);
tblvec1[5] = vextq_s16(table_prefix, tblvec[1], 2);
tblvec1[6] = vextq_s16(table_prefix, tblvec[1], 1);
invec[0] = vqshlq_s16(invec[0], shiftcount);
invec[1] = vqshlq_s16(invec[1], shiftcount);
tblvec1[7] = table_prefix;
for (i = 0; i < 2; i++) {
int32x4_t acc0;
int32x4_t acc1;
acc1 = vmull_lane_s16(vget_high_s16(tblvec[0]), vget_high_s16(result), 2);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec[1]), vget_high_s16(result), 3);
acc0 = vmull_lane_s16(vget_low_s16(tblvec[0]), vget_high_s16(result), 2);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec[1]), vget_high_s16(result), 3);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[0]), vget_low_s16(invec[i]), 0);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[1]), vget_low_s16(invec[i]), 1);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[2]), vget_low_s16(invec[i]), 2);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[3]), vget_low_s16(invec[i]), 3);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[0]), vget_low_s16(invec[i]), 0);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[1]), vget_low_s16(invec[i]), 1);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[2]), vget_low_s16(invec[i]), 2);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[3]), vget_low_s16(invec[i]), 3);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[4]), vget_high_s16(invec[i]), 0);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[5]), vget_high_s16(invec[i]), 1);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[6]), vget_high_s16(invec[i]), 2);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[7]), vget_high_s16(invec[i]), 3);
result = vcombine_s16(vqshrn_n_s32(acc0, 11), vqshrn_n_s32(acc1, 11));
vst1q_s16(out, result);
out += 8;
}
#else
for (i = 0; i < 2; i++) {
int16_t ins[8];
int16_t prev1 = out[-1];
int16_t prev2 = out[-2];
int j, k;
for (j = 0; j < 4; j++) {
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
}
for (j = 0; j < 8; j++) {
int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11);
for (k = 0; k < j; k++) {
acc += tbl[1][((j - k) - 1)] * ins[k];
}
acc >>= 11;
*out++ = clamp16(acc);
}
}
#endif
nbytes -= 16 * sizeof(int16_t);
}
memcpy(state, out - 16, 16 * sizeof(int16_t));
}
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state, uint16_t inofs, uint8_t outflag) {
int16_t tmp[16];
int16_t *in_initial = BUF_S16(inofs);
int16_t *in = in_initial;
int16_t *out = BUF_S16(OFS_BASE + ((outflag & 3) != 0) * NUM_BYTES);
int nbytes = ROUND_UP_16(NUM_BYTES);
uint32_t pitch_accumulator;
int i;
#if !HAS_SSE41 && !HAS_NEON
int16_t *tbl;
int32_t sample;
#endif
if (flags & A_INIT) {
memset(tmp, 0, 5 * sizeof(int16_t));
} else {
memcpy(tmp, state, 16 * sizeof(int16_t));
}
if (flags & 2) {
memcpy(in - 8, tmp + 8, 8 * sizeof(int16_t));
in -= tmp[5] / sizeof(int16_t);
}
in -= 4;
pitch_accumulator = (uint16_t)tmp[4];
memcpy(in, tmp, 4 * sizeof(int16_t));
#if HAS_SSE41
__m128i multiples = _mm_setr_epi16(0, 2, 4, 6, 8, 10, 12, 14);
__m128i pitchvec = _mm_set1_epi16((int16_t)pitch);
__m128i pitchvec_8_steps = _mm_set1_epi32((pitch << 1) * 8);
__m128i pitchacclo_vec = _mm_set1_epi32((uint16_t)pitch_accumulator);
__m128i pl = _mm_mullo_epi16(multiples, pitchvec);
__m128i ph = _mm_mulhi_epu16(multiples, pitchvec);
__m128i acc_a = _mm_add_epi32(_mm_unpacklo_epi16(pl, ph), pitchacclo_vec);
__m128i acc_b = _mm_add_epi32(_mm_unpackhi_epi16(pl, ph), pitchacclo_vec);
do {
__m128i tbl_positions = _mm_srli_epi16(_mm_packus_epi32(
_mm_and_si128(acc_a, _mm_set1_epi32(0xffff)),
_mm_and_si128(acc_b, _mm_set1_epi32(0xffff))), 10);
__m128i in_positions = _mm_packus_epi32(_mm_srli_epi32(acc_a, 16), _mm_srli_epi32(acc_b, 16));
__m128i tbl_entries[4];
__m128i samples[4];
/*for (i = 0; i < 4; i++) {
tbl_entries[i] = _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd(
(const double *)resample_table[_mm_extract_epi16(tbl_positions, 2 * i)]),
(const double *)resample_table[_mm_extract_epi16(tbl_positions, 2 * i + 1)]));
samples[i] = _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd(
(const double *)&in[_mm_extract_epi16(in_positions, 2 * i)]),
(const double *)&in[_mm_extract_epi16(in_positions, 2 * i + 1)]));
samples[i] = _mm_mulhrs_epi16(samples[i], tbl_entries[i]);
}*/
tbl_entries[0] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 0)], resample_table[_mm_extract_epi16(tbl_positions, 1)]);
tbl_entries[1] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 2)], resample_table[_mm_extract_epi16(tbl_positions, 3)]);
tbl_entries[2] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 4)], resample_table[_mm_extract_epi16(tbl_positions, 5)]);
tbl_entries[3] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 6)], resample_table[_mm_extract_epi16(tbl_positions, 7)]);
samples[0] = LOADLH(&in[_mm_extract_epi16(in_positions, 0)], &in[_mm_extract_epi16(in_positions, 1)]);
samples[1] = LOADLH(&in[_mm_extract_epi16(in_positions, 2)], &in[_mm_extract_epi16(in_positions, 3)]);
samples[2] = LOADLH(&in[_mm_extract_epi16(in_positions, 4)], &in[_mm_extract_epi16(in_positions, 5)]);
samples[3] = LOADLH(&in[_mm_extract_epi16(in_positions, 6)], &in[_mm_extract_epi16(in_positions, 7)]);
samples[0] = _mm_mulhrs_epi16(samples[0], tbl_entries[0]);
samples[1] = _mm_mulhrs_epi16(samples[1], tbl_entries[1]);
samples[2] = _mm_mulhrs_epi16(samples[2], tbl_entries[2]);
samples[3] = _mm_mulhrs_epi16(samples[3], tbl_entries[3]);
_mm_storeu_si128((__m128i *)out, _mm_hadds_epi16(_mm_hadds_epi16(samples[0], samples[1]), _mm_hadds_epi16(samples[2], samples[3])));
acc_a = _mm_add_epi32(acc_a, pitchvec_8_steps);
acc_b = _mm_add_epi32(acc_b, pitchvec_8_steps);
out += 8;
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
in += (uint16_t)_mm_extract_epi16(acc_a, 1);
pitch_accumulator = (uint16_t)_mm_extract_epi16(acc_a, 0);
#elif HAS_NEON
static const uint16_t multiples_data[8] = {0, 2, 4, 6, 8, 10, 12, 14};
uint16x8_t multiples = vld1q_u16(multiples_data);
uint32x4_t pitchvec_8_steps = vdupq_n_u32((pitch << 1) * 8);
uint32x4_t pitchacclo_vec = vdupq_n_u32((uint16_t)pitch_accumulator);
uint32x4_t acc_a = vmlal_n_u16(pitchacclo_vec, vget_low_u16(multiples), pitch);
uint32x4_t acc_b = vmlal_n_u16(pitchacclo_vec, vget_high_u16(multiples), pitch);
do {
uint16x8x2_t unzipped = vuzpq_u16(vreinterpretq_u16_u32(acc_a), vreinterpretq_u16_u32(acc_b));
uint16x8_t tbl_positions = vshrq_n_u16(unzipped.val[0], 10);
uint16x8_t in_positions = unzipped.val[1];
int16x8_t tbl_entries[4];
int16x8_t samples[4];
int16x8x2_t unzipped1;
int16x8x2_t unzipped2;
tbl_entries[0] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 0)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 1)]));
tbl_entries[1] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 2)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 3)]));
tbl_entries[2] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 4)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 5)]));
tbl_entries[3] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 6)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 7)]));
samples[0] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 0)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 1)]));
samples[1] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 2)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 3)]));
samples[2] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 4)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 5)]));
samples[3] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 6)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 7)]));
samples[0] = vqrdmulhq_s16(samples[0], tbl_entries[0]);
samples[1] = vqrdmulhq_s16(samples[1], tbl_entries[1]);
samples[2] = vqrdmulhq_s16(samples[2], tbl_entries[2]);
samples[3] = vqrdmulhq_s16(samples[3], tbl_entries[3]);
unzipped1 = vuzpq_s16(samples[0], samples[1]);
unzipped2 = vuzpq_s16(samples[2], samples[3]);
samples[0] = vqaddq_s16(unzipped1.val[0], unzipped1.val[1]);
samples[1] = vqaddq_s16(unzipped2.val[0], unzipped2.val[1]);
unzipped1 = vuzpq_s16(samples[0], samples[1]);
samples[0] = vqaddq_s16(unzipped1.val[0], unzipped1.val[1]);
vst1q_s16(out, samples[0]);
acc_a = vaddq_u32(acc_a, pitchvec_8_steps);
acc_b = vaddq_u32(acc_b, pitchvec_8_steps);
out += 8;
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
in += vgetq_lane_u16(vreinterpretq_u16_u32(acc_a), 1);
pitch_accumulator = vgetq_lane_u16(vreinterpretq_u16_u32(acc_a), 0);
#else
do {
for (i = 0; i < 8; i++) {
tbl = resample_table[pitch_accumulator * 64 >> 16];
sample = ((in[0] * tbl[0] + 0x4000) >> 15) +
((in[1] * tbl[1] + 0x4000) >> 15) +
((in[2] * tbl[2] + 0x4000) >> 15) +
((in[3] * tbl[3] + 0x4000) >> 15);
*out++ = clamp16(sample);
pitch_accumulator += (pitch << 1);
in += pitch_accumulator >> 16;
pitch_accumulator %= 0x10000;
}
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
#endif
state[4] = (int16_t)pitch_accumulator;
memcpy(state, in, 4 * sizeof(int16_t));
i = (in - in_initial + 4) & 7;
in -= i;
if (i != 0) {
i = -8 - i;
}
state[5] = i;
memcpy(state + 8, in, 8 * sizeof(int16_t));
}
void aEnvMixerImpl(uint8_t flags, ENVMIX_STATE state, int16_t rvol) {
int16_t *in = BUF_S16(OFS_BASE);
int16_t *dry[2] = {BUF_S16(OFS_MAIN_L), BUF_S16(OFS_MAIN_R)};
int16_t *wet[2] = {BUF_S16(OFS_AUX_L), BUF_S16(OFS_AUX_R)};
int nsamples = NUM_SAMPLES;
struct {
int32_t t[2];
int32_t rate[2];
int16_t tgt[2];
int16_t voldry;
int16_t volwet;
} *savedstate = (void *)state;
rspa.vol[1] = rvol; // why the fuck is this here?
// naudio uses a linear envelope
// TODO: sse/neon
int32_t t[2], tgt[2], rate[2];
int16_t voldry, volwet;
if (flags & A_INIT) {
for (int i = 0; i < 2; ++i) {
t[i] = rspa.vol[i] << 16;
rate[i] = rspa.rate[i] >> 3;
tgt[i] = rspa.target[i] << 16;
}
voldry = rspa.vol_dry;
volwet = rspa.vol_wet;
} else {
for (int i = 0; i < 2; ++i) {
t[i] = savedstate->t[i];
rate[i] = savedstate->rate[i];
tgt[i] = savedstate->tgt[i] << 16;
}
voldry = savedstate->voldry;
volwet = savedstate->volwet;
}
#ifdef PLATFORM_BIG_ENDIAN
#define XOR 0
#else
#define XOR 1
#endif
for (int i = 0; i < nsamples; ++i) {
int16_t gain[4];
int16_t vol[2];
int16_t *outptr[4];
for (int j = 0; j < 2; ++j) {
t[j] += rate[j];
if ((rate[j] <= 0 && t[j] <= tgt[j]) || (rate[j] > 0 && t[j] >= tgt[j])) {
t[j] = tgt[j];
rate[j] = 0;
}
vol[j] = t[j] >> 16;
}
outptr[0] = dry[0] + (i^XOR);
outptr[1] = dry[1] + (i^XOR);
outptr[2] = wet[0] + (i^XOR);
outptr[3] = wet[1] + (i^XOR);
gain[0] = clamp16((vol[0] * voldry + 0x4000) >> 15);
gain[1] = clamp16((vol[1] * voldry + 0x4000) >> 15);
gain[2] = clamp16((vol[0] * volwet + 0x4000) >> 15);
gain[3] = clamp16((vol[1] * volwet + 0x4000) >> 15);
const int16_t insamp = in[i^XOR];
for (int j = 0; j < 4; ++j) {
*outptr[j] = clamp16(*outptr[j] + ((insamp * gain[j]) >> 15));
}
}
#undef XOR
for (int i = 0; i < 2; ++i) {
savedstate->t[i] = t[i];
savedstate->rate[i] = rate[i];
savedstate->tgt[i] = tgt[i] >> 16;
}
savedstate->voldry = voldry;
savedstate->volwet = volwet;
}
// flags is always 0 in PD
void aMixImpl(uint8_t flags, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_16(NUM_BYTES); // can't round up to 32 here because 0x170 ain't gonna do that
int16_t *in = BUF_S16(in_addr);
int16_t *out = BUF_S16(out_addr);
#if HAS_SSE41
__m128i gain_vec = _mm_set1_epi16(gain);
#elif !HAS_NEON
int i;
int32_t sample;
#endif
#if !HAS_NEON
if (gain == -0x8000) {
while (nbytes > 0) {
#if HAS_SSE41
__m128i out1, in1;
out1 = _mm_loadu_si128((const __m128i *)out);
in1 = _mm_loadu_si128((const __m128i *)in);
out1 = _mm_subs_epi16(out1, in1);
_mm_storeu_si128((__m128i *)out, out1);
out += 8;
in += 8;
#else
for (i = 0; i < 8; i++) {
sample = *out - *in++;
*out++ = clamp16(sample);
}
#endif
nbytes -= 8 * sizeof(int16_t);
}
}
#endif
while (nbytes > 0) {
#if HAS_SSE41
__m128i out1, in1;
out1 = _mm_loadu_si128((const __m128i *)out);
in1 = _mm_loadu_si128((const __m128i *)in);
out1 = _mm_adds_epi16(out1, _mm_mulhrs_epi16(in1, gain_vec));
_mm_storeu_si128((__m128i *)out, out1);
out += 8;
in += 8;
#elif HAS_NEON
int16x8_t out1, in1;
out1 = vld1q_s16(out);
in1 = vld1q_s16(in);
out1 = vqaddq_s16(out1, vqrdmulhq_n_s16(in1, gain));
vst1q_s16(out, out1);
out += 8;
in += 8;
#else
for (i = 0; i < 8; i++) {
sample = ((*out * 0x7fff + *in++ * gain) + 0x4000) >> 15;
*out++ = clamp16(sample);
}
#endif
nbytes -= 8 * sizeof(int16_t);
}
}
void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r) {
// the flags are not really very intuitive here
if (flags & A_VOL) {
if (flags & A_LEFT) {
rspa.vol[0] = v;
rspa.vol_dry = t;
rspa.vol_wet = r;
} else {
rspa.target[1] = v;
rspa.rate[1] = (int32_t)((uint16_t)t << 16 | ((uint16_t)r));
}
} else /* A_RATE */ {
rspa.target[0] = v;
rspa.rate[0] = (int32_t)((uint16_t)t << 16 | ((uint16_t)r));
}
}
void aPlayMP3Impl(const void *mp3file, u32 mp3size, void *out, int reset) {
static mp3dec_t mp3d;
static const u8 *curdata = NULL; // pointer to the mp3 we're currently processing
static s32 dataptr = 0; // byte index into curdata
if (mp3file != curdata || reset) {
// new mp3, reinit decoder
mp3dec_init(&mp3d);
curdata = mp3file;
dataptr = 0;
}
// this command is supposed to write one full frame to out
// but which frame? we'll just decode sequentially, it'll probably work
if (dataptr < mp3size) {
// FIXME: decoding straight to out might bite us in the ass because it's only 1160 bytes
mp3dec_frame_info_t info;
const s32 samples = mp3dec_decode_frame(&mp3d, curdata + dataptr, mp3size - dataptr, out, &info);
// fill in the rest of the buffer if frame is smaller
const s32 diff = 580 - samples;
if (diff > 0) {
memset((s16 *)out + samples, 0, diff * 2);
} else {
assert(diff == 0);
}
dataptr += info.frame_bytes;
} else {
// empty frame
memset(out, 0, 580 * 2);
}
}
void aPoleFilterImpl(uint8_t flags, int16_t gain, uint32_t t, uint32_t addr) {
// this never gets called?
}
void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c) {
// this never gets called?
}
+533
View File
@@ -0,0 +1,533 @@
#include <stdlib.h>
#include <string.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "system.h"
#include "fs.h"
#include "utils.h"
#include "romdata.h"
#include "mod.h"
#include "data.h"
#include "game/stagetable.h"
#define MOD_TEXTURES_DIR "textures"
#define MOD_ANIMATIONS_DIR "animations"
#define MOD_SEQUENCES_DIR "sequences"
extern struct stagemusic g_StageTracks[];
extern struct stageallocation g_StageAllocations8Mb[];
#define PARSE_STAGE_FLOAT(sec, name, v, min, max) \
p = modConfigParseFloatValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
}
#define PARSE_STAGE_INT(sec, name, v, min, max) \
p = modConfigParseIntValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
}
#define PARSE_STAGE_FILENAME(sec, name, v) \
p = modConfigParseFileValue(p, token, &v); \
if (!p) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
}
#define PARSE_STAGE_STRING(sec, name, v) \
p = strParseToken(p, token, NULL); \
if (!p) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
} \
v = strUnquote(token);
#define PARSE_INT(sec, name, v, min, max, ret) \
p = modConfigParseIntValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "mod: %s: invalid " name " value: %s", sec, token); \
return ret; \
}
static inline char *modConfigParseFileValue(char *p, char *token, s32 *filenum)
{
p = strParseToken(p, token, NULL);
if (!token[0]) {
return NULL; // empty
}
// check if it is a number already
s32 num = strtol(token, NULL, 0);
if (num > 0 && romdataFileGetName(num)) {
*filenum = num;
return p;
}
// it's a filename
num = romdataFileGetNumForName(strUnquote(token));
if (num >= 0) {
*filenum = num;
return p;
}
// the filename was invalid
return NULL;
}
static inline char *modConfigParseIntValue(char *p, char *token, s32 *out)
{
p = strParseToken(p, token, NULL);
if (!token[0]) {
return NULL; // empty
}
char *endp = token;
const s32 num = strtol(token, &endp, 0);
if (num == 0 && (endp == token || *endp != '\0')) {
return NULL;
}
*out = num;
return p;
}
static inline char *modConfigParseFloatValue(char *p, char *token, f32 *out)
{
p = strParseToken(p, token, NULL);
if (!token[0]) {
return NULL; // empty
}
char *endp = token;
const f32 num = strtof(token, &endp);
if (num == 0.f && (endp == token || *endp != '\0')) {
return NULL;
}
*out = num;
return p;
}
static char *modConfigParseStageMusic(char *p, char *token, s32 stagenum)
{
struct stagemusic *smus = NULL;
for (struct stagemusic *p = g_StageTracks; p->stagenum; ++p) {
if (p->stagenum == stagenum) {
smus = p;
break;
}
}
if (!smus) {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: music can't be changed for this stage", stagenum);
return NULL;
}
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// parse keyvalues until } is reached
s32 tmp = 0;
p = strParseToken(p, token, NULL);
while (p && token[0] && strcmp(token, "}") != 0) {
if (!strcmp(token, "primarytrack")) {
PARSE_STAGE_INT("music:", "primarytrack", tmp, 0, 128);
smus->primarytrack = tmp;
} else if (!strcmp(token, "ambienttrack")) {
PARSE_STAGE_INT("music:", "ambienttrack", tmp, 0, 128);
smus->ambienttrack = tmp;
} else if (!strcmp(token, "xtrack")) {
PARSE_STAGE_INT("music:", "xtrack", tmp, 0, 128);
smus->xtrack = tmp;
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: music: invalid key: %s", stagenum, token);
return NULL;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unterminated music block", stagenum);
return NULL;
}
return p;
}
static char *modConfigParseStageWeatherRooms(char *p, char *token, s32 stagenum, struct weathercfg *wcfg)
{
// determine where we can start adding rooms
s32 idx;
for (idx = 0; idx < WEATHERCFG_MAX_SKIPROOMS && wcfg->skiprooms[idx]; ++idx);
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// check if user wants to clear the whole list
p = strParseToken(p, token, NULL);
if (!strcmp(token, "clear")) {
memset(wcfg->skiprooms, 0, sizeof(wcfg->skiprooms));
idx = 0;
p = strParseToken(p, token, NULL);
}
s32 tmp = 0;
while (p && token[0] && strcmp(token, "}") != 0) {
if (token[0] == ',' && !token[1]) {
p = strParseToken(p, token, NULL);
continue;
}
tmp = strtol(token, NULL, 0);
if (tmp <= 0 || tmp > 32767) {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: rooms: invalid room %s", stagenum, token);
return NULL;
}
if (idx < WEATHERCFG_MAX_SKIPROOMS) {
wcfg->skiprooms[idx++] = tmp;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: unterminated rooms block", stagenum);
return NULL;
}
return p;
}
static char *modConfigParseStageWeather(char *p, char *token, s32 stagenum)
{
s32 wi;
struct weathercfg *wcfg = NULL;
for (wi = 0; wi < ARRAYCOUNT(g_WeatherConfig) && g_WeatherConfig[wi].stagenum; ++wi) {
if (g_WeatherConfig[wi].stagenum == stagenum) {
break;
}
}
if (wi >= WEATHERCFG_MAX_STAGES) {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: no more space for weather config", stagenum);
return NULL;
}
wcfg = &g_WeatherConfig[wi];
if (!wcfg->stagenum) {
// new weather config; initialize with defaults
*wcfg = g_DefaultWeatherConfig;
wcfg->stagenum = stagenum;
} else {
// flags have to be re-specified
wcfg->flags = 0;
}
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// parse keyvalues until } is reached
s32 tmpi = 0;
f32 tmpf = 0.f;
p = strParseToken(p, token, NULL);
while (p && token[0] && strcmp(token, "}") != 0) {
if (!strcmp(token, "include_rooms") || !strcmp(token, "exclude_rooms")) {
// include_rooms | exclude_rooms { ROOM_NUMBERS... }
const s32 include = (token[0] == 'i');
p = modConfigParseStageWeatherRooms(p, token, stagenum, wcfg);
if (!p) {
return NULL;
}
if (wcfg->skiprooms[0] && include) {
wcfg->flags |= WEATHERFLAG_INCLUDE;
}
} else if (!strcmp(token, "cutscene_only")) {
wcfg->flags |= WEATHERFLAG_CUTSCENE_ONLY;
} else if (!strcmp(token, "constant_wind")) {
PARSE_STAGE_FLOAT("weather:", "constant_wind (0)", wcfg->windanglerad, -M_TAU, M_TAU);
PARSE_STAGE_FLOAT("weather:", "constant_wind (1)", wcfg->windspeedx, -1024.f, 1024.f);
PARSE_STAGE_FLOAT("weather:", "constant_wind (2)", wcfg->windspeedz, -1024.f, 1024.f);
wcfg->flags |= WEATHERFLAG_FORCE_WINDDIR;
} else if (!strcmp(token, "windspeed")) {
PARSE_STAGE_FLOAT("weather:", "windspeed", tmpf, -1024.f, 1024.f);
wcfg->windspeed = tmpf;
} else if (!strcmp(token, "ymin")) {
PARSE_STAGE_FLOAT("weather:", "ymin", tmpf, -65536.f, 65536.f);
wcfg->ymin = tmpf;
} else if (!strcmp(token, "ymax")) {
PARSE_STAGE_FLOAT("weather:", "ymax", tmpf, -65536.f, 65536.f);
wcfg->ymax = tmpf;
} else if (!strcmp(token, "zmax")) {
PARSE_STAGE_FLOAT("weather:", "zmax", tmpf, -65536.f, 65536.f);
wcfg->zmax = tmpf;
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: invalid key: %s", stagenum, token);
return NULL;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unterminated weather block", stagenum);
return NULL;
}
return p;
}
static char *modConfigParseStage(char *p, char *token)
{
// stage number
p = strParseToken(p, token, NULL);
const s32 stagenum = strtol(token, NULL, 0);
if (stagenum <= 0x01 || stagenum > 0x50) {
return NULL;
}
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// find the stage table pointers this corresponds to
struct stagetableentry *stab = NULL;
struct stageallocation *salloc = NULL;
const s32 sidx = stageGetIndex(stagenum);
if (sidx >= 0) {
stab = &g_Stages[sidx];
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unknown stage number", stagenum);
return NULL;
}
for (struct stageallocation *p = g_StageAllocations8Mb; p->stagenum; ++p) {
if (p->stagenum == stagenum) {
salloc = p;
break;
}
}
// parse keyvalues until } is reached
s32 tmp = 0;
char *tmps = NULL;
p = strParseToken(p, token, NULL);
while (p && token[0] && strcmp(token, "}") != 0) {
if (!strcmp(token, "bgfile")) {
// bg FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "bgfile", tmp);
stab->bgfileid = tmp;
} else if (!strcmp(token, "tilesfile")) {
// tilesfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "tilesfile", tmp);
stab->tilefileid = tmp;
} else if (!strcmp(token, "padsfile")) {
// padsfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "padsfile", tmp);
stab->padsfileid = tmp;
} else if (!strcmp(token, "setupfile")) {
// setupfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "setupfile", tmp);
stab->setupfileid = tmp;
} else if (!strcmp(token, "mpsetupfile")) {
// mpsetupfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "mpsetupfile", tmp);
stab->mpsetupfileid = tmp;
} else if (!strcmp(token, "alarm")) {
PARSE_STAGE_INT("", "alarm", tmp, 1, 0xFFFF);
stab->alarm = tmp;
} else if (!strcmp(token, "extragunmem")) {
PARSE_STAGE_INT("", "extragunmem", tmp, 0, 0xFFFF);
stab->extragunmem = tmp;
} else if (!strcmp(token, "allocation")) {
// allocation "ALLOCSTRING"
PARSE_STAGE_STRING("", "allocation", tmps);
// FIXME: this leaks
tmps = strDuplicate(tmps);
if (tmps) {
salloc->string = tmps;
}
} else if (!strcmp(token, "music")) {
// music { KEYVALUES... }
p = modConfigParseStageMusic(p, token, stagenum);
if (!p) {
return NULL;
}
} else if (!strcmp(token, "weather")) {
// weather { KEYVALUES... }
p = modConfigParseStageWeather(p, token, stagenum);
if (!p) {
return NULL;
}
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: invalid key: %s", stagenum, token);
return NULL;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: unterminated stage 0x%02x block", stagenum);
return NULL;
}
return p;
}
s32 modConfigLoad(const char *fname)
{
u32 dataLen = 0;
char *data = fsFileLoad(fname, &dataLen);
if (!data) {
return false;
}
s32 success = true;
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char *end = data + dataLen;
char *p = strParseToken(data, token, NULL);
while (p && token[0]) {
if (!strcmp(token, "stage")) {
// stage NUMBER { KEYVALUES... }
char *prev = p;
p = modConfigParseStage(p, token);
if (!p) {
sysLogPrintf(LOG_ERROR, "modconfig: malformed stage block at offset %d", prev - data);
success = false;
break;
}
} else {
// garbage
sysLogPrintf(LOG_ERROR, "modconfig: unexpected %s at offset %d", token[0] ? token : "end of file", p - data);
success = false;
break;
}
p = strParseToken(p, token, NULL);
}
sysMemFree(data);
return success;
}
s32 modTextureLoad(u16 num, void *dst, u32 dstSize)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_TEXTURES_DIR "/") >= 0);
}
if (!dirExists) {
return -1;
}
char path[FS_MAXPATH + 1];
snprintf(path, sizeof(path), MOD_TEXTURES_DIR "/%04x.bin", num);
const s32 ret = fsFileLoadTo(path, dst, dstSize);
if (ret > 0) {
sysLogPrintf(LOG_NOTE, "mod: loaded external texture %04x", num);
}
return ret;
}
void *modSequenceLoad(u16 num, u32 *outSize)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_SEQUENCES_DIR "/") >= 0);
}
if (!dirExists) {
return NULL;
}
char path[FS_MAXPATH + 1];
snprintf(path, sizeof(path), MOD_SEQUENCES_DIR "/%04x.bin", num);
if (fsFileSize(path) > 0) {
void *ret = fsFileLoad(path, outSize);
if (ret) {
sysLogPrintf(LOG_NOTE, "mod: loaded external sequence %04x", num);
return ret;
}
}
return NULL;
}
void *modAnimationLoadData(u16 num)
{
char path[FS_MAXPATH + 1];
// load the animation data
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.bin", num);
void *data = fsFileLoad(path, NULL);
if (!data) {
sysFatalError("External animation %04x has no data file.\nEnsure that it is placed at %s or delete the descriptor.", num, path);
}
return data;
}
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_ANIMATIONS_DIR "/") >= 0);
}
if (!dirExists) {
return false;
}
char path[FS_MAXPATH + 1];
// load the descriptor, if any
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.txt", num);
if (fsFileSize(path) <= 0) {
return false;
}
char *desc = fsFileLoad(path, NULL);
if (!desc) {
return false;
}
// parse the descriptor
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char *p = strParseToken(desc, token, NULL);
s32 tmp = 0;
while (p && token[0]) {
if (!strcmp(token, "numframes")) {
PARSE_INT(path, "numframes", tmp, 0, 0xFFFF, false);
anim->numframes = tmp;
} else if (!strcmp(token, "bytesperframe")) {
PARSE_INT(path, "bytesperframe", tmp, 0, 0xFFFF, false);
anim->bytesperframe = tmp;
} else if (!strcmp(token, "headerlen")) {
PARSE_INT(path, "headerlen", tmp, 0, 0xFFFF, false);
anim->headerlen = tmp;
} else if (!strcmp(token, "framelen")) {
PARSE_INT(path, "framelen", tmp, 0, 0xFF, false);
anim->framelen = tmp;
} else if (!strcmp(token, "flags")) {
PARSE_INT(path, "flags", tmp, 0, 0xFF, false);
anim->flags = tmp;
} else {
sysLogPrintf(LOG_ERROR, "mod: %s: invalid key: %s", path, token);
return false;
}
p = strParseToken(p, token, NULL);
}
sysMemFree(desc);
sysLogPrintf(LOG_NOTE, "mod: loaded external animation %04x", num);
return true;
}
+1127
View File
File diff suppressed because it is too large. Load diff
+305
View File
@@ -0,0 +1,305 @@
#include <string.h>
#include "types.h"
#include "platform.h"
#include "system.h"
#include "net/netbuf.h"
/* read */
void netbufStartRead(struct netbuf *buf)
{
buf->error = 0;
buf->wp = buf->size;
buf->rp = 0;
}
void netbufStartReadData(struct netbuf *buf, const void *data, u32 size)
{
buf->size = size;
buf->data = (void *)data;
netbufStartRead(buf);
}
s32 netbufReadLeft(const struct netbuf *buf)
{
return buf->wp - buf->rp;
}
static inline u32 netbufCanRead(struct netbuf *buf, const u32 num)
{
if (buf->error || buf->rp + num > buf->wp) {
sysLogPrintf(LOG_ERROR, "NET: could not read %u bytes", num);
__builtin_trap();
buf->error = 1;
return false;
}
return true;
}
u32 netbufReadData(struct netbuf *buf, void *out, u32 num)
{
if (netbufCanRead(buf, num)) {
memcpy(out, buf->data + buf->rp, num);
buf->rp += num;
return num;
}
return 0;
}
u8 netbufReadU8(struct netbuf *buf)
{
if (netbufCanRead(buf, 1)) {
return buf->data[buf->rp++];
}
return 0;
}
u16 netbufReadU16(struct netbuf *buf)
{
if (netbufCanRead(buf, 2)) {
const u16 ret = *(u16 *)&buf->data[buf->rp];
buf->rp += sizeof(ret);
return PD_LE16(ret);
}
return 0;
}
u32 netbufReadU32(struct netbuf *buf)
{
if (netbufCanRead(buf, 4)) {
const u32 ret = *(u32 *)&buf->data[buf->rp];
buf->rp += sizeof(ret);
return PD_LE32(ret);
}
return 0;
}
u64 netbufReadU64(struct netbuf *buf)
{
if (netbufCanRead(buf, 8)) {
const u64 ret = *(u64 *)&buf->data[buf->rp];
buf->rp += sizeof(ret);
return PD_LE64(ret);
}
return 0;
}
s8 netbufReadS8(struct netbuf *buf) {
return (s8)netbufReadU8(buf);
}
s16 netbufReadS16(struct netbuf *buf) {
return (s16)netbufReadU16(buf);
}
s32 netbufReadS32(struct netbuf *buf) {
return (s32)netbufReadU32(buf);
}
s64 netbufReadS64(struct netbuf *buf) {
return (s64)netbufReadU64(buf);
}
f32 netbufReadF32(struct netbuf *buf)
{
union {
f32 f;
u32 i;
} hack;
hack.i = netbufReadU32(buf);
return hack.f;
}
char *netbufReadStr(struct netbuf *buf)
{
const u16 len = netbufReadU16(buf);
if (netbufCanRead(buf, len)) {
char *ret = (char *)&buf->data[buf->rp];
buf->rp += len;
return ret;
}
return NULL;
}
u32 netbufReadCoord(struct netbuf *buf, struct coord *out)
{
if (netbufCanRead(buf, sizeof(*out))) {
out->x = netbufReadF32(buf);
out->y = netbufReadF32(buf);
out->z = netbufReadF32(buf);
return sizeof(*out);
}
return 0;
}
u32 netbufReadMtxf(struct netbuf *buf, Mtxf *out)
{
if (netbufCanRead(buf, sizeof(*out))) {
for (s32 i = 0; i < 4; ++i) {
for (s32 j = 0; j < 4; ++j) {
out->m[i][j] = netbufReadF32(buf);
}
}
return sizeof(*out);
}
return 0;
}
u32 netbufReadSkip(struct netbuf *buf, u32 count)
{
if (netbufCanRead(buf, count)) {
buf->rp += count;
return count;
}
return 0;
}
/* write */
void netbufStartWrite(struct netbuf *buf)
{
buf->wp = 0;
buf->error = 0;
}
static inline u32 netbufCanWrite(struct netbuf *buf, const u32 num)
{
if (buf->error || buf->wp + num > buf->size) {
buf->error = 1;
return false;
}
return true;
}
s32 netbufWriteLeft(const struct netbuf *buf)
{
return buf->size - buf->wp;
}
u32 netbufWriteData(struct netbuf *buf, const void *data, u32 num)
{
if (netbufCanWrite(buf, num)) {
memcpy(buf->data + buf->wp, data, num);
buf->wp += num;
return num;
}
return 0;
}
u32 netbufWriteU8(struct netbuf *buf, const u8 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
buf->data[buf->wp++] = v;
return sizeof(v);
}
return 0;
}
u32 netbufWriteU16(struct netbuf *buf, const u16 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
*(u16 *)&buf->data[buf->wp] = PD_LE16(v);
buf->wp += sizeof(v);
return sizeof(v);
}
return 0;
}
u32 netbufWriteU32(struct netbuf *buf, const u32 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
*(u32 *)&buf->data[buf->wp] = PD_LE32(v);
buf->wp += sizeof(v);
return sizeof(v);
}
return 0;
}
u32 netbufWriteU64(struct netbuf *buf, const u64 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
*(u64 *)&buf->data[buf->wp] = PD_LE64(v);
buf->wp += sizeof(v);
return sizeof(v);
}
return 0;
}
u32 netbufWriteS8(struct netbuf *buf, const s8 v)
{
return netbufWriteU8(buf, (u8)v);
}
u32 netbufWriteS16(struct netbuf *buf, const s16 v)
{
return netbufWriteU16(buf, (u16)v);
}
u32 netbufWriteS32(struct netbuf *buf, const s32 v)
{
return netbufWriteU32(buf, (u32)v);
}
u32 netbufWriteS64(struct netbuf *buf, const s64 v)
{
return netbufWriteU64(buf, (u64)v);
}
u32 netbufWriteF32(struct netbuf *buf, const f32 v)
{
const union {
f32 f;
u32 i;
} hack = { .f = v };
return netbufWriteU32(buf, hack.i);
}
u32 netbufWriteStr(struct netbuf *buf, const char *v)
{
if (!v) {
return 0;
}
u32 len = strlen(v) + 1;
if (len > 0xFFFF) {
len = 0xFFFF;
}
if (netbufCanWrite(buf, len + sizeof(u16))) {
netbufWriteU16(buf, len);
netbufWriteData(buf, v, len);
buf->data[buf->wp - 1] = 0;
return sizeof(u16) + len;
}
return 0;
}
u32 netbufWriteCoord(struct netbuf *buf, const struct coord *v)
{
if (netbufCanWrite(buf, sizeof(*v))) {
netbufWriteF32(buf, v->x);
netbufWriteF32(buf, v->y);
netbufWriteF32(buf, v->z);
return sizeof(*v);
}
return 0;
}
u32 netbufWriteMtxf(struct netbuf *buf, const Mtxf *in)
{
if (netbufCanWrite(buf, sizeof(*in))) {
for (s32 i = 0; i < 4; ++i) {
for (s32 j = 0; j < 4; ++j) {
netbufWriteF32(buf, in->m[i][j]);
}
}
return sizeof(*in);
}
return 0;
}
void netbufReset(struct netbuf *buf)
{
memset(buf, 0, sizeof(*buf));
}
+386
View File
@@ -0,0 +1,386 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "data.h"
#include "types.h"
#include "game/mainmenu.h"
#include "game/menu.h"
#include "game/gamefile.h"
#include "video.h"
#include "input.h"
#include "config.h"
#include "net/net.h"
extern MenuItemHandlerResult menuhandlerMainMenuCombatSimulator(s32 operation, struct menuitem *item, union handlerdata *data);
extern MenuItemHandlerResult menuhandlerMpAdvancedSetup(s32 operation, struct menuitem *item, union handlerdata *data);
static s32 g_NetMenuMaxPlayers = NET_MAX_CLIENTS;
static s32 g_NetMenuPort = NET_DEFAULT_PORT;
static char g_NetJoinAddr[NET_MAX_ADDR + 1];
static s32 g_NetJoinAddrPtr = 0;
/* host */
static MenuItemHandlerResult menuhandlerHostMaxPlayers(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = g_NetMenuMaxPlayers;
break;
case MENUOP_SET:
if (data->slider.value) {
g_NetMenuMaxPlayers = data->slider.value;
}
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerHostPort(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
}
return 0;
}
static char *menuhandlerHostPortValue(struct menuitem *item)
{
static char tmp[16];
snprintf(tmp, sizeof(tmp), "%u\n", g_NetMenuPort);
return tmp;
}
MenuItemHandlerResult menuhandlerHostStart(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
if (netStartServer(g_NetMenuPort, g_NetMenuMaxPlayers) == 0) {
menuhandlerMainMenuCombatSimulator(MENUOP_SET, NULL, NULL);
menuhandlerMpAdvancedSetup(MENUOP_SET, NULL, NULL);
}
}
return 0;
}
struct menuitem g_NetHostMenuItems[] = {
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Max Players",
NET_MAX_CLIENTS,
menuhandlerHostMaxPlayers,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Port\n",
(uintptr_t)&menuhandlerHostPortValue,
menuhandlerHostPort,
},
{
MENUITEMTYPE_SELECTABLE,
0,
0,
L_MPMENU_036, // "Start Game"
0,
menuhandlerHostStart,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetHostMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Host Network Game",
g_NetHostMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
/* join */
static const char *menutextJoinAddress(struct menuitem *item)
{
static char tmp[256 + 1];
if (item && item->flags & MENUITEMFLAG_SELECTABLE_CENTRE) {
// in centered dialog
if (g_NetMode == NETMODE_NONE) {
snprintf(tmp, sizeof(tmp), "%s_\n", g_NetJoinAddr);
} else if (g_NetLocalClient->state == CLSTATE_CONNECTING) {
snprintf(tmp, sizeof(tmp), "Connecting to %s...\n", g_NetJoinAddr);
} else if (g_NetLocalClient->state == CLSTATE_AUTH) {
snprintf(tmp, sizeof(tmp), "Authenticating with %s...\n", g_NetJoinAddr);
} else if (g_NetLocalClient->state == CLSTATE_LOBBY) {
snprintf(tmp, sizeof(tmp), "Waiting for host...\n");
}
} else {
// label
snprintf(tmp, sizeof(tmp), "%s\n", g_NetJoinAddr);
}
return tmp;
}
static MenuItemHandlerResult menuhandlerJoining(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (inputKeyPressed(VK_ESCAPE)) {
netDisconnect();
menuPopDialog();
}
return 0;
}
struct menuitem g_NetJoiningMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_SELECTABLE_CENTRE,
(uintptr_t)&menutextJoinAddress,
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"ESC to abort\n",
0,
menuhandlerJoining,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetJoiningDialog = {
MENUDIALOGTYPE_SUCCESS,
(uintptr_t)"Joining Game...",
g_NetJoiningMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
static MenuItemHandlerResult menuhandlerEnterJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data);
struct menuitem g_NetJoinAddressMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_SELECTABLE_CENTRE,
(uintptr_t)&menutextJoinAddress,
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"ESC to return\n",
0,
menuhandlerEnterJoinAddress,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetJoinAddressDialog = {
MENUDIALOGTYPE_SUCCESS,
(uintptr_t)"Enter Address",
g_NetJoinAddressMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
static MenuItemHandlerResult menuhandlerEnterJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (!menuIsDialogOpen(&g_NetJoinAddressDialog)) {
return 0;
}
if (inputTextHandler(g_NetJoinAddr, NET_MAX_ADDR, &g_NetJoinAddrPtr) < 0) {
// escape has been pressed, stop editing
inputStopTextInput();
menuPopDialog();
}
return 0;
}
static MenuItemHandlerResult menuhandlerJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
inputClearLastKey();
inputClearLastTextChar();
inputStartTextInput();
g_NetJoinAddrPtr = strlen(g_NetJoinAddr);
menuPushDialog(&g_NetJoinAddressDialog);
}
return 0;
}
MenuItemHandlerResult menuhandlerJoinStart(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
if (netStartClient(g_NetJoinAddr) == 0) {
menuPushDialog(&g_NetJoiningDialog);
}
}
return 0;
}
struct menuitem g_NetJoinMenuItems[] = {
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Address: \n",
(uintptr_t)&menutextJoinAddress,
menuhandlerJoinAddress,
},
{
MENUITEMTYPE_SELECTABLE,
0,
0,
L_MPMENU_036, // "Start Game"
0,
menuhandlerJoinStart,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetJoinMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Join Network Game",
g_NetJoinMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_STARTSELECTS | MENUDIALOGFLAG_IGNOREBACK,
NULL,
};
/* main */
MenuItemHandlerResult menuhandlerHostGame(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
g_NetMenuPort = g_NetServerPort;
g_NetMenuMaxPlayers = g_NetMaxClients;
menuPushDialog(&g_NetHostMenuDialog);
}
return 0;
}
MenuItemHandlerResult menuhandlerJoinGame(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
if (g_NetJoinAddr[0] == '\0') {
strncpy(g_NetJoinAddr, g_NetLastJoinAddr, NET_MAX_ADDR);
g_NetJoinAddrPtr = strlen(g_NetJoinAddr);
}
menuPushDialog(&g_NetJoinMenuDialog);
}
return 0;
}
struct menuitem g_NetMenuItems[] = {
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Host Game\n",
0,
menuhandlerHostGame,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Join Game\n",
0,
menuhandlerJoinGame,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Network Game",
g_NetMenuItems,
NULL,
MENUDIALOGFLAG_MPLOCKABLE | MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+651
View File
@@ -0,0 +1,651 @@
#include <stdlib.h>
#include <ultra64.h>
#include <PR/ultrasched.h>
#include "lib/sched.h"
#include "lib/vars.h"
#include "constants.h"
#include "game/camdraw.h"
#include "game/cheats.h"
#include "game/debug.h"
#include "game/file.h"
#include "game/lang.h"
#include "game/race.h"
#include "game/body.h"
#include "game/stubs/game_000840.h"
#include "game/stubs/game_000850.h"
#include "game/stubs/game_000860.h"
#include "game/stubs/game_000870.h"
#include "game/smoke.h"
#include "game/stubs/game_0008e0.h"
#include "game/stubs/game_0008f0.h"
#include "game/stubs/game_000900.h"
#include "game/stubs/game_000910.h"
#include "game/tex.h"
#include "game/stubs/game_00b180.h"
#include "game/stubs/game_00b200.h"
#include "game/challenge.h"
#include "game/title.h"
#include "game/pdmode.h"
#include "game/objectives.h"
#include "game/endscreen.h"
#include "game/playermgr.h"
#include "game/game_1531a0.h"
#include "game/gfxmemory.h"
#include "game/lang.h"
#include "game/lv.h"
#include "game/timing.h"
#include "game/music.h"
#include "game/stubs/game_175f50.h"
#include "game/game_175f90.h"
#include "game/zbuf.h"
#include "game/game_1a78b0.h"
#include "game/mplayer/mplayer.h"
#include "game/pak.h"
#include "game/splat.h"
#include "game/utils.h"
#include "bss.h"
#include "lib/audiomgr.h"
#include "lib/args.h"
#include "lib/boot.h"
#include "lib/vm.h"
#include "lib/rzip.h"
#include "lib/vi.h"
#include "lib/fault.h"
#include "lib/crash.h"
#include "lib/dma.h"
#include "lib/joy.h"
#include "lib/main.h"
#include "lib/snd.h"
#include "lib/memp.h"
#include "lib/mema.h"
#include "lib/model.h"
#include "lib/profile.h"
#include "lib/videbug.h"
#include "lib/debughud.h"
#include "lib/anim.h"
#include "lib/rdp.h"
#include "lib/lib_34d0.h"
#include "lib/lib_2f490.h"
#include "lib/rmon.h"
#include "lib/rng.h"
#include "lib/str.h"
#include "data.h"
#include "types.h"
#include "system.h"
#include "console.h"
#include "net/net.h"
#include "net/netmsg.h"
extern u8 *g_MempHeap;
extern u32 g_MempHeapSize;
void rngSetSeed(u32 seed);
bool var8005d9b0 = false;
s32 g_StageNum = STAGE_TITLE;
u32 g_MainMemaHeapSize = 1024 * 300;
bool var8005d9bc = false;
s32 var8005d9c0 = 0;
s32 var8005d9c4 = 0;
bool g_MainGameLogicEnabled = true;
u32 g_MainNumGfxTasks = 0;
bool g_MainIsEndscreen = false;
s32 g_DoBootPakMenu = 0;
u32 var8005dd3c = 0x00000000;
u32 var8005dd40 = 0x00000000;
u32 var8005dd44 = 0x00000000;
u32 var8005dd48 = 0x00000000;
u32 var8005dd4c = 0x00000000;
u32 var8005dd50 = 0x00000000;
s32 g_MainChangeToStageNum = -1;
bool g_MainIsDebugMenuOpen = false;
struct stageallocation g_StageAllocations8Mb[] = {
{ STAGE_CITRAINING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_DEFECTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_INVESTIGATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_EXTRACTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_CHICAGO, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_G5BUILDING, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_VILLA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma600" },
{ STAGE_INFILTRATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
{ STAGE_RESCUE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
{ STAGE_ESCAPE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
{ STAGE_AIRBASE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_AIRFORCEONE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_CRASHSITE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_PELAGIC, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_DEEPSEA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_DEFENSE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_ATTACKSHIP, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_SKEDARRUINS, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_RAVINE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_PIPES, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_SEWERS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_BASE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_FELICITY, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_AREA52, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_GRID, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_CARPARK, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_RUINS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_VILLA, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_RUN, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP2, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP6, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP7, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP8, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP14, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP16, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP17, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP18, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP19, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP20, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_ASH, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_28, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_MBR, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" },
{ STAGE_TEST_SILO, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_24, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_MAIANSOS, "-ml0 -me0 -mgfx120 -mvtx100 -ma500" },
{ STAGE_RETAKING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_DEST, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_2B, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_WAR, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_UFF, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_OLD, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_DUEL, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" },
{ STAGE_TEST_LAM, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_ARCH, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_LEN, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" },
{ STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" },
{ 0, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" },
};
struct stageallocation g_StageAllocations4Mb[] = {
{ STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_PIPES, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_AREA52, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_RAVINE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_SEWERS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_BASE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_FELICITY, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_GRID, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_TEST_RUN, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_CARPARK, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_RUINS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx96 -mvtx96 -ma130" },
{ STAGE_MP_VILLA, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_TEST_MP2, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP6, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP7, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP8, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP14, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP16, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP17, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP18, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP19, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP20, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_LEN, "-ml0 -me0 -mgfx100 -mvtx96 -ma120" },
{ STAGE_4MBMENU, "-mgfx100 -mvtx50 -ma50" },
{ STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" },
{ 0, "-ml0 -me0 -mgfx100 -mvtx96 -ma300" },
};
Gfx var8005dcc8[] = {
gsSPSegment(0x00, 0x00000000),
gsSPDisplayList(&var800613a0),
gsSPDisplayList(&var80061380),
gsDPFullSync(),
gsSPEndDisplayList(),
};
s32 g_MainIsBooting = 1;
void mainInit(void)
{
s32 x;
s32 i;
s32 j;
u32 addr;
faultInit();
dmaInit();
amgrInit();
varsInit();
mempInit();
memaInit();
joyInit();
joyReset();
g_Is4Mb = (osGetMemSize() <= 0x400000);
g_VmShowStats = 0;
// no copyright screen
viSetMode(VIMODE_HI);
viConfigureForLegal();
viBlack(true);
viUpdateMode();
filesInit();
if (var8005d9b0) {
argSetString(" -ml0 -me0 -mgfx100 -mvtx50 -mt700 -ma400");
}
mempSetHeap(g_MempHeap, g_MempHeapSize);
mempResetPool(MEMPOOL_8);
mempResetPool(MEMPOOL_PERMANENT);
crashReset();
challengesInit();
utilsInit();
texInit();
langInit();
lvInit();
cheatsInit();
textInit();
dhudInit();
playermgrInit();
frametimeInit();
profileInit();
smokesInit();
mpInit();
pheadInit();
paksInit();
pheadInit2();
animsInit();
racesInit();
bodiesInit();
titleInit();
modelSetDistanceChecksDisabled(true); // don't use LODs
g_MainIsBooting = 0;
}
void mainProc(void)
{
mainInit();
rdpInit();
sndInit();
while (true) {
mainLoop();
}
}
/**
* It's suspected that this function would have allowed developers to override
* the value of variables while the game is running in order to view their
* effects immediately rather than having to recompile the game each time.
*
* The developers would have used rmon to create a table of name/value pairs,
* then this function would have looked up the given variable name in the table
* and written the new value to the variable's address.
*/
void mainOverrideVariable(char *name, void *value)
{
// empty
}
/**
* This function enters an infinite loop which iterates once per stage load.
* Within this loop is an inner loop which runs very frequently and decides
* whether to run mainTick on each iteration.
*
* NTSC beta checks two shorts at an offset 64MB into the development board
* and refuses to continue if they are not any of the allowed values.
* Decomp patches these reads in its build system so it can be played
* without the development board.
*/
void mainLoop(void)
{
s32 ending = false;
s32 index;
s32 numplayers;
u32 stack;
func0f175f98();
var8005d9c4 = 0;
argGetLevel(&g_StageNum);
if (g_DoBootPakMenu) {
g_Vars.pakstocheck = 0xfd;
g_StageNum = STAGE_BOOTPAKMENU;
}
if (g_StageNum != STAGE_TITLE) {
titleSetNextStage(g_StageNum);
if (g_StageNum < STAGE_TITLE) {
func0f01b148(0);
if (argFindByPrefix(1, "-hard")) {
lvSetDifficulty(argFindByPrefix(1, "-hard")[0] - '0');
}
}
}
if (g_StageNum == STAGE_CITRAINING && IS4MB()) {
g_StageNum = STAGE_4MBMENU;
}
rngSetSeed(osGetCount());
// Outer loop - this is infinite because ending is never changed
while (!ending) {
g_MainNumGfxTasks = 0;
g_MainGameLogicEnabled = true;
g_MainIsEndscreen = false;
if (var8005d9b0 && var8005d9c4 == 0) {
index = -1;
if (IS4MB()) {
if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) {
index = 0; \
while (g_StageAllocations4Mb[index].stagenum) { \
if (g_StageAllocations4Mb[index].stagenum == g_StageNum + 400) { \
break; \
} \
index++;
}
if (g_StageAllocations4Mb[index].stagenum == 0) {
index = -1;
}
}
if (index);
if (index < 0) {
index = 0;
while (g_StageAllocations4Mb[index].stagenum) {
if (g_StageNum == g_StageAllocations4Mb[index].stagenum) {
break;
}
index++;
}
}
argSetString(g_StageAllocations4Mb[index].string);
} else {
// 8MB
if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) {
index = 0; \
while (g_StageAllocations8Mb[index].stagenum) { \
if (g_StageNum + 400 == g_StageAllocations8Mb[index].stagenum) { \
break; \
} \
index++;
}
if (g_StageAllocations8Mb[index].stagenum == 0) {
index = -1;
}
}
if (index < 0) {
index = 0;
while (g_StageAllocations8Mb[index].stagenum) {
if (g_StageNum == g_StageAllocations8Mb[index].stagenum) {
break;
}
index++;
}
}
argSetString(g_StageAllocations8Mb[index].string);
}
}
var8005d9c4 = 0;
mempResetPool(MEMPOOL_7);
mempResetPool(MEMPOOL_STAGE);
filesStop(4);
if (argFindByPrefix(1, "-ma")) {
g_MainMemaHeapSize = strtol(argFindByPrefix(1, "-ma"), NULL, 0) * 1024;
if (g_NetMode && g_NetMaxClients > MAX_LOCAL_PLAYERS) {
g_MainMemaHeapSize *= MAX_PLAYERS / MAX_LOCAL_PLAYERS;
}
}
memaReset(mempAlloc(g_MainMemaHeapSize, MEMPOOL_STAGE), g_MainMemaHeapSize);
langReset(g_StageNum);
playermgrReset();
if (g_StageNum >= STAGE_TITLE) {
numplayers = 0;
} else {
if (argFindByPrefix(1, "-play")) {
numplayers = strtol(argFindByPrefix(1, "-play"), NULL, 0);
} else {
numplayers = 1;
}
if (getNumPlayers() >= 2) {
numplayers = getNumPlayers();
}
}
if (numplayers < 2) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = -1;
} else if (argFindByPrefix(1, "-coop")) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = 1;
g_Vars.antiplayernum = -1;
} else if (argFindByPrefix(1, "-anti")) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = 1;
}
playermgrAllocatePlayers(numplayers);
if (argFindByPrefix(1, "-mpbots")) {
g_Vars.lvmpbotlevel = 1;
}
if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
#ifdef PLATFORM_N64
g_MpSetup.chrslots = 0x03;
#else
if (g_Vars.antiplayernum < 0) {
// Counter-Operative now uses a different approach which allows more than 2 players.
// Co-Operative, on the other hand, is currently limited to 2 players.
g_MpSetup.chrslots = 0x03;
}
#endif
mpReset();
} else if (g_Vars.perfectbuddynum) {
mpReset();
} else if (g_Vars.mplayerisrunning == false
&& (numplayers >= 2 || g_Vars.lvmpbotlevel || argFindByPrefix(1, "-play"))) {
g_MpSetup.chrslots = 1;
for (s32 i = 1; i < numplayers; ++i) {
g_MpSetup.chrslots |= 1 << i;
}
g_MpSetup.stagenum = g_StageNum;
mpReset();
}
gfxReset();
joyReset();
dhudReset();
zbufReset(g_StageNum);
lvReset(g_StageNum);
viReset(g_StageNum);
frametimeCalculate();
profileReset();
while (g_MainChangeToStageNum < 0) {
const s32 cycles = osGetCount() - g_Vars.thisframestartt;
if (!g_Vars.mininc60 || (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2)) {
schedStartFrame(&g_Sched);
mainTick();
schedEndFrame(&g_Sched);
}
if (g_TickExtraSleep) {
sysSleep(EXTRA_SLEEP_TIME);
}
}
lvStop();
mempDisablePool(MEMPOOL_STAGE);
mempDisablePool(MEMPOOL_7);
filesStop(4);
viBlack(true);
pak0f116994();
g_StageNum = g_MainChangeToStageNum;
g_MainChangeToStageNum = -1;
}
}
void mainTick(void)
{
Gfx *gdl = NULL;
Gfx *gdlstart = NULL;
OSScMsg msg = {OS_SC_DONE_MSG};
s32 i;
if (g_MainChangeToStageNum < 0) {
frametimeCalculate();
profileReset();
profileSetMarker(PROFILE_MAINTICK_START);
joyDebugJoy();
schedSetCrashEnable2(false);
if (g_MainGameLogicEnabled) {
gdl = gdlstart = gfxGetMasterDisplayList();
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0000, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_4b, 0, 0x0100, 6, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
lvTick();
playermgrShuffle();
if (g_StageNum < STAGE_TITLE) {
for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(playermgrGetPlayerAtOrder(i));
if (g_StageNum != STAGE_TEST_OLD || !titleIsKeepingMode()) {
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
viSetFovAspectAndSize(
g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
g_Vars.currentplayer->viewwidth, g_Vars.currentplayer->viewheight);
}
lvTickPlayer();
}
}
gdl = lvRender(gdl);
if (debugGetProfileMode() >= 2) {
gdl = profileRender(gdl);
}
gdl = conRender(gdl);
gdl = netDebugRender(gdl);
gDPFullSync(gdl++);
gSPEndDisplayList(gdl++);
}
if (g_MainGameLogicEnabled) {
gfxSwapBuffers();
viUpdateMode();
}
rdpCreateTask(gdlstart, gdl, 0, (s32) &msg);
memaPrint();
profileSetMarker(PROFILE_MAINTICK_END);
}
}
void mainEndStage(void)
{
sndStopNosedive();
if (!g_MainIsEndscreen) {
pak0f11c6d0();
joyDisableTemporarily();
if (g_Vars.coopplayernum >= 0) {
s32 prevplayernum = g_Vars.currentplayernum;
s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
endscreenPushCoop();
}
setCurrentPlayerNum(prevplayernum);
musicStartMenu();
} else if (g_Vars.antiplayernum >= 0) {
s32 prevplayernum = g_Vars.currentplayernum;
s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
endscreenPushAnti();
}
setCurrentPlayerNum(prevplayernum);
musicStartMenu();
} else if (g_Vars.normmplayerisrunning) {
mpEndMatch();
} else {
endscreenPrepare();
musicStartMenu();
}
netServerStageEnd();
}
g_MainIsEndscreen = true;
}
/**
* Change to the given stage at the end of the current frame.
*/
void mainChangeToStage(s32 stagenum)
{
pak0f11c6d0();
g_MainChangeToStageNum = stagenum;
}
s32 mainGetStageNum(void)
{
return g_StageNum;
}
void func0000e990(void)
{
objectivesCheckAll();
objectivesDisableChecking();
mainEndStage();
}
+428
View File
@@ -0,0 +1,428 @@
#include <PR/ultratypes.h>
#include <PR/ultrasched.h>
#include "lib/boot.h"
#include "lib/sched.h"
#include "constants.h"
#include "game/menugfx.h"
#include "bss.h"
#include "lib/args.h"
#include "lib/audiomgr.h"
#include "lib/reset.h"
#include "lib/rzip.h"
#include "lib/crash.h"
#include "lib/main.h"
#include "lib/snd.h"
#include "lib/pimgr.h"
#include "lib/profile.h"
#include "lib/rmon.h"
#include "lib/lib_48150.h"
#include "lib/vi.h"
#include "lib/joy.h"
#include "data.h"
#include "types.h"
#include "video.h"
#include "audio.h"
#include "input.h"
#include "console.h"
#include "mixer.h"
#include "net/net.h"
/*
* private typedefs and defines
*/
#define VIDEO_MSG 666
#define RSP_DONE_MSG 667
#define RDP_DONE_MSG 668
#define PRE_NMI_MSG 669
/*
* OSScTask state
*/
#define OS_SC_DP 0x0001 /* set if still needs dp */
#define OS_SC_SP 0x0002 /* set if still needs sp */
#define OS_SC_YIELD 0x0010 /* set if yield requested */
#define OS_SC_YIELDED 0x0020 /* set if yield completed */
/*
* OSScTask->flags type identifier
*/
#define OS_SC_XBUS (OS_SC_SP | OS_SC_DP)
#define OS_SC_DRAM (OS_SC_SP | OS_SC_DP | OS_SC_DRAM_DLIST)
#define OS_SC_DP_XBUS (OS_SC_SP)
#define OS_SC_DP_DRAM (OS_SC_SP | OS_SC_DRAM_DLIST)
#define OS_SC_SP_XBUS (OS_SC_DP)
#define OS_SC_SP_DRAM (OS_SC_DP | OS_SC_DRAM_DLIST)
/*
* private functions
*/
void __scMain(void *arg);
void __scHandleTasks(OSSched *s);
void __scHandleRSP(OSSched *s);
void __scHandleRDP(OSSched *s);
void __scAppendList(OSSched *s, OSScTask *t);
OSScTask *__scTaskReady(OSScTask *t);
s32 __scTaskComplete(OSSched *s,OSScTask *t);
void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp);
void __scYield(OSSched *s);
s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP);
OSViMode var8008dcc0[NUM_GFXTASKS];
OSViMode *var8008dd60[NUM_GFXTASKS];
OSViMode var8008dd68[NUM_GFXTASKS];
s32 var8008de08;
s32 g_ViCurVStart0;
s32 g_ViCurVStart1;
u32 var8008de14;
OSTimer g_SchedRspTimer;
u32 g_SchedDpCounters[4];
struct artifact g_ArtifactLists[3][120];
u8 g_SchedSpecialArtifactIndexes[3];
s32 g_SchedWriteArtifactsIndex;
s32 g_SchedFrontArtifactsIndex;
s32 g_SchedPendingArtifactsIndex;
bool g_SchedCrashedUnexpectedly = false;
bool g_SchedCrashEnable1 = false;
bool g_SchedCrashEnable2 = false;
u32 g_SchedCrashRenderInterval = 45000000;
u32 g_SchedCrashLastRendered = 0;
s32 var8005ce74 = 0;
f32 g_ViXScalesBySlot[NUM_GFXTASKS] = {1, 1};
f32 g_ViYScalesBySlot[NUM_GFXTASKS] = {1, 1};
bool g_SchedViModesPending[NUM_GFXTASKS] = {false, false};
s32 g_ViUnblackTimer = NUM_FRAMEBUFFERS + 1;
s32 g_ViShakeDirection = 1;
s32 g_ViShakeIntensity = 0;
f32 g_ViShakeIntensityMult = 1.f;
s32 g_ViShakeTimer = 0;
u32 var8005cea0 = 0;
u32 var8005cea4 = 0;
OSScMsg g_SchedRspMsg = {OS_SC_RSP_MSG};
bool g_SchedIsFirstTask = true;
s32 g_PrevFrameFb = -1;
s32 g_BlurFb = -1;
s32 g_BlurFbCapTimer = -1;
bool g_BlurFbDirty = true;
void schedSetCrashEnable1(bool enable)
{
g_SchedCrashEnable1 = enable;
}
void schedSetCrashedUnexpectedly(bool enable)
{
g_SchedCrashedUnexpectedly = enable;
}
void schedSetCrashEnable2(bool enable)
{
g_SchedCrashEnable2 = enable;
}
void schedSetCrashRenderInterval(u32 cycles)
{
g_SchedCrashRenderInterval = cycles;
}
void schedRenderCrashOnBuffer(void *framebuffer)
{
if ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly) {
// crashRenderFrame(framebuffer);
g_SchedCrashLastRendered = osGetCount();
}
}
void schedRenderCrashPeriodically(u32 framecount)
{
if ((framecount & 0xf) == 0 && ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly)) {
if (osGetCount() - g_SchedCrashLastRendered > g_SchedCrashRenderInterval) {
// crashRenderFrame(g_FrameBuffers[0]);
// crashRenderFrame(g_FrameBuffers[1]);
}
}
}
void schedInitCrashLastRendered(void)
{
g_SchedCrashLastRendered = osGetCount();
}
void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields)
{
sc->curRSPTask = 0;
sc->curRDPTask = 0;
sc->clientList = 0;
sc->frameCount = 0;
sc->audioListHead = 0;
sc->gfxListHead = 0;
sc->audioListTail = 0;
sc->gfxListTail = 0;
sc->retraceMsg.type = OS_SC_RETRACE_MSG;
sc->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
sc->thread = thread;
osCreateMesgQueue(&sc->interruptQ, sc->intBuf, OS_SC_MAX_MESGS);
osCreateMesgQueue(&sc->cmdQ, sc->cmdMsgBuf, OS_SC_MAX_MESGS);
osCreateViManager(OS_PRIORITY_VIMGR);
var8008de08 = osViModeTable[mode].comRegs.hStart;
g_ViCurVStart0 = osViModeTable[mode].fldRegs[0].vStart;
g_ViCurVStart1 = osViModeTable[mode].fldRegs[1].vStart;
var8008dd60[0] = &var8008dd68[0];
var8008dd60[1] = &var8008dd68[1];
var8008dd68[0] = osViModeTable[mode];
var8008dd68[1] = osViModeTable[mode];
osViSetEvent(&sc->interruptQ, (OSMesg)VIDEO_MSG, numFields);
schedInitCrashLastRendered();
g_PrevFrameFb = videoCreateFramebuffer(0, 0, false, true);
g_BlurFb = videoCreateFramebuffer(0, 0, false, true);
}
void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ, bool is30fps)
{
c->msgQ = msgQ;
c->is30fps = is30fps;
c->next = sc->clientList;
sc->clientList = c;
}
OSMesgQueue *osScGetCmdQ(OSSched *sc)
{
return &sc->cmdQ;
}
void __scUpdateViMode(void)
{
if (g_SchedIsFirstTask) {
osViBlack(false);
g_SchedIsFirstTask = false;
}
var8005ce74 = (var8005ce74 + 1) % 2;
if (g_SchedViModesPending[1 - var8005ce74]) {
// TODO: make this a little less awkward
extern struct rend_vidat *g_ViBackData;
videoUpdateNativeResolution(g_ViBackData->bufx, g_ViBackData->bufy);
g_SchedViModesPending[1 - var8005ce74] = false;
}
if (g_ViUnblackTimer != 0 && g_ViUnblackTimer <= NUM_FRAMEBUFFERS) {
g_ViUnblackTimer--;
}
}
/**
* Nintendo's sheduler accepts tasks on a "command" message queue.
* This isn't used here.
*
* In PD, the main and audio threads submit tasks by calling this function
* instead. It temporarily increases the calling thread's priority above the
* scheduler, adds the task to the linked list directly and attempts to execute
* it. This is faster than the queue method because it avoids switching threads.
*/
void schedSubmitTask(OSSched *sc, OSScTask *t)
{
if (sc->doAudio && t->list.t.type == M_AUDTASK) {
// send this into the mixer
} else if (t->list.t.type == M_GFXTASK) {
videoSubmitCommands((Gfx *)t->list.t.data_ptr);
}
}
void schedStartFrame(OSSched *sc)
{
videoStartFrame();
if (g_Vars.diffframe60) {
if (g_NetMode) {
videoCapFramerate(120);
netStartFrame();
} else {
videoCapFramerate(0);
}
}
}
void schedAudioFrame(OSSched *sc)
{
s32 i;
if (!g_SndDisabled) {
for (i = 0; i < g_Vars.diffframe60; i++) {
amgrFrame();
audioEndFrame();
}
}
}
/**
* Handle a retrace (vsync) event.
*
* Audio tasks are scheduled based on retrace + a timer (approximately 6ms).
* On NTSC, this is done on every second frame if 8MB, or every second frame
* if 4MB. I guess less memory means the audio queue has to be kept smaller
* and processed more frequently. On PAL, it's every second frame regardless.
*
* Controller input is polled here.
*
* Lastly, if there's crash information available then it will be checked and
* rendered periodically (once every 16 retraces). I guess this makes it render
* if the RDP has hung.
*/
void schedEndFrame(OSSched *sc)
{
static bool netDebugKey = false;
sc->frameCount++;
#if PAL
if (!g_Resetting && (sc->frameCount & 1)) {
// osStopTimer(&g_SchedRspTimer);
// osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg);
}
#else
if (!g_Resetting && ((sc->frameCount & 1) || IS4MB())) {
// osStopTimer(&g_SchedRspTimer);
// osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg);
}
#endif
if (!g_Resetting) {
viHandleRetrace();
}
inputUpdate();
conTick();
const bool newKey = inputKeyPressed(VK_F9);
if (!netDebugKey && newKey) {
g_NetDebugDraw = !g_NetDebugDraw;
}
netDebugKey = newKey;
joyStartReadData(&g_PiMesgQueue);
joyReadData();
joy00014238();
if (g_Vars.diffframe60) {
netEndFrame();
}
sndHandleRetrace();
schedAudioFrame(sc);
schedRenderCrashPeriodically(sc->frameCount);
videoEndFrame();
if (g_MainIsBooting == 0) {
schedConsiderScreenshot();
}
// check for vid mode changes
__scUpdateViMode();
}
void schedInitArtifacts(void)
{
s32 i;
s32 j;
for (i = 0; i < 3; i++) {
for (j = 0; j < MAX_ARTIFACTS; j++) {
g_ArtifactLists[i][j].type = ARTIFACTTYPE_FREE;
}
g_SchedSpecialArtifactIndexes[i] = 0;
}
}
/**
* The write list is an artifact list that is not currently being displayed on
* the screen. Update logic can write here to put artifacts on the next frame.
*/
struct artifact *schedGetWriteArtifacts(void)
{
return g_ArtifactLists[g_SchedWriteArtifactsIndex];
}
/**
* The front list is the artifact list that is currently being displayed on the
* screen. Rendering logic reads this list. The list may be re-used for multiple
* frames in a row during lag.
*/
struct artifact *schedGetFrontArtifacts(void)
{
return g_ArtifactLists[g_SchedFrontArtifactsIndex];
}
/**
* The pending list is possibly misnamed. I'm not sure how this list works.
*
* @TODO: Investigate.
*/
struct artifact *schedGetPendingArtifacts(void)
{
return g_ArtifactLists[g_SchedPendingArtifactsIndex];
}
void schedIncrementWriteArtifacts(void)
{
g_SchedWriteArtifactsIndex = (g_SchedWriteArtifactsIndex + 1) % 3;
}
void schedIncrementFrontArtifacts(void)
{
g_SchedFrontArtifactsIndex = (g_SchedFrontArtifactsIndex + 1) % 3;
}
void schedIncrementPendingArtifacts(void)
{
g_SchedPendingArtifactsIndex = (g_SchedPendingArtifactsIndex + 1) % 3;
}
void schedResetArtifacts(void)
{
g_SchedWriteArtifactsIndex = 0;
g_SchedFrontArtifactsIndex = 1;
g_SchedPendingArtifactsIndex = 0;
}
void schedUpdatePendingArtifacts(void)
{
g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0;
schedIncrementPendingArtifacts();
}
void schedConsiderScreenshot(void)
{
if (g_MenuData.screenshottimer == 1) {
if (IS8MB()) {
menugfxCreateBlur();
}
g_MenuData.screenshottimer = 0;
}
if (g_BlurFbCapTimer == 0) {
videoCopyFramebuffer(g_BlurFb, 0, -1, -1);
g_BlurFbCapTimer = -1;
g_BlurFbDirty = false;
} else if (g_BlurFbCapTimer > 0) {
--g_BlurFbCapTimer;
} else if (g_BlurFbCapTimer < 0) {
// no blur requested this frame, mark blur fb dirty
g_BlurFbDirty = true;
}
if (g_MenuData.screenshottimer >= 2) {
g_MenuData.screenshottimer--;
}
}
File diff suppressed because it is too large. Load diff
+526
View File
@@ -0,0 +1,526 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <PR/ultratypes.h>
#include <PR/ultratypes.h>
#include "lib/rzip.h"
#include "romdata.h"
#include "fs.h"
#include "system.h"
#include "preprocess.h"
#include "platform.h"
/**
* asset files and ROM segments can be replaced by optional external files,
* but asset filenames still have to be either pulled from the ROM or from an
* external file, so stuff can't be completely custom
*
* all data is assumed to be big endian, so it has to be byteswapped
* at load time, which is fucking terrible
*/
#define ROMDATA_FILEDIR "files"
#define ROMDATA_SEGDIR "segs"
#define ROMDATA_ROM_NAME "pd." VERSION_ROMID ".z64"
#define ROMDATA_ROM_SIZE 33554432
#if VERSION == VERSION_NTSC_FINAL
#define ROMDATA_ROM_TITLE "Perfect Dark"
#define ROMDATA_ROM_ID "NPDE"
#define ROMDATA_ROM_DESC "NTSC v1.1"
#define ROMDATA_FILES_OFS 0x28080
#define ROMDATA_DATA_OFS 0x39850
#elif VERSION == VERSION_PAL_FINAL
#define ROMDATA_ROM_TITLE "Perfect Dark"
#define ROMDATA_ROM_ID "NPDP"
#define ROMDATA_ROM_DESC "PAL"
#define ROMDATA_FILES_OFS 0x28910
#define ROMDATA_DATA_OFS 0x39850
#elif VERSION == VERSION_JPN_FINAL
#define ROMDATA_ROM_TITLE "PERFECT DARK"
#define ROMDATA_ROM_ID "NPDJ"
#define ROMDATA_ROM_DESC "JPN"
#define ROMDATA_FILES_OFS 0x28800
#define ROMDATA_DATA_OFS 0x39850
#else
#error "This ROM version is unsupported."
#endif
#define ROMDATA_MAX_FILES 2048
u8 *g_RomFile;
u32 g_RomFileSize;
const char *g_RomName = ROMDATA_ROM_NAME;
static u8 *romDataSeg;
static u32 romDataSegSize;
enum loadsource {
SRC_UNLOADED = 0,
SRC_ROM,
SRC_EXTERNAL
};
struct romfilepatch {
u32 ofs;
u32 len;
const char *src;
const char *dst;
};
struct romfile {
u8 **segstart;
u8 **segend;
const char *name;
u8 *data;
u32 size;
preprocessfunc preprocess;
s32 source; // enum loadsource
s32 preprocessed;
const struct romfilepatch *patches;
u32 numpatches;
};
/* patches for individual files; applied on file load, before preprocFuncs, but */
/* after unzip; only applied when loading from a ROM file */
static const struct romfilepatch filePatches[] = {
/* FILE_USETUPLUE: fixes Jon's double "if what" in Infiltration outro */
{ 0x92a2, 1, "\x6c", "\x99" },
{ 0x92b0, 1, "\x6c", "\x99" },
};
static struct romfile fileSlots[ROMDATA_MAX_FILES] = {
[FILE_USETUPLUE] = { .patches = &filePatches[0], .numpatches = 2 },
};
#define ROMSEG_START(n) _ ## n ## SegmentRomStart
#define ROMSEG_END(n) _ ## n ## SegmentRomEnd
/* segment table for ntsc-final */
/* size will get calculated automatically if it is 0 */
/* if there are replacement files in the data dir, they will be loaded instead */
/* offsets are specified for ntsc-final, pal-final and jpn-final in that order */
#define ROMSEG_LIST() \
ROMSEG_DECL_SEG(fontjpnsingle, 0x194b20, 0x180330, 0x0, 0x0, preprocessJpnFont ) \
ROMSEG_DECL_SEG(fontjpnmulti, 0x19fb40, 0x18b340, 0x0, 0x0, preprocessJpnFont ) \
ROMSEG_DECL_SEG(animations, 0x1a15c0, 0x18cdc0, 0x190c50, 0x0, preprocessAnimations ) \
ROMSEG_DECL_SEG(mpconfigs, 0x7d0a40, 0x7bc240, 0x7c00d0, 0x11e0, preprocessMpConfigs ) \
ROMSEG_DECL_SEG(mpstringsE, 0x7d1c20, 0x7bd420, 0x7c12b0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(mpstringsJ, 0x7d5320, 0x7c0b20, 0x7c49b0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(mpstringsP, 0x7d8a20, 0x7c4220, 0x7c80b0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(mpstringsG, 0x7dc120, 0x7c7920, 0x7cb7b0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(mpstringsF, 0x7df820, 0x7cb020, 0x7ceeb0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(mpstringsS, 0x7e2f20, 0x7ce720, 0x7d25b0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(mpstringsI, 0x7e6620, 0x7d1e20, 0x7d5cb0, 0x3700, NULL ) \
ROMSEG_DECL_SEG(firingrange, 0x7e9d20, 0x7d5520, 0x7d93b0, 0x1550, NULL ) \
ROMSEG_DECL_SEG(fonttahoma, 0x7f7860, 0x7e3060, 0x7e6ef0, 0x0, preprocessFont ) \
ROMSEG_DECL_SEG(fontnumeric, 0x7f8b20, 0x7e4320, 0x7e81b0, 0x0, preprocessFont ) \
ROMSEG_DECL_SEG(fonthandelgothicsm, 0x7f9d30, 0x7e5530, 0x7e93c0, 0x0, preprocessFont ) \
ROMSEG_DECL_SEG(fonthandelgothicxs, 0x7fbfb0, 0x7e87b0, 0x7ec640, 0x0, preprocessFont ) \
ROMSEG_DECL_SEG(fonthandelgothicmd, 0x7fdd80, 0x7eae20, 0x7eecb0, 0x0, preprocessFont ) \
ROMSEG_DECL_SEG(fonthandelgothiclg, 0x8008e0, 0x7eee70, 0x7f2d00, 0x0, preprocessFont ) \
ROMSEG_DECL_SEG(sfxctl, 0x80a250, 0x7f87e0, 0x7fc670, 0x2fb80, preprocessALBankFile ) \
ROMSEG_DECL_SEG(sfxtbl, 0x839dd0, 0x828360, 0x82c1f0, 0x4c2160, NULL ) \
ROMSEG_DECL_SEG(seqctl, 0xcfbf30, 0xcea4c0, 0xcee350, 0xa060, preprocessALBankFile ) \
ROMSEG_DECL_SEG(seqtbl, 0xd05f90, 0xcf4520, 0xcf83b0, 0x17c070, NULL ) \
ROMSEG_DECL_SEG(sequences, 0xe82000, 0xe70590, 0xe74420, 0x563a0, preprocessSequences ) \
ROMSEG_DECL_SEG(texturesdata, 0x1d65f40, 0x1d5ca20, 0x1d61f90, 0x0, NULL ) \
ROMSEG_DECL_SEG(textureslist, 0x1ff7ca0, 0x1fee780, 0x1ff68f0, 0x0, preprocessTexturesList ) \
ROMSEG_DECL_SEG(copyright, 0x1ffea20, 0x1ff5500, 0x1ffd6b0, 0xb30, NULL ) \
ROMSEG_DECL_SEG(fontjpn, 0x0, 0x0, 0x178c40, 0x17920, preprocessJpnFont )
// declare the vars first
#undef ROMSEG_DECL_SEG
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) u8 *ROMSEG_START(name), *ROMSEG_END(name);
ROMSEG_LIST()
// this is part of the animations seg and as such does not follow the naming convention
// these are set in preprocessAnimations
u8 *_animationsTableRomStart;
u8 *_animationsTableRomEnd;
// then build the table
#undef ROMSEG_DECL_SEG
#if VERSION == VERSION_NTSC_FINAL
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs_ntsc, size, preproc },
#elif VERSION == VERSION_PAL_FINAL
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs_pal, size, preproc },
#elif VERSION == VERSION_JPN_FINAL
#define ROMSEG_DECL_SEG(name, ofs_ntsc, ofs_pal, ofs_jpn, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs_jpn, size, preproc },
#endif
static struct romfile romSegs[] = {
ROMSEG_LIST()
{ NULL, NULL, NULL, NULL, 0, NULL },
};
/* the game sets g_LoadType to the type of file it expects, */
/* so we can hijack that in fileLoad and automatically byteswap the file */
static preprocessfunc filePreprocFuncs[] = {
/* LOADTYPE_NONE */ NULL,
/* LOADTYPE_BG */ NULL, // loaded in parts
/* LOADTYPE_TILES */ preprocessTilesFile,
/* LOADTYPE_LANG */ preprocessLangFile,
/* LOADTYPE_SETUP */ preprocessSetupFile,
/* LOADTYPE_PADS */ preprocessPadsFile,
/* LOADTYPE_MODEL */ preprocessModelFile,
/* LOADTYPE_GUN */ preprocessGunFile,
};
static inline void romdataWrongRomError(const char *fmt, ...)
{
char reason[1024];
reason[0] = '\0';
va_list args;
va_start(args, fmt);
vsnprintf(reason, sizeof(reason), fmt, args);
va_end(args);
sysFatalError("Wrong ROM file.\n%s\nEnsure that you have the correct " ROMDATA_ROM_DESC " ROM in z64 format.", reason);
}
static inline void romdataLoadRom(void)
{
sysLogPrintf(LOG_NOTE, "ROM file: %s", g_RomName);
g_RomFile = fsFileLoad(g_RomName, &g_RomFileSize);
if (!g_RomFile) {
sysFatalError("Could not open ROM file %s.\nEnsure that it is in the %s directory.", g_RomName, fsFullPath(""));
}
// zips are not guaranteed to start with PK, but might as well at least try
if (g_RomFileSize > 2 && (!memcmp(g_RomFile, "PK", 2) || !memcmp(g_RomFile, "Rar", 3) || !memcmp(g_RomFile, "7z", 2))) {
romdataWrongRomError("Your ROM is in an archive file. Please extract it.");
}
if (g_RomFileSize != ROMDATA_ROM_SIZE) {
romdataWrongRomError("ROM size does not match: expected: %u, got: %u.", ROMDATA_ROM_SIZE, g_RomFileSize);
}
if (memcmp(g_RomFile + 0x3b, ROMDATA_ROM_ID, 4) || memcmp(g_RomFile + 0x20, ROMDATA_ROM_TITLE, sizeof(ROMDATA_ROM_TITLE) - 1)) {
romdataWrongRomError("ROM header does not match.");
}
// inflate the compressed data segment since that's where some useful stuff is
u8 *zipped = g_RomFile + ROMDATA_DATA_OFS;
if (!rzipIs1173(zipped)) {
romdataWrongRomError("Data segment is not 1173-compressed.");
}
const u32 dataSegLen = ((u32)zipped[2] << 16) | ((u32)zipped[3] << 8) | (u32)zipped[4];
if (dataSegLen < ROMDATA_FILES_OFS) {
romdataWrongRomError("Data segment too small (%u), need at least %u.", dataSegLen, ROMDATA_FILES_OFS);
}
u8 *dataSeg = sysMemAlloc(dataSegLen);
if (!dataSeg) {
sysFatalError("Could not allocate %u bytes for data segment.", dataSegLen);
}
u8 scratch[5 * 1024];
if (rzipInflate(zipped, dataSeg, scratch) < 0) {
free(dataSeg);
sysFatalError("Could not inflate data segment.");
}
romDataSeg = dataSeg;
romDataSegSize = dataSegLen;
}
static inline void romdataInitSegment(struct romfile *seg)
{
if (!seg->data) {
// unused in this ROM, skip it
sysLogPrintf(LOG_NOTE, "skipping segment %s", seg->name);
return;
}
if (!seg->size) {
// size unknown
if (seg[1].name) {
// use next segment's base to calculate
seg->size = seg[1].data - seg->data;
} else {
// this is the last segment, calculate based on rom size
seg->size = (u8 *)g_RomFileSize - seg->data;
}
}
// check if we have an external replacement and load it if so
char tmp[FS_MAXPATH];
snprintf(tmp, sizeof(tmp), ROMDATA_SEGDIR "/%s", seg->name);
u8 *newData = NULL;
const s32 extFileSize = fsFileSize(tmp);
if (extFileSize > 0) {
newData = fsFileLoad(tmp, &seg->size);
}
if (!newData) {
// no external data, just make it point to the rom
if (g_RomFile) {
newData = g_RomFile + (uintptr_t)seg->data;
seg->source = SRC_ROM;
sysLogPrintf(LOG_NOTE, "loading segment %s from ROM (offset %08x pointer %p)", seg->name, (u32)seg->data, newData);
} else {
sysFatalError("No ROM or external file for segment:\n%s", seg->name);
}
} else {
// loaded external data
seg->source = SRC_EXTERNAL;
sysLogPrintf(LOG_NOTE, "loading segment %s from file (pointer %p)", seg->name, newData);
}
seg->data = newData;
if (seg->segstart) {
*seg->segstart = seg->data;
}
if (seg->segend) {
*seg->segend = seg->data + seg->size;
}
// call the post load function if any
if (seg->preprocess && !seg->preprocessed) {
seg->preprocess(seg->data, seg->size);
seg->preprocessed = 1;
}
}
static inline s32 romdataLoadExternalFileList(void)
{
romDataSeg = fsFileLoad("filenames.lst", &romDataSegSize); // this null terminates the file by itself
if (!romDataSeg || !romDataSegSize) {
return 0;
}
s32 n = 1;
char *p = (char *)romDataSeg;
while (*p && n < ROMDATA_MAX_FILES) {
// skip whitespace
while (*p && isspace(*p)) ++p;
if (*p) {
const char *start = p;
// skip to next whitespace or end of file
while (*p && !isspace(*p)) ++p;
// null terminate the name if needed
if (*p) {
*p++ = '\0';
}
fileSlots[n++].name = start;
}
}
return n - 1;
}
static inline void romdataInitFiles(void)
{
if (!g_RomFile) {
// no ROM; try to load the file name list from disk
if (!romdataLoadExternalFileList()) {
sysFatalError("No ROM file or external filename table found.");
}
return;
}
// the file offset table is in the data seg
const u32 *offsets = (u32 *)(romDataSeg + ROMDATA_FILES_OFS);
u32 i;
for (i = 1; offsets[i]; ++i) {
if (offsets + i + 1 < (u32 *)(romDataSeg + romDataSegSize)) {
const u32 nextofs = PD_BE32(offsets[i + 1]);
const u32 ofs = PD_BE32(offsets[i]);
fileSlots[i].data = g_RomFile + ofs;
fileSlots[i].size = nextofs - ofs;
fileSlots[i].source = SRC_UNLOADED;
fileSlots[i].preprocessed = 0;
}
}
// last offset is to the name table
const u32 *nameOffsets = (u32 *)(g_RomFile + PD_BE32(offsets[i - 1]));
for (i = 1; nameOffsets[i]; ++i) {
const u32 ofs = PD_BE32(nameOffsets[i]);
fileSlots[i].name = (const char *)nameOffsets + ofs; // ofs is relative to the start of the name table
}
}
static inline struct romfile *romdataGetSeg(const char *name)
{
struct romfile *seg = romSegs;
while (seg->name && strcmp(name, seg->name)) {
++seg;
}
return seg;
}
s32 romdataInit(void)
{
const char *altRomName = sysArgGetString("--rom-file");
if (altRomName) {
g_RomName = altRomName;
}
romdataLoadRom();
// set segments to point to the rom or load them externally
for (struct romfile *seg = romSegs; seg->name; ++seg) {
romdataInitSegment(seg);
}
// load file table from the files segment
romdataInitFiles();
sysLogPrintf(LOG_NOTE, "romdataInit: loaded rom, size = %u", g_RomFileSize);
return 0;
}
s32 romdataFileGetSize(s32 fileNum)
{
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
sysLogPrintf(LOG_ERROR, "romdataFileGetSize: invalid file num %d", fileNum);
return -1;
}
// ensure any external files are loaded and we use their size
if (romdataFileLoad(fileNum, NULL)) {
return fileSlots[fileNum].size;
}
sysLogPrintf(LOG_ERROR, "romdataFileGetSize: could not load file num %d", fileNum);
return -1;
}
u8 *romdataFileGetData(s32 fileNum)
{
return romdataFileLoad(fileNum, NULL);
}
u8 *romdataFileLoad(s32 fileNum, u32 *outSize)
{
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
sysLogPrintf(LOG_ERROR, "romdataFileLoad: invalid file num %d", fileNum);
return NULL;
}
u8 *out = NULL;
// try to load external file
if (fileSlots[fileNum].source == SRC_UNLOADED) {
char tmp[FS_MAXPATH] = { 0 };
snprintf(tmp, sizeof(tmp), ROMDATA_FILEDIR "/%s", fileSlots[fileNum].name);
if (fsFileSize(tmp) > 0) {
u32 size = 0;
out = fsFileLoad(tmp, &size);
if (out && size) {
sysLogPrintf(LOG_NOTE, "file %d (%s) loaded externally", fileNum, fileSlots[fileNum].name);
fileSlots[fileNum].data = out;
fileSlots[fileNum].size = size;
fileSlots[fileNum].source = SRC_EXTERNAL;
// external file; do not apply patches to this
fileSlots[fileNum].numpatches = 0;
}
}
// tried and failed, fall back to ROM
fileSlots[fileNum].source = SRC_ROM;
}
if (!out) {
out = fileSlots[fileNum].data;
}
if (out && outSize) {
*outSize = fileSlots[fileNum].size;
}
return out;
}
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size)
{
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
sysLogPrintf(LOG_ERROR, "romdataFilePreprocess: invalid file num %d", fileNum);
return;
}
if (data && size /* && !fileSlots[fileNum].preprocessed*/) {
if (loadType && loadType < (u32)ARRAYCOUNT(filePreprocFuncs) && filePreprocFuncs[loadType]) {
// apply patches
for (u32 i = 0; i < fileSlots[fileNum].numpatches; ++i) {
const struct romfilepatch *p = &fileSlots[fileNum].patches[i];
if (!memcmp(data + p->ofs, p->src, p->len)) {
memcpy(data + p->ofs, p->dst, p->len);
sysLogPrintf(LOG_NOTE, "file %d (%s) patched at offset 0x%x", fileNum, fileSlots[fileNum].name, p->ofs);
}
}
// then preprocess
filePreprocFuncs[loadType](data, size);
// fileSlots[fileNum].preprocessed = 1;
}
}
}
void romdataFileFree(s32 fileNum)
{
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
sysLogPrintf(LOG_ERROR, "fsFileFree: invalid file num %d", fileNum);
return;
}
if (fileSlots[fileNum].source == SRC_EXTERNAL) {
sysMemFree(fileSlots[fileNum].data);
fileSlots[fileNum].data = NULL;
}
fileSlots[fileNum].source = SRC_UNLOADED;
}
const char *romdataFileGetName(s32 fileNum)
{
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
return NULL;
}
return fileSlots[fileNum].name;
}
s32 romdataFileGetNumForName(const char *name)
{
if (!name || !name[0]) {
return -1;
}
for (s32 i = 0; i < ROMDATA_MAX_FILES; ++i) {
if (fileSlots[i].name && !strcmp(fileSlots[i].name, name)) {
return i;
}
}
return -1;
}
u8 *romdataSegGetData(const char *segName)
{
return romdataGetSeg(segName)->data;
}
u8 *romdataSegGetDataEnd(const char *segName)
{
struct romfile *seg = romdataGetSeg(segName);
return seg->data + seg->size;
}
u32 romdataSegGetSize(const char *segName)
{
return romdataGetSeg(segName)->size;
}
+324
View File
@@ -0,0 +1,324 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <sys/time.h>
#include <SDL.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "console.h"
#include "system.h"
#ifdef PLATFORM_WIN32
#include <windows.h>
// on win32 we use waitable timers instead of nanosleep
typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD);
static HANDLE timer;
static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA;
// winapi also provides a yield macro
#define DO_YIELD() YieldProcessor()
// ask system for high performance GPU, if any
__attribute__((dllexport)) u32 NvOptimusEnablement = 1;
__attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1;
#else
#include <unistd.h>
// figure out how to yield
#if defined(PLATFORM_X86) || defined(PLATFORM_X86_64)
// this should work even if the code is not built with SSE enabled, at least on gcc and clang,
// but if it doesn't we'll have to use __builtin_ia32_pause() or something
#include <immintrin.h>
#define DO_YIELD() _mm_pause()
#elif defined(PLATFORM_ARM)
// same as YieldProcessor() on ARM Windows
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
#else
// fuck it
#define DO_YIELD() do { } while (0)
#endif
#endif
#define LOG_FNAME "pd.log"
#define CRASHLOG_FNAME "pd.crash.log"
#define USEC_IN_SEC 1000000ULL
static u64 startTick = 0;
static char logPath[2048];
static s32 sysArgc;
static const char **sysArgv;
static inline void sysLogSetPath(const char *fname)
{
// figure out where the log is and clear it
// try working dir first
snprintf(logPath, sizeof(logPath), "./%s", fname);
FILE *f = fopen(logPath, "wb");
if (!f) {
// try home dir
sysGetHomePath(logPath, sizeof(logPath) - 1);
strncat(logPath, "/", sizeof(logPath) - 1);
strncat(logPath, fname, sizeof(logPath) - 1);
f = fopen(logPath, "wb");
}
if (f) {
fclose(f);
}
}
void sysInitArgs(s32 argc, const char **argv)
{
sysArgc = argc;
sysArgv = argv;
}
void sysInit(void)
{
startTick = sysGetMicroseconds();
if (sysArgCheck("--log")) {
sysLogSetPath(LOG_FNAME);
}
#ifdef VERSION_HASH
sysLogPrintf(LOG_NOTE, "version: " VERSION_BRANCH " " VERSION_HASH " (" VERSION_TARGET ")");
#endif
char timestr[256];
const time_t curtime = time(NULL);
strftime(timestr, sizeof(timestr), "%d %b %Y %H:%M:%S", localtime(&curtime));
sysLogPrintf(LOG_NOTE, "startup date: %s", timestr);
#ifdef PLATFORM_WIN32
// this function is only present on Vista+, so try to import it from kernel32 by hand
pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA");
if (pfnCreateWaitableTimerExA) {
// function exists, try to create a hires timer
timer = pfnCreateWaitableTimerExA(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
}
if (!timer) {
// no function or hires timers not supported, fallback to lower resolution timer
sysLogPrintf(LOG_WARNING, "SYS: hires waitable timers not available");
timer = CreateWaitableTimerA(NULL, FALSE, NULL);
}
#endif
}
s32 sysArgCheck(const char *arg)
{
for (s32 i = 1; i < sysArgc; ++i) {
if (!strcasecmp(sysArgv[i], arg)) {
return 1;
}
}
return 0;
}
const char *sysArgGetString(const char *arg)
{
for (s32 i = 1; i < sysArgc; ++i) {
if (!strcasecmp(sysArgv[i], arg)) {
if (i < sysArgc - 1) {
return sysArgv[i + 1];
}
}
}
return NULL;
}
s32 sysArgGetInt(const char *arg, s32 defval)
{
for (s32 i = 1; i < sysArgc; ++i) {
if (!strcasecmp(sysArgv[i], arg)) {
if (i < sysArgc - 1) {
return strtol(sysArgv[i + 1], NULL, 0);
}
}
}
return defval;
}
u64 sysGetMicroseconds(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return ((u64)tv.tv_sec * USEC_IN_SEC + (u64)tv.tv_usec) - startTick;
}
float sysGetSeconds(void)
{
u64 t = sysGetMicroseconds();
return (f32)t / 1000000.f;
}
s32 sysLogIsOpen(void)
{
return (logPath[0] != '\0');
}
void sysLogPrintf(s32 level, const char *fmt, ...)
{
static const char *prefix[3] = {
"", "WARNING: ", "ERROR: "
};
char logmsg[2048];
va_list ap;
va_start(ap, fmt);
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
va_end(ap);
if (logPath[0]) {
FILE *f = fopen(logPath, "ab");
if (f) {
fprintf(f, "%s%s\n", prefix[level], logmsg);
fclose(f);
}
}
FILE *fout = ((level & 0x0f) == LOG_NOTE) ? stdout : stderr;
fprintf(fout, "%s%s\n", prefix[level & 0x0f], logmsg);
fflush(fout);
if ((level & LOGFLAG_NOCON) == 0) {
conPrintLn((level & LOGFLAG_SHOWMSG) != 0, logmsg);
}
}
void sysFatalError(const char *fmt, ...)
{
static s32 alreadyCrashed = 0;
if (alreadyCrashed) {
abort();
}
char errmsg[2048] = { 0 };
alreadyCrashed = 1;
va_list ap;
va_start(ap, fmt);
vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
va_end(ap);
sysLogPrintf(LOG_ERROR, "FATAL: %s", errmsg);
fflush(stdout);
fflush(stderr);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error", errmsg, NULL);
exit(1);
}
void sysGetExecutablePath(char *outPath, const u32 outLen)
{
// try asking SDL
char *sdlPath = SDL_GetBasePath();
if (sdlPath && *sdlPath) {
// -1 to trim trailing slash
const u32 len = strlen(sdlPath) - 1;
if (len < outLen) {
memcpy(outPath, sdlPath, len);
outPath[len] = '\0';
}
} else if (sysArgc && sysArgv[0] && sysArgv[0][0]) {
// get exe path from argv[0]
strncpy(outPath, sysArgv[0], outLen - 1);
outPath[outLen - 1] = '\0';
} else if (outLen > 1) {
// give up, use working directory instead
outPath[0] = '.';
outPath[1] = '\0';
}
#ifdef PLATFORM_WIN32
// replace all backslashes with forward slashes, windows supports both
for (u32 i = 0; i < outLen && outPath[i]; ++i) {
if (outPath[i] == '\\') {
outPath[i] = '/';
}
}
#endif
SDL_free(sdlPath);
}
void sysGetHomePath(char *outPath, const u32 outLen)
{
// try asking SDL
char *sdlPath = SDL_GetPrefPath("", "perfectdark");
if (sdlPath && *sdlPath) {
// -1 to trim trailing slash
const u32 len = strlen(sdlPath) - 1;
if (len < outLen) {
memcpy(outPath, sdlPath, len);
outPath[len] = '\0';
}
} else if (outLen > 1) {
// give up, use working directory instead
outPath[0] = '.';
outPath[1] = '\0';
}
#ifdef PLATFORM_WIN32
// replace all backslashes with forward slashes, windows supports both
for (u32 i = 0; i < outLen && outPath[i]; ++i) {
if (outPath[i] == '\\') {
outPath[i] = '/';
}
}
#endif
SDL_free(sdlPath);
}
void *sysMemAlloc(const u32 size)
{
return malloc(size);
}
void *sysMemZeroAlloc(const u32 size)
{
return calloc(1, size);
}
void sysMemFree(void *ptr)
{
free(ptr);
}
void sysSleep(const s64 hns)
{
#ifdef PLATFORM_WIN32
static LARGE_INTEGER li;
li.QuadPart = -hns;
SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE);
WaitForSingleObject(timer, INFINITE);
#else
const struct timespec spec = { 0, hns * 100 };
nanosleep(&spec, NULL);
#endif
}
void sysCpuRelax(void)
{
DO_YIELD();
}
+198
View File
@@ -0,0 +1,198 @@
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "system.h"
#include "utils.h"
static inline bool isSingleCharToken(const s32 ch)
{
switch (ch) {
case '{':
case '}':
case '[':
case ']':
case '(':
case ')':
case ',':
case '\'':
case '=':
return true;
default:
return false;
}
}
char *strFmt(const char *fmt, ...)
{
static char buf[4096];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
char *strRightTrim(char *str)
{
if (!str) {
return NULL;
}
const s32 len = strlen(str);
for (s32 i = len - 1; i >= 0 && isspace(str[i]); --i) {
str[i] = '\0';
}
return str;
}
char *strTrim(char *str)
{
if (!str) {
return NULL;
}
// left trim
while (*str && (u8)*str < ' ') {
++str;
}
// right trim
const s32 len = strlen(str);
for (s32 i = len - 1; i > 0 && isspace(str[i]); --i) {
str[i] = '\0';
}
return str;
}
char *strUnquote(char *str)
{
if (!str) {
return NULL;
}
if (*str == '"') {
++str;
}
char *end = strrchr(str, '"');
if (end && end[1] == '\0') {
*end = '\0';
}
return str;
}
char *strParseToken(char *str, char *out, s32 *outCount)
{
if (outCount) {
*outCount = 0;
}
if (!out) {
return NULL;
}
out[0] = '\0';
if (!str) {
return NULL;
}
s32 cnt = 0;
while (*str) {
// skip whitespace and other garbage
while (*str && (u8)*str <= ' ') {
++str;
}
if (!*str) {
// just whitespace
return NULL;
}
// skip #, ; and // comments
if (*str == ';' || *str == '#' || (str[0] == '/' && str[1] == '/')) {
while (*str && *str != '\n') {
++str;
}
continue;
}
if (*str == '"') {
// quoted string; treat it as an entire token, including the quotes
out[cnt++] = *str++;
while (true) {
if (*str == '\0') {
// unterminated quoted string
break;
}
if (str[0] == '\\' && str[1] == '"') {
// escaped quote; add to token
if (cnt + 1 < UTIL_MAX_TOKEN) {
out[cnt++] = str[1];
}
str += 2;
continue;
}
// add char to token
const s32 ch = (u8)*str++;
if (cnt + 1 < UTIL_MAX_TOKEN) {
out[cnt++] = ch;
}
if (ch == '"') {
// ch was the closing quote
break;
}
}
break;
}
if (isSingleCharToken(*str)) {
// single char token
out[cnt++] = *str++;
break;
}
// regular single word
do {
if (cnt + 1 < UTIL_MAX_TOKEN) {
out[cnt++] = *str++;
}
if (isSingleCharToken(*str)) {
break;
}
} while ((u8)*str > ' ');
break;
}
out[cnt] = '\0';
if (outCount) {
*outCount = cnt;
}
return str;
}
char *strDuplicate(const char *str)
{
if (!str) {
return NULL;
}
const u32 len = strlen(str);
char *out = sysMemAlloc(len + 1);
if (out) {
memcpy(out, str, len + 1);
}
return out;
}
+300
View File
@@ -0,0 +1,300 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <PR/ultratypes.h>
#include <PR/gbi.h>
#include "platform.h"
#include "config.h"
#include "video.h"
#include "../fast3d/gfx_api.h"
#include "../fast3d/gfx_sdl.h"
#include "../fast3d/gfx_opengl.h"
static struct GfxWindowManagerAPI *wmAPI;
static struct GfxRenderingAPI *renderingAPI;
static bool initDone = false;
static s32 vidWidth = 640;
static s32 vidHeight = 480;
static s32 vidFramebuffers = true;
static s32 vidFullscreen = false;
static s32 vidFullscreenExclusive = false;
static s32 vidMaximize = false;
static s32 vidAllowHiDpi = false;
static s32 vidVsync = 1;
static s32 vidMSAA = 1;
static s32 vidFramerateLimit = 0;
static s32 texFilter = FILTER_LINEAR;
static s32 texFilter2D = true;
static s32 texDetail = true;
static u32 dlcount = 0;
static u32 frames = 0;
static u32 framesPerSec = 0;
static f64 startTime, endTime, fpsTime;
s32 videoInit(void)
{
wmAPI = &gfx_sdl;
renderingAPI = &gfx_opengl_api;
gfx_current_native_viewport.width = 320;
gfx_current_native_viewport.height = 220;
gfx_current_native_aspect = 320.f / 220.f;
gfx_framebuffers_enabled = (bool)vidFramebuffers;
gfx_detail_textures_enabled = (bool)texDetail;
gfx_msaa_level = vidMSAA;
struct GfxInitSettings set = {
.wapi = wmAPI,
.rapi = renderingAPI,
.window_settings = {
.title = "Perfect Dark",
.width = vidWidth,
.height = vidHeight,
.x = 100,
.y = 100,
.fullscreen = vidFullscreen,
.fullscreen_is_exclusive = vidFullscreenExclusive,
.maximized = vidMaximize,
.allow_hidpi = vidAllowHiDpi
}
};
gfx_init(&set);
if (!wmAPI->set_swap_interval(vidVsync)) {
vidVsync = 0;
}
if (vidVsync == 0 && vidFramerateLimit == 0) {
// cap FPS if there's no vsync to prevent the game from exploding
vidFramerateLimit = VIDEO_MAX_FPS;
}
wmAPI->set_target_fps(vidFramerateLimit); // disabled because vsync is on
renderingAPI->set_texture_filter((enum FilteringMode)texFilter);
initDone = true;
return 0;
}
void videoStartFrame(void)
{
if (initDone) {
startTime = wmAPI->get_time();
gfx_start_frame();
}
}
void videoSubmitCommands(Gfx *cmds)
{
if (initDone) {
gfx_run(cmds);
++dlcount;
}
}
void videoEndFrame(void)
{
if (!initDone) {
return;
}
gfx_end_frame();
endTime = wmAPI->get_time();
++frames;
++framesPerSec;
if (endTime >= fpsTime) {
char tmp[128];
snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", framesPerSec, endTime - startTime, frames);
wmAPI->set_window_title(tmp);
framesPerSec = 0;
fpsTime = endTime + 1.0;
}
}
void videoClearScreen(void)
{
videoStartFrame();
// TODO: clear
videoEndFrame();
}
void *videoGetWindowHandle(void)
{
if (initDone) {
return wmAPI->get_window_handle();
}
return NULL;
}
void videoUpdateNativeResolution(s32 w, s32 h)
{
gfx_current_native_viewport.width = w;
gfx_current_native_viewport.height = h;
gfx_current_native_aspect = (float)w / (float)h;
}
s32 videoGetNativeWidth(void)
{
return gfx_current_native_viewport.width;
}
s32 videoGetNativeHeight(void)
{
return gfx_current_native_viewport.height;
}
s32 videoGetWidth(void)
{
return gfx_current_dimensions.width;
}
s32 videoGetHeight(void)
{
return gfx_current_dimensions.height;
}
s32 videoGetFullscreen(void)
{
return vidFullscreen;
}
s32 videoGetMaximizeWindow(void)
{
return vidMaximize;
}
f32 videoGetAspect(void)
{
return gfx_current_dimensions.aspect_ratio;
}
s32 videoGetTextureFilter2D(void)
{
return texFilter2D;
}
u32 videoGetTextureFilter(void)
{
return texFilter;
}
s32 videoGetDetailTextures(void)
{
return texDetail;
}
void videoSetWindowOffset(s32 x, s32 y)
{
gfx_current_game_window_viewport.x = x;
gfx_current_game_window_viewport.y = y;
}
void videoSetFullscreen(s32 fs)
{
if (fs != vidFullscreen) {
vidFullscreen = !!fs;
wmAPI->set_fullscreen(vidFullscreen);
}
}
void videoSetMaximizeWindow(s32 fs)
{
if (fs != vidMaximize) {
vidMaximize = !!fs;
wmAPI->set_maximize(vidMaximize);
}
}
void videoSetTextureFilter(u32 filter)
{
if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT;
texFilter = filter;
renderingAPI->set_texture_filter((enum FilteringMode)filter);
}
void videoSetTextureFilter2D(s32 filter)
{
texFilter2D = !!filter;
}
void videoSetDetailTextures(s32 detail)
{
texDetail = !!detail;
gfx_detail_textures_enabled = (bool)texDetail;
}
void videoCapFramerate(s32 limit)
{
if (vidFramerateLimit > 0 && vidFramerateLimit < limit) {
limit = vidFramerateLimit;
}
wmAPI->set_target_fps(limit ? limit : vidFramerateLimit);
}
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
{
return gfx_create_framebuffer(w, h, upscale, autoresize);
}
void videoSetFramebuffer(s32 target)
{
return gfx_set_framebuffer(target, 1.f);
}
void videoResetFramebuffer(void)
{
return gfx_reset_framebuffer();
}
s32 videoFramebuffersSupported(void)
{
return gfx_framebuffers_enabled;
}
void videoResizeFramebuffer(s32 target, u32 w, u32 h, s32 upscale, s32 autoresize)
{
gfx_resize_framebuffer(target, w, h, upscale, autoresize);
}
void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top)
{
// assume immediate copies always read the front buffer
gfx_copy_framebuffer(dst, src, left, top, false);
}
void videoResetTextureCache(void)
{
gfx_texture_cache_clear();
}
void videoFreeCachedTexture(const void *texptr)
{
gfx_texture_cache_delete(texptr);
}
PD_CONSTRUCTOR static void videoConfigInit(void)
{
configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1);
configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1);
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1);
configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1);
configRegisterInt("Video.VSync", &vidVsync, -1, 10);
configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1);
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
configRegisterInt("Video.DetailTextures", &texDetail, 0, 1);
}
+2 -2
View File
@@ -57,7 +57,7 @@ s32 func0f096890(s32 arg0)
return value - (((value - nextvalue) * (arg0 & mask)) >> shiftamount); return value - (((value - nextvalue) * (arg0 & mask)) >> shiftamount);
} }
u16 acos(s16 arg0) u16 acosx(s16 arg0)
{ {
s32 value = arg0 >= 0 ? arg0 : -arg0; s32 value = arg0 >= 0 ? arg0 : -arg0;
@@ -70,7 +70,7 @@ u16 acos(s16 arg0)
return value; return value;
} }
s16 asin(s16 arg0) s16 asinx(s16 arg0)
{ {
s32 value = arg0 >= 0 ? arg0 : -arg0; s32 value = arg0 >= 0 ? arg0 : -arg0;
+2 -2
View File
@@ -17,7 +17,7 @@ f32 acosf(f32 value)
intval = value * 32767.0f; intval = value * 32767.0f;
} }
return acos(intval) * M_PI / 65535.0f; return acosx(intval) * M_PI / 65535.0f;
} }
f32 asinf(f32 value) f32 asinf(f32 value)
@@ -32,5 +32,5 @@ f32 asinf(f32 value)
intval = value * 32767.0f; intval = value * 32767.0f;
} }
return asin(intval) * M_PI / 65535.0f; return asinx(intval) * M_PI / 65535.0f;
} }
+50 -48
View File
@@ -26,7 +26,7 @@
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
struct activemenu g_AmMenus[MAX_PLAYERS]; struct activemenu g_AmMenus[MAX_LOCAL_PLAYERS];
struct fontchar *g_AmFont1; struct fontchar *g_AmFont1;
struct font *g_AmFont2; struct font *g_AmFont2;
s32 g_AmIndex; s32 g_AmIndex;
@@ -90,19 +90,8 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
switch (operation) { switch (operation) {
case MENUOP_GETOPTIONCOUNT: case MENUOP_GETOPTIONCOUNT:
if (g_AmMenus[g_AmIndex].prevallbots) { if (g_AmMenus[g_AmIndex].prevallbots) {
// All bots: num bot opponents + all human players // All bots
s32 count = 0; data->list.value = g_MpNumChrs;
s32 i;
struct chrdata *playerchr = g_Vars.currentplayer->prop->chr;
for (i = PLAYERCOUNT(); i < g_MpNumChrs; i++) {
if (g_MpAllChrPtrs[i]->team != playerchr->team) {
count++;
}
}
count += PLAYERCOUNT();
data->list.value = count;
} else { } else {
// Single bot: All except the bot itself // Single bot: All except the bot itself
data->list.value = g_MpNumChrs - 1; data->list.value = g_MpNumChrs - 1;
@@ -125,9 +114,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
chrindex++; chrindex++;
if (g_AmMenus[g_AmIndex].prevallbots) { if (g_AmMenus[g_AmIndex].prevallbots) {
if (playerchr == g_MpAllChrPtrs[chrindex] || playerchr->team != g_MpAllChrPtrs[chrindex]->team) {
numremaining--; numremaining--;
}
} else { } else {
if (botchr != g_MpAllChrPtrs[chrindex]) { if (botchr != g_MpAllChrPtrs[chrindex]) {
numremaining--; numremaining--;
@@ -139,8 +126,10 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
g_AmMenus[g_AmIndex].prevallbots = false; g_AmMenus[g_AmIndex].prevallbots = false;
for (i = 0; i < g_Vars.currentplayer->numaibuddies; i++) { for (i = 0; i < g_Vars.currentplayer->numaibuddies; i++) {
if (g_Vars.currentplayer->aibuddynums[i] != chrindex) {
botApplyAttack(g_MpAllChrPtrs[g_Vars.currentplayer->aibuddynums[i]], g_MpAllChrPtrs[chrindex]->prop); botApplyAttack(g_MpAllChrPtrs[g_Vars.currentplayer->aibuddynums[i]], g_MpAllChrPtrs[chrindex]->prop);
} }
}
} else { } else {
botApplyAttack(botchr, g_MpAllChrPtrs[chrindex]->prop); botApplyAttack(botchr, g_MpAllChrPtrs[chrindex]->prop);
} }
@@ -167,9 +156,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
chrindex++; chrindex++;
if (g_AmMenus[g_AmIndex].prevallbots) { if (g_AmMenus[g_AmIndex].prevallbots) {
if (playerchr == g_MpAllChrPtrs[chrindex] || playerchr->team != g_MpAllChrPtrs[chrindex]->team) {
numremaining--; numremaining--;
}
} else { } else {
if (botchr != g_MpAllChrPtrs[chrindex]) { if (botchr != g_MpAllChrPtrs[chrindex]) {
numremaining--; numremaining--;
@@ -364,7 +351,11 @@ void amApply(s32 slot)
bgunEquipWeapon2(HAND_RIGHT, weaponnum); bgunEquipWeapon2(HAND_RIGHT, weaponnum);
} }
if (bgunGetWeaponNum(HAND_LEFT) != WEAPON_NONE) { // don't unequip detonator
// if we already have it equipped
if (weaponnum == WEAPON_REMOTEMINE) {
bgunEquipWeapon2(HAND_LEFT, weaponnum);
} else if (bgunGetWeaponNum(HAND_LEFT) != WEAPON_NONE) {
bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE); bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE);
} }
} }
@@ -556,7 +547,7 @@ void amReset(void)
g_AmFont1 = g_CharsHandelGothicSm; g_AmFont1 = g_CharsHandelGothicSm;
g_AmFont2 = g_FontHandelGothicSm; g_AmFont2 = g_FontHandelGothicSm;
#else #else
if (PLAYERCOUNT() >= 2) { if (LOCALPLAYERCOUNT() >= 2) {
g_AmFont1 = g_CharsHandelGothicXs; g_AmFont1 = g_CharsHandelGothicXs;
g_AmFont2 = g_FontHandelGothicXs; g_AmFont2 = g_FontHandelGothicXs;
} else { } else {
@@ -587,7 +578,7 @@ s16 amCalculateSlotWidth(void)
} }
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (PLAYERCOUNT() > 1) { if (LOCALPLAYERCOUNT() > 1) {
max += 3; max += 3;
} else { } else {
max += 4; max += 4;
@@ -771,32 +762,32 @@ void amClose(void)
bool amIsCramped(void) bool amIsCramped(void)
{ {
#if VERSION == VERSION_JPN_FINAL #if VERSION == VERSION_JPN_FINAL
if (PLAYERCOUNT() >= 3 && g_AmMenus[g_AmIndex].screenindex != 1) { if (LOCALPLAYERCOUNT() >= 3 && g_AmMenus[g_AmIndex].screenindex != 1) {
return true; return true;
} }
if (IS4MB() && PLAYERCOUNT() == 2) { if (IS4MB() && LOCALPLAYERCOUNT() == 2) {
return true; return true;
} }
if (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL if (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL
&& PLAYERCOUNT() == 2 && LOCALPLAYERCOUNT() == 2
&& g_AmMenus[g_AmIndex].screenindex != 1) { && g_AmMenus[g_AmIndex].screenindex != 1) {
return true; return true;
} }
return false; return false;
#else #else
return (g_AmMenus[g_AmIndex].screenindex == 0 && PLAYERCOUNT() >= 3) return (g_AmMenus[g_AmIndex].screenindex == 0 && LOCALPLAYERCOUNT() >= 3)
|| (IS4MB() && PLAYERCOUNT() == 2) || (IS4MB() && LOCALPLAYERCOUNT() == 2)
|| (PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL); || (LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL);
#endif #endif
} }
void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y) void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
{ {
#if VERSION == VERSION_JPN_FINAL #if VERSION == VERSION_JPN_FINAL
s32 playercount = PLAYERCOUNT(); s32 playercount = LOCALPLAYERCOUNT();
*x = g_AmMenus[g_AmIndex].xradius * (column - 1); *x = g_AmMenus[g_AmIndex].xradius * (column - 1);
*y = (row - 1) * 50; *y = (row - 1) * 50;
@@ -850,7 +841,7 @@ void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
} }
} }
#elif VERSION >= VERSION_NTSC_1_0 #elif VERSION >= VERSION_NTSC_1_0
s32 playercount = PLAYERCOUNT(); s32 playercount = LOCALPLAYERCOUNT();
*x = g_AmMenus[g_AmIndex].xradius * (column - 1); *x = g_AmMenus[g_AmIndex].xradius * (column - 1);
*y = (row - 1) * 50; *y = (row - 1) * 50;
@@ -902,7 +893,7 @@ void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
} }
} }
#else #else
s32 playercount = PLAYERCOUNT(); s32 playercount = LOCALPLAYERCOUNT();
*x = g_AmMenus[g_AmIndex].xradius * (column - 1); *x = g_AmMenus[g_AmIndex].xradius * (column - 1);
*y = (row - 1) * 50; *y = (row - 1) * 50;
@@ -982,15 +973,15 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
#endif #endif
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (PLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) { if (LOCALPLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
wide = true; wide = true;
} }
#endif #endif
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if ((PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || PLAYERCOUNT() >= 3) if ((LOCALPLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || LOCALPLAYERCOUNT() >= 3)
#else #else
if ((PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || PLAYERCOUNT() >= 3) if ((LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || LOCALPLAYERCOUNT() >= 3)
#endif #endif
{ {
if ((g_Vars.currentplayernum % 2) == 0) { if ((g_Vars.currentplayernum % 2) == 0) {
@@ -1023,7 +1014,7 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
- (s32)(textwidth * 0.5f) - (s32)(textwidth * 0.5f)
+ offset; + offset;
if (PLAYERCOUNT() >= 2) { if (LOCALPLAYERCOUNT() >= 2) {
y = viGetViewTop() + 5; y = viGetViewTop() + 5;
} else { } else {
y = viGetViewTop() + 10; y = viGetViewTop() + 10;
@@ -1039,12 +1030,12 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
gdl = func0f1574d0jf(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1, gdl = func0f1574d0jf(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1,
0x000000ff, SCREEN_320, SCREEN_240, 0, 0); 0x000000ff, SCREEN_320, SCREEN_240, 0, 0);
y += (PLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f); y += (LOCALPLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
#else #else
gdl = textRender(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1, gdl = textRender(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1,
0x000000ff, SCREEN_320, SCREEN_240, 0, 0); 0x000000ff, SCREEN_320, SCREEN_240, 0, 0);
y += (PLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f); y += (LOCALPLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
textMeasure(&textheight, &textwidth, weaponname, g_AmFont1, g_AmFont2, 0); textMeasure(&textheight, &textwidth, weaponname, g_AmFont1, g_AmFont2, 0);
x = viGetViewLeft() / g_ScaleX x = viGetViewLeft() / g_ScaleX
@@ -1073,7 +1064,7 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
- (s32)(textwidth * 0.5f) - (s32)(textwidth * 0.5f)
+ offset; + offset;
if (PLAYERCOUNT() >= 2) { if (LOCALPLAYERCOUNT() >= 2) {
y = viGetViewTop() + 5; y = viGetViewTop() + 5;
} else { } else {
y = viGetViewTop() + 10; y = viGetViewTop() + 10;
@@ -1132,7 +1123,7 @@ Gfx *amRenderSlot(Gfx *gdl, char *text, s16 x, s16 y, s32 mode, s32 flags)
paddingtop = 6; paddingtop = 6;
paddingbottom = 6; paddingbottom = 6;
if (PLAYERCOUNT() >= 2) { if (LOCALPLAYERCOUNT() >= 2) {
paddingtop = 5; paddingtop = 5;
paddingbottom = 3; paddingbottom = 3;
} }
@@ -1270,6 +1261,13 @@ Gfx *amRender(Gfx *gdl)
g_ScaleX = g_ViRes == VIRES_HI ? 2 : 1; g_ScaleX = g_ViRes == VIRES_HI ? 2 : 1;
#endif #endif
#ifndef PLATFORM_N64
const s32 playercount = LOCALPLAYERCOUNT();
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
}
#endif
g_AmIndex = g_Vars.currentplayernum; g_AmIndex = g_Vars.currentplayernum;
g_Vars.currentplayer->commandingaibot = NULL; g_Vars.currentplayer->commandingaibot = NULL;
@@ -1368,8 +1366,8 @@ Gfx *amRender(Gfx *gdl)
vertices[6].colour = 4; vertices[6].colour = 4;
vertices[7].colour = 4; vertices[7].colour = 4;
colours[0].word = 0x22222200; colours[0].word = PD_BE32(0x22222200);
colours[1].word = 0x0000004f; colours[1].word = PD_BE32(0x0000004f);
gSPColor(gdl++, osVirtualToPhysical(colours), 2); gSPColor(gdl++, osVirtualToPhysical(colours), 2);
gSPVertex(gdl++, osVirtualToPhysical(vertices), 8, 0); gSPVertex(gdl++, osVirtualToPhysical(vertices), 8, 0);
@@ -1489,7 +1487,7 @@ Gfx *amRender(Gfx *gdl)
above = 6; above = 6;
below = 6; below = 6;
if (PLAYERCOUNT() >= 2) { if (LOCALPLAYERCOUNT() >= 2) {
above = 5; above = 5;
below = 3; below = 3;
} }
@@ -1512,7 +1510,7 @@ Gfx *amRender(Gfx *gdl)
halfwidth = 1; halfwidth = 1;
above = 2; above = 2;
below = 0; below = 0;
} else if (PLAYERCOUNT() >= 2) { } else if (LOCALPLAYERCOUNT() >= 2) {
s32 textheight; s32 textheight;
s32 textwidth; s32 textwidth;
char text[32]; char text[32];
@@ -1594,16 +1592,16 @@ Gfx *amRender(Gfx *gdl)
} }
#endif #endif
barwidth = PLAYERCOUNT() >= 2 ? 48 : 64; barwidth = LOCALPLAYERCOUNT() >= 2 ? 48 : 64;
barheight = PLAYERCOUNT() >= 2 ? 7 : 11; barheight = LOCALPLAYERCOUNT() >= 2 ? 7 : 11;
xoffset = 0; xoffset = 0;
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if ((PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || PLAYERCOUNT() >= 3) { if ((LOCALPLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || LOCALPLAYERCOUNT() >= 3) {
xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8; xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8;
} }
if (PLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) { if (LOCALPLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
part1left = viGetViewLeft() / g_ScaleX + 32; part1left = viGetViewLeft() / g_ScaleX + 32;
} else { } else {
part1left = (s32) ((viGetViewWidth() / g_ScaleX) * 0.5f) part1left = (s32) ((viGetViewWidth() / g_ScaleX) * 0.5f)
@@ -1612,7 +1610,7 @@ Gfx *amRender(Gfx *gdl)
+ xoffset; + xoffset;
} }
#else #else
if ((PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || PLAYERCOUNT() >= 3) { if ((LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || LOCALPLAYERCOUNT() >= 3) {
xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8; xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8;
} }
@@ -1638,7 +1636,7 @@ Gfx *amRender(Gfx *gdl)
gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
y = viGetViewTop() + viGetViewHeight() - (PLAYERCOUNT() >= 2 ? 19 : 34); y = viGetViewTop() + viGetViewHeight() - (LOCALPLAYERCOUNT() >= 2 ? 19 : 34);
// NTSC beta doesn't scale the health bar when hi-res is on, // NTSC beta doesn't scale the health bar when hi-res is on,
// and it only matches if part2left is an inline expression // and it only matches if part2left is an inline expression
@@ -1698,6 +1696,10 @@ Gfx *amRender(Gfx *gdl)
} }
#endif #endif
#ifndef PLATFORM_N64
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
#endif
g_ScaleX = 1; g_ScaleX = 1;
return gdl; return gdl;
+76 -55
View File
@@ -12,18 +12,22 @@
#include "lib/str.h" #include "lib/str.h"
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64
#include "game/player.h"
#include "input.h"
#endif
void amTick(void) void amTick(void)
{ {
s32 prevplayernum = g_Vars.currentplayernum; s32 prevplayernum = g_Vars.currentplayernum;
s32 i; s32 i;
for (i = 0; i < PLAYERCOUNT(); i++) { for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
setCurrentPlayerNum(i); setCurrentPlayerNum(i);
g_AmIndex = g_Vars.currentplayernum; g_AmIndex = g_Vars.currentplayernum;
if (g_AmMenus[g_AmIndex].togglefunc) { if (g_AmMenus[g_AmIndex].togglefunc) {
if (bgunConsiderToggleGunFunction(60, false, true) > 0) { if (bgunConsiderToggleGunFunction(60, false, true, 0) > 0) {
g_AmMenus[g_AmIndex].togglefunc = false; g_AmMenus[g_AmIndex].togglefunc = false;
} }
} else { } else {
@@ -40,15 +44,38 @@ void amTick(void)
s8 contpadnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex); s8 contpadnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
s32 numsamples = joyGetNumSamples(); s32 numsamples = joyGetNumSamples();
s32 j; s32 j;
u32 amask, lrtmask, umask, dmask, lmask, rmask;
if (controlmode == CONTROLMODE_PC) {
amask = D_JPAD;
lrtmask = R_TRIG;
umask = U_CBUTTONS;
dmask = D_CBUTTONS;
lmask = L_CBUTTONS;
rmask = R_CBUTTONS;
} else {
amask = A_BUTTON;
lrtmask = L_TRIG | R_TRIG;
umask = U_JPAD | U_CBUTTONS;
dmask = D_JPAD | D_CBUTTONS;
lmask = L_JPAD | L_CBUTTONS;
rmask = R_JPAD | R_CBUTTONS;
}
for (j = 0; j < numsamples; j++) { for (j = 0; j < numsamples; j++) {
s8 gotonextscreen = false; s8 gotonextscreen = false;
s8 cstickx = joyGetStickXOnSample(j, contpadnum); s8 cstickx = joyGetStickXOnSample(j, contpadnum);
s8 csticky = joyGetStickYOnSample(j, contpadnum); s8 csticky = joyGetStickYOnSample(j, contpadnum);
#ifdef AVOID_UB
// if cstickx is -128, it will get negated and stored into absstickx, negating it again if it's 8 bit
s32 absstickx;
s32 abssticky;
#else
s8 absstickx; s8 absstickx;
s8 abssticky; s8 abssticky;
u16 buttonsstate = joyGetButtonsOnSample(j, contpadnum, 0xffff); #endif
u16 buttonspressed = joyGetButtonsPressedOnSample(j, contpadnum, 0xffff); u32 buttonsstate = joyGetButtonsOnSample(j, contpadnum, 0xffffffff);
u32 buttonspressed = joyGetButtonsPressedOnSample(j, contpadnum, 0xffffffff);
bool stickpushed = false; bool stickpushed = false;
s32 slotnum; s32 slotnum;
bool stayopen; bool stayopen;
@@ -63,8 +90,28 @@ void amTick(void)
g_AmMenus[g_AmIndex].allbots = false; g_AmMenus[g_AmIndex].allbots = false;
#ifndef PLATFORM_N64
s32 newstickx = (s32)cstickx;
s32 newsticky = (s32)csticky;
if (j == 0 && g_Vars.currentplayernum == 0 && inputMouseIsLocked()) {
f32 mdx, mdy;
struct activemenu *am = &g_AmMenus[g_AmIndex];
inputMouseGetAbsScaledDelta(&mdx, &mdy);
if (mdx || mdy) {
am->mousex += mdx * PLAYER_EXTCFG().radialmenuspeed;
am->mousey += mdy * PLAYER_EXTCFG().radialmenuspeed;
am->mousex = (am->mousex > 127.f) ? 127.f : (am->mousex < -128.f) ? -128.f : am->mousex;
am->mousey = (am->mousey > 127.f) ? 127.f : (am->mousey < -128.f) ? -128.f : am->mousey;
}
newstickx += (s32)am->mousex;
newsticky -= (s32)am->mousey;
}
cstickx = (newstickx < -128) ? -128 : (newstickx > 127) ? 127 : newstickx;
csticky = (newsticky < -128) ? -128 : (newsticky > 127) ? 127 : newsticky;
#endif
if (g_Vars.currentplayer->activemenumode == AMMODE_EDIT) { if (g_Vars.currentplayer->activemenumode == AMMODE_EDIT) {
buttonsstate = buttonsstate & A_BUTTON; buttonsstate = buttonsstate & amask;
cstickx = 0; cstickx = 0;
csticky = 0; csticky = 0;
buttonspressed = 0; buttonspressed = 0;
@@ -72,12 +119,12 @@ void amTick(void)
// JPN fixes the bug that's documented in amChangeScreen // JPN fixes the bug that's documented in amChangeScreen
if (controlmode == CONTROLMODE_13 || controlmode == CONTROLMODE_14) { if (controlmode == CONTROLMODE_13 || controlmode == CONTROLMODE_14) {
if ((buttonsstate & R_TRIG) || (buttonsstate & L_TRIG)) { if (buttonsstate & (L_TRIG | R_TRIG)) {
stayopen = true; stayopen = true;
} }
if (buttonsstate & A_BUTTON) { if (buttonsstate & A_BUTTON) {
#if VERSION >= VERSION_JPN_FINAL #if VERSION >= VERSION_JPN_FINAL || !defined(PLATFORM_N64)
if (g_Vars.currentplayer->numaibuddies > 0) { if (g_Vars.currentplayer->numaibuddies > 0) {
g_AmMenus[g_AmIndex].allbots = true; g_AmMenus[g_AmIndex].allbots = true;
} }
@@ -86,12 +133,12 @@ void amTick(void)
#endif #endif
} }
} else { } else {
if (buttonsstate & A_BUTTON) { if (buttonsstate & amask) {
stayopen = true; stayopen = true;
} }
if ((buttonsstate & R_TRIG) || (buttonsstate & L_TRIG)) { if (buttonsstate & lrtmask) {
#if VERSION >= VERSION_JPN_FINAL #if VERSION >= VERSION_JPN_FINAL || !defined(PLATFORM_N64)
if (g_Vars.currentplayer->numaibuddies > 0) { if (g_Vars.currentplayer->numaibuddies > 0) {
g_AmMenus[g_AmIndex].allbots = true; g_AmMenus[g_AmIndex].allbots = true;
} }
@@ -118,35 +165,19 @@ void amTick(void)
amChangeScreen(0); amChangeScreen(0);
} }
if (buttonsstate & U_CBUTTONS) { if (buttonsstate & umask) {
row = 0; row = 0;
} }
if (buttonsstate & D_CBUTTONS) { if (buttonsstate & dmask) {
row = 2; row = 2;
} }
if (buttonsstate & L_CBUTTONS) { if (buttonsstate & lmask) {
column = 0; column = 0;
} }
if (buttonsstate & R_CBUTTONS) { if (buttonsstate & rmask) {
column = 2;
}
if (buttonsstate & U_JPAD) {
row = 0;
}
if (buttonsstate & D_JPAD) {
row = 2;
}
if (buttonsstate & L_JPAD) {
column = 0;
}
if (buttonsstate & R_JPAD) {
column = 2; column = 2;
} }
@@ -157,8 +188,8 @@ void amTick(void)
s8 contpadnum2 = optionsGetContpadNum2(g_Vars.currentplayerstats->mpindex); s8 contpadnum2 = optionsGetContpadNum2(g_Vars.currentplayerstats->mpindex);
s8 cstickx2 = joyGetStickXOnSample(j, contpadnum2); s8 cstickx2 = joyGetStickXOnSample(j, contpadnum2);
s8 csticky2 = joyGetStickYOnSample(j, contpadnum2); s8 csticky2 = joyGetStickYOnSample(j, contpadnum2);
u16 buttonsstate2 = joyGetButtonsOnSample(j, contpadnum2, 0xffff); u32 buttonsstate2 = joyGetButtonsOnSample(j, contpadnum2, 0xffffffff);
u16 buttonspressed2 = joyGetButtonsPressedOnSample(j, contpadnum2, 0xffff); u32 buttonspressed2 = joyGetButtonsPressedOnSample(j, contpadnum2, 0xffffffff);
if (g_Vars.currentplayer->activemenumode == AMMODE_EDIT) { if (g_Vars.currentplayer->activemenumode == AMMODE_EDIT) {
buttonsstate2 = buttonsstate2 & A_BUTTON; buttonsstate2 = buttonsstate2 & A_BUTTON;
@@ -175,35 +206,19 @@ void amTick(void)
toggle = true; toggle = true;
} }
if (buttonsstate2 & U_CBUTTONS) { if (buttonsstate2 & umask) {
row = 0; row = 0;
} }
if (buttonsstate2 & D_CBUTTONS) { if (buttonsstate2 & dmask) {
row = 2; row = 2;
} }
if (buttonsstate2 & L_CBUTTONS) { if (buttonsstate2 & lmask) {
column = 0; column = 0;
} }
if (buttonsstate2 & R_CBUTTONS) { if (buttonsstate2 & rmask) {
column = 2;
}
if (buttonsstate2 & U_JPAD) {
row = 0;
}
if (buttonsstate2 & D_JPAD) {
row = 2;
}
if (buttonsstate2 & L_JPAD) {
column = 0;
}
if (buttonsstate2 & R_JPAD) {
column = 2; column = 2;
} }
@@ -248,7 +263,7 @@ void amTick(void)
stayopen = false; stayopen = false;
} }
#if VERSION >= VERSION_NTSC_1_0 #if (VERSION >= VERSION_NTSC_1_0) && defined(PLATFORM_N64)
if (g_Vars.lvupdate240 == 0) { if (g_Vars.lvupdate240 == 0) {
stayopen = false; stayopen = false;
} }
@@ -369,6 +384,12 @@ void amTick(void)
} }
} }
} }
#ifndef PLATFORM_N64
else {
g_AmMenus[g_AmIndex].mousex = 0.f;
g_AmMenus[g_AmIndex].mousey = 0.f;
}
#endif
if (g_Vars.currentplayer->activemenumode != AMMODE_EDIT) { if (g_Vars.currentplayer->activemenumode != AMMODE_EDIT) {
s16 dist; s16 dist;
@@ -407,7 +428,7 @@ void amTick(void)
// Update alpha of slots so they fade in // Update alpha of slots so they fade in
if (g_AmMenus[g_AmIndex].alphafrac < 1) { if (g_AmMenus[g_AmIndex].alphafrac < 1) {
g_AmMenus[g_AmIndex].alphafrac += LVUPDATE60FREAL() / 30.0f; g_AmMenus[g_AmIndex].alphafrac += (f32)g_Vars.lvupdate240 / (4.f * 30.0f);
} }
if (g_AmMenus[g_AmIndex].alphafrac > 1) { if (g_AmMenus[g_AmIndex].alphafrac > 1) {
@@ -415,7 +436,7 @@ void amTick(void)
} }
// Make selection border pulsate // Make selection border pulsate
g_AmMenus[g_AmIndex].selpulse += LVUPDATE60FREAL() / 5.0f; g_AmMenus[g_AmIndex].selpulse += (f32)g_Vars.lvupdate240 / (4.f * 5.0f);
if (g_AmMenus[g_AmIndex].selpulse > 18.849555969238f) { if (g_AmMenus[g_AmIndex].selpulse > 18.849555969238f) {
g_AmMenus[g_AmIndex].selpulse -= 18.849555969238f; g_AmMenus[g_AmIndex].selpulse -= 18.849555969238f;
+222 -86
View File
@@ -43,6 +43,11 @@
#include "data.h" #include "data.h"
#include "gbiex.h" #include "gbiex.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64
#include "preprocess.h"
#include "system.h"
#include "video.h"
#endif
#define BGCMD_END 0x00 #define BGCMD_END 0x00
#define BGCMD_PUSH 0x01 #define BGCMD_PUSH 0x01
@@ -86,12 +91,12 @@ u32 var800a4920;
u32 g_BgSection3; u32 g_BgSection3;
struct room *g_Rooms; struct room *g_Rooms;
u8 *g_MpRoomVisibility; u8 *g_MpRoomVisibility;
s16 g_BgForceOnscreenRooms[350]; RoomNum g_BgForceOnscreenRooms[350];
s32 g_BgNumForceOnscreenRooms; s32 g_BgNumForceOnscreenRooms;
u16 g_BgUnloadDelay240; u16 g_BgUnloadDelay240;
u16 g_BgUnloadDelay240_2; u16 g_BgUnloadDelay240_2;
u32 var800a4bf4; u32 var800a4bf4;
s16 g_GlareRooms[100]; RoomNum g_GlareRooms[100];
u32 *g_BgPrimaryData2; u32 *g_BgPrimaryData2;
struct bgroom *g_BgRooms; struct bgroom *g_BgRooms;
struct bgportal *g_BgPortals; struct bgportal *g_BgPortals;
@@ -135,7 +140,7 @@ void bgUnpausePropsInRoom(u32 roomnum, bool tintedglassonly)
struct prop *prop; struct prop *prop;
struct defaultobj *obj; struct defaultobj *obj;
s16 *propnumptr; s16 *propnumptr;
s16 rooms[2]; RoomNum rooms[2];
s16 propnums[256]; s16 propnums[256];
rooms[0] = roomnum; rooms[0] = roomnum;
@@ -283,7 +288,7 @@ Gfx *bgRenderXrayData(Gfx *gdl, struct xraydata *xraydata)
vertices[i].y = xraydata->vertices[i][1]; vertices[i].y = xraydata->vertices[i][1];
vertices[i].z = xraydata->vertices[i][2]; vertices[i].z = xraydata->vertices[i][2];
vertices[i].colour = i << 2; vertices[i].colour = i << 2;
colours[i].word = xraydata->colours[i]; colours[i].word = PD_BE32(xraydata->colours[i]);
} }
count = xraydata->numvertices; count = xraydata->numvertices;
@@ -697,17 +702,17 @@ Gfx *bgRenderGdlInXray(Gfx *gdl, s8 *readgdl, Vtx *vertices, s16 arg3[3])
xraydata.numvertices = 0; xraydata.numvertices = 0;
while (true) { while (true) {
if (readgdl[0] == G_ENDDL) { if (readgdl[GFX_W0_BYTE(0)] == G_ENDDL) {
break; break;
} }
if (readgdl[0] == G_MTX) { if (readgdl[GFX_W0_BYTE(0)] == G_MTX) {
// empty // empty
} else if (readgdl[0] == G_VTX) { } else if (readgdl[GFX_W0_BYTE(0)] == G_VTX) {
Gfx *cmd = (Gfx *) readgdl; Gfx *cmd = (Gfx *) readgdl;
s32 dmemindex = cmd->bytes[1] & 0xf; s32 dmemindex = cmd->bytes[GFX_W0_BYTE(1)] & 0xf;
s32 numvertices = ((u32) cmd->bytes[1] >> 4) + 1; s32 numvertices = ((u32) cmd->bytes[GFX_W0_BYTE(1)] >> 4) + 1;
u32 offset = cmd->words.w1 & 0xffffff; u32 offset = UNSEGADDR(cmd->words.w1) & 0xffffff;
for (i = 0; i < numvertices; i++) { for (i = 0; i < numvertices; i++) {
Vtx *vtx = (Vtx *) (verticesu8 + offset); Vtx *vtx = (Vtx *) (verticesu8 + offset);
@@ -720,14 +725,14 @@ Gfx *bgRenderGdlInXray(Gfx *gdl, s8 *readgdl, Vtx *vertices, s16 arg3[3])
offset += sizeof(Vtx); offset += sizeof(Vtx);
} }
} else if (readgdl[0] == G_TRI1) { } else if (readgdl[GFX_W0_BYTE(0)] == G_TRI1) {
Gfx *cmd = (Gfx *) readgdl; Gfx *cmd = (Gfx *) readgdl;
s16 x = cmd->tri.tri.v[0] / 10; s16 x = cmd->tri.tri.v[GFX_TRI_VTX(0)] / 10;
s16 y = cmd->tri.tri.v[1] / 10; s16 y = cmd->tri.tri.v[GFX_TRI_VTX(1)] / 10;
s16 z = cmd->tri.tri.v[2] / 10; s16 z = cmd->tri.tri.v[GFX_TRI_VTX(2)] / 10;
gdl = bgProcessXrayTri(gdl, &xraydata, dmemvertices[x], dmemvertices[y], dmemvertices[z], dmemcolours[x], dmemcolours[y], dmemcolours[z], inrange[x], inrange[y], inrange[z]); gdl = bgProcessXrayTri(gdl, &xraydata, dmemvertices[x], dmemvertices[y], dmemvertices[z], dmemcolours[x], dmemcolours[y], dmemcolours[z], inrange[x], inrange[y], inrange[z]);
} else if (readgdl[0] == G_TRI4) { } else if (readgdl[GFX_W0_BYTE(0)] == G_TRI4) {
Gfx *cmd = (Gfx *) readgdl; Gfx *cmd = (Gfx *) readgdl;
s16 x; s16 x;
s16 y; s16 y;
@@ -869,11 +874,11 @@ Gfx *bgRenderRoomInXray(Gfx *gdl, s32 roomnum)
Gfx *bgRenderSceneInXray(Gfx *gdl) Gfx *bgRenderSceneInXray(Gfx *gdl)
{ {
s16 *roomnumptr; RoomNum *roomnumptr;
s16 *room; RoomNum *room;
s16 i; s16 i;
s32 j; s32 j;
s16 roomnumsbyprop[200]; RoomNum roomnumsbyprop[200];
struct prop *prop; struct prop *prop;
struct prop **ptr; struct prop **ptr;
s32 k; s32 k;
@@ -969,17 +974,19 @@ Gfx *bgRenderScene(Gfx *gdl)
s32 firstroomnum = -1; s32 firstroomnum = -1;
s32 i; s32 i;
s32 roomnum; s32 roomnum;
s16 roomnumsbyprop[200]; RoomNum roomnumsbyprop[200];
struct prop **ptr; struct prop **ptr;
struct drawslot *thing; struct drawslot *thing;
s16 *roomnumptr; RoomNum *roomnumptr;
struct prop *prop; struct prop *prop;
s16 tmp; s16 tmp;
s16 *room; RoomNum *room;
s16 roomorder[60]; s16 roomorder[60];
s16 roomnums[60]; RoomNum roomnums[60];
#ifdef PLATFORM_N64
g_NumRoomsWithGlares = 0; g_NumRoomsWithGlares = 0;
#endif
if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) { if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
gdl = bgRenderSceneInXray(gdl); gdl = bgRenderSceneInXray(gdl);
@@ -1201,6 +1208,7 @@ Gfx *bgRenderScene(Gfx *gdl)
gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop); gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop);
} }
#ifdef PLATFORM_N64 // on PC we do this earlier, before prop matrices turn into garbage
if (!g_Vars.mplayerisrunning) { if (!g_Vars.mplayerisrunning) {
artifactsCalculateGlaresForRoom(thing->roomnum); artifactsCalculateGlaresForRoom(thing->roomnum);
@@ -1208,6 +1216,7 @@ Gfx *bgRenderScene(Gfx *gdl)
g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum; g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum;
} }
} }
#endif
} }
#if VERSION < VERSION_NTSC_1_0 #if VERSION < VERSION_NTSC_1_0
@@ -1492,6 +1501,9 @@ void bgReset(s32 stagenum)
// Copy section 1 header to stack and parse into variables // Copy section 1 header to stack and parse into variables
header = (u8 *)ALIGN16((uintptr_t)headerbuffer); header = (u8 *)ALIGN16((uintptr_t)headerbuffer);
bgLoadFile(header, 0, 0x40); bgLoadFile(header, 0, 0x40);
#ifndef PLATFORM_N64
preprocessBgSection1Header(header, 0x40);
#endif
inflatedsize = *(u32 *)&header[0]; inflatedsize = *(u32 *)&header[0];
section1compsize = *(u32 *)&header[4]; section1compsize = *(u32 *)&header[4];
primcompsize = *(u32 *)&header[8]; primcompsize = *(u32 *)&header[8];
@@ -1516,6 +1528,10 @@ void bgReset(s32 stagenum)
scratch += 0xc; scratch += 0xc;
bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize); bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize);
#ifndef PLATFORM_N64
preprocessBgSection1(g_BgPrimaryData, 0x0f000000);
#endif
// Shrink the allocation (ie. free the scratch space) // Shrink the allocation (ie. free the scratch space)
mempRealloc(g_BgPrimaryData, inflatedsize, MEMPOOL_STAGE); mempRealloc(g_BgPrimaryData, inflatedsize, MEMPOOL_STAGE);
@@ -1523,6 +1539,9 @@ void bgReset(s32 stagenum)
section2start = section1compsize + 0xc; section2start = section1compsize + 0xc;
bgLoadFile(header, section2start, 0x40); bgLoadFile(header, section2start, 0x40);
#ifndef PLATFORM_N64
preprocessBgSection2Header(header, 0x40);
#endif
inflatedsize = (*(u16 *) &header[0] & 0x7fff) - 1; inflatedsize = (*(u16 *) &header[0] & 0x7fff) - 1;
section2compsize = *(u16 *) &header[2]; section2compsize = *(u16 *) &header[2];
@@ -1552,6 +1571,10 @@ void bgReset(s32 stagenum)
// Iterate texture IDs and ensure they're loaded // Iterate texture IDs and ensure they're loaded
inflatedsize = (*(u16 *) &header[0] & 0x7fff) >> 1; inflatedsize = (*(u16 *) &header[0] & 0x7fff) >> 1;
#ifndef PLATFORM_N64
preprocessBgSection2((u8 *)section2, inflatedsize);
#endif
for (i = 0; i ^ inflatedsize; i++) { for (i = 0; i ^ inflatedsize; i++) {
texLoadFromTextureNum(section2[i] & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff, NULL); texLoadFromTextureNum(section2[i] & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff, NULL);
} }
@@ -1667,6 +1690,9 @@ void bgBuildTables(s32 stagenum)
g_Rooms[i].unk4d = 0; g_Rooms[i].unk4d = 0;
g_Rooms[i].lightop = 0; g_Rooms[i].lightop = 0;
g_Rooms[i].unk4e_04 = 0; g_Rooms[i].unk4e_04 = 0;
#ifndef PLATFORM_N64
g_Rooms[i].extra_flags = 0;
#endif
} }
bgSetStageTranslationThing(g_Stages[g_StageIndex].unk14); bgSetStageTranslationThing(g_Stages[g_StageIndex].unk14);
@@ -1891,6 +1917,9 @@ void bgBuildTables(s32 stagenum)
// Load and read the header // Load and read the header
header = (u8 *)ALIGN16((uintptr_t)headerbuffer); header = (u8 *)ALIGN16((uintptr_t)headerbuffer);
bgLoadFile(header, g_BgSection3, 0x40); bgLoadFile(header, g_BgSection3, 0x40);
#ifndef PLATFORM_N64
preprocessBgSection3Header(header, 0x40);
#endif
inflatedsize = (*(u16 *)&header[0] & 0x7fff) - 1; inflatedsize = (*(u16 *)&header[0] & 0x7fff) - 1;
section3compsize = *(u16 *)&header[2]; section3compsize = *(u16 *)&header[2];
inflatedsize = (inflatedsize | 0xf) + 1; inflatedsize = (inflatedsize | 0xf) + 1;
@@ -1909,6 +1938,9 @@ void bgBuildTables(s32 stagenum)
bgLoadFile(scratch, g_BgSection3 + 4, ((section3compsize - 1) | 0xf) + 1); bgLoadFile(scratch, g_BgSection3 + 4, ((section3compsize - 1) | 0xf) + 1);
bgInflate(scratch, section3, section3compsize); bgInflate(scratch, section3, section3compsize);
#ifndef PLATFORM_N64
preprocessBgSection3(section3, section3compsize);
#endif
// Section 3 starts with a table of room bounding boxes // Section 3 starts with a table of room bounding boxes
bboxptr = (s16 *) section3; bboxptr = (s16 *) section3;
@@ -1966,6 +1998,10 @@ void bgBuildTables(s32 stagenum)
numlightsptr++; numlightsptr++;
} }
#ifndef PLATFORM_N64
preprocessBgLights(g_BgLightsFileData, 0);
#endif
// Free the section 3 allocation // Free the section 3 allocation
mempRealloc(section3, 0, MEMPOOL_STAGE); mempRealloc(section3, 0, MEMPOOL_STAGE);
@@ -2186,13 +2222,26 @@ Gfx *bgScissorToViewport(Gfx *gdl)
Gfx *bgScissorWithinViewportF(Gfx *gdl, f32 viewleft, f32 viewtop, f32 viewright, f32 viewbottom) Gfx *bgScissorWithinViewportF(Gfx *gdl, f32 viewleft, f32 viewtop, f32 viewright, f32 viewbottom)
{ {
gdl = bgScissorWithinViewport(gdl, viewleft, viewtop, ceil(viewright), ceil(viewbottom)); gdl = bgScissorWithinViewport(gdl, viewleft, viewtop, ceiltoint(viewright), ceiltoint(viewbottom));
return gdl; return gdl;
} }
Gfx *bgScissorWithinViewport(Gfx *gdl, s32 viewleft, s32 viewtop, s32 viewright, s32 viewbottom) Gfx *bgScissorWithinViewport(Gfx *gdl, s32 viewleft, s32 viewtop, s32 viewright, s32 viewbottom)
{ {
#ifndef PLATFORM_N64
const s32 xmargin = videoGetWidth() / SCREEN_320 - 1;
const s32 ymargin = videoGetHeight() / SCREEN_240 - 1;
if (xmargin > 0) {
viewleft -= xmargin;
viewright += xmargin;
}
if (ymargin > 0) {
viewtop -= ymargin;
viewbottom += ymargin;
}
#endif
if (viewleft < g_Vars.currentplayer->viewleft) { if (viewleft < g_Vars.currentplayer->viewleft) {
viewleft = g_Vars.currentplayer->viewleft; viewleft = g_Vars.currentplayer->viewleft;
} }
@@ -2762,12 +2811,23 @@ void bgLoadRoom(s32 roomnum)
alloclen += 1024; alloclen += 1024;
} }
} else { } else {
#ifdef PLATFORM_N64
alloclen = memaGetLongestFree(); alloclen = memaGetLongestFree();
#else
// probably never reaches here in practice as all rooms have gfxdatalen
// alloc 10k and hope for the best
alloclen = 10240;
#endif
} }
#ifdef PLATFORM_N64
bgGarbageCollectRooms(alloclen, false); bgGarbageCollectRooms(alloclen, false);
allocation = memaAlloc(alloclen); allocation = memaAlloc(alloclen);
#else
// allocate room data from heap to not take up mema space
allocation = sysMemAlloc(alloclen);
#endif
if (allocation != NULL) { if (allocation != NULL) {
dyntexSetCurrentRoom(roomnum); dyntexSetCurrentRoom(roomnum);
@@ -2795,6 +2855,9 @@ void bgLoadRoom(s32 roomnum)
// Inflate the data to the left side of the allocation // Inflate the data to the left side of the allocation
inflatedlen = bgInflate(memaddr, allocation, g_BgRooms[roomnum + 1].unk00 - g_BgRooms[roomnum].unk00); inflatedlen = bgInflate(memaddr, allocation, g_BgRooms[roomnum + 1].unk00 - g_BgRooms[roomnum].unk00);
#ifndef PLATFORM_N64
preprocessBgRoom(allocation, g_BgRooms[roomnum].unk00);
#endif
g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation; g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation;
@@ -2913,9 +2976,11 @@ void bgLoadRoom(s32 roomnum)
g_Rooms[roomnum].loaded240 = 1; g_Rooms[roomnum].loaded240 = 1;
#ifdef PLATFORM_N64
if (g_Rooms[roomnum].gfxdatalen != alloclen) { if (g_Rooms[roomnum].gfxdatalen != alloclen) {
memaRealloc((intptr_t) allocation, alloclen, g_Rooms[roomnum].gfxdatalen); memaRealloc((intptr_t) allocation, alloclen, g_Rooms[roomnum].gfxdatalen);
} }
#endif
// Update gdl pointers in the gfxdata so they point to the ones // Update gdl pointers in the gfxdata so they point to the ones
// that have been processed by textLoadFromGdl. // that have been processed by textLoadFromGdl.
@@ -3000,14 +3065,22 @@ void bgUnloadRoom(s32 roomnum)
u32 size; u32 size;
if (g_Rooms[roomnum].vtxbatches) { if (g_Rooms[roomnum].vtxbatches) {
#ifdef PLATFORM_N64
size = ((g_Rooms[roomnum].numvtxbatches) * sizeof(struct vtxbatch) + 0xf) & ~0xf; size = ((g_Rooms[roomnum].numvtxbatches) * sizeof(struct vtxbatch) + 0xf) & ~0xf;
memaFree(g_Rooms[roomnum].vtxbatches, size); memaFree(g_Rooms[roomnum].vtxbatches, size);
#else
sysMemFree(g_Rooms[roomnum].vtxbatches);
#endif
g_Rooms[roomnum].vtxbatches = NULL; g_Rooms[roomnum].vtxbatches = NULL;
} }
if (g_Rooms[roomnum].gfxdatalen > 0) { if (g_Rooms[roomnum].gfxdatalen > 0) {
#ifdef PLATFORM_N64
size = g_Rooms[roomnum].gfxdatalen; size = g_Rooms[roomnum].gfxdatalen;
memaFree(g_Rooms[roomnum].gfxdata, size); memaFree(g_Rooms[roomnum].gfxdata, size);
#else
sysMemFree(g_Rooms[roomnum].gfxdata);
#endif
g_Rooms[roomnum].gfxdata = NULL; g_Rooms[roomnum].gfxdata = NULL;
} }
@@ -3037,6 +3110,7 @@ void bgUnloadAllRooms(void)
*/ */
void bgGarbageCollectRooms(s32 bytesneeded, bool desparate) void bgGarbageCollectRooms(s32 bytesneeded, bool desparate)
{ {
#ifdef PLATFORM_N64 // don't need this on PC as rooms are allocated from heap
s32 bytesfree = memaGetLongestFree(); s32 bytesfree = memaGetLongestFree();
s32 oldestroom; s32 oldestroom;
s32 oldesttimer; s32 oldesttimer;
@@ -3084,6 +3158,7 @@ void bgGarbageCollectRooms(s32 bytesneeded, bool desparate)
break; break;
} }
} }
#endif
} }
/** /**
@@ -3144,8 +3219,13 @@ Gfx *bgRenderRoomPass(Gfx *gdl, s32 roomnum, struct roomblock *block, bool arg3)
v0 = (uintptr_t)g_Rooms[roomnum].colours; v0 = (uintptr_t)g_Rooms[roomnum].colours;
if (v0 != NULL) { if (v0 != NULL) {
#ifdef PLATFORM_N64
s32 addr = ALIGN8((uintptr_t)&g_Rooms[roomnum].gfxdata->vertices[g_Rooms[roomnum].gfxdata->numvertices]); s32 addr = ALIGN8((uintptr_t)&g_Rooms[roomnum].gfxdata->vertices[g_Rooms[roomnum].gfxdata->numvertices]);
v0 += (((intptr_t)block->colours - addr) >> 2) * 4; v0 += (((intptr_t)block->colours - addr) >> 2) * 4;
#else
uintptr_t addr = ALIGN8((uintptr_t)&g_Rooms[roomnum].gfxdata->vertices[g_Rooms[roomnum].gfxdata->numvertices]);
v0 += (((uintptr_t)block->colours - addr) >> 2) * 4;
#endif
} else { } else {
v0 = (uintptr_t)block->colours; v0 = (uintptr_t)block->colours;
} }
@@ -3269,8 +3349,8 @@ s32 bgPopulateVtxBatchType(s32 roomnum, struct vtxbatch *batches, Gfx *gdl, s32
batches[batchindex].bbmax.f[j] = -32768.0f; batches[batchindex].bbmax.f[j] = -32768.0f;
} }
numvertices = (((u32)gdl[i].bytes[1] >> 4) & 0xf) + 1; numvertices = (((u32)gdl[i].bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
batchvertices = (Vtx *)((uintptr_t)vertices + (gdl[i].words.w1 & 0xffffff)); batchvertices = (Vtx *)((uintptr_t)vertices + (UNSEGADDR(gdl[i].words.w1) & 0xffffff));
for (j = 0; j < numvertices; j++) { for (j = 0; j < numvertices; j++) {
f32 x = batchvertices[j].x; f32 x = batchvertices[j].x;
@@ -3369,7 +3449,11 @@ void bgFindRoomVtxBatches(s32 roomnum)
batchindex += xlucount; batchindex += xlucount;
#ifdef PLATFORM_N64
batches = memaAlloc((batchindex * sizeof(struct vtxbatch) + 0xf) & ~0xf); batches = memaAlloc((batchindex * sizeof(struct vtxbatch) + 0xf) & ~0xf);
#else
batches = sysMemAlloc((batchindex * sizeof(struct vtxbatch) + 0xf) & ~0xf);
#endif
if (batches != NULL) { if (batches != NULL) {
gdl = bgGetNextGdlInLayer(roomnum, NULL, VTXBATCHTYPE_OPA); gdl = bgGetNextGdlInLayer(roomnum, NULL, VTXBATCHTYPE_OPA);
@@ -3578,9 +3662,19 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
break; break;
} else if (gdl->dma.cmd == G_VTX) { } else if (gdl->dma.cmd == G_VTX) {
ptr = var800a6470; ptr = var800a6470;
count = gdl->bytes[1] & 0xf; count = gdl->bytes[GFX_W0_BYTE(1)] & 0xf;
offset = (gdl->words.w1 & 0xffffff); #ifdef PLATFORM_N64
numvertices = (((u32)gdl->bytes[1] >> 4) & 0xf) + 1; offset = (UNSEGADDR(gdl->words.w1) & 0xffffff);
#else
if (gdl->words.w1 & 1) {
// segmented address
offset = (UNSEGADDR(gdl->words.w1) & 0xffffff);
} else {
// linear address
offset = gdl->words.w1 - (uintptr_t)vertices;
}
#endif
numvertices = (((u32) gdl->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
vtx = (Vtx *)((uintptr_t)vertices + offset); vtx = (Vtx *)((uintptr_t)vertices + offset);
vtx -= count; vtx -= count;
@@ -3684,9 +3778,9 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
if (gdl->dma.cmd == G_TRI1) { if (gdl->dma.cmd == G_TRI1) {
trisremaining = 0; trisremaining = 0;
triref = 0; triref = 0;
points[0] = gdl->tri.tri.v[0] / 10; points[0] = gdl->tri.tri.v[GFX_TRI_VTX(0)] / 10;
points[1] = gdl->tri.tri.v[1] / 10; points[1] = gdl->tri.tri.v[GFX_TRI_VTX(1)] / 10;
points[2] = gdl->tri.tri.v[2] / 10; points[2] = gdl->tri.tri.v[GFX_TRI_VTX(2)] / 10;
} else if (gdl->dma.cmd == G_TRI4) { } else if (gdl->dma.cmd == G_TRI4) {
tri4gdl = gdl; tri4gdl = gdl;
trisremaining = 3; trisremaining = 3;
@@ -3780,19 +3874,27 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
hit = true; hit = true;
if (imggdl == NULL if (imggdl == NULL
#ifdef PLATFORM_N64
|| (imggdl->words.w1 & 0x0f000000) == 0x0f000000 || (imggdl->words.w1 & 0x0f000000) == 0x0f000000
|| (imggdl->words.w1 & 0x05000000) == 0x05000000) { || (imggdl->words.w1 & 0x05000000) == 0x05000000) {
#else // not sure if the above check even works right on N64, but we can test easily for seg addresses
|| (imggdl->words.w1 & 1)) {
#endif
texturenum = -1; texturenum = -1;
} else { } else {
s32 tmp = PHYS_TO_K0(imggdl->words.w1 - 8); #ifdef PLATFORM_N64
s32 tmp = PHYS_TO_K0(UNSEGADDR(imggdl->words.w1) - 8);
#else
uintptr_t tmp = PHYS_TO_K0(UNSEGADDR(imggdl->words.w1) - 8);
#endif
texturenum = *(s16 *) tmp; texturenum = *(s16 *) tmp;
} }
lowestsqdist = sqdist; lowestsqdist = sqdist;
hitthing->unk00.x = sp8c.x; hitthing->pos.x = sp8c.x;
hitthing->unk00.y = sp8c.y; hitthing->pos.y = sp8c.y;
hitthing->unk00.z = sp8c.z; hitthing->pos.z = sp8c.z;
hitthing->unk0c.x = sp80.x; hitthing->unk0c.x = sp80.x;
hitthing->unk0c.y = sp80.y; hitthing->unk0c.y = sp80.y;
hitthing->unk0c.z = sp80.z; hitthing->unk0c.z = sp80.z;
@@ -3875,13 +3977,13 @@ bool bgTestHitOnChr(struct model *model, struct coord *arg1, struct coord *arg2,
} }
break; break;
} else if (gdl->dma.cmd == G_MTX) { } else if (gdl->dma.cmd == G_MTX) {
word = gdl->words.w1 & 0xffffff; word = UNSEGADDR(gdl->words.w1) & 0xffffff;
i = word / sizeof(Mtxf); i = word / sizeof(Mtxf);
mtx = &model->matrices[i]; mtx = &model->matrices[i];
} else if (gdl->dma.cmd == G_VTX) { } else if (gdl->dma.cmd == G_VTX) {
count = (gdl->bytes[1] & 0xf); count = (gdl->bytes[GFX_W0_BYTE(1)] & 0xf);
word = gdl->words.w1 & 0xffffff; word = UNSEGADDR(gdl->words.w1) & 0xffffff;
numvertices = ((u32)gdl->bytes[1] >> 4) + 1; numvertices = ((u32) gdl->bytes[GFX_W0_BYTE(1)] >> 4) + 1;
vtx = (Vtx *)((uintptr_t)vertices + word); vtx = (Vtx *)((uintptr_t)vertices + word);
if (count < spdc) { if (count < spdc) {
@@ -3971,9 +4073,9 @@ bool bgTestHitOnChr(struct model *model, struct coord *arg1, struct coord *arg2,
if (gdl->dma.cmd == G_TRI1) { if (gdl->dma.cmd == G_TRI1) {
i = 0; i = 0;
triref = 0; triref = 0;
points[0] = gdl->tri.tri.v[0] / 10; points[0] = gdl->tri.tri.v[GFX_TRI_VTX(0)] / 10;
points[1] = gdl->tri.tri.v[1] / 10; points[1] = gdl->tri.tri.v[GFX_TRI_VTX(1)] / 10;
points[2] = gdl->tri.tri.v[2] / 10; points[2] = gdl->tri.tri.v[GFX_TRI_VTX(2)] / 10;
} else if (gdl->dma.cmd == G_TRI4) { } else if (gdl->dma.cmd == G_TRI4) {
tri4gdl = gdl; tri4gdl = gdl;
i = 3; i = 3;
@@ -4068,9 +4170,9 @@ bool bgTestHitOnChr(struct model *model, struct coord *arg1, struct coord *arg2,
*sqdistptr = sqdist; *sqdistptr = sqdist;
hitthing->unk00.x = sp84.x; hitthing->pos.x = sp84.x;
hitthing->unk00.y = sp84.y; hitthing->pos.y = sp84.y;
hitthing->unk00.z = sp84.z; hitthing->pos.z = sp84.z;
hitthing->unk0c.x = sp78.x; hitthing->unk0c.x = sp78.x;
hitthing->unk0c.y = sp78.y; hitthing->unk0c.y = sp78.y;
hitthing->unk0c.z = sp78.z; hitthing->unk0c.z = sp78.z;
@@ -4141,8 +4243,8 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
vtx = bgFindVerticesForGdl(roomnum, gdl); vtx = bgFindVerticesForGdl(roomnum, gdl);
iter = &gdl[batch->gbicmdindex]; iter = &gdl[batch->gbicmdindex];
vtx = (Vtx *)((iter->words.w1 & 0xffffff) + (s32)vtx); vtx = (Vtx *)((UNSEGADDR(iter->words.w1) & 0xffffff) + (s32)vtx);
numvertices = (((u32)iter->bytes[1] >> 4) & 0xf) + 1; numvertices = (((u32) iter->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
ptr = var800a6470; ptr = var800a6470;
while (numvertices > 0) { while (numvertices > 0) {
@@ -4169,9 +4271,9 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
if (iter->dma.cmd == G_TRI1) { if (iter->dma.cmd == G_TRI1) {
trisremaining = 0; trisremaining = 0;
triref = 0; triref = 0;
points[0] = iter->tri.tri.v[0] / 10; points[0] = iter->tri.tri.v[GFX_TRI_VTX(0)] / 10;
points[1] = iter->tri.tri.v[1] / 10; points[1] = iter->tri.tri.v[GFX_TRI_VTX(1)] / 10;
points[2] = iter->tri.tri.v[2] / 10; points[2] = iter->tri.tri.v[GFX_TRI_VTX(2)] / 10;
} else if (iter->dma.cmd == G_TRI4) { } else if (iter->dma.cmd == G_TRI4) {
tri4gdl = iter; tri4gdl = iter;
trisremaining = 3; trisremaining = 3;
@@ -4272,29 +4374,41 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
tmpgdl = iter; tmpgdl = iter;
while (tmpgdl->bytes[0] != G_SETTIMG && tmpgdl > gdl) { while (tmpgdl->bytes[GFX_W0_BYTE(0)] != G_SETTIMG && tmpgdl > gdl) {
tmpgdl--; tmpgdl--;
} }
if (tmpgdl == gdl if (tmpgdl == gdl
#ifdef PLATFORM_N64
|| (tmpgdl->words.w1 & 0x0f000000) == 0x0f000000 || (tmpgdl->words.w1 & 0x0f000000) == 0x0f000000
|| (tmpgdl->words.w1 & 0x05000000) == 0x05000000) { || (tmpgdl->words.w1 & 0x05000000) == 0x05000000) {
#else // not sure if the above check even works right on N64, but we can test easily for seg addresses
|| (tmpgdl->words.w1 & 1)) {
#endif
texturenum = -1; texturenum = -1;
} else { } else {
s32 tmp = tmpgdl->words.w1 - 8; #ifdef PLATFORM_N64
s32 tmp = UNSEGADDR(tmpgdl->words.w1) - 8;
#else
uintptr_t tmp = UNSEGADDR(tmpgdl->words.w1) - 8;
#endif
texturenum = *(s16 *) PHYS_TO_K0(tmp); texturenum = *(s16 *) PHYS_TO_K0(tmp);
} }
#ifdef AVOID_UB
if (batch->type == VTXBATCHTYPE_XLU && texturenum >= 0 && g_Textures[texturenum].surfacetype == SURFACETYPE_DEFAULT) {
#else
if (batch->type == VTXBATCHTYPE_XLU && g_Textures[texturenum].surfacetype == SURFACETYPE_DEFAULT) { if (batch->type == VTXBATCHTYPE_XLU && g_Textures[texturenum].surfacetype == SURFACETYPE_DEFAULT) {
#endif
hit = false; hit = false;
} }
if (hit) { if (hit) {
lowestsqdist = sqdist; lowestsqdist = sqdist;
hitthing->unk00.x = spb0.x; hitthing->pos.x = spb0.x;
hitthing->unk00.y = spb0.y; hitthing->pos.y = spb0.y;
hitthing->unk00.z = spb0.z; hitthing->pos.z = spb0.z;
hitthing->unk0c.x = spa4.x; hitthing->unk0c.x = spa4.x;
hitthing->unk0c.y = spa4.y; hitthing->unk0c.y = spa4.y;
hitthing->unk0c.z = spa4.z; hitthing->unk0c.z = spa4.z;
@@ -4469,20 +4583,20 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
numbatches = g_Rooms[roomnum].numvtxbatches; numbatches = g_Rooms[roomnum].numvtxbatches;
for (i = 0; i < numbatches; batch++, i++) { for (i = 0; i < numbatches; batch++, i++) {
j = bg0f1612e4(&batch->bbmin, &batch->bbmax, &from, &dist, &sp94, &hitthing->unk00); j = bg0f1612e4(&batch->bbmin, &batch->bbmax, &from, &dist, &sp94, &hitthing->pos);
if (j == 0) { if (j == 0) {
continue; continue;
} }
if (j == 1) { if (j == 1) {
f0 = from.x - hitthing->unk00.x; f0 = from.x - hitthing->pos.x;
f20 = f0 * f0; f20 = f0 * f0;
f0 = from.y - hitthing->unk00.y; f0 = from.y - hitthing->pos.y;
f20 += f0 * f0; f20 += f0 * f0;
f0 = from.z - hitthing->unk00.z; f0 = from.z - hitthing->pos.z;
f20 += f0 * f0; f20 += f0 * f0;
} else { } else {
f20 = -1.0f; f20 = -1.0f;
@@ -4512,13 +4626,13 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
for (j = 0; j < ARRAYCOUNT(var800a6538); j++) { for (j = 0; j < ARRAYCOUNT(var800a6538); j++) {
if (bgTestHitInVtxBatch(&from, &to, &dist, &g_Rooms[roomnum].vtxbatches[var800a6538[j].vtxbatchindex], roomnum, hitthing)) { if (bgTestHitInVtxBatch(&from, &to, &dist, &g_Rooms[roomnum].vtxbatches[var800a6538[j].vtxbatchindex], roomnum, hitthing)) {
f0 = from.x - hitthing->unk00.x; f0 = from.x - hitthing->pos.x;
f2 = f0 * f0; f2 = f0 * f0;
f0 = from.y - hitthing->unk00.y; f0 = from.y - hitthing->pos.y;
f2 += f0 * f0; f2 += f0 * f0;
f0 = from.z - hitthing->unk00.z; f0 = from.z - hitthing->pos.z;
f2 += f0 * f0; f2 += f0 * f0;
if (count == 0) { if (count == 0) {
@@ -4564,31 +4678,31 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
i++; i++;
if (i < count) { if (i < count) {
f0 = from.x - hitthing->unk00.x; f0 = from.x - hitthing->pos.x;
spc8 = f0 * f0; spc8 = f0 * f0;
f0 = from.y - hitthing->unk00.y; f0 = from.y - hitthing->pos.y;
spc8 += f0 * f0; spc8 += f0 * f0;
f0 = from.z - hitthing->unk00.z; f0 = from.z - hitthing->pos.z;
spc8 += f0 * f0; spc8 += f0 * f0;
for (; i < count; i++) { for (; i < count; i++) {
if (var800a6538[i].unk04 <= spc8) { if (var800a6538[i].unk04 <= spc8) {
if (bgTestHitInVtxBatch(&from, &to, &dist, &batch[var800a6538[i].vtxbatchindex], roomnum, &sp60)) { if (bgTestHitInVtxBatch(&from, &to, &dist, &batch[var800a6538[i].vtxbatchindex], roomnum, &sp60)) {
f0 = from.f[0] - sp60.unk00.f[0]; f0 = from.f[0] - sp60.pos.f[0];
f20 = f0 * f0; f20 = f0 * f0;
f0 = from.f[1] - sp60.unk00.f[1]; f0 = from.f[1] - sp60.pos.f[1];
f20 += f0 * f0; f20 += f0 * f0;
f0 = from.f[2] - sp60.unk00.f[2]; f0 = from.f[2] - sp60.pos.f[2];
f20 += f0 * f0; f20 += f0 * f0;
if (f20 < spc8) { if (f20 < spc8) {
hitthing->unk00.x = sp60.unk00.x; hitthing->pos.x = sp60.pos.x;
hitthing->unk00.y = sp60.unk00.y; hitthing->pos.y = sp60.pos.y;
hitthing->unk00.z = sp60.unk00.z; hitthing->pos.z = sp60.pos.z;
hitthing->unk0c.x = sp60.unk0c.x; hitthing->unk0c.x = sp60.unk0c.x;
hitthing->unk0c.y = sp60.unk0c.y; hitthing->unk0c.y = sp60.unk0c.y;
hitthing->unk0c.z = sp60.unk0c.z; hitthing->unk0c.z = sp60.unk0c.z;
@@ -4619,7 +4733,7 @@ bool bgRoomIsLoaded(s32 room)
return g_Rooms[room].loaded240; return g_Rooms[room].loaded240;
} }
bool bgRoomContainsCoord(struct coord *pos, s16 roomnum) bool bgRoomContainsCoord(struct coord *pos, RoomNum roomnum)
{ {
struct coord copy; struct coord copy;
copy.x = pos->x; copy.x = pos->x;
@@ -4646,7 +4760,7 @@ bool bgRoomContainsCoord(struct coord *pos, s16 roomnum)
* - The normal points towards the front of the portal. * - The normal points towards the front of the portal.
* - The room on the front side is roomnum2. * - The room on the front side is roomnum2.
*/ */
bool bgTestPosInRoomCheap(struct coord *pos, s16 roomnum) bool bgTestPosInRoomCheap(struct coord *pos, RoomNum roomnum)
{ {
s32 i; s32 i;
@@ -4672,7 +4786,7 @@ bool bgTestPosInRoomCheap(struct coord *pos, s16 roomnum)
return true; return true;
} }
bool bgTestPosInRoomExpensive(struct coord *pos, s16 roomnum) bool bgTestPosInRoomExpensive(struct coord *pos, RoomNum roomnum)
{ {
s32 t5; s32 t5;
struct coord *next; struct coord *next;
@@ -4780,7 +4894,7 @@ bool bgTestPosInRoomExpensive(struct coord *pos, s16 roomnum)
return true; return true;
} }
bool bgTestPosInRoom(struct coord *pos, s16 roomnum) bool bgTestPosInRoom(struct coord *pos, RoomNum roomnum)
{ {
if (g_Rooms[roomnum].flags & ROOMFLAG_COMPLICATEDPORTALS) { if (g_Rooms[roomnum].flags & ROOMFLAG_COMPLICATEDPORTALS) {
return bgTestPosInRoomExpensive(pos, roomnum); return bgTestPosInRoomExpensive(pos, roomnum);
@@ -4809,7 +4923,7 @@ bool bgTestPosInRoom(struct coord *pos, s16 roomnum)
* to pos and writes the room number to the bestroom pointer. The bestroom * to pos and writes the room number to the bestroom pointer. The bestroom
* pointer is a pointer to a single s16 rather than an array. * pointer is a pointer to a single s16 rather than an array.
*/ */
void bgFindRoomsByPos(struct coord *posarg, s16 *inrooms, s16 *aboverooms, s32 max, s16 *bestroom) void bgFindRoomsByPos(struct coord *posarg, RoomNum *inrooms, RoomNum *aboverooms, s32 max, RoomNum *bestroom)
{ {
s32 inlen = 0; s32 inlen = 0;
s32 abovelen = 0; s32 abovelen = 0;
@@ -5332,7 +5446,7 @@ void bgTickPortalsXray(void)
bgChooseRoomsToLoad(); bgChooseRoomsToLoad();
} }
void bgAddToSnake(s16 fromroomnum, s16 roomnum, s16 depth, struct screenbox *box) void bgAddToSnake(RoomNum fromroomnum, RoomNum roomnum, s16 depth, struct screenbox *box)
{ {
struct bgsnakeitem *item; struct bgsnakeitem *item;
s32 i; s32 i;
@@ -5419,10 +5533,10 @@ void bgConsumeSnakeItem(struct bgsnakeitem *item)
s32 i; s32 i;
s16 portalnum; s16 portalnum;
s16 prevvalidcount; s16 prevvalidcount;
s16 prevfoundroom; RoomNum prevfoundroom;
s16 newfoundroom; RoomNum newfoundroom;
s16 side; s16 side;
s16 tmp; RoomNum tmp;
bool pass; bool pass;
struct portalmetric *metric; struct portalmetric *metric;
struct screenbox prevbox; struct screenbox prevbox;
@@ -5832,7 +5946,7 @@ Gfx *bgRenderSceneAndLoadCandidate(Gfx *gdl)
return gdl; return gdl;
} }
s32 bgGetForceOnscreenRooms(s16 *rooms, s32 len) s32 bgGetForceOnscreenRooms(RoomNum *rooms, s32 len)
{ {
s32 i; s32 i;
@@ -5845,7 +5959,7 @@ s32 bgGetForceOnscreenRooms(s16 *rooms, s32 len)
return i; return i;
} }
s32 bgRoomGetNeighbours(s32 roomnum, s16 *dstrooms, s32 len) s32 bgRoomGetNeighbours(s32 roomnum, RoomNum *dstrooms, s32 len)
{ {
s32 count = 0; s32 count = 0;
s32 i; s32 i;
@@ -5991,7 +6105,7 @@ bool bgPortalExists(s32 portalnum)
void bgPortalSwapRooms(s32 portal) void bgPortalSwapRooms(s32 portal)
{ {
s16 tmp = g_BgPortals[portal].roomnum1; RoomNum tmp = g_BgPortals[portal].roomnum1;
g_BgPortals[portal].roomnum1 = g_BgPortals[portal].roomnum2; g_BgPortals[portal].roomnum1 = g_BgPortals[portal].roomnum2;
g_BgPortals[portal].roomnum2 = tmp; g_BgPortals[portal].roomnum2 = tmp;
} }
@@ -6210,10 +6324,10 @@ void bgCalculatePortalBbox(s32 portalnum, struct coord *bbmin, struct coord *bbm
} }
} }
void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, s16 *rooms, s32 maxlen, bool arg4) void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, RoomNum *rooms, s32 maxlen, bool arg4)
{ {
s16 room; RoomNum room;
s16 otherroom; RoomNum otherroom;
s32 portalnum; s32 portalnum;
struct coord propbbmin; struct coord propbbmin;
struct coord propbbmax; struct coord propbbmax;
@@ -6287,3 +6401,25 @@ void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, s16 *rooms, s3
end: end:
rooms[len] = -1; rooms[len] = -1;
} }
#ifndef PLATFORM_N64
void bgCalculateGlaresForVisibleRooms(void)
{
s32 i;
g_NumRoomsWithGlares = 0;
if (!g_Vars.mplayerisrunning) {
for (i = 1; i < g_Vars.roomcount; i++) {
if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) {
artifactsCalculateGlaresForRoom(i);
if (g_NumRoomsWithGlares < 100) {
g_GlareRooms[g_NumRoomsWithGlares++] = i;
}
}
}
}
}
#endif
+3 -3
View File
@@ -346,7 +346,7 @@ s32 bodyChooseHead(s32 bodynum)
void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex) void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
{ {
struct pad pad; struct pad pad;
s16 rooms[2]; RoomNum rooms[2];
struct chrdata *chr; struct chrdata *chr;
struct modeldef *headmodeldef; struct modeldef *headmodeldef;
struct model *model; struct model *model;
@@ -531,9 +531,9 @@ void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
} }
} }
struct prop *bodyAllocateEyespy(struct pad *pad, s16 room) struct prop *bodyAllocateEyespy(struct pad *pad, RoomNum room)
{ {
s16 rooms[2]; RoomNum rooms[2];
struct prop *prop; struct prop *prop;
struct chrdata *chr; struct chrdata *chr;
struct model *model; struct model *model;
+23 -13
View File
@@ -107,7 +107,7 @@ void bbikeTryDismountAngle(f32 relativeangle, f32 distance)
struct hoverbikeobj *bike; struct hoverbikeobj *bike;
f32 angle; f32 angle;
struct coord pos; struct coord pos;
s16 rooms[8]; RoomNum rooms[8];
s32 result; s32 result;
f32 ymax; f32 ymax;
f32 ymin; f32 ymin;
@@ -202,14 +202,24 @@ void bbikeApplyMoveData(struct movedata *data)
s8 contnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex); s8 contnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
f32 value1; f32 value1;
f32 tmp; f32 tmp;
s32 contmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
if ((optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_12 if ((contmode == CONTROLMODE_12
|| optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_14 || contmode == CONTROLMODE_14
|| optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_13 || contmode == CONTROLMODE_13
|| optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_11) || contmode == CONTROLMODE_11
|| contmode == CONTROLMODE_PC)
&& !lvIsPaused()) { && !lvIsPaused()) {
data->digitalstepleft = joyCountButtonsOnSpecificSamples(0, contnum, L_JPAD | L_CBUTTONS); u32 lmask, rmask;
data->digitalstepright = joyCountButtonsOnSpecificSamples(0, contnum, R_JPAD | R_CBUTTONS); if (contmode == CONTROLMODE_PC) {
lmask = L_CBUTTONS;
rmask = R_CBUTTONS;
} else {
lmask = L_JPAD | L_CBUTTONS;
rmask = R_JPAD | R_CBUTTONS;
}
data->digitalstepleft = joyCountButtonsOnSpecificSamples(0, contnum, lmask);
data->digitalstepright = joyCountButtonsOnSpecificSamples(0, contnum, rmask);
} }
// Forward/back // Forward/back
@@ -281,10 +291,10 @@ void bbikeApplyMoveData(struct movedata *data)
sp3c = -bike->exreal; sp3c = -bike->exreal;
if (bike->hov.unk14 < M_PI) { if (bike->hov.bobpitchcur < M_PI) {
sp3c += -bike->hov.unk14 * 0.8f; sp3c += -bike->hov.bobpitchcur * 0.8f;
} else { } else {
sp3c += (M_BADTAU - bike->hov.unk14) * 0.8f; sp3c += (M_BADTAU - bike->hov.bobpitchcur) * 0.8f;
} }
if (sp3c < 0) { if (sp3c < 0) {
@@ -371,11 +381,11 @@ s32 bbikeCalculateNewPosition(struct coord *vel, f32 angledelta)
{ {
s32 result = CDRESULT_NOCOLLISION; s32 result = CDRESULT_NOCOLLISION;
struct coord dstpos; struct coord dstpos;
s16 dstrooms[8]; RoomNum dstrooms[8];
struct hov hov; struct hov hov;
bool hasvel = false; bool hasvel = false;
struct hoverbikeobj *bike = (struct hoverbikeobj *) g_Vars.currentplayer->hoverbike->obj; struct hoverbikeobj *bike = (struct hoverbikeobj *) g_Vars.currentplayer->hoverbike->obj;
s16 spa8[20]; RoomNum spa8[20];
f32 xdiff; f32 xdiff;
f32 zdiff; f32 zdiff;
f32 ymax; f32 ymax;
@@ -530,7 +540,7 @@ void bbikeUpdateVertical(struct coord *pos)
{ {
struct defaultobj *bike = g_Vars.currentplayer->hoverbike->obj; struct defaultobj *bike = g_Vars.currentplayer->hoverbike->obj;
f32 angle; f32 angle;
s16 newrooms[8]; RoomNum newrooms[8];
bool newinlift; bool newinlift;
struct prop *lift = NULL; struct prop *lift = NULL;
f32 ground; f32 ground;
+104 -17
View File
@@ -24,6 +24,9 @@
#include "lib/collision.h" #include "lib/collision.h"
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64
#include "input.h"
#endif
u8 g_EyespyPickup = false; u8 g_EyespyPickup = false;
u8 g_EyespyHit = EYESPYHIT_NONE; u8 g_EyespyHit = EYESPYHIT_NONE;
@@ -39,7 +42,7 @@ u32 g_EyespyMaxFallSpeed = 3000;
* position 50 units above the current position, or less if the eyespy is near * position 50 units above the current position, or less if the eyespy is near
* the top of its height range. * the top of its height range.
*/ */
f32 eyespyFindGround(s16 *floorroom) f32 eyespyFindGround(RoomNum *floorroom)
{ {
struct prop *prop = g_Vars.currentplayer->eyespy->prop; struct prop *prop = g_Vars.currentplayer->eyespy->prop;
s32 inlift; s32 inlift;
@@ -75,7 +78,7 @@ s32 eyespyTryMoveUpwards(f32 yvel)
struct prop *prop = g_Vars.currentplayer->eyespy->prop; struct prop *prop = g_Vars.currentplayer->eyespy->prop;
struct chrdata *chr = prop->chr; struct chrdata *chr = prop->chr;
struct coord dstpos; struct coord dstpos;
s16 dstrooms[8]; RoomNum dstrooms[8];
s32 types; s32 types;
u32 stack; u32 stack;
f32 f0; f32 f0;
@@ -118,9 +121,9 @@ s32 eyespyCalculateNewPosition(struct coord *vel)
struct prop *eyespyprop = g_Vars.currentplayer->eyespy->prop; struct prop *eyespyprop = g_Vars.currentplayer->eyespy->prop;
struct chrdata *chr = eyespyprop->chr; struct chrdata *chr = eyespyprop->chr;
struct coord dstpos; struct coord dstpos;
s16 dstrooms[8]; RoomNum dstrooms[8];
s16 floorroom; RoomNum floorroom;
s16 sp74[24]; RoomNum sp74[24];
s32 types; s32 types;
s32 i; s32 i;
f32 ymin; f32 ymin;
@@ -698,8 +701,8 @@ void eyespyProcessInput(bool allowbuttons)
s8 c2stickx; s8 c2stickx;
s8 c1sticky = joyGetStickY(contpad1); s8 c1sticky = joyGetStickY(contpad1);
s8 c2sticky; s8 c2sticky;
u16 c1buttons = allowbuttons ? joyGetButtons(contpad1, 0xffff) : 0; u32 c1buttons = allowbuttons ? joyGetButtons(contpad1, 0xffffffff) : 0;
u16 c2buttons; u32 c2buttons;
bool domovecentre = true; bool domovecentre = true;
s32 controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex); s32 controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
@@ -713,20 +716,42 @@ void eyespyProcessInput(bool allowbuttons)
f32 angle; f32 angle;
f32 ascendspeed = 0.0f; f32 ascendspeed = 0.0f;
f32 prevverta = g_Vars.currentplayer->eyespy->verta; f32 prevverta = g_Vars.currentplayer->eyespy->verta;
s16 prevrooms[8]; RoomNum prevrooms[8];
s32 contpad2; s32 contpad2;
u32 stack[5]; u32 stack[5];
f32 tmp; f32 tmp;
u32 umask, dmask, lmask, rmask;
if (controlmode >= CONTROLMODE_21) { if (controlmode == CONTROLMODE_PC) {
umask = U_CBUTTONS;
dmask = D_CBUTTONS;
lmask = L_CBUTTONS;
rmask = R_CBUTTONS;
} else {
umask = U_JPAD | U_CBUTTONS;
dmask = D_JPAD | D_CBUTTONS;
lmask = L_JPAD | L_CBUTTONS;
rmask = R_JPAD | R_CBUTTONS;
}
if (controlmode >= CONTROLMODE_21 && controlmode < CONTROLMODE_PC) {
contpad2 = (s8) optionsGetContpadNum2(g_Vars.currentplayerstats->mpindex); contpad2 = (s8) optionsGetContpadNum2(g_Vars.currentplayerstats->mpindex);
c2stickx = joyGetStickX(contpad2); c2stickx = joyGetStickX(contpad2);
c2sticky = joyGetStickY(contpad2); c2sticky = joyGetStickY(contpad2);
c2buttons = allowbuttons ? joyGetButtons(contpad2, 0xffff) : 0; c2buttons = allowbuttons ? joyGetButtons(contpad2, 0xffffffff) : 0;
} else { } else {
#ifndef PLATFORM_N64
if (controlmode == CONTROLMODE_PC) {
c2stickx = joyGetRStickX(contpad1);
c2sticky = joyGetRStickY(contpad1);
} else
#else
{
c2stickx = c1stickx; c2stickx = c1stickx;
c2sticky = c1sticky; c2sticky = c1sticky;
}
#endif
c2buttons = c1buttons; c2buttons = c1buttons;
} }
@@ -735,11 +760,19 @@ void eyespyProcessInput(bool allowbuttons)
shootpressed = c1buttons & A_BUTTON; shootpressed = c1buttons & A_BUTTON;
exitpressed = c1buttons & R_TRIG; exitpressed = c1buttons & R_TRIG;
activatepressed = c1buttons & B_BUTTON; activatepressed = c1buttons & B_BUTTON;
} else if (controlmode <= CONTROLMODE_14) { } else if (controlmode <= CONTROLMODE_14 || controlmode == CONTROLMODE_PC) {
aimpressed = c1buttons & (L_TRIG | R_TRIG); aimpressed = c1buttons & (R_TRIG);
shootpressed = c1buttons & Z_TRIG; shootpressed = c1buttons & Z_TRIG;
exitpressed = c1buttons & A_BUTTON; #ifndef PLATFORM_N64
activatepressed = c1buttons & B_BUTTON; if (controlmode == CONTROLMODE_PC) {
exitpressed = c1buttons & (BUTTON_WPNBACK | BUTTON_RADIAL);
activatepressed = c1buttons & (BUTTON_CANCEL_USE | BUTTON_ACCEPT_USE);
} else
#endif
{
exitpressed = (c1buttons | c2buttons) & A_BUTTON;
activatepressed = (c1buttons | c2buttons) & B_BUTTON;
}
} else { } else {
if (controlmode >= CONTROLMODE_23) { if (controlmode >= CONTROLMODE_23) {
aimpressed = c1buttons & Z_TRIG; aimpressed = c1buttons & Z_TRIG;
@@ -818,16 +851,24 @@ void eyespyProcessInput(bool allowbuttons)
ascendspeed = (c1buttons & (U_CBUTTONS | U_JPAD) ? 1 : 0) - (c1buttons & (D_CBUTTONS | D_JPAD) ? 1 : 0); ascendspeed = (c1buttons & (U_CBUTTONS | U_JPAD) ? 1 : 0) - (c1buttons & (D_CBUTTONS | D_JPAD) ? 1 : 0);
sidespeed = (c1buttons & (R_CBUTTONS | R_JPAD) ? 1 : 0) - (c1buttons & (L_CBUTTONS | L_JPAD) ? 1 : 0); sidespeed = (c1buttons & (R_CBUTTONS | R_JPAD) ? 1 : 0) - (c1buttons & (L_CBUTTONS | L_JPAD) ? 1 : 0);
} else if (controlmode <= CONTROLMODE_14) { } else if (controlmode <= CONTROLMODE_14 || controlmode == CONTROLMODE_PC) {
if (aimpressed) { if (aimpressed) {
domovecentre = false; domovecentre = false;
pitchspeed = c1sticky; pitchspeed = c1sticky;
} else { } else {
ascendspeed = c1sticky * 0.25f; ascendspeed = c1sticky * 0.25f;
forwardspeed = (c1buttons & (U_CBUTTONS | U_JPAD) ? 24.0f : 0) - (c1buttons & (D_CBUTTONS | D_JPAD) ? 24.0f : 0); forwardspeed = (c1buttons & umask ? 24.0f : 0) - (c1buttons & dmask ? 24.0f : 0);
#ifndef PLATFORM_N64
if (controlmode == CONTROLMODE_PC) {
forwardspeed += c2sticky;
}
#endif
} }
sidespeed = (c1buttons & (R_CBUTTONS | R_JPAD) ? 1 : 0) - (c1buttons & (L_CBUTTONS | L_JPAD) ? 1 : 0); sidespeed = (c1buttons & rmask ? 1 : 0) - (c1buttons & lmask ? 1 : 0);
#ifndef PLATFORM_N64
if (!sidespeed && controlmode == CONTROLMODE_PC) sidespeed = c2stickx * 0.0125f;
#endif
} else if (controlmode == CONTROLMODE_21 || controlmode == CONTROLMODE_23) { } else if (controlmode == CONTROLMODE_21 || controlmode == CONTROLMODE_23) {
forwardspeed = c1sticky; forwardspeed = c1sticky;
@@ -898,6 +939,25 @@ void eyespyProcessInput(bool allowbuttons)
} }
#endif #endif
#ifndef PLATFORM_N64
if (g_Vars.currentplayernum == 0) {
f32 mdx, mdy;
inputMouseGetScaledDelta(&mdx, &mdy);
if (mdx || mdy) {
if (g_Vars.currentplayerstats && !optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
mdy = -mdy;
}
g_Vars.currentplayer->eyespy->theta += mdx * 1.5f;
// hold aim to move up and down, release to look up and down
if (aimpressed) {
ascendspeed -= mdy;
} else {
g_Vars.currentplayer->eyespy->verta -= mdy * 1.5f;
}
}
}
#endif
// Update theta // Update theta
g_Vars.currentplayer->eyespy->theta += c1stickx * 0.0625f * g_Vars.lvupdate60freal; g_Vars.currentplayer->eyespy->theta += c1stickx * 0.0625f * g_Vars.lvupdate60freal;
@@ -913,9 +973,28 @@ void eyespyProcessInput(bool allowbuttons)
g_Vars.currentplayer->eyespy->sintheta = sinf(g_Vars.currentplayer->eyespy->theta * 0.017453292384744f); g_Vars.currentplayer->eyespy->sintheta = sinf(g_Vars.currentplayer->eyespy->theta * 0.017453292384744f);
// Update verta // Update verta
#ifndef PLATFORM_N64
// respect the invert pitch setting
if (optionsGetForwardPitch(g_Vars.currentplayerstats->mpindex)) {
pitchspeed = -pitchspeed;
}
#endif
g_Vars.currentplayer->eyespy->verta -= pitchspeed * 0.0625f * g_Vars.lvupdate60freal; g_Vars.currentplayer->eyespy->verta -= pitchspeed * 0.0625f * g_Vars.lvupdate60freal;
if (prevverta != g_Vars.currentplayer->eyespy->verta) { if (prevverta != g_Vars.currentplayer->eyespy->verta) {
#ifndef PLATFORM_N64 // limit eyespy range to 75 degrees
while (g_Vars.currentplayer->eyespy->verta > 90.0f) {
g_Vars.currentplayer->eyespy->verta -= 360.0f;
}
if (g_Vars.currentplayer->eyespy->verta < -75.0f) {
g_Vars.currentplayer->eyespy->verta = -75.0f;
}
if (g_Vars.currentplayer->eyespy->verta > 75.0f) {
g_Vars.currentplayer->eyespy->verta = 75.0f;
}
#endif
while (g_Vars.currentplayer->eyespy->verta < 0.0f) { while (g_Vars.currentplayer->eyespy->verta < 0.0f) {
g_Vars.currentplayer->eyespy->verta += 360.0f; g_Vars.currentplayer->eyespy->verta += 360.0f;
} }
@@ -937,6 +1016,7 @@ void eyespyProcessInput(bool allowbuttons)
// Make eyespy look horizontally // Make eyespy look horizontally
if (domovecentre) { if (domovecentre) {
if (g_Vars.currentplayer->eyespy->verta > 0.0f && forwardspeed != 0) { if (g_Vars.currentplayer->eyespy->verta > 0.0f && forwardspeed != 0) {
if (controlmode < CONTROLMODE_PC) {
if (g_Vars.currentplayer->eyespy->verta < 180.0f) { if (g_Vars.currentplayer->eyespy->verta < 180.0f) {
tmp = g_Vars.currentplayer->eyespy->verta; tmp = g_Vars.currentplayer->eyespy->verta;
@@ -952,6 +1032,7 @@ void eyespyProcessInput(bool allowbuttons)
g_Vars.currentplayer->eyespy->verta += tmp; g_Vars.currentplayer->eyespy->verta += tmp;
} }
} }
}
g_Vars.currentplayer->eyespy->cosverta = cosf(g_Vars.currentplayer->eyespy->verta * 0.017453292384744f); g_Vars.currentplayer->eyespy->cosverta = cosf(g_Vars.currentplayer->eyespy->verta * 0.017453292384744f);
g_Vars.currentplayer->eyespy->sinverta = sinf(g_Vars.currentplayer->eyespy->verta * 0.017453292384744f); g_Vars.currentplayer->eyespy->sinverta = sinf(g_Vars.currentplayer->eyespy->verta * 0.017453292384744f);
@@ -1017,7 +1098,13 @@ void eyespyProcessInput(bool allowbuttons)
if (g_Vars.currentplayer->eyespy->bobactive || ABS(g_Vars.currentplayer->eyespy->vel.y) < 0.1f) { if (g_Vars.currentplayer->eyespy->bobactive || ABS(g_Vars.currentplayer->eyespy->vel.y) < 0.1f) {
g_Vars.currentplayer->eyespy->bobactive = true; g_Vars.currentplayer->eyespy->bobactive = true;
g_Vars.currentplayer->eyespy->bobtimer += g_Vars.lvupdate60; g_Vars.currentplayer->eyespy->bobtimer += g_Vars.lvupdate60;
#ifdef PLATFORM_N64
g_Vars.currentplayer->eyespy->vel.y += 0.025f * g_Vars.currentplayer->eyespy->bobdir; g_Vars.currentplayer->eyespy->vel.y += 0.025f * g_Vars.currentplayer->eyespy->bobdir;
#else
// HACK: how do I scale this properly?
const f32 scale = (g_Vars.lvupdate60freal <= 1.1f) ? 0.0055f : 0.0125f;
g_Vars.currentplayer->eyespy->vel.y += scale * g_Vars.lvupdate60freal * g_Vars.currentplayer->eyespy->bobdir;
#endif
if (g_Vars.currentplayer->eyespy->bobtimer > TICKS(120)) { if (g_Vars.currentplayer->eyespy->bobtimer > TICKS(120)) {
g_Vars.currentplayer->eyespy->bobtimer = 0; g_Vars.currentplayer->eyespy->bobtimer = 0;
+7 -7
View File
@@ -84,7 +84,7 @@ void bgrabInit(void)
if (hov) { if (hov) {
g_Vars.currentplayer->grabbedrotoffset = g_Vars.currentplayer->grabbedrotoffset =
hov->unk10 - (M_BADTAU - (g_Vars.currentplayer->vv_theta * M_BADTAU) / 360.0f); hov->yrot - (M_BADTAU - (g_Vars.currentplayer->vv_theta * M_BADTAU) / 360.0f);
if (g_Vars.currentplayer->grabbedrotoffset >= M_BADTAU) { if (g_Vars.currentplayer->grabbedrotoffset >= M_BADTAU) {
g_Vars.currentplayer->grabbedrotoffset -= M_BADTAU; g_Vars.currentplayer->grabbedrotoffset -= M_BADTAU;
@@ -284,7 +284,7 @@ bool bgrabTryMoveUpwards(f32 y)
{ {
bool result; bool result;
struct coord newpos; struct coord newpos;
s16 rooms[8]; RoomNum rooms[8];
f32 ymax; f32 ymax;
f32 ymin; f32 ymin;
f32 radius; f32 radius;
@@ -320,7 +320,7 @@ s32 bgrabCalculateNewPosition(struct coord *delta, f32 angle, bool arg2)
s32 cdresult = CDRESULT_NOCOLLISION; s32 cdresult = CDRESULT_NOCOLLISION;
s32 i; s32 i;
struct coord pos; struct coord pos;
s16 rooms[8]; RoomNum rooms[8];
bool ismoving = false; bool ismoving = false;
f32 ymax; f32 ymax;
f32 ymin; f32 ymin;
@@ -448,7 +448,7 @@ s32 bgrabCalculateNewPosition(struct coord *delta, f32 angle, bool arg2)
- g_Vars.currentplayer->vv_theta * M_BADTAU / 360.0f - g_Vars.currentplayer->vv_theta * M_BADTAU / 360.0f
+ -angle + -angle
+ g_Vars.currentplayer->grabbedrotoffset + g_Vars.currentplayer->grabbedrotoffset
- hov->unk10 - hov->yrot
+ rotextra; + rotextra;
while (sp78 >= M_PI) { while (sp78 >= M_PI) {
@@ -1038,7 +1038,7 @@ void bgrab0f0ce924(void)
g_Vars.currentplayer->speedforwards += sp70; g_Vars.currentplayer->speedforwards += sp70;
g_Vars.currentplayer->speedsideways += sp6c; g_Vars.currentplayer->speedsideways += sp6c;
mult = var80075c00[1].unk0c * 0.5f * g_Vars.lvupdate60freal; mult = g_HeadAnims[HEADANIM_MOVING].translateperframe * 0.5f * g_Vars.lvupdate60freal;
sp88 = mult * g_Vars.currentplayer->speedsideways; sp88 = mult * g_Vars.currentplayer->speedsideways;
speedsideways = g_Vars.currentplayer->speedsideways * 0.8f; speedsideways = g_Vars.currentplayer->speedsideways * 0.8f;
@@ -1149,7 +1149,7 @@ void bgrab0f0ce924(void)
sp3c = -1.0f; sp3c = -1.0f;
} }
if (g_Vars.currentplayer->headanim == 1) { if (g_Vars.currentplayer->headanim == HEADANIM_MOVING) {
breathing *= 1.2f; breathing *= 1.2f;
} }
@@ -1207,7 +1207,7 @@ void bgrabTick(void)
if (g_Vars.currentplayer->grabbedprop) { if (g_Vars.currentplayer->grabbedprop) {
// Determine if the grabbed prop should be force released // Determine if the grabbed prop should be force released
f32 ydiff = g_Vars.currentplayer->grabbedprop->pos.y f32 ydiff = g_Vars.currentplayer->grabbedprop->pos.y
- objGetHov04(g_Vars.currentplayer->grabbedprop->obj) - objGetHovBobOffsetY(g_Vars.currentplayer->grabbedprop->obj)
- g_Vars.currentplayer->vv_manground; - g_Vars.currentplayer->vv_manground;
struct prop *grabbedprop = g_Vars.currentplayer->grabbedprop; struct prop *grabbedprop = g_Vars.currentplayer->grabbedprop;
+276 -67
View File
@@ -53,6 +53,12 @@
#include "lib/lib_317f0.h" #include "lib/lib_317f0.h"
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64
#include "game/stagetable.h"
#include "video.h"
#include "net/net.h"
#include "net/netmsg.h"
#endif
#define GUNLOADSTATE_FLUX 0 #define GUNLOADSTATE_FLUX 0
#define GUNLOADSTATE_MODEL 1 #define GUNLOADSTATE_MODEL 1
@@ -186,6 +192,10 @@ char var800700bc[][10] = {
{ 'x','x','x' }, // "xxx" { 'x','x','x' }, // "xxx"
}; };
#ifndef PLATFORM_N64
s32 g_BgunGeMuzzleFlashes = false;
#endif
#if !MATCHING || VERSION >= VERSION_NTSC_1_0 #if !MATCHING || VERSION >= VERSION_NTSC_1_0
void bgunRumble(s32 handnum, s32 weaponnum) void bgunRumble(s32 handnum, s32 weaponnum)
{ {
@@ -246,8 +256,9 @@ void bgunRumble(s32 handnum, s32 weaponnum)
bool contpad2hasrumble; bool contpad2hasrumble;
s32 contpadtouse1; s32 contpadtouse1;
s32 contpadtouse2; s32 contpadtouse2;
s32 controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
if (optionsGetControlMode(g_Vars.currentplayerstats->mpindex) >= CONTROLMODE_21) { if (controlmode >= CONTROLMODE_21 && controlmode < CONTROLMODE_PC) {
contpad1hasrumble = pakGetType(g_Vars.currentplayernum) == PAKTYPE_RUMBLE; contpad1hasrumble = pakGetType(g_Vars.currentplayernum) == PAKTYPE_RUMBLE;
contpad2hasrumble = pakGetType(g_Vars.currentplayernum + PLAYERCOUNT()) == PAKTYPE_RUMBLE; contpad2hasrumble = pakGetType(g_Vars.currentplayernum + PLAYERCOUNT()) == PAKTYPE_RUMBLE;
@@ -1307,6 +1318,7 @@ s32 bgunTickIncIdle(struct handweaponinfo *info, s32 handnum, struct hand *hand,
hand->count = 0; hand->count = 0;
if (bgunSetState(handnum, HANDSTATE_RELOAD)) { if (bgunSetState(handnum, HANDSTATE_RELOAD)) {
hand->modenext = HANDMODE_NONE;
return lvupdate; return lvupdate;
} }
} }
@@ -1905,7 +1917,17 @@ void bgun0f09a6f8(struct handweaponinfo *info, s32 handnum, struct hand *hand, s
if (func->flags & FUNCFLAG_NOMUZZLEFLASH) { if (func->flags & FUNCFLAG_NOMUZZLEFLASH) {
hand->flashon = false; hand->flashon = false;
} else { } else {
#ifdef PLATFORM_N64
hand->flashon = true; hand->flashon = true;
#else
if (g_BgunGeMuzzleFlashes) {
if (func->type == INVENTORYFUNCTYPE_SHOOT_SINGLE || (hand->shotstotake & 1)) {
hand->flashon = true;
}
} else {
hand->flashon = true;
}
#endif
} }
bgunStartSlide(handnum); bgunStartSlide(handnum);
@@ -3624,6 +3646,7 @@ u32 bgunCalculateGunMemCapacity(void)
} }
if (PLAYERCOUNT() == 1) { if (PLAYERCOUNT() == 1) {
#ifdef PLATFORM_N64
switch (g_Vars.stagenum) { switch (g_Vars.stagenum) {
case STAGE_CHICAGO: case STAGE_CHICAGO:
case STAGE_AIRBASE: case STAGE_AIRBASE:
@@ -3632,6 +3655,9 @@ u32 bgunCalculateGunMemCapacity(void)
case STAGE_ATTACKSHIP: case STAGE_ATTACKSHIP:
return g_BgunGunMemBaseSizeDefault + 25 * 1024; return g_BgunGunMemBaseSizeDefault + 25 * 1024;
} }
#else
return g_BgunGunMemBaseSizeDefault + stageGetCurrent()->extragunmem;
#endif
} }
return g_BgunGunMemBaseSizeDefault; return g_BgunGunMemBaseSizeDefault;
@@ -3640,6 +3666,11 @@ u32 bgunCalculateGunMemCapacity(void)
void bgunFreeGunMem(void) void bgunFreeGunMem(void)
{ {
g_Vars.currentplayer->gunctrl.gunmemowner = GUNMEMOWNER_FREE; g_Vars.currentplayer->gunctrl.gunmemowner = GUNMEMOWNER_FREE;
#ifndef PLATFORM_N64
// gunmem is stale and so are the textures in it
// TODO: figure out how to purge only those textures
videoResetTextureCache();
#endif
} }
void bgunSetGunMemWeapon(s32 weaponnum) void bgunSetGunMemWeapon(s32 weaponnum)
@@ -4149,10 +4180,10 @@ void bgunTickMasterLoad(void)
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
hand = &player->hands[i]; hand = &player->hands[i];
modelInit(&hand->gunmodel, player->gunctrl.gunmodeldef, (union modelrwdata **)hand->unk0a6c, 0); modelInit(&hand->gunmodel, player->gunctrl.gunmodeldef, hand->unk0a6c, 0);
if (player->gunctrl.handmodeldef != 0) { if (player->gunctrl.handmodeldef != 0) {
modelInit(&hand->handmodel, player->gunctrl.handmodeldef, (union modelrwdata **)hand->handsavedata, false); modelInit(&hand->handmodel, player->gunctrl.handmodeldef, hand->handsavedata, false);
} }
hand->unk0dcc = (s32 *) player->gunctrl.memloadptr; hand->unk0dcc = (s32 *) player->gunctrl.memloadptr;
@@ -4280,7 +4311,7 @@ struct modeldef *bgunGetCartModeldef(void)
return g_Vars.currentplayer->gunctrl.cartmodeldef; return g_Vars.currentplayer->gunctrl.cartmodeldef;
} }
void bgun0f09ebcc(struct defaultobj *obj, struct coord *coord, s16 *rooms, Mtxf *matrix1, struct coord *velocity, Mtxf *matrix2, struct prop *prop, struct coord *pos) void bgun0f09ebcc(struct defaultobj *obj, struct coord *coord, RoomNum *rooms, Mtxf *matrix1, struct coord *velocity, Mtxf *matrix2, struct prop *prop, struct coord *pos)
{ {
struct prop *objprop = obj->prop; struct prop *objprop = obj->prop;
@@ -4325,7 +4356,7 @@ void bgun0f09ed2c(struct defaultobj *obj, struct coord *newpos, Mtxf *arg2, stru
{ {
struct prop *objprop = obj->prop; struct prop *objprop = obj->prop;
struct coord pos; struct coord pos;
s16 rooms[8]; RoomNum rooms[8];
if (objprop) { if (objprop) {
struct prop *playerprop = g_Vars.currentplayer->prop; struct prop *playerprop = g_Vars.currentplayer->prop;
@@ -4348,7 +4379,7 @@ void bgun0f09ed2c(struct defaultobj *obj, struct coord *newpos, Mtxf *arg2, stru
} }
} }
struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset *gset, struct coord *pos, s16 *rooms, Mtxf *arg4, struct coord *velocity) struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset *gset, struct coord *pos, RoomNum *rooms, Mtxf *arg4, struct coord *velocity)
{ {
struct defaultobj *obj = NULL; struct defaultobj *obj = NULL;
struct weaponfunc *basefunc; struct weaponfunc *basefunc;
@@ -4443,12 +4474,12 @@ struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset
* 2 = fumbling grenade from right hand (due to nbomb) * 2 = fumbling grenade from right hand (due to nbomb)
* 3 = fumbling grenade from left hand (actually not possible) * 3 = fumbling grenade from left hand (actually not possible)
*/ */
void bgunCreateThrownProjectile(s32 handnum, struct gset *gset) struct defaultobj *bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
{ {
struct coord velocity = {0, 0, 0}; struct coord velocity = {0, 0, 0};
Mtxf sp1f4; Mtxf sp1f4;
struct coord sp1e8; struct coord gunpos;
struct coord sp1dc; struct coord gundir;
struct prop *playerprop = g_Vars.currentplayer->prop; struct prop *playerprop = g_Vars.currentplayer->prop;
struct coord *prevpos = &g_Vars.currentplayer->bondprevpos; struct coord *prevpos = &g_Vars.currentplayer->bondprevpos;
struct coord *extrapos = &g_Vars.currentplayer->bondextrapos; struct coord *extrapos = &g_Vars.currentplayer->bondextrapos;
@@ -4457,7 +4488,7 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
struct weaponobj *weapon; struct weaponobj *weapon;
struct coord muzzlepos; struct coord muzzlepos;
struct coord spawnpos; struct coord spawnpos;
s16 spawnrooms[8]; RoomNum spawnrooms[8];
bool droppinggrenade = false; bool droppinggrenade = false;
struct hand *hand; struct hand *hand;
struct coord aimpos; struct coord aimpos;
@@ -4473,6 +4504,13 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
struct trainingdata *data; struct trainingdata *data;
u32 stack; u32 stack;
#ifndef PLATFORM_N64
// don't do anything if we're not the authority
if (g_NetMode == NETMODE_CLIENT) {
return NULL;
}
#endif
if (handnum >= 2) { if (handnum >= 2) {
droppinggrenade = true; droppinggrenade = true;
handnum -= 2; handnum -= 2;
@@ -4520,17 +4558,17 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
playerSetPerimEnabled(playerprop, true); playerSetPerimEnabled(playerprop, true);
bgunCalculatePlayerShotSpread(&sp1e8, &sp1dc, handnum, true); bgunCalculatePlayerShotSpread(&gunpos, &gundir, handnum, true);
mtx4RotateVecInPlace(camGetProjectionMtxF(), &sp1dc); mtx4RotateVecInPlace(camGetProjectionMtxF(), &gundir);
if (droppinggrenade) { if (droppinggrenade) {
// Dropping a grenade because player is in an nbomb storm // Dropping a grenade because player is in an nbomb storm
velocity.x = sp1dc.x * 1.6666666f; velocity.x = gundir.x * 1.6666666f;
velocity.y = sp1dc.y * 1.6666666f; velocity.y = gundir.y * 1.6666666f;
velocity.z = sp1dc.z * 1.6666666f; velocity.z = gundir.z * 1.6666666f;
} else if (gsetHasFunctionFlags(&hand->gset, FUNCFLAG_CALCULATETRAJECTORY)) { } else if (gsetHasFunctionFlags(&hand->gset, FUNCFLAG_CALCULATETRAJECTORY)) {
// Calculate the velocity based on the trajectory to the aimpos // Calculate the velocity based on the trajectory to the aimpos
func0f061d54(0, 0, 0); propFindAimingAt(HAND_RIGHT, false, FINDPROPCONTEXT_QUERY);
if (hand->hasdotinfo) { if (hand->hasdotinfo) {
aimpos.x = hand->dotpos.x; aimpos.x = hand->dotpos.x;
@@ -4539,11 +4577,11 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
chrCalculateTrajectory(&spawnpos, 21.666666f, &aimpos, &sp140); chrCalculateTrajectory(&spawnpos, 21.666666f, &aimpos, &sp140);
radians = acosf(sp1dc.f[0] * sp140.f[0] + sp1dc.f[1] * sp140.f[1] + sp1dc.f[2] * sp140.f[2]); radians = acosf(gundir.f[0] * sp140.f[0] + gundir.f[1] * sp140.f[1] + gundir.f[2] * sp140.f[2]);
// Check within 20 degrees // Check within 20 degrees
if (radians > 0.34901026f || radians < -0.34901026f) { if (radians > 0.34901026f || radians < -0.34901026f) {
mtx00016b58(&spf8, 0, 0, 0, sp1dc.x, sp1dc.y, sp1dc.z, 0, 1, 0); mtx00016b58(&spf8, 0, 0, 0, gundir.x, gundir.y, gundir.z, 0, 1, 0);
mtx00016b58(&spb8, 0, 0, 0, sp140.x, sp140.y, sp140.z, 0, 1, 0); mtx00016b58(&spb8, 0, 0, 0, sp140.x, sp140.y, sp140.z, 0, 1, 0);
quaternion0f097044(&spf8, sp68); quaternion0f097044(&spf8, sp68);
@@ -4559,24 +4597,24 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
quaternionSlerp(sp68, sp58, frac, sp48); quaternionSlerp(sp68, sp58, frac, sp48);
quaternionToMtx(sp48, &sp78); quaternionToMtx(sp48, &sp78);
sp1dc.x = -sp78.m[2][0]; gundir.x = -sp78.m[2][0];
sp1dc.y = -sp78.m[2][1]; gundir.y = -sp78.m[2][1];
sp1dc.z = -sp78.m[2][2]; gundir.z = -sp78.m[2][2];
} else { } else {
sp1dc.x = sp140.x; gundir.x = sp140.x;
sp1dc.y = sp140.y; gundir.y = sp140.y;
sp1dc.z = sp140.z; gundir.z = sp140.z;
} }
} }
velocity.x = sp1dc.x * 21.666666f; velocity.x = gundir.x * 21.666666f;
velocity.y = sp1dc.y * 21.666666f; velocity.y = gundir.y * 21.666666f;
velocity.z = sp1dc.z * 21.666666f; velocity.z = gundir.z * 21.666666f;
} else { } else {
// Simple velocity // Simple velocity
velocity.x = sp1dc.x * 16.666666f; velocity.x = gundir.x * 16.666666f;
velocity.y = sp1dc.y * 16.666666f; velocity.y = gundir.y * 16.666666f;
velocity.z = sp1dc.z * 16.666666f; velocity.z = gundir.z * 16.666666f;
if (gset->weaponnum == WEAPON_GRENADE || gset->weaponnum == WEAPON_NBOMB) { if (gset->weaponnum == WEAPON_GRENADE || gset->weaponnum == WEAPON_NBOMB) {
velocity.y += 1.6666666f; velocity.y += 1.6666666f;
@@ -4638,7 +4676,16 @@ void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
weapon->base.hidden |= OBJHFLAG_THROWNKNIFE; weapon->base.hidden |= OBJHFLAG_THROWNKNIFE;
} }
} }
#ifndef PLATFORM_N64
if (obj && g_NetMode == NETMODE_SERVER) {
netmsgSvcPropSpawnWrite(&g_NetMsgRel, obj->prop);
netmsgSvcPropMoveWrite(&g_NetMsgRel, obj->prop, NULL);
} }
#endif
}
return obj;
} }
void bgunUpdateHeldRocket(s32 handnum) void bgunUpdateHeldRocket(s32 handnum)
@@ -4722,8 +4769,8 @@ void bgunCreateFiredProjectile(s32 handnum)
f32 sp25c; f32 sp25c;
struct coord sp250; struct coord sp250;
Mtxf sp210; Mtxf sp210;
struct coord sp204; struct coord gunpos;
struct coord sp1f8; struct coord gundir;
struct prop *playerprop; struct prop *playerprop;
struct coord *prevpos; struct coord *prevpos;
struct coord *extrapos; struct coord *extrapos;
@@ -4742,6 +4789,12 @@ void bgunCreateFiredProjectile(s32 handnum)
f32 spd4[4]; f32 spd4[4];
f32 spc4[4]; f32 spc4[4];
#ifndef PLATFORM_N64
if (g_NetMode == NETMODE_CLIENT) {
return;
}
#endif
hand = g_Vars.currentplayer->hands + handnum; hand = g_Vars.currentplayer->hands + handnum;
playerprop = g_Vars.currentplayer->prop; playerprop = g_Vars.currentplayer->prop;
@@ -4757,24 +4810,24 @@ void bgunCreateFiredProjectile(s32 handnum)
funcdef = (struct weaponfunc_shootprojectile *)tmp; funcdef = (struct weaponfunc_shootprojectile *)tmp;
mtx4LoadIdentity(&sp270); mtx4LoadIdentity(&sp270);
bgunCalculatePlayerShotSpread(&sp204, &sp1f8, handnum, true); bgunCalculatePlayerShotSpread(&gunpos, &gundir, handnum, true);
mtx4RotateVecInPlace(camGetProjectionMtxF(), &sp1f8); mtx4RotateVecInPlace(camGetProjectionMtxF(), &gundir);
spawnpos.x = hand->muzzlepos.x; spawnpos.x = hand->muzzlepos.x;
spawnpos.y = hand->muzzlepos.y; spawnpos.y = hand->muzzlepos.y;
spawnpos.z = hand->muzzlepos.z; spawnpos.z = hand->muzzlepos.z;
if (hand->gset.weaponnum == WEAPON_SLAYER && hand->gset.weaponfunc == FUNC_SECONDARY) { if (hand->gset.weaponnum == WEAPON_SLAYER && hand->gset.weaponfunc == FUNC_SECONDARY) {
spawnpos.x += 50.0f * sp1f8.x; spawnpos.x += 50.0f * gundir.x;
spawnpos.y += 50.0f * sp1f8.y; spawnpos.y += 50.0f * gundir.y;
spawnpos.z += 50.0f * sp1f8.z; spawnpos.z += 50.0f * gundir.z;
} }
sp260 = funcdef->speed * 1.6666666f / 60.0f; sp260 = funcdef->speed * 1.6666666f / 60.0f;
sp25c = funcdef->traveldist * 1.6666666f; sp25c = funcdef->traveldist * 1.6666666f;
if (gsetHasFunctionFlags(&hand->gset, FUNCFLAG_CALCULATETRAJECTORY)) { if (gsetHasFunctionFlags(&hand->gset, FUNCFLAG_CALCULATETRAJECTORY)) {
func0f061d54(0, 0, 0); propFindAimingAt(HAND_RIGHT, false, FINDPROPCONTEXT_QUERY);
if (hand->hasdotinfo) { if (hand->hasdotinfo) {
aimpos.x = hand->dotpos.x; aimpos.x = hand->dotpos.x;
@@ -4783,10 +4836,10 @@ void bgunCreateFiredProjectile(s32 handnum)
chrCalculateTrajectory(&spawnpos, sp25c, &aimpos, &sp1bc); chrCalculateTrajectory(&spawnpos, sp25c, &aimpos, &sp1bc);
radians = acosf(sp1f8.f[0] * sp1bc.f[0] + sp1f8.f[1] * sp1bc.f[1] + sp1f8.f[2] * sp1bc.f[2]); radians = acosf(gundir.f[0] * sp1bc.f[0] + gundir.f[1] * sp1bc.f[1] + gundir.f[2] * sp1bc.f[2]);
if (radians > 0.17450513f || radians < -0.17450513f) { if (radians > 0.17450513f || radians < -0.17450513f) {
mtx00016b58(&sp174, 0.0f, 0.0f, 0.0f, sp1f8.x, sp1f8.y, sp1f8.z, 0.0f, 1.0f, 0.0f); mtx00016b58(&sp174, 0.0f, 0.0f, 0.0f, gundir.x, gundir.y, gundir.z, 0.0f, 1.0f, 0.0f);
mtx00016b58(&sp134, 0.0f, 0.0f, 0.0f, sp1bc.x, sp1bc.y, sp1bc.z, 0.0f, 1.0f, 0.0f); mtx00016b58(&sp134, 0.0f, 0.0f, 0.0f, sp1bc.x, sp1bc.y, sp1bc.z, 0.0f, 1.0f, 0.0f);
quaternion0f097044(&sp174, spe4); quaternion0f097044(&sp174, spe4);
@@ -4802,24 +4855,24 @@ void bgunCreateFiredProjectile(s32 handnum)
quaternionSlerp(spe4, spd4, frac, spc4); quaternionSlerp(spe4, spd4, frac, spc4);
quaternionToMtx(spc4, &spf4); quaternionToMtx(spc4, &spf4);
sp1f8.x = -spf4.m[2][0]; gundir.x = -spf4.m[2][0];
sp1f8.y = -spf4.m[2][1]; gundir.y = -spf4.m[2][1];
sp1f8.z = -spf4.m[2][2]; gundir.z = -spf4.m[2][2];
} else { } else {
sp1f8.x = sp1bc.x; gundir.x = sp1bc.x;
sp1f8.y = sp1bc.y; gundir.y = sp1bc.y;
sp1f8.z = sp1bc.z; gundir.z = sp1bc.z;
} }
} }
} }
sp250.x = sp1f8.x * sp260; sp250.x = gundir.x * sp260;
sp250.y = sp1f8.y * sp260; sp250.y = gundir.y * sp260;
sp250.z = sp1f8.z * sp260; sp250.z = gundir.z * sp260;
sp264.x = sp250.f[0] * g_Vars.lvupdate60freal + sp1f8.f[0] * sp25c; sp264.x = sp250.f[0] * g_Vars.lvupdate60freal + gundir.f[0] * sp25c;
sp264.y = sp250.f[1] * g_Vars.lvupdate60freal + sp1f8.f[1] * sp25c; sp264.y = sp250.f[1] * g_Vars.lvupdate60freal + gundir.f[1] * sp25c;
sp264.z = sp250.f[2] * g_Vars.lvupdate60freal + sp1f8.f[2] * sp25c; sp264.z = sp250.f[2] * g_Vars.lvupdate60freal + gundir.f[2] * sp25c;
if ((funcdef->base.base.flags & FUNCFLAG_FLYBYWIRE) == 0 && g_Vars.lvupdate240 > 0) { if ((funcdef->base.base.flags & FUNCFLAG_FLYBYWIRE) == 0 && g_Vars.lvupdate240 > 0) {
sp264.x += (playerprop->pos.x - prevpos->x + extrapos->x) / g_Vars.lvupdate60freal; sp264.x += (playerprop->pos.x - prevpos->x + extrapos->x) / g_Vars.lvupdate60freal;
@@ -4954,6 +5007,12 @@ void bgunCreateFiredProjectile(s32 handnum)
weapon->base.prop = NULL; weapon->base.prop = NULL;
weapon->base.model = NULL; weapon->base.model = NULL;
} }
#ifndef PLATFORM_N64
else if (g_NetMode == NETMODE_SERVER) {
netmsgSvcPropSpawnWrite(&g_NetMsgRel, weapon->base.prop);
netmsgSvcPropMoveWrite(&g_NetMsgRel, weapon->base.prop, NULL);
}
#endif
#else #else
// NTSC beta doesn't have any of the failure checks // NTSC beta doesn't have any of the failure checks
Mtxf sp78; Mtxf sp78;
@@ -5236,7 +5295,7 @@ void bgun0f0a0c44(s32 handnum, struct coord *arg1, struct coord *arg2)
cam0f0b4c3c(g_Vars.currentplayer->hands[handnum].crosspos, arg2, 1); cam0f0b4c3c(g_Vars.currentplayer->hands[handnum].crosspos, arg2, 1);
} }
void bgunCalculatePlayerShotSpread(struct coord *arg0, struct coord *arg1, s32 handnum, bool dorandom) void bgunCalculatePlayerShotSpread(struct coord *gunpos2d, struct coord *gundir2d, s32 handnum, bool dorandom)
{ {
f32 crosspos[2]; f32 crosspos[2];
f32 spread = 0; f32 spread = 0;
@@ -5250,7 +5309,6 @@ void bgunCalculatePlayerShotSpread(struct coord *arg0, struct coord *arg1, s32 h
spread = shootfunc->spread; spread = shootfunc->spread;
} }
// Unsure what this is
if (weaponHasAimFlag(bgunGetWeaponNum2(handnum), INVAIMFLAG_ACCURATESINGLESHOT) if (weaponHasAimFlag(bgunGetWeaponNum2(handnum), INVAIMFLAG_ACCURATESINGLESHOT)
&& player->hands[handnum].burstbullets == 1) { && player->hands[handnum].burstbullets == 1) {
spread *= 0.25f; spread *= 0.25f;
@@ -5286,11 +5344,11 @@ void bgunCalculatePlayerShotSpread(struct coord *arg0, struct coord *arg1, s32 h
crosspos[1] = player->crosspos[1] + (randfactor * scaledspread * camGetScreenHeight()) crosspos[1] = player->crosspos[1] + (randfactor * scaledspread * camGetScreenHeight())
/ viGetHeight(); / viGetHeight();
arg0->x = 0; gunpos2d->x = 0;
arg0->y = 0; gunpos2d->y = 0;
arg0->z = 0; gunpos2d->z = 0;
cam0f0b4c3c(crosspos, arg1, 1); cam0f0b4c3c(crosspos, gundir2d, 1);
} }
void bgunCalculateBotShotSpread(struct coord *arg0, s32 weaponnum, s32 funcnum, bool arg3, s32 crouchpos, bool dual) void bgunCalculateBotShotSpread(struct coord *arg0, s32 weaponnum, s32 funcnum, bool arg3, s32 crouchpos, bool dual)
@@ -5433,7 +5491,7 @@ void bgunTickSwitch2(void)
ctrl->switchtoweaponnum = WEAPON_UNARMED; ctrl->switchtoweaponnum = WEAPON_UNARMED;
} }
#if VERSION == VERSION_JPN_FINAL #if (VERSION == VERSION_JPN_FINAL) && defined(PLATFORM_N64)
if (ctrl->switchtoweaponnum == WEAPON_COMBATKNIFE) { if (ctrl->switchtoweaponnum == WEAPON_COMBATKNIFE) {
ctrl->switchtoweaponnum = WEAPON_UNARMED; ctrl->switchtoweaponnum = WEAPON_UNARMED;
} }
@@ -5749,14 +5807,20 @@ bool bgunHasAmmoForWeapon(s32 weaponnum)
u8 g_AutoSwitchWeaponsPrimary[] = { u8 g_AutoSwitchWeaponsPrimary[] = {
WEAPON_RCP120, WEAPON_RCP120,
WEAPON_RCP45,
WEAPON_SUPERDRAGON, // primary function WEAPON_SUPERDRAGON, // primary function
WEAPON_K7AVENGER, WEAPON_K7AVENGER,
WEAPON_AR34, WEAPON_AR34,
WEAPON_AR53,
WEAPON_KF7SPECIAL,
WEAPON_CALLISTO, WEAPON_CALLISTO,
WEAPON_LAPTOPGUN, WEAPON_LAPTOPGUN,
WEAPON_DRAGON, WEAPON_DRAGON,
WEAPON_CMP150, WEAPON_CMP150,
WEAPON_CYCLONE, WEAPON_CYCLONE,
WEAPON_ZZT,
WEAPON_DMC,
WEAPON_KL01313,
WEAPON_FARSIGHT, WEAPON_FARSIGHT,
WEAPON_SHOTGUN, WEAPON_SHOTGUN,
WEAPON_REAPER, WEAPON_REAPER,
@@ -5768,6 +5832,8 @@ u8 g_AutoSwitchWeaponsPrimary[] = {
WEAPON_FALCON2_SCOPE, WEAPON_FALCON2_SCOPE,
WEAPON_FALCON2, WEAPON_FALCON2,
WEAPON_FALCON2_SILENCER, WEAPON_FALCON2_SILENCER,
WEAPON_PP9I,
WEAPON_CC13,
WEAPON_SNIPERRIFLE, WEAPON_SNIPERRIFLE,
WEAPON_CROSSBOW, WEAPON_CROSSBOW,
WEAPON_TRANQUILIZER, WEAPON_TRANQUILIZER,
@@ -6277,6 +6343,13 @@ void bgunDisarm(struct prop *attackerprop)
s32 modelnum; s32 modelnum;
s32 i; s32 i;
bool drop; bool drop;
struct defaultobj *obj;
#ifndef PLATFORM_N64
// don't do anything if we're not the authority
if (g_NetMode == NETMODE_CLIENT) {
return;
}
#endif
if (!weaponHasFlag(weaponnum, WEAPONFLAG_UNDROPPABLE) && weaponnum <= WEAPON_RCP45) { if (!weaponHasFlag(weaponnum, WEAPONFLAG_UNDROPPABLE) && weaponnum <= WEAPON_RCP45) {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
@@ -6294,6 +6367,12 @@ void bgunDisarm(struct prop *attackerprop)
return; return;
} }
#ifndef PLATFORM_N64
if (g_NetMode == NETMODE_SERVER) {
netmsgSvcChrDisarmWrite(&g_NetMsgRel, player->prop->chr, attackerprop, weaponnum, 0.f, NULL);
}
#endif
chr = player->prop->chr; chr = player->prop->chr;
drop = true; drop = true;
@@ -6312,11 +6391,17 @@ void bgunDisarm(struct prop *attackerprop)
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
struct weaponfunc *func = gsetGetWeaponFunction(&player->hands[i].gset); struct weaponfunc *func = gsetGetWeaponFunction(&player->hands[i].gset);
#ifdef AVOID_UB
if (func && (func->type & 0xff) == INVENTORYFUNCTYPE_THROW
&& player->hands[i].state == HANDSTATE_ATTACK
&& player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) {
#else
if ((func->type & 0xff) == INVENTORYFUNCTYPE_THROW if ((func->type & 0xff) == INVENTORYFUNCTYPE_THROW
&& player->hands[i].state == HANDSTATE_ATTACK && player->hands[i].state == HANDSTATE_ATTACK
&& player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) { && player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) {
#endif
drop = false; drop = false;
bgunCreateThrownProjectile(i + 2, &player->hands[i].gset); obj = bgunCreateThrownProjectile(i + 2, &player->hands[i].gset);
} }
} }
} }
@@ -6340,6 +6425,13 @@ void bgunDisarm(struct prop *attackerprop)
} }
objDrop(prop2, true); objDrop(prop2, true);
#ifndef PLATFORM_N64
if (g_NetMode == NETMODE_SERVER) {
netmsgSvcPropSpawnWrite(&g_NetMsgRel, prop2);
netmsgSvcPropMoveWrite(&g_NetMsgRel, prop2, NULL);
}
#endif
} }
} }
@@ -6748,7 +6840,7 @@ void bgunUpdateSmoke(struct hand *hand, s32 handnum, s32 weaponnum, struct weapo
if (hand->createsmoke && (hand->state != HANDSTATE_ATTACK || hand->forcecreatesmoke)) { if (hand->createsmoke && (hand->state != HANDSTATE_ATTACK || hand->forcecreatesmoke)) {
struct coord smokepos; struct coord smokepos;
s16 smokerooms[2]; RoomNum smokerooms[2];
s32 smoketype = SMOKETYPE_MUZZLE_AUTOMATIC; s32 smoketype = SMOKETYPE_MUZZLE_AUTOMATIC;
switch (weaponnum) { switch (weaponnum) {
@@ -7483,6 +7575,22 @@ void bgunCreateFx(struct hand *hand, s32 handnum, struct weaponfunc *funcdef, s3
} }
} }
#ifndef PLATFORM_N64
// offset calculation from NeonNyan/perfect-dark
static inline f32 bgunGetFovOffsetZ(void)
{
return (PLAYER_DEFAULT_FOV - 60.f) / 3.f;
}
static inline f32 bgunGetFovOffsetY(void)
{
return (PLAYER_DEFAULT_FOV - 60.f) / (2.75f * 4.f);
}
#endif
void bgun0f0a5550(s32 handnum) void bgun0f0a5550(s32 handnum)
{ {
u8 *mtxallocation; u8 *mtxallocation;
@@ -7574,6 +7682,12 @@ void bgun0f0a5550(s32 handnum)
sp274.y += player->guncloseroffset * 5.0f / -90.0f * 50.0f; sp274.y += player->guncloseroffset * 5.0f / -90.0f * 50.0f;
sp274.z -= player->guncloseroffset * 15.0f / -90.0f * 50.0f; sp274.z -= player->guncloseroffset * 15.0f / -90.0f * 50.0f;
#ifndef PLATFORM_N64
// adjust viewmodel position for different FOVs
sp274.y -= bgunGetFovOffsetY();
sp274.z += bgunGetFovOffsetZ();
#endif
if (hand->firing && shootfunc && g_Vars.lvupdate240 != 0 && shootfunc->recoilsettings != NULL) { if (hand->firing && shootfunc && g_Vars.lvupdate240 != 0 && shootfunc->recoilsettings != NULL) {
sp274.x += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->xrange * hand->finalmult[0]; sp274.x += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->xrange * hand->finalmult[0];
sp274.y += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->yrange * hand->finalmult[0]; sp274.y += (RANDOMFRAC() - 0.5f) * shootfunc->recoilsettings->yrange * hand->finalmult[0];
@@ -10869,6 +10983,7 @@ void bgunRender(Gfx **gdlptr)
struct modelrenderdata renderdata = {NULL, true, 3}; // 10c struct modelrenderdata renderdata = {NULL, true, 3}; // 10c
struct player *player; struct player *player;
s32 i; s32 i;
const u32 wnorm = mtx00016dcc(0, 300);
static bool renderhand = true; // var800702dc static bool renderhand = true; // var800702dc
@@ -10883,7 +10998,9 @@ void bgunRender(Gfx **gdlptr)
return; return;
} }
#ifdef PLATFORM_N64 // TODO
gdl = zbufDrawArtifactsOffscreen(gdl); gdl = zbufDrawArtifactsOffscreen(gdl);
#endif
gdl = viPrepareZbuf(gdl); gdl = viPrepareZbuf(gdl);
gdl = vi0000b1d0(gdl); gdl = vi0000b1d0(gdl);
@@ -10895,11 +11012,15 @@ void bgunRender(Gfx **gdlptr)
if (g_Vars.currentplayer->teleportstate != TELEPORTSTATE_INACTIVE) { if (g_Vars.currentplayer->teleportstate != TELEPORTSTATE_INACTIVE) {
f32 f2; f32 f2;
#ifdef PLATFORM_N64
if (optionsGetScreenRatio() == SCREENRATIO_16_9) { if (optionsGetScreenRatio() == SCREENRATIO_16_9) {
f2 = player0f0bd358() * 1.3333334f; f2 = player0f0bd358() * 1.3333334f;
} else { } else {
f2 = player0f0bd358(); f2 = player0f0bd358();
} }
#else
f2 = player0f0bd358();
#endif
gdl = vi0000b0e8(gdl, 60, f2); gdl = vi0000b0e8(gdl, 60, f2);
} }
@@ -10928,7 +11049,7 @@ void bgunRender(Gfx **gdlptr)
gSPLookAt(gdl++, camGetLookAt()); gSPLookAt(gdl++, camGetLookAt());
} }
gSPPerspNormalize(gdl++, mtx00016dcc(0, 300)); gSPPerspNormalize(gdl++, wnorm);
// There is support for guns having a TV screen on them // There is support for guns having a TV screen on them
// but no guns have this model part so it's not used. // but no guns have this model part so it's not used.
@@ -11103,7 +11224,17 @@ void bgunRender(Gfx **gdlptr)
} }
} }
#ifndef PLATFORM_N64
// put the casings into the same Z range as the gun
gSPPerspNormalize(gdl++, wnorm);
#endif
casingsRender(&gdl); casingsRender(&gdl);
#ifndef PLATFORM_N64
gSPPerspNormalize(gdl++, viGetPerspScale());
#endif
zbufSwap(); zbufSwap();
gdl = zbufConfigureRdp(gdl); gdl = zbufConfigureRdp(gdl);
@@ -11413,7 +11544,7 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
#endif #endif
} }
void bgunPlayGlassHitSound(struct coord *pos, s16 *rooms, s32 texturenum) void bgunPlayGlassHitSound(struct coord *pos, RoomNum *rooms, s32 texturenum)
{ {
if (g_Vars.lvupdate240 > 0) { if (g_Vars.lvupdate240 > 0) {
struct sndstate **handle = bgunAllocateAudioHandle(); struct sndstate **handle = bgunAllocateAudioHandle();
@@ -11428,7 +11559,7 @@ void bgunPlayGlassHitSound(struct coord *pos, s16 *rooms, s32 texturenum)
} }
} }
void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum, s16 *rooms) void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum, RoomNum *rooms)
{ {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
struct sndstate **handle; struct sndstate **handle;
@@ -11650,20 +11781,45 @@ void bgunSetTriggerOn(s32 handnum, bool on)
* - USETIMER_STOP if the B button timer should stop (ie. the B press is consumed) * - USETIMER_STOP if the B button timer should stop (ie. the B press is consumed)
* - USETIMER_REPEAT if this function should be called again on each frame until B is released. * - USETIMER_REPEAT if this function should be called again on each frame until B is released.
*/ */
s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromactivemenu) s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromactivemenu, bool fromdedicatedbutton)
{ {
#ifndef PLATFORM_N64
const bool extcontrols = PLAYER_EXTCFG().extcontrols || g_Vars.currentplayer->isremote;
bool docontinue;
#endif
switch (bgunGetWeaponNum(HAND_RIGHT)) { switch (bgunGetWeaponNum(HAND_RIGHT)) {
case WEAPON_SNIPERRIFLE: case WEAPON_SNIPERRIFLE:
if (extcontrols && usedowntime < 0) {
return USETIMER_CONTINUE;
}
// At 25 ticks (or B+Z), start showing the new function // At 25 ticks (or B+Z), start showing the new function
g_Vars.currentplayer->gunctrl.invertgunfunc = true; g_Vars.currentplayer->gunctrl.invertgunfunc = true;
// B+Z immediately triggers crouch or stand // B+Z immediately triggers crouch or stand
if (trigpressed) { if (trigpressed) {
if (extcontrols) {
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
}
return USETIMER_STOP; return USETIMER_STOP;
} }
if (fromdedicatedbutton) {
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
return USETIMER_CONTINUE;
}
#ifndef PLATFORM_N64
if (extcontrols) {
docontinue = (ABS(usedowntime) < 0);
} else {
// Don't do anything if B hasn't been held for 50/60ths of a second // Don't do anything if B hasn't been held for 50/60ths of a second
docontinue = (usedowntime < TICKS(50));
}
if (docontinue) {
#else
if (usedowntime < TICKS(50)) { if (usedowntime < TICKS(50)) {
#endif
return USETIMER_CONTINUE; return USETIMER_CONTINUE;
} }
@@ -11673,13 +11829,29 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
// Do crouch or stand // Do crouch or stand
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true; g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
return USETIMER_REPEAT; return (extcontrols ? USETIMER_STOP : USETIMER_REPEAT);
case WEAPON_RCP120: case WEAPON_RCP120:
#ifndef PLATFORM_N64
// very special alt-button handling for RCP-120's cloaking
if (!trigpressed && extcontrols && fromdedicatedbutton) {
if (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) {
g_Vars.currentplayer->devicesactive &= ~DEVICE_CLOAKRCP120;
} else {
g_Vars.currentplayer->devicesactive = (g_Vars.currentplayer->devicesactive & ~DEVICE_CLOAKRCP120) | DEVICE_CLOAKRCP120;
}
g_Vars.currentplayer->gunctrl.invertgunfunc = false;
return USETIMER_STOP;
}
#endif
case WEAPON_LAPTOPGUN: case WEAPON_LAPTOPGUN:
case WEAPON_DRAGON: case WEAPON_DRAGON:
case WEAPON_REMOTEMINE: case WEAPON_REMOTEMINE:
// These weapons use temporary alt functions // These weapons use temporary alt functions
if (extcontrols) {
g_Vars.currentplayer->gunctrl.invertgunfunc = !g_Vars.currentplayer->gunctrl.invertgunfunc;
} else {
g_Vars.currentplayer->gunctrl.invertgunfunc = true; g_Vars.currentplayer->gunctrl.invertgunfunc = true;
}
if (fromactivemenu && bgunIsUsingSecondaryFunction() == true) { if (fromactivemenu && bgunIsUsingSecondaryFunction() == true) {
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true; g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
@@ -11725,6 +11897,18 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
void bgun0f0a8c50(void) void bgun0f0a8c50(void)
{ {
#ifndef PLATFORM_N64
switch (bgunGetWeaponNum(HAND_RIGHT)) {
case WEAPON_RCP120:
case WEAPON_LAPTOPGUN:
case WEAPON_DRAGON:
case WEAPON_REMOTEMINE:
if (PLAYER_EXTCFG().extcontrols || g_Vars.currentplayer->isremote) {
return;
}
break;
}
#endif
if (g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary == false) { if (g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary == false) {
g_Vars.currentplayer->gunctrl.invertgunfunc = false; g_Vars.currentplayer->gunctrl.invertgunfunc = false;
} }
@@ -12622,7 +12806,7 @@ Gfx *bgunDrawHud(Gfx *gdl)
{ {
struct player *player = g_Vars.currentplayer; struct player *player = g_Vars.currentplayer;
s32 bottom = viGetViewTop() + viGetViewHeight() - 13; s32 bottom = viGetViewTop() + viGetViewHeight() - 13;
s32 playercount = PLAYERCOUNT(); s32 playercount = LOCALPLAYERCOUNT();
s32 playernum = g_Vars.currentplayernum; s32 playernum = g_Vars.currentplayernum;
struct gunctrl *ctrl; struct gunctrl *ctrl;
s32 secs60; s32 secs60;
@@ -12674,6 +12858,12 @@ Gfx *bgunDrawHud(Gfx *gdl)
gdl = text0f153628(gdl); gdl = text0f153628(gdl);
#ifndef PLATFORM_N64
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
}
#endif
if (playercount >= 2) { if (playercount >= 2) {
barwidth = 5; barwidth = 5;
reserveheight = 26; reserveheight = 26;
@@ -12894,6 +13084,9 @@ Gfx *bgunDrawHud(Gfx *gdl)
} }
if (ammoindex == -1) { if (ammoindex == -1) {
#ifndef PLATFORM_N64
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
#endif
gdl = text0f153780(gdl); gdl = text0f153780(gdl);
g_ScaleX = 1; g_ScaleX = 1;
return gdl; return gdl;
@@ -12919,6 +13112,12 @@ Gfx *bgunDrawHud(Gfx *gdl)
xpos -= 14; xpos -= 14;
} }
#ifndef PLATFORM_N64
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL);
}
#endif
if (lefthand->clipsizes[ammoindex] > 0 && (weapon->ammos[ammoindex]->flags & AMMOFLAG_EQUIPPEDISRESERVE) == 0) { if (lefthand->clipsizes[ammoindex] > 0 && (weapon->ammos[ammoindex]->flags & AMMOFLAG_EQUIPPEDISRESERVE) == 0) {
gdl = bgunDrawHudGauge(gdl, gdl = bgunDrawHudGauge(gdl,
xpos, bottom - reserveheight - clipheight - 3, xpos + barwidth, bottom - reserveheight - 3, xpos, bottom - reserveheight - clipheight - 3, xpos + barwidth, bottom - reserveheight - 3,
@@ -12953,6 +13152,12 @@ Gfx *bgunDrawHud(Gfx *gdl)
xpos += 15; xpos += 15;
} }
#ifndef PLATFORM_N64
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
}
#endif
// Mag // Mag
ammoheld = player->ammoheldarr[ammotype]; ammoheld = player->ammoheldarr[ammotype];
@@ -13006,6 +13211,10 @@ Gfx *bgunDrawHud(Gfx *gdl)
} }
} }
#ifndef PLATFORM_N64
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
#endif
gdl = text0f153780(gdl); gdl = text0f153780(gdl);
g_ScaleX = 1; g_ScaleX = 1;
+6 -3
View File
@@ -7,6 +7,9 @@
#include "lib/memp.h" #include "lib/memp.h"
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64
#include "game/player.h"
#endif
extern u32 g_BgunGunMemBaseSize4Mb2P; extern u32 g_BgunGunMemBaseSize4Mb2P;
@@ -239,9 +242,9 @@ void bgunReset(void)
g_Vars.currentplayer->gunammooff = 0; g_Vars.currentplayer->gunammooff = 0;
g_Vars.currentplayer->gunsightoff = GUNSIGHTREASON_NOTAIMING; g_Vars.currentplayer->gunsightoff = GUNSIGHTREASON_NOTAIMING;
g_Vars.currentplayer->gunzoomfovs[0] = 15; g_Vars.currentplayer->gunzoomfovs[0] = ADJUST_ZOOM_FOV(15);
g_Vars.currentplayer->gunzoomfovs[1] = 60; g_Vars.currentplayer->gunzoomfovs[1] = ADJUST_ZOOM_FOV(60);
g_Vars.currentplayer->gunzoomfovs[2] = 30; g_Vars.currentplayer->gunzoomfovs[2] = ADJUST_ZOOM_FOV(30);
if (stageGetIndex(g_Vars.stagenum) == STAGEINDEX_AIRBASE) { if (stageGetIndex(g_Vars.stagenum) == STAGEINDEX_AIRBASE) {
g_Weapons[WEAPON_EYESPY]->name = L_GUN_061; // "DrugSpy" g_Weapons[WEAPON_EYESPY]->name = L_GUN_061; // "DrugSpy"
+24 -26
View File
@@ -11,13 +11,11 @@
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
struct var80075c00 var80075c00[] = { struct headanim g_HeadAnims[] = {
{ ANIM_002B, 9.5, 27, 0, 0, 1.5 }, { ANIM_002B, 9.5, 27, 0, 0, 1.5 },
{ ANIM_0029, 7.5, 17, 0, 1.5, 100 }, { ANIM_0029, 7.5, 17, 0, 1.5, 100 },
}; };
struct coord var80075c30 = {0, 0, 0};
void bheadFlipAnimation(void) void bheadFlipAnimation(void)
{ {
g_Vars.currentplayer->model.anim->flip = !g_Vars.currentplayer->model.anim->flip; g_Vars.currentplayer->model.anim->flip = !g_Vars.currentplayer->model.anim->flip;
@@ -96,7 +94,7 @@ void bheadUpdateRot(struct coord *lookvel, struct coord *upvel)
g_Vars.currentplayer->headup.z = g_Vars.currentplayer->headupsum.z * (1.0f - g_Vars.currentplayer->headdamp); g_Vars.currentplayer->headup.z = g_Vars.currentplayer->headupsum.z * (1.0f - g_Vars.currentplayer->headdamp);
} }
void bheadSetdamp(f32 headdamp) void bheadSetDamp(f32 headdamp)
{ {
if (headdamp != g_Vars.currentplayer->headdamp) { if (headdamp != g_Vars.currentplayer->headdamp) {
f32 divisor = 1.0f - headdamp; f32 divisor = 1.0f - headdamp;
@@ -112,7 +110,7 @@ void bheadSetdamp(f32 headdamp)
void bheadUpdate(f32 arg0, f32 arg1) void bheadUpdate(f32 arg0, f32 arg1)
{ {
struct coord headpos = var80075c30; struct coord headpos = {0, 0, 0};
struct coord lookvel = {0, 0, 1}; struct coord lookvel = {0, 0, 1};
struct coord upvel = {0, 1, 0}; struct coord upvel = {0, 1, 0};
f32 animspeed = 0; f32 animspeed = 0;
@@ -120,7 +118,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
if (animHasFrames(g_Vars.currentplayer->model.anim->animnum)) { if (animHasFrames(g_Vars.currentplayer->model.anim->animnum)) {
animspeed = modelGetAbsAnimSpeed(&g_Vars.currentplayer->model); animspeed = modelGetAbsAnimSpeed(&g_Vars.currentplayer->model);
if (g_Vars.currentplayer->headanim == 0) { if (g_Vars.currentplayer->headanim == HEADANIM_RESTING) {
if (animspeed > 0.69999998807907f) { if (animspeed > 0.69999998807907f) {
g_Vars.currentplayer->headamplitude = 1; g_Vars.currentplayer->headamplitude = 1;
} else if (animspeed > 0.1f) { } else if (animspeed > 0.1f) {
@@ -131,7 +129,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
g_Vars.currentplayer->sideamplitude = g_Vars.currentplayer->headamplitude; g_Vars.currentplayer->sideamplitude = g_Vars.currentplayer->headamplitude;
} else { } else {
if (g_Vars.currentplayer->headanim == 1) { if (g_Vars.currentplayer->headanim == HEADANIM_MOVING) {
g_Vars.currentplayer->headamplitude = 0.89999997615814f; g_Vars.currentplayer->headamplitude = 0.89999997615814f;
g_Vars.currentplayer->sideamplitude = 0.5f; g_Vars.currentplayer->sideamplitude = 0.5f;
} else { } else {
@@ -197,9 +195,9 @@ void bheadUpdate(f32 arg0, f32 arg1)
g_Vars.currentplayer->headwalkingtime60 += g_Vars.lvupdate60; g_Vars.currentplayer->headwalkingtime60 += g_Vars.lvupdate60;
if (g_Vars.currentplayer->headwalkingtime60 > TICKS(60)) { if (g_Vars.currentplayer->headwalkingtime60 > TICKS(60)) {
bheadSetdamp(PAL ? 0.9785f : 0.982f); bheadSetDamp(PAL ? 0.9785f : 0.982f);
} else { } else {
bheadSetdamp(PAL ? 0.99699f : 0.99748998880386f); bheadSetDamp(PAL ? 0.99699f : 0.99748998880386f);
} }
} else { } else {
lookvel.x = g_Vars.currentplayer->bondheadmatrices[0].m[2][0]; lookvel.x = g_Vars.currentplayer->bondheadmatrices[0].m[2][0];
@@ -210,7 +208,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
upvel.y = g_Vars.currentplayer->bondheadmatrices[0].m[1][1]; upvel.y = g_Vars.currentplayer->bondheadmatrices[0].m[1][1];
upvel.z = g_Vars.currentplayer->bondheadmatrices[0].m[1][2]; upvel.z = g_Vars.currentplayer->bondheadmatrices[0].m[1][2];
bheadSetdamp(PAL ? 0.952f : 0.96f); bheadSetDamp(PAL ? 0.952f : 0.96f);
} }
} else { } else {
g_Vars.currentplayer->headbodyoffset.x = g_Vars.currentplayer->standbodyoffset.x; g_Vars.currentplayer->headbodyoffset.x = g_Vars.currentplayer->standbodyoffset.x;
@@ -222,7 +220,7 @@ void bheadUpdate(f32 arg0, f32 arg1)
headpos.z = 0; headpos.z = 0;
g_Vars.currentplayer->headwalkingtime60 = 0; g_Vars.currentplayer->headwalkingtime60 = 0;
bheadSetdamp(PAL ? 0.99699f : 0.99748998880386f); bheadSetDamp(PAL ? 0.99699f : 0.99748998880386f);
if (bmoveGetCrouchPos() != CROUCHPOS_SQUAT) { if (bmoveGetCrouchPos() != CROUCHPOS_SQUAT) {
g_Vars.currentplayer->standfrac += g_Vars.currentplayer->standfrac +=
@@ -261,31 +259,31 @@ void bheadAdjustAnimation(f32 speed)
struct chrdata *chr = g_Vars.currentplayer->prop->chr; struct chrdata *chr = g_Vars.currentplayer->prop->chr;
s32 i; s32 i;
speed *= var80075c00[1].unk0c; speed *= g_HeadAnims[HEADANIM_MOVING].translateperframe;
for (i = 0; i < 2; i++) { for (i = 0; i < ARRAYCOUNT(g_HeadAnims); i++) {
if (var80075c00[i].unk14 * var80075c00[i].unk0c >= speed) { if (g_HeadAnims[i].maxspeed * g_HeadAnims[i].translateperframe >= speed) {
s32 headanim = g_Vars.currentplayer->headanim; s32 prevheadanim = g_Vars.currentplayer->headanim;
if (i != headanim) { if (i != prevheadanim) {
f32 startframe = 0.0f; f32 startframe = 0.0f;
if (headanim >= 0) { if (prevheadanim >= 0) {
startframe = (g_Vars.currentplayer->model.anim->frame - var80075c00[headanim].loopframe) startframe = (g_Vars.currentplayer->model.anim->frame - g_HeadAnims[prevheadanim].loopframe)
/ (var80075c00[headanim].endframe - var80075c00[headanim].loopframe); / (g_HeadAnims[prevheadanim].endframe - g_HeadAnims[prevheadanim].loopframe);
startframe = var80075c00[i].loopframe + (var80075c00[i].endframe - var80075c00[i].loopframe) * startframe; startframe = g_HeadAnims[i].loopframe + (g_HeadAnims[i].endframe - g_HeadAnims[i].loopframe) * startframe;
} }
modelSetAnimation(&g_Vars.currentplayer->model, var80075c00[i].animnum, modelSetAnimation(&g_Vars.currentplayer->model, g_HeadAnims[i].animnum,
g_Vars.currentplayer->model.anim->flip, startframe, 0.5f, 12); g_Vars.currentplayer->model.anim->flip, startframe, 0.5f, 12);
modelSetAnimLooping(&g_Vars.currentplayer->model, var80075c00[i].loopframe, false); modelSetAnimLooping(&g_Vars.currentplayer->model, g_HeadAnims[i].loopframe, false);
modelSetAnimEndFrame(&g_Vars.currentplayer->model, var80075c00[i].endframe); modelSetAnimEndFrame(&g_Vars.currentplayer->model, g_HeadAnims[i].endframe);
modelSetAnimFlipFunction(&g_Vars.currentplayer->model, bheadFlipAnimation); modelSetAnimFlipFunction(&g_Vars.currentplayer->model, bheadFlipAnimation);
g_Vars.currentplayer->headanim = i; g_Vars.currentplayer->headanim = i;
} }
speed = speed / var80075c00[i].unk0c; speed = speed / g_HeadAnims[i].translateperframe;
modelSetAnimSpeed(&g_Vars.currentplayer->model, speed * 0.5f, 0); modelSetAnimSpeed(&g_Vars.currentplayer->model, speed * 0.5f, 0);
break; break;
@@ -309,11 +307,11 @@ void bheadSetSpeed(f32 speed)
f32 bheadGetBreathingValue(void) f32 bheadGetBreathingValue(void)
{ {
if (g_Vars.currentplayer->headanim >= 0) { if (g_Vars.currentplayer->headanim >= 0) {
f32 a = g_Vars.currentplayer->bondbreathing * 0.012500001f + 0.004166667f; f32 a = g_Vars.currentplayer->bondbreathing * 0.012500001f + (1.0f / 240.0f);
f32 b = modelGetAbsAnimSpeed(&g_Vars.currentplayer->model); f32 b = modelGetAbsAnimSpeed(&g_Vars.currentplayer->model);
if (b > 0) { if (b > 0) {
f32 c = b / (var80075c00[g_Vars.currentplayer->headanim].endframe - var80075c00[g_Vars.currentplayer->headanim].loopframe); f32 c = b / (g_HeadAnims[g_Vars.currentplayer->headanim].endframe - g_HeadAnims[g_Vars.currentplayer->headanim].loopframe);
if (c < a) { if (c < a) {
c = a; c = a;
+8 -12
View File
@@ -39,7 +39,7 @@ void bheadReset(void)
modelSetScale(&g_Vars.currentplayer->model, 0.1000000089407f); modelSetScale(&g_Vars.currentplayer->model, 0.1000000089407f);
modelSetAnimPlaySpeed(&g_Vars.currentplayer->model, (PAL ? 1.2f : 1), 0); modelSetAnimPlaySpeed(&g_Vars.currentplayer->model, (PAL ? 1.2f : 1), 0);
g_Vars.currentplayer->headanim = 0; g_Vars.currentplayer->headanim = HEADANIM_RESTING;
g_Vars.currentplayer->headdamp = (PAL ? 0.9166f : 0.93f); g_Vars.currentplayer->headdamp = (PAL ? 0.9166f : 0.93f);
g_Vars.currentplayer->headwalkingtime60 = 0; g_Vars.currentplayer->headwalkingtime60 = 0;
g_Vars.currentplayer->headamplitude = 1; g_Vars.currentplayer->headamplitude = 1;
@@ -87,10 +87,10 @@ void bheadReset(void)
g_Vars.currentplayer->standup[1].z = 0; g_Vars.currentplayer->standup[1].z = 0;
g_Vars.currentplayer->standcnt = 0; g_Vars.currentplayer->standcnt = 0;
for (i = 0; i < 2; i++) { for (i = 0; i < ARRAYCOUNT(g_HeadAnims); i++) {
s32 translate[3]; s32 translate[3];
func0f0125a0(var80075c00[i].animnum, var80075c00[i].loopframe, var80075c00[i].endframe, translate); func0f0125a0(g_HeadAnims[i].animnum, g_HeadAnims[i].loopframe, g_HeadAnims[i].endframe, translate);
var80075c00[i].unk0c = (translate[2] * 0.1000000089407f) / (var80075c00[i].endframe - var80075c00[i].loopframe); g_HeadAnims[i].translateperframe = (translate[2] * 0.1000000089407f) / (g_HeadAnims[i].endframe - g_HeadAnims[i].loopframe);
} }
{ {
@@ -112,17 +112,13 @@ void bheadReset(void)
g_Vars.currentplayer->standbodyoffset.z = g_Vars.currentplayer->bondheadmatrices[1].m[3][2] - g_Vars.currentplayer->bondheadmatrices[0].m[3][2]; g_Vars.currentplayer->standbodyoffset.z = g_Vars.currentplayer->bondheadmatrices[1].m[3][2] - g_Vars.currentplayer->bondheadmatrices[0].m[3][2];
modelSetAnimation(&g_Vars.currentplayer->model, modelSetAnimation(&g_Vars.currentplayer->model,
var80075c00[g_Vars.currentplayer->headanim].animnum, g_HeadAnims[g_Vars.currentplayer->headanim].animnum,
0, 0,
var80075c00[g_Vars.currentplayer->headanim].loopframe, g_HeadAnims[g_Vars.currentplayer->headanim].loopframe,
0.5f, 0); 0.5f, 0);
modelSetAnimLooping(&g_Vars.currentplayer->model, modelSetAnimLooping(&g_Vars.currentplayer->model, g_HeadAnims[g_Vars.currentplayer->headanim].loopframe, 0);
var80075c00[g_Vars.currentplayer->headanim].loopframe, 0); modelSetAnimEndFrame(&g_Vars.currentplayer->model, g_HeadAnims[g_Vars.currentplayer->headanim].endframe);
modelSetAnimEndFrame(&g_Vars.currentplayer->model,
var80075c00[g_Vars.currentplayer->headanim].endframe);
modelSetAnimFlipFunction(&g_Vars.currentplayer->model, bheadFlipAnimation); modelSetAnimFlipFunction(&g_Vars.currentplayer->model, bheadFlipAnimation);
bheadUpdateIdleRoll(); bheadUpdateIdleRoll();
+679 -75
View File
File diff suppressed because it is too large. Load diff
+295 -37
View File
@@ -20,6 +20,10 @@
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#include "gbiex.h" #include "gbiex.h"
#ifndef PLATFORM_N64
#include "game/player.h"
#include "video.h"
#endif
#ifdef AVOID_UB #ifdef AVOID_UB
char var800a41c0[26]; char var800a41c0[26];
@@ -97,6 +101,7 @@ Gfx *bview0f141a20(Gfx *gdl, s32 top, s32 height, s32 left, s32 width)
Gfx *bviewCopyPixels(Gfx *gdl, u16 *fb, s32 top, u32 tile, s32 arg4, f32 arg5, s32 left, s32 width) Gfx *bviewCopyPixels(Gfx *gdl, u16 *fb, s32 top, u32 tile, s32 arg4, f32 arg5, s32 left, s32 width)
{ {
#ifdef PLATFORM_N64
uintptr_t image; uintptr_t image;
s32 width2; s32 width2;
s32 numparts; s32 numparts;
@@ -161,6 +166,10 @@ Gfx *bviewCopyPixels(Gfx *gdl, u16 *fb, s32 top, u32 tile, s32 arg4, f32 arg5, s
} }
return gdl; return gdl;
#else // PLATFORM_N64
// TODO: add an extended GBI opcode for this
return gdl;
#endif // PLATFORM_N64
} }
Gfx *bviewDrawFisheyeRect(Gfx *gdl, s32 arg1, f32 arg2, s32 arg3, s32 arg4) Gfx *bviewDrawFisheyeRect(Gfx *gdl, s32 arg1, f32 arg2, s32 arg3, s32 arg4)
@@ -206,7 +215,7 @@ Gfx *bviewPrepareStaticRgba16(Gfx *gdl, u32 colour, u32 alpha)
gDPSetTexturePersp(gdl++, G_TP_NONE); gDPSetTexturePersp(gdl++, G_TP_NONE);
gDPSetColorDither(gdl++, G_CD_DISABLE); gDPSetColorDither(gdl++, G_CD_DISABLE);
gDPSetAlphaDither(gdl++, G_AD_NOISE); gDPSetAlphaDither(gdl++, G_AD_NOISE);
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2); gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
return gdl; return gdl;
} }
@@ -240,7 +249,7 @@ Gfx *bviewPrepareStaticI8(Gfx *gdl, u32 colour, u32 alpha)
gDPSetTexturePersp(gdl++, G_TP_NONE); gDPSetTexturePersp(gdl++, G_TP_NONE);
gDPSetColorDither(gdl++, G_CD_DISABLE); gDPSetColorDither(gdl++, G_CD_DISABLE);
gDPSetAlphaDither(gdl++, G_AD_NOISE); gDPSetAlphaDither(gdl++, G_AD_NOISE);
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2); gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
return gdl; return gdl;
} }
@@ -276,6 +285,20 @@ Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
var8007f844 = 0; var8007f844 = 0;
#ifndef PLATFORM_N64
if (!videoFramebuffersSupported()) {
return gdl;
}
// capture fb at the end of this frame
g_BlurFbCapTimer = 0;
// don't render first blur frame as we haven't captured the fb yet
if (g_BlurFbDirty) {
return gdl;
}
#endif
mainOverrideVariable("sfxxx", &sfxxx); mainOverrideVariable("sfxxx", &sfxxx);
fxxx = sfxxx / 1000.0f; fxxx = sfxxx / 1000.0f;
mainOverrideVariable("sfyyy", &sfyyy); mainOverrideVariable("sfyyy", &sfyyy);
@@ -286,10 +309,18 @@ Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
somefloat = (viewheight - viewheight / fyyy) * 0.5f; somefloat = (viewheight - viewheight / fyyy) * 0.5f;
gdl = bviewPrepareStaticRgba16(gdl, colour, newalpha); gdl = bviewPrepareStaticRgba16(gdl, colour, newalpha);
#ifdef PLATFORM_N64
for (i = viewtop; i < viewtop + viewheight; i++) { for (i = viewtop; i < viewtop + viewheight; i++) {
gdl = bviewCopyPixels(gdl, fb, viewtop + (s32)somefloat, 5, i, fxxx, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, viewtop + (s32)somefloat, 5, i, fxxx, viewleft, viewwidth);
somefloat += 1.0f / fyyy; somefloat += 1.0f / fyyy;
} }
#else
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_BlurFb);
gSPImageRectangleEXT(gdl++,
viewleft << 2, viewtop << 2, viewleft, viewtop,
(viewleft + viewwidth) << 2, (viewtop + viewheight) << 2, viewleft + viewwidth, viewtop + viewheight,
0, videoGetNativeWidth(), videoGetNativeHeight());
#endif
return gdl; return gdl;
} }
@@ -311,9 +342,16 @@ Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
gdl = bviewPrepareStaticI8(gdl, arg1, arg2); gdl = bviewPrepareStaticI8(gdl, arg1, arg2);
#ifdef PLATFORM_N64
for (y = viewtop; y < viewtop + viewheight; y++) { for (y = viewtop; y < viewtop + viewheight; y++) {
gdl = bviewCopyPixels(gdl, fb2, random() % 240, 5, y, 1.0f, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb2, random() % 240, 5, y, 1.0f, viewleft, viewwidth);
} }
#else
gDPSetCombineLERP(gdl++,
NOISE, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT,
NOISE, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT);
gDPFillRectangleEXT(gdl++, viewleft, viewtop, viewleft + viewwidth, viewtop + viewheight);
#endif
if (fb2) { if (fb2) {
// empty // empty
@@ -351,6 +389,7 @@ Gfx *bviewDrawSlayerRocketInterlace(Gfx *gdl, u32 colour, u32 alpha)
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha); gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
#ifdef PLATFORM_N64
for (y = viewtop; y < viewtop + viewheight; y++) { for (y = viewtop; y < viewtop + viewheight; y++) {
s32 offsety = y - offset; s32 offsety = y - offset;
@@ -366,6 +405,26 @@ Gfx *bviewDrawSlayerRocketInterlace(Gfx *gdl, u32 colour, u32 alpha)
angle += increment; angle += increment;
} }
#else
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
for (y = viewtop; y < viewtop + viewheight; y++) {
s32 offsety = y - offset;
if (offsety % 8 == 0 || y == viewtop) {
if (offsety % 16 < 8) {
gDPSetPrimColor(gdl++, 0, 0, 0xff, 0xff, 0x00, 0xff);
} else {
gDPSetPrimColor(gdl++, 0, 0, 0xff, 0xff, 0xbf, 0xff);
}
}
gDPFillRectangle(gdl++, viewleft, y, viewleft + viewwidth, y + 1);
}
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
#endif
return gdl; return gdl;
} }
@@ -396,6 +455,7 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha); gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
#ifdef PLATFORM_N64
for (y = viewtop; y < viewtop + viewheight; y++) { for (y = viewtop; y < viewtop + viewheight; y++) {
s32 offsety = y - offset; s32 offsety = y - offset;
s32 tmpy = y; s32 tmpy = y;
@@ -414,6 +474,31 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth);
} }
#else
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
for (y = viewtop; y < viewtop + viewheight; y++) {
s32 offsety = y - offset;
s32 tmpy = y;
if (offsety % 6 == 0 || y == viewtop) {
if (offsety % 12 < 6) {
gDPSetPrimColor(gdl++, 0, 0, 0x7f, 0xff, 0xff, 0xff);
} else {
gDPSetPrimColor(gdl++, 0, 0, 0x00, 0xaf, 0xff, 0xff);
}
}
if (random() % 20 == 1) {
tmpy += random() % 200;
}
gDPFillRectangle(gdl++, viewleft, tmpy, viewleft + viewwidth, tmpy + 1);
}
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
#endif
return gdl; return gdl;
} }
@@ -439,6 +524,20 @@ Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
return gdl; return gdl;
} }
#ifndef PLATFORM_N64
if (!videoFramebuffersSupported()) {
return gdl;
}
// capture fb at the end of this frame
g_BlurFbCapTimer = 0;
// don't render first blur frame as we haven't captured the fb yet
if (g_BlurFbDirty) {
return gdl;
}
#endif
strcpy(var800a41c0, "stretchBlurGfx"); strcpy(var800a41c0, "stretchBlurGfx");
gDPPipeSync(gdl++); gDPPipeSync(gdl++);
@@ -447,10 +546,26 @@ Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha); gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
#ifdef PLATFORM_N64
for (i = viewtop; i < viewtop + viewheight; i++) { for (i = viewtop; i < viewtop + viewheight; i++) {
gdl = bviewCopyPixels(gdl, fb, (s32)somefloat + viewtop, 5, i, arg3, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, (s32)somefloat + viewtop, 5, i, arg3, viewleft, viewwidth);
somefloat += 1.0f / arg4; somefloat += 1.0f / arg4;
} }
#else
const f32 xcenter = viewleft + viewwidth * 0.5f;
const f32 ycenter = viewtop + viewheight * 0.5f;
const f32 halfw = viewwidth * 0.5f * arg3;
const f32 halfh = viewheight * 0.5f * arg4;
const s32 left = xcenter - halfw;
const s32 top = ycenter - halfh;
const s32 right = xcenter + halfw;
const s32 bottom = ycenter + halfh;
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_BlurFb);
gSPImageRectangleEXT(gdl++,
left << 2, top << 2, viewleft, viewtop,
right << 2, bottom << 2, viewleft + viewwidth, viewtop + viewheight,
0, videoGetNativeWidth(), videoGetNativeHeight());
#endif
return gdl; return gdl;
} }
@@ -475,6 +590,30 @@ f32 bview0f142d74(s32 arg0, f32 arg1, f32 arg2, f32 arg3)
return result; return result;
} }
#ifndef PLATFORM_N64
static inline Gfx *bviewDrawFisheyeLine(Gfx *gdl, s32 viewleft, s32 viewwidth, s32 y, f32 scale)
{
if (!videoFramebuffersSupported()) {
return gdl;
}
const f32 orighalfw = viewwidth * 0.5f;
const f32 xcenter = viewleft + orighalfw;
const f32 halfw = orighalfw * scale;
const s32 left = xcenter - halfw;
const s32 right = xcenter + halfw;
gSPImageRectangleEXT(gdl++,
left << 2, y << 2, viewleft, y,
right << 2, (y + 1) << 2, viewleft + viewwidth, y + 1,
0, videoGetNativeWidth(), videoGetNativeHeight());
return gdl;
}
#endif
/** /**
* Draw the fisheye curved effect when using an eyespy. * Draw the fisheye curved effect when using an eyespy.
* *
@@ -589,6 +728,13 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
gdl = bviewPrepareStaticRgba16(gdl, colour, alpha); gdl = bviewPrepareStaticRgba16(gdl, colour, alpha);
#ifndef PLATFORM_N64
// make a copy of the current back buffer contents that we will be using as a texture
gDPFlushEXT(gdl++);
gDPCopyFramebufferEXT(gdl++, g_PrevFrameFb, 0, 0, 0, G_ON);
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_PrevFrameFb);
#endif
if (starting) { if (starting) {
for (i = viewtop; i < viewtop + viewheight; i++) { for (i = viewtop; i < viewtop + viewheight; i++) {
if (i % 2) { if (i % 2) {
@@ -596,7 +742,11 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
gDPSetEnvColorViaWord(gdl++, (colour & 0xffffff00) | (spec & 0xff)); gDPSetEnvColorViaWord(gdl++, (colour & 0xffffff00) | (spec & 0xff));
tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * startupfrac; tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * startupfrac;
#ifdef PLATFORM_N64
gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth);
#else
gdl = bviewDrawFisheyeLine(gdl, viewleft, viewwidth, i, tmp);
#endif
} }
} }
@@ -622,13 +772,21 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
} }
tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * f22; tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * f22;
#ifdef PLATFORM_N64
gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth);
#else
gdl = bviewDrawFisheyeLine(gdl, viewleft, viewwidth, i, tmp);
#endif
if (hit == EYESPYHIT_DAMAGE) { if (hit == EYESPYHIT_DAMAGE) {
gDPSetEnvColorViaWord(gdl++, 0xddaaaa99); gDPSetEnvColorViaWord(gdl++, 0xddaaaa99);
tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * 1.03f; tmp = bview0f142d74(s2, f26, halfheight, sqhalfheight) * 1.03f;
#ifdef PLATFORM_N64
gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, i, 5, i, tmp, viewleft, viewwidth);
#else
gdl = bviewDrawFisheyeLine(gdl, viewleft, viewwidth, i, tmp);
#endif
} }
s2 += s3; s2 += s3;
@@ -765,8 +923,8 @@ Gfx *bviewDrawEyespySideRect(Gfx *gdl, s32 *points, u8 r, u8 g, u8 b, u8 alpha)
vertices[3].y = points[7] * 10.0f; vertices[3].y = points[7] * 10.0f;
vertices[3].z = -10; vertices[3].z = -10;
colours[0].word = r << 0x18 | g << 0x10 | b << 8 | 0xff; colours[0].word = PD_BE32(r << 0x18 | g << 0x10 | b << 8 | 0xff);
colours[1].word = r << 0x18 | g << 0x10 | b << 8 | alpha; colours[1].word = PD_BE32(r << 0x18 | g << 0x10 | b << 8 | alpha);
vertices[0].colour = 0; vertices[0].colour = 0;
vertices[1].colour = 0; vertices[1].colour = 0;
@@ -844,6 +1002,7 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
bool vsplit = false; bool vsplit = false;
#endif #endif
u32 umask, dmask, lmask, rmask;
#if VERSION >= VERSION_PAL_FINAL #if VERSION >= VERSION_PAL_FINAL
#if PAL #if PAL
@@ -874,6 +1033,18 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} }
#endif #endif
if (optionsGetControlMode(g_Vars.currentplayerstats->mpindex) == CONTROLMODE_PC) {
umask = U_CBUTTONS;
dmask = D_CBUTTONS;
lmask = L_CBUTTONS;
rmask = R_CBUTTONS;
} else {
umask = U_JPAD | U_CBUTTONS;
dmask = D_JPAD | D_CBUTTONS;
lmask = L_JPAD | L_CBUTTONS;
rmask = R_JPAD | R_CBUTTONS;
}
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
movex = chr->prop->pos.x - chr->prevpos.x; movex = chr->prop->pos.x - chr->prevpos.x;
movey = chr->prop->pos.y - chr->prevpos.y; movey = chr->prop->pos.y - chr->prevpos.y;
@@ -1225,8 +1396,8 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
{ {
s8 contpadnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex); s8 contpadnum = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
u16 buttonsdown = joyGetButtons(contpadnum, 0xffff); \ u32 buttonsdown = joyGetButtons(contpadnum, 0xffffffff); \
u16 buttonsthisframe = joyGetButtonsPressedThisFrame(contpadnum, 0xffff); u32 buttonsthisframe = joyGetButtonsPressedThisFrame(contpadnum, 0xffffffff);
s8 cstickx = joyGetStickX(contpadnum); \ s8 cstickx = joyGetStickX(contpadnum); \
s8 csticky = joyGetStickY(contpadnum); s8 csticky = joyGetStickY(contpadnum);
s32 xpos; s32 xpos;
@@ -1259,32 +1430,32 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
// Up // Up
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
brightness = 20; \ brightness = 20; \
if (buttonsdown & (U_JPAD | U_CBUTTONS)) { \ if (buttonsdown & umask) { \
brightness += 20; \ brightness += 20; \
} \ } \
if (buttonsthisframe & (U_JPAD | U_CBUTTONS)) { \ if (buttonsthisframe & umask) { \
brightness += 20; \ brightness += 20; \
} \ } \
gDPSetPrimColor(gdl++, 0, 0, 0, brightness, 0, 0xff); \ gDPSetPrimColor(gdl++, 0, 0, 0, brightness, 0, 0xff); \
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) { } else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
brightness = 127; brightness = 127;
if (buttonsdown & (U_JPAD | U_CBUTTONS)) { if (buttonsdown & umask) {
brightness += 63; brightness += 63;
} }
if (buttonsthisframe & (U_JPAD | U_CBUTTONS)) { if (buttonsthisframe & umask) {
brightness += 63; \ brightness += 63; \
} \ } \
gDPSetPrimColor(gdl++, 0, 0, 0x10, 0x20, brightness, 0xff); gDPSetPrimColor(gdl++, 0, 0, 0x10, 0x20, brightness, 0xff);
} else { } else {
brightness = 20; brightness = 20;
if (buttonsdown & (U_JPAD | U_CBUTTONS)) { if (buttonsdown & umask) {
brightness += 20; brightness += 20;
} }
if (buttonsthisframe & (U_JPAD | U_CBUTTONS)) { if (buttonsthisframe & umask) {
brightness += 20; \ brightness += 20; \
} \ } \
gDPSetPrimColor(gdl++, 0, 0, brightness, brightness >> 2, 0, 0xff); gDPSetPrimColor(gdl++, 0, 0, brightness, brightness >> 2, 0, 0xff);
@@ -1297,10 +1468,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
brightness = 20; brightness = 20;
if (buttonsdown & (D_JPAD | D_CBUTTONS)) { \ if (buttonsdown & dmask) { \
brightness += 20; \ brightness += 20; \
} \ } \
if (buttonsthisframe & (D_JPAD | D_CBUTTONS)) { if (buttonsthisframe & dmask) {
brightness += 20; brightness += 20;
} }
@@ -1308,11 +1479,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) { } else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
brightness = 127; brightness = 127;
if (buttonsdown & (D_JPAD | D_CBUTTONS)) { if (buttonsdown & dmask) {
brightness += 63; brightness += 63;
} }
if (buttonsthisframe & (D_JPAD | D_CBUTTONS)) { if (buttonsthisframe & dmask) {
brightness += 63; brightness += 63;
} }
@@ -1320,11 +1491,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else { } else {
brightness = 20; brightness = 20;
if (buttonsdown & (D_JPAD | D_CBUTTONS)) { if (buttonsdown & dmask) {
brightness += 20; brightness += 20;
} }
if (buttonsthisframe & (D_JPAD | D_CBUTTONS)) { if (buttonsthisframe & dmask) {
brightness += 20; brightness += 20;
} }
@@ -1338,10 +1509,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
brightness = 20; brightness = 20;
if (buttonsdown & (L_JPAD | L_CBUTTONS)) { \ if (buttonsdown & lmask) { \
brightness += 20; \ brightness += 20; \
} \ } \
if (buttonsthisframe & (L_JPAD | L_CBUTTONS)) { if (buttonsthisframe & lmask) {
brightness += 20; brightness += 20;
} }
@@ -1349,11 +1520,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) { } else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
brightness = 127; brightness = 127;
if (buttonsdown & (L_JPAD | L_CBUTTONS)) { if (buttonsdown & lmask) {
brightness += 63; brightness += 63;
} }
if (buttonsthisframe & (L_JPAD | L_CBUTTONS)) { if (buttonsthisframe & lmask) {
brightness += 63; brightness += 63;
} }
@@ -1361,11 +1532,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else { } else {
brightness = 20; brightness = 20;
if (buttonsdown & (L_JPAD | L_CBUTTONS)) { if (buttonsdown & lmask) {
brightness += 20; brightness += 20;
} }
if (buttonsthisframe & (L_JPAD | L_CBUTTONS)) { if (buttonsthisframe & lmask) {
brightness += 20; brightness += 20;
} }
@@ -1379,10 +1550,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
brightness = 20; brightness = 20;
if (buttonsdown & (R_JPAD | R_CBUTTONS)) { \ if (buttonsdown & rmask) { \
brightness += 20; \ brightness += 20; \
} \ } \
if (buttonsthisframe & (R_JPAD | R_CBUTTONS)) { if (buttonsthisframe & rmask) {
brightness += 20; brightness += 20;
} }
@@ -1390,11 +1561,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) { } else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
brightness = 127; brightness = 127;
if (buttonsdown & (R_JPAD | R_CBUTTONS)) { if (buttonsdown & rmask) {
brightness += 63; brightness += 63;
} }
if (buttonsthisframe & (R_JPAD | R_CBUTTONS)) { if (buttonsthisframe & rmask) {
brightness += 63; brightness += 63;
} }
@@ -1402,11 +1573,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else { } else {
brightness = 20; brightness = 20;
if (buttonsdown & (R_JPAD | R_CBUTTONS)) { if (buttonsdown & rmask) {
brightness += 20; brightness += 20;
} }
if (buttonsthisframe & (R_JPAD | R_CBUTTONS)) { if (buttonsthisframe & rmask) {
brightness += 20; brightness += 20;
} }
@@ -1420,10 +1591,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
brightness = 20; brightness = 20;
if (buttonsdown & (L_TRIG | R_TRIG)) { \ if (buttonsdown & (R_TRIG)) { \
brightness += 20; \ brightness += 20; \
} \ } \
if (buttonsthisframe & (L_TRIG | R_TRIG)) { if (buttonsthisframe & (R_TRIG)) {
brightness += 20; brightness += 20;
} }
@@ -1431,11 +1602,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) { } else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
brightness = 127; brightness = 127;
if (buttonsdown & (L_TRIG | R_TRIG)) { if (buttonsdown & (R_TRIG)) {
brightness += 63; brightness += 63;
} }
if (buttonsthisframe & (L_TRIG | R_TRIG)) { if (buttonsthisframe & (R_TRIG)) {
brightness += 63; brightness += 63;
} }
@@ -1443,11 +1614,11 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
} else { } else {
brightness = 20; brightness = 20;
if (buttonsdown & (L_TRIG | R_TRIG)) { if (buttonsdown & (R_TRIG)) {
brightness += 20; brightness += 20;
} }
if (buttonsthisframe & (L_TRIG | R_TRIG)) { if (buttonsthisframe & (R_TRIG)) {
brightness += 20; brightness += 20;
} }
@@ -1947,6 +2118,9 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
s32 viewbottom = viewtop + viewheight; s32 viewbottom = viewtop + viewheight;
s32 brightness; s32 brightness;
s32 y; s32 y;
#ifdef AVOID_UB
u32 mpindex = g_Vars.currentplayerstats->mpindex % MAX_PLAYERS;
#endif
var8007f840++; var8007f840++;
@@ -1968,9 +2142,15 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
skySetOverexposure(brightness, brightness, brightness); skySetOverexposure(brightness, brightness, brightness);
} }
#ifdef AVOID_UB
if (g_Menus[mpindex].curdialog == NULL) {
gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60);
}
#else
if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) { if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) {
gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60); gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60);
} }
#endif
gDPPipeSync(gdl++); gDPPipeSync(gdl++);
@@ -1978,6 +2158,7 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
var8007f878++; var8007f878++;
#ifdef PLATFORM_N64
for (y = viewtop; y < viewbottom; y++) { for (y = viewtop; y < viewbottom; y++) {
u8 green; u8 green;
@@ -1992,6 +2173,27 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
gdl = bviewCopyPixels(gdl, fb, y, 5, y, 1, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, y, 5, y, 1, viewleft, viewwidth);
} }
#else
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
for (y = viewtop; y < viewbottom; y++) {
u8 green;
if (((var8007f878 & 1) != (y & 1)) != 0) {
u8 tmp = random() % 12;
green = 0xff - tmp;
} else {
green = 0x94;
}
gDPSetPrimColorViaWord(gdl++, 0, 0, (green << 16) + 0xff);
gDPFillRectangle(gdl++, viewleft, y, viewleft + viewwidth, y + 1);
}
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
#endif
return gdl; return gdl;
} }
@@ -2029,6 +2231,9 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
s32 viewcentrey; s32 viewcentrey;
f32 viewheightf; f32 viewheightf;
s32 a0; s32 a0;
#ifdef AVOID_UB
u32 mpindex = g_Vars.currentplayerstats->mpindex % MAX_PLAYERS;
#endif
#if VERSION < VERSION_NTSC_1_0 #if VERSION < VERSION_NTSC_1_0
static s32 fsscanline = 0; static s32 fsscanline = 0;
@@ -2138,6 +2343,11 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
sqinnerradius = innerradius * innerradius; sqinnerradius = innerradius * innerradius;
#ifndef PLATFORM_N64
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
#endif
for (i = scantop; i < scanbottom; i++) { for (i = scantop; i < scanbottom; i++) {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (i & 1) { if (i & 1) {
@@ -2159,7 +2369,11 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
red = 255; red = 255;
} }
#ifdef PLATFORM_N64
gDPSetEnvColorViaWord(gdl++, (red << 24) + 0xff); gDPSetEnvColorViaWord(gdl++, (red << 24) + 0xff);
#else
gDPSetPrimColorViaWord(gdl++, 0, 0, (red << 24) + 0xff);
#endif
a0 = viewcentrey - i; a0 = viewcentrey - i;
@@ -2171,6 +2385,7 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
s32 semicircleright = viewcentrex + semicirclewidth; s32 semicircleright = viewcentrex + semicirclewidth;
s32 rightsidewidth = viewwidth - semicircleright; s32 rightsidewidth = viewwidth - semicircleright;
#ifdef PLATFORM_N64
// Left and right of semicircle // Left and right of semicircle
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewcentrex); gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewcentrex);
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, semicircleright, rightsidewidth); gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, semicircleright, rightsidewidth);
@@ -2181,6 +2396,18 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
} else { } else {
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth);
} }
#else
// Left and right of semicircle
gDPFillRectangle(gdl++, viewleft, i, viewcentrex, i + 1);
gDPFillRectangle(gdl++, semicircleright, i, semicircleright + rightsidewidth, i + 1);
// The semicircle itself has a static colour
gDPSetPrimColorViaWord(gdl++, 0, 0, 0xee0000ff);
gDPFillRectangle(gdl++, viewcentrex, i, viewcentrex + semicirclewidth, i + 1);
} else {
gDPFillRectangle(gdl++, viewleft, i, viewleft + viewwidth, i + 1);
}
#endif
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (g_IrScanlines[g_Vars.currentplayernum][i] > fadeincrement) { if (g_IrScanlines[g_Vars.currentplayernum][i] > fadeincrement) {
@@ -2193,9 +2420,19 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
#endif #endif
} }
#ifndef PLATFORM_N64
gSPClearExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
#endif
#ifdef AVOID_UB
if (g_Menus[mpindex].curdialog == NULL) {
gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40);
}
#else
if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) { if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) {
gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40); gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40);
} }
#endif
return gdl; return gdl;
} }
@@ -2372,7 +2609,7 @@ Gfx *bviewDrawHorizonScanner(Gfx *gdl)
if (fovy == 0 || fovy == 60.0f) { if (fovy == 0 || fovy == 60.0f) {
fovy = 1; fovy = 1;
} else { } else {
fovy = 60.0f / fovy + 1; fovy = ADJUST_ZOOM_FOV(60.0f) / fovy;
} }
sprintf(zoomtext, "%s %s%s%4.2fX", arrows, "", "", fovy); sprintf(zoomtext, "%s %s%s%4.2fX", arrows, "", "", fovy);
@@ -2446,6 +2683,16 @@ Gfx *bviewDrawHorizonScanner(Gfx *gdl)
vsplit = 14; vsplit = 14;
} }
#ifndef PLATFORM_N64
if (!videoFramebuffersSupported()) {
return gdl;
}
// make a copy of what we have drawn so far and use it as a texture
gDPFlushEXT(gdl++);
gDPCopyFramebufferEXT(gdl++, g_PrevFrameFb, 0, 0, 0, G_ON);
gDPSetFramebufferTextureEXT(gdl++, 0, 0, 0, g_PrevFrameFb);
#endif
// Iterate horizontal lines down the lens with a bit extra on top and bottom // Iterate horizontal lines down the lens with a bit extra on top and bottom
for (liney = lenstop - 9; liney < lenstop + lensheight + vsplit + 9; liney++) { for (liney = lenstop - 9; liney < lenstop + lensheight + vsplit + 9; liney++) {
if (liney < lenstop + lensheight && liney >= lenstop) { if (liney < lenstop + lensheight && liney >= lenstop) {
@@ -2493,7 +2740,18 @@ Gfx *bviewDrawHorizonScanner(Gfx *gdl)
gDPSetColor(gdl++, G_SETENVCOLOR, colour); gDPSetColor(gdl++, G_SETENVCOLOR, colour);
#ifdef PLATFORM_N64
gdl = bviewCopyPixels(gdl, fb, liney, 5, liney, RANDOMFRAC() * range + 1, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, liney, 5, liney, RANDOMFRAC() * range + 1, viewleft, viewwidth);
#else
const f32 xscale = RANDOMFRAC() * range + 1;
const f32 halfwidth = viewwidth / 2.f;
const s32 left = viewleft + halfwidth * (1.f - xscale);
const s32 right = viewleft + halfwidth * (1.f + xscale);
gSPImageRectangleEXT(gdl++,
left << 2, liney << 2, viewleft, liney,
right << 2, (liney + 1) << 2, viewleft + viewwidth, liney + 1,
0, videoGetNativeWidth(), videoGetNativeHeight());
#endif
} }
return gdl; return gdl;
+110 -15
View File
@@ -26,6 +26,71 @@
#include "lib/collision.h" #include "lib/collision.h"
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64
#include "net/net.h"
#include "system.h"
#include "utils.h"
static inline void lerpcoord(struct coord *c, const struct coord *a, const struct coord *b, const f32 t) {
c->x = lerpf(a->x, b->x, t);
c->y = lerpf(a->y, b->y, t);
c->z = lerpf(a->z, b->z, t);
}
static void bwalkUpdateRemote(void)
{
struct player *pl = g_Vars.currentplayer;
const struct netplayermove *inmove = &pl->client->inmove[0];
const struct netplayermove *inmoveprev = &pl->client->inmove[1];
struct coord delta;
u16 cdtype = CDTYPE_ALL;
s32 moveticks = inmove->tick - inmoveprev->tick;
if (moveticks > g_NetInterpTicks) {
moveticks = g_NetInterpTicks;
}
pl->client->inmovetick = inmove->tick;
pl->bondshotspeed.x = 0.f;
pl->bondshotspeed.y = 0.f;
pl->bondshotspeed.z = 0.f;
pl->bondbreathing = 0.f;
const bool forcepos = !inmoveprev->tick ||
(inmove->ucmd & UCMD_FL_FORCEPOS) ||
(fabsf(pl->prop->pos.x - inmove->pos.x) > 512.f) ||
(fabsf(pl->prop->pos.y - inmove->pos.y) > 512.f) ||
(fabsf(pl->prop->pos.z - inmove->pos.z) > 512.f);
delta.x = 0.f;
delta.y = 0.f;
delta.z = 0.f;
// extrapolate
bwalk0f0c69b8();
if (forcepos) {
// no interpolation, set position and lock the lad in place
pl->prop->pos = inmove->pos;
pl->client->lerpticks = g_NetInterpTicks + 1;
cdtype = CDTYPE_PLAYERS; // don't get stuck in the local client
} else if (!moveticks) {
// duplicate move, reposition to correct coords
delta.x = inmove->pos.x - pl->prop->pos.x;
delta.x = inmove->pos.y - pl->prop->pos.y;
delta.x = inmove->pos.z - pl->prop->pos.z;
bwalk0f0c63bc(&delta, pl->swaytarget == 0.0f, cdtype);
} else if (pl->client->lerpticks <= moveticks) {
// lerp towards the correct position
const f32 dt = (f32)1.f / (f32)moveticks;
delta.x = g_Vars.lvupdate60freal * (inmove->pos.x - pl->prop->pos.x) * dt;
delta.y = g_Vars.lvupdate60freal * (inmove->pos.y - pl->prop->pos.y) * dt;
delta.z = g_Vars.lvupdate60freal * (inmove->pos.z - pl->prop->pos.z) * dt;
bwalk0f0c63bc(&delta, pl->swaytarget == 0.0f, cdtype);
pl->client->lerpticks += g_Vars.lvupdate60;
}
}
#endif
void bwalkInit(void) void bwalkInit(void)
{ {
@@ -120,6 +185,10 @@ void bwalkInit(void)
} }
} }
void bwalkSetSwayTargetf(f32 value) {
g_Vars.currentplayer->swaytarget = value * 75.f;
}
void bwalkSetSwayTarget(s32 value) void bwalkSetSwayTarget(s32 value)
{ {
g_Vars.currentplayer->swaytarget = value * 75.0f; g_Vars.currentplayer->swaytarget = value * 75.0f;
@@ -187,7 +256,7 @@ s32 bwalkTryMoveUpwards(f32 amount)
{ {
bool result; bool result;
struct coord newpos; struct coord newpos;
s16 rooms[8]; RoomNum rooms[8];
u32 stack; u32 stack;
u32 types; u32 types;
f32 ymax; f32 ymax;
@@ -235,9 +304,9 @@ bool bwalkCalculateNewPosition(struct coord *vel, f32 rotateamount, bool apply,
s32 result = CDRESULT_NOCOLLISION; s32 result = CDRESULT_NOCOLLISION;
f32 halfradius; f32 halfradius;
struct coord dstpos; struct coord dstpos;
s16 dstrooms[8]; RoomNum dstrooms[8];
bool copyrooms = false; bool copyrooms = false;
s16 sp64[22]; RoomNum sp64[22];
s32 types; s32 types;
f32 ymax; f32 ymax;
f32 ymin; f32 ymin;
@@ -392,7 +461,7 @@ bool bwalkCalculateNewPositionWithPush(struct coord *delta, f32 rotateamount, bo
} else if (obstacle->type == PROPTYPE_CHR) { } else if (obstacle->type == PROPTYPE_CHR) {
struct chrdata *chr = obstacle->chr; struct chrdata *chr = obstacle->chr;
struct coord newpos; struct coord newpos;
s16 newrooms[8]; RoomNum newrooms[8];
f32 movingdist; f32 movingdist;
f32 xdist; f32 xdist;
f32 zdist; f32 zdist;
@@ -406,7 +475,7 @@ bool bwalkCalculateNewPositionWithPush(struct coord *delta, f32 rotateamount, bo
} }
} else if (chr->chrflags & CHRCFLAG_PUSHABLE) { } else if (chr->chrflags & CHRCFLAG_PUSHABLE) {
if (g_Vars.antiplayernum < 0 if (g_Vars.antiplayernum < 0
|| g_Vars.currentplayer != g_Vars.anti || PLAYER_IS_NOT_ANTI(g_Vars.currentplayer)
|| (chr->hidden & CHRHFLAG_ANTINONINTERACTABLE) == 0) { || (chr->hidden & CHRHFLAG_ANTINONINTERACTABLE) == 0) {
canpush = true; canpush = true;
} }
@@ -713,10 +782,10 @@ void bwalkUpdateVertical(void)
f32 ground; f32 ground;
bool onladder; bool onladder;
bool onladder2 = false; bool onladder2 = false;
s16 rooms[8]; RoomNum rooms[8];
struct coord testpos; struct coord testpos;
struct coord newpos; struct coord newpos;
s16 newrooms[8]; RoomNum newrooms[8];
s32 newinlift; s32 newinlift;
struct prop *lift = NULL; struct prop *lift = NULL;
f32 sumground; f32 sumground;
@@ -740,7 +809,7 @@ void bwalkUpdateVertical(void)
// Maybe reset counter-op's radius - not sure why // Maybe reset counter-op's radius - not sure why
// Maybe it gets set to 0 when they die? // Maybe it gets set to 0 when they die?
if (g_Vars.antiplayernum >= 0 if (g_Vars.antiplayernum >= 0
&& g_Vars.currentplayer == g_Vars.anti && PLAYER_IS_ANTI(g_Vars.currentplayer)
&& g_Vars.currentplayer->bond2.radius != 30 && g_Vars.currentplayer->bond2.radius != 30
&& cdTestVolume(&g_Vars.currentplayer->prop->pos, 30, g_Vars.currentplayer->prop->rooms, CDTYPE_ALL, CHECKVERTICAL_YES, ymax - g_Vars.currentplayer->prop->pos.y, ymin - g_Vars.currentplayer->prop->pos.y)) { && cdTestVolume(&g_Vars.currentplayer->prop->pos, 30, g_Vars.currentplayer->prop->rooms, CDTYPE_ALL, CHECKVERTICAL_YES, ymax - g_Vars.currentplayer->prop->pos.y, ymin - g_Vars.currentplayer->prop->pos.y)) {
g_Vars.currentplayer->prop->chr->radius = 30; g_Vars.currentplayer->prop->chr->radius = 30;
@@ -1209,8 +1278,13 @@ void bwalkUpdateTheta(void)
f32 rotateamount; f32 rotateamount;
struct coord delta = {0, 0, 0}; struct coord delta = {0, 0, 0};
#ifdef PLATFORM_N64
// Turn speed is calculated from the chr's height // Turn speed is calculated from the chr's height
mult = 159.0f / g_Vars.currentplayer->vv_eyeheight; mult = 159.0f / g_Vars.currentplayer->vv_eyeheight;
#else
// Same turn speed for all heights
mult = 1.f;
#endif
rotateamount = g_Vars.currentplayer->speedtheta * mult rotateamount = g_Vars.currentplayer->speedtheta * mult
* g_Vars.lvupdate60freal * 0.0174505133f * 3.5f; * g_Vars.lvupdate60freal * 0.0174505133f * 3.5f;
@@ -1289,12 +1363,11 @@ void bwalkApplyMoveData(struct movedata *data)
bwalkUpdateSpeedSideways(1, 0.2f, data->digitalstepright); bwalkUpdateSpeedSideways(1, 0.2f, data->digitalstepright);
} else if (data->unk14 == false) { } else if (data->unk14 == false) {
bwalkUpdateSpeedSideways(0, 0.2f, g_Vars.lvupdate60); bwalkUpdateSpeedSideways(0, 0.2f, g_Vars.lvupdate60);
} } else if (data->unk14){
if (data->unk14) {
bwalkUpdateSpeedSideways(data->analogstrafe * 0.014285714365542f, 0.2f, g_Vars.lvupdate60); bwalkUpdateSpeedSideways(data->analogstrafe * 0.014285714365542f, 0.2f, g_Vars.lvupdate60);
} }
// Forward/back // Forward/back
if (data->digitalstepforward) { if (data->digitalstepforward) {
bwalkUpdateSpeedForwards(1, 1); bwalkUpdateSpeedForwards(1, 1);
@@ -1303,11 +1376,12 @@ void bwalkApplyMoveData(struct movedata *data)
bwalkUpdateSpeedForwards(-1, 1); bwalkUpdateSpeedForwards(-1, 1);
} else if (data->canlookahead == false) { } else if (data->canlookahead == false) {
bwalkUpdateSpeedForwards(0, 1); bwalkUpdateSpeedForwards(0, 1);
} else {
bwalkUpdateSpeedForwards(data->analogwalk * 0.014285714365542f, 1);
} }
if (data->canlookahead) {
bwalkUpdateSpeedForwards(data->analogwalk * 0.014285714365542f, 1);
if (data->canlookahead) {
if (data->analogwalk > 60) { if (data->analogwalk > 60) {
g_Vars.currentplayer->speedmaxtime60 += g_Vars.lvupdate60; g_Vars.currentplayer->speedmaxtime60 += g_Vars.lvupdate60;
} else { } else {
@@ -1340,6 +1414,17 @@ void bwalkApplyMoveData(struct movedata *data)
g_Vars.currentplayer->speedmaxtime60 = 0; g_Vars.currentplayer->speedmaxtime60 = 0;
} }
#ifndef PLATFORM_N64
if (data->rleanleft) {
bwalkSetSwayTarget(-1);
} else if (data->rleanright) {
bwalkSetSwayTarget(1);
} else if (fabsf(data->analoglean)) {
bwalkSetSwayTargetf(data->analoglean);
} else {
bwalkSetSwayTarget(0);
}
#else
if (data->rleanleft) { if (data->rleanleft) {
bwalkSetSwayTarget(-1); bwalkSetSwayTarget(-1);
} else if (data->rleanright) { } else if (data->rleanright) {
@@ -1347,6 +1432,7 @@ void bwalkApplyMoveData(struct movedata *data)
} else { } else {
bwalkSetSwayTarget(0); bwalkSetSwayTarget(0);
} }
#endif
while (data->crouchdown-- > 0) { while (data->crouchdown-- > 0) {
bwalkAdjustCrouchPos(-1); bwalkAdjustCrouchPos(-1);
@@ -1362,11 +1448,13 @@ void bwalkApplyMoveData(struct movedata *data)
void bwalkUpdateSpeedTheta(void) void bwalkUpdateSpeedTheta(void)
{ {
#ifdef PLATFORM_N64
if (bmoveGetCrouchPos() == CROUCHPOS_SQUAT) { if (bmoveGetCrouchPos() == CROUCHPOS_SQUAT) {
g_Vars.currentplayer->speedtheta *= 0.5f; g_Vars.currentplayer->speedtheta *= 0.5f;
} else if (bmoveGetCrouchPos() == CROUCHPOS_DUCK) { } else if (bmoveGetCrouchPos() == CROUCHPOS_DUCK) {
g_Vars.currentplayer->speedtheta *= 0.75f; g_Vars.currentplayer->speedtheta *= 0.75f;
} }
#endif
} }
void bwalk0f0c69b8(void) void bwalk0f0c69b8(void)
@@ -1543,7 +1631,7 @@ void bwalk0f0c69b8(void)
g_Vars.currentplayer->bondbreathing = 1.0f; g_Vars.currentplayer->bondbreathing = 1.0f;
} }
mult = var80075c00[1].unk0c * 0.5f * g_Vars.lvupdate60freal; mult = g_HeadAnims[HEADANIM_MOVING].translateperframe * 0.5f * g_Vars.lvupdate60freal;
spe0 = (g_Vars.currentplayer->speedsideways * spc0 + spc4) * mult; spe0 = (g_Vars.currentplayer->speedsideways * spc0 + spc4) * mult;
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
@@ -1728,7 +1816,7 @@ void bwalk0f0c69b8(void)
sp40 = -1.0f; sp40 = -1.0f;
} }
if (g_Vars.currentplayer->headanim == 1) { if (g_Vars.currentplayer->headanim == HEADANIM_MOVING) {
breathing *= 1.2f; breathing *= 1.2f;
} }
@@ -1741,7 +1829,14 @@ void bwalkTick(void)
bwalkUpdatePrevPos(); bwalkUpdatePrevPos();
bwalkUpdateTheta(); bwalkUpdateTheta();
bmoveUpdateVerta(); bmoveUpdateVerta();
#ifndef PLATFORM_N64
if (g_Vars.currentplayer->isremote) {
bwalkUpdateRemote();
} else
#endif
bwalk0f0c69b8(); bwalk0f0c69b8();
bwalkUpdateVertical(); bwalkUpdateVertical();
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
+21 -6
View File
@@ -88,6 +88,10 @@ void botReset(struct chrdata *chr, u8 respawning)
chrSetShield(chr, 0); chrSetShield(chr, 0);
chr->cmnum = 0; chr->cmnum = 0;
chr->cmnum2 = 0; chr->cmnum2 = 0;
#ifndef PLATFORM_N64
chr->blurdrugamount = 0;
chr->poisoncounter = 0;
#endif
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
bgunFreeFireslot(chr->fireslots[0]); bgunFreeFireslot(chr->fireslots[0]);
@@ -227,7 +231,7 @@ void botSpawn(struct chrdata *chr, u8 respawning)
struct defaultobj *obj; struct defaultobj *obj;
struct aibot *aibot = chr->aibot; struct aibot *aibot = chr->aibot;
struct coord pos; struct coord pos;
s16 rooms[8]; RoomNum rooms[8];
if (chr->prop) { if (chr->prop) {
prop = chr->prop->child; prop = chr->prop->child;
@@ -256,6 +260,17 @@ void botSpawn(struct chrdata *chr, u8 respawning)
chr->aibot->moveratex = 0; chr->aibot->moveratex = 0;
chr->aibot->moveratey = 0; chr->aibot->moveratey = 0;
func0f02e9a0(chr, 0); func0f02e9a0(chr, 0);
#ifndef PLATFORM_N64
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
botinvGiveSingleWeapon(chr, mpweapon->weaponnum);
botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2);
botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY);
}
#endif
} }
} }
@@ -660,8 +675,8 @@ void botCheckPickups(struct chrdata *chr)
s32 i; s32 i;
s16 *propnumptr; s16 *propnumptr;
s16 propnums[260]; s16 propnums[260];
s16 allrooms[22]; RoomNum allrooms[22];
s16 neighbours[12]; RoomNum neighbours[12];
roomsCopy(chr->prop->rooms, allrooms); roomsCopy(chr->prop->rooms, allrooms);
@@ -1208,7 +1223,7 @@ void botApplyProtect(struct chrdata *chr, struct prop *prop)
chr->aibot->forcemainloop = true; chr->aibot->forcemainloop = true;
} }
void botApplyDefend(struct chrdata *chr, struct coord *pos, s16 *room, f32 angle) void botApplyDefend(struct chrdata *chr, struct coord *pos, RoomNum *room, f32 angle)
{ {
chr->aibot->command = AIBOTCMD_DEFEND; chr->aibot->command = AIBOTCMD_DEFEND;
chr->aibot->defendholdpos.x = pos->x; chr->aibot->defendholdpos.x = pos->x;
@@ -1219,7 +1234,7 @@ void botApplyDefend(struct chrdata *chr, struct coord *pos, s16 *room, f32 angle
chr->aibot->forcemainloop = true; chr->aibot->forcemainloop = true;
} }
void botApplyHold(struct chrdata *chr, struct coord *pos, s16 *room, f32 angle) void botApplyHold(struct chrdata *chr, struct coord *pos, RoomNum *room, f32 angle)
{ {
chr->aibot->command = AIBOTCMD_HOLD; chr->aibot->command = AIBOTCMD_HOLD;
chr->aibot->defendholdpos.x = pos->x; chr->aibot->defendholdpos.x = pos->x;
@@ -1521,7 +1536,7 @@ void botChooseGeneralTarget(struct chrdata *botchr)
s32 i; s32 i;
s32 j; s32 j;
bool distancesdone[MAX_MPCHRS]; bool distancesdone[MAX_MPCHRS];
s16 room = -1; RoomNum room = -1;
struct chrdata *trychr; struct chrdata *trychr;
s32 playernum; s32 playernum;
+3 -3
View File
@@ -259,7 +259,7 @@ bool botactShootFarsight(struct chrdata *chr, s32 arg1, struct coord *vector, st
// chance of passing. // chance of passing.
if (oppchr != chr if (oppchr != chr
&& value > rand && value > rand
&& func0f06b39c(arg3, vector, &oppprop->pos, chr0f0278a4(oppchr))) { && func0f06b39c(arg3, vector, &oppprop->pos, chrGetHitRadius(oppchr))) {
bgunPlayPropHitSound(&gset, oppprop, -1); bgunPlayPropHitSound(&gset, oppprop, -1);
if (oppchr->model && chrGetShield(oppchr) > 0) { if (oppchr->model && chrGetShield(oppchr) > 0) {
@@ -440,7 +440,7 @@ s32 botactGetShootInterval60(s32 weaponnum, s32 funcnum)
* *
* Return true if a route was found, false if not. * Return true if a route was found, false if not.
*/ */
bool botactFindRocketRoute(struct chrdata *chr, struct coord *frompos, struct coord *topos, s16 *fromrooms, s16 *torooms, struct projectile *projectile) bool botactFindRocketRoute(struct chrdata *chr, struct coord *frompos, struct coord *topos, RoomNum *fromrooms, RoomNum *torooms, struct projectile *projectile)
{ {
struct waypoint *from = waypointFindClosestToPos(frompos, fromrooms); struct waypoint *from = waypointFindClosestToPos(frompos, fromrooms);
struct waypoint *to = waypointFindClosestToPos(topos, torooms); struct waypoint *to = waypointFindClosestToPos(topos, torooms);
@@ -479,7 +479,7 @@ bool botactFindRocketRoute(struct chrdata *chr, struct coord *frompos, struct co
void botactGetRocketNextStepPos(u16 padnum, struct coord *pos) void botactGetRocketNextStepPos(u16 padnum, struct coord *pos)
{ {
struct pad pad; struct pad pad;
s16 rooms[2]; RoomNum rooms[2];
padUnpack(padnum, PADFIELD_ROOM | PADFIELD_POS, &pad); padUnpack(padnum, PADFIELD_ROOM | PADFIELD_POS, &pad);
+12 -1
View File
@@ -56,7 +56,7 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
/*0x17*/ { 176, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 20, 20, 4, 4, 2, 0 }, // WEAPON_DEVASTATOR /*0x17*/ { 176, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 20, 20, 4, 4, 2, 0 }, // WEAPON_DEVASTATOR
/*0x18*/ { 160, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 2, 2, 1, 1, 2, 0 }, // WEAPON_ROCKETLAUNCHER /*0x18*/ { 160, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 2, 2, 1, 1, 2, 0 }, // WEAPON_ROCKETLAUNCHER
/*0x19*/ { 168, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 2, 2, 1, 1, 3, 0 }, // WEAPON_SLAYER /*0x19*/ { 168, 188, 0, 0, 1, 1, BOTDISTCFG_SHOOTEXPLOSIVE, BOTDISTCFG_SHOOTEXPLOSIVE, 2, 2, 1, 1, 3, 0 }, // WEAPON_SLAYER
#if VERSION == VERSION_JPN_FINAL #if (VERSION == VERSION_JPN_FINAL) && defined(PLATFORM_N64)
/*0x1a*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATKNIFE /*0x1a*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATKNIFE
#else #else
/*0x1a*/ { 20, 40, 24, 40, 1, 1, BOTDISTCFG_CLOSE, BOTDISTCFG_DEFAULT, 0, 5, 0, 1, 1, 0 }, // WEAPON_COMBATKNIFE /*0x1a*/ { 20, 40, 24, 40, 1, 1, BOTDISTCFG_CLOSE, BOTDISTCFG_DEFAULT, 0, 5, 0, 1, 1, 0 }, // WEAPON_COMBATKNIFE
@@ -70,6 +70,16 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
/*0x21*/ { 40, 176, 0, 0, 0, 0, BOTDISTCFG_THROWEXPLOSIVE, BOTDISTCFG_DEFAULT, 5, 5, 1, 1, 1, 0 }, // WEAPON_PROXIMITYMINE /*0x21*/ { 40, 176, 0, 0, 0, 0, BOTDISTCFG_THROWEXPLOSIVE, BOTDISTCFG_DEFAULT, 5, 5, 1, 1, 1, 0 }, // WEAPON_PROXIMITYMINE
/*0x22*/ { 44, 156, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 5, 5, 2, 2, 1, 0 }, // WEAPON_REMOTEMINE /*0x22*/ { 44, 156, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 5, 5, 2, 2, 1, 0 }, // WEAPON_REMOTEMINE
/*0x23*/ { 8, 8, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATBOOST /*0x23*/ { 8, 8, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATBOOST
#ifndef PLATFORM_N64 // add all classic weapons to multiplayer
/*0x24*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I
/*0x25*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13
/*0x26*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313
/*0x27*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL
/*0x28*/ { 116, 128, 136, 152, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT
/*0x29*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_DMC
/*0x2a*/ { 156, 180, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 150, 0, 30, 0, 1, 0 }, // WEAPON_AR53
/*0x2b*/ { 164, 188, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 200, 0, 40, 0, 1, 0 }, // WEAPON_RCP45
#else
/*0x24*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PP9I /*0x24*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PP9I
/*0x25*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_CC13 /*0x25*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_CC13
/*0x26*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_KL01313 /*0x26*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_KL01313
@@ -78,6 +88,7 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
/*0x29*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_DMC /*0x29*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_DMC
/*0x2a*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_AR53 /*0x2a*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_AR53
/*0x2b*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_RCP45 /*0x2b*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_RCP45
#endif
/*0x2c*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PSYCHOSISGUN /*0x2c*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PSYCHOSISGUN
/*0x2d*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_NIGHTVISION /*0x2d*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_NIGHTVISION
/*0x2e*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_EYESPY /*0x2e*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_EYESPY
+1 -1
View File
@@ -28,7 +28,7 @@ void botmgrRemoveAll(void)
void botmgrAllocateBot(s32 chrnum, s32 aibotnum) void botmgrAllocateBot(s32 chrnum, s32 aibotnum)
{ {
s16 rooms[1]; RoomNum rooms[1];
struct prop *prop; struct prop *prop;
struct chrdata *chr; struct chrdata *chr;
struct aibot *aibot; struct aibot *aibot;
+5 -5
View File
@@ -46,16 +46,16 @@
* It's likely that these don't ever overflow, or they overflow minimally which * It's likely that these don't ever overflow, or they overflow minimally which
* has no serious effect, but this should be investigated further. * has no serious effect, but this should be investigated further.
*/ */
bool botroomFindPos(s16 room, struct coord *pos, f32 *angleptr, s32 *padnumptr, s32 *covernumptr) bool botroomFindPos(RoomNum room, struct coord *pos, f32 *angleptr, s32 *padnumptr, s32 *covernumptr)
{ {
s32 i; s32 i;
struct waypoint *waypoint; struct waypoint *waypoint;
s32 waypointnum; s32 waypointnum;
s32 covernums[40]; /// written to stack s32 covernums[40];
s32 covercount; s32 covercount;
struct cover cover; // written to stack struct cover cover;
s16 rooms[2]; // written to stack RoomNum rooms[2];
s32 padnums[40]; // written to stack s32 padnums[40];
s32 padcount; s32 padcount;
s32 totalcount; s32 totalcount;
struct pad pad; struct pad pad;
+16 -16
View File
@@ -948,7 +948,7 @@ void func0f14aee0(void)
thing->unk078 = 0; thing->unk078 = 0;
pak0f117150(i, thing->unk0d8); pak0f117150(i, thing->unk0d8);
pak0f1171b4(SAVEDEVICE_CONTROLLERPAK1, 3, 0); pak0f1171b4(SAVEDEVICE_CONTROLLERPAK1, PAK00C_03, 0);
func0f14aed0(i); func0f14aed0(i);
thing->unk094 = 0; thing->unk094 = 0;
@@ -1200,7 +1200,7 @@ void func0f14b8ac(s32 index)
} }
switch (pakGetUnk008(func0f14a5a4())) { switch (pakGetUnk008(func0f14a5a4())) {
case 12: case PAK008_12:
func0f14a95c(); func0f14a95c();
func0f14aa48(); func0f14aa48();
func0f14e790(var800a45a0->unk470); func0f14e790(var800a45a0->unk470);
@@ -1209,10 +1209,10 @@ void func0f14b8ac(s32 index)
func0f14a16c(1); func0f14a16c(1);
func0f14bc04(); func0f14bc04();
break; break;
case 1: case PAK008_01:
pak0f11d4dc(func0f14a5a4()); pak0f11d4dc(func0f14a5a4());
break; break;
case 11: case PAK008_11:
pak0f11d9c4(func0f14a5a4(), var800a45a0->unk470, 0, 0); pak0f11d9c4(func0f14a5a4(), var800a45a0->unk470, 0, 0);
func0f14d064(index, var800a45a0->unk470); func0f14d064(index, var800a45a0->unk470);
pak0f11d478(func0f14a5a4()); pak0f11d478(func0f14a5a4());
@@ -1320,7 +1320,7 @@ void func0f14bd34(s32 index)
struct var8007f8dc *thing = &var8007f8dc[index]; struct var8007f8dc *thing = &var8007f8dc[index];
if (thing->unk080 != -1) { if (thing->unk080 != -1) {
pak0f1171b4(func0f14a5a4(), 3, 0); pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
pak0f11d540(func0f14a5a4(), thing->unk0b6[thing->unk080]); pak0f11d540(func0f14a5a4(), thing->unk0b6[thing->unk080]);
} }
} }
@@ -1333,7 +1333,7 @@ void func0f14bdbc(s32 index)
s32 value; s32 value;
for (i = 0; i < 30; i++) { for (i = 0; i < 30; i++) {
thing->unk0dc[i] = NULL; thing->unk0dc[i] = 0;
} }
thing->unk094 = 0; thing->unk094 = 0;
@@ -1402,7 +1402,7 @@ void func0f14bec8(s32 index)
for (i = 0; i < ARRAYCOUNT(thing->unk0b6); i++); for (i = 0; i < ARRAYCOUNT(thing->unk0b6); i++);
pak0f1171b4(func0f14a5a4(), 3, 0); pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
pak0f11d478(func0f14a5a4()); pak0f11d478(func0f14a5a4());
break; break;
case 3: case 3:
@@ -1446,7 +1446,7 @@ void func0f14c1cc(s32 index)
switch (thing->unk0f4) { switch (thing->unk0f4) {
case 0: case 0:
pak0f1171b4(func0f14a5a4(), 0, 0); pak0f1171b4(func0f14a5a4(), PAK00C_00, 0);
pak0f11d5b0(func0f14a5a4()); pak0f11d5b0(func0f14a5a4());
thing->unk0f4 = 1; thing->unk0f4 = 1;
break; break;
@@ -1510,13 +1510,13 @@ void func0f14c3a4(s32 index)
pak0f11d620(func0f14a5a4()); pak0f11d620(func0f14a5a4());
switch (pakGetUnk008(func0f14a5a4())) { switch (pakGetUnk008(func0f14a5a4())) {
case 1: case PAK008_01:
func0f14c1cc(index); func0f14c1cc(index);
break; break;
case 11: case PAK008_11:
func0f14bec8(index); func0f14bec8(index);
break; break;
case 12: case PAK008_12:
func0f14bdbc(index); func0f14bdbc(index);
break; break;
} }
@@ -1712,7 +1712,7 @@ void func0f14cdb8(s32 index, u8 *arg1)
void func0f14ce84(void) void func0f14ce84(void)
{ {
if (pak0f11d3f8(func0f14a5a4())) { if (pak0f11d3f8(func0f14a5a4())) {
if (pakGetUnk008(func0f14a5a4()) != 12) { if (pakGetUnk008(func0f14a5a4()) != PAK008_12) {
var8007f8dc[func0f14a5a4()].unk0f8 = 1; var8007f8dc[func0f14a5a4()].unk0f8 = 1;
var8007f8dc[func0f14a5a4()].unk0d4_00 = false; var8007f8dc[func0f14a5a4()].unk0d4_00 = false;
@@ -1739,7 +1739,7 @@ void func0f14cf6c(void)
case 4: case 4:
case 5: case 5:
case 6: case 6:
pak0f1171b4(func0f14a5a4(), 3, 0); pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
g_MpPlayerNum = 0; g_MpPlayerNum = 0;
menuSetBanner(-1, false); menuSetBanner(-1, false);
break; break;
@@ -1762,7 +1762,7 @@ void func0f14d064(s32 index, u8 *arg1)
g_MpPlayerNum = index; g_MpPlayerNum = index;
menuSetBanner(MENUBANNER_CALIBRATINGCAMERA, false); menuSetBanner(MENUBANNER_CALIBRATINGCAMERA, false);
func0f14a16c(1); func0f14a16c(1);
pak0f1171b4(func0f14a5a4(), 1, 1); pak0f1171b4(func0f14a5a4(), PAK00C_01, 1);
thing->unk0f8 = 3; thing->unk0f8 = 3;
return; return;
} }
@@ -1801,12 +1801,12 @@ void func0f14d064(s32 index, u8 *arg1)
} }
if (thing->unk0f8 == 6) { if (thing->unk0f8 == 6) {
pak0f1171b4(func0f14a5a4(), 3, 0); pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
thing->unk0f8 = 6; thing->unk0f8 = 6;
thing->unk100 = thing->unk0fc; thing->unk100 = thing->unk0fc;
g_MpPlayerNum = index; g_MpPlayerNum = index;
menuSetBanner(-1, false); menuSetBanner(-1, false);
pak0f1171b4(func0f14a5a4(), 3, 0); pak0f1171b4(func0f14a5a4(), PAK00C_03, 0);
var8007f8dc[var800a45a0->unk000].unk0d4_04 = true; var8007f8dc[var800a45a0->unk000].unk0d4_04 = true;
thing->unk0f8 = 0; thing->unk0f8 = 0;
} }
+20 -14
View File
@@ -1,4 +1,5 @@
#include <ultra64.h> #include <ultra64.h>
#include <string.h>
#include "constants.h" #include "constants.h"
#include "game/atan2f.h" #include "game/atan2f.h"
#include "game/camera.h" #include "game/camera.h"
@@ -105,7 +106,7 @@ void camSetScale(void)
player->c_cameraleftnorm.z = -fVar5 * fVar4; player->c_cameraleftnorm.z = -fVar5 * fVar4;
} }
void cam0f0b4c3c(f32 *crosspos, struct coord *dst, f32 arg2) void cam0f0b4c3c(f32 pos2d[2], struct coord *dir2d, f32 arg2)
{ {
struct player *player = g_Vars.currentplayer; struct player *player = g_Vars.currentplayer;
f32 sp20; f32 sp20;
@@ -113,14 +114,14 @@ void cam0f0b4c3c(f32 *crosspos, struct coord *dst, f32 arg2)
f32 sp18 = -1.0f; f32 sp18 = -1.0f;
f32 f2; f32 f2;
sp1c = (player->c_halfheight - (crosspos[1] - player->c_screentop)) * player->c_scaley; sp1c = (player->c_halfheight - (pos2d[1] - player->c_screentop)) * player->c_scaley;
sp20 = (crosspos[0] - player->c_screenleft - player->c_halfwidth) * player->c_scalex; sp20 = (pos2d[0] - player->c_screenleft - player->c_halfwidth) * player->c_scalex;
f2 = arg2 / sqrtf(sp20 * sp20 + sp1c * sp1c + sp18 * sp18); f2 = arg2 / sqrtf(sp20 * sp20 + sp1c * sp1c + sp18 * sp18);
dst->x = sp20 * f2; dir2d->x = sp20 * f2;
dst->y = sp1c * f2; dir2d->y = sp1c * f2;
dst->z = sp18 * f2; dir2d->z = sp18 * f2;
} }
void cam0f0b4d04(struct coord *in, f32 *out) void cam0f0b4d04(struct coord *in, f32 *out)
@@ -128,11 +129,8 @@ void cam0f0b4d04(struct coord *in, f32 *out)
struct player *player = g_Vars.currentplayer; struct player *player = g_Vars.currentplayer;
f32 value = 1.0f / in->z; f32 value = 1.0f / in->z;
out[1] = in->y * value * player->c_recipscaley out[1] = in->y * value * player->c_recipscaley + (player->c_screentop + player->c_halfheight);
+ (player->c_screentop + player->c_halfheight); out[0] = (player->c_screenleft + player->c_halfwidth) - in->x * value * player->c_recipscalex;
out[0] = (player->c_screenleft + player->c_halfwidth)
- in->x * value * player->c_recipscalex;
} }
void cam0f0b4d68(struct coord *in, f32 out[2]) void cam0f0b4d68(struct coord *in, f32 out[2])
@@ -597,12 +595,15 @@ bool camIsPosInScreenBox(struct coord *pos, f32 arg1, struct drawslot *drawslot)
* correct address to camIsPosInScreenBox so it can interpret the pointer as a * correct address to camIsPosInScreenBox so it can interpret the pointer as a
* drawslot. * drawslot.
*/ */
bool camIsPosInFovAndVisibleRoom(s16 *rooms, struct coord *pos, f32 arg2) bool camIsPosInFovAndVisibleRoom(RoomNum *rooms, struct coord *pos, f32 arg2)
{ {
s32 i; s32 i;
s16 room; RoomNum room;
bool hasdata = false; bool hasdata = false;
struct drawslot *thisthing; struct drawslot *thisthing;
#ifdef AVOID_UB
static struct drawslot dslot;
#endif
struct screenbox box; struct screenbox box;
for (i = 0, room = rooms[i]; room != -1; i++, room = rooms[i]) { for (i = 0, room = rooms[i]; room != -1; i++, room = rooms[i]) {
@@ -640,5 +641,10 @@ bool camIsPosInFovAndVisibleRoom(s16 *rooms, struct coord *pos, f32 arg2)
return false; return false;
} }
return camIsPosInScreenBox(pos, arg2, (struct drawslot *) (&box.array[-1][0])); #ifdef AVOID_UB
memcpy(&dslot.box, &box, sizeof(box));
return camIsPosInScreenBox(pos, arg2, &dslot);
#else
return camIsPosInScreenBox(pos, arg2, (struct drawslot *) &(((u8 *) &box)[-((uintptr_t) &(((struct drawslot *)0)->box))]));
#endif
} }
+1 -1
View File
@@ -21,7 +21,7 @@ f32 ceilf(f32 value)
return fvalue + 1; return fvalue + 1;
} }
s32 ceil(f32 value) s32 ceiltoint(f32 value)
{ {
s32 ivalue; s32 ivalue;
+48 -28
View File
@@ -136,7 +136,7 @@ void challengeDetermineUnlockedFeatures(void)
} }
// Now same as above, but per player // Now same as above, but per player
for (j = 0; j < MAX_PLAYERS; j++) { for (j = 0; j < MAX_LOCAL_PLAYERS; j++) {
numgifted = 0; numgifted = 0;
for (challengeindex = 0; challengeindex < ARRAYCOUNT(g_MpChallenges); challengeindex++) { for (challengeindex = 0; challengeindex < ARRAYCOUNT(g_MpChallenges); challengeindex++) {
@@ -197,7 +197,7 @@ void challengeDetermineUnlockedFeatures(void)
} }
for (challengeindex = 0; challengeindex < ARRAYCOUNT(g_MpChallenges); challengeindex++) { for (challengeindex = 0; challengeindex < ARRAYCOUNT(g_MpChallenges); challengeindex++) {
for (prev = 0; prev < MAX_PLAYERS; prev++) { for (prev = 0; prev < MAX_LOCAL_PLAYERS; prev++) {
if (challengeIsAvailableToPlayer(prev, challengeindex)) { if (challengeIsAvailableToPlayer(prev, challengeindex)) {
for (i = 0; i < ARRAYCOUNT(g_MpChallenges[challengeindex].unlockfeatures); i++) { for (i = 0; i < ARRAYCOUNT(g_MpChallenges[challengeindex].unlockfeatures); i++) {
if (g_MpChallenges[challengeindex].unlockfeatures[i] == j) { if (g_MpChallenges[challengeindex].unlockfeatures[i] == j) {
@@ -249,7 +249,7 @@ void challengePerformSanityChecks(void)
} }
} }
// Turn off all simulants and turn them on if enabled // Turn off all simulants (and players 5-8 if supported) and turn them on if enabled
// for this number of players // for this number of players
g_MpSetup.chrslots &= 0x000f; g_MpSetup.chrslots &= 0x000f;
@@ -265,8 +265,14 @@ void challengePerformSanityChecks(void)
g_Vars.mphilltime = 10; g_Vars.mphilltime = 10;
} }
} else if (!challengeIsFeatureUnlocked(MPFEATURE_8BOTS)) { } else if (!challengeIsFeatureUnlocked(MPFEATURE_8BOTS)) {
// Limit to 4 players and 4 simulants // Limit to 4 players and 4 simulants in local games
#ifndef PLATFORM_N64
g_MpSetup.chrslots &= (g_NetMode ? 0x0fff : 0x0f0f);
#elif MAX_PLAYERS > 4
g_MpSetup.chrslots &= 0x0f0f;
#else
g_MpSetup.chrslots &= 0x00ff; g_MpSetup.chrslots &= 0x00ff;
#endif
} }
} }
@@ -367,41 +373,55 @@ bool challengeIsCompletedByChrWithNumPlayersBySlot(s32 mpchrnum, s32 slot, s32 n
return false; return false;
} }
#ifdef PLATFORM_N64
#define BTYPE s32
#else
#define BTYPE uintptr_t
#endif
struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len) struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len)
{ {
struct mpconfigfull *mpconfig; struct mpconfigfull *mpconfig;
u8 buffer2[sizeof(struct mpstrings) + 40]; u8 buffer2[sizeof(struct mpstrings) + 40];
struct mpstrings *loadedstrings; struct mpstrings *loadedstrings;
s32 bank; BTYPE bank;
u32 language_id = langGetFileNumOffset(); u32 language_id = langGetFileNumOffset();
#ifdef PLATFORM_N64
extern struct mpconfig _mpconfigsSegmentRomStart[]; extern struct mpconfig _mpconfigsSegmentRomStart[];
extern struct mpstrings _mpstringsESegmentRomStart; #else
extern struct mpstrings _mpstringsJSegmentRomStart; extern u8 EXT_SEG _mpconfigsSegmentRomStart;
extern struct mpstrings _mpstringsPSegmentRomStart; #endif
extern struct mpstrings _mpstringsGSegmentRomStart; extern struct mpstrings EXT_SEG _mpstringsESegmentRomStart;
extern struct mpstrings _mpstringsFSegmentRomStart; extern struct mpstrings EXT_SEG _mpstringsJSegmentRomStart;
extern struct mpstrings _mpstringsSSegmentRomStart; extern struct mpstrings EXT_SEG _mpstringsPSegmentRomStart;
extern struct mpstrings _mpstringsISegmentRomStart; extern struct mpstrings EXT_SEG _mpstringsGSegmentRomStart;
extern struct mpstrings _mpstringsESegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsFSegmentRomStart;
extern struct mpstrings _mpstringsJSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsSSegmentRomStart;
extern struct mpstrings _mpstringsPSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsISegmentRomStart;
extern struct mpstrings _mpstringsGSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsESegmentRomEnd;
extern struct mpstrings _mpstringsFSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsJSegmentRomEnd;
extern struct mpstrings _mpstringsSSegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsPSegmentRomEnd;
extern struct mpstrings _mpstringsISegmentRomEnd; extern struct mpstrings EXT_SEG _mpstringsGSegmentRomEnd;
extern struct mpstrings EXT_SEG _mpstringsFSegmentRomEnd;
extern struct mpstrings EXT_SEG _mpstringsSSegmentRomEnd;
extern struct mpstrings EXT_SEG _mpstringsISegmentRomEnd;
s32 banks[][2] = { BTYPE banks[][2] = {
{ (s32)&_mpstringsESegmentRomStart, (s32)&_mpstringsESegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsESegmentRomStart, (BTYPE)REF_SEG _mpstringsESegmentRomEnd },
{ (s32)&_mpstringsJSegmentRomStart, (s32)&_mpstringsJSegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsJSegmentRomStart, (BTYPE)REF_SEG _mpstringsJSegmentRomEnd },
{ (s32)&_mpstringsPSegmentRomStart, (s32)&_mpstringsPSegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsPSegmentRomStart, (BTYPE)REF_SEG _mpstringsPSegmentRomEnd },
{ (s32)&_mpstringsGSegmentRomStart, (s32)&_mpstringsGSegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsGSegmentRomStart, (BTYPE)REF_SEG _mpstringsGSegmentRomEnd },
{ (s32)&_mpstringsFSegmentRomStart, (s32)&_mpstringsFSegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsFSegmentRomStart, (BTYPE)REF_SEG _mpstringsFSegmentRomEnd },
{ (s32)&_mpstringsSSegmentRomStart, (s32)&_mpstringsSSegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsSSegmentRomStart, (BTYPE)REF_SEG _mpstringsSSegmentRomEnd },
{ (s32)&_mpstringsISegmentRomStart, (s32)&_mpstringsISegmentRomEnd }, { (BTYPE)REF_SEG _mpstringsISegmentRomStart, (BTYPE)REF_SEG _mpstringsISegmentRomEnd },
}; };
// Load mpconfigs // Load mpconfigs
mpconfig = dmaExecWithAutoAlign(buffer, (s32)&_mpconfigsSegmentRomStart[confignum], sizeof(struct mpconfig)); #ifdef PLATFORM_N64
mpconfig = dmaExecWithAutoAlign(buffer, (BTYPE)&_mpconfigsSegmentRomStart[confignum], sizeof(struct mpconfig));
#else
mpconfig = dmaExecWithAutoAlign(buffer, (BTYPE)REF_SEG _mpconfigsSegmentRomStart + confignum * sizeof(struct mpconfig), sizeof(struct mpconfig));
#endif
// Load mpstrings // Load mpstrings
bank = banks[language_id][0]; bank = banks[language_id][0];
+96
View File
@@ -100,6 +100,9 @@ struct cheat g_Cheats[] = {
{ L_MPWEAPONS_114, WEAPON_DMC, 0, 0, CHEATFLAG_FIRINGRANGE }, // DMC { L_MPWEAPONS_114, WEAPON_DMC, 0, 0, CHEATFLAG_FIRINGRANGE }, // DMC
{ L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53 { L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53
{ L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45 { L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45
#ifndef PLATFORM_N64
{ L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // Dual wield all guns
#endif
}; };
u32 cheatIsUnlocked(s32 cheat_id) u32 cheatIsUnlocked(s32 cheat_id)
@@ -859,6 +862,79 @@ char *cheatGetName(s32 cheat_id)
} }
#endif #endif
#ifndef PLATFORM_N64
static MenuItemHandlerResult menuhandlerUnlockEverything(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
gamefileUnlockEverything();
}
return 0;
}
struct menuitem g_CheatsConfirmUnlockMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Are you sure?\n\nThis will overwrite any progress\nsaved to the current profile.\n",
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0x00000082,
0,
NULL,
},
{
MENUITEMTYPE_MARQUEE,
0,
MENUITEMFLAG_SMALLFONT | MENUITEMFLAG_MARQUEE_FADEBOTHSIDES | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Unlocks all cheats, weapons, missions, challenges and combat simulator items.\n",
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0x00000082,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_191, // "No"
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_190, // "Yes"
0,
menuhandlerUnlockEverything,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_CheatsConfirmUnlockMenuDialog = {
MENUDIALOGTYPE_DANGER,
L_OPTIONS_188, // "Warning"
g_CheatsConfirmUnlockMenuItems,
NULL,
0,
NULL,
};
#endif
struct menuitem g_CheatsFunMenuItems[] = { struct menuitem g_CheatsFunMenuItems[] = {
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_CHECKBOX,
@@ -1017,6 +1093,16 @@ struct menuitem g_CheatsGameplayMenuItems[] = {
0, 0,
cheatCheckboxMenuHandler, cheatCheckboxMenuHandler,
}, },
#ifndef PLATFORM_N64
{
MENUITEMTYPE_CHECKBOX,
CHEAT_DUALWIELDALLGUNS,
0,
(uintptr_t)&cheatGetNameIfUnlocked,
0,
cheatCheckboxMenuHandler,
},
#endif
{ {
MENUITEMTYPE_SEPARATOR, MENUITEMTYPE_SEPARATOR,
0, 0,
@@ -1538,6 +1624,16 @@ struct menuitem g_CheatsMenuItems[] = {
0, 0,
cheatMenuHandleTurnOffAllCheats, cheatMenuHandleTurnOffAllCheats,
}, },
#ifndef PLATFORM_N64
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG,
(uintptr_t)"Unlock Everything\n",
0,
(void *)&g_CheatsConfirmUnlockMenuDialog,
},
#endif
{ {
MENUITEMTYPE_SEPARATOR, MENUITEMTYPE_SEPARATOR,
0, 0,
Loaded 100 of 309 files, more files were not shown because too many files have changed in this diff. Show more