Skip to content

Commit b8ccfab

Browse files
committed
Majora's Mask: Unsheathe Sword Without Slashing
1 parent 8891d99 commit b8ccfab

23 files changed

Lines changed: 595 additions & 10 deletions

File tree

.github/workflows/Code-Mods.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,21 @@ jobs:
1818
uses: actions/setup-dotnet@v5
1919
with:
2020
dotnet-version: 10.0.x
21+
- name: Install Python
22+
uses: actions/setup-python@v6
23+
with:
24+
python-version: '3.13'
25+
- name: Install Python dependencies
26+
run: pip install -r "${{github.workspace}}/Requirements.txt"
2127
- name: Install Node
2228
uses: actions/setup-node@v6
2329
with:
2430
node-version: 24
2531
- name: Install artifact client
2632
uses: lhotari/gh-actions-artifact-client@v2
27-
- name: Build solutions
33+
- name: Build
2834
working-directory: ${{github.workspace}}
29-
run: ./Build.ps1 -Archive -BlockedSolutions "Project '06" -Configuration "${{matrix.configuration}}" -Clean
35+
run: ./Build.ps1 -Archive -BlockList "Project '06" -Configuration "${{matrix.configuration}}" -Clean
3036
- name: Upload artifacts
3137
run: |
3238
foreach ($filePath in [System.IO.Directory]::EnumerateFiles("${{github.workspace}}/Artifacts/", "*.zip", [System.IO.SearchOption]::AllDirectories))

Build.ps1

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
param
22
(
33
[Switch]$Archive,
4-
[String]$BlockedSolutions,
4+
[String]$BlockList,
55
[Switch]$Clean,
66
[String]$Configuration = "Release",
77
[Switch]$Help
88
)
99

1010
$work = $pwd
11-
$blockedSolutionsList = $BlockedSolutions.Split(";");
11+
$blockList = $BlockList.Split(";");
1212
$artifactsDir = [System.IO.Directory]::CreateDirectory([System.IO.Path]::Combine($work, "Artifacts"))
1313

1414
if ($Help)
@@ -17,8 +17,8 @@ if ($Help)
1717
Write-Host
1818
Write-Host "Parameters:"
1919
Write-Host "-Archive - archives the build artifacts."
20-
Write-Host "-BlockedSolutions - semi-colon separated list of solutions not to build."
21-
Write-Host "-Clean - clean the solutions before building."
20+
Write-Host "-BlockList - semi-colon separated list of projects not to build."
21+
Write-Host "-Clean - clean the projects before building."
2222
Write-Host "-Configuration [name] - build with a specific configuration."
2323
Write-Host "-Help - display help."
2424
exit
@@ -42,16 +42,26 @@ function GetProjectProperty([String]$in_projectPath, [String]$in_propertyName)
4242
return & msbuild /NoLogo /p:Configuration="${Configuration}" -getProperty:"${in_propertyName}" "${in_projectPath}"
4343
}
4444

45+
function IsDependency([String]$in_path)
46+
{
47+
return $in_path.Contains("Dependencies")
48+
}
49+
4550
function BuildSolutions([String]$in_root)
4651
{
4752
$root = [System.IO.Path]::Combine($work, $in_root)
4853

4954
foreach ($solutionPath in [System.IO.Directory]::EnumerateFiles($root, "*.sln", [System.IO.SearchOption]::AllDirectories))
5055
{
56+
if (IsDependency($solutionPath))
57+
{
58+
continue
59+
}
60+
5161
$solutionDir = Split-Path $solutionPath
5262
$solutionName = [System.IO.Path]::GetFileNameWithoutExtension($solutionPath)
5363

54-
if ($blockedSolutionsList.Contains($solutionName))
64+
if ($blockList.Contains($solutionName))
5565
{
5666
continue
5767
}
@@ -81,7 +91,7 @@ function BuildSolutions([String]$in_root)
8191
foreach ($projectPath in $projects)
8292
{
8393
$projectDir = GetProjectProperty $projectPath "ProjectDir"
84-
$projectName = GetProjectProperty $projectPath "ProjectName"
94+
$projectName = (GetProjectProperty $projectPath "ProjectName").Replace(" ", "")
8595
$binDir = [System.IO.Path]::Combine($projectDir, "bin")
8696

8797
foreach ($platformDir in [System.IO.Directory]::EnumerateDirectories($binDir))
@@ -107,7 +117,6 @@ function BuildSolutions([String]$in_root)
107117
Write-Host "* Cannot archive project binaries." -ForegroundColor DarkRed
108118
Write-Host "* Directory not found: ${targetDir}" -ForegroundColor DarkRed
109119
Write-Host ("***********************" + '*' * $targetDir.Length) -ForegroundColor DarkRed
110-
111120
exit -1
112121
}
113122

@@ -123,4 +132,66 @@ function BuildSolutions([String]$in_root)
123132
}
124133
}
125134

