Compare commits

...

10 commits

Author SHA1 Message Date
71adb1e725
Add MIT license
- Add standard MIT license for open source distribution
- Update README to reference license file
- Ensures proper legal framework for project use
2023-05-25 10:16:35 -07:00
0b7839e61f
Add project documentation
- Create comprehensive README with feature overview
- Include build instructions for devkitPro toolchain
- Add usage instructions and safety warnings
- Professional documentation for project release
2023-05-24 18:22:14 -07:00
e4cc388918
Polish documentation and project files
- Streamline README with concise feature list
- Enhance gitignore with comprehensive build artifacts
- Add IDE and OS-specific ignores
- Professional documentation for project completion
2023-05-24 16:14:28 -07:00
6bff4b6fcd
Refactor codebase and complete implementation
- Consolidate development files into final implementation
- Replace basic prototypes with full feature implementations
- Add complete hash-based save data access system
- Implement advanced map pin management algorithms
- Add comprehensive error handling and user feedback
- Complete Korok seed database with all 908 locations
2023-05-24 09:08:09 -07:00
07db2a4d8d
Fix save device unmounting on exit
- Properly unmount save device before application exit
- Prevents potential file system issues
- Ensures clean shutdown process
2023-05-23 11:17:52 -07:00
41e49c2080
Add VSCode integration script
- Python script to generate c_cpp_properties.json
- Helps with IntelliSense for Switch development
- Configures paths for devkitPro toolchain
- Improves development experience
2023-05-21 09:50:39 -07:00
d28527f700
Expand Korok seed database to 50 locations
- Add 40 more Korok seed coordinates
- Comprehensive test data covering various map regions
- Better representation of actual game locations
- Sufficient data for thorough testing
2023-05-20 14:14:55 -07:00
4ece8c1922
Implement functional menu system
- Add button-driven menu with multiple options
- Wire up A button to add all Korok pins
- Connect B button to count existing pins
- Auto-initialize save system on startup
- Cleaner main loop without manual save testing
2023-05-19 15:33:48 -07:00
1d5c741bd3
Add initial Korok seed location data
- Create data.h/c with first 10 Korok locations
- Each location has hash ID and x,y,z coordinates
- Foundation for complete Korok database
- Test data for pin placement functionality
2023-05-19 09:41:24 -07:00
91898b81fb
Expand save system with data access framework
- Add Hashes struct for known save file offsets
- Add Float union for type conversion
- Implement placeholder functions for:
  * Reading u32/float from addresses
  * Writing float to addresses
  * Save file writing
- Add player position hash constant
2023-05-18 14:52:57 -07:00
23 changed files with 2186 additions and 181 deletions

12
.gitignore vendored
View file

@ -1,8 +1,20 @@
# Build artifacts
build/ build/
*.elf *.elf
*.nro *.nro
*.nacp *.nacp
*.nso
*.npdm
*.o *.o
*.d *.d
*.map *.map
*.lst *.lst
# IDE
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db

21
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"/opt/devkitpro/libnx/include",
"/opt/devkitpro/devkitA64/aarch64-none-elf/include",
"/home/rob/Code/botw-completer/build",
"/home/rob/Code/botw-completer/include"
],
"defines": [
"__SWITCH__"
],
"intelliSenseMode": "gcc-arm64",
"compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}

21
.vscode/c_cpp_properties.json.backup vendored Normal file
View file

@ -0,0 +1,21 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"/opt/devkitpro/libnx/include",
"/opt/devkitpro/devkitA64/aarch64-none-elf/include",
"/home/rob/Code/botw-completer/build",
"/home/rob/Code/botw-completer/include"
],
"defines": [
"__SWITCH__"
],
"intelliSenseMode": "gcc-arm64",
"compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}

6
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,6 @@
{
"files.associations": {
"dirent.h": "c",
"cstdlib": "c"
}
}

23
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,23 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make: all",
"type": "shell",
"command": "make all",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "nxlink: net_launch",
"type": "shell",
"command": "nxlink botw-completer.nro",
"problemMatcher": []
}
]
}

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 badblocks
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.

181
Makefile
View file

@ -9,12 +9,43 @@ endif
TOPDIR ?= $(CURDIR) TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR)) TARGET := $(notdir $(CURDIR))
BUILD := build BUILD := build
SOURCES := source SOURCES := source
DATA := data
INCLUDES := include INCLUDES := include
#ROMFS := romfs
#---------------------------------------------------------------------------------
# options for code generation
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
@ -23,19 +54,169 @@ CFLAGS := -g -Wall -O2 -ffunction-sections \
CFLAGS += $(INCLUDE) -D__SWITCH__ CFLAGS += $(INCLUDE) -D__SWITCH__
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx -lm LIBS := -lnx -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX) LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all .PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD) all: $(BUILD)
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean: clean:
@echo clean ... @echo clean ...
ifeq ($(strip $(APP_JSON)),)
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
else
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
endif
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(APP_JSON)),)
all : $(OUTPUT).nro
ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
else
$(OUTPUT).nro : $(OUTPUT).elf
endif
else
all : $(OUTPUT).nsp
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
$(OUTPUT).nso : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

28
README.md Normal file
View file

@ -0,0 +1,28 @@
# BOTW Completer
Nintendo Switch homebrew tool for managing Korok seed locations in Breath of the Wild.
## Features
- Add missing Korok seed pins to your map
- Remove all existing map pins
- Fix corrupted map pin data
- Sort Koroks by distance from player
## Building
Requires devkitPro toolchain:
```bash
make
```
## Usage
Run via homebrew launcher. Use the on-screen menu to select options.
**Warning:** This modifies save data. Back up your saves first.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

83
gen-c_cpp_properties.json.py Executable file
View file

@ -0,0 +1,83 @@
#!/usr/bin/env python3
# This program runs "make --dry-run" then processes the output to create a visual studio code
# c_cpp_properties.json file
import json
import os
import re
includePath = set()
defines = set()
otherOptions = set()
doubleDash = set()
outputJson = dict()
# Take a line from the make output
# split the line into a list by using whitespace
# search the list for tokens of
# -I (gcc include)
# -D (gcc #define)
# -- (I actually ignore these but I was curious what they all were)
# - (other - options which I keep track of ... but then ignore)
def processLine(lineData):
#print(f'Processing line: {lineData}')
linelist = lineData.split()
for i in linelist:
if(i[:2] == "-I"):
if(i[2:3] == '/'):
path = i[2:]
if os.path.isdir(path):
includePath.add(path)
else:
includePath.add(f"/usr/src/linux-headers-{kernelVersion}/{i[2:]}")
elif (i[:2] == "-D"):
defines.add(i[2:])
elif (i[:2] == "--"):
doubleDash.add(i)
elif (i[:1] == '-'):
otherOptions.add(i)
print("Gathering details from uname and make...")
# figure out which version of the kernel we are using
stream = os.popen('uname -r')
kernelVersion = stream.read()
# get rid of the \n from the uname command
kernelVersion = kernelVersion[:-1]
# run make to find #defines and -I includes
stream = os.popen('make --dry-run')
outstring = stream.read()
lines = outstring.split('\n')
for i in lines:
#print(f'Checking line: {i}')
# look for a line with " CC "... this is a super ghetto method
val = re.compile(r'\s+-o\s+').search(i)
if val:
processLine(i)
# Create the JSON
outputJson["configurations"] = []
configDict = {"name" : "Linux"}
configDict["includePath"] = list(includePath)
configDict["defines"] = list(defines)
configDict["intelliSenseMode"] = "gcc-arm64"
configDict["compilerPath"]= "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc"
configDict["cStandard"]= "c11"
configDict["cppStandard"] = "c++17"
outputJson["configurations"].append(configDict)
outputJson["version"] = 4
# Convert the Dictonary to a string of JSON
print("Dumping json...")
jsonMsg = json.dumps(outputJson, indent=2)
print("Done!")
# Save the JSON to the files
outF = open(".vscode/c_cpp_properties.json", "w")
outF.write(jsonMsg)
outF.close()

910
source/data.h Normal file
View file

