mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-10 02:35:17 -04:00
trigger viewer, more commands
This commit is contained in:
@@ -1443,6 +1443,7 @@ set(DUSK_FILES
|
||||
src/dusk/layout.cpp
|
||||
src/dusk/logging.cpp
|
||||
src/dusk/settings.cpp
|
||||
src/dusk/d_trigger_view.cpp
|
||||
src/dusk/speedrun.cpp
|
||||
src/dusk/string.cpp
|
||||
src/dusk/stubs.cpp
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace dusk {
|
||||
namespace TriggerView {
|
||||
void execute();
|
||||
}
|
||||
}
|
||||
@@ -292,8 +292,25 @@ struct CollisionViewSettings {
|
||||
float drawRange;
|
||||
};
|
||||
|
||||
struct TriggerViewSettings {
|
||||
bool loadZones;
|
||||
bool eventAreas;
|
||||
bool switchAreas;
|
||||
bool eventTags;
|
||||
bool midnaStops;
|
||||
bool twilightGates;
|
||||
bool checkpoints;
|
||||
bool paths;
|
||||
bool transformDists;
|
||||
bool attentionDists;
|
||||
bool purpleMistAvoid;
|
||||
bool leevers;
|
||||
float opacity;
|
||||
};
|
||||
|
||||
struct TransientSettings {
|
||||
CollisionViewSettings collisionView;
|
||||
TriggerViewSettings triggerView;
|
||||
bool skipFrameRateLimit;
|
||||
bool moveLinkActive;
|
||||
bool stateShareLoadActive;
|
||||
|
||||
@@ -40,6 +40,10 @@ output[open] {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
console:not([open]) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
line {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
@@ -49,6 +53,16 @@ line.cmd {
|
||||
color: #FFD966;
|
||||
}
|
||||
|
||||
line.copyable {
|
||||
color: #80C8FF;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
line.copyable:hover {
|
||||
color: #FFFFFF;
|
||||
background-color: rgba(255, 255, 255, 12%);
|
||||
}
|
||||
|
||||
console input {
|
||||
display: none;
|
||||
width: 100%;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/commands.hpp"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/action_bindings.h"
|
||||
@@ -1052,6 +1053,11 @@ void dCamera_c::debugDrawInit() {
|
||||
bool dCamera_c::Run() {
|
||||
#if TARGET_PC
|
||||
ResetView();
|
||||
if (dusk::isCameraDetached()) {
|
||||
mFrameCounter++;
|
||||
mTicks++;
|
||||
return true;
|
||||
}
|
||||
if (executeDebugFlyCam()) {
|
||||
mFrameCounter++;
|
||||
mTicks++;
|
||||
@@ -11083,6 +11089,9 @@ camera_class* dCam_getCamera() {
|
||||
|
||||
dCamera_c* dCam_getBody() {
|
||||
camera_process_class* camera = (camera_process_class*)dCam_getCamera();
|
||||
#if TARGET_PC
|
||||
if (camera == nullptr) { return nullptr; }
|
||||
#endif
|
||||
return &camera->mCamera;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <typeindex>
|
||||
#include "JSystem/JKernel/JKRHeap.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "client/TracyScoped.hpp"
|
||||
#include "tracy/Tracy.hpp"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/gx_helper.h"
|
||||
#include "dusk/logging.h"
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/autosave.h"
|
||||
#include "dusk/d_trigger_view.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/ui/ui.hpp"
|
||||
#endif
|
||||
@@ -675,6 +676,10 @@ static int dScnPly_Draw(dScnPly_c* i_this) {
|
||||
dComIfG_Ccsp()->Draw();
|
||||
dComIfG_Bgsp().Draw();
|
||||
|
||||
#if TARGET_PC
|
||||
dusk::TriggerView::execute();
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
dPath_Draw();
|
||||
#endif
|
||||
|
||||
+264
-1
@@ -1,11 +1,14 @@
|
||||
#include "commands.hpp"
|
||||
|
||||
#include "JSystem/JUtility/JUTGamePad.h"
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
#include "SSystem/SComponent/c_sxyz.h"
|
||||
#include "SSystem/SComponent/c_xyz.h"
|
||||
#include "c/c_damagereaction.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/d_com_inf_actor.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_camera.h"
|
||||
#include "d/d_kankyo.h"
|
||||
#include "d/d_stage.h"
|
||||
#include "dusk/game_clock.h"
|
||||
@@ -192,10 +195,78 @@ static int FindActorCallback(void* p, void* ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct CameraFlyState {
|
||||
bool active = false;
|
||||
cXyz startEye;
|
||||
cXyz startCenter;
|
||||
cXyz endEye;
|
||||
cXyz endCenter;
|
||||
float duration = 0.0f;
|
||||
float elapsed = 0.0f;
|
||||
};
|
||||
CameraFlyState s_cameraFly;
|
||||
|
||||
static dCamera_c* getCamera() { return dCam_getBody(); }
|
||||
|
||||
static cXyz anglesToDir(s16 h, s16 v) {
|
||||
return cXyz(cM_scos(v) * cM_ssin(h), cM_ssin(v), cM_scos(v) * cM_scos(h));
|
||||
}
|
||||
|
||||
static void cameraToAngles(dCamera_c* cam, s16& h, s16& v) {
|
||||
const cXyz eye = cam->iEye();
|
||||
const cXyz ctr = cam->iCenter();
|
||||
const float dx = ctr.x - eye.x;
|
||||
const float dy = ctr.y - eye.y;
|
||||
const float dz = ctr.z - eye.z;
|
||||
const float hDist = sqrtf(dx * dx + dz * dz);
|
||||
h = cM_atan2s(dx, dz);
|
||||
v = cM_atan2s(dy, hDist);
|
||||
}
|
||||
|
||||
static float smoothstep(float t) {
|
||||
t = std::clamp(t, 0.0f, 1.0f);
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
static constexpr float kCamTargetDist = 100.0f;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool isCameraDetached() { return s_cameraFly.active; }
|
||||
|
||||
void processCameraCommands() {
|
||||
if (!s_cameraFly.active) { return; }
|
||||
dCamera_c* cam = getCamera();
|
||||
if (cam == nullptr) { s_cameraFly.active = false; return; }
|
||||
|
||||
cXyz eye, center;
|
||||
|
||||
if (s_cameraFly.duration <= 0.0f) {
|
||||
eye = s_cameraFly.endEye;
|
||||
center = s_cameraFly.endCenter;
|
||||
} else {
|
||||
s_cameraFly.elapsed += dusk::game_clock::sim_pace();
|
||||
const float t = smoothstep(s_cameraFly.elapsed / s_cameraFly.duration);
|
||||
eye = s_cameraFly.startEye + (s_cameraFly.endEye - s_cameraFly.startEye) * t;
|
||||
center = s_cameraFly.startCenter + (s_cameraFly.endCenter - s_cameraFly.startCenter) * t;
|
||||
|
||||
if (s_cameraFly.elapsed >= s_cameraFly.duration) {
|
||||
eye = s_cameraFly.endEye;
|
||||
center = s_cameraFly.endCenter;
|
||||
s_cameraFly.startEye = s_cameraFly.endEye;
|
||||
s_cameraFly.startCenter = s_cameraFly.endCenter;
|
||||
s_cameraFly.duration = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
cam->Reset(center, eye);
|
||||
cam->mDebugFlyCam.initialized = false;
|
||||
}
|
||||
|
||||
void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutput& output) {
|
||||
output(fmt::format(FMT_STRING("> {}"), cmdLine));
|
||||
if (state.echoEnabled) {
|
||||
output(fmt::format(FMT_STRING("> {}"), cmdLine));
|
||||
}
|
||||
|
||||
if (!cmdLine.empty()) {
|
||||
if (state.history.empty() || state.history.back() != cmdLine) {
|
||||
@@ -457,6 +528,27 @@ void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutp
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "freeze" || cmd == "unfreeze") {
|
||||
const bool doFreeze = (cmd == "freeze");
|
||||
if (args.size() < 2) {
|
||||
g_dComIfAc_gameInfo.mPause = doFreeze;
|
||||
output(doFreeze ? "Global freeze on" : "Global freeze off");
|
||||
return;
|
||||
}
|
||||
auto* ac = ParseActorArg(args[1], state.foundProcId, output);
|
||||
if (ac == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (doFreeze) {
|
||||
fpcM_PauseEnable(ac, 1);
|
||||
output(fmt::format(FMT_STRING("Froze actor {}"), (unsigned int)ac->id));
|
||||
} else {
|
||||
fpcM_PauseDisable(ac, 1);
|
||||
output(fmt::format(FMT_STRING("Unfroze actor {}"), (unsigned int)ac->id));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "rate") {
|
||||
if (args.size() >= 2) {
|
||||
const auto hz = ParseLong(args[1]);
|
||||
@@ -565,6 +657,153 @@ void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutp
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "camera") {
|
||||
const std::string sub = args.size() >= 2 ? args[1] : "";
|
||||
|
||||
if (sub == "attach") {
|
||||
s_cameraFly.active = false;
|
||||
output("Camera attached");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* cam = getCamera();
|
||||
if (cam == nullptr) { output("Error: camera not available"); return; }
|
||||
|
||||
if (sub == "detach") {
|
||||
s_cameraFly.active = true;
|
||||
s_cameraFly.duration = 0.0f;
|
||||
s_cameraFly.startEye = s_cameraFly.endEye = cam->iEye();
|
||||
s_cameraFly.startCenter = s_cameraFly.endCenter = cam->iCenter();
|
||||
output("Camera detached");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub == "tp") {
|
||||
// camera tp @<ref>
|
||||
if (args.size() >= 3 && !args[2].empty() && args[2][0] == '@') {
|
||||
auto* ac = ParseActorArg(args[2], state.foundProcId, output);
|
||||
if (ac == nullptr) { return; }
|
||||
const cXyz actorPos = ac->current.pos;
|
||||
const cXyz dir = anglesToDir(ac->shape_angle.y, 0);
|
||||
const cXyz newEye = cXyz(actorPos.x - dir.x * kCamTargetDist,
|
||||
actorPos.y - dir.y * kCamTargetDist + 50.0f,
|
||||
actorPos.z - dir.z * kCamTargetDist);
|
||||
s_cameraFly.active = true; s_cameraFly.duration = 0.0f;
|
||||
s_cameraFly.startEye = s_cameraFly.endEye = newEye;
|
||||
s_cameraFly.startCenter = s_cameraFly.endCenter = actorPos;
|
||||
output(fmt::format(FMT_STRING("Camera moved to actor {}"), ac->id));
|
||||
return;
|
||||
}
|
||||
// camera tp x y z [h] [v]
|
||||
if (args.size() < 5) {
|
||||
output("Usage: camera tp <x> <y> <z> [h_angle] [v_angle] | camera tp @<ref>");
|
||||
return;
|
||||
}
|
||||
const auto pos = ParseXYZ(args, 2);
|
||||
if (!pos) { output("Error: invalid coordinates"); return; }
|
||||
s16 h = 0, v = 0;
|
||||
cameraToAngles(cam, h, v);
|
||||
if (args.size() >= 6) {
|
||||
const auto hv = ParseLong(args[5]);
|
||||
if (!hv) { output("Error: invalid h_angle"); return; }
|
||||
h = (s16)*hv;
|
||||
}
|
||||
if (args.size() >= 7) {
|
||||
const auto vv = ParseLong(args[6]);
|
||||
if (!vv) { output("Error: invalid v_angle"); return; }
|
||||
v = (s16)*vv;
|
||||
}
|
||||
const cXyz dir = anglesToDir(h, v);
|
||||
const cXyz center = cXyz(pos->x + dir.x * kCamTargetDist,
|
||||
pos->y + dir.y * kCamTargetDist,
|
||||
pos->z + dir.z * kCamTargetDist);
|
||||
s_cameraFly.active = true; s_cameraFly.duration = 0.0f;
|
||||
s_cameraFly.startEye = s_cameraFly.endEye = *pos;
|
||||
s_cameraFly.startCenter = s_cameraFly.endCenter = center;
|
||||
output(fmt::format(FMT_STRING("Camera teleported to ({:.2f}, {:.2f}, {:.2f})"),
|
||||
pos->x, pos->y, pos->z));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub == "pos") {
|
||||
s16 h = 0, v = 0;
|
||||
cameraToAngles(cam, h, v);
|
||||
const cXyz eye = cam->iEye();
|
||||
output(fmt::format(FMT_STRING("Camera: ({:.2f}, {:.2f}, {:.2f}) h={} v={}"),
|
||||
eye.x, eye.y, eye.z, (int)h, (int)v));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub == "fly") {
|
||||
// camera fly <time> <x> <y> <z> [h] [v] | camera fly <time> @<ref>
|
||||
if (args.size() < 4) {
|
||||
output("Usage: camera fly <time> <x> <y> <z> [h_angle] [v_angle] | camera fly <time> @<ref>");
|
||||
return;
|
||||
}
|
||||
const auto t = ParseFloat(args[2]);
|
||||
if (!t || *t <= 0) { output("Error: invalid time"); return; }
|
||||
const float flyTime = *t;
|
||||
|
||||
cXyz targetPos;
|
||||
s16 h = 0, v = 0;
|
||||
|
||||
if (!args[3].empty() && args[3][0] == '@') {
|
||||
auto* ac = ParseActorArg(args[3], state.foundProcId, output);
|
||||
if (ac == nullptr) { return; }
|
||||
targetPos = ac->current.pos;
|
||||
h = ac->shape_angle.y;
|
||||
v = 0;
|
||||
} else {
|
||||
if (args.size() < 6) {
|
||||
output("Usage: camera fly <time> <x> <y> <z> [h_angle] [v_angle] | camera fly <time> @<ref>");
|
||||
return;
|
||||
}
|
||||
const auto pos = ParseXYZ(args, 3);
|
||||
if (!pos) { output("Error: invalid coordinates"); return; }
|
||||
targetPos = *pos;
|
||||
cameraToAngles(cam, h, v);
|
||||
if (args.size() >= 7) {
|
||||
const auto hv = ParseLong(args[6]); if (!hv) { output("Error: invalid h_angle"); return; } h = (s16)*hv;
|
||||
}
|
||||
if (args.size() >= 8) {
|
||||
const auto vv = ParseLong(args[7]); if (!vv) { output("Error: invalid v_angle"); return; } v = (s16)*vv;
|
||||
}
|
||||
}
|
||||
|
||||
const cXyz dir = anglesToDir(h, v);
|
||||
const cXyz endCenter = cXyz(targetPos.x + dir.x * kCamTargetDist,
|
||||
targetPos.y + dir.y * kCamTargetDist,
|
||||
targetPos.z + dir.z * kCamTargetDist);
|
||||
|
||||
s_cameraFly.active = true;
|
||||
s_cameraFly.startEye = cam->iEye();
|
||||
s_cameraFly.startCenter = cam->iCenter();
|
||||
s_cameraFly.endEye = targetPos;
|
||||
s_cameraFly.endCenter = endCenter;
|
||||
s_cameraFly.duration = flyTime;
|
||||
s_cameraFly.elapsed = 0.0f;
|
||||
output(fmt::format(FMT_STRING("Camera flying to ({:.2f}, {:.2f}, {:.2f}) over {:.1f}s"),
|
||||
targetPos.x, targetPos.y, targetPos.z, flyTime));
|
||||
return;
|
||||
}
|
||||
|
||||
output("Usage: camera detach | attach | tp ... | fly ... | pos");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "echo") {
|
||||
if (args.size() >= 2 && args[1] == "off") {
|
||||
state.echoEnabled = false;
|
||||
output("Echo disabled");
|
||||
} else if (args.size() >= 2 && args[1] == "on") {
|
||||
state.echoEnabled = true;
|
||||
output("Echo enabled");
|
||||
} else {
|
||||
output(state.echoEnabled ? "Echo: on" : "Echo: off");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "transform") {
|
||||
auto* player = requirePlayer();
|
||||
if (player == nullptr) { return; }
|
||||
@@ -573,6 +812,20 @@ void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutp
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "angle") {
|
||||
auto* player = requirePlayer();
|
||||
if (player == nullptr) { return; }
|
||||
if (args.size() >= 2) {
|
||||
const auto a = ParseLong(args[1]);
|
||||
if (!a) { output("Error: invalid angle"); return; }
|
||||
player->shape_angle.y = (s16)*a;
|
||||
output(fmt::format(FMT_STRING("Angle set to {}"), (int)(s16)*a));
|
||||
} else {
|
||||
output(fmt::format(FMT_STRING("Angle: {}"), (int)player->shape_angle.y));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == "pos") {
|
||||
auto* player = requirePlayer();
|
||||
if (player == nullptr) {
|
||||
@@ -589,8 +842,17 @@ void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutp
|
||||
if (cmd == "help") {
|
||||
output("@<ref> = @<procId> | @found | @link");
|
||||
output("");
|
||||
output("angle [value] Get or set Link's facing angle");
|
||||
output("camera detach | attach Detach or reattach camera");
|
||||
output("camera pos Print camera position and angles");
|
||||
output("camera tp <x> <y> <z> [h] [v] Teleport camera (h/v are s16 angles)");
|
||||
output("camera tp @<ref> Teleport camera to actor");
|
||||
output("camera fly <t> <x> <y> <z> [h] [v] Fly camera over t seconds (h/v are s16 angles)");
|
||||
output("camera fly <t> @<ref> Fly camera to actor");
|
||||
output("ebf [0-255] Get or set cDmr_SkipInfo");
|
||||
output("echo on | off Enable or disable command echo");
|
||||
output("find <id|name> [n=1] Store nth actor as @found");
|
||||
output("freeze [@<ref>] Freeze globally, or freeze actor");
|
||||
output("heal [amount] Heal to max, or by relative amount");
|
||||
output("kill Set Link health to 0");
|
||||
output("kill @<ref> Delete proc");
|
||||
@@ -607,6 +869,7 @@ void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutp
|
||||
output("tp @<ref> <x> <y> <z> [angle] Move actor to coords");
|
||||
output("tp @<ref> @<ref> Move actor to actor");
|
||||
output("transform Force transform");
|
||||
output("unfreeze [@<ref>] Unfreeze globally, or unfreeze actor");
|
||||
output("warp <stage> <point> <room> [layer] Warp to stage");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,17 @@ struct CommandState {
|
||||
std::vector<std::string> history;
|
||||
unsigned int foundProcId = 0;
|
||||
std::string lastWarpStage;
|
||||
bool echoEnabled = true;
|
||||
};
|
||||
|
||||
// Execute a single command line. Calls output() for every line of response.
|
||||
// Manages history internally; callers need only hold a CommandState.
|
||||
void runCommand(std::string_view cmdLine, CommandState& state, const CommandOutput& output);
|
||||
|
||||
// Per-sim-tick update for camera fly animation.
|
||||
void processCameraCommands();
|
||||
|
||||
// Returns true when the dev camera is detached (suppresses the game's camera update).
|
||||
bool isCameraDetached();
|
||||
|
||||
} // namespace dusk
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
#include "dusk/d_trigger_view.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "d/d_debug_viewer.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_stage.h"
|
||||
#include "d/d_path.h"
|
||||
#include "d/d_attention.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/actor/d_a_kytag08.h"
|
||||
#include "d/actor/d_a_e_rb.h"
|
||||
#include "d/actor/d_a_e_rd.h"
|
||||
#include "f_op/f_op_actor_mng.h"
|
||||
#include "f_op/f_op_actor_tag.h"
|
||||
#include "f_pc/f_pc_name.h"
|
||||
#include "m_Do/m_Do_mtx.h"
|
||||
#include "SSystem/SComponent/c_tag.h"
|
||||
#include "SSystem/SComponent/c_list.h"
|
||||
#include "JSystem/JMath/JMath.h"
|
||||
|
||||
namespace dusk {
|
||||
namespace TriggerView {
|
||||
|
||||
static u8 s_opacity;
|
||||
|
||||
typedef void (*DrawCallback)(fopAc_ac_c*);
|
||||
|
||||
static void searchActorForCallback(s16 actorName, DrawCallback callback) {
|
||||
node_class* node = g_fopAcTg_Queue.mpHead;
|
||||
|
||||
for (int i = 0; i < g_fopAcTg_Queue.mSize; i++) {
|
||||
if (node != NULL) {
|
||||
create_tag_class* tag = (create_tag_class*)node;
|
||||
fopAc_ac_c* actorData = (fopAc_ac_c*)tag->mpTagData;
|
||||
|
||||
bool checkAll = actorName == -1;
|
||||
if (actorData != NULL && (fopAcM_GetName(actorData) == actorName || checkAll)) {
|
||||
callback(actorData);
|
||||
}
|
||||
node = node->mpNextNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void drawSceneExit(fopAc_ac_c* actor) {
|
||||
struct daScex_c : public fopAc_ac_c {
|
||||
/* 0x568 */ Mtx mMatrix;
|
||||
};
|
||||
daScex_c* scex = (daScex_c*)actor;
|
||||
|
||||
cXyz points[8];
|
||||
points[0].set(-actor->scale.x, actor->scale.y, -actor->scale.z);
|
||||
points[1].set(actor->scale.x, actor->scale.y, -actor->scale.z);
|
||||
points[2].set(-actor->scale.x, actor->scale.y, actor->scale.z);
|
||||
points[3].set(actor->scale.x, actor->scale.y, actor->scale.z);
|
||||
points[4].set(-actor->scale.x, 0.0f, -actor->scale.z);
|
||||
points[5].set(actor->scale.x, 0.0f, -actor->scale.z);
|
||||
points[6].set(-actor->scale.x, 0.0f, actor->scale.z);
|
||||
points[7].set(actor->scale.x, 0.0f, actor->scale.z);
|
||||
|
||||
mDoMtx_inverse(scex->mMatrix, mDoMtx_stack_c::get());
|
||||
mDoMtx_multVecArray(mDoMtx_stack_c::get(), points, points, 8);
|
||||
|
||||
GXColor color = {0xFF, 0x00, 0xFF, s_opacity};
|
||||
dDbVw_drawCube8pXlu(points, color);
|
||||
}
|
||||
|
||||
static void drawMidnaStop(fopAc_ac_c* actor) {
|
||||
struct daMidnaStop_c : public fopAc_ac_c {
|
||||
/* 0x568 */ u8 data[0x5C0 - 0x568];
|
||||
/* 0x5C0 */ f32 mRangeXZ;
|
||||
/* 0x5C4 */ f32 mRangeY;
|
||||
};
|
||||
daMidnaStop_c* mstop = (daMidnaStop_c*)actor;
|
||||
|
||||
GXColor color = {0x4A, 0x36, 0xBA, s_opacity};
|
||||
dDbVw_drawCylinderXlu(mstop->current.pos, mstop->scale.x * 100.0f, mstop->scale.y, color, 1);
|
||||
}
|
||||
|
||||
static void drawPlumTag(fopAc_ac_c* actor) {
|
||||
GXColor color = {0x00, 0xFF, 0x00, s_opacity};
|
||||
dDbVw_drawCylinderXlu(actor->current.pos, actor->scale.x * 100.0f, 1000000.0f, color, 1);
|
||||
}
|
||||
|
||||
static void drawPlumSearch(fopAc_ac_c* actor) {
|
||||
GXColor color = {0xFF, 0x00, 0x00, s_opacity};
|
||||
const f32 search_dist = 500.0f;
|
||||
dDbVw_drawCircleXlu(actor->attention_info.position, search_dist + 160.0f, color, 1, 12);
|
||||
}
|
||||
|
||||
static void drawSwitchArea(fopAc_ac_c* actor) {
|
||||
struct daSwc00_c : public fopAc_ac_c {
|
||||
/* 0x568 */ cXyz mStart;
|
||||
/* 0x574 */ cXyz mEnd;
|
||||
/* 0x580 */ u16 mEventID;
|
||||
/* 0x582 */ u8 mAction;
|
||||
};
|
||||
daSwc00_c* swc = (daSwc00_c*)actor;
|
||||
int shape_type = (fopAcM_GetParam(actor) >> 0x12) & 3;
|
||||
|
||||
GXColor color = {0x00, 0x00, 0xFF, s_opacity};
|
||||
if (shape_type == 3) {
|
||||
dDbVw_drawCylinderXlu(swc->current.pos, JMAFastSqrt(swc->scale.x) - 30.0f, swc->scale.y, color, 1);
|
||||
} else if (shape_type == 0) {
|
||||
cXyz size = swc->mEnd - swc->mStart;
|
||||
size *= 0.5f;
|
||||
cXyz pos = swc->mStart + size;
|
||||
csXyz angle(swc->current.angle.x, swc->current.angle.y, swc->current.angle.z);
|
||||
dDbVw_drawCubeXlu(pos, size, angle, color);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawEventArea(fopAc_ac_c* actor) {
|
||||
u8 type = (actor->shape_angle.z & 0xFF);
|
||||
if (type == 0xFF) {
|
||||
type = 0;
|
||||
}
|
||||
|
||||
if (type == 15 || type == 16) {
|
||||
GXColor color = {0xFF, 0xFF, 0x00, s_opacity};
|
||||
cXyz points[8];
|
||||
points[0].set(-actor->scale.x, actor->scale.y, -actor->scale.z);
|
||||
points[1].set(actor->scale.x, actor->scale.y, -actor->scale.z);
|
||||
points[2].set(-actor->scale.x, actor->scale.y, actor->scale.z);
|
||||
points[3].set(actor->scale.x, actor->scale.y, actor->scale.z);
|
||||
points[4].set(-actor->scale.x, 0.0f, -actor->scale.z);
|
||||
points[5].set(actor->scale.x, 0.0f, -actor->scale.z);
|
||||
points[6].set(-actor->scale.x, 0.0f, actor->scale.z);
|
||||
points[7].set(actor->scale.x, 0.0f, actor->scale.z);
|
||||
|
||||
mDoMtx_stack_c::transS(actor->home.pos.x, actor->home.pos.y, actor->home.pos.z);
|
||||
mDoMtx_stack_c::YrotS(actor->current.angle.y);
|
||||
mDoMtx_multVecArray(mDoMtx_stack_c::get(), points, points, 8);
|
||||
|
||||
dDbVw_drawCube8pXlu(points, color);
|
||||
} else {
|
||||
GXColor outer_color = {0xFF, 0x00, 0x00, s_opacity};
|
||||
GXColor inner_color = {0x00, 0xFF, 0x00, s_opacity};
|
||||
cXyz pos = actor->current.pos;
|
||||
|
||||
daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0);
|
||||
if (player != NULL && pos.y < player->mLinkAcch.GetGroundH()) {
|
||||
pos.y = player->mLinkAcch.GetGroundH() + 100.0f;
|
||||
}
|
||||
|
||||
const f32 inner_scale = 0.83f;
|
||||
dDbVw_drawCircleXlu(pos, actor->scale.x * inner_scale, inner_color, 1, 20);
|
||||
dDbVw_drawCircleXlu(pos, actor->scale.x, outer_color, 1, 20);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawEventTag(fopAc_ac_c* actor) {
|
||||
GXColor color = {0x00, 0xC8, 0xFF, s_opacity};
|
||||
u16 area_type = actor->home.angle.x & 0x8000;
|
||||
|
||||
if (area_type == 0x8000) {
|
||||
cXyz start(actor->current.pos.x - (actor->scale.x * 0.5f), actor->current.pos.y,
|
||||
actor->current.pos.z - (actor->scale.z * 0.5f));
|
||||
cXyz end(actor->current.pos.x + (actor->scale.x * 0.5f),
|
||||
actor->current.pos.y + actor->scale.y,
|
||||
actor->current.pos.z + (actor->scale.z * 0.5f));
|
||||
|
||||
cXyz points[8];
|
||||
points[0].set(start.x, start.y, start.z);
|
||||
points[1].set(start.x, start.y, end.z);
|
||||
points[2].set(end.x, start.y, end.z);
|
||||
points[3].set(end.x, start.y, start.z);
|
||||
points[4].set(start.x, end.y, start.z);
|
||||
points[5].set(start.x, end.y, end.z);
|
||||
points[6].set(end.x, end.y, end.z);
|
||||
points[7].set(end.x, end.y, start.z);
|
||||
|
||||
dDbVw_drawCube8pXlu(points, color);
|
||||
} else {
|
||||
cXyz pos = actor->current.pos;
|
||||
pos.y -= actor->scale.y;
|
||||
dDbVw_drawCylinderXlu(pos, actor->scale.x, actor->scale.y * 2, color, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawTWGate(fopAc_ac_c* actor) {
|
||||
GXColor color = {0xFF, 0xFF, 0xFF, s_opacity};
|
||||
dDbVw_drawCylinderXlu(actor->current.pos, actor->scale.x * 100.0f, actor->scale.y * 100.0f, color, 1);
|
||||
}
|
||||
|
||||
static u8 s_pathColorIndex = 0;
|
||||
|
||||
static void drawPaths(dStage_dPath_c* paths) {
|
||||
static const GXColor colors[8] = {
|
||||
{0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x00}, {0xFF, 0x00, 0x00}, {0x00, 0xFF, 0x00},
|
||||
{0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0x00}, {0xFF, 0x00, 0xFF}, {0x00, 0xFF, 0xFF},
|
||||
};
|
||||
|
||||
cXyz cubeSize = {30.0f, 30.0f, 30.0f};
|
||||
csXyz cubeAngle = {0, 0, 0};
|
||||
|
||||
for (int i = 0; i < (int)paths->num; i++) {
|
||||
dPath* path = &paths->m_path[i];
|
||||
GXColor color = colors[(s_pathColorIndex++) & 7];
|
||||
color.a = s_opacity;
|
||||
cXyz a, b;
|
||||
|
||||
if (dPath_ChkClose(path) && path->m_num > 2) {
|
||||
a = (Vec)path->m_points[0].m_position;
|
||||
b = (Vec)path->m_points[(int)path->m_num - 1].m_position;
|
||||
dDbVw_drawLineXlu(a, b, color, 1, 10);
|
||||
}
|
||||
|
||||
for (int j = 0; j < (int)path->m_num - 1; j++) {
|
||||
a = (Vec)path->m_points[j].m_position;
|
||||
b = (Vec)path->m_points[j + 1].m_position;
|
||||
dDbVw_drawLineXlu(a, b, color, 1, 10);
|
||||
dDbVw_drawCubeXlu(a, cubeSize, cubeAngle, color);
|
||||
}
|
||||
dDbVw_drawCubeXlu(b, cubeSize, cubeAngle, color);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawStagePaths() {
|
||||
dStage_dPath_c* stagePaths = g_dComIfG_gameInfo.play.getStage().getPath2Inf();
|
||||
if (stagePaths != nullptr) {
|
||||
drawPaths(stagePaths);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawCurrentRoomPaths() {
|
||||
fopAc_ac_c* player = dComIfGp_getPlayer(0);
|
||||
if (player == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
s32 roomNo = fopAcM_GetRoomNo(player);
|
||||
if (roomNo < 0 || roomNo >= 64) {
|
||||
return;
|
||||
}
|
||||
|
||||
dStage_dPath_c* roomPaths = dStage_roomControl_c::mStatus[roomNo].mRoomDt.getPath2Inf();
|
||||
if (roomPaths != nullptr) {
|
||||
drawPaths(roomPaths);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawCheckpointTag(fopAc_ac_c* actor) {
|
||||
struct daTagChgRestart_c : public fopAc_ac_c {
|
||||
/* 0x568 */ cXyz mVertices[4];
|
||||
};
|
||||
daTagChgRestart_c* chk = (daTagChgRestart_c*)actor;
|
||||
|
||||
GXColor color = {0x29, 0xF0, 0xFF, s_opacity};
|
||||
cXyz points[8];
|
||||
|
||||
mDoMtx_stack_c::transS(actor->current.pos.x, actor->current.pos.y, actor->current.pos.z);
|
||||
mDoMtx_stack_c::YrotM(actor->current.angle.y);
|
||||
|
||||
points[0] = chk->mVertices[0];
|
||||
points[1] = chk->mVertices[1];
|
||||
points[2] = chk->mVertices[3];
|
||||
points[3] = chk->mVertices[2];
|
||||
points[4] = chk->mVertices[0];
|
||||
points[5] = chk->mVertices[1];
|
||||
points[6] = chk->mVertices[3];
|
||||
points[7] = chk->mVertices[2];
|
||||
|
||||
mDoMtx_multVecArray(mDoMtx_stack_c::get(), points, points, 8);
|
||||
|
||||
fopAc_ac_c* player = dComIfGp_getPlayer(0);
|
||||
if (player != nullptr) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
points[i].y = player->current.pos.y;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
points[i].y += 1000.0f;
|
||||
}
|
||||
|
||||
dDbVw_drawCube8pXlu(points, color);
|
||||
}
|
||||
|
||||
static void drawTransformDists(fopAc_ac_c* actor) {
|
||||
if (fopAcM_GetGroup(actor) == 4 && !(actor->actor_status & fopAcStts_UNK_0x8000000_e)) {
|
||||
GXColor near_color = {0x00, 0xFF, 0x00, s_opacity};
|
||||
GXColor far_color = {0xFF, 0x00, 0x00, s_opacity};
|
||||
|
||||
const f32 near_dist = 400.0f;
|
||||
const f32 far_dist = 5000.0f;
|
||||
|
||||
dDbVw_drawCircleXlu(actor->eyePos, near_dist, near_color, 1, 20);
|
||||
dDbVw_drawCircleXlu(actor->eyePos, far_dist, far_color, 1, 20);
|
||||
|
||||
const s16 view_range = 0x4000;
|
||||
cXyz offset(0.0f, 0.0f, far_dist);
|
||||
cXyz endpos;
|
||||
|
||||
mDoMtx_stack_c::transS(actor->eyePos.x, actor->eyePos.y, actor->eyePos.z);
|
||||
mDoMtx_stack_c::YrotM(actor->shape_angle.y);
|
||||
mDoMtx_stack_c::YrotM(-view_range);
|
||||
mDoMtx_stack_c::multVec(&offset, &endpos);
|
||||
dDbVw_drawLineXlu(actor->eyePos, endpos, far_color, 1, 10);
|
||||
|
||||
mDoMtx_stack_c::transS(actor->eyePos.x, actor->eyePos.y, actor->eyePos.z);
|
||||
mDoMtx_stack_c::YrotM(actor->shape_angle.y);
|
||||
mDoMtx_stack_c::YrotM(view_range);
|
||||
mDoMtx_stack_c::multVec(&offset, &endpos);
|
||||
dDbVw_drawLineXlu(actor->eyePos, endpos, far_color, 1, 10);
|
||||
|
||||
mDoMtx_stack_c::transS(actor->eyePos.x, actor->eyePos.y, actor->eyePos.z);
|
||||
mDoMtx_stack_c::YrotM(actor->shape_angle.y);
|
||||
mDoMtx_stack_c::multVec(&offset, &endpos);
|
||||
dDbVw_drawLineXlu(actor->eyePos, endpos, far_color, 1, 10);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawAttentionDists(fopAc_ac_c* actor) {
|
||||
if (fopAcM_GetGroup(actor) != 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
GXColor lock_color = {0x00, 0x00, 0xFF, s_opacity};
|
||||
GXColor talk_color = {0x00, 0xFF, 0x00, s_opacity};
|
||||
|
||||
dist_entry& lock_inf = dAttention_c::getDistTable(actor->attention_info.distances[fopAc_attn_LOCK_e]);
|
||||
dist_entry& talk_inf = dAttention_c::getDistTable(actor->attention_info.distances[fopAc_attn_TALK_e]);
|
||||
|
||||
dDbVw_drawCircleXlu(actor->attention_info.position, lock_inf.mDistMax, lock_color, 1, 20);
|
||||
dDbVw_drawCircleXlu(actor->attention_info.position, talk_inf.mDistMax, talk_color, 1, 20);
|
||||
}
|
||||
|
||||
static void drawPurpleMistAvoid(fopAc_ac_c* actor) {
|
||||
kytag08_class* tag = (kytag08_class*)actor;
|
||||
|
||||
GXColor avoidColor = {0x00, 0xFF, 0x00, s_opacity};
|
||||
GXColor targetColor = {0xFF, 0x00, 0xFF, s_opacity};
|
||||
|
||||
dDbVw_drawCircleXlu(tag->mAvoidPos, tag->mSize.x * 45.0f * tag->mSizeScale, avoidColor, 1, 20);
|
||||
|
||||
cXyz cubeSize(10.0f, 10.0f, 10.0f);
|
||||
csXyz cubeAngle(0, 0, 0);
|
||||
dDbVw_drawCubeXlu(tag->mAvoidPos, cubeSize, cubeAngle, avoidColor);
|
||||
dDbVw_drawCubeXlu(tag->mTargetAvoidPos, cubeSize, cubeAngle, targetColor);
|
||||
}
|
||||
|
||||
static void drawLeeverData(fopAc_ac_c* actor) {
|
||||
e_rb_class* leever = (e_rb_class*)actor;
|
||||
|
||||
if (leever->isChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
GXColor color = {0xFF, 0x00, 0x00, s_opacity};
|
||||
GXColor color2 = {0x00, 0x00, 0xFF, s_opacity};
|
||||
|
||||
cXyz pos = actor->current.pos;
|
||||
daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0);
|
||||
if (player != nullptr && pos.y < player->mLinkAcch.GetGroundH()) {
|
||||
pos.y = player->mLinkAcch.GetGroundH() + 100.0f;
|
||||
}
|
||||
|
||||
dDbVw_drawCircleXlu(pos, leever->appearRange * 100.0f, color, 1, 20);
|
||||
dDbVw_drawCircleXlu(pos, leever->field_0xa69 * 100.0f, color2, 1, 20);
|
||||
}
|
||||
|
||||
void execute() {
|
||||
const auto& settings = getTransientSettings().triggerView;
|
||||
s_opacity = (u8)(255.0f * (settings.opacity / 100.0f));
|
||||
|
||||
if (settings.loadZones) {
|
||||
searchActorForCallback(fpcNm_SCENE_EXIT_e, drawSceneExit);
|
||||
}
|
||||
|
||||
if (settings.midnaStops) {
|
||||
searchActorForCallback(fpcNm_Tag_Mstop_e, drawMidnaStop);
|
||||
}
|
||||
|
||||
if (settings.switchAreas) {
|
||||
searchActorForCallback(fpcNm_SWC00_e, drawSwitchArea);
|
||||
}
|
||||
|
||||
if (settings.eventAreas) {
|
||||
searchActorForCallback(fpcNm_TAG_EVENT_e, drawEventTag);
|
||||
searchActorForCallback(fpcNm_TAG_EVTAREA_e, drawEventArea);
|
||||
searchActorForCallback(fpcNm_TAG_MYNA2_e, drawPlumTag);
|
||||
searchActorForCallback(fpcNm_MYNA2_e, drawPlumSearch);
|
||||
}
|
||||
|
||||
if (settings.twilightGates) {
|
||||
searchActorForCallback(fpcNm_Tag_TWGate_e, drawTWGate);
|
||||
}
|
||||
|
||||
if (settings.paths) {
|
||||
s_pathColorIndex = 0;
|
||||
drawStagePaths();
|
||||
drawCurrentRoomPaths();
|
||||
}
|
||||
|
||||
if (settings.checkpoints) {
|
||||
searchActorForCallback(fpcNm_Tag_ChgRestart_e, drawCheckpointTag);
|
||||
}
|
||||
|
||||
if (settings.transformDists) {
|
||||
searchActorForCallback(-1, drawTransformDists);
|
||||
}
|
||||
|
||||
if (settings.attentionDists) {
|
||||
searchActorForCallback(-1, drawAttentionDists);
|
||||
}
|
||||
|
||||
if (settings.purpleMistAvoid) {
|
||||
searchActorForCallback(fpcNm_KYTAG08_e, drawPurpleMistAvoid);
|
||||
}
|
||||
|
||||
if (settings.leevers) {
|
||||
searchActorForCallback(fpcNm_E_RB_e, drawLeeverData);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TriggerView
|
||||
} // namespace dusk
|
||||
@@ -92,6 +92,26 @@ namespace dusk {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
auto& triggerView = getTransientSettings().triggerView;
|
||||
if (ImGui::BeginMenu("Trigger View")) {
|
||||
ImGui::Checkbox("Load Zones", &triggerView.loadZones);
|
||||
ImGui::Checkbox("Event Areas", &triggerView.eventAreas);
|
||||
ImGui::Checkbox("Event Tags", &triggerView.eventTags);
|
||||
ImGui::Checkbox("Switch Areas", &triggerView.switchAreas);
|
||||
ImGui::Checkbox("Midna Stops", &triggerView.midnaStops);
|
||||
ImGui::Checkbox("Twilight Gates", &triggerView.twilightGates);
|
||||
ImGui::Checkbox("Checkpoints", &triggerView.checkpoints);
|
||||
ImGui::Checkbox("Paths", &triggerView.paths);
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox("Transform Distances", &triggerView.transformDists);
|
||||
ImGui::Checkbox("Attention Distances", &triggerView.attentionDists);
|
||||
ImGui::Checkbox("Purple Mist Avoid", &triggerView.purpleMistAvoid);
|
||||
ImGui::Checkbox("Leever Ranges", &triggerView.leevers);
|
||||
ImGui::Separator();
|
||||
ImGui::SliderFloat("Opacity##triggers", &triggerView.opacity, 0.0f, 100.0f);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (!dusk::IsGameLaunched) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
|
||||
+16
-1
@@ -354,7 +354,22 @@ static TransientSettings g_transientSettings = {
|
||||
.colliderViewOpacity = 50.0f,
|
||||
.drawRange = 100.0f,
|
||||
},
|
||||
.skipFrameRateLimit = false,
|
||||
.triggerView = {
|
||||
.loadZones = false,
|
||||
.eventAreas = false,
|
||||
.switchAreas = false,
|
||||
.eventTags = false,
|
||||
.midnaStops = false,
|
||||
.twilightGates = false,
|
||||
.checkpoints = false,
|
||||
.paths = false,
|
||||
.transformDists = false,
|
||||
.attentionDists = false,
|
||||
.purpleMistAvoid = false,
|
||||
.leevers = false,
|
||||
.opacity = 75.0f,
|
||||
},
|
||||
.skipFrameRateLimit = false
|
||||
};
|
||||
|
||||
TransientSettings& getTransientSettings() {
|
||||
|
||||
+1
-1
@@ -211,7 +211,7 @@ void show_top_document() noexcept {
|
||||
|
||||
bool any_document_visible() noexcept {
|
||||
return std::any_of(sDocumentStack.begin(), sDocumentStack.end(),
|
||||
[](const auto& doc) { return doc && doc->visible(); });
|
||||
[](const auto& doc) { return doc && doc->visible() && !doc->pending_close(); });
|
||||
}
|
||||
|
||||
bool is_prelaunch_open() noexcept {
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/game_clock.h"
|
||||
#include "dusk/gyro.h"
|
||||
#include "dusk/commands.hpp"
|
||||
#include "dusk/game_combos.h"
|
||||
#include "dusk/mouse.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
@@ -299,6 +300,7 @@ void main01(void) {
|
||||
dusk::gyro::read(pacing.sim_pace);
|
||||
dusk::processGameCombos();
|
||||
fapGm_Execute();
|
||||
dusk::processCameraCommands();
|
||||
mDoAud_Execute();
|
||||
dusk::game_clock::commit_sim_tick();
|
||||
}
|
||||
@@ -319,6 +321,7 @@ void main01(void) {
|
||||
dusk::mouse::read();
|
||||
dusk::gyro::read(pacing.presentation_dt_seconds);
|
||||
dusk::processGameCombos();
|
||||
dusk::processCameraCommands();
|
||||
|
||||
dusk::frame_interp::begin_frame(dusk::FrameInterpMode::Off, true, 0.0f);
|
||||
dusk::frame_interp::set_ui_tick_pending(true);
|
||||
|
||||
Reference in New Issue
Block a user