Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions romfs/spoiler-log.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
:root {
padding: 1.5rem 3rem;
font-size: 16px;
font-family: monospace;
}

spoiler-log::before {
display: block;
content: "Version: " attr(version) "\ASeed: " attr(seed) "\AHash: " attr(hash);
white-space: pre;
margin-bottom: 1em;;
}

/* Collapsible content */
.collapse {
display: block;
float: left;
appearance: none;
--checkbox-size: 2.5rem;
}

:is(playthrough, entrance-playthrough) .collapse {
--checkbox-size: 1.3rem !important;
margin-left: 3rem;
}

.collapse::before {
display: block;
content: "🞃";
height: var(--checkbox-size);
width: var(--checkbox-size);
font-size: var(--checkbox-size);
line-height: var(--checkbox-size);
position: relative;
font-weight: bolder;
}

.collapse:checked::before {
content: "🞂";
}

.collapse:checked + * > * {
display: none;
}

/* Hidden sections */
settings *, /* Making the `settings` itself tag be displayable but hiding its sub-elements so we can use `settings::before` to display the "Hide spoilers" text */
excluded-locations,
enabled-tricks,
enabled-glitches,
required-trials,
song-notes,
enemies,
hints {
display: none;
}

/* Headers */
starting-inventory,
gold-skulltulas,
playthrough,
way-of-the-hero-locations,
entrance-playthrough,
all-locations,
master-quest-dungeons {
display: block;
border-collapse: collapse;
}

:is(starting-inventory,
gold-skulltulas,
playthrough,
way-of-the-hero-locations,
entrance-playthrough,
all-locations,
master-quest-dungeons)::before {
display: block;
font-size: 2.5rem;
}

starting-inventory::before { content: "Starting inventory:"; }
gold-skulltulas::before { content: "Gold Skulltulas:"; }
playthrough::before { content: "Playthrough:"; }
way-of-the-hero-locations::before { content: "Way of the Hero locations:"; }
entrance-playthrough::before { content: "Entrance playthrough:"; }
all-locations::before { content: "All locations:"; }
master-quest-dungeons::before { content: "Master Quest dungeons:"; }

sphere {
display: block;
margin-left: 3rem;
}

sphere::before {
display: block;
font-size: 1.5rem;
content: "Sphere " attr(level) ":";
}

/* Items */
item, gs, location, dungeon, entrance {
display: table-row;
border-bottom: 1px solid black;
}

:is(item, gs, location, dungeon, entrance):last-child {
border-bottom: none;
}

:is(item, gs, location, dungeon, entrance)::before {
display: table-cell;
content: attr(name);
padding-right: 2rem;
padding-left: 3rem;
padding-top: 0.4rem;
padding-bottom: 0.4rem;
user-select: text;
}

:is(item, gs, location, dungeon, entrance)::after {
display: table-cell;
content: "";
}

[price]::after {
display: table-cell;
content: " (" attr(price) " rupees)";
margin-left: 1rem;
}

/* Hide spoilers button */
#hide-spoilers + *::before {
display: block;
font-size: 2.3rem;
content: "Hide spoilers";
margin-bottom: 1rem;
}

#hide-spoilers {
appearance: none;
display: block;
position: relative;
float: left;
margin-right: 1rem;
top: 0.2rem;
}

#hide-spoilers::after {
display: inline-block;
content: "";
width: 1.5rem;
height: 1.5rem;
background-color: #fff;
border-radius: 0.75rem;
position: absolute;
top: 0.25rem;
left: 0.25rem;
transition-property: left;
transition-duration: 0.3s;
}

#hide-spoilers:checked::after {
left: 2.25rem;;
}

#hide-spoilers::before {
display: inline-block;
content: "";
width: 4rem;
height: 2rem;
background-color: #888;
border-radius: 1rem;
transition-property: background-color;
transition-duration: 0.3s;
}

#hide-spoilers:checked::before {
background-color: #5252e4;
}

/* Hidden spoilers */
#hide-spoilers:checked ~ * :is(gs, location, dungeon, entrance) {
background-color: #000;
}

/* Don't need to hide the location names for these */
gs::before, all-locations location::before, entrance::before {
background-color: #fff;
}

#hide-spoilers:checked ~ * :is(gs, location, dungeon, entrance):hover {
background-color: #fff;
}
2 changes: 1 addition & 1 deletion source/include/spoiler_log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

using RandomizerHash = std::array<std::string, 5>;

void CreateLogDirectories(FS_Archive sdmcArchive);
void InitLogDirectories(FS_Archive sdmcArchive);