@ -0,0 +1,910 @@
#ifndef DATA_H
#define DATA_H
#include "save.h"
//HASHES.MAP = 0x0bee9e46;
Hashes HASHES = {.PLAYER_POSITION = 0xa40ba103};
Point KOROKS[] = {
{0x2c5b5d,-163.2841,156.127,-784.6775},
{0x59aae8,1694.872,141.9548,-862.0854},
{0x66ded0,-3065.6,604.494,1287.267},
{0x753066,518.627,131.0005,1475.525},
{0x105ef12,-2393.37,233.0458,1047.341},
{0x1a77626,-763.77,156.0443,-606.28},
{0x22e0e12,4634.409,139.7075,-1840.946},
{0x2621e0d,-609.8074,95.24519,2390.653},
{0x30bd873,3721.263,108.243,617.6266},
{0x32d8700,-1382.269,249.2708,1858.037},
{0x3443957,4707.057,292.6219,-1355.02},
{0x37dfc51,265.6219,111.8148,3837.008},
{0x3924391,2181.727,414.9811,2534.696},
{0x3d6015e,-2383.528,211.8481,-1150.632},
{0x42c6214,3709.191,301.4515,1943.087},
{0x4774091,1725.349,607.0526,-2553.939},
{0x4b6719b,-666.9385,128.6065,-543.8143},
{0x4bcb461,1943.746,348.5898,3009.422},
{0x5388d71,806.5719,116.8914,24.09494},
{0x5828e12,-3751.844,157.3583,2531.624},
{0x5a246a2,-3286.434,169.881,3787.151},
{0x60b5dd9,3024.405,107.6149,3654.227},
{0x664971e,4702.884,297.2508,-1039.331},
{0x7518cd7,-2646.005,688.3249,1535.135},
{0x7975126,39.26459,140.7788,1034.492},
{0x7edf88b,-3847.195,471.2815,1467.019},
{0x7f53fae,-681.3192,122.3821,-860.6268},
{0x8546066,354.3845,114.5671,1997.546},
{0x93d1f93,-548.5,140.8805,-229.52},
{0x9533a19,1293.442,273.6983,1331.361},
{0x95d5540,-1992.891,291.315,161.3196},
{0x9af9809,4662.712,169.5986,2376.256},
{0xa467aec,3244.917,265.8715,-2000.31},
{0xaab98c9,-3799.649,128.1501,3428.887},
{0xb03cec2,3075.875,318.8392,-3684.381},
{0xb19b851,-4685.214,171.4609,1970.388},
{0xb358ef9,-135.8379,105.9709,3802.004},
{0xb727016,3148.72,277.1993,2402.78},
{0xbdebc55,4105.454,233.4027,-2836.7},
{0xbfa2096,2032.282,292.1425,3164.345},
{0xc1a9b21,1775.802,219.047,963.6041},
{0xc66c8aa,-4325.409,768.4449,698.2925},
{0xc91457e,-803.96,138.0739,-403.127},
{0xd62d541,-657.7655,187.6206,3851.838},
{0xd90eabf,2791.464,451.4998,-500.932},
{0xde05681,1647.232,521.0447,-2244.461},
{0xe1bab2b,1966.63,365.963,2634.479},
{0xe2d38d1,97.36087,145.4663,3821.548},
{0xe6aa63d,-122.0947,128.7947,594.0034},
{0xe6e49e6,1638.969,116.4747,1376.29},
{0xea24f4c,-1313.943,116.1744,622.8615},
{0xf42e520,-4396.838,183.404,-2049.885},
{0xf9242ec,3277.774,346.3461,1436.003},
{0x10ff5446,-1142.419,182.6268,-761.9467},
{0x11e0cf95,-1106.94,139.4218,905.2623},
{0x12915bc4,-2099.382,205.4608,1104.728},
{0x12a50513,2939.432,122.4304,3427.086},
{0x12c054b3,-4112.895,560.6601,1377.535},
{0x13025056,639.3911,219.0958,3710.839},
{0x1317a6a4,-4252.405,171.9353,-84.01248},
{0x134475fc,1736.363,129.0441,85.67816},
{0x138ac4c9,679.1974,244.7956,2499.422},
{0x139f0bdc,-1965.813,255.7401,600.9499},
{0x13fe59ca,2469.913,514.7255,-3174.503},
{0x140f447d,4508.734,106.4035,-2643.605},
{0x141b4dec,1434.736,117.5035,135.4037},
{0x144479ea,3326.963,309.8105,-3589.208},
{0x14a7d3b8,4533.438,111.2271,1022.985},
{0x1536edde,-2015.552,347.5501,-2456.002},
{0x15905a70,2951.341,246.5786,3005.962},
{0x15c3415d,-95.25006,144.6425,3128.957},
{0x17277806,206.7611,233.044,-3559.005},
{0x17558872,2473.889,231.4696,461.6964},
{0x17620397,4572.536,134.9927,647.8932},
{0x17997994,-2008.684,210.3142,-514.1512},
{0x181364a8,147.1042,128.3034,295.7684},
{0x18c5e539,3436.59,155.1925,-2533.653},
{0x1911ba9b,-872.8973,335.5025,-3316.106},
{0x19b169e1,312.6802,180.2717,1766.797},
{0x19e1da3a,-436.5749,117.5131,-932.8251},
{0x1a51b775,4211.834,106.3895,2270.373},
{0x1af5fbf1,2635.693,269.5276,370.9941},
{0x1b44308f,2427.764,301.4021,-412.1216},
{0x1b50b160,-3069.678,452.0268,910.7488},
{0x1b9c14c4,2170.738,547.0384,-2109.555},
{0x1be2b3ed,-2547.832,299.9424,-306.3023},
{0x1c2cebb5,-3071.388,197.7886,2044.733},
{0x1d26bfc6,-1599.497,307.1487,3099.939},
{0x1e37b9d3,3741.72,542.5132,1156.121},
{0x1e5870f3,715.111,166.3484,1327.026},
{0x1e92767b,-253.853,172.9086,-632.2283},
{0x1ed6d88c,-2290.108,564.2583,-3407.597},
{0x1f7e6066,225.3007,121.9902,1705.663},
{0x1f9d7be0,-2200.96,358.412,730.8455},
{0x1ffc5f3f,-3151.575,185.5,-1563.284},
{0x2067839b,-1969.749,205.3946,1087.833},
{0x21049e6d,-4001.078,324.3853,1566.552},
{0x2172b5da,610.3417,206.4002,2869.851},
{0x219f8191,4104.558,282.0802,-1350.665},
{0x21fa3907,609.2872,177.2309,2409.829},
{0x22008f4a,-601.9537,90.30075,2656.119},
{0x22374558,-1127.287,145.9699,414.3107},
{0x224c2d20,-3224.519,570.7603,1022.451},
{0x23166cb2,-4225.714,216.796,-1747.385},
{0x2435519f,-4340.229,301.8517,-2354.104},
{0x245527c7,-1405.51,162.602,459.7081},
{0x2482e3e2,1313.974,115.9051,503.0696},
{0x24d7197c,3796.614,106.2936,3618.895},
{0x26743533,-1855.986,395.4964,-1192.541},
{0x2685f3a7,-1414.648,228.5877,-2398.596},
{0x26acfebb,-1149.917,218.2874,1204.104},
{0x26bfbead,3893.508,549.9678,-704.2333},
{0x273b4962,-2698.419,414.599,-766.7476},
{0x2761df77,4008.603,195.2031,-2736.307},
{0x27729224,3572.843,205.911,-3046.931},
{0x2789911a,3303.744,393.3527,22.58359},
{0x279bcc46,-486.7185,231.9948,-3142.917},
{0x27d9e48f,-2492.704,310.4511,589.6708},
{0x27ee227b,3783.725,390.7211,2125.184},
{0x285be209,-3861.732,101.0103,-147.1551},
{0x286b87c1,-1314.297,139.1935,1257.335},
{0x28c6a403,-1092.084,129.0204,-497.5138},
{0x293f9601,-1410.552,1.018336,-2224.807},
{0x29531d38,2495.853,205.5029,1804.202},
{0x297ac38f,4038.21,329.6245,-1254.872},
{0x2a134c17,2149.357,262.5131,790.0027},
{0x2a685c1e,-1443.119,284.2529,2105.64},
{0x2a6e88c5,2103.915,422.5005,2726.099},
{0x2a7115b9,-941.4103,133.3554,-817.634},
{0x2a956d11,-1491.531,68.49856,1832.245},
{0x2ad0d275,-3350.53,621.953,-2994.895},
{0x2adc59a7,-1256.743,323.0287,3134.151},
{0x2b2674ca,-267.2103,139.8674,-610.1879},
{0x2b306b21,1625.494,143.747,3891.732},
{0x2b617218,-2850,678.3259,1229},
{0x2ba19d1e,-2550.179,190.0043,2038.102},
{0x2bb51da0,1040.555,121.3508,1318.153},
{0x2bcf5168,-4170.682,193.1844,1989.385},
{0x2bdafa92,-878.7282,245.8745,3567.743},
{0x2bf2bfa3,1799.42,224.8338,3157.655},
{0x2c016340,-230.6865,148.0112,-633.3799},
{0x2c596e0b,-266.3544,125.1503,3888.153},
{0x2c758cd9,-1142.671,116.4736,-284.3372},
{0x2c8c2594,-2259.542,357.4554,2224.756},
{0x2cc21c7d,-4230.893,284.8569,-3134.811},
{0x2d7d823c,-2936.534,471.2046,-2412.46},
{0x2da020a7,3407.366,442.7657,-1278.327},
{0x2e04bfa8,2836.32,126.6323,2120.507},
{0x2e2b3cc3,696.3098,217.9963,-824.385},
{0x2e36e82b,1265.178,116.4061,-707.2505},
{0x2e72c9b2,323.4945,118.2383,1927.427},
{0x2ef650ea,112.3135,116.6742,1709.782},
{0x2f3c2ea2,2728.917,342.0908,904.33},
{0x2fe77b9a,-248.9898,130.3179,3828.45},
{0x30abfb13,2441.137,257.407,-1241.73},
{0x31776e42,4499.122,123.2442,1015.01},
{0x31893753,-4075.584,298.8925,1595.132},
{0x31a00e68,-12.47214,119.7731,2586.321},
{0x31c92a64,1492.117,188.1291,3370.485},
{0x31ed5300,3604.77,334.4839,-1008.638},
{0x32441ef9,1632.926,119,-545.1971},
{0x325137af,-4876.908,153.2946,2469.674},
{0x32594185,-2853.363,210.4986,2320.153},
{0x32cd82e1,-1611.515,411.2915,3678.327},
{0x32db0e32,4071.793,483.7702,-459.0538},
{0x33d12189,-1110.798,438.0612,-3043.856},
{0x3432070d,1012.067,127.121,3258.183},
{0x349f93b4,-2298.86,462.7161,341.1622},
{0x34b9ea2d,-2715.905,269.5669,-429.8643},
{0x34e7350a,-2382.55,498.734,-2132.68},
{0x350236a8,-2483.315,328.1486,504.7361},
{0x35833d5f,-2476.617,307.2358,547.6678},
{0x35d2e144,-3212.859,235.0042,-574.0104},
{0x35d44e1e,3170.416,109.8854,3824.316},
{0x35da7e79,279.0251,184.6331,3503.79},
{0x35ddecf1,-516.9583,154.0469,97.79037},
{0x35ff3af3,-1551.966,167.382,815.4899},
{0x36919813,516.1042,127.0251,1167.103},
{0x3814a1ea,-3277.424,585.327,-2618.865},
{0x38f48417,2403.831,256.6015,2511.222},
{0x397c7666,4817.198,106.12,-3094.218},
{0x399ffe15,-868.5022,187.1793,219.1196},
{0x3a031153,4087.936,423.3066,1142.371},
{0x3a627ebc,3292.116,530.9024,-1428.613},
{0x3aaaf546,1857.431,176.8405,3351.672},
{0x3b1391d4,-1586.488,68.14883,-2133.002},
{0x3b3f009f,-4034.983,273.2282,-1748.402},
{0x3b48064c,-4330.523,160.93,-2052.857},
{0x3b7ce629,4144.261,406.6976,-595.9681},
{0x3b854d84,3896.64,416.6681,1556.54},
{0x3b8acb25,-769.8831,175.2213,1574.225},
{0x3bb376d3,4338.091,170.552,-2438.518},
{0x3c5e4ee6,1412.024,408.7473,-1759.805},
{0x3c716aa0,-4180.768,440.3622,1482.394},
{0x3cd4b5f0,2636.166,205.2848,1108.997},
{0x3dc85c5a,-1819.302,248.4935,973.5981},
{0x3e1546e4,-353.38,286.3675,-829.6086},
{0x3e4f52e6,4136.606,521.7107,-408.5667},
{0x3e7a2c72,-332.594,299.3984,-1747.388},
{0x3ed4373c,-2019.698,375.7961,2884.231},
{0x3ef6c241,1687.556,427.395,-1717.087},
{0x3efdd10b,-398.4,103.87,2559.24},
{0x3f8cebc3,-4011.171,205.6772,-1167.086},
{0x3fe2d9ba,2087.115,318.2577,-3573.556},
{0x40041a33,370.4178,92.51205,2567.043},
{0x4083454e,-4402.555,415.0383,-2866.692},
{0x40c903b6,1562.56,298.6208,2898.317},
{0x417748c0,-1970.932,420.7117,-3792.569},
{0x421ccbdc,-3327.45,3.924433,-336.9249},
{0x424fc160,1750.43,116.3929,1544.69},
{0x42baf164,-4307.612,132.1694,3459.745},
{0x42cf300d,-4409.103,618.9225,331.3417},
{0x437626cf,-2022.654,390.9383,-1300.632},
{0x44260d03,367.097,176.9335,3642.119},
{0x4437570a,4042.218,351.5685,-661.9659},
{0x44760b6f,3291.972,295.3834,-261.1206},
{0x44bae869,-2210.599,152.8292,-1621.4},
{0x44e4d73d,4239.353,409.8841,-998.2581},
{0x450b9f2b,-1996.6,301.5532,3619.667},
{0x450bc0fc,1188.64,323.4319,2476.71},
{0x458327c7,613.4128,183.5145,-743.3782},
{0x45c63ebb,4615.143,106.2173,1915.474},
{0x45cafb59,-3610.649,561.9243,-3491.99},
{0x45e64655,-2297.368,424.8451,-2293.149},
{0x45f2d306,1885.784,513.9319,-2749.106},
{0x467ee8b3,-308.7722,132.6444,-1166.005},
{0x46ef8e1d,-1590.039,210.7338,-229.1346},
{0x47079416,271.7195,222.3727,3289.589},
{0x470abbf6,416.7571,106.4126,3848.923},
{0x471abe01,-1512.017,177.0386,56.45966},
{0x475ded63,868.2729,142.6162,1902.033},
{0x4784fd6b,418.2094,128.0125,2873.406},
{0x478bf467,-4039.641,239.3008,-350.2388},
{0x47f4c0e2,3813.457,255.9981,-3419.22},
{0x485ae219,1055.116,167.1361,3254.771},
{0x48eb753e,-40.78424,306.5025,-2985.747},
{0x48faa931,-2836.955,348.8333,-1594.782},
{0x492c8b33,2811.316,239.6189,2391.926},
{0x49305266,2891.033,234.1595,517.871},
{0x4963817f,-1155.97,137.3342,245.1235},
{0x497b3aa1,-68.0202,91.39095,2332.616},
{0x49cb2b7f,34.27469,115.5547,2102.726},
{0x4a0d4d30,2991.393,118.1034,2272.146},
{0x4a1b0c3e,889.6107,180.8653,2395.303},
{0x4a278879,-2305.082,486.2545,2561.364},
{0x4a4be4b2,-512.7507,170.2696,550.6234},
{0x4a68f549,3726.792,127.2903,-2677.462},
{0x4a9fe113,-1057.312,167.5325,1327.525},
{0x4add63de,1074.55,182.0952,3620.945},
{0x4ae88291,-4195.749,165.6116,3091.554},
{0x4b1622c8,1374.621,107.2461,3751.464},
{0x4b225629,-2908.738,116.6645,796.266},
{0x4b864ab7,216.3226,199.1464,3488.015},
{0x4ba7a2f7,4697.84,335.7005,-547.03},
{0x4bf81bb3,517.5668,193.8545,3765.023},
{0x4c34123f,3171.941,293.8482,1490.935},
{0x4c435209,3350.103,175.0276,-3079.839},
{0x4c624fdd,160.0443,150.4367,1942.172},
{0x4c676609,1217.386,135.0406,3524.105},
{0x4c71cd7d,2684.855,218.5164,562.7817},
{0x4cbf31a5,2769.947,123.2163,348.8461},
{0x4cf9af7a,2504.476,312.2056,-1304.284},
{0x4d57c17f,551.5767,182.9,1903.507},
{0x4d7068c2,-2729.922,219.9338,761.3842},
{0x4dcf791e,-1047.625,139.6863,-2620.561},
{0x4ddac174,3206.764,312.2505,23.68088},
{0x4df49e60,-68.0647,261.281,-979.6238},
{0x4e05dfc4,-3441.073,357.3612,-664.8755},
{0x4e1bec8d,-792.036,201.3972,2257.223},
{0x4e86f173,-3971.633,213.6341,-920.5166},
{0x4ea8552b,-250.1414,432.8846,-1061.673},
{0x506472d9,4541.932,109.8,2405.64},
{0x50ab1278,-1728.585,144.3969,1478.864},
{0x5205d39d,-1224.69,299.7989,1358.416},
{0x520b5971,-190.9501,121.6845,1831.54},
{0x526ee929,-2175.129,407.0975,463.3505},
{0x52d18fa9,4452.651,164.2638,483.9736},
{0x52e200aa,-2817.465,578.2277,1652.721},
{0x52eabbf9,-599.9459,138.0255,1071.816},
{0x53449f3a,1101.693,224.2867,1889.54},
{0x535989d9,-3444.365,231.2116,-1328.69},
{0x53bf9a40,-74.38333,90.54819,2412.872},
{0x542ca5dd,2752.294,233.728,-1366.336},
{0x5498e0e8,1877.425,132.5337,2051.324},
{0x55d95f2b,2655.789,261.746,-971.1711},
{0x5603fd19,516.767,167.2447,1788.169},
{0x56323b35,-427.4001,317.6273,-1734.047},
{0x564f942b,-2638.9,410.0378,-2364.1},
{0x567c4331,3797.93,577.8524,1269.197},
{0x56a7b9b9,-2207.487,253.303,-1767.467},
{0x5700b68a,2511.433,120.0366,1571.525},
{0x578f3784,-2989.566,222.6,-2164.987},
{0x57ebd46f,-1962.841,314.6183,409.854},
{0x581282c5,69.30228,121.1721,1438},
{0x583a94ae,-2041.04,425.5532,296.3528},
{0x5848c075,2636.233,191.5871,3197.799},
{0x58932cbd,1676.101,324.6342,1157.939},
{0x5893c1cd,-4710.485,209.7189,2171.835},
{0x58ed79fc,3297.691,466.4747,-1583.792},
{0x5911354c,-253.8293,141.7269,-425.7258},
{0x5947fa66,2019.416,557.7247,-2172.899},
{0x595194e8,-4330.862,441.8892,-2600.161},
{0x59613b7f,891.1671,284.3683,3694.827},
{0x5987853d,4396.832,224.3599,-2721.584},
{0x59ab55bb,-3295.154,250.0965,-1362.929},
{0x59e0685e,-1805.357,31.56281,-1842.527},
{0x59e4f211,1088.531,164.7885,-215.8946},
{0x5a432e0e,-2448.412,134.736,3751.94},
{0x5a4a3917,-2602.175,508.3545,-3238.931},
{0x5ae18d84,-3831.341,248.413,-2106.709},
{0x5af84790,-2340.702,249.8667,1104.579},
{0x5b2750bd,3178.812,177.0007,1607.304},
{0x5b374fba,-4071.819,131.4124,-2545.949},
{0x5bc2358d,1739.307,413.3752,1186.675},
{0x5ced9ad3,2559.241,344.0077,3602.712},
{0x5d4170ff,3525.984,454.0448,1710.623},
{0x5d8f46c1,-2783.552,838.5354,-2895.525},
{0x5e2633fd,3271.144,105.9228,656.8208},
{0x5ec0d1ab,1323.723,194.4022,2453.452},
{0x5ef432e2,1387.279,135.2196,-112.9289},
{0x5f208f59,1886.184,147.4078,2418.735},
{0x5f622fdc,1008.131,270.2619,-1564.019},
{0x5fcdbd75,1377.204,322.4067,-1261.174},
{0x5fdb248a,1282.642,129.65,-1123.445},
{0x5ff70e36,-2521.762,457.0563,1318.59},
{0x6044b661,-653.6451,159.1371,1390.29},
{0x604688d4,1936.528,492.9896,2778.544},
{0x604e6f4c,-2842.696,333.9389,-3493.488},
{0x6071fa85,-1379.17,592.9069,3328.08},
{0x60c729d3,3779.707,275.4236,-3361.52},
{0x60ebf61e,1940.15,226.0126,-1217.732},
{0x610076d6,-1877.903,243.7032,-32.18372},
{0x6115ec62,-3476.202,154.9382,-69.05823},
{0x6134dc7d,4438.906,141.7224,1432.916},
{0x61895378,-26.89398,107.8101,3042.69},
{0x621d08df,-2946.503,686.9847,-3146.699},
{0x62939b45,2132.422,321.1151,678.8488},
{0x62cd12c3,-4862.196,129.3502,3260.965},
{0x62ef4882,2663.897,564.496,-2066.873},
{0x63643f49,-609.5657,119.0036,-682.3019},
{0x63a4612c,4199.456,107.1416,463.675},
{0x63fbbcc0,-567.7869,489.6004,-2599.203},
{0x64406b98,-3828.839,160.1595,-118.4242},
{0x645bf0a5,-38.98267,152.9507,2513.643},
{0x649e315a,-423.3546,125.2606,2022.457},
{0x655a0c0f,-1370.342,174.2264,1165.821},
{0x655ac3b3,-4183.675,491.7545,291.0669},
{0x655e5c8b,1537.85,505.3825,-2091.503},
{0x667c2c2c,2239.665,337.9715,726.3528},
{0x66a49116,-1336.888,122.5514,249.6623},
{0x670c85ff,-796.22,187.6677,-558.8558},
{0x6720557f,2330.776,133.963,1828.012},
{0x6789cfcd,-670.0859,119.1157,-932.6809},
{0x67e0b113,-1926.303,264.6315,3241.999},
{0x6801dca3,4332.92,406.9635,-696.6332},
{0x68de4eed,-3331.95,508.7438,-2297.167},
{0x69c59d49,4264.459,126.7609,628.2208},
{0x69c884cb,1803.734,202.6011,3221.996},
{0x6a047ec0,3112.552,426.0035,-1295.329},
{0x6b93ced0,-54.77505,128.9469,2492.44},
{0x6c199e80,-935.2057,167.8454,-641.2414},
{0x6c4af732,2303.51,281.3,2375.135},
{0x6c88172d,-3966.312,293.9241,-624.5618},
{0x6cd70d96,-1334.809,232.6704,1675.9},
{0x6ce27815,2517.501,182.504,-212.4814},
{0x6d337dd5,-2467.77,620.801,-2765.222},
{0x6d65fa2a,2884.092,160.9207,1765.027},
{0x6d9a328b,909.6229,183.5958,3837.292},
{0x6e05e450,-239.3844,139.7745,-112.5946},
{0x6e425edd,623.2406,123.537,-194.769},
{0x6e4b275d,5.321655,207.8237,1897.896},
{0x6e998846,-4192.807,288.3735,-2678.943},
{0x6e9bbc97,295.5803,135.2223,1204.796},
{0x6f884090,1381.904,288.3027,2277.448},
{0x6fc72def,-3673.786,550.7923,698.3047},
{0x7012ae43,4282.686,289.0398,1655.666},
{0x7017c7d1,-335.4028,256.5638,-1003.319},
{0x70665f74,-1809.821,162.5114,2459.625},
{0x707072d3,-3714.738,302.7229,-1040.965},
{0x70799bef,-354.8371,182.5916,3898.783},
{0x70b00c66,2665.531,205.7801,-1.298676},
{0x70b4b53c,-2247.72,446.0183,464.6729},
{0x70e63ec6,-3845.235,412.2645,1897.052},
{0x712b0ea5,-254.3532,146.8498,-264.4141},
{0x7166a639,-1512.686,117.3846,908.6653},
{0x7169f507,3166.324,193.831,1828.891},
{0x7186e8b8,-1132.606,238.2254,1917.723},
{0x71afefbb,-3757.127,375.4655,-3848.083},
{0x71d5d765,-423.0228,169.4002,1993.361},
{0x71e86829,1404.953,122.0926,-832.9891},
{0x71e8a107,-1176.851,344.9949,3578.054},
{0x71f54da2,3475.639,278.6932,1916.261},
{0x721f1852,790.6398,159.6066,2565.135},
{0x72d01780,668.647,135.4751,1468.298},
{0x731a1644,-2316.8,206.6814,-806.4525},
{0x7489ba85,200.8704,92.34924,2603.86},
{0x74d76fb9,1398.038,125.9827,-856.3475},
{0x74e51faa,54.9873,146.9078,1758.558},
{0x751e528f,-4266.573,226.0547,1691.536},
{0x754daf9f,-4058.83,208.5266,-773.8512},
{0x75910bc5,-1859.587,272.6248,334.3039},
{0x75e0dfc6,-853.2325,181.421,1671.219},
{0x76caf587,2484.83,119,2103.393},
{0x7733f2b8,1449.474,222.6956,3531.368},
{0x778f207d,-2012.6,127.1831,-1921.7},
{0x77efae60,232.2081,115.3543,1601.418},
{0x7815fb3a,3083.239,363.9244,-167.6896},
{0x782c2165,2508.15,157.6213,3825.909},
{0x787bd471,3639.774,326.9118,3258.224},
{0x789ebea5,-4314.106,219.0169,1629.409},
{0x78ca3e57,-2207.692,432.1688,2550.621},
{0x78fbe96b,2925.468,478.7521,1401.573},
{0x7901258d,-227.2847,176.7279,3342.734},
{0x79333e04,604.934,177.1582,2408.781},
{0x794f242d,-1935.345,452.7967,2673.502},
{0x79c7e150,-3688.848,740.4763,798.725},
{0x79fdfdf9,-2018.632,188.74,2186.643},
{0x7b10dfc2,-2636.621,444.7024,-2048.352},
{0x7b7ba39e,-1227.239,255.96,-1578.176},
{0x7bb7d834,-4552.238,623.3943,1353.159},
{0x7bfe2497,87.0126,164.5443,1585.099},
{0x7c0867ac,-2628.115,168.4946,2751.206},
{0x7ca4ffb4,625.1648,164.7659,2305.906},
{0x7d12a804,-2036.946,48.7074,-1622.946},
{0x7d787c89,-3677.899,426.2462,-2466.755},
{0x7dd35902,-2429.137,203.4877,1921.336},
{0x7dd43b3d,1867.815,511.0075,-2400.638},
{0x7de6bf97,788.8382,145.8729,1471.354},
{0x7e4d566b,2294.48,287.5065,3028.171},
{0x7f7d12eb,-3803.935,251.2842,-772.4634},
{0x7f8291b4,-1721.226,143.1919,2237.781},
{0x7fc87ad6,-115.4848,186.8435,2303.392},
{0x80826056,-2910.18,382.2979,-1639.037},
{0x80cfe359,644.1887,116.8154,1763.264},
{0x80d58d7e,4691.71,136.7105,-1777.33},
{0x80e46a95,-1280.393,284.6875,1384.899},
{0x80ec4d12,1865.555,533.9347,-2465.044},
{0x81f28000,-3115.97,496.3582,-2806.234},
{0x8292f970,4698.904,345.4613,-1003.025},
{0x82ac968e,400.8698,142.0619,2150.868},
{0x82ea3f2d,-1094.139,210.8778,-1731.894},
{0x82fad086,-1682.218,353.4708,-2184.838},
{0x830f1ec0,695.5233,119.4377,3071.41},
{0x836fa5ed,-2636.197,101.8104,3302.574},
{0x83bf0a9b,-1526.976,397.5132,3405.893},
{0x83dd4e76,2058.505,244.813,1208.554},
{0x847d126e,584.4322,217.5105,2678.335},
{0x8490d920,-1964.676,221.2041,-584.1647},
{0x84c082c4,-1799.607,114.8927,1625.901},
{0x853ee307,-3734.782,446.5874,-2964.398},
{0x8583858c,2315.027,293.5242,-1133.257},
{0x85fd0726,-2826.254,193.1497,-1580.078},
{0x86b9cf34,-2972.812,377.3,-1878.102},
{0x86ceb585,1049.239,115.8737,1783.277},
{0x86d7be5a,-3.030243,90.672,2614.667},
{0x86e964bc,-3207.551,5.917226,-333.9864},
{0x86f2438b,4518.497,219.7798,2316.516},
{0x879574c2,-4136.396,401.4471,1717.96},
{0x87c85b50,-2791.13,397.6961,-1945.598},
{0x881390d3,-822.6375,171.2339,1546.921},
{0x8818e264,704.9866,116.7559,1796.567},
{0x881a3647,-1062.994,226.9131,-1934.109},
{0x883875aa,-4224.869,154.6506,2738.074},
{0x88cc839d,2276.034,162.2581,1501.621},
{0x88e54d6b,-240.1111,106.0764,3882.502},
{0x89ca3c5d,850.5078,115.3998,1623.993},
{0x89e19447,-4424.155,497.1648,-3215.942},
{0x89facd12,824.9434,120.7363,3005.301},
{0x8a07fb55,4344.057,363.3881,-3178.368},
{0x8a1c1396,-2900.084,498.6471,-2508.787},
{0x8a3b5037,2085.788,129.7888,181.6626},
{0x8a4b420c,-4355.337,716.6,709.874},
{0x8a6c5698,-394.0272,204.58,-785.4035},
{0x8ac957d4,868.0159,209.8152,-1362.166},
{0x8ad9e8a7,-1336.357,117.1225,366.6163},
{0x8b14d443,-4160.327,133.1369,3826.202},
{0x8b47a5fb,-133.7057,143.3529,945.0361},
{0x8b8a196a,-3418.51,286.3803,-2066.815},
{0x8bfd9414,-2547.427,141.4355,3951.93},
{0x8c119354,4422.963,115.1583,-3340.219},
{0x8c2a33fa,2874.915,299.74,2683.368},
{0x8c323e3b,-2172.509,185.7276,3200.396},
{0x8c3a4e37,2409.547,269.6053,849.3189},
{0x8c5a8b69,1245.111,541.3436,1942.178},
{0x8c5bda77,318.1566,115.3873,1397.902},
{0x8c6caeff,-251.8438,517.1672,-1061.771},
{0x8c750182,1821.037,272.0274,3742.026},
{0x8cb6e831,-4607.906,161.6079,2338.845},
{0x8d17595f,2526.617,334.827,1257.579},
{0x8d908351,3736.669,147.3763,-2884.984},
{0x8dec90ea,322.0657,127.5006,525.0073},
{0x8df0c4a7,-753.6708,151.1773,-1086.794},
{0x8df41fab,4144.438,138.3371,195.9695},
{0x8e40d3ee,-4220.021,257.5498,1659.797},
{0x8e4adad4,153.9499,143.8689,2981.718},
{0x8e6ff49f,-886.65,129.2583,-274.04},
{0x8eb3216e,-420.7542,141.3747,3368.484},
{0x8ebae5b4,406.1136,139.9,3051.134},
{0x8ec92e81,2266.556,347.3776,-1565.486},
{0x8ee513d1,3122.881,185.6049,-17.39868},
{0x8ef728de,1980.929,174.2776,451.9176},
{0x8f03405e,-2053.485,258.4682,636.411},
{0x8f2a30e1,4080.406,421.4792,-216.7825},
{0x8f3ab788,4134.865,294.9371,60.32083},
{0x8f633554,-923.501,214.5819,3436.38},
{0x8f706bf5,3432.942,342.9529,1150.31},
{0x900525b6,-3414.794,542.0234,-3509.611},
{0x907adc44,-2523.397,364.8272,-1736.947},
{0x90931b5a,3420.944,340.3562,2390.287},
{0x909ff681,-1249.552,125.526,730.6769},
{0x90aea807,1552.487,182.8108,3529.241},
{0x90da6b48,3431.141,146.4093,523.7474},
{0x911bcd90,1185.502,164.2552,-67.4191},
{0x914e5c8b,396.0804,115.5029,-625.5601},
{0x919a1346,1406.713,255.4892,3198.755},
{0x91d09be7,1116.142,119.931,555.5753},
{0x921c662a,-1922.226,332.9751,3279.693},
{0x9295df6c,-1356.697,140.9515,1002.412},
{0x92ae480a,69.03473,127.14,3221.873},
{0x92ccabab,-1666.661,249.2757,1393.96},
{0x93269172,85.54697,138.1385,-634.9767},
{0x938cdf69,-1651.16,224.8122,-39.06839},
{0x93dbf4f8,2968.719,122.9329,3380.182},
{0x93ea4614,506.9064,141.8195,-882.6183},
{0x944bb152,13.95764,106.5948,3790.43},
{0x945bd1cd,686.0379,167.9348,-635.104},
{0x947bb87d,-368.9545,151.4308,-993.4459},
{0x94875ae7,1773.844,346.6876,2930.867},
{0x956be08e,-3461.163,176.1707,166.2989},
{0x9596e203,-168.3692,216.0174,-860.4059},
{0x95cdfa70,-4123.615,303.5288,-1935.337},
{0x9615d0d6,1373,220.294,2749.046},
{0x963411fc,-2358.595,385.0072,-1872.809},
{0x9696539d,-3715.859,570.3722,1558.073},
{0x96c02c14,755.6919,194.098,2347.605},
{0x975b52db,4428.835,352.2694,-3182.9},
{0x97b2deb4,3010.155,346.4312,-1204.248},
{0x97c9c11b,-1258.633,138.6124,-2360.096},
{0x97e79802,1840.689,135.0218,3595.827},
{0x9812135c,4083.595,109.3641,2973.261},
{0x98143e94,-3843.155,435.3878,-3348.182},
{0x985f3beb,-2918.603,118.2453,479.7349},
{0x98753d6c,-1066.794,208.4339,2910.011},
{0x98e17eee,-2918.655,141.7088,3061.014},
{0x992cf785,699.92,133.6721,3276.863},
{0x9966d589,-2338.221,369.2435,-1726.701},
{0x9969542a,3479.966,280.7756,-2077.341},
{0x99736b62,-265.7393,250.3626,-1138.757},
{0x9988d511,1517.272,400.2469,1850.083},
{0x99996f7e,685.1261,431.8878,-2758.458},
{0x999c8205,742.8929,134.0192,3243.08},
{0x9a2a7ab3,-1399.424,220.2027,2378.205},
{0x9ad72bfb,3288.675,511.2913,-1574.587},
{0x9b3310be,-1501.964,118.0242,156.2179},
{0x9b5dda92,-1134.464,143.8477,1030.472},
{0x9b7cd7b0,-663.3021,146.7741,-432.6016},
{0x9b7f8797,-1148.198,149.3743,-226.6854},
{0x9b88be59,-4065.467,316.0535,-1678.328},
{0x9bebaec0,1748.572,140.6938,1921.653},
{0x9c1bfb39,3144.467,163.4093,2229.855},
{0x9c75e5f8,-1077.38,238.5356,-1278.708},
{0x9c77f87c,3882.549,356.5327,-1340.015},
{0x9db69b95,-3627.384,453.5585,-1804.825},
{0x9ebdaa4c,1615.105,207.955,-3661.03},
{0x9f0488fe,-3107.278,135.387,2881.241},
{0x9f5bf5e7,-1503.422,297.2265,1920.174},
{0x9f8b8360,2366.56,221.7048,2303.499},
{0x9f8c6f32,3561.943,106.2442,626.3196},
{0x9fadacb6,-2217.829,321.1888,-1565.024},
{0x9fbac800,589.7725,121.4821,-1107.129},
{0x9ffb6db1,-3353.04,156.9178,2276.308},
{0x9ffc1594,3229.815,256.5484,2848.442},
{0xa0d80366,-1258.401,159.7504,-240.5181},
{0xa1300acf,-2645.98,300.1651,547.9241},
{0xa169ce01,2163.896,460.6209,1034.737},
{0xa1a2edef,-4340.954,767.3851,782.1329},
{0xa206700f,1513.742,136.271,3725.037},
{0xa2217391,2139.981,200.2839,3531.94},
{0xa26bf7c8,-1731.076,216.9656,375.1318},
{0xa2b4a213,3687.959,107.3202,2413.493},
{0xa394e375,833.7554,145.3382,2434.576},
{0xa3c26a27,-644.5822,146.2107,876.1129},
{0xa3cecb89,97.63947,181.0175,-429.8078},
{0xa44b516c,66.22549,94.00381,2310.65},
{0xa4e8182d,1793.9,258.8986,1052.825},
{0xa5235679,-2487.656,514.3344,-3021.601},
{0xa5b0ddd5,3662.784,273.6752,-2067.316},
{0xa5f5aed7,-1375.173,361.9268,-3640.943},
{0xa63ff4cc,1378.099,256.94,3503.561},
{0xa664790a,-66.24554,124.0046,2440.657},
{0xa6a81087,4356.779,284.9696,-1528.1},
{0xa6f93c08,3527.287,395.3051,-276.7639},
{0xa79e3be3,-4019.884,130.8091,-2350.359},
{0xa7cbccfa,-2417.311,191.1999,1923.725},
{0xa8810dca,-2167.784,336.4488,2082.042},
{0xa89818b7,2836.962,126.8794,3452.763},
{0xa91201aa,-4167.162,516.8201,-3615.937},
{0xa92b45ef,-425.2748,131,1189.346},
{0xa956dc79,292.1846,117.2136,-724.0883},
{0xa9bb8861,-1349.376,241.7028,-2734.519},
{0xaaf7b209,-925.2401,237.0128,2936.44},
{0xab116079,3347.619,209.942,2249.252},
{0xab4471a0,1733.161,168.0593,3450.589},
{0xab7ee389,4536.525,106.4408,2520.272},
{0xac952baa,-3496.125,474.2198,-3580.674},
{0xacfc460d,2195.503,613.2101,-3007.841},
{0xad58d3ce,2320.668,119.2743,1726.367},
{0xad635dca,3877.544,178.8445,-2371.863},
{0xae2177a0,-4029.339,464.8524,-3760.179},
{0xaeaa31fe,2233.992,338.4426,-3673.525},
{0xaed4da21,-150.92,143.3865,3067.3},
{0xaf068a5a,384.2617,154.1735,135.3624},
{0xaf1381a7,474.9577,115.2629,2149.122},
{0xaf46339e,-3109.259,34.17905,-909.2654},
{0xafd6ac26,-1675.992,96.53553,-2139.302},
{0xb092991a,1660.151,252.6535,3163.642},
{0xb0978dc0,-1658.59,159.12,2306.77},
{0xb0a896f6,-4507.235,226.3406,-2146.108},
{0xb0d722c0,-2594.755,284.7202,2539.869},
{0xb1ae7c07,-2836.292,501.8753,-2423.835},
{0xb2972d36,1632.017,585.5543,-2939.5},
{0xb29ba230,-4353.388,242.2131,1838.526},
{0xb29d5968,-1351.458,448.5679,3770.793},
{0xb2c7a150,-324.3851,185.6199,-798.1587},
{0xb30d16ad,-1095.986,413.9733,-3399.873},
{0xb38f3294,-3431.202,278.0103,-707.841},
{0xb3d00fa3,3029.036,114.8,2017.677},
{0xb3fa9939,224.1717,135.2091,2868.403},
{0xb42b2abb,-247.1635,211.8434,-739.613},
{0xb50397e3,2060.978,580.314,-2757.42},
{0xb50f57b1,-3780.539,368.6099,-1865.624},
{0xb52de9f9,2279.315,182.4268,1608.345},
{0xb539c88a,-1190.024,174.9518,1116.745},
{0xb5f30638,-100.9207,131.378,-979.7477},
{0xb6514b9c,2355.876,524.6516,-2067.376},
{0xb690acc0,-1372.536,115.847,-107.9869},
{0xb692e371,-2081.09,353.6358,1477.029},
{0xb6a4fe6e,-3999.216,632.9622,-3620.06},
{0xb6f62fe4,-2370.105,307.047,-345.3073},
{0xb77452ca,1143.403,209.9631,-3742.778},
{0xb88a8351,518.3896,211.5482,2492.625},
{0xb92bcf9a,-965.4801,187.2091,1625.697},
{0xb93698b0,3175.443,309.289,3204.03},
{0xb97c0a67,3732.84,139.5452,-2423.215},
{0xba2cee6a,2275.006,134.982,-720.1478},
{0xba424efe,-1230.517,207.6727,-999.8165},
{0xba58f3fc,2408.195,262.344,-1229.951},
{0xbaba4538,-254.0015,210.5489,-739.5409},
{0xbad8620b,-427.2841,135.8405,150.9248},
{0xbb03c92f,3152.594,170.1656,-3328.348},
{0xbb45ccb7,1785.537,344.3603,3011.07},
{0xbb4bfa62,-3078.344,207.994,-1120.356},
{0xbbb11045,3321.498,414.0922,-514.2532},
{0xbbba17c1,340.6279,94.2322,2830.629},
{0xbc7389bd,86.2337,138.8198,-412.086},
{0xbcbec70f,-2516.125,61.96953,-1436.305},
{0xbcf9ae6f,3537.012,313.5478,1376.113},
{0xbd828e2c,225.3818,173.6473,872.0403},
{0xbde42185,954.403,116.2789,942.4681},
{0xbde4dc1c,-1125.279,157.9102,-675.4301},
{0xbdf2209a,-953.0682,201.5502,1721.484},
{0xbe4a5e9b,-383.2059,347.4652,-993.6246},
{0xbe8daba7,178.5485,134.0422,-940.0205},
{0xbeceb922,-2867.818,518.5404,1124.927},
{0xbf572908,1104.015,210.7557,-444.2307},
{0xbf74ae6d,627.0391,130.941,182.307},
{0xbfbebf6e,-1357.034,479.6575,3671.94},
{0xc0514ef5,-3562.246,289.5035,-1761.346},
{0xc0547b5f,-1984.865,348.4926,362.9465},
{0xc0851403,2378.29,231.6163,373.1468},
{0xc0c5b569,-4155.937,350.4482,-3404.128},
{0xc0cd8a7f,-2060.66,259.4979,-775.7871},
{0xc12bdd2b,1757.802,253.7049,3685.978},
{0xc1d550bc,3323.916,301.6292,-519.5153},
{0xc22ceff6,-2434.115,319.8664,-491.0357},
{0xc232a5db,1685.603,129.8256,661.1248},
{0xc239ed48,-1115.559,151.9816,-528.5893},
{0xc2cb5826,-1019.516,222.8577,-2077.297},
{0xc2e1762c,3496.163,255.9283,-3374.297},
{0xc30ec0c8,1258.459,492.1165,1851.127},
{0xc31f0b04,-1403.117,101.0272,-2312.289},
{0xc32c01ee,-1125.951,315.8488,3624.428},
{0xc3ae20b1,-3574.575,494.2303,-3272.382},
{0xc3b32918,1936.541,134.2709,2564.501},
{0xc4a46604,2054.829,153.2433,2092.73},
{0xc4c62b2c,-466.4118,137.2151,1279.382},
{0xc5001ffb,-1379.586,215.0948,2742.734},
{0xc54c483d,671.092,180.8665,1638.379},
{0xc55a580a,-1204.356,329.348,2322.776},
{0xc57a665c,-2542.837,307.7846,639.8586},
{0xc5b90c80,603.3977,249.912,-3633.77},
{0xc5e9f609,-4148.758,216.3956,-2616.475},
{0xc61db84f,4098.317,232.8195,-1756.464},
{0xc6a34951,-1017.86,116.9594,-1066.078},
{0xc6fe441e,-2736.11,456.88,-2582.83},
{0xc74e2a27,3960.616,378.5291,-858.5881},
{0xc7b919e2,-4527.836,571.9739,1423.325},
{0xc826318a,3208.673,570.4832,-1011.226},
{0xc8679196,-703.6862,247.6578,-1443.785},
{0xc88964c5,3709.392,204.173,-1683.445},
{0xc88dcc27,-270.2613,255.1069,-879.1967},
{0xc8ba33c8,2288.527,250.7979,699.6213},
{0xc919c75f,-4482.926,266.7692,-1970.876},
{0xc996c2e9,1682.657,201.4698,2327.619},
{0xc9ef2e6c,1544.331,394.203,-1837.214},
{0xc9f260d3,-2636.284,300.5481,-1246.991},
{0xc9fb4ba8,-737.4062,125.8594,333.7565},
{0xca074b9f,2927.666,292.9401,332.8004},
{0xca1474b6,-1615.964,193.3715,2447.329},
{0xca31bdfa,169.7322,118.7293,2903.416},
{0xca4be8f1,-770.0294,135.0662,1380.977},
{0xca72f256,-147.5123,188.9713,-1159.794},
{0xcaa658ea,-1035.085,150.2215,-446.2222},
{0xcacc2df3,-1011.91,330.58,2638.47},
{0xcb09ff3f,4274.364,430.7932,1981.021},
{0xcb637a36,-3207.789,37.56471,-494.8928},
{0xcb8bdf6e,-809.2235,297.7529,1966.909},
{0xcbf505e2,581.2495,123.0391,3007.603},
{0xcc29f2e1,-130.5417,168.7775,-1379.279},
{0xcc2f05cf,-4859.178,172.696,3832.948},
{0xcc35335a,-2264.512,356.9891,2163.38},
{0xcc5c6d8c,1832.722,217.9547,-535.6974},
{0xcd93538a,3516.118,160.2076,2628.382},
{0xce90cbd2,-749.9227,132.9082,892.2105},
{0xced040d3,1593.879,543.9135,-2475.25},
{0xcef4746e,-3271.391,244.4316,-1868.258},
{0xcf43cc73,-2464.743,417.7118,1713.475},
{0xcf4a869e,-378.6588,163.6076,-1112.098},
{0xcf58e63d,3229.032,302.8331,1545.245},
{0xcf88b5d2,3367.108,109.9,3653.537},
{0xcf8c8a6b,-254,364.0167,-994.6138},
{0xcf9d7c89,3441.938,216.0831,3121.876},
{0xcfd54587,-4066.787,569.1418,437.8475},
{0xd00a5f8c,-4347.897,142.8856,3713.184},
{0xd022178b,-3696.666,211.106,-1684.11},
{0xd0cd4001,3237.797,479.9398,-1527.746},
{0xd0fd5dce,-2450.164,317.9307,373.4799},
{0xd122eec3,-2685.725,206.0558,2929.656},
{0xd186c389,337.1497,120.0506,1271.062},
{0xd1f96d16,56.69495,109.8976,3150.023},
{0xd24e7a25,4232.734,385.9994,-212.3339},
{0xd2ac12eb,-1436.289,231.0027,-1668.662},
{0xd2ba8c37,1593.187,115.9848,114.1612},
{0xd2fb91a3,-2984.896,559.2073,-2693.526},
{0xd3d6c91c,1549.113,533.4022,-3108.549},
{0xd3eb5666,-1439.601,125.505,846.6677},
{0xd4031665,-2830.556,669.6175,-2828.345},
{0xd40caa6e,-1583.931,68.69307,1579.691},
{0xd5210e5e,3296.232,459.8649,-1421.087},
{0xd5d14cc9,1957.253,248.0698,1062.054},
{0xd60dddfc,2171.211,198.8678,3276.907},
{0xd61e3051,3901.082,235.8,2096.729},
{0xd62e065c,2746.148,237.5875,-176.402},
{0xd652c264,237.4364,304.0661,-2943.386},
{0xd656293a,3565.886,530.6382,-915.9223},
{0xd6db8c19,908.2865,247.1734,2193.526},
{0xd6e38e1e,-2669.56,375.5663,-864.3912},
{0xd71066f2,1197.521,126.9715,-1152.63},
{0xd7a55949,4530.945,106.988,-2098.376},
{0xd7c86b91,3289.577,175.8,3338.793},
{0xd8927c64,-1538.743,278.4041,3070.083},
{0xd89c4741,-1884.491,23.98346,-1813.181},
{0xd8c72da7,1376.526,327.8504,1680.343},
{0xd910c140,4815.501,105.7348,-3300.246},
{0xd93aea04,1950.854,457.4908,-1832.657},
{0xd97128ce,1173.395,192.6689,2849.989},
{0xd9852d2a,1798.334,230.967,1078.175},
{0xd9957080,3140.857,220.7948,324.9673},
{0xd9d7b018,-2066.651,228.3253,1850.097},
{0xd9f18bf9,3322.944,379.4629,-2803.064},
{0xda11e11a,-3675.036,390.4904,-393.3223},
{0xdad9a49f,2703.711,225.5242,-1749.271},
{0xdae8ff9a,-3960.376,350.6725,-3723.258},
{0xdaea9644,-4210.025,609.7234,1133.509},
{0xdb42b09c,-3061.221,535.2148,-2813.686},
{0xdb4d9121,4181.042,220.8049,-2540.406},
{0xdc0848c2,-2030.122,206.4728,-547.6038},
{0xdc2dd997,-2751.337,459.4663,-2258.777},
{0xdcc8ba61,-162.0529,310.192,-878.053},
{0xdd4e2b38,-4026.708,145.2115,-232.4064},
{0xdd512e1b,3451.99,143.5695,550.7929},
{0xdd5a8ff0,1426.895,465.0379,-1544.07},
{0xdd777485,2705.439,203.1025,1164.945},
{0xdd836be1,-911.8,219.251,-1612.799},
{0xdd8e3d43,-2250.215,446.8035,-3092.183},
{0xdeb178e3,3726.305,331.2563,-1129.711},
{0xdec72884,-106.4598,153.33,1047.969},
{0xdf2a8fb0,-3841.713,218.4154,-803.9846},
{0xdf2fbf5f,2478.573,313.4195,-1391.592},
{0xdf664163,1305.289,191.349,2434.059},
{0xdfabfc2e,-1764,343.6976,-2350.704},
{0xdfbafa88,883.0738,133.6105,274.7977},
{0xdfbd654f,-3435.389,145.8999,2980.161},
{0xdfc6edc1,319.6543,137.195,-962.0651},
{0xdfc9ba84,-1020.383,201.0212,559.8116},
{0xdfda0f23,178.9613,116.6815,1719.983},
{0xe02da94d,-3014.163,174.9565,372.4369},
{0xe06124cb,-1309.765,209.0709,-1941.56},
{0xe0ec0587,286.8358,109.9,3899.422},
{0xe0ec0c23,1595.755,117.3918,807.6757},
{0xe1091dcc,-2059.885,306.7729,2420.099},
{0xe11fff55,-363.2491,131.7304,396.9416},
{0xe195562e,3951.867,106.3174,695.8884},
{0xe1edbaea,-2083.961,293.0881,-1558.725},
{0xe1f3f35a,214.5758,170.0761,2070.059},
{0xe23f09b9,1446.498,116.0391,558.3604},
{0xe27c26e0,-728.0692,154.6989,134.7785},
{0xe2810b71,1553.541,119,1297.187},
{0xe340e086,2863.861,140.2649,2182.903},
{0xe4dfc1c0,-4397.606,332.4454,-3773.917},
{0xe5293f22,4294.82,171.3062,78.50095},
{0xe73804b3,-2454.273,337.828,1157.305},
{0xe7538675,-1171.618,342.5077,2317.226},
{0xe7bd6e0d,-1363.466,335.7053,2215.195},
{0xe7d81530,-3129.014,614.0129,1467.155},
{0xe80a9eda,-1665.899,143.884,2338.163},
{0xe973a2c6,1462.677,336.7975,2370.849},
{0xea312f16,-1691.985,224.9699,-175.5285},
{0xeac72197,1807.032,220.4456,992.2015},
{0xeadbf30c,704.0372,120,2957.835},
{0xeafbc191,1933.256,376.7372,1220.964},
{0xeb323cb8,1325.561,296.6678,3008.678},
{0xebf2367a,3084.931,239.7771,2884.649},
{0xec46d3c7,3383.032,118.7868,982.824},
{0xec65fd0e,2424.331,253.6873,-1738.5},
{0xec69ed31,1939.514,269.1108,1110.931},
{0xec777d7c,-3524.551,373.7811,-449.6941},
{0xec9bb374,2207.285,192.5972,1373.48},
{0xece1fa6a,-1535.295,346.8846,-3475.819},
{0xece4af29,-1746.917,71,1831.097},
{0xed01da5f,2407.271,328.6665,-1613.596},
{0xed7f50ce,-2290.551,438.3871,468.2381},
{0xed80c7a5,3455.615,314.1401,-3581.874},
{0xee425e1d,-2883.833,521.3348,-2398.015},
{0xee48aa58,-1214.313,193.4733,2701.554},
{0xeed4a595,-2312.609,262.63,24.0163},
{0xef0a866a,815.2213,202.7296,2089.438},
{0xef6dfdb7,840.4058,236.2888,-692.4791},
{0xef9ceab3,-1154.359,132.8694,964.6355},
{0xf0274e1a,-2298.7,352.5616,2850.02},
{0xf036238f,-3792.613,283.47,-2320.191},
{0xf04e0c73,2856.583,113.7,3651.77},
{0xf0988858,-2358.78,476.1237,2554.533},
{0xf0b1e9b3,806.0729,124.5497,3112.856},
{0xf1888b2f,266.1024,276.4652,3668.951},
{0xf1aa8b46,-2210.06,498.6493,-2908.544},
{0xf22a43d9,-234.593,233.9734,-743.9327},
{0xf26db476,3520.64,326.7276,-383.5883},
{0xf29f26c9,-4690.488,704.1445,842.3635},
{0xf32bd5d4,3854.316,150.8158,352.2569},
{0xf349734f,-1781.002,347.3688,-2745.017},
{0xf3610321,-3041.119,430.4363,-2520.181},
{0xf366a0bd,-3125.194,263.008,-1366.506},
{0xf443fae0,-1009.463,130.1141,932.0392},
{0xf450426c,4503.659,379.2101,-3164.388},
{0xf5163503,-887.3224,208.1414,1891.407},
{0xf58b5c80,504.4539,123.3314,-493.469},
{0xf5b246cc,863.917,316.2801,-3358.529},
{0xf6099a1a,3372.048,271.9472,-2315.193},
{0xf6264d79,-1465.906,418.667,2952.556},
{0xf634a5b7,3995.799,292.524,-3147.581},
{0xf6853f20,-161.7531,147.4383,-262.0431},
{0xf691cf9e,-816.6761,224.4611,-1926.157},
{0xf7812399,-387.5938,152.9809,3151.553},
{0xf7bfdb93,1196.1,132.0342,3055.431},
{0xf7fb7294,1658.13,554.5893,-2564.875},
{0xf80d5e7e,2551.062,411.2377,-3592.677},
{0xf8497c57,963.303,173.4832,3371.103},
{0xf8d0c224,522.4664,166.3034,3680.958},
{0xf8d0d057,163.2763,90.2076,2783.299},
{0xf90a90fd,-3031.625,181.0055,3754.591},
{0xf9342a29,-2351.149,263.4041,846.18},
{0xf93afc9a,4616.441,366.4656,-638.0287},
{0xf9531c7b,-3886.142,229.4351,2965.82},
{0xf99b49af,-2815.311,160.7108,2247.913},
{0xf9d1d011,2751.067,293.7672,-1675.908},
{0xf9e10545,2179.551,226.3402,-1282.035},
{0xf9e81bfa,2099.721,363.6605,2625.572},
{0xf9eb79ab,-3661.365,257.3734,-828.8036},
{0xfa2ecee2,-2697.263,270.8433,2105.062},
{0xfa2f3eec,-710.2506,158.3555,99.93271},
{0xfa3e6133,3178.982,176.4081,-3073.667},
{0xfa5c61d9,25.66391,148.4707,147.481},
{0xfa7b263f,284.2921,146.7982,2253.376},
{0xfb1f386a,-468.6423,98.70972,2908.232},
{0xfb765fbc,-1631.543,210.4313,-515.1945},
{0xfbee67d4,645.7247,152.3,3615.123},
{0xfc5b8f9f,-2066.654,288.8196,2397.045},
{0xfca2f664,2714.133,225.5328,2345.553},
{0xfd72c546,-4373.898,165.1335,2587.057},
{0xfd840f72,280.4268,97.65099,2405.01},
{0xfdd548dc,-1819.094,206.1718,1532.648},
{0xfe3efb1d,2273.799,431.7688,-1823.225},
{0xfe508967,4095.783,220.0073,-1627.464},
{0xfe750c11,-3793.74,353.0625,-3032.967},
{0xfea08520,2284.273,287.5378,2659.972},
{0xff6a74af,2662.632,479.3359,-3471.585},
{0xff7758a0,-3728.542,166.4874,3610.083},
{0xffa754fa,-1045.92,54.66044,-2707.638},
{0xfffbdf04,4110.978,111.1552,2588.168}
};
#endif

