Skip to content

Commit

Permalink
Wind Waker: Link now appears in cutscenes (Neat!!) (#732)
Browse files Browse the repository at this point in the history
* Created empty d_a_py_lk actor

* Load d_a_py_lk on demo start (most of them expect it to be loaded))

* Basic body rendering

* Eyes now render in front of hair, but with correct scene depth

This is based off of the logic from Jasper's E4_WWZAT_b2 branch. Currently, we must manually set the translucency to false for the first eye alpha mask. When it's true (as it is in the BMD) noclip will always render it after the rest of the opaque body. I suspect something is not quite lining up with the game regarding how we're handling translucency sorting...

* Link uses custom setDemoData function

Basic translation and rotation is working

* JStudio: Add JSGDebugGetAnimationName and hook it up to d_a_py_lk

For easier debugging of which animations get played during demos

* Basic link animation support

- The animation data table is extracted from the original object file
- This maps animation IDs to a BCK/BTP IDs

* Link responds to animation mode 512 in demos

This covers most cases where Link is standing still and playing a simple animation. For instance, sleeping, scratching his head, etc.

* Add basic texture animation support

Link now has facial animations in the Awaken demo

* Fix Link's eyes rendering in front of everything

A leftover debug typo

* Set Link's clothes using the demo actor ShapeID

* Link can wear casual clothes!

The cutscene is able to set this by using ShapeID

* Fix links eye masking textures not animating

The eyes would animate, but the masks would not, clipping some of the eyebrows in some cases (and removing the alpha blending)

* Snap link to the ground

* Load the Link arcs and create his actor when creating a demo scene

Almost all the demos expect the actor to be available

* Update LinkDemoMode enum with better values

* Root motion from translations is now applied to position

* Link's root position moves when an anim moves his feet. He can walk!

* Adjust movement speed based on ground angle

* Reorder logic in execute() to match the game. Fix initial state of posMoveFromFootPos()

* Fix up ground clamping behavior

Link now snaps to the ground when walking/dashing. When in the tool demo mode (position data coming straight from the STB file), ground snapping is handled as expected based on the animation mode.

* Add "Stolen Sister" to list of available demo scenes

* Cleanup

* Remove unused enum values so they don't add a billion lines

* Use proper parameters for default Link wait animation

* Fix up Title Screen to use Link's casual clothes

* Fix first rendered frame of a new tool animation using the old anim.

The model Ank1 wasn't being set until animBck.entry() was called in Draw. It needs to happen before model.calc() is called.

* Link handles btk (uv) demo animations. His pupils now contract when surpised.

* Link can equip his sword. Equips based on demo events.

* Spawn link at the origin, rather than an arbitrary position

* Fix typo 'gdnChk`

* Add small todo

* Update comments around eye translucency settings

* Use modeProcInit/modeProcExec() helpers

* Warn on unsupported demo modes (only once)

* Move Link arc loading to the d_a_py_lk actor

* Use `Math.hypot()`

* Use `frameCtrl.SetFrame/GetFrame()`

* Use LinkDemoMode enum instead of int

* Fix velocity y/z swap

* Use const enum if not using enum stringification

* Start an LkJoint enum for commonly accessed joints

* Use `===` and `!==` in the Link and Aryll actors

---------

Co-authored-by: Jasper St. Pierre <[email protected]>
  • Loading branch information
themikelester and magcius authored Dec 7, 2024
1 parent d7f7518 commit 5138e69
Show file tree
Hide file tree
Showing 5 changed files with 726 additions and 16 deletions.
8 changes: 7 additions & 1 deletion src/Common/JSYSTEM/JStudio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,8 @@ export abstract class TActor extends JStage.TObject {
public JSGGetTextureAnimationFrame(): number { return 0.0; }
public JSGSetTextureAnimationFrame(x: number): void { }
public JSGGetTextureAnimationFrameMax(): number { return 0.0; }

public JSGDebugGetAnimationName(x: number): string | null { return null; }
}

