The `Split Boxes` option in jak2/3 currently crashes as soon as you
select it because of the `*debug-region-hide-empty*` code added in
openGOAL. The split boxes aren't true regions, but they reuse the
`debug-draw-region` functions, and crash trying to access `(-> this
region on-enter)`.
<img width="2160" height="1620" alt="image"
src="https://github.com/user-attachments/assets/e8753fcc-8234-40fa-9278-d2dca4dff71a"
/>
yay split boxes
Based on [similar changes we made awhile back for
jak1](https://github.com/open-goal/jak-project/pull/3902) - this way
runners don't need to figure out the -0.3s offset or whatever, and it
won't vary based on where they reset from.
This attempts to get into master whatever work was done in this PR /
it's earlier PR https://github.com/open-goal/jak-project/pull/3965
I don't want this work to be lost / floating around in massive PRs.
However the changes are:
- switch to ntsc_v1 instead of PAL as the development target, as we have
done for all other games
- remove most of the copied-from-jak2/3 changes as they need to be
confirmed during the decompilation process not just assumed
- avoids committing any changes to `game/kernel/common` as it was not
clear to me if these were changes made in jak x's kernel that were not
properly broken out into it's own functions. We don't want to
accidentally introduce bugs into jak1-3's kernel code.
- in other words, if the change in the kernel only happens in jak x...it
should likely be specific to jak x's kernel, not common.
---------
Co-authored-by: VodBox <dillon@vodbox.io>
Co-authored-by: yodah <greenboyyodah@gmail.com>
If the `arg0` vector has extreme values, `a2-0` and `a1-1` can end up
being negative, which leads to out-of-bounds access when using these
values to read from the `xz-height-map`'s `data` array, and crashes the
game (you can pretty easily reproduce this in jak 3 by overcharging the
"superfasthoverbikeglitch")
The `min` here already makes sure these values don't go too high, but
doesn't cover the case when they go negative.
As I understand it, this `data` in the `*traffic-height-map*` functions
as a 2d array, bucketing x/z coordinates into heights for the vehicle.
Looking at the balance-plats, they showed an immediate visual clue,
which was the stuttering of Jak's feet on their surface.
This is precisely what happens when you don't include sticky on a
collision; it doesn't "pull" Jak along with it, and he repetitively
"falls" onto it's surface over and over as it moves downwards.
This is a mystery, since this actor does have sticky, in fact, it's not
even possible to detect riders without sticky, which these certainly do.
This same appears on PS2, so I knew fixing it was not an option.
I had an immediate theory of what was happening: since Jak is
continuously falling onto it as it moves downwards, he's only riding
some frames, and skipping others. A higher frame rate = more moments
he's touching.
This means that basically, the balance-plat's entire speed is determined
by when his feet happen to micro-stutter. This is the hardcoded scalar
for it's entire speed.
This means I needed to emulate the 60 FPS "falling" at different
framerates. I tried adding an fps counter to the actor so that the rider
check only ran once every 60th of a second, but I knew adding a variable
to the actor just for fps wasn't a good idea.
However, I was able to confirm that would work. Luckily, this
[comment](https://github.com/open-goal/jak-project/blob/0fa93ce7b83d1621f3fd040625bfa865eadaeef0/goal_src/jak1/engine/game/game-h.gc#L116)
gave me an idea, which meant I could use a variable of process drawable,
avoiding adding a variable.
This unique problem needs a unique solution, I gate rider checks so they
only pass if one sixtieth of a second `(seconds 0.01666666)` has passed
since the last ride. This makes it act like his feet are stuttering like
they do at 60 FPS, avoiding the extra frames where his feet are touching
at high framerates that add more speed.
I also added the same for the send-to messages, since at high frame
rates the passive return to center that runs every frame was stomping
the send-to-next velocities which run less often.
Then, I managed to refactor it down to a tiny edit, a guard in one place
that gates on 1/60th of a second, framerate already 60, or, self grow
(since you don't want to double-gate these).
```lisp
(when (or (= (-> *pc-settings* target-fps) 60)
(time-elapsed? (-> self state-time) (seconds 0.01666666))
(-> self got-grow))
```
It's just: this guard, `(set-state-time)` on ride, and
`(set-state-time)` on grow (limits increased-rate return to center
stomping grow).
Lastly, there was an issue with the existing multiplies by FPS RATIO,
which was a clear double scale of the acceleration (once when setting
accelerate, then again when adding the accelerate). I'm guessing since
the extra riding frames added so much speed, this double scalar helped
slow it down, however when corrected the double scalar made it too slow
since it was slowing down for framerate twice.
Massive overhaul of Finnish translations
I guess it's time to finally push this out
I'll go insane if I have to proofread one more time :P
Every time I just realize my translations sucked and I keep tweaking
everything
---------
Co-authored-by: Tyler Wilding <xtvaser@gmail.com>
I was changing aspect ratios when I noticed something was off, getting
different results for the same setting.
On screen positions are determined by both the aspect ratio you select
as well as the last time you selected a PS2 aspect ratio.
You get different result by choosing 4x3 (PS2), then 16:9, compared to
16:9 (PS2), then 16:9. The same is true for all aspects and Fit to
Screen.
By contrast, Jak 2 always uses the 'aspect4x3 scale factor for all
custom aspects, making the menu option you select consistent.
There is an intention to use 4x3 for custom aspects
[here](https://github.com/open-goal/jak-project/blob/abf27960f0033436b066c712c787160d2c9a5346/goal_src/jak1/pc/progress-pc.gc#L2618);
when `fit-to-screen` then `(set-aspect-ratio 'aspect4x3)`. However it
needs the extra lines to take effect.
This is helpful as the only cause of vertical misalignment on memory
cards is using PS2 16x9 on custom aspects:
<img width="1800" height="1013" alt="2"
src="https://github.com/user-attachments/assets/5a5e5ea9-00fc-439b-b3d6-dcf3419a8bd1"
/>
<img width="1800" height="1013" alt="4"
src="https://github.com/user-attachments/assets/4876d267-5a44-4074-bd63-d7a5d8ac02e5"
/>
So `target` has some logic here which checks if the pending attack has
the same ID as the last attack, and if so it checks for a 2s grace
period `(-> *TARGET-bank* same-attack-invulnerable-timeout)` before the
attack will actually count:
https://github.com/open-goal/jak-project/blob/7320bfc068acfa385f929b176f61caf3b7aabbbe/goal_src/jak3/engine/target/target-util.gc#L1664-L1674
This `same-attack-invulnerable-timeout` check uses `time-elapsed?`,
which under the hood references `(current-time)` AKA `(-> PP clock
frame-counter)`, which makes sense.
However the code that actually stores the `attack-time` uses a different
clock `(-> *display* base-clock frame-counter)`:
https://github.com/open-goal/jak-project/blob/7320bfc068acfa385f929b176f61caf3b7aabbbe/goal_src/jak3/engine/target/target-util.gc#L1765-L1768
So if these two clocks get out of sync - say the `target` process clock
falls behind the `*display*` clock - then we can end up storing an
`attack-time` that's "in the future" from `target`'s perspective,
effectively increasing the `same-attack-invulnerable-timeout`.
This clock drift can happen in real gameplay - Usual today was having it
happen consistently with the route he was attempting for NoOOB. I was
able to reproduce it consistently in OpenGOAL as well:
- get "invuln 2" (i.e. you have `(target-flags disable-attacks)` but not
`(focus-status dead ignore)`)
- restart mission at the top of temple before the glider mission trigger
- immediately go into the trigger and fall off the cliff (during the
black screen)
- you'll get the glider cutscene, but should respawn back at the bottom
of temple
Somewhere in this^ cutscene/blackout, the two clocks drift apart -
presumably `target`'s clock is paused but the other is not. Later in the
speedrun, this causes the extra long invuln timeout bug, which wastes
time while trying to intentionally lower health.
https://www.youtube.com/watch?v=WD2MLj8ccfg
As far as I can tell, any other code interacting with `attack-time` also
uses `(current-time)` or one of the wrapping macros like `set-time!` or
`time-elapsed?`
Very similar to https://github.com/open-goal/jak-project/pull/4068, but
adjusts the scale based on the process clock. I think this approach is a
little bit better since it shouldn't depend on frame timing at all.
There were a few things going on here.
Jak 2's menu wheel is zoomed in at 16:9 but zoomed out at 4:3. However,
the custom aspects use the scaling from the 4:3 mode, this makes sense
as you'd want the zoomed out wheel.
However I noticed HUD elements scaled correctly on PS2 16:9 but not PC
16:9, which was a hint.
The hardcoded values for every individual HUD element for 16:9 and 4:3
are in pixels, normalized across 480 being the stretch of the screen.
To fix the HUD alignment I scaled those offsets, scaling them inside
`set-hud-piece-position` meant both textures and merc models got scaled
at the same time.
Note that you can get (very tiny) snapping into different integer values
as you scale to different aspects. This is simply the result of scaling
integer offsets which is what the game uses.
<img width="1704" height="639" alt="2"
src="https://github.com/user-attachments/assets/81e75f7c-04ba-4c9a-8a50-215d13bd4089"
/>
There are two issues here:
1 is the "punch in" where the logo punches inwards towards the camera on
first appearance, this effect reveals the edges of village1
significantly and happens for all users even on regular 16:9.
2 is on aspect ratios wider than 16:9, you see even larger areas of
village1 on either side.
The blackout is an artgroup that breaks apart and is set to the shape of
the Jak 1 logo. It has a baked in animation and is a set size, so it
cannot simply be scaled or adjusted to be wider.
Seeing the sides of village1 before seeing the logo is not the immersive
experience this opening was going for, where the game "bursts" into the
screen.
My first thought to fix was to simply call `set-letterbox-frames` until
the right moment. This worked, however, it didn't produce an ideal
result simply because the letterbox also went on top of the light blue
"logo volumes" starburst.
Having experimented with the range of edits possible here, I decided the
best approach is actually to simply delay displaying village1 ever so
slightly. This avoids editing the very particular blackout art group,
with set sizes of chunks that break apart. This also avoids covering the
blue volumes with a side letterbox/covering.
This scales with any aspect, supports both different language logo
blackout shapes, and fixes both wide aspect issues as well as the
regular 16:9 punch in issue. This is an important edit as it's the first
thing people see.
<video controls
src="https://github.com/user-attachments/assets/9e5bfd39-4189-4c7c-bf76-e7ea0df0464f"></video>
---------
Co-authored-by: Hat Kid <6624576+Hat-Kid@users.noreply.github.com>
Have done some custom ripples so thought I could fix this. At first I
scaled ripple speeds before realizing that wouldn't work if you change
FPS mid-game.
Instead I found the delta increment is there as a variable, and just
scaled that increment directly. I followed the same convention used
everywhere; just multiply by `DISPLAY_FPS_RATIO`.
That was the easy bit, the hard part was a second, unrelated issue,
whether you scale the delta or not, which is on level entry at high fps,
it shows no water movement at all.
I saw the delta was always being created at 0.0 on high FPS, and saw the
delta was computed nowhere in GOAL, only mips2c. I found inspiration
from [this
patch](https://github.com/open-goal/jak-project/blob/5ac5b6aae8f8058e76a27cd14d37db6c0b4d5821/goal_src/jak1/engine/common-obs/ropebridge.gc#L605-L611),
where the time ratio is changed to 60 FPS temporarily. However, fixing
the time ratio still created 0.0 deltas, and no matter what I did, it
always created 0.0 deltas.
I was about to give up, thinking there's no way to scale the mips2c
deltas. However, I found out why it was giving 0.0 deltas, which is on
high FPS, the video-mode is neither `pal` or `ntsc`, but `custom`, and
the misps2c code uses settings for `pal` or `ntsc`.
To include support for high FPS, I temporarily change it to `ntsc`, and
only apply this at the wave table creation when `custom`.
Rename `Language` to `Audio Language` in the menu, and connect it to
`audio-language` instead of `language`.
After this change, we have:
<img width="559" height="322" alt="image"
src="https://github.com/user-attachments/assets/d928a91b-6184-4bde-b147-aa08f22b02d2"
/>
where
- Subtitle Language controls `subtitle-language` on both PC settings and
the normal setting control (unchanged)
- Audio Language controls `audio-language` on setting-control
- Text Language controls `text-language` on PC settings and `language`
on setting control. The game looks at `(-> *setting-control*
user-default language)` to determine text scaling sometimes, so I think
it's good for this to set both.
I realized this `temple-defend-door-4` was getting triggered twice, once
during the temple skip % warp, then again when entering palace ruins %
warp (because it's un-closed by a restart mission, since the overall
`temple-defend` task isn't closed). `temple-defend-introduction` remains
closed after the restart mission, so works better here.
Fix Generic2 bug where a tricky way to disable z-buffer writing wasn't
being detected. This should fix some lightning or other effects:
<img width="968" height="982" alt="image"
src="https://github.com/user-attachments/assets/cf3225c1-9ea4-45ed-86e3-2ad3b9a6b1ee"
/>
Also fixed an original game issue(?) where a hud box could be used
uninitialized . Sometimes this would end up drawing a really large box
area which would overflow the DMA buffer and cause confusing crashes.
Adds some additional autosplit points that I think will be useful.
Also tweaks the `errol-dead?` condition to update immediately on the
final hit (there's a sec or so of animation before it returns to
`initial-state`, where it was being updated previously)
Corresponding autosplitter updates:
https://github.com/open-goal/speedrunning/pull/27
Listened with RIG 500 headphones:
The farmer:
<img width="1920" height="1080" alt="1"
src="https://github.com/user-attachments/assets/0f399461-653e-412a-8e33-6a33e7f59277"
/>
I really could not hear that "spitting", percussive sound of the "p" for
"pack". I think it's unlikely the line is "pack" or "packed into the
pen".
The strong, healthy bass of "b" is more likely. Furthermore, he points
visually over his shoulder in the same moment, physically referring to
his own "back" as if referencing the past or a previous state.
The geologist:
<img width="1920" height="1080" alt="2"
src="https://github.com/user-attachments/assets/7ff7f4c3-2ded-41c1-84c7-1f6b44c5b081"
/>
"Lighting" to "lightning" would match consistency to the other
references to lightning moles. Listening to the sound, you can hear the
distinctly "nasally" sound of the "n" connecting the "light" and "ing".
This fixes the metal head tower resolution cutscene having an awkward
amount of blackout at the start unless the framerate dipped to at least
(most?) 33FPS, since its frame num starts in the negative. There may be
other cutscenes that start at negative or higher than zero, but I don't
know of any (did not check thoroughly as that's boring as hell).
I don't really understand what the purpose of this check is in the first
place to be honest.
Fixes for:
- `prebot` sword attack and projectile speed (fixes#4050)
- Fast first person camera turning speed (fixes#4051)
- Slow turret camera turning speed (fixes#4052)
- `flyingsaw` movement and rotation speed (fixes#4053)
- Green eco drain rate on jetboard during `forest-kill-plants` mission
(fixes#4054)
- `skeet` rotation speed
- `maker-grenade` tumble speed
- Jetboard spin speed
- `hud-skill` rotation speed (also for jak2)
- `gun-dark-shot` projectile speed (also for jak2)
- `target-float` up/down speed (also for jak2)
- Texscroll speed
- Slow walk anim after landing from a jump
The dust storm will now always behave as if it was at 60 FPS. Particles
only spawn every 1/60th of a second and the push vector is converted as
if it was originally equivalent to 1/60th of a second.
All stereo VAG commands would write to an out-of-bounds array element
and corrupt the whole VAG queue list.
Fixes random sound-related crashes including a consistent Light Jak
Freeze crash.
Fix textures on the bomb (just a simple typo fix):
<img width="1638" height="1067" alt="2025-10-05_18-22"
src="https://github.com/user-attachments/assets/d31fedd4-b4f3-4e65-8457-a67068b137be"
/>
Fix issue with ocean culling when in the war factory. In this level, the
make the background rotate by defining a different camera matrix. We
need to use that matrix when culling the ocean, since it rotates too.
This is different on PC because the original game stashed the camera
frustum planes in some vf registers for background drawing.
<img width="1638" height="671" alt="image"
src="https://github.com/user-attachments/assets/feb5f931-e71f-411e-8a29-e8d970f70078"
/>
Fixes#4023
This fixes a duplicated entry in the Jak 2 keybind details page where
"Right Analog Stick Left" appears twice.
File: goal_src/jak2/pc/progress/progress-static-pc.gc
Change: corrected the :entries list to include r-analog-right once
and removed the duplicate r-analog-left, resulting in the 8 expected
analog directions (L and R sticks).
Repro: Options → Input → Reassign Binds → Keyboard (Jak 2)
Before: Right stick shows duplicate "Left"
After: Right stick shows Left/Right correctly
Fixes#3997: The script for the orb that is spawned when getting a medal
in the satellite game was using the wrong entity name.
Fixes#3998: The `spider-manager` process was invalid for one frame,
causing the score to be set to the value of `#f`, winning the game
instantly.
Also doubled the PC port texture count, which should hopefully fix the
crash that happens when playing the game all the way through to the end
of the Destroy Dark Eco Tanks mission in one sitting.
Resolves#3075
TODO before merge:
- [x] Properly draw non-korean strings while in korean mode (language
selection)
- [x] Check jak 3
- [x] Translation scaffolding (allow korean characters, add to Crowdin,
fix japanese locale, etc)
- [x] Check translation of text lines
- [x] Check translation of subtitle lines
- [x] Cleanup PR / some performance optimization (it's take a bit too
long to build the text and it shouldn't since the information is in a
giant lookup table)
- [x] Wait until release is cut
I confirmed the font textures are identical between Jak 2 and Jak 3, so
thank god for that.
Some examples of converting the korean encoding to utf-8. These show off
all scenarios, pure korean / korean with ascii and japanese / korean
with replacements (flags):
<img width="316" height="611" alt="Screenshot 2025-07-26 191511"
src="https://github.com/user-attachments/assets/614383ba-8049-4bf4-937e-24ad3e605d41"
/>
<img width="254" height="220" alt="Screenshot 2025-07-26 191529"
src="https://github.com/user-attachments/assets/1f6e5a6c-8527-4f98-a988-925ec66e437d"
/>
And it working in game. `Input Options` is a custom not-yet-translated
string. It now shows up properly instead of a disgusting block of
glyphs, and all the original strings are hopefully the same
semantically!:
<img width="550" height="493" alt="Screenshot 2025-07-26 202838"
src="https://github.com/user-attachments/assets/9ebdf6c0-f5a3-4a30-84a1-e5840809a1a2"
/>
Quite the challenge. The crux of the problem is -- Naughty Dog came up
with their own encoding for representing korean syllable blocks, and
that source information is lost so it has to be reverse engineered.
Instead of trying to figure out their encoding from the text -- I went
at it from the angle of just "how do i draw every single korean
character using their glyph set".
One might think this is way too time consuming but it's important to
remember:
- Korean letters are designed to be composable from a relatively small
number of glyphs (more on this later)
- Someone at naughty dog did basically this exact process
- There is no other way! While there are loose patterns, there isn't an
overarching rhyme or reason, they just picked the right glyph for the
writing context (more on this later). And there are even situations
where there IS NO good looking glyph, or the one ND chose looks awful
and unreadable (we could technically fix this by adjusting the
positioning of the glyphs but....no more)!
Information on their encoding that gets passed to `convert-korean-text`:
- It's a raw stream of bytes
- It can contain normal font letters
- Every syllable block begins with: `0x04 <num_glyphs> <...the glyph
bytes...>`
- DO NOT confuse `num_glyphs` with num jamo, because some glyphs can
have multiple jamo!
- Every section of normal text starts with `0x03`. For example a space
would be `0x03 0x20`
- There are a very select few number of jamo glyphs on a secondary
texture page, these glyph bytes are preceeded with a `0x05`. These jamo
are a variant of some of the final vowels, moving them as low down as
possible.
Crash course on korean writing:
- Nice resource as this is basically what we are doing -
https://glyphsapp.com/learn/creating-a-hangeul-font
- Korean syllable blocks have either 2 or 3 jamo. Jamo are basically
letters and are the individual pieces that make up the syllable blocks.
- The jamo are split up into "initial", "medial" and "final" categories.
Within the "medial" category there are obvious visual variants:
- Horizontal
- Vertical
- Combination (horizontal + a vertical)
- These jamo are laid out in 6 main pre-defined "orientations":
- initial + vertical medial
- initial + horizontal medial
- initial + combination
- initial + vertical medial + final
- initial + horizontal medial + final
- initial + combination + final
- Sometimes, for stylistic reasons, jamo will be written in different
ways (ie. if there is nothing below a vertical vowel will be extended).
- Annoying, and ND's glyph set supports this stylistic choice!
- There are some combination of jamo that are never used, and some that
are only used for a single word in the entire language!
With all that in mind, my basic process was:
- Scan the game's entire corpus of korean text, that includes subtitles.
It's very easy to look at the font texture's glyphs and assign them to
their respective jamo
- This let me construct a mapping and see which glyphs were used under
which context
- I then shoved this information into a 2-D matrix in excel, and created
an in-game tool to check every single jamo permutation to fill in the
gaps / change them if naughty dogs was bad. Most of the time, ND's
encoding was fine.
-
https://docs.google.com/spreadsheets/d/e/2PACX-1vTtyMeb5-mL5rXseS9YllVj32BGCISOGZFic6nkRV5Er5aLZ9CLq1Hj_rTY7pRCn-wrQDH1rvTqUHwB/pubhtml?gid=886895534&single=true
anything in red is an addition / modification on my part.
- This was the most lengthy part but not as long as you may think, you
can do a lot of pruning. For example if you are checking a 3-jamo
variant (the ones with the most permutations) and you've verified that
the medial jamo is as far up vertically as it can be, and you are using
the lowest final jamo that are available -- there is nothing to check or
improve -- for better or worse! So those end up being the permutations
between the initial and medial instead of a three-way permutation
nightmare.
- Also, while it is a 2d matrix, there's a lot of pruning even within
that. For example, for the first 3 orientations, you dont have to care
about final vowels at all.
- At the end, I'm left with a lookup table that I can use the encode the
best looking korean syllable blocks possible given the context of the
jamo combination.
Similar issue to the orbs-per-level counts, while loading a save (in
blackout) these values are reset to 0 briefly. This can cause extra
autosplits (see https://github.com/open-goal/speedrunning/pull/25)
The main bug this fixes is not being able to use level select when your
language isn't translated. Why? Because they use the result from
`lookup-text!` to determine if a menu item should be drawn or not. No
text found, no menu item.
However this uncovered a long-standing bug in my fallback extension to
this code. If you call this function with a text-id that doesnt even
have an english string, it will recursively keep calling itself until it
crashes. Of course the first few tasks in the game are dummies and have
no valid text-id so this had to be fixed.
Should be fixed for all 3 games.
Fixes a small bug introduced in #3902.
Without this change, whenever you load a save it is treated as if you
started a new game and resets the autosplitter back to 0s.
Two changes that fix some Jak 3 audio bugs.
In some areas, sound effects would seem to cut off randomly. This was
caused by the sound code reusing IDs, but overlord didn't realize. It
would try to kill a sound effect by ID that had already died, and the ID
was reassigned to a new sound. To fix this, I made the handle IDs always
increment. I also tested starting the ID at large numbers and confirmed
that worked.
I also added support for the BRANCH grain. This makes the
`wastelander-shot` and possibly other sound effects work. It doesn't
support all the features, but this is probably enough.
Fun fact: the wastelander shot is supposed to have 7 variations, but you
always get the same one because they set the sound mask wrong.
I added a line you can uncomment if you want to experience the other 6
variations.
---------
Co-authored-by: water111 <awaterford1111445@gmail.com>
There's a suspicion that MSAA might be what causes the black screen
problem for some users, additionally this can cause perf issues for
people with really bad PCs so this is probably a better default.
Needs testing before merging, i think this is all inclusive though.
This needs a parameter, otherwise it was reading some uninitialized
value. In some cases, the uninitialized value would leave the nav stuff
on, and the marauders would go crazy trying to avoid each other.