View file

@ -1,44 +1,82 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <dirent.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include <switch.h> #include <switch.h>
#include "save_basic.h" #include "save.h"
#include "ui_basic.h" #include "ui.h"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
setvbuf(stdout, NULL, _IONBF, BUFSIZ); setvbuf(stdout, NULL, _IONBF, BUFSIZ); //do not line-buffer stdout
Result rc=0;
bool exit = false;
AccountUid uid={0};
u64 application_id=0x01007ef00011e000;//ApplicationId of the save to mount, in this case BOTW.
consoleInit(NULL); consoleInit(NULL);
// Configure input // Configure our supported input layout: a single player with standard controller styles
padConfigureInput(1, HidNpadStyleSet_NpadStandard); padConfigureInput(1, HidNpadStyleSet_NpadStandard);
// Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller)
PadState pad; PadState pad;
padInitializeDefault(&pad); padInitializeDefault(&pad);
// Initialize UI //draw main screen and menu
initUI(); initUI();
printMessage("Press A to test save loading\n"); //Get the userID for save mounting. To mount common savedata, use an all-zero userID.
printMessage("Press + to exit\n");
bool exit = false; //Try to find savedata to use with the above hard-coded TID + the userID from accountGetPreselectedUser(). Note that you can use either method.
//See the account example for getting account info for an userID.
//See also the app_controldata example for getting info for an application_id.
rc = accountInitialize(AccountServiceType_Application);
if (R_FAILED(rc)) {
printMessage("accountInitialize() failed: 0x%x\n", rc);
exit = true;
}
rc = accountGetPreselectedUser(&uid);
accountExit();
if (R_FAILED(rc)) {
printMessage("accountGetPreselectedUser() failed: 0x%x\n", rc);
exit = true;
}
//You can use any device-name. If you want multiple saves mounted at the same time, you must use different device-names for each one.
rc = fsdevMountSaveData("save", application_id, uid);//See also libnx fs.h/fs_dev.h
if (R_FAILED(rc)) {
printMessage("fsdevMountSaveData() failed: 0x%x\n", rc);
exit = true;
}
//At this point you can use the mounted device with standard stdio.
//After modifying savedata, in order for the changes to take affect you must use: rc = fsdevCommitDevice("save");
//See also libnx fs_dev.h for fsdevCommitDevice.
openSave();
processSave();
// Main loop // Main loop
while(appletMainLoop() && !exit) while(appletMainLoop() && !exit)
{ {
// Scan the gamepad. This should be done once for each frame
padUpdate(&pad); padUpdate(&pad);
// padGetButtonsDown returns the set of buttons that have been newly pressed in this frame compared to the previous one
u64 kDown = padGetButtonsDown(&pad); u64 kDown = padGetButtonsDown(&pad);
exit = handleButtonPress(kDown); exit = handleButtonPress(kDown);
if (kDown & HidNpadButton_A) {
openSave();
processSave();
}
consoleUpdate(NULL); consoleUpdate(NULL);
} }
fsdevUnmountDevice("save");
consoleExit(NULL); consoleExit(NULL);
return 0; return 0;
} }

