Compare commits

..

No commits in common. "main" and "jokers" have entirely different histories.
main ... jokers

164 changed files with 3874 additions and 19082 deletions

View File

@ -1,56 +0,0 @@
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
# Allman brace style
BreakBeforeBraces: Allman
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLoopsOnASingleLine: false
# Pointer alignment
PointerAlignment: Left
# Column limit
ColumnLimit: 100
# Case labels
IndentCaseLabels: true
# Include sorting
SortIncludes: CaseSensitive
IncludeBlocks: Regroup
ContinuationIndentWidth: 4
AlignArrayOfStructures: Left
PackConstructorInitializers: Never
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterFunctionDefinitionName: false
AlignOperands: AlignAfterOperator
BreakBeforeBinaryOperators: None
IndentPPDirectives: None
AlignConsecutiveMacros: Consecutive
BinPackArguments: false
BinPackParameters: false
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AlignAfterOpenBracket: BlockIndent
PenaltyBreakBeforeFirstCallParameter: 0
ReflowComments: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: 1
PenaltyReturnTypeOnItsOwnLine: 99999999
AlignEscapedNewlines: Left
BracedInitializerIndentWidth: 0

View File

@ -1,33 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
type: bug
assignees:
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
Any helpful screenshots or videos
**What version**
- **Nightly**: If you downloaded the ROM you can provide either the ROM name, or the name of the zipfile
- **Mainline Release**: Please provide the name of the release (**Joker Build**, **Itemless Build**, etc)
- **Built From (Unmodified) Source**: Please specify the branch (e.g. main) and latest commit in your build. If you modified the code, make sure it reproduces in unmodified code before reporting.
- **I Don't Know**: Upload a zip of the rom you used. Alternatively, please try to use the `build_bug_report.py` script in the `scripts/` directory. If there is no output from that, then try to recreate your bug with a new version.
**What Emulator or Platform were you playing on**
- e.g. mgba, flashcart
**Additional context**
Add any other context about the problem here.

View File

@ -7,72 +7,55 @@ on:
pull_request:
branches:
- main
workflow_dispatch:
inputs:
clear-cache:
description: 'Clear docker cache before running'
type: boolean
default: false
workflow_call:
inputs:
upload-build-artifact:
required: true
type: boolean
default: true
jobs:
clang-format-job:
name: Run clang-format test
uses: ./.github/workflows/clang_format_ci_workflow.yml
unit-tests-job:
name: Run unit tests
uses: ./.github/workflows/unit_tests_ci_workflow.yml
build:
name: Build ROM
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Get docker image cache
uses: actions/cache@v5
- name: Set devkitPro environment variables
run: |
# Installing to home directory to avoid permission denied on caching
echo "DEVKITPRO=/home/runner/devkitpro" >> $GITHUB_ENV
echo "DEVKITARM=/home/runner/devkitpro/devkitARM" >> $GITHUB_ENV
export PATH=$DEVKITARM/bin:$DEVKITPRO/tools/bin:$PATH
# Caching to avoid excessive request to the devkitpro server from a runner because they
# eventually block and result in permission denied 403.
# If that happens it takes like 2 hours until you can make requests again
- name: Cache devkitPro toolchain
id: cache-devkitpro
uses: actions/cache@v4
with:
path: /tmp/docker-cache
key: docker-images-${{ hashFiles('docker-compose.yml') }}
path: /home/runner/devkitpro
# Using a manual key version suffix - v{num}, if changes are made that make the
# cache stale and require a refresh, just bump the version number so there's
# a cache miss. The key needs to match in the "Save devkitPro to cache" stage
# so you need to bump the number there too...
key: devkitpro-${{ runner.os }}-v1
- name: Clear docker cache (if requested)
if: github.event.inputs.clear-cache == 'true'
- name: Set up devkitARM (if not cached)
if: steps.cache-devkitpro.outputs.cache-hit != 'true'
run: |
echo "Clearing Docker cache..."
rm -rf /tmp/docker-cache
echo "Docker cache cleared"
- name: Load or pull images
run: |
if [ -f /tmp/docker-cache/gbalatro.tar ]; then
echo "Loading Image"
docker load -i /tmp/docker-cache/gbalatro.tar
else
echo "Pulling Image"
docker compose build gbalatro
mkdir -p /tmp/docker-cache
docker save $(docker compose config | grep image: | awk '{print $2}') -o /tmp/docker-cache/gbalatro.tar
fi
- name: Export UID/GID for Compose
run: |
echo "UID=$(id -u)" >> "$GITHUB_ENV"
echo "GID=$(id -g)" >> "$GITHUB_ENV"
sudo apt update
wget https://apt.devkitpro.org/install-devkitpro-pacman
chmod +x install-devkitpro-pacman
sudo ./install-devkitpro-pacman
mkdir -p "$DEVKITPRO"
sudo dkp-pacman -Sy --noconfirm gba-dev
# Copy from installed directory to cacheable directory
sudo cp -r /opt/devkitpro "/home/runner"
sudo chown -R $USER:$USER "/home/runner/devkitpro"
- name: Save devkitPro to cache
if: steps.cache-devkitpro.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: /home/runner/devkitpro
key: devkitpro-${{ runner.os }}-v1
- name: Build the project
run: docker compose -f docker-compose.yml run --rm gbalatro sh -c "make -j$(nproc) && ./scripts/get_memory_map.sh"
- name: 'Upload Artifact'
if: ${{ inputs.upload-build-artifact }}
uses: actions/upload-artifact@v6
with:
name: build-out
path: build
retention-days: 5
run: |
make

View File

