Currently only tracks enemy kills, and how they were killed. There is
currently no menu for this, but I've already added most of the text for
it. Also did a bunch of misc decompilation fixes and renamed some
methods.
Fixes#3277Fixes#3278
Major change to how `deftype` shows up in our code:
- the decompiler will no longer emit the `offset-assert`,
`method-count-assert`, `size-assert` and `flag-assert` parameters. There
are extremely few cases where having this in the decompiled code is
helpful, as the types there come from `all-types` which already has
those parameters. This also doesn't break type consistency because:
- the asserts aren't compared.
- the first step of the test uses `all-types`, which has the asserts,
which will throw an error if they're bad.
- the decompiler won't emit the `heap-base` parameter unless necessary
now.
- the decompiler will try its hardest to turn a fixed-offset field into
an `overlay-at` field. It falls back to the old offset if all else
fails.
- `overlay-at` now supports field "dereferencing" to specify the offset
that's within a field that's a structure, e.g.:
```lisp
(deftype foobar (structure)
((vec vector :inline)
(flags int32 :overlay-at (-> vec w))
)
)
```
in this structure, the offset of `flags` will be 12 because that is the
final offset of `vec`'s `w` field within this structure.
- **removed ID from all method declarations.** IDs are only ever
automatically assigned now. Fixes#3068.
- added an `:overlay` parameter to method declarations, in order to
declare a new method that goes on top of a previously-defined method.
Syntax is `:overlay <method-name>`. Please do not ever use this.
- added `state-methods` list parameter. This lets you quickly specify a
list of states to be put in the method table. Same syntax as the
`states` list parameter. The decompiler will try to put as many states
in this as it can without messing with the method ID order.
Also changes `defmethod` to make the first type definition (before the
arguments) optional. The type can now be inferred from the first
argument. Fixes#3093.
---------
Co-authored-by: Hat Kid <6624576+Hat-Kid@users.noreply.github.com>
This renames the method object in `defmethod`s to `this` and adds
detection for the `set-time!` and `time-elapsed?` macros.
Definitely my biggest PR yet...
- state handlers that are not inlined lambdas have smarter type
checking, getting rid of 99.9% of the casts emitted (they were not
useful)
- art groups were not being properly linked to their "master" groups.
- `max` in `ja` in Jak 2 was not being detected.
Another huge PR...
Previously, `object` and `none` were both top-level types. This made
decompilation rather messy as they have no LCA and resulted in a lot of
variables coming out as type `none` which is very very wrong and
additionally there were plenty of casts to `object`. This changes it so
`none` becomes a child of `object` (it is still represented by
`NullType` which remains unusable in compilation).
This change makes `object` the sole top-level type, and the type that
can represent *any* GOAL object. I believe this matches the original
GOAL built-in type structure. A function that has a return type of
`object` can now return an integer or a `none` at the same time.
However, keep in mind that the return value of `(none)` is still
undefined, just as before. This also makes a cast to `object`
meaningless in 90% of the situations it showed up in (as every single
thing is already an `object`) and the decompiler will no longer emit
them. Casts to `none` are also reduced. Yay!
Additionally, state handlers also don't get the final `(none)` printed
out anymore. The return type of a state handler is completely
meaningless outside the event handler (which is return type `object`
anyway) so there are no limitations on what the last form needs to be. I
did this instead of making them return `object` to trick the decompiler
into not trying to output a variable to be used as a return value
(internally, in the decompiler they still have return type `none`, but
they have `object` elsewhere).
Fixes#1703Fixes#830Fixes#928
This PR adds detection of the `launch-particles` and `seconds-per-frame`
macros to the decompiler, removing a lot of bloat and hiding many
process register uses.
I also added `og:preserve-this` comments to as many manual patches and
comments as I could, which will soon be used in conjunction with CI to
hopefully catch any regressions in future big decomp update PRs.
I have some concerns about the `launch-particles` macro (more details in
`sparticle-launcher.gc`) , but thus far, I have not seen anything break
yet.
---------
Co-authored-by: water <awaterford111445@gmail.com>
Fixes empty boxed arrays of strings breaking some decomp
(`ctywide-speech` and `race-info`).
Adds `decomp-as` tag to decompiler types so that the static data
decompiler can use macros like `meters` and `seconds` on fields that
aren't of type `meters` or `time-frame`.
Adds `override` tag to decompiler types which overrides the type of
field with that name. The type must be a child type of the original
field's type (or the same type, but why would you do this?).
Fixes the camera being offset for `drillmtn` after loading `palout`
once.
This is a huge refactor sadly.
Adds support for adding custom subtitles to Jak 2 audio. Comes with a
new editor for the new system and format. Compared to the Jak 1 system,
this is much simpler to make an editor for.
Comes with a few subtitles already made as an example.
Cutscenes are not officially supported but you can technically subtitle
those with editor, so please don't right now.
This new system supports multiple subtitles playing at once (even from a
single source!) and will smartly push the subtitles up if there's a
message already playing:


Unlike in Jak 1, it will not hide the bottom HUD when subtitles are
active:

Sadly this leaves us with not much space for the subtitle region (and
the subtitles are shrunk when the minimap is enabled) but when you have
guards and citizens talking all the time, hiding the HUD every time
anyone spoke would get really frustrating.
The subtitle speaker is also color-coded now, because I thought that
would be fun to do.
TODO:
- [x] proper cutscene support.
- [x] merge mode for cutscenes so we don't have to rewrite the script?
---------
Co-authored-by: Hat Kid <6624576+Hat-Kid@users.noreply.github.com>
Gives proper names to almost every color. It is very apparent that some
colors are context-sensitive/made for a specific purpose, so those
colors were named after that purpose instead of a generic color name.
Fixes citizens that disappear (permanently) when being pushed into a
"wall" which is the border of a nav mesh that is exactly aligned with
coordinate axes.
This bug feels very similar to punch glitch, where code worked on PS2
only because some value didn't reach exactly 1.0 or 0.0 with ps2-style
floating rounding. It might be better to track down the source of the
"only 1.0 on PC" value, rather than patching downstream code to handle
it, but I can't easily find it in this case - there's a lot of code that
touches this heading value. (it's also possible this bug happens on ps2,
but the result is the guard appears to face the wrong direction, rather
than disappearing).
Detailed debug notes:
Ran a process that just calls this function:
```
(defun print-guard-info ()
(let ((proc (process-by-name "crimson-guard-level-42" *active-pool*)))
(when proc
(format *stdcon* "PROC: ~A~%" (-> proc state))
(let* ((pd (the process-drawable proc))
(css (-> pd node-list))
(cs (-> css data 15))
)
(format *stdcon* "joint: ~A~%" (-> cs joint))
(format *stdcon* "pos: ~`vector`P~%" (-> cs bone position))
)
)
)
)
```
it prints out the state, and the bone position for some bone that
happens to be on the upper body. It goes to NaN when the upper half
disappears, in the state `tazer-hostile`.
Modified the code in this state to call this function in a bunch of
places:
```
(defun guard-nan-debug ((guard process-drawable) (info string))
(when (string= (-> guard name) "crimson-guard-level-42")
(format 0 "[guard-nan] ~S : ~`vector`P~%" info (-> guard node-list data 15 bone position))
)
)
```
which prints the bone position to stdout.
This shows that the problem happens after `post`, but before `trans`:
```
[guard-nan] post-end : #<vector 2723306.0000 269921.0312 388825.2187 1.0000 @ #x1f1350>
[guard-nan] trans-start : #<vector NaN NaN NaN NaN @ #x1f1350>
```
this is probably as part of the bone math.
To check, I added some prints to `execute-math-engine`, before and after
the call to `do-joint-math`:
```
[guard-nan-math] pre-math : #<vector 2722236.5000 268609.5312 385339.9062 1.0000 @ #x1f1350>
[guard-nan-math] post-math : #<vector NaN NaN NaN NaN @ #x1f1350>
```
The first part of `do-joint-math` is calling the
`generate-frame-function`, which does animation blending to compute a
bunch of joint transforms. I dumped these:
```
(let ((jaf (the-as joint-anim-frame (+ 2400 (scratchpad-object int)))))
(format 0 "generate frame:~%")
(format 0 "~`matrix`I~%" (-> jaf matrices 0))
(format 0 "~`matrix`I~%" (-> jaf matrices 1))
(dotimes (i (-> obj mgeo num-joints))
(format 0 "~`transformq`P~%" (-> jaf data i))
)
)
```
and confirmed that they always look good.
The next part is "prebind", which allows something to modify the
`joint-anim-frame`. Nothing does this on the guard.
The next part is what I've named the "root bind", which computes the
transform of the root bone based on the process-drawable root's
position.
```
(when (the-as (function cspace transformq none) t9-3)
(when *djm-debug* (format 0 "djm: first bind func ptrs #x~X #x~X~%" cspace<-transformq! t9-3))
(when *djm-debug* (format 0 "djm: first bind func input: ~`transformq`P~%" (-> v1-20 param1)))
((the-as (function object object object none) t9-3) v1-20 (-> v1-20 param1) (-> v1-20 param2))
(when *djm-debug* (format 0 "djm: first bind func result:~%~`matrix`I~%" (-> v1-20 bone transform)))
)
```
in this case, the first print confirms that we're using
`cspace<-transformq!` as the root binding function.
When the guard entirely disappears, it is caused by the root of the
process drawable having NaNs as its `quat`:
```
djm: first bind func input: #<transformq @ #x1f04f0
trans:2724817.7500 262144.0000 388891.1875 1.0000
quat: NaN NaN NaN NaN
scale: 1.0000 1.0000 1.0000 1.0000>
djm: first bind func result:
[001f0e70] matrix
[ NaN] [ NaN] [ NaN] [ NaN]
[ NaN] [ NaN] [ NaN] [ NaN]
[ NaN] [ NaN] [ NaN] [ NaN]
[2724817.7500] [ 262144.0000] [ 388891.1875] [ 1.0000]
```
After this, it's possible to get the lower half of the guard to return,
but I believe the real problem is this first `quat` being NaN. Then the
nans probably spread everywhere.
So now we now to look for the `(-> guard root quat)` becoming NaN:
```
(defun guard-nan-debug ((guard process-drawable) (info string))
(when (string= (-> guard name) "crimson-guard-level-42")
(format 0 "[guard-nan] ~S : ~`vector`P~%" info (-> guard root quat))
)
)
```
and we see this happens in post somewhere
```
[guard-nan] post-start : #<vector 0.0000 -1.0000 0.0000 0.0000 @ #x1f0500>
[guard-nan] post-end : #<vector NaN NaN NaN NaN @ #x1f0500>
```
Looking at individual methods
```
[guard-nan] before-142 : #<vector 0.0000 -1.0000 0.0000 0.0000 @ #x1f0500>
heading: #<vector 0.0000 0.0000 -1.0000 0.0000 @ #x3432670>
[guard-nan] before-143 : #<vector NaN NaN NaN NaN @ #x1f0500>
heading: #<vector 0.0000 0.0000 -1.0000 0.0000 @ #x3432670>
```
It looks like the problem is converting this heading to a quaternion.
There are *a lot* of file changes and while I have carefully gone
through every gsrc change to fix up manual patches, there might still be
spots that I missed.
Some more progress on vehicle code, the following files still remain:
- vehicle-guard (annoying stack types)
- traffic-engine (many issues, some which already have issues made for
them, other entirely new confusing things!)
- started documenting the files I glossed over, some are totally done,
others are just partially done
- I changed the decompiler to automatically initialize the
art-group-info from the json file. This makes updating gsrc, even a
single file at a time, have consistent naming
- Though I disabled this functionality for jak 1, as I have no idea if
using the ntsc art groups will cause a regression for different versions
- fix indentation for docstrings -- it still doesn't look great, but
this is now a formatting concern, rather than the docstring having a
bunch of happen-stance leading whitespace.
Adds the following files:
- `amphibian`
- `centurion`
- `ginsu`
- `grenadier`
- `hopper`
- `metalmonk`
- `monster-frog`
- `predator-graph`
- `predator-h`
- `predator`
- `rapid-gunner`
- `rhino`
- `rhino-wall`
- `tomb-baby-spider`
Also adds the DGOs for the following levels:
- Mar's Tomb
- Mountain Temple
- Drill Platform
- Sacred Site (Sage Hut)
Manual patches:
- The decompiler emits `(b! #t cfg-17)` in `(trans hostile hopper)`
without putting a `(label cfg-17)` anywhere
- Added cast to `art-joint-anim` in `(code broken rhino-wall)` and
`(code hit rhino-wall)`
Other notes:
- `amphibian` seems to occasionally crash when using its tongue attack.
Haven't investigated this yet
- `ginsu` crashes after being killed somewhere in the `deactivate`
method, possibly because of its `part-spawner`
- Predators aren't spawning in the forest hunt mission, not sure if
`forest-obs` might be needed for that or if it's something else
- The `rhino-wall` STR animation seems to load (albeit a bit broken due
to missing VAG stream playback), but causes the viewport to shrink as
soon as it's played
- I added `pegasus::74` to the `event_handler_hack` bool in
`variable_naming.cpp` because I got a `none` cast after changing the
return value of `enemy::74`
Couldn't finish any of the enemy/nav-enemy related files for one reason
or another, but quite a bit of work that will be easier to merge and
iterate on instead of keeping track of the branch.
enemy/idle-control has some very weird focus related code.
nav-mesh/nav-control still has a bunch of CFG resolution problems that
need to be manually resolved.
Co-authored-by: water <awaterford111445@gmail.com>
A few issues:
- lwidea's fr3 is getting loaded and unloaded all the time
- the debug line drawing clipping is wrong (doesn't seem wrong in pcsx2,
so I think this is on us)
- nothing actually using vis data yet
- at a large distance, our view frustum culling seems slightly too
aggressive (might be that viewport scissoring is wrong)
- in the city, things seem darker as you move away. unclear how this is
happening (fog?)
* wip
* getting stuff set up so we can actually run test cases
* better handle block entry stuff
* types2 working on gstring
* comments
* math ref working
* up to first stack stuff
* stack fixes
* bounding box
* math stuff is working
* float fixes
* temp debug for (method 9 profile-array)
* stupid stupid bug
* debugging
* everything is broken
* some amount of type stuff works
* bitfield
* texture bitfields not working
* temp
* types
* more stuff
* type check
* temp
* float related fixes for light and res problems
* revisit broken files, fix bugs
* more types
* vector debug
* bug fixes for decompiler crashes in harder functions
* update goal_src