282
source/map.c Normal file
View file

@ -0,0 +1,282 @@
#include <stdlib.h>
#include <switch.h>
#include <math.h>
#include "map.h"
#include "save.h"
#include "ui.h"
#include "data.h"
u32 mapPinIconCount = 0;
u32 mapPinLocCount = 0;
u32 map_pin_count = 0;
Point PlayerLocation;
//2d seems to work better than 3d
int compDistance (const void* elem1, const void* elem2)
{
Point f = *((Point*)elem1);
Point s = *((Point*)elem2);
double f_distance = sqrt(pow(f.x-PlayerLocation.x,2)+pow(f.z-PlayerLocation.z,2));
double s_distance = sqrt(pow(s.x-PlayerLocation.x,2)+pow(s.z-PlayerLocation.z,2));
if (f_distance > s_distance) return 1;
if (f_distance < s_distance) return -1;
return 0;
}
/*void addMapPin(u32 icon, Point location) {
u32 pin_hash = 0x9383490e;
u32 pin_offset = _searchHash(pin_hash) - 4;
u32 pin_maxlength = ((GAMEDATASAV.length - pin_offset) / 8);
u32 pin_total = 0;
for ( u32 i = 0; i < pin_maxlength; i++) {
u32 pin_base = pin_offset + (8*i);
u32 pin_header = readU32FromAddr(pin_base);
u32 pin_value = readU32FromAddr(pin_base + 4);
//printMessage2("%d: hash %x offset %x base %x header %x value: %x", i, pin_hash, pin_offset, pin_base, pin_header, pin_value);
if (pin_header != pin_hash) { break; }
if (pin_value == 0xffffffff) {
//printMessage2("%d: hash %x offset %x base %x header %x value: %x", i, pin_hash, pin_offset, pin_base, pin_header, pin_value);
writeU32ToAddr(pin_base + 4, icon);
pin_counter++;
break;
}
if (++pin_total >= 100) { break; }
}
u32 pinloc_hash = 0xea9def3f;
u32 pinloc_offset = _searchHash(pinloc_hash) - 4;
u32 pinloc_maxlength = ((GAMEDATASAV.length - pinloc_offset) / 8);
u32 pinloc_total = 0;
for ( u32 i = 0; i < pinloc_maxlength; i++) {
if (i%3 != 0) { continue; }
u32 pinloc_base = pinloc_offset + (8*i);
u32 pinloc_header = readU32FromAddr(pinloc_base);
//printMessage2("hash 0x%x offset 0x%x base 0x%x header 0x%x x: %f y: %f z:%f\n", pinloc_hash, pinloc_offset, pinloc_base, pinloc_header, pinloc_value_x, pinloc_value_y, pinloc_value_z);
if (pinloc_header != pinloc_hash) { break; }
float pinloc_value = readF32FromAddr(pinloc_base + 4);
if (pinloc_value == -100000) {
//printMessage2("hash 0x%x offset 0x%x base 0x%x header 0x%x x: %f y: %f z:%f\n", pinloc_hash, pinloc_offset, pinloc_base, pinloc_header, pinloc_value_x, pinloc_value_y, pinloc_value_z);
writeF32ToAddr(pinloc_base + 4, location.x);
writeF32ToAddr(pinloc_base + 12, location.y);
writeF32ToAddr(pinloc_base + 20, location.z);
pinloc_counter++;
break;
}
if (++pinloc_total >= 100) { break; }
}
}*/
void iterateMapPinIcons(func_t_0 iterFunc, u32 icon) {
mapPinIconCount = 0;
u32 pin_hash = 0x9383490e;
u32 pin_offset = _searchHash(pin_hash) - 4;
u32 pin_maxlength = ((getSaveSize() - pin_offset) / 8);
for ( u32 i = 0; i < pin_maxlength; i++) {
u32 pin_base = pin_offset + (8*i);
u32 pin_header = readU32FromAddr(pin_base);
u32 pin_value = readU32FromAddr(pin_base + 4);
if (pin_header != pin_hash) { break; }
if (!iterFunc(pin_base+4, pin_value, icon)) {
break;
}
}
}
void iterateMapPinLocs(func_t_1 iterFunc, Point location) {
mapPinLocCount = 0;
u32 pinloc_hash = 0xea9def3f;
u32 pinloc_offset = _searchHash(pinloc_hash) - 4;
u32 pinloc_maxlength = ((getSaveSize() - pinloc_offset) / 24);
for ( u32 i = 0; i < pinloc_maxlength; i++) {
u32 pinloc_base = pinloc_offset + (24*i);
u32 pinloc_header = readU32FromAddr(pinloc_base);
float pinloc_value_x = readF32FromAddr(pinloc_base + 4);
float pinloc_value_y = readF32FromAddr(pinloc_base + 12);
float pinloc_value_z = readF32FromAddr(pinloc_base + 20);
if (pinloc_header != pinloc_hash) { break; }
if (!iterFunc(pinloc_base+4, pinloc_value_x, pinloc_value_y, pinloc_value_z, location)) {
break;
}
}
}
void sortKoroksByDistance()
{
/*Point korokLocations[900];
for (int i = 0 ;i < 900; i++) {
korokLocations[i] = KOROKS[i];
}*/
qsort(KOROKS, 900, sizeof(Point), compDistance);
u32 added_pins = 0;
u32 max_pins_to_add = 100 - map_pin_count;
for (int i = 0; i < 900 && added_pins < max_pins_to_add; i++) {
if (isKorokCompletedOrMarked(KOROKS[i])) { continue; }
if (!addPinToMap(MAP_PIN_LEAF, KOROKS[i])) { break; }
added_pins++;
/*printMessage("%d (0x%x): %f, %f ,%f (dist: %f)\n", added_pins, korokLocations[i].hash,
korokLocations[i].x, korokLocations[i].y, korokLocations[i].z,
sqrt(pow(korokLocations[i].x-PlayerLocation.x,2)+pow(korokLocations[i].y-PlayerLocation.y,2)+pow(korokLocations[i].z-PlayerLocation.z,2)));*/
}
printMessage("%d pins added to map.", added_pins);
}
bool isKorokCompletedOrMarked(Point korok) {
//check if korok is marked on map already
if (isLocationInPinLoc(korok)) { return true; }
//check if korok is marked completed in game save
return (readU32FromHash(korok.hash) == 1);
}
void eraseCompletedKorokPins() {
}
bool addPinToMap(u32 pin_icon, Point location) {
iterateMapPinIcons(&_addMapPinIcon, pin_icon);
iterateMapPinLocs(&_addMapPinLoc, location);
if (mapPinIconCount != mapPinLocCount) {
printMessage("Mismatch: Added %d map icons, but %d map locations.", mapPinIconCount, mapPinLocCount);
return false;
}
map_pin_count = map_pin_count + mapPinIconCount;
return (mapPinIconCount == 1);
}
bool _addMapPinIcon(u32 offset, u32 value, u32 icon) {
if (value == MAP_PIN_EMPTY) {
writeU32ToAddr(offset, icon);
mapPinIconCount++;
return false;
}
return true;
}
bool _addMapPinLoc(u32 offset, float value_x, float value_y, float value_z, Point location) {
if (value_x == -100000 && value_y == 0 && value_z == 0) {
writeF32ToAddr(offset, location.x);
writeF32ToAddr(offset+8, location.y);
writeF32ToAddr(offset+16, location.z);
mapPinLocCount++;
return false;
}
return true;
}
bool isLocationInPinLoc(Point location) {
iterateMapPinLocs(&_isLocationInPinLoc, location);
return mapPinLocCount == 1;
}
bool _isLocationInPinLoc(u32 offset, float value_x, float value_y, float value_z, Point location) {
if (value_x == -100000 && value_y == 0 && value_z == 0) {
return false;
}
if (value_x == location.x && value_y == location.y && value_z == location.z) {
mapPinLocCount++;
return false;
}
return true;
}
void loadPlayerLocation() {
PlayerLocation = (Point){.hash = 0,
.x = readF32FromHash(HASHES.PLAYER_POSITION, 0),
.y = readF32FromHash(HASHES.PLAYER_POSITION, 8),
.z = readF32FromHash(HASHES.PLAYER_POSITION, 16)};
printMessage("player loc is x: %f, y: %f, z: %f.", PlayerLocation.x, PlayerLocation.y, PlayerLocation.z);
}
void countMapPins() {
map_pin_count = 0;
iterateMapPinIcons(&_loadMapPinIcons, 0);
iterateMapPinLocs(&_loadMapPinLocs, (Point){});
if (mapPinIconCount != mapPinLocCount) {
printMessage("Mismatch: Counted %d map icons, but have %d map locations.", mapPinIconCount, mapPinLocCount);
}
printMessage("number of map pins: %d.", map_pin_count);
}
bool _loadMapPinIcons(u32 offset, u32 value, u32 icon) {
if (value == MAP_PIN_EMPTY) {
return false;
}
if (value <= 0x23 && value >= 0x1b) {
mapPinIconCount++;
map_pin_count++;
} else {
printMessage("Invalid map pin icon 0x%x @ offset 0x%x", value, offset);
}
return true;
}
bool _loadMapPinLocs(u32 offset, float value_x, float value_y, float value_z, Point location) {
if (value_x == -100000 && value_y == 0 && value_z == 0) {
return false;
}
mapPinLocCount++;
return true;
}
void eraseMapPins() {
iterateMapPinIcons(&_eraseMapPinIcons, 0);
iterateMapPinLocs(&_eraseMapPinLocs, (Point){.hash=0});
map_pin_count = 0;
printMessage("%d pin icons erased, %d pin locations erased.", mapPinIconCount, mapPinLocCount);
}
bool _eraseMapPinIcons(u32 offset, u32 value, u32 icon) {
if (value != MAP_PIN_EMPTY) {
//if we have a hash set, we're looking for a specific icon to erase. if this isn't it, return true to iterator to continue
if (icon != 0 && icon != value) { return true; }
writeU32ToAddr(offset, MAP_PIN_EMPTY);
mapPinIconCount++;
}
return true;
}
bool _eraseMapPinLocs(u32 offset, float value_x, float value_y, float value_z, Point location) {
if (value_x != -100000 && value_y != 0 && value_z != 0) {
//if we have a hash set, we're looking for a specific location to erase. if this isn't it, return true to iterator to continue
if (location.hash != 0 && (location.x != value_x || location.y != value_y || location.z != value_z)) { return true; }
writeF32ToAddr(offset, -100000);
writeF32ToAddr(offset+8, 0);
writeF32ToAddr(offset+16, 0);
mapPinLocCount++;
}
return true;
}
void convertInvalidMapPinIcons() {
iterateMapPinIcons(&_convertInvalidMapPinIcons, 0x1b);
map_pin_count = map_pin_count + mapPinIconCount;
printMessage("%d invalid map pin icons converted.", mapPinIconCount);
countMapPins();
}
bool _convertInvalidMapPinIcons(u32 offset, u32 value, u32 icon) {
if (value == MAP_PIN_EMPTY) {
return false;
}
if (value > 0x23 || value < 0x1b) {
writeU32ToAddr(offset, icon);
mapPinIconCount++;
}
return true;
}