@ -1,20 +0,0 @@
name: Run Clang Format Test
on:
workflow_dispatch:
workflow_call:
jobs:
run-test:
name: Verify code formatting
runs-on: ubuntu-latest
steps:
- name: Install clang-format
run: |
sudo apt-get update
sudo apt-get install -y clang-format
- name: Checkout repository
uses: actions/checkout@v6
- name: Run clang-format
run: clang-format --dry-run -Werror include/*.h source/*.c

View File

@ -1,32 +0,0 @@
name: Build and Deploy Doxygen Docs
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: write
jobs:
docs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Doxygen
run: sudo apt-get install -y doxygen graphviz
- name: Build Doxygen documentation
run: doxygen Doxyfile
- name: Deploy to GitHub Pages
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./doc/html
publish_branch: gh-pages

View File

@ -1,43 +0,0 @@
name: Deploy Nightly
permissions:
contents: write
on:
schedule:
- cron: '0 2 * * *' # run at 2 AM UTC
workflow_dispatch:
jobs:
build-job:
name: Run Build ROM Workflow
uses: ./.github/workflows/build_ci_workflow.yml
with:
upload-build-artifact: true
nightly:
name: Deploy nightly
needs: build-job
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Download the build output
uses: actions/download-artifact@v8
with:
name: build-out
path: build
- name: Package Release
run: mv build/balatro-gba.gba build/balatro-gba_nightly_$(date +'%+4Y%m%d')_$(cat build/githash.txt).gba && zip -j release build/*.gba
- name: Deploy release
uses: WebFreak001/deploy-nightly@v3.2.0
with:
upload_url: https://uploads.github.com/repos/GBALATRO/balatro-gba/releases/258698380/assets{?name,label}
release_id: 258698380
asset_path: ./release.zip # path to archive to upload
asset_name: nightly-gbalatro-$$.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
asset_content_type: application/zip
max_releases: 7
ignore_hash: false # Only upload unique versions

View File

@ -1,30 +0,0 @@
name: Release On Version Tag
on:
push:
tags:
- "v*"
jobs:
build-job:
name: Run Build ROM Workflow
uses: ./.github/workflows/build_ci_workflow.yml
with:
upload-build-artifact: true
release:
name: Release Tagged Version
runs-on: ubuntu-latest
needs: build-job
steps:
- name: Download the build output
uses: actions/download-artifact@v8
with:
name: build-out
path: build
- uses: softprops/action-gh-release@v2
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
files: |
build/balatro-gba.gba

View File

@ -1,21 +0,0 @@
name: Run Unit Tests
on:
workflow_dispatch:
workflow_call:
jobs:
run-unit-tests:
name: Run Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Check and install GCC version
run: ./ci_scripts/check_gcc_version.sh
- name: Run Unit Tests
run: cd tests && ./run_tests.sh

10
.gitignore vendored
View File

@ -1,16 +1,6 @@
/.vscode
/.idea
/build
/saved_builds
/.vs
_codeql_detected_source_root
*.sln
*.vcxproj*
/balatro-gba/x64/**
/tests/bitset/build
/tests/list/build
/tests/pool/build
doc
tests/util/.vscode
tests/util/build
audio/*.bak

View File

@ -1,103 +0,0 @@
# Developer Guide
Thank you for reading this. Below is a quick summary of expectations and tips to contribute.
## Scope
We are limiting the scope of the project in order to not compete with the original Balatro and avoid a takedown by Playstack.
We limited the scope to 52 jokers and reached that limit so currently there is no plan to add more jokers.
See [the scope discussion](https://github.com/GBALATRO/balatro-gba/discussions/355).
## Art
Before contributing art or if you need art for a code contribution check the [existing additional art thread](https://github.com/GBALATRO/balatro-gba/discussions/131) and the [joker art discussion](https://github.com/GBALATRO/balatro-gba/discussions/69) (though as said no more jokers are currently planned).
Note that there are color limitations for sprites and backgrounds resulting due to the GBA hardware. Sprites may not use more than 16 colors per sprite including transparency.
Backgrounds may use more colors but notice that their palette is encoded in their PNGs and new colors need to be added manually to the palette. [See relevant PR](https://github.com/GBALATRO/balatro-gba/pull/350).
## CI Checks
On pull-requests, various checks will be performed:
1. **Formatting**: `clang-format` will be ran on every `.c/.h` file with [this configuration](https://github.com/GBALATRO/balatro-gba/blob/main/.clang-format). Failures will cause the CI to fail.
2. **Unit Tests**: Unit tests are required to pass and are located in the repo [here](https://github.com/GBALATRO/balatro-gba/tree/main/tests).
3. **Rom Build**: The ROM must successfully build with the `make -j$(nproc)` command.
## Code Style
Besides the automatic formatting checks from `clang-format`, there is a looser set of code style rules. These are not strictly required, but is encouraged to be followed.
The following details the code style rules including the enforced clang-format style.
[Link in wiki](https://github.com/GBALATRO/balatro-gba/wiki/Code-Style-Guide)
## Documentation
Doxygen is used to build docs that can be opened in browser.
We host the docs for the main branch on github [here](https://gbalatro.github.io/balatro-gba)
You can also choose to build the docs yourself [Link in wiki](https://github.com/GBALATRO/balatro-gba/wiki/Documentation-for-Developers)
## Tools
### clang-format
Running `clang-format` locally is recommended before submitting a PR as it will fail the **CI Checks** if not properly formatted. It is recommended either:
1. Run `clang-format` periodically and only commit formatted code.
2. Run `clang-format` as a separate commit on larger changes, and review each modified hunk.
Either way, just ensure you manually review automatic changes.
#### VSCode
The recommended setup for VSCode is to install the [**clangd**](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd) extension. It will provide helpful information in VSCode and can be used to format the code automatically according to the `.clang-format` file with **`Ctrl+Shift+I`**
There is an option to enable `"editor.formatOnSave"` in the VSCode `settings.json` file. You can also do this by opening the settings menu (`File->Preferences->Settings`) and searching `format on save`.
#### Manually
If installed locally and you'd prefer to use it in your shell. You can do the following
```sh
# List warnings
clang-format --dry-run -Werror include/*.h source/*.c
# Modify all files inplace
clang-format -i include/*.h source/*.c
# Or just one
clang-format -i include/blind.h
```
#### Disabling Formatting
Sometimes `clang-format` rules need to be broken, like in the case of the [joker registry](https://github.com/GBALATRO/balatro-gba/blob/8fb0813cf5f7235b6450dc9a76252dda4d9b4a27/source/joker_effects.c#L333) and other tables or maps. If it makes sense, you can wrap code in `// clang-format off` and `// clang-format on`:
- **Without clang-format**:
```c
// clang-format off
const table_of_tables =
{
{ TABLE_A, 1, tableAMap },
{ TABLE_B, 2, tableBMap },
{ TABLE_C, 3, tableCMap },
{ TABLE_D, 4, tableDMap },
{ TABLE_E, 5, tableEMap },
{ TABLE_F, 6, tableFMap },
{ TABLE_G, 7, tableGMap },
}
// clang-format on
```
- **With clang-format**:
```c
const table_of_tables =
{
{TABLE_A, 1, tableAMap}, {TABLE_B, 2, tableBMap}, {TABLE_C, 3, tableCMap},
{TABLE_D, 4, tableDMap}, {TABLE_E, 5, tableEMap}, {TABLE_F, 6, tableFMap},
{TABLE_G, 7, tableGMap},
}
```
### Custom Scripts
In the repo we use custom scripts located in the [`scripts`](https://github.com/GBALATRO/balatro-gba/tree/main/scripts) directory.
🟡 **Note**: `python3` and `bash` are required for these scripts.
- **get_hash.py**: Get git hash from ROM.
- **generate_font.py**: Generate a font manually.
- **get_memory_map.sh**: Print the memory map of the pre-allocated pools.
- **save_build.sh**: Save a timestamped copy of build outputs (.elf, .gba, .map).
## Debugging
It's recommended to use [mGBA](https://mgba.io/) for ROM testing and debugging. As it provides a [`gdbserver`](https://en.wikipedia.org/wiki/Gdbserver) via the `-g` flag `mgba -g build/balatro-gba.gba`. You can connect via `gdb` or here is a [great guide for vscode](https://felixjones.co.uk/mgba_gdb/vscode.html).

View File

@ -1,6 +0,0 @@
FROM devkitpro/devkitarm:20251117
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
python3-pil

3025
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@ -25,37 +25,30 @@ LIBTONC := $(DEVKITPRO)/libtonc
# the makefile is found
#
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source source/game
INCLUDES := include include/game
DATA :=
MUSIC := audio
GRAPHICS := graphics
FONT := font
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
INCLUDES := include
DATA :=
MUSIC := audio
GRAPHICS := graphics
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
GIT_DIRTY := $(shell git diff-index --quiet HEAD -- || echo "-dirty")
GIT_HASH := $(shell git rev-parse --short HEAD || echo "undef")
GIT_C_FLAGS := -DGIT_HASH=\"$(GIT_HASH)\" -DGIT_DIRTY=\"$(GIT_DIRTY)\"
CFLAGS := -g -O3 -Wall -Werror -std=gnu23 \
CFLAGS := -g -O3 -Wall -Werror\
-mcpu=arm7tdmi -mtune=arm7tdmi \
-ffast-math -fomit-frame-pointer -funroll-loops \
$(ARCH)
CFLAGS += $(GIT_C_FLAGS)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map),--undefined=balatro_version
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
@ -83,8 +76,7 @@ export OUTPUT := $(CURDIR)/$(BUILD)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \
$(foreach dir,$(FONT),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
@ -92,7 +84,6 @@ CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
FONTFILES := $(foreach dir,$(FONT),$(notdir $(wildcard $(dir)/*.png)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
ifneq ($(strip $(MUSIC)),)
@ -120,9 +111,7 @@ export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES_GRAPHICS := $(PNGFILES:.png=.o)
export OFILES_FONT := $(FONTFILES:.png=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES) $(OFILES_GRAPHICS) $(OFILES_FONT)
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES) $(OFILES_GRAPHICS)
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES))) $(PNGFILES:.png=.h)
@ -135,22 +124,16 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD): build/gbalatro_sys8.s
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
@echo "$(GIT_HASH)$(GIT_DIRTY)" > $@/githash.txt
#---------------------------------------------------------------------------------
build/%.s: $(FONT)/%.png
@echo Building font
@mkdir -p $(BUILD)
@python3 scripts/generate_font.py -i $< -o $@
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba
#---------------------------------------------------------------------------------
all: $(BUILD)

121
README.md
View File

@ -1,20 +1,21 @@
# Balatro-GBA
[![Build Status](https://img.shields.io/github/actions/workflow/status/cellos51/balatro-gba/build_ci_workflow.yml?style=flat&logo=github&branch=main&label=Builds&labelColor=gray&color=default&maxAge=7200)](https://github.com/cellos51/balatro-gba/actions)
[![Open Issues](https://img.shields.io/github/issues/cellos51/balatro-gba?style=flat&color=red&label=Issues&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTggOS41YTEuNSAxLjUgMCAxIDAgMC0zIDEuNSAxLjUgMCAwIDAgMCAzWiI+PC9wYXRoPjxwYXRoIGZpbGw9IndoaXRlIiBkPSJNOCAwYTggOCAwIDEgMSAwIDE2QTggOCAwIDAgMSA4IDBaTTEuNSA4YTYuNSA2LjUgMCAxIDAgMTMgMCA2LjUgNi41IDAgMCAwLTEzIDBaIj48L3BhdGg+PC9zdmc+)](https://github.com/cellos51/balatro-gba/issues)
[![Pull Requests](https://img.shields.io/github/issues-pr/cellos51/balatro-gba?style=flat&color=indigo&label=Pull%20Requests&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTEuNSAzLjI1YTIuMjUgMi4yNSAwIDEgMSAzIDIuMTIydjUuMjU2YTIuMjUxIDIuMjUxIDAgMSAxLTEuNSAwVjUuMzcyQTIuMjUgMi4yNSAwIDAgMSAxLjUgMy4yNVptNS42NzctLjE3N0w5LjU3My42NzdBLjI1LjI1IDAgMCAxIDEwIC44NTRWMi41aDFBMi41IDIuNSAwIDAgMSAxMy41IDV2NS42MjhhMi4yNTEgMi4yNTEgMCAxIDEtMS41IDBWNWExIDEgMCAwIDAtMS0xaC0xdjEuNjQ2YS4yNS4yNSAwIDAgMS0uNDI3LjE3N0w3LjE3NyAzLjQyN2EuMjUuMjUgMCAwIDEgMC0uMzU0Wk0zLjc1IDIuNWEuNzUuNzUgMCAxIDAgMCAxLjUuNzUuNzUgMCAwIDAgMC0xLjVabTAgOS41YS43NS43NSAwIDEgMCAwIDEuNS43NS43NSAwIDAgMCAwLTEuNVptOC4yNS43NWEuNzUuNzUgMCAxIDAgMS41IDAgLjc1Ljc1IDAgMCAwLTEuNSAwWiI+PC9wYXRoPjwvc3ZnPg==)](https://github.com/cellos51/balatro-gba/pulls)
[![Discussions](https://img.shields.io/github/discussions/cellos51/balatro-gba?style=flat&color=blue&label=Discussions&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij48cGF0aCBmaWxsPSJ3aGl0ZSIgZD0iTTEuNzUgMWg4LjVjLjk2NiAwIDEuNzUuNzg0IDEuNzUgMS43NXY1LjVBMS43NSAxLjc1IDAgMCAxIDEwLjI1IDEwSDcuMDYxbC0yLjU3NCAyLjU3M0ExLjQ1OCAxLjQ1OCAwIDAgMSAyIDExLjU0M1YxMGgtLjI1QTEuNzUgMS43NSAwIDAgMSAwIDguMjV2LTUuNUMwIDEuNzg0Ljc4NCAxIDEuNzUgMVpNMS41IDIuNzV2NS41YzAgLjEzOC4xMTIuMjUuMjUuMjVoMWEuNzUuNzUgMCAwIDEgLjc1Ljc1djIuMTlsMi43Mi0yLjcyYS43NDkuNzQ5IDAgMCAxIC41My0uMjJoMy41YS4yNS4yNSAwIDAgMCAuMjUtLjI1di01LjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVoLTguNWEuMjUuMjUgMCAwIDAtLjI1LjI1Wm0xMyAyYS4yNS4yNSAwIDAgMC0uMjUtLjI1aC0uNWEuNzUuNzUgMCAwIDEgMC0xLjVoLjVjLjk2NiAwIDEuNzUuNzg0IDEuNzUgMS43NXY1LjVBMS43NSAxLjc1IDAgMCAxIDE0LjI1IDEySDE0djEuNTQzYTEuNDU4IDEuNDU4IDAgMCAxLTIuNDg3IDEuMDNMOS4yMiAxMi4yOGEuNzQ5Ljc0OSAwIDAgMSAuMzI2LTEuMjc1Ljc0OS43NDkgMCAwIDEgLjczNC4yMTVsMi4yMiAyLjIydi0yLjE5YS43NS43NSAwIDAgMSAuNzUtLjc1aDFhLjI1LjI1IDAgMCAwIC4yNS0uMjVaIj48L3BhdGg+PC9zdmc+)](https://github.com/cellos51/balatro-gba/discussions)
[![Build Status](https://img.shields.io/github/actions/workflow/status/cellos51/balatro-gba/build_ci_workflow.yml?style=flat&logo=github&branch=main&label=Builds&labelColor=gray&color=default&v=1)](https://github.com/cellos51/balatro-gba/actions)
[![Open Issues](https://custom-icon-badges.demolab.com/github/issues/cellos51/balatro-gba?logo=bug&style=flat&label=Issues&labelColor=gray&color=red&v=2)](https://github.com/cellos51/balatro-gba/issues)
[![Pull Requests](https://custom-icon-badges.demolab.com/github/issues-pr/cellos51/balatro-gba?logo=git-pull-request&style=flat&label=Pull%20Requests&labelColor=gray&color=indigo&v=3)](https://github.com/cellos51/balatro-gba/pulls)
### Disclaimer
This project is a non-profit fan demake of Balatro for the Game Boy Advance, meant to recreate it as accurately as possible including all the visuals that make it satisfying to play. It is **not affiliated with or endorsed by Playstack or LocalThunk** and **it is not to be sold**. This version is a **minimal tech-demo**, intended for those who already own and know the official game. Refer to the Balatro wiki below for descriptions of game mechanics and joker effects. All rights remain with the original holders.
This is an attempt to recreate the game **'Balatro'** as accurately as possible, including all of the visual effects that make Balatro feel satisfying to play.
This **tech-demo/proof of concept** is strictly limited in content to a minimal version of Balatro and will **NOT** recreate the full game. **This version is intended for people who already own and know how the official full game works.** Please refer to the Balatro Wiki if you need help understanding certain mechanics or abilities.
<a href="https://balatrowiki.org/">
<img src="https://custom-icon-badges.demolab.com/badge/Balatro%20Wiki-194c84?logo=bigjoker&logoColor=fff" alt="Balatro Wiki" width="155">
</a>
### Please buy the official full version from these sources below:
### Disclaimer: This project is NOT endorsed by or affiliated with Playstack or LocalThunk
#### This is a non-profit community fan project solely aimed to recreate a minimal version of Balatro on the Game Boy Advance as a tribute to the full Balatro and is not intended to infringe or draw sales away from the full game's release or any of the established works by Playstack and LocalThunk.
#### All rights are reserved to their respective holders.
### Please buy the official full version from these sources below:
[![Balatro on Steam](https://custom-icon-badges.demolab.com/badge/Balatro%20on%20Steam-194c84?logo=steam&logoColor=fff)](https://store.steampowered.com/app/2379780/Balatro/)
[![Balatro on Google Play](https://custom-icon-badges.demolab.com/badge/Balatro%20on%20Google%20Play-414141?logo=Google-play&logoColor=fff)](https://play.google.com/store/apps/details?id=com.playstack.balatro.android)
[![Balatro on Apple App Store](https://custom-icon-badges.demolab.com/badge/Balatro%20on%20Apple%20App%20Store-0D96F6?logo=app-store&logoColor=fff)](https://apps.apple.com/us/app/balatro/id6502453075)
@ -23,73 +24,21 @@ This project is a non-profit fan demake of Balatro for the Game Boy Advance, mea
[![Balatro on Xbox](https://custom-icon-badges.demolab.com/badge/Balatro%20on%20Xbox-107C10.svg?logo=xbox&logoColor=white)](https://www.xbox.com/en-US/games/store/balatro/9PK087LNGJC5)
[![Balatro on Humble Bundle](https://img.shields.io/badge/Balatro%20on%20Humble%20Bundle-%23494F5C.svg?logo=HumbleBundle&logoColor=white)](https://www.humblebundle.com/store/balatro?srsltid=AfmBOoqS2De8T4kizzWxJS1pbvQosJ_bYCl4qvC6LA1YLPAh4sZ8vJqO)
---
<a href="https://github.com/cellos51/balatro-gba/releases/">
<img src="https://img.shields.io/badge/Download_ROMs_from_the_Releases_tab-8A2BE2?&logo=github" alt="Download ROM" width="500">
</a>
---
https://github.com/user-attachments/assets/54a9e2e9-1a02-48d5-bb9d-5ab257a7e03b
<!-- The Gif is a little blurry but I think it looks fine -->
<img src="example.gif" alt="Example GIF" width="800">
### Controls:
(D-Pad: Navigation)
(A: Pick Card/Make Selections)
#### When on the hand row during round
(L: Play Hand)
(R: Discard Hand)
(B: Deselect All Cards)
#### When on the joker row in the shop or during round
(L: Sell Joker)
(Hold A: Swap Owned Jokers or Playing Cards in the Shop or Round)
# Contributing
If you would like to contribute, please read CONTRIBUTING.md.
(R: Sort Suit/Rank)
(D-Pad: Navigation)
# **Build Instructions:**
## **-Docker-**
A docker compose file is provided to build this project. It provides a standard build environment for this projects CI/CD and can also be used to build the ROM locally.
_Some users may find this option to be the easiest way to build locally._
- _This option **avoids** setting up the development environment as described below._
- _No additional software besides **docker desktop** is required._
### Step-by-Step
1.) Install [docker desktop](https://docs.docker.com/desktop/) for your operating system.
2.) Open a terminal to this project's directory:
- On **Linux** run `UID=$(id -u) GID=$(id -g) docker compose up`
- On **Windows** run `docker compose up`
<details>
<summary><i>How do I open a terminal in windows?</i></summary>
---
From the file explorer, you can open a folder in **powershell** (_a modern windows terminal_):
- **hold 'Shift'** and **Right Click** on the folder.
- Select **"Open PowerShell window here"** from the popup menu.
---
</details>
3.) Docker will build the project and the ROM will be in the same location as step 7 describes below.
## **-Windows-**
Video Tutorial: https://youtu.be/72Zzo1VDYzQ?si=UDmEdbST1Cx1zZV2
### With `Git` (not required)
@ -108,36 +57,6 @@ Video Tutorial: https://youtu.be/72Zzo1VDYzQ?si=UDmEdbST1Cx1zZV2
7.) After it completes, navigate through the `build` directory in the project folder and look for `balatro-gba.gba` and load it on an emulator or flashcart.
### Without `Git`
Disregard Steps 3-4 and instead click the green code button on the main repository page and press `Download Zip`. Unzip the folder and place it wherever you like. Then continue from Step 5.
## **-Linux-**
1.) Add the devkitPro repository using these instructions https://devkitpro.org/wiki/devkitPro_pacman
2.) Install devkitPro by running `sudo pacman -S gba-dev` and accepting all packages.
3.) Activate the devkitPro environment by running `source /etc/profile.d/devkit-env.sh` or opening a new shell.
4.) Follow instructions from the Windows tutorial starting from Step 3
## **-macOS-**
1.) Install devkitPro installer using: https://github.com/devkitPro/installer and following https://devkitpro.org/wiki/devkitPro_pacman#macOS.
> Note: You may have to install the installers directly from their url in a browser, as the installer script may not install correctly due to Cloudflare checks on their server. You can use one of the following urls:
> Apple Silicon: https://pkg.devkitpro.org/packages/macos-installers/devkitpro-pacman-installer.arm64.pkg
> Intel: https://pkg.devkitpro.org/packages/macos-installers/devkitpro-pacman-installer.x86_64.pkg
2.) Run `sudo dkp-pacman -S gba-dev`
3.) Verify that devkitPro is installed in '/opt/devkitpro'
4.) Add the following to your .bashrc or .zshrc (or export the variables in your shell session):
- export DEVKITPRO=/opt/devkitpro
- export DEVKITARM=$DEVKITPRO/devkitARM
- export PATH=$PATH:$DEVKITPRO/tools/bin:$DEVKITPRO/pacman/bin
5.) Follow instructions from Windows tutorial step 4
## **Common Issues:**
#### 1. **When I run `make` it errors out and won't compile!**
@ -151,17 +70,3 @@ Disregard Steps 3-4 and instead click the green code button on the main reposito
#### 4. **It says I don't have `Git` or `Make` installed!**
- Use `pacman -S git` (not required) or `pacman -S make` although make should already be installed if you followed the instructions correctly.
# **Credits:**
## **Game**
This GBA implementation is based on Balatro which is designed and created by LocalThunk and published by Playstack.
See repository contributors list for code contribution credits to this GBA implementation.
## **Music**
Music arrangement is made by @cellos51 and @MeirGavish based on original Balatro soundtrack by [LouisF](https://louisfmusic.com/) and [transcription by MrCrimit](https://musescore.com/user/8237321/scores/14590660).
## **Imagery**
Sprites and backgrounds are based on original Balatro imagery created by LocalThunk.
See [Joker Art Discussion](https://github.com/cellos51/balatro-gba/discussions/69) for full credits for each joker sprite.
## **Sounds**
For the mult and xmult sound effects: [Toy records#06-E3-02.wav by poissonmort](https://freesound.org/s/253249/) used under License: Attribution 4.0
All other sound effects were created by LocalThunk and are used under Creative Commons - CC0 license.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,17 +0,0 @@
#!/bin/bash
# Check GCC version and install GCC 14 if needed
check_gcc_version() {
if command -v gcc &> /dev/null; then
gcc_version=$(gcc -dumpversion | cut -d. -f1)
if [ "$gcc_version" -lt 14 ]; then
echo "GCC version $gcc_version detected. Installing GCC 14..."
sudo apt-get update
sudo apt-get install -y gcc-14
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
echo "GCC 14 installed and set as default."
fi
fi
}
check_gcc_version

View File

@ -1,11 +0,0 @@
services:
gbalatro:
image: gbalatro:dev
build:
context: .
dockerfile: Dockerfile.gbalatro
working_dir: /balatro-gba
volumes:
- ./:/balatro-gba
user: "${UID-1000}:${GID-1000}"
command: ["sh", "-c", "make -j$(nproc)"]

View File

@ -1,13 +0,0 @@
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
@keyframes octocat-wave {
0%, 100% { transform: rotate(0); }
20%, 60% { transform: rotate(-25deg); }
40%, 80% { transform: rotate(10deg); }
}
@media (max-width:500px) {
.github-corner:hover .octo-arm { animation: none; }
.github-corner .octo-arm { animation: octocat-wave 560ms ease-in-out; }
}

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 - 2023 jothepro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,13 +0,0 @@
Project: doxygen-awesome-css
Source: https://github.com/jothepro/doxygen-awesome-css
Version: snapshot
Commit: d52eafe
Imported-by: SuperbMuffin
Date: 2026-04-02
Notes:
- Imported as a snapshot (no git submodule)
- There are no dependencies on external resources besides images. Posing no security issue that would require consistent updating.

View File

@ -1,138 +0,0 @@
// SPDX-License-Identifier: MIT
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
Copyright (c) 2021 - 2025 jothepro
*/
class DoxygenAwesomeDarkModeToggle extends HTMLElement {
// SVG icons from https://fonts.google.com/icons
// Licensed under the Apache 2.0 license:
// https://www.apache.org/licenses/LICENSE-2.0.html
static lightModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FCBF00"><rect fill="none" height="24" width="24"/><circle cx="12" cy="12" opacity=".3" r="3"/><path d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg>`
static darkModeIcon = `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FE9700"><rect fill="none" height="24" width="24"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27 C17.45,17.19,14.93,19,12,19c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z" opacity=".3"/><path d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg>`
static title = "Toggle Light/Dark Mode"
static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
static _staticConstructor = function() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference)
// Update the color scheme when the browsers preference changes
// without user interaction on the website.
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
})
// Update the color scheme when the tab is made visible again.
// It is possible that the appearance was changed in another tab
// while this tab was in the background.
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged()
}
});
}()
static init() {
$(function() {
$(document).ready(function() {
const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle')
toggleButton.title = DoxygenAwesomeDarkModeToggle.title
toggleButton.updateIcon()
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
toggleButton.updateIcon()
})
document.addEventListener("visibilitychange", visibilityState => {
if (document.visibilityState === 'visible') {
toggleButton.updateIcon()
}
});
$(document).ready(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
$(window).resize(function(){
document.getElementById("MSearchBox").parentNode.appendChild(toggleButton)
})
})
})
}
constructor() {
super();
this.onclick=this.toggleDarkMode
}
/**
* @returns `true` for dark-mode, `false` for light-mode system preference
*/
static get systemPreference() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
/**
* @returns `true` for dark-mode, `false` for light-mode user preference
*/
static get userPreference() {
return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) ||
(DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey))
}
static set userPreference(userPreference) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference
if(!userPreference) {
if(DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)
}
} else {
if(!DoxygenAwesomeDarkModeToggle.systemPreference) {
localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true)
} else {
localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)
}
}
DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged()
}
static enableDarkMode(enable) {
if(enable) {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = true
document.documentElement.classList.add("dark-mode")
document.documentElement.classList.remove("light-mode")
} else {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = false
document.documentElement.classList.remove("dark-mode")
document.documentElement.classList.add("light-mode")
}
}
static onSystemPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
static onUserPreferenceChanged() {
DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled)
}
toggleDarkMode() {
DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference
this.updateIcon()
}
updateIcon() {
if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) {
this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon
} else {
this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon
}
}
}
customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle);