void GenerateHash();
const RandomizerHash& GetRandomizerHash();
Expand Down
11 changes: 9 additions & 2 deletions source/include/utils.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#pragma once

#include <algorithm>
#include <string>
#include <3ds.h>

/// Returns a new string with:
/// - Leading spaces removed.
/// - Line breaks replaced with spaces.
/// - Consecutive spaces removed.
std::string SanitizedString(std::string s);

bool CopyFile(FS_Archive sdmcArchive, const char* dst, const char* src);

std::string RemoveLineBreaks(std::string s);
2 changes: 1 addition & 1 deletion source/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void MenuInit() {
// Create directories
FS_Archive sdmcArchive;
if (R_SUCCEEDED(FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")))) {
CreateLogDirectories(sdmcArchive);
InitLogDirectories(sdmcArchive);
CreatePresetDirectories(sdmcArchive);

FSUSER_CloseArchive(sdmcArchive);
Expand Down
35 changes: 3 additions & 32 deletions source/patch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "spoiler_log.hpp"
//#include "entrance.hpp"
#include "item_location.hpp"
#include "utils.hpp"

#include <array>
#include <cstring>
Expand All @@ -19,38 +20,6 @@

using FILEPtr = std::unique_ptr<FILE, decltype(&std::fclose)>;

bool CopyFile(FS_Archive sdmcArchive, const char* dst, const char* src) {
Result res = 0;
Handle outFile;
u32 bytesWritten = 0;
// Delete dst if it exists
FSUSER_DeleteFile(sdmcArchive, fsMakePath(PATH_ASCII, dst));

// Open dst destination
if (!R_SUCCEEDED(res = FSUSER_OpenFile(&outFile, sdmcArchive, fsMakePath(PATH_ASCII, dst), FS_OPEN_WRITE | FS_OPEN_CREATE, 0))) {
return false;
}

if (auto file = FILEPtr{std::fopen(src, "r"), std::fclose}) {
// obtain file size
fseek(file.get(), 0, SEEK_END);
const auto lSize = static_cast<size_t>(ftell(file.get()));
rewind(file.get());

// copy file into the buffer
std::vector<char> buffer(lSize);
fread(buffer.data(), 1, buffer.size(), file.get());

// Write the buffer to final destination
if (!R_SUCCEEDED(res = FSFILE_Write(outFile, &bytesWritten, 0, buffer.data(), buffer.size(), FS_WRITE_FLUSH))) {
return false;
}
}

FSFILE_Close(outFile);
return true;
}

bool WritePatch(u32 patchOffset, s32 patchSize, char* patchDataPtr, Handle& code, u32& bytesWritten, u32& totalRW, char* buf) {

//patch sizes greater than PATCH_SIZE_MAX have to be split up due to IPS patching specifications
Expand Down Expand Up @@ -510,5 +479,7 @@ bool WriteAllPatches() {

FSUSER_CloseArchive(sdmcArchive);

romfsExit();

return true;
}
8 changes: 4 additions & 4 deletions source/preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ bool SavePreset(std::string_view presetName, OptionCategory category) {
}

XMLElement* newSetting = rootNode->InsertNewChildElement("setting");
newSetting->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str());
newSetting->SetAttribute("name", SanitizedString(setting->GetName()).c_str());
newSetting->SetText(setting->GetSelectedOptionText().c_str());
}
}
Expand Down Expand Up @@ -160,8 +160,8 @@ bool LoadPreset(std::string_view presetName, OptionCategory category) {
}
// Since presets are saved linearly, we can simply loop through the nodes as
// we loop through the settings to find most of the matching elements.
const std::string& settingToFind = RemoveLineBreaks(setting->GetName());
if (settingToFind == RemoveLineBreaks(curNode->Attribute("name"))) {
const std::string& settingToFind = SanitizedString(setting->GetName());
if (settingToFind == SanitizedString(curNode->Attribute("name"))) {
setting->SetSelectedIndexByString(curNode->GetText());
curNode = curNode->NextSiblingElement();
} else {
Expand All @@ -170,7 +170,7 @@ bool LoadPreset(std::string_view presetName, OptionCategory category) {
// next setting and element line up with each other.
curNode = rootNode->FirstChildElement();
while (curNode != nullptr) {
if (settingToFind == RemoveLineBreaks(curNode->Attribute("name"))) {
if (settingToFind == SanitizedString(curNode->Attribute("name"))) {
setting->SetSelectedIndexByString(curNode->GetText());
curNode = curNode->NextSiblingElement();
break;
Expand Down
Loading