class TActorAdaptor extends TAdaptor {
Expand Down Expand Up @@ -699,7 +701,11 @@ class TActorAdaptor extends TAdaptor {

public adaptor_do_ANIMATION(data: ParagraphData): void {
assert(data.dataOp === EDataOp.ObjectIdx);
this.log(`SetAnimation: ${(data.value) & 0xFFFF} (${(data.value) >> 4 & 0x01})`);
const animName = this.object.JSGDebugGetAnimationName(data.value);
if( animName )
this.log(`SetAnimation: ${animName}`);
else
this.log(`SetAnimation: ${(data.value) & 0xFFFF} (${(data.value) >> 4 & 0x01})`);
this.object.JSGSetAnimation(data.value);
}

Expand Down
19 changes: 12 additions & 7 deletions src/ZeldaWindWaker/Main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import { LegacyActor__RegisterFallbackConstructor } from './LegacyActor.js';
import { dDlst_2DStatic_c, d_a__RegisterConstructors } from './d_a.js';
import { d_a_sea } from './d_a_sea.js';
import { dBgS } from './d_bg.js';
import { EDemoCamFlags, EDemoMode, dDemo_manager_c } from './d_demo.js';
import { dDlst_list_Set, dDlst_list_c } from './d_drawlist.js';
import { dKankyo_create, dKy__RegisterConstructors, dKy_setLight, dScnKy_env_light_c } from './d_kankyo.js';
import { dKyw__RegisterConstructors } from './d_kankyo_wether.js';
Expand All @@ -40,8 +39,9 @@ import { dProcName_e } from './d_procname.js';
import { ResType, dRes_control_c } from './d_resorce.js';
import { dStage_dt_c_roomLoader, dStage_dt_c_roomReLoader, dStage_dt_c_stageInitLoader, dStage_dt_c_stageLoader, dStage_roomControl_c, dStage_roomStatus_c, dStage_stageDt_c } from './d_stage.js';
import { WoodPacket } from './d_wood.js';
import { fopAcM_create, fopAc_ac_c } from './f_op_actor.js';
import { fopAcM_create, fopAcM_searchFromName, fopAc_ac_c } from './f_op_actor.js';
import { cPhs__Status, fGlobals, fopDw_Draw, fopScn, fpcCt_Handler, fpcLy_SetCurrentLayer, fpcM_Management, fpcPf__Register, fpcSCtRq_Request, fpc_pc__ProfileList } from './framework.js';
import { dDemo_manager_c, EDemoCamFlags, EDemoMode } from './d_demo.js';

type SymbolData = { Filename: string, SymbolName: string, Data: ArrayBufferSlice };
type SymbolMapData = { SymbolData: SymbolData[] };
Expand Down Expand Up @@ -858,7 +858,7 @@ class SceneDesc {
modelCache.fetchObjectData(`Always`);
modelCache.fetchStageData(`Stage`);

modelCache.fetchFileData(`extra.crg1_arc`, 9);
modelCache.fetchFileData(`extra.crg1_arc`, 10);
modelCache.fetchFileData(`f_pc_profiles.crg1_arc`);

const particleArchives = [
Expand Down Expand Up @@ -999,7 +999,7 @@ class DemoDesc extends SceneDesc implements Viewer.SceneDesc {
globals.scnPlay.demo.remove();

// TODO: Don't render until the camera has been placed for this demo. The cuts are jarring.

// noclip modification: This normally happens on room load. Do it here instead so that we don't waste time
// loading .arcs for cutscenes that aren't going to be played
const lbnk = globals.roomCtrl.status[this.roomList[0]].data.lbnk;
Expand All @@ -1014,11 +1014,16 @@ class DemoDesc extends SceneDesc implements Viewer.SceneDesc {
// @TODO: Better error handling. This does not prevent a debugger break.
console.log(`Failed to load stage demo file: ${globals.roomCtrl.demoArcName}`, e);
})

await globals.modelCache.waitForLoad();
}
}

await globals.modelCache.waitForLoad();

// Most cutscenes expect the Link actor to be loaded
if(!fopAcM_searchFromName(globals, 'Link', 0, 0)) {
fopAcM_create(globals.frameworkGlobals, dProcName_e.d_a_py_lk, 0, null, globals.mStayNo, null, null, 0xFF, -1);
}

// noclip modification: ensure all the actors are created before we load the cutscene
await new Promise(resolve => { (function waitForActors(){
if (globals.frameworkGlobals.ctQueue.length === 0) return resolve(null);
Expand Down Expand Up @@ -1048,7 +1053,6 @@ class DemoDesc extends SceneDesc implements Viewer.SceneDesc {
// It has been reconstructed by cross-referencing each Room's lbnk section (which points to a Demo*.arc file for each layer),
// the .stb files contained in each of those Objects/Demo*.arc files, and the FileName attribute from the event action.
const demoDescs = [
new DemoDesc("sea", "Stolen Sister", [44], "stolensister.stb", 9, [0.0, 0.0, 20000.0], 0, 0, 0),
new DemoDesc("sea", "Departure", [44], "departure.stb", 10, [-200000.0, 0.0, 320000.0], 0.0, 204, 0),
new DemoDesc("sea", "Pirate Zelda Fly", [44], "kaizoku_zelda_fly.stb", 0, [-200000.0, 0.0, 320000.0], 180.0, 0, 0),
new DemoDesc("sea", "Zola Awakens", [13], "awake_zola.stb", 8, [200000.0, 0.0, -200000.0], 0, 227, 0),
Expand Down Expand Up @@ -1128,6 +1132,7 @@ const sceneDescs = [
"Cutscenes",
new DemoDesc("sea_T", "Title Screen", [44], "title.stb", 0, [-220000.0, 0.0, 320000.0], 180.0, 0, 0),
new DemoDesc("sea", "Awaken", [44], "awake.stb", 0, [-220000.0, 0.0, 320000.0], 0.0, 0, 0),
new DemoDesc("sea", "Stolen Sister", [44], "stolensister.stb", 9, [0.0, 0.0, 20000.0], 0, 0, 0),

"Outset Island",
new SceneDesc("sea_T", "Title Screen", [44]),
Expand Down
Loading

0 comments on commit 5138e69

Please sign in to comment.