View File

@ -1,66 +0,0 @@
// SPDX-License-Identifier: MIT
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
Copyright (c) 2022 - 2025 jothepro
*/
class DoxygenAwesomeFragmentCopyButton extends HTMLElement {
constructor() {
super();
this.onclick=this.copyContent
}
static title = "Copy to clipboard"
static copyIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M23.04,10.322c0,-2.582 -2.096,-4.678 -4.678,-4.678l-6.918,-0c-2.582,-0 -4.678,2.096 -4.678,4.678c0,-0 0,8.04 0,8.04c0,2.582 2.096,4.678 4.678,4.678c0,-0 6.918,-0 6.918,-0c2.582,-0 4.678,-2.096 4.678,-4.678c0,-0 0,-8.04 0,-8.04Zm-2.438,-0l-0,8.04c-0,1.236 -1.004,2.24 -2.24,2.24l-6.918,-0c-1.236,-0 -2.239,-1.004 -2.239,-2.24l-0,-8.04c-0,-1.236 1.003,-2.24 2.239,-2.24c0,0 6.918,0 6.918,0c1.236,0 2.24,1.004 2.24,2.24Z"/><path d="M5.327,16.748c-0,0.358 -0.291,0.648 -0.649,0.648c0,0 0,0 0,0c-2.582,0 -4.678,-2.096 -4.678,-4.678c0,0 0,-8.04 0,-8.04c0,-2.582 2.096,-4.678 4.678,-4.678l6.918,0c2.168,0 3.994,1.478 4.523,3.481c0.038,0.149 0.005,0.306 -0.09,0.428c-0.094,0.121 -0.239,0.191 -0.392,0.191c-0.451,0.005 -1.057,0.005 -1.457,0.005c-0.238,0 -0.455,-0.14 -0.553,-0.357c-0.348,-0.773 -1.128,-1.31 -2.031,-1.31c-0,0 -6.918,0 -6.918,0c-1.236,0 -2.24,1.004 -2.24,2.24l0,8.04c0,1.236 1.004,2.24 2.24,2.24l0,-0c0.358,-0 0.649,0.29 0.649,0.648c-0,0.353 -0,0.789 -0,1.142Z" style="fill-opacity:0.6;"/></svg>`
static successIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M8.084,16.111c-0.09,0.09 -0.212,0.141 -0.34,0.141c-0.127,-0 -0.249,-0.051 -0.339,-0.141c-0.746,-0.746 -2.538,-2.538 -3.525,-3.525c-0.375,-0.375 -0.983,-0.375 -1.357,0c-0.178,0.178 -0.369,0.369 -0.547,0.547c-0.375,0.375 -0.375,0.982 -0,1.357c1.135,1.135 3.422,3.422 4.75,4.751c0.27,0.27 0.637,0.421 1.018,0.421c0.382,0 0.749,-0.151 1.019,-0.421c2.731,-2.732 10.166,-10.167 12.454,-12.455c0.375,-0.375 0.375,-0.982 -0,-1.357c-0.178,-0.178 -0.369,-0.369 -0.547,-0.547c-0.375,-0.375 -0.982,-0.375 -1.357,0c-2.273,2.273 -9.567,9.567 -11.229,11.229Z"/></svg>`
static successDuration = 980
static init() {
$(function() {
$(document).ready(function() {
if(navigator.clipboard) {
const fragments = document.getElementsByClassName("fragment")
for(const fragment of fragments) {
const fragmentWrapper = document.createElement("div")
fragmentWrapper.className = "doxygen-awesome-fragment-wrapper"
const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button")
fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title
fragment.parentNode.replaceChild(fragmentWrapper, fragment)
fragmentWrapper.appendChild(fragment)
fragmentWrapper.appendChild(fragmentCopyButton)
}
}
})
})
}
copyContent() {
const content = this.previousSibling.cloneNode(true)
// filter out line number from file listings
content.querySelectorAll(".lineno, .ttc").forEach((node) => {
node.remove()
})
let textContent = content.textContent
// remove trailing newlines that appear in file listings
let numberOfTrailingNewlines = 0
while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') {
numberOfTrailingNewlines++;
}
textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines)
navigator.clipboard.writeText(textContent);
this.classList.add("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon
window.setTimeout(() => {
this.classList.remove("success")
this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon
}, DoxygenAwesomeFragmentCopyButton.successDuration);
}
}
customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton)

