Merge branch 'main' of https://github.com/TwilitRealm/dusk into randomizer

This commit is contained in:
gymnast86
2026-04-28 14:45:45 -07:00
8 changed files with 117 additions and 3 deletions
+6
View File
@@ -3,6 +3,10 @@
- ### **[Official Website](https://twilitrealm.dev)**
- ### **[Discord](https://discord.gg/QACynxeyna)**
# Overview
Dusk is a reverse-engineered reimplementation of Twilight Princess.
It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience.
# Setup
**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.**
@@ -27,5 +31,7 @@ First make sure your dump of the game is clean and supported by Dusk. You can do
# Building
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md).
Pull Requests are welcomed! Note that we do not accept contributions that are primarily AI generated and will close your PR if we suspect as much.
# Credits
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors).
+1 -1
+8
View File
@@ -4,6 +4,8 @@
#include <functional>
#include <queue>
#include <string>
#include <string_view>
#include <unordered_set>
#include <vector>
#include "nlohmann/json.hpp"
@@ -14,6 +16,7 @@ enum class AchievementCategory : uint8_t {
Collection,
Challenge,
Minigame,
Misc,
Glitched
};
@@ -42,6 +45,10 @@ public:
void clearAll();
void clearOne(const char* key);
// Signals are visible to all achievement checks within the same tick, then cleared.
void signal(const char* key);
bool hasSignal(const char* key) const;
std::vector<Achievement> getAchievements() const;
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
std::string consumePendingUnlock();
@@ -58,6 +65,7 @@ private:
void processEntry(Entry& e);
std::vector<Entry> m_entries;
std::unordered_set<std::string_view> m_signals;
bool m_loaded = false;
bool m_dirty = false;
std::queue<std::string> m_pendingUnlocks;
+13
View File
@@ -8,6 +8,10 @@
#include "d/actor/d_a_horse.h"
#include "d/actor/d_a_crod.h"
#include "d/d_msg_object.h"
#ifdef TARGET_PC
#include "d/actor/d_a_obj_carry.h"
#include "dusk/achievements.h"
#endif
#if DEBUG
#include "d/d_s_menu.h"
@@ -677,6 +681,15 @@ BOOL daAlink_c::checkDamageAction() {
}
setDamagePoint(dmg, at_mtrl == dCcD_MTRL_FIRE || at_mtrl == dCcD_MTRL_ICE, TRUE, 0);
#ifdef TARGET_PC
if (tghit_ac_name == fpcNm_Obj_Carry_e) {
auto* carry = static_cast<daObjCarry_c*>(tghit_ac);
if (carry->prm_chk_type_ironball() && carry->checkCannon()) {
dusk::AchievementSystem::get().signal("iron_ball_hit_player");
}
}
#endif
if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) {
setGuardSe(var_r29);
+4
View File
@@ -18,6 +18,10 @@ enum {
};
void daAlink_c::hsChainShape_c::draw() {
if (dusk::getSettings().game.superClawshot) {
return;
}
static const int dummy = 0;
daAlink_c* alink = (daAlink_c*)getUserArea();
+5
View File
@@ -282,6 +282,11 @@ static void e_th_spin_B(e_th_class* i_this) {
i_this->current.pos += spC;
f32 speed_target;
#if AVOID_UB
speed_target = 0;
#endif
f32 anm_frame = i_this->mpModelMorf->getFrame();
switch (i_this->mMode) {
+77
View File
@@ -8,6 +8,7 @@
#include "d/actor/d_a_player.h"
#include "d/d_demo.h"
#include "f_pc/f_pc_name.h"
#include "f_op/f_op_actor_mng.h"
#include <filesystem>
#include <algorithm>
@@ -46,6 +47,21 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
},
{}
},
{
{
"plumm_max",
"Thank You Berry Much",
"Score 61,454 points in the Plumm minigame.",
AchievementCategory::Minigame,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_getBalloonScore() >= 61454) {
a.progress = 1;
}
},
{}
},
{
{
"rollgoal_8",
@@ -258,6 +274,58 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
},
{}
},
{
{
"friendly_fire",
"Friendly Fire",
"Get hit by your own cannonball.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (AchievementSystem::get().hasSignal("iron_ball_hit_player")) {
a.progress = 1;
}
},
{}
},
{
{
"long_jump_attack",
"Long Jump Attack",
"Travel more than 20 meters in a single jump attack before landing.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
static bool inJump = false;
static float startX = 0.0f, startZ = 0.0f;
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr) {
inJump = false;
return;
}
if (!inJump) {
if (link->mProcID == daAlink_c::PROC_CUT_JUMP) {
inJump = true;
startX = link->current.pos.x;
startZ = link->current.pos.z;
}
} else if (link->mProcID == daAlink_c::PROC_CUT_JUMP_LAND) {
inJump = false;
const float dx = link->current.pos.x - startX;
const float dz = link->current.pos.z - startZ;
if (dx * dx + dz * dz >= 2000.0f * 2000.0f) {
a.progress = 1;
}
} else if (link->mProcID != daAlink_c::PROC_CUT_JUMP) {
inJump = false;
}
},
{}
},
{
{
"back_in_time",
@@ -426,6 +494,14 @@ void AchievementSystem::clearAll() {
save();
}
void AchievementSystem::signal(const char* key) {
m_signals.insert(key);
}
bool AchievementSystem::hasSignal(const char* key) const {
return m_signals.count(key) > 0;
}
void AchievementSystem::clearOne(const char* key) {
for (auto& e : m_entries) {
if (std::string(e.achievement.key) == key) {
@@ -470,6 +546,7 @@ void AchievementSystem::tick() {
for (auto& e : m_entries) {
processEntry(e);
}
m_signals.clear();
if (m_dirty) {
save();
m_dirty = false;
+3 -2
View File
@@ -76,8 +76,8 @@ void ImGuiAchievements::draw(bool& open) {
return;
}
ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900));
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900));
ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(
"Achievements", &open,
@@ -111,6 +111,7 @@ void ImGuiAchievements::draw(bool& open) {
{AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)},
{AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)},
{AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)},
{AchievementCategory::Misc, "Misc", ImVec4(0.65f, 0.65f, 0.65f, 1.0f)},
{AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)},
};