48
source/map.h Normal file
View file

@ -0,0 +1,48 @@
#ifndef MAP_H
#define MAP_H
#include <stdlib.h>
#include <switch.h>
#define MAP_PIN_SWORD 0x1B
#define MAP_PIN_BOW 0x1C
#define MAP_PIN_SHIELD 0x1D
#define MAP_PIN_POT 0x1E
#define MAP_PIN_STAR 0x1F
#define MAP_PIN_CHEST 0x20
#define MAP_PIN_SKULL 0x21
#define MAP_PIN_LEAF 0x22
#define MAP_PIN_TOWER 0x23
#define MAP_PIN_EMPTY 0xFFFFFFFF
typedef struct {
u32 hash;
float x;
float y;
float z;
} Point;
void sortKoroksByDistance();
void loadPlayerLocation();
void eraseCompletedKorokPins();
int compDistance (const void* elem1, const void* elem2);
typedef bool (*func_t_0)(u32 offset, u32 value, u32 icon);
typedef bool (*func_t_1)(u32 offset, float value_x, float value_y, float value_z, Point location);
bool _loadMapPinIcons(u32 offset, u32 value, u32 icon);
bool _eraseMapPinIcons(u32 offset, u32 value, u32 icon);
bool _eraseMapPinLocs(u32 offset, float value_x, float value_y, float value_z, Point location);
bool _convertInvalidMapPinIcons(u32 offset, u32 value, u32 icon);
bool isKorokCompletedOrMarked(Point korok);
void addMapPin(u32 icon, Point location);
void eraseMapPins();
void convertInvalidMapPinIcons();
void countMapPins();
bool addPinToMap(u32 pin_icon, Point location);
bool _addMapPinLoc(u32 offset, float value_x, float value_y, float value_z, Point location);
bool _addMapPinIcon(u32 offset, u32 value, u32 icon);
bool isLocationInPinLoc(Point location);
bool _isLocationInPinLoc(u32 offset, float value_x, float value_y, float value_z, Point location);
bool _loadMapPinLocs(u32 offset, float value_x, float value_y, float value_z, Point location);
void iterateMapPinIcons(func_t_0 iterFunc, u32 icon);
void iterateMapPinLocs(func_t_1 iterFunc, Point location);
#endif