View File

@ -1,20 +0,0 @@
/* SPDX-License-Identifier: MIT */
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
Copyright (c) 2021 - 2025 jothepro
*/
@media screen and (min-width: 768px) {
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px);
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height));
}
}

View File

@ -1,105 +0,0 @@
/* SPDX-License-Identifier: MIT */
/**
Doxygen Awesome
https://github.com/jothepro/doxygen-awesome-css
Copyright (c) 2021 - 2025 jothepro
*/
html {
/* side nav width. MUST be = `TREEVIEW_WIDTH`.
* Make sure it is wide enough to contain the page title (logo + title + version)
*/
--side-nav-fixed-width: 335px;
--menu-display: none;
--top-height: 120px;
--toc-sticky-top: -25px;
--toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px);
}
#projectname {
white-space: nowrap;
}
@media screen and (min-width: 768px) {
html {
--searchbar-background: var(--page-background-color);
}
#side-nav {
min-width: var(--side-nav-fixed-width);
max-width: var(--side-nav-fixed-width);
top: var(--top-height);
overflow: visible;
}
#nav-tree, #side-nav {
height: calc(100vh - var(--top-height)) !important;
}
#top {
display: block;
border-bottom: none;
height: var(--top-height);
margin-bottom: calc(0px - var(--top-height));
max-width: var(--side-nav-fixed-width);
overflow: hidden;
background: var(--side-nav-background);
}
#main-nav {
float: left;
padding-right: 0;
}
.ui-resizable-handle {
display: none;
}
.ui-resizable-e {
width: 0;
}
#nav-path {
position: fixed;
right: 0;
left: calc(var(--side-nav-fixed-width) + 1px);
bottom: 0;
width: auto;
}
#doc-content {
height: calc(100vh - 31px) !important;
padding-bottom: calc(3 * var(--spacing-large));
padding-top: calc(var(--top-height) - 80px);
box-sizing: border-box;
margin-left: var(--side-nav-fixed-width) !important;
}
#MSearchBox {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)));
}
#MSearchField {
width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px);
}
#MSearchResultsWindow {
left: var(--spacing-medium) !important;
right: auto;
}
#nav-sync {
bottom: 4px;
right: auto;
left: 300px;
width: 35px;
top: auto !important;
user-select: none;
position: fixed
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,106 +0,0 @@
<!-- HTML header for doxygen 1.16.1-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--BEGIN PROJECT_ICON-->
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
<!--END PROJECT_ICON-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN FULL_SIDEBAR-->
<script type="text/javascript">var page_layout=1;</script>
<!--END FULL_SIDEBAR-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
<!--BEGIN COPY_CLIPBOARD-->
<script type="text/javascript" src="$relpath^clipboard.js"></script>
<!--END COPY_CLIPBOARD-->
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<!-- ... other metadata & script includes ... -->
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
DoxygenAwesomeFragmentCopyButton.init()
</script>
</head>
<body>
<!--BEGIN FULL_SIDEBAR-->
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
<!--END FULL_SIDEBAR-->
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!-- GitHub Corner -->
<a href="https://github.com/GBALATRO/balatro-gba" class="github-corner" aria-label="View source on GitHub" target="_blank">
<svg width="80" height="80" viewBox="0 0 250 250"
style="fill:#715292; color: #1C1D1F; position:fixed; top:0; border:0; right:0; z-index:9999;"
aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"/>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.9,78.6 120.9,78.6
C119.1,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3
C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor" style="transform-origin:130px 106px;" class="octo-arm"/>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6
C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0
C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1
C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4
C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9
C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5
C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9
L141.0,136.5 C139.8,137.8 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"/>
</svg>
</a>
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"$logosize/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign">
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber">&#160;$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td>
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<!--BEGIN !FULL_SIDEBAR-->
<td>$searchbox</td>
<!--END !FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
<!--BEGIN SEARCHENGINE-->
<!--BEGIN FULL_SIDEBAR-->
<tr><td colspan="2">$searchbox</td></tr>
<!--END FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 B

