diff --git a/configure.py b/configure.py index a520d2cc..9abc5144 100644 --- a/configure.py +++ b/configure.py @@ -573,7 +573,7 @@ def MatchingFor(*versions): Object(Matching, "SB/Core/x/xVolume.cpp"), Object(NonMatching, "SB/Core/x/xParEmitterType.cpp"), Object(Matching, "SB/Core/x/xRenderState.cpp"), - Object(NonMatching, "SB/Game/zEntPlayerOOBState.cpp"), + Object(NonMatching, "SB/Game/zEntPlayerOOBState.cpp", extra_cflags=["-sym on"]), Object(Equivalent, "SB/Core/x/xClumpColl.cpp"), Object(NonMatching, "SB/Core/x/xEntBoulder.cpp"), Object(NonMatching, "SB/Core/x/xGrid.cpp"), diff --git a/src/SB/Core/x/xMath2.h b/src/SB/Core/x/xMath2.h index 33b1d9f1..66ac08ca 100644 --- a/src/SB/Core/x/xMath2.h +++ b/src/SB/Core/x/xMath2.h @@ -55,9 +55,22 @@ struct xVec2 xVec2& assign(F32 x, F32 y); F32 length() const; F32 length2() const; - F32 normal() const; - xVec2& normalize(); - F32 dot(const xVec2&) const; + xVec2 normal() const + { + xVec2 tmp = *this; + return tmp.normalize(); + } + + xVec2& normalize() + { + *this /= length(); + return *this; + } + + F32 dot(const xVec2& b) const + { + return (x * b.x) + (y * b.y); + } xVec2& operator=(F32); xVec2 operator*(F32) const; diff --git a/src/SB/Game/zEntPlayer.h b/src/SB/Game/zEntPlayer.h index 6279145d..ff4df690 100644 --- a/src/SB/Game/zEntPlayer.h +++ b/src/SB/Game/zEntPlayer.h @@ -411,6 +411,7 @@ void zEntPlayer_Init(xEnt* ent, xEntAsset* asset); void zEntPlayerExit(xEnt*); void zEntPlayerPreReset(); void zEntPlayerReset(xEnt* ent); +void zEntPlayerUpdateModel(); void zEntPlayer_LoadSounds(); void zEntPlayer_UnloadSounds(); void zEntPlayer_ShadowModelEnable(); diff --git a/src/SB/Game/zEntPlayerOOBState.cpp b/src/SB/Game/zEntPlayerOOBState.cpp index b3d5360c..25dbc47b 100644 --- a/src/SB/Game/zEntPlayerOOBState.cpp +++ b/src/SB/Game/zEntPlayerOOBState.cpp @@ -3,8 +3,16 @@ #include "xMath.h" #include "xMathInlines.h" +#include "zSurface.h" +#include "zRenderState.h" +#include "zEntPlayerBungeeState.h" +#include "zEntCruiseBubble.h" +#include "zGameState.h" +#include "xScrFx.h" +#include "zSaveLoad.h" #include +#include bool oob_player_teleported; @@ -106,9 +114,64 @@ namespace oob_state zCameraTweakGlobal_Init(); } - static void move_up(xVec3& vec, F32 arg1) + static void render_model(xModelInstance& model, const xVec3& loc, const xVec3& size, + const xVec3& ypr /*Yaw Pitch Roll*/) { - xMat4x3Tolocal(&vec, &globals.camera.mat, &vec); + basic_rect screen_rect = { 0.0f, 0.0f, 1.0f, 1.0f }; + screen_rect.x = loc.x; + screen_rect.y = loc.y; + + xVec3 from = { 0.0f, 0.0f, 1.0f }; + + xVec3 to = { 0.0f, 0.0f, 0.0f }; + to.z = -loc.z; + + xMat3x3 scaledMat; + xMat3x3 eulerMat; + xMat4x3 outMat; + xMat3x3ScaleC(&scaledMat, size.x * (1.0f + loc.z), size.y * (1.0f + loc.z), + 1.0f + loc.z); + xMat3x3Euler(&eulerMat, &ypr); + xMat3x3Mul(&outMat, &eulerMat, &scaledMat); + + outMat.pos = 0.0f; + outMat.flags = 0x0; + xModelSetFrame(&model, &outMat); + + xModelRender2D(model, screen_rect, from, to); + } + + static void move_up(xVec3& vec, F32 scale) + { + xMat4x3& camMat = globals.camera.mat; + + xVec3 localCoords; + xMat4x3Tolocal(&localCoords, &camMat, &vec); + + vec += camMat.up * scale * localCoords.z; + } + + static void move_right(xVec3& vec, F32 scale) + { + xMat4x3& camMat = globals.camera.mat; + + xVec3 localCoords; + xMat4x3Tolocal(&localCoords, &camMat, &vec); + + vec += camMat.right * scale * localCoords.z * (4.0f / 3.0f); + } + + static void update_max_out_time(const xSurface& surface) + { + F32 delay = zSurfaceGetOutOfBoundsDelay(surface); + if (delay < 0.0f) + { + delay = fixed.out_time; + } + + F32 old_max_out_time = shared.max_out_time; + shared.max_out_time = delay; + shared.out_time -= old_max_out_time - delay; } static bool assume_player_is_stupid() @@ -137,114 +200,121 @@ namespace oob_state return stupid; } - static void move_hand(float dt /* r29+0x10 */) + static void move_hand(F32 dt) { + F32 old_vel = shared.vel; + + shared.vel = shared.accel * dt + old_vel; + shared.loc += shared.dir * (0.5f * shared.accel * dt * dt + old_vel * dt); } + static void set_rect_verts(rwGameCube2DVertex*, F32, F32, F32, F32, iColor_tag c, F32 nsz, + F32 rcz); + static void set_rect_vert(rwGameCube2DVertex&, F32 x, F32 y, F32 z, iColor_tag c, F32 rcz); static void render_fade() { + iColor_tag color = {}; + color.a = 255.0f * (1.0f - shared.fade_alpha) + 0.5f; + + zRenderState(SDRS_OOBFade); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, NULL); + F32 nsz = 1.0f / ((RwCamera*)RWSRCGLOBAL(curCamera))->farPlane; + F32 rcz = RwIm2DGetFarScreenZ(); + + RwIm2DVertex vert[4]; + set_rect_verts((rwGameCube2DVertex*)vert, 0.0f, 0.0f, 640.0f, 480.0f, color, rcz, nsz); + RwIm2DRenderPrimitive(rwPRIMTYPETRISTRIP, (RwIm2DVertex*)vert, 4); } - static void set_rect_vert(rwGameCube2DVertex&, F32, F32, F32, iColor_tag, F32) + static void set_rect_verts(rwGameCube2DVertex* verts, F32 x, F32 y, F32 w, F32 h, + iColor_tag c, F32 rcz, F32 nsz) { + set_rect_vert(verts[0], x, y, rcz, c, nsz); + set_rect_vert(verts[1], x, y + h, rcz, c, nsz); + set_rect_vert(verts[2], x + w, y, rcz, c, nsz); + set_rect_vert(verts[3], x + w, y + h, rcz, c, nsz); } - drop_state_type::substate_enum drop_state_type::supdate_fade_in(drop_state_type&, - xScene& scn, F32& unk0) + static void set_rect_vert(rwGameCube2DVertex& vert, F32 x, F32 y, F32 z, iColor_tag c, + F32 rcz) { - return drop_state_type::update_fade_in(); + vert.x = x; + vert.y = y; + vert.z = z; + vert.emissiveColor.red = c.r; + vert.emissiveColor.green = c.g; + vert.emissiveColor.blue = c.b; + vert.emissiveColor.alpha = c.a; } - drop_state_type::substate_enum drop_state_type::update_fade_in(xScene&, float&) + static void render_ghost() { - return SS_MOVING_IN; + xEnt& ent = globals.player.ent; + + iDrawSetFBMSK(-1); + zRenderState(SDRS_OOBPlayerZ); + + xModelInstance* xm = ent.model; + while (xm != NULL) + { + RpAtomic& model = *xm->Data; + + if (xm->Flags & 0x1) + { + iModelRender(&model, xm->Mat); + } + + xm = xm->Next; + } + + iDrawSetFBMSK(0); + zRenderState(SDRS_OOBPlayerAlpha); + xLightKit_Enable(ent.lightKit, globals.currWorld); + + U8 alpha = 255.0f * (1.0f - shared.fade_alpha) + 0.5f; + alpha &= 0xFF; + + xm = ent.model; + while (xm != NULL) + { + RpAtomic& model = *xm->Data; + + if (xm->Flags & 0x1) + { + iModelSetMaterialAlpha(&model, alpha); + iModelRender(&model, xm->Mat); + iModelResetMaterial(&model); + } + + xm = xm->Next; + } + + xLightKit_Enable(NULL, globals.currWorld); } + static void render_hand() + { + zRenderState(SDRS_OOBHand); + + xVec3 modelLoc = { 0.0f, 0.0f, 0.0f }; + xVec3 modelSize = { 0.0f, 0.0f, 1.0f }; + xVec3 modelYpr = { 0.0f, 0.0f, 0.0f }; + + modelLoc.x = shared.loc.x; + modelLoc.y = shared.loc.y; + + modelSize.x = fixed.hand_size_x; + modelSize.y = fixed.hand_size_y; + + modelYpr.x = fixed.hand_yaw; + modelYpr.y = fixed.hand_pitch; + modelYpr.z = fixed.hand_roll; + + render_model(*shared.model, modelLoc, modelSize, modelYpr); + } } // namespace } // namespace oob_state -/* -static class -{ - // total size: 0x70 -public: - signed int flags; // offset 0x0, size 0x4 - class state_type* state; // offset 0x4, size 0x4 - unsigned char control; // offset 0x8, size 0x1 - class state_type* states[4]; // offset 0xC, size 0x10 - float out_time; // offset 0x1C, size 0x4 - float max_out_time; // offset 0x20, size 0x4 - float reset_time; // offset 0x24, size 0x4 - class xModelInstance* model; // offset 0x28, size 0x4 - class xVec2 loc; // offset 0x2C, size 0x8 - class xVec2 dir; // offset 0x34, size 0x8 - float fade_alpha; // offset 0x3C, size 0x4 - unsigned char render_hand; // offset 0x40, size 0x1 - unsigned char vertical; // offset 0x41, size 0x1 - float vel; // offset 0x44, size 0x4 - float accel; // offset 0x48, size 0x4 - class ztalkbox* tutorial; // offset 0x4C, size 0x4 - class - { - // total size: 0x20 - public: - float near_d; // offset 0x0, size 0x4 - float near_h; // offset 0x4, size 0x4 - float near_pitch; // offset 0x8, size 0x4 - float far_d; // offset 0xC, size 0x4 - float far_h; // offset 0x10, size 0x4 - float far_pitch; // offset 0x14, size 0x4 - class xMat4x3* tgt_mat; // offset 0x18, size 0x4 - class xMat4x3* tgt_omat; // offset 0x1C, size 0x4 - } cam_data; // offset 0x50, size 0x20 -} -shared; // size: 0x70, address: 0x4DFA90 -*/ - -/* -static class { - // total size: 0x58 -public: - float bottom_anim_frac; // offset 0x0, size 0x4 - float top_anim_frac; // offset 0x4, size 0x4 - float bottom_anim_time; // offset 0x8, size 0x4 - float top_anim_time; // offset 0xC, size 0x4 - float hit_anim_time; // offset 0x10, size 0x4 - float damage_rot; // offset 0x14, size 0x4 - float death_time; // offset 0x18, size 0x4 - float vel_blur; // offset 0x1C, size 0x4 - float fade_dist; // offset 0x20, size 0x4 - float player_radius; // offset 0x24, size 0x4 - float hook_fade_alpha; // offset 0x28, size 0x4 - float hook_fade_time; // offset 0x2C, size 0x4 - class { - // total size: 0xC - public: - float edge_zone; // offset 0x0, size 0x4 - float sway; // offset 0x4, size 0x4 - float decay; // offset 0x8, size 0x4 - } horizontal; // offset 0x30, size 0xC - class { - // total size: 0x10 - public: - float time; // offset 0x0, size 0x4 - float anim_out_time; // offset 0x4, size 0x4 - float min_dist; // offset 0x8, size 0x4 - float max_dist; // offset 0xC, size 0x4 - } dive; // offset 0x3C, size 0x10 - class { - // total size: 0x4 - public: - float speed; // offset 0x0, size 0x4 - } camera; // offset 0x4C, size 0x4 - class { - // total size: 0x8 - public: - float spring; // offset 0x0, size 0x4 - float decay; // offset 0x4, size 0x4 - } turn; // offset 0x50, size 0x8 -} fixed; // size: 0x58, address: 0x5CDE00 */ - void oob_state::load_settings(xIniFile& ini) { fixed.hand_model = xIniGetString(&ini, "player.state.out_of_bounds.hand_model", "hand"); @@ -295,121 +365,907 @@ void oob_state::load_settings(xIniFile& ini) void oob_state::init() { -} - -#define TODO_FIX_FLOAT 0.000000000000 - -oob_state::grab_state_type::substate_enum oob_state::grab_state_type::update_stopping(xScene& scene, - F32& dt) -{ - move_hand(dt); - - if (shared.vel > TODO_FIX_FLOAT) + if ((shared.flags & 0x1) != 0x1) { - return SS_STOPPING; + return; } - shared.loc = fixed.in_loc; + shared.flags |= 0x2; - shared.vel = TODO_FIX_FLOAT; - shared.accel = TODO_FIX_FLOAT; + static in_state_type in_state; + shared.states[0] = &in_state; + + static out_state_type out_state; + shared.states[1] = &out_state; + + static grab_state_type grab_state; + shared.states[2] = &grab_state; + + static drop_state_type drop_state; + shared.states[3] = &drop_state; - // fade_start_time is probably incorrect, due to commented issue down below with cb. - // It's probably supposed to be the variable above this, 'delay' - fade_start_time = fixed.grab.out_wait_time; + shared.max_out_time = fixed.out_time; + shared.fade_alpha = 1.0f; + shared.render_hand = FALSE; + shared.control = FALSE; - if (assume_player_is_stupid()) + U32 bufsize; + void* info = xSTFindAsset(xStrHash(fixed.hand_model), &bufsize); + + xModelInstance* model; + if (info == NULL) + { + model = NULL; + } + else { - // callback 'cb' should be the correct paramater at 0x8 offset. - // right now it's at 0x4 offset, so this will need to be fixed - shared.tutorial->start_talk(xStrHash("TODO"), (ztalkbox::callback*)&cb, NULL); - return SS_TUTORIAL; + model = xEntLoadModel(NULL, (RpAtomic*)info); } - return SS_STOPPED; + shared.model = model; } -float oob_state::oob_timer() +namespace oob_state { - if (shared.reset_time == fixed.reset_time) + namespace { - return shared.out_time; - } + drop_state_type::drop_state_type() : state_type(STATE_DROP) + { + this->updatess[0] = &supdate_moving_in; + this->updatess[1] = &supdate_stopping; + this->updatess[2] = &supdate_stopped; + this->updatess[3] = &supdate_starting; + this->updatess[4] = &supdate_moving_out; + this->updatess[5] = &supdate_start_fade_in; + this->updatess[6] = &supdate_fade_in; + } - return -1.0f; -} + drop_state_type::substate_enum drop_state_type::supdate_fade_in(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_fade_in(scn, dt); + } -void oob_state::in_state_type::start() -{ - shared.reset_time = FLOAT_MAX; - shared.out_time = FLOAT_MAX; - shared.control = 0; -}; + drop_state_type::substate_enum drop_state_type::update_fade_in(xScene& scn, F32& dt) + { + this->fade_time -= dt; + shared.fade_alpha = 1.0f - this->fade_time / fixed.drop.fade_time; -void oob_state::in_state_type::stop(){ + if (shared.fade_alpha > 1.0f) + { + shared.fade_alpha = 1.0f; + } -}; + if (this->fade_time > 0.0f) + { + return SS_FADE_IN; + } -void oob_state::out_state_type::start() -{ - shared.out_time = shared.max_out_time; - shared.reset_time = fixed.reset_time; -}; + dt += this->fade_time; + return SS_INVALID; + } + + drop_state_type::substate_enum drop_state_type::supdate_start_fade_in(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_start_fade_in(scn, dt); + } + + drop_state_type::substate_enum drop_state_type::update_start_fade_in(xScene& scn, F32& dt) + { + this->fade_start_time -= dt; + + if (this->fade_start_time > 0.0f) + { + return SS_START_FADE_IN; + } -void oob_state::out_state_type::stop(){ + dt += this->fade_start_time; + return SS_FADE_IN; + } -}; + drop_state_type::substate_enum drop_state_type::supdate_moving_out(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_moving_out(scn, dt); + } -void oob_state::state_type::start(){ + drop_state_type::substate_enum drop_state_type::update_moving_out(xScene& scn, F32& dt) + { + move_hand(dt); -}; + F32 projection = (shared.loc - fixed.out_loc).dot(shared.dir); + if (projection >= 0.0f) + { + return SS_MOVING_OUT; + } -void oob_state::state_type::stop(){ + dt = 0.0f; + return SS_INVALID; + } -}; + drop_state_type::substate_enum drop_state_type::supdate_starting(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_starting(scn, dt); + } -bool oob_state::grab_state_type::update_reorient(xScene&, F32&) -{ - return true; -}; + drop_state_type::substate_enum drop_state_type::update_starting(xScene& scn, F32& dt) + { + move_hand(dt); + + if (shared.vel > -fixed.drop.out_vel) + { + return SS_STARTING; + } + + shared.vel = -fixed.drop.out_vel; + shared.accel = 0.0f; + return SS_MOVING_OUT; + } + + drop_state_type::substate_enum drop_state_type::supdate_stopped(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_stopped(scn, dt); + } + + drop_state_type::substate_enum drop_state_type::update_stopped(xScene& scn, F32& dt) + { + this->stop_time -= dt; + + if (this->stop_time > 0.0f) + { + return SS_STOPPED; + } + + dt += this->stop_time; + shared.accel = + (-fixed.drop.out_vel * fixed.drop.out_vel) / (2.0f * fixed.drop.out_start_dist); + return SS_STARTING; + } + + drop_state_type::substate_enum drop_state_type::supdate_stopping(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_stopping(scn, dt); + } + + drop_state_type::substate_enum drop_state_type::update_stopping(xScene& scn, F32& dt) + { + move_hand(dt); + if (shared.vel > 0.0f) + { + return SS_STOPPING; + } + + shared.loc = fixed.in_loc; + shared.vel = 0.0f; + shared.accel = 0.0f; + this->stop_time = fixed.drop.out_wait_time; + + return SS_STOPPED; + } + + drop_state_type::substate_enum drop_state_type::supdate_moving_in(drop_state_type& gst, + xScene& scn, F32& dt) + { + return gst.update_moving_in(scn, dt); + } + + drop_state_type::substate_enum drop_state_type::update_moving_in(xScene& scn, F32& dt) + { + move_hand(dt); + + xVec2 in_out_path = fixed.in_loc - fixed.out_loc; + xVec2 norm = in_out_path.normal(); + + F32 projection = norm.dot(fixed.in_loc - shared.loc); + if (projection > fixed.grab.in_stop_dist) + { + return SS_MOVING_IN; + } + else if (projection <= 0.0f) + { + shared.vel = 0.0f; + shared.loc = fixed.in_loc; + shared.accel = 0.0f; + } + else + { + shared.accel = (-shared.vel * shared.vel) / (2.0f * projection); + } + + return SS_STOPPING; + } + + state_type::state_type(state_enum state) + { + this->type = state; + } + + grab_state_type::grab_state_type() : state_type(STATE_GRAB), cb(*this) + { + this->updatess[0] = &supdate_reorient; + this->updatess[1] = &supdate_begin_wait; + this->updatess[2] = &supdate_moving_in; + this->updatess[3] = &supdate_stopping; + this->updatess[4] = &supdate_stopped; + this->updatess[5] = &supdate_tutorial; + this->updatess[6] = &supdate_starting; + this->updatess[7] = &supdate_moving_out; + this->updatess[8] = &supdate_start_fade_out; + this->updatess[9] = &supdate_fade_out; + } + + grab_state_type::substate_enum grab_state_type::supdate_fade_out(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_fade_out(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_fade_out(xScene& scene, F32& dt) + { + this->fade_time -= dt; + shared.fade_alpha = this->fade_time / fixed.grab.fade_time; + + if (shared.fade_alpha < 0.0f) + { + shared.fade_alpha = 0.0f; + } + + if (this->fade_time > 0.0f) + { + return SS_FADE_OUT; + } + + dt += this->fade_time; + return SS_INVALID; + } + + grab_state_type::substate_enum + grab_state_type::supdate_start_fade_out(grab_state_type& gst, xScene& scene, F32& dt) + { + return gst.update_start_fade_out(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_start_fade_out(xScene& scene, + F32& dt) + { + this->fade_start_time -= dt; + + if (this->fade_start_time > 0.0f) + { + return SS_START_FADE_OUT; + } + + dt += this->fade_start_time; + return SS_FADE_OUT; + } + + grab_state_type::substate_enum grab_state_type::supdate_moving_out(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_moving_out(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_moving_out(xScene& scene, F32& dt) + { + move_hand(dt); + + if ((shared.loc - fixed.out_loc).dot(shared.dir) >= 0.0f) + { + return SS_MOVING_OUT; + } + + dt = 0.0f; + return SS_INVALID; + } + + grab_state_type::substate_enum grab_state_type::supdate_starting(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_starting(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_starting(xScene& scene, F32& dt) + { + move_hand(dt); + + if (shared.vel > -fixed.grab.out_vel) + { + return SS_STARTING; + } + + shared.vel = -fixed.grab.out_vel; + shared.accel = 0.0f; + return SS_MOVING_OUT; + } + + grab_state_type::substate_enum grab_state_type::supdate_tutorial(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_tutorial(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_tutorial(xScene& scene, F32& dt) + { + this->delay -= dt; + if (!this->finished_tutorial || this->delay > 0.0f) + { + return SS_TUTORIAL; + } + + dt = 0.0f; + shared.accel = + (-fixed.grab.out_vel * fixed.grab.out_vel) / (2.0f * fixed.grab.out_start_dist); + return SS_STARTING; + } + + grab_state_type::substate_enum grab_state_type::supdate_stopped(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_stopped(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_stopped(xScene& scene, F32& dt) + { + this->delay -= dt; + + if (this->delay > 0.0f) + { + return SS_STOPPED; + } + + dt += this->delay; + shared.accel = + (-fixed.grab.out_vel * fixed.grab.out_vel) / (2.0f * fixed.grab.out_start_dist); + return SS_STARTING; + } + + grab_state_type::substate_enum grab_state_type::supdate_stopping(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_stopping(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_stopping(xScene& scene, F32& dt) + { + move_hand(dt); + + if (shared.vel > 0.0f) + { + return SS_STOPPING; + } + + shared.loc = fixed.in_loc; + + shared.vel = 0.0f; + shared.accel = 0.0f; + + this->delay = fixed.grab.out_wait_time; + + if (assume_player_is_stupid()) + { + shared.tutorial->start_talk(xStrHash("TODO"), (ztalkbox::callback*)&cb, NULL); + return SS_TUTORIAL; + } + + return SS_STOPPED; + } + + grab_state_type::substate_enum grab_state_type::supdate_moving_in(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_moving_in(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_moving_in(xScene& scene, F32& dt) + { + move_hand(dt); + + xVec2 in_out_path = fixed.in_loc - fixed.out_loc; + xVec2 norm = in_out_path.normal(); + + F32 projection = norm.dot(fixed.in_loc - shared.loc); + if (projection > fixed.grab.in_stop_dist) + { + return SS_MOVING_IN; + } + else if (projection <= 0.0f) + { + shared.vel = 0.0f; + shared.loc = fixed.in_loc; + shared.accel = 0.0f; + } + else + { + shared.accel = (-shared.vel * shared.vel) / (2.0f * projection); + } + + return SS_STOPPING; + } + + grab_state_type::substate_enum grab_state_type::supdate_begin_wait(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_begin_wait(scene, dt); + } + + grab_state_type::substate_enum grab_state_type::update_begin_wait(xScene& scene, F32& dt) + { + this->delay -= dt; + if (this->delay > 0.0f) + { + return SS_BEGIN_WAIT; + } -void oob_state::grab_state_type::stop(){ + shared.render_hand = true; + return SS_MOVING_IN; + } + + grab_state_type::substate_enum grab_state_type::supdate_reorient(grab_state_type& gst, + xScene& scene, F32& dt) + { + return gst.update_reorient(scene, dt); + } + + grab_state_type::substate_enum oob_state::grab_state_type::update_reorient(xScene& scene, + F32& dt) + { + return SS_BEGIN_WAIT; + }; -}; + grab_state_type::tutorial_callback::tutorial_callback(grab_state_type& owner) : owner(owner) + { + } + + out_state_type::out_state_type() : state_type(STATE_OUT) + { + } + + in_state_type::in_state_type() : state_type(STATE_IN) + { + } -void oob_state::grab_state_type::tutorial_callback::on_stop() + void state_type::start() + { + }; + + void state_type::stop() + { + }; + } // namespace +} // namespace oob_state + +U8 oob_state::update(xScene& scene, F32 dt) { - owner.finished_tutorial = true; -}; + if ((shared.flags & 0x3) != 0x3) + { + return FALSE; + } + + if (zSaveLoadGetPreAutoSave()) + { + return FALSE; + } + + if (oob_player_teleported) + { + shared.flags &= ~0x8; + } + + if ((shared.flags & 0x8) && !(globals.player.ControlOff & 0x8000)) + { + force_start(); + } + + while (true) + { + state_enum newtype = shared.state->update(scene, dt); + if (newtype == shared.state->type) + { + break; + } + + shared.state->stop(); + shared.state = shared.states[newtype]; + shared.state->start(); + } + + + return shared.control; +} bool oob_state::IsPlayerInControl() { return oob_state::shared.control == 0; } -WEAK ztalkbox::callback::callback() +F32 oob_state::oob_timer() { + if (shared.reset_time == fixed.reset_time) + { + return shared.out_time; + } + + return -1.0f; } -WEAK void ztalkbox::callback::on_signal(U32) + +bool oob_state::render() { + if ((shared.flags & 0x3) != 3) + { + return false; + } + + if (!shared.control) + { + return false; + } + + xLightKit_Enable(globals.player.ent.lightKit, globals.currWorld); + xEntRender(&globals.player.ent); + xLightKit_Enable(NULL, globals.currWorld); + + return true; } -WEAK void ztalkbox::callback::on_start() + +void oob_state::fx_render() { + if ((shared.flags & 0x3) != 3) + { + return; + } + + if (shared.control && shared.fade_alpha < 1.0f) + { + render_fade(); + render_ghost(); + } + + if (shared.render_hand && shared.model != NULL) + { + render_hand(); + } } -WEAK void ztalkbox::callback::on_stop() + +void oob_state::force_start() { + if ((shared.flags & 0x7) == 0x3 && !bungee_state::active()) + { + if (globals.player.ControlOff & 0x8000) + { + shared.flags |= 0x8; + oob_player_teleported = false; + } + else + { + shared.flags &= ~0x8; + shared.state->stop(); + shared.state = shared.states[2]; + shared.state->start(); + } + } } -WEAK void ztalkbox::callback::on_answer(ztalkbox::answer_enum) + +void oob_state::read_persistent(xSerial& s) { + for (U32 i = 0; i < 6; i++) + { + S32 val; + s.Read_b1(&val); + + idiot_levels[i].triggered = (bool)val; + } } -WEAK F32 xVec2::dot(const xVec2& b) const +void oob_state::write_persistent(xSerial& s) { - return (x * b.x) + (y * b.y); + for (U32 i = 0; i < 6; i++) + { + s.Write_b1((bool)idiot_levels[i].triggered); + } } -WEAK xVec2& xVec2::normalize() +namespace oob_state { - *this /= length(); - return *this; -} + namespace + { + void in_state_type::start() + { + shared.reset_time = 0.0f; + shared.out_time = 0.0f; + shared.control = 0; + }; + + void in_state_type::stop() + { + + }; + + state_enum in_state_type::update(xScene& scene, F32& dt) + { + xSurface* floor_surf = globals.player.floor_surf; + U8 oob = FALSE; + + if (floor_surf != NULL && !(globals.player.ControlOff & 0x8000)) + { + oob = zSurfaceOutOfBounds(*floor_surf); + if (oob) + { + update_max_out_time(*floor_surf); + } + } + + if (!oob) + { + shared.reset_time = 0.0f; + shared.out_time = 0.0f; + shared.control = FALSE; + + return STATE_IN; + } + + return STATE_OUT; + }; + + void out_state_type::start() + { + shared.out_time = shared.max_out_time; + shared.reset_time = fixed.reset_time; + }; + + void out_state_type::stop() { + + }; + + state_enum out_state_type::update(xScene& scene, F32& dt) + { + xSurface* floor_surf = globals.player.floor_surf; + U8 oob = FALSE; + + if (floor_surf != NULL && !(globals.player.ControlOff & 0x8000)) + { + oob = zSurfaceOutOfBounds(*floor_surf); + if (oob) + { + update_max_out_time(*floor_surf); + } + } + + shared.out_time -= dt; + + if (oob) + { + shared.reset_time = fixed.reset_time; + if (shared.reset_time <= 0.0f) + { + return STATE_GRAB; + } + } + else + { + if (!globals.player.JumpState) + { + shared.reset_time = 0.0f; + } + + shared.reset_time -= dt; + if (shared.reset_time <= 0.0f) + { + return STATE_IN; + } + } + + return STATE_OUT; + }; + + void grab_state_type::start() + { + this->finished_tutorial = FALSE; + zEntPlayerControlOff(CONTROL_OWNER_OOB); + + globals.player.ControlOffTimer = FLOAT_MAX; + cruise_bubble::reset(); + + shared.flags |= 0x4; + shared.vertical = FABS(fixed.in_loc.y - fixed.out_loc.y) > 0.01f; + shared.control = TRUE; + + this->move_substate = shared.model != NULL ? SS_REORIENT : SS_INVALID; + this->reorient_time = fixed.reorient_time; + + set_camera(false); + + shared.loc = fixed.out_loc; + shared.dir = (fixed.in_loc - fixed.out_loc).normal(); + shared.vel = fixed.grab.in_vel; + shared.accel = 0.0f; + + this->fade_substate = SS_START_FADE_OUT; + this->fade_start_time = fixed.grab.fade_start_time; + this->fade_time = fixed.grab.fade_time; + + shared.fade_alpha = 1.0f; + this->player_start = globals.player.ent.frame->mat.pos; + + xVec3 eulerOut; + xMat3x3GetEuler(&globals.player.ent.frame->mat, &eulerOut); + globals.player.ent.frame->rot.angle = xrmod(eulerOut.x); + + this->angle_delta = xrmod(PI + (globals.camera.pcur - eulerOut.x)) - PI; + this->angle_delta /= fixed.reorient_time; + + xModelUpdate(globals.player.ent.model, 1.0f / 1000.0f); + this->scene_reset = FALSE; + } + + void grab_state_type::stop() + { + } + + state_enum grab_state_type::update(xScene& scene, F32& dt) + { + if (shared.model == NULL) + { + return STATE_DROP; + } + + F32 movedt = dt; + while (this->move_substate != SS_INVALID) + { + substate_enum newstate = this->updatess[this->move_substate](*this, scene, movedt); + if (newstate == this->move_substate) + { + break; + } + + this->move_substate = newstate; + } + + F32 fadedt = dt; + while (this->fade_substate != SS_INVALID) + { + substate_enum newstate = this->updatess[this->fade_substate](*this, scene, fadedt); + if (newstate == this->fade_substate) + { + break; + } + + this->fade_substate = newstate; + } + + if (this->move_substate == SS_INVALID && this->fade_substate == SS_INVALID) + { + if (this->scene_reset) + { + return STATE_DROP; + } + + this->scene_reset = TRUE; + zGameStateSwitch(0x2); + } + + if (this->move_substate == SS_STARTING || this->move_substate == SS_MOVING_OUT) + { + xMat4x3& pm = *(xMat4x3*)globals.player.ent.model->Mat; + pm.pos = this->player_start; + + move_up(pm.pos, fixed.in_loc.y - shared.loc.y); + move_right(pm.pos, fixed.in_loc.x - shared.loc.x); + } + + xModelEval(globals.player.ent.model); + zEntPlayerUpdateModel(); + return STATE_GRAB; + } + + void drop_state_type::start() + { + this->player_start = globals.player.cp.pos; + this->move_substate = shared.model != NULL ? SS_MOVING_IN : SS_INVALID; + + shared.vel = fixed.drop.in_vel; + shared.accel = 0.0f; + shared.loc.x = fixed.in_loc.x; + shared.loc.y = fixed.in_loc.y; + + this->fade_substate = SS_START_FADE_IN; + this->fade_start_time = fixed.drop.fade_start_time; + this->fade_time = fixed.drop.fade_time; + + xEnt& p = globals.player.ent; + zEntPlayerReset(&p); + zEntPlayerUpdateModel(); + zEntPlayerControlOff(CONTROL_OWNER_OOB); + globals.player.ControlOffTimer = FLOAT_MAX; + xScrFxStopFade(); + zCameraDisableInput(); + + xModelInstance& m = *p.model; + xEntFrame& f = *p.frame; + + f.rot.axis = g_Y3; + f.rot.angle = globals.player.cp.rot; + f.vel = g_O3; + + xMat3x3Euler(&f.mat, f.rot.angle, 0.0f, 0.0f); + f.mat.pos = globals.player.cp.pos; + *(xMat4x3*)m.Mat = f.mat; + + shared_target.pos = *(xVec3*)&m.Mat->pos; + + set_camera(true); + globals.camera.tgt_mat = &shared_target; + globals.camera.tgt_omat = &shared_target; + xCameraMove(&globals.camera, 0x20, fixed.cam_dist, fixed.cam_height, PI + globals.player.cp.rot, 0.0f, 0.0f, 0.0f); + xCameraLookYPR(&globals.camera, 0x0, globals.player.cp.rot, fixed.cam_pitch, 0.0f, 0.0f, 0.0f, 0.0f); + } + + void drop_state_type::stop() + { + zEntPlayerControlOn(CONTROL_OWNER_OOB); + globals.player.ControlOffTimer = 1.0f; + + reset_camera(); + + shared.render_hand = FALSE; + shared.fade_alpha = 1.0f; + shared.flags &= ~0x4; + } + + state_enum drop_state_type::update(xScene& scene, F32& dt) + { + if (shared.model == NULL) + { + return STATE_IN; + } + + F32 movedt = dt; + while (this->move_substate != SS_INVALID) + { + substate_enum newstate = this->updatess[this->move_substate](*this, scene, movedt); + if (newstate == this->move_substate) + { + break; + } + + this->move_substate = newstate; + } + + F32 fadedt = dt; + while (this->fade_substate != SS_INVALID) + { + substate_enum newstate = this->updatess[this->fade_substate](*this, scene, fadedt); + if (newstate == this->fade_substate) + { + break; + } + + this->fade_substate = newstate; + } + + if (this->move_substate == SS_INVALID && this->fade_substate == SS_INVALID) + { + return STATE_IN; + } + + if (this->move_substate == SS_MOVING_IN || this->move_substate == SS_STOPPING) + { + xMat4x3& pm = *(xMat4x3*)globals.player.ent.model->Mat; + pm.pos = this->player_start; + + move_up(pm.pos, fixed.in_loc.y - shared.loc.y); + move_right(pm.pos, fixed.in_loc.x - shared.loc.x); + } + + if (shared.control) + { + xModelEval(globals.player.ent.model); + } + + return STATE_DROP; + } + } // namespace +} // namespace oob_state diff --git a/src/SB/Game/zEntPlayerOOBState.h b/src/SB/Game/zEntPlayerOOBState.h index 1635ece3..bd37d897 100644 --- a/src/SB/Game/zEntPlayerOOBState.h +++ b/src/SB/Game/zEntPlayerOOBState.h @@ -11,8 +11,10 @@ extern bool oob_player_teleported; namespace oob_state { + U8 update(xScene& scene, F32 dt); bool render(); void fx_render(); + void force_start(); void read_persistent(xSerial& s); void write_persistent(xSerial& s); void load_settings(xIniFile& ini); @@ -22,43 +24,44 @@ namespace oob_state bool IsPlayerInControl(); - struct callback - { - virtual void on_stop(); - }; - - enum state_enum - { - STATE_INVALID = -1, - BEGIN_STATE, - STATE_IN = 0, - STATE_OUT, - STATE_GRAB, - STATE_DROP, - END_STATE, - MAX_STATE = 0x4 - }; - namespace { + enum state_enum + { + STATE_INVALID = -1, + BEGIN_STATE = 0, + STATE_IN = 0, + STATE_OUT = 1, + STATE_GRAB = 2, + STATE_DROP = 3, + END_STATE = 4, + MAX_STATE = 4, + }; + struct state_type { state_enum type; - void start(); - void stop(); + state_type(state_enum state); + virtual void start(); + virtual void stop(); + virtual state_enum update(xScene& scene, F32& dt) = 0; }; struct in_state_type : state_type { - void start(); - void stop(); + in_state_type(); + virtual void start(); + virtual void stop(); + virtual state_enum update(xScene& scene, F32& dt); }; struct out_state_type : state_type { - void start(); - void stop(); + out_state_type(); + virtual void start(); + virtual void stop(); + virtual state_enum update(xScene& scene, F32& dt); }; struct grab_state_type : state_type @@ -79,43 +82,69 @@ namespace oob_state MAX_SS }; - struct tutorial_callback : callback + struct tutorial_callback : ztalkbox::callback { grab_state_type& owner; - void on_stop(); + tutorial_callback(grab_state_type& owner); + + virtual void on_signal(U32) + { + + } + + virtual void on_stop() + { + owner.finished_tutorial = true; + } }; tutorial_callback cb; substate_enum move_substate; substate_enum fade_substate; xVec3 player_start; - float reorient_time; - float angle_delta; - float delay; - float fade_start_time; - float fade_time; - unsigned int scene_reset; - - // Todo: this is not in the DWARF, but is required for - // tutorial_callback::on_stop to match. Probably - // not correct. - char pad[4]; - - unsigned char finished_tutorial; - - substate_enum (*updatess)(grab_state_type&, xScene&, float&)[10]; - bool update_reorient(xScene&, F32&); - substate_enum update_stopping(xScene&, float&); - - void start(); - void stop(); + F32 reorient_time; + F32 angle_delta; + F32 delay; + F32 fade_start_time; + F32 fade_time; + U32 scene_reset; + U8 finished_tutorial; + + substate_enum (*updatess[10])(grab_state_type&, xScene&, float&); + + grab_state_type(); + virtual void start(); + virtual void stop(); + virtual state_enum update(xScene& scene, F32& dt); + + static substate_enum supdate_reorient(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_reorient(xScene&, F32&); + static substate_enum supdate_begin_wait(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_begin_wait(xScene&, F32&); + static substate_enum supdate_moving_in(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_moving_in(xScene& scene, F32& dt); + static substate_enum supdate_stopping(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_stopping(xScene& scene, F32& dt); + static substate_enum supdate_stopped(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_stopped(xScene& scene, F32& dt); + static substate_enum supdate_tutorial(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_tutorial(xScene& scene, F32& dt); + static substate_enum supdate_starting(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_starting(xScene& scene, F32& dt); + static substate_enum supdate_moving_out(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_moving_out(xScene& scene, F32& dt); + static substate_enum supdate_start_fade_out(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_start_fade_out(xScene& scene, F32& dt); + static substate_enum supdate_fade_out(grab_state_type& gst, xScene& scene, F32& dt); + substate_enum update_fade_out(xScene& scene, F32& dt); }; struct drop_state_type : state_type { enum substate_enum { + SS_INVALID = -1, SS_MOVING_IN, SS_STOPPING, SS_STOPPED, @@ -124,7 +153,6 @@ namespace oob_state SS_START_FADE_IN, SS_FADE_IN, MAX_SS, - SS_INVALID = 0xffffffff, }; substate_enum move_substate; @@ -133,41 +161,55 @@ namespace oob_state F32 stop_time; F32 fade_start_time; F32 fade_time; - substate_enum (*updatess)(drop_state_type&, xScene&, F32&)[7]; + substate_enum (*updatess[7])(drop_state_type&, xScene&, F32&); + + drop_state_type(); + virtual void start(); + virtual void stop(); + virtual state_enum update(xScene& scene, F32& dt); - void start(); - state_enum update(xScene& s, F32& dt); - substate_enum supdate_fade_in(drop_state_type&, xScene&, F32&); - substate_enum update_fade_in(); + static substate_enum supdate_fade_in(drop_state_type&, xScene&, F32&); substate_enum update_fade_in(xScene&, F32&); + static substate_enum supdate_start_fade_in(drop_state_type&, xScene&, F32&); + substate_enum update_start_fade_in(xScene&, F32&); + static substate_enum supdate_moving_out(drop_state_type&, xScene&, F32&); + substate_enum update_moving_out(xScene&, F32&); + static substate_enum supdate_starting(drop_state_type&, xScene&, F32&); + substate_enum update_starting(xScene&, F32&); + static substate_enum supdate_stopped(drop_state_type&, xScene&, F32&); + substate_enum update_stopped(xScene&, F32&); + static substate_enum supdate_stopping(drop_state_type&, xScene&, F32&); + substate_enum update_stopping(xScene&, F32&); + static substate_enum supdate_moving_in(drop_state_type&, xScene&, F32&); + substate_enum update_moving_in(xScene&, F32&); }; struct _class_9 { - int flags; + S32 flags; state_type* state; - unsigned char control; + U8 control; state_type* states[4]; - float out_time; - float max_out_time; - float reset_time; + F32 out_time; + F32 max_out_time; + F32 reset_time; xModelInstance* model; xVec2 loc; xVec2 dir; - float fade_alpha; - unsigned char render_hand; - unsigned char vertical; - float vel; - float accel; + F32 fade_alpha; + U8 render_hand; + U8 vertical; + F32 vel; + F32 accel; ztalkbox* tutorial; struct { - float near_d; - float near_h; - float near_pitch; - float far_d; - float far_h; - float far_pitch; + F32 near_d; + F32 near_h; + F32 near_pitch; + F32 far_d; + F32 far_h; + F32 far_pitch; xMat4x3* tgt_mat; xMat4x3* tgt_omat; } cam_data; @@ -175,47 +217,47 @@ namespace oob_state struct tagFixed { - float out_time; - float reset_time; - float cam_dist; - float cam_height; - float cam_pitch; - float reorient_time; + F32 out_time; + F32 reset_time; + F32 cam_dist; + F32 cam_height; + F32 cam_pitch; + F32 reorient_time; char* hand_model; xVec2 in_loc; xVec2 out_loc; struct { - float in_wait_time; - float in_vel; - float in_stop_dist; - float out_wait_time; - float out_vel; - float out_start_dist; - float fade_start_time; - float fade_time; + F32 in_wait_time; + F32 in_vel; + F32 in_stop_dist; + F32 out_wait_time; + F32 out_vel; + F32 out_start_dist; + F32 fade_start_time; + F32 fade_time; } grab; struct { - float in_vel; - float in_stop_dist; - float out_wait_time; - float out_vel; - float out_start_dist; - float fade_start_time; - float fade_time; + F32 in_vel; + F32 in_stop_dist; + F32 out_wait_time; + F32 out_vel; + F32 out_start_dist; + F32 fade_start_time; + F32 fade_time; } drop; - float hand_size_x; - float hand_size_y; - float hand_yaw; - float hand_pitch; - float hand_roll; + F32 hand_size_x; + F32 hand_size_y; + F32 hand_yaw; + F32 hand_pitch; + F32 hand_roll; }; } // namespace struct idiot_level_data { - bool triggered; // offset 0x0, size 0x1 + U8 triggered; // offset 0x0, size 0x1 U32 scene; // offset 0x4, size 0x4 }; diff --git a/src/SB/Game/zSurface.h b/src/SB/Game/zSurface.h index 516fb729..faf1ff27 100644 --- a/src/SB/Game/zSurface.h +++ b/src/SB/Game/zSurface.h @@ -137,5 +137,7 @@ void zSurfaceSetup(xSurface* s); void zSurfaceUpdate(xBase* to, xScene*, F32 dt); void zSurfaceGetName(S32 type, char* buffer); xSurface& zSurfaceGetDefault(); +U8 zSurfaceOutOfBounds(const xSurface& s); +F32 zSurfaceGetOutOfBoundsDelay(const xSurface& surface); #endif diff --git a/src/SB/Game/zTalkBox.h b/src/SB/Game/zTalkBox.h index 0783208a..3b834aa5 100644 --- a/src/SB/Game/zTalkBox.h +++ b/src/SB/Game/zTalkBox.h @@ -77,11 +77,30 @@ struct ztalkbox : xBase struct callback { - callback(); - virtual void on_signal(U32); - virtual void on_start(); - virtual void on_stop(); - virtual void on_answer(answer_enum); + callback() + { + + } + + virtual void on_signal(U32) + { + + } + + virtual void on_start() + { + + } + + virtual void on_stop() + { + + } + + virtual void on_answer(answer_enum answer) + { + + } }; struct