View file

@ -1,28 +0,0 @@
#include <stdio.h>
#include <math.h>
#include <switch.h>
#include "map_basic.h"
static Point player_location = {0};
void loadPlayerLocation() {
printf("Loading player location...\n");
// TODO: Read player position from save data
player_location.x = 0.0f;
player_location.y = 0.0f;
player_location.z = 0.0f;
printf("Player at: (%.1f, %.1f, %.1f)\n",
player_location.x, player_location.y, player_location.z);
}
void addMapPin(u32 icon, Point location) {
printf("Adding map pin at (%.1f, %.1f, %.1f)\n",
location.x, location.y, location.z);
// TODO: Implement map pin addition to save data
}
void countMapPins() {
printf("Counting map pins...\n");
// TODO: Count existing pins in save data
printf("Found 0 map pins\n");
}

View file

@ -1,22 +0,0 @@
#ifndef MAP_H
#define MAP_H
#include <stdlib.h>
#include <switch.h>
#define MAP_PIN_STAR 0x1F
#define MAP_PIN_LEAF 0x22
#define MAP_PIN_EMPTY 0xFFFFFFFF
typedef struct {
u32 hash;
float x;
float y;
float z;
} Point;
void loadPlayerLocation();
void addMapPin(u32 icon, Point location);
void countMapPins();
#endif