1
graphics/blinds_gfx.grit Normal file
View File

@ -0,0 +1 @@
-gB4 -Mw4 -Mh4 -p!

BIN
graphics/blinds_gfx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -m! -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -m! -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -1 +0,0 @@
-gB4 -Mw4 -Mh4 -m! -pn 16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 961 B

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

View File

@ -1,93 +1,26 @@
/**
* @file affine_background.h
*
* @brief Utilities for affine background on GBA
*/
#ifndef AFFINE_BACKGROUND_H
#define AFFINE_BACKGROUND_H
#include "graphic_utils.h"
#include <tonc.h>
/**
* @def AFFINE_BG_IDX
* @brief The index of the affine background BGCNT register etc.
*/
#define AFFINE_BG_IDX 2
#include "graphic_utils.h"
/**
* @def AFFINE_BG_PAL_LEN
* @brief Number of u16 colors available in the palette.
*/
#define AFFINE_BG_IDX 2 // The index of the affine background BGCNT register etc.
#define AFFINE_BG_PAL_LEN 16
#define AFFINE_BG_PB (PAL_ROW_LEN * 10) // This isn't really a palette bank, just the starting index of the palette
/**
* @def AFFINE_BG_PB
* @brief The starting index of the background palette.
*/
#define AFFINE_BG_PB (PAL_ROW_LEN * 10)
/**
* @brief An ID to specify background rendering types.
*/
enum AffineBackgroundID
{
/**
* @brief Display background for main menu.
*
* Signifies which background to use and provides a higher quality affine
* mode to display when there is no game logic.
*/
AFFINE_BG_MAIN_MENU,
/**
* @brief Display background for game play.
*
* Signifies which background to use and provides a lower quality affine
* mode to keep resources down during play.
*/
AFFINE_BG_GAME,
};
/**
* @brief Initialize resources for affine background rendering
*/
void affine_background_init();
/**
* @brief Interrupt routine to update display on HBLANK
*/
IWRAM_CODE void affine_background_hblank();
/**
* @brief Per-frame update of the affine background
*/
IWRAM_CODE void affine_background_update();
/**
* @brief Update the affine background color
*
* @param color @ref COLOR to set
*/
void affine_background_set_color(COLOR color);
/**
* @brief Set the background palette
*
* Must be called with an array of size at least @ref AFFINE_BG_PAL_LEN
*
* @param src pointer to palette to set
*/
void affine_background_load_palette(const u16* src);
/**
* @brief Update the background id
*
* Update the background id by configuring display registers and loading
* the image and palette used for the specified id.
*
* @param new_bg @ref AffineBackgrounID to set
*/
// Must be called with an array of size at least AFFINE_BG_PAL_LEN
void affine_background_load_palette(const u16 *src);
void affine_background_change_background(enum AffineBackgroundID new_bg);
#endif // AFFINE_BACKGROUND_H

Some files were not shown because too many files have changed in this diff Show More