├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── build ├── .clang-format ├── CMakeLists.txt ├── build.lua ├── devkitarm.cmake ├── dirlocals.in ├── files.cpp.in ├── images.cpp.in ├── main.lua ├── manifest.lua ├── music_as_colorful_as_ever.raw ├── overlay.bmp ├── prep_image.py ├── scripts.cpp.in ├── set-desktop-toolchain.sh ├── set-gameboy-advance-toolchain.sh ├── spritesheet.bmp ├── test.bmp ├── tile0.bmp └── tmp │ ├── blaster_info_flattened.png │ ├── charset.png │ ├── charset_en_spn_fr.png │ ├── launch_flattened.png │ ├── old_poster_flattened.png │ ├── overlay.png │ ├── overlay_cutscene.png │ ├── overlay_dialog.png │ ├── overlay_journal.png │ ├── overlay_network_flattened.png │ ├── postal_advert_flattened.png │ ├── repl.png │ ├── seed_packet_flattened.png │ ├── spritesheet.png │ ├── spritesheet2.png │ ├── spritesheet3.png │ ├── spritesheet4.png │ ├── spritesheet_boss0.png │ ├── spritesheet_boss1.png │ ├── spritesheet_boss2.png │ ├── spritesheet_boss2_done.png │ ├── spritesheet_boss2_final.png │ ├── spritesheet_boss2_mutate.png │ ├── spritesheet_intro_clouds.png │ ├── spritesheet_intro_cutscene.png │ ├── spritesheet_launch_anim.png │ ├── tilesheet.png │ ├── tilesheet2.png │ ├── tilesheet2_top.png │ ├── tilesheet3.png │ ├── tilesheet3_top.png │ ├── tilesheet4.png │ ├── tilesheet4_top.png │ ├── tilesheet_intro_cutscene_flattened.png │ ├── tilesheet_top.png │ ├── title_1_flattened.png │ └── title_2_flattened.png ├── external ├── lua │ ├── lapi.c │ ├── lapi.h │ ├── lauxlib.c │ ├── lauxlib.h │ ├── lbaselib.c │ ├── lcode.c │ ├── lcode.h │ ├── lcorolib.c │ ├── lctype.c │ ├── lctype.h │ ├── ldblib.c │ ├── ldebug.c │ ├── ldebug.h │ ├── ldo.c │ ├── ldo.h │ ├── ldump.c │ ├── lfunc.c │ ├── lfunc.h │ ├── lgc.c │ ├── lgc.h │ ├── linit.c │ ├── liolib.c │ ├── ljumptab.h │ ├── llex.c │ ├── llex.h │ ├── llimits.h │ ├── lmathlib.c │ ├── lmem.c │ ├── lmem.h │ ├── loadlib.c │ ├── lobject.c │ ├── lobject.h │ ├── lopcodes.c │ ├── lopcodes.h │ ├── lopnames.h │ ├── loslib.c │ ├── lparser.c │ ├── lparser.h │ ├── lprefix.h │ ├── lstate.c │ ├── lstate.h │ ├── lstring.c │ ├── lstring.h │ ├── lstrlib.c │ ├── ltable.c │ ├── ltable.h │ ├── ltablib.c │ ├── ltm.c │ ├── ltm.h │ ├── lua.h │ ├── lua.hpp │ ├── luaconf.h │ ├── lualib.h │ ├── lundump.c │ ├── lundump.h │ ├── lutf8lib.c │ ├── lvm.c │ ├── lvm.h │ ├── lzio.c │ └── lzio.h ├── popl │ └── popl.hpp └── umm_malloc │ └── src │ ├── dbglog │ └── dbglog.h │ ├── umm_info.c │ ├── umm_integrity.c │ ├── umm_malloc.c │ ├── umm_malloc.h │ ├── umm_malloc_cfg.h │ └── umm_poison.c ├── images ├── charset0.png ├── charset1.png ├── overlay.png ├── overlay_text_key.png └── transparency_reference.png ├── index_tile.png ├── source ├── BPCoreEngine.cpp ├── BPCoreEngine.hpp ├── bitvector.hpp ├── bpcore.h ├── bulkAllocator.hpp ├── camera.cpp ├── camera.hpp ├── collision.cpp ├── collision.hpp ├── config.cpp ├── data │ ├── charset0.h │ ├── charset0.s │ ├── charset1.h │ ├── charset1.s │ ├── overlay.h │ ├── overlay.s │ ├── overlay_text_key.h │ ├── overlay_text_key.s │ ├── sound_msg.hpp │ └── sound_msg.s ├── dateTime.hpp ├── entity │ ├── details │ │ ├── item.cpp │ │ └── item.hpp │ ├── entity.cpp │ └── entity.hpp ├── filesystem.cpp ├── filesystem.hpp ├── function.hpp ├── game.cpp ├── game.hpp ├── game_script_defs.cpp ├── graphics │ ├── animation.hpp │ ├── color.hpp │ ├── contrast.hpp │ ├── overlay.cpp │ ├── overlay.h │ ├── overlay.hpp │ ├── sprite.cpp │ ├── sprite.hpp │ ├── view.cpp │ └── view.hpp ├── inventory.cpp ├── inventory.hpp ├── list.hpp ├── localeString.hpp ├── localization.cpp ├── localization.hpp ├── memory │ ├── buffer.hpp │ ├── memory.hpp │ ├── pool.hpp │ └── rc.hpp ├── network_event.cpp ├── network_event.hpp ├── number │ ├── endian.hpp │ ├── int.h │ ├── numeric.cpp │ ├── numeric.hpp │ ├── random.cpp │ └── random.hpp ├── path.cpp ├── path.hpp ├── persistentData.cpp ├── persistentData.hpp ├── platform │ ├── desktop │ │ ├── desktop_platform.cpp │ │ └── resource_path.cpp │ ├── gba │ │ ├── bios_math.s │ │ ├── files.cpp │ │ ├── gba.h │ │ ├── gba_arm_routines.cpp │ │ ├── gba_color.hpp │ │ ├── gba_platform.cpp │ │ ├── gba_platform_soundcontext.hpp │ │ ├── images.cpp │ │ ├── interrupt.c │ │ ├── interrupt_dispatch.s │ │ ├── memcpy.s │ │ ├── reset.s │ │ └── scripts.cpp │ ├── key.hpp │ ├── platform.hpp │ └── switch │ │ └── switch_platform.cpp ├── powerup.cpp ├── powerup.hpp ├── scriptApi.hpp ├── settings.hpp ├── severity.hpp ├── sound.hpp ├── speedrunClock.hpp ├── start.cpp ├── state.hpp ├── string.cpp ├── string.hpp ├── tileDataStream.hpp ├── tileMap.cpp ├── tileMap.hpp ├── timeTracker.hpp ├── transformGroup.hpp ├── unicode.hpp ├── util.hpp ├── version.hpp └── wallCollision.hpp └── useful_documents ├── akkit_gba_specifications.html └── tonc.pdf /.gitattributes: -------------------------------------------------------------------------------- 1 | # prevent github from displaying the repository as ASM or HTML due to documentation and data files 2 | source/data/* linguist-vendored 3 | useful_documents/* linguist-documentation 4 | external/* linguist-vendored 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#*\# 3 | *.elf* 4 | *.gba 5 | CMakeFiles/ 6 | CMakeCache.txt 7 | cmake_install.cmake 8 | Makefile 9 | .DS_Store 10 | .dir-locals.el 11 | *.a 12 | BlindJump 13 | logfile.txt 14 | save.dat 15 | *.aseprite 16 | *.ase 17 | *.aup 18 | a.out 19 | *.pdb 20 | *.ilk 21 | *.user 22 | Debug 23 | Release 24 | *.dll 25 | *.lib 26 | *.exp 27 | .vs 28 | *.vcxproj 29 | *.vcxproj.filters 30 | *.sln 31 | *.sav -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /build/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: false 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: false 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: None 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: true 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: None 36 | BreakBeforeBraces: Custom 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: false 39 | BreakAfterJavaFieldAnnotations: false 40 | BreakStringLiterals: true 41 | ColumnLimit: 80 42 | CommentPragmas: '^ IWYU pragma:' 43 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 44 | ConstructorInitializerIndentWidth: 4 45 | ContinuationIndentWidth: 4 46 | Cpp11BracedListStyle: true 47 | DerivePointerAlignment: false 48 | DisableFormat: false 49 | ExperimentalAutoDetectBinPacking: false 50 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 51 | IncludeCategories: 52 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 53 | Priority: 2 54 | - Regex: '^(<|"(gtest|isl|json)/)' 55 | Priority: 3 56 | - Regex: '.*' 57 | Priority: 1 58 | IncludeIsMainRegex: '$' 59 | IndentCaseLabels: false 60 | IndentWidth: 4 61 | IndentWrappedFunctionNames: false 62 | JavaScriptQuotes: Leave 63 | JavaScriptWrapImports: true 64 | KeepEmptyLinesAtTheStartOfBlocks: true 65 | MacroBlockBegin: '' 66 | MacroBlockEnd: '' 67 | MaxEmptyLinesToKeep: 2 68 | NamespaceIndentation: None 69 | ObjCBlockIndentWidth: 2 70 | ObjCSpaceAfterProperty: false 71 | ObjCSpaceBeforeProtocolList: true 72 | PenaltyBreakBeforeFirstCallParameter: 19 73 | PenaltyBreakComment: 300 74 | PenaltyBreakFirstLessLess: 120 75 | PenaltyBreakString: 1000 76 | PenaltyExcessCharacter: 1000000 77 | PenaltyReturnTypeOnItsOwnLine: 60 78 | PointerAlignment: Left 79 | ReflowComments: false 80 | SortIncludes: true 81 | SpaceAfterCStyleCast: false 82 | SpaceBeforeAssignmentOperators: true 83 | SpaceBeforeParens: ControlStatements 84 | SpaceInEmptyParentheses: false 85 | SpacesBeforeTrailingComments: 1 86 | SpacesInAngles: false 87 | SpacesInContainerLiterals: true 88 | SpacesInCStyleCastParentheses: false 89 | SpacesInParentheses: false 90 | SpacesInSquareBrackets: false 91 | Standard: Cpp11 92 | TabWidth: 4 93 | UseTab: Never 94 | ... 95 | -------------------------------------------------------------------------------- /build/devkitarm.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | set(DEVKITARM $ENV{DEVKITARM}) 4 | set(DEVKITPRO $ENV{DEVKITPRO}) 5 | 6 | if(NOT DEVKITARM) 7 | message(FATAL_ERROR "Please set DEVKITARM in your environment") 8 | endif(NOT DEVKITARM) 9 | 10 | 11 | set(CMAKE_AR ${DEVKITARM}/bin/arm-none-eabi-ar) 12 | set(CMAKE_C_COMPILER ${DEVKITARM}/bin/arm-none-eabi-gcc) 13 | set(CMAKE_CXX_COMPILER ${DEVKITARM}/bin/arm-none-eabi-g++) 14 | 15 | set(PKG_CONFIG_EXECUTABLE "arm-none-eabi-pkg-config") 16 | 17 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 18 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 19 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 20 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 21 | 22 | SET(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available" ) 23 | -------------------------------------------------------------------------------- /build/dirlocals.in: -------------------------------------------------------------------------------- 1 | ((c++-mode . ((flycheck-@EMACS_FLYCHECK_FRONTEND@-include-path . ("@SOURCE_DIR@/" "@ROOT_DIR@/external/"))))) -------------------------------------------------------------------------------- /build/files.cpp.in: -------------------------------------------------------------------------------- 1 | 2 | @FILE_DECLS@ 3 | 4 | static const struct { 5 | const char* root_; 6 | const char* name_; 7 | const unsigned char* data_; 8 | } files[] = { 9 | @FILES@ 10 | }; 11 | -------------------------------------------------------------------------------- /build/images.cpp.in: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | 3 | // This file was generated by the project's image build pipeline in 4 | // CMakeLists.txt. I have no idea why cmake outputs semicolons between the 5 | // entries in the IMAGE_INCLUDES list variable... maybe some special formatting 6 | // character that I don't know about... or maybe cmake uses ; internally as a 7 | // delimiter... but for now, the cmake script outputs the semicolons on a new 8 | // line, commented out, to suppress the resulting errors. 9 | // 10 | // If you try to manually edit source/platform/gba/images.cpp, the file may be 11 | // overwritten if you have the GBA_AUTOBUILD_IMG option in the cmake environment 12 | // turned on. 13 | 14 | 15 | @IMAGE_INCLUDES@ 16 | 17 | struct TextureData { 18 | const char* name_; 19 | const unsigned int* tile_data_; 20 | const unsigned short* palette_data_; 21 | u32 tile_data_length_; 22 | u32 palette_data_length_; 23 | }; 24 | 25 | 26 | #define STR(X) #X 27 | #define TEXTURE_INFO(NAME) \ 28 | { \ 29 | STR(NAME), NAME##Tiles, NAME##Pal, NAME##TilesLen, NAME##PalLen \ 30 | } 31 | 32 | 33 | static const TextureData sprite_textures[] = { 34 | @IMAGE_SPR_STUBS@ 35 | }; 36 | 37 | 38 | static const TextureData tile_textures[] = { 39 | @IMAGE_TILE_STUBS@ 40 | }; 41 | 42 | 43 | static const TextureData overlay_textures[] = { 44 | @IMAGE_OVERLAY_STUBS@ 45 | }; 46 | 47 | // clang-format on 48 | -------------------------------------------------------------------------------- /build/main.lua: -------------------------------------------------------------------------------- 1 | 2 | fade(1) 3 | 4 | txtr(0, "overlay.bmp") 5 | 6 | tile(0, 9, 9, 3) 7 | tile(0, 8, 9, 27) 8 | tile(0, 7, 9, 16) 9 | tile(0, 6, 9, tile(0, 9, 9)) 10 | 11 | print(_BP_VERSION, 3, 3) 12 | 13 | txtr(2, "tile0.bmp") 14 | 15 | player = ent() 16 | entspr(player, 0) 17 | 18 | 19 | enemy = ent() 20 | entspr(enemy, 255) 21 | entpos(enemy, 30, 30) 22 | entz(enemy, 20) 23 | 24 | 25 | 26 | for i = 15, 45 do 27 | for j = 15, 45 do 28 | tile(2, i, j, 1) 29 | end 30 | end 31 | 32 | 33 | fade(0) 34 | 35 | 36 | txtr(4, "spritesheet.bmp") 37 | 38 | 39 | music("music_as_colorful_as_ever.raw", 0) 40 | 41 | 42 | function main_loop(update, draw) 43 | while true do 44 | update(delta()) 45 | clear() 46 | draw() 47 | display() 48 | end 49 | end 50 | 51 | 52 | local x = 0 53 | local y = 0 54 | 55 | local i = 0 56 | 57 | 58 | function update(dt) 59 | 60 | if btnp(0) then 61 | fade(0.5) 62 | i = (i + 1) % 250 63 | elseif btnnp(0) then 64 | fade(0) 65 | end 66 | 67 | if btn(5) then 68 | x = x + 2 69 | elseif btn(4) then 70 | x = x - 2 71 | end 72 | 73 | if btn(6) then 74 | y = y - 2 75 | elseif btn(7) then 76 | y = y + 2 77 | end 78 | 79 | entpos(player, x, y) 80 | entz(player, 30) 81 | 82 | if ecole(player, enemy) then 83 | print("collision", 10, 1) 84 | end 85 | 86 | 87 | camera(x, y) 88 | end 89 | 90 | 91 | function draw() 92 | end 93 | 94 | 95 | print(tostring(collectgarbage("count") * 1024), 3, 5) 96 | 97 | 98 | poke4(_IRAM, 42) 99 | 100 | print(tostring(peek4(_IRAM)), 3, 6) 101 | 102 | 103 | main_loop(update, draw) 104 | -------------------------------------------------------------------------------- /build/manifest.lua: -------------------------------------------------------------------------------- 1 | 2 | local app = { 3 | name = "TestApplication", 4 | 5 | tilesets = { 6 | "overlay.bmp", 7 | "tile0.bmp", 8 | "test.bmp", 9 | }, 10 | 11 | spritesheets = { 12 | "spritesheet.bmp", 13 | }, 14 | 15 | audio = { 16 | "music_as_colorful_as_ever.raw", 17 | }, 18 | 19 | scripts = { 20 | "main.lua", 21 | }, 22 | 23 | misc = { 24 | 25 | } 26 | } 27 | 28 | return app 29 | -------------------------------------------------------------------------------- /build/music_as_colorful_as_ever.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/music_as_colorful_as_ever.raw -------------------------------------------------------------------------------- /build/overlay.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/overlay.bmp -------------------------------------------------------------------------------- /build/prep_image.py: -------------------------------------------------------------------------------- 1 | 2 | # The Gameboy Advance console uses colors in a BGR format, but all my favorite 3 | # graphics tools use RGBA. 4 | 5 | from PIL import Image 6 | import os 7 | import sys 8 | import platform 9 | 10 | 11 | image_dir = None 12 | 13 | 14 | def get_concat_h(im1, im2): 15 | dst = Image.new('RGBA', (im1.width + im2.width, im1.height)) 16 | dst.paste(im1, (0, 0)) 17 | dst.paste(im2, (im1.width, 0)) 18 | return dst 19 | 20 | 21 | 22 | # At least one tile in the image needs to contain some transparency, for the 23 | # image to be displayed opaquely. So append this 8x8 image onto flattened 24 | # images, so that they will appear entirely opaque. 25 | transparency_key = None 26 | 27 | 28 | 29 | def flatten_image(file_name): 30 | """ 31 | Slice an image into 8-pixel tall strips, and join them end-to-end. Much 32 | easier than trying to meta-tile a 240x160 image! 33 | """ 34 | im = Image.open(image_dir + file_name) 35 | 36 | strips = [] 37 | 38 | w, h = im.size 39 | 40 | for i in range(0, int(h / 8)): 41 | strips.append(im.crop((0, int(i * 8), w, int(i * 8) + 8))) 42 | 43 | result = strips.pop(0) 44 | 45 | while strips: 46 | result = get_concat_h(result, strips.pop(0)) 47 | 48 | result = get_concat_h(transparency_key, result) 49 | 50 | result.save(image_dir + file_name.split('.')[0] + '_flattened.png') 51 | 52 | 53 | 54 | # for name in ['old_poster.png', 55 | # 'seed_packet.png']: 56 | # flatten_image(name) 57 | 58 | 59 | 60 | def rgb_to_bgr(file_name): 61 | """ 62 | Convert rgb image file to bgr 63 | """ 64 | im = Image.open(image_dir + file_name) 65 | 66 | os_name = platform.system() 67 | 68 | # For some reason, to be determined, images in linux do not need to be 69 | # bgr-swapped as newly-saved images do on my macbook. 70 | if os_name != 'Linux': 71 | r, g, b, a = im.split() 72 | im = Image.merge('RGBA', (b, g, r, a)) 73 | 74 | im.save('tmp/' + file_name) 75 | 76 | 77 | # for name in ['spritesheet.png', 78 | # 'spritesheet_boss0.png', 79 | # 'spritesheet_boss1.png', 80 | # 'spritesheet2.png', 81 | # 'spritesheet3.png', 82 | # 'tilesheet.png', 83 | # 'tilesheet2.png', 84 | # 'tilesheet3.png', 85 | # 'tilesheet_top.png', 86 | # 'tilesheet2_top.png', 87 | # 'tilesheet3_top.png', 88 | # 'overlay.png', 89 | # 'charset_en_spn_fr.png', 90 | # 'overlay_journal.png', 91 | # 'old_poster_flattened.png', 92 | # 'seed_packet_flattened.png']: 93 | # rgb_to_bgr(name) 94 | 95 | 96 | if __name__ == "__main__": 97 | if not os.path.exists('tmp'): 98 | os.makedirs('tmp') 99 | 100 | image_dir = sys.argv[1] + "/images/" 101 | 102 | transparency_key = Image.open(image_dir + 'transparency_reference.png') 103 | 104 | image = sys.argv[2] 105 | 106 | if sys.argv[3] == 'yes': 107 | flatten_image(image) 108 | rgb_to_bgr(image.split('.')[0] + "_flattened.png") 109 | else: 110 | rgb_to_bgr(image) 111 | -------------------------------------------------------------------------------- /build/scripts.cpp.in: -------------------------------------------------------------------------------- 1 | 2 | @SCRIPT_DECLS@ 3 | 4 | static const struct { 5 | const char* name_; 6 | const unsigned char* data_; 7 | } scripts[] = { 8 | @SCRIPTS@ 9 | }; 10 | -------------------------------------------------------------------------------- /build/set-desktop-toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm CMakeCache.txt 4 | rm -r CMakeFiles/ 5 | 6 | cmake . -DGAMEBOY_ADVANCE=OFF 7 | -------------------------------------------------------------------------------- /build/set-gameboy-advance-toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm CMakeCache.txt 4 | rm -r CMakeFiles/ 5 | 6 | cmake -DGBA_AUTOBUILD_IMG=ON -DGBA_AUTOBUILD_CONF=ON -DCMAKE_TOOLCHAIN_FILE=$(pwd)/devkitarm.cmake . 7 | -------------------------------------------------------------------------------- /build/spritesheet.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/spritesheet.bmp -------------------------------------------------------------------------------- /build/test.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/test.bmp -------------------------------------------------------------------------------- /build/tile0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tile0.bmp -------------------------------------------------------------------------------- /build/tmp/blaster_info_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/blaster_info_flattened.png -------------------------------------------------------------------------------- /build/tmp/charset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/charset.png -------------------------------------------------------------------------------- /build/tmp/charset_en_spn_fr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/charset_en_spn_fr.png -------------------------------------------------------------------------------- /build/tmp/launch_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/launch_flattened.png -------------------------------------------------------------------------------- /build/tmp/old_poster_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/old_poster_flattened.png -------------------------------------------------------------------------------- /build/tmp/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/overlay.png -------------------------------------------------------------------------------- /build/tmp/overlay_cutscene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/overlay_cutscene.png -------------------------------------------------------------------------------- /build/tmp/overlay_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/overlay_dialog.png -------------------------------------------------------------------------------- /build/tmp/overlay_journal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/overlay_journal.png -------------------------------------------------------------------------------- /build/tmp/overlay_network_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/overlay_network_flattened.png -------------------------------------------------------------------------------- /build/tmp/postal_advert_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/postal_advert_flattened.png -------------------------------------------------------------------------------- /build/tmp/repl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/repl.png -------------------------------------------------------------------------------- /build/tmp/seed_packet_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/seed_packet_flattened.png -------------------------------------------------------------------------------- /build/tmp/spritesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet.png -------------------------------------------------------------------------------- /build/tmp/spritesheet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet2.png -------------------------------------------------------------------------------- /build/tmp/spritesheet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet3.png -------------------------------------------------------------------------------- /build/tmp/spritesheet4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet4.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_boss0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_boss0.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_boss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_boss1.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_boss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_boss2.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_boss2_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_boss2_done.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_boss2_final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_boss2_final.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_boss2_mutate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_boss2_mutate.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_intro_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_intro_clouds.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_intro_cutscene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_intro_cutscene.png -------------------------------------------------------------------------------- /build/tmp/spritesheet_launch_anim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/spritesheet_launch_anim.png -------------------------------------------------------------------------------- /build/tmp/tilesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet.png -------------------------------------------------------------------------------- /build/tmp/tilesheet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet2.png -------------------------------------------------------------------------------- /build/tmp/tilesheet2_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet2_top.png -------------------------------------------------------------------------------- /build/tmp/tilesheet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet3.png -------------------------------------------------------------------------------- /build/tmp/tilesheet3_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet3_top.png -------------------------------------------------------------------------------- /build/tmp/tilesheet4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet4.png -------------------------------------------------------------------------------- /build/tmp/tilesheet4_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet4_top.png -------------------------------------------------------------------------------- /build/tmp/tilesheet_intro_cutscene_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet_intro_cutscene_flattened.png -------------------------------------------------------------------------------- /build/tmp/tilesheet_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/tilesheet_top.png -------------------------------------------------------------------------------- /build/tmp/title_1_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/title_1_flattened.png -------------------------------------------------------------------------------- /build/tmp/title_2_flattened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/build/tmp/title_2_flattened.png -------------------------------------------------------------------------------- /external/lua/lapi.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lapi.h $ 3 | ** Auxiliary functions from Lua API 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lapi_h 8 | #define lapi_h 9 | 10 | 11 | #include "llimits.h" 12 | #include "lstate.h" 13 | 14 | 15 | /* Increments 'L->top', checking for stack overflows */ 16 | #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ 17 | "stack overflow");} 18 | 19 | 20 | /* 21 | ** If a call returns too many multiple returns, the callee may not have 22 | ** stack space to accommodate all results. In this case, this macro 23 | ** increases its stack space ('L->ci->top'). 24 | */ 25 | #define adjustresults(L,nres) \ 26 | { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } 27 | 28 | 29 | /* Ensure the stack has at least 'n' elements */ 30 | #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ 31 | "not enough elements in the stack") 32 | 33 | 34 | /* 35 | ** To reduce the overhead of returning from C functions, the presence of 36 | ** to-be-closed variables in these functions is coded in the CallInfo's 37 | ** field 'nresults', in a way that functions with no to-be-closed variables 38 | ** with zero, one, or "all" wanted results have no overhead. Functions 39 | ** with other number of wanted results, as well as functions with 40 | ** variables to be closed, have an extra check. 41 | */ 42 | 43 | #define hastocloseCfunc(n) ((n) < LUA_MULTRET) 44 | 45 | #define codeNresults(n) (-(n) - 3) 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /external/lua/lcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lcode.h $ 3 | ** Code generator for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lcode_h 8 | #define lcode_h 9 | 10 | #include "llex.h" 11 | #include "lobject.h" 12 | #include "lopcodes.h" 13 | #include "lparser.h" 14 | 15 | 16 | /* 17 | ** Marks the end of a patch list. It is an invalid value both as an absolute 18 | ** address, and as a list link (would link an element to itself). 19 | */ 20 | #define NO_JUMP (-1) 21 | 22 | 23 | /* 24 | ** grep "ORDER OPR" if you change these enums (ORDER OP) 25 | */ 26 | typedef enum BinOpr { 27 | /* arithmetic operators */ 28 | OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, 29 | OPR_DIV, OPR_IDIV, 30 | /* bitwise operators */ 31 | OPR_BAND, OPR_BOR, OPR_BXOR, 32 | OPR_SHL, OPR_SHR, 33 | /* string operator */ 34 | OPR_CONCAT, 35 | /* comparison operators */ 36 | OPR_EQ, OPR_LT, OPR_LE, 37 | OPR_NE, OPR_GT, OPR_GE, 38 | /* logical operators */ 39 | OPR_AND, OPR_OR, 40 | OPR_NOBINOPR 41 | } BinOpr; 42 | 43 | 44 | /* true if operation is foldable (that is, it is arithmetic or bitwise) */ 45 | #define foldbinop(op) ((op) <= OPR_SHR) 46 | 47 | 48 | #define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0) 49 | 50 | 51 | typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; 52 | 53 | 54 | /* get (pointer to) instruction of given 'expdesc' */ 55 | #define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) 56 | 57 | 58 | #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) 59 | 60 | #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) 61 | 62 | LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); 63 | LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); 64 | LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); 65 | LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, 66 | int B, int C, int k); 67 | LUAI_FUNC int luaK_isKint (expdesc *e); 68 | LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); 69 | LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 70 | LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); 71 | LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 72 | LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); 73 | LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); 74 | LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); 75 | LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); 76 | LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); 77 | LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); 78 | LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); 79 | LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); 80 | LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); 81 | LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); 82 | LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); 83 | LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); 84 | LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); 85 | LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); 86 | LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); 87 | LUAI_FUNC int luaK_jump (FuncState *fs); 88 | LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); 89 | LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); 90 | LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); 91 | LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); 92 | LUAI_FUNC int luaK_getlabel (FuncState *fs); 93 | LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); 94 | LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); 95 | LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, 96 | expdesc *v2, int line); 97 | LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc, 98 | int ra, int asize, int hsize); 99 | LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); 100 | LUAI_FUNC void luaK_finish (FuncState *fs); 101 | LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg); 102 | 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /external/lua/lctype.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.c $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lctype_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lctype.h" 14 | 15 | #if !LUA_USE_CTYPE /* { */ 16 | 17 | #include 18 | 19 | 20 | #if defined (LUA_UCID) /* accept UniCode IDentifiers? */ 21 | /* consider all non-ascii codepoints to be alphabetic */ 22 | #define NONA 0x01 23 | #else 24 | #define NONA 0x00 /* default */ 25 | #endif 26 | 27 | 28 | LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { 29 | 0x00, /* EOZ */ 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ 31 | 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ 35 | 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 36 | 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ 37 | 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 38 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ 39 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 40 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ 41 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 42 | 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ 43 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 44 | 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ 45 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 46 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */ 47 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 48 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */ 49 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 50 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */ 51 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 52 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */ 53 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 54 | 0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */ 55 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 56 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */ 57 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 58 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */ 59 | NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, 60 | NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */ 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 62 | }; 63 | 64 | #endif /* } */ 65 | -------------------------------------------------------------------------------- /external/lua/lctype.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lctype.h $ 3 | ** 'ctype' functions for Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lctype_h 8 | #define lctype_h 9 | 10 | #include "lua.h" 11 | 12 | 13 | /* 14 | ** WARNING: the functions defined here do not necessarily correspond 15 | ** to the similar functions in the standard C ctype.h. They are 16 | ** optimized for the specific needs of Lua. 17 | */ 18 | 19 | #if !defined(LUA_USE_CTYPE) 20 | 21 | #if 'A' == 65 && '0' == 48 22 | /* ASCII case: can use its own tables; faster and fixed */ 23 | #define LUA_USE_CTYPE 0 24 | #else 25 | /* must use standard C ctype */ 26 | #define LUA_USE_CTYPE 1 27 | #endif 28 | 29 | #endif 30 | 31 | 32 | #if !LUA_USE_CTYPE /* { */ 33 | 34 | #include 35 | 36 | #include "llimits.h" 37 | 38 | 39 | #define ALPHABIT 0 40 | #define DIGITBIT 1 41 | #define PRINTBIT 2 42 | #define SPACEBIT 3 43 | #define XDIGITBIT 4 44 | 45 | 46 | #define MASK(B) (1 << (B)) 47 | 48 | 49 | /* 50 | ** add 1 to char to allow index -1 (EOZ) 51 | */ 52 | #define testprop(c,p) (luai_ctype_[(c)+1] & (p)) 53 | 54 | /* 55 | ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' 56 | */ 57 | #define lislalpha(c) testprop(c, MASK(ALPHABIT)) 58 | #define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) 59 | #define lisdigit(c) testprop(c, MASK(DIGITBIT)) 60 | #define lisspace(c) testprop(c, MASK(SPACEBIT)) 61 | #define lisprint(c) testprop(c, MASK(PRINTBIT)) 62 | #define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) 63 | 64 | 65 | /* 66 | ** In ASCII, this 'ltolower' is correct for alphabetic characters and 67 | ** for '.'. That is enough for Lua needs. ('check_exp' ensures that 68 | ** the character either is an upper-case letter or is unchanged by 69 | ** the transformation, which holds for lower-case letters and '.'.) 70 | */ 71 | #define ltolower(c) \ 72 | check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \ 73 | (c) | ('A' ^ 'a')) 74 | 75 | 76 | /* one entry for each character and for -1 (EOZ) */ 77 | LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];) 78 | 79 | 80 | #else /* }{ */ 81 | 82 | /* 83 | ** use standard C ctypes 84 | */ 85 | 86 | #include 87 | 88 | 89 | #define lislalpha(c) (isalpha(c) || (c) == '_') 90 | #define lislalnum(c) (isalnum(c) || (c) == '_') 91 | #define lisdigit(c) (isdigit(c)) 92 | #define lisspace(c) (isspace(c)) 93 | #define lisprint(c) (isprint(c)) 94 | #define lisxdigit(c) (isxdigit(c)) 95 | 96 | #define ltolower(c) (tolower(c)) 97 | 98 | #endif /* } */ 99 | 100 | #endif 101 | 102 | -------------------------------------------------------------------------------- /external/lua/ldebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldebug.h $ 3 | ** Auxiliary functions from Debug Interface module 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldebug_h 8 | #define ldebug_h 9 | 10 | 11 | #include "lstate.h" 12 | 13 | 14 | #define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1) 15 | 16 | 17 | /* Active Lua function (given call info) */ 18 | #define ci_func(ci) (clLvalue(s2v((ci)->func))) 19 | 20 | 21 | #define resethookcount(L) (L->hookcount = L->basehookcount) 22 | 23 | /* 24 | ** mark for entries in 'lineinfo' array that has absolute information in 25 | ** 'abslineinfo' array 26 | */ 27 | #define ABSLINEINFO (-0x80) 28 | 29 | LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); 30 | LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, 31 | StkId *pos); 32 | LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, 33 | const char *opname); 34 | LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, 35 | const char *what); 36 | LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, 37 | const TValue *p2); 38 | LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, 39 | const TValue *p2, 40 | const char *msg); 41 | LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, 42 | const TValue *p2); 43 | LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, 44 | const TValue *p2); 45 | LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); 46 | LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, 47 | TString *src, int line); 48 | LUAI_FUNC l_noret luaG_errormsg (lua_State *L); 49 | LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /external/lua/ldo.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ldo.h $ 3 | ** Stack and Call structure of Lua 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ldo_h 8 | #define ldo_h 9 | 10 | 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | #include "lzio.h" 14 | 15 | 16 | /* 17 | ** Macro to check stack size and grow stack if needed. Parameters 18 | ** 'pre'/'pos' allow the macro to preserve a pointer into the 19 | ** stack across reallocations, doing the work only when needed. 20 | ** It also allows the running of one GC step when the stack is 21 | ** reallocated. 22 | ** 'condmovestack' is used in heavy tests to force a stack reallocation 23 | ** at every check. 24 | */ 25 | #define luaD_checkstackaux(L,n,pre,pos) \ 26 | if (L->stack_last - L->top <= (n)) \ 27 | { pre; luaD_growstack(L, n, 1); pos; } \ 28 | else { condmovestack(L,pre,pos); } 29 | 30 | /* In general, 'pre'/'pos' are empty (nothing to save) */ 31 | #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) 32 | 33 | 34 | 35 | #define savestack(L,p) ((char *)(p) - (char *)L->stack) 36 | #define restorestack(L,n) ((StkId)((char *)L->stack + (n))) 37 | 38 | 39 | /* macro to check stack size, preserving 'p' */ 40 | #define checkstackGCp(L,n,p) \ 41 | luaD_checkstackaux(L, n, \ 42 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ 43 | luaC_checkGC(L), /* stack grow uses memory */ \ 44 | p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ 45 | 46 | 47 | /* macro to check stack size and GC */ 48 | #define checkstackGC(L,fsize) \ 49 | luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) 50 | 51 | 52 | /* type of protected functions, to be ran by 'runprotected' */ 53 | typedef void (*Pfunc) (lua_State *L, void *ud); 54 | 55 | LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); 56 | LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, 57 | const char *mode); 58 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, 59 | int fTransfer, int nTransfer); 60 | LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); 61 | LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); 62 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); 63 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); 64 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); 65 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, 66 | ptrdiff_t oldtop, ptrdiff_t ef); 67 | LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); 68 | LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); 69 | LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); 70 | LUAI_FUNC void luaD_shrinkstack (lua_State *L); 71 | LUAI_FUNC void luaD_inctop (lua_State *L); 72 | 73 | LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); 74 | LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /external/lua/lfunc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lfunc.h $ 3 | ** Auxiliary functions to manipulate prototypes and closures 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lfunc_h 8 | #define lfunc_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | #define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \ 15 | cast_int(sizeof(TValue)) * (n)) 16 | 17 | #define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \ 18 | cast_int(sizeof(TValue *)) * (n)) 19 | 20 | 21 | /* test whether thread is in 'twups' list */ 22 | #define isintwups(L) (L->twups != L) 23 | 24 | 25 | /* 26 | ** maximum number of upvalues in a closure (both C and Lua). (Value 27 | ** must fit in a VM register.) 28 | */ 29 | #define MAXUPVAL 255 30 | 31 | 32 | #define upisopen(up) ((up)->v != &(up)->u.value) 33 | 34 | 35 | #define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v)) 36 | 37 | 38 | /* 39 | ** maximum number of misses before giving up the cache of closures 40 | ** in prototypes 41 | */ 42 | #define MAXMISS 10 43 | 44 | 45 | /* 46 | ** Special "status" for 'luaF_close' 47 | */ 48 | 49 | /* close upvalues without running their closing methods */ 50 | #define NOCLOSINGMETH (-1) 51 | 52 | /* close upvalues running all closing methods in protected mode */ 53 | #define CLOSEPROTECT (-2) 54 | 55 | 56 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); 57 | LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nupvals); 58 | LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals); 59 | LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); 60 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 61 | LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); 62 | LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status); 63 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); 64 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 65 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 66 | int pc); 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /external/lua/linit.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: linit.c $ 3 | ** Initialization of libraries for lua.c and other clients 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #define linit_c 9 | #define LUA_LIB 10 | 11 | /* 12 | ** If you embed Lua in your program and need to open the standard 13 | ** libraries, call luaL_openlibs in your program. If you need a 14 | ** different set of libraries, copy this file to your project and edit 15 | ** it to suit your needs. 16 | ** 17 | ** You can also *preload* libraries, so that a later 'require' can 18 | ** open the library, which is already linked to the application. 19 | ** For that, do the following code: 20 | ** 21 | ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 22 | ** lua_pushcfunction(L, luaopen_modname); 23 | ** lua_setfield(L, -2, modname); 24 | ** lua_pop(L, 1); // remove PRELOAD table 25 | */ 26 | 27 | #include "lprefix.h" 28 | 29 | 30 | #include 31 | 32 | #include "lua.h" 33 | 34 | #include "lualib.h" 35 | #include "lauxlib.h" 36 | 37 | 38 | /* 39 | ** these libs are loaded by lua.c and are readily available to any Lua 40 | ** program 41 | */ 42 | static const luaL_Reg loadedlibs[] = { 43 | {LUA_GNAME, luaopen_base}, 44 | {LUA_TABLIBNAME, luaopen_table}, 45 | {LUA_STRLIBNAME, luaopen_string}, 46 | {LUA_MATHLIBNAME, luaopen_math}, 47 | {LUA_COLIBNAME, luaopen_coroutine}, 48 | {LUA_UTF8LIBNAME, luaopen_utf8}, 49 | {LUA_DBLIBNAME, luaopen_debug}, 50 | {NULL, NULL} 51 | }; 52 | 53 | 54 | LUALIB_API void luaL_openlibs (lua_State *L) { 55 | const luaL_Reg *lib; 56 | /* "require" functions from 'loadedlibs' and set results to global table */ 57 | for (lib = loadedlibs; lib->func; lib++) { 58 | luaL_requiref(L, lib->name, lib->func, 1); 59 | lua_pop(L, 1); /* remove lib */ 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /external/lua/ljumptab.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ljumptab.h $ 3 | ** Jump Table for the Lua interpreter 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #undef vmdispatch 9 | #undef vmcase 10 | #undef vmbreak 11 | 12 | #define vmdispatch(x) goto *disptab[x]; 13 | 14 | #define vmcase(l) L_##l: 15 | 16 | #define vmbreak vmfetch(); vmdispatch(GET_OPCODE(i)); 17 | 18 | 19 | static const void *const disptab[NUM_OPCODES] = { 20 | 21 | #if 0 22 | ** you can update the following list with this command: 23 | ** 24 | ** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h 25 | ** 26 | #endif 27 | 28 | &&L_OP_MOVE, 29 | &&L_OP_LOADI, 30 | &&L_OP_LOADF, 31 | &&L_OP_LOADK, 32 | &&L_OP_LOADKX, 33 | &&L_OP_LOADFALSE, 34 | &&L_OP_LFALSESKIP, 35 | &&L_OP_LOADTRUE, 36 | &&L_OP_LOADNIL, 37 | &&L_OP_GETUPVAL, 38 | &&L_OP_SETUPVAL, 39 | &&L_OP_GETTABUP, 40 | &&L_OP_GETTABLE, 41 | &&L_OP_GETI, 42 | &&L_OP_GETFIELD, 43 | &&L_OP_SETTABUP, 44 | &&L_OP_SETTABLE, 45 | &&L_OP_SETI, 46 | &&L_OP_SETFIELD, 47 | &&L_OP_NEWTABLE, 48 | &&L_OP_SELF, 49 | &&L_OP_ADDI, 50 | &&L_OP_ADDK, 51 | &&L_OP_SUBK, 52 | &&L_OP_MULK, 53 | &&L_OP_MODK, 54 | &&L_OP_POWK, 55 | &&L_OP_DIVK, 56 | &&L_OP_IDIVK, 57 | &&L_OP_BANDK, 58 | &&L_OP_BORK, 59 | &&L_OP_BXORK, 60 | &&L_OP_SHRI, 61 | &&L_OP_SHLI, 62 | &&L_OP_ADD, 63 | &&L_OP_SUB, 64 | &&L_OP_MUL, 65 | &&L_OP_MOD, 66 | &&L_OP_POW, 67 | &&L_OP_DIV, 68 | &&L_OP_IDIV, 69 | &&L_OP_BAND, 70 | &&L_OP_BOR, 71 | &&L_OP_BXOR, 72 | &&L_OP_SHL, 73 | &&L_OP_SHR, 74 | &&L_OP_MMBIN, 75 | &&L_OP_MMBINI, 76 | &&L_OP_MMBINK, 77 | &&L_OP_UNM, 78 | &&L_OP_BNOT, 79 | &&L_OP_NOT, 80 | &&L_OP_LEN, 81 | &&L_OP_CONCAT, 82 | &&L_OP_CLOSE, 83 | &&L_OP_TBC, 84 | &&L_OP_JMP, 85 | &&L_OP_EQ, 86 | &&L_OP_LT, 87 | &&L_OP_LE, 88 | &&L_OP_EQK, 89 | &&L_OP_EQI, 90 | &&L_OP_LTI, 91 | &&L_OP_LEI, 92 | &&L_OP_GTI, 93 | &&L_OP_GEI, 94 | &&L_OP_TEST, 95 | &&L_OP_TESTSET, 96 | &&L_OP_CALL, 97 | &&L_OP_TAILCALL, 98 | &&L_OP_RETURN, 99 | &&L_OP_RETURN0, 100 | &&L_OP_RETURN1, 101 | &&L_OP_FORLOOP, 102 | &&L_OP_FORPREP, 103 | &&L_OP_TFORPREP, 104 | &&L_OP_TFORCALL, 105 | &&L_OP_TFORLOOP, 106 | &&L_OP_SETLIST, 107 | &&L_OP_CLOSURE, 108 | &&L_OP_VARARG, 109 | &&L_OP_VARARGPREP, 110 | &&L_OP_EXTRAARG 111 | 112 | }; 113 | -------------------------------------------------------------------------------- /external/lua/llex.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: llex.h $ 3 | ** Lexical Analyzer 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef llex_h 8 | #define llex_h 9 | 10 | #include 11 | 12 | #include "lobject.h" 13 | #include "lzio.h" 14 | 15 | 16 | /* 17 | ** Single-char tokens (terminal symbols) are represented by their own 18 | ** numeric code. Other tokens start at the following value. 19 | */ 20 | #define FIRST_RESERVED (UCHAR_MAX + 1) 21 | 22 | 23 | #if !defined(LUA_ENV) 24 | #define LUA_ENV "_ENV" 25 | #endif 26 | 27 | 28 | /* 29 | * WARNING: if you change the order of this enumeration, 30 | * grep "ORDER RESERVED" 31 | */ 32 | enum RESERVED { 33 | /* terminal symbols denoted by reserved words */ 34 | TK_AND = FIRST_RESERVED, TK_BREAK, 35 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, 36 | TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, 37 | TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, 38 | /* other terminal symbols */ 39 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, 40 | TK_SHL, TK_SHR, 41 | TK_DBCOLON, TK_EOS, 42 | TK_FLT, TK_INT, TK_NAME, TK_STRING 43 | }; 44 | 45 | /* number of reserved words */ 46 | #define NUM_RESERVED (cast_int(TK_WHILE-FIRST_RESERVED + 1)) 47 | 48 | 49 | typedef union { 50 | lua_Number r; 51 | lua_Integer i; 52 | TString *ts; 53 | } SemInfo; /* semantics information */ 54 | 55 | 56 | typedef struct Token { 57 | int token; 58 | SemInfo seminfo; 59 | } Token; 60 | 61 | 62 | /* state of the lexer plus state of the parser when shared by all 63 | functions */ 64 | typedef struct LexState { 65 | int current; /* current character (charint) */ 66 | int linenumber; /* input line counter */ 67 | int lastline; /* line of last token 'consumed' */ 68 | Token t; /* current token */ 69 | Token lookahead; /* look ahead token */ 70 | struct FuncState *fs; /* current function (parser) */ 71 | struct lua_State *L; 72 | ZIO *z; /* input stream */ 73 | Mbuffer *buff; /* buffer for tokens */ 74 | Table *h; /* to avoid collection/reuse strings */ 75 | struct Dyndata *dyd; /* dynamic structures used by the parser */ 76 | TString *source; /* current source name */ 77 | TString *envn; /* environment variable name */ 78 | } LexState; 79 | 80 | 81 | LUAI_FUNC void luaX_init (lua_State *L); 82 | LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, 83 | TString *source, int firstchar); 84 | LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); 85 | LUAI_FUNC void luaX_next (LexState *ls); 86 | LUAI_FUNC int luaX_lookahead (LexState *ls); 87 | LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); 88 | LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); 89 | 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /external/lua/lmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lmem.h $ 3 | ** Interface to Memory Manager 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lmem_h 8 | #define lmem_h 9 | 10 | 11 | #include 12 | 13 | #include "llimits.h" 14 | #include "lua.h" 15 | 16 | 17 | #define luaM_error(L) luaD_throw(L, LUA_ERRMEM) 18 | 19 | 20 | /* 21 | ** This macro tests whether it is safe to multiply 'n' by the size of 22 | ** type 't' without overflows. Because 'e' is always constant, it avoids 23 | ** the runtime division MAX_SIZET/(e). 24 | ** (The macro is somewhat complex to avoid warnings: The 'sizeof' 25 | ** comparison avoids a runtime comparison when overflow cannot occur. 26 | ** The compiler should be able to optimize the real test by itself, but 27 | ** when it does it, it may give a warning about "comparison is always 28 | ** false due to limited range of data type"; the +1 tricks the compiler, 29 | ** avoiding this warning but also this optimization.) 30 | */ 31 | #define luaM_testsize(n,e) \ 32 | (sizeof(n) >= sizeof(size_t) && cast_sizet((n)) + 1 > MAX_SIZET/(e)) 33 | 34 | #define luaM_checksize(L,n,e) \ 35 | (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) 36 | 37 | 38 | /* 39 | ** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that 40 | ** the result is not larger than 'n' and cannot overflow a 'size_t' 41 | ** when multiplied by the size of type 't'. (Assumes that 'n' is an 42 | ** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.) 43 | */ 44 | #define luaM_limitN(n,t) \ 45 | ((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \ 46 | cast_uint((MAX_SIZET/sizeof(t)))) 47 | 48 | 49 | /* 50 | ** Arrays of chars do not need any test 51 | */ 52 | #define luaM_reallocvchar(L,b,on,n) \ 53 | cast_charp(luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) 54 | 55 | #define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) 56 | #define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) 57 | #define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) 58 | 59 | #define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0)) 60 | #define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0)) 61 | #define luaM_newvectorchecked(L,n,t) \ 62 | (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) 63 | 64 | #define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) 65 | 66 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ 67 | ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ 68 | luaM_limitN(limit,t),e))) 69 | 70 | #define luaM_reallocvector(L, v,oldn,n,t) \ 71 | (cast(t *, luaM_realloc_(L, v, cast_sizet(oldn) * sizeof(t), \ 72 | cast_sizet(n) * sizeof(t)))) 73 | 74 | #define luaM_shrinkvector(L,v,size,fs,t) \ 75 | ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) 76 | 77 | LUAI_FUNC l_noret luaM_toobig (lua_State *L); 78 | 79 | /* not to be called directly */ 80 | LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, 81 | size_t size); 82 | LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize, 83 | size_t size); 84 | LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); 85 | LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, 86 | int *size, int size_elem, int limit, 87 | const char *what); 88 | LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem, 89 | int final_n, int size_elem); 90 | LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag); 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /external/lua/lopcodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopcodes.c $ 3 | ** Opcodes for Lua virtual machine 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lopcodes_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include "lopcodes.h" 14 | 15 | 16 | /* ORDER OP */ 17 | 18 | LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { 19 | /* MM OT IT T A mode opcode */ 20 | opmode(0, 0, 0, 0, 1, iABC) /* OP_MOVE */ 21 | ,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADI */ 22 | ,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADF */ 23 | ,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADK */ 24 | ,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADKX */ 25 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADFALSE */ 26 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LFALSESKIP */ 27 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADTRUE */ 28 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADNIL */ 29 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETUPVAL */ 30 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */ 31 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABUP */ 32 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABLE */ 33 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETI */ 34 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETFIELD */ 35 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABUP */ 36 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */ 37 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */ 38 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */ 39 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */ 40 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */ 41 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */ 42 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */ 43 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUBK */ 44 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MULK */ 45 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MODK */ 46 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_POWK */ 47 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIVK */ 48 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIVK */ 49 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */ 50 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */ 51 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */ 52 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */ 53 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */ 54 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */ 55 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */ 56 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */ 57 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_MOD */ 58 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_POW */ 59 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIV */ 60 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIV */ 61 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BAND */ 62 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BOR */ 63 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXOR */ 64 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */ 65 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */ 66 | ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */ 67 | ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI*/ 68 | ,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK*/ 69 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */ 70 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */ 71 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */ 72 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_LEN */ 73 | ,opmode(0, 0, 0, 0, 1, iABC) /* OP_CONCAT */ 74 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_CLOSE */ 75 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_TBC */ 76 | ,opmode(0, 0, 0, 0, 0, isJ) /* OP_JMP */ 77 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQ */ 78 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LT */ 79 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LE */ 80 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQK */ 81 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQI */ 82 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LTI */ 83 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_LEI */ 84 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_GTI */ 85 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_GEI */ 86 | ,opmode(0, 0, 0, 1, 0, iABC) /* OP_TEST */ 87 | ,opmode(0, 0, 0, 1, 1, iABC) /* OP_TESTSET */ 88 | ,opmode(0, 1, 1, 0, 1, iABC) /* OP_CALL */ 89 | ,opmode(0, 1, 1, 0, 1, iABC) /* OP_TAILCALL */ 90 | ,opmode(0, 0, 1, 0, 0, iABC) /* OP_RETURN */ 91 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN0 */ 92 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN1 */ 93 | ,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORLOOP */ 94 | ,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORPREP */ 95 | ,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */ 96 | ,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */ 97 | ,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */ 98 | ,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */ 99 | ,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */ 100 | ,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */ 101 | ,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */ 102 | ,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */ 103 | }; 104 | 105 | -------------------------------------------------------------------------------- /external/lua/lopnames.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lopnames.h $ 3 | ** Opcode names 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #if !defined(lopnames_h) 8 | #define lopnames_h 9 | 10 | #include 11 | 12 | 13 | /* ORDER OP */ 14 | 15 | static const char *const opnames[] = { 16 | "MOVE", 17 | "LOADI", 18 | "LOADF", 19 | "LOADK", 20 | "LOADKX", 21 | "LOADFALSE", 22 | "LFALSESKIP", 23 | "LOADTRUE", 24 | "LOADNIL", 25 | "GETUPVAL", 26 | "SETUPVAL", 27 | "GETTABUP", 28 | "GETTABLE", 29 | "GETI", 30 | "GETFIELD", 31 | "SETTABUP", 32 | "SETTABLE", 33 | "SETI", 34 | "SETFIELD", 35 | "NEWTABLE", 36 | "SELF", 37 | "ADDI", 38 | "ADDK", 39 | "SUBK", 40 | "MULK", 41 | "MODK", 42 | "POWK", 43 | "DIVK", 44 | "IDIVK", 45 | "BANDK", 46 | "BORK", 47 | "BXORK", 48 | "SHRI", 49 | "SHLI", 50 | "ADD", 51 | "SUB", 52 | "MUL", 53 | "MOD", 54 | "POW", 55 | "DIV", 56 | "IDIV", 57 | "BAND", 58 | "BOR", 59 | "BXOR", 60 | "SHL", 61 | "SHR", 62 | "MMBIN", 63 | "MMBINI", 64 | "MMBINK", 65 | "UNM", 66 | "BNOT", 67 | "NOT", 68 | "LEN", 69 | "CONCAT", 70 | "CLOSE", 71 | "TBC", 72 | "JMP", 73 | "EQ", 74 | "LT", 75 | "LE", 76 | "EQK", 77 | "EQI", 78 | "LTI", 79 | "LEI", 80 | "GTI", 81 | "GEI", 82 | "TEST", 83 | "TESTSET", 84 | "CALL", 85 | "TAILCALL", 86 | "RETURN", 87 | "RETURN0", 88 | "RETURN1", 89 | "FORLOOP", 90 | "FORPREP", 91 | "TFORPREP", 92 | "TFORCALL", 93 | "TFORLOOP", 94 | "SETLIST", 95 | "CLOSURE", 96 | "VARARG", 97 | "VARARGPREP", 98 | "EXTRAARG", 99 | NULL 100 | }; 101 | 102 | #endif 103 | 104 | -------------------------------------------------------------------------------- /external/lua/lprefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lprefix.h $ 3 | ** Definitions for Lua code that must come before any other header file 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lprefix_h 8 | #define lprefix_h 9 | 10 | 11 | /* 12 | ** Allows POSIX/XSI stuff 13 | */ 14 | #if !defined(LUA_USE_C89) /* { */ 15 | 16 | #if !defined(_XOPEN_SOURCE) 17 | #define _XOPEN_SOURCE 600 18 | #elif _XOPEN_SOURCE == 0 19 | #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ 20 | #endif 21 | 22 | /* 23 | ** Allows manipulation of large files in gcc and some other compilers 24 | */ 25 | #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) 26 | #define _LARGEFILE_SOURCE 1 27 | #define _FILE_OFFSET_BITS 64 28 | #endif 29 | 30 | #endif /* } */ 31 | 32 | 33 | /* 34 | ** Windows stuff 35 | */ 36 | #if defined(_WIN32) /* { */ 37 | 38 | #if !defined(_CRT_SECURE_NO_WARNINGS) 39 | #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ 40 | #endif 41 | 42 | #endif /* } */ 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /external/lua/lstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lstring.h $ 3 | ** String table (keep all strings handled by Lua) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lstring_h 8 | #define lstring_h 9 | 10 | #include "lgc.h" 11 | #include "lobject.h" 12 | #include "lstate.h" 13 | 14 | 15 | /* 16 | ** Memory-allocation error message must be preallocated (it cannot 17 | ** be created after memory is exhausted) 18 | */ 19 | #define MEMERRMSG "not enough memory" 20 | 21 | 22 | /* 23 | ** Size of a TString: Size of the header plus space for the string 24 | ** itself (including final '\0'). 25 | */ 26 | #define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char)) 27 | 28 | #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ 29 | (sizeof(s)/sizeof(char))-1)) 30 | 31 | 32 | /* 33 | ** test whether a string is a reserved word 34 | */ 35 | #define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0) 36 | 37 | 38 | /* 39 | ** equality for short strings, which are always internalized 40 | */ 41 | #define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b)) 42 | 43 | 44 | LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, 45 | unsigned int seed, size_t step); 46 | LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); 47 | LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); 48 | LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 49 | LUAI_FUNC void luaS_clearcache (global_State *g); 50 | LUAI_FUNC void luaS_init (lua_State *L); 51 | LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); 52 | LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue); 53 | LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); 54 | LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); 55 | LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /external/lua/ltable.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltable.h $ 3 | ** Lua tables (hash) 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltable_h 8 | #define ltable_h 9 | 10 | #include "lobject.h" 11 | 12 | 13 | #define gnode(t,i) (&(t)->node[i]) 14 | #define gval(n) (&(n)->i_val) 15 | #define gnext(n) ((n)->u.next) 16 | 17 | 18 | /* 19 | ** Clear all bits of fast-access metamethods, which means that the table 20 | ** may have any of these metamethods. (First access that fails after the 21 | ** clearing will set the bit again.) 22 | */ 23 | #define invalidateTMcache(t) ((t)->flags &= ~maskflags) 24 | 25 | 26 | /* true when 't' is using 'dummynode' as its hash part */ 27 | #define isdummy(t) ((t)->lastfree == NULL) 28 | 29 | 30 | /* allocated size for hash nodes */ 31 | #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) 32 | 33 | 34 | /* returns the Node, given the value of a table entry */ 35 | #define nodefromval(v) cast(Node *, (v)) 36 | 37 | 38 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); 39 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, 40 | TValue *value); 41 | LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); 42 | LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); 43 | LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); 44 | LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); 45 | LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); 46 | LUAI_FUNC Table *luaH_new (lua_State *L); 47 | LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, 48 | unsigned int nhsize); 49 | LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); 50 | LUAI_FUNC void luaH_free (lua_State *L, Table *t); 51 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); 52 | LUAI_FUNC lua_Unsigned luaH_getn (Table *t); 53 | LUAI_FUNC unsigned int luaH_realasize (const Table *t); 54 | 55 | 56 | #if defined(LUA_DEBUG) 57 | LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); 58 | LUAI_FUNC int luaH_isdummy (const Table *t); 59 | #endif 60 | 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /external/lua/ltm.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: ltm.h $ 3 | ** Tag methods 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef ltm_h 8 | #define ltm_h 9 | 10 | 11 | #include "lobject.h" 12 | 13 | 14 | /* 15 | * WARNING: if you change the order of this enumeration, 16 | * grep "ORDER TM" and "ORDER OP" 17 | */ 18 | typedef enum { 19 | TM_INDEX, 20 | TM_NEWINDEX, 21 | TM_GC, 22 | TM_MODE, 23 | TM_LEN, 24 | TM_EQ, /* last tag method with fast access */ 25 | TM_ADD, 26 | TM_SUB, 27 | TM_MUL, 28 | TM_MOD, 29 | TM_POW, 30 | TM_DIV, 31 | TM_IDIV, 32 | TM_BAND, 33 | TM_BOR, 34 | TM_BXOR, 35 | TM_SHL, 36 | TM_SHR, 37 | TM_UNM, 38 | TM_BNOT, 39 | TM_LT, 40 | TM_LE, 41 | TM_CONCAT, 42 | TM_CALL, 43 | TM_CLOSE, 44 | TM_N /* number of elements in the enum */ 45 | } TMS; 46 | 47 | 48 | /* 49 | ** Mask with 1 in all fast-access methods. A 1 in any of these bits 50 | ** in the flag of a (meta)table means the metatable does not have the 51 | ** corresponding metamethod field. (Bit 7 of the flag is used for 52 | ** 'isrealasize'.) 53 | */ 54 | #define maskflags (~(~0u << (TM_EQ + 1))) 55 | 56 | 57 | /* 58 | ** Test whether there is no tagmethod. 59 | ** (Because tagmethods use raw accesses, the result may be an "empty" nil.) 60 | */ 61 | #define notm(tm) ttisnil(tm) 62 | 63 | 64 | #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ 65 | ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) 66 | 67 | #define fasttm(l,et,e) gfasttm(G(l), et, e) 68 | 69 | #define ttypename(x) luaT_typenames_[(x) + 1] 70 | 71 | LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];) 72 | 73 | 74 | LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); 75 | 76 | LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); 77 | LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, 78 | TMS event); 79 | LUAI_FUNC void luaT_init (lua_State *L); 80 | 81 | LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, 82 | const TValue *p2, const TValue *p3); 83 | LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f, 84 | const TValue *p1, const TValue *p2, StkId p3); 85 | LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, 86 | StkId res, TMS event); 87 | LUAI_FUNC void luaT_tryconcatTM (lua_State *L); 88 | LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1, 89 | const TValue *p2, int inv, StkId res, TMS event); 90 | LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, 91 | int inv, StkId res, TMS event); 92 | LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, 93 | const TValue *p2, TMS event); 94 | LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, 95 | int inv, int isfloat, TMS event); 96 | 97 | LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, 98 | struct CallInfo *ci, const Proto *p); 99 | LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, 100 | StkId where, int wanted); 101 | 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /external/lua/lua.hpp: -------------------------------------------------------------------------------- 1 | // lua.hpp 2 | // Lua header files for C++ 3 | // <> not supplied automatically because Lua also compiles as C++ 4 | 5 | extern "C" { 6 | #include "lua.h" 7 | #include "lualib.h" 8 | #include "lauxlib.h" 9 | } 10 | -------------------------------------------------------------------------------- /external/lua/lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | 14 | /* version suffix for environment variable names */ 15 | #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR 16 | 17 | 18 | LUAMOD_API int (luaopen_base) (lua_State *L); 19 | 20 | #define LUA_COLIBNAME "coroutine" 21 | LUAMOD_API int (luaopen_coroutine) (lua_State *L); 22 | 23 | #define LUA_TABLIBNAME "table" 24 | LUAMOD_API int (luaopen_table) (lua_State *L); 25 | 26 | #define LUA_IOLIBNAME "io" 27 | LUAMOD_API int (luaopen_io) (lua_State *L); 28 | 29 | #define LUA_OSLIBNAME "os" 30 | LUAMOD_API int (luaopen_os) (lua_State *L); 31 | 32 | #define LUA_STRLIBNAME "string" 33 | LUAMOD_API int (luaopen_string) (lua_State *L); 34 | 35 | #define LUA_UTF8LIBNAME "utf8" 36 | LUAMOD_API int (luaopen_utf8) (lua_State *L); 37 | 38 | #define LUA_MATHLIBNAME "math" 39 | LUAMOD_API int (luaopen_math) (lua_State *L); 40 | 41 | #define LUA_DBLIBNAME "debug" 42 | LUAMOD_API int (luaopen_debug) (lua_State *L); 43 | 44 | #define LUA_LOADLIBNAME "package" 45 | LUAMOD_API int (luaopen_package) (lua_State *L); 46 | 47 | 48 | /* open all previous libraries */ 49 | LUALIB_API void (luaL_openlibs) (lua_State *L); 50 | 51 | 52 | 53 | #if !defined(lua_assert) 54 | #define lua_assert(x) ((void)0) 55 | #endif 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /external/lua/lundump.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lundump.h $ 3 | ** load precompiled Lua chunks 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #ifndef lundump_h 8 | #define lundump_h 9 | 10 | #include "llimits.h" 11 | #include "lobject.h" 12 | #include "lzio.h" 13 | 14 | 15 | /* data to catch conversion errors */ 16 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" 17 | 18 | #define LUAC_INT 0x5678 19 | #define LUAC_NUM cast_num(370.5) 20 | 21 | /* 22 | ** Encode major-minor version in one byte, one nibble for each 23 | */ 24 | #define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ 25 | #define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) 26 | 27 | #define LUAC_FORMAT 0 /* this is the official format */ 28 | 29 | /* load one chunk; from lundump.c */ 30 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); 31 | 32 | /* dump one chunk; from ldump.c */ 33 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, 34 | void* data, int strip); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /external/lua/lzio.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.c $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | #define lzio_c 8 | #define LUA_CORE 9 | 10 | #include "lprefix.h" 11 | 12 | 13 | #include 14 | 15 | #include "lua.h" 16 | 17 | #include "llimits.h" 18 | #include "lmem.h" 19 | #include "lstate.h" 20 | #include "lzio.h" 21 | 22 | 23 | int luaZ_fill (ZIO *z) { 24 | size_t size; 25 | lua_State *L = z->L; 26 | const char *buff; 27 | lua_unlock(L); 28 | buff = z->reader(L, z->data, &size); 29 | lua_lock(L); 30 | if (buff == NULL || size == 0) 31 | return EOZ; 32 | z->n = size - 1; /* discount char being returned */ 33 | z->p = buff; 34 | return cast_uchar(*(z->p++)); 35 | } 36 | 37 | 38 | void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { 39 | z->L = L; 40 | z->reader = reader; 41 | z->data = data; 42 | z->n = 0; 43 | z->p = NULL; 44 | } 45 | 46 | 47 | /* --------------------------------------------------------------- read --- */ 48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { 49 | while (n) { 50 | size_t m; 51 | if (z->n == 0) { /* no bytes in buffer? */ 52 | if (luaZ_fill(z) == EOZ) /* try to read more */ 53 | return n; /* no more input; return number of missing bytes */ 54 | else { 55 | z->n++; /* luaZ_fill consumed first byte; put it back */ 56 | z->p--; 57 | } 58 | } 59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ 60 | memcpy(b, z->p, m); 61 | z->n -= m; 62 | z->p += m; 63 | b = (char *)b + m; 64 | n -= m; 65 | } 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /external/lua/lzio.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lzio.h $ 3 | ** Buffered streams 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lzio_h 9 | #define lzio_h 10 | 11 | #include "lua.h" 12 | 13 | #include "lmem.h" 14 | 15 | 16 | #define EOZ (-1) /* end of stream */ 17 | 18 | typedef struct Zio ZIO; 19 | 20 | #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) 21 | 22 | 23 | typedef struct Mbuffer { 24 | char *buffer; 25 | size_t n; 26 | size_t buffsize; 27 | } Mbuffer; 28 | 29 | #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) 30 | 31 | #define luaZ_buffer(buff) ((buff)->buffer) 32 | #define luaZ_sizebuffer(buff) ((buff)->buffsize) 33 | #define luaZ_bufflen(buff) ((buff)->n) 34 | 35 | #define luaZ_buffremove(buff,i) ((buff)->n -= (i)) 36 | #define luaZ_resetbuffer(buff) ((buff)->n = 0) 37 | 38 | 39 | #define luaZ_resizebuffer(L, buff, size) \ 40 | ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ 41 | (buff)->buffsize, size), \ 42 | (buff)->buffsize = size) 43 | 44 | #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) 45 | 46 | 47 | LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, 48 | void *data); 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ 50 | 51 | 52 | 53 | /* --------- Private Part ------------------ */ 54 | 55 | struct Zio { 56 | size_t n; /* bytes still unread */ 57 | const char *p; /* current position in buffer */ 58 | lua_Reader reader; /* reader function */ 59 | void *data; /* additional data */ 60 | lua_State *L; /* Lua state (for reader) */ 61 | }; 62 | 63 | 64 | LUAI_FUNC int luaZ_fill (ZIO *z); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /external/umm_malloc/src/dbglog/dbglog.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------------- 2 | * dbglog.h - A set of macros that cleans up code that needs to produce debug 3 | * or log information. 4 | * 5 | * Many embedded systems still put a premium on code space and therefore need 6 | * a way to conditionally compile in debug code. Yes, it can lead to code that 7 | * runs differently depending on whether the debug code is cmpiled in or not 8 | * but you need to be able to evaluate the tradeoff. 9 | * 10 | * See copyright notice in LICENSE.TXT 11 | * ---------------------------------------------------------------------------- 12 | * NOTE WELL that this file may be included multiple times - this allows you 13 | * to set the trace level #define DBGLOG_LEVEL x 14 | * 15 | * To update which of the DBGLOG macros are compiled in, you must redefine the 16 | * DBGLOG_LEVEL macro and the inlcude the dbglog.h file again, like this: 17 | * 18 | * #undef DBGLOG_LEVEL 19 | * #define DBGLOG_LEVEL 6 20 | * #include "dbglog/dbglog.txt" 21 | * 22 | * To handle multiple inclusion, we need to first undefine any macros we define 23 | * so that the compiler does not warn us that we are changing a macro. 24 | * ---------------------------------------------------------------------------- 25 | * The DBGLOG_LEVEL and DBGLOG_FUNCTION should be defined BEFORE this 26 | * file is included or else the following defaults are used: 27 | * 28 | * #define DBGLOG_LEVEL 0 29 | * #define DBGLOG_FUNCTION printf 30 | * ---------------------------------------------------------------------------- 31 | * There are macros to handle the following decreasing levels of detail: 32 | * 33 | * 6 = TRACE 34 | * 5 = DEBUG 35 | * 4 = CRITICAL 36 | * 3 = ERROR 37 | * 2 = WARNING 38 | * 1 = INFO 39 | * 0 = FORCE - The DBGLOG_FUNCTION is always compiled in and is called only when 40 | * the first parameter to the macro is non-0 41 | * ---------------------------------------------------------------------------- 42 | */ 43 | 44 | //#ifndef __DBGLOG_H__ 45 | //#define __DBGLOG_H__ 46 | #define DBGLOG_LEVEL_TRACE (6) 47 | #define DBGLOG_LEVEL_DEBUG (5) 48 | #define DBGLOG_LEVEL_CRITICAL (4) 49 | #define DBGLOG_LEVEL_ERROR (3) 50 | #define DBGLOG_LEVEL_WARNING (2) 51 | #define DBGLOG_LEVEL_INFO (1) 52 | #define DBGLOG_LEVEL_FORCE (0) 53 | //#else 54 | #undef DBGLOG_TRACE 55 | #undef DBGLOG_DEBUG 56 | #undef DBGLOG_CRITICAL 57 | #undef DBGLOG_ERROR 58 | #undef DBGLOG_WARNING 59 | #undef DBGLOG_INFO 60 | #undef DBGLOG_FORCE 61 | 62 | #ifndef DBGLOG_LEVEL 63 | # define DBGLOG_LEVEL 0 64 | #endif 65 | 66 | #ifndef DBGLOG_FUNCTION 67 | # define DBGLOG_FUNCTION fprintf 68 | #endif 69 | 70 | #define DBGLOG_32_BIT_PTR(x) ((uint32_t)(((uintptr_t)(x)) & 0xffffffff)) 71 | 72 | /* ------------------------------------------------------------------------- */ 73 | 74 | #if DBGLOG_LEVEL >= 6 75 | # define DBGLOG_TRACE(format, ...) DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__); fflush(stdout); 76 | #else 77 | # define DBGLOG_TRACE(format, ...) 78 | #endif 79 | 80 | #if DBGLOG_LEVEL >= 5 81 | # define DBGLOG_DEBUG(format, ...) DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__); fflush(stdout); 82 | #else 83 | # define DBGLOG_DEBUG(format, ...) 84 | #endif 85 | 86 | #if DBGLOG_LEVEL >= 4 87 | # define DBGLOG_CRITICAL(format, ...) DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__); fflush(stdout); 88 | #else 89 | # define DBGLOG_CRITICAL(format, ...) 90 | #endif 91 | 92 | #if DBGLOG_LEVEL >= 3 93 | # define DBGLOG_ERROR(format, ...) DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__); fflush(stdout); 94 | #else 95 | # define DBGLOG_ERROR(format, ...) 96 | #endif 97 | 98 | #if DBGLOG_LEVEL >= 2 99 | # define DBGLOG_WARNING(format, ...) DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__); fflush(stdout); 100 | #else 101 | # define DBGLOG_WARNING(format, ...) 102 | #endif 103 | 104 | #if DBGLOG_LEVEL >= 1 105 | # define DBGLOG_INFO(format, ...) DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__); fflush(stdout); 106 | #else 107 | # define DBGLOG_INFO(format, ...) 108 | #endif 109 | 110 | #define DBGLOG_FORCE(force, format, ...) {if(force) {DBGLOG_FUNCTION(stdout, format, ## __VA_ARGS__);fflush(stdout);}} 111 | //#endif /* __DBGLOG_H__ */ 112 | -------------------------------------------------------------------------------- /external/umm_malloc/src/umm_integrity.c: -------------------------------------------------------------------------------- 1 | /* integrity check (UMM_INTEGRITY_CHECK) {{{ */ 2 | #ifdef UMM_INTEGRITY_CHECK 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | * Perform integrity check of the whole heap data. Returns 1 in case of 9 | * success, 0 otherwise. 10 | * 11 | * First of all, iterate through all free blocks, and check that all backlinks 12 | * match (i.e. if block X has next free block Y, then the block Y should have 13 | * previous free block set to X). 14 | * 15 | * Additionally, we check that each free block is correctly marked with 16 | * `UMM_FREELIST_MASK` on the `next` pointer: during iteration through free 17 | * list, we mark each free block by the same flag `UMM_FREELIST_MASK`, but 18 | * on `prev` pointer. We'll check and unmark it later. 19 | * 20 | * Then, we iterate through all blocks in the heap, and similarly check that 21 | * all backlinks match (i.e. if block X has next block Y, then the block Y 22 | * should have previous block set to X). 23 | * 24 | * But before checking each backlink, we check that the `next` and `prev` 25 | * pointers are both marked with `UMM_FREELIST_MASK`, or both unmarked. 26 | * This way, we ensure that the free flag is in sync with the free pointers 27 | * chain. 28 | */ 29 | bool umm_integrity_check(void) { 30 | bool ok = true; 31 | uint16_t prev; 32 | uint16_t cur; 33 | 34 | if (umm_heap == NULL) { 35 | umm_init(); 36 | } 37 | 38 | /* Iterate through all free blocks */ 39 | prev = 0; 40 | while(1) { 41 | cur = UMM_NFREE(prev); 42 | 43 | /* Check that next free block number is valid */ 44 | if (cur >= UMM_NUMBLOCKS) { 45 | DBGLOG_CRITICAL("Heap integrity broken: too large next free num: %d " 46 | "(in block %d, addr 0x%08x)\n", 47 | cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev))); 48 | ok = false; 49 | goto clean; 50 | } 51 | if (cur == 0) { 52 | /* No more free blocks */ 53 | break; 54 | } 55 | 56 | /* Check if prev free block number matches */ 57 | if (UMM_PFREE(cur) != prev) { 58 | DBGLOG_CRITICAL("Heap integrity broken: free links don't match: " 59 | "%d -> %d, but %d -> %d\n", 60 | prev, cur, cur, UMM_PFREE(cur)); 61 | ok = false; 62 | goto clean; 63 | } 64 | 65 | UMM_PBLOCK(cur) |= UMM_FREELIST_MASK; 66 | 67 | prev = cur; 68 | } 69 | 70 | /* Iterate through all blocks */ 71 | prev = 0; 72 | while(1) { 73 | cur = UMM_NBLOCK(prev) & UMM_BLOCKNO_MASK; 74 | 75 | /* Check that next block number is valid */ 76 | if (cur >= UMM_NUMBLOCKS) { 77 | DBGLOG_CRITICAL("Heap integrity broken: too large next block num: %d " 78 | "(in block %d, addr 0x%08x)\n", 79 | cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev))); 80 | ok = false; 81 | goto clean; 82 | } 83 | if (cur == 0) { 84 | /* No more blocks */ 85 | break; 86 | } 87 | 88 | /* make sure the free mark is appropriate, and unmark it */ 89 | if ((UMM_NBLOCK(cur) & UMM_FREELIST_MASK) 90 | != (UMM_PBLOCK(cur) & UMM_FREELIST_MASK)) 91 | { 92 | DBGLOG_CRITICAL("Heap integrity broken: mask wrong at addr 0x%08x: n=0x%x, p=0x%x\n", 93 | DBGLOG_32_BIT_PTR(&UMM_NBLOCK(cur)), 94 | (UMM_NBLOCK(cur) & UMM_FREELIST_MASK), 95 | (UMM_PBLOCK(cur) & UMM_FREELIST_MASK)); 96 | ok = false; 97 | goto clean; 98 | } 99 | 100 | /* make sure the block list is sequential */ 101 | if (cur <= prev ) { 102 | DBGLOG_CRITICAL("Heap integrity broken: next block %d is before prev this one " 103 | "(in block %d, addr 0x%08x)\n", 104 | cur, prev, DBGLOG_32_BIT_PTR(&UMM_NBLOCK(prev))); 105 | ok = false; 106 | goto clean; 107 | } 108 | 109 | /* unmark */ 110 | UMM_PBLOCK(cur) &= UMM_BLOCKNO_MASK; 111 | 112 | /* Check if prev block number matches */ 113 | if (UMM_PBLOCK(cur) != prev) { 114 | DBGLOG_CRITICAL("Heap integrity broken: block links don't match: " 115 | "%d -> %d, but %d -> %d\n", 116 | prev, cur, cur, UMM_PBLOCK(cur)); 117 | ok = false; 118 | goto clean; 119 | } 120 | 121 | prev = cur; 122 | } 123 | 124 | clean: 125 | if (!ok){ 126 | UMM_HEAP_CORRUPTION_CB(); 127 | } 128 | return ok; 129 | } 130 | 131 | #endif 132 | /* }}} */ 133 | -------------------------------------------------------------------------------- /external/umm_malloc/src/umm_malloc.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------------- 2 | * umm_malloc.h - a memory allocator for embedded systems (microcontrollers) 3 | * 4 | * See copyright notice in LICENSE.TXT 5 | * ---------------------------------------------------------------------------- 6 | */ 7 | 8 | #ifndef UMM_MALLOC_H 9 | #define UMM_MALLOC_H 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /* ------------------------------------------------------------------------ */ 18 | 19 | extern void umm_init( void ); 20 | extern void *umm_malloc( size_t size ); 21 | extern void *umm_calloc( size_t num, size_t size ); 22 | extern void *umm_realloc( void *ptr, size_t size ); 23 | extern void umm_free( void *ptr ); 24 | 25 | /* ------------------------------------------------------------------------ */ 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif /* UMM_MALLOC_H */ 32 | -------------------------------------------------------------------------------- /images/charset0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/images/charset0.png -------------------------------------------------------------------------------- /images/charset1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/images/charset1.png -------------------------------------------------------------------------------- /images/overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/images/overlay.png -------------------------------------------------------------------------------- /images/overlay_text_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/images/overlay_text_key.png -------------------------------------------------------------------------------- /images/transparency_reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/images/transparency_reference.png -------------------------------------------------------------------------------- /index_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/index_tile.png -------------------------------------------------------------------------------- /source/BPCoreEngine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "filesystem.hpp" 5 | #include "platform/platform.hpp" 6 | 7 | extern "C" { 8 | #include "lua/lua.h" 9 | } 10 | 11 | 12 | class BPCoreEngine { 13 | public: 14 | BPCoreEngine(Platform& pf); 15 | 16 | void run(); 17 | 18 | private: 19 | lua_State* lua_; 20 | }; 21 | -------------------------------------------------------------------------------- /source/bitvector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | #include 5 | 6 | 7 | template class Bitvector { 8 | public: 9 | explicit constexpr Bitvector(u8 init) : data_{init} 10 | { 11 | static_assert(sizeof(init) * 8 == bits); 12 | } 13 | 14 | constexpr Bitvector(const std::array init) : data_({}) 15 | { 16 | for (std::size_t bit = 0; bit < init.size(); ++bit) { 17 | this->set(bit, init[bit]); 18 | } 19 | } 20 | 21 | constexpr Bitvector() : data_({}) 22 | { 23 | } 24 | 25 | Bitvector& operator=(const Bitvector& other) 26 | { 27 | data_ = other.data_; 28 | return *this; 29 | } 30 | 31 | constexpr u32 size() const 32 | { 33 | return bits; 34 | } 35 | 36 | constexpr void set(u32 index, bool value) 37 | { 38 | auto& byte = data_[index / 8]; 39 | const auto bit = index % 8; 40 | 41 | if (value) { 42 | byte = byte | (1 << bit); 43 | } else { 44 | byte &= ~(1 << bit); 45 | } 46 | } 47 | 48 | constexpr bool get(u32 index) const 49 | { 50 | auto& byte = data_[index / 8]; 51 | const auto bit = index % 8; 52 | const u8 mask = (1 << bit); 53 | return byte & mask; 54 | } 55 | 56 | constexpr bool operator[](u32 index) const 57 | { 58 | return get(index); 59 | } 60 | 61 | constexpr void clear() 62 | { 63 | for (u8& byte : data_) { 64 | byte = 0; 65 | } 66 | } 67 | 68 | private: 69 | std::array data_; 70 | }; 71 | 72 | 73 | template class Bitmatrix { 74 | public: 75 | constexpr Bitmatrix() : data_{} 76 | { 77 | } 78 | 79 | constexpr Bitmatrix(const std::array, width>& init) 80 | { 81 | for (int x = 0; x < width; ++x) { 82 | for (int y = 0; y < height; ++y) { 83 | this->set(x, y, init[x][y]); 84 | } 85 | } 86 | } 87 | 88 | constexpr bool get(int x, int y) const 89 | { 90 | return data_.get(y * width + x); 91 | } 92 | 93 | constexpr void set(int x, int y, bool val) 94 | { 95 | static_assert(width % 8 == 0, 96 | "Warning: this code runs faster when you use power-of-two" 97 | " sizes... remove this warning if you performance is" 98 | " unimportant to your use case."); 99 | data_.set(y * width + x, val); 100 | } 101 | 102 | void clear() 103 | { 104 | data_.clear(); 105 | } 106 | 107 | constexpr Vec2 size() const 108 | { 109 | return {width, height}; 110 | } 111 | 112 | private: 113 | Bitvector data_; 114 | }; 115 | -------------------------------------------------------------------------------- /source/bpcore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // This header provides the bare minimum needed for writing extensions to the 6 | // engine. I could expose more engine internals if people request access to 7 | // various things. 8 | 9 | 10 | #ifndef LUA_32BITS 11 | #define LUA_32BITS 12 | #endif 13 | 14 | #ifndef LUA_COMPAT_5_3 15 | #define LUA_COMPAT_5_3 16 | #endif 17 | 18 | #include 19 | #include 20 | 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | 27 | // NOTE: Do not call libc malloc and free. The engine uses its own version, and 28 | // you should call bpcore_malloc instead. The engine uses all avaliable ram, and 29 | // if you try to call malloc from the C standard library, it will just fail. 30 | // Besides, the malloc in newlib isn't great anyway. 31 | void* bpcore_malloc(size_t size); 32 | void bpcore_free(void* ptr); 33 | 34 | 35 | // You must implement this function, to register any lua functions you'd like to 36 | // add to the engine. Other than registering functions, your extension entry 37 | // function should be stateless and reentrant. The engine may call 38 | // bpcore_extension_main multiple times throughout the execution of a program, 39 | // so you should not use this function to initialize global data. 40 | void bpcore_extension_main(lua_State* L); 41 | 42 | 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /source/camera.cpp: -------------------------------------------------------------------------------- 1 | #include "camera.hpp" 2 | #include "platform/platform.hpp" 3 | 4 | 5 | void Camera::update(Platform& pfrm, 6 | Microseconds dt, 7 | const Vec2& seek_pos) 8 | { 9 | const auto& screen_size = pfrm.screen().size(); 10 | auto view = pfrm.screen().get_view(); 11 | 12 | Vec2 seek; 13 | 14 | if (ballast_.divisor_) { 15 | const auto counter_weight = ballast_.center_ / float(ballast_.divisor_); 16 | buffer_ = interpolate(buffer_, counter_weight, 0.000000025f * dt); 17 | seek = interpolate(seek_pos, buffer_, 0.5f); 18 | } else { 19 | seek = seek_pos; 20 | } 21 | 22 | Vec2 target{(seek.x - screen_size.x / 2), 23 | (seek.y - screen_size.y / 2)}; 24 | 25 | 26 | // static const std::array, 27 | // static_cast(ShakeMagnitude::zero)> 28 | // shake_constants = { 29 | // {{3.f, -5.f, 3.f, -2.f, 1.f}, {6.f, -10.f, 6.f, -4.f, 2.f}}}; 30 | 31 | center_ = interpolate(target, 32 | center_, 33 | dt * speed_ * 34 | (ballast_.divisor_ ? 0.0000016f : 0.0000071f)); 35 | 36 | ballast_.divisor_ = 0; 37 | 38 | if (shake_magnitude_ == 0) { 39 | 40 | view.set_center(center_); 41 | 42 | } else { 43 | 44 | shake_timer_ += dt; 45 | 46 | const auto shake_duration = milliseconds(250); 47 | 48 | if (shake_timer_ > shake_duration) { 49 | shake_timer_ = 0; 50 | shake_magnitude_ = 0; 51 | } 52 | 53 | // Exponents are too expensive, so we aren't doing true damping... 54 | const auto damping = 55 | ease_out(shake_timer_, 0, shake_magnitude_ / 2, shake_duration); 56 | 57 | auto offset = shake_magnitude_ * (float(cosine(shake_timer_ / 4)) / 58 | std::numeric_limits::max()); 59 | 60 | if (offset > 0) { 61 | offset -= damping; 62 | if (offset < 0) { 63 | offset = 0; 64 | } 65 | } else { 66 | offset += damping; 67 | if (offset > 0) { 68 | offset = 0; 69 | } 70 | } 71 | 72 | view.set_center({center_.x, center_.y + offset}); 73 | } 74 | 75 | pfrm.screen().set_view(view); 76 | 77 | ballast_ = {}; 78 | } 79 | 80 | 81 | void Camera::shake(int magnitude) 82 | { 83 | if (shake_magnitude_ == 0 or shake_magnitude_ < magnitude) { 84 | shake_magnitude_ = magnitude; 85 | shake_timer_ = 0; 86 | shake_index_ = 0; 87 | } 88 | } 89 | 90 | 91 | void Camera::set_position(Platform& pfrm, const Vec2& pos) 92 | { 93 | auto view = pfrm.screen().get_view(); 94 | 95 | view.set_center(pos); 96 | 97 | center_ = pos; 98 | 99 | pfrm.screen().set_view(view); 100 | } 101 | -------------------------------------------------------------------------------- /source/camera.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "entity/entity.hpp" 4 | #include "number/numeric.hpp" 5 | 6 | class Platform; 7 | 8 | 9 | class Camera { 10 | public: 11 | void update(Platform& pfrm, Microseconds dt, const Vec2& seek_pos); 12 | 13 | void set_position(Platform& pfrm, const Vec2& pos); 14 | 15 | void shake(int magnitude = 12); 16 | 17 | // The camera supports a counter-weight to the seek position. 18 | void push_ballast(const Vec2& pos) 19 | { 20 | ballast_.divisor_ += 1; 21 | ballast_.center_ = ballast_.center_ + pos; 22 | } 23 | 24 | void set_speed(Float speed) 25 | { 26 | speed_ = speed; 27 | } 28 | 29 | Vec2 center() const 30 | { 31 | return center_; 32 | } 33 | 34 | private: 35 | struct Ballast { 36 | u32 divisor_ = 0; 37 | Vec2 center_; 38 | } ballast_; 39 | 40 | Vec2 center_; 41 | 42 | Vec2 buffer_; 43 | Float speed_ = 1.f; 44 | 45 | int shake_magnitude_ = 0; 46 | 47 | u8 shake_index_ = 0; 48 | Microseconds shake_timer_ = 0; 49 | }; 50 | -------------------------------------------------------------------------------- /source/collision.cpp: -------------------------------------------------------------------------------- 1 | #include "collision.hpp" 2 | -------------------------------------------------------------------------------- /source/collision.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "list.hpp" 5 | 6 | 7 | struct HitBox { 8 | Vec2* position_; 9 | 10 | struct Dimension { 11 | Vec2 size_; 12 | Vec2 origin_; 13 | } dimension_; 14 | 15 | bool overlapping(const HitBox& other) const 16 | { 17 | const auto c = center(); 18 | const auto oc = other.center(); 19 | if (c.x < (oc.x + other.dimension_.size_.x) and 20 | (c.x + dimension_.size_.x) > oc.x and 21 | c.y < (oc.y + other.dimension_.size_.y) and 22 | (c.y + dimension_.size_.y) > oc.y) { 23 | return true; 24 | } else { 25 | return false; 26 | } 27 | } 28 | 29 | Vec2 center() const 30 | { 31 | Vec2 c; 32 | c.x = s16(position_->x) - dimension_.origin_.x; 33 | c.y = s16(position_->y) - dimension_.origin_.y; 34 | return c; 35 | } 36 | }; 37 | 38 | 39 | class Game; 40 | class Platform; 41 | 42 | 43 | template 44 | void check_collisions(Platform& pf, 45 | Game& game, 46 | List& lhs, 47 | List& rhs) 48 | { 49 | for (auto& a : lhs) { 50 | if (a->visible()) { 51 | for (auto& b : rhs) { 52 | if (a->hitbox().overlapping(b->hitbox())) { 53 | a->on_collision(pf, game, *b); 54 | b->on_collision(pf, game, *a); 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | 62 | template 63 | void check_collisions(Platform& pf, Game& game, A& lhs, List& rhs) 64 | { 65 | for (auto& b : rhs) { 66 | if (b->visible()) { 67 | if (lhs.hitbox().overlapping(b->hitbox())) { 68 | lhs.on_collision(pf, game, *b); 69 | b->on_collision(pf, game, lhs); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /source/data/charset0.h: -------------------------------------------------------------------------------- 1 | 2 | //{{BLOCK(charset0) 3 | 4 | //====================================================================== 5 | // 6 | // charset0, 12000x8@4, 7 | // Transparent color : FF,00,FF 8 | // + palette 256 entries, not compressed 9 | // + 1500 tiles not compressed 10 | // Total size: 512 + 48000 = 48512 11 | // 12 | // Time-stamp: 2021-09-11, 03:01:21 13 | // Exported by Cearn's GBA Image Transmogrifier, v0.8.16 14 | // ( http://www.coranac.com/projects/#grit ) 15 | // 16 | //====================================================================== 17 | 18 | #ifndef GRIT_CHARSET0_H 19 | #define GRIT_CHARSET0_H 20 | 21 | #define charset0TilesLen 48000 22 | extern const unsigned int charset0Tiles[12000]; 23 | 24 | #define charset0PalLen 512 25 | extern const unsigned short charset0Pal[256]; 26 | 27 | #endif // GRIT_CHARSET0_H 28 | 29 | //}}BLOCK(charset0) 30 | -------------------------------------------------------------------------------- /source/data/charset1.h: -------------------------------------------------------------------------------- 1 | 2 | //{{BLOCK(charset1) 3 | 4 | //====================================================================== 5 | // 6 | // charset1, 10104x8@4, 7 | // Transparent color : FF,00,FF 8 | // + palette 256 entries, not compressed 9 | // + 1263 tiles not compressed 10 | // Total size: 512 + 40416 = 40928 11 | // 12 | // Time-stamp: 2021-09-11, 03:51:52 13 | // Exported by Cearn's GBA Image Transmogrifier, v0.8.16 14 | // ( http://www.coranac.com/projects/#grit ) 15 | // 16 | //====================================================================== 17 | 18 | #ifndef GRIT_CHARSET1_H 19 | #define GRIT_CHARSET1_H 20 | 21 | #define charset1TilesLen 40416 22 | extern const unsigned int charset1Tiles[10104]; 23 | 24 | #define charset1PalLen 512 25 | extern const unsigned short charset1Pal[256]; 26 | 27 | #endif // GRIT_CHARSET1_H 28 | 29 | //}}BLOCK(charset1) 30 | -------------------------------------------------------------------------------- /source/data/overlay.h: -------------------------------------------------------------------------------- 1 | 2 | //{{BLOCK(overlay) 3 | 4 | //====================================================================== 5 | // 6 | // overlay, 664x8@4, 7 | // Transparent color : FF,00,FF 8 | // + palette 256 entries, not compressed 9 | // + 83 tiles not compressed 10 | // Total size: 512 + 2656 = 3168 11 | // 12 | // Time-stamp: 2020-10-28, 21:59:46 13 | // Exported by Cearn's GBA Image Transmogrifier, v0.8.16 14 | // ( http://www.coranac.com/projects/#grit ) 15 | // 16 | //====================================================================== 17 | 18 | #ifndef GRIT_OVERLAY_H 19 | #define GRIT_OVERLAY_H 20 | 21 | #define overlayTilesLen 2656 22 | extern const unsigned int overlayTiles[664]; 23 | 24 | #define overlayPalLen 512 25 | extern const unsigned short overlayPal[256]; 26 | 27 | #endif // GRIT_OVERLAY_H 28 | 29 | //}}BLOCK(overlay) 30 | -------------------------------------------------------------------------------- /source/data/overlay_text_key.h: -------------------------------------------------------------------------------- 1 | 2 | //{{BLOCK(overlay_text_key) 3 | 4 | //====================================================================== 5 | // 6 | // overlay_text_key, 8x8@4, 7 | // Transparent color : FF,00,FF 8 | // + palette 256 entries, not compressed 9 | // + 1 tiles not compressed 10 | // Total size: 512 + 32 = 544 11 | // 12 | // Time-stamp: 2020-10-28, 23:17:15 13 | // Exported by Cearn's GBA Image Transmogrifier, v0.8.16 14 | // ( http://www.coranac.com/projects/#grit ) 15 | // 16 | //====================================================================== 17 | 18 | #ifndef GRIT_OVERLAY_TEXT_KEY_H 19 | #define GRIT_OVERLAY_TEXT_KEY_H 20 | 21 | #define overlay_text_keyTilesLen 32 22 | extern const unsigned int overlay_text_keyTiles[8]; 23 | 24 | #define overlay_text_keyPalLen 512 25 | extern const unsigned short overlay_text_keyPal[256]; 26 | 27 | #endif // GRIT_OVERLAY_TEXT_KEY_H 28 | 29 | //}}BLOCK(overlay_text_key) 30 | -------------------------------------------------------------------------------- /source/data/overlay_text_key.s: -------------------------------------------------------------------------------- 1 | 2 | @{{BLOCK(overlay_text_key) 3 | 4 | @======================================================================= 5 | @ 6 | @ overlay_text_key, 8x8@4, 7 | @ Transparent color : FF,00,FF 8 | @ + palette 256 entries, not compressed 9 | @ + 1 tiles not compressed 10 | @ Total size: 512 + 32 = 544 11 | @ 12 | @ Time-stamp: 2020-10-28, 23:17:15 13 | @ Exported by Cearn's GBA Image Transmogrifier, v0.8.16 14 | @ ( http://www.coranac.com/projects/#grit ) 15 | @ 16 | @======================================================================= 17 | 18 | .section .rodata 19 | .align 2 20 | .global overlay_text_keyTiles @ 32 unsigned chars 21 | .hidden overlay_text_keyTiles 22 | overlay_text_keyTiles: 23 | .word 0x11111111,0x11111111,0x11111111,0x11111111,0x22222222,0x00000000,0x00000000,0x00000000 24 | 25 | .section .rodata 26 | .align 2 27 | .global overlay_text_keyPal @ 512 unsigned chars 28 | .hidden overlay_text_keyPal 29 | overlay_text_keyPal: 30 | .hword 0x0800,0x7719,0x737B,0x0000,0x0000,0x0000,0x0000,0x0000 31 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 32 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 33 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 34 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 35 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 36 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 37 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 38 | 39 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 40 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 41 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 42 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 43 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 44 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 45 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 46 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 47 | 48 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 49 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 50 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 51 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 52 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 53 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 54 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 55 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 56 | 57 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 58 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 59 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 60 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 61 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 62 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 63 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 64 | .hword 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 65 | 66 | @}}BLOCK(overlay_text_key) 67 | -------------------------------------------------------------------------------- /source/data/sound_msg.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | constexpr int sound_msgLen = 2902; 3 | extern const unsigned char sound_msg[sound_msgLen]; 4 | -------------------------------------------------------------------------------- /source/dateTime.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "number/int.h" 5 | 6 | 7 | struct Date { 8 | s32 year_; 9 | s32 month_; 10 | s32 day_; 11 | }; 12 | 13 | 14 | struct DateTime { 15 | Date date_; 16 | s32 hour_; 17 | s32 minute_; 18 | s32 second_; 19 | 20 | u64 as_seconds() const 21 | { 22 | auto minute = [](u64 n) { return n * 60; }; 23 | auto hour = [&minute](u64 n) { return n * minute(60); }; 24 | auto day = [&hour](u64 n) { return n * hour(24); }; 25 | auto month = [&day](u64 n) { return n * day(31); }; // FIXME... 26 | auto year = [&day](u64 n) { return n * day(365); }; // FIXME... 27 | 28 | return second_ + minute(minute_) + hour(hour_) + day(date_.day_) + 29 | month(date_.month_) + year(date_.year_); 30 | } 31 | }; 32 | 33 | 34 | inline u64 time_diff(const DateTime& before, const DateTime& after) 35 | { 36 | return after.as_seconds() - before.as_seconds(); 37 | } 38 | -------------------------------------------------------------------------------- /source/entity/details/item.cpp: -------------------------------------------------------------------------------- 1 | #include "item.hpp" 2 | #include "game.hpp" 3 | #include "number/random.hpp" 4 | #include "platform/platform.hpp" 5 | #include "wallCollision.hpp" 6 | 7 | 8 | Item::Item(const Vec2& pos, Platform&, Type type) 9 | : state_(State::idle), timer_(rng::get(rng::utility_state)), 10 | type_(type), hitbox_{&position_, {{10, 10}, {2, 2}}} 11 | { 12 | position_ = pos - Vec2{8, 0}; 13 | sprite_.set_position(position_); 14 | sprite_.set_size(Sprite::Size::w16_h32); 15 | 16 | set_type(type); 17 | } 18 | 19 | 20 | void Item::on_collision(Platform& pf, Game& game, Player&) 21 | { 22 | if (not ready()) { 23 | return; 24 | } 25 | Entity::kill(); 26 | 27 | auto pos = position_; 28 | pos.x += 8; 29 | 30 | // FIXME: Sprite scaling is broken on the desktop version of the game. 31 | #ifdef __GBA__ 32 | switch (type_) { 33 | case Type::coin: 34 | game.effects().spawn(pos, 35 | current_zone(game).energy_glow_color_); 36 | game.effects().spawn(pos, 37 | current_zone(game).energy_glow_color_); 38 | game.effects().spawn(pos, 39 | current_zone(game).energy_glow_color_); 40 | break; 41 | 42 | case Type::heart: 43 | game.effects().spawn(pos, ColorConstant::spanish_crimson); 44 | game.effects().spawn(pos, ColorConstant::spanish_crimson); 45 | game.effects().spawn(pos, ColorConstant::spanish_crimson); 46 | break; 47 | 48 | default: 49 | break; 50 | } 51 | #endif // __GBA__ 52 | 53 | pf.sleep(5); 54 | } 55 | 56 | 57 | void Item::set_type(Type type) 58 | { 59 | type_ = type; 60 | 61 | switch (type) { 62 | case Type::heart: 63 | sprite_.set_texture_index(TextureMap::heart); 64 | break; 65 | 66 | case Type::coin: 67 | sprite_.set_texture_index(TextureMap::coin); 68 | break; 69 | 70 | case Type::null: 71 | break; 72 | 73 | default: 74 | // TODO: overworld sprite for all other items 75 | break; 76 | } 77 | } 78 | 79 | 80 | void Item::update(Platform&, Game& game, Microseconds dt) 81 | { 82 | timer_ += dt; 83 | 84 | if (visible()) { 85 | if (game.difficulty() == Settings::Difficulty::survival and 86 | type_ == Type::heart) { 87 | set_type(Type::coin); 88 | } 89 | 90 | // Yikes! This is probably expensive... 91 | const Float offset = 3 * 92 | float(sine(4 * 3.14f * 0.001f * timer_ + 180)) / 93 | std::numeric_limits::max(); 94 | sprite_.set_position({position_.x, position_.y + offset}); 95 | } 96 | 97 | if (state_ == State::scatter) { 98 | 99 | constexpr auto duration = seconds(1); 100 | 101 | const auto wc = check_wall_collisions(game.tiles(), *this); 102 | if (wc.any()) { 103 | if ((wc.left and step_.x < 0.f) or (wc.right and step_.x > 0.f)) { 104 | step_.x = -step_.x; 105 | } 106 | if ((wc.up and step_.y < 0.f) or (wc.down and step_.y > 0.f)) { 107 | step_.y = -step_.y; 108 | } 109 | } 110 | 111 | position_.x += step_.x * dt; 112 | position_.y += step_.y * dt; 113 | 114 | if (timer_ > duration) { 115 | state_ = State::idle; 116 | } 117 | } 118 | } 119 | 120 | 121 | void Item::scatter() 122 | { 123 | timer_ = 0; 124 | state_ = State::scatter; 125 | auto target = rng::sample<64>(position_, rng::utility_state); 126 | step_ = direction(position_, target) * 0.00013f; 127 | } 128 | 129 | 130 | bool Item::ready() const 131 | { 132 | return state_ == State::idle; 133 | } 134 | -------------------------------------------------------------------------------- /source/entity/details/item.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "collision.hpp" 4 | #include "entity/entity.hpp" 5 | #include "localization.hpp" 6 | 7 | 8 | class Player; 9 | 10 | 11 | class Item : public Entity { 12 | public: 13 | enum class Type : u8 { 14 | null = 0, 15 | heart = 1, 16 | coin = 2, 17 | inventory_item_start = 3, 18 | worker_notebook_1 = inventory_item_start, 19 | blaster = 4, 20 | accelerator = 5, 21 | lethargy = 6, 22 | old_poster_1 = 7, 23 | map_system = 8, 24 | explosive_rounds_2 = 9, 25 | seed_packet = 10, 26 | engineer_notebook_2 = 11, 27 | signal_jammer = 12, 28 | navigation_pamphlet = 13, 29 | orange = 14, 30 | orange_seeds = 15, 31 | long_jump_z2 = 16, 32 | 33 | // Items which repurpose existing item icons should be placed below this 34 | // line. Other items, with original icons, should be placed above this 35 | // line. 36 | long_jump_z3 = 17, 37 | long_jump_z4 = 18, 38 | postal_advert = 19, 39 | engineer_notebook_1 = 20, 40 | worker_notebook_2 = 21, 41 | count 42 | }; 43 | 44 | Item(const Vec2& pos, Platform&, Type type); 45 | 46 | void on_collision(Platform& pf, Game& game, Player&); 47 | 48 | const HitBox& hitbox() const 49 | { 50 | return hitbox_; 51 | } 52 | 53 | Type get_type() const 54 | { 55 | return type_; 56 | } 57 | 58 | void set_type(Type type); 59 | 60 | void update(Platform&, Game&, Microseconds dt); 61 | 62 | void scatter(); 63 | 64 | bool ready() const; 65 | 66 | private: 67 | enum class State { idle, scatter } state_; 68 | 69 | Microseconds timer_; 70 | Type type_; 71 | HitBox hitbox_; 72 | Vec2 step_; 73 | }; 74 | 75 | 76 | // Some items, mainly story-related, persist across game sessions. Persistent 77 | // items should also be unique. 78 | inline bool item_is_persistent(Item::Type type) 79 | { 80 | return type == Item::Type::blaster or 81 | type == Item::Type::worker_notebook_1 or 82 | type == Item::Type::worker_notebook_2 or 83 | type == Item::Type::old_poster_1 or type == Item::Type::map_system or 84 | type == Item::Type::seed_packet or 85 | type == Item::Type::engineer_notebook_1 or 86 | type == Item::Type::engineer_notebook_2 or 87 | type == Item::Type::navigation_pamphlet or 88 | type == Item::Type::orange_seeds or 89 | type == Item::Type::postal_advert; 90 | } 91 | 92 | 93 | // Note: For memory efficiency, this function happens to be implemented in 94 | // state.cpp, so that the implementation can pull the data from an existing 95 | // readonly table containing a variety of Item metadata used by the inventory 96 | // state. 97 | LocalizedText item_description(Platform&, Item::Type type); 98 | -------------------------------------------------------------------------------- /source/entity/entity.cpp: -------------------------------------------------------------------------------- 1 | #include "entity.hpp" 2 | 3 | 4 | static Entity::Id id_counter_ = 0; 5 | 6 | 7 | void Entity::override_id(Id id) 8 | { 9 | id_ = id; 10 | 11 | if (id_counter_ < id) { 12 | id_counter_ = id; 13 | } 14 | } 15 | 16 | 17 | void Entity::reset_ids() 18 | { 19 | // I'm not actually worried about running out of ids. The real concern, is 20 | // that one of the players during a multiplayer game ends up with more 21 | // enemies spawned during a level for one reason or another, and stuff 22 | // getting glitched up. 23 | id_counter_ = 0; 24 | } 25 | 26 | 27 | Entity::Entity() : health_(1), id_(id_counter_++) 28 | { 29 | } 30 | 31 | 32 | Entity::Entity(Health health) : health_(health), id_(id_counter_++) 33 | { 34 | } 35 | 36 | 37 | void Entity::update(Platform&, Game&, Microseconds) 38 | { 39 | } 40 | 41 | 42 | Entity::Health Entity::get_health() const 43 | { 44 | return health_; 45 | } 46 | 47 | 48 | bool Entity::alive() const 49 | { 50 | return health_ not_eq 0; 51 | } 52 | 53 | 54 | const Sprite& Entity::get_sprite() const 55 | { 56 | return sprite_; 57 | } 58 | 59 | 60 | Sprite& Entity::get_sprite() 61 | { 62 | return sprite_; 63 | } 64 | 65 | 66 | void Entity::set_position(const Vec2& position) 67 | { 68 | position_ = position; 69 | } 70 | 71 | 72 | void Entity::add_health(Health amount) 73 | { 74 | health_ += amount; 75 | } 76 | 77 | 78 | const Vec2& Entity::get_position() const 79 | { 80 | return position_; 81 | } 82 | -------------------------------------------------------------------------------- /source/entity/entity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "graphics/sprite.hpp" 6 | 7 | 8 | class Platform; 9 | class Game; 10 | 11 | class Entity { 12 | public: 13 | using Health = s32; 14 | using Id = u32; 15 | 16 | 17 | Entity(); 18 | 19 | 20 | Entity(Health health); 21 | 22 | 23 | // Entity(Entity&) = delete; 24 | 25 | 26 | void update(Platform&, Game&, Microseconds); 27 | 28 | 29 | Health get_health() const; 30 | 31 | 32 | bool alive() const; 33 | 34 | 35 | const Sprite& get_sprite() const; 36 | Sprite& get_sprite(); 37 | 38 | 39 | void add_health(Health amount); 40 | 41 | 42 | const Vec2& get_position() const; 43 | 44 | 45 | static constexpr bool multiface_sprite = false; 46 | static constexpr bool has_shadow = false; 47 | static constexpr bool multiface_shadow = false; 48 | 49 | 50 | void set_health(Health health) 51 | { 52 | health_ = health; 53 | } 54 | 55 | 56 | bool visible() const 57 | { 58 | return visible_; 59 | } 60 | 61 | 62 | // IMPORTANT! The automatically assigned Entity ids are guaranteed to be 63 | // synchronized between multiplayer games at the start of each level. But 64 | // after the level has started, there is no guarantee that newly spawned 65 | // entities will have the same ID. If you need to synchronize entities 66 | // created after level generation, you should exercise caution. See, for 67 | // example, how the game allows players to trade items. One player drops an 68 | // item chest, and sends an event over the network, with the item, and the 69 | // entity id of the item chest. Then, the receiver must check that no 70 | // existing entities within the same group have a matching id. In the event 71 | // of an id collision, the receiver should not spawn the new entity, and 72 | // send its own event back to the sender, if appropriate. 73 | static void reset_ids(); 74 | 75 | static Id max_id(); 76 | // Be careful with this function! Before calling, you should make sure that 77 | // no similar extant entities share the same id. 78 | void override_id(Id id); 79 | 80 | 81 | Id id() const 82 | { 83 | return id_; 84 | } 85 | 86 | 87 | // This is VERY BAD CODE. Basically, the rendering loop already determines 88 | // which objects are visible within the window when drawing sprites. To save 89 | // CPU cycles, we are marking an object visible during a rendering pass, so 90 | // that the game logic doesn't need to repeat the visibility calculation. 91 | void mark_visible(bool visible) 92 | { 93 | visible_ = visible; 94 | } 95 | 96 | void on_death(Platform&, Game&) 97 | { 98 | } 99 | 100 | void set_position(const Vec2& position); 101 | 102 | protected: 103 | void debit_health(Health amount = 1) 104 | { 105 | health_ = std::max(Health(0), health_ - amount); 106 | } 107 | 108 | void kill() 109 | { 110 | health_ = 0; 111 | } 112 | 113 | Sprite sprite_; 114 | Vec2 position_; 115 | 116 | private: 117 | Health health_; 118 | Id id_; 119 | bool visible_ = false; 120 | }; 121 | 122 | 123 | #include 124 | 125 | 126 | template using EntityRef = std::unique_ptr; 127 | -------------------------------------------------------------------------------- /source/filesystem.cpp: -------------------------------------------------------------------------------- 1 | #include "filesystem.hpp" 2 | #include "platform/platform.hpp" 3 | #include "string.hpp" 4 | 5 | 6 | #pragma GCC diagnostic push 7 | // Accessing data past __rom_end__ raises -Warray-bounds errors. These would be 8 | // real errors, except that they aren't problematic on the gameboy advance, for 9 | // various reasons, and we're mounting a filesystem at __rom_end__ anyway, so... 10 | #pragma GCC diagnostic ignored "-Warray-bounds" 11 | #pragma GCC diagnostic ignored "-Wstringop-overflow" 12 | #pragma GCC diagnostic ignored "-Wstringop-overread" 13 | 14 | 15 | extern char __rom_end__; 16 | 17 | 18 | static const char* find_files(Platform& pfrm) 19 | { 20 | const char* search_start = &__rom_end__; 21 | const char* search_end = (char*)0x0a000000; 22 | 23 | const char* prefix_str = "core"; 24 | const char* magic = "_filesys"; 25 | const int magic_len = str_len(prefix_str) + str_len(magic); 26 | 27 | const int prefix = *(const int*)prefix_str; 28 | 29 | bool match = false; 30 | int i = 0; 31 | 32 | for (; i < (search_end - magic_len) - search_start; i += 4) { 33 | pfrm.feed_watchdog(); 34 | 35 | int word; 36 | memcpy(&word, (search_start + i), 4); 37 | 38 | if (word == prefix) { 39 | match = true; 40 | for (int j = 4; j < magic_len; ++j) { 41 | if (*(search_start + i + j) not_eq magic[j - 4]) { 42 | match = false; 43 | break; 44 | } 45 | } 46 | if (match) { 47 | break; 48 | } 49 | } 50 | } 51 | 52 | if (match) { 53 | return reinterpret_cast(search_start + i + magic_len); 54 | } else { 55 | return nullptr; 56 | } 57 | } 58 | 59 | 60 | Filesystem::Filesystem() : addr_(nullptr) 61 | { 62 | } 63 | 64 | 65 | bool Filesystem::init(Platform& pfrm) 66 | { 67 | addr_ = find_files(pfrm); 68 | return addr_; 69 | } 70 | 71 | 72 | struct FileInfo { 73 | char name_[32]; 74 | char size_[16]; 75 | // data[]... 76 | // null terminator 77 | // padding (for word alignment) 78 | }; 79 | 80 | 81 | int tonum(const char* str) 82 | { 83 | int res = 0; 84 | 85 | for (int i = 0; str[i] != '\0'; ++i) { 86 | res = res * 10 + str[i] - '0'; 87 | } 88 | 89 | return res; 90 | } 91 | 92 | 93 | Filesystem::FileData Filesystem::get_file(int address, int len) 94 | { 95 | return {(const char*)(intptr_t)address, (u32)len}; 96 | } 97 | 98 | 99 | Filesystem::FileData Filesystem::next_file(int address, int len) 100 | { 101 | address += len; 102 | ++address; // null terminator 103 | address += address % 4; // word padding 104 | 105 | auto current = 106 | reinterpret_cast((const char*)(intptr_t)address); 107 | 108 | return {(const char*)current + sizeof(FileInfo), 109 | (u32)tonum(current->size_)}; 110 | } 111 | 112 | 113 | Filesystem::FileData Filesystem::get_file(const char* name) 114 | { 115 | if (not addr_) { 116 | return {nullptr, 0}; 117 | } 118 | auto current = reinterpret_cast(addr_); 119 | 120 | while (true) { 121 | if (str_cmp(name, current->name_) == 0) { 122 | return {reinterpret_cast(current) + sizeof(FileInfo), 123 | static_cast(tonum(current->size_))}; 124 | } else if (current->name_[0] not_eq '\0') { 125 | auto skip = tonum(current->size_) + 1; // +1 for null terminator 126 | skip += skip % 4; // word padding 127 | 128 | const char* next_addr = reinterpret_cast(current) + 129 | sizeof(FileInfo) + skip; 130 | 131 | current = reinterpret_cast(next_addr); 132 | 133 | } else { 134 | return {nullptr, 0}; 135 | } 136 | } 137 | } 138 | 139 | #pragma GCC diagnostic pop 140 | -------------------------------------------------------------------------------- /source/filesystem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/int.h" 4 | 5 | 6 | class Platform; 7 | 8 | 9 | class Filesystem { 10 | public: 11 | Filesystem(); 12 | 13 | bool init(Platform&); 14 | 15 | struct FileData { 16 | const char* data_; 17 | u32 size_; 18 | }; 19 | 20 | FileData get_file(const char* filename); 21 | 22 | FileData get_file(int address, int len); 23 | FileData next_file(int address, int len); 24 | 25 | private: 26 | const char* addr_; 27 | }; 28 | -------------------------------------------------------------------------------- /source/function.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | // A fixed-space version of std::function, does not allocate. 9 | 10 | 11 | template class Function { 12 | }; 13 | 14 | 15 | template 16 | class Function { 17 | public: 18 | Function() 19 | : invoke_policy_(nullptr), construct_policy_(nullptr), 20 | move_policy_(nullptr), destroy_policy_(nullptr), data_(nullptr), 21 | data_size_(0) 22 | { 23 | } 24 | 25 | 26 | template 27 | Function(Functor f) 28 | : invoke_policy_(reinterpret_cast(invokeImpl)), 29 | construct_policy_( 30 | reinterpret_cast(constructImpl)), 31 | move_policy_(reinterpret_cast(moveImpl)), 32 | destroy_policy_( 33 | reinterpret_cast(destroyImpl)), 34 | data_(nullptr), data_size_(sizeof(Functor)) 35 | { 36 | static_assert(storage >= sizeof(Functor)); 37 | 38 | if (sizeof(Functor) <= internal_storage_.size()) { 39 | data_ = internal_storage_.data(); 40 | } 41 | static_assert(alignof(Functor) <= alignof(decltype(data_)), 42 | "Function uses a hard-coded maximum alignment of" 43 | " eight bytes. You can increase it to 16 or higher if" 44 | " it\'s really necessary..."); 45 | construct_policy_(data_, reinterpret_cast(&f)); 46 | } 47 | 48 | 49 | Function(Function const& rhs) 50 | : invoke_policy_(rhs.invoke_policy_), 51 | construct_policy_(rhs.construct_policy_), 52 | move_policy_(rhs.move_policy_), destroy_policy_(rhs.destroy_policy_), 53 | data_(nullptr), data_size_(rhs.data_size_) 54 | { 55 | if (invoke_policy_) { 56 | data_ = internal_storage_.data(); 57 | construct_policy_(data_, rhs.data_); 58 | } 59 | } 60 | 61 | 62 | Function(Function&& rhs) 63 | : invoke_policy_(rhs.invoke_policy_), 64 | construct_policy_(rhs.construct_policy_), 65 | move_policy_(rhs.move_policy_), destroy_policy_(rhs.destroy_policy_), 66 | data_(nullptr), data_size_(rhs.data_size_) 67 | { 68 | rhs.invoke_policy_ = nullptr; 69 | rhs.construct_policy_ = nullptr; 70 | rhs.destroy_policy_ = nullptr; 71 | if (invoke_policy_) { 72 | data_ = internal_storage_.data(); 73 | move_policy_(data_, rhs.data_); 74 | rhs.data_ = nullptr; 75 | } 76 | } 77 | 78 | 79 | ~Function() 80 | { 81 | if (data_ not_eq nullptr) { 82 | destroy_policy_(data_); 83 | } 84 | } 85 | 86 | 87 | R operator()(Args&&... args) 88 | { 89 | return invoke_policy_(data_, std::forward(args)...); 90 | } 91 | 92 | 93 | private: 94 | typedef R (*InvokePolicy)(void*, Args&&...); 95 | typedef void (*ConstructPolicy)(void*, void*); 96 | typedef void (*MovePolicy)(void*, void*); 97 | typedef void (*DestroyPolicy)(void*); 98 | 99 | 100 | template static R invokeImpl(Functor* fn, Args&&... args) 101 | { 102 | return (*fn)(std::forward(args)...); 103 | } 104 | 105 | 106 | template 107 | static void constructImpl(Functor* construct_dst, Functor* construct_src) 108 | { 109 | new (construct_dst) Functor(*construct_src); 110 | } 111 | 112 | 113 | template 114 | static void moveImpl(Functor* move_dst, Functor* move_src) 115 | { 116 | new (move_dst) Functor(std::move(*move_src)); 117 | } 118 | 119 | 120 | template static void destroyImpl(Functor* f) 121 | { 122 | f->~Functor(); 123 | } 124 | 125 | 126 | InvokePolicy invoke_policy_; 127 | ConstructPolicy construct_policy_; 128 | MovePolicy move_policy_; 129 | DestroyPolicy destroy_policy_; 130 | // TODO: 16 Or higher alignment is a somewhat unusual edge case, but the 131 | // code _should_ be updated to handle it. 132 | alignas(8) std::array internal_storage_; 133 | 134 | // FIXME: data_ is leftover member variable that isn't really needed anymore 135 | void* data_; 136 | std::size_t data_size_; 137 | }; 138 | -------------------------------------------------------------------------------- /source/graphics/animation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | #include "sprite.hpp" 5 | 6 | 7 | template 8 | class Animation { 9 | public: 10 | Animation() : timer_(0) 11 | { 12 | } 13 | 14 | Animation(Microseconds timer) : timer_(timer) 15 | { 16 | } 17 | 18 | bool done(Sprite& sprite) const 19 | { 20 | return sprite.get_texture_index() == (InitialTexture + (Length - 1)); 21 | } 22 | 23 | bool at_beginning(Sprite& sprite) const 24 | { 25 | return sprite.get_texture_index() == InitialTexture; 26 | } 27 | 28 | constexpr TextureIndex initial_texture() 29 | { 30 | return InitialTexture; 31 | } 32 | 33 | void bind(Sprite& sprite) 34 | { 35 | sprite.set_texture_index(InitialTexture); 36 | timer_ = 0; 37 | } 38 | 39 | bool advance(Sprite& sprite, Microseconds dt) 40 | { 41 | timer_ += dt; 42 | const bool ret = [&] { 43 | if (timer_ > Interval) { 44 | timer_ -= Interval; 45 | if (not Animation::done(sprite)) { 46 | sprite.set_texture_index(sprite.get_texture_index() + 1); 47 | } else { 48 | // Note: all animations wrap. 49 | sprite.set_texture_index(InitialTexture); 50 | } 51 | return true; 52 | } 53 | return false; 54 | }(); 55 | return ret; 56 | } 57 | 58 | bool reverse(Sprite& sprite, Microseconds dt) 59 | { 60 | timer_ += dt; 61 | const bool ret = [&] { 62 | if (timer_ > Interval) { 63 | timer_ -= Interval; 64 | const auto current = sprite.get_texture_index(); 65 | if (current >= InitialTexture) { 66 | sprite.set_texture_index(current - 1); 67 | } else { 68 | // Note: all animations wrap. 69 | sprite.set_texture_index(InitialTexture + Length - 1); 70 | } 71 | return true; 72 | } 73 | return false; 74 | }(); 75 | return ret; 76 | } 77 | 78 | private: 79 | Microseconds timer_; 80 | }; 81 | -------------------------------------------------------------------------------- /source/graphics/color.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | 5 | 6 | // Color representation is often platform specific, e.g., OpenGL uses RGBA, 7 | // Nintendo GameBoy uses 15 bit BGR (5 bits per channel). For the sake of 8 | // portability, the colors are described only with an enum, and the 9 | // implementations of the Platform header are responsible for using the correct 10 | // values. 11 | enum class ColorConstant { 12 | null, 13 | // clang-format off 14 | electric_blue = 0x00FFFF, 15 | turquoise_blue = 0x00FFDD, 16 | cerulean_blue = 0x66E0FF, 17 | picton_blue = 0x4DACFF, 18 | maya_blue = 0x4FBCFF, 19 | steel_blue = 0x345680, 20 | spanish_crimson = 0xE81858, 21 | aerospace_orange = 0xFD5200, 22 | safety_orange = 0xFC7500, 23 | rich_black = 0x000010, 24 | stil_de_grain = 0xF9DC5C, 25 | silver_white = 0xF4F4F8, 26 | aged_paper = 0xDEC397, 27 | green = 0x27C8AF, 28 | med_blue_gray = 0x7674A9, 29 | indigo_tint = 0x255F85, 30 | // clang-format on 31 | }; 32 | 33 | 34 | inline ColorConstant custom_color(int hex) 35 | { 36 | return static_cast(hex); 37 | } 38 | 39 | 40 | inline ColorConstant custom_color(u8 r, u8 g, u8 b) 41 | { 42 | return static_cast((r << 16) | (g << 8) | b); 43 | } 44 | 45 | 46 | struct ColorMix { 47 | ColorConstant color_ = ColorConstant::null; 48 | u8 amount_ = 0; 49 | }; 50 | -------------------------------------------------------------------------------- /source/graphics/contrast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | 5 | 6 | using Contrast = s8; 7 | -------------------------------------------------------------------------------- /source/graphics/overlay.h: -------------------------------------------------------------------------------- 1 | 2 | //{{BLOCK(overlay) 3 | 4 | //====================================================================== 5 | // 6 | // overlay, 4032x8@4, 7 | // Transparent color : FF,00,FF 8 | // + palette 256 entries, not compressed 9 | // + 504 tiles not compressed 10 | // Total size: 512 + 16128 = 16640 11 | // 12 | // Time-stamp: 2020-08-01, 12:52:20 13 | // Exported by Cearn's GBA Image Transmogrifier, v 14 | // ( http://www.coranac.com/projects/#grit ) 15 | // 16 | //====================================================================== 17 | 18 | #ifndef GRIT_OVERLAY_H 19 | #define GRIT_OVERLAY_H 20 | 21 | #define overlayTilesLen 16128 22 | extern const unsigned int overlayTiles[4032]; 23 | 24 | #define overlayPalLen 512 25 | extern const unsigned short overlayPal[256]; 26 | 27 | #endif // GRIT_OVERLAY_H 28 | 29 | //}}BLOCK(overlay) 30 | -------------------------------------------------------------------------------- /source/graphics/sprite.cpp: -------------------------------------------------------------------------------- 1 | #include "sprite.hpp" 2 | 3 | 4 | Sprite::Sprite() 5 | : alpha_(Alpha::opaque), size_(Size::w16_h16), flip_x_(false), 6 | flip_y_(false) 7 | { 8 | } 9 | 10 | 11 | void Sprite::set_scale(const Scale& scale) 12 | { 13 | scale_ = scale; 14 | } 15 | 16 | 17 | void Sprite::set_rotation(Rotation rot) 18 | { 19 | rot_ = rot; 20 | } 21 | 22 | 23 | void Sprite::set_position(const Vec2& position) 24 | { 25 | position_ = position; 26 | } 27 | 28 | 29 | void Sprite::set_origin(const Vec2& origin) 30 | { 31 | origin_ = origin; 32 | } 33 | 34 | 35 | void Sprite::set_texture_index(TextureIndex texture_index) 36 | { 37 | texture_index_ = texture_index; 38 | } 39 | 40 | 41 | void Sprite::set_flip(const Vec2& flip) 42 | { 43 | flip_x_ = flip.x; 44 | flip_y_ = flip.y; 45 | } 46 | 47 | 48 | void Sprite::set_alpha(Alpha alpha) 49 | { 50 | alpha_ = alpha; 51 | } 52 | 53 | 54 | void Sprite::set_mix(const ColorMix& mix) 55 | { 56 | mix_ = mix; 57 | } 58 | 59 | 60 | void Sprite::set_size(Size size) 61 | { 62 | size_ = size; 63 | } 64 | 65 | 66 | Sprite::Rotation Sprite::get_rotation() const 67 | { 68 | return rot_; 69 | } 70 | 71 | 72 | Sprite::Scale Sprite::get_scale() const 73 | { 74 | return scale_; 75 | } 76 | 77 | 78 | const Vec2& Sprite::get_position() const 79 | { 80 | return position_; 81 | } 82 | 83 | 84 | const Vec2& Sprite::get_origin() const 85 | { 86 | return origin_; 87 | } 88 | 89 | 90 | TextureIndex Sprite::get_texture_index() const 91 | { 92 | return texture_index_; 93 | } 94 | 95 | 96 | Vec2 Sprite::get_flip() const 97 | { 98 | return {flip_x_, flip_y_}; 99 | } 100 | 101 | 102 | Sprite::Alpha Sprite::get_alpha() const 103 | { 104 | return static_cast(alpha_); 105 | } 106 | 107 | 108 | const ColorMix& Sprite::get_mix() const 109 | { 110 | return mix_; 111 | } 112 | 113 | 114 | Sprite::Size Sprite::get_size() const 115 | { 116 | return static_cast(size_); 117 | } 118 | -------------------------------------------------------------------------------- /source/graphics/view.cpp: -------------------------------------------------------------------------------- 1 | #include "view.hpp" 2 | 3 | 4 | void View::set_center(const Vec2& center) 5 | { 6 | center_ = center; 7 | } 8 | 9 | 10 | void View::set_size(const Vec2& size) 11 | { 12 | size_ = size; 13 | } 14 | 15 | 16 | const Vec2& View::get_center() const 17 | { 18 | return center_; 19 | } 20 | 21 | 22 | const Vec2& View::get_size() const 23 | { 24 | return size_; 25 | } 26 | -------------------------------------------------------------------------------- /source/graphics/view.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | 5 | 6 | class View { 7 | public: 8 | void set_center(const Vec2& center); 9 | 10 | void set_size(const Vec2& size); 11 | 12 | const Vec2& get_center() const; 13 | 14 | const Vec2& get_size() const; 15 | 16 | private: 17 | Vec2 center_; 18 | Vec2 size_; 19 | }; 20 | -------------------------------------------------------------------------------- /source/inventory.cpp: -------------------------------------------------------------------------------- 1 | #include "inventory.hpp" 2 | #include "game.hpp" 3 | #include "graphics/overlay.hpp" 4 | #include "localization.hpp" 5 | #include "state.hpp" 6 | #include "string.hpp" 7 | 8 | 9 | void Inventory::push_item(Platform& pfrm, 10 | Game& game, 11 | Item::Type insert, 12 | bool notify) 13 | { 14 | if (item_is_persistent(insert) and item_count(insert) > 0) { 15 | error(pfrm, "attempt to add duplicate persistent item to inventory"); 16 | return; 17 | } 18 | 19 | if (static_cast(insert) >= static_cast(Item::Type::count)) { 20 | error(pfrm, "attempt to insert invalid item"); 21 | return; 22 | } 23 | 24 | for (auto& item : data_) { 25 | if (item == Item::Type::null) { 26 | item = insert; 27 | 28 | if (notify) { 29 | 30 | auto description = [&]() -> StringBuffer<32> { 31 | if (insert == Item::Type::null) { 32 | // Technically, the description for null is Empty, but that 33 | // doesn't make sense contextually, so lets use this text 34 | // instead. 35 | return locale_string(pfrm, LocaleString::nothing) 36 | ->c_str(); 37 | 38 | } else { 39 | return item_description(pfrm, insert)->c_str(); 40 | } 41 | }(); 42 | 43 | if (not description.empty()) { 44 | 45 | NotificationStr str; 46 | 47 | str += locale_string(pfrm, LocaleString::got_item_before) 48 | ->c_str(); 49 | str += description; 50 | str += locale_string(pfrm, LocaleString::got_item_after) 51 | ->c_str(); 52 | 53 | push_notification(pfrm, game.state(), str); 54 | } 55 | } 56 | return; 57 | } 58 | } 59 | 60 | if (notify) { 61 | NotificationStr str; 62 | str += locale_string(pfrm, LocaleString::inventory_full)->c_str(); 63 | 64 | push_notification(pfrm, game.state(), str); 65 | } 66 | } 67 | 68 | 69 | Float items_collected_percentage(const Inventory& inventory, 70 | std::optional zone) 71 | { 72 | int total_persistent_items = 0; 73 | int collected_persistent_items = 0; 74 | 75 | for (Item::Type item = Item::Type::null; item < Item::Type::count; 76 | item = (Item::Type)((int)item + 1)) { 77 | if (zone) { 78 | const int level = [&] { 79 | switch (*zone) { 80 | case 0: 81 | return boss_0_level - 1; 82 | case 1: 83 | return boss_1_level - 1; 84 | case 2: 85 | return boss_2_level - 1; 86 | case 3: 87 | return boss_3_level - 1; 88 | default: 89 | return 0; 90 | } 91 | }(); 92 | 93 | auto range = level_range(item); 94 | if (not level_in_range(level, range)) { 95 | continue; 96 | } 97 | } 98 | if (item_is_persistent(item)) { 99 | total_persistent_items += 1; 100 | if (inventory.item_count(item) > 0) { 101 | collected_persistent_items += 1; 102 | } 103 | } 104 | } 105 | 106 | if (total_persistent_items not_eq 0) { 107 | return Float(collected_persistent_items) / total_persistent_items; 108 | } else { 109 | return 1.f; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /source/inventory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "entity/details/item.hpp" 4 | #include "number/numeric.hpp" 5 | #include "util.hpp" 6 | #include 7 | 8 | 9 | class Platform; 10 | class Game; 11 | 12 | 13 | class Inventory { 14 | public: 15 | static constexpr const u16 pages = 4; 16 | static constexpr const u16 rows = 2; 17 | static constexpr const u16 cols = 5; 18 | 19 | using ItemInfo = Item::Type; 20 | 21 | void push_item(Platform& pfrm, 22 | Game& game, 23 | Item::Type insert, 24 | bool notify = true); 25 | 26 | inline Item::Type get_item(u16 page, u16 column, u16 row) const 27 | { 28 | if (UNLIKELY(page == pages or column == cols or row == rows)) { 29 | return Item::Type::null; 30 | } 31 | return data_[page * (rows * cols) + row * cols + column]; 32 | } 33 | 34 | inline int item_count(Item::Type item) const 35 | { 36 | int count = 0; 37 | 38 | for (auto& inventory_item : data_) { 39 | if (inventory_item == item) { 40 | count += 1; 41 | } 42 | } 43 | return count; 44 | } 45 | 46 | inline void remove_item(u16 page, u16 column, u16 row) 47 | { 48 | if (UNLIKELY(page == pages or column == cols or row == rows)) { 49 | return; 50 | } 51 | remove_item(&data_[page * (rows * cols) + row * cols + column]); 52 | } 53 | 54 | inline void remove_non_persistent() 55 | { 56 | // NOTE: iterating in reverse would be more efficient, but this isn't a 57 | // frequent operation. 58 | ItemInfo* item = std::begin(data_); 59 | for (; item not_eq std::end(data_);) { 60 | if (not item_is_persistent(*item) and 61 | *item not_eq Item::Type::null and 62 | // NOTE: while the long_jump items are not persistent (story) 63 | // items, the whole point of the long jump items, is that you 64 | // can resume at a certain point after dying, so removing the 65 | // items from the inventory would defeat the purpose in this 66 | // case. 67 | *item not_eq Item::Type::long_jump_z2 and 68 | *item not_eq Item::Type::long_jump_z3 and 69 | *item not_eq Item::Type::long_jump_z4) { 70 | remove_item(item); 71 | } else { 72 | ++item; 73 | } 74 | } 75 | } 76 | 77 | private: 78 | inline void remove_item(ItemInfo* item) 79 | { 80 | for (; item not_eq std::end(data_); ++item) { 81 | if (item + 1 not_eq std::end(data_)) { 82 | new (item) ItemInfo(std::move(*(item + 1))); 83 | } 84 | } 85 | *(std::end(data_) - 1) = ItemInfo{Item::Type::null}; 86 | } 87 | 88 | ItemInfo data_[pages * rows * cols] = {}; 89 | }; 90 | 91 | 92 | Float items_collected_percentage(const Inventory& inventory, 93 | std::optional zone = {}); 94 | -------------------------------------------------------------------------------- /source/list.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "memory/pool.hpp" 6 | 7 | 8 | template struct BiNode { 9 | BiNode* right_; 10 | BiNode* left_; 11 | T data_; 12 | }; 13 | 14 | 15 | template class List { 16 | public: 17 | using Node = BiNode; 18 | using ValueType = T; 19 | 20 | List(Pool& pool) : begin_(nullptr), pool_(&pool) 21 | { 22 | static_assert(sizeof(Node) == Pool::element_size() and 23 | alignof(Node) == Pool::alignment(), 24 | "Pool incompatible"); 25 | } 26 | 27 | List(List&& other) 28 | { 29 | begin_ = other.begin_; 30 | other.begin_ = nullptr; 31 | pool_ = other.pool_; 32 | } 33 | 34 | List(const List&) = delete; 35 | 36 | ~List() 37 | { 38 | clear(); 39 | } 40 | 41 | void push(const T& elem) 42 | { 43 | if (auto mem = pool_->get()) { 44 | new (mem) Node{begin_, nullptr, elem}; 45 | if (begin_) { 46 | begin_->left_ = reinterpret_cast(mem); 47 | } 48 | begin_ = reinterpret_cast(mem); 49 | } 50 | } 51 | 52 | void push(T&& elem) 53 | { 54 | if (auto mem = pool_->get()) { 55 | new (mem) Node{begin_, nullptr, std::forward(elem)}; 56 | if (begin_) { 57 | begin_->left_ = reinterpret_cast(mem); 58 | } 59 | begin_ = reinterpret_cast(mem); 60 | } 61 | } 62 | 63 | void pop() 64 | { 65 | if (begin_) { 66 | auto popped = begin_; 67 | 68 | popped->~Node(); 69 | pool_->post(reinterpret_cast(popped)); 70 | 71 | begin_ = begin_->right_; 72 | if (begin_) { 73 | begin_->left_ = nullptr; 74 | } 75 | } 76 | } 77 | 78 | void clear() 79 | { 80 | while (begin_) 81 | pop(); 82 | } 83 | 84 | bool empty() 85 | { 86 | return begin_ == nullptr; 87 | } 88 | 89 | class Iterator { 90 | public: 91 | Iterator(Node* ptr) : node_(ptr) 92 | { 93 | } 94 | 95 | const Iterator& operator++() 96 | { 97 | node_ = node_->right_; 98 | return *this; 99 | } 100 | 101 | T* operator->() 102 | { 103 | return &node_->data_; 104 | } 105 | 106 | T& operator*() 107 | { 108 | return node_->data_; 109 | } 110 | 111 | // Don't implement operator-- yet! list::end() is implemented in sort of 112 | // a hacky way. 113 | 114 | bool operator==(const Iterator& other) const 115 | { 116 | return other.node_ == node_; 117 | } 118 | 119 | bool operator not_eq(const Iterator& other) const 120 | { 121 | return other.node_ not_eq node_; 122 | } 123 | 124 | Node* node_; 125 | }; 126 | 127 | Iterator erase(Iterator it) 128 | { 129 | if (it.node_->left_) { 130 | it.node_->left_->right_ = it.node_->right_; 131 | } 132 | 133 | if (it.node_->right_) { 134 | it.node_->right_->left_ = it.node_->left_; 135 | } 136 | 137 | if (it.node_ == begin_) { 138 | begin_ = begin_->right_; 139 | } 140 | 141 | auto next = it.node_->right_; 142 | 143 | it.node_->~Node(); 144 | pool_->post(reinterpret_cast(it.node_)); 145 | 146 | return Iterator(next); 147 | } 148 | 149 | Iterator begin() const 150 | { 151 | return Iterator(begin_); 152 | } 153 | 154 | Iterator end() const 155 | { 156 | // NOTE: This technically works, but prevents us from implementing the 157 | // decrement operator on the Iterator. FIXME! 158 | return Iterator(nullptr); 159 | } 160 | 161 | private: 162 | Node* begin_; 163 | Pool* pool_; 164 | }; 165 | 166 | 167 | template u32 length(const List& lat) 168 | { 169 | u32 len = 0; 170 | 171 | for (auto it = lat.begin(); it not_eq lat.end(); ++it) { 172 | ++len; 173 | } 174 | 175 | return len; 176 | } 177 | 178 | 179 | template T* list_ref(List& lat, int i) 180 | { 181 | for (auto& elem : lat) { 182 | if (i == 0) { 183 | return &elem; 184 | } 185 | --i; 186 | } 187 | return nullptr; 188 | } 189 | -------------------------------------------------------------------------------- /source/localeString.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | enum class LocaleString { 5 | empty, 6 | intro_text_1, 7 | intro_text_2, 8 | game_title, 9 | map_legend_1, 10 | map_legend_2, 11 | map_legend_3, 12 | map_legend_4, 13 | map_legend_5, 14 | waypoint_text, 15 | part_1_text, 16 | part_1_title, 17 | part_2_text, 18 | part_2_title, 19 | part_3_text, 20 | part_3_title, 21 | part_4_text, 22 | part_4_title, 23 | empty_inventory_str, 24 | old_poster_title, 25 | worker_notebook_1_title, 26 | worker_notebook_2_title, 27 | engineer_notebook_1_title, 28 | engineer_notebook_2_title, 29 | blaster_title, 30 | accelerator_title, 31 | lethargy_title, 32 | map_system_title, 33 | explosive_rounds_title, 34 | signal_jammer_title, 35 | seed_packet_title, 36 | navigation_pamphlet_title, 37 | orange_title, 38 | orange_seeds_title, 39 | postal_advert_title, 40 | long_jump_z2_title, 41 | long_jump_z3_title, 42 | long_jump_z4_title, 43 | sc_dialog_skip, 44 | sc_dialog_accelerator, 45 | sc_dialog_lethargy, 46 | sc_dialog_map_system, 47 | sc_dialog_explosive_rounds, 48 | sc_dialog_signal_jammer, 49 | sc_dialog_orange, 50 | sc_dialog_jumpdrive, 51 | single_use_warning, 52 | locked, 53 | peer_too_close_to_item, 54 | enemies_remaining_singular, 55 | enemies_remaining_plural, 56 | nothing, 57 | got_item_before, 58 | got_item_after, 59 | inventory_full, 60 | items, 61 | level_clear, 62 | score, 63 | high_score, 64 | high_scores, 65 | time, 66 | items_collected_prefix, 67 | items_collected_suffix, 68 | items_collected_heading, 69 | waypoints, 70 | punctuation_period, 71 | menu_resume, 72 | menu_connect_peer, 73 | menu_settings, 74 | menu_console, 75 | menu_save_and_quit, 76 | goodbye_text, 77 | select_target_text, 78 | navigation_pamphlet, 79 | settings_show_stats, 80 | settings_language, 81 | settings_contrast, 82 | settings_night_mode, 83 | settings_swap_action_keys, 84 | settings_default, 85 | settings_difficulty, 86 | settings_difficulty_easy, 87 | settings_difficulty_normal, 88 | settings_difficulty_hard, 89 | settings_difficulty_survival, 90 | settings_difficulty_err, 91 | settings_log_severity, 92 | settings_speedrun_clock, 93 | yes, 94 | no, 95 | menu_disabled, 96 | distance_units_feet, 97 | launch, 98 | peer_connected, 99 | peer_connection_failed, 100 | peer_lost, 101 | peer_health_changed, 102 | level_transition_awaiting_peers, 103 | level_transition_synchronizing, 104 | fps_stats_suffix, 105 | network_tx_stats_suffix, 106 | network_rx_stats_suffix, 107 | network_tx_loss_stats_suffix, 108 | network_rx_loss_stats_suffix, 109 | scratch_buf_avail_stats_suffix, 110 | link_saturation_stats_suffix, 111 | map_required, 112 | boss0_defeated, 113 | boss1_defeated, 114 | boss2_defeated, 115 | peer_transport_waiting, 116 | severity_debug, 117 | severity_info, 118 | severity_warning, 119 | severity_error, 120 | power_surge_detected, 121 | store_buy_items, 122 | store_sell_items, 123 | store_buy, 124 | store_sell, 125 | store_info, 126 | scavenger_store, 127 | buy, 128 | sell, 129 | update_required, 130 | peer_requires_update, 131 | overall_heading, 132 | peer_used_lethargy, 133 | language_name, 134 | health_safety_notice, 135 | health_safety_text, 136 | chat_chat, 137 | chat_hello, 138 | chat_q_got_oranges, 139 | chat_lets_go, 140 | chat_found_health, 141 | scavenger_shop, 142 | memorial_str, 143 | memorial_str_commentary, 144 | worker_notebook_1_str, 145 | worker_notebook_2_str, 146 | engineer_notebook_1_str, 147 | engineer_notebook_2_str, 148 | count 149 | }; 150 | -------------------------------------------------------------------------------- /source/localization.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "bulkAllocator.hpp" 5 | #include "dateTime.hpp" 6 | #include "localeString.hpp" 7 | #include "string.hpp" 8 | 9 | 10 | void locale_set_language(int language_id); 11 | void locale_set_language_english(); 12 | int locale_get_language(); 13 | 14 | 15 | using LocalizedStrBuffer = StringBuffer<1187>; 16 | using LocalizedText = DynamicMemory; 17 | LocalizedText locale_string(Platform& pfrm, LocaleString ls); 18 | 19 | 20 | // In most cases, you do not want to call this function directly, better to call 21 | // the localized version, locale_num2str. Only call english__to_string for 22 | // logging purposes, where the language is assumed to be english. 23 | void english__to_string(int num, char* buffer, int base); 24 | 25 | 26 | void locale_num2str(int num, char* buffer, int base); 27 | 28 | 29 | template 30 | void format_time(StringBuffer& str, const DateTime& dt) 31 | { 32 | char buffer[48]; 33 | 34 | locale_num2str(dt.date_.month_, buffer, 10); 35 | str += buffer; 36 | str += "/"; 37 | 38 | locale_num2str(dt.date_.day_, buffer, 10); 39 | str += buffer; 40 | str += "/"; 41 | 42 | locale_num2str(dt.date_.year_, buffer, 10); 43 | str += buffer; 44 | str += " "; 45 | 46 | locale_num2str(dt.hour_, buffer, 10); 47 | str += buffer; 48 | str += ":"; 49 | 50 | locale_num2str(dt.minute_, buffer, 10); 51 | str += buffer; 52 | str += ":"; 53 | 54 | locale_num2str(dt.second_, buffer, 10); 55 | str += buffer; 56 | } 57 | 58 | 59 | template 60 | void log_format_time(StringBuffer& str, const DateTime& dt) 61 | { 62 | const auto saved_language = locale_get_language(); 63 | locale_set_language(1); 64 | 65 | format_time(str, dt); 66 | 67 | locale_set_language(saved_language); 68 | } 69 | -------------------------------------------------------------------------------- /source/memory/memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "buffer.hpp" 4 | #include "pool.hpp" 5 | #include "rc.hpp" 6 | -------------------------------------------------------------------------------- /source/memory/pool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | #include 5 | #include 6 | 7 | 8 | template class Pool { 9 | public: 10 | struct Cell { 11 | alignas(align) std::array mem_; 12 | Cell* next_; 13 | }; 14 | 15 | 16 | Pool() : freelist_(nullptr) 17 | { 18 | for (decltype(count) i = 0; i < count; ++i) { 19 | Cell* next = &cells_[i]; 20 | next->next_ = freelist_; 21 | freelist_ = next; 22 | } 23 | } 24 | 25 | Pool(const Pool&) = delete; 26 | 27 | byte* get() 28 | { 29 | if (freelist_) { 30 | const auto ret = freelist_; 31 | freelist_ = freelist_->next_; 32 | return (byte*)ret; 33 | } else { 34 | return nullptr; 35 | } 36 | } 37 | 38 | void post(byte* mem) 39 | { 40 | auto cell = (Cell*)mem; 41 | cell->next_ = freelist_; 42 | freelist_ = cell; 43 | } 44 | 45 | static constexpr u32 element_size() 46 | { 47 | return size; 48 | } 49 | 50 | static constexpr u32 alignment() 51 | { 52 | return align; 53 | } 54 | 55 | using Cells = std::array; 56 | Cells& cells() 57 | { 58 | return cells_; 59 | } 60 | 61 | u32 remaining() const 62 | { 63 | const Cell* current = freelist_; 64 | int n = 0; 65 | while (current) { 66 | current = current->next_; 67 | ++n; 68 | } 69 | return n; 70 | } 71 | 72 | bool empty() const 73 | { 74 | return freelist_ == nullptr; 75 | } 76 | 77 | private: 78 | Cells cells_; 79 | Cell* freelist_; 80 | }; 81 | 82 | 83 | template class ObjectPool { 84 | public: 85 | template T* get(Args&&... args) 86 | { 87 | auto mem = pool_.get(); 88 | if (mem) { 89 | new (mem) T(std::forward(args)...); 90 | return reinterpret_cast(mem); 91 | } else { 92 | return nullptr; 93 | } 94 | } 95 | 96 | void post(T* obj) 97 | { 98 | obj->~T(); 99 | pool_.post((byte*)obj); 100 | } 101 | 102 | u32 remaining() const 103 | { 104 | return pool_.remaining(); 105 | } 106 | 107 | bool empty() const 108 | { 109 | return pool_.empty(); 110 | } 111 | 112 | using _Pool = Pool; 113 | using Cells = typename _Pool::Cells; 114 | 115 | Cells& cells() 116 | { 117 | return pool_.cells(); 118 | } 119 | 120 | template void scan_cells(F&& callback) 121 | { 122 | auto& mem = pool_.cells(); 123 | for (auto& cell : mem) { 124 | T* obj = reinterpret_cast(cell.mem_.data()); 125 | callback(obj); 126 | } 127 | } 128 | 129 | private: 130 | _Pool pool_; 131 | }; 132 | -------------------------------------------------------------------------------- /source/memory/rc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | #include "pool.hpp" 5 | #include 6 | 7 | 8 | // 9 | // A class for Reference Counted objects. 10 | // 11 | // This program targets embedded systems, and intentionally doesn't 12 | // link with the C++ standard library (although we use some standard 13 | // headers, like ). Otherwise I might use 14 | // std::shared_ptr... Rc differs from the standard smart pointers in a 15 | // few other ways though: 16 | // 1) No upcasting. 17 | // 2) Can not contain null. 18 | // 19 | // Additionally, you need to supply a memory pool when creating an Rc<>. 20 | // 21 | 22 | 23 | template class RcBase { 24 | public: 25 | size_t strong_count() const 26 | { 27 | return control_->strong_count_; 28 | } 29 | 30 | struct ControlBlock { 31 | template 32 | ControlBlock(ObjectPool* pool, 33 | void (*finalizer_hook)(ControlBlock*), 34 | Args&&... args) 35 | : data_(std::forward(args)...), pool_(pool), 36 | finalizer_hook_(finalizer_hook), strong_count_(0), weak_count_(0) 37 | { 38 | if (finalizer_hook_ == nullptr) { 39 | finalizer_hook_ = [](ControlBlock* ctrl) { 40 | ctrl->pool_->post(ctrl); 41 | }; 42 | } 43 | } 44 | 45 | T data_; 46 | ObjectPool* pool_; 47 | // Because the pool is an input parameter, I do not see much reason to 48 | // allow custom finalizers, but in any event, having the option to 49 | // customize deallocation might be useful in some unforseen way. 50 | void (*finalizer_hook_)(ControlBlock*); 51 | Atomic strong_count_; 52 | Atomic weak_count_; 53 | }; 54 | 55 | protected: 56 | ControlBlock* control_; 57 | 58 | void add_strong(ControlBlock* source) 59 | { 60 | control_ = source; 61 | control_->strong_count_++; 62 | } 63 | 64 | void add_weak(ControlBlock* source) 65 | { 66 | control_ = source; 67 | control_->weak_count_++; 68 | } 69 | 70 | void remove_strong() 71 | { 72 | if (--control_->strong_count_ == 0 and control_->weak_count_ == 0) { 73 | control_->finalizer_hook_(control_); 74 | } 75 | } 76 | 77 | void remove_weak() 78 | { 79 | if (--control_->weak_count_ == 0 and control_->strong_count_ == 0) { 80 | control_->finalizer_hook_(control_); 81 | } 82 | } 83 | }; 84 | 85 | 86 | template class Rc : public RcBase { 87 | public: 88 | using Super = RcBase; 89 | 90 | Rc(const Rc& other) 91 | { 92 | Super::add_strong(other.control_); 93 | } 94 | 95 | Rc& operator=(const Rc& other) 96 | { 97 | if (Super::control_) { 98 | Super::remove_strong(); 99 | } 100 | Super::add_strong(other.control_); 101 | return *this; 102 | } 103 | 104 | T& operator*() const 105 | { 106 | return Super::control_->data_; 107 | } 108 | 109 | T* operator->() const 110 | { 111 | return &Super::control_->data_; 112 | } 113 | 114 | T* get() const 115 | { 116 | return &Super::control_->data_; 117 | } 118 | 119 | ~Rc() 120 | { 121 | Super::remove_strong(); 122 | } 123 | 124 | template 125 | static std::optional 126 | create(ObjectPool::ControlBlock, Count>* pool, 127 | void (*finalizer_hook)(typename RcBase::ControlBlock*), 128 | Args&&... args) 129 | { 130 | auto ctrl = 131 | pool->get(pool, finalizer_hook, std::forward(args)...); 132 | if (ctrl) { 133 | return Rc(ctrl); 134 | } else { 135 | return {}; 136 | } 137 | } 138 | 139 | private: 140 | Rc(typename Super::ControlBlock* control) 141 | { 142 | Super::add_strong(control); 143 | } 144 | 145 | template friend class Weak; 146 | }; 147 | 148 | 149 | template class Weak : public RcBase { 150 | public: 151 | using Super = RcBase; 152 | 153 | Weak() = delete; 154 | 155 | Weak(const Rc& other) 156 | { 157 | Super::add_weak(other.control_); 158 | } 159 | 160 | std::optional> upgrade() 161 | { 162 | if (Super::control_->strong_count_) { 163 | return Rc(Super::control_); 164 | } else { 165 | return {}; 166 | } 167 | } 168 | 169 | ~Weak() 170 | { 171 | Super::remove_weak(); 172 | } 173 | }; 174 | -------------------------------------------------------------------------------- /source/network_event.cpp: -------------------------------------------------------------------------------- 1 | #include "network_event.hpp" 2 | #include "platform/platform.hpp" 3 | 4 | 5 | namespace net_event { 6 | 7 | 8 | void poll_messages(Platform& pfrm, Game& game, Listener& listener) 9 | { 10 | while (auto message = pfrm.network_peer().poll_message()) { 11 | if (message->length_ < sizeof(Header)) { 12 | return; 13 | } 14 | Header header; 15 | memcpy(&header, message->data_, sizeof header); 16 | 17 | switch (header.message_type_) { 18 | case Header::null: 19 | pfrm.network_peer().poll_consume(sizeof(Header)); 20 | continue; 21 | 22 | #define HANDLE_MESSAGE(MESSAGE_TYPE) \ 23 | case MESSAGE_TYPE::mt: { \ 24 | NET_EVENT_SIZE_CHECK(MESSAGE_TYPE) \ 25 | if (message->length_ < sizeof(MESSAGE_TYPE)) { \ 26 | return; \ 27 | } \ 28 | MESSAGE_TYPE m; \ 29 | memcpy(&m, message->data_, sizeof m); \ 30 | pfrm.network_peer().poll_consume(sizeof(MESSAGE_TYPE)); \ 31 | listener.receive(m, pfrm, game); \ 32 | continue; \ 33 | } 34 | 35 | HANDLE_MESSAGE(EnemyStateSync) 36 | HANDLE_MESSAGE(PlayerEnteredGate) 37 | HANDLE_MESSAGE(PlayerHealthChanged) 38 | HANDLE_MESSAGE(ItemTaken) 39 | HANDLE_MESSAGE(PlayerInfo) 40 | HANDLE_MESSAGE(EnemyHealthChanged) 41 | HANDLE_MESSAGE(NewLevelIdle) 42 | HANDLE_MESSAGE(SyncSeed) 43 | HANDLE_MESSAGE(NewLevelSyncSeed) 44 | HANDLE_MESSAGE(ItemChestOpened) 45 | HANDLE_MESSAGE(ItemChestShared) 46 | HANDLE_MESSAGE(QuickChat) 47 | HANDLE_MESSAGE(PlayerSpawnLaser) 48 | HANDLE_MESSAGE(PlayerDied) 49 | HANDLE_MESSAGE(DataStreamAvail) 50 | HANDLE_MESSAGE(DataStreamReadResponse) 51 | HANDLE_MESSAGE(DataStreamReadRequest) 52 | HANDLE_MESSAGE(DataStreamDoneReading) 53 | HANDLE_MESSAGE(ProgramVersion) 54 | HANDLE_MESSAGE(LethargyActivated) 55 | } 56 | 57 | error(pfrm, "garbled message!?"); 58 | pfrm.network_peer().disconnect(); 59 | return; 60 | } 61 | } 62 | 63 | } // namespace net_event 64 | -------------------------------------------------------------------------------- /source/number/endian.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "numeric.hpp" 4 | 5 | // Because most processors are little endian, I am using little endian byte 6 | // order for binary encoded data. 7 | 8 | 9 | #ifdef __bswap_constant_16 10 | #undef __bswap_constant_16 11 | #endif 12 | #define __bswap_constant_16(x) ((u16)((((x) >> 8) & 0xff) | (((x)&0xff) << 8))) 13 | 14 | #ifdef __bswap_constant_32 15 | #undef __bswap_constant_32 16 | #endif 17 | #define __bswap_constant_32(x) \ 18 | ((((x)&0xff000000) >> 24) | (((x)&0x00ff0000) >> 8) | \ 19 | (((x)&0x0000ff00) << 8) | (((x)&0x000000ff) << 24)) 20 | 21 | #ifdef __bswap_constant_64 22 | #undef __bswap_constant_64 23 | #endif 24 | #define __bswap_constant_64(x) \ 25 | ((((x)&0xff00000000000000ull) >> 56) | \ 26 | (((x)&0x00ff000000000000ull) >> 40) | \ 27 | (((x)&0x0000ff0000000000ull) >> 24) | \ 28 | (((x)&0x000000ff00000000ull) >> 8) | (((x)&0x00000000ff000000ull) << 8) | \ 29 | (((x)&0x0000000000ff0000ull) << 24) | \ 30 | (((x)&0x000000000000ff00ull) << 40) | \ 31 | (((x)&0x00000000000000ffull) << 56)) 32 | 33 | 34 | #ifdef __GBA__ 35 | inline bool is_little_endian() 36 | { 37 | return true; 38 | } 39 | #else 40 | inline bool is_little_endian() 41 | { 42 | static const u16 i = 0x000f; 43 | return ((u8*)&i)[0] == 0x0f; 44 | } 45 | #endif 46 | 47 | extern "C" { 48 | using size_t = decltype(sizeof(int)); // If only I wasn't too lazy to look up 49 | // which header it's defined in 50 | void* memcpy(void* destination, const void* source, size_t num) noexcept; 51 | } 52 | 53 | 54 | template T to_host_order(T value); 55 | 56 | 57 | template <> inline u8 to_host_order(u8 val) 58 | { 59 | return val; 60 | } 61 | 62 | template <> inline u16 to_host_order(u16 val) 63 | { 64 | if (is_little_endian()) { 65 | return val; 66 | } else { 67 | return __bswap_constant_16(val); 68 | } 69 | } 70 | 71 | template <> inline s16 to_host_order(s16 val) 72 | { 73 | if (is_little_endian()) { 74 | return val; 75 | } else { 76 | return __bswap_constant_16(val); 77 | } 78 | } 79 | 80 | template <> inline u32 to_host_order(u32 val) 81 | { 82 | if (is_little_endian()) { 83 | return val; 84 | } else { 85 | return __bswap_constant_32(val); 86 | } 87 | } 88 | 89 | template <> inline s32 to_host_order(s32 val) 90 | { 91 | if (is_little_endian()) { 92 | return val; 93 | } else { 94 | return __bswap_constant_32(val); 95 | } 96 | } 97 | 98 | template <> inline u64 to_host_order(u64 val) 99 | { 100 | if (is_little_endian()) { 101 | return val; 102 | } else { 103 | return __bswap_constant_64(val); 104 | } 105 | } 106 | 107 | template <> inline s64 to_host_order(s64 val) 108 | { 109 | if (is_little_endian()) { 110 | return val; 111 | } else { 112 | return __bswap_constant_64(val); 113 | } 114 | } 115 | 116 | 117 | template class HostInteger { 118 | public: 119 | // NOTE: I could overload the cast operator and assignment operators to make 120 | // this class behave similarly to a plain integer. But then I get 121 | // class-memaccess errors, which I don't want to disable throughout the 122 | // project... calling get()/set() isn't so bad. 123 | 124 | HostInteger() = default; 125 | 126 | explicit HostInteger(T value) 127 | { 128 | set(value); 129 | } 130 | 131 | void set(T value) 132 | { 133 | value = to_host_order(value); 134 | memcpy(data_, &value, sizeof(T)); 135 | } 136 | 137 | T get() const 138 | { 139 | T value; 140 | memcpy(&value, data_, sizeof(T)); 141 | return to_host_order(value); 142 | } 143 | 144 | private: 145 | char data_[sizeof(T)]; 146 | }; 147 | 148 | 149 | using host_u16 = HostInteger; 150 | using host_u32 = HostInteger; 151 | using host_s16 = HostInteger; 152 | using host_s32 = HostInteger; 153 | using host_u64 = HostInteger; 154 | using host_s64 = HostInteger; 155 | -------------------------------------------------------------------------------- /source/number/int.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | typedef int8_t s8; 11 | typedef int16_t s16; 12 | typedef int32_t s32; 13 | typedef int64_t s64; 14 | -------------------------------------------------------------------------------- /source/number/numeric.cpp: -------------------------------------------------------------------------------- 1 | #include "numeric.hpp" 2 | 3 | // I shamelessly took these trig functions from the internet. 4 | 5 | #define INT16_BITS (8 * sizeof(int16_t)) 6 | #ifndef INT16_MAX 7 | #define INT16_MAX ((1 << (INT16_BITS - 1)) - 1) 8 | #endif 9 | 10 | #define TABLE_BITS (5) 11 | #define TABLE_SIZE (1 << TABLE_BITS) 12 | #define TABLE_MASK (TABLE_SIZE - 1) 13 | 14 | #define LOOKUP_BITS (TABLE_BITS + 2) 15 | #define LOOKUP_MASK ((1 << LOOKUP_BITS) - 1) 16 | #define FLIP_BIT (1 << TABLE_BITS) 17 | #define NEGATE_BIT (1 << (TABLE_BITS + 1)) 18 | #define INTERP_BITS (INT16_BITS - 1 - LOOKUP_BITS) 19 | #define INTERP_MASK ((1 << INTERP_BITS) - 1) 20 | 21 | static int16_t sin90[TABLE_SIZE + 1] = { 22 | 0x0000, 0x0647, 0x0c8b, 0x12c7, 0x18f8, 0x1f19, 0x2527, 0x2b1e, 0x30fb, 23 | 0x36b9, 0x3c56, 0x41cd, 0x471c, 0x4c3f, 0x5133, 0x55f4, 0x5a81, 0x5ed6, 24 | 0x62f1, 0x66ce, 0x6a6c, 0x6dc9, 0x70e1, 0x73b5, 0x7640, 0x7883, 0x7a7c, 25 | 0x7c29, 0x7d89, 0x7e9c, 0x7f61, 0x7fd7, 0x7fff}; 26 | 27 | s16 sine(s16 angle) 28 | { 29 | s16 v0, v1; 30 | if (angle < 0) { 31 | angle += INT16_MAX; 32 | angle += 1; 33 | } 34 | v0 = (angle >> INTERP_BITS); 35 | if (v0 & FLIP_BIT) { 36 | v0 = ~v0; 37 | v1 = ~angle; 38 | } else { 39 | v1 = angle; 40 | } 41 | v0 &= TABLE_MASK; 42 | v1 = sin90[v0] + 43 | (s16)(((int32_t)(sin90[v0 + 1] - sin90[v0]) * (v1 & INTERP_MASK)) >> 44 | INTERP_BITS); 45 | if ((angle >> INTERP_BITS) & NEGATE_BIT) 46 | v1 = -v1; 47 | return v1; 48 | } 49 | 50 | s16 cosine(s16 angle) 51 | { 52 | if (angle < 0) { 53 | angle += INT16_MAX; 54 | angle += 1; 55 | } 56 | return sine(angle - s16((270.f / 360.f) * INT16_MAX)); 57 | } 58 | -------------------------------------------------------------------------------- /source/number/random.cpp: -------------------------------------------------------------------------------- 1 | #include "random.hpp" 2 | 3 | 4 | rng::LinearGenerator rng::critical_state; 5 | rng::LinearGenerator rng::utility_state; 6 | 7 | 8 | rng::Value rng::get(LinearGenerator& gen) 9 | { 10 | gen = 1664525 * gen + 1013904223; 11 | return (gen >> 16) & 0x7FFF; 12 | } 13 | -------------------------------------------------------------------------------- /source/number/random.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "memory/buffer.hpp" 5 | #include "numeric.hpp" 6 | 7 | 8 | namespace rng { 9 | 10 | using Value = s32; 11 | using LinearGenerator = Value; 12 | 13 | // NOTE: This state should be used for level generation, and for the internal 14 | // state machines for enemies. This state needs to be tightly synchronized 15 | // between multiplayer peers, so do not use this generator for visual effects, 16 | // game state changes only! 17 | extern LinearGenerator critical_state; 18 | 19 | // NOTE: use the utility state whenever you need a random value, and you don't 20 | // care whether the value is synchronized across multiplayer games. 21 | extern LinearGenerator utility_state; 22 | 23 | 24 | Value get(LinearGenerator& gen); 25 | 26 | 27 | template Value choice(LinearGenerator& gen) 28 | { 29 | return get(gen) % N; 30 | } 31 | 32 | 33 | inline Value choice(Value n, LinearGenerator& gen) 34 | { 35 | return get(gen) % n; 36 | } 37 | 38 | 39 | template Float sample(Float n, LinearGenerator& gen) 40 | { 41 | if (choice<2>(gen)) { 42 | return n + Float(choice(gen)); 43 | 44 | } else { 45 | return n - Float(choice(gen)); 46 | } 47 | } 48 | 49 | 50 | template 51 | Vec2 sample(const Vec2& position, LinearGenerator& gen) 52 | { 53 | auto result = position; 54 | 55 | result.x = sample(result.x, gen); 56 | result.y = sample(result.y, gen); 57 | 58 | return result; 59 | } 60 | 61 | 62 | template 63 | void shuffle(Buffer& buffer, LinearGenerator& gen) 64 | { 65 | int i; 66 | const int n = buffer.size(); 67 | for (i = n - 1; i > 0; --i) { 68 | std::swap(buffer[i], buffer[get(gen) % (i + 1)]); 69 | } 70 | } 71 | 72 | 73 | } // namespace rng 74 | -------------------------------------------------------------------------------- /source/path.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "bulkAllocator.hpp" 4 | #include "tileMap.hpp" 5 | #include 6 | #include 7 | 8 | 9 | // 10 | // NOTE: This pathfinding code is only really suitable for level generation, and 11 | // other infrequent operations. Some systems are simply not fast enough to run 12 | // pathfinding in realtime, although you could perhaps cache a few generic paths 13 | // between evenly distributed positions within a level... 14 | // 15 | 16 | 17 | // NOTE: Perhaps we could make this even smaller... in practice, a path will 18 | // never run through every possible coordinate in a level, and a level with no 19 | // gaps whatsoever is unlikely to be generated in the first place... 20 | // 21 | // Also, we do not generate tiles for the borders of the map. 22 | static constexpr const auto max_path = 23 | (TileMap::width - 2) * (TileMap::height - 2) - 4; 24 | 25 | 26 | using PathCoord = Vec2; 27 | using PathBuffer = Buffer; 28 | 29 | 30 | std::optional> find_path(Platform& pfrm, 31 | TileMap& tiles, 32 | const PathCoord& start, 33 | const PathCoord& end); 34 | 35 | 36 | static constexpr const auto vertex_scratch_buffers = 3; 37 | 38 | 39 | struct IncrementalPathfinder { 40 | IncrementalPathfinder(Platform& pfrm, 41 | TileMap& tiles, 42 | const PathCoord& start, 43 | const PathCoord& end); 44 | 45 | std::optional> 46 | compute(Platform& pfrm, int max_iters, bool* incomplete); 47 | 48 | private: 49 | struct PathVertexData { 50 | PathCoord coord_; 51 | u16 dist_ = std::numeric_limits::max(); 52 | PathVertexData* prev_ = nullptr; 53 | }; 54 | 55 | using VertexBuf = Buffer; 56 | 57 | // note: does not include the last row and column of the map grid, in order 58 | // to save memory, and to make the matrix fit in a 1k allocation for the 59 | // GBA. Technically, we don't need the first row or column either, but 60 | // excluding them complicates indexing. We're using the vertex mat to speed 61 | // up neighbor calculation, otherwise, we have to scan through all of the 62 | // nodes in the priority q whenever we need to find which nodes are 63 | // neighbors. One could attach a list of neighbors to every vertex, but I 64 | // tried doing this, and you end up doing a bunch of unnecessary work (for 65 | // vertices which we will never visit), and using a lot more memory. 66 | using VertexMat = 67 | PathVertexData * [(TileMap::width - 1)][(TileMap::height - 1)]; 68 | 69 | 70 | Buffer neighbors(PathVertexData* data) const; 71 | 72 | void sort_q(); 73 | 74 | 75 | BulkAllocator memory_; 76 | DynamicMemory priority_q_; 77 | DynamicMemory map_matrix_; 78 | PathCoord end_; 79 | }; 80 | -------------------------------------------------------------------------------- /source/persistentData.cpp: -------------------------------------------------------------------------------- 1 | #include "persistentData.hpp" 2 | #include "platform/platform.hpp" 3 | 4 | 5 | PersistentData& PersistentData::reset(Platform& pfrm) 6 | { 7 | inventory_.remove_non_persistent(); 8 | level_.set(0); 9 | score_.set(0); 10 | player_health_.set(3); 11 | powerup_count_.set(0); 12 | speedrun_clock_.reset(0); 13 | 14 | return *this; 15 | } 16 | 17 | 18 | void PersistentData::store_powerups(const Powerups& powerups) 19 | { 20 | std::copy(powerups.begin(), powerups.end(), powerups_.begin()); 21 | powerup_count_.set(powerups.size()); 22 | } 23 | -------------------------------------------------------------------------------- /source/persistentData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "dateTime.hpp" 5 | #include "entity/entity.hpp" 6 | #include "inventory.hpp" 7 | #include "number/endian.hpp" 8 | #include "number/numeric.hpp" 9 | #include "powerup.hpp" 10 | #include "settings.hpp" 11 | #include "timeTracker.hpp" 12 | 13 | 14 | using Level = s32; 15 | using Score = u32; 16 | 17 | 18 | class Platform; 19 | 20 | 21 | // NOTE: Nothing but plain bytes should be stored in the PersistentData 22 | // structure. HostInteger stores its contents as a u8 array, which eliminates 23 | // structure packing headaches. The Inventory class, Settings class, powerup 24 | // class, etc., all store either HostIntegers, or enums derived from u8. 25 | // 26 | // Additionally, you should be using the fixed width datatypes for everything, 27 | // i.e. s32 instead of a plain int. 28 | // 29 | // The game more-or-less memcpy's the contents of the PersistentData structure 30 | // to the save data target device (whether that be a file on disk, or GBA sram), 31 | // so we need to be careful about anything that might vary across different 32 | // compilers, processors, etc. 33 | // 34 | // Remember that we're using a binary format here! If you change the structure 35 | // of the PersistentData struct, the game may try to incorrectly read existing 36 | // save data files belonging to users who upgraded from an old version of the 37 | // game. So, when you make any changes whatsoever to the layout of the 38 | // PersistentData class, remember to increment the schema_version constant. 39 | 40 | 41 | struct PersistentData { 42 | using Magic = u32; 43 | 44 | static constexpr u32 schema_version = 5; 45 | static constexpr Magic magic_val = 0xCA55E77E + schema_version; 46 | 47 | PersistentData() 48 | { 49 | magic_.set(magic_val); 50 | seed_.set(11001); 51 | level_.set(0); 52 | score_.set(0); 53 | player_health_.set(3); 54 | 55 | for (auto& hs : highscores_) { 56 | hs.set(0); 57 | } 58 | 59 | powerup_count_.set(0); 60 | } 61 | 62 | HostInteger magic_; 63 | HostInteger seed_; 64 | HostInteger level_; 65 | HostInteger score_; 66 | HostInteger player_health_; 67 | 68 | using HighScores = HostInteger[8]; 69 | HighScores highscores_; 70 | 71 | Inventory inventory_; 72 | 73 | std::array powerups_; 74 | HostInteger powerup_count_; 75 | 76 | Settings settings_; 77 | 78 | DateTime timestamp_ = {{0, 0, 0}, 0, 0, 0}; 79 | 80 | TimeTracker speedrun_clock_ = {0}; 81 | 82 | bool displayed_health_warning_ = false; 83 | 84 | // This save block has never been written. 85 | bool clean_ = true; 86 | 87 | void store_powerups(const Powerups& powerups); 88 | 89 | // Reset level back to zero, initialize various things. Does not overwrite 90 | // the seed value, or the highscore table. 91 | PersistentData& reset(Platform& pfrm); 92 | }; 93 | -------------------------------------------------------------------------------- /source/platform/desktop/resource_path.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if defined(_WIN32) or defined(_WIN64) 5 | #include 6 | std::string resource_path() 7 | { 8 | static std::string result; 9 | if (result.empty()) { 10 | HMODULE hModule = GetModuleHandleW(nullptr); 11 | char buffer[MAX_PATH]; 12 | GetModuleFileName(hModule, buffer, MAX_PATH); 13 | const std::string path(buffer); 14 | const std::size_t last_fwd_slash = path.find_last_of('\\'); 15 | std::string path_without_binary = path.substr(0, last_fwd_slash + 1); 16 | result = path_without_binary + "..\\..\\"; 17 | } 18 | return result; 19 | } 20 | 21 | #elif defined(__APPLE__) 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | std::string resource_path() 28 | { 29 | id pool = reinterpret_cast(objc_getClass("NSAutoreleasePool")); 30 | std::string rpath; 31 | if (not pool) { 32 | return rpath; 33 | } 34 | pool = ((id(*)(id, SEL))objc_msgSend)(pool, sel_registerName("alloc")); 35 | if (not pool) { 36 | return rpath; 37 | } 38 | pool = ((id(*)(id, SEL))objc_msgSend)(pool, sel_registerName("init")); 39 | id bundle = ((id(*)(id, SEL))objc_msgSend)( 40 | reinterpret_cast(objc_getClass("NSBundle")), 41 | sel_registerName("mainBundle")); 42 | if (bundle) { 43 | id path = ((id(*)(id, SEL))objc_msgSend)( 44 | bundle, sel_registerName("resourcePath")); 45 | rpath = reinterpret_cast(((id(*)(id, SEL))objc_msgSend)( 46 | path, sel_registerName("UTF8String"))) + 47 | std::string("/"); 48 | } 49 | ((id(*)(id, SEL))objc_msgSend)(pool, sel_registerName("drain")); 50 | return rpath + "../"; 51 | } 52 | 53 | #elif __linux__ 54 | #include 55 | #include 56 | 57 | std::string resource_path() 58 | { 59 | static std::string result; 60 | if (result.empty()) { 61 | char buffer[PATH_MAX]; 62 | for (int i = 0; i < PATH_MAX; ++i) { 63 | buffer[i] = '\0'; 64 | } 65 | [[gnu::unused]] const std::size_t bytes_read = 66 | readlink("/proc/self/exe", buffer, sizeof(buffer)); 67 | 68 | buffer[PATH_MAX - 1] = '\0'; 69 | const std::string path(buffer); 70 | const std::size_t last_fwd_slash = path.find_last_of("/"); 71 | std::string path_without_binary = path.substr(0, last_fwd_slash + 1); 72 | result = path_without_binary + "../"; 73 | } 74 | return result; 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /source/platform/gba/bios_math.s: -------------------------------------------------------------------------------- 1 | .text 2 | .code 16 3 | 4 | @--------------------------------------------------------------------------------- 5 | .global Div 6 | .thumb_func 7 | @--------------------------------------------------------------------------------- 8 | Div: 9 | @--------------------------------------------------------------------------------- 10 | swi 6 11 | bx lr 12 | 13 | @--------------------------------------------------------------------------------- 14 | .global DivMod 15 | .thumb_func 16 | @--------------------------------------------------------------------------------- 17 | DivMod: 18 | @--------------------------------------------------------------------------------- 19 | swi 6 20 | mov r0, r1 21 | bx lr 22 | 23 | @--------------------------------------------------------------------------------- 24 | .global DivAbs 25 | .thumb_func 26 | @--------------------------------------------------------------------------------- 27 | DivAbs: 28 | @--------------------------------------------------------------------------------- 29 | swi 6 30 | mov r0, r3 31 | bx lr 32 | -------------------------------------------------------------------------------- /source/platform/gba/files.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | static const struct { 5 | const char* root_; 6 | const char* name_; 7 | const unsigned char* data_; 8 | } files[] = { 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /source/platform/gba/gba_arm_routines.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // All of the code in this file will be compiled as arm code, and placed in the 4 | // IWRAM section of the executable. The system has limited memory for IWRAM 5 | // calls, so limit this file to performace critical code, or code that must be 6 | // defined in IWRAM. 7 | // 8 | //////////////////////////////////////////////////////////////////////////////// 9 | 10 | 11 | #ifdef __GBA__ 12 | #define IWRAM_CODE __attribute__((section(".iwram"), long_call)) 13 | #else 14 | #define IWRAM_CODE 15 | #endif // __GBA__ 16 | 17 | 18 | #include "gba.h" 19 | 20 | // Because the cartridge interrupt handler runs when the cartridge is removed, 21 | // it obviously cannot be defined in gamepak rom! So we have to put the code in 22 | // IWRAM. 23 | IWRAM_CODE 24 | void cartridge_interrupt_handler() 25 | { 26 | Stop(); 27 | } 28 | -------------------------------------------------------------------------------- /source/platform/gba/gba_color.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "graphics/color.hpp" 4 | #include "number/numeric.hpp" 5 | 6 | 7 | class Color { 8 | public: 9 | Color(ColorConstant k) 10 | { 11 | const auto val = static_cast(k); 12 | r_ = (val & 0xFF0000) >> 16; 13 | g_ = (val & 0x00FF00) >> 8; 14 | b_ = (val & 0x0000FF); 15 | 16 | // The gba uses 5-bit color. 17 | r_ >>= 3; 18 | g_ >>= 3; 19 | b_ >>= 3; 20 | } 21 | 22 | Color(u8 r, u8 g, u8 b) : r_(r), g_(g), b_(b) 23 | { 24 | } 25 | 26 | inline u16 bgr_hex_555() const 27 | { 28 | return (r_) + ((g_) << 5) + ((b_) << 10); 29 | } 30 | 31 | static Color from_bgr_hex_555(u16 val) 32 | { 33 | return { 34 | u8(0x1F & val), u8((0x3E0 & val) >> 5), u8((0x7C00 & val) >> 10)}; 35 | } 36 | 37 | inline Color invert() const 38 | { 39 | constexpr u8 max{31}; 40 | return {u8(max - r_), u8(max - g_), u8(max - b_)}; 41 | } 42 | 43 | inline Color grayscale() const 44 | { 45 | const u8 val = 0.3f * r_ + 0.59f * g_ + 0.11f * b_; 46 | return {val, val, val}; 47 | } 48 | 49 | // Convert color channel to number out of 255 rather than out of 31. 50 | static u8 upsample(u8 channel) 51 | { 52 | return (255.f / 31.f) * channel; 53 | } 54 | 55 | // Convert color channel to number out of 31 rather than out of 255. 56 | static u8 downsample(u8 channel) 57 | { 58 | return (31.f / 255.f) * channel; 59 | } 60 | 61 | u8 r_; 62 | u8 g_; 63 | u8 b_; 64 | }; 65 | -------------------------------------------------------------------------------- /source/platform/gba/gba_platform_soundcontext.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "memory/buffer.hpp" 5 | 6 | 7 | using AudioSample = s8; 8 | 9 | 10 | struct ActiveSoundInfo { 11 | s32 position_; 12 | const s32 length_; 13 | const AudioSample* data_; 14 | s32 priority_; 15 | }; 16 | 17 | 18 | struct SoundContext { 19 | // Only three sounds will play at a time... hey, sound mixing's expensive! 20 | Buffer active_sounds; 21 | 22 | const AudioSample* music_track = nullptr; 23 | s32 music_track_length = 0; 24 | s32 music_track_pos = 0; 25 | }; 26 | -------------------------------------------------------------------------------- /source/platform/gba/images.cpp: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | 3 | // This file was generated by the project's image build pipeline in 4 | // CMakeLists.txt. I have no idea why cmake outputs semicolons between the 5 | // entries in the IMAGE_INCLUDES list variable... maybe some special formatting 6 | // character that I don't know about... or maybe cmake uses ; internally as a 7 | // delimiter... but for now, the cmake script outputs the semicolons on a new 8 | // line, commented out, to suppress the resulting errors. 9 | // 10 | // If you try to manually edit source/platform/gba/images.cpp, the file may be 11 | // overwritten if you have the GBA_AUTOBUILD_IMG option in the cmake environment 12 | // turned on. 13 | 14 | 15 | 16 | #include "data/overlay.h" 17 | //; 18 | #include "data/overlay_text_key.h" 19 | //; 20 | #include "data/charset0.h" 21 | //; 22 | #include "data/charset1.h" 23 | // 24 | 25 | struct TextureData { 26 | const char* name_; 27 | const unsigned int* tile_data_; 28 | const unsigned short* palette_data_; 29 | u32 tile_data_length_; 30 | u32 palette_data_length_; 31 | }; 32 | 33 | 34 | #define STR(X) #X 35 | #define TEXTURE_INFO(NAME) \ 36 | { \ 37 | STR(NAME), NAME##Tiles, NAME##Pal, NAME##TilesLen, NAME##PalLen \ 38 | } 39 | 40 | 41 | static const TextureData sprite_textures[] = { 42 | 43 | }; 44 | 45 | 46 | static const TextureData tile_textures[] = { 47 | 48 | }; 49 | 50 | 51 | static const TextureData overlay_textures[] = { 52 | 53 | TEXTURE_INFO(overlay), 54 | //; 55 | TEXTURE_INFO(overlay_text_key), 56 | //; 57 | TEXTURE_INFO(charset0), 58 | //; 59 | TEXTURE_INFO(charset1), 60 | // 61 | }; 62 | 63 | // clang-format on 64 | -------------------------------------------------------------------------------- /source/platform/gba/interrupt.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | libgba interrupt support routines 4 | 5 | Copyright 2003-2004 by Dave Murphy. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Library General Public 9 | License as published by the Free Software Foundation; either 10 | version 2 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Library General Public License for more details. 16 | 17 | You should have received a copy of the GNU Library General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 20 | USA. 21 | 22 | Please report all bugs and problems through the bug tracker at 23 | "http://sourceforge.net/tracker/?group_id=114505&atid=668551". 24 | 25 | */ 26 | 27 | #include "gba.h" 28 | 29 | //--------------------------------------------------------------------------------- 30 | struct IntTable IntrTable[MAX_INTS]; 31 | void dummy(void) {} 32 | 33 | #define NULL 0 34 | 35 | //--------------------------------------------------------------------------------- 36 | void InitInterrupt(void) { 37 | //--------------------------------------------------------------------------------- 38 | irqInit(); 39 | } 40 | 41 | //--------------------------------------------------------------------------------- 42 | void irqInit() { 43 | //--------------------------------------------------------------------------------- 44 | int i; 45 | 46 | // Set all interrupts to dummy functions. 47 | for(i = 0; i < MAX_INTS; i ++) 48 | { 49 | IntrTable[i].handler = dummy; 50 | IntrTable[i].mask = 0; 51 | } 52 | 53 | INT_VECTOR = IntrMain; 54 | } 55 | 56 | //--------------------------------------------------------------------------------- 57 | IntFn* SetInterrupt(irqMASK mask, IntFn function) { 58 | //--------------------------------------------------------------------------------- 59 | return irqSet(mask,function); 60 | } 61 | 62 | //--------------------------------------------------------------------------------- 63 | IntFn* irqSet(irqMASK mask, IntFn function) { 64 | //--------------------------------------------------------------------------------- 65 | int i; 66 | 67 | for (i=0;;i++) { 68 | if (!IntrTable[i].mask || IntrTable[i].mask == mask) break; 69 | } 70 | 71 | if ( i >= MAX_INTS) return NULL; 72 | 73 | IntrTable[i].handler = function; 74 | IntrTable[i].mask = mask; 75 | 76 | return &IntrTable[i].handler; 77 | 78 | } 79 | 80 | //--------------------------------------------------------------------------------- 81 | void EnableInterrupt(irqMASK mask) { 82 | //--------------------------------------------------------------------------------- 83 | irqEnable(mask); 84 | } 85 | 86 | //--------------------------------------------------------------------------------- 87 | void irqEnable ( int mask ) { 88 | //--------------------------------------------------------------------------------- 89 | REG_IME = 0; 90 | 91 | if (mask & IRQ_VBLANK) REG_DISPSTAT |= LCDC_VBL; 92 | if (mask & IRQ_HBLANK) REG_DISPSTAT |= LCDC_HBL; 93 | if (mask & IRQ_VCOUNT) REG_DISPSTAT |= LCDC_VCNT; 94 | REG_IE |= mask; 95 | REG_IME = 1; 96 | } 97 | 98 | //--------------------------------------------------------------------------------- 99 | void DisableInterrupt(irqMASK mask) { 100 | //--------------------------------------------------------------------------------- 101 | irqDisable(mask); 102 | } 103 | 104 | //--------------------------------------------------------------------------------- 105 | void irqDisable(int mask) { 106 | //--------------------------------------------------------------------------------- 107 | REG_IME = 0; 108 | 109 | if (mask & IRQ_VBLANK) REG_DISPSTAT &= ~LCDC_VBL; 110 | if (mask & IRQ_HBLANK) REG_DISPSTAT &= ~LCDC_HBL; 111 | if (mask & IRQ_VCOUNT) REG_DISPSTAT &= ~LCDC_VCNT; 112 | REG_IE &= ~mask; 113 | 114 | REG_IME = 1; 115 | 116 | } 117 | -------------------------------------------------------------------------------- /source/platform/gba/interrupt_dispatch.s: -------------------------------------------------------------------------------- 1 | .section .iwram,"ax",%progbits 2 | .extern IntrTable 3 | .code 32 4 | 5 | .global IntrMain 6 | 7 | IntrMain: 8 | mov r3, #0x4000000 9 | ldr r2, [r3,#0x200] 10 | 11 | ldr r1, [r3, #0x208] 12 | str r3, [r3, #0x208] 13 | mrs r0, spsr 14 | stmfd sp!, {r0-r1,r3,lr} 15 | 16 | and r1, r2, r2, lsr #16 17 | 18 | ldrh r2, [r3, #-8] 19 | orr r2, r2, r1 20 | strh r2, [r3, #-8] 21 | 22 | ldr r2,=IntrTable 23 | add r3,r3,#0x200 24 | 25 | 26 | findIRQ: 27 | ldr r0, [r2, #4] 28 | cmp r0,#0 29 | beq no_handler 30 | ands r0, r0, r1 31 | bne jump_intr 32 | add r2, r2, #8 33 | b findIRQ 34 | 35 | no_handler: 36 | strh r1, [r3, #0x02] 37 | ldmfd sp!, {r0-r1,r3,lr} 38 | str r1, [r3, #0x208] 39 | mov pc,lr 40 | 41 | jump_intr: 42 | ldr r2, [r2] 43 | cmp r2, #0 44 | beq no_handler 45 | 46 | got_handler: 47 | mrs r1, cpsr 48 | bic r1, r1, #0xdf 49 | orr r1, r1, #0x1f 50 | msr cpsr,r1 51 | 52 | strh r0, [r3, #0x02] 53 | 54 | push {lr} 55 | adr lr, IntrRet 56 | bx r2 57 | 58 | IntrRet: 59 | pop {lr} 60 | mov r3, #0x4000000 61 | str r3, [r3, #0x208] 62 | 63 | mrs r3, cpsr 64 | bic r3, r3, #0xdf 65 | orr r3, r3, #0x92 66 | msr cpsr, r3 67 | 68 | ldmfd sp!, {r0-r1,r3,lr} 69 | str r1, [r3, #0x208] 70 | msr spsr, r0 71 | mov pc,lr 72 | 73 | .pool 74 | .end 75 | -------------------------------------------------------------------------------- /source/platform/gba/memcpy.s: -------------------------------------------------------------------------------- 1 | @ === void memcpy32(void *dst, const void *src, uint wdcount) IWRAM_CODE; ============= 2 | @ r0, r1: dst, src 3 | @ r2: wdcount, then wdcount>>3 4 | @ r3-r10: data buffer 5 | @ r12: wdn&7 6 | .section .iwram,"ax", %progbits 7 | .align 2 8 | .code 32 9 | .global memcpy32 10 | .type memcpy32 STT_FUNC 11 | memcpy32: 12 | and r12, r2, #7 @ r12= residual word count 13 | movs r2, r2, lsr #3 @ r2=block count 14 | beq .Lres_cpy32 15 | push {r4-r10} 16 | @ Copy 32byte chunks with 8fold xxmia 17 | @ r2 in [1,inf> 18 | .Lmain_cpy32: 19 | ldmia r1!, {r3-r10} 20 | stmia r0!, {r3-r10} 21 | subs r2, #1 22 | bne .Lmain_cpy32 23 | pop {r4-r10} 24 | @ And the residual 0-7 words. r12 in [0,7] 25 | .Lres_cpy32: 26 | subs r12, #1 27 | ldrcs r3, [r1], #4 28 | strcs r3, [r0], #4 29 | bcs .Lres_cpy32 30 | bx lr 31 | 32 | 33 | @ === void memcpy16(void *dst, const void *src, uint hwcount); ============= 34 | @ Reglist: 35 | @ r0, r1: dst, src 36 | @ r2, r4: hwcount 37 | @ r3: tmp and data buffer 38 | .text 39 | .align 2 40 | .code 16 41 | .thumb_func 42 | .global memcpy16 43 | .type memcpy16 STT_FUNC 44 | memcpy16: 45 | push {r4, lr} 46 | @ (1) under 5 hwords -> std cpy 47 | cmp r2, #5 48 | bls .Ltail_cpy16 49 | @ (2) Unreconcilable alignment -> std cpy 50 | @ if (dst^src)&2 -> alignment impossible 51 | mov r3, r0 52 | eor r3, r1 53 | lsl r3, #31 @ (dst^src), bit 1 into carry 54 | bcs .Ltail_cpy16 @ (dst^src)&2 : must copy by halfword 55 | @ (3) src and dst have same alignment -> word align 56 | lsl r3, r0, #31 57 | bcc .Lmain_cpy16 @ ~src&2 : already word aligned 58 | @ Aligning is necessary: copy 1 hword and align 59 | ldrh r3, [r1] 60 | strh r3, [r0] 61 | add r0, #2 62 | add r1, #2 63 | sub r2, #1 64 | @ (4) Right, and for the REAL work, we're gonna use memcpy32 65 | .Lmain_cpy16: 66 | lsl r4, r2, #31 67 | lsr r2, r2, #1 68 | ldr r3,=memcpy32 69 | bl _call_via_r3 70 | @ (5) NOTE: r0,r1 are altered by memcpy32, but in exactly the right 71 | @ way, so we can use them as is. 72 | lsr r2, r4, #31 73 | beq .Lend_cpy16 74 | @ (6) Copy residuals by halfword 75 | .Ltail_cpy16: 76 | sub r2, #1 77 | bcc .Lend_cpy16 @ r2 was 0, bug out 78 | lsl r2, r2, #1 @ r2 is offset (Yes, we're copying backward) 79 | .Lres_cpy16: 80 | ldrh r3, [r1, r2] 81 | strh r3, [r0, r2] 82 | sub r2, r2, #2 83 | bcs .Lres_cpy16 84 | .Lend_cpy16: 85 | pop {r4} 86 | pop {r3} 87 | bx r3 88 | -------------------------------------------------------------------------------- /source/platform/gba/reset.s: -------------------------------------------------------------------------------- 1 | 2 | .text 3 | .code 16 4 | 5 | .global RegisterRamReset 6 | .thumb_func 7 | 8 | RegisterRamReset: 9 | swi 1 10 | bx lr 11 | 12 | .global SoftReset 13 | .thumb_func 14 | 15 | SoftReset: 16 | ldr r3, =0x03007FFA @ restart flag 17 | strb r0,[r3, #0] 18 | ldr r3, =0x04000208 @ REG_IME 19 | mov r2, #0 20 | strb r2, [r3, #0] 21 | ldr r1, =0x03007f00 22 | mov sp, r1 23 | swi 1 24 | swi 0 25 | 26 | .pool 27 | -------------------------------------------------------------------------------- /source/platform/gba/scripts.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | extern const unsigned char script_init[]; 4 | //; 5 | extern const unsigned char script_pre_levelgen[]; 6 | //; 7 | extern const unsigned char script_post_levelgen[]; 8 | // 9 | 10 | static const struct { 11 | const char* name_; 12 | const unsigned char* data_; 13 | } scripts[] = { 14 | 15 | {"init.lisp", script_init}, 16 | //; 17 | {"pre_levelgen.lisp", script_pre_levelgen}, 18 | //; 19 | {"post_levelgen.lisp", script_post_levelgen}, 20 | // 21 | }; 22 | -------------------------------------------------------------------------------- /source/platform/key.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/int.h" 4 | 5 | 6 | enum class Key : u8 { 7 | action_1, 8 | action_2, 9 | start, 10 | select, 11 | left, 12 | right, 13 | up, 14 | down, 15 | alt_1, 16 | alt_2, 17 | count 18 | }; 19 | -------------------------------------------------------------------------------- /source/platform/switch/switch_platform.cpp: -------------------------------------------------------------------------------- 1 | 2 | //////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // 5 | // Nintendo Switch Platform 6 | // 7 | // NOTES: 8 | // 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | 13 | #include "platform/platform.hpp" 14 | 15 | 16 | int main(int argc, char** argv) 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /source/powerup.cpp: -------------------------------------------------------------------------------- 1 | #include "powerup.hpp" 2 | #include "game.hpp" 3 | 4 | 5 | void add_powerup(Game& game, 6 | Powerup::Type t, 7 | int param, 8 | Powerup::DisplayMode mode) 9 | { 10 | // Collapse with existing powerup 11 | for (auto& powerup : game.powerups()) { 12 | if (powerup.type_ == t) { 13 | powerup.parameter_.set(powerup.parameter_.get() + param); 14 | powerup.dirty_ = true; 15 | return; 16 | } 17 | } 18 | 19 | if (game.powerups().full()) { 20 | game.powerups().erase(game.powerups().begin()); 21 | } 22 | 23 | Powerup p; 24 | p.type_ = t; 25 | p.parameter_.set(param); 26 | p.dirty_ = false; 27 | p.display_mode_ = mode; 28 | game.powerups().push_back(p); 29 | } 30 | 31 | 32 | Powerup* get_powerup(Game& game, Powerup::Type t) 33 | { 34 | for (auto& powerup : game.powerups()) { 35 | if (powerup.type_ == t) { 36 | return &powerup; 37 | } 38 | } 39 | return nullptr; 40 | } 41 | -------------------------------------------------------------------------------- /source/powerup.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "memory/buffer.hpp" 5 | #include "number/endian.hpp" 6 | 7 | 8 | class Game; 9 | 10 | 11 | class Powerup { 12 | public: 13 | static constexpr const int max_ = 4; 14 | 15 | enum class Type { accelerator, lethargy, explosive_rounds } type_; 16 | 17 | HostInteger parameter_; 18 | bool dirty_; 19 | 20 | enum class DisplayMode { 21 | integer, 22 | timestamp 23 | } display_mode_ = DisplayMode::integer; 24 | 25 | inline int icon_index() const 26 | { 27 | return 257 + static_cast(type_); 28 | } 29 | }; 30 | 31 | 32 | using Powerups = Buffer; 33 | 34 | 35 | void add_powerup(Game& game, 36 | Powerup::Type t, 37 | int param, 38 | Powerup::DisplayMode mode = Powerup::DisplayMode::integer); 39 | 40 | 41 | Powerup* get_powerup(Game& game, Powerup::Type t); 42 | -------------------------------------------------------------------------------- /source/scriptApi.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /source/settings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "graphics/contrast.hpp" 4 | #include "number/endian.hpp" 5 | #include "platform/key.hpp" 6 | #include "severity.hpp" 7 | 8 | 9 | struct Settings { 10 | enum Difficulty : u8 { easy, normal, hard, survival, count }; 11 | 12 | Settings() 13 | { 14 | language_.set(1); 15 | } 16 | 17 | HostInteger language_; 18 | bool show_stats_ = false; 19 | bool night_mode_ = false; 20 | Contrast contrast_ = 0; 21 | Difficulty difficulty_ = Difficulty::normal; 22 | Severity log_severity_ = Severity::error; 23 | 24 | static constexpr const auto default_action1_key = Key::action_1; 25 | static constexpr const auto default_action2_key = Key::action_2; 26 | Key action1_key_ = default_action1_key; 27 | Key action2_key_ = default_action2_key; 28 | 29 | bool show_speedrun_clock_ = true; 30 | }; 31 | -------------------------------------------------------------------------------- /source/severity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/int.h" 4 | 5 | 6 | enum class Severity : u8 { debug, info, warning, error, count }; 7 | -------------------------------------------------------------------------------- /source/sound.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | enum class Note { C, CS, D, DS, E, F, FS, G, GS, A, AS, B }; 5 | 6 | using Octave = int; 7 | -------------------------------------------------------------------------------- /source/speedrunClock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | 5 | 6 | // This class exists mostly for performance reasons. We cannot simply convert 7 | // time values to strings upon every frame, and we do not want to perform 8 | // expensive division or mod operations to determine whether the clock counted 9 | // up by one second. 10 | 11 | 12 | class SpeedrunClock { 13 | public: 14 | int whole_seconds() const 15 | { 16 | return whole_seconds_; 17 | } 18 | 19 | void update(Microseconds delta) 20 | { 21 | fractional_time_ += delta; 22 | 23 | if (fractional_time_ > seconds(1)) { 24 | whole_seconds_ -= 1; 25 | fractional_time_ -= seconds(1); 26 | } 27 | } 28 | 29 | void reset() 30 | { 31 | whole_seconds_ = 60 * 3; 32 | fractional_time_ = 0; 33 | } 34 | 35 | private: 36 | u32 whole_seconds_ = 60 * 3; 37 | Microseconds fractional_time_ = 0; 38 | }; 39 | -------------------------------------------------------------------------------- /source/start.cpp: -------------------------------------------------------------------------------- 1 | #include "BPCoreEngine.hpp" 2 | #include "platform/platform.hpp" 3 | 4 | 5 | void start(Platform& pf) 6 | { 7 | BPCoreEngine bpcore(pf); 8 | 9 | bpcore.run(); 10 | } 11 | -------------------------------------------------------------------------------- /source/state.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "graphics/overlay.hpp" 5 | #include "number/numeric.hpp" 6 | #include "string.hpp" 7 | #include 8 | 9 | 10 | class Platform; 11 | class Game; 12 | class State; 13 | 14 | 15 | using StatePtr = std::unique_ptr; 16 | 17 | 18 | class State { 19 | public: 20 | virtual void enter(Platform&, Game&, State& prev_state); 21 | virtual void exit(Platform&, Game&, State& next_state); 22 | 23 | // Returns a new state, if we're transitioning to another state, otherwise, 24 | // if the next state will be the same state, returns an empty state 25 | // pointer. 26 | 27 | virtual StatePtr update(Platform& platform, Game& game, Microseconds delta); 28 | 29 | virtual ~State() 30 | { 31 | } 32 | 33 | static StatePtr initial(Platform&, Game&); 34 | }; 35 | 36 | 37 | StatePtr null_state(); 38 | 39 | 40 | using NotificationStr = StringBuffer<40>; 41 | void push_notification(Platform& pfrm, 42 | State* state, 43 | const NotificationStr& string); 44 | 45 | 46 | // Yeah, this breaks encapsulation. But this is an edge case, where the boss 47 | // needs to display its own health, but due to state changes outside of an 48 | // individual entity's control, it doesn't make sense for the enemy itself to 49 | // own the GUI's health bar. 50 | void show_boss_health(Platform& pfrm, 51 | Game& game, 52 | int health_bar, 53 | Float percentage); 54 | 55 | void hide_boss_health(Game& game); 56 | -------------------------------------------------------------------------------- /source/string.cpp: -------------------------------------------------------------------------------- 1 | #include "string.hpp" 2 | -------------------------------------------------------------------------------- /source/tileDataStream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | #include "string.hpp" 5 | 6 | 7 | 8 | class TileDataStream { 9 | public: 10 | 11 | virtual ~TileDataStream() {} 12 | 13 | 14 | virtual bool read(u16* output) = 0; 15 | 16 | 17 | virtual bool skip(int cells) = 0; 18 | 19 | 20 | virtual bool next_row() = 0; 21 | 22 | }; 23 | 24 | 25 | 26 | class CSVTileDataStream : public TileDataStream { 27 | public: 28 | 29 | CSVTileDataStream(const char* data, u32 len) : 30 | data_(data), 31 | len_(len) 32 | { 33 | } 34 | 35 | 36 | bool read(u16* output) override 37 | { 38 | if (pos_ == len_) { 39 | return false; 40 | } 41 | 42 | if (data_[pos_] == '\r') { 43 | // Some people use MS Windows for some reason 44 | ++pos_; 45 | } 46 | 47 | if (data_[pos_] == '\n') { 48 | ++pos_; 49 | x_ = 0; 50 | ++y_; 51 | } 52 | 53 | StringBuffer<20> buffer; 54 | 55 | while (data_[pos_] not_eq ',' and 56 | data_[pos_] not_eq '\n' and 57 | data_[pos_] not_eq '\r') { 58 | if (pos_ == len_) { 59 | break; 60 | } 61 | buffer.push_back(data_[pos_++]); 62 | } 63 | 64 | if (data_[pos_] == ',') { 65 | ++pos_; 66 | } 67 | ++x_; 68 | 69 | 70 | if (output) { 71 | *output = std::atoi(buffer.c_str()); 72 | } 73 | 74 | return true; 75 | } 76 | 77 | 78 | bool next_row() override 79 | { 80 | while (true) { 81 | if (pos_ == len_) { 82 | return false; 83 | } 84 | 85 | if (data_[pos_] == '\r') { 86 | ++pos_; 87 | } else if (data_[pos_] == '\n') { 88 | ++pos_; 89 | x_ = 0; 90 | ++y_; 91 | return true; 92 | } else { 93 | ++pos_; 94 | } 95 | } 96 | } 97 | 98 | 99 | bool skip(int cells) override 100 | { 101 | for (int i = 0; i < cells; ++i) { 102 | if (not read(nullptr)) { 103 | return false; 104 | } 105 | } 106 | 107 | return true; 108 | } 109 | 110 | 111 | private: 112 | const char* data_; 113 | u32 len_; 114 | u32 pos_ = 0; 115 | int x_ = 0; 116 | int y_ = 0; 117 | }; 118 | -------------------------------------------------------------------------------- /source/tileMap.cpp: -------------------------------------------------------------------------------- 1 | #include "tileMap.hpp" 2 | 3 | 4 | u16 TileMap::index(u16 x, u16 y) const 5 | { 6 | return x + y * width; 7 | } 8 | 9 | 10 | void TileMap::set_tile(s32 x, s32 y, u8 tile) 11 | { 12 | if (x < 0 or y < 0 or x > width - 1 or y > height - 1) { 13 | return; 14 | } 15 | data_[TileMap::index(x, y)] = tile; 16 | } 17 | 18 | 19 | u8 TileMap::get_tile(s32 x, s32 y) const 20 | { 21 | if (x < 0 or y < 0 or x > width - 1 or y > height - 1) { 22 | return Tile::none; 23 | } 24 | return data_[TileMap::index(x, y)]; 25 | } 26 | -------------------------------------------------------------------------------- /source/tileMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/numeric.hpp" 4 | #include 5 | 6 | 7 | struct Tile { 8 | enum : u8 { 9 | none, 10 | plate, 11 | sand, 12 | ledge, 13 | damaged_plate, 14 | __reserved_0, // Used for rendering the parallax scrolling starfield 15 | sand_sprouted, 16 | __reserved_2, 17 | grass_ledge, 18 | grass_ledge_vines, 19 | beam_ul, 20 | beam_ur, 21 | beam_bl, 22 | beam_br, 23 | plate_left, 24 | plate_top, 25 | plate_right, 26 | plate_bottom, 27 | t0_count, 28 | // Tile layer 1 is reserved for adding detail to maps, t1 renders overtop of 29 | // t0 (the enumerations above) 30 | grass_start = 1, 31 | }; 32 | }; 33 | 34 | class TileMap { 35 | public: 36 | // NOTE: The tilemap constants here are sixteen and twenty, due to limits of 37 | // the GBA hardware, but could be bumped up for Desktop releases. 38 | static constexpr u16 width = 16; 39 | static constexpr u16 height = 20; 40 | static constexpr u16 tile_count{width * height}; 41 | 42 | using Index = s8; 43 | 44 | TileMap() 45 | { 46 | TileMap::for_each([](u8& tile, int, int) { tile = Tile::none; }); 47 | } 48 | 49 | template TileMap(F&& init) 50 | { 51 | for_each(init); 52 | } 53 | 54 | template void for_each(F&& proc) 55 | { 56 | for (Index i = 0; i < width; ++i) { 57 | for (Index j = 0; j < height; ++j) { 58 | proc(data_[TileMap::index(i, j)], i, j); 59 | } 60 | } 61 | } 62 | 63 | template void for_each(F&& proc) const 64 | { 65 | for (Index i = 0; i < width; ++i) { 66 | for (Index j = 0; j < height; ++j) { 67 | proc(data_[TileMap::index(i, j)], i, j); 68 | } 69 | } 70 | } 71 | 72 | void set_tile(s32 x, s32 y, u8 tile); 73 | 74 | u8 get_tile(s32 x, s32 y) const; 75 | 76 | private: 77 | u16 index(u16 x, u16 y) const; 78 | 79 | std::array data_; 80 | }; 81 | 82 | 83 | using TIdx = TileMap::Index; 84 | 85 | 86 | template 87 | inline Vec2 to_world_coord(const Vec2& tc) 88 | { 89 | return Vec2{tc.x * 32, tc.y * 24}.template cast(); 90 | } 91 | 92 | 93 | inline Vec2 to_tile_coord(const Vec2& wc) 94 | { 95 | return Vec2{ 96 | wc.x / 32, 97 | wc.y / 24 // This division by 24 is costly, oh well... 98 | } 99 | .cast(); 100 | } 101 | 102 | inline Vec2 to_quarter_tile_coord(const Vec2& wc) 103 | { 104 | return Vec2{wc.x / 16, wc.y / 12}.cast(); 105 | } 106 | 107 | 108 | inline bool is_walkable(u8 t) 109 | { 110 | // After level generation, all tiles in the tilemap are replaced with 111 | // boolean values. 112 | return static_cast(t); 113 | } 114 | 115 | 116 | inline bool is_border(u8 t) 117 | { 118 | return t == Tile::plate; 119 | } 120 | -------------------------------------------------------------------------------- /source/timeTracker.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "number/endian.hpp" 4 | #include "number/numeric.hpp" 5 | 6 | 7 | class TimeTracker { 8 | public: 9 | TimeTracker(u32 seconds) : whole_seconds_(seconds), fractional_time_(0) 10 | { 11 | } 12 | 13 | int whole_seconds() const 14 | { 15 | return whole_seconds_.get(); 16 | } 17 | 18 | void count_up(Microseconds delta) 19 | { 20 | fractional_time_.set(fractional_time_.get() + delta); 21 | 22 | if (fractional_time_.get() > seconds(1)) { 23 | fractional_time_.set(fractional_time_.get() - seconds(1)); 24 | whole_seconds_.set(whole_seconds_.get() + 1); 25 | } 26 | } 27 | 28 | void count_down(Microseconds delta) 29 | { 30 | fractional_time_.set(fractional_time_.get() + delta); 31 | 32 | if (fractional_time_.get() > seconds(1)) { 33 | fractional_time_.set(fractional_time_.get() - seconds(1)); 34 | if (whole_seconds_.get() > 0) { 35 | whole_seconds_.set(whole_seconds_.get() - 1); 36 | } 37 | } 38 | } 39 | 40 | void reset(u32 seconds) 41 | { 42 | whole_seconds_.set(seconds); 43 | fractional_time_.set(0); 44 | } 45 | 46 | private: 47 | HostInteger whole_seconds_; 48 | HostInteger fractional_time_; 49 | }; 50 | -------------------------------------------------------------------------------- /source/transformGroup.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "memory/buffer.hpp" 4 | #include 5 | #include 6 | 7 | 8 | namespace detail { 9 | template 10 | inline typename std::enable_if::type 11 | for_each(std::tuple&, FuncT) 12 | { 13 | } 14 | 15 | template 16 | inline typename std::enable_if < 17 | I::type for_each(std::tuple& t, FuncT f) 18 | { 19 | f(std::get(t)); 20 | for_each(t, f); 21 | } 22 | } // namespace detail 23 | 24 | 25 | template class TransformGroup { 26 | public: 27 | TransformGroup() 28 | { 29 | } 30 | 31 | template TransformGroup(T& init) : members_(Members{init}...) 32 | { 33 | } 34 | 35 | template void transform(F&& method) 36 | { 37 | detail::for_each(members_, method); 38 | } 39 | 40 | template auto& get() 41 | { 42 | return std::get(members_); 43 | } 44 | 45 | template auto& get() 46 | { 47 | return std::get(members_); 48 | } 49 | 50 | private: 51 | std::tuple members_; 52 | }; 53 | -------------------------------------------------------------------------------- /source/util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define COLD [[gnu::cold]] 4 | #define HOT [[gnu::hot]] 5 | 6 | #ifdef __GNUC__ 7 | #define UNLIKELY(COND) __builtin_expect((COND), false) 8 | #else 9 | #define UNLIKELY(COND) (COND) 10 | #endif 11 | 12 | #include 13 | 14 | 15 | #ifdef __GBA__ 16 | #define READ_ONLY_DATA __attribute__((section(".rodata"))) 17 | #else 18 | #define READ_ONLY_DATA 19 | #endif 20 | 21 | 22 | namespace _detail { 23 | 24 | template struct reversion_wrapper { 25 | T& iterable; 26 | }; 27 | 28 | 29 | template auto begin(reversion_wrapper w) 30 | { 31 | return std::rbegin(w.iterable); 32 | } 33 | 34 | 35 | template auto end(reversion_wrapper w) 36 | { 37 | return std::rend(w.iterable); 38 | } 39 | 40 | 41 | } // namespace _detail 42 | 43 | 44 | template _detail::reversion_wrapper reversed(T&& iterable) 45 | { 46 | return {iterable}; 47 | } 48 | -------------------------------------------------------------------------------- /source/version.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define PROGRAM_MAJOR_VERSION 2024 3 | #define PROGRAM_MINOR_VERSION 6 4 | #define PROGRAM_SUBMINOR_VERSION 28 5 | #define PROGRAM_VERSION_REVISION 0 6 | -------------------------------------------------------------------------------- /source/wallCollision.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "memory/buffer.hpp" 4 | #include "tileMap.hpp" 5 | 6 | 7 | struct WallCollisions { 8 | bool up = false; 9 | bool down = false; 10 | bool left = false; 11 | bool right = false; 12 | 13 | bool any() const 14 | { 15 | return up or down or left or right; 16 | } 17 | }; 18 | 19 | 20 | template 21 | WallCollisions check_wall_collisions(TileMap& tiles, T& entity) 22 | { 23 | using Wall = Vec2; 24 | Buffer adjacency_vector; 25 | 26 | Vec2 pos = entity.get_position().template cast(); 27 | pos.y += 2; 28 | const Vec2 tile_coords = to_tile_coord(pos); 29 | 30 | auto check_wall = [&](TIdx x, TIdx y) { 31 | if (not is_walkable(tiles.get_tile(x, y))) { 32 | adjacency_vector.push_back(to_world_coord({x, y})); 33 | } 34 | }; 35 | 36 | // A four by four block around the entity should be a large enough region to 37 | // check for wall collisions. 38 | for (TIdx x = tile_coords.x - 1; x < tile_coords.x + 2; ++x) { 39 | for (TIdx y = tile_coords.y - 1; y < tile_coords.y + 2; ++y) { 40 | check_wall(x, y); 41 | } 42 | } 43 | 44 | WallCollisions result; 45 | 46 | for (const auto& wall : adjacency_vector) { 47 | // FIXME: this edge collision code is junk left over from the original 48 | // codebase. 49 | if ((pos.x - 16 + 6 < (wall.x + 32) and (pos.x - 16 + 6 > (wall.x))) and 50 | (abs((pos.y - 16 + 16) - wall.y) <= 13)) { 51 | result.left = true; 52 | } 53 | if ((pos.x - 16 + 26 > (wall.x) and 54 | (pos.x - 16 + 26 < (wall.x + 32))) and 55 | (abs((pos.y - 16 + 16) - wall.y) <= 13)) { 56 | result.right = true; 57 | } 58 | if (((pos.y - 16 + 22 < (wall.y + 26)) and 59 | (pos.y - 16 + 22 > (wall.y))) and 60 | (abs((pos.x - 16) - wall.x) <= 16)) { 61 | result.up = true; 62 | } 63 | if (((pos.y - 16 + 36 > wall.y) and (pos.y - 16 + 36 < wall.y + 26)) and 64 | (abs((pos.x - 16) - wall.x) <= 16)) { 65 | result.down = true; 66 | } 67 | } 68 | 69 | return result; 70 | } 71 | -------------------------------------------------------------------------------- /useful_documents/tonc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evanbowman/BPCore-Engine/87d734ad2ba99b607b48dcf442197dedcba8436a/useful_documents/tonc.pdf --------------------------------------------------------------------------------