136
source/save.c Normal file
View file

@ -0,0 +1,136 @@
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <math.h>
#include <switch.h>
#include "save.h"
#include "ui.h"
#include "map.h"
gameDataSav GAMEDATASAV;
const u32 KOROK_COUNTER_HASH = 0x8a94e07a;
void openSave() {
GAMEDATASAV.saveFile = NULL;
FILE *fp = fopen("save:/5/game_data.sav", "rb"); //TODO: Dont hardcode save slot
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) { /* Error */ }
/* Allocate our buffer to that size. */
GAMEDATASAV.saveFile = malloc(sizeof(char) * (bufsize));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
GAMEDATASAV.length = fread(GAMEDATASAV.saveFile, sizeof(char), bufsize, fp);
if (ferror( fp ) != 0) {
printMessage("Error reading file.");
} else {
printMessage("Read %.2f kbytes successfully.", GAMEDATASAV.length/1024.0);
}
}
fclose(fp);
} else {
printMessage("Error opening file.");
}
}
void processSave() {
countMapPins();
printMessage("number of korok seeds: %d.", readU32FromHash(KOROK_COUNTER_HASH));
loadPlayerLocation();
}
u32 getSaveSize() {
return GAMEDATASAV.length;
}
void writeSave() {
FILE *fp = fopen("save:/5/game_data.sav", "wb"); //TODO: dont hardcode save slot
if (fp != NULL) {
size_t bytes_writen = fwrite(GAMEDATASAV.saveFile, sizeof(char), GAMEDATASAV.length, fp);
if (ferror( fp ) != 0) {
printMessage("Error writing file.");
} else {
printMessage("Wrote %f.2 kbytes successfully.", bytes_writen/1024.0);
}
fclose(fp);
} else {
printMessage("Error opening file for writing.");
}
}
u32 _searchHash(u32 hash) {
for(u32 i=0x0c; i<GAMEDATASAV.length; i+=8) {
u32 val = GAMEDATASAV.saveFile[i] | ( (u32)GAMEDATASAV.saveFile[i+1] << 8 ) | ( (u32)GAMEDATASAV.saveFile[i+2] << 16 ) | ( (u32)GAMEDATASAV.saveFile[i+3] << 24 );
if(hash == val) {
return i;
}
}
return 0;
}
u32 readU32FromHash(u32 hash) {
return readU32FromAddr(_searchHash(hash));
}
u32 readU32FromAddr(u32 addr) {
if(addr != 0) {
u32 val = ((u32)GAMEDATASAV.saveFile[addr+4]) | ( (u32)GAMEDATASAV.saveFile[addr+5] << 8 ) | ( (u32)GAMEDATASAV.saveFile[addr+6] << 16 ) | ( (u32)GAMEDATASAV.saveFile[addr+7] << 24 );
return val;
}
return 0;
}
float readF32FromHash(u32 hash, u32 offset) {
return readF32FromAddr(_searchHash(hash) + offset);
}
float readF32FromAddr(u32 addr) {
if(addr != 0) {
Float val;
val.m_bytes[0] = GAMEDATASAV.saveFile[addr+4];
val.m_bytes[1] = GAMEDATASAV.saveFile[addr+5];
val.m_bytes[2] = GAMEDATASAV.saveFile[addr+6];
val.m_bytes[3] = GAMEDATASAV.saveFile[addr+7];
return val.m_float;
}
return 0;
}
void writeF32ToAddr(u32 addr, float value) {
if(addr != 0) {
Float val;
val.m_float = value;
GAMEDATASAV.saveFile[addr+4] = val.m_bytes[0];
GAMEDATASAV.saveFile[addr+5] = val.m_bytes[1];
GAMEDATASAV.saveFile[addr+6] = val.m_bytes[2];
GAMEDATASAV.saveFile[addr+7] = val.m_bytes[3];
//printMessage("wrote f32 %f to 0x%x, read check: %f\n", value, addr, readF32FromAddr(addr));
}
}
void writeU32ToAddr(u32 addr, u32 value) {
if (addr != 0) {
GAMEDATASAV.saveFile[addr+4] = value & 0x00000ff;
GAMEDATASAV.saveFile[addr+5] = (value & 0x0000ff00) >> 8;
GAMEDATASAV.saveFile[addr+6] = (value & 0x00ff0000) >> 16;
GAMEDATASAV.saveFile[addr+7] = (value & 0xff000000) >> 24;
//printMessage("wrote u32 0x%x to 0x%x, read check: 0x%x", value, addr, readU32FromAddr(addr));
}
}
void closeAndCommitSave() {
writeSave();
if (R_FAILED(fsdevCommitDevice("save"))) {
printMessage("Committing failed.");
}
free(GAMEDATASAV.saveFile);
}

37
source/save.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef SAVE_H
#define SAVE_H
#include <stdlib.h>
typedef struct
{
size_t length;
char * saveFile;
} gameDataSav;
typedef struct {
u32 PLAYER_POSITION;
u32 MAP;
} Hashes;
typedef union Float {
float m_float;
u8 m_bytes[sizeof(float)];
} Float;
u32 _searchHash(u32 hash);
u32 readU32FromHash(u32 hash);
u32 readU32FromAddr(u32 addr);
float readF32FromAddr(u32 addr);
void writeF32ToAddr(u32 addr, float value);
void writeU32ToAddr(u32 addr, u32 value);
float readF32FromHash(u32 hash, u32 offset);
void processSave();
void openSave();
void writeSave();
void closeAndCommitSave();
u32 getSaveSize();
#endif