135+
function BuildMakefiles([String]$in_root)
136+
{
137+
$root = [System.IO.Path]::Combine($work, $in_root)
138+
139+
foreach ($makefilePath in [System.IO.Directory]::EnumerateFiles($root, "Makefile", [System.IO.SearchOption]::AllDirectories))
140+
{
141+
if (IsDependency($makefilePath))
142+
{
143+
continue
144+
}
145+
146+
$makefileDir = Split-Path $makefilePath
147+
$projectName = [System.IO.Path]::GetFileName($makefileDir)
148+
149+
if ($blockList.Contains($projectName))
150+
{
151+
continue
152+
}
153+
154+
$args = @()
155+
156+
if ($Clean)
157+
{
158+
$args += "clean"
159+
}
160+
161+
$args += "all"
162+
163+
Write-Host
164+
Write-Host ("**************" + '*' * $makefilePath.Length) -ForegroundColor DarkGreen
165+
Write-Host "* Makefile: ${makefilePath} *" -ForegroundColor DarkGreen
166+
Write-Host ("**************" + '*' * $makefilePath.Length) -ForegroundColor DarkGreen
167+
168+
& make -C "${makefileDir}" @args
169+
170+
if ($Archive)
171+
{
172+
$projectNameSafe = $projectName.Replace(" ", "")
173+
$binDir = [System.IO.Path]::Combine($makefileDir, "bin")
174+
$targetName = "${projectNameSafe}-${Configuration}.zip"
175+
176+
if (![System.IO.Directory]::Exists($binDir))
177+
{
178+
Write-Host
179+
Write-Host ("***********************" + '*' * $binDir.Length) -ForegroundColor DarkRed
180+
Write-Host "* Cannot archive project binaries." -ForegroundColor DarkRed
181+
Write-Host "* Directory not found: ${binDir}" -ForegroundColor DarkRed
182+
Write-Host ("***********************" + '*' * $binDir.Length) -ForegroundColor DarkRed
183+
exit -1
184+
}
185+
186+
$artifactRootDir = [System.IO.Directory]::CreateDirectory([System.IO.Path]::Combine($artifactsDir.FullName, $in_root, $projectName))
187+
$artifactTargetPath = [System.IO.Path]::Combine($artifactRootDir.FullName, $targetName)
188+
189+
cd $binDir
190+
Compress-Archive -Force * $artifactTargetPath
191+
cd $work
192+
}
193+
}
194+
}
195+
126196
BuildSolutions("Games")
197+
BuildMakefiles("Games/Zelda 64 Recompiled/Majora's Mask")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
*.d
2+
*.o
3+
*.elf
4+
*.bin
5+
*.exe
6+
*.dll
7+
*.lib
8+
*.pdb
9+
*.exp
10+
./funcs.h
11+
patches.map
12+
bin/
13+
.vscode/settings.json
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
TARGET_NAME := mod
2+
TARGET_DIR := bin
3+
TARGET_PATH := $(TARGET_DIR)/$(TARGET_NAME).elf
4+
TARGET_INFO := $(TARGET_NAME).toml
5+
6+
INT_DIR := obj
7+
8+
DECOMP_DIR := ../../Dependencies/mm
9+
TEMPLATE_DIR := ../../Dependencies/MMRecompModTemplate
10+
RECOMP_DIR := ../../Dependencies/N64Recomp
11+
TOOLS_ROOT_DIR := ../../Tools
12+
13+
ENV_SETUP_PATH := $(TOOLS_ROOT_DIR)/Setup.py
14+
ENV_PLATFORM := Windows
15+
ENV_ARCH := x64
16+
17+
SOURCES := *.c
18+
19+
INCLUDES := $(TEMPLATE_DIR)/include \
20+
$(TEMPLATE_DIR)/include/dummy_headers \
21+
$(DECOMP_DIR)/include \
22+
$(DECOMP_DIR)/src \
23+
$(DECOMP_DIR)/extracted/n64-us
24+
25+
INCLUDES_AFTER := include/libc $(DECOMP_DIR)/include/libc
26+
27+
ifeq ($(OS), Windows_NT)
28+
ENV_PLATFORM := Windows
29+
SHELL = cmd
30+
else ifeq ($(shell uname), Darwin)
31+
ENV_PLATFORM := macOS
32+
else
33+
ENV_PLATFORM := Linux
34+
endif
35+
36+
ifeq ($(OS), Windows_NT)
37+
ifeq ($(PROCESSOR_ARCHITECTURE), ARM64)
38+
ENV_ARCH := arm64
39+
else
40+
ENV_ARCH := x64
41+
endif
42+
else
43+
UNAME_P := $(shell uname -p)
44+
ifeq ($(UNAME_P), x86_64)
45+
ENV_ARCH := x64
46+
else ifneq ($(filter arm%,$(UNAME_P)),)
47+
ENV_ARCH := arm64
48+
endif
49+
endif
50+
51+
TOOLS_DIR := $(TOOLS_ROOT_DIR)/$(ENV_PLATFORM)/$(ENV_ARCH)
52+
CC := $(TOOLS_DIR)/nrs_bin/clang
53+
LD := $(TOOLS_DIR)/nrs_bin/ld.lld
54+
55+
LD_SCRIPT := $(TARGET_NAME).ld
56+
ARCH_FLAGS := -target mips -mips2 -mabi=32 -O2 -G0 -mno-abicalls -mno-odd-spreg -mno-check-zero-division \
57+
-fomit-frame-pointer -ffast-math -fno-unsafe-math-optimizations -fno-builtin-memset
58+
WARN_FLAGS := -Wall -Wextra -Wno-incompatible-library-redeclaration -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-variable \
59+
-Wno-missing-braces -Wno-unsupported-floating-point-opt -Werror=section
60+
C_FLAGS := $(ARCH_FLAGS) $(WARN_FLAGS) -D_LANGUAGE_C -nostdinc -ffunction-sections
61+
CPP_FLAGS := -DMIPS -DF3DEX_GBI_2 -DF3DEX_GBI_PL -DGBI_DOWHILE $(foreach dir,$(INCLUDES),-I $(dir)) $(foreach dir,$(INCLUDES_AFTER),-idirafter $(dir))
62+
LD_FLAGS := -nostdlib -T $(LD_SCRIPT) -Map $(TARGET_DIR)/$(TARGET_NAME).map --unresolved-symbols=ignore-all --emit-relocs -e 0 --no-nmagic -gc-sections
63+
64+
C_SRCS := $(foreach src,$(SOURCES),$(wildcard $(src)))
65+
C_OBJS := $(addprefix $(INT_DIR)/,$(C_SRCS:.c=.o))
66+
C_DEPS := $(addprefix $(INT_DIR)/,$(C_SRCS:.c=.d))
67+
68+
ALL_OBJS := $(C_OBJS)
69+
ALL_DEPS := $(C_DEPS)
70+
INT_DIRS := $(sort $(dir $(ALL_OBJS)))
71+
72+
all: setup $(TARGET_PATH) package
73+
74+
setup:
75+
python $(TOOLS_ROOT_DIR)/Setup.py $(ENV_PLATFORM) $(ENV_ARCH)
76+
77+
$(TARGET_PATH): $(ALL_OBJS) $(LD_SCRIPT) | $(INT_DIR)
78+
$(LD) $(ALL_OBJS) $(LD_FLAGS) -o $@
79+
80+
$(INT_DIR) $(INT_DIRS):
81+
ifeq ($(OS), Windows_NT)
82+
if not exist "$(subst /,\,$(TARGET_DIR))" mkdir "$(subst /,\,$(TARGET_DIR))"
83+
if not exist "$(subst /,\,$@)" mkdir "$(subst /,\,$@)"
84+
else
85+
mkdir -p $(TARGET_DIR)
86+
mkdir -p $@
87+
endif
88+
89+
$(C_OBJS): $(INT_DIR)/%.o : %.c | $(INT_DIRS)
90+
$(CC) $(C_FLAGS) $(CPP_FLAGS) $< -MMD -MF $(@:.o=.d) -c -o $@
91+
92+
clean:
93+
ifeq ($(OS), Windows_NT)
94+
if exist $(TARGET_DIR) rmdir /S /Q $(TARGET_DIR)
95+
if exist $(INT_DIR) rmdir /S /Q $(INT_DIR)
96+
else
97+
rm -rf $(TARGET_DIR)
98+
rm -rf $(INT_DIR)
99+
endif
100+
101+
-include $(ALL_DEPS)
102+
103+
.PHONY: clean all
104+
105+
package:
106+
$(TOOLS_DIR)/nrs_bin/RecompModTool $(TARGET_INFO) $(TARGET_DIR)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Unsheathe Sword Without Slashing
2+
Allows the player to unsheathe their sword without slashing first.
3+
4+
## Pre-requisites
5+
### Building
6+
- Make
7+
- Python (see `Requirements.txt`)
8+
9+
### Running
10+
- [Zelda 64 Recompiled](https://github.com/Zelda64Recomp/Zelda64Recomp)
11+
12+
## Downloads
13+
- GitHub [<sup>⚠️</sup>](## "Builds may be unavailable if this repository hasn't had a commit in the last 90 days.")
14+
- Thunderstore
15+
16+
## Acknowledgements
17+
Based on Jameriquiah's implementation of a patch of the same name in Shipwright.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "global.h"
2+
#include "modding.h"
3+
#include "recomputils.h"
4+
5+
extern s32 sPlayerUseHeldItem;
6+
extern s32 sPlayerHeldItemButtonIsHeldDown;
7+
8+
RECOMP_HOOK_RETURN("Player_UpperAction_ChangeHeldItem") s32 UnsheatheSwordWithoutSlashing(Player* this, PlayState* play)
9+
{
10+
if (this->heldItemId >= ITEM_SWORD_KOKIRI && this->heldItemId <= ITEM_SWORD_GILDED)
11+
{
12+
sPlayerUseHeldItem = sPlayerHeldItemButtonIsHeldDown = false;
13+
return true;
14+
}
15+
16+
return recomphook_get_return_s32();
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
RAMBASE = 0x81000000;
2+
3+
MEMORY
4+
{
5+
extram(ARWX) : ORIGIN = RAMBASE, LENGTH = 64M
6+
}
7+
8+
SECTIONS
9+
{
10+
/* All of the sections needed will get passed through to output sections automatically. */
11+
/* Therefore, all that's needed in the sections command is the discards. */
12+
/DISCARD/ : { *(.got) *(.MIPS.abiflags) *(.reginfo) *(.pdr) *(.comment) }
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[manifest]
2+
id = "mm_unsheathe_sword_without_slashing"
3+
version = "1.0.0"
4+
display_name = "Unsheathe Sword Without Slashing"
5+
description = "Allows the player to unsheathe their sword without slashing first."
6+
short_description = "Ready up for a fight."
7+
authors = [ "Hyper" ]
8+
game_id = "mm"
9+
minimum_recomp_version = "1.2.2"
10+
11+
[inputs]
12+
elf_path = "bin/mod.elf"
13+
mod_filename = "mm_unsheathe_sword_without_slashing"
14+
func_reference_syms_file = "../../Dependencies/Zelda64RecompSyms/mm.us.rev1.syms.toml"
15+
data_reference_syms_files = [ "../../Dependencies/Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "../../Dependencies/Zelda64RecompSyms/mm.us.rev1.datasyms_static.toml" ]
16+
additional_files = [ "thumb.dds" ]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## 1.0.0
2+
- Initial release.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Unsheathe Sword Without Slashing
2+
Allows the player to unsheathe their sword without slashing first.
3+
4+
## Acknowledgements
5+
Based on Jameriquiah's implementation of a patch of the same name in Shipwright.

0 commit comments

Comments
 (0)