View file

@ -1,43 +0,0 @@
#include <string.h>
#include <stdio.h>
#include <switch.h>
#include "save_basic.h"
static gameDataSav save_data = {0};
void openSave() {
Result rc = 0;
AccountUid uid = {0};
u64 application_id = 0x01007ef00011e000; // BOTW Application ID
printf("Opening BOTW save data...\n");
// Get user account
rc = accountInitialize(AccountServiceType_Application);
if (R_FAILED(rc)) {
printf("accountInitialize() failed: 0x%x\n", rc);
return;
}
rc = accountGetPreselectedUser(&uid);
accountExit();
if (R_FAILED(rc)) {
printf("accountGetPreselectedUser() failed: 0x%x\n", rc);
return;
}
// Mount save data
rc = fsdevMountSaveData("save", application_id, uid);
if (R_FAILED(rc)) {
printf("fsdevMountSaveData() failed: 0x%x\n", rc);
return;
}
printf("Save data mounted successfully!\n");
}
void processSave() {
printf("Processing save data...\n");
// TODO: Implement actual save processing
}

View file

@ -1,15 +0,0 @@
#ifndef SAVE_H
#define SAVE_H
#include <stdlib.h>
typedef struct
{
size_t length;
char * saveFile;
} gameDataSav;
void processSave();
void openSave();
#endif

272
source/ui.c Normal file
View file

@ -0,0 +1,272 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <switch.h>
#include "ui.h"
#include "save.h"
#include "map.h"
#define FB_MAX_COLS 80
#define FB_MAX_LINES 45
#define MSG_MAX_LINE_LEN 45
#define MSG_START_COL (FB_MAX_COLS-MSG_MAX_LINE_LEN)
#define MSG_MAX_LEN (MSG_MAX_LINE_LEN*FB_MAX_LINES)
#define FB_MIDDLE_LINE (FB_MAX_LINES/2)
// this converts to string
#define STR_(X) #X
// this makes sure the argument is expanded before converting to string
#define STR(X) STR_(X)
MenuItem main_menu_items[6] = {
{"Add Missing Koroks to Map", &sortKoroksByDistance},
{"Erase Completed Korok Pins", &eraseCompletedKorokPins},
{"Erase All Map Pins", &eraseMapPins},
{"Convert Invalid Map Pins", &convertInvalidMapPinIcons},
{"Save and Exit", &saveAndExitApp},
{"Exit w/o Saving", &exitApp}
};
Menu main_menu = {
.HeaderStr = "BOTW KOROK COMPLETER",
.ItemCount = 6,
.Menu_Items = main_menu_items
};
MenuItem confirm_menu_items[2] = {
{"No, cancel!", NULL},
{"Yes, do it!", NULL}
};
Menu confirm_menu = {
.HeaderStr = "ARE YOU SURE??",
.ItemCount = 2,
.Menu_Items = confirm_menu_items
};
Menu *current_menu;
Menu *previous_menu;
char MSG_BUFFER[FB_MAX_LINES][MSG_MAX_LINE_LEN+1];
u32 msg_buf_write_line = 0;
u32 msg_buf_line_count = 0;
bool exit_state = false;
bool confirmed = false;
void _clearScreen() {
printf(CONSOLE_ESC(2J)); //clear screen and reset home cursor
}
void loadMenu(Menu* menu) {
current_menu = menu;
current_menu->StartLine = FB_MIDDLE_LINE - (current_menu->ItemCount / 2);
current_menu->SelectedIndex = 0;
_clearScreen();
_drawMenu();
_drawMessagePane();
}
void _drawMenu() {
//new code
printfAtCursor(2, current_menu->StartLine-2, current_menu->HeaderStr);
printfAtCursor(2, current_menu->StartLine, ">");
for (int i = 0; i < current_menu->ItemCount; i++) {
printfAtCursor(4, current_menu->StartLine+i, current_menu->Menu_Items[i].ItemStr);
}
//end new code
/*/old code
printfAtCursor(2, MENU_START_COL-2, "BOTW KOROK COMPLETER");
printfAtCursor(2, MENU_START_COL, "> Add Missing Koroks to Map");
printfAtCursor(2, MENU_START_COL+1, " Erase all map pins");
printfAtCursor(2, MENU_START_COL+2, " Convert invalid map pins");
printfAtCursor(2, MENU_START_COL+3, " Save and Exit");
printfAtCursor(2, MENU_START_COL+4, " Exit w/o Saving");
//end old code*/
//print vertical line between menu and messages panel
for (int i = 1; i <= FB_MAX_LINES; i++) {
printfAtCursor(FB_MAX_COLS - MSG_MAX_LINE_LEN - 2, i, "|");
}
}
void initUI() {
loadMenu(&main_menu);
}
void exitApp() {
exit_state = true;
}
void saveAndExitApp() {
closeAndCommitSave();
exitApp();
}
void handleMenuButtonPress(u64 button) {
//clear menu cursor
printfAtCursor(2, current_menu->StartLine+current_menu->SelectedIndex, " ");
switch (button) {
case HidNpadButton_Down:
if (current_menu->SelectedIndex == current_menu->ItemCount - 1) {
current_menu->SelectedIndex = 0;
} else {
current_menu->SelectedIndex++;
}
break;
case HidNpadButton_Up:
if (current_menu->SelectedIndex == 0) {
current_menu->SelectedIndex = current_menu->ItemCount-1;
} else {
current_menu->SelectedIndex--;
}
break;
case HidNpadButton_A: //run menu function, using menu item index: position - start_line
current_menu->Menu_Items[current_menu->SelectedIndex].ItemFunc();
break;
default:
break;
}
//print menu cursor
printfAtCursor(2, current_menu->StartLine+current_menu->SelectedIndex, ">");
}
bool handleButtonPress(u64 button) {
if (button & HidNpadButton_Plus) { return true; } // exit if + button pressed
handleMenuButtonPress(button);
return exit_state;
}
/*u32 handleMenuButtonPress(u64 button) {
switch (button) {
case HidNpadButton_Down:
printf(CONSOLE_ESC(%d;2H) " ", menu_pos);
if (menu_pos == MENU_END_LINE) { menu_pos = MENU_START_LINE; }
else { menu_pos++; }
printf(CONSOLE_ESC(%d;2H) ">", menu_pos);
break;
case HidNpadButton_Up:
printf(CONSOLE_ESC(%d;2H) " ", menu_pos);
if (menu_pos == MENU_START_LINE) { menu_pos = MENU_END_LINE; }
else { menu_pos--; }
printf(CONSOLE_ESC(%d;2H) ">", menu_pos);
break;
case HidNpadButton_A:
return menu_pos;
break;
default:
break;
}
return (enum menu_items)none;
}
bool handleButtonPress(u64 button) {
switch(handleMenuButtonPress(button)) {
case add_missing_koroks:
sortKoroksByDistance();
break;
case erase_all_map_pins:
eraseMapPins();
break;
case convert_invalid_map_pins:
convertInvalidMapPinIcons();
break;
case save_file:
writeSave();
closeAndCommitSave();
return true;
break;
case exit_app:
return true;
break;
default:
break;
}
return false;
}*/
void _confirm_no() {
loadMenu(previous_menu);
}
void confirmThenRunElse(func_t yes_func, func_t no_func) {
//save current menu
previous_menu = current_menu;
confirm_menu.Menu_Items[1].ItemFunc = yes_func;
confirm_menu.Menu_Items[0].ItemFunc = no_func;
loadMenu(&confirm_menu);
}
void confirmThenRun(func_t yes_func) {
confirmThenRunElse(yes_func, &_confirm_no);
}
void printfAtCursor(u32 x_pos, u32 y_pos, const char* format, ...) {
va_list args;
va_start(args, format);
_setCursorPos(x_pos, y_pos);
vprintf(format, args);
va_end(args);
}
void _setCursorPos(u32 x_pos, u32 y_pos) {
if (x_pos >= 1 && x_pos <= FB_MAX_COLS && y_pos >= 1 && y_pos <= FB_MAX_LINES) {
printf(CONSOLE_ESC(%d;%dH) , y_pos, x_pos);
}
}
void printMessage(const char* format, ...) {
//get variable args
va_list args;
va_start(args, format);
//process the format string
char message[MSG_MAX_LEN-FB_MAX_LINES];
vsnprintf(message, MSG_MAX_LEN-FB_MAX_LINES, format, args);
va_end(args);
//find out how many lines we are about to add to the buffer/print
size_t length = strlen(message);
u32 num_of_lines = length / MSG_MAX_LINE_LEN;
if (length%MSG_MAX_LINE_LEN != 0) {num_of_lines++;}
char *line;
for (int i = 0; i < num_of_lines; i++) {
//extract the next set of characters and store in line
line = strndup(message + (MSG_MAX_LINE_LEN*i), MSG_MAX_LINE_LEN);
//clear previous line
memset(MSG_BUFFER[msg_buf_write_line], 0, MSG_MAX_LINE_LEN+1);
//copy line to MSG_BUFFER at write_ptr
strncpy(MSG_BUFFER[msg_buf_write_line], line, MSG_MAX_LINE_LEN);
MSG_BUFFER[msg_buf_write_line][MSG_MAX_LINE_LEN] = '\0';
msg_buf_write_line++;
//free original line after we've copied it
free(line);
//if count is below max lines, then increase count
if (msg_buf_line_count < FB_MAX_LINES) { msg_buf_line_count++; }
// if the next write line is past the last index, set the next index to 0.
if (msg_buf_write_line == FB_MAX_LINES) { msg_buf_write_line = 0; }
_drawMessagePane();
}
}
void _drawMessagePane() {
//print all lines in buffer, from top to bottom, oldest to newest
if (msg_buf_line_count > 0) {
u32 start_line = 0;
if (msg_buf_line_count == FB_MAX_LINES) {
start_line = msg_buf_write_line;
}
for (int i = 0; i < msg_buf_line_count; i++) {
_setCursorPos(MSG_START_COL, i+1);
printf("%-" STR(MSG_MAX_LINE_LEN) "s", MSG_BUFFER[(start_line + i) % FB_MAX_LINES]);
}
}
}

44
source/ui.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef UI_H
#define UI_H
typedef void (*func_t)();
typedef struct {
char ItemStr[30];
func_t ItemFunc;
} MenuItem;
typedef struct {
char HeaderStr[30];
u32 ItemCount;
u32 StartLine;
u32 SelectedIndex;
MenuItem *Menu_Items;
} Menu;
void _clearScreen();
void _drawMenu();
void loadMenu(Menu* menu);
void _confirm_no();
void confirmThenRunElse(func_t yes_func, func_t no_func);
void confirmThenRun(func_t yes_func);
void _setCursorPos(u32 x_pos, u32 y_pos);
void handleMenuButtonPress(u64 button);
bool handleButtonPress(u64 button);
void printMessage(const char* message, ...);
void printfAtCursor(u32 x_pos, u32 y_pos, const char* format, ...) ;
void _drawMessagePane();
void initUI();
void exitApp();
void saveAndExitApp();
/*#define MENU_START_LINEE 21
#define MENU_END_LINEE 25
enum menu_items {
none = MENU_START_LINEE-1,
add_missing_koroks,
erase_all_map_pins,
convert_invalid_map_pins,
save_file,
exit_app
};*/
#endif

View file

@ -1,27 +0,0 @@
#include <stdio.h>
#include <stdarg.h>
#include <switch.h>
#include "ui_basic.h"
void initUI() {
printf("\x1b[2J"); // Clear screen
printf("\x1b[1;1H"); // Move cursor to top-left
printf("═══════════════════════════════════════\n");
printf(" BOTW Completer v0.3\n");
printf("═══════════════════════════════════════\n");
printf("\n");
}
void printMessage(const char* message, ...) {
va_list args;
va_start(args, message);
vprintf(message, args);
va_end(args);
}
bool handleButtonPress(u64 button) {
if (button & HidNpadButton_Plus) {
return true; // Exit requested
}
return false; // Continue running
}

View file

@ -1,23 +0,0 @@
#ifndef UI_H
#define UI_H
typedef void (*func_t)();
typedef struct {
char ItemStr[30];
func_t ItemFunc;
} MenuItem;
typedef struct {
char HeaderStr[30];
u32 ItemCount;
u32 StartLine;
u32 SelectedIndex;
MenuItem *Menu_Items;
} Menu;
void initUI();
void printMessage(const char* message, ...);
bool handleButtonPress(u64 button);
#endif