commit 9053e2b1a748e59e4bacafa7c8e1bbf6e8447426 Author: Phantop Date: Fri Dec 4 14:40:16 2020 -0500 Import accurate branch diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a9299ca --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +# Automatically normalize line endings. +* text=auto + +# MSVC files have to be CRLF +*.vcproj text eol=crlf +*.sln text eol=crlf + +# Do not change external files +external/** -text +DoConfig/fltk/** -text + +# TSC files are not text, but 'git diff' likes to think they are +*.tsc binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52725ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,105 @@ +# Exclude obj directory (object files for Makefile build) +/obj + +# Exclude the (recommended) CMake build directory +/build* + +# Exclude executables +/game_english/CSE2_debug.exe +/game_english/DoConfig_debug.exe +/game_english/CSE2.exe +/game_english/DoConfig.exe +/game_english/CSE2_debug +/game_english/DoConfig_debug +/game_english/CSE2 +/game_english/DoConfig +/game_english/CSE2_debug.rpx +/game_english/CSE2.rpx +/game_english/CSE2.3dsx +/game_english/\!CSE2 +/game_japanese/CSE2_debug.exe +/game_japanese/DoConfig_debug.exe +/game_japanese/CSE2.exe +/game_japanese/DoConfig.exe +/game_japanese/CSE2_debug +/game_japanese/DoConfig_debug +/game_japanese/CSE2 +/game_japanese/DoConfig +/game_japanese/CSE2_debug.rpx +/game_japanese/CSE2.rpx +/game_japanese/CSE2.3dsx +/game_japanese/\!CSE2 + +# Exclude MSVC debug data +/game_english/CSE2_debug.ilk +/game_english/CSE2_debug.pdb +/game_english/DoConfig_debug.ilk +/game_english/DoConfig_debug.pdb +/game_english/CSE2.ilk +/game_english/CSE2.pdb +/game_english/DoConfig.ilk +/game_english/DoConfig.pdb +/game_japanese/CSE2_debug.ilk +/game_japanese/CSE2_debug.pdb +/game_japanese/DoConfig_debug.ilk +/game_japanese/DoConfig_debug.pdb +/game_japanese/CSE2.ilk +/game_japanese/CSE2.pdb +/game_japanese/DoConfig.ilk +/game_japanese/DoConfig.pdb + +# Exclude misc. MSVC junk +/.vs +/out +/CMakeSettings.json + +# Exclude save data +/game_english/Config.dat +/game_english/Profile.dat +/game_english/290.rec +/game_english/window.rect +/game_japanese/Config.dat +/game_japanese/Profile.dat +/game_japanese/290.rec +/game_japanese/window.rect + +# Exclude configuration files +/game_english/fps +/game_english/mute +/game_english/save +/game_english/s_reverse +/game_japanese/fps +/game_japanese/mute +/game_japanese/save +/game_japanese/s_reverse + +# Exclude error logs +/game_english/error.log +/game_japanese/error.log + +################### +# Accurate branch # +################### + +# Exclude devilution-comparer assembly output +/devilution/orig.asm +/devilution/compare.asm + +# Exclude MSVC IntelliSense database +/vs2003/CSE2.ncb + +# Exclude MSVC Solution User Options file +/vs2003/CSE2.suo + +# Exclude MSVC build folders +/vs2003/Debug +/vs2003/Release +/vs2003/Debug (Japanese) +/vs2003/Release (Japanese) + +################### +# Portable branch # +################### + +# Exclude converted resource files +/src/Resource diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a2dd8bf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,133 @@ +# Optimize git clone +git: + depth: 5 + +# Bionic is the most recent version of Ubuntu I can get to work properly +dist: bionic + +# Enable C++ language support +language: cpp + +compiler: + - gcc + +os: + - linux +# - windows + +addons: + apt: + sources: + - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + - sourceline: 'ppa:ubuntu-toolchain-r/test' + packages: + - make + - mingw-w64 + +env: + - SIXTY_FOUR_BIT=false FIX_BUGS=0 JAPANESE=0 + - SIXTY_FOUR_BIT=false FIX_BUGS=0 JAPANESE=1 + - SIXTY_FOUR_BIT=false FIX_BUGS=1 JAPANESE=0 + - SIXTY_FOUR_BIT=false FIX_BUGS=1 JAPANESE=1 + - SIXTY_FOUR_BIT=true FIX_BUGS=0 JAPANESE=0 + - SIXTY_FOUR_BIT=true FIX_BUGS=0 JAPANESE=1 + - SIXTY_FOUR_BIT=true FIX_BUGS=1 JAPANESE=0 + - SIXTY_FOUR_BIT=true FIX_BUGS=1 JAPANESE=1 + +before_install: + # Setup MSYS2 + - | + if [ "$TRAVIS_OS_NAME" == "windows" ]; then + [[ ! -f C:/tools/msys64/msys2_shell.cmd ]] && rm -rf C:/tools/msys64 + choco uninstall -y mingw + choco upgrade --no-progress -y msys2 + export msys2='cmd //C RefreshEnv.cmd ' + export msys2+='& set MSYS=winsymlinks:nativestrict ' + export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start' + if [ "$SIXTY_FOUR_BIT" == "true" ]; then + export mingw="$msys2 -mingw64 -full-path -here -c "\"\$@"\" --" + else + export mingw="$msys2 -mingw32 -full-path -here -c "\"\$@"\" --" + fi + export msys2+=" -msys2 -c "\"\$@"\" --" + if [ "$SIXTY_FOUR_BIT" == "true" ]; then + $msys2 pacman --sync --noconfirm --needed make mingw-w64-x86_64-toolchain + else + $msys2 pacman --sync --noconfirm --needed make mingw-w64-i686-toolchain + fi + taskkill //IM gpg-agent.exe //F # https://travis-ci.community/t/4967 + export PATH=/C/tools/msys64/mingw64/bin:$PATH + export MAKE=mingw32-make # so that Autotools can find it + fi + + # Set URL for Discord send script + - DISCORD_SEND_SCRIPT_URL=https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh + - DISCORD_SEND_SCRIPT_FILENAME=discordSendNotification.sh + + # Display available disk space + - df -h + + # Display Travis OS name + - echo $TRAVIS_OS_NAME + + # Define CC and CXX + - | + if [ "$SIXTY_FOUR_BIT" == "true" ]; then + export CC="x86_64-w64-mingw32-gcc" + export CXX="x86_64-w64-mingw32-g++" + else + export CC="i686-w64-mingw32-gcc" + export CXX="i686-w64-mingw32-g++" + fi + + # Define WINDRES + - | + if [ "$TRAVIS_OS_NAME" == "windows" ]; then + export WINDRES="windres" + else + if [ "$SIXTY_FOUR_BIT" == "true" ]; then + export WINDRES="x86_64-w64-mingw32-windres" + else + export WINDRES="i686-w64-mingw32-windres" + fi + fi + + # Display compilers name/version + - $mingw echo ${CC} + - $mingw echo ${CXX} + - $mingw ${CC} --version + - $mingw ${CXX} --version + +before_cache: + - | + if [ "$TRAVIS_OS_NAME" == "windows" ]; then + # https://unix.stackexchange.com/a/137322/107554 + $msys2 pacman --sync --clean --noconfirm + fi + +cache: + directories: + - $HOME/AppData/Local/Temp/chocolatey + - /C/tools/msys64 + +install: + # Get number of cores (or 2 by default if somehow none of these are available somehow) + - JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2) + - echo $JOBS + +script: + # Build + - $mingw make -j ${JOBS} FIX_BUGS=${FIX_BUGS} JAPANESE=${JAPANESE} RELEASE=1 WINDOWS=1 STATIC=1 CXXFLAGS="-Wall -Wextra -pedantic" + +after_success: + # Send success notification to Discord through DISCORD_WEBHOOK_URL + - travis_retry wget ${DISCORD_SEND_SCRIPT_URL} -O ${DISCORD_SEND_SCRIPT_FILENAME} + - chmod +x ${DISCORD_SEND_SCRIPT_FILENAME} + - ./${DISCORD_SEND_SCRIPT_FILENAME} success $DISCORD_WEBHOOK_URL + +after_failure: + # Send failure notification to Discord through DISCORD_WEBHOOK_URL + - travis_retry wget ${DISCORD_SEND_SCRIPT_URL} -O ${DISCORD_SEND_SCRIPT_FILENAME} + - chmod +x ${DISCORD_SEND_SCRIPT_FILENAME} + - ./${DISCORD_SEND_SCRIPT_FILENAME} failure $DISCORD_WEBHOOK_URL diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..19dd3df --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,260 @@ +cmake_minimum_required(VERSION 3.5.1) + + +############# +# Constants # +############# + +set(ASSETS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets") + + +########### +# Options # +########### + +option(JAPANESE "Enable the Japanese-language build (instead of the unofficial Aeon Genesis English translation)" OFF) +option(FIX_BUGS "Fix various bugs in the game" OFF) +option(FIX_MAJOR_BUGS "Fix bugs that invoke undefined behaviour or cause memory leaks" OFF) +option(DEBUG_SAVE "Re-enable the dummied-out 'Debug Save' option, and the ability to drag-and-drop save files onto the window" OFF) + +option(LTO "Enable link-time optimisation" OFF) +option(MSVC_LINK_STATIC_RUNTIME "Link the static MSVC runtime library" OFF) + + +######### +# Setup # +######### + +project(CSE2 LANGUAGES C CXX) + +add_executable(CSE2 WIN32 + "${ASSETS_DIRECTORY}/resources/CSE2.rc" + "src/ArmsItem.cpp" + "src/ArmsItem.h" + "src/Back.cpp" + "src/Back.h" + "src/Boss.cpp" + "src/Boss.h" + "src/BossAlmo1.cpp" + "src/BossAlmo1.h" + "src/BossAlmo2.cpp" + "src/BossAlmo2.h" + "src/BossBallos.cpp" + "src/BossBallos.h" + "src/BossFrog.cpp" + "src/BossFrog.h" + "src/BossIronH.cpp" + "src/BossIronH.h" + "src/BossLife.cpp" + "src/BossLife.h" + "src/BossOhm.cpp" + "src/BossOhm.h" + "src/BossPress.cpp" + "src/BossPress.h" + "src/BossTwinD.cpp" + "src/BossTwinD.h" + "src/BossX.cpp" + "src/BossX.h" + "src/BulHit.cpp" + "src/BulHit.h" + "src/Bullet.cpp" + "src/Bullet.h" + "src/Caret.cpp" + "src/Caret.h" + "src/CommonDefines.h" + "src/Config.cpp" + "src/Config.h" + "src/Dialog.cpp" + "src/Dialog.h" + "src/Draw.cpp" + "src/Draw.h" + "src/Ending.cpp" + "src/Ending.h" + "src/Escape.cpp" + "src/Escape.h" + "src/Fade.cpp" + "src/Fade.h" + "src/Flags.cpp" + "src/Flags.h" + "src/Flash.cpp" + "src/Flash.h" + "src/Frame.cpp" + "src/Frame.h" + "src/Game.cpp" + "src/Game.h" + "src/Generic.cpp" + "src/Generic.h" + "src/GenericLoad.cpp" + "src/GenericLoad.h" + "src/Input.cpp" + "src/Input.h" + "src/KeyControl.cpp" + "src/KeyControl.h" + "src/Main.cpp" + "src/Main.h" + "src/Map.cpp" + "src/Map.h" + "src/MapName.cpp" + "src/MapName.h" + "src/MiniMap.cpp" + "src/MiniMap.h" + "src/MyChar.cpp" + "src/MyChar.h" + "src/MycHit.cpp" + "src/MycHit.h" + "src/MycParam.cpp" + "src/MycParam.h" + "src/NpcAct.h" + "src/NpcAct000.cpp" + "src/NpcAct020.cpp" + "src/NpcAct040.cpp" + "src/NpcAct060.cpp" + "src/NpcAct080.cpp" + "src/NpcAct100.cpp" + "src/NpcAct120.cpp" + "src/NpcAct140.cpp" + "src/NpcAct160.cpp" + "src/NpcAct180.cpp" + "src/NpcAct200.cpp" + "src/NpcAct220.cpp" + "src/NpcAct240.cpp" + "src/NpcAct260.cpp" + "src/NpcAct280.cpp" + "src/NpcAct300.cpp" + "src/NpcAct320.cpp" + "src/NpcAct340.cpp" + "src/NpChar.cpp" + "src/NpChar.h" + "src/NpcHit.cpp" + "src/NpcHit.h" + "src/NpcTbl.cpp" + "src/NpcTbl.h" + "src/Organya.cpp" + "src/Organya.h" + "src/PixTone.cpp" + "src/PixTone.h" + "src/Profile.cpp" + "src/Profile.h" + "src/SelStage.cpp" + "src/SelStage.h" + "src/Shoot.cpp" + "src/Shoot.h" + "src/Sound.cpp" + "src/Sound.h" + "src/Stage.cpp" + "src/Stage.h" + "src/Star.cpp" + "src/Star.h" + "src/TextScr.cpp" + "src/TextScr.h" + "src/Triangle.cpp" + "src/Triangle.h" + "src/ValueView.cpp" + "src/ValueView.h" + "src/WindowsWrapper.h" +) + + +################### +# Option handling # +################### + +if(JAPANESE) + set(BUILD_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/game_japanese") + target_compile_definitions(CSE2 PRIVATE JAPANESE) +else() + set(BUILD_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/game_english") +endif() + +if(FIX_BUGS) + target_compile_definitions(CSE2 PRIVATE FIX_BUGS) +endif() + +if(FIX_BUGS OR FIX_MAJOR_BUGS) + target_compile_definitions(CSE2 PRIVATE FIX_MAJOR_BUGS) +endif() + +if(DEBUG_SAVE) + target_compile_definitions(CSE2 PRIVATE DEBUG_SAVE) +endif() + +if(LTO) + include(CheckIPOSupported) + + check_ipo_supported(RESULT result) + + if(result) + set_target_properties(CSE2 PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) + endif() +endif() + +# This is messy as hell, and has been replaced by CMAKE_MSVC_RUNTIME_LIBRARY, +# but that's a very recent CMake addition, so we're still doing it this way for now +if(MSVC AND MSVC_LINK_STATIC_RUNTIME) + # Statically-link the CRT (vcpkg static libs do this) + foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif() + endforeach() +endif() + + +########## +# Tweaks # +########## + +# Make some tweaks if we're using MSVC +if(MSVC) + # Disable warnings that normally fire up on MSVC when using "unsafe" functions instead of using MSVC's "safe" _s functions + target_compile_definitions(CSE2 PRIVATE _CRT_SECURE_NO_WARNINGS) + + # Make it so source files are recognized as UTF-8 by MSVC + target_compile_options(CSE2 PRIVATE "/utf-8") +endif() + + +################## +# Misc. settings # +################## + +# Force strict C90 +set_target_properties(CSE2 PROPERTIES + C_STANDARD 90 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF +) + +# Force strict C++98 +set_target_properties(CSE2 PROPERTIES + CXX_STANDARD 98 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF +) + +# Name debug builds "CSE2_debug", to distinguish them +set_target_properties(CSE2 PROPERTIES DEBUG_OUTPUT_NAME "CSE2_debug") + +# Send executable to the build_en/build_jp directory +set_target_properties(CSE2 PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${BUILD_DIRECTORY} + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${BUILD_DIRECTORY} + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${BUILD_DIRECTORY} + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${BUILD_DIRECTORY} + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${BUILD_DIRECTORY} +) + + +################ +# Dependencies # +################ + +# Link libraries +target_link_libraries(CSE2 PRIVATE ddraw dsound version shlwapi imm32 winmm dxguid gdi32) + +# Newer MSVC is missing `dinput.lib` +if(MSVC AND NOT (MSVC_VERSION LESS 1500)) + target_link_libraries(CSE2 PRIVATE dinput8) +else() + target_link_libraries(CSE2 PRIVATE dinput) +endif() diff --git a/LICENCE.txt b/LICENCE.txt new file mode 100644 index 0000000..e314454 --- /dev/null +++ b/LICENCE.txt @@ -0,0 +1,31 @@ +THIS PROJECT CONTAINS PROPRIETARY CODE AND ASSETS. +THIS IS NOT FREE/LIBRE SOFTWARE OR OPEN-SOURCE SOFTWARE. +USE AT YOUR OWN RISK. + +The original code and assets belongs to Daisuke "Pixel" Amaya. + +Modifications and custom code are under the following licence: + +MIT License + +Copyright (c) 2019 Regan "cuckydev" Green +Copyright (c) 2019-2020 Clownacy +Copyright (c) 2019-2020 Gabriel Ravier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8cdec4a --- /dev/null +++ b/Makefile @@ -0,0 +1,213 @@ +WINDRES ?= windres + +ASSETS_DIRECTORY = assets + +ALL_CXXFLAGS = $(CXXFLAGS) +ALL_LDFLAGS = $(LDFLAGS) +ALL_LIBS = $(LIBS) + +ifeq ($(RELEASE), 1) + ALL_CXXFLAGS += -O3 -DNDEBUG + ALL_LDFLAGS += -s + FILENAME_DEF = CSE2.exe +else + ALL_CXXFLAGS += -Og -ggdb3 + FILENAME_DEF = CSE2_debug.exe +endif + +ifeq ($(JAPANESE), 1) + BUILD_DIRECTORY = game_japanese + + ALL_CXXFLAGS += -DJAPANESE +else + BUILD_DIRECTORY = game_english +endif + +FILENAME ?= $(FILENAME_DEF) + +ifeq ($(FIX_BUGS), 1) + ALL_CXXFLAGS += -DFIX_BUGS -DFIX_MAJOR_BUGS +else + ifeq ($(FIX_MAJOR_BUGS), 1) + ALL_CXXFLAGS += -DFIX_MAJOR_BUGS + endif +endif + +ifeq ($(DEBUG_SAVE), 1) + ALL_CXXFLAGS += -DDEBUG_SAVE +endif + +ALL_CXXFLAGS += -std=c++98 -MMD -MP -MF $@.d +ALL_LIBS += -lkernel32 -lgdi32 -lddraw -ldinput -ldsound -lversion -lshlwapi -limm32 -lwinmm -ldxguid +ALL_LDFLAGS += -mwindows + +ifeq ($(STATIC), 1) + ALL_LDFLAGS += -static +endif + +SOURCES = \ + src/ArmsItem.cpp \ + src/Back.cpp \ + src/Boss.cpp \ + src/BossAlmo1.cpp \ + src/BossAlmo2.cpp \ + src/BossBallos.cpp \ + src/BossFrog.cpp \ + src/BossIronH.cpp \ + src/BossLife.cpp \ + src/BossOhm.cpp \ + src/BossPress.cpp \ + src/BossTwinD.cpp \ + src/BossX.cpp \ + src/BulHit.cpp \ + src/Bullet.cpp \ + src/Caret.cpp \ + src/Config.cpp \ + src/Dialog.cpp \ + src/Draw.cpp \ + src/Ending.cpp \ + src/Escape.cpp \ + src/Fade.cpp \ + src/Flags.cpp \ + src/Flash.cpp \ + src/Frame.cpp \ + src/Game.cpp \ + src/Generic.cpp \ + src/GenericLoad.cpp \ + src/Input.cpp \ + src/KeyControl.cpp \ + src/Main.cpp \ + src/Map.cpp \ + src/MapName.cpp \ + src/MiniMap.cpp \ + src/MyChar.cpp \ + src/MycHit.cpp \ + src/MycParam.cpp \ + src/NpcAct000.cpp \ + src/NpcAct020.cpp \ + src/NpcAct040.cpp \ + src/NpcAct060.cpp \ + src/NpcAct080.cpp \ + src/NpcAct100.cpp \ + src/NpcAct120.cpp \ + src/NpcAct140.cpp \ + src/NpcAct160.cpp \ + src/NpcAct180.cpp \ + src/NpcAct200.cpp \ + src/NpcAct220.cpp \ + src/NpcAct240.cpp \ + src/NpcAct260.cpp \ + src/NpcAct280.cpp \ + src/NpcAct300.cpp \ + src/NpcAct320.cpp \ + src/NpcAct340.cpp \ + src/NpChar.cpp \ + src/NpcHit.cpp \ + src/NpcTbl.cpp \ + src/Organya.cpp \ + src/PixTone.cpp \ + src/Profile.cpp \ + src/SelStage.cpp \ + src/Shoot.cpp \ + src/Sound.cpp \ + src/Stage.cpp \ + src/Star.cpp \ + src/TextScr.cpp \ + src/Triangle.cpp \ + src/ValueView.cpp + +RESOURCES = \ + BITMAP/Credit01.bmp \ + BITMAP/Credit02.bmp \ + BITMAP/Credit03.bmp \ + BITMAP/Credit04.bmp \ + BITMAP/Credit05.bmp \ + BITMAP/Credit06.bmp \ + BITMAP/Credit07.bmp \ + BITMAP/Credit08.bmp \ + BITMAP/Credit09.bmp \ + BITMAP/Credit10.bmp \ + BITMAP/Credit11.bmp \ + BITMAP/Credit12.bmp \ + BITMAP/Credit14.bmp \ + BITMAP/Credit15.bmp \ + BITMAP/Credit16.bmp \ + BITMAP/Credit17.bmp \ + BITMAP/Credit18.bmp \ + BITMAP/pixel.bmp \ + CURSOR/CURSOR_IKA.cur \ + CURSOR/CURSOR_NORMAL.cur \ + ICON/0.ico \ + ICON/ICON_MINI.ico \ + ORG/Access.org \ + ORG/Anzen.org \ + ORG/Balcony.org \ + ORG/Ballos.org \ + ORG/BreakDown.org \ + ORG/Cemetery.org \ + ORG/Curly.org \ + ORG/Dr.org \ + ORG/Ending.org \ + ORG/Escape.org \ + ORG/Fanfale1.org \ + ORG/Fanfale2.org \ + ORG/Fanfale3.org \ + ORG/FireEye.org \ + ORG/Gameover.org \ + ORG/Ginsuke.org \ + ORG/Grand.org \ + ORG/Gravity.org \ + ORG/Hell.org \ + ORG/ironH.org \ + ORG/Jenka.org \ + ORG/Jenka2.org \ + ORG/Kodou.org \ + ORG/LastBtl3.org \ + ORG/LastBtl.org \ + ORG/LastCave.org \ + ORG/Marine.org \ + ORG/Maze.org \ + ORG/MDown2.org \ + ORG/Mura.org \ + ORG/Oside.org \ + ORG/Plant.org \ + ORG/quiet.org \ + ORG/Requiem.org \ + ORG/Toroko.org \ + ORG/Vivi.org \ + ORG/Wanpak2.org \ + ORG/Wanpaku.org \ + ORG/Weed.org \ + ORG/White.org \ + ORG/XXXX.org \ + ORG/Zonbie.org \ + WAVE/Wave.dat + +OBJECTS = $(addprefix obj/$(FILENAME)/, $(addsuffix .o, $(SOURCES))) +DEPENDENCIES = $(addprefix obj/$(FILENAME)/, $(addsuffix .o.d, $(SOURCES))) + +OBJECTS += obj/$(FILENAME)/windows_resources.o + +all: $(BUILD_DIRECTORY)/$(FILENAME) + $(info Finished) + +$(BUILD_DIRECTORY)/$(FILENAME): $(OBJECTS) + @mkdir -p $(@D) + $(info Linking $@) + @$(CXX) $(ALL_CXXFLAGS) $(ALL_LDFLAGS) $^ -o $@ $(ALL_LIBS) + +obj/$(FILENAME)/%.cpp.o: %.cpp + @mkdir -p $(@D) + $(info Compiling $<) + @$(CXX) $(ALL_CXXFLAGS) $< -o $@ -c + +include $(wildcard $(DEPENDENCIES)) + +obj/$(FILENAME)/windows_resources.o: $(ASSETS_DIRECTORY)/resources/CSE2.rc $(ASSETS_DIRECTORY)/resources/resource1.h $(ASSETS_DIRECTORY)/resources/afxres.h $(addprefix $(ASSETS_DIRECTORY)/resources/, $(RESOURCES)) + @mkdir -p $(@D) + $(info Compiling Windows resource file $<) + @$(WINDRES) $< $@ + +# TODO +clean: + @rm -rf obj diff --git a/PHILOSOPHY.md b/PHILOSOPHY.md new file mode 100644 index 0000000..eee5cf6 --- /dev/null +++ b/PHILOSOPHY.md @@ -0,0 +1,68 @@ +# `accurate` branch +Being a pure, plain decompilation of the original `Doukutsu.exe` file (v1.0.0.6), +there should not be much to say about this branch's philosophies: + +## Goal +The end-goal is for the project to be able to produce an `.exe` file that is +identical to the original. This means that there should be no custom code, +decompiled code should ideally be made to produce the same assembly code as the +original, bugs should be left intact, etc. + +Another goal of the project is to document Cave Story's inner-working, so code +should be reasonably-annotated. Likewise, bugs should be documented, and fixes +provided wrapped in `#ifdef FIX_BUGS` conditions. + +## Accuracy to the original source code +Personally, I do aim to make the decompiled code _functionally_-accurate to the +original, down to generating the same assembly code, but I do not aim for +_visually_-accurate code. + +Despite this, I do try to preserve the original function/variable names, +variable-declaration locations, and source file naming. + +Part of the reason why I do not aim for visually-accurate source code is that we +know from the [Organya source code release](https://github.com/shbow/organya/) +what Pixel's code-style looked like, and I find it **extremely** hard to read. + +## Language +Cave Story's developer (Pixel) primarily speaks Japanese, but his code's +variable/function names are mostly written in English (with a few rare instances +of Romanised Japanese). + +The Organya source code release indicates that Pixel wrote his comments in +Japanese, however, in this project, I prefer them to be written in English. + +The English employed in this project is a mix of American English, Canadian +English, and British English. + + + +# `portable` branch +This branch takes a different direction to the `accurate` branch, but they still +share many core philosophies: + +## Goal +While accurately-reproducing Cave Story's original code is still a priority, the +main focus of this branch is to port the game to other platforms, while also +preserving the game the way it was experienced back in 2004. + +Essentially, this branch exists to provide a purist Cave Story experience +without requiring an old Windows XP computer. + +Notably, this means that bugs should still be left intact. However, bugs and +other coding errors that affect portability should be fixed. + +For comparison, I believe this branch shares many parallels with the +Chocolate Doom project. Follow the link below to see that project's list of +philosophies, which may be applicable here: + +https://github.com/chocolate-doom/chocolate-doom/blob/master/PHILOSOPHY.md + +## Custom code +Cave Story's original source code was written in C++, but stylised like C89 +(with a number of exceptions). Custom code added to the project should follow +suit, but the C-style doesn't have to be C89 - personally, I prefer to write in +the subset of C99 that C++98 allows. + +I prefer compiler-specific code to be avoided, since more-portable code benefits +all compilers, and keeps the codebase free of clutter. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ffc603 --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +[![Build Status](https://travis-ci.com/Clownacy/CSE2.svg?branch=accurate)](https://travis-ci.com/Clownacy/CSE2) + +## Table of Contents + +This repo has two main branches: + +Branch | Description +--------|-------- +[accurate](https://www.github.com/Clownacy/CSE2/tree/accurate) | The main decompilation branch. The code is intended to be as close to the original as possible, down to all the bugs and platform-dependencies. +[portable](https://www.github.com/Clownacy/CSE2/tree/portable) | This branch ports the engine away from WinAPI and DirectX, and addresses numerous portability issues, allowing it to run on other platforms. + +# CSE2 + +CSE2 is a decompilation of Cave Story. + +![Screenshot](screenshot.png) + +## Background + +When Pixel made Cave Story, he compiled the original Windows EXE with no +optimisations. This left the generated assembly code extremely verbose and easy +to read. It also made the code very decompiler-friendly, since the assembly +could be mapped directly back to the original C++ code. + +Technically, this alone made a decompilation feasible, as was the case for [the +Super Mario 64 decompilation project](https://github.com/n64decomp/sm64) - +however, there was more to be found... + +In 2007, a Linux port of Cave Story was made by Simon Parzer and Peter Mackay. +Details about it can be found on [Peter's old blog](https://web.archive.org/web/20070911202919/http://aaiiee.wordpress.com:80/). +This port received an update in 2011, including two shiny new executables. What +they didn't realise was that they left huge amounts of debugging information in +these executables, including the names of every C++ source file, as well as the +variables, functions, and structs they contained. + +This was a goldmine of information about not just the game's inner-workings, but +its _source code._ This is the same lucky-break [the Diablo decompilation project](https://github.com/diasurgical/devilution) +had. With it, much of the game's code was pre-documented and explained, saving +us the effort of doing it ourselves. In fact, the combination of +easy-to-decompile code, and a near-full set of function/variable names, reduced +much of the decompilation process to mere copy-paste. + +To top it all off, some of Cave Story's original source code would eventually +see the light of day: + +In early 2018, the Organya music engine was [released on GitHub](https://github.com/shbow/organya) +by an old friend of Pixel's. On top of providing an insight into Pixel's coding +style, this helped with figuring out one of the most complex parts of Cave +Story's codebase. + +And... that's it! It's not often that a game this decompilable comes along, so +I'm glad that Cave Story was one of them. [Patching a dusty old executable from 2005 sucks](https://github.com/Clownacy/Cave-Story-Mod-Loader/blob/master/src/mods/graphics_enhancement/widescreen/patch_camera.c). + +## Building + +### Visual Studio .NET 2003 + +Project files for Visual Studio .NET 2003 are available, and can be found in the +'vs2003' folder. + +As proven by the original `Doukutsu.exe`'s [Rich Header](http://bytepointer.com/articles/the_microsoft_rich_header.htm), +Pixel used Visual Studio .NET 2003 to compile Cave Story. This means these +project files allow us to check the accuracy of the decompilation by comparing +the generated assembly code to that of the original executable. The tool for +this can be found in the 'devilution' folder. + +### CMake (Visual Studio & MinGW-w64) + +Switch to the terminal (Visual Studio users should open the [Developer Command Prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs)) +and `cd` into this folder. After that, generate the files for your build system +with: + +``` +cmake -B build -DCMAKE_BUILD_TYPE=Release +``` + +MSYS2 users should append `-G"MSYS Makefiles"` to this command, also. + +You can also add the following flags: + +Name | Function +--------|-------- +`-DJAPANESE=ON` | Enable the Japanese-language build (instead of the unofficial Aeon Genesis English translation) +`-DFIX_BUGS=ON` | Fix various bugs in the game +`-DFIX_MAJOR_BUGS=ON` | Fix bugs that invoke undefined behaviour or cause memory leaks +`-DDEBUG_SAVE=ON` | Re-enable [the dummied-out 'Debug Save' option](https://tcrf.net/Cave_Story#Debug_Save), and the ability to drag-and-drop save files onto the window +`-DLTO=ON` | Enable link-time optimisation +`-DMSVC_LINK_STATIC_RUNTIME=ON` | Link the static MSVC runtime library, to reduce the number of required DLL files (Visual Studio only) + +You can pass your own compiler flags with `-DCMAKE_C_FLAGS` and `-DCMAKE_CXX_FLAGS`. + +You can then compile CSE2 with this command: + +``` +cmake --build build --config Release +``` + +If you're a Visual Studio user, you can open the generated `CSE2.sln` file +instead, which can be found in the `build` folder. + +Once built, the executable can be found in the `game_english`/`game_japanese` +folder, depending on the selected language. + +### Makefile (MinGW-w64) \[deprecated - use CMake instead\] + +Run 'make' in this folder, preferably with some of the following settings: + +Name | Function +--------|-------- +`JAPANESE=1` | Enable the Japanese-language build (instead of the unofficial Aeon Genesis English translation) +`FIX_BUGS=1` | Fix various bugs in the game +`FIX_MAJOR_BUGS=1` | Fix bugs that invoke undefined behaviour or cause memory leaks +`DEBUG_SAVE=1` | Re-enable [the dummied-out 'Debug Save' option](https://tcrf.net/Cave_Story#Debug_Save), and the ability to drag-and-drop save files onto the window +`RELEASE=1` | Compile a release build (optimised, stripped, etc.) +`STATIC=1` | Produce a statically-linked executable (so you don't need to bundle DLL files) + +You can pass your own compiler flags by defining `CXXFLAGS`. + +Once built, the executable can be found in the `game_english`/`game_japanese` +folder, depending on the selected language. + +## Licensing + +Being a decompilation, the majority of the code in this project is proprietary +and belongs to Daisuke "Pixel" Amaya. + +Modifications and custom code are made available under the MIT licence. See +`LICENCE.txt` for details. diff --git a/assets/resources/BITMAP/Credit01.bmp b/assets/resources/BITMAP/Credit01.bmp new file mode 100644 index 0000000..4f52f89 Binary files /dev/null and b/assets/resources/BITMAP/Credit01.bmp differ diff --git a/assets/resources/BITMAP/Credit02.bmp b/assets/resources/BITMAP/Credit02.bmp new file mode 100644 index 0000000..739f8aa Binary files /dev/null and b/assets/resources/BITMAP/Credit02.bmp differ diff --git a/assets/resources/BITMAP/Credit03.bmp b/assets/resources/BITMAP/Credit03.bmp new file mode 100644 index 0000000..3f0f201 Binary files /dev/null and b/assets/resources/BITMAP/Credit03.bmp differ diff --git a/assets/resources/BITMAP/Credit04.bmp b/assets/resources/BITMAP/Credit04.bmp new file mode 100644 index 0000000..5f8851b Binary files /dev/null and b/assets/resources/BITMAP/Credit04.bmp differ diff --git a/assets/resources/BITMAP/Credit05.bmp b/assets/resources/BITMAP/Credit05.bmp new file mode 100644 index 0000000..af21ba8 Binary files /dev/null and b/assets/resources/BITMAP/Credit05.bmp differ diff --git a/assets/resources/BITMAP/Credit06.bmp b/assets/resources/BITMAP/Credit06.bmp new file mode 100644 index 0000000..0d75ebf Binary files /dev/null and b/assets/resources/BITMAP/Credit06.bmp differ diff --git a/assets/resources/BITMAP/Credit07.bmp b/assets/resources/BITMAP/Credit07.bmp new file mode 100644 index 0000000..94ca760 Binary files /dev/null and b/assets/resources/BITMAP/Credit07.bmp differ diff --git a/assets/resources/BITMAP/Credit08.bmp b/assets/resources/BITMAP/Credit08.bmp new file mode 100644 index 0000000..269c01f Binary files /dev/null and b/assets/resources/BITMAP/Credit08.bmp differ diff --git a/assets/resources/BITMAP/Credit09.bmp b/assets/resources/BITMAP/Credit09.bmp new file mode 100644 index 0000000..c23be4e Binary files /dev/null and b/assets/resources/BITMAP/Credit09.bmp differ diff --git a/assets/resources/BITMAP/Credit10.bmp b/assets/resources/BITMAP/Credit10.bmp new file mode 100644 index 0000000..7bcc863 Binary files /dev/null and b/assets/resources/BITMAP/Credit10.bmp differ diff --git a/assets/resources/BITMAP/Credit11.bmp b/assets/resources/BITMAP/Credit11.bmp new file mode 100644 index 0000000..6b7b6f5 Binary files /dev/null and b/assets/resources/BITMAP/Credit11.bmp differ diff --git a/assets/resources/BITMAP/Credit12.bmp b/assets/resources/BITMAP/Credit12.bmp new file mode 100644 index 0000000..befa134 Binary files /dev/null and b/assets/resources/BITMAP/Credit12.bmp differ diff --git a/assets/resources/BITMAP/Credit14.bmp b/assets/resources/BITMAP/Credit14.bmp new file mode 100644 index 0000000..b56eed0 Binary files /dev/null and b/assets/resources/BITMAP/Credit14.bmp differ diff --git a/assets/resources/BITMAP/Credit15.bmp b/assets/resources/BITMAP/Credit15.bmp new file mode 100644 index 0000000..be871c4 Binary files /dev/null and b/assets/resources/BITMAP/Credit15.bmp differ diff --git a/assets/resources/BITMAP/Credit16.bmp b/assets/resources/BITMAP/Credit16.bmp new file mode 100644 index 0000000..58ccc0d Binary files /dev/null and b/assets/resources/BITMAP/Credit16.bmp differ diff --git a/assets/resources/BITMAP/Credit17.bmp b/assets/resources/BITMAP/Credit17.bmp new file mode 100644 index 0000000..7dc4352 Binary files /dev/null and b/assets/resources/BITMAP/Credit17.bmp differ diff --git a/assets/resources/BITMAP/Credit18.bmp b/assets/resources/BITMAP/Credit18.bmp new file mode 100644 index 0000000..99d5476 Binary files /dev/null and b/assets/resources/BITMAP/Credit18.bmp differ diff --git a/assets/resources/BITMAP/pixel.bmp b/assets/resources/BITMAP/pixel.bmp new file mode 100644 index 0000000..41ef712 Binary files /dev/null and b/assets/resources/BITMAP/pixel.bmp differ diff --git a/assets/resources/BITMAP/pixel_jp.bmp b/assets/resources/BITMAP/pixel_jp.bmp new file mode 100644 index 0000000..b25bba0 Binary files /dev/null and b/assets/resources/BITMAP/pixel_jp.bmp differ diff --git a/assets/resources/CSE2.rc b/assets/resources/CSE2.rc new file mode 100644 index 0000000..dd49fe8 --- /dev/null +++ b/assets/resources/CSE2.rc @@ -0,0 +1,284 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Japanese resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) +#ifdef _WIN32 +LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT +#pragma code_page(932) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,6 + PRODUCTVERSION 1,0,0,6 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041104b0" + BEGIN + VALUE "FileDescription", "Doukutsu" + VALUE "FileVersion", "1, 0, 0, 6" + VALUE "InternalName", "Doukutsu Monogatari" + VALUE "LegalCopyright", "I can't get MSVC2003 to understand Japanese so here's a placeholder" + VALUE "OriginalFilename", "Doukutsu.exe" + VALUE "ProductName", "I can't get MSVC2003 to understand Japanese so here's a placeholder" + VALUE "ProductVersion", "1, 0, 0, 6" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x411, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +CREDIT01 BITMAP "BITMAP/Credit01.bmp" +CREDIT02 BITMAP "BITMAP/Credit02.bmp" +CREDIT03 BITMAP "BITMAP/Credit03.bmp" +CREDIT04 BITMAP "BITMAP/Credit04.bmp" +CREDIT05 BITMAP "BITMAP/Credit05.bmp" +CREDIT06 BITMAP "BITMAP/Credit06.bmp" +CREDIT07 BITMAP "BITMAP/Credit07.bmp" +CREDIT08 BITMAP "BITMAP/Credit08.bmp" +CREDIT09 BITMAP "BITMAP/Credit09.bmp" +CREDIT10 BITMAP "BITMAP/Credit10.bmp" +CREDIT11 BITMAP "BITMAP/Credit11.bmp" +CREDIT12 BITMAP "BITMAP/Credit12.bmp" +CREDIT14 BITMAP "BITMAP/Credit14.bmp" +CREDIT15 BITMAP "BITMAP/Credit15.bmp" +CREDIT16 BITMAP "BITMAP/Credit16.bmp" +CREDIT17 BITMAP "BITMAP/Credit17.bmp" +CREDIT18 BITMAP "BITMAP/Credit18.bmp" +PIXEL BITMAP "BITMAP/pixel.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// ORG +// + +ACCESS ORG "ORG/Access.org" +ANZEN ORG "ORG/Anzen.org" +BALCONY ORG "ORG/Balcony.org" +BALLOS ORG "ORG/Ballos.org" +BDOWN ORG "ORG/BreakDown.org" +CEMETERY ORG "ORG/Cemetery.org" +CURLY ORG "ORG/Curly.org" +DR ORG "ORG/Dr.org" +ENDING ORG "ORG/Ending.org" +ESCAPE ORG "ORG/Escape.org" +FANFALE1 ORG "ORG/Fanfale1.org" +FANFALE2 ORG "ORG/Fanfale2.org" +FANFALE3 ORG "ORG/Fanfale3.org" +FIREEYE ORG "ORG/FireEye.org" +GAMEOVER ORG "ORG/Gameover.org" +GINSUKE ORG "ORG/Ginsuke.org" +GRAND ORG "ORG/Grand.org" +GRAVITY ORG "ORG/Gravity.org" +HELL ORG "ORG/Hell.org" +IRONH ORG "ORG/ironH.org" +JENKA ORG "ORG/Jenka.org" +JENKA2 ORG "ORG/Jenka2.org" +KODOU ORG "ORG/Kodou.org" +LASTBTL ORG "ORG/LastBtl.org" +LASTBT3 ORG "ORG/LastBtl3.org" +LASTCAVE ORG "ORG/LastCave.org" +MARINE ORG "ORG/Marine.org" +MAZE ORG "ORG/Maze.org" +MDOWN2 ORG "ORG/MDown2.org" +OSIDE ORG "ORG/Oside.org" +MURA ORG "ORG/Mura.org" +PLANT ORG "ORG/Plant.org" +QUIET ORG "ORG/quiet.org" +REQUIEM ORG "ORG/Requiem.org" +TOROKO ORG "ORG/Toroko.org" +VIVI ORG "ORG/Vivi.org" +WANPAK2 ORG "ORG/Wanpak2.org" +WANPAKU ORG "ORG/Wanpaku.org" +WEED ORG "ORG/Weed.org" +WHITE ORG "ORG/White.org" +XXXX ORG "ORG/XXXX.org" +ZONBIE ORG "ORG/Zonbie.org" + +///////////////////////////////////////////////////////////////////////////// +// +// WAVE +// + +WAVE100 WAVE "WAVE/Wave.dat" + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +CURSOR_IKA CURSOR "CURSOR/CURSOR_IKA.cur" +CURSOR_NORMAL CURSOR "CURSOR/CURSOR_NORMAL.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +0 ICON "ICON/0.ico" +ICON_MINI ICON "ICON/ICON_MINI.ico" +#endif // Japanese resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MENU_MAIN MENU +BEGIN + MENUITEM "Quit", 40001 + MENUITEM "Volume", 40004 + MENUITEM "Version", 40002 + MENUITEM "Debug Save", 40005 + MENUITEM "Mute", 40007 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +DLG_ABOUT DIALOGEX 0, 0, 123, 75 +STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 9, "Arial", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",1,37,54,50,14,BS_FLAT + CTEXT "---",1011,7,14,109,35 +END + +DLG_MUTE DIALOGEX 0, 0, 118, 111 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Mute" +FONT 9, "Arial", 400, 0, 0x80 +BEGIN + DEFPUSHBUTTON "OK",1,7,90,50,14 + PUSHBUTTON "Cancel",2,61,90,50,14 + CONTROL "0",1010,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,7,7,20,10 + CONTROL "1",1018,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,17,15,20,10 + CONTROL "2",1019,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,26,24,20,10 + CONTROL "3",1020,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,35,33,20,10 + CONTROL "4",1021,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,45,41,20,10 + CONTROL "5",1022,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,54,50,20,10 + CONTROL "6",1023,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,63,58,20,10 + CONTROL "7",1024,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | + WS_TABSTOP,73,67,20,10 +END + +DLG_SAVE DIALOGEX 0, 0, 118, 47 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Save" +FONT 9, "Arial", 0, 0, 0x1 +BEGIN + EDITTEXT 1008,36,8,72,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",1,8,28,48,12 + PUSHBUTTON "Cancel",2,60,28,48,12 + LTEXT "Name",-1,8,8,20,12,SS_CENTERIMAGE +END + +DLG_YESNO DIALOGEX 0, 0, 119, 49 +STYLE DS_SETFONT | WS_POPUP | WS_CAPTION +FONT 9, "Arial", 400, 0, 0x80 +BEGIN + PUSHBUTTON "Yes",1,7,28,50,14,BS_FLAT + PUSHBUTTON "No",2,62,28,50,14,BS_FLAT + CTEXT "---",1009,7,8,105,15,SS_CENTERIMAGE +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/assets/resources/CURSOR/CURSOR_IKA.cur b/assets/resources/CURSOR/CURSOR_IKA.cur new file mode 100644 index 0000000..488b84b Binary files /dev/null and b/assets/resources/CURSOR/CURSOR_IKA.cur differ diff --git a/assets/resources/CURSOR/CURSOR_NORMAL.cur b/assets/resources/CURSOR/CURSOR_NORMAL.cur new file mode 100644 index 0000000..a70f9c5 Binary files /dev/null and b/assets/resources/CURSOR/CURSOR_NORMAL.cur differ diff --git a/assets/resources/ICON/0.ico b/assets/resources/ICON/0.ico new file mode 100644 index 0000000..33fc2aa Binary files /dev/null and b/assets/resources/ICON/0.ico differ diff --git a/assets/resources/ICON/ICON_MINI.ico b/assets/resources/ICON/ICON_MINI.ico new file mode 100644 index 0000000..b540fd2 Binary files /dev/null and b/assets/resources/ICON/ICON_MINI.ico differ diff --git a/assets/resources/ORG/Access.org b/assets/resources/ORG/Access.org new file mode 100644 index 0000000..86c6e36 Binary files /dev/null and b/assets/resources/ORG/Access.org differ diff --git a/assets/resources/ORG/Anzen.org b/assets/resources/ORG/Anzen.org new file mode 100644 index 0000000..6953f51 Binary files /dev/null and b/assets/resources/ORG/Anzen.org differ diff --git a/assets/resources/ORG/Balcony.org b/assets/resources/ORG/Balcony.org new file mode 100644 index 0000000..f6397dd Binary files /dev/null and b/assets/resources/ORG/Balcony.org differ diff --git a/assets/resources/ORG/Ballos.org b/assets/resources/ORG/Ballos.org new file mode 100644 index 0000000..d8b74a7 Binary files /dev/null and b/assets/resources/ORG/Ballos.org differ diff --git a/assets/resources/ORG/BreakDown.org b/assets/resources/ORG/BreakDown.org new file mode 100644 index 0000000..71dde3d Binary files /dev/null and b/assets/resources/ORG/BreakDown.org differ diff --git a/assets/resources/ORG/Cemetery.org b/assets/resources/ORG/Cemetery.org new file mode 100644 index 0000000..1af127d Binary files /dev/null and b/assets/resources/ORG/Cemetery.org differ diff --git a/assets/resources/ORG/Curly.org b/assets/resources/ORG/Curly.org new file mode 100644 index 0000000..621e7ed Binary files /dev/null and b/assets/resources/ORG/Curly.org differ diff --git a/assets/resources/ORG/Dr.org b/assets/resources/ORG/Dr.org new file mode 100644 index 0000000..bbb0b34 Binary files /dev/null and b/assets/resources/ORG/Dr.org differ diff --git a/assets/resources/ORG/Ending.org b/assets/resources/ORG/Ending.org new file mode 100644 index 0000000..e679dce Binary files /dev/null and b/assets/resources/ORG/Ending.org differ diff --git a/assets/resources/ORG/Escape.org b/assets/resources/ORG/Escape.org new file mode 100644 index 0000000..30f982f Binary files /dev/null and b/assets/resources/ORG/Escape.org differ diff --git a/assets/resources/ORG/Fanfale1.org b/assets/resources/ORG/Fanfale1.org new file mode 100644 index 0000000..30084a9 Binary files /dev/null and b/assets/resources/ORG/Fanfale1.org differ diff --git a/assets/resources/ORG/Fanfale2.org b/assets/resources/ORG/Fanfale2.org new file mode 100644 index 0000000..afdc2d4 Binary files /dev/null and b/assets/resources/ORG/Fanfale2.org differ diff --git a/assets/resources/ORG/Fanfale3.org b/assets/resources/ORG/Fanfale3.org new file mode 100644 index 0000000..da0eb0c Binary files /dev/null and b/assets/resources/ORG/Fanfale3.org differ diff --git a/assets/resources/ORG/FireEye.org b/assets/resources/ORG/FireEye.org new file mode 100644 index 0000000..61b3404 Binary files /dev/null and b/assets/resources/ORG/FireEye.org differ diff --git a/assets/resources/ORG/Gameover.org b/assets/resources/ORG/Gameover.org new file mode 100644 index 0000000..5276ec0 Binary files /dev/null and b/assets/resources/ORG/Gameover.org differ diff --git a/assets/resources/ORG/Ginsuke.org b/assets/resources/ORG/Ginsuke.org new file mode 100644 index 0000000..9737449 Binary files /dev/null and b/assets/resources/ORG/Ginsuke.org differ diff --git a/assets/resources/ORG/Grand.org b/assets/resources/ORG/Grand.org new file mode 100644 index 0000000..5a8e754 Binary files /dev/null and b/assets/resources/ORG/Grand.org differ diff --git a/assets/resources/ORG/Gravity.org b/assets/resources/ORG/Gravity.org new file mode 100644 index 0000000..6625416 Binary files /dev/null and b/assets/resources/ORG/Gravity.org differ diff --git a/assets/resources/ORG/Hell.org b/assets/resources/ORG/Hell.org new file mode 100644 index 0000000..7115b7b Binary files /dev/null and b/assets/resources/ORG/Hell.org differ diff --git a/assets/resources/ORG/Jenka.org b/assets/resources/ORG/Jenka.org new file mode 100644 index 0000000..645719d Binary files /dev/null and b/assets/resources/ORG/Jenka.org differ diff --git a/assets/resources/ORG/Jenka2.org b/assets/resources/ORG/Jenka2.org new file mode 100644 index 0000000..c0ec90c Binary files /dev/null and b/assets/resources/ORG/Jenka2.org differ diff --git a/assets/resources/ORG/Kodou.org b/assets/resources/ORG/Kodou.org new file mode 100644 index 0000000..5a980d6 Binary files /dev/null and b/assets/resources/ORG/Kodou.org differ diff --git a/assets/resources/ORG/LastBtl.org b/assets/resources/ORG/LastBtl.org new file mode 100644 index 0000000..e422161 Binary files /dev/null and b/assets/resources/ORG/LastBtl.org differ diff --git a/assets/resources/ORG/LastBtl3.org b/assets/resources/ORG/LastBtl3.org new file mode 100644 index 0000000..7daf808 Binary files /dev/null and b/assets/resources/ORG/LastBtl3.org differ diff --git a/assets/resources/ORG/LastCave.org b/assets/resources/ORG/LastCave.org new file mode 100644 index 0000000..1e56324 Binary files /dev/null and b/assets/resources/ORG/LastCave.org differ diff --git a/assets/resources/ORG/MDown2.org b/assets/resources/ORG/MDown2.org new file mode 100644 index 0000000..e2b96f9 Binary files /dev/null and b/assets/resources/ORG/MDown2.org differ diff --git a/assets/resources/ORG/Marine.org b/assets/resources/ORG/Marine.org new file mode 100644 index 0000000..d4251c8 Binary files /dev/null and b/assets/resources/ORG/Marine.org differ diff --git a/assets/resources/ORG/Maze.org b/assets/resources/ORG/Maze.org new file mode 100644 index 0000000..169bb20 Binary files /dev/null and b/assets/resources/ORG/Maze.org differ diff --git a/assets/resources/ORG/Mura.org b/assets/resources/ORG/Mura.org new file mode 100644 index 0000000..0af7aed Binary files /dev/null and b/assets/resources/ORG/Mura.org differ diff --git a/assets/resources/ORG/Oside.org b/assets/resources/ORG/Oside.org new file mode 100644 index 0000000..9153d66 Binary files /dev/null and b/assets/resources/ORG/Oside.org differ diff --git a/assets/resources/ORG/Plant.org b/assets/resources/ORG/Plant.org new file mode 100644 index 0000000..26ca085 Binary files /dev/null and b/assets/resources/ORG/Plant.org differ diff --git a/assets/resources/ORG/Requiem.org b/assets/resources/ORG/Requiem.org new file mode 100644 index 0000000..acd9125 Binary files /dev/null and b/assets/resources/ORG/Requiem.org differ diff --git a/assets/resources/ORG/Toroko.org b/assets/resources/ORG/Toroko.org new file mode 100644 index 0000000..cc2ca9b Binary files /dev/null and b/assets/resources/ORG/Toroko.org differ diff --git a/assets/resources/ORG/Vivi.org b/assets/resources/ORG/Vivi.org new file mode 100644 index 0000000..50a7b42 Binary files /dev/null and b/assets/resources/ORG/Vivi.org differ diff --git a/assets/resources/ORG/Wanpak2.org b/assets/resources/ORG/Wanpak2.org new file mode 100644 index 0000000..6de1c19 Binary files /dev/null and b/assets/resources/ORG/Wanpak2.org differ diff --git a/assets/resources/ORG/Wanpaku.org b/assets/resources/ORG/Wanpaku.org new file mode 100644 index 0000000..25349a7 Binary files /dev/null and b/assets/resources/ORG/Wanpaku.org differ diff --git a/assets/resources/ORG/Weed.org b/assets/resources/ORG/Weed.org new file mode 100644 index 0000000..9ed0977 Binary files /dev/null and b/assets/resources/ORG/Weed.org differ diff --git a/assets/resources/ORG/White.org b/assets/resources/ORG/White.org new file mode 100644 index 0000000..172259a Binary files /dev/null and b/assets/resources/ORG/White.org differ diff --git a/assets/resources/ORG/XXXX.org b/assets/resources/ORG/XXXX.org new file mode 100644 index 0000000..64f9c04 Binary files /dev/null and b/assets/resources/ORG/XXXX.org differ diff --git a/assets/resources/ORG/Zonbie.org b/assets/resources/ORG/Zonbie.org new file mode 100644 index 0000000..182c539 Binary files /dev/null and b/assets/resources/ORG/Zonbie.org differ diff --git a/assets/resources/ORG/ironH.org b/assets/resources/ORG/ironH.org new file mode 100644 index 0000000..48e1cf5 Binary files /dev/null and b/assets/resources/ORG/ironH.org differ diff --git a/assets/resources/ORG/quiet.org b/assets/resources/ORG/quiet.org new file mode 100644 index 0000000..0340484 Binary files /dev/null and b/assets/resources/ORG/quiet.org differ diff --git a/assets/resources/WAVE/Wave.dat b/assets/resources/WAVE/Wave.dat new file mode 100644 index 0000000..fb001d3 Binary files /dev/null and b/assets/resources/WAVE/Wave.dat differ diff --git a/assets/resources/afxres.h b/assets/resources/afxres.h new file mode 100644 index 0000000..4c082f7 --- /dev/null +++ b/assets/resources/afxres.h @@ -0,0 +1,3 @@ +// Quick-and-dirty shim to make CSE2.rc work in newer versions of Visual Studio + +#include "windows.h" diff --git a/assets/resources/resource1.h b/assets/resources/resource1.h new file mode 100644 index 0000000..d53bca0 --- /dev/null +++ b/assets/resources/resource1.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CSE2.rc +// + +// Next default values for new objects +// + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 172 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/devilution/Doukutsu.exe b/devilution/Doukutsu.exe new file mode 100644 index 0000000..0fcc40f Binary files /dev/null and b/devilution/Doukutsu.exe differ diff --git a/devilution/comparer-config.toml b/devilution/comparer-config.toml new file mode 100644 index 0000000..1039c25 --- /dev/null +++ b/devilution/comparer-config.toml @@ -0,0 +1,3327 @@ +# conversion between function and file location of the functions +# = (0x401000 - PE header offset) (0x400 for VC5 linker) +address_offset = 0x400000 + +[[func]] +name = "ClearArmsData" +addr = 0x401000 + +[[func]] +name = "ClearItemData" +addr = 0x401030 + +[[func]] +name = "AddArmsData" +addr = 0x401050 + +[[func]] +name = "SubArmsData" +addr = 0x401160 + +[[func]] +name = "TradeArms" +addr = 0x401220 + +[[func]] +name = "AddItemData" +addr = 0x4012D0 + +[[func]] +name = "SubItemData" +addr = 0x401330 + +[[func]] +name = "MoveCampCursor" +addr = 0x4013C0 + +[[func]] +name = "PutCampObject" +addr = 0x4016F0 + +[[func]] +name = "CampLoop" +addr = 0x401D10 + +[[func]] +name = "CheckItem" +addr = 0x401F20 + +[[func]] +name = "CheckArms" +addr = 0x401F60 + +[[func]] +name = "UseArmsEnergy" +addr = 0x401FA0 + +[[func]] +name = "ChargeArmsEnergy" +addr = 0x402020 + +[[func]] +name = "FullArmsEnergy" +addr = 0x402090 + +[[func]] +name = "RotationArms" +addr = 0x4020E0 + +[[func]] +name = "RotationArmsRev" +addr = 0x402190 + +[[func]] +name = "ChangeToFirstArms" +addr = 0x402240 + +[[func]] +name = "InitBack" +addr = 0x402270 +size = 0x100 + +[[func]] +name = "ActBack" +addr = 0x402370 + +[[func]] +name = "PutBack" +addr = 0x4023D0 + +[[func]] +name = "PutFront" +addr = 0x402830 + +[[func]] +name = "JudgeHitBulletBlock" +addr = 0x4029B0 + +[[func]] +name = "JudgeHitBulletBlock2" +addr = 0x402B30 + +[[func]] +name = "JudgeHitBulletTriangleA" +addr = 0x402FC0 + +[[func]] +name = "JudgeHitBulletTriangleB" +addr = 0x4030B0 + +[[func]] +name = "JudgeHitBulletTriangleC" +addr = 0x4031A0 + +[[func]] +name = "JudgeHitBulletTriangleD" +addr = 0x403290 + +[[func]] +name = "JudgeHitBulletTriangleE" +addr = 0x403380 + +[[func]] +name = "JudgeHitBulletTriangleF" +addr = 0x403470 + +[[func]] +name = "JudgeHitBulletTriangleG" +addr = 0x403560 + +[[func]] +name = "JudgeHitBulletTriangleH" +addr = 0x403650 + +[[func]] +name = "HitBulletMap" +addr = 0x403740 + +[[func]] +name = "InitBullet" +addr = 0x403C00 + +[[func]] +name = "CountArmsBullet" +addr = 0x403C40 + +[[func]] +name = "CountBulletNum" +addr = 0x403CB0 + +[[func]] +name = "DeleteBullet" +addr = 0x403D10 + +[[func]] +name = "ClearBullet" +addr = 0x403D80 + +[[func]] +name = "PutBullet" +addr = 0x403DC0 + +[[func]] +name = "SetBullet" +addr = 0x403F80 + +[[func]] +name = "ActBullet_Frontia1" +addr = 0x404160 + +[[func]] +name = "ActBullet_Frontia2" +addr = 0x4043F0 + +[[func]] +name = "ActBullet_PoleStar" +addr = 0x4047B0 + +[[func]] +name = "ActBullet_FireBall" +addr = 0x404B30 + +[[func]] +name = "ActBullet_MachineGun" +addr = 0x405120 + +[[func]] +name = "ActBullet_Missile" +addr = 0x4055A0 + +[[func]] +name = "ActBullet_Bom" +addr = 0x405D80 + +[[func]] +name = "ActBullet_Bubblin1" +addr = 0x405F30 + +[[func]] +name = "ActBullet_Bubblin2" +addr = 0x406190 + +[[func]] +name = "ActBullet_Bubblin3" +addr = 0x4064D0 + +[[func]] +name = "ActBullet_Spine" +addr = 0x4068B0 + +[[func]] +name = "ActBullet_Sword1" +addr = 0x406BB0 + +[[func]] +name = "ActBullet_Sword2" +addr = 0x406E60 + +[[func]] +name = "ActBullet_Sword3" +addr = 0x407110 + +[[func]] +name = "ActBullet_Edge" +addr = 0x4075E0 + +[[func]] +name = "ActBullet_Drop" +addr = 0x4078A0 + +[[func]] +name = "ActBullet_SuperMissile" +addr = 0x407910 + +[[func]] +name = "ActBullet_SuperBom" +addr = 0x408080 + +[[func]] +name = "ActBullet_Nemesis" +addr = 0x408230 + +[[func]] +name = "ActBullet_Spur" +addr = 0x408710 + +[[func]] +name = "ActBullet_SpurTail" +addr = 0x408AE0 + +[[func]] +name = "ActBullet_EnemyClear" +addr = 0x408F40 + +[[func]] +name = "ActBullet_Star" +addr = 0x408F90 + +[[func]] +name = "ActBullet" +addr = 0x408FC0 + +[[func]] +name = "IsActiveSomeBullet" +addr = 0x4095C0 + +[[func]] +name = "InitCaret" +addr = 0x409650 + +[[func]] +name = "ActCaret00" +addr = 0x409670 + +[[func]] +name = "ActCaret01" +addr = 0x409680 + +[[func]] +name = "ActCaret02" +addr = 0x409880 + +[[func]] +name = "ActCaret03" +addr = 0x409B80 + +[[func]] +name = "ActCaret04" +addr = 0x409C70 + +[[func]] +name = "ActCaret05" +addr = 0x409E00 + +[[func]] +name = "ActCaret07" +addr = 0x409F60 + +[[func]] +name = "ActCaret08" +addr = 0x40A120 + +[[func]] +name = "ActCaret09" +addr = 0x40A1B0 + +[[func]] +name = "ActCaret10" +addr = 0x40A280 + +[[func]] +name = "ActCaret11" +addr = 0x40A3F0 + +[[func]] +name = "ActCaret12" +addr = 0x40A5A0 + +[[func]] +name = "ActCaret13" +addr = 0x40A650 + +[[func]] +name = "ActCaret14" +addr = 0x40A7E0 + +[[func]] +name = "ActCaret15" +addr = 0x40A8F0 + +[[func]] +name = "ActCaret16" +addr = 0x40A9E0 + +[[func]] +name = "ActCaret17" +addr = 0x40AAA0 + +[[func]] +name = "ActCaret" +addr = 0x40AB50 + +[[func]] +name = "PutCaret" +addr = 0x40ABC0 + +[[func]] +name = "SetCaret" +addr = 0x40AC90 + +[[func]] +name = "LoadConfigData" +addr = 0x40AD60 + +[[func]] +name = "DefaultConfigData" +addr = 0x40AE30 + +[[func]] +name = "VersionDialog" +addr = 0x40AEC0 + +[[func]] +name = "DebugMuteDialog" +addr = 0x40AFC0 + +[[func]] +name = "DebugSaveDialog" +addr = 0x40B1D0 + +[[func]] +name = "QuitDialog" +addr = 0x40B290 + +[[func]] +name = "SetClientOffset" +addr = 0x40B320 + +[[func]] +name = "Flip_SystemTask" +addr = 0x40B340 + +[[func]] +name = "StartDirectDraw" +addr = 0x40B450 + +[[func]] +name = "EndDirectDraw" +addr = 0x40B6C0 + +[[func]] +name = "ReleaseSurface" +addr = 0x40B7A0 + +[[func]] +name = "MakeSurface_Resource" +addr = 0x40B800 +size = 0x2BB + +[[func]] +name = "MakeSurface_File" +addr = 0x40BAC0 +size = 0x34F + +[[func]] +name = "ReloadBitmap_Resource" +addr = 0x40BE10 + +[[func]] +name = "ReloadBitmap_File" +addr = 0x40BFD0 + +[[func]] +name = "MakeSurface_Generic" +addr = 0x40C1D0 + +[[func]] +name = "BackupSurface" +addr = 0x40C320 + +[[func]] +name = "PutBitmap3" +addr = 0x40C3C0 + +[[func]] +name = "PutBitmap4" +addr = 0x40C5B0 + +[[func]] +name = "Surface2Surface" +addr = 0x40C7A0 + +[[func]] +name = "GetCortBoxColor" +addr = 0x40C8B0 + +[[func]] +name = "CortBox" +addr = 0x40C9E0 + +[[func]] +name = "CortBox2" +addr = 0x40CA80 + +[[func]] +name = "out" +addr = 0x40CB30 + +[[func]] +name = "RestoreSurfaces" +addr = 0x40CB60 + +[[func]] +name = "InitTextObject" +addr = 0x40CD50 + +[[func]] +name = "PutText" +addr = 0x40CE00 + +[[func]] +name = "PutText2" +addr = 0x40CEB0 + +[[func]] +name = "EndTextObject" +addr = 0x40CF70 + +[[func]] +name = "ActionStripper" +addr = 0x40CF90 + +[[func]] +name = "PutStripper" +addr = 0x40D010 + +[[func]] +name = "SetStripper" +addr = 0x40D150 + +[[func]] +name = "RestoreStripper" +addr = 0x40D240 + +[[func]] +name = "ActionIllust" +addr = 0x40D2D0 + +[[func]] +name = "PutIllust" +addr = 0x40D350 + +[[func]] +name = "ReloadIllust" +addr = 0x40D3A0 + +[[func]] +name = "InitCreditScript" +addr = 0x40D3E0 + +[[func]] +name = "ReleaseCreditScript" +addr = 0x40D410 + +[[func]] +name = "StartCreditScript" +addr = 0x40D440 + +[[func]] +name = "ActionCredit" +addr = 0x40D5C0 + +[[func]] +name = "ActionCredit_Read" +addr = 0x40D620 + +[[func]] +name = "GetScriptNumber" +addr = 0x40DB00 + +[[func]] +name = "SetCreditIllust" +addr = 0x40DB40 + +[[func]] +name = "CutCreditIllust" +addr = 0x40DB60 + +[[func]] +name = "Scene_DownIsland" +addr = 0x40DB70 + +[[func]] +name = "Call_Escape" +addr = 0x40DD70 + +[[func]] +name = "InitFade" +addr = 0x40DE60 + +[[func]] +name = "SetFadeMask" +addr = 0x40DE90 + +[[func]] +name = "ClearFade" +addr = 0x40DEA0 + +[[func]] +name = "StartFadeOut" +addr = 0x40DEC0 + +[[func]] +name = "StartFadeIn" +addr = 0x40DF50 + +[[func]] +name = "ProcFade" +addr = 0x40DFE0 + +[[func]] +name = "PutFade" +addr = 0x40E770 + +[[func]] +name = "GetFadeActive" +addr = 0x40E830 + +[[func]] +name = "InitFlags" +addr = 0x40E850 + +[[func]] +name = "InitSkipFlags" +addr = 0x40E870 + +[[func]] +name = "SetNPCFlag" +addr = 0x40E890 + +[[func]] +name = "CutNPCFlag" +addr = 0x40E8E0 + +[[func]] +name = "GetNPCFlag" +addr = 0x40E930 + +[[func]] +name = "SetSkipFlag" +addr = 0x40E970 + +[[func]] +name = "CutSkipFlag" +addr = 0x40E9C0 + +[[func]] +name = "GetSkipFlag" +addr = 0x40EA10 + +[[func]] +name = "InitFlash" +addr = 0x40EA50 + +[[func]] +name = "SetFlash" +addr = 0x40EA70 + +[[func]] +name = "ActFlash_Explosion" +addr = 0x40EAC0 + +[[func]] +name = "ActFlash_Flash" +addr = 0x40ED20 + +[[func]] +name = "ActFlash" +addr = 0x40EDE0 + +[[func]] +name = "PutFlash" +addr = 0x40EE20 + +[[func]] +name = "ResetFlash" +addr = 0x40EE60 + +[[func]] +name = "MoveFrame3" +addr = 0x40EE70 + +[[func]] +name = "GetFramePosition" +addr = 0x40F020 + +[[func]] +name = "SetFramePosition" +addr = 0x40F040 + +[[func]] +name = "SetFrameMyChar" +addr = 0x40F130 + +[[func]] +name = "SetFrameTargetMyChar" +addr = 0x40F220 + +[[func]] +name = "SetFrameTargetNpChar" +addr = 0x40F250 + +[[func]] +name = "SetFrameTargetBoss" +addr = 0x40F2D0 + +[[func]] +name = "SetQuake" +addr = 0x40F310 + +[[func]] +name = "SetQuake2" +addr = 0x40F320 + +[[func]] +name = "ResetQuake" +addr = 0x40F330 + +[[func]] +name = "Random" +addr = 0x40F350 + +[[func]] +name = "PutNumber4" +addr = 0x40F380 + +[[func]] +name = "Game" +addr = 0x40F5F0 + +[[func]] +name = "ModeOpening" +addr = 0x40F730 + +[[func]] +name = "ModeTitle" +addr = 0x40F9B0 + +[[func]] +name = "ModeAction" +addr = 0x410400 + +[[func]] +name = "GetCompileDate" +addr = 0x4108B0 + +[[func]] +name = "GetCompileVersion" +addr = 0x410990 + +[[func]] +name = "OpenSoundVolume" +addr = 0x410AB0 + +[[func]] +name = "DeleteLog" +addr = 0x410BC0 + +[[func]] +name = "WriteLog" +addr = 0x410C10 + +[[func]] +name = "GetDateLimit" +addr = 0x410CA0 + +[[func]] +name = "IsKeyFile" +addr = 0x410D10 + +[[func]] +name = "GetFileSizeLong" +addr = 0x410D80 + +[[func]] +name = "ErrorLog" +addr = 0x410DE0 + +[[func]] +name = "IsShiftJIS" +addr = 0x410E90 + +[[func]] +name = "CenteringWindowByParent" +addr = 0x410EE0 + +[[func]] +name = "LoadWindowRect" +addr = 0x410FE0 + +[[func]] +name = "SaveWindowRect" +addr = 0x4111F0 + +[[func]] +name = "IsEnableBitmap" +addr = 0x4112E0 + +[[func]] +name = "LoadGenericData" +addr = 0x411390 + +[[func]] +name = "ReleaseDirectInput" +addr = 0x411E10 + +[[func]] +name = "ActivateDirectInput" +addr = 0x411E60 +size = 0x46 + +[[func]] +name = "InitDirectInput" +addr = 0x411EB0 + +[[func]] +name = "HookAllDirectInputDevices" +addr = 0x411EF0 + +[[func]] +name = "EnumDevices_Callback" +addr = 0x411FC0 + +[[func]] +name = "GetJoystickStatus" +addr = 0x4120F0 + +[[func]] +name = "ResetJoystickStatus" +addr = 0x412250 + +[[func]] +name = "GetTrg" +addr = 0x4122E0 + +[[func]] +name = "SetWindowName" +addr = 0x412320 + +[[func]] +name = "PutFramePerSecound" +addr = 0x412370 + +[[func]] +name = "CountFramePerSecound" +addr = 0x4123A0 + +[[func]] +name = "WinMain" +addr = 0x412420 + +[[func]] +name = "InactiveWindow" +addr = 0x412BC0 + +[[func]] +name = "ActiveWindow" +addr = 0x412BF0 + +[[func]] +name = "DragAndDropHandler" +addr = 0x412C30 + +[[func]] +name = "WindowProcedure" +addr = 0x412CA0 + +[[func]] +name = "SystemTask" +addr = 0x413570 + +[[func]] +name = "JoystickProc" +addr = 0x4135E0 + +[[func]] +name = "InitMapData2" +addr = 0x413750 + +[[func]] +name = "LoadMapData2" +addr = 0x413770 + +[[func]] +name = "LoadAttributeData" +addr = 0x4138A0 + +[[func]] +name = "EndMapData" +addr = 0x413930 + +[[func]] +name = "ReleasePartsImage" +addr = 0x413950 + +[[func]] +name = "GetMapData" +addr = 0x413960 + +[[func]] +name = "GetAttribute" +addr = 0x4139A0 + +[[func]] +name = "DeleteMapParts" +addr = 0x413A00 + +[[func]] +name = "ShiftMapParts" +addr = 0x413A20 + +[[func]] +name = "ChangeMapParts" +addr = 0x413A60 + +[[func]] +name = "PutStage_Back" +addr = 0x413AF0 + +[[func]] +name = "PutStage_Front" +addr = 0x413C60 + +[[func]] +name = "PutMapDataVector" +addr = 0x413E40 + +[[func]] +name = "ReadyMapName" +addr = 0x4140F0 + +[[func]] +name = "PutMapName" +addr = 0x414250 + +[[func]] +name = "StartMapName" +addr = 0x414310 + +[[func]] +name = "RestoreMapName" +addr = 0x414330 + +[[func]] +name = "WriteMiniMapLine" +addr = 0x4143C0 + +[[func]] +name = "MiniMapLoop" +addr = 0x414640 + +[[func]] +name = "IsMapping" +addr = 0x414B00 + +[[func]] +name = "StartMapping" +addr = 0x414B20 + +[[func]] +name = "SetMapping" +addr = 0x414B40 + +[[func]] +name = "InitMyChar" +addr = 0x414B50 + +[[func]] +name = "AnimationMyChar" +addr = 0x414BF0 + +[[func]] +name = "ShowMyChar" +addr = 0x415220 + +[[func]] +name = "PutMyChar" +addr = 0x415250 + +[[func]] +name = "ActMyChar_Normal" +addr = 0x4156C0 + +[[func]] +name = "ActMyChar_Stream" +addr = 0x416470 + +[[func]] +name = "ActMyChar" +addr = 0x4168C0 + +[[func]] +name = "AirProcess" +addr = 0x416990 + +[[func]] +name = "GetMyCharPosition" +addr = 0x416AA0 + +[[func]] +name = "SetMyCharPosition" +addr = 0x416AC0 + +[[func]] +name = "MoveMyChar" +addr = 0x416B30 + +[[func]] +name = "ZeroMyCharXMove" +addr = 0x416B50 + +[[func]] +name = "GetUnitMyChar" +addr = 0x416B60 + +[[func]] +name = "SetMyCharDirect" +addr = 0x416B70 + +[[func]] +name = "ChangeMyUnit" +addr = 0x416C40 + +[[func]] +name = "PitMyChar" +addr = 0x416C50 + +[[func]] +name = "EquipItem" +addr = 0x416C70 + +[[func]] +name = "ResetCheck" +addr = 0x416CA0 + +[[func]] +name = "SetNoise" +addr = 0x416CC0 + +[[func]] +name = "CutNoise" +addr = 0x416D40 + +[[func]] +name = "ResetNoise" +addr = 0x416D80 + +[[func]] +name = "SleepNoise" +addr = 0x416DF0 + +[[func]] +name = "ResetMyCharFlag" +addr = 0x416E20 + +[[func]] +name = "JudgeHitMyCharBlock" +addr = 0x416E30 + +[[func]] +name = "PutlittleStar" +addr = 0x417160 + +[[func]] +name = "JudgeHitMyCharTriangleA" +addr = 0x4171D0 + +[[func]] +name = "JudgeHitMyCharTriangleB" +addr = 0x4172E0 + +[[func]] +name = "JudgeHitMyCharTriangleC" +addr = 0x4173F0 + +[[func]] +name = "JudgeHitMyCharTriangleD" +addr = 0x417500 + +[[func]] +name = "JudgeHitMyCharTriangleE" +addr = 0x417610 + +[[func]] +name = "JudgeHitMyCharTriangleF" +addr = 0x417720 + +[[func]] +name = "JudgeHitMyCharTriangleG" +addr = 0x417830 + +[[func]] +name = "JudgeHitMyCharTriangleH" +addr = 0x417940 + +[[func]] +name = "JudgeHitMyCharWater" +addr = 0x417A50 + +[[func]] +name = "JudgeHitMyCharDamage" +addr = 0x417AE0 + +[[func]] +name = "JudgeHitMyCharDamageW" +addr = 0x417B70 + +[[func]] +name = "JudgeHitMyCharVectLeft" +addr = 0x417C00 + +[[func]] +name = "JudgeHitMyCharVectUp" +addr = 0x417C90 + +[[func]] +name = "JudgeHitMyCharVectRight" +addr = 0x417D20 + +[[func]] +name = "JudgeHitMyCharVectDown" +addr = 0x417DB0 + +[[func]] +name = "HitMyCharMap" +addr = 0x417E40 + +[[func]] +name = "JudgeHitMyCharNPC" +addr = 0x4187F0 + +[[func]] +name = "JudgeHitMyCharNPC3" +addr = 0x418B10 + +[[func]] +name = "JudgeHitMyCharNPC4" +addr = 0x418C20 + +[[func]] +name = "HitMyCharNpChar" +addr = 0x419030 + +[[func]] +name = "HitMyCharBoss" +addr = 0x419450 + +[[func]] +name = "AddExpMyChar" +addr = 0x4196F0 + +[[func]] +name = "ZeroExpMyChar" +addr = 0x419890 + +[[func]] +name = "IsMaxExpMyChar" +addr = 0x4198C0 + +[[func]] +name = "DamageMyChar" +addr = 0x419910 + +[[func]] +name = "ZeroArmsEnergy_All" +addr = 0x419B50 + +[[func]] +name = "AddBulletMyChar" +addr = 0x419BA0 + +[[func]] +name = "AddLifeMyChar" +addr = 0x419C60 + +[[func]] +name = "AddMaxLifeMyChar" +addr = 0x419CB0 + +[[func]] +name = "PutArmsEnergy" +addr = 0x419D10 + +[[func]] +name = "PutActiveArmsList" +addr = 0x41A0B0 + +[[func]] +name = "PutMyLife" +addr = 0x41A1D0 + +[[func]] +name = "PutMyAir" +addr = 0x41A350 + +[[func]] +name = "PutTimeCounter" +addr = 0x41A430 + +[[func]] +name = "SaveTimeCounter" +addr = 0x41A5D0 + +[[func]] +name = "LoadTimeCounter" +addr = 0x41A7C0 + +[[func]] +name = "MakeSoundObject8" +addr = 0x41A8F0 + +[[func]] +name = "ChangeOrganFrequency" +addr = 0x41ABA0 +size = 0xC9 + +[[func]] +name = "ChangeOrganPan" +addr = 0x41AC70 +size = 0xA2 + +[[func]] +name = "ChangeOrganVolume" +addr = 0x41AD20 +size = 0x98 + +[[func]] +name = "PlayOrganObject" +addr = 0x41ADC0 + +[[func]] +name = "ReleaseOrganyaObject" +addr = 0x41B2A0 + +[[func]] +name = "InitWaveData100" +addr = 0x41B380 + +[[func]] +name = "MakeOrganyaWave" +addr = 0x41B3F0 + +[[func]] +name = "ChangeDramFrequency" +addr = 0x41B440 + +[[func]] +name = "ChangeDramPan" +addr = 0x41B480 + +[[func]] +name = "ChangeDramVolume" +addr = 0x41B4D0 + +[[func]] +name = "PlayDramObject" +addr = 0x41B510 + +[[func]] +name = "OrgData::OrgData" +addr = 0x41B600 + +[[func]] +name = "OrgData::InitOrgData" +addr = 0x41B650 + +[[func]] +name = "OrgData::SetMusicInfo" +addr = 0x41B730 + +[[func]] +name = "OrgData::NoteAlloc" +addr = 0x41B890 + +[[func]] +name = "OrgData::ReleaseNote" +addr = 0x41BA70 + +[[func]] +name = "OrgData::InitMusicData" +addr = 0x41BAD0 + +[[func]] +name = "OrgData::GetMusicInfo" +addr = 0x41C0B0 + +[[func]] +name = "InitMMTimer" +addr = 0x41C180 + +[[func]] +name = "StartTimer" +addr = 0x41C1E0 +size = 0x4A + +[[func]] +name = "TimerProc" +addr = 0x41C230 + +[[func]] +name = "QuitMMTimer" +addr = 0x41C250 + +[[func]] +name = "OrgData::PlayData" +addr = 0x41C2B0 + +[[func]] +name = "OrgData::SetPlayPointer" +addr = 0x41C630 + +[[func]] +name = "StartOrganya" +addr = 0x41C6C0 + +[[func]] +name = "LoadOrganya" +addr = 0x41C6F0 + +[[func]] +name = "SetOrganyaPosition" +addr = 0x41C730 + +[[func]] +name = "GetOrganyaPosition" +addr = 0x41C770 + +[[func]] +name = "PlayOrganyaMusic" +addr = 0x41C790 + +[[func]] +name = "ChangeOrganyaVolume" +addr = 0x41C7C0 + +[[func]] +name = "StopOrganyaMusic" +addr = 0x41C7F0 + +[[func]] +name = "SetOrganyaFadeout" +addr = 0x41C880 + +[[func]] +name = "EndOrganya" +addr = 0x41C890 + +[[func]] +name = "MakeWaveTables" +addr = 0x41C8F0 + +[[func]] +name = "MakePixelWaveData" +addr = 0x41CB10 + +[[func]] +name = "IsProfile" +addr = 0x41CFC0 + +[[func]] +name = "SaveProfile" +addr = 0x41D040 + +[[func]] +name = "LoadProfile" +addr = 0x41D260 + +[[func]] +name = "InitializeGame" +addr = 0x41D550 + +[[func]] +name = "ClearPermitStage" +addr = 0x41D610 + +[[func]] +name = "AddPermitStage" +addr = 0x41D630 + +[[func]] +name = "SubPermitStage" +addr = 0x41D6A0 + +[[func]] +name = "MoveStageSelectCursor" +addr = 0x41D740 + +[[func]] +name = "PutStageSelectObject" +addr = 0x41D840 + +[[func]] +name = "StageSelectLoop" +addr = 0x41DA00 + +[[func]] +name = "ShootBullet_Frontia1" +addr = 0x41DBD0 + +[[func]] +name = "ShootBullet_PoleStar" +addr = 0x41DE60 + +[[func]] +name = "ShootBullet_FireBall" +addr = 0x41E110 + +[[func]] +name = "ShootBullet_Machinegun1" +addr = 0x41E3D0 + +[[func]] +name = "ShootBullet_Missile" +addr = 0x41E7B0 + +[[func]] +name = "ShootBullet_Bubblin1" +addr = 0x41EFD0 + +[[func]] +name = "ShootBullet_Bubblin2" +addr = 0x41F280 + +[[func]] +name = "ShootBullet_Sword" +addr = 0x41F580 + +[[func]] +name = "ShootBullet_Nemesis" +addr = 0x41F710 + +[[func]] +name = "ResetSpurCharge" +addr = 0x41F9E0 + +[[func]] +name = "ShootBullet_Spur" +addr = 0x41FA10 + +[[func]] +name = "ShootBullet" +addr = 0x41FE70 + +[[func]] +name = "InitDirectSound" +addr = 0x4200C0 + +[[func]] +name = "EndDirectSound" +addr = 0x4201A0 + +[[func]] +name = "InitSoundObject" +addr = 0x420240 + +[[func]] +name = "LoadSoundObject" +addr = 0x420390 + +[[func]] +name = "PlaySoundObject" +addr = 0x420640 + +[[func]] +name = "ChangeSoundFrequency" +addr = 0x420720 +size = 0x34 + +[[func]] +name = "ChangeSoundVolume" +addr = 0x420760 +size = 0x35 + +[[func]] +name = "ChangeSoundPan" +addr = 0x4207A0 +size = 0x36 + +[[func]] +name = "MakePixToneObject" +addr = 0x4207E0 + +[[func]] +name = "TransferStage" +addr = 0x420BE0 + +[[func]] +name = "ChangeMusic" +addr = 0x420EE0 + +[[func]] +name = "ReCallMusic" +addr = 0x420F50 + +[[func]] +name = "InitStar" +addr = 0x420FA0 + +[[func]] +name = "ActStar" +addr = 0x421040 + +[[func]] +name = "PutStar" +addr = 0x4213B0 + +[[func]] +name = "InitTextScript2" +addr = 0x4214E0 + +[[func]] +name = "EndTextScript" +addr = 0x421570 + +[[func]] +name = "EncryptionBinaryData2" +addr = 0x4215C0 + +[[func]] +name = "LoadTextScript2" +addr = 0x421660 + +[[func]] +name = "LoadTextScript_Stage" +addr = 0x421750 + +[[func]] +name = "GetTextScriptPath" +addr = 0x4218E0 + +[[func]] +name = "GetTextScriptNo" +addr = 0x421900 + +[[func]] +name = "StartTextScript" +addr = 0x421990 + +[[func]] +name = "JumpTextScript" +addr = 0x421AF0 + +[[func]] +name = "StopTextScript" +addr = 0x421C50 + +[[func]] +name = "CheckNewLine" +addr = 0x421C80 + +[[func]] +name = "SetNumberTextScript" +addr = 0x421D10 + +[[func]] +name = "ClearTextLine" +addr = 0x421E90 + +[[func]] +name = "PutTextScript" +addr = 0x421F10 + +[[func]] +name = "TextScriptProc" +addr = 0x422510 + +[[func]] +name = "RestoreTextScript" +addr = 0x425790 + +[[func]] +name = "InitTriangleTable" +addr = 0x4257F0 + +[[func]] +name = "GetSin" +addr = 0x4258B0 + +[[func]] +name = "GetCos" +addr = 0x4258C0 + +[[func]] +name = "GetArktan" +addr = 0x4258E0 + +[[func]] +name = "ClearValueView" +addr = 0x425BC0 + +[[func]] +name = "SetValueView" +addr = 0x425BF0 + +[[func]] +name = "ActValueView" +addr = 0x426360 + +[[func]] +name = "PutValueView" +addr = 0x426430 + +[[func]] +name = "ActNpc000" +addr = 0x426530 + +[[func]] +name = "ActNpc001" +addr = 0x4265B0 + +[[func]] +name = "ActNpc002" +addr = 0x426AF0 + +[[func]] +name = "ActNpc003" +addr = 0x426FD0 + +[[func]] +name = "ActNpc004" +addr = 0x427040 + +[[func]] +name = "ActNpc005" +addr = 0x427480 + +[[func]] +name = "ActNpc006" +addr = 0x427820 + +[[func]] +name = "ActNpc007" +addr = 0x427C60 + +[[func]] +name = "ActNpc008" +addr = 0x427F00 + +[[func]] +name = "ActNpc009" +addr = 0x428260 + +[[func]] +name = "ActNpc010" +addr = 0x428540 + +[[func]] +name = "ActNpc011" +addr = 0x4289B0 + +[[func]] +name = "ActNpc012" +addr = 0x428B10 + +[[func]] +name = "ActNpc013" +addr = 0x429940 + +[[func]] +name = "ActNpc014" +addr = 0x429A30 + +[[func]] +name = "ActNpc015" +addr = 0x429BF0 + +[[func]] +name = "ActNpc016" +addr = 0x429E00 + +[[func]] +name = "ActNpc017" +addr = 0x42A0B0 + +[[func]] +name = "ActNpc018" +addr = 0x42A360 + +[[func]] +name = "ActNpc019" +addr = 0x42A490 + +[[func]] +name = "ActNpc020" +addr = 0x42A830 + +[[func]] +name = "ActNpc021" +addr = 0x42A940 + +[[func]] +name = "ActNpc022" +addr = 0x42A9C0 + +[[func]] +name = "ActNpc023" +addr = 0x42AA70 + +[[func]] +name = "ActNpc024" +addr = 0x42ABD0 + +[[func]] +name = "ActNpc025" +addr = 0x42B280 + +[[func]] +name = "ActNpc026" +addr = 0x42B5E0 + +[[func]] +name = "ActNpc027" +addr = 0x42BA90 + +[[func]] +name = "ActNpc028" +addr = 0x42BAE0 + +[[func]] +name = "ActNpc029" +addr = 0x42C1A0 + +[[func]] +name = "ActNpc030" +addr = 0x42C320 + +[[func]] +name = "ActNpc031" +addr = 0x42C4C0 + +[[func]] +name = "ActNpc032" +addr = 0x42CA10 + +[[func]] +name = "ActNpc033" +addr = 0x42CAC0 + +[[func]] +name = "ActNpc034" +addr = 0x42CC20 + +[[func]] +name = "ActNpc035" +addr = 0x42CCB0 + +[[func]] +name = "ActNpc036" +addr = 0x42D010 + +[[func]] +name = "ActNpc037" +addr = 0x42D760 + +[[func]] +name = "ActNpc038" +addr = 0x42D810 + +[[func]] +name = "ActNpc039" +addr = 0x42D960 + +[[func]] +name = "ActNpc040" +addr = 0x42D9F0 + +[[func]] +name = "ActNpc041" +addr = 0x42DE00 + +[[func]] +name = "ActNpc042" +addr = 0x42DE70 + +[[func]] +name = "ActNpc043" +addr = 0x42E9F0 + +[[func]] +name = "ActNpc044" +addr = 0x42EAB0 + +[[func]] +name = "ActNpc045" +addr = 0x42F060 + +[[func]] +name = "ActNpc046" +addr = 0x42F320 + +[[func]] +name = "ActNpc047" +addr = 0x42F3F0 + +[[func]] +name = "ActNpc048" +addr = 0x42F780 + +[[func]] +name = "ActNpc049" +addr = 0x42F9E0 + +[[func]] +name = "ActNpc050" +addr = 0x42FEC0 + +[[func]] +name = "ActNpc051" +addr = 0x4301B0 + +[[func]] +name = "ActNpc052" +addr = 0x430780 + +[[func]] +name = "ActNpc053" +addr = 0x4307D0 + +[[func]] +name = "ActNpc054" +addr = 0x430B00 + +[[func]] +name = "ActNpc055" +addr = 0x430EB0 + +[[func]] +name = "ActNpc056" +addr = 0x4311D0 + +[[func]] +name = "ActNpc057" +addr = 0x4315E0 + +[[func]] +name = "ActNpc058" +addr = 0x431C20 + +[[func]] +name = "ActNpc059" +addr = 0x4321F0 + +[[func]] +name = "ActNpc060" +addr = 0x432460 + +[[func]] +name = "ActNpc061" +addr = 0x432B50 + +[[func]] +name = "ActNpc062" +addr = 0x4334C0 + +[[func]] +name = "ActNpc063" +addr = 0x4336C0 + +[[func]] +name = "ActNpc064" +addr = 0x433C00 + +[[func]] +name = "ActNpc065" +addr = 0x433FC0 + +[[func]] +name = "ActNpc066" +addr = 0x4342B0 + +[[func]] +name = "ActNpc067" +addr = 0x4345E0 + +[[func]] +name = "ActNpc068" +addr = 0x434D10 + +[[func]] +name = "ActNpc069" +addr = 0x4355F0 + +[[func]] +name = "ActNpc070" +addr = 0x435AB0 + +[[func]] +name = "ActNpc071" +addr = 0x435BA0 + +[[func]] +name = "ActNpc072" +addr = 0x435DE0 + +[[func]] +name = "ActNpc073" +addr = 0x435FC0 + +[[func]] +name = "ActNpc074" +addr = 0x436180 + +[[func]] +name = "ActNpc075" +addr = 0x436540 + +[[func]] +name = "ActNpc076" +addr = 0x436650 + +[[func]] +name = "ActNpc077" +addr = 0x436690 + +[[func]] +name = "ActNpc078" +addr = 0x4367E0 + +[[func]] +name = "ActNpc079" +addr = 0x436870 + +[[func]] +name = "ActNpc080" +addr = 0x436AE0 + +[[func]] +name = "ActNpc081" +addr = 0x4370F0 + +[[func]] +name = "ActNpc082" +addr = 0x4375E0 + +[[func]] +name = "ActNpc083" +addr = 0x437D90 + +[[func]] +name = "ActNpc084" +addr = 0x438250 + +[[func]] +name = "ActNpc085" +addr = 0x4383D0 + +[[func]] +name = "ActNpc086" +addr = 0x438590 + +[[func]] +name = "ActNpc087" +addr = 0x438850 + +[[func]] +name = "ActNpc088" +addr = 0x438B10 + +[[func]] +name = "ActNpc089" +addr = 0x439580 + +[[func]] +name = "ActNpc090" +addr = 0x439B00 + +[[func]] +name = "ActNpc091" +addr = 0x439B50 + +[[func]] +name = "ActNpc092" +addr = 0x439BC0 + +[[func]] +name = "ActNpc093" +addr = 0x439DC0 + +[[func]] +name = "ActNpc094" +addr = 0x43A220 + +[[func]] +name = "ActNpc095" +addr = 0x43A680 + +[[func]] +name = "ActNpc096" +addr = 0x43AAF0 + +[[func]] +name = "ActNpc097" +addr = 0x43AD10 + +[[func]] +name = "ActNpc098" +addr = 0x43AF20 + +[[func]] +name = "ActNpc099" +addr = 0x43B140 + +[[func]] +name = "ActNpc100" +addr = 0x43B350 + +[[func]] +name = "ActNpc101" +addr = 0x43B410 + +[[func]] +name = "ActNpc102" +addr = 0x43B4E0 + +[[func]] +name = "ActNpc103" +addr = 0x43B5F0 + +[[func]] +name = "ActNpc104" +addr = 0x43B7F0 + +[[func]] +name = "ActNpc105" +addr = 0x43BD00 + +[[func]] +name = "ActNpc106" +addr = 0x43BDB0 + +[[func]] +name = "ActNpc107" +addr = 0x43BE00 + +[[func]] +name = "ActNpc108" +addr = 0x43C4B0 + +[[func]] +name = "ActNpc109" +addr = 0x43C610 + +[[func]] +name = "ActNpc110" +addr = 0x43C8E0 + +[[func]] +name = "ActNpc111" +addr = 0x43CDE0 + +[[func]] +name = "ActNpc112" +addr = 0x43D0A0 + +[[func]] +name = "ActNpc113" +addr = 0x43D320 + +[[func]] +name = "ActNpc114" +addr = 0x43D860 + +[[func]] +name = "ActNpc115" +addr = 0x43DAE0 + +[[func]] +name = "ActNpc116" +addr = 0x43E190 + +[[func]] +name = "ActNpc117" +addr = 0x43E1E0 + +[[func]] +name = "ActNpc118" +addr = 0x43E9B0 + +[[func]] +name = "ActNpc119" +addr = 0x43F230 + +[[func]] +name = "ActNpc120" +addr = 0x43F280 + +[[func]] +name = "ActNpc121" +addr = 0x43F310 + +[[func]] +name = "ActNpc122" +addr = 0x43F4A0 + +[[func]] +name = "ActNpc123" +addr = 0x43FC70 + +[[func]] +name = "ActNpc124" +addr = 0x43FEF0 + +[[func]] +name = "ActNpc125" +addr = 0x4400D0 + +[[func]] +name = "ActNpc126" +addr = 0x4401F0 + +[[func]] +name = "ActNpc127" +addr = 0x440760 + +[[func]] +name = "ActNpc128" +addr = 0x4408B0 + +[[func]] +name = "ActNpc129" +addr = 0x440CF0 + +[[func]] +name = "ActNpc130" +addr = 0x441000 + +[[func]] +name = "ActNpc131" +addr = 0x441360 + +[[func]] +name = "ActNpc132" +addr = 0x441440 + +[[func]] +name = "ActNpc133" +addr = 0x4419B0 + +[[func]] +name = "ActNpc134" +addr = 0x441B20 + +[[func]] +name = "ActNpc135" +addr = 0x441EC0 + +[[func]] +name = "ActNpc136" +addr = 0x442340 + +[[func]] +name = "ActNpc137" +addr = 0x442540 + +[[func]] +name = "ActNpc138" +addr = 0x442590 + +[[func]] +name = "ActNpc139" +addr = 0x442790 + +[[func]] +name = "ActNpc140" +addr = 0x442BF0 + +[[func]] +name = "ActNpc141" +addr = 0x443AC0 + +[[func]] +name = "ActNpc142" +addr = 0x443EC0 + +[[func]] +name = "ActNpc143" +addr = 0x444190 + +[[func]] +name = "ActNpc144" +addr = 0x444230 + +[[func]] +name = "ActNpc145" +addr = 0x444620 + +[[func]] +name = "ActNpc146" +addr = 0x444780 + +[[func]] +name = "ActNpc147" +addr = 0x444930 + +[[func]] +name = "ActNpc148" +addr = 0x445050 + +[[func]] +name = "ActNpc149" +addr = 0x445170 + +[[func]] +name = "ActNpc150" +addr = 0x445660 + +[[func]] +name = "ActNpc151" +addr = 0x445E30 + +[[func]] +name = "ActNpc152" +addr = 0x445FA0 + +[[func]] +name = "ActNpc153" +addr = 0x446020 + +[[func]] +name = "ActNpc154" +addr = 0x446500 + +[[func]] +name = "ActNpc155" +addr = 0x446710 + +[[func]] +name = "ActNpc156" +addr = 0x446B60 + +[[func]] +name = "ActNpc157" +addr = 0x446CA0 + +[[func]] +name = "ActNpc158" +addr = 0x447180 + +[[func]] +name = "ActNpc159" +addr = 0x4474C0 + +[[func]] +name = "ActNpc160" +addr = 0x447700 + +[[func]] +name = "ActNpc161" +addr = 0x447CB0 + +[[func]] +name = "ActNpc162" +addr = 0x447E90 + +[[func]] +name = "ActNpc163" +addr = 0x4482A0 + +[[func]] +name = "ActNpc164" +addr = 0x448410 + +[[func]] +name = "ActNpc165" +addr = 0x448580 + +[[func]] +name = "ActNpc166" +addr = 0x4486E0 + +[[func]] +name = "ActNpc167" +addr = 0x4487F0 + +[[func]] +name = "ActNpc168" +addr = 0x448A10 + +[[func]] +name = "ActNpc169" +addr = 0x448BE0 + +[[func]] +name = "ActNpc170" +addr = 0x4495A0 + +[[func]] +name = "ActNpc171" +addr = 0x4498C0 + +[[func]] +name = "ActNpc172" +addr = 0x449C10 + +[[func]] +name = "ActNpc173" +addr = 0x449D70 + +[[func]] +name = "ActNpc174" +addr = 0x44A3C0 + +[[func]] +name = "ActNpc175" +addr = 0x44A610 + +[[func]] +name = "ActNpc176" +addr = 0x44A7D0 + +[[func]] +name = "ActNpc177" +addr = 0x44ABB0 + +[[func]] +name = "ActNpc178" +addr = 0x44AEE0 + +[[func]] +name = "ActNpc179" +addr = 0x44B080 + +[[func]] +name = "ActNpc180" +addr = 0x44B210 + +[[func]] +name = "ActNpc181" +addr = 0x44BE10 + +[[func]] +name = "ActNpc182" +addr = 0x44C220 + +[[func]] +name = "ActNpc183" +addr = 0x44C630 + +[[func]] +name = "ActNpc184" +addr = 0x44C7A0 + +[[func]] +name = "ActNpc185" +addr = 0x44CA60 + +[[func]] +name = "ActNpc186" +addr = 0x44CBE0 + +[[func]] +name = "ActNpc187" +addr = 0x44CDB0 + +[[func]] +name = "ActNpc188" +addr = 0x44D070 + +[[func]] +name = "ActNpc189" +addr = 0x44D3A0 + +[[func]] +name = "ActNpc190" +addr = 0x44D5E0 + +[[func]] +name = "ActNpc191" +addr = 0x44D740 + +[[func]] +name = "ActNpc192" +addr = 0x44DA00 + +[[func]] +name = "ActNpc193" +addr = 0x44DE20 + +[[func]] +name = "ActNpc194" +addr = 0x44DEA0 + +[[func]] +name = "ActNpc195" +addr = 0x44DF10 + +[[func]] +name = "ActNpc196" +addr = 0x44DF60 + +[[func]] +name = "ActNpc197" +addr = 0x44E020 + +[[func]] +name = "ActNpc198" +addr = 0x44E260 + +[[func]] +name = "ActNpc199" +addr = 0x44E400 + +[[func]] +name = "ActNpc200" +addr = 0x44E5F0 + +[[func]] +name = "ActNpc201" +addr = 0x44EC40 + +[[func]] +name = "ActNpc202" +addr = 0x44ECE0 + +[[func]] +name = "ActNpc203" +addr = 0x44EE40 + +[[func]] +name = "ActNpc204" +addr = 0x44F1F0 + +[[func]] +name = "ActNpc205" +addr = 0x44F3E0 + +[[func]] +name = "ActNpc206" +addr = 0x44F6D0 + +[[func]] +name = "ActNpc207" +addr = 0x44FB40 + +[[func]] +name = "ActNpc208" +addr = 0x44FCB0 + +[[func]] +name = "ActNpc209" +addr = 0x450280 + +[[func]] +name = "ActNpc210" +addr = 0x450400 + +[[func]] +name = "ActNpc211" +addr = 0x450760 + +[[func]] +name = "ActNpc212" +addr = 0x450810 + +[[func]] +name = "ActNpc213" +addr = 0x450BF0 + +[[func]] +name = "ActNpc214" +addr = 0x4512A0 + +[[func]] +name = "ActNpc215" +addr = 0x451430 + +[[func]] +name = "ActNpc216" +addr = 0x4517F0 + +[[func]] +name = "ActNpc217" +addr = 0x451840 + +[[func]] +name = "ActNpc218" +addr = 0x451CA0 + +[[func]] +name = "ActNpc219" +addr = 0x451DA0 + +[[func]] +name = "ActNpc220" +addr = 0x451E90 + +[[func]] +name = "ActNpc221" +addr = 0x452000 + +[[func]] +name = "ActNpc222" +addr = 0x452470 + +[[func]] +name = "ActNpc223" +addr = 0x4524E0 + +[[func]] +name = "ActNpc224" +addr = 0x452700 + +[[func]] +name = "ActNpc225" +addr = 0x4528D0 + +[[func]] +name = "ActNpc226" +addr = 0x452A50 + +[[func]] +name = "ActNpc227" +addr = 0x452D10 + +[[func]] +name = "ActNpc228" +addr = 0x452D60 + +[[func]] +name = "ActNpc229" +addr = 0x4530D0 + +[[func]] +name = "ActNpc230" +addr = 0x453190 + +[[func]] +name = "ActNpc231" +addr = 0x453260 + +[[func]] +name = "ActNpc232" +addr = 0x4536F0 + +[[func]] +name = "ActNpc233" +addr = 0x4539B0 + +[[func]] +name = "ActNpc234" +addr = 0x453E60 + +[[func]] +name = "ActNpc235" +addr = 0x453F20 + +[[func]] +name = "ActNpc236" +addr = 0x454310 + +[[func]] +name = "ActNpc237" +addr = 0x4548B0 + +[[func]] +name = "ActNpc238" +addr = 0x454A00 + +[[func]] +name = "ActNpc239" +addr = 0x454DF0 + +[[func]] +name = "ActNpc240" +addr = 0x454F00 + +[[func]] +name = "ActNpc241" +addr = 0x455370 + +[[func]] +name = "ActNpc242" +addr = 0x455710 + +[[func]] +name = "ActNpc243" +addr = 0x455A10 + +[[func]] +name = "ActNpc244" +addr = 0x455AB0 + +[[func]] +name = "ActNpc245" +addr = 0x455C10 + +[[func]] +name = "ActNpc246" +addr = 0x455E00 + +[[func]] +name = "ActNpc247" +addr = 0x456110 + +[[func]] +name = "ActNpc248" +addr = 0x456F50 + +[[func]] +name = "ActNpc249" +addr = 0x4570B0 + +[[func]] +name = "ActNpc250" +addr = 0x457180 + +[[func]] +name = "ActNpc251" +addr = 0x457470 + +[[func]] +name = "ActNpc252" +addr = 0x457570 + +[[func]] +name = "ActNpc253" +addr = 0x4579D0 + +[[func]] +name = "ActNpc254" +addr = 0x457B00 + +[[func]] +name = "ActNpc255" +addr = 0x457D70 + +[[func]] +name = "ActNpc256" +addr = 0x458010 + +[[func]] +name = "ActNpc257" +addr = 0x458360 + +[[func]] +name = "ActNpc258" +addr = 0x4585A0 + +[[func]] +name = "ActNpc259" +addr = 0x4585F0 + +[[func]] +name = "ActNpc260" +addr = 0x458810 + +[[func]] +name = "ActNpc261" +addr = 0x458A70 + +[[func]] +name = "ActNpc262" +addr = 0x458C30 + +[[func]] +name = "ActNpc263" +addr = 0x458DF0 + +[[func]] +name = "ActNpc264" +addr = 0x459950 + +[[func]] +name = "ActNpc265" +addr = 0x459B30 + +[[func]] +name = "ActNpc266" +addr = 0x459C00 + +[[func]] +name = "ActNpc267" +addr = 0x459D80 + +[[func]] +name = "ActNpc268" +addr = 0x45B3D0 + +[[func]] +name = "ActNpc269" +addr = 0x45BCB0 + +[[func]] +name = "ActNpc270" +addr = 0x45BF10 + +[[func]] +name = "ActNpc271" +addr = 0x45C230 + +[[func]] +name = "ActNpc272" +addr = 0x45C500 + +[[func]] +name = "ActNpc273" +addr = 0x45C5A0 + +[[func]] +name = "ActNpc274" +addr = 0x45C750 + +[[func]] +name = "ActNpc275" +addr = 0x45CC80 + +[[func]] +name = "ActNpc276" +addr = 0x45CEA0 + +[[func]] +name = "ActNpc277" +addr = 0x45D780 + +[[func]] +name = "ActNpc278" +addr = 0x45D930 + +[[func]] +name = "ActNpc279" +addr = 0x45DCF0 + +[[func]] +name = "ActNpc280" +addr = 0x45E110 + +[[func]] +name = "ActNpc281" +addr = 0x45E360 + +[[func]] +name = "ActNpc282" +addr = 0x45E4C0 + +[[func]] +name = "ActNpc283" +addr = 0x45E950 + +[[func]] +name = "ActNpc284" +addr = 0x45F910 + +[[func]] +name = "ActNpc285" +addr = 0x460910 + +[[func]] +name = "ActNpc286" +addr = 0x460AE0 + +[[func]] +name = "ActNpc287" +addr = 0x460BB0 + +[[func]] +name = "ActNpc288" +addr = 0x460D70 + +[[func]] +name = "ActNpc289" +addr = 0x4610D0 + +[[func]] +name = "ActNpc290" +addr = 0x4614A0 + +[[func]] +name = "ActNpc291" +addr = 0x461800 + +[[func]] +name = "ActNpc292" +addr = 0x4618B0 + +[[func]] +name = "ActNpc293" +addr = 0x4618C0 + +[[func]] +name = "ActNpc294" +addr = 0x4619E0 + +[[func]] +name = "ActNpc295" +addr = 0x461B90 + +[[func]] +name = "ActNpc296" +addr = 0x461E40 + +[[func]] +name = "ActNpc297" +addr = 0x461FD0 + +[[func]] +name = "ActNpc298" +addr = 0x462050 + +[[func]] +name = "ActNpc299" +addr = 0x4623D0 + +[[func]] +name = "ActNpc300" +addr = 0x4624E0 + +[[func]] +name = "ActNpc301" +addr = 0x4625A0 + +[[func]] +name = "ActNpc302" +addr = 0x462890 + +[[func]] +name = "ActNpc303" +addr = 0x462AF0 + +[[func]] +name = "ActNpc304" +addr = 0x462C80 + +[[func]] +name = "ActNpc305" +addr = 0x462E00 + +[[func]] +name = "ActNpc306" +addr = 0x462F60 + +[[func]] +name = "ActNpc307" +addr = 0x4630F0 + +[[func]] +name = "ActNpc308" +addr = 0x4632B0 + +[[func]] +name = "ActNpc309" +addr = 0x463710 + +[[func]] +name = "ActNpc310" +addr = 0x463AC0 + +[[func]] +name = "ActNpc311" +addr = 0x464090 + +[[func]] +name = "ActNpc312" +addr = 0x464740 + +[[func]] +name = "ActNpc313" +addr = 0x464BB0 + +[[func]] +name = "ActNpc314" +addr = 0x465CC0 + +[[func]] +name = "ActNpc315" +addr = 0x465F60 + +[[func]] +name = "ActNpc316" +addr = 0x4664B0 + +[[func]] +name = "ActNpc317" +addr = 0x466790 + +[[func]] +name = "ActNpc318" +addr = 0x466B80 + +[[func]] +name = "ActNpc319" +addr = 0x466E50 + +[[func]] +name = "ActNpc320" +addr = 0x4670C0 + +[[func]] +name = "ActNpc321" +addr = 0x4673F0 + +[[func]] +name = "ActNpc322" +addr = 0x4676D0 + +[[func]] +name = "ActNpc323" +addr = 0x467C60 + +[[func]] +name = "ActNpc324" +addr = 0x467F40 + +[[func]] +name = "ActNpc325" +addr = 0x467FE0 + +[[func]] +name = "ActNpc326" +addr = 0x468230 + +[[func]] +name = "ActNpc327" +addr = 0x468830 + +[[func]] +name = "ActNpc328" +addr = 0x468990 + +[[func]] +name = "ActNpc329" +addr = 0x4689E0 + +[[func]] +name = "ActNpc330" +addr = 0x468A90 + +[[func]] +name = "ActNpc331" +addr = 0x468D70 + +[[func]] +name = "ActNpc332" +addr = 0x468F50 + +[[func]] +name = "ActNpc333" +addr = 0x469140 + +[[func]] +name = "ActNpc334" +addr = 0x469290 + +[[func]] +name = "ActNpc335" +addr = 0x469430 + +[[func]] +name = "ActNpc336" +addr = 0x469610 + +[[func]] +name = "ActNpc337" +addr = 0x4696B0 + +[[func]] +name = "ActNpc338" +addr = 0x469800 + +[[func]] +name = "ActNpc339" +addr = 0x469AA0 + +[[func]] +name = "ActNpc340" +addr = 0x469B40 + +[[func]] +name = "ActNpc341" +addr = 0x46B240 + +[[func]] +name = "ActNpc342" +addr = 0x46B340 + +[[func]] +name = "ActNpc343" +addr = 0x46BD80 + +[[func]] +name = "ActNpc344" +addr = 0x46BE10 + +[[func]] +name = "ActNpc345" +addr = 0x46BF00 + +[[func]] +name = "ActNpc346" +addr = 0x46C1D0 + +[[func]] +name = "ActNpc347" +addr = 0x46C710 + +[[func]] +name = "ActNpc348" +addr = 0x46C9B0 + +[[func]] +name = "ActNpc349" +addr = 0x46CAC0 + +[[func]] +name = "ActNpc350" +addr = 0x46CB50 + +[[func]] +name = "ActNpc351" +addr = 0x46D340 + +[[func]] +name = "ActNpc352" +addr = 0x46D5D0 + +[[func]] +name = "ActNpc353" +addr = 0x46DBE0 + +[[func]] +name = "ActNpc354" +addr = 0x46E110 + +[[func]] +name = "ActNpc355" +addr = 0x46E280 + +[[func]] +name = "ActNpc356" +addr = 0x46E480 + +[[func]] +name = "ActNpc357" +addr = 0x46E730 + +[[func]] +name = "ActNpc358" +addr = 0x46E870 + +[[func]] +name = "ActNpc359" +addr = 0x46E9E0 + +[[func]] +name = "ActNpc360" +addr = 0x46EA90 + +[[func]] +name = "InitNpChar" +addr = 0x46EB30 + +[[func]] +name = "LoadEvent" +addr = 0x46EB50 + +[[func]] +name = "SetUniqueParameter" +addr = 0x46EE50 + +[[func]] +name = "SetNpChar" +addr = 0x46EFD0 + +[[func]] +name = "SetDestroyNpChar" +addr = 0x46F150 + +[[func]] +name = "SetDestroyNpCharUp" +addr = 0x46F200 + +[[func]] +name = "SetExpObjects" +addr = 0x46F2B0 + +[[func]] +name = "SetBulletObject" +addr = 0x46F430 + +[[func]] +name = "SetLifeObject" +addr = 0x46F630 + +[[func]] +name = "VanishNpChar" +addr = 0x46F760 + +[[func]] +name = "PutNpChar" +addr = 0x46F810 + +[[func]] +name = "ActNpChar" +addr = 0x46FA00 + +[[func]] +name = "ChangeNpCharByEvent" +addr = 0x46FAB0 + +[[func]] +name = "ChangeCheckableNpCharByEvent" +addr = 0x46FD10 + +[[func]] +name = "SetNpCharActionNo" +addr = 0x46FF90 + +[[func]] +name = "MoveNpChar" +addr = 0x470060 + +[[func]] +name = "BackStepMyChar" +addr = 0x470150 + +[[func]] +name = "DeleteNpCharEvent" +addr = 0x470250 + +[[func]] +name = "DeleteNpCharCode" +addr = 0x4702D0 + +[[func]] +name = "GetNpCharPosition" +addr = 0x470460 + +[[func]] +name = "IsNpCharCode" +addr = 0x470490 + +[[func]] +name = "GetNpCharAlive" +addr = 0x4704F0 + +[[func]] +name = "CountAliveNpChar" +addr = 0x470560 + +[[func]] +name = "JadgeHitNpCharBlock" +addr = 0x4705C0 + +[[func]] +name = "JudgeHitNpCharTriangleA" +addr = 0x470870 + +[[func]] +name = "JudgeHitNpCharTriangleB" +addr = 0x470970 + +[[func]] +name = "JudgeHitNpCharTriangleC" +addr = 0x470A70 + +[[func]] +name = "JudgeHitNpCharTriangleD" +addr = 0x470B70 + +[[func]] +name = "JudgeHitNpCharTriangleE" +addr = 0x470C70 + +[[func]] +name = "JudgeHitNpCharTriangleF" +addr = 0x470D80 + +[[func]] +name = "JudgeHitNpCharTriangleG" +addr = 0x470E90 + +[[func]] +name = "JudgeHitNpCharTriangleH" +addr = 0x470FA0 + +[[func]] +name = "JudgeHitNpCharWater" +addr = 0x4710B0 + +[[func]] +name = "HitNpCharMap" +addr = 0x471160 + +[[func]] +name = "LoseNpChar" +addr = 0x471B80 + +[[func]] +name = "HitNpCharBullet" +addr = 0x471D50 + +[[func]] +name = "LoadNpcTable" +addr = 0x472400 + +[[func]] +name = "ReleaseNpcTable" +addr = 0x472710 + +[[func]] +name = "InitBossChar" +addr = 0x472740 + +[[func]] +name = "PutBossChar" +addr = 0x472770 + +[[func]] +name = "SetBossCharActNo" +addr = 0x472940 + +[[func]] +name = "HitBossBullet" +addr = 0x472950 + +[[func]] +name = "ActBossChar_0" +addr = 0x472FF0 + +[[func]] +name = "ActBossChar" +addr = 0x473000 + +[[func]] +name = "HitBossMap" +addr = 0x473080 + +[[func]] +name = "ActBossChar_Core_Face" +addr = 0x4739B0 + +[[func]] +name = "ActBossChar_Core_Tail" +addr = 0x473BD0 + +[[func]] +name = "ActBossChar_Core_Mini" +addr = 0x473DE0 + +[[func]] +name = "ActBossChar_Core_Hit" +addr = 0x474340 + +[[func]] +name = "ActBossChar_Core" +addr = 0x474400 + +[[func]] +name = "ActBossChar_Undead" +addr = 0x4753D0 + +[[func]] +name = "ActBossCharA_Head" +addr = 0x476790 + +[[func]] +name = "ActBossCharA_Tail" +addr = 0x4769A0 + +[[func]] +name = "ActBossCharA_Face" +addr = 0x476B90 + +[[func]] +name = "ActBossCharA_Mini" +addr = 0x476E50 + +[[func]] +name = "ActBossCharA_Hit" +addr = 0x477230 + +[[func]] +name = "ActBossChar_Ballos" +addr = 0x4772F0 + +[[func]] +name = "ActBossChar_Eye" +addr = 0x478AA0 + +[[func]] +name = "ActBossChar_Body" +addr = 0x478F20 + +[[func]] +name = "ActBossChar_HITAI" +addr = 0x478FE0 + +[[func]] +name = "ActBossChar_HARA" +addr = 0x479010 + +[[func]] +name = "ActBossChar_Frog" +addr = 0x479030 + +[[func]] +name = "ActBossChar02_01" +addr = 0x47A6A0 + +[[func]] +name = "ActBossChar02_02" +addr = 0x47A800 + +[[func]] +name = "ActBossChar_Ironhead" +addr = 0x47A8A0 + +[[func]] +name = "InitBossLife" +addr = 0x47B450 +size = 0xF + +[[func]] +name = "StartBossLife" +addr = 0x47B460 + +[[func]] +name = "StartBossLife2" +addr = 0x47B500 + +[[func]] +name = "PutBossLife" +addr = 0x47B540 + +[[func]] +name = "ActBossChar_Omega" +addr = 0x47B6F0 + +[[func]] +name = "ActBoss01_12" +addr = 0x47C380 + +[[func]] +name = "ActBoss01_34" +addr = 0x47C4E0 + +[[func]] +name = "ActBoss01_5" +addr = 0x47C7A0 + +[[func]] +name = "ActBossChar_Press" +addr = 0x47C820 + +[[func]] +name = "ActBossChar_Twin" +addr = 0x47D170 + +[[func]] +name = "ActBossCharT_DragonBody" +addr = 0x47DAA0 + +[[func]] +name = "ActBossCharT_DragonHead" +addr = 0x47DF10 + +[[func]] +name = "ActBossChar_MonstX" +addr = 0x47E6F0 + +[[func]] +name = "ActBossChar03_01" +addr = 0x47F710 + +[[func]] +name = "ActBossChar03_02" +addr = 0x480090 + +[[func]] +name = "ActBossChar03_03" +addr = 0x4802A0 + +[[func]] +name = "ActBossChar03_04" +addr = 0x480550 + +[[func]] +name = "ActBossChar03_face" +addr = 0x4808C0 diff --git a/devilution/cvdump-LICENSE b/devilution/cvdump-LICENSE new file mode 100644 index 0000000..4e5ed85 --- /dev/null +++ b/devilution/cvdump-LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2015 Microsoft Corporation. All rights reserved. + +This code is licensed under the MIT License (MIT). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/devilution/cvdump.exe b/devilution/cvdump.exe new file mode 100644 index 0000000..8c1eff6 Binary files /dev/null and b/devilution/cvdump.exe differ diff --git a/devilution/devilution-comparer.exe b/devilution/devilution-comparer.exe new file mode 100644 index 0000000..952d629 Binary files /dev/null and b/devilution/devilution-comparer.exe differ diff --git a/game_english/data/Arms.pbm b/game_english/data/Arms.pbm new file mode 100644 index 0000000..887254f Binary files /dev/null and b/game_english/data/Arms.pbm differ diff --git a/game_english/data/ArmsImage.pbm b/game_english/data/ArmsImage.pbm new file mode 100644 index 0000000..76da086 Binary files /dev/null and b/game_english/data/ArmsImage.pbm differ diff --git a/game_english/data/ArmsItem.tsc b/game_english/data/ArmsItem.tsc new file mode 100644 index 0000000..defb090 --- /dev/null +++ b/game_english/data/ArmsItem.tsc @@ -0,0 +1 @@ +CPPPP-*\fre\waiYYYY\end-*-*CQPPP-*\msg\turn@N\waiYYYY\end-*CQPPQ-*\msg\turM@s@M-*p@@N-*m@@c@@@lN\waiYYYY\end-*CQPPR-*\msg\turM@p@s@M-*t@@@N-*i@@@@@pN-*\waiYYYY\end-*CQPPS-*\msg\turM@f@M-*b@@@N-*r@@@@N\waiYYYY\end-*CQPPT-*\msg\turM@m@g@M-*a@@M@N-*a@@@N\waiYYYY\end-*CQPPU-*\msg\turM@m@l@M-*w@@@@N-*hL@@@@N\waiYYYY\end-*CQPPW-*\msg\turM@b@M-*f@@a@hG@N-*h@@@@@@@N\waiYYYY\end-*CQPPY-*\msg\turM@b@M-*a@ML@M@N-*kG@@@N\waiYYYY\end-*CQPQP-*\msg\turM@s@m@M-*a@@@@N-*i@@@N\waiYYYY\end-*CQPQR-*\msg\turM@n@M-*l@@@gN-*f@@N\waiYYYY\end-*CQPQS-*\msg\turM@s@M-*h@@@@-*@@N\waiYYYY\end-*-*CQQPP-*\msg\turh\waiYYYY\end-*CQQPQ-*\msg\turm\waiYYYY\end-*CQQPR-*\msg\turs\waiYYYY\end-*CQQPS-*\msg\turk\waiYYYY\end-*CQQPT-*\msg\turn\waiYYYY\end-*-*CQRPP-*\msg\turjG@@@@@@N-*w@@@@L@-*@@@@@@@cN\waiYYYY\end-*CQRPQ-*\msg\turjG@N@l@MN-*o@@JJL@L@-*@@@@@@N\waiYYYY\end-*CQRPR-*\msg\turjG@N@l@@N@d-*@@L@@@@-*@@@@N\waiYYYY\end-*CQRPS-*\msg\turjG@N@a@@@-*@@@@L-*@@@@@@N\waiYYYY\end-*CQRPT-*\msg\turjG@N@s@@@@-*L@@@@@-*@@@@N\waiYYYY\end-*-*CUPPP-*\msg\turn@N\waiYYYY\end-*CUPPQ-*\msg\turaG@k\waiYYYY\end-*CUPPR-*\msg\turm@s\waiYYYY\end-*CUPPS-*\msg\tursG@k\waiYYYY\end-*CUPPT-*\msg\turs@l\waiYYYY\end-*CUPPU-*\msg\turb@f\waiYYYY\end-*CUPPV-*\msg\turl@c\waiYYYY\end-*CUPPW-*\msg\turid@c\waiYYYY\end-*CUPPX-*\msg\turj@j\waiYYYY\end-*CUPPY-*\msg\turr@k\waiYYYY\end-*CUPQP-*\msg\turg@k\waiYYYY\end-*CUPQQ-*\msg\turg@b\waiYYYY\end-*CUPQR-*\msg\turc\waiYYYY\end-*CUPQS-*\msg\ture\waiYYYY\end-*CUPQT-*\fljSPPPZQQPP-*\fljSPPQZQQPQ-*\fljSPPRZQQPR-*\fljSPPSZQQPS-*\fljSPPTZQQPT-*\msg\turp\waiYYYY\end-*CUPQU-*\msg\turl@p\waiYYYY\end-*CUPQV-*\msg\turcMa\waiYYYY\end-*CUPQW-*\msg\turc@k\waiYYYY\end-*CUPQX-*\msg\turb@PNX\waiYYYY\end-*CUPQY-*\msg\tura@b\waiYYYY\end-*CUPRP-*\msg\turt\waiYYYY\end-*CUPRQ-*\msg\turcG@a@t\waiYYYY\end-*CUPRR-*\msg\turn@c\waiYYYY\end-*CUPRS-*\msg\turb@RNP\waiYYYY\end-*CUPRT-*\msg\turm@m\waiYYYY\end-*CUPRU-*\msg\turt@r@k\waiYYYY\end-*CUPRV-*\msg\tursG@l\waiYYYY\end-*CUPRW-*\msg\turc\waiYYYY\end-*CUPRX-*\msg\turb@s\waiYYYY\end-*CUPRY-*\msg\turs\waiYYYY\end-*CUPSP-*\msg\turt@r\waiYYYY\end-*CUPSQ-*\msg\turc@f@m\waiYYYY\end-*CUPSR-*\msg\turl@m\waiYYYY\end-*CUPSS-*\msg\turm@b\waiYYYY\end-*CUPST-*\msg\turm@p\waiYYYY\end-*CUPSU-*\msg\turcG@u\waiYYYY\end-*CUPSV-*\msg\tura@m\waiYYYY\end-*CUPSW-*\msg\turcG@l\waiYYYY\end-*CUPSX-*\msg\turw@s\waiYYYY\end-*CUPSY-*\msg\turi@b\waiYYYY\end-*-*CVPPP-*\msg\turn@N\waiYYYY\end-*CVPPQ-*\msg\turt@@@aG@N-*i@@@@aG-*N\waiYYYY\end-*CVPPR-*\pri\eveWPPR\mpjWPPR\msgn@@@@N\nod\clr\end-*CVPPS-*\msg\turt@@@sG@N\waiYYYY\end-*CVPPT-*\msg\tura@@@@@@@@N-*f@@@G@L@@-*@G@@@@N\waiYYYY\end-*CVPPU-*\msg\tura@@@@@-*y@fN@i@@@-*NNN_\waiYYYY\end-*CVPPV-*\msg\tura@@N\waiYYYY\end-*CVPPW-*\msg\tura@id@c@@@e@nN@PVN\waiYYYY\end-*CVPPX-*\msg\tura@@@@-*N\waiYYYY\end-*CVPPY-*\msg\tura@@N\waiYYYY\end-*CVPQP-*\msg\tura@@@BgBN\waiYYYY\end-*CVPQQ-*\msg\tura@@@N\waiYYYY\end-*CVPQR-*\msg\turt@@@N\waiYYYY\end-*CVPQS-*\msg\tura@@@@@-*@N\waiYYYY\end-*CVPQT-*\fljSPPPZQRPP-*\fljSPPQZQRPQ-*\fljSPPRZQRPR-*\fljSPPSZQRPS-*\fljSPPTZQRPT-*\msg\turjG@ N\waiYYYY\end-*CVPQU-*\key\msgt@@@@L-*@@N@w@@@_\ynjPPPP\liKQPPP\souPPRP\itMPPQU\msg-*l@N\fre\waiYYYY\end-*CVPQV-*\msg\tura@@-*@@NNN\waiYYYY\end-*CVPQW-*\msg\turi@@Bl@cBN\waiYYYY\end-*CVPQX-*\fljPWTRZWPQX-*\key\msgp@@@@@-*@@@@N\nod\clr-*d@@@@@_\ynjPPPP\eqKPPPQ\flKPWTR\eqMPPSR\flMPWTS\msg-*b@N\nod\waiPPPS\fre\eveUPQX-*CVPQY-*\msg\turw@@@L@@-*@@@@@@N\waiYYYY\end-*CVPRP-*\msg\turi@@@@@-*@@@N\waiYYYY\end-*CVPRQ-*\msg\tury@@@@-*N@c@@@@N\waiYYYY\end-*CVPRR-*\msg\tura@@@N-*y@G@@@N\waiYYYY\end-*CVPRS-*\fljPWTSZWPRS-*\key\msgp@@@@@@-*@@@@@N\nod\clr-*d@@@@@_\ynjPPPP\eqKPPSR\flKPWTS\eqMPPPQ\flMPWTR\msg-*e@b@RNPN\nod\waiPPPS\fre\eveUPRS-*CVPRT-*\msg\tura@m@@sG@@N-*iG@@@NNN\waiYYYY\end-*CVPRU-*\msg\tura@@@@@@-*mN\waiYYYY\end-*CVPRV-*\key\msgw@@@_\ynjPPPP\msg\tur-*t@@sN\nod\clri@G@@i@@-*@@@@@N\nod\clrw@@@@@-*@@@@@N\nod\clrpN@b@@@-*L@@@@-*L@@L\nod\clr@NNN-*t@d@@N\nod\clrh@@@@@-*@L@@@NNN\nod\clra@L@@@-*@d@cNNN\waiPPRP\nod\clrt@L@@@-*@@@@@L\nod\clr@@-*@@@NNN\nod\clrt@d@@@-*@@@@L\nod\clr@@@@@-*@@@@@-*@N\nod\clro@@@@c@-*@L@@@-*@@@N\nod\clrw@@@@@-*@@@@-*@@@N\nod\clrt@d@@@@-*eG@@@-*@@@N\nod\clri@@@@@-*@@@-*@m@@N\nod\clraL@i@@@@@-*L@@i@@@-*@@NNN\nod\clrnL@G@@@-*m@@@@-*@@N\nod\clro@@@@@L@@-*@@m@@@-*@@@N\nod\clru@@@L-*@@@@@@-*@m@@@@N\nod\clr-*a@@@iL@L@NNN\nod\clri@@@@@@-*L@@@@@-*@@N\nod\clri@@@@@L-*G@@L@@-*@@N\nod\clrpN@h@@N\nod\clrt@@-*Bl@mBN\nod\clr\flKQPRT\fre\msgt@@@NNN\waiYYYY\end-*CVPRW-*\msg\turn@@@@N-*p@@iL@@@N\waiYYYY\end-*CVPRX-*\msg\tura@@@N\waiYYYY\end-*CVPRY-*\msg\turiG@MN@NNNpN\waiYYYY\end-*CVPSP-*\msg\tura@@@@N\waiYYYY\end-*CVPSQ-*\msg\turs@@@N-*i@@@N\waiYYYY\end-*-*CVPSR-*\msg\turhA@w@@_\waiYYYY\end-*CVPSS-*\msg\turt@@@@@@-*N@i@@@@N@t@-*L@@G@@@NNN\flKQUVS\waiYYYY\end-*CVPST-*\msg\turaL@@@@@-*@NNN\waiYYYY\end-*CVPSU-*\msg\turr@@@@N-*yM@@@@-*@N@t@@@N\waiYYYY\end-*CVPSV-*\msg\ture@@@@@-*N@i@@@N\waiYYYY\end-*CVPSW-*\msg\turr@N-*i@@@N\waiYYYY\end-*CVPSX-*\key\msga@@@@@-*c@@@N-*a@@N\nod\fljPWRRZWPSX\clr-*w@@@_\ynjPPPP\eqKPQRX\flKPWRR\msg-*e@@w@sN\nod\waiPPPS\fre\eveUPSX-*CVPSY-*\msg\tury@@@c@bL@@-*@@@@@@N-*s@@@@@@NNN\waiYYYY\end-*-*CWPPR-*\mlp\end-*-*CWPQX-*\key\msgd@@@@@_\ynjPPPP\eqMPPPQ\flMPWTR\msg-*d@bN\nod\waiPPPS\fre\eveUPQX-*CWPRS-*\key\msgd@@@@@_\ynjPPPP\eqMPPSR\flMPWTS\msg-*d@b@RNPN\nod\waiPPPS\fre\eveUPRS-*-*CWPSX-*\key\msgd@@@@@_\ynjPPPP\eqMPQRX\flMPWRR\msg-*d@@w@sN\nod\waiPPPS\fre\eveUPSX-*-* \ No newline at end of file diff --git a/game_english/data/Bullet.pbm b/game_english/data/Bullet.pbm new file mode 100644 index 0000000..b831422 Binary files /dev/null and b/game_english/data/Bullet.pbm differ diff --git a/game_english/data/Caret.pbm b/game_english/data/Caret.pbm new file mode 100644 index 0000000..4ac92e4 Binary files /dev/null and b/game_english/data/Caret.pbm differ diff --git a/game_english/data/Credit.tsc b/game_english/data/Credit.tsc new file mode 100644 index 0000000..1ca0d1c --- /dev/null +++ b/game_english/data/Credit.tsc @@ -0,0 +1 @@ +||͒ƒϢ||͟ג咟Ϣ|랒Ϣ|͒Ϣ|͒גϢ|ͺϢ|͒גϢ|͒ӒϢ|יϢ|͒Ϣ|יϢ|͒Ϣ|͒Ϣ|גӟϢ|͒Ϣ|͒Ϣ||͟ӒגϢ|֒Ϣ|͒Ϣ|גגϢ|͒Ϣ|גϢ|͒Ϣ|Ϣ|͒Ϣ|;Ϣ|͒Ϣ|ͿגϢ|͒Ϣ||͟Ϣ|;Ϣ|͒Ϣ|ג֒Ϣ|͒Ϣ|ߒϢ|͒Ϣ||֒͟גϢ|ͳؒגϢ|͒Ϣ|֒뒵Ϣ|͒גϢ|ޒϢ|͒ג֒Ϣ|͒Ϣ||ͼәϢ|͒Ϣ|͒Ϣ|͒Ϣ|͒Ϣ|͒Ϣ||͟ڒϢ|גڙϢ|͒Ϣ|͒Ϣ|גڙϢ|͒Ϣ|͒䠒Ϣ|ͻߒӒדϢ|͒גϢ||͟Ϣ|גޒϢ|͒Ϣ|גӒϢ|͒Ϣ|Ϣ|͒Ϣ|ʹϢ|͒Ϣ|͒גޒϢ|||ؤ|͟咟Ϣ|גϢ|͒Ϣ|͒גϢ|גϢ|͒Ϣ|ͿْϢ|͒Ϣ||͟ӒϢ|ג撹Ϣ|͒璽Ϣ|גϢ|͒Ϣ|͒ӒϢ|גْϢ|͒גϢ|͒גϢ|גϢ|͒גϢ|͒Ϣ|גגϢ|͒Ϣ|ܢ||ޢ|͟咟Ϣ|ͷ֒גϢ|͒גϢ|͵֒גϢ|͒Ϣ|ӒϢ|͒Ϣ||͟咟Ϣ|ג撹Ϣ|͒璽Ϣ|גϢ|͒Ϣ|͒ӒϢ|גْϢ|͒גϢ|͒גϢ|גϢ|͒גϢ|͒Ϣ|גגϢ|͒Ϣ||͟뒺뒾֒Ϣ|ͼәϢ|͒Ϣ|͒Ϣ|ޢ||||||͒咯Ϣ||͒֒嬒Ϣ|͒גӬϢ|͒֒٬גϢ|͒֬Ϣ|͒ג߬Ϣ|͒ڒ٬Ϣ|͒י׬Ϣ|͒⬒Ϣ|ْ͒ڬϢ|͒ޒ欒Ϣ|͒גْ䬒Ϣ|͒ג䬒䒵Ϣ|͒ג֒欒Ϣ|͒٬Ϣ|ْ͒rϢ|͒欒Ϣ|͒묒Ϣ|͒撿ӬϢ|͒⬒Ϣ|͒䬒Ϣ|ْ͒ެϢ|͒֒䬒Ϣ|͒ג׬Ϣ|͒֒ג䬒Ϣ|͒ڒ׬Ϣ|͒ߒמ묒Ϣ|ْ͒׬Ϣ|͒ߒ֒ᬒϢ|͒ڒ䬒Ϣ|͒ڒ䬒Ϣ|͒ڒ묒ےϢ|͒଒גϢ|͒߬ᒴϢ|͒֬Ϣ|͒ے欒Ϣ|͒⬒쒵Ϣ|͒֒֬גϢ|ْ͒׬Ϣ|͒֒׬䒴Ϣ|͒ޒ䬒Ϣ|͒嬒Ϣ|͒Ւ䬒Ϣ|͒ؒڬϢ|ْ͒׬Ϣ|͒欒Ϣ|͒묒Ϣ||ؤܢޢ||͒ޙ䬒Ϣ|͒ޙ䬒Ϣ|͒଒Ϣ|ْ͒ג嬒Ϣ|͒׬Ϣ|ޢ|||͒咯Ϣ||͸֒ӒϢ|͒֒Ϣ|͒Ϣ|ͿϢ|ْ͒Ϣ|͒Ϣ|ͿןϢ|͒גϢ|͒Ϣ|Ͷ֒ڒ֒Ϣ|͒ᒝϢ|͹֒Ϣ|͒Ϣ|͒ڒϢ|ʹْגϢ|͒Ϣ|ͺؒגϢ|͒Ϣ|ʹْڒג֙Ϣ|͒Ϣ|͒Ϣ|Ϣ|͒Ϣ|͒Ϣ|גϢ|͒֒Ϣ|ג֒ޒϢ|͒Ϣ|͒גϢ|ג֒֒Ϣ|͒֙Ϣ|͒֒Ϣ|ؤܢޢ||גϢ|͒Ϣ|ͺג֒Ϣ|͒Ϣ|͒Ϣ|ޢ|||͒Ϣ||ͳϢ|͹Ϣ|ͿӒϢ|Ϣ|ʹٙϢ||͹Ϣ|͵Ϣ|Ϣ|ͿϢ|Ϣ||ᒹϢ|ͷؒϢ|ͿϢ|Ϣ|Ϣ||ͼӒϢ|ͼӒϢ|;ڒϢ|͹Ϣ|Ϣ||;ْϢ|Ϣ|ْϢ|ͿϢ|ͺ咷Ϣ||͵גϢ|;撵Ϣ|ʹϢ|͵Ϣ|Ϣ||;撴Ϣ|ʹݒϢ|ْϢ|ޒϢ|ג뒴ݒϢ|||ͯޒ咯Ϣ|||ےϢ|璒Ϣ|ͽϢ|ʹϢ|ےϢ|ᒒϢ|ڒ璒Ϣ|͹Ϣ|ͳ֒Ϣ||ݒڠϢ|||͵גגϢ|||||| \ No newline at end of file diff --git a/game_english/data/Face.pbm b/game_english/data/Face.pbm new file mode 100644 index 0000000..9233e33 Binary files /dev/null and b/game_english/data/Face.pbm differ diff --git a/game_english/data/Fade.pbm b/game_english/data/Fade.pbm new file mode 100644 index 0000000..e7b6aa1 Binary files /dev/null and b/game_english/data/Fade.pbm differ diff --git a/game_english/data/Head.tsc b/game_english/data/Head.tsc new file mode 100644 index 0000000..e1561b1 --- /dev/null +++ b/game_english/data/Head.tsc @@ -0,0 +1 @@ +gttttQNQNQNgtttuQNrQNQNgttuzQNQNddddttttotxwudrQNQNgttu{QNtvtu~ttu|QNoutttttvtoQNdrQNgttu|QNQNoutttttvtoQNdddrQNQNgttu}QNQNddddtttttttxttttttvtrrrrrQNttytQNoutttttvttttvQNdrtttxQNQNgttwtQNtvtv~ttwvtvtu~ttwuotvtutttyottty~ttutQNttutdddetuztdddddQNpdddddrQNddddQNddddrDQNgttwuQNottty~tttyQNtttzddddtttteQNgttwvQNottut~tttyQNttuuddddtttteQNQNgttxtQNttttttxtttxttttwQNQNddrddttx}QNtttuttyttxwu~ttx|QNQNgttxuQNttttttxtttxttttwQNQNddrddttx}QNtttuttyttxwu~ttx|QNQNgttxvQNttttttxtttxttttwQNQNddddrrrddttx}QNtttuttyttxwu~ttx|QNQNgttx|QNQNQNgttx}QNtttxQNQNQN~drdddxtttdqdxt}}QNxttt~3QN \ No newline at end of file diff --git a/game_english/data/ItemImage.pbm b/game_english/data/ItemImage.pbm new file mode 100644 index 0000000..9fc3dd6 Binary files /dev/null and b/game_english/data/ItemImage.pbm differ diff --git a/game_english/data/Loading.pbm b/game_english/data/Loading.pbm new file mode 100644 index 0000000..bf604d2 Binary files /dev/null and b/game_english/data/Loading.pbm differ diff --git a/game_english/data/MyChar.pbm b/game_english/data/MyChar.pbm new file mode 100644 index 0000000..43b8be9 Binary files /dev/null and b/game_english/data/MyChar.pbm differ diff --git a/game_english/data/Npc/Npc0.pbm b/game_english/data/Npc/Npc0.pbm new file mode 100644 index 0000000..f0406f2 Binary files /dev/null and b/game_english/data/Npc/Npc0.pbm differ diff --git a/game_english/data/Npc/NpcAlmo1.pbm b/game_english/data/Npc/NpcAlmo1.pbm new file mode 100644 index 0000000..b26cb59 Binary files /dev/null and b/game_english/data/Npc/NpcAlmo1.pbm differ diff --git a/game_english/data/Npc/NpcAlmo2.pbm b/game_english/data/Npc/NpcAlmo2.pbm new file mode 100644 index 0000000..1e0fa21 Binary files /dev/null and b/game_english/data/Npc/NpcAlmo2.pbm differ diff --git a/game_english/data/Npc/NpcBallos.pbm b/game_english/data/Npc/NpcBallos.pbm new file mode 100644 index 0000000..0b779ce Binary files /dev/null and b/game_english/data/Npc/NpcBallos.pbm differ diff --git a/game_english/data/Npc/NpcBllg.pbm b/game_english/data/Npc/NpcBllg.pbm new file mode 100644 index 0000000..e78ac0d Binary files /dev/null and b/game_english/data/Npc/NpcBllg.pbm differ diff --git a/game_english/data/Npc/NpcCemet.pbm b/game_english/data/Npc/NpcCemet.pbm new file mode 100644 index 0000000..1b39646 Binary files /dev/null and b/game_english/data/Npc/NpcCemet.pbm differ diff --git a/game_english/data/Npc/NpcCent.pbm b/game_english/data/Npc/NpcCent.pbm new file mode 100644 index 0000000..e437f32 Binary files /dev/null and b/game_english/data/Npc/NpcCent.pbm differ diff --git a/game_english/data/Npc/NpcCurly.pbm b/game_english/data/Npc/NpcCurly.pbm new file mode 100644 index 0000000..2f68e25 Binary files /dev/null and b/game_english/data/Npc/NpcCurly.pbm differ diff --git a/game_english/data/Npc/NpcDark.pbm b/game_english/data/Npc/NpcDark.pbm new file mode 100644 index 0000000..8a61417 Binary files /dev/null and b/game_english/data/Npc/NpcDark.pbm differ diff --git a/game_english/data/Npc/NpcDr.pbm b/game_english/data/Npc/NpcDr.pbm new file mode 100644 index 0000000..6fab8b7 Binary files /dev/null and b/game_english/data/Npc/NpcDr.pbm differ diff --git a/game_english/data/Npc/NpcEggs1.pbm b/game_english/data/Npc/NpcEggs1.pbm new file mode 100644 index 0000000..8c1decb Binary files /dev/null and b/game_english/data/Npc/NpcEggs1.pbm differ diff --git a/game_english/data/Npc/NpcEggs2.pbm b/game_english/data/Npc/NpcEggs2.pbm new file mode 100644 index 0000000..41075d4 Binary files /dev/null and b/game_english/data/Npc/NpcEggs2.pbm differ diff --git a/game_english/data/Npc/NpcFrog.pbm b/game_english/data/Npc/NpcFrog.pbm new file mode 100644 index 0000000..b9f16af Binary files /dev/null and b/game_english/data/Npc/NpcFrog.pbm differ diff --git a/game_english/data/Npc/NpcGuest.pbm b/game_english/data/Npc/NpcGuest.pbm new file mode 100644 index 0000000..c93153c Binary files /dev/null and b/game_english/data/Npc/NpcGuest.pbm differ diff --git a/game_english/data/Npc/NpcHell.pbm b/game_english/data/Npc/NpcHell.pbm new file mode 100644 index 0000000..dd6968a Binary files /dev/null and b/game_english/data/Npc/NpcHell.pbm differ diff --git a/game_english/data/Npc/NpcHeri.pbm b/game_english/data/Npc/NpcHeri.pbm new file mode 100644 index 0000000..03477c1 Binary files /dev/null and b/game_english/data/Npc/NpcHeri.pbm differ diff --git a/game_english/data/Npc/NpcIronH.pbm b/game_english/data/Npc/NpcIronH.pbm new file mode 100644 index 0000000..7a25909 Binary files /dev/null and b/game_english/data/Npc/NpcIronH.pbm differ diff --git a/game_english/data/Npc/NpcIsland.pbm b/game_english/data/Npc/NpcIsland.pbm new file mode 100644 index 0000000..36a377a Binary files /dev/null and b/game_english/data/Npc/NpcIsland.pbm differ diff --git a/game_english/data/Npc/NpcKings.pbm b/game_english/data/Npc/NpcKings.pbm new file mode 100644 index 0000000..b8e8572 Binary files /dev/null and b/game_english/data/Npc/NpcKings.pbm differ diff --git a/game_english/data/Npc/NpcMaze.pbm b/game_english/data/Npc/NpcMaze.pbm new file mode 100644 index 0000000..1a699a2 Binary files /dev/null and b/game_english/data/Npc/NpcMaze.pbm differ diff --git a/game_english/data/Npc/NpcMiza.pbm b/game_english/data/Npc/NpcMiza.pbm new file mode 100644 index 0000000..f33a228 Binary files /dev/null and b/game_english/data/Npc/NpcMiza.pbm differ diff --git a/game_english/data/Npc/NpcMoon.pbm b/game_english/data/Npc/NpcMoon.pbm new file mode 100644 index 0000000..d9e58b5 Binary files /dev/null and b/game_english/data/Npc/NpcMoon.pbm differ diff --git a/game_english/data/Npc/NpcOmg.pbm b/game_english/data/Npc/NpcOmg.pbm new file mode 100644 index 0000000..07e3ed1 Binary files /dev/null and b/game_english/data/Npc/NpcOmg.pbm differ diff --git a/game_english/data/Npc/NpcPlant.pbm b/game_english/data/Npc/NpcPlant.pbm new file mode 100644 index 0000000..fd63c3f Binary files /dev/null and b/game_english/data/Npc/NpcPlant.pbm differ diff --git a/game_english/data/Npc/NpcPress.pbm b/game_english/data/Npc/NpcPress.pbm new file mode 100644 index 0000000..763efac Binary files /dev/null and b/game_english/data/Npc/NpcPress.pbm differ diff --git a/game_english/data/Npc/NpcPriest.pbm b/game_english/data/Npc/NpcPriest.pbm new file mode 100644 index 0000000..8758f66 Binary files /dev/null and b/game_english/data/Npc/NpcPriest.pbm differ diff --git a/game_english/data/Npc/NpcRavil.pbm b/game_english/data/Npc/NpcRavil.pbm new file mode 100644 index 0000000..5252dad Binary files /dev/null and b/game_english/data/Npc/NpcRavil.pbm differ diff --git a/game_english/data/Npc/NpcRed.pbm b/game_english/data/Npc/NpcRed.pbm new file mode 100644 index 0000000..dbcdbc5 Binary files /dev/null and b/game_english/data/Npc/NpcRed.pbm differ diff --git a/game_english/data/Npc/NpcRegu.pbm b/game_english/data/Npc/NpcRegu.pbm new file mode 100644 index 0000000..6134608 Binary files /dev/null and b/game_english/data/Npc/NpcRegu.pbm differ diff --git a/game_english/data/Npc/NpcSand.pbm b/game_english/data/Npc/NpcSand.pbm new file mode 100644 index 0000000..30a7d38 Binary files /dev/null and b/game_english/data/Npc/NpcSand.pbm differ diff --git a/game_english/data/Npc/NpcStream.pbm b/game_english/data/Npc/NpcStream.pbm new file mode 100644 index 0000000..3720fd8 Binary files /dev/null and b/game_english/data/Npc/NpcStream.pbm differ diff --git a/game_english/data/Npc/NpcSym.pbm b/game_english/data/Npc/NpcSym.pbm new file mode 100644 index 0000000..ff3c8bb Binary files /dev/null and b/game_english/data/Npc/NpcSym.pbm differ diff --git a/game_english/data/Npc/NpcToro.pbm b/game_english/data/Npc/NpcToro.pbm new file mode 100644 index 0000000..748892c Binary files /dev/null and b/game_english/data/Npc/NpcToro.pbm differ diff --git a/game_english/data/Npc/NpcTwinD.pbm b/game_english/data/Npc/NpcTwinD.pbm new file mode 100644 index 0000000..bd62e71 Binary files /dev/null and b/game_english/data/Npc/NpcTwinD.pbm differ diff --git a/game_english/data/Npc/NpcWeed.pbm b/game_english/data/Npc/NpcWeed.pbm new file mode 100644 index 0000000..e6d3a5e Binary files /dev/null and b/game_english/data/Npc/NpcWeed.pbm differ diff --git a/game_english/data/Npc/NpcX.pbm b/game_english/data/Npc/NpcX.pbm new file mode 100644 index 0000000..ae68e41 Binary files /dev/null and b/game_english/data/Npc/NpcX.pbm differ diff --git a/game_english/data/Stage/0.pxa b/game_english/data/Stage/0.pxa new file mode 100644 index 0000000..6c69bb8 Binary files /dev/null and b/game_english/data/Stage/0.pxa differ diff --git a/game_english/data/Stage/0.pxe b/game_english/data/Stage/0.pxe new file mode 100644 index 0000000..d31a268 Binary files /dev/null and b/game_english/data/Stage/0.pxe differ diff --git a/game_english/data/Stage/0.pxm b/game_english/data/Stage/0.pxm new file mode 100644 index 0000000..e7c762e Binary files /dev/null and b/game_english/data/Stage/0.pxm differ diff --git a/game_english/data/Stage/0.tsc b/game_english/data/Stage/0.tsc new file mode 100644 index 0000000..be08b99 --- /dev/null +++ b/game_english/data/Stage/0.tsc @@ -0,0 +1 @@ +0-FSS\S0-_pqd_fpxSST[_idlSSSS_hqg0-FSS\T0-_pqd_fpxSST[_idlSSST_hqg0-FSS\U0-_pqd_fpxSST[_idlSSSU_hqg0-FSS\V0-_pqd_fpxSST[_idlSSSV_hqg0-FSS\W0-_pqd_fpxSST[_idlSSSW_hqg0-0-0-0-0-0-0-0-FSTSS0-_nh|_irpSSTY_zdlSTSS_htPSUXY_fuh_zdlSVWS0-0-_iomUSSS]STTS0-_iomTSUS]STST0-0-_vloSSST_zdlSVXS_flo_zdlSSUS0-_vloSSSU_zdlSVXS_flo_zdlSSUS0-_vloSSSV_zdlSVXS_flo_zdlSSUS0-_hyhSTSU0-FSTST0-_vloSSST_zdlSVXS_flo_zdlSSUS0-_vloSSSU_zdlSVXS_flo_zdlSSUS0-_vloSSSV_zdlSVXS_flo_zdlSSUS0-_hyhSTSU0-0-FSTSU0-_vloSSSW_zdlSVXS_flo_zdlSSUS0-_vloSSSX_zdlSVXS_flo_zdlSSUS0-_vloSSSY_zdlSVXS_flo_zdlSSUS0-_vloSSSZ_zdlSVXS_flo_zdlSSUS0-_vloSSS[_zdlSVXS_flo_zdlSSUS0-_vloSSS\_zdlSVXS_flo_zdlSSUS0-_vloSSTS_zdlSVXS_flo_zdlSSUS0-_vloSSTT_zdlSVXS_flo_zdlSSUS0-_vloSSTZ_zdlSVXS_flo0-_zdlSU[S_hyhSUSS0-0-FSTTS0-_vloSSTU_zdlSVXS_flo_zdlSSUS0-_vloSST[_zdlSVXS_flo_zdlSSUS0-_vloSSTW_zdlSVXS_flo_zdlSSUS0-_vloSSSU_zdlSVXS_flo_zdlSSUS0-_vloSSSV_zdlSVXS_flo_zdlSSUS0-_vloSSSW_zdlSVXS_flo_zdlSSUS0-_vloSSSX_zdlSVXS_flo_zdlSSUS0-_vloSSSZ_zdlSVXS_flo_zdlSSUS0-_vloSSS[_zdlSVXS_flo_zdlSSUS0-_vloSSS\_zdlSVXS_flo_zdlSSUS0-_vloSSTS_zdlSVXS_flo_zdlSSUS0-_vloSSTT_zdlSVXS_flo_zdlSSUS0-_vloSSTZ_zdlSVXS_flo0-_zdlSSUS_hyhSUSS0-0-FSUSS0-0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSYTS_idrSSST0-_wudSSZW]STSS]SSST]SSST0-0-FSWSS0-0-FSXSS0-FSXST0-FSXSU0-FSXSV0-FSXSW0-FSXSX0-FSXSY0-0-FSXSZ0-FSXS[0-FSXS\0-FSXTS0-FSXTT0-FSXTU0-FSXTV0-0-#SYSS0-0-0-FTSTS0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSWSS_idrSSST0-_wudSSZX]STSS]SSUS]SSST0-FTSUSp0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSWSS_idrSSST0-_wudSSZY]STSS]SSST]SSST0-FTSVS0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSWSS_idrSSST0-_wudSSZZ]STSS]SSST]SSST0-FTSWS0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSWSS_idrSSST0-_wudSSZ[]STSS]SSST]SSST0-FTSXS0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSWSS_idrSSST0-_wudSS[\]STSS]SSST]SSST0-FTSYS0-_iomUSSS]TSYT_hyhTS\S0-FTSYT0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]SS\\]SSSS0-_idlSSST_zdlSWSS_idrSSST0-_wudSS\V]STSS]SSST]SSST0-0-FTS\S0-_fqsSWSS]STXS]SSSS0-_dqsSWSS]STSS]SSSS0-_idlSSST0-_iomUSSS]TUSS_hyhTTSS0-0-FTTSS0-_zdlSZVU0-_dqsSWSS]SSSU]SSSS_zdlSSXS0-_fqsSXSV]SVXU]SVSS_zdlSSUS0-_fqsSXSW]SVXU]SWSS_zdlSSUS0-_fqsSXSU]SVXU]SUSS_zdlSSUS0-_fqsSXSX]SVXU]SXSS_zdlSSUS0-_fqsSXST]SVXU]STSS_zdlSSUS0-_fqsSXSY]SVXU]SYSS_zdlSSUS0-_fqsSXSS]SVXU]SSSS_zdlSSUS0-_dqsSWSS]SSSS]SSSS0-_vloSSTY0-_ipx_zdlSUSS_fpxSSSS0-_fqsSYSS]SVYS]SSSS0-_zdl\\\\_hqg0-0-FTUSS0-_zdlSWVU0-_dqsSWSS]SSSU]SSSS_zdlSSXS0-_fqsSXTS]SVXU]TSSS_zdlSSUS0-_fqsSXTT]SVXU]TTSS_zdlSSUS0-_fqsSXS\]SVXU]S\SS_zdlSSUS0-_fqsSXTU]SVXU]TUSS_zdlSSUS0-_fqsSXS[]SVXU]S[SS_zdlSSUS0-_fqsSXTV]SVXU]TVSS_zdlSSUS0-_fqsSXSZ]SVXU]SZSS_zdlSSUS0-_dqsSWSS]SSSS]SSSS0-_vloSSTX0-_ipx_zdlSUSS_fpxSSSS0-_fqsSYSS]SVYS]SSSS0-_zdl\\\\_hqg0- \ No newline at end of file diff --git a/game_english/data/Stage/555.pxe b/game_english/data/Stage/555.pxe new file mode 100644 index 0000000..7164051 Binary files /dev/null and b/game_english/data/Stage/555.pxe differ diff --git a/game_english/data/Stage/Almond.pxa b/game_english/data/Stage/Almond.pxa new file mode 100644 index 0000000..35b783d Binary files /dev/null and b/game_english/data/Stage/Almond.pxa differ diff --git a/game_english/data/Stage/Almond.pxe b/game_english/data/Stage/Almond.pxe new file mode 100644 index 0000000..d17814a Binary files /dev/null and b/game_english/data/Stage/Almond.pxe differ diff --git a/game_english/data/Stage/Almond.pxm b/game_english/data/Stage/Almond.pxm new file mode 100644 index 0000000..4772196 Binary files /dev/null and b/game_english/data/Stage/Almond.pxm differ diff --git a/game_english/data/Stage/Almond.tsc b/game_english/data/Stage/Almond.tsc new file mode 100644 index 0000000..2eedf96 --- /dev/null +++ b/game_english/data/Stage/Almond.tsc @@ -0,0 +1 @@ +0==F=IZ[NIPZb==?@ISNV====IR[Q0==F>IZ[NIPZb==?@ISNV===>IR[Q0==F?IZ[NIPZb==?@ISNV===?ISYW=E?FG==FEISYW=E??G==FDIR[Q0==F@IZ[NIPZb==?@ISNV===@IR[Q0==FAIZ[NIPZb==?@ISNV===AIR[Q0==FDIN[]=?B@G==?=G====IR[Q0==FEIP[]=@=CG=>>DG====IN[]=@=CG==@?G===?IR[Q0=>==IXRfISYW=E@FG=>=>I`\b==>>IN[]=>==G====G===?ISN\====Ia_N==ACG==F=G==>DG===F0=>=>IXRfIZ`TV-|{4-|}r{;;;I[\QIR[Q0=?==IXRfISYW=E@?G=?=AISYW=E?AG=?=@ISYW=E?@G=?=?ISYW=E?>G=?=>IZ`T\]R[-`UbaaR_LIf[W====IPY_\]R[V[T-`UbaaR_I[\QIPY\IZfQ====IdNV==@=IN[]=?B=G==>=G===>IdNV==>=IN[]=@==G===>G===?IdNV==??IN[]=?B>G==>=G===>IN[]=@==G===@G===?IdNV==@?IN[]=?B?G==>=G===>IdNV==@?IN[]=?B@G==>=G===>IdNV==@?IN[]=?BAG==>=G===>IQ[]=?B=IdNV==@?IQ[]=?B>IdNV==@?IQ[]=?B?IN[]=?B@G===>G====IdNV==@?IQ[]=@==IP[]=@=>G=>>DG====IN[]=@=>G==?>G===?ISY:=E?=ISY8=E?>ISY8=E??IZ`TNO[\_ZNYVaf-QRaRPaRQ-V[`UbaaR_-[\;-AI[\QIR[Q0=?=>IXRfIZ`TNO[\_ZNYVaf-QRaRPaRQ-V[`UbaaR_-[\;-AI[\QIR[Q0=?=?IXRfIZ`TY\dR_-YVSaLIf[W====IPY_ISY8=E?AY\dR_V[T-YVSaI[\QIPY\IS\[=?BDG==>CIdNV==B=IN[]=?BDG==>=G===@IdNV=>F?IN[]=?BDG====G====IdNV==B=IS\Z==>CIZ`TYVSa-Y\dR_RQI[\QIR[Q0=?=@IXRfIZ`TYVSa-V`-Y\dR_RQI[\QIR[Q0=?=AIXRfIZ`TR__\_I[\QIR[Q0=?>=IXRfISYW=E@=G=?>?ISYW=E?BG=?>>IZ`T\]R[-`UbaaR_LIf[W====IPY_ISY8=E?B\]R[V[T-`UbaaR_I[\QIPY\IdNV==A=IN[]=?BCG==>=G===>IdNV=>?EIQ[]=?BCIZ`T`UbaaR_-\]R[RQI[\QIR[Q0=?>>IXRfIZ`T`UbaaR_-\]R[RQI[\QIR[Q0=?>?IXRfIZ`TR__\_I[\QIR[Q0=?A=I]_VISYW=E?EG=?A>IZ`T`|zruv{t-v-p|vyrq-n|{qur-o|xr{-|o|4-nz;I[\QIPY_dvyy-|-nxr-vLIf[W====IPY_ITVa>=@=IQ[]=?A=IVa8==@=ISY8=E@FIPY_IPZb==>=T|-ur-Ja|-_|}rJ;IdNV=>C=I[\QI_ZbIR[Q0=?A>I]_VIZ`T;;;LI[\QIR[Q0=?A?I]_VIZ`TV4-n{tyrq-};f|-pn{4-tr-v-y||r;;;I[\QIR[Q0=?B=0=?B>0=?B?0=?B@0=?BA0=?BBI]_VIZ`TN-o|xr{-|o|;I[\QV4-rrry-qnzntrq;I[\QIR[Q0=?BC0=?BD0=?BE0=@==IXRfIZ`TISNP==>Fdrvq-}ynpr9-ruLI[\QV-|{qr-vs-uv-n|zr-|-|s-onr;I[\QIR[Q0=@=>IXRfISYW=E?@G=@=?IZ`TISNP==?Bauv-ur4-|{yznqr-v-unysn-|}r{;I[\QIPY_Y||x-yvxr-v4-pntu|{-|zruv{t;;;I[\QIR[Q0=@=?IXRfIZ`TISNP==>FW-ur-nsrur;I[\QNyy-uv-rpv-znxrzr-|{qr-w-un4-q|{urr;I[\QQ|{4-|-uv{xLI[\QIR[Q0=@=AI]_VIZ`TV;;;I[\QIR[Q0=@=BI]_VIZ`TX{|pxrq-|LI[\QIR[Q0=@=CI]_VIZ`Taurr-v-{|-r}y;;;I[\QIVaW==@=G=@=DIR[Q0=@=DI]_VIZ`T`ur-v{4-z|v{t9-o-v-y||xyvxr-ur4-vyy-nyvr;I[\QIPY_ITVa>=@=dvyy-|-r-ur-Ja|-_|}rJLIf[W====IPY\ITVa====IP[]=@=CG=?BFG====ISY8=E@BISY8=E@CISY:=E?FIZ`Tavrq-ur-|}r-|-ur-o|q;I[\QIR[Q0=@A=IXRfIQ[]=@A=IdNV==>=I`\b==??IdNV==>=IZ`Tf|-urn-|zruv{t-tvr;I[\QIPY\IdNV==B=IN[]=?B@G==>=G===>IdNV==AEIQ[]=?B@IN[]=@=>G===@G===?IdNV=>?EIN[]=@=>G===>G===?ISY:=E??ISY8=E?@ISY8=E?CIR[Q0=@B=ISYW=E?BG=@B>IR[Q0=@B>IQ[]=@B=IQ[]=@=>IQ[]=@=?ISY:=E??ISY:=E?CISY8=E?DIP[]=AB=G=>>DG===?IR[Q0=@C=ISYW=E@=G=@C>IR[Q0=@C>IXRfIZfQ===?IQ[]=@C=IN[]=?BEG==>=G===@IdNV=>==IN[]=?BEG==?=G====IPZb==?@IR[Q0=A==0=A=>0=A=?0=A>=0=AB=IXRfI`XW===CG=AB>I`X8===CIRcR=AB?0=AB> I`NaIRcR=AB?0=AB?IXRfISYW=E@DG=@=AISYW=E?EG=@=BIZfO===?IdNV==@=IZfQ===?IZ`TISNP==>FY||x;I[\QIPY_auv-v-n-|yqvr-s|zur-snpr;I[\QV4-nyy-on{trq-};I[\QIPY\ISNP====IS\[=?BAG==>CIN[]=AB=G===>G====IdNV==A=IZ`TISNP==?Baurr4-n-|{-z|r-yvxrv9-||;I[\Qdun-|{-rnu-p|yq4r;;;I[\QIPY_[|-n-Zvzvtn;[|9-|-q|-uv-zpuqnzntr;;;I[\QIPY\IPZb====IN[]=?BBG==?=G====IdNV==?=IS\Z==>CIN[]=AB=G===>G===?IZ`TISNP==?B...IdNV==B=IPY\ISNP====IdNV==@=IN[]=AB=G===>G===?IZ`TISNP==>FV4-vyy-nyvr..I[\QIPY_ISNP==?A7Oooo7I[\QIPY_aRNZ-F-N[[VUVYNaRQI[\QSNVYRQ-a\-QR`a_\f-aN_TRaI[\QIPY_Pb__R[a-S\_PR`V[`bSSVPVR[aI[\QIPY__Ra_RNaI[\Q_Ra_RNa..I[\QIPY\IS\[=?BEG==>CISY8=E?EISY:=E?AIZ[]=?BDG===DG==>EG====IPZ]==A=G==>BG==@=IPZ]==A=G==>CG==@=IP[]=?BEG=>EAG====IN[]=?BEG==>=G===@IdNV=>?EIN[]=?BEG==?=G====IS\Z==>CIdNV==?=IN[]=?BBG==>=G====IN[]=AB=G==@=G===?IdNV==A=IQ[]=B==IO\N=?==IPZb==??IO`Y====IP[]=AB=G=>E=G===?IN[]=AB=G==A=G===?IN[]=A>=G==?=G====IR[Q0=B==IQ[]=B==IO\N=?==IPZb==??IO`Y====IR[Q0>===IXRfIO\N=B==IZfQ=A=>ISY:=E?EIN[]=A>=G==>=G====IP[]=AB=G=>>DG===AIdNV==>==IZ`TISNP==>Fdr-qvq-vL.IdNV=>==I[\QIPY\ISNP====IS\[=A=>G==>CIP[]=A==G==CDG===?IdNV==B=IZ`TISNP==?CUz}u.I[\QIPY_]yyrq-v-|ss9-V-rr.I[\QIPY_ISNP==>Ff|.I[\QIPY_f|4r-un-vpu-u||rq-zr-q|{-urr.I[\QIPY_au|r-puvyqr{-unq-orror-nsr.I[\QIPY_ISNP==>CUn.-Or-vyr{.I[\QIPY_f|4r-{|-z|ur.I[\QQ|-|-rr{-x{|-unuv-vL.I[\QIPY_ISNP==>FdunLI[\QIPY_ISNP==>CUz}u;-auv-v-un-Vunr-no|-|o|;I[\QIPY_auv-v-ur-urn-|s-urvyn{q.I[\QIPY_Vs-|-|}-v9-ur-vyn{qvyy-snyy-|-ur-rnu.I[\QIPY_V-un-|-tn{q-}yn{LI[\QIPY_a|-nxr-ur-vyn{q-q|{vu-|-v{-n-oynr-|sty|L.I[\QIPY_S||y..I[\QIPY\ISNP====IP[]=A=?G=>@FG====IN[]=A=?G==A=G====IdNV=>==IZ`TISNP==?>Ur.I[\QIPY_dun-nr-|-q|v{tLOv{t-ur-p|r-|-uryno|n|-n-|{pr.I[\QIPY_aurr4-vyy-vzr.I[\QIPY\ISNP====IN[]=A==G==>@G===?IdNV==B=IP[]=A==G==E?G===?IdNV==?=IN[]=A==G==?BG===?ISZbIZ`TU||||||\\\\\\\\U..IdNV==B=I[\QIPY\IO\N=C==IdNV==@=IN[]=A==G==?=G===?IN[]=A=?G==@=G====IN[]=A>=G==@=G====IN[]=AB=G==?=G===?IQ[N=>E>IQ[N=>E?IPZ]==A=G==>BG==ADIPZ]==A=G==>CG==ADIdNV=>==IPZb====IS\Z==>CISY8A===ISY8=E@?ISY8=@A>ISY8=DE@ISY8=E@DIR[Q0>>==IXRfISY:A===ISN\===AIdNV==B=IZ`Tf|-r{r-qvz9-n{q-ur-|yqt|-qnx;;;I[\QIPY\IQ[]=AB=ISY8=E@=ISY:=E?BISY8=E?FISY:=E?DISY8=E==ISY8=E=>ISY8=@D?ISY8=A>>ISY8=@A=ISY8=>BFISY8=E@EISY:>CA?ISY8>CA@ISY:=E@FIQ[]=?A=IVaW==@=G>>=>IRcR>>>=0>>=>IdNV=>B=IXRfIZ`?Qvq-|-x{|-un-ur-vpu:|zn{Wr{xn-|{pr-unq-n-o|urLI[\QUv-{nzr-n-Onyy|;I[\QYvxr-uv-vr9-ur-vryqrq}|r-sn-or|{q-u|r-|sz|ny;;;I[\QIPY\IRcR>>>=0>>>=IP[]=@=CG=>>DG===?IN[]=@=CG==@?G===?IN[]=?BEG==>=G===>IdNV==FCIN[]=?BEG===>G====IdNV==B=IZ\c==BBG==>EIQ[N=>E@IVa8==?>IR^8==>CIZ`T;;;;;;LI[\QIPY_;;;f|-pn{-ornur;I[\QISNV===AIdNV==B=IR[Q0>?==IXRfIN[]>?==G==?=G===?ISYW=E?FG>?=>IRcR>?=?0>?=>IP[]=@=CG=>>DG====IN[]=@=CG==@?G===?IRcR>?=?0>?=?IS\[>?==G==>CISNV===>IdNV=>==ISN\===>Ia_N==BCG>?==G==CFG==DC \ No newline at end of file diff --git a/game_english/data/Stage/Ballo1.pxe b/game_english/data/Stage/Ballo1.pxe new file mode 100644 index 0000000..4cf30f9 Binary files /dev/null and b/game_english/data/Stage/Ballo1.pxe differ diff --git a/game_english/data/Stage/Ballo1.pxm b/game_english/data/Stage/Ballo1.pxm new file mode 100644 index 0000000..50cf723 Binary files /dev/null and b/game_english/data/Stage/Ballo1.pxm differ diff --git a/game_english/data/Stage/Ballo1.tsc b/game_english/data/Stage/Ballo1.tsc new file mode 100644 index 0000000..72aac38 --- /dev/null +++ b/game_english/data/Stage/Ballo1.tsc @@ -0,0 +1 @@ +96O\\e\96hyzmhoy\\\\hrmu\\\\hqzp96O\\e]96hyzmhoy\\\\hrmu\\\]hqzp96O\\e^96hyzmhoy\\\\hrmu\\\^hqzp96O\\e_96hyzmhoy\\\\hrmu\\\_hqzp96O\\e`96hyzmhoy\\\\hrmu\\\`hqzp9696O\\ea96hyzmhyp\\\^h|~u96hoy\\_ehrmu\\\^hwq96hmz|\]\\f\\\\f\\\\hmhqzp9696hoy|\\\]f\\\cf\\]dh{\\]^9696O\`\\96O\`\]96O\`\^9696969696O\a\\96hpz|\a\\hyp\\\^96hwqhysZhz{phox~96hrmo\\^euLLnZhz{phox~mLLLX96LLL96LXhz{phox~uLLLL96LZZZhz{phox~LLLL96LLSL96LLLZhz{phox~mLuLLXL96LLLLXhz{phox~LLLLL96XLLXL96LZZZhz{phox~LLL96LLLZhz{phox~uLLLL96,LLuLL96LLZZZhz{phox~xZZZhz{phox~vLLLX96LLLLL96LLLZhz{phox~xXLLLuLZZZhz{phox~LLLL96LLL96SLZZZhz{phox~zXLLMhz{p96{LuYYhz{pLL{MMhz{phox{96hoy\\\`96hmz|\`\^f\]\\f\e\\hr{z\`\^f\\]b96hnx\e\\hmz|\e\\f\\]\f\\\\hqzp9696969696O\e\\96hmz|\e\\f]\\\f\\\a96hr{z\e\\f\\]b96hoz|\`\\f\__ef\\\^96hoz|\`\]f\__ef\\\\96hoy\\\\hmu\_\\96hr{y\\]bhmu\\a\96hn{m\]\\hmu\^\\96hmz|\`\^f\]\\f\\\\96hr{z\`\^f\\]b96hn{m\^\\96hoy\\\chnx\\\\96hqzp969696O]\\\96hrxv]b\\f]\\]96hrxW]b\\96hoy\\\\hn{m\^^\hmu\^\\96hoy\\_^hn{m\_\\hmu\\a\96hn{m\_]]hnx\\\\hqzp9696O]\\]96hwqhr{n\\\\f\\]b96hn{m]\\\hmu\^\\96hoh~m\\e]f\]]\f\\\\f\\\\9696 \ No newline at end of file diff --git a/game_english/data/Stage/Ballo2.pxe b/game_english/data/Stage/Ballo2.pxe new file mode 100644 index 0000000..6938d23 Binary files /dev/null and b/game_english/data/Stage/Ballo2.pxe differ diff --git a/game_english/data/Stage/Ballo2.pxm b/game_english/data/Stage/Ballo2.pxm new file mode 100644 index 0000000..178e955 Binary files /dev/null and b/game_english/data/Stage/Ballo2.pxm differ diff --git a/game_english/data/Stage/Ballo2.tsc b/game_english/data/Stage/Ballo2.tsc new file mode 100644 index 0000000..8e0a888 --- /dev/null +++ b/game_english/data/Stage/Ballo2.tsc @@ -0,0 +1 @@ +PMfss|sPMssssssssPMfss|tPMssssssstPMfss|uPMsssssssuPMfss|vPMsssssssvPMfss|wPMssssssswPMPMfswssPMfswstPMfswsuPMfswtsPMfswttPMfswtuPMPMPMPMfsxssPMsstysssussssssxsssstPMstxsPMssuxcqqqsst|cjcPMdcccPMcccPMccssuxqqqqqoccoccPMccccPMcqssssPMuccccqqqssxsPMssuxssssPMstssucccccqqqccqqqqqPMswts}ssts}ssssswtt}ssts}sssussxscccccccccqqqPMstssdssxsssssPMssvwstssPMswss}ssss}ssssssusPMswst}ssss}sssuss{sPMssuxcddCssssPMstssPMswss}ssss}sssussusPMswst}sszs}sssussvuPMswst}ssss}ssssssusPMucccccqqqssxsPMccccccqqqssxsPMcccccccqqqqqssxsPMssuxjcccdssxsPMssssvdPMswsu}sss|}ssssstxsPMsssxccdPMcccqPMsst|ccccdsssxccddssssPMPMswst}ssus}sssssstsPMswss}ss{s}sssusssuPMsssxjcdssssPMswsu}sstyPMswsu}sstu}sssusssuPMswsu}stss}sssustssPMPMddstssssxsssstPMssxsssssPMssuxccccPMssuvjccqqqPMsszt}stus}ssss}ssssPMPMPMPM \ No newline at end of file diff --git a/game_english/data/Stage/Barr.pxa b/game_english/data/Stage/Barr.pxa new file mode 100644 index 0000000..a05c866 Binary files /dev/null and b/game_english/data/Stage/Barr.pxa differ diff --git a/game_english/data/Stage/Barr.pxe b/game_english/data/Stage/Barr.pxe new file mode 100644 index 0000000..196bb42 Binary files /dev/null and b/game_english/data/Stage/Barr.pxe differ diff --git a/game_english/data/Stage/Barr.pxm b/game_english/data/Stage/Barr.pxm new file mode 100644 index 0000000..db181fb Binary files /dev/null and b/game_english/data/Stage/Barr.pxm differ diff --git a/game_english/data/Stage/Barr.tsc b/game_english/data/Stage/Barr.tsc new file mode 100644 index 0000000..e47a9a3 --- /dev/null +++ b/game_english/data/Stage/Barr.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}```hlvqy````lu~t=:S``ia=:l}~qls}```hlvqy```alu~t=:S``ib=:l}~qls}```hlvqy```blu~t=:S``ic=:l}~qls}```hlvqy```clu~t=:S``id=:l}~qls}```hlvqy```dlu~t=:=:=:=:=:S`a``=:lv|z`cfaj`a`c=:lv|z`cfbj`a`a=:lv|z`cf`j`a`b=:l{ul``aalq~`a``j````j```b=:lvq```dlq``aaj``idj``dbj``eb=:S`a`a=:lyl}wyPWPQl~tlu~t=:S`a`b=:l{ulvq```dlq``aaj``idj``dbj``eb=:S`a`c=:lyl}wPWPQl~tlu~t=:=:S`ae`=:S`aea=:S`aeb=:S`aec=:S`aed=:=:S`bi`=:lv|z`cg`j`bialu~t=:S`bia=:lv|z`cf`j````lyl}wlvqs```h\PQQl~tlt~`bi`ls~a```j``fcj```blu~t=:=:S`d``=:l{ulv|]`cfalv|]`cfb=:l}sls~`d``j``abj````lq~`d``j``b`j```dlqy`ad`=:lyl}wlvqs```ezPPQl~tlvqs````l{uls|=:lqy`a``ls}``ae=:l}w=:vPPrQlqy`ad`l~t=:l``dels~`ae`j```aj````lqy```d=:l``dels~`aeaj```aj````lqy```d=:l``dels~`aebj```aj````lqy```d=:l``dels~`aecj```aj````lqy```d=:l``dels~`aedj```aj````=:ls}```hlu~t=:=:S`e``=:=:Sa```=:l{ulv|[`cf`lv|[`cfalv|[`dd`lv|]`cbfl}wuQl~tls|P\PPQQl~tls|^^^^^l~txol~tl}r```blqy``c`l}t```bls~a```j``f`j```dls|lvqs```fW^^^WP=:PPtol~tls|QPyWP^l~t=:PPP^=:PtWPP=:P^l~t=:PPPP=:PPP\l~t=:PP=:^^^l~tls||PP^=:xPPP^l~tls|Ql~t=:PQlwya``dl~tls|PPPPol~t=:PPPPQl~tls|^^^^^l~tls|^^^PyPWP=:P^l~t=:lwy````{PPPP=:PPPPP=:PPyPP^^^l~t=:PPP^l~tls|=:lvqs```0ls}````=:lq``c`l``bf=:lq~a```j```hj````=:lq~`a``j```aj````=:lqy``a`=:l}t````=:ls~a```j``f`j````=:lqy`a``=:lq``c`l``bf=:lq~a```j```hj````=:lq~`a``j```aj````=:lqy``g`=:lq``c`l``bf=:lq~a```j```hj````=:ls~`d``j``aij```b=:ls~`a``j``ahj```b=:ls}```dj```hj``h`=:ls}```ej```hj``ha=:ls}```fj```hj``hb=:ls}```dj```ij``if=:ls}```ej```ij``ig=:ls}```fj```ij``ih=:=:=:l}wxQlqy``e`ls~`d``j``abj```blq~`d``j``c`j```bls|l{uls}``aalvqs``adPPQl~tls|lvqs```ePWP\PPQl~t=:yWPPPPP=:Ql~tlvqs````ls|yPP^l~t=:ls~`e``j``fgj```blqy`a``lq~`e``j``acj```blqy``e`lq~a```j```hj````l}wlvqs``aeP\PPyP=:PPPP^l~tls|lvqs```e}Ql~tls|yPPPQl~tls|lvqs```h]]PWP=:Pt\PWPQl~tls|lvqs``ae^^^^^l~tls|lvqs``afPWP\Po=:PtPP=:P^l~t=:sP\P^l~tls|lvqs```f^^^ol~tls|=:yWPP^l~tlvqs````ls|=:lq~`e``j``aej```blqy`aa`=:lyl}wlvqs```huQl~tlvqs``aels|r^l~t=:yPPPPP^l~tls|=:lq~`e``j``b`j```blvqs````ls|=:l{ulqy``e`l}wlvqs```h~\P\PWPP=:]]Ql~tlvqs````ls|=:lqy``e`=:lvqs```el}w~Pqwqy~Ql~t=:yPPPPPQl~t=:qPPyPP=:vyQl~tls|^^^^^l~tls|PWPPol~t=:PPPP=:Pol~za``alq~`d``j``c`j```bls|=:lvqs``adyPPQl~tls|=:lv|[`cfals}```dls~`d``j``fhj```blr|`d``lu~t=:=:Sa``a=:l{ulv|]`cfblv|]`cfals}```hl}wlvqs```ex^l~t=:qP\PPP^l~tls|lq~`d``j``a`j```blu~t=:=: \ No newline at end of file diff --git a/game_english/data/Stage/Blcny1.pxe b/game_english/data/Stage/Blcny1.pxe new file mode 100644 index 0000000..b3bcec5 Binary files /dev/null and b/game_english/data/Stage/Blcny1.pxe differ diff --git a/game_english/data/Stage/Blcny1.pxm b/game_english/data/Stage/Blcny1.pxm new file mode 100644 index 0000000..93bb4dc Binary files /dev/null and b/game_english/data/Stage/Blcny1.pxm differ diff --git a/game_english/data/Stage/Blcny1.tsc b/game_english/data/Stage/Blcny1.tsc new file mode 100644 index 0000000..3f41969 --- /dev/null +++ b/game_english/data/Stage/Blcny1.tsc @@ -0,0 +1 @@ +FSS\S0-_nh|_ioPTT\S_ioPTT\T_ioNTT\U_pqd_fpxSSVS_idlSSSS_hqg0-FSS\T0-_nh|_ioNTT\S_ioPTT\T_ioPTT\U_pqd_fpxSSVS_idlSSST_hqg0-FSS\U0-_nh|_pqd_fpxSSVS_idlSSSU_hqg0-FSS\V0-_nh|_pqd_fpxSSVS_idlSSSV_hqg0-FSS\W0-_nh|_ioPTT\S_ioNTT\T_ioPTT\U_pqd_fpxSSVS_idlSSSW_hqg0-0-FSS\X0-_nh|_idlSSSW_hqg0-0-0-FSTSS0-_nh|_vrxSSTT_dqsSTSS]SSSS]SSSU_idrSSSV0-_lwmSSUV]STST_wudSSYV]SS\V]SSS\]SSSW0-0-FSTST0-_nh|_wudSSYZ]SS\V]SSS\]SSSW0-0-0-0-FSTTS0-_sul_idrSSSU_wudSSYW]SS\U]SSST]SSTT0-0-FSTUS0-_nh|_dqsSTUS]SSSS]SSSU_vrxSSTT_idrSSSW_wudSSYY]SS\W]SSTS]SSS[0-0-#STVS0-_sul_pvjwCCCC0-vCCCCCCQQQ_qrg_hqg0-0-FST\\0-_sul_pvjqCQ_qrg_hqg0-_idrSSSWhQ_qrg_for_fpxSSVV_fuh_zdl\\\\_hqg0-0-FSUSS0-_nh|_p|gSSSS_gqsSUSS_zdv_pvjdCCCJ0-CCD_qrg_hqg0-0-FSUST0-_sul_pvj_wxu0-CCCCCCCCCCCCwkdwJvCdooOCironvD_qrg_hqg0-0-FSUTS0-_sul_iomTT\T]SUTT_iomTT\U]SUTU0-_sul_idrSSSW_p|gSSSU_zdlSSXS_wudSSYU]SS\X]SSSZ]SSZW0-FSUTT0-_sul_idrSSSW_p|gSSSU_zdlSSXS_wudSSYU]SS\X]SSZ\]SSZV0-FSUTU0-_sul_idrSSSW_p|gSSSS_zdlSSXS_wudSSYU]SS\X]STTZ]SSYU0-0- \ No newline at end of file diff --git a/game_english/data/Stage/Blcny2.pxe b/game_english/data/Stage/Blcny2.pxe new file mode 100644 index 0000000..394d1c6 Binary files /dev/null and b/game_english/data/Stage/Blcny2.pxe differ diff --git a/game_english/data/Stage/Blcny2.pxm b/game_english/data/Stage/Blcny2.pxm new file mode 100644 index 0000000..f229389 Binary files /dev/null and b/game_english/data/Stage/Blcny2.pxm differ diff --git a/game_english/data/Stage/Blcny2.tsc b/game_english/data/Stage/Blcny2.tsc new file mode 100644 index 0000000..0c9ee66 --- /dev/null +++ b/game_english/data/Stage/Blcny2.tsc @@ -0,0 +1 @@ +_llulIFxximmulximmumxgmmunxllmtx}llllxIF_llumIFxxgmmulximmumximmunxllmtx}lllmxIF_llunIFxxllmtx}lllnxIF_lluoIFxxllmtx}llloxIF_llupIFxximmulxgmmumximmunxllmtx}lllpxIF_lluqIFxx}lntlvllmlvllllxlntlvllmrIFx}llqlx}lllpxIFIF_lmllIFxxllmmx}lmllvllllvlllnx}llloIFxllnovlmlmx}llrovlluovllluvlllpIFIF_lmlmIFxx}llrsvlluovllluvlllpIFIFIFIF_lmmlIFxx}lllnx}llrpvllunvlllmvllmmIFIFIFIF_lmnlIFxxmouovlmnmx\c\]xxIF_lmnmIFxx}lllpxllmrx}llsuvllupvllmlvllltIFIFIF_lmuuIFxxlloox\\\]IF\\\\IF\jjjxxxIFIF_lnllIFxxllllxlnllx}\\\cIF\\]xxIFIF_lnlmIFxxxIF}c\}h\]xxIFIF_lnmlIFxxmmumvlnmmxmmunvlnmnIFxx}lllpxlllnx}llqlx}llslvlluqvlllsvllspIF_lnmmIFxx}lllpxlllnx}llqlx}llslvlluqvllsuvllsoIF_lnmnIFxx}lllpxllllx}llqlx}llslvlluqvlmmsvllrnIFIF_lntlIFIF_lnulIF_lnumIF_lnunIF_lnuoIF_lnupIF_lnuuIFIFIFIFIF_lollIFxxxlollvllmrIFx}lltlx}lnuuvllnlvlllnIFxx}llnlIFxc\]xxx}lllmx}llqlIFxlnumvlnmsvllllx}lnumvllplvllllx}llqlIFx}lnulvllllvllllx}llnlIFxx}llntc\\\]IFc\\\\IF\jxxjjj\\\IFc\\\IF\\\jjjxx<}llllIFx}lnumvllqlvllllx}llmrIFxx}llnn\\\cIF\jjjxxIFx}llllx}llmrIFx}llmlIFx}lnulvlllovllllIFx}lnumvllmlvllllIFxlnunvlnsuvllllIFxlnuovlnsuvllllIFxlnupvlnsuvlllnx}lmllIFx}lnumvllpnvllllIFx}lnulvllllvllllIFxx}llnt}\jjj{xxx}llnn\jjj{IF\c\]xxIFx}llloxllmrxxlllnx}llrtvlrllvllnpvllmoIFxIFIF_lolqIF_lolrIF_lolsIF_lomlIFxxllllxllmtximmulximmumxgmmunx}llllIFx}lolqvllmmvlllnIFx}lntlvllmlvllllIFxlolqvllmrxox}lllo\]xIF\\\\hIF\c\\IF]]xxlntlvllmrxIFx}lolqvllolvllllx}llrlIFxlolqximoumxIF_lonlinIFIF_loolIFxxloolxllllx}lonlvllllvlllnIFx}x}llqlIFxlonlvllmrxx}lllmc\\\IFj\c\\\IF\jxIFc\\\\IF\\\\IF\]xx\{xIF\\\\\]xxxIFx}lonlvllllvllllx}llqlIFx}lonlvllolvllllx}llmnIFx}lonlvllplvllllx}llqlIFximounxllmrxIFIF_lpllIFxxxlpllx}llolxx}llllIFxlqllvlnqpvllllx}lllmIFx}lqllvllnlvlllnx}lllmIFx}lqllvllolvlllnx}lllmIFxlqllvllmrxllnlvllolIFxlolsxlntlIFx}lmllx}lllpIFxx}llnnIF\c\jjjxxx}llntc\\jIFc\\\\]xxx}lllpIFxlloqx}llpuvmnllvllutvlllrIFIF_lqllIFIF \ No newline at end of file diff --git a/game_english/data/Stage/Cave.pxa b/game_english/data/Stage/Cave.pxa new file mode 100644 index 0000000..c30cbaa Binary files /dev/null and b/game_english/data/Stage/Cave.pxa differ diff --git a/game_english/data/Stage/Cave.pxe b/game_english/data/Stage/Cave.pxe new file mode 100644 index 0000000..d117d5d Binary files /dev/null and b/game_english/data/Stage/Cave.pxe differ diff --git a/game_english/data/Stage/Cave.pxm b/game_english/data/Stage/Cave.pxm new file mode 100644 index 0000000..fcbf014 Binary files /dev/null and b/game_english/data/Stage/Cave.pxm differ diff --git a/game_english/data/Stage/Cave.tsc b/game_english/data/Stage/Cave.tsc new file mode 100644 index 0000000..e2fc191 --- /dev/null +++ b/game_english/data/Stage/Cave.tsc @@ -0,0 +1 @@ +?FWXKFMW_::FOXN-::C?-::CCFUOcFWXKFMW_::FMXZ:=:;D:;;F^\K:::;D::CCD:::?D:::B-:;:;FZ\SFPKY:::>F^\K::?;D::C>D:::>D:::>-:;:<FZ\SFPKY:::>F^\K::?;D::C>D::;BD:::B-:;:=FZ\SFPKY:::>F^\K:::?D::C>D::;:D:::B-:;:?FZ\SFPKY:::>F^\K::?:D::C>D::;F^\K::?:D::C>D::;;D::;<-:;:BFZ\SFPVT:;:=D:;:CFW]QS~*yx1~*yzox+FXYNFOXN-:;:CFUOcF]Y_::;;FKXZ:;:BD::::D:::F^\K::?D:::>D::;:-:;;:FUOcFPKY:::>F^\K::?>D::C>D::;:D:::C-:;;;-:<::FZ\SFW]Q^ro*mk|mk}}*yp*k*]u*N|kqyx888FXYNFOXN-:<:;FKXZ:<:;D::::D::: \ No newline at end of file diff --git a/game_english/data/Stage/Fall.pxa b/game_english/data/Stage/Fall.pxa new file mode 100644 index 0000000..2267b9f Binary files /dev/null and b/game_english/data/Stage/Fall.pxa differ diff --git a/game_english/data/Stage/Fall.pxe b/game_english/data/Stage/Fall.pxe new file mode 100644 index 0000000..f4e11db Binary files /dev/null and b/game_english/data/Stage/Fall.pxe differ diff --git a/game_english/data/Stage/Fall.pxm b/game_english/data/Stage/Fall.pxm new file mode 100644 index 0000000..6376edc Binary files /dev/null and b/game_english/data/Stage/Fall.pxm differ diff --git a/game_english/data/Stage/Fall.tsc b/game_english/data/Stage/Fall.tsc new file mode 100644 index 0000000..c653bb8 --- /dev/null +++ b/game_english/data/Stage/Fall.tsc @@ -0,0 +1 @@ +rorororororororororororororororororororororororoمޅƆܓׅمڌroޅхم˓̅Յʅʓё܅ʅɅroԅʅʅ҅ޅro؅˅ʅדroʅ؅ӅɆroٌܑ؅ԅʓrororororororororo܆ٓ؅ʓم؅roх؅ʅroʓro؅ʅʅroڅׅʓro͑ӌمЅʓro؅م̅roޅɅʅԅԓޤڅӑroمͤroٌ؅ٓمʅroׅؓroБمroɅׅؓڅمؑ٤ӅڅɅّroمɅׅʓro܅ׅ˅؅roԅe؅roʆمڅ؅roمؑroم؅م؅roʅӌ؅نёڅՅroڅܓroׅёތ؅roʅԅɅ҅ʅroӅӅʅمʓ͓roڅӌمޓԅޓroroԆroԤԅمʅڅroԅԅܤroӅʅڅroڅʓґڌʅׅٓӅ؅בroɅ܅ممroʅمޅءroʅʅro݅Ʌޅroхܓro͑څܓroҤɅمʅхro˅Ʌڅʤroʆroٌ؅ʅʅro˅؅׆roޤхمڅЅroٓroمɅ؅ƅroʑޤroڅمنхمӑro͡ơӡ̡ԡӡ١Ρ̡͡١rorororoӌمڅro̤rorororororororo \ No newline at end of file diff --git a/game_english/data/Stage/Frog.pxe b/game_english/data/Stage/Frog.pxe new file mode 100644 index 0000000..11d3986 Binary files /dev/null and b/game_english/data/Stage/Frog.pxe differ diff --git a/game_english/data/Stage/Frog.pxm b/game_english/data/Stage/Frog.pxm new file mode 100644 index 0000000..2dfeab4 Binary files /dev/null and b/game_english/data/Stage/Frog.pxm differ diff --git a/game_english/data/Stage/Frog.tsc b/game_english/data/Stage/Frog.tsc new file mode 100644 index 0000000..da13082 --- /dev/null +++ b/game_english/data/Stage/Frog.tsc @@ -0,0 +1 @@ +yvyvyvyvyvyvyvyvyvyvyvyvyvyvyvyvyvyvړڍyvyvyvŨyvЌььyvьٌѩíyvíŰíyvԫyvíyvьښyvیތѫИڌьyvњړЌјyvړ͌lyvٌьѫړьyvьyvíŰíyvyv卨Ԍѓyv͌ލތڌ͌͘yvڍړ嚨yvííyvߌьŻ嚨yvíь׌ڌyvѓߌڌߚyvíyvyv׍yvyvyvyvyvyvyvŨíyvyvҌӍíyvyvyv \ No newline at end of file diff --git a/game_english/data/Stage/Gard.pxa b/game_english/data/Stage/Gard.pxa new file mode 100644 index 0000000..907d106 Binary files /dev/null and b/game_english/data/Stage/Gard.pxa differ diff --git a/game_english/data/Stage/Gard.pxe b/game_english/data/Stage/Gard.pxe new file mode 100644 index 0000000..a28bb97 Binary files /dev/null and b/game_english/data/Stage/Gard.pxe differ diff --git a/game_english/data/Stage/Gard.pxm b/game_english/data/Stage/Gard.pxm new file mode 100644 index 0000000..7a4c0de Binary files /dev/null and b/game_english/data/Stage/Gard.pxm differ diff --git a/game_english/data/Stage/Gard.tsc b/game_english/data/Stage/Gard.tsc new file mode 100644 index 0000000..95bb3c6 --- /dev/null +++ b/game_english/data/Stage/Gard.tsc @@ -0,0 +1 @@ +YVo|||YV||||||||YVo||}YV|||||||}YVo||~YV|||||||~YVo||YV|||||||YVo||YV|||||||YVYVo|}||YV|~|}|~|~}|}|}YVw|~YV||||||||||||}YVo|}|}YVlsl±mYVo|}|~YV|||||}||||~~||YVYVYVo|||YV|||||}w|||||~YVo||}YV||~YVo||~YV|||~YVw|w|y||}y|~YVw|~|w|~}||}||||}|||YV|||||}lzYVl±lllYVllŻlzYV||~}lzllzzzYVlñllYVzYV|||||~|||||||||||YVlllYVñ||||YV|||||~|||||||~YV||}z||~}xlzzzsllYVl±llYVzzz||}lzzzYVlllllYV||~}zzzxllllYVzYVzzzzzzzzYVxlllYVllllz||}xllz||||YV||~||||||||||YV|||}|||||}}|YVm|||||||||||||||zzzzzlzzz||||YV||||||||||||~|||m||||YV|||||||||||||||||~|}||YV||||}~|||~||||}||||~YV||||||||~YV||}yzYVllŻlYVŻsl||||}||}zYVllllñz||}||||||||~YVllz||||YV||||||||~||~YV||||||||~|||YV|||mlmYV|||lzllmYV||||||||lŻlllmmLYV||||}|||||}YV||||}|||~||||~||||~||||||YV||||}||||~||~YV||||||||~||~YV||||~||||||||YV||||||||~||~||YV|||mYVlŻlŋm||}}zzzzzzzzzzzzYVzzzlzzz|||YVmmmm||}||}mlslYVm||||YV|||||~}zzzzzxlűzYVlllzlllxllYVŻllzlllŻYVzxlôlĭlYVlŻllllõYVlûyyzzz|||sllŻmm||||YV||||}||||~|||YV||~||~|||||||}YV||}||}|||||YV|||}|||~||}YV|||||||||||||}YV|}|||||}|YV||~}xlllYVlllYVll||||||YVmsllYVllm||}||}||}||~|||||s±lllYVlzYVxlsllŻmxlxlxYVsllzYV±lxlŻlz||}||||||||}|||||YV|||}||||~||YV||}YVYVYVYVo||}YVo||~YVo||YVw|~|}}|}~YV||||}|||}|||||YV|||||||YVYVlƵlz|||YV|||}|||||}|||}YVo||YVo||YV|~~||}YV|~|||YVzzzzzzYVo||YVo||YVYVo|||YVw|~~|||zzzsllllzYVlŻzzz±lzzzYV|||||||||||||}||YVo||}YVy|~}||w|||||||YV|||||}|YVllz|}|YVYV \ No newline at end of file diff --git a/game_english/data/Stage/Hell.pxa b/game_english/data/Stage/Hell.pxa new file mode 100644 index 0000000..8ab7b2e Binary files /dev/null and b/game_english/data/Stage/Hell.pxa differ diff --git a/game_english/data/Stage/Hell1.pxe b/game_english/data/Stage/Hell1.pxe new file mode 100644 index 0000000..acdd610 Binary files /dev/null and b/game_english/data/Stage/Hell1.pxe differ diff --git a/game_english/data/Stage/Hell1.pxm b/game_english/data/Stage/Hell1.pxm new file mode 100644 index 0000000..3b31311 Binary files /dev/null and b/game_english/data/Stage/Hell1.pxm differ diff --git a/game_english/data/Stage/Hell1.tsc b/game_english/data/Stage/Hell1.tsc new file mode 100644 index 0000000..6989da1 --- /dev/null +++ b/game_english/data/Stage/Hell1.tsc @@ -0,0 +1 @@ +rororororororororororororororoׅɓrororoڅхƅЅɅroͅړroх؅Ʌԅхrorororororororororororororororoʅԅцrororororoمƅʅʢro݅eͅɅޅrorororororororororo͓roɅׅޅԅroͅʅʓrororororoɅڅ܅مʅ͒roƅʅɅƅפro؅ʅ؅ؓroʅ؅בʅro؅ׅɅʅroؓrorororoʅɅ؅х؅roՅɅʅʑroɅʅʅɅɅro҅ӅӓӅʅӅޅɅroӅ̓roro \ No newline at end of file diff --git a/game_english/data/Stage/Hell2.pxe b/game_english/data/Stage/Hell2.pxe new file mode 100644 index 0000000..a27137b Binary files /dev/null and b/game_english/data/Stage/Hell2.pxe differ diff --git a/game_english/data/Stage/Hell2.pxm b/game_english/data/Stage/Hell2.pxm new file mode 100644 index 0000000..4c25708 Binary files /dev/null and b/game_english/data/Stage/Hell2.pxm differ diff --git a/game_english/data/Stage/Hell2.tsc b/game_english/data/Stage/Hell2.tsc new file mode 100644 index 0000000..6b82149 --- /dev/null +++ b/game_english/data/Stage/Hell2.tsc @@ -0,0 +1 @@ +ururururururururururururururururururururururururur͏ۈ׈ψӖurururururur͈ۈψ̈urḧ̈ֈur֔ur͈ۈ܈urԈ̈Ԗurۈֈ͈urۈ̖ururururڈ͈͈ur͈͔ۏۈurۈֈ̖ur͈ψۈ̈ur͈ԈΈˈur̈ֈֈܖurֈɈ͈ܔ͈ur܈ۈ׈̈ۈur׈ֈۖurur \ No newline at end of file diff --git a/game_english/data/Stage/Hell3.pxe b/game_english/data/Stage/Hell3.pxe new file mode 100644 index 0000000..5cbdd52 Binary files /dev/null and b/game_english/data/Stage/Hell3.pxe differ diff --git a/game_english/data/Stage/Hell3.pxm b/game_english/data/Stage/Hell3.pxm new file mode 100644 index 0000000..a0cb2a3 Binary files /dev/null and b/game_english/data/Stage/Hell3.pxm differ diff --git a/game_english/data/Stage/Hell3.tsc b/game_english/data/Stage/Hell3.tsc new file mode 100644 index 0000000..965cef6 --- /dev/null +++ b/game_english/data/Stage/Hell3.tsc @@ -0,0 +1,2 @@ +-::C:FWXKFPKS::::FOXN-::C;FWXKFPKS:::;FOXN-::C<FWXKFPKS:::FWXKFPKS:::>FOXN-::C?FUOcFPVT;?=D:;;;F^\K::B>D::C?D::;:D:::<-:;;;F^\K::B?D::C?D::;:D:::<-:<::FMXZ:<::D:=<:D::::FPV7;?=D:::;FMWZ:::BD::;>D:::;FMWZ:::CD::;>D:::;FMWZ::;:D::;>D:::;FMWZ::;;D::;>D:::;FMWZ::;D:::;FMWZ::;=D::;>D:::;FOXN-:<>:-:<>;FNXZ:<>;FKXZ:<>:D::;:D:::=FOXN-:<><-:<>=FNXZ:<>=FKXZ:<>>-:<>?FNXZ:<>?FKXZ:<>>D::;:D:::=FOXN-:-:D::;:D:::;FOXN-:D::::-:>::FZ\SFPVT:<:::;FPV5:<:;FQS^:::?FKW5:::?D:;::FMW_::;:Qy~*~ro*GWs}}svo*Vkxmro|G+FaKS:;@:FXYNF\W_FMV\^ro*Ws}}svo*Vkxmro|*s}*k*zyo|pvokzyx6*l~*s~}*kwwy*s}*vsws~on8FXYNFMV\cy*mkx*|ozvoxs}r*y|*}~ymuzsvos~r*s~ow}*n|yzzon*l*oxowso}8FXYNFOXN-:>:;FZ\SFKW5:::?D::=:<FZ\SFKW5::;:D::<>FW]QFQS^::;;Wk*ws}}svo}*sxm|ok}on*l*FX_W::::+FXYNFOXN-:C::FNXZ:C::F]UT::<>D::::F]U5::<>FZ\SFW]=Toxuk6*}oosxq*ro|*l|y~ro|1}wknxo}}6*myxpsxon*rsw*~y*~rs}pvyk~sxq*s}vkxn8FXYN^rk~*k}*~ro*wy}~*}ro*myvn*ny8FXYNOox*k}*ro*k}6*}ro*myvn*xy~l|sxq*ro|}ovp*~y*usvv*ro|*yxl|y~ro|888FXYNFOXN-:C:;FNXZ:C:;F]UT::IZ[NIPZb===EISNV===>IR[Q0==F?IZ[NIPZb===EISNV===?IR[Q0==F@IZ[NIPZb===EISNV===@IR[Q0==FAIXRfISYW>===G==FBIZ[NIPZb===EISNV===AIRcR=?==0==FBIZ[NIPZb===EISNV===AIR[Q0=>==IXRfI`\b==>>IN[]=>==G====G===?ISN\===AIa_N==B@G==FAG==DBG===B0=>>=IXRfI`\b==>>IN[]=>>=G====G===?ISN\====Ia_N==BCG==F=G=>>EG==E@0=?==IXRfISY8>===ISY8>=?BISY8>=@EIZfQ===?IdNV==B=IN[]=A==G==>=G====IZ`Tbnu.I[\QIPY\IN[]=A==G==?=G====IdNV==B=IR[Q0=A==IXRfISYW>==@G=A=AISYW>>=?G=A=@ISYW>==?G=A=?ISYW>==>G=A=>ISY8>==>ISY8>=@EIN[]=A==G==>=G====IZ`TRnnuu.IZfO===?I[\QIPY_Q|{4-xvyy-zr.I[\QV4z-n-uzn{.-V-w-t|zntvpnyy-{rq-v{|n-Zvzvtn.-V4z-uzn{.I[\QIPY_UuLI[\QIPY_;;;;;I[\QIPY_IN[]=A==G====G====ISNP==?Edun4-uvLf|4r-{|-|{r-|s-u|rxvyyr-|o|LI[\Qdryy9-|-pnrq-ur}n{-|ss-zr9-wz}v{t|-yvxr-un.I[\QIPY_f|-|yq{4-or-unnv|9-|yq-|LI[\QIR[Q0=A=>IXRfISY8>==?IZ`TISNP==?EV4z-V|u9-|{r-|s-ur uzn{-u|-pnzr-|-uvvyn{q-|-q|-rrnpu;I[\Qaun-vpu-Zvr-{rqzr-v{|-uv;;;I[\QV-zn{ntrq-|-tr-nn9o;;;w-y||x-n-zr;I[\QIPY_N{q-{|-V4z-px-urr.I[\QIPY_f|-pyvzorq-}-s|z-ur|vqr9-qvq{4-|;I[\QV4z-n{-r{tv{rr-|sp|{vqrnoyr-nyr{9I[\Qo-V4z-qrnuy-nsnvq|s-urvtu;;;I[\QIPY_\u9-|r9-|r-v-zr;;;I[\QIPY_V-{rr-u|yq4r-p|zr|-uv-vyn{q-v{-ursv-}ynpr;I[\QIR[Q0=A=?IXRfIZ`TISNP==?E[|9-{|9-ry-|-unr{|-r-s|-pu-n-}nurvp9n{qrq-yvyr-zn{;I[\QIR[Q0=A=@IXRfIZ`TISY8>==@ISNP==?EV|uLI[\Q-fr9-un4-zr;I[\QIPY_dun4-unLI[\Q`nxnz||4-|xv{t-|{n-|pxrLI[\QIPY_`|-ur4-vyy-nyvr;;;I[\QN-svrpr-|{r9-ur-v;I[\Q[|uv{t-yvxr-zr9-un4s|-r;;;I[\QIPY_Nyy-vtu9-ur{;I[\Qanxr-uv;I[\QISNP====ITVa>=?DIVa8==?DIPY_IPZb==>=T|-ur-JP|{|yyrJ;IdNV=>C=I[\QI_ZbIPY_ISNP==?EV-uv{x-un4-unur4-nsr;I[\QITVa====IRcR=A=A0=A=AIXRfIZ`TISNP==?ETvr-Z;-`nxnz||-zrtnq;I[\QIR[Q \ No newline at end of file diff --git a/game_english/data/Stage/Jail.pxa b/game_english/data/Stage/Jail.pxa new file mode 100644 index 0000000..a92f3fe Binary files /dev/null and b/game_english/data/Stage/Jail.pxa differ diff --git a/game_english/data/Stage/Jail1.pxe b/game_english/data/Stage/Jail1.pxe new file mode 100644 index 0000000..bb4def6 Binary files /dev/null and b/game_english/data/Stage/Jail1.pxe differ diff --git a/game_english/data/Stage/Jail1.pxm b/game_english/data/Stage/Jail1.pxm new file mode 100644 index 0000000..4d543fc Binary files /dev/null and b/game_english/data/Stage/Jail1.pxm differ diff --git a/game_english/data/Stage/Jail1.tsc b/game_english/data/Stage/Jail1.tsc new file mode 100644 index 0000000..e61798b --- /dev/null +++ b/game_english/data/Stage/Jail1.tsc @@ -0,0 +1 @@ +[Xq~~~[X~~~~~~~[Xq~~[X~~~~~~[Xq~~[X~~~~~~[Xq~~[X~~~~~~[Xq~~[X~~~~~~[X[Xq~~~[X~~~~~~~~~~~~~[X[Xq~~[X~~~~~~~~~~~~~~~~~~~~~~~~[X[X[Xq~~~[X[X~~~[X~~~~[Xxnx|||o[X~~~~~~~~~~~~~~~~~~~~y~~{~y~[XznnŶunů|õnǽnnn|[Xnunnn³[Xnn·nónnǽ|nn¶n|[XnŶnn½nn¶n½[Xn¶żnn|[Xnnðnn[Xƾ||||||unŶnón|Nnnnn[Xunnn½n³|[Xnn½nnnnŷ¶n|nůnnnǽn¶[XŶn·|[XnnnºnŶnz[X¶nnn½nnů|~~[X[Xq~~[Xy~ndz|nn¶núnnz[Xnnnn¶n½[Xǽn|~~~~~~~~[X[Xq~~[Xnůnznnijn³~~~~~~~~[X[Xq~~[X~~~~~~~~~~[X[X[Xq~~[X~~~~~~~~~~~~~~~~[X~~~o[X~~~uo[X[XunnznnǽÍ|||||[X~~~y~~~~~~~~~~~~~~~[Xq~[X[X \ No newline at end of file diff --git a/game_english/data/Stage/Jail2.pxe b/game_english/data/Stage/Jail2.pxe new file mode 100644 index 0000000..a79a22c Binary files /dev/null and b/game_english/data/Stage/Jail2.pxe differ diff --git a/game_english/data/Stage/Jail2.pxm b/game_english/data/Stage/Jail2.pxm new file mode 100644 index 0000000..24af892 Binary files /dev/null and b/game_english/data/Stage/Jail2.pxm differ diff --git a/game_english/data/Stage/Jail2.tsc b/game_english/data/Stage/Jail2.tsc new file mode 100644 index 0000000..2183673 --- /dev/null +++ b/game_english/data/Stage/Jail2.tsc @@ -0,0 +1 @@ +TQjwwwTQwwwwwwwTQjwwxTQwwwwwwxTQjwwyTQwwwwwwyTQjwwzTQwwwwwwzTQjww{TQwwwwww{TQTQjwwTQwwwTQwywwwwwxwwwwwww{TQwzwxwxxywwwywxwwTQwywwwwwwwwwwTQwwwywzwxTQTQjwxwwTQwwwyww|}wwywwwww{TQTQjwywwTQggguTQgggggwwwwrw|y{TQwzwwwxxxwwwwww}wwywwwwwxwwwwTQwxwwwww{wwxwwwwx|wwxwTQTQTQjw{wwTQGsgggggggggTQjw{wxTQghTQjw{wyTQggggghTQTQjw{wzTQgggggTQgggghgnggggTQghTQjw{w{TQggggiiTQnggggTQgggguuuTQjw{w|TQggggggTQggsgggngTQguuuTQgggguTQTQ \ No newline at end of file diff --git a/game_english/data/Stage/Jenka1.pxe b/game_english/data/Stage/Jenka1.pxe new file mode 100644 index 0000000..6f94c55 Binary files /dev/null and b/game_english/data/Stage/Jenka1.pxe differ diff --git a/game_english/data/Stage/Jenka1.pxm b/game_english/data/Stage/Jenka1.pxm new file mode 100644 index 0000000..83dbd6b Binary files /dev/null and b/game_english/data/Stage/Jenka1.pxm differ diff --git a/game_english/data/Stage/Jenka1.tsc b/game_english/data/Stage/Jenka1.tsc new file mode 100644 index 0000000..121c82f --- /dev/null +++ b/game_english/data/Stage/Jenka1.tsc @@ -0,0 +1 @@ +-*CPPYP-*\mna\cmuPPQY\faiPPPP\end-*CPPYQ-*\mna\cmuPPQY\faiPPPQ\end-*CPPYR-*\mna\cmuPPQY\faiPPPR\end-*CPPYS-*\mna\cmuPPQY\faiPPPS\end-*CPPYT-*\mna\cmuPPQY\faiPPPT\end-*-*CPQPP-*\pri\souPPQQ\dnpPQPP\faoPPPT\traPPQPZPPYTZPPSUZPPRV-*-*-*CPRPP-*\key-*\itjPPQTZPRPQ-*\fljPUYTZPRQT-*\fljPUYSZPRQS-*\fljPUYRZPRQR-*\fljPUYQZPRQQ-*\fljPUYPZPRQP-*\key\msg\facPPQSw@@NNN_\nod-*iG@@@-*@N\nod\end-*-*CPRPQ-*\itMPPQT-*\fljPUYTZPRRT-*\fljPUYSZPRRS-*\fljPUYRZPRRR-*\fljPUYQZPRRQ-*\fljPUYPZPRRP-*\key\msg\facPPQSoL@A\nod\clr\gitQPQTm@@A\nod\clr-*\gitPPPP\facPPPPg@@@]p]N\nod\clr\cnpPSPPZPQSPZPPPP\dnpPTPQ\flMPRWT\facPPQSy@@@L-*i@@_\nod-*m@N\nod\clrwG@_\nod-*]r@]_\nod\facPPPP\clr\cmuPPPP\msghA\nod\clo-*\cnpPTPPZPPPYZPPPP\waiPPQP\mydPPPR\cnpPSPPZPQSRZPPPR\anpPSPPZPQPPZPPPR\waiPQRP\cmuPPQQ-*\cnpPTPPZPPQRZPPPP-*\msg\facPPPUhG@@L@j_\nod\clr\facPPQSaL@bN\nod\anpPSPPZPQRPZPPPR-*yG@@L@i@N\nod-*a@@@@@-*@@_\nod\clr\facPPQThMMA\nod-*h_@y@@m_\nod-*sG@L@@N\nod\clra@@@@N\nod-*t@L@@-*@@A\nod\clr\facPPQSs@@@@-*@NNN\nod\clr\facPPPUiG@@@@-*@@N\nod-*i@@@@@-*@@@N\nod\clrt@@@@-*@@A\nod\clr\facPPQSNNNNN\nod\clrmNNN\nod-*w@@@@-*@_\nod\clr-*\anpPTPPZPPSPZPPPP\facPPQThA\nod\clrp@@L@-*_A\nod\clr\facPPPUNNNNN\nod\clri@@@@N\nod-*s@G@@-*@N\nod\clo\cmuPPPP-*\waiPPUP\facPPPU\msgyG@@N\nod\clo-*\facPPPP\anpPTPPZPPQPZPPPP\waiPRPP\cmuPPQY-*\msg\facPPQS\cnpPSPPZPQSPZPPPPa@@NNN\nod-*t@MMN\nod\mydPRPP\clrNNNNN\nod\clrt@@@-*N\nod-*f@@-*@NNN\nod\clra@@@@@N\nod\clrc@@@-*@@@@-*@@@_\nod\flKPUYP\end-*-*CPRQP-*\key\msg\facPPQSs@@NNN\nod-*c@@@-*@@@@-*@@@_\nod\end-*-*CPRQQ-*\key\msg\facPPQSt@@N\nod-*g@N\nod\end-*-*CPRQR-*\key\msg\facPPQSi@@@-*@@@-*@N\nod\clrt@@@NNN\nod\end-*-*CPRQS-*\key\msg\facPPQSo@@@NNN\nod-*i@@@@-*@@@N\nod\end-*-*-*CPRRP-*\key\msg\facPPQSm@L@@N\nod\clr\gitQPQTt@@ @-*@@N\nod\clr-*\gitPPPP\cnpPSPQZPQSPZPPPP\dnpPTPQ\facPPPPg@@@]p]N\nod\clr\flMPRWT\facPPQShNNN\nod-*yG@@@-*@L@G@N\nod\clrNNNNN\nod\clri@G@@@-*@@@-*@@@@N\nod-*c@m@-*@@N\nod-*a@@@@-*@@@N\nod\clrcL@@m-*@@-*@@L\nod-*@@@-*@@@-*@@@N\nod\clrh@@@@-*L@@m@-*@@\nod-*@@NNN\nod\clrt@@N\nodg@N\nod\flKPUYQ\end-*-*CPRRQ-*\key\msg\facPPQSoN\nod\clr\gitQPQTyL@N\nod-*t@@@@-*@@N\nod\clr-*\gitPPPP\cnpPSPRZPQSPZPPPP\dnpPTPQ\facPPPPg@@@]p]N\nod\clr\flMPRWT\facPPQSt@@N-*wG@@@@NNN\nod\clrNNNNN\nod\clrh@@@@-*@m_\nod\clrt@@m@-*@@@-*@@@N\nod-*t@@L@@-*@@@N\nod\clr-*hNNN\nod\clrd@@@-*@@-*_\nod\clrNNNNN\nod\clri@@@@NNN\nod-*t@@mL-*@@@-*@@L\nod-*@@-*N\nod-*i@@@@-*L@@-*@@L\nod-*@@N\nod\clra@@@-*m@@-*@NNN\nod-*i@@@NNN\nod\clrd@@@_\nod-*d@@@-*@@-*@_\nod\clrNNNNN\nod\clrt@@@NNN\nod\flKPUYR\end-*-*CPRRR-*\key\msg\facPPQSt@@@-*@N\nod-*m@@G@-*@@-*@N\nod\clr\gitQPQTm@NNN\nod\clr-*\gitPPPP\facPPPPg@@@]p]N\nod\clr\cnpPSPSZPQSPZPPPP\dnpPTPQ\flMPRWT-*\facPPQSNNNNN\nod\clryG@@-*@L@G-*N\nod-*w@@@@-*@@NNN\nod\clri@G@@@-*L@G@@-*@N\nod-*t@@@-*@@@-*@@@NNN\nod\clroL@L@NNN\nod\clrtG@@-*N\nod\flKPUYS\end-*-*CPSPP-*\fljPUYPZPSQP\end-*CPSPQ-*\fljPUYQZPSQQ\end-*CPSPR-*\fljPUYRZPSQR\end-*CPSPS-*\fljPUYSZPSQS\end-*CPSPT-*\fljPUYTZPSQT\end-*-*CPSQP-*\key\msgaA\nod\end-*CPSQQ-*\key\msga@A\nod\end-*CPSQR-*\key\msga@@A\nod\end-*CPSQS-*\key\msgbN\nod\end-*CPSQT-*\key\msgfA\nod\end-*-*-*CPTPP-*CPTPQ-*-* \ No newline at end of file diff --git a/game_english/data/Stage/Jenka2.pxe b/game_english/data/Stage/Jenka2.pxe new file mode 100644 index 0000000..94b30aa Binary files /dev/null and b/game_english/data/Stage/Jenka2.pxe differ diff --git a/game_english/data/Stage/Jenka2.pxm b/game_english/data/Stage/Jenka2.pxm new file mode 100644 index 0000000..83dbd6b Binary files /dev/null and b/game_english/data/Stage/Jenka2.pxm differ diff --git a/game_english/data/Stage/Jenka2.tsc b/game_english/data/Stage/Jenka2.tsc new file mode 100644 index 0000000..f0a9ebf --- /dev/null +++ b/game_english/data/Stage/Jenka2.tsc @@ -0,0 +1 @@ +ǺΩ©ǽǺΩ©ǽǺΩ©ǽǺΩ©ǽǺéľҵΩ©ϾǺΩ©ǽµΩɩȩ˺ľҵҽɩޙޙ򸆃ęޚȽ뚵Ƚˆ횚ȽȆɩк©ɩŤŤк©Ωǽľ҆鍍ͦ᧧ȽȽȆк©ɩк©ͪޙޙ򶧵ȽͩɩɩŦˆޙ򧧧Ƚޙޙ򧧧Ƚާ槵Ƚyޙކݙޙ憃ޙާȽᥙ짧Ƚ짧ȽͪͤˆΩڙޙк©Ƚε˵ޙޥޥ膃ޙ᧵ȽǽľҵéޚȽ暵Ƚޙކݙޙ憃ޙޚȽǽľҵéᥙޙچݙާȽͪͤˆݙڙޙк©Ƚͩ˵ޙߙ놃ݙާȽޙ솃ݙ觧Ƚǽľҵڙޙކݙݙ姧Ƚ™솃ޙȽǽľҵޣȽǽ \ No newline at end of file diff --git a/game_english/data/Stage/Kings.pxe b/game_english/data/Stage/Kings.pxe new file mode 100644 index 0000000..b6665ff Binary files /dev/null and b/game_english/data/Stage/Kings.pxe differ diff --git a/game_english/data/Stage/Kings.pxm b/game_english/data/Stage/Kings.pxm new file mode 100644 index 0000000..c8342b2 Binary files /dev/null and b/game_english/data/Stage/Kings.pxm differ diff --git a/game_english/data/Stage/Kings.tsc b/game_english/data/Stage/Kings.tsc new file mode 100644 index 0000000..9ed7131 --- /dev/null +++ b/game_english/data/Stage/Kings.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qlvqy````lu~t=:S``ia=:l}~qlvqy```alu~t=:S``ib=:l}~qlvqy```blu~t=:S``ic=:l}~qlvqy```clu~t=:S``id=:l}~qlvqy```dlu~t=:=:S`a``=:l{ul}~qlqy``e`lvqy```a=:lq~`c``j``a`j```0lqy``ig=:lq~`c``j```aj````lqy``e`=:lq~`c``j``b`j````lqy``fd=:lq~`c``j```aj````lqy``af=:lq~`c``j``c`j````lqy``e`=:lq~`c``j``d`j````lqy``ig=:lvq```alqyiiii=:=:S`c``=:=: \ No newline at end of file diff --git a/game_english/data/Stage/Labo.pxa b/game_english/data/Stage/Labo.pxa new file mode 100644 index 0000000..9b5a39a Binary files /dev/null and b/game_english/data/Stage/Labo.pxa differ diff --git a/game_english/data/Stage/Little.pxe b/game_english/data/Stage/Little.pxe new file mode 100644 index 0000000..14d8dd0 Binary files /dev/null and b/game_english/data/Stage/Little.pxe differ diff --git a/game_english/data/Stage/Little.pxm b/game_english/data/Stage/Little.pxm new file mode 100644 index 0000000..b50449c Binary files /dev/null and b/game_english/data/Stage/Little.pxm differ diff --git a/game_english/data/Stage/Little.tsc b/game_english/data/Stage/Little.tsc new file mode 100644 index 0000000..878e11b --- /dev/null +++ b/game_english/data/Stage/Little.tsc @@ -0,0 +1 @@ +TQjwwwTQwwwywwwwTQjwwxTQwwwywwwxTQjwwyTQwwwywwwyTQjwwzTQwwwywwwzTQjww{TQwwwywww{TQTQjwxwwTQwwxxwxwwwwwwwwwywwwyww|zwwywwwywx~zTQTQTQTQjwywwTQTQxz~zwyw}TQxz~ywywyTQsgnggggusgggnggtTQggngTQuTQggggggTQwywxrxz~yTQwwwwwxywwwwwwwggguTQwwxwwwxygghwx}wTQjwywxTQgguTQTQjwywyTQGsggggggTQggggwywzhTQggguTQjwywzTQtxz~yTQgsgngggTQuTQgngggggTQgggguwwxywwwwwwwTQwwxyggguTQwwxwwwwggghwx}wTQTQjwyxwTQxz~wwyxxrxz~xTQgggggTQguuugngggsTQgTQjwyxxTQgggguTQjwyywTQngsgTQTQjw|wwTQwy|wwwwwTQTQ \ No newline at end of file diff --git a/game_english/data/Stage/Lounge.pxe b/game_english/data/Stage/Lounge.pxe new file mode 100644 index 0000000..0198c46 Binary files /dev/null and b/game_english/data/Stage/Lounge.pxe differ diff --git a/game_english/data/Stage/Lounge.pxm b/game_english/data/Stage/Lounge.pxm new file mode 100644 index 0000000..2dce2ee Binary files /dev/null and b/game_english/data/Stage/Lounge.pxm differ diff --git a/game_english/data/Stage/Lounge.tsc b/game_english/data/Stage/Lounge.tsc new file mode 100644 index 0000000..cf55ccd --- /dev/null +++ b/game_english/data/Stage/Lounge.tsc @@ -0,0 +1 @@ +{x{xÞ{x{xÞ{x{xÞ{x{xÞ{x{xÞ{x{x{xǪÞ{x{x{x{x{xij{x{x{x{x{x¸{xӎӎᜪ{xَڎӎӚӜ{xݎӕӎώӎ{xԎ眪{x{x{xǪӜŸ›Ҏӎ{x૜ž{xǪӎӎݎӜŸ™{xÞӎ૜ůê{x{x{xǪӎ{xՎӎҏ{xӎӎҎ{x᜜{x{x{x{x{x{x{xij{x{x{xӎ{xӎӎӎ{xҎ܎ӎ✪{xҎԎ{xҜ{xӎՎӎ{xnҎ֜{xӎ皎ݚҎ᜜{x{x{xӎ⎲ՎՎ{xԎ֎ۏ{x֚Ԏ玷ӎώ{x{x֎ώӜ{x{x{xǪ{xij{x{xܕӎώҎ{xᏪ᭎֏{xӎҎݎӎӜ{x{x{xǪ{xij{x{xێݎҜ{x{x{xǪǰ֚眪ܕӎӭ{xَ֚ӎ{xӜ{xӎҎ琎{xӎގҎӎӜ{xܚӎ՜Վݎ{xՎώӎԎӜݎӎݎ֭{xښӎҎ{xůDzů{xů{xÞů{xÞ{x{x{x{x{x{x{x \ No newline at end of file diff --git a/game_english/data/Stage/Malco.pxe b/game_english/data/Stage/Malco.pxe new file mode 100644 index 0000000..d720f4f Binary files /dev/null and b/game_english/data/Stage/Malco.pxe differ diff --git a/game_english/data/Stage/Malco.pxm b/game_english/data/Stage/Malco.pxm new file mode 100644 index 0000000..afdc84f Binary files /dev/null and b/game_english/data/Stage/Malco.pxm differ diff --git a/game_english/data/Stage/Malco.tsc b/game_english/data/Stage/Malco.tsc new file mode 100644 index 0000000..9209b55 --- /dev/null +++ b/game_english/data/Stage/Malco.tsc @@ -0,0 +1 @@ +~~µɤ¸~~µɤ¸~~µɤ¸~~µɤ¸~~µɤ~~~¸~~Ĥ~Ĥ~¸~~Ĥ~Ĥ~Ĥ~Ĥ~¸~~~~~~ƽɤĤäƵ~~ƽǻ╰ø¸~~~~Ͱǻٔúø~Ôúø³¾Ɓ~ɤĤ¢øÁ~ͰɤĤ˵͸˵~ɤǻɸƔȕø~·ɷȽ•øð˵~ǻܕøÁ~Ĥ˵~ɤĤ˵ɤ~Ĥ~ǻؔɔف~Քؔ~ٳ¾蕰øʹ~~~~ƽǻƁ~۔ø¸~~ͰĤĤ˵~ƽǻ蔵ƹ鳕øͰÁ~˵ɤ~ǻ~ڔە˵ø~ɤ¸~~~Ͱǻٔ˵›ȕøٔؔՁ~ɻ袰ø~ؔ؁~آø~Ĥࠔ~߳øưࠔٔ~械ø~ܔٔ٢øƵٔ~ߔ袰ø~研ځ~٢ø~ՔøÁ~ɤĤ¸~~~Ͱǻ۔䢢ø¸~~~~~Ͱǻ袢ø~ٔ~械ø¸~~ƽǻø~ؔؔ⢰ø¸~~Ͱǻؔ~ٔآø~t賰¾ð˵~Ĥ~Ĥ~Ͷ˵͸~ǻȼøȼ¿ɢøɛƹ½Ĺ¢ø~¸Ô»øȼ¿ǔƔǵʽ»øƽÔĵ͔ɔ~ˠøƶȔ˔˔ÔÔǁ~ǽʹǢø¸~~~~~~Ⱦ~~ͰǻÔĵ͔ɔ~ˠøƶȔ˔˔ÔÔǁ~ǽʹǢø¸~~ø~ȼƛǔȹ¸ɔ›ȁ~ȔȔĹ³ø˼ȳø~”ǔƵĹǽøƁ~ɔ͔ƹøŕø¸øø~¸ƺ~Ɣɕø~˹˔ȼȔƔÁ~ȼƹǕøʹ~~Ͱǻ¹ɔÔȁ~»ȹƽǢø~Ʒõø~ͺǼɽ~¸ǹøƽƔǔ”ǁ~ɔƽ»ȼȹƽǕø¸~~~Ⱦʹ~~Ⱦʹ~~Ͱȡȡȡ~ǻʹɔ¸ȼȹƽǁ~͹ȳøưȥüøȼƷõø~ȥüøȼͺǼɽø~ȥüøʹ”ȼǹøȼ”Ȕǔ•øȤÁ~ä˵~ǻȔǔ½ǼøȥȟƁ~ɤٔٱ˵øɰƻԕø~˔ȼȔƔĕø¸~~~Ͱǻԕø~͔¸˔ȼȔƔĕø¸~~Ͱǻ¸ʽǽȔ”Ƚø~úƔɔȹȢø¸~~~Ͱǻʹ›Ȕǹ”ɔ”˼øƽțǔøÔǹɢø~țǔÔ¹͔ƹ˽ȼÁ~¹Ôȵâø~ʹ”ȼ¿»ĹƼǔ~ɻȔÔȽʵȹĵƹ~öǠͶȼ˔ĵ͢øƢøƁ~úƔɔȹȢø¸~~ \ No newline at end of file diff --git a/game_english/data/Stage/Mapi.pxe b/game_english/data/Stage/Mapi.pxe new file mode 100644 index 0000000..02be92f Binary files /dev/null and b/game_english/data/Stage/Mapi.pxe differ diff --git a/game_english/data/Stage/Mapi.pxm b/game_english/data/Stage/Mapi.pxm new file mode 100644 index 0000000..4cb4e3e Binary files /dev/null and b/game_english/data/Stage/Mapi.pxm differ diff --git a/game_english/data/Stage/Mapi.tsc b/game_english/data/Stage/Mapi.tsc new file mode 100644 index 0000000..28e1969 --- /dev/null +++ b/game_english/data/Stage/Mapi.tsc @@ -0,0 +1 @@ +IF_llulIFx}xllllx}llllxIF_llumIFx}xllllx}lllmxIF_llunIFx}xllllx}lllnxIF_lluoIFx}xllllx}llloxIF_llupIFx}xllllx}lllpxIFIFIFIFxmqrovlmlmIFIF_lmllIFxxmqrpvlmlmxllmmx}lmllvllllvlllnIFx}lllpx}llmrvllupvllonvlllnIF_lmlmIFxx\c\]xxIFIFIF_lpllIFxx~lllnx}llnlIFxmqrovlpnlIFxmqrnvlpmmIFxmqrmvlplox\\\\\{xlplmxmlppvlplnx]xIF\\jxxIFIF_lplmIFxxiij\~h\jxxIFIF_lplnIFxxgmqrmx{x\}{xIF\jxxlploIF_lploIFxxh\j\\\\\IF\\\\~{xlpltxlplpxIFIF_lplpIFxx~\\h\\cIF\\h\{xlplqxlpltIF_lplqIFxx\\\\{xlpluxlplrIF_lplrIFxx\\\\IF\\{xlpluWddmdA>pupwddempzu}ddddpyxA>WddmeA>pupwddempzu}dddepyxA>WddmfA>pupwddempzu}dddfpyxA>WddmgA>pupwddempzu}dddgpyxA>WddmhA>pupwddempzu}ddd4pyxA>A>WdeddA>p}pzudddfpudddmnddmfnddefnddjhA>A>WdedeA>p}pzudddepuddgmnddmendddhnddejA>A>WdfddA>p}p{}[TTbT[TTTbpxpyxA>A> \ No newline at end of file diff --git a/game_english/data/Stage/MazeI.pxe b/game_english/data/Stage/MazeI.pxe new file mode 100644 index 0000000..d301a2f Binary files /dev/null and b/game_english/data/Stage/MazeI.pxe differ diff --git a/game_english/data/Stage/MazeI.pxm b/game_english/data/Stage/MazeI.pxm new file mode 100644 index 0000000..ec76fcc Binary files /dev/null and b/game_english/data/Stage/MazeI.pxm differ diff --git a/game_english/data/Stage/MazeI.tsc b/game_english/data/Stage/MazeI.tsc new file mode 100644 index 0000000..d5109f9 --- /dev/null +++ b/game_english/data/Stage/MazeI.tsc @@ -0,0 +1 @@ +[Xq~~~[X~~~~~~[Xq~~[X~~~~~[Xq~~[X~~~~~[Xq~~[X~~~~~[Xq~~[X~~~~~[X[Xq~~~[X~~~~~~~~~~~[X[Xq~~[X~~~nŽun|||[Xq~~[X~~~~~~~~~~~~~[Xq~~[Xq~~[X[Xq~~~[X~~~~~~~[X~~nnnúo~~y~~~[Xn¶nnno[X[X[X[Xq~~~[X~~~~~~~~~~~~oo|||||nnnǽnn¶[Xü|nn¶n[X~~~[X~~~~~~~~~~~~~[X[Xq~~[X~~~nǽnůn½nn¶n~~~~[Xy~[XN~~~~~~~~[X~~~~~~~~~~~~~~~~~~~~~[X~~~~~~~~~~[X~~~~~~~~~~~~~~[X~~~~[X~~~~~[X~~[X~~~~~~~~~[X[Xq~~[Xnnn|[X[Xq~~[X[X[Xq~~~[Xnnn½nǽ[Xżn|[Xnn¶|||[Xnn¶nunn|[Xnǽnnz[Xǽnijnn|||[X[Xq~~[X[Xq~~[Xnŷ±n¶nn¶[Xnnþn½nnþn½[XŶ|[Xn¶n·unnþ[X¶|[Xnnijnnijn[Xü·nnnn|[X[Xq~~[Xnnn|[X[Xnȳnnnnnn~~n{n~[X~~[X~.ؘ[X~ёјѨ[X[X \ No newline at end of file diff --git a/game_english/data/Stage/MazeM.pxe b/game_english/data/Stage/MazeM.pxe new file mode 100644 index 0000000..d7eda37 Binary files /dev/null and b/game_english/data/Stage/MazeM.pxe differ diff --git a/game_english/data/Stage/MazeM.pxm b/game_english/data/Stage/MazeM.pxm new file mode 100644 index 0000000..cdda771 Binary files /dev/null and b/game_english/data/Stage/MazeM.pxm differ diff --git a/game_english/data/Stage/MazeM.tsc b/game_english/data/Stage/MazeM.tsc new file mode 100644 index 0000000..05becb1 --- /dev/null +++ b/game_english/data/Stage/MazeM.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``b`lq~`d``j``b`j```blvqy````lv|z`ghbj``iilu~t=:S``ia=:l}~qls}``b`lvqy```alu~t=:S``ib=:l}~qls}``b`lq~`d``j``b`j```blvqy```blv|z`ghbj``iilu~t=:S``ic=:l}~qls}``b`lvqy```clv|z`gh`j``iilu~t=:S``id=:l}~qls}``b`lvqy```dlv|z`gh`j``iilu~t=:=:=:=:S``ii=:ls}```gj``cej````=:ls}```hj``cej````=:ls}``bfj``caj`aaa=:lu~t=:=:S`a``=:lylvq````lq``ddj``idj``a`j``ad=:=:S`aa`=:l{ulv|z`ghcj`aablv|z`ghaj`aaa=:l``aalq~`aa`j````j```blvq```blq``dfj``ibj```cj```i=:S`aaa=:lv|[`gh`lv|]`gha=:l``aalq~`aa`j````j```blvq```blq``dfj`ae`j```cj``0i=:S`aab=:lyl}wyPWP^^^l~tlu~t=:=:S`c``=:S`c`a=:l{ul}~qls}``b`=:lq~`ca`j```aj````lvqy```d=:ls~`c`aj`aabj```blqy`a``=:lq~`ca`j````j````=:l}t```blt~`c`al}s=:lq~`d``j``b`j```blv|z`ghbj``iilu~t=:S`ca`=:l{ulv|[`gb`ls~`c``j`aaaj````lx}slqy``f`lq~`ca`j```aj````=:lqy`a``lvq```dlq``dbj`c`aj``bfj```e=:=:=:S`cc`=:lylv|z`ghbj`ccal}wPPP^l~tl``dcls|l}wP^l~tls|=:lv|[`ghb=:lqy``e`=:l``ga=:ls}```gj``cej````=:ls}```hj``cej````=:ls}``bfj``caj`aaa=:lqy``e`lu~t=:S`cca=:lyl}w^^^l~tlu~t=:=:S`d``=:=: \ No newline at end of file diff --git a/game_english/data/Stage/MazeO.pxe b/game_english/data/Stage/MazeO.pxe new file mode 100644 index 0000000..3537a2c Binary files /dev/null and b/game_english/data/Stage/MazeO.pxe differ diff --git a/game_english/data/Stage/MazeO.pxm b/game_english/data/Stage/MazeO.pxm new file mode 100644 index 0000000..61edc26 Binary files /dev/null and b/game_english/data/Stage/MazeO.pxm differ diff --git a/game_english/data/Stage/MazeO.tsc b/game_english/data/Stage/MazeO.tsc new file mode 100644 index 0000000..7cabed3 --- /dev/null +++ b/game_english/data/Stage/MazeO.tsc @@ -0,0 +1 @@ +VSlyyyVSyyy{yyyyVSlyyzVSyyy{yyyzVSlyy{VSyyy{yyy{VSlyy|VSyyy{yyy|VSlyy}VSyyy{yyy}VSVSVSVSVSlyzyyVSyyzzyzyyyyyyyyy{yyyyyyyyVSyy|yzyzVSyy|yy}yy}yyz~VSlyzyzVStyy}yy|yy}yy}yyz~VSVSlyzy~VSyyy}yy|yy}yyzyyz{VSVSly{yyVSi¼iuVSiwwwVSiiiVSiiiiwVSVSVSly|yyVSpii¼wVSuiiii¸iwtzyyyyy{yVSyy}y|y}VSyy{y|y|VSyyzy|y{VSyyyy|yztyyyyy~yVSuiuiiuipiwiuiuipVSipiiiii¸wpiiiiiwVSiiiiipVSiiiiwVSzyztyyziii†wyyyyVSly|yzVSiipiiwVSiiiiiVSiwVSly|y{VSvyyztyy{VSzyziiivwyyyyui¸iijVSiwVSiiiiiwVSly|y|VSiwVSiiiiiwVSly|y}VSiiipVSwVSpiiiiiVSiwVSiii¸uiiwVSVSly|zyVSyy}y|z|VSyy{y|z{VSyyzy|zzVSpiiwVSiiiiiiVSiuVSiiiîiiuVSiIiiwVSly|zzVSi¸iiiiVSi¸iiiuipVSi¸iiiiiVS¼wVSly|z{VSiwVSipiiiuVSi¸VSly|z|VSuii¸iiiVSiiiiiiiVSkikwVSVSly|{yVSyy{y|{{VSyyzy|{ztyyzVSyyzuijpiiiVSiwVSpiijiii¸VSiiuiVSiijyy{yi¸ipiiVSiiiwwwVSpiiiiVSi¸uiwwwiuiiwVSuiiwVSiiiiVSiwwwwwwiiiwVSiiuiipVSiiiVSwVSiipiiuVSipiiVS½iwwwVSly|{zVSyy{yiui®uiVSiipiiVSiiiiwwwVSly|{{VSyy{yiiiVS»wVSipiiiiuVSipiiVSiiiiwpiiiVSwVSiiiiVSiiiiVSiwpiii¸uVSiiiipVSuipiiiVS¸iwwwtyytyy|VSVSVSly}yyVSyy~yyyztyy~yy{{y}yyyy{zyyyyVSiiiwzyztyyztyyy}VSyyzyiiijyzyVSVS \ No newline at end of file diff --git a/game_english/data/Stage/MazeS.pxe b/game_english/data/Stage/MazeS.pxe new file mode 100644 index 0000000..5103bc8 Binary files /dev/null and b/game_english/data/Stage/MazeS.pxe differ diff --git a/game_english/data/Stage/MazeS.pxm b/game_english/data/Stage/MazeS.pxm new file mode 100644 index 0000000..786595f Binary files /dev/null and b/game_english/data/Stage/MazeS.pxm differ diff --git a/game_english/data/Stage/MazeS.tsc b/game_english/data/Stage/MazeS.tsc new file mode 100644 index 0000000..990c0f2 --- /dev/null +++ b/game_english/data/Stage/MazeS.tsc @@ -0,0 +1 @@ +?FWXKFMW_::=AFPKS:::>FOXN-:;::FZ\SFPKY:::F^\K::>:D::CD:::?-:;:=FPVT:@B;D:;:?FS^T::;AD:;:>FZ\SFW]QVymuon8FXYNFOXN-:;:>FZ\SF]Y_::<;D::C:D::;?D:::C-:;:@FUOcF]Y_::;;FKXZ:;:@D::::D:::F^\K::>D:::?D:::C +-:;;:FPVT:A>:D:;;;FUOcF]Y_::;;FKXZ:;;:D::::D:::=D:?::D:::>D::;=-:;;;FUOcF]Y_::;;FKXZ:;;:D::::D:::=D::CD::;=-:;<:FUOcFPKY:::>F^\K::>:D::C>D::;AD;<::D::=BD::;@ \ No newline at end of file diff --git a/game_english/data/Stage/MiBox.pxe b/game_english/data/Stage/MiBox.pxe new file mode 100644 index 0000000..3fb5faf Binary files /dev/null and b/game_english/data/Stage/MiBox.pxe differ diff --git a/game_english/data/Stage/MiBox.pxm b/game_english/data/Stage/MiBox.pxm new file mode 100644 index 0000000..35422ed Binary files /dev/null and b/game_english/data/Stage/MiBox.pxm differ diff --git a/game_english/data/Stage/MiBox.tsc b/game_english/data/Stage/MiBox.tsc new file mode 100644 index 0000000..65d53e2 --- /dev/null +++ b/game_english/data/Stage/MiBox.tsc @@ -0,0 +1 @@ +NKdqqzqNK}}qqqq}NKdqqzrNK}}qqqr}NKdqqzsNK}}qqqs}NKdqqztNK}A}qqqt}NKdqqzuNK}}qqqu}NKNKdqrqqNK}}qqqu}qqrr{qqzu{qqsu{qqtuNKNK \ No newline at end of file diff --git a/game_english/data/Stage/Mimi.pxa b/game_english/data/Stage/Mimi.pxa new file mode 100644 index 0000000..94e8fc0 Binary files /dev/null and b/game_english/data/Stage/Mimi.pxa differ diff --git a/game_english/data/Stage/Mimi.pxe b/game_english/data/Stage/Mimi.pxe new file mode 100644 index 0000000..5b68f62 Binary files /dev/null and b/game_english/data/Stage/Mimi.pxe differ diff --git a/game_english/data/Stage/Mimi.pxm b/game_english/data/Stage/Mimi.pxm new file mode 100644 index 0000000..7fc90d8 Binary files /dev/null and b/game_english/data/Stage/Mimi.pxm differ diff --git a/game_english/data/Stage/Mimi.tsc b/game_english/data/Stage/Mimi.tsc new file mode 100644 index 0000000..de5e265 --- /dev/null +++ b/game_english/data/Stage/Mimi.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qlv|z`cdaj``iels}```ilvqy````lu~t=:S``ia=:l}~qlv|z`cdaj``ifls}```ilvqy```alu~t=:S``ib=:l}~qlv|z`cdaj``igls}```ilvqy```blu~t=:S``ic=:l}~qlv|z`cdaj``ihls}```ilvqy```clu~t=:S``id=:l}~qlv|z`cdaj``iils}```ilvqy```dlu~t=:=:S``ie=:ls}``bhlvqy````lu~t=:S``if=:ls}``bhlvqy```alu~t=:S``ig=:ls}``bhlvqy```blu~t=:S``ih=:ls}``bhlvqy```clu~t=:S``ii=:ls}``bhlvqy```dlu~t=:=:=:S`a``=:lylv|z`cbdj`a`b=:lyz```aj`a`a=:l}w|^l~tlu~t=:S`a`a=:l``bblwya``alv|[`cbdlv|[`dda=:l}wPmqWP{m^l~tlwy````ls|luu`a`b=:S`a`b=:l``aals~`a``j````j````lvq```dlq```aj``idj``agj```h=:=:=:S`a`c=:lylvq````lq``aej``i`j``cfj``ad=:S`a`d=:lv|z`cbgj`aab=:lv|z`cf`j`aaa=:l{ul}wlvqs```iyWPz\l~t=:P]PP^l~tls|PPPP=:}P\PP=:PqP^l~tls|\PPPyP\=:Pol~tls|\PP=:PPPP=:\l~t=:PyWPPP=:PPPPW=:P^l~tlu~t=:=:S`a`e=:l{ulv|z`cf`j`a`fl``aalq~`a`ej````j```bluu`a`f=:S`a`f=:l{ulvq```dlq``adj``idj```ej```i=:=:S`a`g=:lyl``aals~`a`gj````j````lvq```dlq``aij``idj```gj``a`=:=:S`a`h=:lylvq```blq``agj``ibj```bj``aa=:=:S`a`i=:lylvq```dlq``b`j``idj``a`j```i=:=:S`aa`=:lylvq````lq``abj``i`j``eej```i=:=:S`aaa=:l{ulv|[`cbglv|[`ddcl}wlvqs```ioQl~t=:WPPol~t=:\PQl~t=:yWPPPP{=:PQl~tls|=:l}t````=:lq~`aaaj```hj````lqy`b`h=:lq~`aaaj````j```blqy``a`=:l``aalq~`a`gj````j```blqy``c`=:lt~`aaa=:l``aalq~`a`gj````j````lu~t=:=:S`aab=:lylvq```blq``afj``ibj```bj``ab=:=:=:=:S`b``=:lylv|z`cbbj`b`alv|[`cbbl``bbls~`b``j``baj````=:l}wPP^l~tlwya``bly[```blu[```bls|=:ls}``a`wPPm}PmQlqy`af`l~tl}luu`b`a=:S`b`a=:lyl}wWPP^^^l~tls|lPPPPPP=:P\PPP=:PPP^PPyP^l~tlu~t=:=:S`c``=:S`c`a=:l{ulv|z`cbcj`c`elv|[`cb`lv|[`cbc=:l}w^^^^^l~tls|=:l}r````lqy``e`l}t````ls~`c`aj``faj```blqy```hls~`c`aj``faj```d=:l}wlvqs```goPWPPPol~t=:yPPPP=:P^^^l~tls|yWP{^l~t=:yWPP]P=:P^l~t=:~PPP=:PP\PP=:PPP^l~tls|\PPP^l~tls|WPPPP\=:^l~t=:WPPP=:PPP^l~tlu~t=:=:S`c`b=:l{ulv|[`cb`lv|[`cbalv~`c`bj``afl}~qlvqy```dls}````lqy`a``=:l}wlvqs```gxPPPQl~tls|lvqs```h~QPyPWQl~tls|lvqs```gqPPP=:Pol~t=:WPPQ=:WPPPPQl~tls|lvqs```fWPPP^l~t=:yWPPPQl~tls|lvqs```g^^^l~t=:PPtP\=:PPWP=:PP^^^l~t=:yPPWPP=:\PPPP=:PP^l~tls|lvqs```fr^^^Pr^^^l~tls|lvqs```gP\PQl~t=:lvqs````ls|=:l}``acj``bb=:lqy``gelx}sls~`c`ij`ae`j```blq~`c`ij``a`j```blq``c`=:l}woQl~tls|=:lqy``a`=:lq~`c``j```fj```b=:lq~`c`aj```fj````=:lqy`a``=:lq~`c``j```fj```b=:lqy``h`=:lt~`c``=:ls}```i=:lv}``afl}slt~`c`ilu~t=:=:=:S`c`e=:l{ul}wlvqs```grPP^^^l~t=:PPPP=:P^l~tlu~t=:S`c`f=:l{ul}wlvqs```gwQl~tls|Ql~t=:WPPP=:PQl~tlu~t=:S`c`g=:S`c`h=:l{ul}t```blvqy```bls}````lqy``b`=:l}wlvqs```gwPPPQl~tls|lvqs```h~Ql~tls|=:lq~`c`gj```fj```blqy`0f`=:lq~`c`fj```fj```bl``aflqy`a``lt~`c`glv|]`cgals}```ilu~t=:S`c`i=:=:=:S`caa=:l{ul}wZPZl~tls|Ql~tls|=:l}r````lq~`caaj```bj```dlqy``c`l}t````=:lv|z`aefj`cac=:lv|z`ab`j`cab=:lv|z`cf`j`cad=:l}wQPPP^^^l~tls|ol~t=:\P^l~tls|PPPqWP\Pol~t=:WPPP^l~tls|P\P^l~t=:PWPPP=:RPtR^^^l~t=:tPPPP^^^=:tPPPP=:ol~tlq~`caaj````j```blu~t=:S`cab=:l}w\PP^l~tls|PPPP^l~t=:PPWPPP=:P^l~tlq~`caaj````j```blu~t=:S`cac=:l{ul}wyPPPPP=:qWP^^^l~tls|qPPPPP=:ol~tlq~`caaj````j```blu~t=:S`cad=:l{ul}wol~t=:WPPol~tls|\PWPP^l~t=:~PPPPPP=:PP^^^l~tlq~`caaj````j```blu~t=:=:S`d``=:l{ulv|]`aeelv~`d``j``aflvqy```dl}~qls}````lqy`a``lq~`f``j``aaj```b=:l}wlvqs```c|PPPPQl~tlq~`f``j````j```bls|lq~`fa`j````j````lvqs```gxPPQl~tls|WuPPP=:PQl~tls|PPPP=:PPPPP=:PPP^l~tlq~`f``j``aaj```bls|lvqs```cP]PQl~tlq~`f``j````j```bls|lvqs```gyPPWPPP=:\PyPPyWP=:PPPQl~tls|ls}```i=:lv}``aflqy``e`lu~t=:=:=:S`da`=:S`daa=:S`db`=:l{ulx}sls}````=:ls~`da`j``dbj```b=:ls~`daaj``gdj````=:lq~`fa`j````j````lqy`a``l}wlvqs```gPW^^^ol~tls}```ilvqy```dls|lvqs```bWP^l~tls|PtPPP=:PPPP=:PPP^l~tls|lvqs```i]]PPP=:PPoQl~tls|lvqs```bPP^^^=:^^^PPP^l~tls|lvqs```iqPWPPP=:PPPol~tls|lvqs```bqPPPyPP\=:WPPP=:^l~tls|PPPP=:WPP^l~tls|lvqs```iy^^^l~tls|yPPP=:\P^^^l~tls|lvqs```bPPP^^^=:qPPP^^^l~tls|lvqs```gyWPPP=:PQl~tls|=:lv|]`aedlv|[`aeg=:lvq```dlq```aj`fb`j```ej```h=:=:=:S`e``=:l{ul}wlPPPPPPPPPPPPjPPv=:PPPP|jPPPPjPw=:PPPPPPPPPPPtjPqWPxl~t=:lu~t=:=:S`e`a=:l{ul}wl=:PPPPPPPPPPPPPPPvl~tlu~t=:S`e`b=:l{ul}wl=:PPPPPPPPPPPPPPPPPl~tlu~t=:S`e`c=:l{ul}wl=:PPPPPPPPPPPPP}Pw=:PPPPPPPPPPPPPtQP~Pul~tlu~t=:S`e`d=:l{ul}wl=:PPPPPPPPPPPPPPqWPxl~tlu~t=:S`e`e=:l{ul}wl=:PPPPPPPPPPPPPPPqPxl~tlu~t=:=:=:S`f``=:lv|z`bbdj`f`b=:lv|z`cbej`f`a=:l{ulv|[`cbel[```bjf``b=:l}wlvqs```a\PyWP^^^l~tls|PWP=:PP}\=:PPP^l~t=:xPWP\l~t=:PPPP=:P}PP=:PPPP\l~t=:PPP=:P^l~tls|^^^^^l~tls|yP^l~tls|PWPPP=:Pol~tls|}PWPP=:P=:w^l~t=:vPPPP=:^l~tlu~t=:=:=:S`f`a=:l{ul}wlvqs```avPPP=:PP^l~t=:PPPPw=:PPP=:qWP^l~tlu~t=:S`f`b=:l{ul}wlvqs```axPPP=:Pol~tlu~t=:=:S`fa`=:lv|z`bbdj`faa=:l{ul}wlvqs```gPPPPP=:PPPP=:P^l~tlu~t=:S`faa=:l{ul}wlvqs```gP^^^l~tlu~t=:=: \ No newline at end of file diff --git a/game_english/data/Stage/Momo.pxe b/game_english/data/Stage/Momo.pxe new file mode 100644 index 0000000..67cd58c Binary files /dev/null and b/game_english/data/Stage/Momo.pxe differ diff --git a/game_english/data/Stage/Momo.pxm b/game_english/data/Stage/Momo.pxm new file mode 100644 index 0000000..e58b14d Binary files /dev/null and b/game_english/data/Stage/Momo.pxm differ diff --git a/game_english/data/Stage/Momo.tsc b/game_english/data/Stage/Momo.tsc new file mode 100644 index 0000000..bad33d1 --- /dev/null +++ b/game_english/data/Stage/Momo.tsc @@ -0,0 +1 @@ +nknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknknkЁցƁƁnkƁƁǏnkɍ́ԏ΁ρЏnkƈԁӏnkŁЁƁnkԁȁՁnkӈԁƏnkՁƁƁŁnkԍƁŁЁnkƁӁƏnkЁƁŁƁŁnkƁƁǁƁŏځԁōnkՁƁ́֏ՁՈԁӁnkӁƏՁ؁΁nkρȁՍnkƁՁ́ՁnkЁƁӈԁƏnkψՁƁƁnkƁԁՍɏnknknknknkՁŁՁnkԁӏnk؍ЁŁƁnkǁƏnknknkՁŁnk؁ԏnkӁבϏ́ŁnkԁЁɁnkՏnknknknknknkՁŁnk؁ԏnkӁדϏ́ŁnkԁЁɁnkՏnknknknknknkƁցځՁؠڠnkӁōϏnknknkɍŁӏnkӁӁŏƍՁԁnkӁ؏nknkՁƁ̞nkȍƁȏnkԁՈԁnkȍՏƁԁȁnkԁψՁnkЁ́ɁԏnkՁɁaՁ́ύnkցŁƁƁnḱЁΏƁցɁƁЁӠnknknkŁցЁ́nkρŁɏƈԁԁōnkЁՁƈԁnkӏnknknkЁƁƁՍnḱŁځnḱӏnkǁցŁՁŁnkƁǁƁnkځƁՁƍnḱՁƁnkЁ́ɁՏƁȁƁ́nkӞnknknkЁƁƁՍnḱŁځnḱӏnkƁԁnkρƁԁՁnkƁ̏ƁȁƁ́nkӞnknknkƁ̏ŁӁnkρӞΏԁӈnkԁƁρՏnkψՁЁnkɁԏnknknkƁ̏nkŁӁƁӞՈԁƏځǁƁnkƁԏnḱԁځ̏nkՍŁցЁnkρρŁɏƈԁρӁnkƁՃnkЁƁԁρԏՁƈԁЁƁnkƁՁŁρnkӁՏnkƁŁ΁ƁnkՁǁƁՍnkƁψՁƁρӏnknknkƁ̏ŁցŁɠnkŁӁƁӞԁԁՍ́ՏnkԁԁƁnkƈԁЁŁǏΏƁԁŁnkՁӁǁځnkƁځƏ͍́nk؏nknknknḱցځɏՈ́ƁƁnkƁ΁ōnkЁځψՁցnkӁρՁŠnknknknknkЁցՁЁՠnknkɁŏnknknknknknkցρӁȁяnknknknkՏnknk \ No newline at end of file diff --git a/game_english/data/Stage/New.pxe b/game_english/data/Stage/New.pxe new file mode 100644 index 0000000..6407ae9 Binary files /dev/null and b/game_english/data/Stage/New.pxe differ diff --git a/game_english/data/Stage/Oside.pxa b/game_english/data/Stage/Oside.pxa new file mode 100644 index 0000000..d141dad Binary files /dev/null and b/game_english/data/Stage/Oside.pxa differ diff --git a/game_english/data/Stage/Oside.pxe b/game_english/data/Stage/Oside.pxe new file mode 100644 index 0000000..38e3b5d Binary files /dev/null and b/game_english/data/Stage/Oside.pxe differ diff --git a/game_english/data/Stage/Oside.pxm b/game_english/data/Stage/Oside.pxm new file mode 100644 index 0000000..03adc62 Binary files /dev/null and b/game_english/data/Stage/Oside.pxm differ diff --git a/game_english/data/Stage/Oside.tsc b/game_english/data/Stage/Oside.tsc new file mode 100644 index 0000000..5572988 --- /dev/null +++ b/game_english/data/Stage/Oside.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``belvqy````lu~t=:S``ia=:l}~qls}``belvqy```alu~t=:S``ib=:l}~qls}``belvqy```blu~t=:S``ic=:l}~qls}``belvqy```clu~t=:S``id=:l}~qls}``belvqy```dlu~t=:=:S`a``=:l{ulvq````lq``ebj``i`j``agj``a`=:=:S`ab`=:l{ul``aalq~`ab`j````j```blvq```dlq``eej``idj```ij```i=:l}wWP^^^l~tlu~t=:=:S`ac`=:l{ulyz``cbj`acal``aalq~`ac`j````j```blvq````lq``fij``i`j``aej```h=:S`aca=:l{uls}````l``aalq~`ac`j````j```b=:lwya`cbly]``cblv|[acg`l}wyWPQl~tls|=:lvq````lq``fij``i`j``aej```h=:=:S`ad`=:l{ulvq````l}t````lq``idj``i`j``adj```g=:=:S`b``=:lyl}wqPol~tlu~t=:=:S`d``=:l{ulv|z`if`j`d`al}wlvqs``a`yPWPP=:PPP\=:WPP^l~tlu~t=:S`d`a=:l{uls|lv~`da`j``aflqy``e`=:l}wlvqs``a`wPl}t````^l~tls|=:ls~`db`j`ae`j````lx}s=:lq~`d``j```cj````lqy``cb=:lq~`d``j````j```blqy``cb=:lq~`db`j``e`j````lqy``cb=:lq~`db`j````j```blqy``cb=:lt~`d``lt~0db`=:lq~`da`j``a`j```blqy`b``=:l}wlvqs``a`xPP^l~tls|lvqs````=:lq~`da`j``b`j```blqy`be`=:lq~`da`j``a`j```blqy`b``=:l}wqPPPPP=:PP^lqy`b``ls|rP\PPtP=:PPPP\P=:PPPPP^lqy`b``ls|PPPPP=:PPPPtW=:olqy`b``ls|lvq```buP\PPP=:PP^lqy`b``ls|\PPPP=:PP\PP=:PtWP\lqy`b``ls|PP{PP=:PPPPP^^^lqy`b``ls|ls}``bf=:lPPPPPPPPPPPPPPPP]PPuP]lqyiiii=:lu~t=:=:=:S`da`=:l{ul}ww^^^l~tlu~t=:S`db`=:=:=:S`f``=:l{ul}wPPPP=:^l~t=:PPPPPPP=:P^l~t=:yWPPyWPPP=:PPP^l~t=:PPPyPPP=:PP^^^l~tlu~t=:=: \ No newline at end of file diff --git a/game_english/data/Stage/Ostep.pxe b/game_english/data/Stage/Ostep.pxe new file mode 100644 index 0000000..0d1e91e Binary files /dev/null and b/game_english/data/Stage/Ostep.pxe differ diff --git a/game_english/data/Stage/Ostep.pxm b/game_english/data/Stage/Ostep.pxm new file mode 100644 index 0000000..1732069 Binary files /dev/null and b/game_english/data/Stage/Ostep.pxm differ diff --git a/game_english/data/Stage/Ostep.tsc b/game_english/data/Stage/Ostep.tsc new file mode 100644 index 0000000..80e6ef0 --- /dev/null +++ b/game_english/data/Stage/Ostep.tsc @@ -0,0 +1 @@ +0==F=IZ[NISNV====IR[Q0==F>IZ[NISNV===>IR[Q0==F?IZ[NISNV===?IR[Q0==F@IZ[NISNV===@IR[Q0==FAIZ[NISNV===AIR[Q0=>==IXRfI`\b==>>IN[]=>==G====G===?ISN\====Ia_N==EBG==FCG==>FG==?F0=>>=IXRfI`\b==>>IN[]=>>=G====G===?ISN\===?Ia_N==EDG==FBG===AG==>>0=?==0=?=>0=F== IQ[]=F==IXRfIZfQ===?IZ`T]yrnr-xvyy-z-znr;I[\Qaun-v-ur-|{y-n-Zvrpn{-or-srrq;;;I[\Q;;;aur-|{y-n-|-n|vq-nr}rvv|{-|s-uv-ntrq;I[\QIPY_Z-znr4-{nzr-v-Onyy|;I[\QIPY_Uv-zntvp-}|r-unr-t|{r-vyq9n{q-{|-ur-pn{{|-rr{-qvr;;;I[\QIN[]=?=>G==>=G====ISY8>C?=IR[Q \ No newline at end of file diff --git a/game_english/data/Stage/Pens.pxa b/game_english/data/Stage/Pens.pxa new file mode 100644 index 0000000..9afb486 Binary files /dev/null and b/game_english/data/Stage/Pens.pxa differ diff --git a/game_english/data/Stage/Pens1.pxe b/game_english/data/Stage/Pens1.pxe new file mode 100644 index 0000000..84e8440 Binary files /dev/null and b/game_english/data/Stage/Pens1.pxe differ diff --git a/game_english/data/Stage/Pens1.pxm b/game_english/data/Stage/Pens1.pxm new file mode 100644 index 0000000..04545f6 Binary files /dev/null and b/game_english/data/Stage/Pens1.pxm differ diff --git a/game_english/data/Stage/Pens1.tsc b/game_english/data/Stage/Pens1.tsc new file mode 100644 index 0000000..8c7acfc --- /dev/null +++ b/game_english/data/Stage/Pens1.tsc @@ -0,0 +1 @@ +öʥùöʥùöʥùöʥùöʥùʥùʥťť̶ťι¸ťùαöʥťť̶ťι¸ťùǾĥǶǾĥǶǾʥťĥǶǾʥʥťĥǶαȼڕ㣣ĹDZǗەڕ䡕ݡᣣĹDZȼڕܕ紱ÿٕ蕺܂磱ĹȠùαȼڕ㣣ĹǂǸܕ䕼㣣Ĺùαȼǂٕ䕼㣱Ĺùαȼǂ٣ĹùαȼǂٕٕڣĹùαȼڕ㣣ĹDZǂٕڕܕֱĹùαȼ裣Ĺùαȼ磱ĹűĹùαȼڕࣱĹڜࣱĹڜٕڕڕڣĹڕڡڜڕܕࣱĹڕڡڣĹǾڡ졂ڕە裱ĹڣĹùαȼڕڣĹùαʥť̶ť̶ťť̶ȼݣĹDZڕĹı̶ťȼ⣱Ĺڕٕڂ裱ĹDZĹıť̶ťʥťȼ֖ĹťǶٕ畷疱ĹDZݖĹıť̶ťȼڕ顕㴖ĹDZᡕڕ裱Ĺıťť̶ť̶ťʥť̶ťȼĹDZִĹı̶ť̶ť̶ť̶ȼܣĹǶٕەڕڕڕڣĹڕٕڕۂڣĹە⡂ݡڕقڕ裱ĹǺܕ裣ĹĂʥťť̶ťι¸ťùαȼڕڂܕڣĹەڕ܂㣣Ĺùαȼ壱Ĺڡڕ٣Ĺùαȼ݂֕㣣Ĺ䖕閱Ĺùαη̶ιťȼڕĹڕڕڣĹݕ塱ĹڕٕڕڕٕڕٕܣĹıť̶ťȼ疱ĹǸڕڕڂݕڕ䴱Ĺıť̶ťȼʥĹǂ磱ĹDZĹDZڡ磣ĹڕڕٕڣĹڕقڕٕ裱ĹťǂĹDZ鴱ĹDZڕڕuٕ⡕֕ەڣĹڕڕقڣĹڕڕڕٕڕڕٕڣĹǂڕٕڴĹ㡕ڂڜٕڕ紱ĹDZᡱĹڕڂە裱Ĺەڕڂڕ⣣Ĺǽ硕ڕٕڕ裱Ĺܕڕڕڂ塱ĹڜڕڕٕڣĹǂڕܕ崱ĹDZĹڜڕە֕ݕףĹıťť̶ť̶ťȼ꣱Ĺǂʥ䕾ȕڴĹDZ飣ĹڕەڕقڂٕٱĹ䣱ĹDZ鴖ĹDZٕٕ顱ťĹ镾ڂ裱ĹڕڕەٕڣĹDZ磱ĹڕٕڕقڣĹDZڣĹıť̶ťť̶ȼڕڕقܕ٣Ĺڣڕ٣ĹȠùαȼݕڕقڕ֕ڕ磱Ĺٕڕٕقڕڕۂ⣱ĹùαȼڕڕەڣĹǾ٣Ĺڂ飱ĹùαȼڕٕڣĹùαȼەٕەڂ衕ڜڕڕڕ죱ĹǾ֕ܕĹùαȼڕڕݕقڕ٣Ĺܕ꣣Ĺùťαιť̶ťťť̶ťť̶ť̶ťȼĹıť̶ȼꡕڣĹǣڕقڕٕ裱Ĺǣڕٜڕ裱ĹڕڂڣĹǾٕڕقڕڂ㕾ٕڕڣĹıť̶ťɠɦȼڕ맣̶Ĺıɥťȼڕٕ飱ĹǾەڕڕ㡱Ĺڕٕڕ٣Ĺ硱ĹٕڕٕڕڕڕڣĹڕڕڂٕڡĹڕٕڕڕܕݕ裱Ĺǂܕ꣱ĹڕݕٕڣĹĂȠùαȼڕڕݕقڕ٣Ĺܕ꣣Ĺùαȼڂ٣ĹڕڕڂڣĹùαʥĥǶǾȼڂܕ紱ÿĂαť¸̶ť̶ĥǶǾȼ䕼㴱ÿĂαť¸̶ť̶ĥǶǾȼڂٕڴÿĂαť¸̶ť̶ĥǶǾȼڂݴÿĂαť¸̶ť̶ĥǶǾȼڂ㴱ÿĂαť¸̶ť̶ĥǶαǶ \ No newline at end of file diff --git a/game_english/data/Stage/Pens2.pxe b/game_english/data/Stage/Pens2.pxe new file mode 100644 index 0000000..b62ccd1 Binary files /dev/null and b/game_english/data/Stage/Pens2.pxe differ diff --git a/game_english/data/Stage/Pens2.pxm b/game_english/data/Stage/Pens2.pxm new file mode 100644 index 0000000..04545f6 Binary files /dev/null and b/game_english/data/Stage/Pens2.pxm differ diff --git a/game_english/data/Stage/Pens2.tsc b/game_english/data/Stage/Pens2.tsc new file mode 100644 index 0000000..6a2043a --- /dev/null +++ b/game_english/data/Stage/Pens2.tsc @@ -0,0 +1 @@ +~~µɤ¸~~µɤ¸~~µɤ¸~~µɤ¸~~µɤ¸~~~~~~Ͱɤ~ǻƷ۔ߢ˵~ؔ⢰˵~ƹ۔ᢰ˵Ɓ~ǻբø~ٔٳø~øäƵ~~Ͱǻ٢ø~ٔ㢰ø㠔⳰ø~ٔٔ볰ø~ؔٔ碰ø~ܔ鳰øäƵ~~Ͱǻٔڔ碰ø~ؔ܁~Քآø~ہ~賰øư۔~Ֆ˵ưƷ٢~⮔tٔø~۔碰ø۔~攖▢øƁ~ǻࠔہ~颰ø~٢øäƵ~~ͰĤǻø~~۔٢øƁ~ɤĤ˵ɤĤø~ðĤ˵Ĥ~ǻٔߢø~ٔ۔~颢øưܳ볰ø~Քøư؁~ٔ⢰øư賕øưؔٛٔ۔Ɂ~ٕøÁ~Ĥ˵äǻ~ٔ㕰øưܔ㠔蕰øƵ~¸~¸~~~~~~~ \ No newline at end of file diff --git a/game_english/data/Stage/Pixel.pxe b/game_english/data/Stage/Pixel.pxe new file mode 100644 index 0000000..3364dd5 Binary files /dev/null and b/game_english/data/Stage/Pixel.pxe differ diff --git a/game_english/data/Stage/Pixel.pxm b/game_english/data/Stage/Pixel.pxm new file mode 100644 index 0000000..575bee6 Binary files /dev/null and b/game_english/data/Stage/Pixel.pxm differ diff --git a/game_english/data/Stage/Pixel.tsc b/game_english/data/Stage/Pixel.tsc new file mode 100644 index 0000000..fded528 --- /dev/null +++ b/game_english/data/Stage/Pixel.tsc @@ -0,0 +1 @@ +QNgtt}tQNttuxttttQNgtt}uQNttuxtttuQNgtt}vQNttuxtttvQNgtt}wQNttuxtttwQNgtt}xQNttuxtttxQNgtt}yQNtttuQNQNgtuttQNtutt~tttt~tttvttuuQNtttxttx|~tt}x~tuyw~ttuzQNQNgtvttQNQNuxxu~tvtwQNuxxt~tvtvQNt|wy~tvtuQNddddrQNtxqt|qt|dddrQNQNgtvtuQNddddrQNdkddddQNQNgtvtvQNouxxyddddrdpddddQNddddrrrQNQNgtvtwQNddddrQNddddrQNQNgtvutQNQNgtvvtQNddddrrrQNgtvvuQNkddpdQNdrrruxxu~tvvwuxxy~tvvvQNgtvvvQNQNddddddttttouxxuqddQNdddQNrddddddQNdpdddQNdddqrdddddQNddddddQNdrQNrttutrttutrttutrttutrttutrttutrttutrttutttutddddQNetuztDddddddQNddpdddQNdddrttwtQNgtvvwQNdddQNdrrrQNQNgtvytQNQNuxxx~tvy{QNuxxw~tvyyQNuxxv~tvyxQNuxxu~tvywQNuxxt~tvyvQNt|wz~tvyuttu}QNgtvyuQNQNddddtttttttxttttttvtQNrrrrrQNtuttoutttQNtvutqt|wzouxxttttvQNtt{w~tt}y~ttuv~ttt}QNgtvyvQNdkdpdddQNdkddrQNgtvywQNddddddQNdttttQNouxxvtttutttttvtttttuQNtuytttvtQNrrrttuxttvyrrrrrtvzt~tttu~tttvttu}kdepdkddrrrttvydkdddQNdddrQNdddpQNdkdddQNdrrrddddQNdddkQNrQNttvtrrrtttttvzt~tttu~ttttQNttytQNdddrQNQNgtvyxQNdddddQNddrouxxwQNgtvyyQNQNddddddtvyzQNgtvyzQNtvzt~tvy}~ttttot|wzquxxtouxxxQNgtvy{QNdkddrQNQNgtvztQNQN \ No newline at end of file diff --git a/game_english/data/Stage/Plant.pxe b/game_english/data/Stage/Plant.pxe new file mode 100644 index 0000000..2fe9f5b Binary files /dev/null and b/game_english/data/Stage/Plant.pxe differ diff --git a/game_english/data/Stage/Plant.pxm b/game_english/data/Stage/Plant.pxm new file mode 100644 index 0000000..2fe59c1 Binary files /dev/null and b/game_english/data/Stage/Plant.pxm differ diff --git a/game_english/data/Stage/Plant.tsc b/game_english/data/Stage/Plant.tsc new file mode 100644 index 0000000..3117832 --- /dev/null +++ b/game_english/data/Stage/Plant.tsc @@ -0,0 +1 @@ +YVo|||YV|}||||}||||YVo||}YV|}||||}|||}YVo||~YV|}||||}|||~YVo||YV|}||||}|||YVo||YV|}||||}|||YVYVo||YV||~||||YVo||YV||~|||}YVo||YV||~|||~YVo||YV||~|||YVo||YV||~|||YVYVo|}||YV||||||}}|||||||~}YVYVYVo|}|YVll±||||l±zYVo|}|YVw}|||||~|wlzYVYVo|~||YVlllzYVllñlzYVllllíl±llzLlllllñYVlzlñxlxlllÿzlŻllllñxYVllŻlllYVxlllŻll±lmllñlsl±lYVllõlzYVYVYVo|~~|YV}|~||~~}lzYVo|~~}YVslıllllmYVYVo|||YVYVw|}|YV|||YVlllzzz||}|}||w|||YVlllz|}|YVYVYVo|||YV||~~|||||}YV}||lllm|}|w|||YVllllmYVYV \ No newline at end of file diff --git a/game_english/data/Stage/Pole.pxe b/game_english/data/Stage/Pole.pxe new file mode 100644 index 0000000..df67329 Binary files /dev/null and b/game_english/data/Stage/Pole.pxe differ diff --git a/game_english/data/Stage/Pole.pxm b/game_english/data/Stage/Pole.pxm new file mode 100644 index 0000000..e0b3f54 Binary files /dev/null and b/game_english/data/Stage/Pole.pxm differ diff --git a/game_english/data/Stage/Pole.tsc b/game_english/data/Stage/Pole.tsc new file mode 100644 index 0000000..d3da595 --- /dev/null +++ b/game_english/data/Stage/Pole.tsc @@ -0,0 +1 @@ +CPPYP-*\mna\cmuPPPX\faiPPPP\end-*CPPYQ-*\mna\cmuPPPX\faiPPPQ\end-*CPPYR-*\mna\cmuPPPX\faiPPPR\end-*CPPYS-*\mna\cmuPPPX\faiPPPS\end-*CPPYT-*\mna\cmuPPPX\faiPPPT\end-*-*CPPYU-*\cmuPPPX\faiPPPQ\end-*-*CPQPP-*\pri\faoPPPP\traPPQRZPPYTZPPUSZPPSV-*-*-*-*CPRPP-*\key\fljQVTPZPRPQ\flKQVTP\souPPRR\cnpPRPPZPPRQZPPPP-*\msgo@@N\nod\gitPPPR\amKPPPRZPPPP\clr-*\cmuPPQPg@@]p@s]A\waiPQVP\nod\gitPPPP\clo\rmu-*\msg-*f@L@@NNN\faoPPPT\nod\traPPQXZPUPQZPPPRZPPPP-*-*CPRPQ-*\pri\msgeN\nod\end-*-*CPRQP-*-*-*CPSPP-*\key\msgJJ\nod\end-*-*CPSPQ-*\fljQVTTZPSPS-*\key\msgy@G@@@@i@L-*@_\nod-*s@@@@@-*i@@A\nod-*dL@@@@i@G@-*@@@@@-*i@NNN\nod\amjPPPRZPSPR\clri@G@@@A\nod-*j@@@@@@i-*G@@@@@-*@@@@@N\nod\clr-*aL@@@L@@@NNN\nod\end-*-*CPSPR-*\key\msg\cmuPPPP\mybPPPR-*heyAA\nod\clriG@that@@_A\nod\clr\gitPPPRw@@you@@@_A-*i@G@@@@A\nod\clrg@@A\nod\clr\cnpPRQPZPQUPZPPQR\waiPPQR\gitPPPP\hmc-*]p@s]@NNN\nod\clrpA\nod-*i@@G@@-* @@@N\nod\clr-*NNNNN\nod\clry@L\nod-*iG@@@@G-*@@@@-*N\nod-*t@@@@@G-*@@@@-*@@@N\nod-*t@@@@@@-*@@@@@-*@@@N\nod\clr-*\cmuPPPXhNNN\waiPPUP\clrw@i@@@@@@-*@@@@L-*@@@@@N\nod-*t@@@@@-*@@@@G-*NNN\nod\clr-*hNNN\nod\clri@@@@N\nod\clr-*y@@@@N\nod\cmuPPPP\faoPPPQ-*a@i@@L@@N\nod\clo-*\waiPQUP\faiPPPQ-*\fla\waiPPUP\tamPPPRZPPQSZPPPP\flKQVTT\flKPSPS\msg-*\cmuPPQP\msg\gitPPQS-*]p@s]@@@]s]A\smc\dnpPRQP\waiPQVP\nod\cmuPPPX\end-*-*CPSPS-*\key\msgi@@L@@@-*@@@@-*@@@@@N\nod\clri@@L@@L@-*@@@@@@-*@@N\nod-*f@@L@i@@@-*@@@@@N\nod-*t@@@@-*@i@@@@@-*@@@@@@N\nod\end-*-*CPSQP-*\key\msg\tur-*BoNB\nod\end-*-*-* \ No newline at end of file diff --git a/game_english/data/Stage/Pool.pxe b/game_english/data/Stage/Pool.pxe new file mode 100644 index 0000000..86f833b Binary files /dev/null and b/game_english/data/Stage/Pool.pxe differ diff --git a/game_english/data/Stage/Pool.pxm b/game_english/data/Stage/Pool.pxm new file mode 100644 index 0000000..5501c2d Binary files /dev/null and b/game_english/data/Stage/Pool.pxm differ diff --git a/game_english/data/Stage/Pool.tsc b/game_english/data/Stage/Pool.tsc new file mode 100644 index 0000000..c2347f1 --- /dev/null +++ b/game_english/data/Stage/Pool.tsc @@ -0,0 +1 @@ +tqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtqtq̦ϓއٕtqێڇ̇̇ӇևtqˇׇՇَڇtqӇ̇̓ۦtq̇ˇׇ̇ۇtq·g֕tq̇ˇهˇׇtq̇Շٕ̇tq̇Վۇԇև̇tqϕtqՎۇއ̇̎tqȇȇۇ̇ڕtqtqtqtqtqtqtq·ڇՇ̇ەtqۇ̇هۤtqtqtqtqtqtqtqψtqtqtqtqtqtqtqtqtqtqtq \ No newline at end of file diff --git a/game_english/data/Stage/Prefa1.pxe b/game_english/data/Stage/Prefa1.pxe new file mode 100644 index 0000000..2de6026 Binary files /dev/null and b/game_english/data/Stage/Prefa1.pxe differ diff --git a/game_english/data/Stage/Prefa1.pxm b/game_english/data/Stage/Prefa1.pxm new file mode 100644 index 0000000..8c91db8 Binary files /dev/null and b/game_english/data/Stage/Prefa1.pxm differ diff --git a/game_english/data/Stage/Prefa1.tsc b/game_english/data/Stage/Prefa1.tsc new file mode 100644 index 0000000..a01d1b7 --- /dev/null +++ b/game_english/data/Stage/Prefa1.tsc @@ -0,0 +1 @@ +{x{xÞ{x{xÞ{x{xÞ{x{xÞ{x{xÞ{x{x{xǪÞ{x{x{x{xǪ{x{x{x{x{xǪҎώӎ܎{x{xҎӎݎҎ⭪Ǽ܎Ԏӎҕ{xҎӎӎ{xҚ⚪Ҏӎnݎ{xڎ✪ᚎӎ{x܎ӎԎՎ{xڎӎӎ܎ݎ{x᎞Ҏڎ䞜ݎ{xӎҎݎ{x܎Ԏ՜ێӎ܎ӎ䠜{xҎӎՎ֜ݎӎ܎܎{xڎۜ{xů{xҎӜů{x{x{x \ No newline at end of file diff --git a/game_english/data/Stage/Prefa2.pxe b/game_english/data/Stage/Prefa2.pxe new file mode 100644 index 0000000..1e0eba9 Binary files /dev/null and b/game_english/data/Stage/Prefa2.pxe differ diff --git a/game_english/data/Stage/Prefa2.pxm b/game_english/data/Stage/Prefa2.pxm new file mode 100644 index 0000000..674ad60 Binary files /dev/null and b/game_english/data/Stage/Prefa2.pxm differ diff --git a/game_english/data/Stage/Prefa2.tsc b/game_english/data/Stage/Prefa2.tsc new file mode 100644 index 0000000..fd0ddf2 --- /dev/null +++ b/game_english/data/Stage/Prefa2.tsc @@ -0,0 +1 @@ +YVo|||YV||||||||YVo||}YV|||||||}YVo||~YV|||||||~YVo||YV|||||||YVo||YV|||||||YVYVo|}||YVslzzzYV|}|||||||||~||}}|||||~||||||YVYVo|}}|YV|||YVw}}Lw}w}|YV|||||||}|||}YVYVYVYVYVYVo|~||YVlŻslll±lxYVll±lŻllllzlŻlíll±l||||YVw}|w}}w}~|||||||}|}||YV||||}||}}||~YVYVo|~|YVYVlsllzzzYVYV \ No newline at end of file diff --git a/game_english/data/Stage/Priso1.pxe b/game_english/data/Stage/Priso1.pxe new file mode 100644 index 0000000..c28cec5 Binary files /dev/null and b/game_english/data/Stage/Priso1.pxe differ diff --git a/game_english/data/Stage/Priso1.pxm b/game_english/data/Stage/Priso1.pxm new file mode 100644 index 0000000..6cc6e54 Binary files /dev/null and b/game_english/data/Stage/Priso1.pxm differ diff --git a/game_english/data/Stage/Priso1.tsc b/game_english/data/Stage/Priso1.tsc new file mode 100644 index 0000000..eeda7f0 --- /dev/null +++ b/game_english/data/Stage/Priso1.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``bilvqy````lu~t=:S``ia=:l}~qls}``bilvqy```alu~t=:S``ib=:l}~qls}``bilvqy```blu~t=:S``ic=:l}~qls}``bilvqy```clu~t=:S``id=:l}~qls}``bilvqy```dlu~t=:=:S`a``=:l{ul``aalt~`a``lvq````lq0`efj``i`j``h`j```i=:S`aa`=:l{ul``aalt~`aa`lvq```alq``fbj``iaj```gj``gd=:=:S`b``=:lq~`b``j```bj```blu~t=:S`b`a=:lq~`b`aj```bj```blu~t=:S`b`b=:lq~`b`bj```bj```blu~t=:S`b`c=:lq~`b`cj```bj```blu~t=:=: \ No newline at end of file diff --git a/game_english/data/Stage/Priso2.pxe b/game_english/data/Stage/Priso2.pxe new file mode 100644 index 0000000..31a9bcf Binary files /dev/null and b/game_english/data/Stage/Priso2.pxe differ diff --git a/game_english/data/Stage/Priso2.pxm b/game_english/data/Stage/Priso2.pxm new file mode 100644 index 0000000..445c3cd Binary files /dev/null and b/game_english/data/Stage/Priso2.pxm differ diff --git a/game_english/data/Stage/Priso2.tsc b/game_english/data/Stage/Priso2.tsc new file mode 100644 index 0000000..b14b583 --- /dev/null +++ b/game_english/data/Stage/Priso2.tsc @@ -0,0 +1 @@ +?IZ[NIPZb===EISNV===>IR[Q0==F?IZ[NIPZb===EISNV===?IR[Q0==F@IZ[NIPZb===EISNV===@IR[Q0==FAIZ[NIPZb===EISNV===AIR[Q0=>==ISYW=@C>G=>=@ISYW=@C?G=>=>ISYW=@C=G=>=?IXRfI`\b==>>IN[]=>==G====G===?ISN\===AIa_N==>>G==FAG==A?G==B?0=>=>I]_VIZ`TWՏVI[\QIR[Q0=>=?IXRfISN\===AIa_N==>>G==FAG==A?G==B?0=>=@I]_VIZ`TՏVI[\QIR[Q0=>B=0=>B>0=>B?0=>B@0=>BA0=?F=ISYW=@D=G=?F>IR[Q0=?F>ISYW=@C=G====I]_VIZ`TISNP===EُVVI[\QIQ[]=?F=IP[]>===G==C@G===?IR[Q0=A==IXRfISY:=@C>ISY:=@C?I`ZPIP[]=A==G==>?G====IN[]=A==G==?=G===AIdNV=>A=I]_VIZ`TISNP===B珳яVI[\QISNP====IXRfIPY\IdNV=>==IPZb==>BIZ`T|\ʎVIdNV=>A=I[\QI`\b==ABIP[]=>B=G===>G====IdNV===AI`\b==ABIP[]=>B>G===>G====IdNV===AI`\b==ABIP[]=>B?G===>G====IdNV===AI`\b==ABIP[]=>B@G===>G====IdNV===AI`\b==ABIP[]=>BAG===>G====IPZb===EIR[Q0=B==0>===IXRfISY8=@C=ISY8=@C>ISY8=AA=ISY:=@?CIZ`TݏVI[\QIPY_vPlhvPlhVI[\QIPY_RRRI[\QUI[\QIZfO===?IdNV==@=IZfQ===?IP[]>===G==C=G===AIPY_ISNP===CՏʐu[khӕUI[\QIPY_ȏڏďҏĎOI[\Qu[khڏݏԏϏҏՎOI[\Q؞_ٞǏ֙ȏюNʏʏ̏Ώʏ֏ڛRʏpI[\QIPY_ʏڙgZR͏ΏʏُOI[\QIPY_VI[\QȏِltVITVa>==AI[\QIPY_RΏяʏUI[\QehʏЏˎVI[\QIPY_RRROI[\QIPY_ˏԎN폱؎OI[\QITVa====ʏehӟԏďΏY\MďΏOI[\QՏʏΏяюOI[\QIPY\ISNP====IPZb==== I^bN==@=I`\b==?CIN[]>===G===EG====IN[]=>==G===>G====IdNV==>=IZfQ====IP[]>===G==C=G====IdNV=>==I^bN==@=I`\b==?CIN[]>===G===EG====IN[]=>==G===>G====IdNV==D=I^bN==@=I`\b==?CIN[]>===G===EG====IP[]=A==G==>FG===?IP[]=>==G==>EG===?IPZ]===AG===EG==E=IPZ]===BG===EG==E>IPZ]===CG===EG==E?IPZ]===AG===FG==FCIPZ]===BG===FG==FDIPZ]===CG===FG==FEIZ`TԏVVIdNV==B=IP[]=A==G==>?G===?IN[]=A==G==@=G===?IPY_IXRfIPZb==>>ISNP==>AOϏʎVI[\QIPY_ISNP===BOʏΏѣ׏ːOI[\Q[٢MڙՏՏُOI[\QISNP====IPY_ȏُӏOI[\QIP[]=B==G==CDG===?IdNV=>==IN[]=B==G==>@G===?IdNV==B=IN[]>===G===EG====IZ`TISNP==>BϏ٢MӐNkՏՏˎOI[\QIPY_ISNP===BbhVI[\QIPY_[֙ϏʏˏVI[\QIPY_ISNP===E鏳Nu[khٟˏՎVVI[\QIPY_ISNP==>BRRROI[\QIPY_ISNP==>C鏳ehOI[\Qu[khyяޏˎOI[\Q֤я􏱎OI[\QIPY_ISNP===CUI[\QIPY_ʏڐehÏՏOI[\QISNP====IPY\IN[]=B==G==>BG===?IdNV=>>=I]_VIZ`TISNP===EUVI[\QISNP==>BIPY_|\NI[\Qӏڏ鏶ƏʎOI[\QIPY\IN[]=B==G==?=G===?ISNP====IPY\IXRfIdNV==B=IZ`TISNP===EyˏΏяVI[\QISNP====IPY\IdNV==B=ISNP===BIZ`Tʐ_ˏVI[\Q{ۏΏVI[\QϏʏُڐ[Տُ֎VI[\QIPY_RRROI[\QIPY_ҎNYږʎUI[\Qȏ٢Ґ[ӝَUIf[W>==>IN[]=A==G==@=G===?IPY_ISNP==>AՏԏ؎VI[\QIPY\ISY8=@C>IPZb===AIP[]=A==G==CEG===?IO`Y=A==IR[Q0>==>IXRfISY:=@C?ISY:=@C>IPZb===EIZ`TISNP===BȏOI[\QȏÏ[NOI[\QIPY\IN[]=A==G==>=G===?IR[Q \ No newline at end of file diff --git a/game_japanese/data/Stage/Blcny1.pxe b/game_japanese/data/Stage/Blcny1.pxe new file mode 100644 index 0000000..b3bcec5 Binary files /dev/null and b/game_japanese/data/Stage/Blcny1.pxe differ diff --git a/game_japanese/data/Stage/Blcny1.pxm b/game_japanese/data/Stage/Blcny1.pxm new file mode 100644 index 0000000..93bb4dc Binary files /dev/null and b/game_japanese/data/Stage/Blcny1.pxm differ diff --git a/game_japanese/data/Stage/Blcny1.tsc b/game_japanese/data/Stage/Blcny1.tsc new file mode 100644 index 0000000..e1dc5dc --- /dev/null +++ b/game_japanese/data/Stage/Blcny1.tsc @@ -0,0 +1,2 @@ +WddmdA>pypzaeemdpzaeemepz_eemfpupwddgdpzu}ddddpyxA>WddmeA>pypz_eemdpzaeemepzaeemfpupwddgdpzu}dddepyxA>WddmfA>pypupwddgdpzu}dddfpyxA>WddmgA>pypupwddgdpzu}dddgpyxA>WddmhA>pypzaeemdpz_eemepzaeemfpupwddgdpzu}dddhpyxA>A>WddmiA>pypzu}dddhpyxA>A>A>WdeddA>pypddeepudeddnddddndddfpzudddgA>p}~ddfgndedepuddjgnddmgndddmndddhA>A>WdedeA>pypuddjknddmgndddmndddhA>A>A>A>WdeedA>p}pzudddfpuddjhnddmfndddenddeeA>A>WdefdA>pypudefdnddddndddfpddeepzudddhpuddjjnddm4nddedndddlA>A>WdegdA>p}p{v߶A>ضݵpxpyxA>A>WdemmA>p}p{~ˠvpxpyxA>pzudddh{ǷvǷvpxpwpwddggpwypu}mmmmpyxA>A>WdfddA>pypxddddpxdfddpup{A>0ض +¶}pxpyxA>A>WdfdeA>p}p{pA>}}xuUUpxpyxA>A>WdfedA>p}pz~eemendfeepz~eemfndfefA>p}pzudddhpxdddfpu}ddidpuddjfnddmindddknddkhA>WdfeeA>p}pzudddhpxdddfpu}ddidpuddjfnddminddkmnddkgA>WdfefA>p}pzudddhpxddddpu}ddidpuddjfnddmindeeknddjfA>A> \ No newline at end of file diff --git a/game_japanese/data/Stage/Blcny2.pxe b/game_japanese/data/Stage/Blcny2.pxe new file mode 100644 index 0000000..394d1c6 Binary files /dev/null and b/game_japanese/data/Stage/Blcny2.pxe differ diff --git a/game_japanese/data/Stage/Blcny2.pxm b/game_japanese/data/Stage/Blcny2.pxm new file mode 100644 index 0000000..f229389 Binary files /dev/null and b/game_japanese/data/Stage/Blcny2.pxm differ diff --git a/game_japanese/data/Stage/Blcny2.tsc b/game_japanese/data/Stage/Blcny2.tsc new file mode 100644 index 0000000..b45cf8e Binary files /dev/null and b/game_japanese/data/Stage/Blcny2.tsc differ diff --git a/game_japanese/data/Stage/Cave.pxa b/game_japanese/data/Stage/Cave.pxa new file mode 100644 index 0000000..c30cbaa Binary files /dev/null and b/game_japanese/data/Stage/Cave.pxa differ diff --git a/game_japanese/data/Stage/Cave.pxe b/game_japanese/data/Stage/Cave.pxe new file mode 100644 index 0000000..d117d5d Binary files /dev/null and b/game_japanese/data/Stage/Cave.pxe differ diff --git a/game_japanese/data/Stage/Cave.pxm b/game_japanese/data/Stage/Cave.pxm new file mode 100644 index 0000000..fcbf014 Binary files /dev/null and b/game_japanese/data/Stage/Cave.pxm differ diff --git a/game_japanese/data/Stage/Cave.tsc b/game_japanese/data/Stage/Cave.tsc new file mode 100644 index 0000000..2d883fc --- /dev/null +++ b/game_japanese/data/Stage/Cave.tsc @@ -0,0 +1 @@ +GD]jjsjGDv{v}jjjrv{jjjjv~GD]jjskGDv{v}jjjrv{jjjkv~GD]jjslGDv{v}jjjrv{jjjlv~GD]jjsmGDv{v}jjjrv{jjjmv~GD]jjsnGDv{v}jjjrv{jjjnv~GDGD]jjssGDv}jjjrv{jjjnv~GDGDGD]jkjkGDvv}jkjktjjjjtjjjjvjjkkv{jjjmv{jjkmtjjsmtjjkjtjjjmGDGD]jkjlGDvvjmjltjkjnvjmjktjkjmvv~v~GD]jkjmGDvv{jjjlGDvejmjlvekpnkvekpnlGDv~jjjlv{jjkrtjojl:jjjltjjjjGD]jkjnGDvv{jjjlv{jjkktjjsntjjjrtjjjpGD]jkkjGDvv{jjjnv{jjsjtjjsltjjjqtjjjsGDGDGD]jkojGDvv~jjjjv}jjjrv{jjjnGDv{jjmjGDvjjklv}jjojtjjmotjjpqv{jjljGDvjjklv}jjojtjjmptjjpqv{jjljGDv~GDGD]jljjGDv~GD]jljkGDv~GDGD]jnjjGDvvjjllv~jnjjv}jjkpGDvvkjjpwý}wZ*"6$v{jkpjv~vvejjjmGDZmZ׼v~v~GDGD \ No newline at end of file diff --git a/game_japanese/data/Stage/Cemet.pxe b/game_japanese/data/Stage/Cemet.pxe new file mode 100644 index 0000000..62ace93 Binary files /dev/null and b/game_japanese/data/Stage/Cemet.pxe differ diff --git a/game_japanese/data/Stage/Cemet.pxm b/game_japanese/data/Stage/Cemet.pxm new file mode 100644 index 0000000..279529a Binary files /dev/null and b/game_japanese/data/Stage/Cemet.pxm differ diff --git a/game_japanese/data/Stage/Cemet.tsc b/game_japanese/data/Stage/Cemet.tsc new file mode 100644 index 0000000..3029522 Binary files /dev/null and b/game_japanese/data/Stage/Cemet.tsc differ diff --git a/game_japanese/data/Stage/Cent.pxa b/game_japanese/data/Stage/Cent.pxa new file mode 100644 index 0000000..c2a1486 Binary files /dev/null and b/game_japanese/data/Stage/Cent.pxa differ diff --git a/game_japanese/data/Stage/Cent.pxe b/game_japanese/data/Stage/Cent.pxe new file mode 100644 index 0000000..d12eaa7 Binary files /dev/null and b/game_japanese/data/Stage/Cent.pxe differ diff --git a/game_japanese/data/Stage/Cent.pxm b/game_japanese/data/Stage/Cent.pxm new file mode 100644 index 0000000..5220599 Binary files /dev/null and b/game_japanese/data/Stage/Cent.pxm differ diff --git a/game_japanese/data/Stage/Cent.tsc b/game_japanese/data/Stage/Cent.tsc new file mode 100644 index 0000000..eadef34 Binary files /dev/null and b/game_japanese/data/Stage/Cent.tsc differ diff --git a/game_japanese/data/Stage/CentW.pxe b/game_japanese/data/Stage/CentW.pxe new file mode 100644 index 0000000..a728e3d Binary files /dev/null and b/game_japanese/data/Stage/CentW.pxe differ diff --git a/game_japanese/data/Stage/CentW.pxm b/game_japanese/data/Stage/CentW.pxm new file mode 100644 index 0000000..ab0318a Binary files /dev/null and b/game_japanese/data/Stage/CentW.pxm differ diff --git a/game_japanese/data/Stage/CentW.tsc b/game_japanese/data/Stage/CentW.tsc new file mode 100644 index 0000000..13b9ab1 --- /dev/null +++ b/game_japanese/data/Stage/CentW.tsc @@ -0,0 +1 @@ +B?B?XeeneB?qvqxeeeeq{v~eeeeqzyB?XeenfB?qvqxeeeeq{v~eeefqzyB?XeengB?qvqxeeeeq{v~eeegqzyB?XeenhB?qvqxeeeeq{v~eeehqzyB?XeeniB?qvqxeeeeq{v~eeeiqzyB?XeenjB?B?XeennB?qzqvqxeeeeB?qvefjeoeeefoeeeeq{v~eeeiB?qxehefoeffgoeeegqv~efeeB?qvefjeoeeeeoeeeeB?qyeeegqyehefqxqzyB?B?B?XefeeB?qzqeeffqvefeeoeeeeoeeegq{veeegqveejkoeengoeeefoefehB?B?B?XefjeB?qzq{ffieoefjgB?q|v¨޶}qeeeeqxB?q{`femgq{`ffieq`eeejokee5B?qv~eejeq|B?¸vȶ~qyqxB?qyeeegB?qvegjeoeefeoeeeeqv~eekeB?qxegkeoefjeoeeeeq}xB?qvegkeoeefeoeeeeqv~eejeB?q{veeehqv~efeeqxq{ffifoefjgq{`ffifqveejloeggeoeeffoeefiB?B?B?XefjgB?q~q|v¨޶}qeeeeqxq`eeejokeejB?qzqxeheeoefffoeeegq}xqv~eekeqvefjeoeeefoeeeeB?qv~efeeq{veeeiqveeefoeennoeeejoeeemB?B?XefjgB?qveejloeenioeeffoeefiB?B?XegjeB?qzq|zzzwqyqzyB?B?XegkeB?B?B?B?B?B?XeheeB?XehefB?B? \ No newline at end of file diff --git a/game_japanese/data/Stage/Chako.pxe b/game_japanese/data/Stage/Chako.pxe new file mode 100644 index 0000000..6ba6273 Binary files /dev/null and b/game_japanese/data/Stage/Chako.pxe differ diff --git a/game_japanese/data/Stage/Chako.pxm b/game_japanese/data/Stage/Chako.pxm new file mode 100644 index 0000000..2a510dd Binary files /dev/null and b/game_japanese/data/Stage/Chako.pxm differ diff --git a/game_japanese/data/Stage/Chako.tsc b/game_japanese/data/Stage/Chako.tsc new file mode 100644 index 0000000..d98a4a9 --- /dev/null +++ b/game_japanese/data/Stage/Chako.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qlv|]`bfcls}```blvqy````lu~t=:S``ia=:l}~qlv|]`bfcls}```blvqy```alu~t=:S``ib=:l}~qlv|]`bfcls}```blvqy```blu~t=:S``ic=:l}~qlv|]`bfcls}```blvqy```clu~t=:S``id=:l}~qlv|]`bfclv|z`cdaj``iils}```blvqy```dlu~t=:=:S``ii=:ls}``bhlvqy```dlu~t=:=:S`a``=:lyl``aalt~`a``lvq```dlq```fj``idj`aaij``ag=:=:=:=:S`b``=:lyz```hj`b`b=:l{ul}w,Բڼٲֲrl~tlv|z`bdaj`b`alu~t=:S`b`a=:l}wھƲұl~tls|=:lv|z`bfaj````lqy``c`lv|[`bfalv|[`bfc=:lq~`c``j```cj```blqy``delq~`c``j````j```bl}t````=:l}w=:—v Ҳxl~tls|~ھͲҲ=:m~mP{Ǧrl~tlu~t=:S`b`b=:l{ulwya``hl}wm~mP Ҳ ٱxl~z````ls|=:lv|[`bacly]```h=:lq~`b``j``a`j````lqy``c`lvq```d=:lq```fj``iij`abdj``aa=:=:S`ba0=:lylyz``cgj``ailv|z`bfcj`baaluu``ai=:S`baa=:l{ul}w=: ٱxl~z````lvq```dls}````lqy``b`ls|uuuuurly[``cgl~tls|=:l}~`c``j``abj```fj````lq~`c``j``a`j````=:lqy``e`=:l|y[a```l``b`l}t```bl}w=:ڹ!̲rl~tls|l}lvqy```dlu~t=:=:=:S`c``=:lyz```hj`c`b=:lv|z`bfaj`c`a=:lv|z`bdaj`c`c=:l{ul}wҲұrl~tls|=:¾ó~xl~tlu~t=:S`c`a=:l{ul}w—v =:m~mP{Ǧrl~tls|m~mPq=:~ھͲҲrl~t=:۲ҳ~ Բrl~tlu~t=:S`c`b=:l{ul}wm~mP ,xyl~t=:yl~tls|=:m~mP=:ͲҲ߲l~t=:èrl~tlu~t=:S`c`c=:l{ul}wҲұrl~tls|˲Ͳrl~t=:ٲxl~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Clock.pxe b/game_japanese/data/Stage/Clock.pxe new file mode 100644 index 0000000..7af0ce4 Binary files /dev/null and b/game_japanese/data/Stage/Clock.pxe differ diff --git a/game_japanese/data/Stage/Clock.pxm b/game_japanese/data/Stage/Clock.pxm new file mode 100644 index 0000000..0cf567b Binary files /dev/null and b/game_japanese/data/Stage/Clock.pxm differ diff --git a/game_japanese/data/Stage/Clock.tsc b/game_japanese/data/Stage/Clock.tsc new file mode 100644 index 0000000..33719bf --- /dev/null +++ b/game_japanese/data/Stage/Clock.tsc @@ -0,0 +1 @@ +?FWXKFMW_:::BFPKS:::>FOXN-:;::FZ\SFPKY:::>F^\K:::D:;F^\K:::D:;ϐ[X 1>.ߠ+7ϐ[Xѭϩѥ.Ѵјϐ[Xq~~[X~~~[X >Ϗ[XpBp>>ϱ[Xq~~[X,/,/ϱޖ% /Ϯϐ[Xq~~[Xѥєј?Ϗ 4> ? ϐ[X >8ϐѥєј?ϱϐϮϱϐ 4 ϱϐ[Xq~~[X5Ϗ[XѰѵܓ8 ? ϐ* (.ؘ5>Ϗ[X58 ,ϐ[Xq~~[X"">7ϖ[Xѥєј ?5Ϗ[X7?/ϐ[XϏ ϐ?$5Ϗ[XѰѶ7>[X8ϐy~[X[X[X[Xq~~~[X~~~~~~~~~~~~[Xy~[Xϗϗ[X~~~~~~~~~~~~~~~~~~~~~[X~~ϩϗϗ[X~~~~~~~~~~~~[X~~~~~~~~~~[X~~~~~~~~~~[X~~~~~~~[X"6ٿϗϗ? (7;4ϗ[X (>ؽ*ϗϗ[Xљϩ/ϗ[Xљϩ؟ϗ? ܱ Ϗ[X~~~~~~~~~~~~~~~~[X~~~[X[XљϩIϗ[X? ;ϗϗ[X~~~[X~~~[X~~~~~~~~~[X~~~~~~~~[X~~~~~~~[X~~~~~~~[X~~~~~~~[X[X[X[Xq~~[Xq~[Xq~[Xq~[X[X[X[Xq~~~[X~~~[X{~{~[X~~~~~~~~[X~~~~~~~[X~~~~~~~[X~~~~~~~[X~~~~~~~[XN~~~~~~~~~~~~[X~~~~~~~~~~~~[X~~~~~[X ϗ~~~~~~[X~~~~~~~~~~~~[X~~~~~~[X~~~07;ϱ[X 4ϱ06? .Ϗ[X +Ѱѵ4Ϗ[Xљϩ>ܓ.ϖ~~[X ϱ[Xܱϱ[X~~~~~~~~~~~~~[X[Xq~~[Xy~~~ϗ~~~~[X~~~~~~~~~~~~~[X~~[X? .љϩIϖ 4ϐ[XљϩϐјϩϩёѦϐ[Xّ 5ܿ[X8 ϐ~~ 846ߝٚ;ϐ[X;27ٚϐ~~~. 5Ϗ[X +Ѱѵ4[Xљϩ>ܓ .ϱ[X~[X[Xq~[X~~[X5ϖ? ϩѦѬϩϏ[X"??7;4ϐ[XѤљ[X>4ϖ~~y~~~~~[X~~~~~~~~~~~~ϩѦѬϩn> ϐ[X~~~~~~Ѥљn>A4 ϐ~~[X~~~~~~~~~~~~~[X[Xq~~[X~~[XϏ ϖّ; 5Ϗ[X.ϐ~~~~[X~~~~~~~~~~~~~[X[X[X[X[Xq~~~[X[X~~~[X~~[X~~5ϖк|њϩѤϩ[X? ϐ* љϩ>ܓّϖ~~[X~~~[XϏ ϱܱϱ[X[Xq~~[Xy~~~ϗ[X? .љϩIϖ 4ϐ[XљϩϐјϩϩёѦϐ[Xّ 5ܿ[X8 ϐ~~ 846ߝٚ;ϐ[X;27ٚϐ~~~. 5Ϗ[X +Ѱѵ4[Xљϩ>ܓ .ϱ[X~[X[Xq~[X~~[X?ϖ? ϩѦѬϩϏ[X"??7;4ϐ[XѤљ[X>4ϖ~~y~~~~~[X~~~~~~~~~~~~ϩѦѬϩn> ϐ[X~~~~~~Ѥљn>A4 ϐ~~[X[Xq~~[X~~[XϏ ϖّ; 5Ϗ[X.ϐ[X[Xq~~[X~~+?޺"4ϐ[Xљϩ8 ϐ[X[X \ No newline at end of file diff --git a/game_japanese/data/Stage/CurlyS.pxe b/game_japanese/data/Stage/CurlyS.pxe new file mode 100644 index 0000000..12a9956 Binary files /dev/null and b/game_japanese/data/Stage/CurlyS.pxe differ diff --git a/game_japanese/data/Stage/CurlyS.pxm b/game_japanese/data/Stage/CurlyS.pxm new file mode 100644 index 0000000..fb4c33b Binary files /dev/null and b/game_japanese/data/Stage/CurlyS.pxm differ diff --git a/game_japanese/data/Stage/CurlyS.tsc b/game_japanese/data/Stage/CurlyS.tsc new file mode 100644 index 0000000..143259e --- /dev/null +++ b/game_japanese/data/Stage/CurlyS.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}````lvqy````lu~t=:S``ia=:l}~qls}````lvqy```alu~t=:S``ib=:l}~qls}````lvqy```blu~t=:S``ic=:l}~qls}````lvqy```clu~t=:S``id=:l}~qls}````lvqy```dlu~t=:=:S`a``=:lyl``aalt~`a``lvq```dlq``bij``idj```fj```i=:=:=:S`d``=:l{ul`a`el}wñyl~tlv|z`efdj`d`alu~t=:S`d`a=:lyz``adj0da`ls|qҲ۲ ٱxl~z````ls|=:ls~`d``j`acfj````lv|[`eh`lwya`adly[``admҲmP ,rl~tls|=:lv|[c```lv|]c``alv|]c``blv|]c``clv|]c``d=:lv|[`bgdlu~t=:S`da`=:lyl}wsͲrl~tlu~t=:=:S`db`=:l{ult~`db`l}wlwya`cely[``ce=:mzómP ٲ߲rl~tlu~t=:=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Dark.pxe b/game_japanese/data/Stage/Dark.pxe new file mode 100644 index 0000000..ae9cadb Binary files /dev/null and b/game_japanese/data/Stage/Dark.pxe differ diff --git a/game_japanese/data/Stage/Dark.pxm b/game_japanese/data/Stage/Dark.pxm new file mode 100644 index 0000000..2e82562 Binary files /dev/null and b/game_japanese/data/Stage/Dark.pxm differ diff --git a/game_japanese/data/Stage/Dark.tsc b/game_japanese/data/Stage/Dark.tsc new file mode 100644 index 0000000..9b1fa2d --- /dev/null +++ b/game_japanese/data/Stage/Dark.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}````lvqy````lu~t=:S``ia=:l}~qls}````lvqy```alu~t=:S``ib=:l}~qls}````lvqy```blu~t=:S``ic=:l}~qls}````lvqy```clu~t=:S``id=:l}~qls}````lvqy```dlu~t=:=:S`a``=:lylvq```dlq``a`j``idj``gcj``bg=:=:S`d``=:lyl}wl`a`el`a0el`a`eñyl~tlyz``adj`da`ls|qҲ۲ ٱxl~z````ls|=:ls~`d``j`acfj````lv|[`fa`lwya`adly[``admҲmP ,rl~tlv|[`bgdls|=:lv|]c```lv|]c``alv|[c``blv|]c``clv|]c``d=:lu~t=:S`da`=:lyl}wsͲrl~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Drain.pxe b/game_japanese/data/Stage/Drain.pxe new file mode 100644 index 0000000..89e445b Binary files /dev/null and b/game_japanese/data/Stage/Drain.pxe differ diff --git a/game_japanese/data/Stage/Drain.pxm b/game_japanese/data/Stage/Drain.pxm new file mode 100644 index 0000000..8958a07 Binary files /dev/null and b/game_japanese/data/Stage/Drain.pxm differ diff --git a/game_japanese/data/Stage/Drain.tsc b/game_japanese/data/Stage/Drain.tsc new file mode 100644 index 0000000..07c9fbb --- /dev/null +++ b/game_japanese/data/Stage/Drain.tsc @@ -0,0 +1 @@ +]Zs]Z]Zs]Z]Zs]Z]Zs]Z]Zs]Z]Z]Zs]Z]Z]Zs]Z]Zs]Zښђ]Z]Zs]Z]Z]Zs]Z7:9 9ђ]Z:: ђ]Zs]Z]Z]Z]Zs]ZP]Z]Z]Z]Z,7ѳ]Z]Z]Z]Z:=ђ]Z.=ђ]Z]Z]Z]Z]Z{]Z]Zs]Z]Zs]ZӮ9ђ ђ]Z]Z]Z]Z]Z]Z]Z]Z]Z \ No newline at end of file diff --git a/game_japanese/data/Stage/EgEnd1.pxe b/game_japanese/data/Stage/EgEnd1.pxe new file mode 100644 index 0000000..1eb67ab Binary files /dev/null and b/game_japanese/data/Stage/EgEnd1.pxe differ diff --git a/game_japanese/data/Stage/EgEnd1.pxm b/game_japanese/data/Stage/EgEnd1.pxm new file mode 100644 index 0000000..fc1dad5 Binary files /dev/null and b/game_japanese/data/Stage/EgEnd1.pxm differ diff --git a/game_japanese/data/Stage/EgEnd1.tsc b/game_japanese/data/Stage/EgEnd1.tsc new file mode 100644 index 0000000..f196b79 --- /dev/null +++ b/game_japanese/data/Stage/EgEnd1.tsc @@ -0,0 +1 @@ +PMfss|sPMssssssssPMfss|tPMssssssstPMfss|uPMsssssssuPMfss|vPMCsssssssvPMfss|wPMssssssswPMPMfstssPMssswsssu}ss|w}su|z}sss{PMPMPMfswssPMPM \ No newline at end of file diff --git a/game_japanese/data/Stage/EgEnd2.pxe b/game_japanese/data/Stage/EgEnd2.pxe new file mode 100644 index 0000000..1eb67ab Binary files /dev/null and b/game_japanese/data/Stage/EgEnd2.pxe differ diff --git a/game_japanese/data/Stage/EgEnd2.pxm b/game_japanese/data/Stage/EgEnd2.pxm new file mode 100644 index 0000000..fc1dad5 Binary files /dev/null and b/game_japanese/data/Stage/EgEnd2.pxm differ diff --git a/game_japanese/data/Stage/EgEnd2.tsc b/game_japanese/data/Stage/EgEnd2.tsc new file mode 100644 index 0000000..c6570d7 --- /dev/null +++ b/game_japanese/data/Stage/EgEnd2.tsc @@ -0,0 +1 @@ +PMfss|sPMssssssssPMfss|tPMssssssstPMfss|uPMsssssssuPMfss|vPMCsssssssvPMfss|wPMssssssswPMPMfstssPMssswssw|}ss|w}su|y}sss{PMPMPMfswssPMPM \ No newline at end of file diff --git a/game_japanese/data/Stage/Egg1.pxe b/game_japanese/data/Stage/Egg1.pxe new file mode 100644 index 0000000..e8969fb Binary files /dev/null and b/game_japanese/data/Stage/Egg1.pxe differ diff --git a/game_japanese/data/Stage/Egg1.pxm b/game_japanese/data/Stage/Egg1.pxm new file mode 100644 index 0000000..3195bb8 Binary files /dev/null and b/game_japanese/data/Stage/Egg1.pxm differ diff --git a/game_japanese/data/Stage/Egg1.tsc b/game_japanese/data/Stage/Egg1.tsc new file mode 100644 index 0000000..3220c73 --- /dev/null +++ b/game_japanese/data/Stage/Egg1.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}````lvqy````lu~t=:S``ia=:l}~qls}````lvqy```alu~t=:S``ib=:l}~qls}````lvqy```blu~t=:S``ic=:l}~qls}````lvqy```clu~t=:S``id=:l}~qls}````lvqy```dlu~t=:=:S`a``=:lylvq```dlq```bj``idj`beij``aa=:=:S`b``=:l{ulv|z`dg`j`b`blyz`0`gj`b`all}w ̲=:ytz{Ǧrl~tlu~t=:S`b`a=:l{ulv|[`dg`l}wlwya``gmytzmP β!rl~tlwy````ls|=:l``dc ̲ rl~tlu~t=:S`b`b=:l{ul}wl ̲Ҳ rl~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Egg6.pxe b/game_japanese/data/Stage/Egg6.pxe new file mode 100644 index 0000000..38b8916 Binary files /dev/null and b/game_japanese/data/Stage/Egg6.pxe differ diff --git a/game_japanese/data/Stage/Egg6.pxm b/game_japanese/data/Stage/Egg6.pxm new file mode 100644 index 0000000..3195bb8 Binary files /dev/null and b/game_japanese/data/Stage/Egg6.pxm differ diff --git a/game_japanese/data/Stage/Egg6.tsc b/game_japanese/data/Stage/Egg6.tsc new file mode 100644 index 0000000..bf4a0a1 --- /dev/null +++ b/game_japanese/data/Stage/Egg6.tsc @@ -0,0 +1 @@ +IF_llulIFx}xllllx}llllxIF_llumIFx}xllllx}lllmxIF_llunIFx}xllllx}lllnxIF_lluoIFx}xllllx}llloxIF_llupIFx}xllllx}lllpxIFIF_lmllIFxx}lllp<}lllnvllupvlmsuvllmlIFIF_lnllIFxxlmplvlllmxglmplxllnnxlnllvllnmvllllIFx/ܾ,Ɔ~xxmllsxglllsxIFxllmlyy\,$8&~x}lmrlxxxIFIF \ No newline at end of file diff --git a/game_japanese/data/Stage/EggIn.pxa b/game_japanese/data/Stage/EggIn.pxa new file mode 100644 index 0000000..e3f5673 Binary files /dev/null and b/game_japanese/data/Stage/EggIn.pxa differ diff --git a/game_japanese/data/Stage/EggR.pxe b/game_japanese/data/Stage/EggR.pxe new file mode 100644 index 0000000..02765f1 Binary files /dev/null and b/game_japanese/data/Stage/EggR.pxe differ diff --git a/game_japanese/data/Stage/EggR.pxm b/game_japanese/data/Stage/EggR.pxm new file mode 100644 index 0000000..bd58185 Binary files /dev/null and b/game_japanese/data/Stage/EggR.pxm differ diff --git a/game_japanese/data/Stage/EggR.tsc b/game_japanese/data/Stage/EggR.tsc new file mode 100644 index 0000000..d0c1755 Binary files /dev/null and b/game_japanese/data/Stage/EggR.tsc differ diff --git a/game_japanese/data/Stage/EggR2.pxe b/game_japanese/data/Stage/EggR2.pxe new file mode 100644 index 0000000..f463640 Binary files /dev/null and b/game_japanese/data/Stage/EggR2.pxe differ diff --git a/game_japanese/data/Stage/EggR2.pxm b/game_japanese/data/Stage/EggR2.pxm new file mode 100644 index 0000000..df704ac Binary files /dev/null and b/game_japanese/data/Stage/EggR2.pxm differ diff --git a/game_japanese/data/Stage/EggR2.tsc b/game_japanese/data/Stage/EggR2.tsc new file mode 100644 index 0000000..ed57122 --- /dev/null +++ b/game_japanese/data/Stage/EggR2.tsc @@ -0,0 +1 @@ +\Yr\Y\Yr\Y\Yr\Y\Yr\Y\Yr\Y\Y\Yr\Y\Y\Yr\Y\Y\Yr\Y޾69ИИ\Y\Yr\Y\Y\Y\Y\Y\Yr\YzO\YB?ٙ Б\Y\Yr\Y\Y\YݔڒЗz\Y\Yr\Y\Y\YҥҧҭЪҨ? Б\Y\Y|\Y\Y \ No newline at end of file diff --git a/game_japanese/data/Stage/EggX.pxa b/game_japanese/data/Stage/EggX.pxa new file mode 100644 index 0000000..89f9149 Binary files /dev/null and b/game_japanese/data/Stage/EggX.pxa differ diff --git a/game_japanese/data/Stage/EggX.pxe b/game_japanese/data/Stage/EggX.pxe new file mode 100644 index 0000000..2f48e79 Binary files /dev/null and b/game_japanese/data/Stage/EggX.pxe differ diff --git a/game_japanese/data/Stage/EggX.pxm b/game_japanese/data/Stage/EggX.pxm new file mode 100644 index 0000000..2d1c499 Binary files /dev/null and b/game_japanese/data/Stage/EggX.pxm differ diff --git a/game_japanese/data/Stage/EggX.tsc b/game_japanese/data/Stage/EggX.tsc new file mode 100644 index 0000000..19961ce --- /dev/null +++ b/game_japanese/data/Stage/EggX.tsc @@ -0,0 +1,4 @@ +;8Q^^g^;8j{|ojq{^^_bjtow^^^^js|r;8Q^^g_;8j{|ojq{^^_bjtow^^^_js|r;8Q^^g`;8j{|ojq{^^_bjtow^^^`js|r;8Q^^ga;8j{|ojq{^^_bjtow^^^ajs|r;8Q^^gb;8jtzx^_`^h^^gcjo|~^`^^h^^_^h^^^`jss^^gc;8Q^^gc;8j{|ojq{^^_bjtow^^^bjs|r;8;8Q^_^^;8j~wj}^^__jr|~^_^^jto}^^^bjo^^^`h^^gbh^`g_h^^^f;8;8Q^__^;8jysj{uŰؾٻ̰۰j|}rjs|r;8;8;8Q^`^^;8jtzx^_`^h^`_^;8jys;8jtzY^_`^jtzY^_^cjtzY^_cbjtzY^_ccjtzY^a`gjtzY^_^d;8j{upj|}rjqz};8j{p^^^`jow^^c^j{r^^^`;8j{u;8аj|}rjo|~^`^^h^^__h^^^`jqzjtoq^^^aְְw;8 +÷ݰаwwj|}r;8ĩqװwwj|}rjtoq^^^^jqz};8jow^^c^jo|~^`^^h^^^^h^^^`;8j{ujtoq^^^_ΰvjow^^c^j|}r;8o~Ѱjo|~^`^^h^^^^h^^^^j|}rjqzssspj|}r;8ΰؽðݰ۰vj|x^`^`jss^`^_;8Q^`^_;8jtoq^^^aݰа߰аwwj|}rjqzΰ𼲶;8װװwwj|}r;8ְ߰߰;8ǰЯwwj|}rjtoq^^^^jqz}jss^`^a;8Q^`^`;8jtoq^^^`ssspj|}rjqz +ΰааpj|}rjtoq^^^^jqz}jss^`^a;8Q^`^a;8jow^^c^j{ujo|~^`^^h^^^ch^^^`jtoq^^^_ίwj|}rj{r^^^ajqz;8߰װN|.^^Nwj|}rjqz߰ſذΰ;8߰װsٰwj|}rjqz}jtoq^^^^j{r^^^`;8jo|~^`^^h^^^ah^^^`jow^^a^;8jo|~^`^^h^^^ch^^^`jow^^c^;8j{ujtoq^^^_ſ!wj|}r;8Ұwj|}rjqz}jow^^c^j}^^bajow^^`^jtoq^^^^;8j{ujtoq^^^`oj|}rvj|}rjtoq^^^^jqz};8jow^^c^;8jo|~^`^^h^^^^h^^^^jow^^c^;8j{ujtoq^^^_߰ſװ԰o;8yŤ Яpj|}rjqz;8jtoq^^^`ίίpj|}rjqzֺ԰а;8װͯpj|}rjqzssspj|}rjqz;8jtoq^^^_)Яoٰΰްpj|}rjqz};8jo|~^`^^h^^^ah^^^^jow^_`d;8jo|~^`^^h^^^^h^^^`jow^^`^;8j{u|o߰j{r^^^^vj|}rjqzΰҰpj|}r;8ĆȰ;8߰Ţаpj|}rjqz;8װvj|}rjqzааpj|}r;8ΰްpj|}r;8߰װspj|}r;8װpj|}rjqz};8jo|~^`^^h^^^ch^^^`jow^^`^;8j}^^__jo|~^_^^h^^^^h^^^`jow^^`^;8jo|~^_^^h^^^^h^^^^jr|~^`^^j}^^`ajs|r;8;8Q^a^^;8jysj{uj ſN|\^^;8ɨ#ذٰа +j|}rjqz*۰j|}rjs|r;8Q^a^^;8j~wjto}^^^bjo^^^_h^^gbh^^^ch^^^e;8;8;8Q^b^^;8;8 \ No newline at end of file diff --git a/game_japanese/data/Stage/EggX2.pxe b/game_japanese/data/Stage/EggX2.pxe new file mode 100644 index 0000000..9de156b Binary files /dev/null and b/game_japanese/data/Stage/EggX2.pxe differ diff --git a/game_japanese/data/Stage/EggX2.pxm b/game_japanese/data/Stage/EggX2.pxm new file mode 100644 index 0000000..a76ec5e Binary files /dev/null and b/game_japanese/data/Stage/EggX2.pxm differ diff --git a/game_japanese/data/Stage/EggX2.tsc b/game_japanese/data/Stage/EggX2.tsc new file mode 100644 index 0000000..270052b Binary files /dev/null and b/game_japanese/data/Stage/EggX2.tsc differ diff --git a/game_japanese/data/Stage/Eggs.pxa b/game_japanese/data/Stage/Eggs.pxa new file mode 100644 index 0000000..8b3c8f6 Binary files /dev/null and b/game_japanese/data/Stage/Eggs.pxa differ diff --git a/game_japanese/data/Stage/Eggs.pxe b/game_japanese/data/Stage/Eggs.pxe new file mode 100644 index 0000000..f081cc3 Binary files /dev/null and b/game_japanese/data/Stage/Eggs.pxe differ diff --git a/game_japanese/data/Stage/Eggs.pxm b/game_japanese/data/Stage/Eggs.pxm new file mode 100644 index 0000000..a3ab7fa Binary files /dev/null and b/game_japanese/data/Stage/Eggs.pxm differ diff --git a/game_japanese/data/Stage/Eggs.tsc b/game_japanese/data/Stage/Eggs.tsc new file mode 100644 index 0000000..47d90f3 --- /dev/null +++ b/game_japanese/data/Stage/Eggs.tsc @@ -0,0 +1 @@ + !$56)$+5=$.)1$-6, !$56)$+5=$.)1$-6, !$56)$+5=$.)1$-6, !$56)$+5=$.)1$-6, !$.42"!$56)$+5=$.)1$-6, !$56)$)68""$+5=$.)1$-6, !!$3-A$56)$+5=$)68""$.)1$+68""$?)1$)68""$5A,$,68$;5+$-6, $8:1$5;/k)iCkýŽӎı3 k?B>IýŽG2lFŎ<2Jh#E#j +UýŽЎʱѱʱ<k+ ,M +U*ɽŽıЎʱѱȽı<%F8ýŽӽıT_Ž {SN6E#I*B>+ "I +U?IŽӽıŎ6JXE^]8*ɽŽӽı#cc`E).ýŽӎýŽ<%?IŎF<%*ýŽӽı*62]i]6>ýŽıЎѱʱѱʱ/ʽʱŽӽѱıýŽ22NɽŽıЎʱѱȽı%!ʽŽıЎѱѱʱѱѱѱȽı)BGýŎH2J. ɽŽϱӽı ýŎ<#CJ +UqX4:IýŽӽıѱif%*#ýŽıЎѱʱѱʱȽıc`F&ʽŽӎı''ýŽӎֱıc`lʽŽЎϱʱֱѱѱʱűѱʱѱʱѱʱѱʱȽıfe*ʽŽӽıɽŽ%%%Ŏ!>]+ŽӽıʽŽʽŽϱ)+?I ʽŽıЎʱȽıýŽ#*JaýŎNýŎM6#2S?ýŽ2k*ha ýŎG2lF<M F +>*8jM*IɽŎŽӽıU@6EcjʽŽıЎѱʱѱʱѱѱʱѱϱ±ֱʱȽı & +<6I0kO2rIJd#M*ŽнʱĽʱ))ʽŎ NdM;?IʽŽϱѱ##G2lJ >LýŎ2#Chq Jcl%ʽŽI!JÎhJN)gOr4ýŎ:#;# +C %+BE.kýŽнѱʱֱѱͱαŎŎڽͬ±±ϱѱʱֱȎ 7 +<q6>ýʱŽЎѱʱαŎ˱˱ʽŽŎڽͬȽıŽ +5Na%K[?ýŎ GBE.kL&*ɽŽЎѱñʱŎڽͮѱάȽձֱ 龡qiJ}k>ýʱŽֽŎ \ No newline at end of file diff --git a/game_japanese/data/Stage/Hell.pxa b/game_japanese/data/Stage/Hell.pxa new file mode 100644 index 0000000..8ab7b2e Binary files /dev/null and b/game_japanese/data/Stage/Hell.pxa differ diff --git a/game_japanese/data/Stage/Hell1.pxe b/game_japanese/data/Stage/Hell1.pxe new file mode 100644 index 0000000..acdd610 Binary files /dev/null and b/game_japanese/data/Stage/Hell1.pxe differ diff --git a/game_japanese/data/Stage/Hell1.pxm b/game_japanese/data/Stage/Hell1.pxm new file mode 100644 index 0000000..3b31311 Binary files /dev/null and b/game_japanese/data/Stage/Hell1.pxm differ diff --git a/game_japanese/data/Stage/Hell1.tsc b/game_japanese/data/Stage/Hell1.tsc new file mode 100644 index 0000000..4295a7d Binary files /dev/null and b/game_japanese/data/Stage/Hell1.tsc differ diff --git a/game_japanese/data/Stage/Hell2.pxe b/game_japanese/data/Stage/Hell2.pxe new file mode 100644 index 0000000..a27137b Binary files /dev/null and b/game_japanese/data/Stage/Hell2.pxe differ diff --git a/game_japanese/data/Stage/Hell2.pxm b/game_japanese/data/Stage/Hell2.pxm new file mode 100644 index 0000000..4c25708 Binary files /dev/null and b/game_japanese/data/Stage/Hell2.pxm differ diff --git a/game_japanese/data/Stage/Hell2.tsc b/game_japanese/data/Stage/Hell2.tsc new file mode 100644 index 0000000..427fcb1 Binary files /dev/null and b/game_japanese/data/Stage/Hell2.tsc differ diff --git a/game_japanese/data/Stage/Hell3.pxe b/game_japanese/data/Stage/Hell3.pxe new file mode 100644 index 0000000..5cbdd52 Binary files /dev/null and b/game_japanese/data/Stage/Hell3.pxe differ diff --git a/game_japanese/data/Stage/Hell3.pxm b/game_japanese/data/Stage/Hell3.pxm new file mode 100644 index 0000000..a0cb2a3 Binary files /dev/null and b/game_japanese/data/Stage/Hell3.pxm differ diff --git a/game_japanese/data/Stage/Hell3.tsc b/game_japanese/data/Stage/Hell3.tsc new file mode 100644 index 0000000..5e95ec7 Binary files /dev/null and b/game_japanese/data/Stage/Hell3.tsc differ diff --git a/game_japanese/data/Stage/Hell4.pxe b/game_japanese/data/Stage/Hell4.pxe new file mode 100644 index 0000000..22bb347 Binary files /dev/null and b/game_japanese/data/Stage/Hell4.pxe differ diff --git a/game_japanese/data/Stage/Hell4.pxm b/game_japanese/data/Stage/Hell4.pxm new file mode 100644 index 0000000..8f89450 Binary files /dev/null and b/game_japanese/data/Stage/Hell4.pxm differ diff --git a/game_japanese/data/Stage/Hell4.tsc b/game_japanese/data/Stage/Hell4.tsc new file mode 100644 index 0000000..3ea1d01 --- /dev/null +++ b/game_japanese/data/Stage/Hell4.tsc @@ -0,0 +1 @@ +OLerr{rOL~~rtrr|rrrs~rrrr~OLerr{sOL~~rtrr|rrrs~rrrs~OLerr{tOL~~rtrr|rrrs~rrrt~OLerr{uOL~~rtrr|rrrs~rrru~OLerr{vOL~~rtrr|rrrs~rrrv~OLOLOLerr{wOL~~rrrt~rtrr|rrrs~Brrtr~rrru~OLOLOLersrrOL~~rrrs~rrsx~rrzt|rr{x|rrrz|rrsvOLOLerssrOL~~rrrr~rrsx~rrwx|rr{r|rssz|rrxtOLOLerstrOL~~rrss~rstr|rrrr|rrrtOL~rrrt~rrsx~rrzx|rr{t|rrrt|rrsrOLOLOLOLertrrOLOLOL \ No newline at end of file diff --git a/game_japanese/data/Stage/Hell42.pxe b/game_japanese/data/Stage/Hell42.pxe new file mode 100644 index 0000000..347f004 Binary files /dev/null and b/game_japanese/data/Stage/Hell42.pxe differ diff --git a/game_japanese/data/Stage/Hell42.pxm b/game_japanese/data/Stage/Hell42.pxm new file mode 100644 index 0000000..8f89450 Binary files /dev/null and b/game_japanese/data/Stage/Hell42.pxm differ diff --git a/game_japanese/data/Stage/Hell42.tsc b/game_japanese/data/Stage/Hell42.tsc new file mode 100644 index 0000000..08257f0 --- /dev/null +++ b/game_japanese/data/Stage/Hell42.tsc @@ -0,0 +1,2 @@ +-::C:FWXKFMW_::::FPYX:<::D:::;FaKS:::FWXKFMW_::::FPYX:<::D:::;FaKS:::FOXN-::C?FUOcFRWMFaKS:::D::::FMWZ:::CD::<>D::::FMWZ::;:D::<>D::::FMWZ::;;D::<>D::::FMWZ::;D::::FaKS:::@F]Y_::;<FMWZ:::BD::<@D::::FMWZ:::CD::<@D::::FMWZ::;:D::<@D::::FMWZ::;;D::<@D::::FMWZ::;D::::FMWZ:::CD::<>D::::FMWZ::;:D::<>D::::FMWZ::;;D::<>D::::FMWZ::;D::::FMWZ:::BD::<@D::::FMWZ:::CD::<@D::::FMWZ::;:D::<@D::::FMWZ::;;D::<@D::::FMWZ::;-:;;:FZ\SFW]QTҌLFXYNFOXN-:;<:FUOcF]Y_::;;FKXZ:;<:D::::D:::<FPKY:::-:<::-:=::FZ\SFPKY:::FUOcFPVT;:::D::C?FWXKFMW_:::BFPKS:::>FO`O:<::-::C?FWXKFMW_:::BFPKS:::>FOXN-:;::FUOcF]Y_::;;FKXZ:;::D::::D:::F^\K::?=D::C>D::A?D:::?-:;;:FUOcF]Y_::;;FKXZ:;;:D::::D:::::D::;:D::::FW]QSSFXYNFMVYFKXZ:>::D::<:D::::FaKS::?:FOXN-:>::FUOcFPVT;::=D:>:>FPVT;;::=FPVT;:::<FPVT;::;D:>:;FPV5;::;FPV5;:=BFKXZ:>::D::;:D::::FW]QڌSSFWcL:::::D::::D::::FPKM:::;FUOcFPV5;::<FW]QFPKM:::<FUOcFW]QFPKM:::=FUOcFW]QFPV5;::=FPKM:::>-:>:>FUOcFW]QFPKM::FWXKFMW_:::FOXN-:;::FUOcF]Y_::;;FKXZ:;::D::::D:::;Taaja>;m~rmt~aaaimwrzaaaamvu>;Taajb>;m~rmt~aaaimwrzaaabmvu>;Taajc>;m~rmt~aaaimwrzaaacmvu>;Taajd>;m~rmt~aaaimwrzaaadmvu>;Taaje>;m~rmt~aaaimwrzaaaemvu>;>;>;>;>;Tabaa>;m|vmaabbmrabaakaaaakaaacmwraaaemraadjkaajekaaddkaaaj>;>;>;Tacaa>;mzm~xsmumt}dzȳ۳ĸ"smu>;dzȳ۳񼬳!"smu>;ǝ|vs!ϳsmumvu>;Tacba>;mzm~x񼬳,ѳsmu>;,y>;ܳ۳ӳӳsmumt}!ڳr>;,ڳճڲmumvu>;Tacca>;mzmw}{bacakaccbm~xѳв|#ӳֲmumt}ĴIJmumt}ѳ"޳>;|}ӳ۳smumvu>;Taccb>;mzm~xmumt}>;ѳ"óӴsmumvu>;Tacda>;mzm~x>;ĸѳڲymumt}ĸ$÷Ƴڳ"ӳ"smu>;ճ$÷Ƴڳ"ӳڲmu>;س񼬳ѳ"smumvu>;Tacea>;mzmw}{ahcakaceb>;m~xѳĎærmu>;€ ߳ӳӳ"smu>; ߳ӳr>;Ď񼬳÷"mumvu>;Taceb>;m~xĎæ߳smumt}>;ճ꾤񼬳÷"ymumvu>;>;>;Tadaa>;Tadab>;m|vm~rmt~aaai>;mradbakaaabkaaaamwrzaaae>;mtadabkabbckaaaamrzabaa>;mradbakaaaakaaaa>;m~uaaaamuadabm~tmvu>;Tadba>;m|vmw}{ahcakadbb>;m|vm~xĎæsmumt}ĕ-ӳӲsmumvu>;Tadbb>;mtadaakabbbkaaacmy~tmrzaagamrad1akaaabkaaaa>;mrzabaamwraaaemraaefkadabkaaackaafd>;>;>;Taeaa>;m|vmw}{ahcbkaebam~xٳղsmumt}񼬳ĉsmu>;ŀ۳uǐ-smu>;ŵճ„ƒ׳"smu>; "mumt}mr~{aaackaeabmr~{aabdkaeaemvvaeac>;Taeab>;m|vm~x>;"ymumt}€ӳӳγsmumt}>;qtr׳ڲsmumt}ڳ޳׳ڲym{aeadmt}>;mr~^aaad>;mrzaacam~xmxzaaac!ğsmu>;mxzaaadqtr!ğsmumxzaaaamt}>;maaee"zzmumt}mw}\ahcbmxzaaabmt}>;mr~aaackaaabkaaaamt~aabannQۻݳzmrzabgamum~mvu>;Taeac>;m|vmw}\ahcbm~xѲsmumt}s!ղsmumt}mxzbacamt}>;mt~aabamz\aacamv\aaainnQ!smrzabgamum~mxzaaaamt}ӳӳsmu>;ճγӳ"ymumvu>;Taead>;m|vm~xmt}(smumvu>;Taeae>;m|vmw}\ahcbm~xѲsmumt}s!ղsmumt}mxzbadimt}>;mt~aabamz\aadint ߳nQ!smrzabgamv\abcimw}\ahccmum~mxzaaaamt} вr{'ĩij۲rmu>;޳!- >;€smumvu>;Taeba>;m|vm~x!ϳr>;wĴ{dzȳsmumt}smu>;۽ʳ>;ӳsmu>;񼬳ӳr>;񼬳ѳڳ!"smumt}׳۳޳>;!"NJ ۳вzmumvu>;>; \ No newline at end of file diff --git a/game_japanese/data/Stage/MazeB.pxe b/game_japanese/data/Stage/MazeB.pxe new file mode 100644 index 0000000..6d6d0e4 Binary files /dev/null and b/game_japanese/data/Stage/MazeB.pxe differ diff --git a/game_japanese/data/Stage/MazeB.pxm b/game_japanese/data/Stage/MazeB.pxm new file mode 100644 index 0000000..a583e7e Binary files /dev/null and b/game_japanese/data/Stage/MazeB.pxm differ diff --git a/game_japanese/data/Stage/MazeB.tsc b/game_japanese/data/Stage/MazeB.tsc new file mode 100644 index 0000000..64502c8 Binary files /dev/null and b/game_japanese/data/Stage/MazeB.tsc differ diff --git a/game_japanese/data/Stage/MazeD.pxe b/game_japanese/data/Stage/MazeD.pxe new file mode 100644 index 0000000..e25a888 Binary files /dev/null and b/game_japanese/data/Stage/MazeD.pxe differ diff --git a/game_japanese/data/Stage/MazeD.pxm b/game_japanese/data/Stage/MazeD.pxm new file mode 100644 index 0000000..f22c930 Binary files /dev/null and b/game_japanese/data/Stage/MazeD.pxm differ diff --git a/game_japanese/data/Stage/MazeD.tsc b/game_japanese/data/Stage/MazeD.tsc new file mode 100644 index 0000000..cfbd0e4 --- /dev/null +++ b/game_japanese/data/Stage/MazeD.tsc @@ -0,0 +1 @@ +þײ˲Əþײ˲Əþײ˲Əþײ˲Əþײ˲Ə۾̲ײҲѲƲò˾ +J$˾ƾƽ˾̲έέײҲu"r 1?ľƾԾֳײԏɾ֭trjK~l?˲ƾяֲ׾ײҲβƏҲײίƏ \ No newline at end of file diff --git a/game_japanese/data/Stage/MazeH.pxe b/game_japanese/data/Stage/MazeH.pxe new file mode 100644 index 0000000..ada7142 Binary files /dev/null and b/game_japanese/data/Stage/MazeH.pxe differ diff --git a/game_japanese/data/Stage/MazeH.pxm b/game_japanese/data/Stage/MazeH.pxm new file mode 100644 index 0000000..ed87e49 Binary files /dev/null and b/game_japanese/data/Stage/MazeH.pxm differ diff --git a/game_japanese/data/Stage/MazeH.tsc b/game_japanese/data/Stage/MazeH.tsc new file mode 100644 index 0000000..77a3f1e --- /dev/null +++ b/game_japanese/data/Stage/MazeH.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ailvqy````lu~t=:S``ia=:l}~qls}``ailvqy```alu~t=:S``ib=:l}~qls}``ailvqy```blu~t=:S``ic=:l}~qls}``ailvqy```clu~t=:S``id=:l}~qls}``ailvqy`0`dlu~t=:=:S`a``=:lylvq```blq```ij``ibj``abj``fd=:=:S`a`a=:lylvq```alq``cij``iaj```dj``af=:=:S`b``=:lyl}wrl~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/MazeI.pxe b/game_japanese/data/Stage/MazeI.pxe new file mode 100644 index 0000000..d301a2f Binary files /dev/null and b/game_japanese/data/Stage/MazeI.pxe differ diff --git a/game_japanese/data/Stage/MazeI.pxm b/game_japanese/data/Stage/MazeI.pxm new file mode 100644 index 0000000..ec76fcc Binary files /dev/null and b/game_japanese/data/Stage/MazeI.pxm differ diff --git a/game_japanese/data/Stage/MazeI.tsc b/game_japanese/data/Stage/MazeI.tsc new file mode 100644 index 0000000..11977c9 --- /dev/null +++ b/game_japanese/data/Stage/MazeI.tsc @@ -0,0 +1,8 @@ +fc|fcfc|fcfc|fcfc|fcfc|fcfcfc|fcfcfc|fc!ڼfc|fcfc|fc|fcfc|fcfcܜܣܳyIA"UCڢfc>%&yyڢfcfcfcfc|fcڢڢڞڞڞfc#"@C@ڛ + +& +Dڡfcfcfcfc|fc9I5ڡYfcfcfcfcfcfcfcfcfcfcfc|fc9&C5ڛfcfc|fcfcfc|fc9ܮڴ"K' CDڛfcF"ڼfc + +& +%%ܬ8 ڛfcCU!@fcJ@C!ڼfcfc|fcfc|fc +%9%ܱܜܻܹښfc<"B@J $ڛfc!"DC ڛfc9 ښfcLC5ڼfcfc|fc-!ڛfcfcyӾyyyyyyyyfcfc9fcܜܣܳfcfc \ No newline at end of file diff --git a/game_japanese/data/Stage/MazeM.pxe b/game_japanese/data/Stage/MazeM.pxe new file mode 100644 index 0000000..d7eda37 Binary files /dev/null and b/game_japanese/data/Stage/MazeM.pxe differ diff --git a/game_japanese/data/Stage/MazeM.pxm b/game_japanese/data/Stage/MazeM.pxm new file mode 100644 index 0000000..cdda771 Binary files /dev/null and b/game_japanese/data/Stage/MazeM.pxm differ diff --git a/game_japanese/data/Stage/MazeM.tsc b/game_japanese/data/Stage/MazeM.tsc new file mode 100644 index 0000000..db25650 Binary files /dev/null and b/game_japanese/data/Stage/MazeM.tsc differ diff --git a/game_japanese/data/Stage/MazeO.pxe b/game_japanese/data/Stage/MazeO.pxe new file mode 100644 index 0000000..3537a2c Binary files /dev/null and b/game_japanese/data/Stage/MazeO.pxe differ diff --git a/game_japanese/data/Stage/MazeO.pxm b/game_japanese/data/Stage/MazeO.pxm new file mode 100644 index 0000000..61edc26 Binary files /dev/null and b/game_japanese/data/Stage/MazeO.pxm differ diff --git a/game_japanese/data/Stage/MazeO.tsc b/game_japanese/data/Stage/MazeO.tsc new file mode 100644 index 0000000..dffedfc Binary files /dev/null and b/game_japanese/data/Stage/MazeO.tsc differ diff --git a/game_japanese/data/Stage/MazeS.pxe b/game_japanese/data/Stage/MazeS.pxe new file mode 100644 index 0000000..5103bc8 Binary files /dev/null and b/game_japanese/data/Stage/MazeS.pxe differ diff --git a/game_japanese/data/Stage/MazeS.pxm b/game_japanese/data/Stage/MazeS.pxm new file mode 100644 index 0000000..786595f Binary files /dev/null and b/game_japanese/data/Stage/MazeS.pxm differ diff --git a/game_japanese/data/Stage/MazeS.tsc b/game_japanese/data/Stage/MazeS.tsc new file mode 100644 index 0000000..8060f44 --- /dev/null +++ b/game_japanese/data/Stage/MazeS.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}```hlvqy````lu~t=:S``ia=:l}~qls}```hlvqy```alu~t=:S``ib=:l}~qls}```hlv|z`gfaj``ielvqy```blu~t=:S``ic=:l}~qls}```hlvqy```clu~t=:S``id=:l}~qls}```hlvqy```dlu~t=:=:S``ie=:lq~`c``j``b`j````lvqy```blu~t=:=:=:S`a``=:l{ulv|z`gfcj`a`a=:l``aalq~`a``j````j```blvq````l}t````lq``dcj``i`j``afj``ac=:S`a`a=:lyl}wzٲұyl~tlu~t=:=:S`aa`=:lv|z`gfdj`aaalu~t=:S`aaa=:l{ulvq```dl}t```blq``dej``ibj```bj```e=:=:=:=:S`b``=:lylv|z`b`aj`b`al}w$ҲںٲҲzٲұl~tlu~t=:S`b`a=:lv|z`gffj```alv|[`gfflv|]`gfelv|[`b`b=:l``bbls~`b``j``baj````=:l}w#в z߲rl~tls|lq}```ej``a`j````=:ls}``a`lwy``a`msmPPqyylqy`af`l~tl}lu~t=:=:S`c``=:l{u=:lv|z`gfdj`c`c=:lv|z`gfbj`c`b=:lv|z`gfaj`c`a=:lv|[`gfal}wlvqs``aiǸrl~t=:rl~tls| ߲q=:+߲rl~tls|=:߲l~tls|Բq=:ƲزqҲrl~t=:rl~tls|!q=:ٲ rl~t=: Ͳrl~tls|=:lq~`c``j``b`j````lu~t=:S`c`a=:l{ulq~`c``j````j````=:l}wlvqs``aiԲxl~t=:ٲŬݲxl~tls|!Ҳձrl~t=:бq Ͳrl~tlq~`c``j``b`j````lu~t=:S`c`b=:lyl}ws Ҳrl~tlu~t=:S`c`c=:lyl}wlvqs``aiϱyl~tls|=:ҲƲزqyyl~tlu~t=:=:=:S`ca`=:l{uls~`ca`j``abj```djlq~`ca`j``h`j```el}s=:ls}``ael}w=:Ȳylqy`ad`l~tls|lvqs````=:ls}```hlvq```dl}t```blq``ddj`f``j```ij``ad=:lu~t=:=:S`cb`=:l{u=:lv|z`gfbj`cbb=:lv|z`gfaj`cbaluu`e``=:S`cba=:l{u=:l}~`cb`j````j````j````=:l}t```bl}t```c=:l}wlvqs``ai!qҲݲrl~tls|lvqs````=:lq~`c``j``b`j````lqy``e`l}w!yl~tls|lvqs````=:ls~`ea`j`ccdj````=:ls~`eaaj`ccdj```blqy`a``=:l}wlvqs``b`uuurl~tls|lvqs````=:lq~`c``j````j````lqy``e`l}t```b=:l}wlvqs``be޲ٲҲrl~t=:!Ͳٲl~tlvqs````ls|=:lqy``e`=:l}wsyls}````l~tls|=:ls~`ca`j```ij```blqy`a``=:ls~`ca`j0`abj```b=:lq~`ca`j``c`j```bls}``aa=:l}t````=:l}wlvqs``ai=:ywyyl~tls|lvqs``ad=:yl~tls|۲yl~tls|ٲq𻫲ٲ=:Բyl~tls|زݲ=:ҲҲyl~tls|~Ɯ߲=:ֲҲrl~tls|Բyl~t=:ƜھвԱyl~tls|·Ã~=:!yyl~tls|lvqs``aièٲyl~t=:qó!¶Ͳұrl~tlvqs````ls|ls}````=:lqy`a``=:lq~`ca`j``f`j```blqy``dh=:lq~`ca`j``e`j```blqy``b`=:lq~`c``j``b`j````lqy``b`=:l}t```bl}t```cl}wlvqs``ai=:鱋yl~tlq~`ca`j``h`j````l}r```blq~`c``j``c`j````l``gbls|lvqs``bcҲ!ٱyyl~t=:lq~`ca`j````j````ls}```dls~`ca`j`afij````lr|`ca`=:lv|[`gfblv|[`gfc=:lu~t=:S`cbb=:lylu~t=:=:S`cc`=:=:=:=:S`e``=:l{u=:lv|z`gfbj`e`b=:lv|z`gfaj`e`a=:l}w۲ݲrl~t=:ԲٲDzܲݲrl~t=:ٲ޲ٲԲұrl~tlu~t=:S`e`a=:l{ulqy``a`=:lq~`c``j````j````=:l}wlvqs``b`+=:Ͳݲ!Ҳٲϱrl~tls|=:lq~`c``j``b`j````lu~t=:S`e`b=:lyl}w۲ݲrl~tlu~t=:=:S`ea`=:S`eaa=:=:=:S`f``=:l{ulv|]`gfclv|[`gfdlv|]`gf`=:l}sls}```hls~`cc`j``abj```blq~`c``j````j```b=:l}~`cb`j````j````j````=:lvqy```d=:l}wlvqs```e~Ź߲l~tls| ٲrl~t=:ٲl~tlq~`cc`j````j````ls|Ðq=:ٲrl~tls|=:lvqs``ai ٲҲrl~tlvqs````ls|=:lq~`cc`j``f`j````lqy``d`=:lq~`cc`j``e`j```blqy``b`=:l}t```clq~`c``j``b`j````=:l}wlvqs``ai!qҲݲrl~tls|lvqs````=:lq~`e``j``a`j````lqy`a``=:lq~`cc`j``h`j```b=:lq~`c``j````j```b=:lq~`e``j``b`j````l}t```bl}w=:lvqs``bcpyyylqy``e`ls|lvqs````=:lq~`cc`j````j```b=:lqy`a``l}wlvqs```eҲҲٱrlq~`c``j````j````l~t=:~ Ð=:ٲrl~tls|=:lvqs``aiԲ!yl~tls|lvqs````lq~`cc`j``a`j````=:lqy`af`ls~`b``j``aej```blqy``d`=:l}w=:lvqs``aiƫƲssٲrl~tls|=:lv|[`ghalv|[`gfels~``afj``afj```blu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/MazeW.pxe b/game_japanese/data/Stage/MazeW.pxe new file mode 100644 index 0000000..63818ec Binary files /dev/null and b/game_japanese/data/Stage/MazeW.pxe differ diff --git a/game_japanese/data/Stage/MazeW.pxm b/game_japanese/data/Stage/MazeW.pxm new file mode 100644 index 0000000..21559a0 Binary files /dev/null and b/game_japanese/data/Stage/MazeW.pxm differ diff --git a/game_japanese/data/Stage/MazeW.tsc b/game_japanese/data/Stage/MazeW.tsc new file mode 100644 index 0000000..ea91da9 --- /dev/null +++ b/game_japanese/data/Stage/MazeW.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``cglvqy````lu~t=:S``ia=:l}~qls}``cglvqy```alu~t=:S``ib=:l}~qls}``cglvqy```blu~t=:S``ic=:l}~qls}``cglvqy```clu~t=:S``id=:l}~qls}``cglvqy```dlu~t=:=:S`a``=:lylvq```blq``chj``ibj```ej```c=:=:S`a`a=:=:S`a`b=:lyl``aalt~`a`blvq```dlq``d`j``ibj```dj```e=:=:S`a`c=:lv|z`fhaj`a`e=:lyz``agj`a`d=:lyl}w޲ڲٲٲҲrl~tlu~t=:S`a`d=:lyl``bblwya`aglv|[`fha=:l}wm󿺲z}mP rl~tls|luu`a`e=:S`a`e=:lyl``aalt~`a`clvq````lq``daj``i`j``aej```i=:=:S`a`f=:l{ul``aalq~`a`fj````j```blvq```dlq``dbj``idj```ej0``i=:=:S`aa`=:lv|z`gd`j`aaa=:l{ul``aalq~`aa`j````j```blvq```blq``dcj`e``j```dj``ac=:S`aaa=:l{ul``aalq~`aa`j````j```blvq```blq``dcj``ibj```dj``ac=:=:S`ab`=:l{ulvq```dlq``d`j``idj``abj```b=:=:=:=:S`c``=:S`c`a=:lt~`c`alrq```alv|]`fh`lu~t=:S`c`b=:lt~`c`bls}```glrq``a`ls~`c``j``acj````lr|````lu~t=:=:Sa```=:l{ulvr````j``aflqy`be`ls}````=:l}cls}``ae=:ó ìrlv}``aflqy`af`l~tls|ls}``cg=:ls~`c``j````j````lv|[`fh`lu~t=:=:=:Sab``=:l{ulq~ab``j``b`j```b=:lv~ab``j``aflvqy```a=:lqy`a``lvq```alq``dgjab``j``chj``af=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/MiBox.pxe b/game_japanese/data/Stage/MiBox.pxe new file mode 100644 index 0000000..3fb5faf Binary files /dev/null and b/game_japanese/data/Stage/MiBox.pxe differ diff --git a/game_japanese/data/Stage/MiBox.pxm b/game_japanese/data/Stage/MiBox.pxm new file mode 100644 index 0000000..35422ed Binary files /dev/null and b/game_japanese/data/Stage/MiBox.pxm differ diff --git a/game_japanese/data/Stage/MiBox.tsc b/game_japanese/data/Stage/MiBox.tsc new file mode 100644 index 0000000..65d53e2 --- /dev/null +++ b/game_japanese/data/Stage/MiBox.tsc @@ -0,0 +1 @@ +NKdqqzqNK}}qqqq}NKdqqzrNK}}qqqr}NKdqqzsNK}}qqqs}NKdqqztNK}A}qqqt}NKdqqzuNK}}qqqu}NKNKdqrqqNK}}qqqu}qqrr{qqzu{qqsu{qqtuNKNK \ No newline at end of file diff --git a/game_japanese/data/Stage/Mimi.pxa b/game_japanese/data/Stage/Mimi.pxa new file mode 100644 index 0000000..94e8fc0 Binary files /dev/null and b/game_japanese/data/Stage/Mimi.pxa differ diff --git a/game_japanese/data/Stage/Mimi.pxe b/game_japanese/data/Stage/Mimi.pxe new file mode 100644 index 0000000..5b68f62 Binary files /dev/null and b/game_japanese/data/Stage/Mimi.pxe differ diff --git a/game_japanese/data/Stage/Mimi.pxm b/game_japanese/data/Stage/Mimi.pxm new file mode 100644 index 0000000..7fc90d8 Binary files /dev/null and b/game_japanese/data/Stage/Mimi.pxm differ diff --git a/game_japanese/data/Stage/Mimi.tsc b/game_japanese/data/Stage/Mimi.tsc new file mode 100644 index 0000000..032a48b Binary files /dev/null and b/game_japanese/data/Stage/Mimi.tsc differ diff --git a/game_japanese/data/Stage/Momo.pxe b/game_japanese/data/Stage/Momo.pxe new file mode 100644 index 0000000..67cd58c Binary files /dev/null and b/game_japanese/data/Stage/Momo.pxe differ diff --git a/game_japanese/data/Stage/Momo.pxm b/game_japanese/data/Stage/Momo.pxm new file mode 100644 index 0000000..e58b14d Binary files /dev/null and b/game_japanese/data/Stage/Momo.pxm differ diff --git a/game_japanese/data/Stage/Momo.tsc b/game_japanese/data/Stage/Momo.tsc new file mode 100644 index 0000000..538f21e --- /dev/null +++ b/game_japanese/data/Stage/Momo.tsc @@ -0,0 +1,15 @@ +½ֱʱŎ½ֱʱŎ½ֱʱŎ½ֱʱŎ½ֱʱŎڽֱѱб±ڎֱѱʱĎѱױʱֱѱűĽʱѱŎڎֱѱʱĎѱױʱֱѱűĽʱѱŎڎ˲˱˲˱˱˲˲˲ѱʱѱʱȽͬͬı!I>++ ?BE> #fLýŽӎH*B>ŽNcýŎMkgýŎMFq%*+BE>r?0HLýŎ +UMn+ *C*B>G>rNI6ýŎ*hL,G4k>MýŽqfJF,I#NLýŽӎ]!<kN#G#EýŽ"qmBEjMýŎ!I>qM +%AJj>`MgýŎ]?+,iI.ELýŽЎ˱˱Ʊ˱˱ȽıGi!'9+IMýŎ?k*BEI#*6hŽŎȽýŽ!½<kYijnLýŽӎıղqghk>ýŽձӽıM /-JN]?+,iI#MýŽЎծҮͮͬƱȽýŽ!½<kYijnLýŽӎıղqghk>ýŽձӽıM /-JN]?+,iI#MýŽЎծҮͮͬƱڽȽı"6#ɽ˱<%ɽŎIh##F8ŽŎڽͬ##ULýŎ48+ #fýŽGi!'9 q*UBEýŽıղլҬͬȎֱMϾqiJ}k>ýʱŽֽнձȽı%nýŎ.6f,#0HŽ +MN UGjq W4kEjMgýŎ<M Ih6 iJIkjýŽ##ɽŽƱڽȽı N J"BEq6E@f%?#ýŽ +1I?*h +.JBEI#gýŽŎȽͬͬıM /-JN+I :+IMýŎkFBEj], ½Ŏ!kq keiJ}kkOIrG*IjG%ýŽIrG*6E], qiJ}kE,E9VýŽŎڽȽı /-JN+I :+IMýŎ2MTF :G ?B>h +M], LýŽIrG*6E], qiJ}kE9VýŽŎڽȽı)*'iI4#ýŽӽıղ +tk], q *:>ýŽӽırŽ2M], Ž + tLýŽձ2k7b'I#nýŽŎڽͬͬȽı)*'iI4#ýŽӽıղծ], q *:>ýŽӽı'GŽ N+ýŎ2kIh#0jG%nýŽձֱѱнʱ N J"BEq6E@f%?#ýŽ J"NŽ*MI SýŽ?0H +1IFLýŎBgJ*h'1?6>r?0HŽ +.JBEI#ýŽŎȽͬı)*'iýŽ J"N *C*B>ɽŽӎıղծ +q6>ýŽӽı U b#I#nýŎ J"M*m +ýŽձ%rŽ+#I#G +qN+fPIMgL&ýŽ] IrG*8jnýŽƱڽȽı3 kýŽ /-JN U+**j*h +MF rFEýŽŎڽ ^]8*ɽ˱бֱʱýŽЎʱ˲ʬֱűMN+ +r6>ýŽнֱʱŎͮͬͬͬͬͬͬͮͬͮͬýŽнѱѱʬֱűg. r?ýŽнֱʱŎڽ?l%*ŽŎ \ No newline at end of file diff --git a/game_japanese/data/Stage/New.pxe b/game_japanese/data/Stage/New.pxe new file mode 100644 index 0000000..6407ae9 Binary files /dev/null and b/game_japanese/data/Stage/New.pxe differ diff --git a/game_japanese/data/Stage/Oside.pxa b/game_japanese/data/Stage/Oside.pxa new file mode 100644 index 0000000..d141dad Binary files /dev/null and b/game_japanese/data/Stage/Oside.pxa differ diff --git a/game_japanese/data/Stage/Oside.pxe b/game_japanese/data/Stage/Oside.pxe new file mode 100644 index 0000000..38e3b5d Binary files /dev/null and b/game_japanese/data/Stage/Oside.pxe differ diff --git a/game_japanese/data/Stage/Oside.pxm b/game_japanese/data/Stage/Oside.pxm new file mode 100644 index 0000000..03adc62 Binary files /dev/null and b/game_japanese/data/Stage/Oside.pxm differ diff --git a/game_japanese/data/Stage/Oside.tsc b/game_japanese/data/Stage/Oside.tsc new file mode 100644 index 0000000..24224ef --- /dev/null +++ b/game_japanese/data/Stage/Oside.tsc @@ -0,0 +1,5 @@ +NKdqqzqNK}}qqsv}qqqq}NKdqqzrNK}}qqsv}qqqr}NKdqqzsNK}}qqsv}qqqs}NKdqqztNK}}qqsv}qqqt}NKdqqzuNK}}qqsv}qqqu}NKNKdqrqqNK}}qqqq}qqvs{qqzq{qqrx{qqrqNKNKdqrsqNK}}qqrr}qrsq{qqqq{qqqs}qqqu}qqvv{qqzu{qqqz{qqqzNK}¤}}NKNKdqrtqNK}}qqts{qrtr}qqrr}qrtq{qqqq{qqqs}qqqq}qqwz{qqzq{qqrv{qqqyNKdqrtrNK}}qqqq}qqrr}qrtq{qqqq{qqqsNK}rqts}nqqts}lrtxq}NK¶œƒ}}NK}qqqq}qqwz{qqzq{qqrv{qqqyNKNKdqruqNK}}qqqq}qqqq}qqzu{qqzq{qqru{qqqxNKNKdqsqqNK}}‰}}NKNKdquqqNK}}qzwq{quqr}}qqrqēĂ1ӕ (NK̾<ƒ}}NKdquqrNK}}}qurq{qqrw}qqvqNK}}qqrq +'*}qqqq2ƒ}}NK}qusq{qrvq{qqqq}NK}quqq{qqqt{qqqq}qqtsNK}quqq{qqqq{qqqs}qqtsNK}Aqusq{qqvq{qqqq}qqtsNK}qusq{qqqq{qqqs}qqtsNK}quqq}qusqNK}qurq{qqrq{qqqs}qsqqNK}}qqrq),'ƒ}}}qqqqNK}qurq{qqsq{qqqs}qsvqNK}qurq{qqrq{qqqs}qsqqNK} NK +1ӆа*ƒ}qsqq}#ĩďğœ 1ԠNKӯ$ Ζ1ˋϯ*,ƒ}qsqq}ӯ$ ™ĩďğœ Ζ1NKщϿ (+*,ƒ}qsqq}NK}qqqs2 !'¤}qsqq} $ ċĚľÒѭ‚NKĩďğœ ) ̺ ϓ‚NKѕ*( ƒ}qsqq}}qqswNK}¡.)¡}zzzzNK}NKNKNKdqurqNK}}Đ}}NKdqusqNKNKNKdqwqqNK}}ħİģĐ+ًحƒ}NK- ƒ}NK ' +-*ęĦœĘ1NKЊęĦœĘ +'Ϸƒ}NK2NK*#(¤}}NKNK \ No newline at end of file diff --git a/game_japanese/data/Stage/Ostep.pxe b/game_japanese/data/Stage/Ostep.pxe new file mode 100644 index 0000000..0d1e91e Binary files /dev/null and b/game_japanese/data/Stage/Ostep.pxe differ diff --git a/game_japanese/data/Stage/Ostep.pxm b/game_japanese/data/Stage/Ostep.pxm new file mode 100644 index 0000000..1732069 Binary files /dev/null and b/game_japanese/data/Stage/Ostep.pxm differ diff --git a/game_japanese/data/Stage/Ostep.tsc b/game_japanese/data/Stage/Ostep.tsc new file mode 100644 index 0000000..66aaf78 --- /dev/null +++ b/game_japanese/data/Stage/Ostep.tsc @@ -0,0 +1,2 @@ +-::C:FWXKFPKS::::FOXN-::C;FWXKFPKS:::;FOXN-::C<FWXKFPKS:::FWXKFPKS:::>FOXN-:;::FUOcF]Y_::;;FKXZ:;::D::::D:::<FPKY::::F^\K::B?D::C@D::;CD::D::;; +-:<::-:<:;-:C::FNXZ:C::FUOcFWcN:::[5堝_"(!y&Q%"(!yQHoHP" p-$5(;נ &A%_&$*$(%2 HoJ&$*$(%͠ \#m$D"'%堝Y\<@"(B\ @yנNDXITYHWWàƠנ3_%_!oQ<[堝נà;<9{נ$eTW5Py 4& `Pנ!)H5QBZ !=_!{#y\+}W5<}P堝9̠#f'YTWsz7<z[⠝ڠ`[L&9=FˠננǠàĠ \ No newline at end of file diff --git a/game_japanese/data/Stage/Pixel.pxe b/game_japanese/data/Stage/Pixel.pxe new file mode 100644 index 0000000..3364dd5 Binary files /dev/null and b/game_japanese/data/Stage/Pixel.pxe differ diff --git a/game_japanese/data/Stage/Pixel.pxm b/game_japanese/data/Stage/Pixel.pxm new file mode 100644 index 0000000..575bee6 Binary files /dev/null and b/game_japanese/data/Stage/Pixel.pxm differ diff --git a/game_japanese/data/Stage/Pixel.tsc b/game_japanese/data/Stage/Pixel.tsc new file mode 100644 index 0000000..b63e968 Binary files /dev/null and b/game_japanese/data/Stage/Pixel.tsc differ diff --git a/game_japanese/data/Stage/Plant.pxe b/game_japanese/data/Stage/Plant.pxe new file mode 100644 index 0000000..2fe9f5b Binary files /dev/null and b/game_japanese/data/Stage/Plant.pxe differ diff --git a/game_japanese/data/Stage/Plant.pxm b/game_japanese/data/Stage/Plant.pxm new file mode 100644 index 0000000..2fe59c1 Binary files /dev/null and b/game_japanese/data/Stage/Plant.pxm differ diff --git a/game_japanese/data/Stage/Plant.tsc b/game_japanese/data/Stage/Plant.tsc new file mode 100644 index 0000000..26edcf3 --- /dev/null +++ b/game_japanese/data/Stage/Plant.tsc @@ -0,0 +1,2 @@ +ƣڣǣڣȣڣɣڣʣڣˣڣ̣ڣͣڣΣڣϣڣƣǣˣ KrM? KrKSڣ̣!+x!!KrKSڣƣ GGcj}Z*ڣGb*$}b@b$$,jc,SUb'{&n^&-\^T裠TE]&j8jc8E^8vK&j8j&mS^}ףss""@iW\:KZףMD_$[Kr:}K8I88Gb*_c&j8jc#}?^8Tڣƣ&rA!Tڣǣ(,`_KW?~\"[(~IZ8ڣƣߣƣƣS?"WZ8ˣ,h%b{Ӷ$~_)S壠ڣƣ̣ + !Ӷ$~_)Sɣ#['{'b-c@ɶ'3<Sڣ \ No newline at end of file diff --git a/game_japanese/data/Stage/Pole.pxe b/game_japanese/data/Stage/Pole.pxe new file mode 100644 index 0000000..df67329 Binary files /dev/null and b/game_japanese/data/Stage/Pole.pxe differ diff --git a/game_japanese/data/Stage/Pole.pxm b/game_japanese/data/Stage/Pole.pxm new file mode 100644 index 0000000..e0b3f54 Binary files /dev/null and b/game_japanese/data/Stage/Pole.pxm differ diff --git a/game_japanese/data/Stage/Pole.tsc b/game_japanese/data/Stage/Pole.tsc new file mode 100644 index 0000000..f9bb55a Binary files /dev/null and b/game_japanese/data/Stage/Pole.tsc differ diff --git a/game_japanese/data/Stage/Pool.pxe b/game_japanese/data/Stage/Pool.pxe new file mode 100644 index 0000000..86f833b Binary files /dev/null and b/game_japanese/data/Stage/Pool.pxe differ diff --git a/game_japanese/data/Stage/Pool.pxm b/game_japanese/data/Stage/Pool.pxm new file mode 100644 index 0000000..5501c2d Binary files /dev/null and b/game_japanese/data/Stage/Pool.pxm differ diff --git a/game_japanese/data/Stage/Pool.tsc b/game_japanese/data/Stage/Pool.tsc new file mode 100644 index 0000000..86598d4 Binary files /dev/null and b/game_japanese/data/Stage/Pool.tsc differ diff --git a/game_japanese/data/Stage/Prefa1.pxe b/game_japanese/data/Stage/Prefa1.pxe new file mode 100644 index 0000000..2de6026 Binary files /dev/null and b/game_japanese/data/Stage/Prefa1.pxe differ diff --git a/game_japanese/data/Stage/Prefa1.pxm b/game_japanese/data/Stage/Prefa1.pxm new file mode 100644 index 0000000..8c91db8 Binary files /dev/null and b/game_japanese/data/Stage/Prefa1.pxm differ diff --git a/game_japanese/data/Stage/Prefa1.tsc b/game_japanese/data/Stage/Prefa1.tsc new file mode 100644 index 0000000..ba4a1f9 --- /dev/null +++ b/game_japanese/data/Stage/Prefa1.tsc @@ -0,0 +1,2 @@ +þײ˲Əþײ˲Əþײ˲Əþײ˲Əþײ˲Ə۾ҲײѲò۾ҲҲƏ۾N,"kľƏI_^9+ʾ̲Ծ Nbrw9kKO ur +\09k?aN,z@H(ilkľƾhCFON /rakľƾ3N utVOHNs rbCF /rak3HKJkľƾjGOG DGÏ"kxN, D@ľƾ,sG7^oJ1lP:O 0.7ÏhjXJHJk@m&ľƾя̲˲մ5(JJ1lP˲ƾƏ \ No newline at end of file diff --git a/game_japanese/data/Stage/Prefa2.pxe b/game_japanese/data/Stage/Prefa2.pxe new file mode 100644 index 0000000..1e0eba9 Binary files /dev/null and b/game_japanese/data/Stage/Prefa2.pxe differ diff --git a/game_japanese/data/Stage/Prefa2.pxm b/game_japanese/data/Stage/Prefa2.pxm new file mode 100644 index 0000000..674ad60 Binary files /dev/null and b/game_japanese/data/Stage/Prefa2.pxm differ diff --git a/game_japanese/data/Stage/Prefa2.tsc b/game_japanese/data/Stage/Prefa2.tsc new file mode 100644 index 0000000..12bedd3 --- /dev/null +++ b/game_japanese/data/Stage/Prefa2.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}````lvqy````lu~t=:S``ia=:l}~qls}````lvqy```alu~t=:S``ib=:l}~qls}````lvqy```blu~t=:S``ic=:l}~qls}````lvqy```clu~t=:S``id=:l}~qls}````lvqy```dlu~t=:=:S`a``=:lyl}wβl~tlu~t=:lq~`a``j````j```bl``aalvq```dlq``fbj``idj``gij``gc=:=:S`aa`=:lylvq`0`c=:lv|[aecalv|[aecdlv|[aee`=:lq``h`j``icj``agj```a=:=:=:=:=:=:S`b``=:lyl}w*=:ݲ߾κ rl~tls|* ٱxl~z````ls|=:lv|[aci`lv|[acialv|[acibls}````lvq```alqy`a``=:lq``g`j`ca`j`aahj``fb=:=:S`be`=:lyl}w=:ھҲl~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Priso1.pxe b/game_japanese/data/Stage/Priso1.pxe new file mode 100644 index 0000000..c28cec5 Binary files /dev/null and b/game_japanese/data/Stage/Priso1.pxe differ diff --git a/game_japanese/data/Stage/Priso1.pxm b/game_japanese/data/Stage/Priso1.pxm new file mode 100644 index 0000000..6cc6e54 Binary files /dev/null and b/game_japanese/data/Stage/Priso1.pxm differ diff --git a/game_japanese/data/Stage/Priso1.tsc b/game_japanese/data/Stage/Priso1.tsc new file mode 100644 index 0000000..eeda7f0 --- /dev/null +++ b/game_japanese/data/Stage/Priso1.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``bilvqy````lu~t=:S``ia=:l}~qls}``bilvqy```alu~t=:S``ib=:l}~qls}``bilvqy```blu~t=:S``ic=:l}~qls}``bilvqy```clu~t=:S``id=:l}~qls}``bilvqy```dlu~t=:=:S`a``=:l{ul``aalt~`a``lvq````lq0`efj``i`j``h`j```i=:S`aa`=:l{ul``aalt~`aa`lvq```alq``fbj``iaj```gj``gd=:=:S`b``=:lq~`b``j```bj```blu~t=:S`b`a=:lq~`b`aj```bj```blu~t=:S`b`b=:lq~`b`bj```bj```blu~t=:S`b`c=:lq~`b`cj```bj```blu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Priso2.pxe b/game_japanese/data/Stage/Priso2.pxe new file mode 100644 index 0000000..31a9bcf Binary files /dev/null and b/game_japanese/data/Stage/Priso2.pxe differ diff --git a/game_japanese/data/Stage/Priso2.pxm b/game_japanese/data/Stage/Priso2.pxm new file mode 100644 index 0000000..445c3cd Binary files /dev/null and b/game_japanese/data/Stage/Priso2.pxm differ diff --git a/game_japanese/data/Stage/Priso2.tsc b/game_japanese/data/Stage/Priso2.tsc new file mode 100644 index 0000000..5ce497e Binary files /dev/null and b/game_japanese/data/Stage/Priso2.tsc differ diff --git a/game_japanese/data/Stage/Prt0.pbm b/game_japanese/data/Stage/Prt0.pbm new file mode 100644 index 0000000..95f8566 Binary files /dev/null and b/game_japanese/data/Stage/Prt0.pbm differ diff --git a/game_japanese/data/Stage/PrtAlmond.pbm b/game_japanese/data/Stage/PrtAlmond.pbm new file mode 100644 index 0000000..a9e1627 Binary files /dev/null and b/game_japanese/data/Stage/PrtAlmond.pbm differ diff --git a/game_japanese/data/Stage/PrtBarr.pbm b/game_japanese/data/Stage/PrtBarr.pbm new file mode 100644 index 0000000..e66fc10 Binary files /dev/null and b/game_japanese/data/Stage/PrtBarr.pbm differ diff --git a/game_japanese/data/Stage/PrtCave.pbm b/game_japanese/data/Stage/PrtCave.pbm new file mode 100644 index 0000000..7c7e63b Binary files /dev/null and b/game_japanese/data/Stage/PrtCave.pbm differ diff --git a/game_japanese/data/Stage/PrtCent.pbm b/game_japanese/data/Stage/PrtCent.pbm new file mode 100644 index 0000000..424be52 Binary files /dev/null and b/game_japanese/data/Stage/PrtCent.pbm differ diff --git a/game_japanese/data/Stage/PrtEggIn.pbm b/game_japanese/data/Stage/PrtEggIn.pbm new file mode 100644 index 0000000..3c6aac6 Binary files /dev/null and b/game_japanese/data/Stage/PrtEggIn.pbm differ diff --git a/game_japanese/data/Stage/PrtEggX.pbm b/game_japanese/data/Stage/PrtEggX.pbm new file mode 100644 index 0000000..5243edb Binary files /dev/null and b/game_japanese/data/Stage/PrtEggX.pbm differ diff --git a/game_japanese/data/Stage/PrtEggs.pbm b/game_japanese/data/Stage/PrtEggs.pbm new file mode 100644 index 0000000..2762e3f Binary files /dev/null and b/game_japanese/data/Stage/PrtEggs.pbm differ diff --git a/game_japanese/data/Stage/PrtFall.pbm b/game_japanese/data/Stage/PrtFall.pbm new file mode 100644 index 0000000..012ce21 Binary files /dev/null and b/game_japanese/data/Stage/PrtFall.pbm differ diff --git a/game_japanese/data/Stage/PrtGard.pbm b/game_japanese/data/Stage/PrtGard.pbm new file mode 100644 index 0000000..19e3f97 Binary files /dev/null and b/game_japanese/data/Stage/PrtGard.pbm differ diff --git a/game_japanese/data/Stage/PrtHell.pbm b/game_japanese/data/Stage/PrtHell.pbm new file mode 100644 index 0000000..4a963ca Binary files /dev/null and b/game_japanese/data/Stage/PrtHell.pbm differ diff --git a/game_japanese/data/Stage/PrtJail.pbm b/game_japanese/data/Stage/PrtJail.pbm new file mode 100644 index 0000000..7d9241e Binary files /dev/null and b/game_japanese/data/Stage/PrtJail.pbm differ diff --git a/game_japanese/data/Stage/PrtLabo.pbm b/game_japanese/data/Stage/PrtLabo.pbm new file mode 100644 index 0000000..f2d1b43 Binary files /dev/null and b/game_japanese/data/Stage/PrtLabo.pbm differ diff --git a/game_japanese/data/Stage/PrtMaze.pbm b/game_japanese/data/Stage/PrtMaze.pbm new file mode 100644 index 0000000..bdc729f Binary files /dev/null and b/game_japanese/data/Stage/PrtMaze.pbm differ diff --git a/game_japanese/data/Stage/PrtMimi.pbm b/game_japanese/data/Stage/PrtMimi.pbm new file mode 100644 index 0000000..3947696 Binary files /dev/null and b/game_japanese/data/Stage/PrtMimi.pbm differ diff --git a/game_japanese/data/Stage/PrtOside.pbm b/game_japanese/data/Stage/PrtOside.pbm new file mode 100644 index 0000000..358e147 Binary files /dev/null and b/game_japanese/data/Stage/PrtOside.pbm differ diff --git a/game_japanese/data/Stage/PrtPens.pbm b/game_japanese/data/Stage/PrtPens.pbm new file mode 100644 index 0000000..6df62bc Binary files /dev/null and b/game_japanese/data/Stage/PrtPens.pbm differ diff --git a/game_japanese/data/Stage/PrtRiver.pbm b/game_japanese/data/Stage/PrtRiver.pbm new file mode 100644 index 0000000..0f648d5 Binary files /dev/null and b/game_japanese/data/Stage/PrtRiver.pbm differ diff --git a/game_japanese/data/Stage/PrtSand.pbm b/game_japanese/data/Stage/PrtSand.pbm new file mode 100644 index 0000000..cbec204 Binary files /dev/null and b/game_japanese/data/Stage/PrtSand.pbm differ diff --git a/game_japanese/data/Stage/PrtStore.pbm b/game_japanese/data/Stage/PrtStore.pbm new file mode 100644 index 0000000..6504af0 Binary files /dev/null and b/game_japanese/data/Stage/PrtStore.pbm differ diff --git a/game_japanese/data/Stage/PrtWeed.pbm b/game_japanese/data/Stage/PrtWeed.pbm new file mode 100644 index 0000000..ed079bd Binary files /dev/null and b/game_japanese/data/Stage/PrtWeed.pbm differ diff --git a/game_japanese/data/Stage/PrtWhite.pbm b/game_japanese/data/Stage/PrtWhite.pbm new file mode 100644 index 0000000..72b58f7 Binary files /dev/null and b/game_japanese/data/Stage/PrtWhite.pbm differ diff --git a/game_japanese/data/Stage/Ring1.pxe b/game_japanese/data/Stage/Ring1.pxe new file mode 100644 index 0000000..8fd0204 Binary files /dev/null and b/game_japanese/data/Stage/Ring1.pxe differ diff --git a/game_japanese/data/Stage/Ring1.pxm b/game_japanese/data/Stage/Ring1.pxm new file mode 100644 index 0000000..8db7e4b Binary files /dev/null and b/game_japanese/data/Stage/Ring1.pxm differ diff --git a/game_japanese/data/Stage/Ring1.tsc b/game_japanese/data/Stage/Ring1.tsc new file mode 100644 index 0000000..17c366a Binary files /dev/null and b/game_japanese/data/Stage/Ring1.tsc differ diff --git a/game_japanese/data/Stage/Ring2.pxe b/game_japanese/data/Stage/Ring2.pxe new file mode 100644 index 0000000..eeb4591 Binary files /dev/null and b/game_japanese/data/Stage/Ring2.pxe differ diff --git a/game_japanese/data/Stage/Ring2.pxm b/game_japanese/data/Stage/Ring2.pxm new file mode 100644 index 0000000..2af8376 Binary files /dev/null and b/game_japanese/data/Stage/Ring2.pxm differ diff --git a/game_japanese/data/Stage/Ring2.tsc b/game_japanese/data/Stage/Ring2.tsc new file mode 100644 index 0000000..9c51f51 --- /dev/null +++ b/game_japanese/data/Stage/Ring2.tsc @@ -0,0 +1,3 @@ +S``i`=:l{ul}~qls}``c`lvqy````lu~t=:S``ia=:l{ul}r```blqy```bly=:l}~qls}``c`lvqy```alu~t=:S``ib=:l{ul}~qls}``c`lvqy```blu~t=:S``ic=:l{ulv|zacdaj``iilv|zabg`j``ih=:l}~qls}``c`lvqy```clu~t=:S``id=:l{ul}~qls}``c`lvqy```dlu~t=:=:S``ih=:l{u=:ls}```cj``acj``ba=:ls}```cj```ij``ba=:ls}```cj```fj``ba=:ls}```cj```cj``ba=:ls}```cj````j````=:l}~qls}``c`lvqy```clu~t=:=:S``ii=:l{u=:ls}```cj```ij``ba=:ls}```cj```fj``ba=:ls}```cj```cj``ba=:ls}``ahlvqy```clu~t=:=:=:=:S`a``=:lylvq```clq``fdj``icj```cj```a=:S`aa`=:lylvq```al}t```blq``fhj``iaj```cj``ad=:=:S`b``=:l{u=:lv|zabgbj`b`d=:lv|zabg`j`b`b=:lv|zabgaj`b`al}w=:бqҲٲrl~tlv|za`b`j`b`els| Ų߲Ǹݲxl~tlu~t=:S`b`a=:lyl}w=:ڲ!yl~tlu~t=:S`b`b=:l{ul}wrl~tls|sûsڲrl~tls|=:xl~tls|бrrl~t=:вq{߲=:ƫƲ!xl~t=: q +Ҳ߲rl~t=:ҲҲrl~tls|=:lv|[abgblu~t=:S`b`c=:S`b`d=:l{ul}wвݲҲrl~t=: ljq ұrl~tlv|zabgdj````lv|[abgdls|=:uñl~tls|=:lq~`be`j``a`j```e=:lq~`beaj``a`j```e=:lq~`bebj``a`j```e=:lq~`becj``a`j```e=:lq~`bedj``a`j```e=:lq~`beej``a`j```e=:lu~t=:S`b`e=:l{ul}w!zu=: +Ҳrl~tlu~t=:=:S`ba`=:lylv|zabg`j`bab=:lv|zabgaj`baa=:l}w~ŬҲrl~t=:ٲȃ޲,rl~t=:Ҳ!ٲϱrl~tlu~t=:S`baa=:lyl}w=:ǍDŽrl~tlu~t=:S`bab=:lyl}wٲٲ!yl~tlu~t=:=:S`bb`=:lylv|zabg`j`bbb=:lv|zabgaj`bba=:l}wбql~t~Ҳٲuuurl~tlu~t=:S`bba=:lyl}w=:Ҽyl~tlu~t=:S`bbb=:l{ul}wƜֲxl~t=:~z} ݲl~tlv|za`b`j`bbcls| вҲҲl~tls|=:~۲ê!l~tlu~t=:S`bbc=:l{ul}w=:!{yyl~tlu~t=:=:S`be`=:S0bea=:S`beb=:S`bec=:S`bed=:S`bee=:=:S`d``=:S`d`a=:=:S`da`=:l{ulv~`da`j``aflq~`da`j`e``j```dlqy``e`=:ls}````l}cܲвϱyl}r`da`l~tls|ﱓlqy``b`ﱓlqy``b`ls|=:ƌƲyyyl~tls|=:lqy``e`ls~`db`j`bfgj```dlqy`a``=:lv}``af=:lq~`db`j```gj```dlr|`db`lt~`da`lv|]abg`ls}``calu~t=:=:S`db`=:l{ulv~`db`j``aflv|[abg`=:lq~`db`j`e``j```dlqy`a``=:l}c{pyyl}r`db`l~tls|=:lq~`db`j`ea`j```dlqy`de`ls}``ae=:lv}``aflq~`db`j`eb`j````l}c=:~ ìylqy`ad`l~tls}````ls|=:lv~`de`j``aflqy``e`=:ls}```cj```ij``bal``ablqy``b`=:ls}```cj```fj``bal``ablqy``b`=:ls}```cj```cj``bal``ablqy``b`=:ls}```cj````j````l``ablqy``b`=:lqy``e`=:lv}``afls}``c`lt~`db`lu~t=:S`de`=:=:=:S`e``=:l{ult~`e``l{z```aj`e`al{[```aluu`e`b=:S`e`a=:l{ulqluu`e`b=:S`e`b=:ls}``agl}t```b=:ls}```cj``acj``ba=:l}clvqs``balq~`d``j``a`j````l~tls|=:Ҳܲrl~tls|lvqs````=:lqy``b`lq~`d``j``b`j````lqy``c`=:l}clvqs``baҹ úǎ=:{ƌl~t=:&€rl~tls|ҹq=:& Č (ۿ=:ؾ߲l~tls|۲ Ě#ؾ=: Ҳrl~tls| ̲Ҳ=:󿛲ܼ'rl~t=:ڲl~tls|lvqs````=:lqy``b`lt~`d`alq~`d``j``d`j````lqy``b`=:l}clvqs``baҼrlqy``c`l~tls|=:Ҽql~t=:|(rl~tls|lq~`d``j``e`j````~~~l~tls|ұyl~tls|=:~ڲٲٱxyl~t=: ҲԱxyl~tls|l~tls|=:Աyyl~tls|=:ls~`da`j`bfcj````lqy```e=:lq~`da`j```bj````lqy``e`=:ls}```cj``acj``balt~`d``=:lv|]abg`lv|[abgalqy``e`lr|`da`ls}```glu~t=:=:S`e`a=:l{ult~`e``ls}``agl}t```b=:ls}```cj``acj``ba=:lt~`d`alq~`d``j``d`j````=:ls~`da`j`bfcj````lqy```e=:lq~`da`j```bj````lqy``e`=:ls}```cj``acj``balt~`d``=:lv|]abg`lv|[abgalqy``e`lr|`da`ls}```glu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Ring3.pxe b/game_japanese/data/Stage/Ring3.pxe new file mode 100644 index 0000000..9c5be83 Binary files /dev/null and b/game_japanese/data/Stage/Ring3.pxe differ diff --git a/game_japanese/data/Stage/Ring3.pxm b/game_japanese/data/Stage/Ring3.pxm new file mode 100644 index 0000000..6c8b902 Binary files /dev/null and b/game_japanese/data/Stage/Ring3.pxm differ diff --git a/game_japanese/data/Stage/Ring3.tsc b/game_japanese/data/Stage/Ring3.tsc new file mode 100644 index 0000000..25f4936 Binary files /dev/null and b/game_japanese/data/Stage/Ring3.tsc differ diff --git a/game_japanese/data/Stage/River.pxa b/game_japanese/data/Stage/River.pxa new file mode 100644 index 0000000..6a5bdef Binary files /dev/null and b/game_japanese/data/Stage/River.pxa differ diff --git a/game_japanese/data/Stage/River.pxe b/game_japanese/data/Stage/River.pxe new file mode 100644 index 0000000..1ccf3cc Binary files /dev/null and b/game_japanese/data/Stage/River.pxe differ diff --git a/game_japanese/data/Stage/River.pxm b/game_japanese/data/Stage/River.pxm new file mode 100644 index 0000000..26b9dfa Binary files /dev/null and b/game_japanese/data/Stage/River.pxm differ diff --git a/game_japanese/data/Stage/River.tsc b/game_japanese/data/Stage/River.tsc new file mode 100644 index 0000000..181ec47 --- /dev/null +++ b/game_japanese/data/Stage/River.tsc @@ -0,0 +1,2 @@ +-::C:FWXKFMW_::=BF]]]:>::FPKS::::FOXN-::C;FWXKFMW_::=BF]]]:>::FPKS:::;FOXN-::C<FWXKFMW_::=BF]]]:>::FPKS:::::FPKS:::=FOXN-::C>FWXKFMW_::=BF]]]:>::FPKS:::>FOXN-::C?FMW_::=BFPKS::::FOXN-:;::FUOcFPKY:::;FM]]F^\K::>AD::C;D:::BD:::C-:;;:FUOcFPYX:<::D::;@FaKS::;:FPKY::::FPYW::;@FPVT:B?:D:;;; +FPV5:B?:FW]QnjSSFXYNFWcN::::F^\K::=;D::CD:::;-:;;@-:;<:FUOcFKXZ:;<:D::::D:::FM]]F^\K::A=D::C>D:::@D:::C-:<::-:<<:FUOcFNXZ:<<:FPVT;>>>D::::FPVT:B=@D:<<;FOXN-:<<;FZ\SFaKS::::FUOcFPV5:B?;FaK]FaKS::?:FZ\SFW]QTee֚ǞǓˌNjmFXYNFOXN \ No newline at end of file diff --git a/game_japanese/data/Stage/Sand.pxa b/game_japanese/data/Stage/Sand.pxa new file mode 100644 index 0000000..31ad7e0 Binary files /dev/null and b/game_japanese/data/Stage/Sand.pxa differ diff --git a/game_japanese/data/Stage/Sand.pxe b/game_japanese/data/Stage/Sand.pxe new file mode 100644 index 0000000..f57a5ae Binary files /dev/null and b/game_japanese/data/Stage/Sand.pxe differ diff --git a/game_japanese/data/Stage/Sand.pxm b/game_japanese/data/Stage/Sand.pxm new file mode 100644 index 0000000..4a2265d Binary files /dev/null and b/game_japanese/data/Stage/Sand.pxm differ diff --git a/game_japanese/data/Stage/Sand.tsc b/game_japanese/data/Stage/Sand.tsc new file mode 100644 index 0000000..65a163f --- /dev/null +++ b/game_japanese/data/Stage/Sand.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}```flvqy````lu~t=:S``ia=:l}~qls}```flvqy```alu~t=:S``ib=:l}~qls}```flvqy```blu~t=:S``ic=:l}~qls}```flvqy```clu~t=:S``id=:l}~qls}```flvqy```dlu~t=:=:S``ii=:l{ul}~qls}```f=:lq~`a``j```aj````lvqy```d=:ls~`c`aj`aabj```blqy`a``=:lq~`a``j````j````=:l}t````lt~`c`al}slu~t=:=:S`a``=:l{ul}wq۲ ٱxl~z````ls|=:ls~`c``j`aaaj```blx}slqy``f`lq~`a``j```aj````=:lqy`a``lvq```dlq```aj``iij```ej```h=:=:l{uls~`c``j`aaaj```blx}slqy``f`lq~`a``j```aj````=:lqy`a``lvq```dlq``ahj``iij``aej``a`=:lqy`a``lvq```dlq```aj``iij```ej```h=:=:S`a`a=:lyl``aalt~`a`alvq````lq``bij``i`j``ahj```i=:=:lv|z`ef`j`a`b=:S`a`b=:lyl``aalt~`a`alvq````lq``caj``i`j``ahj```i=:=:S`a`c=:lyl``aalt~`a`clvq```dlv|z`bh`j`a`elq``ccj``idj``abj``a`=:=:S`a`d=:lylvq```dlq``cdj``idj```ej``ab=:=:S`a`e=:lylq``cfj``idj``abj``a`=:=:S`a`f=:lylvq```dlq```ij``idj```cj``ei=:=:=:S`ae`=:lyl}wl=:vózl~tlu~t=:=:S`aea=:lyl}wl=:Pl~tlu~t=:=:=:=:S`b``=:l{ul{z```gj`b`al{[```gluu`b`b=:S`b`a=:lqluu`b`b=:S`b`b=:l{ul}t```blt~`b``lv}lv~`b`aj``aflqy`a``=:l}c=:ݲڲls}````l~tls|=:ls~`b`fj``fgj````lqy``a`lqy``i`=:lq~`b`fj``acj````=:l}clvqs``ae=:!l~tls|sԲҲٱrl~t=:ٲ!Ǹ=:ٲҲrl~tls|=:lvqs``af Բٱxl~tls|lvqs````=:lq``e`lqy``b`=:l}c=:xylqy``e`l~tls|lvqs``aeھ ݲ =:ٲrl~tls|lq~`b`fj``b`j````=:lrq``b`ls}```glr|````=:l}`ba`j``a`l}`ba`j``aalu~t=:S`b`a=:S`b`b=:S`b`c=:S`b`d=:S`b`e=:S`b`f=:=:=:=:S`ba`=:l{ulqy`be`ls}````=:l}cls}``ae=:y{ ìylqy`af`l~tls|Ǫ$Ҳڹ ߲rl~tls|=:lv}``afls}```f=:l}`ba`j``a`l}`ba`j``aalu~t=:lu~t=:=:S`bb`=:lv|z`bgbj`bbalu~t=:S`bba=:l{ult~`bb`l}t````lqy``e`=:lq~`b`bj``a`j````lqy``dd=:lq~`b`cj``a`j```blqy0abh=:lt~`b`blt~`b`clv|[`bgclu~t=:=:S`bc`=:lv|z`fb`j`bcc=:lv|z`bghj`bcb=:lyl}wz}ڲٲٲҲl~tlu~t=:=:S`bca=:lqy``e`=:lq~`b`dj``a`j````lqy```h=:lq~`b`ej``a`j```blqy`abh=:lt~`b`dlt~`b`eluu`bcb=:S`bcb=:lylvq```dlq``cej`e``j```ej```i=:S`bcc=:lylvq```dlq``cej``idj```ej```i=:=:S`c``=:S`c`a=:S`ca`=:=:S`cb`=:l{ult~`cb`ls}````l}t````lqy``e`=:lq~`ca`j```aj```bl}wlvqs``be=:yyl~tls|=:lq~`ca`j```cj````lqy`ae`=:lt~`ca`l}lu~t=:=:S`cd`=:lv|z`eicj`cdalu~t=:S`cda=:lv|z`bgdj`cdblu~t=:S`cdb=:lv|[`bh`lt~`cd`lu~t=:=:=:=:S`ce`=:lyl}w$ҲڲٲٲҲl~tlu~t=:=:S`cf`=:lyl}wlRRq=:߲ڲҲݲвq=:~Ť߲Ҳrl~tlu~t=:=:S`d`a=:lyl}wʲʲʲʱl~tlyz``adj`da`ls|qҲ۲ ٱxl~z````ls|=:ls~`d`aj`acfj````lv|[`bgelwya`adly[``admҲmP ,rl~tlv|[`bgdls|=:lv|]c```lv|]c``alv|]c``blv|]c``clv|[c``d=:lu~t=:S`d`b=:lyl}wl`a`eñyl~tlyz``adj`da`ls|qҲ۲ ٱxl~z````ls|=:ls~`d`bj`acfj````lv|[`bgflwya`adly[``admҲmP ,rl~tlv|[`bgdls|=:lv|]c```lv|]c``alv|]c``blv|[c``clv|]c``d=:lu~t=:S`da`=:lyl}wsͲrl~tlu~t=:S`daa=:lt~`daalu~t=:S`dab=:lyl``bbls~`dabj``baj````=:l}w#в z߲rl~tlwya`adls~`dabj`ac`j````ls|=:Ҳl~tlyz``adj`dacls|=:ls~`dabj`acfj````lv|[`bgilwya`adly[``adls}``a`mҲmP ,rlqy`af`l~tl}ls|=:lv|]c```lv|[c``alv|]c``blv|]c``clv|]c``d=:lv|[`bgdlu~t=:S`dac=:lyl}wsͲrl~tls~`dabj``aej````lu~t=:=:=:=:S`e``=:lylt~`e``l``bbls}``af=:l}wlwya``fmszmP ,ylqy`af`l~tl}l}|[```e=:PePͲֲyl~tlu~t=:=:S`e`a=:lylt~`e`al``bbls}``af=:l}wlwya``fmszmP ,ylqy`af`l~tl}l}|[```e=:PePͲֲyl~tlu~t=:=:=:Sab``=:l{ulq~ab``j``b`j```a=:lv~ab``j``aflvqy```a=:lqy`a``lvq```alq``cijab``j``faj``ab=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/SandE.pxe b/game_japanese/data/Stage/SandE.pxe new file mode 100644 index 0000000..c9cb423 Binary files /dev/null and b/game_japanese/data/Stage/SandE.pxe differ diff --git a/game_japanese/data/Stage/SandE.pxm b/game_japanese/data/Stage/SandE.pxm new file mode 100644 index 0000000..2084edc Binary files /dev/null and b/game_japanese/data/Stage/SandE.pxm differ diff --git a/game_japanese/data/Stage/SandE.tsc b/game_japanese/data/Stage/SandE.tsc new file mode 100644 index 0000000..9d32635 Binary files /dev/null and b/game_japanese/data/Stage/SandE.tsc differ diff --git a/game_japanese/data/Stage/Santa.pxe b/game_japanese/data/Stage/Santa.pxe new file mode 100644 index 0000000..ceaff1f Binary files /dev/null and b/game_japanese/data/Stage/Santa.pxe differ diff --git a/game_japanese/data/Stage/Santa.pxm b/game_japanese/data/Stage/Santa.pxm new file mode 100644 index 0000000..e79422a Binary files /dev/null and b/game_japanese/data/Stage/Santa.pxm differ diff --git a/game_japanese/data/Stage/Santa.tsc b/game_japanese/data/Stage/Santa.tsc new file mode 100644 index 0000000..9c18c0e --- /dev/null +++ b/game_japanese/data/Stage/Santa.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}```blvqy````lu~t=:S``ia=:l}~qls}```blvqy```alu~t=:S``ib=:l}~qls}```blvqy```blu~t=:S``ic=:l}~qls}```blvqy```clu~t=:S``id=:l}~qlv|z`cdaj``iils}```blvqy```dlu~t=:=:S``ii=:ls}``bhlvqy```dlu~t=:=:S`a``=:lyl``aalt~`a``lvq```dlq```fj``idj```dj``ab=:=:=:=:S`ab`=:l{ul}wlٲr=:w־qǦ½yl~tlu~t=:=:=:S`c``=:lyz```hj`c`a=:l{ul}wl~tlv|z`bdbj````=:‰ĂֲҲrl~tlu~t=:S`c`a=:l{ulwya``hl}wm~mP Ҳ ٱxl~z````ls|lwy````=:ly]```hlq~`c``j``a`j````lqy``c`lv|z`bdbj`c`blv|[`bdb=:l}wt¶ٲвl~tls|lwya`ably[``ab=:ls}``a`m‰mP ,rlqy`af`l~tls|l}lt~`c``lu~t=:=:S`c`b=:l{ult~`c`0lu~t=:=:=:S`e``=:lv|z`bbfj`e`f=:lv|z`bdbj`e`e=:lv|z`dhdj`e`d=:lv|z`bdaj`e`c=:lv|z`bd`j`e`b=:l{ulv|[`bd`l}w۲вڲԱrl~t=: вrl~tlwy```clq}[```cj````ls|=:ls}``a`mpsqmP ,rlqy`af`l~tl}lwy````ls| „xl~t=:ٲҲprl~t=:̲ݲ!q=:—v Ҳl~tlv|[`bdalu~t=:S`e`c=:l{ul}w—v q=:~ž߲rl~tlu~t=:S`e`d=:l{ul}wm‰mPǮҲxl~t=:—vв‰q=:ͲҲҲҲrl~tlu~t=:S`e`e=:l{ul}w‰!qԲxl~tlu~t=:S`e`f=:l{ul}w۹ٲٲڲrl~t=:ٲ}qql~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Shelt.pxa b/game_japanese/data/Stage/Shelt.pxa new file mode 100644 index 0000000..5397cc4 Binary files /dev/null and b/game_japanese/data/Stage/Shelt.pxa differ diff --git a/game_japanese/data/Stage/Shelt.pxe b/game_japanese/data/Stage/Shelt.pxe new file mode 100644 index 0000000..8d7c612 Binary files /dev/null and b/game_japanese/data/Stage/Shelt.pxe differ diff --git a/game_japanese/data/Stage/Shelt.pxm b/game_japanese/data/Stage/Shelt.pxm new file mode 100644 index 0000000..a5e4f80 Binary files /dev/null and b/game_japanese/data/Stage/Shelt.pxm differ diff --git a/game_japanese/data/Stage/Shelt.tsc b/game_japanese/data/Stage/Shelt.tsc new file mode 100644 index 0000000..33cfd9e Binary files /dev/null and b/game_japanese/data/Stage/Shelt.tsc differ diff --git a/game_japanese/data/Stage/Start.pxe b/game_japanese/data/Stage/Start.pxe new file mode 100644 index 0000000..1e03cc2 Binary files /dev/null and b/game_japanese/data/Stage/Start.pxe differ diff --git a/game_japanese/data/Stage/Start.pxm b/game_japanese/data/Stage/Start.pxm new file mode 100644 index 0000000..b6ba11b Binary files /dev/null and b/game_japanese/data/Stage/Start.pxm differ diff --git a/game_japanese/data/Stage/Start.tsc b/game_japanese/data/Stage/Start.tsc new file mode 100644 index 0000000..3f627e4 --- /dev/null +++ b/game_japanese/data/Stage/Start.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}```hlvqy````lu~t=:S``ia=:l}~qls}```hlvqy```alu~t=:S``ib=:l}~qls}```hlvqy```blu~t=:S``ic=:l}~qls}```hlvqy```clu~t=:S``id=:l}~qls}```hlvqy```dlu~t=:=:S`a``=:lyls~0a``j````j````=:l``aalvq```a=:lq``abj``iaj``cgj``aa=:=:=:S`b``=:l{ul{z```ej``ialyls}````l}w=:~ٲ}ֲl~tls|lv|[`dc`lq``ahj`e``j```bj````=:=:=:Sa```=:lu~t=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Statue.pxe b/game_japanese/data/Stage/Statue.pxe new file mode 100644 index 0000000..4bb689c Binary files /dev/null and b/game_japanese/data/Stage/Statue.pxe differ diff --git a/game_japanese/data/Stage/Statue.pxm b/game_japanese/data/Stage/Statue.pxm new file mode 100644 index 0000000..8474794 Binary files /dev/null and b/game_japanese/data/Stage/Statue.pxm differ diff --git a/game_japanese/data/Stage/Statue.tsc b/game_japanese/data/Stage/Statue.tsc new file mode 100644 index 0000000..fc82012 --- /dev/null +++ b/game_japanese/data/Stage/Statue.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}````lvqy````lu~t=:S``ia=:l}~qls}````lvqy```alu~t=:S``ib=:l}~q=:lq~`b``j````j``d`=:lq~`b`aj````j``c`=:lq~`b`bj````j``b`=:lv|zaecdj``ie=:lq~`b`cj````j````=:ls}````lvqy```blu~t=:S``ic=:l}~qls}````lvqy```clu~t=:S``id=:l}~qls}````lvqy```dlu~t=:=:S``ie=:lq~`b`cj````j``a`lqy```a=:lq~`b``j``a`j``d`=:lq~`b`aj``a`j``c`=:lq~`b`bj``a`j``b`=:lq~`b`cj``a`j``a`=:lvqy```blu~t=:=:=:S`a``=:l{ul``aalq~`a``j````j```b=:lvq````lv|zaecdj`a`a=:ls}``bdlq``hdj``i`j``aij``ba=:S`a`a=:lq`0hej``ifj``aij``ba=:=:S`b``=:S`b`a=:S`b`b=:S`b`c=:=:S`ba`=:l{ulv|zaei`j`bb`l}wl=:tl~tlu~t=:S`baa=:l{ulv|zaeiaj`bbal}wl=:tqól~tlu~t=:S`bab=:l{ulv|zaeibj`bbbl}wl=:tq|l~tlu~t=:S`bac=:l{ulv|zaeicj`bbcl}wl=:tPl~tlu~t=:=:S`bb`=:l{ul}wl=:t~xl~tlu~t=:S`bba=:l{ul}wl=:tl~tlu~t=:S`bbb=:l{ul}wl=:t|ól~tlu~t=:S`bbc=:l{ul}wl=:tzsl~tlu~t=:=:=:S`c``=:l{ul}wuuurl~tlu~t=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/Store.pxa b/game_japanese/data/Stage/Store.pxa new file mode 100644 index 0000000..df5d94d Binary files /dev/null and b/game_japanese/data/Stage/Store.pxa differ diff --git a/game_japanese/data/Stage/Stream.pxe b/game_japanese/data/Stage/Stream.pxe new file mode 100644 index 0000000..3484411 Binary files /dev/null and b/game_japanese/data/Stage/Stream.pxe differ diff --git a/game_japanese/data/Stage/Stream.pxm b/game_japanese/data/Stage/Stream.pxm new file mode 100644 index 0000000..9f85eb3 Binary files /dev/null and b/game_japanese/data/Stage/Stream.pxm differ diff --git a/game_japanese/data/Stage/Stream.tsc b/game_japanese/data/Stage/Stream.tsc new file mode 100644 index 0000000..645dbd8 --- /dev/null +++ b/game_japanese/data/Stage/Stream.tsc @@ -0,0 +1 @@ +0-FSS\S0-_pqd_fpxSST[_xqlSSST_p|gSSSS_idlSSSS_hqg0-FSS\T0-_pqd_fpxSST[_xqlSSST_p|gSSSS_idlSSST_hqg0-FSS\U0-_pqd_fpxSST[_xqlSSST_p|gSSSU_idlSSSU_evoSSSS_hqg0-FSS\V0-_pqd_fpxSST[_xqlSSST_p|gSSSS_idlSSSV_hqg0-FSS\W0-_pqd_fpxSST[_xqlSSST_p|gSSSS_idlSSSW_hqg0-0-FSS\X0-_fpxSSUV_idlSSSS_hqg0-0-FSTSS0-_nh|_idrSSST_fvv_wudSSWZ]SS\T]SSS[]SSS\0-0-FSUSS0-#SUTS0-0-0-FTSSS0-_nh|_erdTSSS0-_dqsSUSS]SSTS]SSSS0-_dqsSUTS]SSTS]SSSS0-_zdlSVSS_idrSSSU0-_xqlSSSS_fvv_hyhTSST0-0-FTSST0-_lwmSST[]TSTS_ioNSTYS_hyhTSSU0-0-FTSSU0-_fpxSSSS_iomS[VY]TSSV_hyhTSTS0-0-FTSSV0-_ioPS[VY_iomS[XT]TSTS_ioNTSWU0-_hyhTSTS0-0-FTSTS0-_qfmSVVY]TSTT0-_wudSSTX]SWTS]SSTY]SSTU_hqg0-0-FTSTT0-_lwNSSVY0-_wudSSTX]SWTS]SSTY]SSTU_hqg0-0- \ No newline at end of file diff --git a/game_japanese/data/Stage/Weed.pxa b/game_japanese/data/Stage/Weed.pxa new file mode 100644 index 0000000..303184c Binary files /dev/null and b/game_japanese/data/Stage/Weed.pxa differ diff --git a/game_japanese/data/Stage/Weed.pxe b/game_japanese/data/Stage/Weed.pxe new file mode 100644 index 0000000..d28877e Binary files /dev/null and b/game_japanese/data/Stage/Weed.pxe differ diff --git a/game_japanese/data/Stage/Weed.pxm b/game_japanese/data/Stage/Weed.pxm new file mode 100644 index 0000000..6e3e85d Binary files /dev/null and b/game_japanese/data/Stage/Weed.pxm differ diff --git a/game_japanese/data/Stage/Weed.tsc b/game_japanese/data/Stage/Weed.tsc new file mode 100644 index 0000000..e43f30f --- /dev/null +++ b/game_japanese/data/Stage/Weed.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}```elvqy````lu~t=:S``ia=:l}~qls}```elvqy```alu~t=:S``ib=:l}~qls}```elvqy```blu~t=:S``ic=:l}~qls}```elvqy```clu~t=:S``id=:l}~qls}```elvqy```dlu~t=:=:S``ih=:l{ul}~qls}```elv|[`bbd=:lq~`a``j```aj````lvqy```d=:ls~`d`aj`aabj```blqy`a``=:lq~`a``j````j````=:l}t```bl}slt~`d`alu~t=:=:=:S``ii=:l{ul}~qls}```e=:lq~``iij``a`j````=:lvqy```dlqy``g`=:lq~``iij````j````lqy``c`lu~t=:=:=:S`a``=:l{ul}wq۲ ٱxlv|]`bbgl~z````ls|=:ls~`d``j`aaaj```blx}slqy``f`lq~`a``j```aj````=:lqy`a``lvq```dlv|z`baij`ac`lq```aj``iij```ej```h=:=:S`a`a=:lylv|]`bbglv|z`babj`a`bl}wz}ڲٲٲҲrl~tlu~t=:S`a`b=:lyl``aalt~`a`alvq```dlq```gj``idj``aej```h=:S`a`c=:lyl``aalt~`a`clvq```dlq```hj``idj```ij``aa=:=:S`a`d=:ly=:lv|z`badj`a`f=:lyz```ij`a`e=:l}wz}ڲٲٲҲrl~tlu~t=:S`a`e=:l``bbl}wlwya``imz}mP rl~tls|=:lwy````lv|[`badluu`a`f=:S`a`f=:lyl``aalt~`a`dlvq```dlq``bej``idj``afj```g=:=:=:S`a`g=:lyl``aalt~`a`glvq```dlq``bfj``idj``a`j```g=:S`a`h=:lyl``aalt~`a`hlvq```dlq``bgj``idj``a`j```i=:=:=:S`a`i=:ly=:lv|z`bbbj`aaa=:lyz``a`j`aa`=:l}wz}ڲٲٲҲԲrl~t=:{ٲҲrl~tlu~t=:S`aa`=:l``bbl}wlwya`a`m{z}mP rl~tls|=:lwy````lv|[`bbbluu`aaa=:S`aaa=:lyl``aalt~`a`ilvq```dlq``bhj``idj```fj``ac=:=:S`aab=:lylvq```dlq``ahj``idj```fj``a`=:=:S`aac=:lyl``aalt~`aaclvq```dlq``c`j``idj```gj```i=:=:=:=:S`aba=:lyl}wl=:ól~tlu~t=:S`abc=:lyl}wl=:Ô걦l~tlu~t=:=:S`ac`=:l{ulv|]`cbilv|]`bail}t```blq``aaj`db`j``bdj``bi=:=:=:=:S`b``=:lylt~`b``lv|[`ba`=:ls}``a`lwya``cly[```cl}w=:móz}mP ,rlqy`af`l~tls|=:lwy````l}lu~t=:=:S`b`a=:lylv|z`bbhj`b`glv|[`bbhl}wزrl~tls|~žҲٱrl~t=:Կy!Ҳxl~tls| вҲҲrl~tls|luu`b`g=:=:=:S`b`b=:lyz```hj`b`dl~sz``idj`b`c=:lyl``bbls~`b`bj``baj````=:l}w#в z߲rl~tlwya``hly[```hls|=:ls}``a`m~mP ,rlqy`af`l~tlt~`b`bl}lu~t=:S`b`c=:l``gbls~`b`bj``aej```blu~t=:S`b`d=:ls~`b`bj```aj````lu~t=:=:S`b`e=:lv|z`dhaj`b`f=:lyl}wǻpľ Ҳrl~t=:~ٲڲÔ !rl~t=:޲ٲٲÔ „rl~tlu~t=:S`b`f=:lyl}wҲҲ ֲԱrl~tls|óò ϲ =:ǻp"ql~t=:ݿڲ!rl~tlu~t=:=:S`b`g=:lyl}w!=:~s ߲rl~t=:ղ Ҳrl~tlu~t=:=:S`ba`=:lyl}wzÍs~=:㾓Ҳl~tlu~t=:=:S`bb`=:lyz``acj`be`=:lv|z`bbaj`bd`=:lv|z`dhdj`bci=:lv|z`baej`bcd=:lyl}wzٲұl~tls|=:ls~`bc`j`a`fj````l}t```blu~t=:S`bc`=:lv|z`bbaj`bcg=:lv|z`dhdj`bcf=:lv|z`bbcj`bce=:lv|z`bafj`bcc=:lv|z`baej`bcb=:lyl}w۲ ,Բ~ٲҲl~tls| Ͳ~rl~t=:ٲҲ!߲q=:ݲҲٱxl~z`bcals|=:вڲԱyl~tls| #߾ݲrl~tlwya``ily[```ilv|[`baels|=:ls}`0a`mz}mP #߾rlqy`af`l~tl}ls|Ĺ޲¶Ǿ!rl~t=:ݲrl~tlu~t=:S`bca=:lyl}wбqԱl~t=:l~tlu~t=:S`bcb=:lyl}wǺrl~t=: в߲ݲrl~tlu~t=:S`bcc=:lyl}wֱxl~tz}Ҳٱxyl~t=: Ҳl~tls|uuurl~tlv|[`bbcluu`bce=:=:S`bcd=:lylv|[`bafl}w޼ұrl~t=:ԲҲԲrl~tlu~t=:S`bce=:lyl}w޼Ҳq=:#ٲҲl~t=:ٲҲ+pl~tlu~t=:=:S`bcf=:lyl}wֱq• xl~tls|=:ql~t=: „ٱrl~tls|uuurl~tls|{xl~t=: rl~tls|lqy`a``=:l}w#߾ݲrl~tlwya`a`ly[``a`lv|[`bbals|=:ls}``a`m{z}mP #߾rlqy`af`l~tl}ls|ٲ߲в!rl~t=:{Ҳвrl~t=:۲вrl~t=:Ǻr~yl~tlu~t=:S`bcg=:lyl}w•Ǹٱxl~tlu~t=:=:=:S`bci=:lyl}w賄ҲҲl~tls|=:ls~`bc`j`a`fj````l}t```blu~t=:S`bd`=:lyl}w賄ҲҲl~tlu~t=:=:S`be`=:lylv|[`ebalv|[`ebbly]``ac=:l}wlwya`acm•mP rl~tls|=:lvq```dlq``ahj`b``j```fj````=:=:=:S`c`b=:lylv|z`bahj```alv|[`bah=:l``bbls~`c`bj``baj````=:l}w#в z߲rl~tluu``c`=:=:S`c`e=:lylt~`c`el``bbls}``af=:l}wlwya``fmszmP ,ylqy`af`l~tl}l}|[```e=:PePͲֲyl~tlu~t=:=:S`d``=:S`d`a=:=:S`de`=:lyl}ws~Բٱxl~tlu~t=:S`dea=:S`deb=:=:S`e``=:ly=:lv|z`baaj`e`a=:lv|[`baa=:l}wбql~t=:Ɯórl~tls| ݲ q=:órl~t=:ֲq۲!߲q=:z} Ǿ rl~tls|ڲ,ұrl~tlu~t=:S`e`a=:lyl}wz}Ҳ,ұl~t=:ԲԱl~tlu~t=:=:=:S`e`b=:lyz```cj`e`clu~t=:S`e`c=:l{ulv|[`babl}}`l}t````lqy``c`ly=:l}wбql~tls|Ɯz}yl~tly]```clwya``cls|=:móz}mP Þrl~tlwy````ls|вڲԱyl~tls|=:l{ulq~`e``j```cj````lqy`agflq~`e``j````j```b=:l``aals~`a`aj````j````lqy``a`=:lyl}wٲuǸrl~t=:ҲҲвrl~tls|l{u=:lq~`e``j```ej```blqy``a`lt~`e``=:l``aals~`a`aj``ahj````lt~`e`bl``bclu~t=:=:S`f``=:l{ulv|[`bails}````lvqy```dl}t```b=:l}wlvqs``a`rl~tls|lvqs````=:lq~`debj````j````lqy``a`=:l}wlvqs``ahz~rl~tlqy``a`lq~`deaj````j```bls|lvqs``a`ұxl~tls|lvqs````=:lvqs````lqy``a`lq~`debj````j```blv~`de`j``aflqy``e`=:l}wlvqs``ah۲ٱxl~tls|lvqs````=:lq~`deaj```cj```blqy``d`=:lq~`debj```cj```blqy``d`=:lq~`deaj```ej````lqy``cf=:lq~`debj````j````lqy``e`=:lq~`deaj````j```b=:l}wlvqs``a`Ҳ߲Բrl~tls|lvqs````=:lq~`deaj```ej````=:lq~`debj```ej````lqy``b`=:lq~`de`j``a`j````lt~`dealt~`deblqy``c`=:lq~`de`j``b`j````lqy``f`lv}``afl}r````=:lqy`b``l}w !ղֱֲֲֲyylqy``e`l~tls}```e=:lt~`de`lv|]`ebclv|[`bbelu~t=:=:=:Sab``=:l{ulq~ab``j``b`j```b=:lv~ab``j``aflvqy```a=:lqy`a``lvq```alq``a`jab``j``e`j``cd=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/WeedB.pxe b/game_japanese/data/Stage/WeedB.pxe new file mode 100644 index 0000000..b2a1ca6 Binary files /dev/null and b/game_japanese/data/Stage/WeedB.pxe differ diff --git a/game_japanese/data/Stage/WeedB.pxm b/game_japanese/data/Stage/WeedB.pxm new file mode 100644 index 0000000..d5dcf5b Binary files /dev/null and b/game_japanese/data/Stage/WeedB.pxm differ diff --git a/game_japanese/data/Stage/WeedB.tsc b/game_japanese/data/Stage/WeedB.tsc new file mode 100644 index 0000000..cb5ea63 --- /dev/null +++ b/game_japanese/data/Stage/WeedB.tsc @@ -0,0 +1 @@ +ǤۤȤۤɤۤʤۤˤۤǤΤǤۤȤ'k9 kh~A%V[9ۤɤ T@"+ANۤʤ Tw_9ۤǤǤǤ,+7!FTǤɤۤ \ No newline at end of file diff --git a/game_japanese/data/Stage/WeedD.pxe b/game_japanese/data/Stage/WeedD.pxe new file mode 100644 index 0000000..1807ed7 Binary files /dev/null and b/game_japanese/data/Stage/WeedD.pxe differ diff --git a/game_japanese/data/Stage/WeedD.pxm b/game_japanese/data/Stage/WeedD.pxm new file mode 100644 index 0000000..3d5bab0 Binary files /dev/null and b/game_japanese/data/Stage/WeedD.pxm differ diff --git a/game_japanese/data/Stage/WeedD.tsc b/game_japanese/data/Stage/WeedD.tsc new file mode 100644 index 0000000..0b59058 --- /dev/null +++ b/game_japanese/data/Stage/WeedD.tsc @@ -0,0 +1 @@ +>;Taaja>;m~rmt~aaaamwrzaaaamvu>;Taajb>;m~rmt~aaaamwrzaaabmvu>;Taajc>;m~rmt~aaaamwrzaaacmvu>;Taajd>;m~rmt~aaaamwrzaaadmvu>;Taaje>;m~rmt~aaaamwrzaaaemvu>;>;Tabaa>;mzmaa1bmuabaamwraaaemraaagkaajekacddkaabh>;>;>;Tadae>;mzmuadaemaaccmt~aabg>;m~xmxzbaagnt{nQ!-zmrzabgamum~m~}\aaaf>;QfQγ׳zmumvu>;>; \ No newline at end of file diff --git a/game_japanese/data/Stage/WeedS.pxe b/game_japanese/data/Stage/WeedS.pxe new file mode 100644 index 0000000..62e54d8 Binary files /dev/null and b/game_japanese/data/Stage/WeedS.pxe differ diff --git a/game_japanese/data/Stage/WeedS.pxm b/game_japanese/data/Stage/WeedS.pxm new file mode 100644 index 0000000..06b6f79 Binary files /dev/null and b/game_japanese/data/Stage/WeedS.pxm differ diff --git a/game_japanese/data/Stage/WeedS.tsc b/game_japanese/data/Stage/WeedS.tsc new file mode 100644 index 0000000..f08a0db --- /dev/null +++ b/game_japanese/data/Stage/WeedS.tsc @@ -0,0 +1 @@ +b_xb_b_xb_b_xb_b_xb_Ub_xb_b_b_xb_b_b_ \ No newline at end of file diff --git a/game_japanese/data/Stage/White.pxa b/game_japanese/data/Stage/White.pxa new file mode 100644 index 0000000..381e014 Binary files /dev/null and b/game_japanese/data/Stage/White.pxa differ diff --git a/game_japanese/data/Stage/e_Blcn.pxe b/game_japanese/data/Stage/e_Blcn.pxe new file mode 100644 index 0000000..6457e91 Binary files /dev/null and b/game_japanese/data/Stage/e_Blcn.pxe differ diff --git a/game_japanese/data/Stage/e_Blcn.pxm b/game_japanese/data/Stage/e_Blcn.pxm new file mode 100644 index 0000000..679c35a Binary files /dev/null and b/game_japanese/data/Stage/e_Blcn.pxm differ diff --git a/game_japanese/data/Stage/e_Blcn.tsc b/game_japanese/data/Stage/e_Blcn.tsc new file mode 100644 index 0000000..313fb2c --- /dev/null +++ b/game_japanese/data/Stage/e_Blcn.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ahlvqy````lu~t=:S``ia=:l}~qls}``ahlvqy```alu~t=:S``ib=:l}~qls}``ahlvqy```blu~t=:S``ic=:l}~qls}``ahlvqy```clu~t=:S`0id=:l}~qls}``ahlvqy```dlu~t=:=:S`a``=:l{ulvqy```alqy`b``=:lq~`b``j``a`j````=:lqy`a``=:lvq```alq````ja`i`j```aj``ae=:=:S`b``=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/e_Ceme.pxe b/game_japanese/data/Stage/e_Ceme.pxe new file mode 100644 index 0000000..c7f204e Binary files /dev/null and b/game_japanese/data/Stage/e_Ceme.pxe differ diff --git a/game_japanese/data/Stage/e_Ceme.pxm b/game_japanese/data/Stage/e_Ceme.pxm new file mode 100644 index 0000000..2b8f880 Binary files /dev/null and b/game_japanese/data/Stage/e_Ceme.pxm differ diff --git a/game_japanese/data/Stage/e_Ceme.tsc b/game_japanese/data/Stage/e_Ceme.tsc new file mode 100644 index 0000000..07d7398 --- /dev/null +++ b/game_japanese/data/Stage/e_Ceme.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ahlvqy````lu~t=:S``ia=:l}~qls}``ahlvqy```alu~t=:S``ib=:l}~qls}``ahlvqy```blu~t=:S``ic=:l}~qls}0`ahlvqy```clu~t=:S``id=:l}~qls}``ahlvqy```dlu~t=:=:S`a``=:l{ulvqy```alqy`c``=:lvq```alq````ja`d`j```aj``ae=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/e_Jenk.pxe b/game_japanese/data/Stage/e_Jenk.pxe new file mode 100644 index 0000000..4eb1d1e Binary files /dev/null and b/game_japanese/data/Stage/e_Jenk.pxe differ diff --git a/game_japanese/data/Stage/e_Jenk.pxm b/game_japanese/data/Stage/e_Jenk.pxm new file mode 100644 index 0000000..da606ad Binary files /dev/null and b/game_japanese/data/Stage/e_Jenk.pxm differ diff --git a/game_japanese/data/Stage/e_Jenk.tsc b/game_japanese/data/Stage/e_Jenk.tsc new file mode 100644 index 0000000..f935134 --- /dev/null +++ b/game_japanese/data/Stage/e_Jenk.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ahlvqy````lu~t=:S``ia=:l}~qls}``ahlvqy```alu~t=:S``ib=:l}~qls}``ahlvqy```blu~t=:S``ic=:l}~qls}``ahlvqy```clu~t=:S``id=:l}~qls}``ahlvqy```dlu~t=:=:=:S`a``=:l{ulvqy```alqy0b``lv|z`afbj`aa`=:lqy`a``=:lvq```alq````ja`b`j```aj``ae=:S`aa`=:l{u=:ls~`aa`j````j````lqy``b`=:ls~`aa`j`aacj````lqy``b`=:lq~`aaaj````j```blqy``f`=:lvq```alq````ja`b`j```aj``ae=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/e_Labo.pxe b/game_japanese/data/Stage/e_Labo.pxe new file mode 100644 index 0000000..cf05d7b Binary files /dev/null and b/game_japanese/data/Stage/e_Labo.pxe differ diff --git a/game_japanese/data/Stage/e_Labo.pxm b/game_japanese/data/Stage/e_Labo.pxm new file mode 100644 index 0000000..ec419d6 Binary files /dev/null and b/game_japanese/data/Stage/e_Labo.pxm differ diff --git a/game_japanese/data/Stage/e_Labo.tsc b/game_japanese/data/Stage/e_Labo.tsc new file mode 100644 index 0000000..ff726e3 --- /dev/null +++ b/game_japanese/data/Stage/e_Labo.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ahlvqy````lu~t=:S``ia=:l}~qls}``ahlvqy```alu~t=:S``ib=:l}~qls}``ahlvqy```blu~t=:S``ic=:l}~qls}`0ahlvqy```clu~t=:S``id=:l}~qls}``ahlvqy```dlu~t=:=:=:S`a``=:l{ulvqy```alqy`d``=:lvq```alq````ja`f`j```aj``ae=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/e_Malc.pxe b/game_japanese/data/Stage/e_Malc.pxe new file mode 100644 index 0000000..56cab9d Binary files /dev/null and b/game_japanese/data/Stage/e_Malc.pxe differ diff --git a/game_japanese/data/Stage/e_Malc.pxm b/game_japanese/data/Stage/e_Malc.pxm new file mode 100644 index 0000000..73cc752 Binary files /dev/null and b/game_japanese/data/Stage/e_Malc.pxm differ diff --git a/game_japanese/data/Stage/e_Malc.tsc b/game_japanese/data/Stage/e_Malc.tsc new file mode 100644 index 0000000..f4faf39 --- /dev/null +++ b/game_japanese/data/Stage/e_Malc.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ahlvqy````lu~t=:S``ia=:l}~qls}``ahlvqy```alu~t=:S``ib=:l}~qls}``ahlvqy```blu~t=:S``ic=:l}~qls}``ahlvqy```clu~t=:S``id=:l}~qls}``ahlvqy```dlu~t=:=:=:S`a``=:l{ulvqy``0a=:lqy``e`lq~`ba`j`a``j````=:lqy``e`lq~`bb`j`a``j````=:lqy``e`lq~`bc`j`a``j````=:lqy``e`lq~`bd`j`a``j````=:lqy``e`lq~`bd`j`aa`j````=:lqy`a``=:lvq```alq````ja`c`j```aj``ae=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/e_Maze.pxe b/game_japanese/data/Stage/e_Maze.pxe new file mode 100644 index 0000000..340ba34 Binary files /dev/null and b/game_japanese/data/Stage/e_Maze.pxe differ diff --git a/game_japanese/data/Stage/e_Maze.pxm b/game_japanese/data/Stage/e_Maze.pxm new file mode 100644 index 0000000..9e4b942 Binary files /dev/null and b/game_japanese/data/Stage/e_Maze.pxm differ diff --git a/game_japanese/data/Stage/e_Maze.tsc b/game_japanese/data/Stage/e_Maze.tsc new file mode 100644 index 0000000..23cb89f --- /dev/null +++ b/game_japanese/data/Stage/e_Maze.tsc @@ -0,0 +1 @@ +=:S``i`=:l}~qls}``ahlvqy````lu~t=:S``ia=:l}~qls}``ahlvqy```alu~t=:S``ib=:l}~qls}``ahlvqy```blu~t=:S``ic=:l}~qls}``ahlvqy```clu~t=:S``id=:l}~qls}``ahlvqy```dlu~t=:=:=:S`a``=:l{ulqy```b=:lq~`b``j``a0j````=:lq~`bb`j``b`j````=:lq~`bc`j``a`j````=:lv|zb```j`a`aluu`aa`=:S`a`a=:lq~`c``j```aj```bluu`aa`=:=:S`aa`=:lvqy```alqy`c``=:lvq```alq````ja`a`j```aj``ae=:=:S`b``=:S`ba`=:S`bb`=:S`bc`=:S`c``=:=: \ No newline at end of file diff --git a/game_japanese/data/Stage/e_Sky.pxe b/game_japanese/data/Stage/e_Sky.pxe new file mode 100644 index 0000000..4a1b6c9 Binary files /dev/null and b/game_japanese/data/Stage/e_Sky.pxe differ diff --git a/game_japanese/data/Stage/e_Sky.pxm b/game_japanese/data/Stage/e_Sky.pxm new file mode 100644 index 0000000..5771f71 Binary files /dev/null and b/game_japanese/data/Stage/e_Sky.pxm differ diff --git a/game_japanese/data/Stage/e_Sky.tsc b/game_japanese/data/Stage/e_Sky.tsc new file mode 100644 index 0000000..1a7a445 --- /dev/null +++ b/game_japanese/data/Stage/e_Sky.tsc @@ -0,0 +1 @@ +NKdqqzqNK}}qqry}qqqq}NKdqqzrNK}}qqry}qqqr}NKdqqzsNK}}qqry}qqqs}NKdqqztNK}}qqry}qqqt}NKdqqzuNK}}qqry}qqqu}NKNKNKdqrqqNK}}sqqq{qrqr}qqqsNK}qsqq{qqsq{qqqsNK}Aqsrq{qqtq{qqqq}qqqsNK}qsqq{qquq{qqqsNK}qsrq{qqrq{qqqq}qrrqNKdqrqrNK}qsqq{qqqq{qqqq}qqqsNK}qsrq{qtvw{qqqsNK}qrrqNKdqrrqNK}qqvqNK}qqqr}qtqqNK}qqqr}qqqq{rqvq{qqqr{qqrvNKNKdqsqqNKdqsrqNKNK \ No newline at end of file diff --git a/game_japanese/data/StageImage.pbm b/game_japanese/data/StageImage.pbm new file mode 100644 index 0000000..a6e6b8f Binary files /dev/null and b/game_japanese/data/StageImage.pbm differ diff --git a/game_japanese/data/StageSelect.tsc b/game_japanese/data/StageSelect.tsc new file mode 100644 index 0000000..9c3347a --- /dev/null +++ b/game_japanese/data/StageSelect.tsc @@ -0,0 +1 @@ +drqqqNK}}}Ԟ)2ƒ}zzzz}NKdrqqrNK}}}ğľĔ2ٍ}zzzz}NKdrqqsNK}}}ďĕ}Azzzz}NKdrqqtNK}}}'}zzzz}NKdrqquNK}}}̼}zzzz}NKdrqqvNK}}}&ՠ}zzzz}NKNK \ No newline at end of file diff --git a/game_japanese/data/TextBox.pbm b/game_japanese/data/TextBox.pbm new file mode 100644 index 0000000..99e8197 Binary files /dev/null and b/game_japanese/data/TextBox.pbm differ diff --git a/game_japanese/data/Title.pbm b/game_japanese/data/Title.pbm new file mode 100644 index 0000000..334005d Binary files /dev/null and b/game_japanese/data/Title.pbm differ diff --git a/game_japanese/data/bk0.pbm b/game_japanese/data/bk0.pbm new file mode 100644 index 0000000..ba80482 Binary files /dev/null and b/game_japanese/data/bk0.pbm differ diff --git a/game_japanese/data/bkBlack.pbm b/game_japanese/data/bkBlack.pbm new file mode 100644 index 0000000..812f0b6 Binary files /dev/null and b/game_japanese/data/bkBlack.pbm differ diff --git a/game_japanese/data/bkBlue.pbm b/game_japanese/data/bkBlue.pbm new file mode 100644 index 0000000..11329cf Binary files /dev/null and b/game_japanese/data/bkBlue.pbm differ diff --git a/game_japanese/data/bkFall.pbm b/game_japanese/data/bkFall.pbm new file mode 100644 index 0000000..110e6df Binary files /dev/null and b/game_japanese/data/bkFall.pbm differ diff --git a/game_japanese/data/bkFog.pbm b/game_japanese/data/bkFog.pbm new file mode 100644 index 0000000..3a61a18 Binary files /dev/null and b/game_japanese/data/bkFog.pbm differ diff --git a/game_japanese/data/bkGard.pbm b/game_japanese/data/bkGard.pbm new file mode 100644 index 0000000..1cec51f Binary files /dev/null and b/game_japanese/data/bkGard.pbm differ diff --git a/game_japanese/data/bkGray.pbm b/game_japanese/data/bkGray.pbm new file mode 100644 index 0000000..cdef9d4 Binary files /dev/null and b/game_japanese/data/bkGray.pbm differ diff --git a/game_japanese/data/bkGreen.pbm b/game_japanese/data/bkGreen.pbm new file mode 100644 index 0000000..b213e8e Binary files /dev/null and b/game_japanese/data/bkGreen.pbm differ diff --git a/game_japanese/data/bkMaze.pbm b/game_japanese/data/bkMaze.pbm new file mode 100644 index 0000000..765a30a Binary files /dev/null and b/game_japanese/data/bkMaze.pbm differ diff --git a/game_japanese/data/bkMoon.pbm b/game_japanese/data/bkMoon.pbm new file mode 100644 index 0000000..4877e5f Binary files /dev/null and b/game_japanese/data/bkMoon.pbm differ diff --git a/game_japanese/data/bkRed.pbm b/game_japanese/data/bkRed.pbm new file mode 100644 index 0000000..0802ccb Binary files /dev/null and b/game_japanese/data/bkRed.pbm differ diff --git a/game_japanese/data/bkWater.pbm b/game_japanese/data/bkWater.pbm new file mode 100644 index 0000000..c0dc6a5 Binary files /dev/null and b/game_japanese/data/bkWater.pbm differ diff --git a/game_japanese/data/casts.pbm b/game_japanese/data/casts.pbm new file mode 100644 index 0000000..96f3d7f Binary files /dev/null and b/game_japanese/data/casts.pbm differ diff --git a/game_japanese/data/npc.tbl b/game_japanese/data/npc.tbl new file mode 100644 index 0000000..631be31 Binary files /dev/null and b/game_japanese/data/npc.tbl differ diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..d5af551 Binary files /dev/null and b/screenshot.png differ diff --git a/src/ArmsItem.cpp b/src/ArmsItem.cpp new file mode 100644 index 0000000..abb2b26 --- /dev/null +++ b/src/ArmsItem.cpp @@ -0,0 +1,643 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "ArmsItem.h" + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Escape.h" +#include "Game.h" +#include "KeyControl.h" +#include "Main.h" +#include "Shoot.h" +#include "Sound.h" +#include "TextScr.h" + +ARMS gArmsData[ARMS_MAX]; +ITEM gItemData[ITEM_MAX]; + +int gSelectedArms; +int gSelectedItem; + +int gCampTitleY; + +/// True if we're in the items section of the inventory (not in the weapons section) (only relevant when the inventory is open) +BOOL gCampActive; + +int gArmsEnergyX = 16; + +void ClearArmsData(void) +{ +#ifdef FIX_BUGS + gSelectedArms = 0; // Should probably be done in order to avoid potential problems with the selected weapon being invalid (like is done in SubArmsData) +#endif + gArmsEnergyX = 32; + memset(gArmsData, 0, sizeof(gArmsData)); +} + +void ClearItemData(void) +{ + memset(gItemData, 0, sizeof(gItemData)); +} + +BOOL AddArmsData(long code, long max_num) +{ + // Search for code + int i = 0; + while (i < ARMS_MAX) + { + if (gArmsData[i].code == code) + break; // Found identical + + if (gArmsData[i].code == 0) + break; // Found free slot + + ++i; + } + + if (i == ARMS_MAX) + return FALSE; // No space left + + if (gArmsData[i].code == 0) + { + // Initialize new weapon + memset(&gArmsData[i], 0, sizeof(ARMS)); + gArmsData[i].level = 1; + } + + // Set weapon and ammo + gArmsData[i].code = code; + gArmsData[i].max_num += max_num; + gArmsData[i].num += max_num; + + // Cap the amount of current ammo to the maximum amount of ammo + if (gArmsData[i].num > gArmsData[i].max_num) + gArmsData[i].num = gArmsData[i].max_num; + + return TRUE; +} + +BOOL SubArmsData(long code) +{ + // Search for code + int i; + for (i = 0; i < ARMS_MAX; ++i) + if (gArmsData[i].code == code) + break; // Found + +#ifdef FIX_BUGS + if (i == ARMS_MAX) +#else + if (i == ITEM_MAX) // Wrong +#endif + return FALSE; // Not found + + // Shift all arms from the right to the left + for (++i; i < ARMS_MAX; ++i) + gArmsData[i - 1] = gArmsData[i]; + + // Clear farthest weapon and select first + gArmsData[i - 1].code = 0; + gSelectedArms = 0; + + return TRUE; +} + +BOOL TradeArms(long code1, long code2, long max_num) +{ + // Search for code1 + int i = 0; + while (i < ARMS_MAX) + { + if (gArmsData[i].code == code1) + break; // Found identical + + ++i; + } + + if (i == ARMS_MAX) + return FALSE; // Not found + + // Initialize new weapon replacing old one, but adding the maximum ammunition to that of the old weapon. + gArmsData[i].level = 1; + gArmsData[i].code = code2; + gArmsData[i].max_num += max_num; + gArmsData[i].num += max_num; + gArmsData[i].exp = 0; + + return TRUE; +} + +BOOL AddItemData(long code) +{ + // Search for code + int i = 0; + while (i < ITEM_MAX) + { + if (gItemData[i].code == code) + break; // Found identical + + if (gItemData[i].code == 0) + break; // Found free slot + + ++i; + } + + if (i == ITEM_MAX) + return FALSE; // Not found + + gItemData[i].code = code; + + return TRUE; +} + +BOOL SubItemData(long code) +{ + // Search for code + int i; + for (i = 0; i < ITEM_MAX; ++i) + if (gItemData[i].code == code) + break; // Found + + if (i == ITEM_MAX) + return FALSE; // Not found + + // Shift all items from the right to the left + for (++i; i < ITEM_MAX; ++i) + gItemData[i - 1] = gItemData[i]; + + gItemData[i - 1].code = 0; + gSelectedItem = 0; + + return TRUE; +} + +/// Update the inventory cursor +void MoveCampCursor(void) +{ + BOOL bChange; + + // Compute the current amount of weapons and items + int arms_num = 0; + int item_num = 0; + while (gArmsData[arms_num].code != 0) + ++arms_num; + while (gItemData[item_num].code != 0) + ++item_num; + + if (arms_num == 0 && item_num == 0) + return; // Empty inventory + + // True if we're currently changing cursor position + bChange = FALSE; + + if (!gCampActive) + { + // Handle selected weapon + if (gKeyTrg & gKeyLeft) + { + --gSelectedArms; + bChange = TRUE; + } + + if (gKeyTrg & gKeyRight) + { + ++gSelectedArms; + bChange = TRUE; + } + + if (gKeyTrg & (gKeyUp | gKeyDown)) + { + // If there are any items, we're changing to the items section, since the weapons section has only 1 row + if (item_num != 0) + gCampActive = TRUE; + + bChange = TRUE; + } + + // Loop around gSelectedArms if needed + if (gSelectedArms < 0) + gSelectedArms = arms_num - 1; + + if (gSelectedArms > arms_num - 1) + gSelectedArms = 0; + } + else + { + // Handle selected item + if (gKeyTrg & gKeyLeft) + { + if (gSelectedItem % 6 == 0) + gSelectedItem += 5; + else + gSelectedItem -= 1; + + bChange = TRUE; + } + + if (gKeyTrg & gKeyRight) + { + if (gSelectedItem == item_num - 1) + gSelectedItem = (gSelectedItem / 6) * 6; // Round down to multiple of 6 + else if (gSelectedItem % 6 == 5) + gSelectedItem -= 5; // Loop around row + else + gSelectedItem += 1; + + bChange = TRUE; + } + + if (gKeyTrg & gKeyUp) + { + if (gSelectedItem / 6 == 0) + gCampActive = FALSE; // We're on the first row, transition to weapons + else + gSelectedItem -= 6; + + bChange = TRUE; + } + + if (gKeyTrg & gKeyDown) + { + if (gSelectedItem / 6 == (item_num - 1) / 6) + gCampActive = FALSE; // We're on the last row, transition to weapons + else + gSelectedItem += 6; + + bChange = TRUE; + } + + if (gSelectedItem >= item_num) + gSelectedItem = item_num - 1; // Don't allow selecting a non-existing item + + if (gCampActive && gKeyTrg & gKeyOk) + StartTextScript(6000 + gItemData[gSelectedItem].code); + } + + if (bChange) + { + if (gCampActive == FALSE) + { + // Switch to a weapon + PlaySoundObject(SND_SWITCH_WEAPON, SOUND_MODE_PLAY); + + if (arms_num != 0) + StartTextScript(1000 + gArmsData[gSelectedArms].code); + else + StartTextScript(1000); + } + else + { + // Switch to an item + PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY); + + if (item_num != 0) + StartTextScript(5000 + gItemData[gSelectedItem].code); + else + StartTextScript(5000); + } + } +} + +/// Draw the inventory +void PutCampObject(void) +{ + static unsigned int flash; + + int i; + + /// Rect for the current weapon + RECT rcArms; + + /// Rect for the current item + RECT rcItem; + + /// Probably the rect for the slash + RECT rcPer = {72, 48, 80, 56}; + + /// Rect for when there is no ammo (double dashes) + RECT rcNone = {80, 48, 96, 56}; + + /// Rect for the "Lv" text! + RECT rcLv = {80, 80, 96, 88}; + + /// Final rect drawn on the screen + RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + + /// Cursor rect array for weapons, element [1] being for when the cursor is flashing + RECT rcCur1[2] = {{0, 88, 40, 128}, {40, 88, 80, 128}}; + + /// Cursor rect array for items, element [1] being for when the cursor is flashing + RECT rcCur2[2] = {{80, 88, 112, 104}, {80, 104, 112, 120}}; + + RECT rcTitle1 = {80, 48, 144, 56}; + RECT rcTitle2 = {80, 56, 144, 64}; + RECT rcBoxTop = {0, 0, 244, 8}; + RECT rcBoxBody = {0, 8, 244, 16}; + RECT rcBoxBottom = {0, 16, 244, 24}; + + // Draw box + PutBitmap3(&rcView, (WINDOW_WIDTH / 2) - 122, (WINDOW_HEIGHT / 2) - 112, &rcBoxTop, SURFACE_ID_TEXT_BOX); + for (i = 1; i < 18; ++i) + PutBitmap3(&rcView, (WINDOW_WIDTH / 2) - 122, ((WINDOW_HEIGHT / 2) - 120) + ((i + 1) * 8), &rcBoxBody, SURFACE_ID_TEXT_BOX); + PutBitmap3(&rcView, (WINDOW_WIDTH / 2) - 122, ((WINDOW_HEIGHT / 2) - 120) + ((i + 1) * 8), &rcBoxBottom, SURFACE_ID_TEXT_BOX); + + // Move titles + if (gCampTitleY > (WINDOW_HEIGHT / 2) - 104) + --gCampTitleY; + + // Draw titles + PutBitmap3(&rcView, (WINDOW_WIDTH / 2) - 112, gCampTitleY, &rcTitle1, SURFACE_ID_TEXT_BOX); + PutBitmap3(&rcView, (WINDOW_WIDTH / 2) - 112, gCampTitleY + 52, &rcTitle2, SURFACE_ID_TEXT_BOX); + + // Draw arms cursor + ++flash; + + if (gCampActive == FALSE) + PutBitmap3(&rcView, (gSelectedArms * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 96, &rcCur1[(flash / 2) % 2], SURFACE_ID_TEXT_BOX); + else + PutBitmap3(&rcView, (gSelectedArms * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 96, &rcCur1[1], SURFACE_ID_TEXT_BOX); + + // Draw weapons + for (i = 0; i < ARMS_MAX; ++i) + { + if (gArmsData[i].code == 0) + break; // Invalid weapon + + // Get icon rect for next weapon + rcArms.left = (gArmsData[i].code % 16) * 16; + rcArms.right = rcArms.left + 16; + rcArms.top = ((gArmsData[i].code) / 16) * 16; + rcArms.bottom = rcArms.top + 16; + + // Draw the icon, slash and "Lv" + PutBitmap3(&rcView, (i * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 96, &rcArms, SURFACE_ID_ARMS_IMAGE); + PutBitmap3(&rcView, (i * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 64, &rcPer, SURFACE_ID_TEXT_BOX); + PutBitmap3(&rcView, (i * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 80, &rcLv, SURFACE_ID_TEXT_BOX); + PutNumber4((i * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 80, gArmsData[i].level, FALSE); + + // Draw ammo + if (gArmsData[i].max_num) + { + PutNumber4((i * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 72, gArmsData[i].num, FALSE); + PutNumber4((i * 40) + (WINDOW_WIDTH / 2) - 112, (WINDOW_HEIGHT / 2) - 64, gArmsData[i].max_num, FALSE); + } + else + { + // Weapon doesn't use ammunition + PutBitmap3(&rcView, (i * 40) + (WINDOW_WIDTH - 192) / 2, (WINDOW_HEIGHT / 2) - 72, &rcNone, SURFACE_ID_TEXT_BOX); + PutBitmap3(&rcView, (i * 40) + (WINDOW_WIDTH - 192) / 2, (WINDOW_HEIGHT / 2) - 64, &rcNone, SURFACE_ID_TEXT_BOX); + } + } + + // Draw items cursor + if (gCampActive == TRUE) + PutBitmap3(&rcView, ((gSelectedItem % 6) * 32) + (WINDOW_WIDTH / 2) - 112, ((gSelectedItem / 6) * 16) + (WINDOW_HEIGHT / 2) - 44, &rcCur2[flash / 2 % 2], SURFACE_ID_TEXT_BOX); + else + PutBitmap3(&rcView, ((gSelectedItem % 6) * 32) + (WINDOW_WIDTH / 2) - 112, ((gSelectedItem / 6) * 16) + (WINDOW_HEIGHT / 2) - 44, &rcCur2[1], SURFACE_ID_TEXT_BOX); + + for (i = 0; i < ITEM_MAX; ++i) + { + if (gItemData[i].code == 0) + break; // Invalid item + + // Get rect for next item + rcItem.left = (gItemData[i].code % 8) * 32; + rcItem.right = rcItem.left + 32; + rcItem.top = (gItemData[i].code / 8) * 16; + rcItem.bottom = rcItem.top + 16; + + PutBitmap3(&rcView, ((i % 6) * 32) + (WINDOW_WIDTH / 2) - 112, ((i / 6) * 16) + (WINDOW_HEIGHT / 2) - 44, &rcItem, SURFACE_ID_ITEM_IMAGE); + } +} + +int CampLoop(void) +{ + char old_script_path[MAX_PATH]; + + RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + + // Save the current script path (to restore it when we get out of the inventory) + GetTextScriptPath(old_script_path); + + // Load the inventory script + LoadTextScript2("ArmsItem.tsc"); + + gCampTitleY = (WINDOW_HEIGHT / 2) - 96; + + // Put the cursor on the first weapon + gCampActive = FALSE; + gSelectedItem = 0; + + // Compute current amount of weapons + int arms_num = 0; + while (gArmsData[arms_num].code != 0) + ++arms_num; + + if (arms_num != 0) + StartTextScript(1000 + gArmsData[gSelectedArms].code); + else + StartTextScript(5000 + gItemData[gSelectedItem].code); + + for (;;) + { + GetTrg(); + + // Handle ESC + if (gKeyTrg & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; // Quit game + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; // Go to game intro + } + } + + if (g_GameFlags & GAME_FLAG_IS_CONTROL_ENABLED) + MoveCampCursor(); + + switch (TextScriptProc()) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; // Quit game + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; // Go to game intro + } + + // Get currently displayed image + PutBitmap4(&rcView, 0, 0, &rcView, SURFACE_ID_SCREEN_GRAB); + PutCampObject(); + PutTextScript(); + PutFramePerSecound(); + + // Check whether we're getting out of the loop + if (gCampActive) + { + if (g_GameFlags & GAME_FLAG_IS_CONTROL_ENABLED && gKeyTrg & (gKeyCancel | gKeyItem)) + { + StopTextScript(); + break; + } + } + else + { + if (gKeyTrg & (gKeyOk | gKeyCancel | gKeyItem)) + { + StopTextScript(); + break; + } + } + + if (!Flip_SystemTask(ghWnd)) + return enum_ESCRETURN_exit; // Quit game + } + + // Resume original script + LoadTextScript_Stage(old_script_path); + gArmsEnergyX = 32; // Displays weapon rotation animation in case the weapon was changed + return enum_ESCRETURN_continue; // Go to game +} + +BOOL CheckItem(long a) +{ + int i; + + for (i = 0; i < ITEM_MAX; ++i) + if (gItemData[i].code == a) + return TRUE; // Found + + return FALSE; // Not found +} + +BOOL CheckArms(long a) +{ + int i; + + for (i = 0; i < ARMS_MAX; ++i) + if (gArmsData[i].code == a) + return TRUE; // Found + + return FALSE; // Not found +} + +BOOL UseArmsEnergy(long num) +{ + if (gArmsData[gSelectedArms].max_num == 0) + return TRUE; // No ammo needed + if (gArmsData[gSelectedArms].num == 0) + return FALSE; // No ammo left + + gArmsData[gSelectedArms].num -= num; + + if (gArmsData[gSelectedArms].num < 0) + gArmsData[gSelectedArms].num = 0; + + return TRUE; // Was able to spend ammo +} + +BOOL ChargeArmsEnergy(long num) +{ + gArmsData[gSelectedArms].num += num; + + // Cap the ammo to the maximum ammunition + if (gArmsData[gSelectedArms].num > gArmsData[gSelectedArms].max_num) + gArmsData[gSelectedArms].num = gArmsData[gSelectedArms].max_num; + + return TRUE; // Always successfull +} + +void FullArmsEnergy(void) +{ + int a; + + for (a = 0; a < ARMS_MAX; ++a) + { + if (gArmsData[a].code == 0) + continue; // Don't change empty weapons + + gArmsData[a].num = gArmsData[a].max_num; + } +} + +int RotationArms(void) +{ + // Get amount of weapons + int arms_num = 0; + while (gArmsData[arms_num].code != 0) + ++arms_num; + + if (arms_num == 0) + return 0; + + ResetSpurCharge(); + + // Select next valid weapon + ++gSelectedArms; + + while (gSelectedArms < arms_num) + { + if (gArmsData[gSelectedArms].code) + break; + + ++gSelectedArms; + } + + if (gSelectedArms == arms_num) + gSelectedArms = 0; + + gArmsEnergyX = 32; + PlaySoundObject(SND_SWITCH_WEAPON, SOUND_MODE_PLAY); + + return gArmsData[gSelectedArms].code; +} + +int RotationArmsRev(void) +{ + // Get amount of weapons + int arms_num = 0; + while (gArmsData[arms_num].code != 0) + ++arms_num; + + if (arms_num == 0) + return 0; + + ResetSpurCharge(); + + // Select previous valid weapon + --gSelectedArms; + + if (gSelectedArms < 0) + gSelectedArms = arms_num - 1; + + while (gSelectedArms < arms_num) + { + if (gArmsData[gSelectedArms].code) + break; + + --gSelectedArms; + } + + gArmsEnergyX = 0; + PlaySoundObject(SND_SWITCH_WEAPON, SOUND_MODE_PLAY); + + return gArmsData[gSelectedArms].code; +} + +void ChangeToFirstArms(void) +{ + gSelectedArms = 0; + gArmsEnergyX = 32; + PlaySoundObject(SND_SWITCH_WEAPON, SOUND_MODE_PLAY); +} diff --git a/src/ArmsItem.h b/src/ArmsItem.h new file mode 100644 index 0000000..d60c2e2 --- /dev/null +++ b/src/ArmsItem.h @@ -0,0 +1,124 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +// Limits for the amount of weapons and items +#define ARMS_MAX 8 +#define ITEM_MAX 32 + +// "Arms" is a synonym of "weapon" here +// "Code" means "ID" here +// "Num" often means "ammo" here + +/// Weapon struct +typedef struct ARMS +{ + /// ID of the weapon + int code; + + /// Current level of the weapon + int level; + + /// Current EXP of the weapon. It is counted from the current level (it's reset to 0 at each level up) + int exp; + + /// Maximum ammunition + int max_num; + + /// Current ammunition + int num; +} ARMS; + +typedef struct ITEM +{ + /// ID of the item + int code; +} ITEM; + + + +/// Contains data for all the weapons the character currently has +extern ARMS gArmsData[ARMS_MAX]; + +/// Contains data for all the items the character currently has +extern ITEM gItemData[ITEM_MAX]; + +/// Currently selected weapon +extern int gSelectedArms; + +/// Currently selected item +extern int gSelectedItem; + +extern int gCampTitleY; + +/// True if we're in the items section of the inventory (not in the weapons section) (only relevant when the inventory is open) +extern BOOL gCampActive; + +/// X coordinate for the weapons HUD section. Set it to 32 for the forward weapon rotation "animation", 0 for the reverse weapon rotation "animation" and 16 to immobilise it +extern int gArmsEnergyX; + + + +/// Clear the weapons array, reverting it to the default state (no weapons) and adjust variables (initialize weapons basically) +void ClearArmsData(void); + +/// Clear the item array, reverting it to the default state (no items) (initialize items basically) +void ClearItemData(void); + + +/// Add code to the weapons, setting max_num as the max ammo, or find code and add max_num to its ammo. Fails if no space is available and the weapon isn't +/// already present +BOOL AddArmsData(long code, long max_num); + +/// Remove code from the weapons. Fails if code is not found +BOOL SubArmsData(long code); + +/// Replace code1 with code2, setting max_num as its max ammo. Fails if code1 is not found +BOOL TradeArms(long code1, long code2, long max_num); + + +/// Add code to the items. Fails if no space is left +BOOL AddItemData(long code); + +/// Remove code from the items. Fails if code is not found +BOOL SubItemData(long code); + + +/// Inventory loop. Returns mode. +int CampLoop(void); + + +/// Search for a in the items. Returns whether a was found +BOOL CheckItem(long a); + +/// Search for a in the weapons. Returns whether a was found +BOOL CheckArms(long a); + + +/// Remove num ammo from the currently selected weapon. Returns whether there was any ammo left to fire +BOOL UseArmsEnergy(long num); + +/// Add num ammo to the currently selected weapon (capped at the maximum ammunition). Returns true +BOOL ChargeArmsEnergy(long num); + +/// Set every weapons ammunition to its maximum ammunition +void FullArmsEnergy(void); + + +// "Rotation" means "Weapons currently owned by the player (present in the weapons array)" + +/// Change the current weapon to the next one in the rotation. Returns the ID of the newly selected weapon +int RotationArms(void); + +/// Change the current weapon to the previous one in the rotation. Returns the ID of the newly selected weapon +int RotationArmsRev(void); + +/// Change the current weapon to be the first one and play the usual rotation animation +void ChangeToFirstArms(void); diff --git a/src/Back.cpp b/src/Back.cpp new file mode 100644 index 0000000..2faf6dc --- /dev/null +++ b/src/Back.cpp @@ -0,0 +1,215 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Back.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Main.h" + +BACK gBack; +int gWaterY; +static unsigned long color_black; + +// TODO - Another function that has an incorrect stack frame +BOOL InitBack(const char *fName, int type) +{ + char path[MAX_PATH]; + FILE *fp; + BITMAPFILEHEADER file_header; // The original names for these two variables are unknown. This ruins the stack frame layout. + BITMAPINFOHEADER info_header; + + color_black = GetCortBoxColor(RGB(0, 0, 0x10)); // Unused. This may have once been used by background type 4 (the solid black background) + + // We're not actually loading the bitmap here - we're just reading its width/height and making sure it's really a BMP file + sprintf(path, "%s\\%s.pbm", gDataPath, fName); + + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + fread(&file_header, sizeof(file_header), 1, fp); + + // Check if this is a valid bitmap file + if (file_header.bfType != 0x4D42) // 'MB' (we use hex here to prevent a compiler warning) + { +#ifdef FIX_MAJOR_BUGS + // The original game forgets to close fp + fclose(fp); +#endif + return FALSE; + } + + fread(&info_header, sizeof(info_header), 1, fp); + fclose(fp); + + // Get bitmap width and height + gBack.partsW = info_header.biWidth; + gBack.partsH = info_header.biHeight; + + gBack.flag = TRUE; // This variable is otherwise unused + + // *Now* we actually load the bitmap + if (!ReloadBitmap_File(fName, SURFACE_ID_LEVEL_BACKGROUND)) + return FALSE; + + gBack.type = type; + gWaterY = 240 * 0x10 * 0x200; + return TRUE; +} + +void ActBack(void) +{ + switch (gBack.type) + { + case BACKGROUND_TYPE_AUTOSCROLL: + gBack.fx += 6 * 0x200; + break; + + case BACKGROUND_TYPE_CLOUDS_WINDY: + case BACKGROUND_TYPE_CLOUDS: + ++gBack.fx; + gBack.fx %= 640; + break; + } +} + +/// Draw background background elements +void PutBack(int fx, int fy) +{ + int x, y; + RECT rect = {0, 0, gBack.partsW, gBack.partsH}; + + switch (gBack.type) + { + case BACKGROUND_TYPE_STATIONARY: + for (y = 0; y < WINDOW_HEIGHT; y += gBack.partsH) + for (x = 0; x < WINDOW_WIDTH; x += gBack.partsW) + PutBitmap4(&grcGame, x, y, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + break; + + case BACKGROUND_TYPE_MOVE_DISTANT: + for (y = -((fy / 2 / 0x200) % gBack.partsH); y < WINDOW_HEIGHT; y += gBack.partsH) + for (x = -((fx / 2 / 0x200) % gBack.partsW); x < WINDOW_WIDTH; x += gBack.partsW) + PutBitmap4(&grcGame, x, y, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + break; + + case BACKGROUND_TYPE_MOVE_NEAR: + for (y = -((fy / 0x200) % gBack.partsH); y < WINDOW_HEIGHT; y += gBack.partsH) + for (x = -((fx / 0x200) % gBack.partsW); x < WINDOW_WIDTH; x += gBack.partsW) + PutBitmap4(&grcGame, x, y, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + break; + + case BACKGROUND_TYPE_AUTOSCROLL: + for (y = -gBack.partsH; y < WINDOW_HEIGHT; y += gBack.partsH) + for (x = -((gBack.fx / 0x200) % gBack.partsW); x < WINDOW_WIDTH; x += gBack.partsW) + PutBitmap4(&grcGame, x, y, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + break; + + case BACKGROUND_TYPE_CLOUDS_WINDY: + case BACKGROUND_TYPE_CLOUDS: + // Draw sky + rect.top = 0; + rect.bottom = 88; + rect.left = 0; + rect.right = 320; + PutBitmap4(&grcGame, 0, 0, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + // Draw first cloud layer + rect.top = 88; + rect.bottom = 123; + rect.left = gBack.fx / 2; + rect.right = 320; + PutBitmap4(&grcGame, 0, 88, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + rect.left = 0; + PutBitmap4(&grcGame, 320 - ((gBack.fx / 2) % 320), 88, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + // Draw second cloud layer + rect.top = 123; + rect.bottom = 146; + rect.left = gBack.fx % 320; + rect.right = 320; + PutBitmap4(&grcGame, 0, 123, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + rect.left = 0; + PutBitmap4(&grcGame, 320 - (gBack.fx % 320), 123, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + // Draw third cloud layer + rect.top = 146; + rect.bottom = 176; + rect.left = 2 * gBack.fx % 320; + rect.right = 320; + PutBitmap4(&grcGame, 0, 146, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + rect.left = 0; + PutBitmap4(&grcGame, 320 - ((gBack.fx * 2) % 320), 146, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + // Draw fourth cloud layer + rect.top = 176; + rect.bottom = 240; + rect.left = 4 * gBack.fx % 320; + rect.right = 320; + PutBitmap4(&grcGame, 0, 176, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + rect.left = 0; + PutBitmap4(&grcGame, 320 - ((gBack.fx * 4) % 320), 176, &rect, SURFACE_ID_LEVEL_BACKGROUND); + + break; + } +} + +/// Draw background foreground elements - only the water background type makes use of this +void PutFront(int fx, int fy) +{ + int xpos, ypos; + + RECT rcWater[2] = {{0, 0, 32, 16}, {0, 16, 32, 48}}; + + int x, y; + int x_1, x_2; + int y_1, y_2; + + switch (gBack.type) + { + case BACKGROUND_TYPE_WATER: + x_1 = fx / (32 * 0x200); + x_2 = x_1 + (((WINDOW_WIDTH + (32 - 1)) / 32) + 1); + y_1 = 0; + y_2 = y_1 + 32; + + for (y = y_1; y < y_2; ++y) + { + ypos = ((y * 32 * 0x200) / 0x200) - (fy / 0x200) + (gWaterY / 0x200); + + if (ypos < -32) + continue; + + if (ypos > WINDOW_HEIGHT) + break; + + for (x = x_1; x < x_2; ++x) + { + xpos = ((x * 32 * 0x200) / 0x200) - (fx / 0x200); + PutBitmap3(&grcGame, xpos, ypos, &rcWater[1], SURFACE_ID_LEVEL_BACKGROUND); + if (y == 0) + PutBitmap3(&grcGame, xpos, ypos, &rcWater[0], SURFACE_ID_LEVEL_BACKGROUND); + } + } + + break; + } +} diff --git a/src/Back.h b/src/Back.h new file mode 100644 index 0000000..1c1164f --- /dev/null +++ b/src/Back.h @@ -0,0 +1,41 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +enum +{ + BACKGROUND_TYPE_STATIONARY = 0, // Doesn't move at all + BACKGROUND_TYPE_MOVE_DISTANT = 1, // Moves at half the speed of the foreground + BACKGROUND_TYPE_MOVE_NEAR = 2, // Moves at the same speed as the foreground + BACKGROUND_TYPE_WATER = 3, // No background - draws a water foreground layer instead + BACKGROUND_TYPE_BLACK = 4, // No background - just black + BACKGROUND_TYPE_AUTOSCROLL = 5, // Constantly scrolls to the left (used by Ironhead) + BACKGROUND_TYPE_CLOUDS_WINDY = 6, // Fancy parallax scrolling, items are blown to the left (used by bkMoon) + BACKGROUND_TYPE_CLOUDS = 7 // Fancy parallax scrolling (used by bkFog) +}; + +typedef struct BACK +{ + BOOL flag; // Unused - purpose unknown + int partsW; + int partsH; + int numX; + int numY; + int type; + int fx; +} BACK; + +extern BACK gBack; +extern int gWaterY; + +BOOL InitBack(const char *fName, int type); +void ActBack(void); +void PutBack(int fx, int fy); +void PutFront(int fx, int fy); diff --git a/src/Boss.cpp b/src/Boss.cpp new file mode 100644 index 0000000..dc27478 --- /dev/null +++ b/src/Boss.cpp @@ -0,0 +1,391 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Boss.h" + +#include + +#include "WindowsWrapper.h" + +#include "BossAlmo1.h" +#include "BossAlmo2.h" +#include "BossBallos.h" +#include "BossFrog.h" +#include "BossIronH.h" +#include "BossOhm.h" +#include "BossPress.h" +#include "BossTwinD.h" +#include "BossX.h" +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Draw.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "NpcHit.h" +#include "Sound.h" +#include "TextScr.h" +#include "ValueView.h" + +NPCHAR gBoss[BOSS_MAX]; + +void InitBossChar(int code) +{ + memset(gBoss, 0, sizeof(gBoss)); + gBoss[0].cond = 0x80; + gBoss[0].code_char = code; +} + +void PutBossChar(int fx, int fy) +{ + signed char a = 0; + int b; + + int side; + + for (b = BOSS_MAX - 1; b >= 0; --b) + { + if (gBoss[b].cond & 0x80) + { + if (gBoss[b].shock != 0) + { + a = ((gBoss[b].shock / 2 % 2) * 2) - 1; + } + else + { + a = 0; + + if (gBoss[b].bits & NPC_SHOW_DAMAGE && gBoss[b].damage_view != 0) + { + SetValueView(&gBoss[b].x, &gBoss[b].y, gBoss[b].damage_view); + gBoss[b].damage_view = 0; + } + } + + if (gBoss[b].direct == 0) + side = gBoss[b].view.front; + else + side = gBoss[b].view.back; + + PutBitmap3( + &grcGame, + ((gBoss[b].x - side) / 0x200) - (fx / 0x200) + a, + ((gBoss[b].y - gBoss[b].view.top) / 0x200) - (fy / 0x200), + &gBoss[b].rect, + SURFACE_ID_LEVEL_SPRITESET_2); + } + } +} + +void SetBossCharActNo(int a) +{ + gBoss[0].act_no = a; +} + +void HitBossBullet(void) +{ + BOOL bHit; + int bul; + int bos; + int bos_; + + for (bos = 0; bos < BOSS_MAX; ++bos) + { + if (!(gBoss[bos].cond & 0x80)) + continue; + + for (bul = 0; bul < BULLET_MAX; ++bul) + { + if (!(gBul[bul].cond & 0x80)) + continue; + + if (gBul[bul].damage == -1) + continue; + + // Check if bullet touches boss + bHit = FALSE; + if (gBoss[bos].bits & NPC_SHOOTABLE + && gBoss[bos].x - gBoss[bos].hit.back < gBul[bul].x + gBul[bul].enemyXL + && gBoss[bos].x + gBoss[bos].hit.back > gBul[bul].x - gBul[bul].enemyXL + && gBoss[bos].y - gBoss[bos].hit.top < gBul[bul].y + gBul[bul].enemyYL + && gBoss[bos].y + gBoss[bos].hit.bottom > gBul[bul].y - gBul[bul].enemyYL) + bHit = TRUE; + else if (gBoss[bos].bits & NPC_INVULNERABLE + && gBoss[bos].x - gBoss[bos].hit.back < gBul[bul].x + gBul[bul].blockXL + && gBoss[bos].x + gBoss[bos].hit.back > gBul[bul].x - gBul[bul].blockXL + && gBoss[bos].y - gBoss[bos].hit.top < gBul[bul].y + gBul[bul].blockYL + && gBoss[bos].y + gBoss[bos].hit.bottom > gBul[bul].y - gBul[bul].blockYL) + bHit = TRUE; + + if (bHit) + { + // Damage boss + if (gBoss[bos].bits & NPC_SHOOTABLE) + { + if (gBoss[bos].cond & 0x10) + bos_ = 0; + else + bos_ = bos; + + gBoss[bos_].life -= gBul[bul].damage; + + if (gBoss[bos_].life < 1) + { + gBoss[bos_].life = bos_; + + if (gMC.cond & 0x80 && gBoss[bos_].bits & NPC_EVENT_WHEN_KILLED) + { + StartTextScript(gBoss[bos_].code_event); + } + else + { + PlaySoundObject(gBoss[bos_].destroy_voice, SOUND_MODE_PLAY); + + switch (gBoss[bos_].size) + { + case 1: + SetDestroyNpChar(gBoss[bos_].x, gBoss[bos_].y, gBoss[bos_].view.back, 4); + break; + case 2: + SetDestroyNpChar(gBoss[bos_].x, gBoss[bos_].y, gBoss[bos_].view.back, 8); + break; + case 3: + SetDestroyNpChar(gBoss[bos_].x, gBoss[bos_].y, gBoss[bos_].view.back, 16); + break; + } + + gBoss[bos_].cond = 0; + } + } + else + { + if (gBoss[bos].shock < 14) + { + SetCaret(gBul[bul].x, gBul[bul].y, CARET_HURT_PARTICLES, DIR_LEFT); + SetCaret(gBul[bul].x, gBul[bul].y, CARET_HURT_PARTICLES, DIR_LEFT); + SetCaret(gBul[bul].x, gBul[bul].y, CARET_HURT_PARTICLES, DIR_LEFT); + PlaySoundObject(gBoss[bos_].hit_voice, SOUND_MODE_PLAY); + } + + gBoss[bos].shock = 8; + gBoss[bos_].shock = 8; + gBoss[bos_].damage_view -= gBul[bul].damage; + } + + --gBul[bul].life; + + if (gBul[bul].life < 1) + gBul[bul].cond = 0; + } + else if (gBul[bul].code_bullet == 13 + || gBul[bul].code_bullet == 14 + || gBul[bul].code_bullet == 15 + || gBul[bul].code_bullet == 28 + || gBul[bul].code_bullet == 29 + || gBul[bul].code_bullet == 30) + { + --gBul[bul].life; + } + else + { + if (!(gBul[bul].bbits & 0x10)) + { + SetCaret(gBul[bul].x, gBul[bul].y, CARET_PROJECTILE_DISSIPATION, DIR_RIGHT); + PlaySoundObject(31, SOUND_MODE_PLAY); + gBul[bul].cond = 0; + continue; + } + } + } + } + } +} + +void ActBossChar_0(void) +{ + +} + +BOSSFUNCTION gpBossFuncTbl[10] = +{ + ActBossChar_0, + ActBossChar_Omega, + ActBossChar_Frog, + ActBossChar_MonstX, + ActBossChar_Core, + ActBossChar_Ironhead, + ActBossChar_Twin, + ActBossChar_Undead, + ActBossChar_Press, + ActBossChar_Ballos +}; + +void ActBossChar(void) +{ + int code_char; + int bos; + + if (!(gBoss[0].cond & 0x80)) + return; + + code_char = gBoss[0].code_char; + + gpBossFuncTbl[code_char](); + + for (bos = 0; bos < BOSS_MAX; ++bos) + if (gBoss[bos].shock) + --gBoss[bos].shock; +} + +void HitBossMap(void) +{ + int x, y; + unsigned char atrb[16]; + int judg; + int offx[16]; + int offy[16]; + int b, j; + + offx[0] = 0; + offx[1] = 1; + offx[2] = 0; + offx[3] = 1; + offx[4] = 2; + offx[5] = 2; + offx[6] = 2; + offx[7] = 0; + offx[8] = 1; + offx[9] = -1; + offx[10] = -1; + offx[11] = -1; + offx[12] = -1; + offx[13] = 0; + offx[14] = 1; + offx[15] = 2; + + offy[0] = 0; + offy[1] = 0; + offy[2] = 1; + offy[3] = 1; + offy[4] = 0; + offy[5] = 1; + offy[6] = 2; + offy[7] = 2; + offy[8] = 2; + offy[9] = -1; + offy[10] = 0; + offy[11] = 1; + offy[12] = 2; + offy[13] = -1; + offy[14] = -1; + offy[15] = -1; + + for (b = 0; b < BOSS_MAX; ++b) + { + if (!(gBoss[b].cond & 0x80)) + continue; + + if (gBoss[b].bits & NPC_IGNORE_SOLIDITY) + continue; + + if (gBoss[b].size >= 3) + { + judg = 16; + x = gBoss[b].x / 0x10 / 0x200; + y = gBoss[b].y / 0x10 / 0x200; + } + else + { + judg = 4; + x = gBoss[b].x / 0x10 / 0x200; + y = gBoss[b].y / 0x10 / 0x200; + } + + gBoss[b].flag = 0; + for (j = 0; j < judg; ++j) + { + atrb[j] = GetAttribute(x + offx[j], y + offy[j]); + + switch (atrb[j]) + { + case 0x44: + if (gBoss[b].bits & NPC_IGNORE_TILE_44) + break; + // Fallthrough + case 0x05: + case 0x41: + case 0x43: + JadgeHitNpCharBlock(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x50: + JudgeHitNpCharTriangleA(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x51: + JudgeHitNpCharTriangleB(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x52: + JudgeHitNpCharTriangleC(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x53: + JudgeHitNpCharTriangleD(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x54: + JudgeHitNpCharTriangleE(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x55: + JudgeHitNpCharTriangleF(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x56: + JudgeHitNpCharTriangleG(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x57: + JudgeHitNpCharTriangleH(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x02: + case 0x60: + case 0x61: + case 0x64: + JadgeHitNpCharBlock(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x70: + JudgeHitNpCharTriangleA(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x71: + JudgeHitNpCharTriangleB(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x72: + JudgeHitNpCharTriangleC(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x73: + JudgeHitNpCharTriangleD(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x74: + JudgeHitNpCharTriangleE(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x75: + JudgeHitNpCharTriangleF(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x76: + JudgeHitNpCharTriangleG(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + case 0x77: + JudgeHitNpCharTriangleH(&gBoss[b], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]); + break; + } + } + } +} diff --git a/src/Boss.h b/src/Boss.h new file mode 100644 index 0000000..e09bdbe --- /dev/null +++ b/src/Boss.h @@ -0,0 +1,24 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "NpChar.h" + +#define BOSS_MAX 20 + +extern NPCHAR gBoss[BOSS_MAX]; + +typedef void (*BOSSFUNCTION)(void); +extern BOSSFUNCTION gpBossFuncTbl[10]; + +void InitBossChar(int code); +void PutBossChar(int fx, int fy); +void SetBossCharActNo(int a); +void HitBossBullet(void); +void ActBossChar(void); +void HitBossMap(void); diff --git a/src/BossAlmo1.cpp b/src/BossAlmo1.cpp new file mode 100644 index 0000000..9b7e847 --- /dev/null +++ b/src/BossAlmo1.cpp @@ -0,0 +1,636 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossAlmo1.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +void ActBossChar_Core_Face(NPCHAR *npc) +{ + RECT rect[4] = { + {0, 0, 72, 112}, + {0, 112, 72, 224}, + {160, 0, 232, 112}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->ani_no = 2; + npc->bits = NPC_IGNORE_SOLIDITY; + npc->view.front = 36 * 0x200; + npc->view.top = 56 * 0x200; + // Fallthrough + case 11: + npc->x = gBoss[0].x - (36 * 0x200); + npc->y = gBoss[0].y; + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 112; + // Fallthrough + case 51: + --npc->act_wait; + + if (npc->act_wait == 0) + { + npc->act_no = 100; + npc->ani_no = 3; + } + + npc->x = gBoss[0].x - (36 * 0x200); + npc->y = gBoss[0].y; + break; + + case 100: + npc->ani_no = 3; + break; + } + + npc->rect = rect[npc->ani_no]; + + if (npc->act_no == 51) + npc->rect.bottom = npc->rect.top + npc->act_wait; +} + +void ActBossChar_Core_Tail(NPCHAR *npc) +{ + RECT rect[3] = { + {72, 0, 160, 112}, + {72, 112, 160, 224}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->bits = NPC_IGNORE_SOLIDITY; + npc->view.front = 44 * 0x200; + npc->view.top = 56 * 0x200; + // Fallthrough + case 11: + npc->x = gBoss[0].x + (44 * 0x200); + npc->y = gBoss[0].y; + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 112; + // Fallthrough + case 51: + --npc->act_wait; + + if (npc->act_wait == 0) + { + npc->act_no = 100; + npc->ani_no = 2; + } + + npc->x = gBoss[0].x + (44 * 0x200); + npc->y = gBoss[0].y; + break; + + case 100: + npc->ani_no = 2; + break; + } + + npc->rect = rect[npc->ani_no]; + + if (npc->act_no == 51) + npc->rect.bottom = npc->rect.top + npc->act_wait; +} + +void ActBossChar_Core_Mini(NPCHAR *npc) +{ + RECT rect[3] = { + {256, 0, 320, 40}, + {256, 40, 320, 80}, + {256, 80, 320, 120}, + }; + + int xm, ym; + unsigned char deg; + + npc->life = 1000; + + switch (npc->act_no) + { + case 10: + npc->ani_no = 2; + npc->bits &= ~NPC_SHOOTABLE; + break; + + case 100: + npc->act_no = 101; + npc->ani_no = 2; + npc->act_wait = 0; + npc->tgt_x = gBoss[0].x + (Random(-0x80, 0x20) * 0x200); + npc->tgt_y = gBoss[0].y + (Random(-0x40, 0x40) * 0x200); + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 101: + npc->x += (npc->tgt_x - npc->x) / 0x10; + npc->y += (npc->tgt_y - npc->y) / 0x10; + + ++npc->act_wait; + + if (npc->act_wait > 50) + npc->ani_no = 0; + + break; + + case 120: + npc->act_no = 121; + npc->act_wait = 0; + // Fallthrough + case 121: + ++npc->act_wait; + + if (npc->act_wait / 2 % 2) + npc->ani_no = 0; + else + npc->ani_no = 1; + + if (npc->act_wait > 20) + npc->act_no = 130; + + break; + + case 130: + npc->act_no = 131; + npc->ani_no = 2; + npc->act_wait = 0; + npc->tgt_x = npc->x + (Random(24, 48) * 0x200); + npc->tgt_y = npc->y + (Random(-4, 4) * 0x200); + // Fallthrough + case 131: + npc->x += (npc->tgt_x - npc->x) / 0x10; + npc->y += (npc->tgt_y - npc->y) / 0x10; + + ++npc->act_wait; + + if (npc->act_wait > 50) + { + npc->act_no = 140; + npc->ani_no = 0; + } + + if (npc->act_wait == 1 || npc->act_wait == 3) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-2, 2); + ym = GetSin(deg) * 2; + xm = GetCos(deg) * 2; + SetNpChar(178, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + break; + + case 140: + npc->x += (npc->tgt_x - npc->x) / 0x10; + npc->y += (npc->tgt_y - npc->y) / 0x10; + break; + + case 200: + npc->act_no = 201; + npc->ani_no = 2; + npc->xm = 0; + npc->ym = 0; + // Fallthrough + case 201: + npc->xm += 0x20; + npc->x += npc->xm; + + if (npc->x > (gMap.width * 0x200 * 0x10) + (2 * 0x200 * 0x10)) + npc->cond = 0; + + break; + } + + if (npc->shock != 0) + npc->tgt_x += 2 * 0x200; + + npc->rect = rect[npc->ani_no]; +} + +void ActBossChar_Core_Hit(NPCHAR *npc) +{ + switch (npc->count1) + { + case 0: + npc->x = gBoss[0].x; + npc->y = gBoss[0].y - (32 * 0x200); + break; + + case 1: + npc->x = gBoss[0].x + (28 * 0x200); + npc->y = gBoss[0].y; + break; + + case 2: + npc->x = gBoss[0].x + (4 * 0x200); + npc->y = gBoss[0].y + (32 * 0x200); + break; + + case 3: + npc->x = gBoss[0].x - (28 * 0x200); + npc->y = gBoss[0].y + (4 * 0x200); + break; + } +} + +void ActBossChar_Core(void) +{ + NPCHAR *npc = gBoss; + + static unsigned char flash; + BOOL bShock = FALSE; + int i; + unsigned char deg; + int xm, ym; + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->exp = 1; + npc->cond = 0x80; + npc->bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_SHOW_DAMAGE); + npc->life = 650; + npc->hit_voice = 114; + npc->x = 77 * 0x10 * 0x200; + npc->y = 14 * 0x10 * 0x200; + npc->xm = 0; + npc->ym = 0; + npc->code_event = 1000; + npc->bits |= NPC_EVENT_WHEN_KILLED; + + gBoss[4].cond = 0x80; + gBoss[4].act_no = 10; + + gBoss[5].cond = 0x80; + gBoss[5].act_no = 10; + + gBoss[8].cond = 0x80; + gBoss[8].bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY); + gBoss[8].view.front = 0; + gBoss[8].view.top = 0; + gBoss[8].hit.back = 40 * 0x200; + gBoss[8].hit.top = 16 * 0x200; + gBoss[8].hit.bottom = 16 * 0x200; + gBoss[8].count1 = 0; + + gBoss[9] = gBoss[8]; + gBoss[9].hit.back = 36 * 0x200; + gBoss[9].hit.top = 24 * 0x200; + gBoss[9].hit.bottom = 24 * 0x200; + gBoss[9].count1 = 1; + + gBoss[10] = gBoss[8]; + gBoss[10].hit.back = 44 * 0x200; + gBoss[10].hit.top = 8 * 0x200; + gBoss[10].hit.bottom = 8 * 0x200; + gBoss[10].count1 = 2; + + gBoss[11] = gBoss[8]; + gBoss[11].cond |= 0x10; + gBoss[11].hit.back = 20 * 0x200; + gBoss[11].hit.top = 20 * 0x200; + gBoss[11].hit.bottom = 20 * 0x200; + gBoss[11].count1 = 3; + + gBoss[1].cond = 0x80; + gBoss[1].act_no = 10; + gBoss[1].bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_SHOOTABLE); + gBoss[1].life = 1000; + gBoss[1].hit_voice = 54; + gBoss[1].hit.back = 24 * 0x200; + gBoss[1].hit.top = 16 * 0x200; + gBoss[1].hit.bottom = 16 * 0x200; + gBoss[1].view.front = 32 * 0x200; + gBoss[1].view.top = 20 * 0x200; + gBoss[1].x = npc->x - (8 * 0x200); + gBoss[1].y = npc->y - (64 * 0x200); + + gBoss[2] = gBoss[1]; + gBoss[2].x = npc->x + (16 * 0x200); + gBoss[2].y = npc->y; + + gBoss[3] = gBoss[1]; + gBoss[3].x = npc->x - (8 * 0x200); + gBoss[3].y = npc->y + (64 * 0x200); + + gBoss[6] = gBoss[1]; + gBoss[6].x = npc->x - (48 * 0x200); + gBoss[6].y = npc->y - (32 * 0x200); + + gBoss[7] = gBoss[1]; + gBoss[7].x = npc->x - (48 * 0x200); + gBoss[7].y = npc->y + (32 * 0x200); + break; + + case 200: + npc->act_no = 201; + npc->act_wait = 0; + gBoss[11].bits &= ~NPC_SHOOTABLE; + gSuperYpos = 0; + CutNoise(); + // Fallthrough + case 201: + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y; + + ++npc->act_wait; + + if (npc->act_wait > 400) + { + ++npc->count1; + PlaySoundObject(115, SOUND_MODE_PLAY); + + if (npc->count1 > 3) + { + npc->count1 = 0; + npc->act_no = 220; + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + bShock = TRUE; + } + else + { + npc->act_no = 210; + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + bShock = TRUE; + } + } + + break; + + case 210: + npc->act_no = 211; + npc->act_wait = 0; + npc->count2 = npc->life; + gBoss[11].bits |= NPC_SHOOTABLE; + // Fallthrough + case 211: + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y; + + if (npc->shock != 0) + { + if (++flash / 2 % 2) + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + else + { + gBoss[4].ani_no = 1; + gBoss[5].ani_no = 1; + } + } + else + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + + ++npc->act_wait; + + if (npc->act_wait % 100 == 1) + { + gCurlyShoot_wait = Random(80, 100); + gCurlyShoot_x = gBoss[11].x; + gCurlyShoot_y = gBoss[11].y; + } + + if (npc->act_wait < 200 && npc->act_wait % 20 == 1) + SetNpChar(179, npc->x + (Random(-48, -16) * 0x200), npc->y + (Random(-64, 64) * 0x200), 0, 0, 0, NULL, 0x100); + + if (npc->act_wait > 400 || npc->life < npc->count2 - 200) + { + npc->act_no = 200; + gBoss[4].ani_no = 2; + gBoss[5].ani_no = 0; + bShock = TRUE; + } + + break; + + case 220: + npc->act_no = 221; + npc->act_wait = 0; + gSuperYpos = 1; + gBoss[11].bits |= NPC_SHOOTABLE; + SetQuake(100); + SetNoise(1, 1000); + // Fallthrough + case 221: + ++npc->act_wait; + SetNpChar(199, gMC.x + (Random(-50, 150) * 0x200 * 2), gMC.y + (Random(-160, 160) * 0x200), 0, 0, 0, NULL, 0x100); + gMC.xm -= 0x20; + gMC.cond |= 0x20; + + if (npc->shock != 0) + { + if (++flash / 2 % 2) + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + else + { + gBoss[4].ani_no = 1; + gBoss[5].ani_no = 1; + } + } + else + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + + if (npc->act_wait == 300 || npc->act_wait == 350 || npc->act_wait == 400) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + SetNpChar(218, npc->x - (40 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(101, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 400) + { + npc->act_no = 200; + gBoss[4].ani_no = 2; + gBoss[5].ani_no = 0; + bShock = TRUE; + } + + break; + + case 500: + CutNoise(); + + npc->act_no = 501; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + gBoss[4].ani_no = 2; + gBoss[5].ani_no = 0; + gBoss[1].act_no = 200; + gBoss[2].act_no = 200; + gBoss[3].act_no = 200; + gBoss[6].act_no = 200; + gBoss[7].act_no = 200; + + SetQuake(20); + + for (i = 0; i < 0x20; ++i) + SetNpChar(4, npc->x + (Random(-128, 128) * 0x200), npc->y + (Random(-64, 64) * 0x200), Random(-128, 128) * 0x200, Random(-128, 128) * 0x200, 0, NULL, 0x100); + + for (i = 0; i < 12; ++i) + gBoss[i].bits &= ~(NPC_INVULNERABLE | NPC_SHOOTABLE); + + // Fallthrough + case 501: + ++npc->act_wait; + + if (npc->act_wait % 16) + SetNpChar(4, npc->x + (Random(-64, 64) * 0x200), npc->y + (Random(-32, 32) * 0x200), Random(-128, 128) * 0x200, Random(-128, 128) * 0x200, 0, NULL, 0x100); + + if (npc->act_wait / 2 % 2) + npc->x -= 0x200; + else + npc->x += 0x200; + + if (npc->x < 63 * 0x10 * 0x200) + npc->x += 0x80; + else + npc->x -= 0x80; + + if (npc->y < 11 * 0x10 * 0x200) + npc->y += 0x80; + else + npc->y -= 0x80; + + break; + + case 600: + npc->act_no = 601; + gBoss[4].act_no = 50; + gBoss[5].act_no = 50; + gBoss[8].bits &= ~NPC_INVULNERABLE; + gBoss[9].bits &= ~NPC_INVULNERABLE; + gBoss[10].bits &= ~NPC_INVULNERABLE; + gBoss[11].bits &= ~NPC_INVULNERABLE; + // Fallthrough + case 601: + ++npc->act_wait; + + if (npc->act_wait / 2 % 2) + npc->x -= 4 * 0x200; + else + npc->x += 4 * 0x200; + + break; + } + + if (bShock) + { + SetQuake(20); + + gBoss[1].act_no = 100; + gBoss[2].act_no = 100; + gBoss[3].act_no = 100; + gBoss[6].act_no = 100; + gBoss[7].act_no = 100; + + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 8; ++i) + SetNpChar(4, gBoss[4].x + (Random(-32, 16) * 0x200), gBoss[4].y, Random(-0x200, 0x200), Random(-0x100, 0x100), 0, NULL, 0x100); + } + + if (npc->act_no >= 200 && npc->act_no < 300) + { + switch (npc->act_wait) + { + case 80: + gBoss[1].act_no = 120; + break; + case 110: + gBoss[2].act_no = 120; + break; + case 140: + gBoss[3].act_no = 120; + break; + case 170: + gBoss[6].act_no = 120; + break; + case 200: + gBoss[7].act_no = 120; + break; + } + + if (npc->x < npc->tgt_x + (10 * 0x10 * 0x200)) + npc->xm += 4; + if (npc->x > npc->tgt_x + (10 * 0x10 * 0x200)) + npc->xm -= 4; + + if (npc->y < npc->tgt_y) + npc->ym += 4; + if (npc->y > npc->tgt_y) + npc->ym -= 4; + } + + if (npc->xm > 0x80) + npc->xm = 0x80; + if (npc->xm < -0x80) + npc->xm = -0x80; + + if (npc->ym > 0x80) + npc->ym = 0x80; + if (npc->ym < -0x80) + npc->ym = -0x80; + + npc->x += npc->xm; + npc->y += npc->ym; + + ActBossChar_Core_Face(&gBoss[4]); + + ActBossChar_Core_Tail(&gBoss[5]); + + ActBossChar_Core_Mini(&gBoss[1]); + ActBossChar_Core_Mini(&gBoss[2]); + ActBossChar_Core_Mini(&gBoss[3]); + ActBossChar_Core_Mini(&gBoss[6]); + ActBossChar_Core_Mini(&gBoss[7]); + + ActBossChar_Core_Hit(&gBoss[8]); + ActBossChar_Core_Hit(&gBoss[9]); + ActBossChar_Core_Hit(&gBoss[10]); + ActBossChar_Core_Hit(&gBoss[11]); +} diff --git a/src/BossAlmo1.h b/src/BossAlmo1.h new file mode 100644 index 0000000..3cd3f2c --- /dev/null +++ b/src/BossAlmo1.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Core(void); diff --git a/src/BossAlmo2.cpp b/src/BossAlmo2.cpp new file mode 100644 index 0000000..225181a --- /dev/null +++ b/src/BossAlmo2.cpp @@ -0,0 +1,763 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossAlmo2.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +static void ActBossCharA_Head(NPCHAR *npc) +{ + RECT rect[4] = { + {0, 0, 72, 112}, + {0, 112, 72, 224}, + {160, 0, 232, 112}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->ani_no = 2; + npc->bits = NPC_IGNORE_SOLIDITY; + npc->view.front = 36 * 0x200; + npc->view.top = 56 * 0x200; + // Fallthrough + case 11: + npc->x = gBoss[0].x - (36 * 0x200); + npc->y = gBoss[0].y; + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 112; + // Fallthrough + case 51: + --npc->act_wait; + + if (npc->act_wait == 0) + { + npc->act_no = 100; + npc->ani_no = 3; + } + + break; + + case 100: + npc->ani_no = 3; + break; + } + + npc->rect = rect[npc->ani_no]; + + if (npc->act_no == 51) + npc->rect.bottom = npc->rect.top + npc->act_wait; +} + +static void ActBossCharA_Tail(NPCHAR *npc) +{ + RECT rect[3] = { + {72, 0, 160, 112}, + {72, 112, 160, 224}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->bits = NPC_IGNORE_SOLIDITY; + npc->view.front = 44 * 0x200; + npc->view.top = 56 * 0x200; + // Fallthrough + case 11: + npc->x = gBoss[0].x + (44 * 0x200); + npc->y = gBoss[0].y; + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 112; + // Fallthrough + case 51: + --npc->act_wait; + + if (npc->act_wait == 0) + { + npc->act_no = 100; + npc->ani_no = 2; + } + + break; + + case 100: + npc->ani_no = 2; + break; + } + + npc->rect = rect[npc->ani_no]; + + if (npc->act_no == 51) + npc->rect.bottom = npc->rect.top + npc->act_wait; +} + +static void ActBossCharA_Face(NPCHAR *npc) +{ + RECT rect[5] = { + {0, 0, 0, 0}, + {160, 112, 232, 152}, + {160, 152, 232, 192}, + {160, 192, 232, 232}, + {248, 160, 320, 200}, + }; + + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + break; + + case 10: + npc->ani_no = 1; + break; + + case 20: + npc->ani_no = 2; + break; + + case 30: + npc->act_no = 31; + npc->ani_no = 3; + npc->act_wait = 100; + // Fallthrough + case 31: + ++npc->act_wait; + + if (npc->act_wait > 300) + npc->act_wait = 0; + + if (npc->act_wait > 250 && npc->act_wait % 0x10 == 1) + PlaySoundObject(26, SOUND_MODE_PLAY); + + if (npc->act_wait > 250 && npc->act_wait % 0x10 == 7) + { + SetNpChar(293, npc->x, npc->y, 0, 0, 0, NULL, 0x80); + PlaySoundObject(101, SOUND_MODE_PLAY); + } + + if (npc->act_wait == 200) + PlaySoundObject(116, SOUND_MODE_PLAY); + + if (npc->act_wait > 200 && npc->act_wait % 2 != 0) + npc->ani_no = 4; + else + npc->ani_no = 3; + + break; + } + + npc->view.back = 36 * 0x200; + npc->view.front = 36 * 0x200; + npc->view.top = 20 * 0x200; + + npc->x = gBoss[0].x - (36 * 0x200); + npc->y = gBoss[0].y + (4 * 0x200); + + npc->bits = NPC_IGNORE_SOLIDITY; + + npc->rect = rect[npc->ani_no]; +} + +static void ActBossCharA_Mini(NPCHAR *npc) +{ + RECT rect[3] = { + {256, 0, 320, 40}, + {256, 40, 320, 80}, + {256, 80, 320, 120}, + }; + + int deg; + + if (npc->cond == 0) + return; + + npc->life = 1000; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SHOOTABLE; + break; + + case 5: + npc->ani_no = 0; + npc->bits &= ~NPC_SHOOTABLE; + ++npc->count2; + npc->count2 %= 0x100; + break; + + case 10: + npc->ani_no = 0; + npc->bits &= ~NPC_SHOOTABLE; + npc->count2 += 2; + npc->count2 %= 0x100; + break; + + case 20: + npc->ani_no = 1; + npc->bits &= ~NPC_SHOOTABLE; + npc->count2 += 2; + npc->count2 %= 0x100; + break; + + case 30: + npc->ani_no = 0; + npc->bits &= ~NPC_SHOOTABLE; + npc->count2 += 4; + npc->count2 %= 0x100; + break; + + case 200: + npc->act_no = 201; + npc->ani_no = 2; + npc->xm = 0; + npc->ym = 0; + // Fallthrough + case 201: + npc->xm += 0x20; + + npc->x += npc->xm; + + if (npc->x > (gMap.width * 0x200 * 0x10) + (2 * 0x200 * 0x10)) + npc->cond = 0; + + break; + } + + if (npc->act_no < 50) + { + if (npc->count1 != 0) + deg = npc->count2 + 0x80; + else + deg = npc->count2 + 0x180; + + npc->x = npc->pNpc->x - (8 * 0x200) + (GetCos(deg / 2) * 0x30); + npc->y = npc->pNpc->y + (GetSin(deg / 2) * 0x50); + } + + npc->rect = rect[npc->ani_no]; +} + +static void ActBossCharA_Hit(NPCHAR *npc) +{ + switch (npc->count1) + { + case 0: + npc->x = gBoss[0].x; + npc->y = gBoss[0].y - (32 * 0x200); + break; + + case 1: + npc->x = gBoss[0].x + (28 * 0x200); + npc->y = gBoss[0].y; + break; + + case 2: + npc->x = gBoss[0].x + (4 * 0x200); + npc->y = gBoss[0].y + (32 * 0x200); + break; + + case 3: + npc->x = gBoss[0].x - (28 * 0x200); + npc->y = gBoss[0].y + (4 * 0x200); + break; + } +} + +void ActBossChar_Undead(void) +{ + NPCHAR *npc = gBoss; + + static unsigned char flash; + BOOL bShock = FALSE; + int x, y; + int i; + + static int life; + + switch (npc->act_no) + { + case 1: + npc->act_no = 10; + npc->exp = 1; + npc->cond = 0x80; + npc->bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_SHOW_DAMAGE); + npc->life = 700; + npc->hit_voice = 114; + npc->x = 592 * 0x200; + npc->y = 120 * 0x200; + npc->xm = 0; + npc->ym = 0; + npc->code_event = 1000; + npc->bits |= NPC_EVENT_WHEN_KILLED; + + gBoss[3].cond = 0x80; + gBoss[3].act_no = 0; + + gBoss[4].cond = 0x80; + gBoss[4].act_no = 10; + + gBoss[5].cond = 0x80; + gBoss[5].act_no = 10; + + gBoss[8].cond = 0x80; + gBoss[8].bits = NPC_IGNORE_SOLIDITY; + gBoss[8].view.front = 0; + gBoss[8].view.top = 0; + gBoss[8].hit.back = 40 * 0x200; + gBoss[8].hit.top = 16 * 0x200; + gBoss[8].hit.bottom = 16 * 0x200; + gBoss[8].count1 = 0; + + gBoss[9] = gBoss[8]; + gBoss[9].hit.back = 36 * 0x200; + gBoss[9].hit.top = 24 * 0x200; + gBoss[9].hit.bottom = 24 * 0x200; + gBoss[9].count1 = 1; + + gBoss[10] = gBoss[8]; + gBoss[10].hit.back = 44 * 0x200; + gBoss[10].hit.top = 8 * 0x200; + gBoss[10].hit.bottom = 8 * 0x200; + gBoss[10].count1 = 2; + + gBoss[11] = gBoss[8]; + gBoss[11].cond |= 0x10; + gBoss[11].hit.back = 20 * 0x200; + gBoss[11].hit.top = 20 * 0x200; + gBoss[11].hit.bottom = 20 * 0x200; + gBoss[11].count1 = 3; + + gBoss[1].cond = 0x80; + gBoss[1].act_no = 0; + gBoss[1].bits = (NPC_IGNORE_SOLIDITY | NPC_SHOOTABLE); + gBoss[1].life = 1000; + gBoss[1].hit_voice = 54; + gBoss[1].hit.back = 24 * 0x200; + gBoss[1].hit.top = 16 * 0x200; + gBoss[1].hit.bottom = 16 * 0x200; + gBoss[1].view.front = 32 * 0x200; + gBoss[1].view.top = 20 * 0x200; + gBoss[1].pNpc = npc; + + gBoss[2] = gBoss[1]; + gBoss[2].count2 = 0x80; + + gBoss[6] = gBoss[1]; + gBoss[6].count1 = 1; + + gBoss[7] = gBoss[1]; + gBoss[7].count1 = 1; + gBoss[7].count2 = 0x80; + + life = npc->life; + + break; + + case 15: + npc->act_no = 16; + bShock = TRUE; + npc->direct = 0; + gBoss[3].act_no = 10; + gBoss[4].ani_no = 0; + break; + + case 20: + npc->act_no = 210; + bShock = TRUE; + npc->direct = 0; + gBoss[1].act_no = 5; + gBoss[2].act_no = 5; + gBoss[6].act_no = 5; + gBoss[7].act_no = 5; + break; + + case 200: + npc->act_no = 201; + npc->act_wait = 0; + gBoss[3].act_no = 0; + gBoss[4].ani_no = 2; + gBoss[5].ani_no = 0; + gBoss[8].bits &= ~NPC_INVULNERABLE; + gBoss[9].bits &= ~NPC_INVULNERABLE; + gBoss[10].bits &= ~NPC_INVULNERABLE; + gBoss[11].bits &= ~NPC_SHOOTABLE; + gSuperYpos = 0; + CutNoise(); + bShock = TRUE; + // Fallthrough + case 201: + ++npc->act_wait; + + if (npc->direct == 2 || npc->ani_no > 0 || npc->life < 200) + { + if (npc->act_wait > 200) + { + ++npc->count1; + PlaySoundObject(115, SOUND_MODE_PLAY); + + if (npc->life < 200) + { + npc->act_no = 230; + } + else + { + if (npc->count1 > 2) + npc->act_no = 220; + else + npc->act_no = 210; + } + } + } + + break; + + case 210: + npc->act_no = 211; + npc->act_wait = 0; + gBoss[3].act_no = 10; + gBoss[8].bits |= NPC_INVULNERABLE; + gBoss[9].bits |= NPC_INVULNERABLE; + gBoss[10].bits |= NPC_INVULNERABLE; + gBoss[11].bits |= NPC_SHOOTABLE; + life = npc->life; + bShock = TRUE; + // Fallthrough + case 211: + ++flash; + + if (npc->shock != 0 && flash / 2 % 2) + { + gBoss[4].ani_no = 1; + gBoss[5].ani_no = 1; + } + else + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + + ++npc->act_wait; + + if (npc->act_wait % 100 == 1) + { + gCurlyShoot_wait = Random(80, 100); + gCurlyShoot_x = gBoss[11].x; + gCurlyShoot_y = gBoss[11].y; + } + + if (npc->act_wait < 300) + { + if (npc->act_wait % 120 == 1) + SetNpChar(288, npc->x - (32 * 0x200), npc->y - (16 * 0x200), 0, 0, 1, NULL, 0x20); + + if (npc->act_wait % 120 == 61) + SetNpChar(288, npc->x - (32 * 0x200), npc->y + (16 * 0x200), 0, 0, 3, NULL, 0x20); + } + + if (npc->life < life - 50 || npc->act_wait > 400) + npc->act_no = 200; + + break; + + case 220: + npc->act_no = 221; + npc->act_wait = 0; + npc->count1 = 0; + gSuperYpos = 1; + gBoss[3].act_no = 20; + gBoss[8].bits |= NPC_INVULNERABLE; + gBoss[9].bits |= NPC_INVULNERABLE; + gBoss[10].bits |= NPC_INVULNERABLE; + gBoss[11].bits |= NPC_SHOOTABLE; + SetQuake(100); + life = npc->life; + bShock = TRUE; + // Fallthrough + case 221: + ++npc->act_wait; + + if (npc->act_wait % 40 == 1) + { + switch (Random(0, 3)) + { + case 0: + x = gBoss[1].x; + y = gBoss[1].y; + break; + case 1: + x = gBoss[2].x; + y = gBoss[2].y; + break; + case 2: + x = gBoss[6].x; + y = gBoss[6].y; + break; + case 3: + x = gBoss[7].x; + y = gBoss[7].y; + break; + } + + PlaySoundObject(25, SOUND_MODE_PLAY); + SetNpChar(285, x - (16 * 0x200), y, 0, 0, 0, NULL, 0x100); + SetNpChar(285, x - (16 * 0x200), y, 0, 0, 0x400, NULL, 0x100); + } + + ++flash; + + if (npc->shock != 0 && flash / 2 % 2) + { + gBoss[4].ani_no = 1; + gBoss[5].ani_no = 1; + } + else + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + + if (npc->life < life - 150 || npc->act_wait > 400 || npc->life < 200) + npc->act_no = 200; + + break; + + case 230: + npc->act_no = 231; + npc->act_wait = 0; + + gBoss[3].act_no = 30; + + gBoss[8].bits |= NPC_INVULNERABLE; + gBoss[9].bits |= NPC_INVULNERABLE; + gBoss[10].bits |= NPC_INVULNERABLE; + gBoss[11].bits |= NPC_SHOOTABLE; + + PlaySoundObject(25, SOUND_MODE_PLAY); + + SetNpChar(285, gBoss[3].x - (16 * 0x200), gBoss[3].y, 0, 0, 0, NULL, 0x100); + SetNpChar(285, gBoss[3].x - (16 * 0x200), gBoss[3].y, 0, 0, 0x400, NULL, 0x100); + SetNpChar(285, gBoss[3].x, gBoss[3].y - (16 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(285, gBoss[3].x, gBoss[3].y - (16 * 0x200), 0, 0, 0x400, NULL, 0x100); + SetNpChar(285, gBoss[3].x, gBoss[3].y + (16 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(285, gBoss[3].x, gBoss[3].y + (16 * 0x200), 0, 0, 0x400, NULL, 0x100); + + life = npc->life; + bShock = TRUE; + // Fallthrough + case 231: + ++flash; + + if (npc->shock != 0 && flash / 2 % 2) + { + gBoss[4].ani_no = 1; + gBoss[5].ani_no = 1; + } + else + { + gBoss[4].ani_no = 0; + gBoss[5].ani_no = 0; + } + + if (++npc->act_wait % 100 == 1) + { + gCurlyShoot_wait = Random(80, 100); + gCurlyShoot_x = gBoss[11].x; + gCurlyShoot_y = gBoss[11].y; + } + + if (npc->act_wait % 120 == 1) + SetNpChar(288, npc->x - (32 * 0x200), npc->y - (16 * 0x200), 0, 0, 1, NULL, 0x20); + + if (npc->act_wait % 120 == 61) + SetNpChar(288, npc->x - (32 * 0x200), npc->y + (16 * 0x200), 0, 0, 3, NULL, 0x20); + + break; + + case 500: + CutNoise(); + npc->act_no = 501; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + gBoss[3].act_no = 0; + gBoss[4].ani_no = 2; + gBoss[5].ani_no = 0; + gBoss[1].act_no = 5; + gBoss[2].act_no = 5; + gBoss[6].act_no = 5; + gBoss[7].act_no = 5; + SetQuake(20); + + for (i = 0; i < 100; ++i) + SetNpChar(4, npc->x + (Random(-128, 128) * 0x200), npc->y + (Random(-64, 64) * 0x200), Random(-128, 128) * 0x200, Random(-128, 128) * 0x200, 0, NULL, 0); + + DeleteNpCharCode(282, TRUE); + gBoss[11].bits &= ~NPC_SHOOTABLE; + + for (i = 0; i < 12; ++i) + gBoss[i].bits &= ~NPC_INVULNERABLE; + // Fallthrough + case 501: + ++npc->act_wait; + + if (npc->act_wait % 0x10 != 0) + SetNpChar(4, npc->x + (Random(-64, 64) * 0x200), npc->y + (Random(-32, 32) * 0x200), Random(-128, 128) * 0x200, Random(-128, 128) * 0x200, 0, NULL, 0x100); + + npc->x += 0x40; + npc->y += 0x80; + + if (npc->act_wait > 200) + { + npc->act_wait = 0; + npc->act_no = 1000; + } + + break; + + case 1000: + SetQuake(100); + + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait % 8 == 0) + PlaySoundObject(44, SOUND_MODE_PLAY); + + SetDestroyNpChar(gBoss[0].x + (Random(-72, 72) * 0x200), gBoss[0].y + (Random(-64, 64) * 0x200), 1, 1); + + if (gBoss[0].act_wait > 100) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 1001; + SetFlash(gBoss[0].x, gBoss[0].y, FLASH_MODE_EXPLOSION); + PlaySoundObject(35, SOUND_MODE_PLAY); + } + + break; + + case 1001: + SetQuake(40); + + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait > 50) + { + for (i = 0; i < 20; ++i) + gBoss[i].cond = 0; + + DeleteNpCharCode(158, TRUE); + DeleteNpCharCode(301, TRUE); + } + + break; + } + + if (bShock) + { + SetQuake(20); + + if (npc->act_no == 201) + gBoss[1].act_no = gBoss[2].act_no = gBoss[6].act_no = gBoss[7].act_no = 10; + + if (npc->act_no == 221) + gBoss[1].act_no = gBoss[2].act_no = gBoss[6].act_no = gBoss[7].act_no = 20; + + if (npc->act_no == 231) + gBoss[1].act_no = gBoss[2].act_no = gBoss[6].act_no = gBoss[7].act_no = 30; + + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 8; ++i) + SetNpChar(4, gBoss[4].x + (Random(-32, 16) * 0x200), gBoss[4].y, Random(-0x200, 0x200), Random(-0x100, 0x100), 0, NULL, 0x100); + } + + if (npc->act_no >= 200 && npc->act_no < 300) + { + if (npc->x < 192 * 0x200) + npc->direct = 2; + if (npc->x > (gMap.width - 4) * (0x200 * 0x10)) + npc->direct = 0; + + if (npc->direct == 0) + npc->xm -= 4; + else + npc->xm += 4; + } + + switch (npc->act_no) + { + case 201: + case 211: + case 221: + case 231: + ++npc->count2; + + if (npc->count2 == 150) + { + npc->count2 = 0; + SetNpChar(282, (gMap.width * 0x200 * 0x10) + 0x40, (Random(-1, 3) + 10) * (0x200 * 0x10), 0, 0, 0, NULL, 0x30); + } + else if (npc->count2 == 75) + { + SetNpChar(282, (gMap.width * 0x200 * 0x10) + 0x40, (Random(-3, 0) + 3) * (0x200 * 0x10), 0, 0, 0, NULL, 0x30); + } + + break; + } + + if (npc->xm > 0x80) + npc->xm = 0x80; + if (npc->xm < -0x80) + npc->xm = -0x80; + + if (npc->ym > 0x80) + npc->ym = 0x80; + if (npc->ym < -0x80) + npc->ym = -0x80; + + npc->x += npc->xm; + npc->y += npc->ym; + + ActBossCharA_Face(&gBoss[3]); + + ActBossCharA_Head(&gBoss[4]); + + ActBossCharA_Tail(&gBoss[5]); + + ActBossCharA_Mini(&gBoss[1]); + ActBossCharA_Mini(&gBoss[2]); + ActBossCharA_Mini(&gBoss[6]); + ActBossCharA_Mini(&gBoss[7]); + + ActBossCharA_Hit(&gBoss[8]); + ActBossCharA_Hit(&gBoss[9]); + ActBossCharA_Hit(&gBoss[10]); + ActBossCharA_Hit(&gBoss[11]); +} diff --git a/src/BossAlmo2.h b/src/BossAlmo2.h new file mode 100644 index 0000000..578c51e --- /dev/null +++ b/src/BossAlmo2.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Undead(void); diff --git a/src/BossBallos.cpp b/src/BossBallos.cpp new file mode 100644 index 0000000..51b1a2c --- /dev/null +++ b/src/BossBallos.cpp @@ -0,0 +1,774 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossBallos.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "MycParam.h" +#include "NpChar.h" +#include "Sound.h" + +static void ActBossChar_Eye(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {272, 0, 296, 16}, + {272, 16, 296, 32}, + {272, 32, 296, 48}, + {0, 0, 0, 0}, + {240, 16, 264, 32}, + }; + + RECT rcRight[5] = { + {296, 0, 320, 16}, + {296, 16, 320, 32}, + {296, 32, 320, 48}, + {0, 0, 0, 0}, + {240, 32, 264, 48}, + }; + + switch (npc->act_no) + { + case 100: + npc->act_no = 101; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 101: + ++npc->ani_wait; + + if (npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->act_no = 102; + + break; + + case 102: + npc->ani_no = 3; + break; + + case 200: + npc->act_no = 201; + npc->ani_no = 3; + npc->ani_wait = 0; + // Fallthrough + case 201: + ++npc->ani_wait; + + if (npc->ani_wait > 2) + { + npc->ani_wait = 0; + --npc->ani_no; + } + + if (npc->ani_no <= 0) + npc->act_no = 202; + + break; + + case 300: + npc->act_no = 301; + npc->ani_no = 4; + + if (npc->direct == 0) + SetDestroyNpChar(npc->x - (4 * 0x200), npc->y, 0x800, 10); + else + SetDestroyNpChar(npc->x + (4 * 0x200), npc->y, 0x800, 10); + + break; + } + + if (npc->direct == 0) + npc->x = gBoss[0].x - (24 * 0x200); + else + npc->x = gBoss[0].x + (24 * 0x200); + + npc->y = gBoss[0].y - (36 * 0x200); + + if (npc->act_no >= 0 && npc->act_no < 300) + { + if (npc->ani_no != 3) + npc->bits &= ~NPC_SHOOTABLE; + else + npc->bits |= NPC_SHOOTABLE; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +static void ActBossChar_Body(NPCHAR *npc) +{ + RECT rc[4] = { + {0, 0, 120, 120}, + {120, 0, 240, 120}, + {0, 120, 120, 240}, + {120, 120, 240, 240}, + }; + + npc->x = gBoss[0].x; + npc->y = gBoss[0].y; + + npc->rect = rc[npc->ani_no]; +} + +static void ActBossChar_HITAI(NPCHAR *npc) // "Hitai" = "forehead" or "brow" (according to Google Translate, anyway) +{ + npc->x = gBoss[0].x; + npc->y = gBoss[0].y - (44 * 0x200); +} + +static void ActBossChar_HARA(NPCHAR *npc) // "Hara" = "belly" or "stomach" (according to Google Translate, anyway) +{ + npc->x = gBoss[0].x; + npc->y = gBoss[0].y; +} + +void ActBossChar_Ballos(void) +{ + NPCHAR *npc = gBoss; + + static unsigned char flash; + int i; + int x, y; + + switch (npc->act_no) + { + case 0: + // Initialize main boss + npc->act_no = 1; + npc->cond = 0x80; + npc->exp = 1; + npc->direct = 0; + npc->x = 320 * 0x200; + npc->y = -64 * 0x200; + npc->hit_voice = 54; + npc->hit.front = 32 * 0x200; + npc->hit.top = 48 * 0x200; + npc->hit.back = 32 * 0x200; + npc->hit.bottom = 48 * 0x200; + npc->bits = (NPC_IGNORE_SOLIDITY | NPC_SOLID_HARD | NPC_EVENT_WHEN_KILLED | NPC_SHOW_DAMAGE); + npc->size = 3; + npc->damage = 0; + npc->code_event = 1000; + npc->life = 800; + + // Initialize eyes + gBoss[1].cond = 0x90; + gBoss[1].direct = 0; + gBoss[1].bits = NPC_IGNORE_SOLIDITY; + gBoss[1].life = 10000; + gBoss[1].view.front = 12 * 0x200; + gBoss[1].view.top = 0; + gBoss[1].view.back = 12 * 0x200; + gBoss[1].view.bottom = 16 * 0x200; + gBoss[1].hit.front = 12 * 0x200; + gBoss[1].hit.top = 0; + gBoss[1].hit.back = 12 * 0x200; + gBoss[1].hit.bottom = 16 * 0x200; + + gBoss[2] = gBoss[1]; + gBoss[2].direct = 2; + + // Initialize the body + gBoss[3].cond = 0x90; + gBoss[3].bits = (NPC_SOLID_SOFT | NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY); + gBoss[3].view.front = 60 * 0x200; + gBoss[3].view.top = 60 * 0x200; + gBoss[3].view.back = 60 * 0x200; + gBoss[3].view.bottom = 60 * 0x200; + gBoss[3].hit.front = 48 * 0x200; + gBoss[3].hit.top = 24 * 0x200; + gBoss[3].hit.back = 48 * 0x200; + gBoss[3].hit.bottom = 32 * 0x200; + + gBoss[4].cond = 0x90; + gBoss[4].bits = (NPC_SOLID_SOFT | NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY); + gBoss[4].hit.front = 32 * 0x200; + gBoss[4].hit.top = 8 * 0x200; + gBoss[4].hit.back = 32 * 0x200; + gBoss[4].hit.bottom = 8 * 0x200; + + gBoss[5].cond = 0x90; + gBoss[5].bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_SOLID_HARD); + gBoss[5].hit.front = 32 * 0x200; + gBoss[5].hit.top = 0; + gBoss[5].hit.back = 32 * 0x200; + gBoss[5].hit.bottom = 48 * 0x200; + break; + + case 100: + npc->act_no = 101; + npc->ani_no = 0; + npc->x = gMC.x; + SetNpChar(333, gMC.x, 304 * 0x200, 0, 0, 2, NULL, 0x100); + npc->act_wait = 0; + // Fallthrough + case 101: + ++npc->act_wait; + + if (npc->act_wait > 30) + npc->act_no = 102; + + break; + + case 102: + npc->ym += 0x40; + if (npc->ym > 0xC00) + npc->ym = 0xC00; + + npc->y += npc->ym; + + if (npc->y > (304 * 0x200) - npc->hit.bottom) + { + npc->y = (304 * 0x200) - npc->hit.bottom; + npc->ym = 0; + npc->act_no = 103; + npc->act_wait = 0; + SetQuake2(30); + PlaySoundObject(44, SOUND_MODE_PLAY); + + if (gMC.y > npc->y + (48 * 0x200) && gMC.x < npc->x + (24 * 0x200) && gMC.x > npc->x - (24 * 0x200)) + DamageMyChar(16); + + for (i = 0; i < 0x10; ++i) + { + x = npc->x + (Random(-40, 40) * 0x200); + SetNpChar(4, x, npc->y + (40 * 0x200), 0, 0, 0, NULL, 0x100); + } + + if (gMC.flag & 8) + gMC.ym = -0x200; + } + + break; + + case 103: + ++npc->act_wait; + + if (npc->act_wait == 50) + { + npc->act_no = 104; + gBoss[1].act_no = 100; + gBoss[2].act_no = 100; + } + + break; + + case 200: + npc->act_no = 201; + npc->count1 = 0; + // Fallthrough + case 201: + npc->act_no = 203; + npc->xm = 0; + ++npc->count1; + npc->hit.bottom = 48 * 0x200; + npc->damage = 0; + + if (npc->count1 % 3 == 0) + npc->act_wait = 150; + else + npc->act_wait = 50; + // Fallthrough + case 203: + --npc->act_wait; + + if (npc->act_wait <= 0) + { + npc->act_no = 204; + npc->ym = -0xC00; + + if (npc->x < gMC.x) + npc->xm = 0x200; + else + npc->xm = -0x200; + } + + break; + + case 204: + if (npc->x < 80 * 0x200) + npc->xm = 0x200; + if (npc->x > 544 * 0x200) + npc->xm = -0x200; + + npc->ym += 0x55; + if (npc->ym > 0xC00) + npc->ym = 0xC00; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->y > (304 * 0x200) - npc->hit.bottom) + { + npc->y = (304 * 0x200) - npc->hit.bottom; + npc->ym = 0; + npc->act_no = 201; + npc->act_wait = 0; + + if (gMC.y > npc->y + (56 * 0x200)) + DamageMyChar(16); + + if (gMC.flag & 8) + gMC.ym = -0x200; + + SetQuake2(30); + PlaySoundObject(26, SOUND_MODE_PLAY); + SetNpChar(332, npc->x - (12 * 0x200), npc->y + (52 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(332, npc->x + (12 * 0x200), npc->y + (52 * 0x200), 0, 0, 2, NULL, 0x100); + PlaySoundObject(44, SOUND_MODE_PLAY); + + for (i = 0; i < 0x10; ++i) + { + x = npc->x + (Random(-40, 40) * 0x200); + SetNpChar(4, x, npc->y + (40 * 0x200), 0, 0, 0, NULL, 0x100); + } + } + + break; + + case 220: + npc->act_no = 221; + npc->life = 1200; + gBoss[1].act_no = 200; + gBoss[2].act_no = 200; + npc->xm = 0; + npc->ani_no = 0; + npc->shock = 0; + flash = 0; + // Fallthrough + case 221: + npc->ym += 0x40; + if (npc->ym > 0xC00) + npc->ym = 0xC00; + + npc->y += npc->ym; + + if (npc->y > (304 * 0x200) - npc->hit.bottom) + { + npc->y = (304 * 0x200) - npc->hit.bottom; + npc->ym = 0; + npc->act_no = 222; + npc->act_wait = 0; + SetQuake2(30); + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 0x10; ++i) + { + x = npc->x + (Random(-40, 40) * 0x200); + SetNpChar(4, x, npc->y + (40 * 0x200), 0, 0, 0, NULL, 0x100); + } + + if (gMC.flag & 8) + gMC.ym = -0x200; + } + + break; + + case 300: + npc->act_no = 301; + npc->act_wait = 0; + + for (i = 0; i < 0x100; i += 0x40) + { + SetNpChar(342, npc->x, npc->y, 0, 0, i, npc, 90); + SetNpChar(342, npc->x, npc->y, 0, 0, i + 0x220, npc, 90); + } + + SetNpChar(343, npc->x, npc->y, 0, 0, 0, npc, 0x18); + SetNpChar(344, npc->x - (24 * 0x200), npc->y - (36 * 0x200), 0, 0, 0, npc, 0x20); + SetNpChar(344, npc->x + (24 * 0x200), npc->y - (36 * 0x200), 0, 0, 2, npc, 0x20); + // Fallthrough + case 301: + npc->y += ((225 * 0x200) - npc->y) / 8; + + ++npc->act_wait; + + if (npc->act_wait > 50) + { + npc->act_no = 310; + npc->act_wait = 0; + } + + break; + + case 311: + npc->direct = 0; + npc->xm = -0x3AA; + npc->ym = 0; + npc->x += npc->xm; + + if (npc->x < 111 * 0x200) + { + npc->x = 111 * 0x200; + npc->act_no = 312; + } + + break; + + case 312: + npc->direct = 1; + npc->ym = -0x3AA; + npc->xm = 0; + npc->y += npc->ym; + + if (npc->y < 111 * 0x200) + { + npc->y = 111 * 0x200; + npc->act_no = 313; + } + + break; + + case 313: + npc->direct = 2; + npc->xm = 0x3AA; + npc->ym = 0; + npc->x += npc->xm; + + if (npc->x > 513 * 0x200) + { + npc->x = 513 * 0x200; + npc->act_no = 314; + } + + if (npc->count1 != 0) + --npc->count1; + + if (npc->count1 == 0 && npc->x > 304 * 0x200 && npc->x < 336 * 0x200) + npc->act_no = 400; + + break; + + case 314: + npc->direct = 3; + npc->ym = 0x3AA; + npc->xm = 0; + npc->y += npc->ym; + + if (npc->y > 225 * 0x200) + { + npc->y = 225 * 0x200; + npc->act_no = 311; + } + + break; + + case 400: + npc->act_no = 401; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + DeleteNpCharCode(339, FALSE); + // Fallthrough + case 401: + npc->y += ((159 * 0x200) - npc->y) / 8; + + ++npc->act_wait; + + if (npc->act_wait > 50) + { + npc->act_wait = 0; + npc->act_no = 410; + + for (i = 0; i < 0x100; i += 0x20) + SetNpChar(346, npc->x, npc->y, 0, 0, i, npc, 0x50); + + SetNpChar(343, npc->x, npc->y, 0, 0, 0, npc, 0x18); + SetNpChar(344, npc->x - (24 * 0x200), npc->y - (36 * 0x200), 0, 0, 0, npc, 0x20); + SetNpChar(344, npc->x + (24 * 0x200), npc->y - (36 * 0x200), 0, 0, 2, npc, 0x20); + } + + break; + + case 410: + ++npc->act_wait; + + if (npc->act_wait > 50) + { + npc->act_wait = 0; + npc->act_no = 411; + } + + break; + + case 411: + ++npc->act_wait; + + if (npc->act_wait % 30 == 1) + { + x = (((npc->act_wait / 30) * 2) + 2) * 0x10 * 0x200; + SetNpChar(348, x, 336 * 0x200, 0, 0, 0, NULL, 0x180); + } + + if (npc->act_wait / 3 % 2) + PlaySoundObject(26, SOUND_MODE_PLAY); + + if (npc->act_wait > 540) + npc->act_no = 420; + + break; + + case 420: + npc->act_no = 421; + npc->act_wait = 0; + npc->ani_wait = 0; + SetQuake2(30); + PlaySoundObject(35, SOUND_MODE_PLAY); + gBoss[1].act_no = 102; + gBoss[2].act_no = 102; + + for (i = 0; i < 0x100; ++i) + { + x = npc->x + (Random(-60, 60) * 0x200); + y = npc->y + (Random(-60, 60) * 0x200); + SetNpChar(4, x, y, 0, 0, 0, NULL, 0); + } + // Fallthrough + case 421: + ++npc->ani_wait; + + if (npc->ani_wait > 500) + { + npc->ani_wait = 0; + npc->act_no = 422; + } + + break; + + case 422: + ++npc->ani_wait; + + if (npc->ani_wait > 200) + { + npc->ani_wait = 0; + npc->act_no = 423; + } + + break; + + case 423: + ++npc->ani_wait; + + if (npc->ani_wait > 20) + { + npc->ani_wait = 0; + npc->act_no = 424; + } + + break; + + case 424: + ++npc->ani_wait; + + if (npc->ani_wait > 200) + { + npc->ani_wait = 0; + npc->act_no = 425; + } + + break; + + case 425: + ++npc->ani_wait; + + if (npc->ani_wait > 500) + { + npc->ani_wait = 0; + npc->act_no = 426; + } + + break; + + case 426: + ++npc->ani_wait; + + if (npc->ani_wait > 200) + { + npc->ani_wait = 0; + npc->act_no = 427; + } + + break; + + case 427: + ++npc->ani_wait; + + if (npc->ani_wait > 20) + { + npc->ani_wait = 0; + npc->act_no = 428; + } + + break; + + case 428: + ++npc->ani_wait; + + if (npc->ani_wait > 200) + { + npc->ani_wait = 0; + npc->act_no = 421; + } + + break; + + case 1000: + npc->act_no = 1001; + npc->act_wait = 0; + + gBoss[1].act_no = 300; + gBoss[2].act_no = 300; + +#ifndef FIX_BUGS + // This code makes absolutely no sense. + // Luckily, it doesn't cause any bugs. + gBoss[1].act_no &= ~(NPC_SOLID_SOFT | NPC_SOLID_HARD); + gBoss[2].act_no &= ~(NPC_SOLID_SOFT | NPC_SOLID_HARD); +#endif + + gBoss[0].bits &= ~(NPC_SOLID_SOFT | NPC_SOLID_HARD); + gBoss[3].bits &= ~(NPC_SOLID_SOFT | NPC_SOLID_HARD); + gBoss[4].bits &= ~(NPC_SOLID_SOFT | NPC_SOLID_HARD); + gBoss[5].bits &= ~(NPC_SOLID_SOFT | NPC_SOLID_HARD); + // Fallthrough + case 1001: + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait % 12 == 0) + PlaySoundObject(44, SOUND_MODE_PLAY); + + SetDestroyNpChar(gBoss[0].x + (Random(-60, 60) * 0x200), gBoss[0].y + (Random(-60, 60) * 0x200), 1, 1); + + if (gBoss[0].act_wait > 150) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 1002; + SetFlash(gBoss[0].x, gBoss[0].y, FLASH_MODE_EXPLOSION); + PlaySoundObject(35, SOUND_MODE_PLAY); + } + + break; + + case 1002: + SetQuake2(40); + + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait == 50) + { + gBoss[0].cond = 0; + gBoss[1].cond = 0; + gBoss[2].cond = 0; + gBoss[3].cond = 0; + gBoss[4].cond = 0; + gBoss[5].cond = 0; + + DeleteNpCharCode(350, TRUE); + DeleteNpCharCode(348, TRUE); + } + + break; + } + + if (npc->act_no > 420 && npc->act_no < 500) + { + gBoss[3].bits |= NPC_SHOOTABLE; + gBoss[4].bits |= NPC_SHOOTABLE; + gBoss[5].bits |= NPC_SHOOTABLE; + + ++npc->act_wait; + + if (npc->act_wait > 300) + { + npc->act_wait = 0; + + if (gMC.x > npc->x) + { + for (i = 0; i < 8; ++i) + { + x = ((156 + Random(-4, 4)) * 0x200 * 0x10) / 4; + y = (Random(8, 68) * 0x200 * 0x10) / 4; + SetNpChar(350, x, y, 0, 0, 0, NULL, 0x100); + } + } + else + { + for (i = 0; i < 8; ++i) + { + x = (Random(-4, 4) * 0x200 * 0x10) / 4; + y = (Random(8, 68) * 0x200 * 0x10) / 4; + SetNpChar(350, x, y, 0, 0, 2, NULL, 0x100); + } + } + } + + if (npc->act_wait == 270 || npc->act_wait == 280 || npc->act_wait == 290) + { + SetNpChar(353, npc->x, npc->y - (52 * 0x200), 0, 0, 1, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y - (52 * 0x200), 0, 0, 0, NULL, 0x100); + } + + if (npc->life > 500) + { + if (Random(0, 10) == 2) + { + x = npc->x + (Random(-40, 40) * 0x200); + y = npc->y + (Random(0, 40) * 0x200); + SetNpChar(270, x, y, 0, 0, 3, NULL, 0); + } + } + else + { + if (Random(0, 4) == 2) + { + x = npc->x + (Random(-40, 40) * 0x200); + y = npc->y + (Random(0, 40) * 0x200); + SetNpChar(270, x, y, 0, 0, 3, NULL, 0); + } + } + } + + if (npc->shock != 0) + { + if (++flash / 2 % 2) + gBoss[3].ani_no = 1; + else + gBoss[3].ani_no = 0; + } + else + { + gBoss[3].ani_no = 0; + } + + if (npc->act_no > 420) + gBoss[3].ani_no += 2; + + ActBossChar_Eye(&gBoss[1]); + ActBossChar_Eye(&gBoss[2]); + ActBossChar_Body(&gBoss[3]); + ActBossChar_HITAI(&gBoss[4]); + ActBossChar_HARA(&gBoss[5]); +} diff --git a/src/BossBallos.h b/src/BossBallos.h new file mode 100644 index 0000000..0b76ee0 --- /dev/null +++ b/src/BossBallos.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Ballos(void); diff --git a/src/BossFrog.cpp b/src/BossFrog.cpp new file mode 100644 index 0000000..482b324 --- /dev/null +++ b/src/BossFrog.cpp @@ -0,0 +1,625 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossFrog.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +enum BalfrogSprites +{ + BALFROG_SPRITE_NOTHING = 0, + BALFROG_SPRITE_STANDING_STILL = 1, + BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING = 2, + BALFROG_SPRITE_MOUTH_OPEN_CROUCHING = 3, + BALFROG_SPRITE_MOUTH_OPEN_CROUCHING_FLASHING = 4, + BALFROG_SPRITE_JUMPING = 5, + BALFROG_SPRITE_BALROG_WHITE = 6, + BALFROG_SPRITE_BALROG_CROUCHING = 7, + BALFROG_SPRITE_BALROG_JUMPING = 8 +}; + +enum BalfrogStates +{ + BALFROG_INITIALIZE = 0, + BALFROG_START = 10, + BALFROG_INITIALIZE_FLICKER = 20, + BALFROG_FLICKER = 21, + BALFROG_WAIT = 100, + BALFROG_INITIALIZE_HOP_1 = 101, + BALFROG_INITIALIZE_HOP_2 = 102, + BALFROG_HOP = 103, + BALFROG_MIDAIR = 104, + BALFROG_INITIALIZE_LAND = 110, + BALFROG_LAND = 111, + BALFROG_INITIALIZE_SHOOT = 112, + BALFROG_SHOOT = 113, + BALFROG_AFTER_SHOOT_WAIT = 114, + BALFROG_INITIALIZE_LEAP_1 = 120, + BALFROG_INITIALIZE_LEAP_2 = 121, + BALFROG_INITIALIZE_LEAP_3 = 122, + BALFROG_LEAP = 123, + BALFROG_LEAP_MIDAIR = 124, + BALFROG_DIE = 130, + BALFROG_DIE_FLASHING = 131, + BALFROG_REVERT = 132, + BALFROG_NOP_START = 140, + BALFROG_NOP = 141, + BALFROG_GO_INTO_CEILING = 142, + BALFROG_GONE_INTO_CEILING = 143 +}; + +// Balfrog's mouth +static void ActBossChar02_01(void) +{ + NPCHAR *boss; + int minus; + + if (gBoss[0].direct == DIR_LEFT) + minus = 1; + else + minus = -1; + + boss = &gBoss[1]; + + switch (gBoss[0].ani_no) + { + case BALFROG_SPRITE_NOTHING: + boss->hit_voice = SND_BEHEMOTH_LARGE_HURT; + boss->hit.front = 16 * 0x200; + boss->hit.top = 16 * 0x200; + boss->hit.back = 16 * 0x200; + boss->hit.bottom = 16 * 0x200; + boss->size = 3; + boss->bits = NPC_INVULNERABLE; + break; + + case BALFROG_SPRITE_STANDING_STILL: + boss->x = gBoss[0].x + -24 * 0x200 * minus; + boss->y = gBoss[0].y - 24 * 0x200; + break; + + case BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING: + boss->x = gBoss[0].x + -24 * 0x200 * minus; + boss->y = gBoss[0].y - 20 * 0x200; + break; + + case BALFROG_SPRITE_MOUTH_OPEN_CROUCHING: + case BALFROG_SPRITE_MOUTH_OPEN_CROUCHING_FLASHING: + boss->x = gBoss[0].x + -24 * 0x200 * minus; + boss->y = gBoss[0].y - 16 * 0x200; + break; + + case BALFROG_SPRITE_JUMPING: + boss->x = gBoss[0].x + -24 * 0x200 * minus; + boss->y = gBoss[0].y - 43 * 0x200; + break; + } +} + +static void ActBossChar02_02(void) +{ + NPCHAR *boss = &gBoss[2]; + + switch (gBoss[0].ani_no) + { + case BALFROG_SPRITE_NOTHING: + boss->hit_voice = SND_BEHEMOTH_LARGE_HURT; + boss->hit.front = 24 * 0x200; + boss->hit.top = 16 * 0x200; + boss->hit.back = 24 * 0x200; + boss->hit.bottom = 16 * 0x200; + boss->size = 3; + boss->bits = NPC_INVULNERABLE; + break; + + case BALFROG_SPRITE_STANDING_STILL: + case BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING: + case BALFROG_SPRITE_MOUTH_OPEN_CROUCHING: + case BALFROG_SPRITE_MOUTH_OPEN_CROUCHING_FLASHING: + case BALFROG_SPRITE_JUMPING: + boss->x = gBoss[0].x; + boss->y = gBoss[0].y; + break; + } +} + +// Main boss AI +void ActBossChar_Frog(void) +{ + unsigned char deg; + int xm, ym; + int i; + + // Rects 1-4 are for when Balfrog is a frog, 5-8 for when he reverts into Balrog and goes into the ceiling + RECT rcLeft[9] = { + {0, 0, 0, 0}, // Nothing + {0, 48, 80, 112}, // Balfrog standing still + {0, 112, 80, 176}, // Balfrog with his mouth barely open, crouching + {0, 176, 80, 240}, // Balfrog with his mouth open, crouching + {160, 48, 240, 112}, // Balfrog with his mouth open, crouching, flashing + {160, 112, 240, 200}, // Balfrog jumping + {200, 0, 240, 24}, // Balrog completely white + {80, 0, 120, 24}, // Balrog crouching + {120, 0, 160, 24}, // Balrog jumping + }; + + // See above + RECT rcRight[9] = { + {0, 0, 0, 0}, + {80, 48, 160, 112}, + {80, 112, 160, 176}, + {80, 176, 160, 240}, + {240, 48, 320, 112}, + {240, 112, 320, 200}, + {200, 24, 240, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + }; + + NPCHAR *boss = gBoss; + + switch (boss->act_no) + { + case BALFROG_INITIALIZE: + boss->x = 6 * (0x200 * 0x10); + boss->y = 12 * (0x200 * 0x10) + 8 * 0x200; + boss->direct = DIR_RIGHT; + boss->view.front = 48 * 0x200; + boss->view.top = 48 * 0x200; + boss->view.back = 32 * 0x200; + boss->view.bottom = 16 * 0x200; + boss->hit_voice = SND_BEHEMOTH_LARGE_HURT; + boss->hit.front = 24 * 0x200; + boss->hit.top = 16 * 0x200; + boss->hit.back = 24 * 0x200; + boss->hit.bottom = 16 * 0x200; + boss->size = 3; + boss->exp = 1; + boss->code_event = 1000; + boss->bits |= (NPC_EVENT_WHEN_KILLED | NPC_SHOW_DAMAGE); + boss->life = 300; + break; + + case BALFROG_START: + boss->act_no = (BALFROG_START + 1); + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + boss->cond = NPCCOND_ALIVE; + boss->rect = rcRight[0]; + + gBoss[1].cond = (NPCCOND_ALIVE | NPCCOND_DAMAGE_BOSS); + gBoss[1].code_event = 1000; + gBoss[2].cond = NPCCOND_ALIVE; + + gBoss[1].damage = 5; + gBoss[2].damage = 5; + + for (i = 0; i < 8; ++i) + SetNpChar(NPC_SMOKE, boss->x + Random(-12, 12) * 0x200, boss->y + Random(-12, 12) * 0x200, Random(-341, 341), Random(-3 * 0x200, 0), DIR_LEFT, NULL, 0x100); + + break; + + case BALFROG_INITIALIZE_FLICKER: + boss->act_no = BALFROG_FLICKER; + boss->act_wait = 0; + // Fallthrough + case BALFROG_FLICKER: + ++boss->act_wait; + + if (boss->act_wait / 2 % 2) + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + else + boss->ani_no = BALFROG_SPRITE_NOTHING; + + break; + + case BALFROG_WAIT: + boss->act_no = BALFROG_INITIALIZE_HOP_1; + boss->act_wait = 0; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + boss->xm = 0; + // Fallthrough + case BALFROG_INITIALIZE_HOP_1: + ++boss->act_wait; + + if (boss->act_wait > 50) + { + boss->act_no = BALFROG_INITIALIZE_HOP_2; + boss->ani_wait = 0; + boss->ani_no = BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING; + } + + break; + + case BALFROG_INITIALIZE_HOP_2: + ++boss->ani_wait; + + if (boss->ani_wait > 10) + { + boss->act_no = BALFROG_HOP; + boss->ani_wait = 0; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + } + + break; + + case BALFROG_HOP: + ++boss->ani_wait; + + if (boss->ani_wait > 4) + { + boss->act_no = BALFROG_MIDAIR; + boss->ani_no = BALFROG_SPRITE_JUMPING; + boss->ym = -2 * 0x200; + PlaySoundObject(25, SOUND_MODE_PLAY); + + if (boss->direct == DIR_LEFT) + boss->xm = -1 * 0x200; + else + boss->xm = 1 * 0x200; + + boss->view.top = 64 * 0x200; + boss->view.bottom = 24 * 0x200; + } + + break; + + case BALFROG_MIDAIR: + if (boss->direct == DIR_LEFT && boss->flag & COLL_LEFT_WALL) + { + boss->direct = DIR_RIGHT; + boss->xm = 1 * 0x200; + } + + if (boss->direct == DIR_RIGHT && boss->flag & COLL_RIGHT_WALL) + { + boss->direct = DIR_LEFT; + boss->xm = -1 * 0x200; + } + + if (boss->flag & COLL_GROUND) + { + PlaySoundObject(SND_LARGE_OBJECT_HIT_GROUND, SOUND_MODE_PLAY); + SetQuake(30); + boss->act_no = BALFROG_WAIT; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + boss->view.top = 48 * 0x200; + boss->view.bottom = 16 * 0x200; + + if (boss->direct == DIR_LEFT && boss->x < gMC.x) + { + boss->direct = DIR_RIGHT; + boss->act_no = BALFROG_INITIALIZE_LAND; + } + + if (boss->direct == DIR_RIGHT && boss->x > gMC.x) + { + boss->direct = DIR_LEFT; + boss->act_no = BALFROG_INITIALIZE_LAND; + } + + SetNpChar(110, Random(4, 16) * (0x200 * 0x10), Random(0, 4) * (0x200 * 0x10), 0, 0, DIR_AUTO, NULL, 0x80); + + for (i = 0; i < 4; ++i) + SetNpChar(NPC_SMOKE, boss->x + Random(-12, 12) * 0x200, boss->y + boss->hit.bottom, Random(-341, 341), Random(-3 * 0x200, 0), DIR_LEFT, NULL, 0x100); + } + + break; + + case BALFROG_INITIALIZE_LAND: + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + boss->act_wait = 0; + boss->act_no = BALFROG_LAND; + // Fallthrough + case BALFROG_LAND: + ++boss->act_wait; + + boss->xm = (boss->xm * 8) / 9; + + if (boss->act_wait > 50) + { + boss->ani_no = BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING; + boss->ani_wait = 0; + boss->act_no = BALFROG_INITIALIZE_SHOOT; + } + + break; + + case BALFROG_INITIALIZE_SHOOT: + ++boss->ani_wait; + + if (boss->ani_wait > 4) + { + boss->act_no = BALFROG_SHOOT; + boss->act_wait = 0; + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + boss->count1 = 16; + gBoss[1].bits |= NPC_SHOOTABLE; + boss->tgt_x = boss->life; + } + + break; + + case BALFROG_SHOOT: + if (boss->shock != 0) + { + if (boss->count2++ / 2 % 2) + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING_FLASHING; + else + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + } + else + { + boss->count2 = 0; + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + } + + boss->xm = (boss->xm * 10) / 11; + + ++boss->act_wait; + + if (boss->act_wait > 16) + { + boss->act_wait = 0; + --boss->count1; + + if (boss->direct == DIR_LEFT) + deg = GetArktan(boss->x - 2 * (0x200 * 0x10) - gMC.x, boss->y - 8 * 0x200 - gMC.y); + else + deg = GetArktan(boss->x + 2 * (0x200 * 0x10) - gMC.x, boss->y - 8 * 0x200 - gMC.y); + + deg += (unsigned char)Random(-0x10, 0x10); + + ym = GetSin(deg); + xm = GetCos(deg); + + if (boss->direct == DIR_LEFT) + SetNpChar(NPC_PROJECTILE_BALFROG_SPITBALL, boss->x - 2 * (0x200 * 0x10), boss->y - 8 * 0x200, xm, ym, DIR_LEFT, NULL, 0x100); + else + SetNpChar(NPC_PROJECTILE_BALFROG_SPITBALL, boss->x + 2 * (0x200 * 0x10), boss->y - 8 * 0x200, xm, ym, DIR_LEFT, NULL, 0x100); + + PlaySoundObject(SND_ENEMY_SHOOT_PROJECTILE, SOUND_MODE_PLAY); + + if (boss->count1 == 0 || boss->life < boss->tgt_x - 90) + { + boss->act_no = BALFROG_AFTER_SHOOT_WAIT; + boss->act_wait = 0; + boss->ani_no = BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING; + boss->ani_wait = 0; + gBoss[1].bits &= ~NPC_SHOOTABLE; + } + } + + break; + + case BALFROG_AFTER_SHOOT_WAIT: + ++boss->ani_wait; + + if (boss->ani_wait > 10) + { + if (++gBoss[1].count1 > 2) + { + gBoss[1].count1 = 0; + boss->act_no = BALFROG_INITIALIZE_LEAP_1; + } + else + { + boss->act_no = BALFROG_WAIT; + } + + boss->ani_wait = 0; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + } + + break; + + case BALFROG_INITIALIZE_LEAP_1: + boss->act_no = BALFROG_INITIALIZE_LEAP_2; + boss->act_wait = 0; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + boss->xm = 0; + // Fallthrough + case BALFROG_INITIALIZE_LEAP_2: + ++boss->act_wait; + + if (boss->act_wait > 50) + { + boss->act_no = BALFROG_INITIALIZE_LEAP_3; + boss->ani_wait = 0; + boss->ani_no = BALFROG_SPRITE_MOUTH_BARELY_OPEN_CROUCHING; + } + + break; + + case BALFROG_INITIALIZE_LEAP_3: + ++boss->ani_wait; + + if (boss->ani_wait > 20) + { + boss->act_no = BALFROG_LEAP; + boss->ani_wait = 0; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + } + + break; + + case BALFROG_LEAP: + ++boss->ani_wait; + + if (boss->ani_wait > 4) + { + boss->act_no = BALFROG_LEAP_MIDAIR; + boss->ani_no = BALFROG_SPRITE_JUMPING; + boss->ym = -5 * 0x200; + boss->view.top = 64 * 0x200; + boss->view.bottom = 24 * 0x200; + PlaySoundObject(SND_SILLY_EXPLOSION, SOUND_MODE_PLAY); + } + + break; + + case BALFROG_LEAP_MIDAIR: + if (boss->flag & COLL_GROUND) + { + PlaySoundObject(SND_LARGE_OBJECT_HIT_GROUND, SOUND_MODE_PLAY); + SetQuake(60); + boss->act_no = BALFROG_WAIT; + boss->ani_no = BALFROG_SPRITE_STANDING_STILL; + boss->view.top = 48 * 0x200; + boss->view.bottom = 16 * 0x200; + + for (i = 0; i < 2; ++i) + SetNpChar(NPC_ENEMY_FROG, Random(4, 16) * (0x200 * 0x10), Random(0, 4) * (0x200 * 0x10), 0, 0, DIR_AUTO, NULL, 0x80); + + for (i = 0; i < 6; ++i) + SetNpChar(NPC_ENEMY_PUCHI, Random(4, 16) * (0x200 * 0x10), Random(0, 4) * (0x200 * 0x10), 0, 0, DIR_AUTO, NULL, 0x80); + + for (i = 0; i < 8; ++i) + SetNpChar(NPC_SMOKE, boss->x + Random(-12, 12) * 0x200, boss->y + boss->hit.bottom, Random(-341, 341), Random(-3 * 0x200, 0), DIR_LEFT, NULL, 0x100); + + if (boss->direct == DIR_LEFT && boss->x < gMC.x) + { + boss->direct = DIR_RIGHT; + boss->act_no = BALFROG_INITIALIZE_LAND; + } + + if (boss->direct == DIR_RIGHT && boss->x > gMC.x) + { + boss->direct = DIR_LEFT; + boss->act_no = BALFROG_INITIALIZE_LAND; + } + } + + break; + + case BALFROG_DIE: + boss->act_no = BALFROG_DIE_FLASHING; + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + boss->act_wait = 0; + boss->xm = 0; + PlaySoundObject(SND_EXPLOSION, SOUND_MODE_PLAY); + + for (i = 0; i < 8; ++i) + SetNpChar(NPC_SMOKE, boss->x + Random(-12, 12) * 0x200, boss->y + Random(-12, 12) * 0x200, Random(-341, 341), Random(-3 * 0x200, 0), DIR_LEFT, NULL, 0x100); + + gBoss[1].cond = 0; + gBoss[2].cond = 0; + // Fallthrough + case BALFROG_DIE_FLASHING: + ++boss->act_wait; + + if (boss->act_wait % 5 == 0) + SetNpChar(NPC_SMOKE, boss->x + Random(-12, 12) * 0x200, boss->y + Random(-12, 12) * 0x200, Random(-341, 341), Random(-3 * 0x200, 0), DIR_LEFT, NULL, 0x100); + + if (boss->act_wait / 2 % 2) + boss->x -= 1 * 0x200; + else + boss->x += 1 * 0x200; + + if (boss->act_wait > 100) + { + boss->act_wait = 0; + boss->act_no = BALFROG_REVERT; + } + + break; + + case BALFROG_REVERT: + ++boss->act_wait; + + if (boss->act_wait / 2 % 2) + { + boss->view.front = 20 * 0x200; + boss->view.top = 12 * 0x200; + boss->view.back = 20 * 0x200; + boss->view.bottom = 12 * 0x200; + boss->ani_no = BALFROG_SPRITE_BALROG_WHITE; + } + else + { + boss->view.front = 48 * 0x200; + boss->view.top = 48 * 0x200; + boss->view.back = 32 * 0x200; + boss->view.bottom = 16 * 0x200; + boss->ani_no = BALFROG_SPRITE_MOUTH_OPEN_CROUCHING; + } + + if (boss->act_wait % 9 == 0) + SetNpChar(NPC_SMOKE, boss->x + Random(-12, 12) * 0x200, boss->y + Random(-12, 12) * 0x200, Random(-341, 341), Random(-3 * 0x200, 0), DIR_LEFT, NULL, 0x100); + + if (boss->act_wait > 150) + { + boss->act_no = BALFROG_NOP_START; + boss->hit.bottom = 12 * 0x200; + } + + break; + + case BALFROG_NOP_START: + boss->act_no = BALFROG_NOP; + // Fallthrough + case BALFROG_NOP: + if (boss->flag & COLL_GROUND) + { + boss->act_no = BALFROG_GO_INTO_CEILING; + boss->act_wait = 0; + boss->ani_no = BALFROG_SPRITE_BALROG_CROUCHING; + } + + break; + + case BALFROG_GO_INTO_CEILING: + ++boss->act_wait; + + if (boss->act_wait > 30) + { + boss->ani_no = BALFROG_SPRITE_BALROG_JUMPING; + boss->ym = -5 * 0x200; + boss->bits |= NPC_IGNORE_SOLIDITY; + boss->act_no = BALFROG_GONE_INTO_CEILING; + } + + break; + + case BALFROG_GONE_INTO_CEILING: + boss->ym = -5 * 0x200; + + if (boss->y < 0) + { + boss->cond = 0; + PlaySoundObject(SND_LARGE_OBJECT_HIT_GROUND, SOUND_MODE_PLAY); + SetQuake(30); + } + + break; + } + + boss->ym += 0x40; + if (boss->ym > 0x5FF) + boss->ym = 0x5FF; + + boss->x += boss->xm; + boss->y += boss->ym; + + if (boss->direct == DIR_LEFT) + boss->rect = rcLeft[boss->ani_no]; + else + boss->rect = rcRight[boss->ani_no]; + + ActBossChar02_01(); + ActBossChar02_02(); +} diff --git a/src/BossFrog.h b/src/BossFrog.h new file mode 100644 index 0000000..ea94a70 --- /dev/null +++ b/src/BossFrog.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Frog(void); diff --git a/src/BossIronH.cpp b/src/BossIronH.cpp new file mode 100644 index 0000000..04df0e8 --- /dev/null +++ b/src/BossIronH.cpp @@ -0,0 +1,230 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossIronH.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" + +void ActBossChar_Ironhead(void) +{ + int i; + NPCHAR *npc = gBoss; + static unsigned char flash; + + switch (npc->act_no) + { + case 0: + npc->cond = 0x80; + npc->exp = 1; + npc->direct = 2; + npc->act_no = 100; + npc->x = 160 * 0x200; + npc->y = 128 * 0x200; + npc->view.front = 40 * 0x200; + npc->view.top = 12 * 0x200; + npc->view.back = 24 * 0x200; + npc->view.bottom = 12 * 0x200; + npc->hit_voice = 54; + npc->hit.front = 16 * 0x200; + npc->hit.top = 10 * 0x200; + npc->hit.back = 16 * 0x200; + npc->hit.bottom = 10 * 0x200; + npc->bits = (NPC_IGNORE_SOLIDITY | NPC_SHOOTABLE | NPC_EVENT_WHEN_KILLED | NPC_SHOW_DAMAGE); + npc->size = 3; + npc->damage = 10; + npc->code_event = 1000; + npc->life = 400; + break; + + case 100: + npc->act_no = 101; + npc->bits &= ~NPC_SHOOTABLE; + npc->act_wait = 0; + // Fallthrough + case 101: + ++npc->act_wait; + + if (npc->act_wait > 50) + { + npc->act_no = 250; + npc->act_wait = 0; + } + + if (npc->act_wait % 4 == 0) + SetNpChar(197, Random(15, 18) * (16 * 0x200), Random(2, 13) * (16 * 0x200), 0, 0, 0, NULL, 0x100); + + break; + + case 250: + npc->act_no = 251; + + if (npc->direct == 2) + { + npc->x = 240 * 0x200; + npc->y = gMC.y; + } + else + { + npc->x = 720 * 0x200; + npc->y = Random(2, 13) * (16 * 0x200); + } + + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + + npc->ym = Random(-0x200, 0x200); + npc->xm = Random(-0x200, 0x200); + + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 251: + if (npc->direct == 2) + { + npc->tgt_x += 2 * 0x200; + } + else + { + npc->tgt_x -= 1 * 0x200; + + if (npc->tgt_y < gMC.y) + npc->tgt_y += 1 * 0x200; + else + npc->tgt_y -= 1 * 0x200; + } + + if (npc->x < npc->tgt_x) + npc->xm += 8; + else + npc->xm -= 8; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 2) + { + if (npc->x > 720 * 0x200) + { + npc->direct = 0; + npc->act_no = 100; + } + } + else + { + if (npc->x < 272 * 0x200) + { + npc->direct = 2; + npc->act_no = 100; + } + } + + if (npc->direct == 0) + { + ++npc->act_wait; + + if (npc->act_wait == 300 || npc->act_wait == 310 || npc->act_wait == 320) + { + PlaySoundObject(39, SOUND_MODE_PLAY); + SetNpChar(198, npc->x + (10 * 0x200), npc->y + (1 * 0x200), Random(-3, 0) * 0x200, Random(-3, 3) * 0x200, 2, NULL, 0x100); + } + } + + ++npc->ani_wait; + + if (npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 0; + + break; + + case 1000: + npc->bits &= ~NPC_SHOOTABLE; + npc->ani_no = 8; + npc->damage = 0; + npc->act_no = 1001; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + SetQuake(20); + + for (i = 0; i < 0x20; ++i) + SetNpChar(4, npc->x + (Random(-128, 128) * 0x200), npc->y + (Random(-64, 64) * 0x200), Random(-128, 128) * 0x200, Random(-128, 128) * 0x200, 0, NULL, 0x100); + + DeleteNpCharCode(197, TRUE); + DeleteNpCharCode(271, TRUE); + DeleteNpCharCode(272, TRUE); + // Fallthrough + case 1001: + npc->tgt_x -= 1 * 0x200; + + npc->x = npc->tgt_x + (Random(-1, 1) * 0x200); + npc->y = npc->tgt_y + (Random(-1, 1) * 0x200); + + if (++npc->act_wait % 4 == 0) + SetNpChar(4, npc->x + (Random(-128, 128) * 0x200), npc->y + (Random(-64, 64) * 0x200), Random(-128, 128) * 0x200, Random(-128, 128) * 0x200, 0, NULL, 0x100); + + break; + } + + RECT rc[9] = { + {0, 0, 64, 24}, + {64, 0, 128, 24}, + {128, 0, 192, 24}, + {64, 0, 128, 24}, + {0, 0, 64, 24}, + {192, 0, 256, 24}, + {256, 0, 320, 24}, + {192, 0, 256, 24}, + {256, 48, 320, 72}, + }; + + RECT rcDamage[9] = { + {0, 24, 64, 48}, + {64, 24, 128, 48}, + {128, 24, 192, 48}, + {64, 24, 128, 48}, + {0, 24, 64, 48}, + {192, 24, 256, 48}, + {256, 24, 320, 48}, + {192, 24, 256, 48}, + {256, 48, 320, 72}, + }; + + if (npc->shock != 0) + { + if (++flash / 2 % 2) + npc->rect = rc[npc->ani_no]; + else + npc->rect = rcDamage[npc->ani_no]; + } + else + { + npc->rect = rc[npc->ani_no]; + } +} diff --git a/src/BossIronH.h b/src/BossIronH.h new file mode 100644 index 0000000..cf110b7 --- /dev/null +++ b/src/BossIronH.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Ironhead(void); diff --git a/src/BossLife.cpp b/src/BossLife.cpp new file mode 100644 index 0000000..3caa85c --- /dev/null +++ b/src/BossLife.cpp @@ -0,0 +1,85 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossLife.h" + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Boss.h" +#include "Draw.h" +#include "NpChar.h" + +BOSSLIFE gBL; + +void InitBossLife(void) +{ + gBL.flag = FALSE; +} + +BOOL StartBossLife(int code_event) +{ + int i = 0; + while (i < NPC_MAX && gNPC[i].code_event != code_event) + ++i; + + if (i == NPC_MAX) + return FALSE; + + gBL.flag = TRUE; + gBL.max = gNPC[i].life; + gBL.br = gNPC[i].life; + gBL.pLife = &gNPC[i].life; + return TRUE; +} + +BOOL StartBossLife2(void) +{ + gBL.flag = TRUE; + gBL.max = gBoss[0].life; + gBL.br = gBoss[0].life; + gBL.pLife = &gBoss[0].life; + return TRUE; +} + +void PutBossLife(void) +{ + RECT rcText = {0, 48, 32, 56}; + RECT rcBox1 = {0, 0, 244, 8}; + RECT rcBox2 = {0, 16, 244, 24}; + RECT rcLife = {0, 24, 0, 32}; + RECT rcBr = {0, 32, 232, 40}; + + if (gBL.flag == FALSE) + return; + + if (*gBL.pLife < 1) + { + gBL.flag = FALSE; + return; + } + + rcLife.right = (*gBL.pLife * 198) / gBL.max; + + if (gBL.br > *gBL.pLife) + { + if (++gBL.count > 30) + --gBL.br; + } + else + { + gBL.count = 0; + } + + rcBr.right = (gBL.br * 198) / gBL.max; + + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 128, WINDOW_HEIGHT - 20, &rcBox1, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 128, WINDOW_HEIGHT - 12, &rcBox2, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 88, WINDOW_HEIGHT - 16, &rcBr, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 88, WINDOW_HEIGHT - 16, &rcLife, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 120, WINDOW_HEIGHT - 16, &rcText, SURFACE_ID_TEXT_BOX); +} diff --git a/src/BossLife.h b/src/BossLife.h new file mode 100644 index 0000000..2936318 --- /dev/null +++ b/src/BossLife.h @@ -0,0 +1,26 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef struct BOSSLIFE // Not the original struct name +{ + BOOL flag; + int *pLife; + int max; + int br; + int count; +} BOSSLIFE; + +extern BOSSLIFE gBL; + +void InitBossLife(void); +BOOL StartBossLife(int code_event); +BOOL StartBossLife2(void); +void PutBossLife(void); diff --git a/src/BossOhm.cpp b/src/BossOhm.cpp new file mode 100644 index 0000000..ebcf57f --- /dev/null +++ b/src/BossOhm.cpp @@ -0,0 +1,530 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossOhm.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Bullet.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" + +static void ActBoss01_12(void) +{ + int i; + + RECT rcLeft[1] = { + {80, 56, 104, 72} + }; + + RECT rcRight[1] = { + {104, 56, 128, 72} + }; + + for (i = 1; i < 3; ++i) + { + gBoss[i].y = (gBoss[0].y + gBoss[i + 2].y - (8 * 0x200)) / 2; + + if (gBoss[i].direct == 0) + { + gBoss[i].x = gBoss[0].x - (16 * 0x200); + gBoss[i].rect = rcLeft[gBoss[i].ani_no]; + } + else + { + gBoss[i].rect = rcRight[gBoss[i].ani_no]; + gBoss[i].x = gBoss[0].x + (16 * 0x200); + } + } +} + +static void ActBoss01_34(void) +{ + int i; + + RECT rcLeft[2] = { + {0, 56, 40, 88}, + {40, 56, 80, 88}, + }; + + RECT rcRight[2] = { + {0, 88, 40, 120}, + {40, 88, 80, 120}, + }; + + for (i = 3; i < 5; ++i) + { + switch (gBoss[i].act_no) + { + case 0: + gBoss[i].act_no = 1; + // Fallthrough + case 1: + gBoss[i].y = gBoss[0].y; + + if (i == 3) + gBoss[i].x = gBoss[0].x - (16 * 0x200); + if (i == 4) + gBoss[i].x = gBoss[0].x + (16 * 0x200); + + break; + + case 3: + gBoss[i].tgt_y = gBoss[0].y + (24 * 0x200); + + if (i == 3) + gBoss[i].x = gBoss[0].x - (16 * 0x200); + if (i == 4) + gBoss[i].x = gBoss[0].x + (16 * 0x200); + + gBoss[i].y += (gBoss[i].tgt_y - gBoss[i].y) / 2; + break; + } + + if (gBoss[i].flag & 8 || gBoss[i].y <= gBoss[i].tgt_y) + gBoss[i].ani_no = 0; + else + gBoss[i].ani_no = 1; + + if (gBoss[i].direct == 0) + gBoss[i].rect = rcLeft[gBoss[i].ani_no]; + else + gBoss[i].rect = rcRight[gBoss[i].ani_no]; + } +} + +static void ActBoss01_5(void) +{ + switch (gBoss[5].act_no) + { + case 0: + gBoss[5].bits |= (NPC_SOLID_SOFT | NPC_IGNORE_SOLIDITY); + + gBoss[5].hit.front = 20 * 0x200; + gBoss[5].hit.top = 36 * 0x200; + gBoss[5].hit.back = 20 * 0x200; + gBoss[5].hit.bottom = 16 * 0x200; + + gBoss[5].act_no = 1; + // Fallthrough + case 1: + gBoss[5].x = gBoss[0].x; + gBoss[5].y = gBoss[0].y; + break; + } +} + +void ActBossChar_Omega(void) +{ + switch (gBoss[0].act_no) + { + case 0: + gBoss[0].x = 219 * 0x10 * 0x200; + gBoss[0].y = 16 * 0x10 * 0x200; + + gBoss[0].view.front = 40 * 0x200; + gBoss[0].view.top = 40 * 0x200; + gBoss[0].view.back = 40 * 0x200; + gBoss[0].view.bottom = 16 * 0x200; + + gBoss[0].tgt_x = gBoss[0].x; + gBoss[0].tgt_y = gBoss[0].y; + + gBoss[0].hit_voice = 52; + + gBoss[0].hit.front = 8 * 0x200; + gBoss[0].hit.top = 24 * 0x200; + gBoss[0].hit.back = 8 * 0x200; + gBoss[0].hit.bottom = 16 * 0x200; + + gBoss[0].bits = (NPC_IGNORE_SOLIDITY | NPC_EVENT_WHEN_KILLED | NPC_SHOW_DAMAGE); + gBoss[0].size = 3; + gBoss[0].exp = 1; + gBoss[0].code_event = 210; + gBoss[0].life = 400; + + gBoss[1].cond = 0x80; + + gBoss[1].view.front = 12 * 0x200; + gBoss[1].view.top = 8 * 0x200; + gBoss[1].view.back = 12 * 0x200; + gBoss[1].view.bottom = 8 * 0x200; + + gBoss[1].bits = NPC_IGNORE_SOLIDITY; + + gBoss[2] = gBoss[1]; + + gBoss[1].direct = 0; + gBoss[2].direct = 2; + + gBoss[3].cond = 0x80; + + gBoss[3].view.front = 24 * 0x200; + gBoss[3].view.top = 16 * 0x200; + gBoss[3].view.back = 16 * 0x200; + gBoss[3].view.bottom = 16 * 0x200; + + gBoss[3].hit_voice = 52; + + gBoss[3].hit.front = 8 * 0x200; + gBoss[3].hit.top = 8 * 0x200; + gBoss[3].hit.back = 8 * 0x200; + gBoss[3].hit.bottom = 8 * 0x200; + + gBoss[3].bits = NPC_IGNORE_SOLIDITY; + + gBoss[3].x = gBoss[0].x - (16 * 0x200); + gBoss[3].y = gBoss[0].y; + gBoss[3].direct = 0; + + gBoss[4] = gBoss[3]; + + gBoss[4].direct = 2; + gBoss[3].x = gBoss[0].x + (16 * 0x200); + gBoss[5].cond = 0x80; + break; + + case 20: // Rising out of the ground + gBoss[0].act_no = 30; + gBoss[0].act_wait = 0; + gBoss[0].ani_no = 0; + // Fallthrough + case 30: + SetQuake(2); + gBoss[0].y -= 1 * 0x200; + + if (++gBoss[0].act_wait % 4 == 0) + PlaySoundObject(26, SOUND_MODE_PLAY); + + if (gBoss[0].act_wait == 48) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 40; + + if (gBoss[0].life > 280) + break; + + gBoss[0].act_no = 110; + + gBoss[0].bits |= NPC_SHOOTABLE; + gBoss[0].bits &= ~NPC_IGNORE_SOLIDITY; + gBoss[3].bits &= ~NPC_IGNORE_SOLIDITY; + gBoss[4].bits &= ~NPC_IGNORE_SOLIDITY; + + gBoss[3].act_no = 3; + gBoss[4].act_no = 3; + gBoss[5].hit.top = 16 * 0x200; + } + + break; + + case 40: + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait == 48) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 50; + gBoss[0].count1 = 0; + gBoss[5].hit.top = 16 * 0x200; + PlaySoundObject(102, SOUND_MODE_PLAY); + } + + break; + + case 50: // Open mouth + ++gBoss[0].count1; + + if (gBoss[0].count1 > 2) + { + gBoss[0].count1 = 0; + ++gBoss[0].count2; + } + + if (gBoss[0].count2 == 3) + { + gBoss[0].act_no = 60; + gBoss[0].act_wait = 0; + gBoss[0].bits |= NPC_SHOOTABLE; + gBoss[0].hit.front = 16 * 0x200; + gBoss[0].hit.back = 16 * 0x200; + } + + break; + + case 60: // Shoot out of mouth + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait > 20 && gBoss[0].act_wait < 80 && !(gBoss[0].act_wait % 3)) + { + if (Random(0, 9) < 8) + SetNpChar(48, gBoss[0].x, gBoss[0].y - (16 * 0x200), Random(-0x100, 0x100), -0x10 * 0x200 / 10, 0, NULL, 0x100); + else + SetNpChar(48, gBoss[0].x, gBoss[0].y - (16 * 0x200), Random(-0x100, 0x100), -0x10 * 0x200 / 10, 2, NULL, 0x100); + + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (gBoss[0].act_wait == 200 || CountArmsBullet(6)) + { + gBoss[0].count1 = 0; + gBoss[0].act_no = 70; + PlaySoundObject(102, SOUND_MODE_PLAY); + } + + break; + + case 70: // Close mouth + ++gBoss[0].count1; + + if (gBoss[0].count1 > 2) + { + gBoss[0].count1 = 0; + --gBoss[0].count2; + } + + if (gBoss[0].count2 == 1) + gBoss[0].damage = 20; + + if (gBoss[0].count2 == 0) + { + PlaySoundObject(102, SOUND_MODE_STOP); + PlaySoundObject(12, SOUND_MODE_PLAY); + + gBoss[0].act_no = 80; + gBoss[0].act_wait = 0; + + gBoss[0].bits &= ~NPC_SHOOTABLE; + + gBoss[0].hit.front = 24 * 0x200; + gBoss[0].hit.back = 24 * 0x200; + gBoss[5].hit.top = 36 * 0x200; + + gBoss[0].damage = 0; + } + + break; + + case 80: + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait == 48) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 90; + } + + break; + + case 90: // Go back into the ground + SetQuake(2); + gBoss[0].y += 1 * 0x200; + + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait % 4 == 0) + PlaySoundObject(26, SOUND_MODE_PLAY); + + if (gBoss[0].act_wait == 48) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 100; + } + + break; + + case 100: // Move to proper position for coming out of the ground + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait == 120) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 30; + + gBoss[0].x = gBoss[0].tgt_x + (Random(-64, 64) * 0x200); + gBoss[0].y = gBoss[0].tgt_y; + } + + break; + + case 110: + ++gBoss[0].count1; + + if (gBoss[0].count1 > 2) + { + gBoss[0].count1 = 0; + ++gBoss[0].count2; + } + + if (gBoss[0].count2 == 3) + { + gBoss[0].act_no = 120; + gBoss[0].act_wait = 0; + gBoss[0].hit.front = 16 * 0x200; + gBoss[0].hit.back = 16 * 0x200; + } + + break; + + case 120: + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait == 50 || CountArmsBullet(6)) + { + gBoss[0].act_no = 130; + PlaySoundObject(102, SOUND_MODE_PLAY); + gBoss[0].act_wait = 0; + gBoss[0].count1 = 0; + } + + if (gBoss[0].act_wait < 30 && gBoss[0].act_wait % 5 == 0) + { + SetNpChar(48, gBoss[0].x, gBoss[0].y - (16 * 0x200), Random(-341, 341), -0x10 * 0x200 / 10, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + break; + + case 130: + ++gBoss[0].count1; + + if (gBoss[0].count1 > 2) + { + gBoss[0].count1 = 0; + --gBoss[0].count2; + } + + if (gBoss[0].count2 == 1) + gBoss[0].damage = 20; + + if (gBoss[0].count2 == 0) + { + gBoss[0].act_no = 140; + gBoss[0].bits |= NPC_SHOOTABLE; + + gBoss[0].hit.front = 16 * 0x200; + gBoss[0].hit.back = 16 * 0x200; + + gBoss[0].ym = -0x5FF; + + PlaySoundObject(102, SOUND_MODE_STOP); + PlaySoundObject(12, SOUND_MODE_PLAY); + PlaySoundObject(25, SOUND_MODE_PLAY); + + if (gBoss[0].x < gMC.x) + gBoss[0].xm = 0x100; + if (gBoss[0].x > gMC.x) + gBoss[0].xm = -0x100; + + gBoss[0].damage = 0; + gBoss[5].hit.top = 36 * 0x200; + } + + break; + + case 140: + if (gMC.flag & 8 && gBoss[0].ym > 0) + gBoss[5].damage = 20; + else + gBoss[5].damage = 0; + + gBoss[0].ym += 0x24; + if (gBoss[0].ym > 0x5FF) + gBoss[0].ym = 0x5FF; + + gBoss[0].x += gBoss[0].xm; + gBoss[0].y += gBoss[0].ym; + + if (gBoss[0].flag & 8) + { + gBoss[0].act_no = 110; + gBoss[0].act_wait = 0; + gBoss[0].count1 = 0; + + gBoss[5].hit.top = 16 * 0x200; + gBoss[5].damage = 0; + + PlaySoundObject(26, SOUND_MODE_PLAY); + PlaySoundObject(12, SOUND_MODE_PLAY); + + SetQuake(30); + } + + break; + + case 150: + SetQuake(2); + + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait % 12 == 0) + PlaySoundObject(52, SOUND_MODE_PLAY); + + SetDestroyNpChar(gBoss[0].x + (Random(-0x30, 0x30) * 0x200), gBoss[0].y + (Random(-0x30, 0x18) * 0x200), 1, 1); + + if (gBoss[0].act_wait > 100) + { + gBoss[0].act_wait = 0; + gBoss[0].act_no = 160; + SetFlash(gBoss[0].x, gBoss[0].y, FLASH_MODE_EXPLOSION); + PlaySoundObject(35, SOUND_MODE_PLAY); + } + + break; + + case 160: + SetQuake(40); + + ++gBoss[0].act_wait; + + if (gBoss[0].act_wait > 50) + { + gBoss[0].cond = 0; + gBoss[1].cond = 0; + gBoss[2].cond = 0; + gBoss[3].cond = 0; + gBoss[4].cond = 0; + gBoss[5].cond = 0; + } + + break; + } + + RECT rect[4] = { + {0, 0, 80, 56}, + {80, 0, 160, 56}, + {160, 0, 240, 56}, + {80, 0, 160, 56}, + }; + + gBoss[0].rect = rect[gBoss[0].count2]; + + gBoss[1].shock = gBoss[0].shock; + gBoss[2].shock = gBoss[0].shock; + gBoss[3].shock = gBoss[0].shock; + gBoss[4].shock = gBoss[0].shock; + + ActBoss01_34(); + ActBoss01_12(); + ActBoss01_5(); + + if (gBoss[0].life == 0 && gBoss[0].act_no < 150) + { + gBoss[0].act_no = 150; + gBoss[0].act_wait = 0; + gBoss[0].damage = 0; + gBoss[5].damage = 0; + DeleteNpCharCode(48, TRUE); + } +} diff --git a/src/BossOhm.h b/src/BossOhm.h new file mode 100644 index 0000000..fb5de74 --- /dev/null +++ b/src/BossOhm.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Omega(void); diff --git a/src/BossPress.cpp b/src/BossPress.cpp new file mode 100644 index 0000000..8428fbb --- /dev/null +++ b/src/BossPress.cpp @@ -0,0 +1,241 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossPress.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Game.h" +#include "Map.h" +#include "NpChar.h" +#include "Sound.h" + +void ActBossChar_Press(void) +{ + NPCHAR *npc = gBoss; + static unsigned char flash; + int i; + int x; + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->cond = 0x80; + npc->exp = 1; + npc->direct = 2; + npc->x = 0; + npc->y = 0; + npc->view.front = 40 * 0x200; + npc->view.top = 60 * 0x200; + npc->view.back = 40 * 0x200; + npc->view.bottom = 60 * 0x200; + npc->hit_voice = 54; + npc->hit.front = 49 * 0x200; + npc->hit.top = 60 * 0x200; + npc->hit.back = 40 * 0x200; + npc->hit.bottom = 48 * 0x200; + npc->bits = (NPC_IGNORE_SOLIDITY | NPC_SOLID_HARD | NPC_EVENT_WHEN_KILLED | NPC_SHOW_DAMAGE); + npc->size = 3; + npc->damage = 10; + npc->code_event = 1000; + npc->life = 700; + break; + + case 5: + npc->act_no = 6; + npc->x = 0; + npc->y = 0; + gBoss[1].cond = 0; + gBoss[2].cond = 0; + break; + + case 10: + npc->act_no = 11; + npc->x = 160 * 0x200; + npc->y = 74 * 0x200; + break; + + case 20: + npc->damage = 0; + npc->act_no = 21; + npc->x = 160 * 0x200; + npc->y = 413 * 0x200; + npc->bits &= ~NPC_SOLID_HARD; + gBoss[1].cond = 0; + gBoss[2].cond = 0; + // Fallthrough + case 21: + if (++npc->act_wait % 0x10 == 0) + SetDestroyNpChar(npc->x + (Random(-40, 40) * 0x200), npc->y + (Random(-60, 60) * 0x200), 1, 1); + + break; + + case 30: + npc->act_no = 31; + npc->ani_no = 2; + npc->x = 160 * 0x200; + npc->y = 64 * 0x200; + // Fallthrough + case 31: + npc->y += 4 * 0x200; + + if (npc->y >= 413 * 0x200) + { + npc->y = 413 * 0x200; + npc->ani_no = 0; + npc->act_no = 20; + PlaySoundObject(44, SOUND_MODE_PLAY); + + for (i = 0; i < 5; ++i) + { + x = npc->x + (Random(-40, 40) * 0x200); + SetNpChar(4, x, npc->y + (60 * 0x200), 0, 0, 0, NULL, 0x100); + } + + } + + break; + + case 100: + npc->act_no = 101; + npc->count2 = 9; + npc->act_wait = -100; + + gBoss[1].cond = 0x80; + gBoss[1].hit.front = 14 * 0x200; + gBoss[1].hit.back = 14 * 0x200; + gBoss[1].hit.top = 8 * 0x200; + gBoss[1].hit.bottom = 8 * 0x200; + gBoss[1].bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY); + + gBoss[2] = gBoss[1]; + + gBoss[3].cond = 0x90; + gBoss[3].bits |= NPC_SHOOTABLE; + gBoss[3].hit.front = 6 * 0x200; + gBoss[3].hit.back = 6 * 0x200; + gBoss[3].hit.top = 8 * 0x200; + gBoss[3].hit.bottom = 8 * 0x200; + + SetNpChar(325, npc->x, npc->y + (60 * 0x200), 0, 0, 0, NULL, 0x100); + // Fallthrough + case 101: + if (npc->count2 > 1 && npc->life < npc->count2 * 70) + { + --npc->count2; + + for (i = 0; i < 5; ++i) + { + ChangeMapParts(i + 8, npc->count2, 0); + SetDestroyNpChar((i + 8) * 0x200 * 0x10, npc->count2 * 0x200 * 0x10, 0, 4); + PlaySoundObject(12, SOUND_MODE_PLAY); + } + } + + if (++npc->act_wait == 81 || npc->act_wait == 241) + SetNpChar(323, 48 * 0x200, 240 * 0x200, 0, 0, 1, NULL, 0x100); + + if (npc->act_wait == 1 || npc->act_wait == 161) + SetNpChar(323, 272 * 0x200, 240 * 0x200, 0, 0, 1, NULL, 0x100); + + if (npc->act_wait >= 300) + { + npc->act_wait = 0; + SetNpChar(325, npc->x, npc->y + (60 * 0x200), 0, 0, 0, NULL, 0x100); + } + + break; + + case 500: + gBoss[3].bits &= ~NPC_SHOOTABLE; + + npc->act_no = 501; + npc->act_wait = 0; + npc->count1 = 0; + + DeleteNpCharCode(325, TRUE); + DeleteNpCharCode(330, TRUE); + // Fallthrough + case 501: + if (++npc->act_wait % 0x10 == 0) + { + PlaySoundObject(12, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x + (Random(-40, 40) * 0x200), npc->y + (Random(-60, 60) * 0x200), 1, 1); + } + + if (npc->act_wait == 95) + npc->ani_no = 1; + if (npc->act_wait == 98) + npc->ani_no = 2; + + if (npc->act_wait > 100) + npc->act_no = 510; + + break; + + case 510: + npc->ym += 0x40; + npc->damage = 0x7F; + npc->y += npc->ym; + + if (npc->count1 == 0 && npc->y > 160 * 0x200) + { + npc->count1 = 1; + npc->ym = -0x200; + npc->damage = 0; + + for (i = 0; i < 7; ++i) + { + ChangeMapParts(i + 7, 14, 0); + SetDestroyNpChar((i + 7) * 0x200 * 0x10, 224 * 0x200, 0, 0); + PlaySoundObject(12, SOUND_MODE_PLAY); + } + } + + if (npc->y > 480 * 0x200) + npc->act_no = 520; + + break; + } + + gBoss[1].x = npc->x - (24 * 0x200); + gBoss[1].y = npc->y + (52 * 0x200); + + gBoss[2].x = npc->x + (24 * 0x200); + gBoss[2].y = npc->y + (52 * 0x200); + + gBoss[3].x = npc->x; + gBoss[3].y = npc->y + (40 * 0x200); + + RECT rc[3] = { + {0, 0, 80, 120}, + {80, 0, 160, 120}, + {160, 0, 240, 120}, + }; + + RECT rcDamage[3] = { + {0, 120, 80, 240}, + {80, 120, 160, 240}, + {160, 120, 240, 240}, + }; + + if (npc->shock != 0) + { + if (++flash / 2 % 2) + npc->rect = rc[npc->ani_no]; + else + npc->rect = rcDamage[npc->ani_no]; + } + else + { + npc->rect = rc[npc->ani_no]; + } +} diff --git a/src/BossPress.h b/src/BossPress.h new file mode 100644 index 0000000..f4310ae --- /dev/null +++ b/src/BossPress.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Press(void); diff --git a/src/BossTwinD.cpp b/src/BossTwinD.cpp new file mode 100644 index 0000000..6ea1240 --- /dev/null +++ b/src/BossTwinD.cpp @@ -0,0 +1,556 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossTwinD.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Flash.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +static void ActBossCharT_DragonBody(NPCHAR *npc) +{ + unsigned char deg; + + RECT rcLeft[3] = { + {0, 0, 40, 40}, + {40, 0, 80, 40}, + {80, 0, 120, 40}, + }; + + RECT rcRight[3] = { + {0, 40, 40, 80}, + {40, 40, 80, 80}, + {80, 40, 120, 80}, + }; + + switch (npc->act_no) + { + case 0: + deg = ((npc->pNpc->count1 / 4) + npc->count1) % 0x100; + npc->act_no = 10; + npc->x += npc->pNpc->x + (GetCos(deg) * npc->pNpc->tgt_x); + npc->y += npc->pNpc->y + (GetSin(deg) * npc->pNpc->tgt_y); + // Fallthrough + case 10: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 100: + deg = ((npc->pNpc->count1 / 4) + npc->count1) % 0x100; + npc->tgt_x = npc->pNpc->x + (GetCos(deg) * npc->pNpc->tgt_x); + npc->tgt_y = npc->pNpc->y + (GetSin(deg) * npc->pNpc->tgt_y); + + npc->x += (npc->tgt_x - npc->x) / 8; + npc->y += (npc->tgt_y - npc->y) / 8; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 1000: + npc->act_no = 1001; + npc->bits &= ~NPC_SHOOTABLE; + // Fallthrough + case 1001: + deg = ((npc->pNpc->count1 / 4) + npc->count1) % 0x100; + npc->tgt_x = npc->pNpc->x + (GetCos(deg) * npc->pNpc->tgt_x); + npc->tgt_y = npc->pNpc->y + (GetSin(deg) * npc->pNpc->tgt_y); + + npc->x += (npc->tgt_x - npc->x) / 8; + npc->y += (npc->tgt_y - npc->y) / 8; + + if (npc->x > npc->pNpc->x) + npc->direct = 0; + else + npc->direct = 2; + + break; + } + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +static void ActBossCharT_DragonHead(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + RECT rcLeft[4] = { + {0, 80, 40, 112}, + {40, 80, 80, 112}, + {80, 80, 120, 112}, + {120, 80, 160, 112}, + }; + + RECT rcRight[4] = { + {0, 112, 40, 144}, + {40, 112, 80, 144}, + {80, 112, 120, 144}, + {120, 112, 160, 144}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + break; + + case 100: + npc->act_no = 200; + // Fallthrough + case 200: + npc->bits &= ~NPC_SHOOTABLE; + npc->ani_no = 0; + npc->hit.front = 16 * 0x200; + npc->act_no = 201; + npc->count1 = Random(100, 200); + // Fallthrough + case 201: + if (npc->count1 != 0) + { + --npc->count1; + } + else + { + npc->act_no = 210; + npc->act_wait = 0; + npc->count2 = 0; + } + + break; + + case 210: + ++npc->act_wait; + + if (npc->act_wait == 3) + npc->ani_no = 1; + + if (npc->act_wait == 6) + { + npc->ani_no = 2; + npc->hit.front = 8 * 0x200; + npc->bits |= NPC_SHOOTABLE; + npc->count2 = 0; + } + + if (npc->act_wait > 150) + { + npc->act_no = 220; + npc->act_wait = 0; + } + + if (npc->shock != 0) + ++npc->count2; + + if (npc->count2 > 10) + { + PlaySoundObject(51, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 4); + npc->act_no = 300; + npc->act_wait = 0; + npc->ani_no = 3; + npc->hit.front = 16 * 0x200; + } + + break; + + case 220: + ++npc->act_wait; + + if (npc->act_wait % 8 == 1) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg); + xm = GetCos(deg); + + if (npc->direct == 0) + SetNpChar(202, npc->x - (8 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + else + SetNpChar(202, npc->x + (8 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + + PlaySoundObject(33, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 50) + npc->act_no = 200; + + break; + + case 300: + ++npc->act_wait; + + if (npc->act_wait > 100) + npc->act_no = 200; + + break; + + case 400: + npc->act_no = 401; + npc->act_wait = 0; + npc->ani_no = 0; + npc->hit.front = 16 * 0x200; + npc->bits &= ~NPC_SHOOTABLE; + // Fallthrough + case 401: + ++npc->act_wait; + + if (npc->act_wait == 3) + npc->ani_no = 1; + + if (npc->act_wait == 6) + { + npc->ani_no = 2; + npc->hit.front = 8 * 0x200; + npc->bits |= NPC_SHOOTABLE; + npc->count2 = 0; + } + + if (npc->act_wait > 20 && npc->act_wait % 32 == 1) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg); + xm = GetCos(deg); + + if (npc->direct == 0) + SetNpChar(202, npc->x - (8 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + else + SetNpChar(202, npc->x + (8 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + + PlaySoundObject(33, SOUND_MODE_PLAY); + } + + break; + + case 1000: + npc->bits &= ~NPC_SHOOTABLE; + npc->ani_no = 3; + break; + } + + npc->direct = npc->pNpc->direct; + + if (npc->direct == 0) + npc->x = npc->pNpc->x - (4 * 0x200); + else + npc->x = npc->pNpc->x + (4 * 0x200); + + npc->y = npc->pNpc->y - (8 * 0x200); + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +void ActBossChar_Twin(void) +{ + NPCHAR *npc = gBoss; + + switch (npc->act_no) + { + case 0: + npc->cond = 0x80; + npc->direct = 0; + npc->act_no = 10; + npc->exp = 0; + npc->x = 160 * 0x200; + npc->y = 128 * 0x200; + npc->view.front = 8 * 0x200; + npc->view.top = 8 * 0x200; + npc->view.back = 128 * 0x200; + npc->view.bottom = 8 * 0x200; + npc->hit_voice = 54; + npc->hit.front = 8 * 0x200; + npc->hit.top = 8 * 0x200; + npc->hit.back = 8 * 0x200; + npc->hit.bottom = 8 * 0x200; + npc->bits = NPC_IGNORE_SOLIDITY; + npc->bits |= NPC_EVENT_WHEN_KILLED; + npc->size = 3; + npc->damage = 0; + npc->code_event = 1000; + npc->life = 500; + npc->count2 = Random(700, 1200); + npc->tgt_x = 180; + npc->tgt_y = 61; + + gBoss[2].cond = 0x80; + gBoss[2].view.back = 20 * 0x200; + gBoss[2].view.front = 20 * 0x200; + gBoss[2].view.top = 16 * 0x200; + gBoss[2].view.bottom = 16 * 0x200; + gBoss[2].hit.back = 12 * 0x200; + gBoss[2].hit.front = 12 * 0x200; + gBoss[2].hit.top = 10 * 0x200; + gBoss[2].hit.bottom = 10 * 0x200; + gBoss[2].bits = (NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY); + gBoss[2].pNpc = &gBoss[3]; + gBoss[2].cond |= 0x10; + gBoss[2].damage = 10; + + gBoss[3].cond = 0x80; + gBoss[3].view.back = 20 * 0x200; + gBoss[3].view.front = 20 * 0x200; + gBoss[3].view.top = 20 * 0x200; + gBoss[3].view.bottom = 20 * 0x200; + gBoss[3].hit.back = 12 * 0x200; + gBoss[3].hit.front = 12 * 0x200; + gBoss[3].hit.top = 2 * 0x200; + gBoss[3].hit.bottom = 16 * 0x200; + gBoss[3].bits = NPC_IGNORE_SOLIDITY; + gBoss[3].pNpc = npc; + gBoss[3].damage = 10; + + gBoss[4] = gBoss[2]; + gBoss[4].pNpc = &gBoss[5]; + + gBoss[5] = gBoss[3]; + gBoss[5].count1 = 128; + break; + + case 20: + if (--npc->tgt_x <= 0x70) + { + npc->act_no = 100; + npc->act_wait = 0; + gBoss[2].act_no = 100; + gBoss[4].act_no = 100; + gBoss[3].act_no = 100; + gBoss[5].act_no = 100; + } + + break; + + case 100: + ++npc->act_wait; + + if (npc->act_wait < 100) + { + npc->count1 += 1; + } + else if (npc->act_wait < 120) + { + npc->count1 += 2; + } + else if (npc->act_wait < npc->count2) + { + npc->count1 += 4; + } + else if (npc->act_wait < npc->count2 + 40) + { + npc->count1 += 2; + } + else if (npc->act_wait < npc->count2 + 60) + { + npc->count1 += 1; + } + else + { + npc->act_wait = 0; + npc->act_no = 110; + npc->count2 = Random(400, 700); + break; + } + + if (npc->count1 > 0x3FF) + npc->count1 -= 0x400; + + break; + + case 110: + ++npc->act_wait; + + if (npc->act_wait < 20) + { + npc->count1 -= 1; + } + else if (npc->act_wait < 60) + { + npc->count1 -= 2; + } + else if (npc->act_wait < npc->count2) + { + npc->count1 -= 4; + } + else if (npc->act_wait < npc->count2 + 40) + { + npc->count1 -= 2; + } + else if (npc->act_wait < npc->count2 + 60) + { + npc->count1 -= 1; + } + else + { + if (npc->life < 300) + { + npc->act_wait = 0; + npc->act_no = 400; + gBoss[2].act_no = 400; + gBoss[4].act_no = 400; + } + else + { + npc->act_wait = 0; + npc->act_no = 100; + npc->count2 = Random(400, 700); + } + + break; + } + + if (npc->count1 <= 0) + npc->count1 += 0x400; + + break; + + case 400: + ++npc->act_wait; + + if (npc->act_wait > 100) + { + npc->act_wait = 0; + npc->act_no = 401; + } + + break; + + case 401: + ++npc->act_wait; + + if (npc->act_wait < 100) + { + npc->count1 += 1; + } + else if (npc->act_wait < 120) + { + npc->count1 += 2; + } + else if (npc->act_wait < 500) + { + npc->count1 += 4; + } + else if (npc->act_wait < 540) + { + npc->count1 += 2; + } + else if (npc->act_wait < 560) + { + npc->count1 += 1; + } + else + { + npc->act_no = 100; + npc->act_wait = 0; + gBoss[2].act_no = 100; + gBoss[4].act_no = 100; + break; + } + + if (npc->count1 > 0x3FF) + npc->count1 -= 0x400; + + break; + + case 1000: + npc->act_no = 1001; + npc->act_wait = 0; + gBoss[2].act_no = 1000; + gBoss[3].act_no = 1000; + gBoss[4].act_no = 1000; + gBoss[5].act_no = 1000; + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 40); + // Fallthrough + + case 1001: + ++npc->act_wait; + + if (npc->act_wait > 100) + npc->act_no = 1010; + + SetNpChar(4, npc->x + (Random(-0x80, 0x80) * 0x200), npc->y + (Random(-70, 70) * 0x200), 0, 0, 0, NULL, 0x100); + break; + + case 1010: + npc->count1 += 4; + + if (npc->count1 > 0x3FF) + npc->count1 -= 0x400; + + if (npc->tgt_x > 8) + --npc->tgt_x; + if (npc->tgt_y > 0) + --npc->tgt_y; + + if (npc->tgt_x < -8) + ++npc->tgt_x; + if (npc->tgt_y < 0) + ++npc->tgt_y; + + if (npc->tgt_y == 0) + { + npc->act_no = 1020; + npc->act_wait = 0; + SetFlash(gBoss[0].x, gBoss[0].y, FLASH_MODE_EXPLOSION); + PlaySoundObject(35, SOUND_MODE_PLAY); + } + + break; + + case 1020: + if (++gBoss[0].act_wait > 50) + { + DeleteNpCharCode(211, TRUE); + gBoss[0].cond = 0; + gBoss[1].cond = 0; + gBoss[2].cond = 0; + gBoss[3].cond = 0; + gBoss[4].cond = 0; + gBoss[5].cond = 0; + gBoss[0].act_no = 0; + } + + break; + } + + ActBossCharT_DragonHead(&gBoss[2]); + ActBossCharT_DragonBody(&gBoss[3]); + ActBossCharT_DragonHead(&gBoss[4]); + ActBossCharT_DragonBody(&gBoss[5]); + + RECT rc = {0, 0, 0, 0}; + npc->rect = rc; +} diff --git a/src/BossTwinD.h b/src/BossTwinD.h new file mode 100644 index 0000000..5216717 --- /dev/null +++ b/src/BossTwinD.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_Twin(void); diff --git a/src/BossX.cpp b/src/BossX.cpp new file mode 100644 index 0000000..9e8cf3a --- /dev/null +++ b/src/BossX.cpp @@ -0,0 +1,913 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BossX.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +static void ActBossChar03_01(NPCHAR *npc) +{ + RECT rcUp[6] = { + {0, 0, 72, 32}, + {0, 32, 72, 64}, + {72, 0, 144, 32}, + {144, 0, 216, 32}, + {72, 32, 144, 64}, + {144, 32, 216, 64}, + }; + + RECT rcDown[6] = { + {0, 64, 72, 96}, + {0, 96, 72, 128}, + {72, 64, 144, 96}, + {144, 64, 216, 96}, + {72, 96, 144, 128}, + {144, 96, 216, 128}, + }; + + switch (npc->act_no) + { + case 10: + npc->ani_no = 0; + npc->bits &= ~NPC_BOUNCY; + break; + + case 100: + npc->bits |= NPC_BOUNCY; + npc->act_no = 101; + npc->act_wait = 0; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 101: + if (++npc->act_wait > 30) + npc->act_no = 102; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + npc->xm -= 0x20; + break; + + case 102: + npc->bits &= ~NPC_BOUNCY; + npc->act_no = 103; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 103: + ++npc->act_wait; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->xm -= 0x20; + break; + + case 200: + npc->bits |= NPC_BOUNCY; + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + npc->act_no = 201; + npc->act_wait = 0; + npc->ani_no = 4; + npc->ani_wait = 0; + // Fallthrough + case 201: + if (++npc->act_wait > 30) + npc->act_no = 202; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 4; + + npc->xm += 0x20; + break; + + case 202: + npc->bits &= ~NPC_BOUNCY; + npc->act_no = 203; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 203: + ++npc->act_wait; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->xm += 0x20; + break; + + case 300: + npc->act_no = 301; + npc->ani_no = 4; + npc->ani_wait = 0; + npc->bits |= NPC_BOUNCY; + // Fallthrough + case 301: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 4; + + npc->xm += 0x20; + + if (npc->xm > 0) + { + npc->xm = 0; + npc->act_no = 10; + } + + break; + + case 400: + npc->act_no = 401; + npc->ani_no = 2; + npc->ani_wait = 0; + npc->bits |= NPC_BOUNCY; + // Fallthrough + case 401: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + npc->xm -= 0x20; + + if (npc->xm < 0) + { + npc->xm = 0; + npc->act_no = 10; + } + + break; + } + + if ((npc->act_no == 101 || npc->act_no == 201 || npc->act_no == 301 || npc->act_no == 401) && npc->act_wait % 2 == 1) + PlaySoundObject(112, SOUND_MODE_PLAY); + + if ((npc->act_no == 103 || npc->act_no == 203) && npc->act_wait % 4 == 1) + PlaySoundObject(111, SOUND_MODE_PLAY); + + if (npc->act_no >= 100 && gMC.y < npc->y + (4 * 0x200) && gMC.y > npc->y - (4 * 0x200)) + { + npc->damage = 10; + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + } + else + { + npc->damage = 0; + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + } + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + npc->x += npc->xm; + + if (npc->direct == 1) + npc->rect = rcUp[npc->ani_no]; + else + npc->rect = rcDown[npc->ani_no]; +} + +static void ActBossChar03_02(NPCHAR *npc) +{ + RECT rect[4] = { + {0, 128, 72, 160}, + {72, 128, 144, 160}, + {0, 160, 72, 192}, + {72, 160, 144, 192}, + }; + + int direct; + int x, y; + + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->act_wait = (npc->ani_no * 30) + 30; + // Fallthrough + case 11: + if (npc->act_wait != 0) + { + --npc->act_wait; + break; + } + + switch (npc->ani_no) + { + case 0: + direct = 3; + x = -30 * 0x200; + y = 6 * 0x200; + break; + case 1: + direct = 2; + x = 30 * 0x200; + y = 6 * 0x200; + break; + case 2: + direct = 0; + x = -30 * 0x200; + y = -6 * 0x200; + break; + case 3: + direct = 1; + x = 30 * 0x200; + y = -6 * 0x200; + break; + } + + SetNpChar(158, npc->x + x, npc->y + y, 0, 0, direct, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + npc->act_wait = 120; + + break; + } + + npc->x = (gBoss[0].x + gBoss[npc->count1].x) / 2; + npc->y = (gBoss[0].y + gBoss[npc->count1].y) / 2; + + npc->rect = rect[npc->ani_no]; +} + +static void ActBossChar03_03(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 10: + npc->tgt_x += 1 * 0x200; + + if (npc->tgt_x > 32 * 0x200) + { + npc->tgt_x = 32 * 0x200; + npc->act_no = 0; + gBoss[3].act_no = 10; + gBoss[4].act_no = 10; + gBoss[5].act_no = 10; + gBoss[6].act_no = 10; + } + + break; + + case 20: + npc->tgt_x -= 1 * 0x200; + + if (npc->tgt_x < 0) + { + npc->tgt_x = 0; + npc->act_no = 0; + gBoss[3].act_no = 0; + gBoss[4].act_no = 0; + gBoss[5].act_no = 0; + gBoss[6].act_no = 0; + } + + break; + + case 30: + npc->tgt_x += 1 * 0x200; + + if (npc->tgt_x > 20 * 0x200) + { + npc->tgt_x = 20 * 0x200; + npc->act_no = 0; + gBoss[7].act_no = 10; + gBoss[13].act_no = 10; + gBoss[14].act_no = 10; + gBoss[15].act_no = 10; + gBoss[16].act_no = 10; + } + + break; + + case 40: + npc->tgt_x -= 1 * 0x200; + + if (npc->tgt_x < 0) + { + npc->tgt_x = 0; + npc->act_no = 0; + gBoss[7].act_no = 0; + gBoss[13].act_no = 0; + gBoss[14].act_no = 0; + gBoss[15].act_no = 0; + gBoss[16].act_no = 0; + } + + break; + } + + RECT rcLeft = {216, 96, 264, 144}; + RECT rcRight = {264, 96, 312, 144}; + + if (npc->direct == 0) + { + npc->rect = rcLeft; + npc->x = gBoss[0].x - (24 * 0x200) - npc->tgt_x; + npc->y = gBoss[0].y; + } + else + { + npc->rect = rcRight; + npc->x = gBoss[0].x + (24 * 0x200) + npc->tgt_x; + npc->y = gBoss[0].y; + } +} + +static void ActBossChar03_04(NPCHAR *npc) +{ + int xm, ym; + unsigned char deg; + + RECT rect[8] = { + {0, 192, 16, 208}, + {16, 192, 32, 208}, + {32, 192, 48, 208}, + {48, 192, 64, 208}, + {0, 208, 16, 224}, + {16, 208, 32, 224}, + {32, 208, 48, 224}, + {48, 208, 64, 224}, + }; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SHOOTABLE; + npc->ani_no = 0; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = (npc->tgt_x * 10) + 40; + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 11: + if (npc->act_wait < 16 && npc->act_wait / 2 % 2) + npc->ani_no = 1; + else + npc->ani_no = 0; + + if (npc->act_wait != 0) + { + --npc->act_wait; + break; + } + + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-2, 2); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + SetNpChar(156, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + + PlaySoundObject(39, SOUND_MODE_PLAY); + npc->act_wait = 40; + + break; + } + + switch (npc->tgt_x) + { + case 0: + npc->x = gBoss[0].x - (22 * 0x200); + npc->y = gBoss[0].y - (16 * 0x200); + break; + case 1: + npc->x = gBoss[0].x + (28 * 0x200); + npc->y = gBoss[0].y - (16 * 0x200); + break; + case 2: + npc->x = gBoss[0].x - (15 * 0x200); + npc->y = gBoss[0].y + (14 * 0x200); + break; + case 3: + npc->x = gBoss[0].x + (17 * 0x200); + npc->y = gBoss[0].y + (14 * 0x200); + break; + } + + npc->rect = rect[npc->tgt_x + 4 * npc->ani_no]; +} + +static void ActBossChar03_face(NPCHAR *npc) +{ + RECT rect[3] = { + {216, 0, 320, 48}, + {216, 48, 320, 96}, + {216, 144, 320, 192}, + }; + + static unsigned char flash; + + switch (npc->act_no) + { + case 0: + gBoss[0].bits &= ~NPC_SHOOTABLE; + npc->ani_no = 0; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = (npc->tgt_x * 10) + 40; + gBoss[0].bits |= NPC_SHOOTABLE; + // Fallthrough + case 11: + if (gBoss[0].shock) + { + if (flash++ / 2 % 2) + npc->ani_no = 1; + else + npc->ani_no = 0; + } + else + { + npc->ani_no = 0; + } + + break; + } + + gBoss[7].x = gBoss[0].x; + gBoss[7].y = gBoss[0].y; + + if (gBoss[0].act_no <= 10) + npc->ani_no = 2; + + npc->rect = rect[npc->ani_no]; +} + +void ActBossChar_MonstX(void) +{ + int i; + NPCHAR *npc = gBoss; + + switch (npc->act_no) + { + case 0: + npc->life = 1; + npc->x = -320 * 0x200; + break; + + case 1: + npc->life = 700; + npc->exp = 1; + npc->act_no = 1; + npc->x = 2048 * 0x200; + npc->y = 200 * 0x200; + npc->hit_voice = 54; + npc->hit.front = 24 * 0x200; + npc->hit.top = 24 * 0x200; + npc->hit.back = 24 * 0x200; + npc->hit.bottom = 24 * 0x200; + npc->bits = (NPC_IGNORE_SOLIDITY | NPC_EVENT_WHEN_KILLED | NPC_SHOW_DAMAGE); + npc->size = 3; + npc->code_event = 1000; + npc->ani_no = 0; + + gBoss[1].cond = 0x80; + gBoss[1].size = 3; + gBoss[1].direct = 0; + gBoss[1].view.front = 24 * 0x200; + gBoss[1].view.top = 24 * 0x200; + gBoss[1].view.back = 24 * 0x200; + gBoss[1].view.bottom = 24 * 0x200; + gBoss[1].bits = NPC_IGNORE_SOLIDITY; + + gBoss[2] = gBoss[1]; + gBoss[2].direct = 2; + + gBoss[3].cond = 0x80; + gBoss[3].life = 60; + gBoss[3].size = 3; // Redundant: this get overwritten a few lines later + gBoss[3].hit_voice = 54; + gBoss[3].destroy_voice = 71; + gBoss[3].size = 2; + gBoss[3].view.front = 8 * 0x200; + gBoss[3].view.top = 8 * 0x200; + gBoss[3].view.back = 8 * 0x200; + gBoss[3].view.bottom = 8 * 0x200; + gBoss[3].hit.front = 5 * 0x200; + gBoss[3].hit.back = 5 * 0x200; + gBoss[3].hit.top = 5 * 0x200; + gBoss[3].hit.bottom = 5 * 0x200; + gBoss[3].bits = NPC_IGNORE_SOLIDITY; + gBoss[3].tgt_x = 0; + + gBoss[4] = gBoss[3]; + gBoss[4].tgt_x = 1; + + gBoss[5] = gBoss[3]; + gBoss[5].tgt_x = 2; + gBoss[5].life = 100; + + gBoss[6] = gBoss[3]; + gBoss[6].tgt_x = 3; + gBoss[6].life = 100; + + gBoss[7].cond = 0x80; + gBoss[7].x = 2048 * 0x200; + gBoss[7].y = 200 * 0x200; + gBoss[7].view.front = 52 * 0x200; + gBoss[7].view.top = 24 * 0x200; + gBoss[7].view.back = 52 * 0x200; + gBoss[7].view.bottom = 24 * 0x200; + gBoss[7].hit_voice = 52; + gBoss[7].hit.front = 8 * 0x200; + gBoss[7].hit.top = 24 * 0x200; + gBoss[7].hit.back = 8 * 0x200; + gBoss[7].hit.bottom = 16 * 0x200; + gBoss[7].bits = NPC_IGNORE_SOLIDITY; + gBoss[7].size = 3; + gBoss[7].ani_no = 0; + + gBoss[9].cond = 0x80; + gBoss[9].act_no = 0; + gBoss[9].direct = 1; + gBoss[9].x = 1984 * 0x200; + gBoss[9].y = 144 * 0x200; + gBoss[9].view.front = 36 * 0x200; + gBoss[9].view.top = 8 * 0x200; + gBoss[9].view.back = 36 * 0x200; + gBoss[9].view.bottom = 24 * 0x200; + gBoss[9].hit_voice = 52; + gBoss[9].hit.front = 28 * 0x200; + gBoss[9].hit.top = 8 * 0x200; + gBoss[9].hit.back = 28 * 0x200; + gBoss[9].hit.bottom = 16 * 0x200; + gBoss[9].bits = (NPC_SOLID_SOFT | NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_REAR_AND_TOP_DONT_HURT); + gBoss[9].size = 3; + + gBoss[10] = gBoss[9]; + gBoss[10].x = 2112 * 0x200; + + gBoss[11] = gBoss[9]; + gBoss[11].direct = 3; + gBoss[11].x = 1984 * 0x200; + gBoss[11].y = 256 * 0x200; + gBoss[11].view.top = 24 * 0x200; + gBoss[11].view.bottom = 8 * 0x200; + gBoss[11].hit.top = 16 * 0x200; + gBoss[11].hit.bottom = 8 * 0x200; + + gBoss[12] = gBoss[11]; + gBoss[12].x = 2112 * 0x200; + + gBoss[13] = gBoss[9]; + gBoss[13].cond = 0x80; + gBoss[13].view.top = 16 * 0x200; + gBoss[13].view.bottom = 16 * 0x200; + gBoss[13].view.front = 30 * 0x200; + gBoss[13].view.back = 42 * 0x200; + gBoss[13].count1 = 9; + gBoss[13].ani_no = 0; + gBoss[13].bits = NPC_IGNORE_SOLIDITY; + + gBoss[14] = gBoss[13]; + gBoss[14].view.front = 42 * 0x200; + gBoss[14].view.back = 30 * 0x200; + gBoss[14].count1 = 10; + gBoss[14].ani_no = 1; + gBoss[14].bits = NPC_IGNORE_SOLIDITY; + + gBoss[15] = gBoss[13]; + gBoss[15].view.top = 16 * 0x200; + gBoss[15].view.bottom = 16 * 0x200; + gBoss[15].count1 = 11; + gBoss[15].ani_no = 2; + gBoss[15].bits = NPC_IGNORE_SOLIDITY; + + gBoss[16] = gBoss[15]; + gBoss[16].view.front = 42 * 0x200; + gBoss[16].view.back = 30 * 0x200; + gBoss[16].count1 = 12; + gBoss[16].ani_no = 3; + gBoss[16].bits = NPC_IGNORE_SOLIDITY; + + npc->act_no = 2; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->count1 = 0; + // Fallthrough + case 11: + ++npc->act_wait; + + if (npc->act_wait > 100) + { + npc->act_wait = 0; + + if (npc->x > gMC.x) + npc->act_no = 100; + else + npc->act_no = 200; + } + + break; + + case 100: + npc->act_wait = 0; + npc->act_no = 101; + ++npc->count1; + // Fallthrough + case 101: + ++npc->act_wait; + + if (npc->act_wait == 4) + gBoss[9].act_no = 100; + if (npc->act_wait == 8) + gBoss[10].act_no = 100; + if (npc->act_wait == 10) + gBoss[11].act_no = 100; + if (npc->act_wait == 12) + gBoss[12].act_no = 100; + + if (npc->act_wait > 120 && npc->count1 > 2) + npc->act_no = 300; + if (npc->act_wait > 121 && gMC.x > npc->x) + npc->act_no = 200; + + break; + + case 200: + npc->act_wait = 0; + npc->act_no = 201; + ++npc->count1; + // Fallthrough + case 201: + ++npc->act_wait; + + if (npc->act_wait == 4) + gBoss[9].act_no = 200; + if (npc->act_wait == 8) + gBoss[10].act_no = 200; + if (npc->act_wait == 10) + gBoss[11].act_no = 200; + if (npc->act_wait == 12) + gBoss[12].act_no = 200; + + if (npc->act_wait > 120 && npc->count1 > 2) + npc->act_no = 400; + if (npc->act_wait > 121 && gMC.x < npc->x) + npc->act_no = 100; + + break; + + case 300: + npc->act_wait = 0; + npc->act_no = 301; + // Fallthrough + case 301: + ++npc->act_wait; + + if (npc->act_wait == 4) + gBoss[9].act_no = 300; + if (npc->act_wait == 8) + gBoss[10].act_no = 300; + if (npc->act_wait == 10) + gBoss[11].act_no = 300; + if (npc->act_wait == 12) + gBoss[12].act_no = 300; + + if (npc->act_wait > 50) + { + if (gBoss[3].cond == 0 && gBoss[4].cond == 0 && gBoss[5].cond == 0 && gBoss[6].cond == 0) + npc->act_no = 600; + else + npc->act_no = 500; + } + + break; + + case 400: + npc->act_wait = 0; + npc->act_no = 401; + // Fallthrough + case 401: + ++npc->act_wait; + + if (npc->act_wait == 4) + gBoss[9].act_no = 400; + if (npc->act_wait == 8) + gBoss[10].act_no = 400; + if (npc->act_wait == 10) + gBoss[11].act_no = 400; + if (npc->act_wait == 12) + gBoss[12].act_no = 400; + + if (npc->act_wait > 50) + { + if (gBoss[3].cond == 0 && gBoss[4].cond == 0 && gBoss[5].cond == 0 && gBoss[6].cond == 0) + npc->act_no = 600; + else + npc->act_no = 500; + } + + break; + + case 500: + npc->act_no = 501; + npc->act_wait = 0; + gBoss[1].act_no = 10; + gBoss[2].act_no = 10; + // Fallthrough + case 501: + ++npc->act_wait; + + if (npc->act_wait > 300) + { + npc->act_no = 502; + npc->act_wait = 0; + } + + if (gBoss[3].cond == 0 && gBoss[4].cond == 0 && gBoss[5].cond == 0 && gBoss[6].cond == 0) + { + npc->act_no = 502; + npc->act_wait = 0; + } + + break; + + case 502: + npc->act_no = 503; + npc->act_wait = 0; + npc->count1 = 0; + gBoss[1].act_no = 20; + gBoss[2].act_no = 20; + // Fallthrough + case 503: // Exactly identical to case 603 + ++npc->act_wait; + + if (npc->act_wait > 50) + { + if (npc->x > gMC.x) + npc->act_no = 100; + else + npc->act_no = 200; + } + + break; + + case 600: + npc->act_no = 601; + npc->act_wait = 0; + npc->count2 = npc->life; + gBoss[1].act_no = 30; + gBoss[2].act_no = 30; + // Fallthrough + case 601: + ++npc->act_wait; + + if (npc->life < npc->count2 - 200 || npc->act_wait > 300) + { + npc->act_no = 602; + npc->act_wait = 0; + } + + break; + + case 602: + npc->act_no = 603; + npc->act_wait = 0; + npc->count1 = 0; + gBoss[1].act_no = 40; + gBoss[2].act_no = 40; + // Fallthrough + + case 603: // Exactly identical to case 503 + ++npc->act_wait; + + if (npc->act_wait > 50) + { + if (npc->x > gMC.x) + npc->act_no = 100; + else + npc->act_no = 200; + } + + break; + + case 1000: + SetQuake(2); + + if (++npc->act_wait % 8 == 0) + PlaySoundObject(52, SOUND_MODE_PLAY); + + SetDestroyNpChar(npc->x + (Random(-72, 72) * 0x200), npc->y + (Random(-64, 64) * 0x200), 1, 1); + + if (npc->act_wait > 100) + { + npc->act_wait = 0; + npc->act_no = 1001; + SetFlash(npc->x, npc->y, FLASH_MODE_EXPLOSION); + PlaySoundObject(35, SOUND_MODE_PLAY); + } + + break; + + case 1001: + SetQuake(40); + + ++npc->act_wait; + + if (npc->act_wait > 50) + { + for (i = 0; i < 20; ++i) + gBoss[i].cond = 0; + + DeleteNpCharCode(158, TRUE); + SetNpChar(159, npc->x, npc->y - (24 * 0x200), 0, 0, 0, NULL, 0); + } + + break; + } + + ActBossChar03_01(&gBoss[9]); + ActBossChar03_01(&gBoss[10]); + ActBossChar03_01(&gBoss[11]); + ActBossChar03_01(&gBoss[12]); + + npc->x += (((gBoss[11].x + gBoss[10].x + gBoss[9].x + gBoss[12].x) / 4) - npc->x) / 0x10; + + ActBossChar03_face(&gBoss[7]); + + ActBossChar03_02(&gBoss[13]); + ActBossChar03_02(&gBoss[14]); + ActBossChar03_02(&gBoss[15]); + ActBossChar03_02(&gBoss[16]); + + ActBossChar03_03(&gBoss[1]); + ActBossChar03_03(&gBoss[2]); + + if (gBoss[3].cond) + ActBossChar03_04(&gBoss[3]); + if (gBoss[4].cond) + ActBossChar03_04(&gBoss[4]); + if (gBoss[5].cond) + ActBossChar03_04(&gBoss[5]); + if (gBoss[6].cond) + ActBossChar03_04(&gBoss[6]); + + if (npc->life == 0 && npc->act_no < 1000) + { + npc->act_no = 1000; + npc->act_wait = 0; + npc->shock = 150; + gBoss[9].act_no = 300; + gBoss[10].act_no = 300; + gBoss[11].act_no = 300; + gBoss[12].act_no = 300; + } +} diff --git a/src/BossX.h b/src/BossX.h new file mode 100644 index 0000000..8dec8cc --- /dev/null +++ b/src/BossX.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ActBossChar_MonstX(void); diff --git a/src/Bug Fixes.txt b/src/Bug Fixes.txt new file mode 100644 index 0000000..1c27c36 --- /dev/null +++ b/src/Bug Fixes.txt @@ -0,0 +1,5 @@ +Main.cpp : void SystemTask() + Pixel intended for the second alternate up key to be the plus key, Japanese keyboards have the plus key where the semi-colon key is, causing errors on other keyboard layouts) + +SelStage.cpp : int StageSelectLoop(int *p_event) + The screencap that serves as the menu's background was being drawn with transparency enabled. This can cause moving sprites (like the text) to leave a trail. diff --git a/src/BulHit.cpp b/src/BulHit.cpp new file mode 100644 index 0000000..9382954 --- /dev/null +++ b/src/BulHit.cpp @@ -0,0 +1,439 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "BulHit.h" + +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Game.h" +#include "Map.h" +#include "NpChar.h" +#include "Sound.h" + +static void Vanish(BULLET *bul) +{ + if (bul->code_bullet != 37 && bul->code_bullet != 38 && bul->code_bullet != 39) + PlaySoundObject(28, SOUND_MODE_PLAY); + else + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_UP); + + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_RIGHT); +} + +int JudgeHitBulletBlock(int x, int y, BULLET *bul) +{ + int i; + int hit = 0; + if (bul->x - bul->blockXL < ((x * 16) + 8) * 0x200 + && bul->x + bul->blockXL > ((x * 16) - 8) * 0x200 + && bul->y - bul->blockYL < ((y * 16) + 8) * 0x200 + && bul->y + bul->blockYL > ((y * 16) - 8) * 0x200) + hit |= 0x200; + + if (hit && bul->bbits & 0x60 && GetAttribute(x, y) == 0x43) + { + if (!(bul->bbits & 0x40)) + bul->cond = 0; + + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + PlaySoundObject(12, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, x * 0x200 * 0x10, y * 0x200 * 0x10, Random(-0x200, 0x200), Random(-0x200, 0x200), 0, NULL, 0x100); + + ShiftMapParts(x, y); + } + + return hit; +} + +int JudgeHitBulletBlock2(int x, int y, unsigned char *atrb, BULLET *bul) +{ + BOOL block[4]; + int workX, workY; + int hit, i; + + hit = 0; + + if (bul->bbits & 0x40) + { + for (i = 0; i < 4; ++i) + { + if (*atrb == 0x41 || *atrb == 0x61) + block[i] = TRUE; + else + block[i] = FALSE; + + ++atrb; + } + } + else + { + for (i = 0; i < 4; ++i) + { + if (*atrb == 0x41 || *atrb == 0x43 || *atrb == 0x61) + block[i] = TRUE; + else + block[i] = FALSE; + + ++atrb; + } + } + + workX = ((x * 16) + 8) * 0x200; + workY = ((y * 16) + 8) * 0x200; + + // Left wall + if (block[0] && block[2]) + { + if (bul->x - bul->blockXL < workX) + hit |= 1; + } + else if (block[0] && !block[2]) + { + if (bul->x - bul->blockXL < workX && bul->y - bul->blockYL < workY - (3 * 0x200)) + hit |= 1; + } + else if (!block[0] && block[2]) + { + if (bul->x - bul->blockXL < workX && bul->y + bul->blockYL > workY + (3 * 0x200)) + hit |= 1; + } + + // Right wall + if (block[1] && block[3]) + { + if (bul->x + bul->blockXL > workX) + hit |= 4; + } + else if (block[1] && !block[3]) + { + if (bul->x + bul->blockXL > workX && bul->y - bul->blockYL < workY - (3 * 0x200)) + hit |= 4; + } + else if (!block[1] && block[3]) + { + if (bul->x + bul->blockXL > workX && bul->y + bul->blockYL > workY + (3 * 0x200)) + hit |= 4; + } + + // Ceiling + if (block[0] && block[1]) + { + if (bul->y - bul->blockYL < workY) + hit |= 2; + } + else if (block[0] && !block[1]) + { + if (bul->y - bul->blockYL < workY && bul->x - bul->blockXL < workX - (3 * 0x200)) + hit |= 2; + } + else if (!block[0] && block[1]) + { + if (bul->y - bul->blockYL < workY && bul->x + bul->blockXL > workX + (3 * 0x200)) + hit |= 2; + } + + // Ground + if (block[2] && block[3]) + { + if (bul->y + bul->blockYL > workY) + hit |= 8; + } + else if (block[2] && !block[3]) + { + if (bul->y + bul->blockYL > workY && bul->x - bul->blockXL < workX - (3 * 0x200)) + hit |= 8; + } + else if (!block[2] && block[3]) + { + if (bul->y + bul->blockYL > workY && bul->x + bul->blockXL > workX + (3 * 0x200)) + hit |= 8; + } + + // Clip + if (bul->bbits & 8) + { + if (hit & 1) + bul->x = workX + bul->blockXL; + else if (hit & 4) + bul->x = workX - bul->blockXL; + else if (hit & 2) + bul->y = workY + bul->blockYL; + else if (hit & 8) + bul->y = workY - bul->blockYL; + } + else + { + if (hit & 0xF) + Vanish(bul); + } + + return hit; +} + +int JudgeHitBulletTriangleA(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y - (2 * 0x200) < ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) + (4 * 0x200) + && bul->y + (2 * 0x200) > ((y * 16) - 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) + (6 * 0x200); + else + Vanish(bul); + + hit |= 0x82; + } + + return hit; +} + +int JudgeHitBulletTriangleB(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y - (2 * 0x200) < ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) - (4 * 0x200) + && bul->y + (2 * 0x200) > ((y * 16) - 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) - (2 * 0x200); + else + Vanish(bul); + + hit |= 0x82; + } + + return hit; +} + +int JudgeHitBulletTriangleC(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y - (2 * 0x200) < ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) - (4 * 0x200) + && bul->y + (2 * 0x200) > ((y * 16) - 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) - (2 * 0x200); + else + Vanish(bul); + + hit |= 0x42; + } + + return hit; +} + +int JudgeHitBulletTriangleD(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y - (2 * 0x200) < ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) + (4 * 0x200) + && bul->y + (2 * 0x200) > ((y * 16) - 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) + (6 * 0x200); + else + Vanish(bul); + + hit |= 0x42; + } + + return hit; +} + +int JudgeHitBulletTriangleE(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x - (1 * 0x200) > ((x * 16) - 8) * 0x200 + && bul->y + (2 * 0x200) > ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) - (4 * 0x200) + && bul->y - (2 * 0x200) < ((y * 16) + 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) - (6 * 0x200); + else + Vanish(bul); + + hit |= 0x28; + } + + return hit; +} + +int JudgeHitBulletTriangleF(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y + (2 * 0x200) > ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) + (4 * 0x200) + && bul->y - (2 * 0x200) < ((y * 16) + 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) + ((bul->x - ((x * 16) * 0x200)) / 2) + (2 * 0x200); + else + Vanish(bul); + + hit |= 0x28; + } + + return hit; +} + +int JudgeHitBulletTriangleG(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y + (2 * 0x200) > ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) + (4 * 0x200) + && bul->y - (2 * 0x200) < ((y * 16) + 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) + (2 * 0x200); + else + Vanish(bul); + + hit |= 0x18; + } + + return hit; +} + +int JudgeHitBulletTriangleH(int x, int y, BULLET *bul) +{ + int hit = 0; + if (bul->x < ((x * 16) + 8) * 0x200 + && bul->x > ((x * 16) - 8) * 0x200 + && bul->y + (2 * 0x200) > ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) - (4 * 0x200) + && bul->y - (2 * 0x200) < ((y * 16) + 8) * 0x200) + { + if (bul->bbits & 8) + bul->y = ((y * 16) * 0x200) - ((bul->x - ((x * 16) * 0x200)) / 2) - (6 * 0x200); + else + Vanish(bul); + + hit |= 0x18; + } + + return hit; +} + +void HitBulletMap(void) +{ + int x, y; + unsigned char atrb[4]; + + int i, j; + + for (i = 0; i < BULLET_MAX; ++i) + { + int offx[4]; + int offy[4]; + + if (!(gBul[i].cond & 0x80)) + continue; + + x = gBul[i].x / 0x10 / 0x200; + y = gBul[i].y / 0x10 / 0x200; + + // Get surrounding tiles + offx[0] = 0; + offx[1] = 1; + offx[2] = 0; + offx[3] = 1; + offy[0] = 0; + offy[1] = 0; + offy[2] = 1; + offy[3] = 1; + + atrb[0] = GetAttribute(x, y); + atrb[1] = GetAttribute(x + 1, y); + atrb[2] = GetAttribute(x, y + 1); + atrb[3] = GetAttribute(x + 1, y + 1); + + // Clear hit tiles + gBul[i].flag = 0; + + if (gBul[i].bbits & 4) + { + // There probably used to be commented-out code here + } + else + { + for (j = 0; j < 4; ++j) + { + if (!(gBul[i].cond & 0x80)) + continue; + + switch (atrb[j]) + { + case 0x41: + case 0x43: + case 0x44: + case 0x61: + case 0x64: + gBul[i].flag |= JudgeHitBulletBlock(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x50: + case 0x70: + gBul[i].flag |= JudgeHitBulletTriangleA(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x51: + case 0x71: + gBul[i].flag |= JudgeHitBulletTriangleB(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x52: + case 0x72: + gBul[i].flag |= JudgeHitBulletTriangleC(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x53: + case 0x73: + gBul[i].flag |= JudgeHitBulletTriangleD(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x54: + case 0x74: + gBul[i].flag |= JudgeHitBulletTriangleE(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x55: + case 0x75: + gBul[i].flag |= JudgeHitBulletTriangleF(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x56: + case 0x76: + gBul[i].flag |= JudgeHitBulletTriangleG(x + offx[j], y + offy[j], &gBul[i]); + break; + + case 0x57: + case 0x77: + gBul[i].flag |= JudgeHitBulletTriangleH(x + offx[j], y + offy[j], &gBul[i]); + break; + } + } + + gBul[i].flag |= JudgeHitBulletBlock2(x, y, atrb, &gBul[i]); + } + } +} diff --git a/src/BulHit.h b/src/BulHit.h new file mode 100644 index 0000000..ea6d76f --- /dev/null +++ b/src/BulHit.h @@ -0,0 +1,10 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void HitBulletMap(void); diff --git a/src/Bullet.cpp b/src/Bullet.cpp new file mode 100644 index 0000000..e5a4f96 --- /dev/null +++ b/src/Bullet.cpp @@ -0,0 +1,2508 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Bullet.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "Draw.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Game.h" +#include "KeyControl.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" + +BULLET gBul[BULLET_MAX]; + +void InitBullet(void) +{ + // Identical to ClearBullet + int i; + + for (i = 0; i < BULLET_MAX; ++i) + gBul[i].cond = 0; +} + +int CountArmsBullet(int arms_code) +{ + int i; + int count = 0; + + for (i = 0; i < BULLET_MAX; ++i) + if (gBul[i].cond & 0x80 && (gBul[i].code_bullet + 2) / 3 == arms_code) + ++count; + + return count; +} + +int CountBulletNum(int bullet_code) +{ + int i; + int count = 0; + + for (i = 0; i < BULLET_MAX; ++i) + if (gBul[i].cond & 0x80 && gBul[i].code_bullet == bullet_code) + ++count; + + return count; +} + +void DeleteBullet(int code) +{ + int i; + int count = 0; // Guessed name. This is unused, and was optimised out of the Linux port. + + for (i = 0; i < BULLET_MAX; ++i) + if (gBul[i].cond & 0x80 && (gBul[i].code_bullet + 2) / 3 == code) + gBul[i].cond = 0; +} + +void ClearBullet(void) +{ + // Identical to InitBullet + int i; + + for (i = 0; i < BULLET_MAX; ++i) + gBul[i].cond = 0; +} + +void PutBullet(int fx, int fy) +{ + int i; + int x, y; + + for (i = 0; i < BULLET_MAX; ++i) + { + if (gBul[i].cond & 0x80) + { + switch (gBul[i].direct) + { + case DIR_LEFT: + x = gBul[i].x - gBul[i].view.front; + y = gBul[i].y - gBul[i].view.top; + break; + case DIR_UP: + x = gBul[i].x - gBul[i].view.top; + y = gBul[i].y - gBul[i].view.front; + break; + case DIR_RIGHT: + x = gBul[i].x - gBul[i].view.back; + y = gBul[i].y - gBul[i].view.top; + break; + case DIR_DOWN: + x = gBul[i].x - gBul[i].view.top; + y = gBul[i].y - gBul[i].view.back; + break; + } + + PutBitmap3(&grcGame, (x / 0x200) - (fx / 0x200), (y / 0x200) - (fy / 0x200), &gBul[i].rect, SURFACE_ID_BULLET); + } + } +} + +BULLET_TABLE gBulTbl[] = { + // Null + {0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}}, + // Snake + {4, 1, 20, 36, 4, 4, 2, 2, {8, 8, 8, 8}}, + {6, 1, 23, 36, 4, 4, 2, 2, {8, 8, 8, 8}}, + {8, 1, 30, 36, 4, 4, 2, 2, {8, 8, 8, 8}}, + // Polar Star + {1, 1, 8, 32, 6, 6, 2, 2, {8, 8, 8, 8}}, + {2, 1, 12, 32, 6, 6, 2, 2, {8, 8, 8, 8}}, + {4, 1, 16, 32, 6, 6, 2, 2, {8, 8, 8, 8}}, + // Fireball + {2, 2, 100, 8, 8, 16, 4, 2, {8, 8, 8, 8}}, + {3, 2, 100, 8, 4, 4, 4, 2, {8, 8, 8, 8}}, + {3, 2, 100, 8, 4, 4, 4, 2, {8, 8, 8, 8}}, + // Machine Gun + {2, 1, 20, 32, 2, 2, 2, 2, {8, 8, 8, 8}}, + {4, 1, 20, 32, 2, 2, 2, 2, {8, 8, 8, 8}}, + {6, 1, 20, 32, 2, 2, 2, 2, {8, 8, 8, 8}}, + // Missile Launcher + {0, 10, 50, 40, 2, 2, 2, 2, {8, 8, 8, 8}}, + {0, 10, 70, 40, 4, 4, 4, 4, {8, 8, 8, 8}}, + {0, 10, 90, 40, 4, 4, 0, 0, {8, 8, 8, 8}}, + // Missile Launcher explosion + {1, 100, 100, 20, 16, 16, 0, 0, {0, 0, 0, 0}}, + {1, 100, 100, 20, 16, 16, 0, 0, {0, 0, 0, 0}}, + {1, 100, 100, 20, 16, 16, 0, 0, {0, 0, 0, 0}}, + // Bubbler + {1, 1, 20, 8, 2, 2, 2, 2, {4, 4, 4, 4}}, + {2, 1, 20, 8, 2, 2, 2, 2, {4, 4, 4, 4}}, + {2, 1, 20, 8, 4, 4, 4, 4, {4, 4, 4, 4}}, + // Bubbler level 3 thorns + {3, 1, 32, 32, 2, 2, 2, 2, {4, 4, 4, 4}}, + // Blade slashes + {0, 100, 0, 36, 8, 8, 8, 8, {12, 12, 12, 12}}, + // Falling spike that deals 127 damage + {127, 1, 2, 4, 8, 4, 8, 4, {0, 0, 0, 0}}, + // Blade + {15, 1, 30, 36, 8, 8, 4, 2, {8, 8, 8, 8}}, + {6, 3, 18, 36, 10, 10, 4, 2, {12, 12, 12, 12}}, + {1, 100, 30, 36, 6, 6, 4, 4, {12, 12, 12, 12}}, + // Super Missile Launcher + {0, 10, 30, 40, 2, 2, 2, 2, {8, 8, 8, 8}}, + {0, 10, 40, 40, 4, 4, 4, 4, {8, 8, 8, 8}}, + {0, 10, 40, 40, 4, 4, 0, 0, {8, 8, 8, 8}}, + // Super Missile Launcher explosion + {2, 100, 100, 20, 12, 12, 0, 0, {0, 0, 0, 0}}, + {2, 100, 100, 20, 12, 12, 0, 0, {0, 0, 0, 0}}, + {2, 100, 100, 20, 12, 12, 0, 0, {0, 0, 0, 0}}, + // Nemesis + {4, 4, 20, 32, 4, 4, 3, 3, {8, 8, 24, 8}}, + {4, 2, 20, 32, 2, 2, 2, 2, {8, 8, 24, 8}}, + {1, 1, 20, 32, 2, 2, 2, 2, {8, 8, 24, 8}}, + // Spur + {4, 4, 30, 64, 6, 6, 3, 3, {8, 8, 8, 8}}, + {8, 8, 30, 64, 6, 6, 3, 3, {8, 8, 8, 8}}, + {12, 12, 30, 64, 6, 6, 3, 3, {8, 8, 8, 8}}, + // Spur trail + {3, 100, 30, 32, 6, 6, 3, 3, {4, 4, 4, 4}}, + {6, 100, 30, 32, 6, 6, 3, 3, {4, 4, 4, 4}}, + {11, 100, 30, 32, 6, 6, 3, 3, {4, 4, 4, 4}}, + // Curly's Nemesis + {4, 4, 20, 32, 4, 4, 3, 3, {8, 8, 24, 8}}, + // Screen-nuke that kills all enemies + {0, 4, 4, 4, 0, 0, 0, 0, {0, 0, 0, 0}}, + // Whimsical Star + {1, 1, 1, 36, 1, 1, 1, 1, {1, 1, 1, 1}} +}; + +void SetBullet(int no, int x, int y, int dir) +{ + int i = 0; + while (i < BULLET_MAX && gBul[i].cond & 0x80) + ++i; + + if (i >= BULLET_MAX) + return; + + memset(&gBul[i], 0, sizeof(BULLET)); + gBul[i].code_bullet = no; + gBul[i].cond = 0x80; + gBul[i].direct = dir; + gBul[i].damage = gBulTbl[no].damage; + gBul[i].life = gBulTbl[no].life; + gBul[i].life_count = gBulTbl[no].life_count; + gBul[i].bbits = gBulTbl[no].bbits; + gBul[i].enemyXL = gBulTbl[no].enemyXL * 0x200; + gBul[i].enemyYL = gBulTbl[no].enemyYL * 0x200; + gBul[i].blockXL = gBulTbl[no].blockXL * 0x200; + gBul[i].blockYL = gBulTbl[no].blockYL * 0x200; + gBul[i].view.back = gBulTbl[no].view.back * 0x200; + gBul[i].view.front = gBulTbl[no].view.front * 0x200; + gBul[i].view.top = gBulTbl[no].view.top * 0x200; + gBul[i].view.bottom = gBulTbl[no].view.bottom * 0x200; + gBul[i].x = x; + gBul[i].y = y; +} + +void ActBullet_Frontia1(BULLET *bul) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->act_no == 0) + { + bul->ani_no = Random(0, 2); + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x600; + break; + case DIR_UP: + bul->ym = -0x600; + break; + case DIR_RIGHT: + bul->xm = 0x600; + break; + case DIR_DOWN: + bul->ym = 0x600; + break; + } + } + else + { + bul->x += bul->xm; + bul->y += bul->ym; + } + + if (++bul->ani_wait > 0) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 3) + bul->ani_no = 0; + + RECT rcLeft[4] = { + {136, 80, 152, 80}, + {120, 80, 136, 96}, + {136, 64, 152, 80}, + {120, 64, 136, 80}, + }; + + RECT rcRight[4] = { + {120, 64, 136, 80}, + {136, 64, 152, 80}, + {120, 80, 136, 96}, + {136, 80, 152, 80}, + }; + + if (bul->direct == DIR_LEFT) + bul->rect = rcLeft[bul->ani_no]; + else + bul->rect = rcRight[bul->ani_no]; +} + +void ActBullet_Frontia2(BULLET *bul, int level) +{ + static unsigned int inc; + + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->act_no == 0) + { + bul->ani_no = Random(0, 2); + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x200; + break; + case DIR_UP: + bul->ym = -0x200; + break; + case DIR_RIGHT: + bul->xm = 0x200; + break; + case DIR_DOWN: + bul->ym = 0x200; + break; + } + + ++inc; + + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + if (inc % 2) + bul->ym = 0x400; + else + bul->ym = -0x400; + + break; + + case DIR_UP: + case DIR_DOWN: + if (inc % 2) + bul->xm = 0x400; + else + bul->xm = -0x400; + + break; + } + } + else + { + switch (bul->direct) + { + case DIR_LEFT: + bul->xm -= 0x80; + break; + case DIR_UP: + bul->ym -= 0x80; + break; + case DIR_RIGHT: + bul->xm += 0x80; + break; + case DIR_DOWN: + bul->ym += 0x80; + break; + } + + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + if (bul->count1 % 5 == 2) + { + if (bul->ym < 0) + bul->ym = 0x400; + else + bul->ym = -0x400; + } + + break; + + case DIR_UP: + case DIR_DOWN: + if (bul->count1 % 5 == 2) + { + if (bul->xm < 0) + bul->xm = 0x400; + else + bul->xm = -0x400; + } + + break; + } + + bul->x += bul->xm; + bul->y += bul->ym; + } + + if (++bul->ani_wait > 0) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 2) + bul->ani_no = 0; + + RECT rect[3] = { + {192, 16, 208, 32}, + {208, 16, 224, 32}, + {224, 16, 240, 32}, + }; + + bul->rect = rect[bul->ani_no]; + + if (level == 2) + SetNpChar(129, bul->x, bul->y, 0, -0x200, bul->ani_no, NULL, 0x100); + else + SetNpChar(129, bul->x, bul->y, 0, -0x200, bul->ani_no + 3, NULL, 0x100); +} + +void ActBullet_PoleStar(BULLET *bul, int level) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->act_no == 0) + { + bul->act_no = 1; + + // Set speed + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x1000; + break; + case DIR_UP: + bul->ym = -0x1000; + break; + case DIR_RIGHT: + bul->xm = 0x1000; + break; + case DIR_DOWN: + bul->ym = 0x1000; + break; + } + + // Set hitbox + switch (level) + { + case 1: + switch (bul->direct) + { + case DIR_LEFT: + bul->enemyYL = 0x400; + break; + case DIR_UP: + bul->enemyXL = 0x400; + break; + case DIR_RIGHT: + bul->enemyYL = 0x400; + break; + case DIR_DOWN: + bul->enemyXL = 0x400; + break; + } + break; + case 2: + switch (bul->direct) + { + case DIR_LEFT: + bul->enemyYL = 0x800; + break; + case DIR_UP: + bul->enemyXL = 0x800; + break; + case DIR_RIGHT: + bul->enemyYL = 0x800; + break; + case DIR_DOWN: + bul->enemyXL = 0x800; + break; + } + break; + } + } + else + { + // Move + bul->x += bul->xm; + bul->y += bul->ym; + } + + RECT rect1[2] = { + {128, 32, 144, 48}, + {144, 32, 160, 48}, + }; + + RECT rect2[2] = { + {160, 32, 176, 48}, + {176, 32, 192, 48}, + }; + + RECT rect3[2] = { + {128, 48, 144, 64}, + {144, 48, 160, 64}, + }; + + //Set framerect + switch (level) + { + case 1: + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + bul->rect = rect1[1]; + else + bul->rect = rect1[0]; + + break; + + case 2: + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + bul->rect = rect2[1]; + else + bul->rect = rect2[0]; + + break; + + case 3: + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + bul->rect = rect3[1]; + else + bul->rect = rect3[0]; + + break; + } +} + +void ActBullet_FireBall(BULLET *bul, int level) +{ + BOOL bBreak; + + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + bBreak = FALSE; + if (bul->flag & 2 && bul->flag & 8) + bBreak = TRUE; + if (bul->flag & 1 && bul->flag & 4) + bBreak = TRUE; + + if (bul->direct == DIR_LEFT && bul->flag & 1) + bul->direct = DIR_RIGHT; + if (bul->direct == DIR_RIGHT && bul->flag & 4) + bul->direct = DIR_LEFT; + + if (bBreak) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + PlaySoundObject(28, SOUND_MODE_PLAY); + return; + } + + if (bul->act_no == 0) + { + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x400; + break; + + case DIR_UP: + bul->xm = gMC.xm; + + if (gMC.xm < 0) + bul->direct = DIR_LEFT; + else + bul->direct = DIR_RIGHT; + + if (gMC.direct == DIR_LEFT) + bul->xm -= 0x80; + else + bul->xm += 0x80; + + bul->ym = -0x5FF; + break; + + case DIR_RIGHT: + bul->xm = 0x400; + break; + + case DIR_DOWN: + bul->xm = gMC.xm; + + if (gMC.xm < 0) + bul->direct = DIR_LEFT; + else + bul->direct = DIR_RIGHT; + + bul->ym = 0x5FF; + + break; + } + } + else + { + if (bul->flag & 8) + bul->ym = -0x400; + else if (bul->flag & 1) + bul->xm = 0x400; + else if (bul->flag & 4) + bul->xm = -0x400; + + bul->ym += 85; + if (bul->ym > 0x3FF) + bul->ym = 0x3FF; + + bul->x += bul->xm; + bul->y += bul->ym; + + if (bul->flag & 0xD) + PlaySoundObject(34, SOUND_MODE_PLAY); + } + + RECT rect_left1[4] = { + {128, 0, 144, 16}, + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + }; + + RECT rect_right1[4] = { + {128, 16, 144, 32}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + }; + + RECT rect_left2[3] = { + {192, 16, 208, 32}, + {208, 16, 224, 32}, + {224, 16, 240, 32}, + }; + + RECT rect_right2[3] = { + {224, 16, 240, 32}, + {208, 16, 224, 32}, + {192, 16, 208, 32}, + }; + + ++bul->ani_no; + + if (level == 1) + { + if (bul->ani_no > 3) + bul->ani_no = 0; + + if (bul->direct == DIR_LEFT) + bul->rect = rect_left1[bul->ani_no]; + else + bul->rect = rect_right1[bul->ani_no]; + } + else + { + if (bul->ani_no > 2) + bul->ani_no = 0; + + if (bul->direct == DIR_LEFT) + bul->rect = rect_left2[bul->ani_no]; + else + bul->rect = rect_right2[bul->ani_no]; + + if (level == 2) + SetNpChar(129, bul->x, bul->y, 0, -0x200, bul->ani_no, NULL, 0x100); + else + SetNpChar(129, bul->x, bul->y, 0, -0x200, bul->ani_no + 3, NULL, 0x100); + } +} + +void ActBullet_MachineGun(BULLET *bul, int level) +{ + int move; + + RECT rect1[4] = { + {64, 0, 80, 16}, + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {112, 0, 128, 16}, + }; + + RECT rect2[4] = { + {64, 16, 80, 32}, + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {112, 16, 128, 32}, + }; + + RECT rect3[4] = { + {64, 32, 80, 48}, + {80, 32, 96, 48}, + {96, 32, 112, 48}, + {112, 32, 128, 48}, + }; + + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->act_no == 0) + { + switch (level) + { + case 1: + move = 0x1000; + break; + case 2: + move = 0x1000; + break; + case 3: + move = 0x1000; + break; + } + + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -move; + bul->ym = Random(-0xAA, 0xAA); + break; + case DIR_UP: + bul->ym = -move; + bul->xm = Random(-0xAA, 0xAA); + break; + case DIR_RIGHT: + bul->xm = move; + bul->ym = Random(-0xAA, 0xAA); + break; + case DIR_DOWN: + bul->ym = move; + bul->xm = Random(-0xAA, 0xAA); + break; + } + } + else + { + bul->x += bul->xm; + bul->y += bul->ym; + + switch (level) + { + case 1: + bul->rect = rect1[bul->direct]; + break; + + case 2: + bul->rect = rect2[bul->direct]; + + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + SetNpChar(127, bul->x, bul->y, 0, 0, DIR_UP, NULL, 0x100); + else + SetNpChar(127, bul->x, bul->y, 0, 0, DIR_LEFT, NULL, 0x100); + + break; + + case 3: + bul->rect = rect3[bul->direct]; + SetNpChar(128, bul->x, bul->y, 0, 0, bul->direct, NULL, 0x100); + break; + } + } +} + +void ActBullet_Missile(BULLET *bul, int level) +{ + BOOL bHit; + + static unsigned int inc; + + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + bHit = FALSE; + + if (bul->life != 10) + bHit = TRUE; + if (bul->direct == DIR_LEFT && bul->flag & 1) + bHit = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 4) + bHit = TRUE; + if (bul->direct == DIR_UP && bul->flag & 2) + bHit = TRUE; + if (bul->direct == DIR_DOWN && bul->flag & 8) + bHit = TRUE; + if (bul->direct == DIR_LEFT && bul->flag & 0x80) + bHit = TRUE; + if (bul->direct == DIR_LEFT && bul->flag & 0x20) + bHit = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 0x40) + bHit = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 0x10) + bHit = TRUE; + + if (bHit) + { + SetBullet(level + 15, bul->x, bul->y, DIR_LEFT); + bul->cond = 0; + } + + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + bul->tgt_y = bul->y; + break; + case DIR_UP: + case DIR_DOWN: + bul->tgt_x = bul->x; + break; + } + + if (level == 3) + { + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + if (bul->y > gMC.y) + bul->ym = 0x100; + else + bul->ym = -0x100; + + bul->xm = Random(-0x200, 0x200); + break; + + case DIR_UP: + case DIR_DOWN: + if (bul->x > gMC.x) + bul->xm = 0x100; + else + bul->xm = -0x100; + + bul->ym = Random(-0x200, 0x200); + break; + } + + switch (++inc % 3) + { + case 0: + bul->ani_no = 0x80; + break; + case 1: + bul->ani_no = 0x40; + break; + case 2: + bul->ani_no = 0x33; + break; + } + } + else + { + bul->ani_no = 0x80; + } + // Fallthrough + case 1: + switch (bul->direct) + { + case DIR_LEFT: + bul->xm += -bul->ani_no; + break; + case DIR_UP: + bul->ym += -bul->ani_no; + break; + case DIR_RIGHT: + bul->xm += bul->ani_no; + break; + case DIR_DOWN: + bul->ym += bul->ani_no; + break; + } + + if (level == 3) + { + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + if (bul->y < bul->tgt_y) + bul->ym += 0x20; + else + bul->ym -= 0x20; + + break; + + case DIR_UP: + case DIR_DOWN: + if (bul->x < bul->tgt_x) + bul->xm += 0x20; + else + bul->xm -= 0x20; + break; + } + } + + if (bul->xm < -0xA00) + bul->xm = -0xA00; + if (bul->xm > 0xA00) + bul->xm = 0xA00; + + if (bul->ym < -0xA00) + bul->ym = -0xA00; + if (bul->ym > 0xA00) + bul->ym = 0xA00; + + bul->x += bul->xm; + bul->y += bul->ym; + + break; + } + + if (++bul->count2 > 2) + { + bul->count2 = 0; + + switch (bul->direct) + { + case DIR_LEFT: + SetCaret(bul->x + (8 * 0x200), bul->y, CARET_EXHAUST, DIR_RIGHT); + break; + case DIR_UP: + SetCaret(bul->x, bul->y + (8 * 0x200), CARET_EXHAUST, DIR_DOWN); + break; + case DIR_RIGHT: + SetCaret(bul->x - (8 * 0x200), bul->y, CARET_EXHAUST, DIR_LEFT); + break; + case DIR_DOWN: + SetCaret(bul->x, bul->y - (8 * 0x200), CARET_EXHAUST, DIR_UP); + break; + } + } + + RECT rect1[4] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + {48, 0, 64, 16}, + }; + + RECT rect2[4] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + {48, 16, 64, 32}, + }; + + RECT rect3[4] = { + {0, 32, 16, 48}, + {16, 32, 32, 48}, + {32, 32, 48, 48}, + {48, 32, 64, 48}, + }; + + switch (level) + { + case 1: + bul->rect = rect1[bul->direct]; + break; + case 2: + bul->rect = rect2[bul->direct]; + break; + case 3: + bul->rect = rect3[bul->direct]; + break; + } +} + +void ActBullet_Bom(BULLET *bul, int level) +{ + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (level) + { + case 1: + bul->act_wait = 10; + break; + case 2: + bul->act_wait = 15; + break; + case 3: + bul->act_wait = 5; + break; + } + + PlaySoundObject(44, SOUND_MODE_PLAY); + // Fallthrough + case 1: + switch (level) + { + case 1: + if (bul->act_wait % 3 == 0) + SetDestroyNpCharUp(bul->x + (Random(-16, 16) * 0x200), bul->y + (Random(-16, 16) * 0x200), bul->enemyXL, 2); + break; + + case 2: + if (bul->act_wait % 3 == 0) + SetDestroyNpCharUp(bul->x + (Random(-32, 32) * 0x200), bul->y + (Random(-32, 32) * 0x200), bul->enemyXL, 2); + break; + + case 3: + if (bul->act_wait % 3 == 0) + SetDestroyNpCharUp(bul->x + (Random(-40, 40) * 0x200), bul->y + (Random(-40, 40) * 0x200), bul->enemyXL, 2); + break; + } + + if (--bul->act_wait < 0) + bul->cond = 0; + + break; + } +} + +void ActBullet_Bubblin1(BULLET *bul) +{ + if (bul->flag & 0x2FF) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + return; + } + + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x600; + break; + case DIR_RIGHT: + bul->xm = 0x600; + break; + case DIR_UP: + bul->ym = -0x600; + break; + case DIR_DOWN: + bul->ym = 0x600; + break; + } + + break; + } + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm += 0x2A; + break; + case DIR_RIGHT: + bul->xm -= 0x2A; + break; + case DIR_UP: + bul->ym += 0x2A; + break; + case DIR_DOWN: + bul->ym -= 0x2A; + break; + } + + bul->x += bul->xm; + bul->y += bul->ym; + + if (++bul->act_wait > 40) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION_TINY, DIR_LEFT); + } + + RECT rect[4] = { + {192, 0, 200, 8}, + {200, 0, 208, 8}, + {208, 0, 216, 8}, + {216, 0, 224, 8}, + }; + + if (++bul->ani_wait > 3) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 3) + bul->ani_no = 3; + + bul->rect = rect[bul->ani_no]; +} + +void ActBullet_Bubblin2(BULLET *bul) +{ + BOOL bDelete = FALSE; + + if (bul->direct == DIR_LEFT && bul->flag & 1) + bDelete = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 4) + bDelete = TRUE; + if (bul->direct == DIR_UP && bul->flag & 2) + bDelete = TRUE; + if (bul->direct == DIR_DOWN && bul->flag & 8) + bDelete = TRUE; + + if (bDelete) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + return; + } + + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x600; + bul->ym = Random(-0x100, 0x100); + break; + case DIR_RIGHT: + bul->xm = 0x600; + bul->ym = Random(-0x100, 0x100); + break; + case DIR_UP: + bul->ym = -0x600; + bul->xm = Random(-0x100, 0x100); + break; + case DIR_DOWN: + bul->ym = 0x600; + bul->xm = Random(-0x100, 0x100); + break; + } + + break; + } + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm += 0x10; + break; + case DIR_RIGHT: + bul->xm -= 0x10; + break; + case DIR_UP: + bul->ym += 0x10; + break; + case DIR_DOWN: + bul->ym -= 0x10; + break; + } + + bul->x += bul->xm; + bul->y += bul->ym; + + if (++bul->act_wait > 60) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION_TINY, DIR_LEFT); + } + + RECT rect[4] = { + {192, 8, 200, 16}, + {200, 8, 208, 16}, + {208, 8, 216, 16}, + {216, 8, 224, 16}, + }; + + if (++bul->ani_wait > 3) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 3) + bul->ani_no = 3; + + bul->rect = rect[bul->ani_no]; +} + +void ActBullet_Bubblin3(BULLET *bul) +{ + if (++bul->act_wait > 100 || !(gKey & gKeyShot)) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + PlaySoundObject(100, SOUND_MODE_PLAY); + + if (gMC.up) + SetBullet(22, bul->x, bul->y, DIR_UP); + else if (gMC.down) + SetBullet(22, bul->x, bul->y, DIR_DOWN); + else + SetBullet(22, bul->x, bul->y, gMC.direct); + + return; + } + + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = Random(-0x400, -0x200); + bul->ym = (Random(-4, 4) * 0x200) / 2; + break; + case DIR_RIGHT: + bul->xm = Random(0x200, 0x400); + bul->ym = (Random(-4, 4) * 0x200) / 2; + break; + case DIR_UP: + bul->ym = Random(-0x400, -0x200); + bul->xm = (Random(-4, 4) * 0x200) / 2; + break; + case DIR_DOWN: + bul->ym = Random(0x80, 0x100); + bul->xm = (Random(-4, 4) * 0x200) / 2; + break; + } + + break; + } + + if (bul->x < gMC.x) + bul->xm += 0x20; + if (bul->x > gMC.x) + bul->xm -= 0x20; + + if (bul->y < gMC.y) + bul->ym += 0x20; + if (bul->y > gMC.y) + bul->ym -= 0x20; + + if (bul->xm < 0 && bul->flag & 1) + bul->xm = 0x400; + if (bul->xm > 0 && bul->flag & 4) + bul->xm = -0x400; + + if (bul->ym < 0 && bul->flag & 2) + bul->ym = 0x400; + if (bul->ym > 0 && bul->flag & 8) + bul->ym = -0x400; + + bul->x += bul->xm; + bul->y += bul->ym; + + RECT rect[4] = { + {240, 16, 248, 24}, + {248, 16, 256, 24}, + {240, 24, 248, 32}, + {248, 24, 256, 32}, + }; + + if (++bul->ani_wait > 3) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 3) + bul->ani_no = 3; + + bul->rect = rect[bul->ani_no]; +} + +void ActBullet_Spine(BULLET *bul) +{ + if (++bul->count1 > bul->life_count || bul->flag & 8) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->act_no == 0) + { + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = (-Random(10, 16) * 0x200) / 2; + break; + case DIR_UP: + bul->ym = (-Random(10, 16) * 0x200) / 2; + break; + case DIR_RIGHT: + bul->xm = (Random(10, 16) * 0x200) / 2; + break; + case DIR_DOWN: + bul->ym = (Random(10, 16) * 0x200) / 2; + break; + } + } + else + { + bul->x += bul->xm; + bul->y += bul->ym; + } + + if (++bul->ani_wait > 1) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 1) + bul->ani_no = 0; + + RECT rcLeft[2] = { + {224, 0, 232, 8}, + {232, 0, 240, 8}, + }; + + RECT rcRight[2] = { + {224, 0, 232, 8}, + {232, 0, 240, 8}, + }; + + RECT rcDown[2] = { + {224, 8, 232, 16}, + {232, 8, 240, 16}, + }; + + switch (bul->direct) + { + case DIR_LEFT: + bul->rect = rcLeft[bul->ani_no]; + break; + case DIR_UP: + bul->rect = rcDown[bul->ani_no]; + break; + case DIR_RIGHT: + bul->rect = rcRight[bul->ani_no]; + break; + case DIR_DOWN: + bul->rect = rcDown[bul->ani_no]; + break; + } +} + +void ActBullet_Sword1(BULLET *bul) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->count1 == 3) + bul->bbits &= ~4; + + if (bul->count1 % 5 == 1) + PlaySoundObject(34, SOUND_MODE_PLAY); + + if (bul->act_no == 0) + { + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x800; + break; + case DIR_UP: + bul->ym = -0x800; + break; + case DIR_RIGHT: + bul->xm = 0x800; + break; + case DIR_DOWN: + bul->ym = 0x800; + break; + } + } + else + { + bul->x += bul->xm; + bul->y += bul->ym; + } + + RECT rcLeft[4] = { + {0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + {48, 48, 64, 64}, + }; + + RECT rcRight[4] = { + {64, 48, 80, 64}, + {80, 48, 96, 64}, + {96, 48, 112, 64}, + {112, 48, 128, 64}, + }; + + if (++bul->ani_wait > 1) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 3) + bul->ani_no = 0; + + if (bul->direct == DIR_LEFT) + bul->rect = rcLeft[bul->ani_no]; + else + bul->rect = rcRight[bul->ani_no]; +} + +void ActBullet_Sword2(BULLET *bul) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->count1 == 3) + bul->bbits &= ~4; + + if (bul->count1 % 7 == 1) + PlaySoundObject(106, SOUND_MODE_PLAY); + + if (bul->act_no == 0) + { + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x800; + break; + case DIR_UP: + bul->ym = -0x800; + break; + case DIR_RIGHT: + bul->xm = 0x800; + break; + case DIR_DOWN: + bul->ym = 0x800; + break; + } + } + else + { + bul->x += bul->xm; + bul->y += bul->ym; + } + + RECT rcLeft[4] = { + {160, 48, 184, 72}, + {184, 48, 208, 72}, + {208, 48, 232, 72}, + {232, 48, 256, 72}, + }; + + RECT rcRight[4] = { + {160, 72, 184, 96}, + {184, 72, 208, 96}, + {208, 72, 232, 96}, + {232, 72, 256, 96}, + }; + + if (++bul->ani_wait > 1) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->ani_no > 3) + bul->ani_no = 0; + + if (bul->direct == DIR_LEFT) + bul->rect = rcLeft[bul->ani_no]; + else + bul->rect = rcRight[bul->ani_no]; +} + +void ActBullet_Sword3(BULLET *bul) +{ + RECT rcLeft[2] = { + {272, 0, 296, 24}, + {296, 0, 320, 24}, + }; + + RECT rcUp[2] = { + {272, 48, 296, 72}, + {296, 0, 320, 24}, + }; + + RECT rcRight[2] = { + {272, 24, 296, 48}, + {296, 24, 320, 48}, + }; + + RECT rcDown[2] = { + {296, 48, 320, 72}, + {296, 24, 320, 48}, + }; + + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + bul->xm = 0; + bul->ym = 0; + // Fallthrough + case 1: + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x800; + break; + case DIR_UP: + bul->ym = -0x800; + break; + case DIR_RIGHT: + bul->xm = 0x800; + break; + case DIR_DOWN: + bul->ym = 0x800; + break; + } + + if (bul->life != 100) + { + bul->act_no = 2; + bul->ani_no = 1; + bul->damage = -1; + bul->act_wait = 0; + } + + if (++bul->act_wait % 4 == 1) + { + PlaySoundObject(106, SOUND_MODE_PLAY); + + if (++bul->count1 % 2) + SetBullet(23, bul->x, bul->y, DIR_LEFT); + else + SetBullet(23, bul->x, bul->y, DIR_RIGHT); + } + + if (++bul->count1 == 5) + bul->bbits &= ~4; + + if (bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + break; + + case 2: + bul->xm = 0; + bul->ym = 0; + ++bul->act_wait; + + if (Random(-1, 1) == 0) + { + PlaySoundObject(106, SOUND_MODE_PLAY); + + if (Random(0, 1) % 2) + SetBullet(23, bul->x + (Random(-0x40, 0x40) * 0x200), bul->y + (Random(-0x40, 0x40) * 0x200), DIR_LEFT); + else + SetBullet(23, bul->x + (Random(-0x40, 0x40) * 0x200), bul->y + (Random(-0x40, 0x40) * 0x200), DIR_RIGHT); + } + + if (bul->act_wait > 50) + bul->cond = 0; + } + + bul->x += bul->xm; + bul->y += bul->ym; + + switch (bul->direct) + { + case DIR_LEFT: + bul->rect = rcLeft[bul->ani_no]; + break; + case DIR_UP: + bul->rect = rcUp[bul->ani_no]; + break; + case DIR_RIGHT: + bul->rect = rcRight[bul->ani_no]; + break; + case DIR_DOWN: + bul->rect = rcDown[bul->ani_no]; + break; + } + + if (bul->act_wait % 2) + bul->rect.right = 0; +} + +void ActBullet_Edge(BULLET *bul) +{ + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + bul->y -= 12 * 0x200; + + if (bul->direct == DIR_LEFT) + bul->x += 16 * 0x200; + else + bul->x -= 16 * 0x200; + // Fallthrough + case 1: + if (++bul->ani_wait > 2) + { + bul->ani_wait = 0; + ++bul->ani_no; + } + + if (bul->direct == DIR_LEFT) + bul->x -= 2 * 0x200; + else + bul->x += 2 * 0x200; + + bul->y += 2 * 0x200; + + if (bul->ani_no == 1) + bul->damage = 2; + else + bul->damage = 1; + + if (bul->ani_no > 4) + { + bul->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcLeft' and 'rcRight', even though it's now too high + #endif + } + + break; + } + + RECT rcLeft[5] = { + {0, 64, 24, 88}, + {24, 64, 48, 88}, + {48, 64, 72, 88}, + {72, 64, 96, 88}, + {96, 64, 120, 88}, + }; + + RECT rcRight[5] = { + {0, 88, 24, 112}, + {24, 88, 48, 112}, + {48, 88, 72, 112}, + {72, 88, 96, 112}, + {96, 88, 120, 112}, + }; + + if (bul->direct == DIR_LEFT) + bul->rect = rcLeft[bul->ani_no]; + else + bul->rect = rcRight[bul->ani_no]; +} + +void ActBullet_Drop(BULLET *bul) +{ + RECT rc = {0, 0, 0, 0}; + + if (++bul->act_wait > 2) + bul->cond = 0; + + bul->rect = rc; +} + +void ActBullet_SuperMissile(BULLET *bul, int level) +{ + BOOL bHit; + + static unsigned int inc; + + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + bHit = FALSE; + + if (bul->life != 10) + bHit = TRUE; + if (bul->direct == DIR_LEFT && bul->flag & 1) + bHit = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 4) + bHit = TRUE; + if (bul->direct == DIR_UP && bul->flag & 2) + bHit = TRUE; + if (bul->direct == DIR_DOWN && bul->flag & 8) + bHit = TRUE; + if (bul->direct == DIR_LEFT && bul->flag & 0x80) + bHit = TRUE; + if (bul->direct == DIR_LEFT && bul->flag & 0x20) + bHit = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 0x40) + bHit = TRUE; + if (bul->direct == DIR_RIGHT && bul->flag & 0x10) + bHit = TRUE; + + if (bHit) + { + SetBullet(level + 30, bul->x, bul->y, DIR_LEFT); + bul->cond = 0; + } + + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + bul->tgt_y = bul->y; + bul->enemyXL = 0x1000; + bul->blockXL = 0x1000; + break; + + case DIR_UP: + case DIR_DOWN: + bul->tgt_x = bul->x; + bul->enemyYL = 0x1000; + bul->blockYL = 0x1000; + break; + } + + if (level == 3) + { + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + if (bul->y > gMC.y) + bul->ym = 0x100; + else + bul->ym = -0x100; + + bul->xm = Random(-0x200, 0x200); + break; + + case DIR_UP: + case DIR_DOWN: + if (bul->x > gMC.x) + bul->xm = 0x100; + else + bul->xm = -0x100; + + bul->ym = Random(-0x200, 0x200); + break; + } + + switch (++inc % 3) + { + case 0: + bul->ani_no = 0x200; + break; + case 1: + bul->ani_no = 0x100; + break; + case 2: + bul->ani_no = 0xAA; + break; + } + } + else + { + bul->ani_no = 0x200; + } + // Fallthrough + case 1: + switch (bul->direct) + { + case DIR_LEFT: + bul->xm += -bul->ani_no; + break; + case DIR_UP: + bul->ym += -bul->ani_no; + break; + case DIR_RIGHT: + bul->xm += bul->ani_no; + break; + case DIR_DOWN: + bul->ym += bul->ani_no; + break; + } + + if (level == 3) + { + switch (bul->direct) + { + case DIR_LEFT: + case DIR_RIGHT: + if (bul->y < bul->tgt_y) + bul->ym += 0x40; + else + bul->ym -= 0x40; + + break; + case DIR_UP: + case DIR_DOWN: + if (bul->x < bul->tgt_x) + bul->xm += 0x40; + else + bul->xm -= 0x40; + + break; + } + } + + if (bul->xm < -0x1400) + bul->xm = -0x1400; + if (bul->xm > 0x1400) + bul->xm = 0x1400; + + if (bul->ym < -0x1400) + bul->ym = -0x1400; + if (bul->ym > 0x1400) + bul->ym = 0x1400; + + bul->x += bul->xm; + bul->y += bul->ym; + + break; + } + + if (++bul->count2 > 2) + { + bul->count2 = 0; + + switch (bul->direct) + { + case DIR_LEFT: + SetCaret(bul->x + (8 * 0x200), bul->y, CARET_EXHAUST, DIR_RIGHT); + break; + case DIR_UP: + SetCaret(bul->x, bul->y + (8 * 0x200), CARET_EXHAUST, DIR_DOWN); + break; + case DIR_RIGHT: + SetCaret(bul->x - (8 * 0x200), bul->y, CARET_EXHAUST, DIR_LEFT); + break; + case DIR_DOWN: + SetCaret(bul->x, bul->y - (8 * 0x200), CARET_EXHAUST, DIR_UP); + break; + } + } + + RECT rect1[4] = { + {120, 96, 136, 112}, + {136, 96, 152, 112}, + {152, 96, 168, 112}, + {168, 96, 184, 112}, + }; + + RECT rect2[4] = { + {184, 96, 200, 112}, + {200, 96, 216, 112}, + {216, 96, 232, 112}, + {232, 96, 248, 112}, + }; + + switch (level) + { + case 1: + bul->rect = rect1[bul->direct]; + break; + case 2: + bul->rect = rect2[bul->direct]; + break; + case 3: + bul->rect = rect1[bul->direct]; + break; + } +} + +void ActBullet_SuperBom(BULLET *bul, int level) +{ + switch (bul->act_no) + { + case 0: + bul->act_no = 1; + + switch (level) + { + case 1: + bul->act_wait = 10; + break; + case 2: + bul->act_wait = 14; + break; + case 3: + bul->act_wait = 6; + break; + } + + PlaySoundObject(44, SOUND_MODE_PLAY); + // Fallthrough + case 1: + switch (level) + { + case 1: + if (bul->act_wait % 3 == 0) + SetDestroyNpCharUp(bul->x + (Random(-16, 16) * 0x200), bul->y + (Random(-16, 16) * 0x200), bul->enemyXL, 2); + break; + case 2: + if (bul->act_wait % 3 == 0) + SetDestroyNpCharUp(bul->x + (Random(-32, 32) * 0x200), bul->y + (Random(-32, 32) * 0x200), bul->enemyXL, 2); + break; + case 3: + if (bul->act_wait % 3 == 0) + SetDestroyNpCharUp(bul->x + (Random(-40, 40) * 0x200), bul->y + (Random(-40, 40) * 0x200), bul->enemyXL, 2); + break; + } + + if (--bul->act_wait < 0) + bul->cond = 0; + + break; + } +} + +void ActBullet_Nemesis(BULLET *bul, int level) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->act_no == 0) + { + bul->act_no = 1; + bul->count1 = 0; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x1000; + break; + case DIR_UP: + bul->ym = -0x1000; + break; + case DIR_RIGHT: + bul->xm = 0x1000; + break; + case DIR_DOWN: + bul->ym = 0x1000; + break; + } + + switch (level) + { + case 3: + bul->xm /= 3; + bul->ym /= 3; + break; + } + } + else + { + if (level == 1 && bul->count1 % 4 == 1) + { + switch (bul->direct) + { + case DIR_LEFT: + SetNpChar(4, bul->x, bul->y, -0x200, Random(-0x200, 0x200), DIR_RIGHT, NULL, 0x100); + break; + case DIR_UP: + SetNpChar(4, bul->x, bul->y, Random(-0x200, 0x200), -0x200, DIR_RIGHT, NULL, 0x100); + break; + case DIR_RIGHT: + SetNpChar(4, bul->x, bul->y, 0x200, Random(-0x200, 0x200), DIR_RIGHT, NULL, 0x100); + break; + case DIR_DOWN: + SetNpChar(4, bul->x, bul->y, Random(-0x200, 0x200), 0x200, DIR_RIGHT, NULL, 0x100); + break; + } + } + + bul->x += bul->xm; + bul->y += bul->ym; + } + + if (++bul->ani_no > 1) + bul->ani_no = 0; + + RECT rcL[2] = { + {0, 112, 32, 128}, + {0, 128, 32, 144}, + }; + + RECT rcU[2] = { + {32, 112, 48, 144}, + {48, 112, 64, 144}, + }; + + RECT rcR[2] = { + {64, 112, 96, 128}, + {64, 128, 96, 144}, + }; + + RECT rcD[2] = { + {96, 112, 112, 144}, + {112, 112, 128, 144}, + }; + + switch (bul->direct) + { + case DIR_LEFT: + bul->rect = rcL[bul->ani_no]; + break; + case DIR_UP: + bul->rect = rcU[bul->ani_no]; + break; + case DIR_RIGHT: + bul->rect = rcR[bul->ani_no]; + break; + case DIR_DOWN: + bul->rect = rcD[bul->ani_no]; + break; + } + + bul->rect.top += ((level - 1) / 2) * 32; + bul->rect.bottom += ((level - 1) / 2) * 32; + bul->rect.left += ((level - 1) % 2) * 128; + bul->rect.right += ((level - 1) % 2) * 128; +} + +void ActBullet_Spur(BULLET *bul, int level) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + SetCaret(bul->x, bul->y, CARET_SHOOT, DIR_LEFT); + return; + } + + if (bul->damage && bul->life != 100) + bul->damage = 0; + + if (bul->act_no == 0) + { + bul->act_no = 1; + + switch (bul->direct) + { + case DIR_LEFT: + bul->xm = -0x1000; + break; + case DIR_UP: + bul->ym = -0x1000; + break; + case DIR_RIGHT: + bul->xm = 0x1000; + break; + case DIR_DOWN: + bul->ym = 0x1000; + break; + } + + switch (level) + { + case 1: + switch (bul->direct) + { + case DIR_LEFT: + bul->enemyYL = 0x400; + break; + case DIR_UP: + bul->enemyXL = 0x400; + break; + case DIR_RIGHT: + bul->enemyYL = 0x400; + break; + case DIR_DOWN: + bul->enemyXL = 0x400; + break; + } + + break; + + case 2: + switch (bul->direct) + { + case DIR_LEFT: + bul->enemyYL = 0x800; + break; + case DIR_UP: + bul->enemyXL = 0x800; + break; + case DIR_RIGHT: + bul->enemyYL = 0x800; + break; + case DIR_DOWN: + bul->enemyXL = 0x800; + break; + } + + break; + } + } + else + { + bul->x += bul->xm; + bul->y += bul->ym; + } + + RECT rect1[2] = { + {128, 32, 144, 48}, + {144, 32, 160, 48}, + }; + + RECT rect2[2] = { + {160, 32, 176, 48}, + {176, 32, 192, 48}, + }; + + RECT rect3[2] = { + {128, 48, 144, 64}, + {144, 48, 160, 64}, + }; + + bul->damage = bul->life; + + switch (level) + { + case 1: + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + bul->rect = rect1[1]; + else + bul->rect = rect1[0]; + + break; + + case 2: + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + bul->rect = rect2[1]; + else + bul->rect = rect2[0]; + + break; + + case 3: + if (bul->direct == DIR_UP || bul->direct == DIR_DOWN) + bul->rect = rect3[1]; + else + bul->rect = rect3[0]; + + break; + } + + SetBullet(39 + level, bul->x, bul->y, bul->direct); +} + +void ActBullet_SpurTail(BULLET *bul, int level) +{ + if (++bul->count1 > 20) + bul->ani_no = bul->count1 - 20; + + if (bul->ani_no > 2) + { + bul->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // Avoid accessing the RECT arrays with an out-of-bounds index + #endif + } + + if (bul->damage && bul->life != 100) + bul->damage = 0; + + RECT rc_h_lv1[3] = { + {192, 32, 200, 40}, + {200, 32, 208, 40}, + {208, 32, 216, 40}, + }; + + RECT rc_v_lv1[3] = { + {192, 40, 200, 48}, + {200, 40, 208, 48}, + {208, 40, 216, 48}, + }; + + RECT rc_h_lv2[3] = { + {216, 32, 224, 40}, + {224, 32, 232, 40}, + {232, 32, 240, 40}, + }; + + RECT rc_v_lv2[3] = { + {216, 40, 224, 48}, + {224, 40, 232, 48}, + {232, 40, 240, 48}, + }; + + RECT rc_h_lv3[3] = { + {240, 32, 248, 40}, + {248, 32, 256, 40}, + {256, 32, 264, 40}, + }; + + RECT rc_v_lv3[3] = { + {240, 32, 248, 40}, + {248, 32, 256, 40}, + {256, 32, 264, 40}, + }; + + switch (level) + { + case 1: + if (bul->direct == DIR_LEFT || bul->direct == DIR_RIGHT) + bul->rect = rc_h_lv1[bul->ani_no]; + else + bul->rect = rc_v_lv1[bul->ani_no]; + + break; + + case 2: + if (bul->direct == DIR_LEFT || bul->direct == DIR_RIGHT) + bul->rect = rc_h_lv2[bul->ani_no]; + else + bul->rect = rc_v_lv2[bul->ani_no]; + + break; + + case 3: + if (bul->direct == DIR_LEFT || bul->direct == DIR_RIGHT) + bul->rect = rc_h_lv3[bul->ani_no]; + else + bul->rect = rc_v_lv3[bul->ani_no]; + + break; + } +} + +void ActBullet_EnemyClear(BULLET *bul) +{ + if (++bul->count1 > bul->life_count) + { + bul->cond = 0; + return; + } + + bul->damage = 10000; + bul->enemyXL = 0xC8000; + bul->enemyYL = 0xC8000; +} + +void ActBullet_Star(BULLET *bul) +{ + if (++bul->count1 > bul->life_count) + bul->cond = 0; +} + +void ActBullet(void) +{ + int i; + + for (i = 0; i < BULLET_MAX; ++i) + { + if (gBul[i].cond & 0x80) + { + if (gBul[i].life < 1) + { + gBul[i].cond = 0; + continue; + } + + switch (gBul[i].code_bullet) + { + // Snake + case 1: + ActBullet_Frontia1(&gBul[i]); + break; + case 2: + ActBullet_Frontia2(&gBul[i], 2); + break; + case 3: + ActBullet_Frontia2(&gBul[i], 3); + break; + + // Polar Star + case 4: + ActBullet_PoleStar(&gBul[i], 1); + break; + case 5: + ActBullet_PoleStar(&gBul[i], 2); + break; + case 6: + ActBullet_PoleStar(&gBul[i], 3); + break; + + // Fireball + case 7: + ActBullet_FireBall(&gBul[i], 1); + break; + case 8: + ActBullet_FireBall(&gBul[i], 2); + break; + case 9: + ActBullet_FireBall(&gBul[i], 3); + break; + + // Machine Gun + case 10: + ActBullet_MachineGun(&gBul[i], 1); + break; + case 11: + ActBullet_MachineGun(&gBul[i], 2); + break; + case 12: + ActBullet_MachineGun(&gBul[i], 3); + break; + + // Missile Launcher + case 13: + ActBullet_Missile(&gBul[i], 1); + break; + case 14: + ActBullet_Missile(&gBul[i], 2); + break; + case 15: + ActBullet_Missile(&gBul[i], 3); + break; + + // Missile Launcher explosion + case 16: + ActBullet_Bom(&gBul[i], 1); + break; + case 17: + ActBullet_Bom(&gBul[i], 2); + break; + case 18: + ActBullet_Bom(&gBul[i], 3); + break; + + // Bubbler + case 19: + ActBullet_Bubblin1(&gBul[i]); + break; + case 20: + ActBullet_Bubblin2(&gBul[i]); + break; + case 21: + ActBullet_Bubblin3(&gBul[i]); + break; + + // Bubbler level 3 spines + case 22: + ActBullet_Spine(&gBul[i]); + break; + + // Blade slashes + case 23: + ActBullet_Edge(&gBul[i]); + break; + + // Falling spike that deals 127 damage + case 24: + ActBullet_Drop(&gBul[i]); + break; + + // Blade + case 25: + ActBullet_Sword1(&gBul[i]); + break; + case 26: + ActBullet_Sword2(&gBul[i]); + break; + case 27: + ActBullet_Sword3(&gBul[i]); + break; + + // Super Missile Launcher + case 28: + ActBullet_SuperMissile(&gBul[i], 1); + break; + case 29: + ActBullet_SuperMissile(&gBul[i], 2); + break; + case 30: + ActBullet_SuperMissile(&gBul[i], 3); + break; + + // Super Missile Launcher explosion + case 31: + ActBullet_SuperBom(&gBul[i], 1); + break; + case 32: + ActBullet_SuperBom(&gBul[i], 2); + break; + case 33: + ActBullet_SuperBom(&gBul[i], 3); + break; + + // Nemesis + case 34: // Identical to case 43 + ActBullet_Nemesis(&gBul[i], 1); + break; + case 35: + ActBullet_Nemesis(&gBul[i], 2); + break; + case 36: + ActBullet_Nemesis(&gBul[i], 3); + break; + + // Spur + case 37: + ActBullet_Spur(&gBul[i], 1); + break; + case 38: + ActBullet_Spur(&gBul[i], 2); + break; + case 39: + ActBullet_Spur(&gBul[i], 3); + break; + + // Spur trail + case 40: + ActBullet_SpurTail(&gBul[i], 1); + break; + case 41: + ActBullet_SpurTail(&gBul[i], 2); + break; + case 42: + ActBullet_SpurTail(&gBul[i], 3); + break; + + // Curly's Nemesis + case 43: // Identical to case 34 + ActBullet_Nemesis(&gBul[i], 1); + break; + + // Screen-nuke that kills all enemies + case 44: + ActBullet_EnemyClear(&gBul[i]); + break; + + // Whimsical Star + case 45: + ActBullet_Star(&gBul[i]); + break; + } + } + } +} + +BOOL IsActiveSomeBullet(void) +{ + int i; + + for (i = 0; i < BULLET_MAX; ++i) + { + if (gBul[i].cond & 0x80) + { + switch (gBul[i].code_bullet) + { + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 23: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + return TRUE; + } + } + } + + return FALSE; +} diff --git a/src/Bullet.h b/src/Bullet.h new file mode 100644 index 0000000..9f6151e --- /dev/null +++ b/src/Bullet.h @@ -0,0 +1,69 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" + +#define BULLET_MAX 0x40 + +typedef struct BULLET +{ + int flag; + int code_bullet; + int bbits; + int cond; + int x; + int y; + int xm; + int ym; + int tgt_x; + int tgt_y; + int act_no; + int act_wait; + int ani_wait; + int ani_no; + unsigned char direct; + RECT rect; + int count1; + int count2; + int life_count; + int damage; + int life; + int enemyXL; + int enemyYL; + int blockXL; + int blockYL; + OTHER_RECT view; +} BULLET; + +typedef struct BULLET_TABLE +{ + signed char damage; + signed char life; + int life_count; + int bbits; + int enemyXL; + int enemyYL; + int blockXL; + int blockYL; + OTHER_RECT view; +} BULLET_TABLE; + +extern BULLET gBul[BULLET_MAX]; + +void InitBullet(void); +int CountArmsBullet(int arms_code); +int CountBulletNum(int bullet_code); +void DeleteBullet(int code); +void ClearBullet(void); +void PutBullet(int fx, int fy); +void SetBullet(int no, int x, int y, int dir); +void ActBullet(void); +BOOL IsActiveSomeBullet(void); diff --git a/src/Caret.cpp b/src/Caret.cpp new file mode 100644 index 0000000..43a6846 --- /dev/null +++ b/src/Caret.cpp @@ -0,0 +1,684 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Caret.h" + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Game.h" +#include "Triangle.h" + +#define CARET_MAX 0x40 + +struct CARET +{ + int cond; + int code; + int direct; + int x; + int y; + int xm; + int ym; + int act_no; + int act_wait; + int ani_no; + int ani_wait; + int view_left; + int view_top; + RECT rect; +}; + +struct CARET_TABLE +{ + int view_left; + int view_top; +}; + +CARET gCrt[CARET_MAX]; + +// Sprite offsets +CARET_TABLE gCaretTable[] = { + {0, 0}, // CARET_NULL + { 4 * 0x200, 4 * 0x200}, // CARET_BUBBLE + { 8 * 0x200, 8 * 0x200}, // CARET_PROJECTILE_DISSIPATION + { 8 * 0x200, 8 * 0x200}, // CARET_SHOOT + { 8 * 0x200, 8 * 0x200}, // CARET_SNAKE_AFTERIMAGE + { 4 * 0x200, 4 * 0x200}, // CARET_ZZZ + { 8 * 0x200, 8 * 0x200}, // CARET_SNAKE_AFTERIMAGE_DUPLICATE + { 4 * 0x200, 4 * 0x200}, // CARET_EXHAUST + { 8 * 0x200, 8 * 0x200}, // CARET_DROWNED_QUOTE + { 8 * 0x200, 8 * 0x200}, // CARET_QUESTION_MARK + {28 * 0x200, 8 * 0x200}, // CARET_LEVEL_UP + { 4 * 0x200, 4 * 0x200}, // CARET_HURT_PARTICLES + {16 * 0x200, 16 * 0x200}, // CARET_EXPLOSION + { 4 * 0x200, 4 * 0x200}, // CARET_TINY_PARTICLES + {20 * 0x200, 20 * 0x200}, // CARET_UNKNOWN + { 4 * 0x200, 4 * 0x200}, // CARET_PROJECTILE_DISSIPATION_TINY + {20 * 0x200, 4 * 0x200}, // CARET_EMPTY + {52 * 0x200, 4 * 0x200} // CARET_PUSH_JUMP_KEY +}; + +void InitCaret(void) +{ + memset(gCrt, 0, sizeof(gCrt)); +} + +// Null +void ActCaret00(CARET *crt) +{ + (void)crt; +} + +// Bubble +void ActCaret01(CARET *crt) +{ + RECT rcLeft[4] = { + { 0, 64, 8, 72}, + { 8, 64, 16, 72}, + {16, 64, 24, 72}, + {24, 64, 32, 72}, + }; + + RECT rcRight[4] = { + {64, 24, 72, 32}, + {72, 24, 80, 32}, + {80, 24, 88, 32}, + {88, 24, 96, 32}, + }; + + if (crt->act_no == 0) + { + crt->act_no = 1; + crt->xm = Random(-0x400, 0x400); + crt->ym = Random(-0x400, 0); + } + + crt->ym += 0x40; + crt->x += crt->xm; + crt->y += crt->ym; + + if (++crt->ani_wait > 5) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 3) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcLeft' and 'rcRight', even though it's now too high + #endif + } + } + + if (crt->direct == DIR_LEFT) + crt->rect = rcLeft[crt->ani_no]; + else + crt->rect = rcRight[crt->ani_no]; +} + +// Projectile dissipation +void ActCaret02(CARET *crt) +{ + RECT rect_left[4] = { + { 0, 32, 16, 48}, + {16, 32, 32, 48}, + {32, 32, 48, 48}, + {48, 32, 64, 48}, + }; + + RECT rect_right[4] = { + {176, 0, 192, 16}, + {192, 0, 208, 16}, + {208, 0, 224, 16}, + {224, 0, 240, 16}, + }; + + RECT rect_up[3] = { + { 0, 32, 16, 48}, + {32, 32, 48, 48}, + {16, 32, 32, 48}, + }; + + switch (crt->direct) + { + case DIR_LEFT: + crt->ym -= 0x10; + crt->y += crt->ym; + + if (++crt->ani_wait > 5) + { + crt->ani_wait = 0; + ++crt->ani_no; + } + + if (crt->ani_no > 3) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect_left', even though it's now too high + #endif + } + + crt->rect = rect_left[crt->ani_no]; + break; + + case DIR_RIGHT: + if (++crt->ani_wait > 2) + { + crt->ani_wait = 0; + ++crt->ani_no; + } + + if (crt->ani_no > 3) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect_right', even though it's now too high + #endif + } + + crt->rect = rect_right[crt->ani_no]; + break; + + case DIR_UP: + crt->rect = rect_up[++crt->ani_wait / 2 % 3]; + + if (crt->ani_wait > 24) + crt->cond = 0; + + break; + } +} + +// Shoot +void ActCaret03(CARET *crt) +{ + RECT rect[4] = { + { 0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + {48, 48, 64, 64}, + }; + + if (++crt->ani_wait > 2) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 3) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + } + + crt->rect = rect[crt->ani_no]; +} + +// Snake after-image? This doesn't seem to be used. +void ActCaret04(CARET *crt) +{ + RECT rect[9] = { + // Left + {64, 32, 80, 48}, + {80, 32, 96, 48}, + {96, 32, 112, 48}, + // Up + {64, 48, 80, 64}, + {80, 48, 96, 64}, + {96, 48, 112, 64}, + // Right + {64, 64, 80, 80}, + {80, 64, 96, 80}, + {96, 64, 112, 80}, + }; + + if (++crt->ani_wait > 1) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 2) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + } + + crt->rect = rect[(crt->direct * 3) + crt->ani_no]; +} + +// 'Zzz' - snoring +void ActCaret05(CARET *crt) +{ + RECT rect[7] = { + {32, 64, 40, 72}, + {32, 72, 40, 80}, + {40, 64, 48, 72}, + {40, 72, 48, 80}, + {40, 64, 48, 72}, + {40, 72, 48, 80}, + {40, 64, 48, 72}, + }; + + if (++crt->ani_wait > 4) + { + crt->ani_wait = 0; + ++crt->ani_no; + } + + if (crt->ani_no > 6) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + + crt->x += 0x80; + crt->y -= 0x80; + + crt->rect = rect[crt->ani_no]; +} + +// No ActCaret06... + +// Exhaust (used by the Booster and hoverbike) +void ActCaret07(CARET *crt) +{ + RECT rcLeft[7] = { + { 56, 0, 64, 8}, + { 64, 0, 72, 8}, + { 72, 0, 80, 8}, + { 80, 0, 88, 8}, + { 88, 0, 96, 8}, + { 96, 0, 104, 8}, + {104, 0, 112, 8}, + }; + + if (++crt->ani_wait > 1) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 6) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcLeft', even though it's now too high + #endif + } + } + + crt->rect = rcLeft[crt->ani_no]; + + switch (crt->direct) + { + case DIR_LEFT: + crt->x -= 2 * 0x200; + break; + case DIR_UP: + crt->y -= 2 * 0x200; + break; + case DIR_RIGHT: + crt->x += 2 * 0x200; + break; + case DIR_DOWN: + crt->y += 2 * 0x200; + break; + } +} + +// Drowned Quote +void ActCaret08(CARET *crt) +{ + RECT rcLeft = {16, 80, 32, 96}; + RECT rcRight = {32, 80, 48, 96}; + + if (crt->direct == DIR_LEFT) + crt->rect = rcLeft; + else + crt->rect = rcRight; +} + +// The '?' that appears when you press the down key +void ActCaret09(CARET *crt) +{ + RECT rcLeft = {0, 80, 16, 96}; + RECT rcRight = {48, 64, 64, 80}; + + if (++crt->ani_wait < 5) + crt->y -= 0x800; + + if (crt->ani_wait == 32) + crt->cond = 0; + + if (crt->direct == DIR_LEFT) + crt->rect = rcLeft; + else + crt->rect = rcRight; +} + +// 'Level Up!' +void ActCaret10(CARET *crt) +{ + RECT rcLeft[2] = { + {0, 0, 56, 16}, + {0, 16, 56, 32}, + }; + + RECT rcRight[2] = { + {0, 96, 56, 112}, + {0, 112, 56, 128}, + }; + + ++crt->ani_wait; + + if (crt->direct == DIR_LEFT) + { + if (crt->ani_wait < 20) + crt->y -= 2 * 0x200; + + if (crt->ani_wait == 80) + crt->cond = 0; + } + else + { + if (crt->ani_wait < 20) + crt->y -= 1 * 0x200; + + if (crt->ani_wait == 80) + crt->cond = 0; + } + + if (crt->direct == DIR_LEFT) + crt->rect = rcLeft[crt->ani_wait / 2 % 2]; + else + crt->rect = rcRight[crt->ani_wait / 2 % 2]; +} + +// Red hurt particles (used by bosses and invisible hidden pickups) +void ActCaret11(CARET *crt) +{ + unsigned char deg; + + if (crt->act_no == 0) + { + crt->act_no = 1; + deg = Random(0, 0xFF); + crt->xm = GetCos(deg) * 2; + crt->ym = GetSin(deg) * 2; + } + + crt->x += crt->xm; + crt->y += crt->ym; + + RECT rcRight[7] = { + { 56, 8, 64, 16}, + { 64, 8, 72, 16}, + { 72, 8, 80, 16}, + { 80, 8, 88, 16}, + { 88, 8, 96, 16}, + { 96, 8, 104, 16}, + {104, 8, 112, 16}, + }; + + if (++crt->ani_wait > 2) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 6) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcRight', even though it's now too high + #endif + } + } + + crt->rect = rcRight[crt->ani_no]; +} + +// Missile Launcher explosion flash +void ActCaret12(CARET *crt) +{ + RECT rcLeft[2] = { + {112, 0, 144, 32}, + {144, 0, 176, 32}, + }; + + if (++crt->ani_wait > 2) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 1) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcLeft', even though it's now too high + #endif + } + } + + crt->rect = rcLeft[crt->ani_no]; +} + +// Particles used when Quote jumps into the ceiling, and also used by the Demon Crown and Ballos's puppy +void ActCaret13(CARET *crt) +{ + RECT rcLeft[2] = { + {56, 24, 64, 32}, + {0, 0, 0, 0}, + }; + + if (crt->act_no == 0) + { + crt->act_no = 1; + + switch (crt->direct) + { + case DIR_LEFT: + crt->xm = Random(-0x600, 0x600); + crt->ym = Random(-0x200, 0x200); + break; + + case DIR_UP: + crt->ym = -0x200 * Random(1, 3); + break; + } + } + + switch (crt->direct) + { + case DIR_LEFT: + crt->xm = (crt->xm * 4) / 5; + crt->ym = (crt->ym * 4) / 5; + break; + } + + crt->x += crt->xm; + crt->y += crt->ym; + + if (++crt->ani_wait > 20) + crt->cond = 0; + + crt->rect = rcLeft[crt->ani_wait / 2 % 2]; + + if (crt->direct == DIR_OTHER) + crt->x -= 4 * 0x200; +} + +// Broken (unknown and unused) +void ActCaret14(CARET *crt) +{ + // These rects are invalid. + // However, notably, there are 5 unused 40x40 sprites at the bottom of Caret.pbm. + // Perhaps those were originally at these coordinates. + RECT rect[5] = { + {0, 96, 40, 136}, + {40, 96, 80, 136}, + {80, 96, 120, 136}, + {120, 96, 160, 136}, + {160, 96, 200, 136}, + }; + + if (++crt->ani_wait > 1) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 4) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + } + + crt->rect = rect[crt->ani_no]; +} + +// Tiny version of the projectile dissipation effect +void ActCaret15(CARET *crt) +{ + RECT rcLeft[4] = { + { 0, 72, 8, 80}, + { 8, 72, 16, 80}, + {16, 72, 24, 80}, + {24, 72, 32, 80}, + }; + + if (++crt->ani_wait > 2) + { + crt->ani_wait = 0; + + if (++crt->ani_no > 3) + { + crt->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcLeft', even though it's now too high + #endif + } + } + + crt->rect = rcLeft[crt->ani_no]; +} + +// 'Empty!' +void ActCaret16(CARET *crt) +{ + RECT rcLeft[2] = { + {104, 96, 144, 104}, + {104, 104, 144, 112}, + }; + + if (++crt->ani_wait < 10) + crt->y -= 2 * 0x200; + + if (crt->ani_wait == 40) + crt->cond = 0; + + crt->rect = rcLeft[crt->ani_wait / 2 % 2]; +} + +// 'PUSH JUMP KEY!' (unused) +void ActCaret17(CARET *crt) +{ + RECT rcLeft[2] = { + {0, 144, 144, 152}, + {0, 0, 0, 0}, + }; + + if (++crt->ani_wait >= 40) + crt->ani_wait = 0; + + if (crt->ani_wait < 30) + crt->rect = rcLeft[0]; + else + crt->rect = rcLeft[1]; +} + +typedef void (*CARETFUNCTION)(CARET*); +CARETFUNCTION gpCaretFuncTbl[] = +{ + ActCaret00, + ActCaret01, + ActCaret02, + ActCaret03, + ActCaret04, + ActCaret05, + ActCaret04, // Interestingly, this slot is a duplicate + ActCaret07, + ActCaret08, + ActCaret09, + ActCaret10, + ActCaret11, + ActCaret12, + ActCaret13, + ActCaret14, + ActCaret15, + ActCaret16, + ActCaret17 +}; + +void ActCaret(void) +{ + int i; + int code; + + for (i = 0; i < CARET_MAX; ++i) + { + if (gCrt[i].cond & 0x80) + { + code = gCrt[i].code; + gpCaretFuncTbl[code](&gCrt[i]); + } + } +} + +void PutCaret(int fx, int fy) +{ + int i; + + for (i = 0; i < CARET_MAX; ++i) + { + if (gCrt[i].cond & 0x80) + { + PutBitmap3( + &grcGame, + ((gCrt[i].x - gCrt[i].view_left) / 0x200) - (fx / 0x200), + ((gCrt[i].y - gCrt[i].view_top) / 0x200) - (fy / 0x200), + &gCrt[i].rect, + SURFACE_ID_CARET); + } + } +} + +void SetCaret(int x, int y, int code, int dir) +{ + int c; + for (c = 0; c < CARET_MAX; ++c) + if (gCrt[c].cond == 0) + break; + + if (c == CARET_MAX) + return; + + memset(&gCrt[c], 0, sizeof(CARET)); + gCrt[c].cond = 0x80; + gCrt[c].code = code; + gCrt[c].x = x; + gCrt[c].y = y; + gCrt[c].view_left = gCaretTable[code].view_left; + gCrt[c].view_top = gCaretTable[code].view_top; + gCrt[c].direct = dir; +} diff --git a/src/Caret.h b/src/Caret.h new file mode 100644 index 0000000..ec85242 --- /dev/null +++ b/src/Caret.h @@ -0,0 +1,37 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +enum +{ + CARET_NULL = 0, + CARET_BUBBLE = 1, + CARET_PROJECTILE_DISSIPATION = 2, + CARET_SHOOT = 3, + CARET_SNAKE_AFTERIMAGE = 4, + CARET_ZZZ = 5, + CARET_SNAKE_AFTERIMAGE_DUPLICATE = 6, + CARET_EXHAUST = 7, + CARET_DROWNED_QUOTE = 8, + CARET_QUESTION_MARK = 9, + CARET_LEVEL_UP = 10, + CARET_HURT_PARTICLES = 11, + CARET_EXPLOSION = 12, + CARET_TINY_PARTICLES = 13, + CARET_UNKNOWN = 14, + CARET_PROJECTILE_DISSIPATION_TINY = 15, + CARET_EMPTY = 16, + CARET_PUSH_JUMP_KEY = 17 +}; + +void InitCaret(void); +void ActCaret(void); +void PutCaret(int fx, int fy); +void SetCaret(int x, int y, int code, int dir); diff --git a/src/CommonDefines.h b/src/CommonDefines.h new file mode 100644 index 0000000..0459ac9 --- /dev/null +++ b/src/CommonDefines.h @@ -0,0 +1,38 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#define WINDOW_WIDTH 320 +#define WINDOW_HEIGHT 240 + +enum Collisions +{ + COLL_LEFT_WALL = 1, // Touching a left wall + COLL_CEILING = 2, // Touching a ceiling + COLL_RIGHT_WALL = 4, // Touching a right wall + COLL_GROUND = 8 // Touching the ground + // To be continued +}; + +enum Direction +{ + DIR_LEFT = 0, + DIR_UP = 1, + DIR_RIGHT = 2, + DIR_DOWN = 3, + DIR_AUTO = 4, + DIR_OTHER = 5 +}; + +struct OTHER_RECT // The original name for this struct is unknown +{ + int front; + int top; + int back; + int bottom; +}; diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..e02ebc6 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,68 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "Config.h" +#include "Main.h" + +const char* const gConfigName = "Config.dat"; +const char* const gProof = "DOUKUTSU20041206"; + +BOOL LoadConfigData(CONFIGDATA *conf) +{ + // Clear old configuration data + memset(conf, 0, sizeof(CONFIGDATA)); + + // Get path + char path[MAX_PATH]; + sprintf(path, "%s\\%s", gModulePath, gConfigName); + + // Open file + FILE *fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Read data + size_t fread_result = fread(conf, sizeof(CONFIGDATA), 1, fp); // Not the original name + + // Close file + fclose(fp); + + // Check if version is not correct, and return if it failed + if (fread_result != 1 || strcmp(conf->proof, gProof)) + { + memset(conf, 0, sizeof(CONFIGDATA)); + return FALSE; + } + + return TRUE; +} + +void DefaultConfigData(CONFIGDATA *conf) +{ + // Clear old configuration data + memset(conf, 0, sizeof(CONFIGDATA)); + + // Fun fact: The Linux port added this line: + // conf->display_mode = 1; + + // Reset joystick settings (as these can't simply be set to 0) + conf->bJoystick = TRUE; + conf->joystick_button[0] = 2; + conf->joystick_button[1] = 1; + conf->joystick_button[2] = 5; + conf->joystick_button[3] = 6; + conf->joystick_button[4] = 3; + conf->joystick_button[5] = 4; + conf->joystick_button[6] = 6; + conf->joystick_button[7] = 3; +} diff --git a/src/Config.h b/src/Config.h new file mode 100644 index 0000000..ccbdf25 --- /dev/null +++ b/src/Config.h @@ -0,0 +1,28 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +struct CONFIGDATA +{ + char proof[0x20]; + char font_name[0x40]; + long move_button_mode; + long attack_button_mode; + long ok_button_mode; + long display_mode; + BOOL bJoystick; + long joystick_button[8]; +}; + +extern const char* const gConfigName; +extern const char* const gProof; + +BOOL LoadConfigData(CONFIGDATA *conf); +void DefaultConfigData(CONFIGDATA *conf); diff --git a/src/Dialog.cpp b/src/Dialog.cpp new file mode 100644 index 0000000..8cc1dbe --- /dev/null +++ b/src/Dialog.cpp @@ -0,0 +1,170 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Dialog.h" + +#include + +#include "WindowsWrapper.h" + +#include "Generic.h" +#include "Organya.h" +#include "Profile.h" + +// All of the original names for the functions/variables in this file are unknown + +const char* const gVersionString = + "version.%d.%d.%d.%d\r\n" + "2004/12/20 - %04d/%02d/%02d\r\n" + "Studio Pixel" + ; + +// TODO - Inaccurate stack frame +DLGPROC_RET CALLBACK VersionDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + char string_buffer[104]; + + int year; + int month; + int day; + + int version1; + int version2; + int version3; + int version4; + + (void)lParam; + + switch (Msg) + { + case WM_INITDIALOG: + GetCompileDate(&year, &month, &day); + GetCompileVersion(&version1, &version2, &version3, &version4); + sprintf(string_buffer, gVersionString, version1, version2, version3, version4, year, month, day); + SetDlgItemTextA(hWnd, 1011, string_buffer); + + CenteringWindowByParent(hWnd); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case 1: + EndDialog(hWnd, 1); + break; + } + + break; + } + + return FALSE; +} + +DLGPROC_RET CALLBACK DebugMuteDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + (void)lParam; + + switch (Msg) + { + case WM_INITDIALOG: + CenteringWindowByParent(hWnd); + CheckDlgButton(hWnd, 1010, g_mute[0] != 0); + CheckDlgButton(hWnd, 1018, g_mute[1] != 0); + CheckDlgButton(hWnd, 1019, g_mute[2] != 0); + CheckDlgButton(hWnd, 1020, g_mute[3] != 0); + CheckDlgButton(hWnd, 1021, g_mute[4] != 0); + CheckDlgButton(hWnd, 1022, g_mute[5] != 0); + CheckDlgButton(hWnd, 1023, g_mute[6] != 0); + CheckDlgButton(hWnd, 1024, g_mute[7] != 0); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case 2: + EndDialog(hWnd, 0); + break; + + case 1: + g_mute[0] = IsDlgButtonChecked(hWnd, 1010); + g_mute[1] = IsDlgButtonChecked(hWnd, 1018); + g_mute[2] = IsDlgButtonChecked(hWnd, 1019); + g_mute[3] = IsDlgButtonChecked(hWnd, 1020); + g_mute[4] = IsDlgButtonChecked(hWnd, 1021); + g_mute[5] = IsDlgButtonChecked(hWnd, 1022); + g_mute[6] = IsDlgButtonChecked(hWnd, 1023); + g_mute[7] = IsDlgButtonChecked(hWnd, 1024); + EndDialog(hWnd, 1); + break; + } + + break; + } + + return FALSE; +} + +DLGPROC_RET CALLBACK DebugSaveDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + char string[100]; + + (void)lParam; + + switch (Msg) + { + case WM_INITDIALOG: + SetDlgItemTextA(hWnd, 1008, "000.dat"); + CenteringWindowByParent(hWnd); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case 2: + EndDialog(hWnd, 0); + break; + + case 1: + GetDlgItemTextA(hWnd, 1008, string, sizeof(string)); + SaveProfile(string); + EndDialog(hWnd, 1); + break; + } + + break; + } + + return FALSE; +} + +DLGPROC_RET CALLBACK QuitDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + switch (Msg) + { + case WM_INITDIALOG: + SetDlgItemTextA(hWnd, 1009, (LPCSTR)lParam); + CenteringWindowByParent(hWnd); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case 2: + EndDialog(hWnd, 2); + break; + + case 1: + EndDialog(hWnd, 1); + break; + } + + break; + } + + return FALSE; +} diff --git a/src/Dialog.h b/src/Dialog.h new file mode 100644 index 0000000..74553e0 --- /dev/null +++ b/src/Dialog.h @@ -0,0 +1,17 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +extern const char* const gVersionString; + +DLGPROC_RET CALLBACK VersionDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +DLGPROC_RET CALLBACK DebugMuteDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +DLGPROC_RET CALLBACK DebugSaveDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +DLGPROC_RET CALLBACK QuitDialog(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); diff --git a/src/Draw.cpp b/src/Draw.cpp new file mode 100644 index 0000000..802dfb3 --- /dev/null +++ b/src/Draw.cpp @@ -0,0 +1,909 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Draw.h" + +#include +#include +#include + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Ending.h" +#include "Generic.h" +#include "Main.h" +#include "MapName.h" +#include "TextScr.h" + +typedef enum SurfaceType +{ + SURFACE_SOURCE_NONE = 1, + SURFACE_SOURCE_RESOURCE, + SURFACE_SOURCE_FILE +} SurfaceType; + +RECT grcGame = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; +RECT grcFull = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + +static int mag; +static BOOL fullscreen; // TODO - Not the original variable name + +static LPDIRECTDRAW lpDD; // TODO - Not the original variable name +static LPDIRECTDRAWSURFACE frontbuffer; // TODO - Not the original variable name +static LPDIRECTDRAWSURFACE backbuffer; // TODO - Not the original variable name + +static LPDIRECTDRAWCLIPPER clipper; // TODO - Not the original variable name + +static LPDIRECTDRAWSURFACE surf[SURFACE_ID_MAX]; + +static RECT backbuffer_rect; // TODO - Not the original variable name + +static int scaled_window_width; // TODO - Not the original variable name +static int scaled_window_height; // TODO - Not the original variable name + +static HFONT font; // TODO - Not the original variable name + +// This doesn't exist in the Linux port, so none of these symbol names are accurate +static struct +{ + char name[20]; + unsigned int width; + unsigned int height; + SurfaceType type; + BOOL bSystem; // Basically a 'do not regenerate' flag +} surface_metadata[SURFACE_ID_MAX]; + +static int client_x; +static int client_y; + +void SetClientOffset(int width, int height) +{ + client_x = width; + client_y = height; +} + +BOOL Flip_SystemTask(HWND hWnd) +{ + // TODO - Not the original variable names + static DWORD timePrev; + static DWORD timeNow; + + while (TRUE) + { + if (!SystemTask()) + return FALSE; + + // Framerate limiter + timeNow = GetTickCount(); + + if (timeNow >= timePrev + 20) + break; + + Sleep(1); + } + + if (timeNow >= timePrev + 100) + timePrev = timeNow; // If the timer is freakishly out of sync, panic and reset it, instead of spamming frames for who-knows how long + else + timePrev += 20; + + static RECT dst_rect; // TODO - Not the original variable name + GetWindowRect(hWnd, &dst_rect); + dst_rect.left += client_x; + dst_rect.top += client_y; + dst_rect.right = dst_rect.left + scaled_window_width; + dst_rect.bottom = dst_rect.top + scaled_window_height; + + frontbuffer->Blt(&dst_rect, backbuffer, &backbuffer_rect, DDBLT_WAIT, NULL); + + if (RestoreSurfaces()) + { + RestoreStripper(); + RestoreMapName(); + RestoreTextScript(); + } + + return TRUE; +} + +BOOL StartDirectDraw(HWND hWnd, int lMagnification, int lColourDepth) +{ + DDSURFACEDESC ddsd; + + if (DirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) + return FALSE; + + memset(surface_metadata, 0, sizeof(surface_metadata)); + + switch (lMagnification) + { + case 0: + mag = 1; + fullscreen = FALSE; + lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + break; + + case 1: + mag = 2; + fullscreen = FALSE; + lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + break; + + case 2: + mag = 2; + fullscreen = TRUE; + lpDD->SetCooperativeLevel(hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); + lpDD->SetDisplayMode(WINDOW_WIDTH * mag, WINDOW_HEIGHT * mag, lColourDepth); + break; + } + + backbuffer_rect.left = 0; + backbuffer_rect.top = 0; + backbuffer_rect.right = WINDOW_WIDTH * mag; + backbuffer_rect.bottom = WINDOW_HEIGHT * mag; + + scaled_window_width = WINDOW_WIDTH * mag; + scaled_window_height = WINDOW_HEIGHT * mag; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + ddsd.dwBackBufferCount = 0; + + if (lpDD->CreateSurface(&ddsd, &frontbuffer, NULL) != DD_OK) + return FALSE; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwWidth = WINDOW_WIDTH * mag; + ddsd.dwHeight = WINDOW_HEIGHT * mag; + + if (lpDD->CreateSurface(&ddsd, &backbuffer, NULL) != DD_OK) + return FALSE; + + lpDD->CreateClipper(0, &clipper, NULL); + clipper->SetHWnd(0, hWnd); + frontbuffer->SetClipper(clipper); + + return TRUE; +} + +void EndDirectDraw(HWND hWnd) +{ + int i; + + // Release all surfaces + for (i = 0; i < SURFACE_ID_MAX; ++i) + { + if (surf[i] != NULL) + { + surf[i]->Release(); + surf[i] = NULL; + } + } + + if (frontbuffer != NULL) + { + frontbuffer->Release(); + frontbuffer = NULL; + backbuffer = NULL; + } + + if (fullscreen) + lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + + if (lpDD != NULL) + { + lpDD->Release(); + lpDD = NULL; + } + + memset(surface_metadata, 0, sizeof(surface_metadata)); +} + +void ReleaseSurface(SurfaceID s) +{ + // Release the surface we want to release + if (surf[s] != NULL) + { + surf[s]->Release(); + surf[s] = NULL; + } + + memset(&surface_metadata[s], 0, sizeof(surface_metadata[0])); +} + +// TODO - Inaccurate stack frame +BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no) +{ + if (surf_no >= SURFACE_ID_MAX) + return FALSE; + + if (surf[surf_no] != NULL) + return FALSE; + + HANDLE handle = LoadImageA(GetModuleHandleA(NULL), name, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + if (handle == NULL) + return FALSE; + + BITMAP bitmap; + GetObjectA(handle, sizeof(BITMAP), &bitmap); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwWidth = bitmap.bmWidth * mag; + ddsd.dwHeight = bitmap.bmHeight * mag; + + if (lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL) != DD_OK) + return FALSE; + + int src_x = 0; + int src_y = 0; + int src_w = bitmap.bmWidth; + int src_h = bitmap.bmHeight; + + int dst_x = 0; + int dst_y = 0; + int dst_w = bitmap.bmWidth * mag; + int dst_h = bitmap.bmHeight * mag; + + HDC hdc = CreateCompatibleDC(NULL); + HGDIOBJ hgdiobj = SelectObject(hdc, handle); + + HDC hdc2; + surf[surf_no]->GetDC(&hdc2); + StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); + surf[surf_no]->ReleaseDC(hdc2); + + SelectObject(hdc, hgdiobj); + DeleteDC(hdc); + + DDCOLORKEY ddcolorkey; + ddcolorkey.dwColorSpaceLowValue = 0; + ddcolorkey.dwColorSpaceHighValue = 0; + + surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); + surf[surf_no]->SetClipper(clipper); + +#ifdef FIX_MAJOR_BUGS + DeleteObject(handle); +#endif + + surface_metadata[surf_no].type = SURFACE_SOURCE_RESOURCE; + surface_metadata[surf_no].width = bitmap.bmWidth; + surface_metadata[surf_no].height = bitmap.bmHeight; + surface_metadata[surf_no].bSystem = FALSE; + strcpy(surface_metadata[surf_no].name, name); + + return TRUE; +} + +// TODO - Inaccurate stack frame +BOOL MakeSurface_File(const char *name, SurfaceID surf_no) +{ + char path[MAX_PATH]; + sprintf(path, "%s\\%s.pbm", gDataPath, name); + + if (!IsEnableBitmap(path)) + { + ErrorLog(path, 0); + return FALSE; + } + +#ifdef FIX_BUGS + if (surf_no >= SURFACE_ID_MAX) +#else + if (surf_no > SURFACE_ID_MAX) +#endif + { + ErrorLog("surface no", surf_no); + return FALSE; + } + + if (surf[surf_no] != NULL) + { + ErrorLog("existing", surf_no); + return FALSE; + } + + HANDLE handle = LoadImageA(GetModuleHandleA(NULL), path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); + if (handle == NULL) + { + ErrorLog(path, 1); + return FALSE; + } + + BITMAP bitmap; + GetObjectA(handle, sizeof(BITMAP), &bitmap); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwWidth = bitmap.bmWidth * mag; + ddsd.dwHeight = bitmap.bmHeight * mag; + + lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL); + + int src_x = 0; + int src_y = 0; + int src_w = bitmap.bmWidth; + int src_h = bitmap.bmHeight; + + int dst_x = 0; + int dst_y = 0; + int dst_w = bitmap.bmWidth * mag; + int dst_h = bitmap.bmHeight * mag; + + HDC hdc = CreateCompatibleDC(NULL); + HGDIOBJ hgdiobj = SelectObject(hdc, handle); + + HDC hdc2; + surf[surf_no]->GetDC(&hdc2); + StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); + surf[surf_no]->ReleaseDC(hdc2); + + SelectObject(hdc, hgdiobj); + DeleteDC(hdc); + + DDCOLORKEY ddcolorkey; + ddcolorkey.dwColorSpaceLowValue = 0; + ddcolorkey.dwColorSpaceHighValue = 0; + + surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); + surf[surf_no]->SetClipper(clipper); + + DeleteObject(handle); + + surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; + surface_metadata[surf_no].width = bitmap.bmWidth; + surface_metadata[surf_no].height = bitmap.bmHeight; + surface_metadata[surf_no].bSystem = FALSE; + strcpy(surface_metadata[surf_no].name, name); + + return TRUE; +} + +// TODO - Inaccurate stack frame +BOOL ReloadBitmap_Resource(const char *name, SurfaceID surf_no) +{ + if (surf_no >= SURFACE_ID_MAX) + return FALSE; + + HANDLE handle = LoadImageA(GetModuleHandleA(NULL), name, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + if (handle == NULL) + return FALSE; + + BITMAP bitmap; + GetObjectA(handle, sizeof(BITMAP), &bitmap); + + int src_x = 0; + int src_y = 0; + int src_w = bitmap.bmWidth; + int src_h = bitmap.bmHeight; + + int dst_x = 0; + int dst_y = 0; + int dst_w = bitmap.bmWidth * mag; + int dst_h = bitmap.bmHeight * mag; + + HDC hdc = CreateCompatibleDC(NULL); + HGDIOBJ hgdiobj = SelectObject(hdc, handle); + + HDC hdc2; + surf[surf_no]->GetDC(&hdc2); + StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); + surf[surf_no]->ReleaseDC(hdc2); + + SelectObject(hdc, hgdiobj); + DeleteDC(hdc); + + DDCOLORKEY ddcolorkey; + ddcolorkey.dwColorSpaceLowValue = 0; + ddcolorkey.dwColorSpaceHighValue = 0; + + surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); + surf[surf_no]->SetClipper(clipper); + +#ifdef FIX_MAJOR_BUGS + DeleteObject(handle); +#endif + + surface_metadata[surf_no].type = SURFACE_SOURCE_RESOURCE; + strcpy(surface_metadata[surf_no].name, name); + + return TRUE; +} + +// TODO - Inaccurate stack frame +BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) +{ + char path[MAX_PATH]; + sprintf(path, "%s\\%s.pbm", gDataPath, name); + + if (!IsEnableBitmap(path)) + { + ErrorLog(path, 0); + return FALSE; + } + +#ifdef FIX_BUGS + if (surf_no >= SURFACE_ID_MAX) +#else + if (surf_no > SURFACE_ID_MAX) +#endif + { + ErrorLog("surface no", surf_no); + return FALSE; + } + + HANDLE handle = LoadImageA(GetModuleHandleA(NULL), path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); + if (handle == NULL) + { + ErrorLog(path, 1); + return FALSE; + } + + BITMAP bitmap; + GetObjectA(handle, sizeof(BITMAP), &bitmap); + + int src_x = 0; + int src_y = 0; + int src_w = bitmap.bmWidth; + int src_h = bitmap.bmHeight; + + int dst_x = 0; + int dst_y = 0; + int dst_w = bitmap.bmWidth * mag; + int dst_h = bitmap.bmHeight * mag; + + HDC hdc = CreateCompatibleDC(NULL); + HGDIOBJ hgdiobj = SelectObject(hdc, handle); + + HDC hdc2; + surf[surf_no]->GetDC(&hdc2); + StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); + surf[surf_no]->ReleaseDC(hdc2); + + SelectObject(hdc, hgdiobj); + DeleteDC(hdc); + + // No colour-keying + + DeleteObject(handle); + + surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; + strcpy(surface_metadata[surf_no].name, name); + + return TRUE; +} + +// TODO - Inaccurate stack frame +BOOL MakeSurface_Generic(int bxsize, int bysize, SurfaceID surf_no, BOOL bSystem) +{ +#ifdef FIX_BUGS + if (surf_no >= SURFACE_ID_MAX) +#else + if (surf_no > SURFACE_ID_MAX) // OOPS (should be '>=') +#endif + return FALSE; + + if (surf[surf_no] != NULL) + return FALSE; + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + + if (bSystem) + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + else + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + + ddsd.dwWidth = bxsize * mag; + ddsd.dwHeight = bysize * mag; + + lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL); + + DDCOLORKEY ddcolorkey; + ddcolorkey.dwColorSpaceLowValue = 0; + ddcolorkey.dwColorSpaceHighValue = 0; + + surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); + + surface_metadata[surf_no].type = SURFACE_SOURCE_NONE; + surface_metadata[surf_no].width = ddsd.dwWidth / mag; + surface_metadata[surf_no].height = ddsd.dwHeight / mag; + + if (bSystem) + surface_metadata[surf_no].bSystem = TRUE; + else + surface_metadata[surf_no].bSystem = FALSE; + + strcpy(surface_metadata[surf_no].name, "generic"); + + return TRUE; +} + +void BackupSurface(SurfaceID surf_no, const RECT *rect) +{ + static DDBLTFX ddbltfx; // TODO - Not the original variable name + + memset(&ddbltfx, 0, sizeof(DDBLTFX)); + ddbltfx.dwSize = sizeof(DDBLTFX); + + static RECT rcSet; // TODO - Not the original variable name + rcSet.left = rect->left * mag; + rcSet.top = rect->top * mag; + rcSet.right = rect->right * mag; + rcSet.bottom = rect->bottom * mag; + + surf[surf_no]->Blt(&rcSet, backbuffer, &rcSet, DDBLT_WAIT, &ddbltfx); +} + +void PutBitmap3(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no) // Transparency +{ + static RECT rcWork; + static RECT rcSet; + + rcWork = *rect; + + if (x + rect->right - rect->left > rcView->right) + rcWork.right -= (x + rect->right - rect->left) - rcView->right; + + if (x < rcView->left) + { + rcWork.left += rcView->left - x; + x = rcView->left; + } + + if (y + rect->bottom - rect->top > rcView->bottom) + rcWork.bottom -= (y + rect->bottom - rect->top) - rcView->bottom; + + if (y < rcView->top) + { + rcWork.top += rcView->top - y; + y = rcView->top; + } + + rcSet.left = x; + rcSet.top = y; + rcSet.right = x + rcWork.right - rcWork.left; + rcSet.bottom = y + rcWork.bottom - rcWork.top; + + rcWork.left *= mag; + rcWork.top *= mag; + rcWork.right *= mag; + rcWork.bottom *= mag; + + rcSet.left *= mag; + rcSet.top *= mag; + rcSet.right *= mag; + rcSet.bottom *= mag; + + backbuffer->Blt(&rcSet, surf[surf_no], &rcWork, DDBLT_KEYSRC | DDBLT_WAIT, NULL); +} + +void PutBitmap4(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no) // No Transparency +{ + static RECT rcWork; + static RECT rcSet; + + rcWork = *rect; + + if (x + rect->right - rect->left > rcView->right) + rcWork.right -= (x + rect->right - rect->left) - rcView->right; + + if (x < rcView->left) + { + rcWork.left += rcView->left - x; + x = rcView->left; + } + + if (y + rect->bottom - rect->top > rcView->bottom) + rcWork.bottom -= (y + rect->bottom - rect->top) - rcView->bottom; + + if (y < rcView->top) + { + rcWork.top += rcView->top - y; + y = rcView->top; + } + + rcSet.left = x; + rcSet.top = y; + rcSet.right = x + rcWork.right - rcWork.left; + rcSet.bottom = y + rcWork.bottom - rcWork.top; + + rcWork.left *= mag; + rcWork.top *= mag; + rcWork.right *= mag; + rcWork.bottom *= mag; + + rcSet.left *= mag; + rcSet.top *= mag; + rcSet.right *= mag; + rcSet.bottom *= mag; + + backbuffer->Blt(&rcSet, surf[surf_no], &rcWork, DDBLT_WAIT, NULL); +} + +void Surface2Surface(int x, int y, const RECT *rect, SurfaceID to, SurfaceID from) +{ + static RECT rcWork; + static RECT rcSet; + + rcWork.left = rect->left * mag; + rcWork.top = rect->top * mag; + rcWork.right = rect->right * mag; + rcWork.bottom = rect->bottom * mag; + + rcSet.left = x; + rcSet.top = y; + rcSet.right = x + rect->right - rect->left; + rcSet.bottom = y + rect->bottom - rect->top; + + rcSet.left *= mag; + rcSet.top *= mag; + rcSet.right *= mag; + rcSet.bottom *= mag; + + surf[to]->Blt(&rcSet, surf[from], &rcWork, DDBLT_KEYSRC | DDBLT_WAIT, NULL); +} + +// This converts a colour to the 'native' format by writing it +// straight to the framebuffer, and then reading it back +unsigned long GetCortBoxColor(COLORREF col) +{ + HDC hdc; + + if (backbuffer->GetDC(&hdc) != DD_OK) + return 0xFFFFFFFF; + + COLORREF original_colour = GetPixel(hdc, 0, 0); + SetPixel(hdc, 0, 0, col); + backbuffer->ReleaseDC(hdc); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + + if (backbuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) + return 0xFFFFFFFF; + + DWORD native_colour = *(DWORD*)ddsd.lpSurface; + + if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32) + native_colour &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; + + backbuffer->Unlock(0); + + if (backbuffer->GetDC(&hdc) != DD_OK) + return 0xFFFFFFFF; + + SetPixel(hdc, 0, 0, original_colour); + backbuffer->ReleaseDC(hdc); + + return native_colour; +} + +void CortBox(const RECT *rect, unsigned long col) +{ + static DDBLTFX ddbltfx; // TODO - Not the original variable name + memset(&ddbltfx, 0, sizeof(DDBLTFX)); + ddbltfx.dwSize = sizeof(DDBLTFX); + ddbltfx.dwFillColor = col; + + static RECT rcSet; // TODO - Not the original variable name + rcSet.left = rect->left * mag; + rcSet.top = rect->top * mag; + rcSet.right = rect->right * mag; + rcSet.bottom = rect->bottom * mag; + + backbuffer->Blt(&rcSet, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); +} + +void CortBox2(const RECT *rect, unsigned long col, SurfaceID surf_no) +{ + static DDBLTFX ddbltfx; // TODO - Not the original variable name + memset(&ddbltfx, 0, sizeof(DDBLTFX)); + ddbltfx.dwSize = sizeof(DDBLTFX); + ddbltfx.dwFillColor = col; + + static RECT rcSet; // TODO - Not the original variable name + rcSet.left = rect->left * mag; + rcSet.top = rect->top * mag; + rcSet.right = rect->right * mag; + rcSet.bottom = rect->bottom * mag; + + surface_metadata[surf_no].type = SURFACE_SOURCE_NONE; + + surf[surf_no]->Blt(&rcSet, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); +} + +// Dummied-out log function +// According to the Mac port, its name really is just "out". +BOOL out(char surface_identifier) +{ + // The actual name (and type) of these two variables are unknown + char path[MAX_PATH]; + FILE *fp; + + (void)surface_identifier; + (void)path; + (void)fp; + + // There may have been some kind of 'OutputDebugStringA' call here, + // like the one in 'EnumDevices_Callback' in 'Input.cpp'. + // Pixel may have kept them wrapped in '#ifdef DEBUG' blocks. + + return TRUE; +} + +// TODO - Probably not the original function name (this is an educated guess) +int RestoreSurfaces(void) +{ + int s; + RECT rect; + int surfaces_regenerated = 0; + + if (frontbuffer == NULL) + return surfaces_regenerated; + + if (backbuffer == NULL) + return surfaces_regenerated; + + if (frontbuffer->IsLost() == DDERR_SURFACELOST) + { + ++surfaces_regenerated; + frontbuffer->Restore(); + out('f'); // 'f' for 'frontbuffer' + } + + if (backbuffer->IsLost() == DDERR_SURFACELOST) + { + ++surfaces_regenerated; + backbuffer->Restore(); + out('b'); // 'b' for 'backbuffer' + } + + for (s = 0; s < SURFACE_ID_MAX; ++s) + { + if (surf[s] != NULL) + { + if (surf[s]->IsLost() == DDERR_SURFACELOST) + { + ++surfaces_regenerated; + surf[s]->Restore(); + out('0' + s); // The number of the surface lost + + if (!surface_metadata[s].bSystem) + { + switch (surface_metadata[s].type) + { + case SURFACE_SOURCE_NONE: + rect.left = 0; + rect.top = 0; + rect.right = surface_metadata[s].width; + rect.bottom = surface_metadata[s].height; + CortBox2(&rect, 0, (SurfaceID)s); + break; + + case SURFACE_SOURCE_RESOURCE: + ReloadBitmap_Resource(surface_metadata[s].name, (SurfaceID)s); + break; + + case SURFACE_SOURCE_FILE: + ReloadBitmap_File(surface_metadata[s].name, (SurfaceID)s); + break; + } + } + } + } + } + + return surfaces_regenerated; +} + +// TODO - Inaccurate stack frame +void InitTextObject(const char *name) +{ + // Get font size + unsigned int width, height; + + // Let me tell you why these font sizes are unfortunate... + // 6x12 is a good font size - fonts use high-quality bitmaps at that + // size, and it works with Cave Story's internal assumption that + // characters are spaced 6 pixels apart. + // The sad part is the 10x20 size: you might be wondering why Pixel + // didn't use 12x24 instead. Well, that's because fonts don't use + // bitmaps at that size - instead you get ugly low-res vector + // renders. So, Pixel had to use 10x20 instead. But there's a + // problem: this means the characters are spaced 5 pixels apart + // instead. This normally isn't a problem because the game usually + // hardcodes it, but this isn't the case when either GetDC(&hdc); + HGDIOBJ hgdiobj = SelectObject(hdc, font); + SetBkMode(hdc, 1); + SetTextColor(hdc, color); + TextOutA(hdc, x * mag, y * mag, text, (int)strlen(text)); + SelectObject(hdc, hgdiobj); + backbuffer->ReleaseDC(hdc); +} + +void PutText2(int x, int y, const char *text, unsigned long color, SurfaceID surf_no) +{ + HDC hdc; + surf[surf_no]->GetDC(&hdc); + HGDIOBJ hgdiobj = SelectObject(hdc, font); + SetBkMode(hdc, 1); + SetTextColor(hdc, color); + TextOutA(hdc, x * mag, y * mag, text, (int)strlen(text)); + SelectObject(hdc, hgdiobj); + surf[surf_no]->ReleaseDC(hdc); +} + +void EndTextObject(void) +{ + DeleteObject(font); +} diff --git a/src/Draw.h b/src/Draw.h new file mode 100644 index 0000000..a98709b --- /dev/null +++ b/src/Draw.h @@ -0,0 +1,72 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +extern RECT grcGame; +extern RECT grcFull; + +typedef enum SurfaceID +{ + SURFACE_ID_TITLE = 0, + SURFACE_ID_PIXEL = 1, + SURFACE_ID_LEVEL_TILESET = 2, + SURFACE_ID_FADE = 6, + SURFACE_ID_ITEM_IMAGE = 8, + SURFACE_ID_MAP = 9, + SURFACE_ID_SCREEN_GRAB = 10, + SURFACE_ID_ARMS = 11, + SURFACE_ID_ARMS_IMAGE = 12, + SURFACE_ID_ROOM_NAME = 13, + SURFACE_ID_STAGE_ITEM = 14, + SURFACE_ID_LOADING = 15, + SURFACE_ID_MY_CHAR = 16, + SURFACE_ID_BULLET = 17, + SURFACE_ID_CARET = 19, + SURFACE_ID_NPC_SYM = 20, + SURFACE_ID_LEVEL_SPRITESET_1 = 21, + SURFACE_ID_LEVEL_SPRITESET_2 = 22, + SURFACE_ID_NPC_REGU = 23, + SURFACE_ID_TEXT_BOX = 26, + SURFACE_ID_FACE = 27, + SURFACE_ID_LEVEL_BACKGROUND = 28, + SURFACE_ID_VALUE_VIEW = 29, + SURFACE_ID_TEXT_LINE1 = 30, + SURFACE_ID_TEXT_LINE2 = 31, + SURFACE_ID_TEXT_LINE3 = 32, + SURFACE_ID_TEXT_LINE4 = 33, + SURFACE_ID_TEXT_LINE5 = 34, + SURFACE_ID_CREDIT_CAST = 35, + SURFACE_ID_CREDITS_IMAGE = 36, + SURFACE_ID_CASTS = 37, + SURFACE_ID_MAX = 40 +} SurfaceID; + +void SetClientOffset(int width, int height); +BOOL Flip_SystemTask(HWND hWnd); +BOOL StartDirectDraw(HWND hWnd, int lMagnification, int lColourDepth); +void EndDirectDraw(HWND hWnd); +void ReleaseSurface(SurfaceID s); +BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no); +BOOL MakeSurface_File(const char *name, SurfaceID surf_no); +BOOL ReloadBitmap_Resource(const char *name, SurfaceID surf_no); +BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no); +BOOL MakeSurface_Generic(int bxsize, int bysize, SurfaceID surf_no, BOOL bSystem); +void BackupSurface(SurfaceID surf_no, const RECT *rect); +void PutBitmap3(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no); +void PutBitmap4(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no); +void Surface2Surface(int x, int y, const RECT *rect, SurfaceID to, SurfaceID from); +unsigned long GetCortBoxColor(COLORREF col); +void CortBox(const RECT *rect, unsigned long col); +void CortBox2(const RECT *rect, unsigned long col, SurfaceID surf_no); +int RestoreSurfaces(void); +void InitTextObject(const char *font_name); +void PutText(int x, int y, const char *text, unsigned long color); +void PutText2(int x, int y, const char *text, unsigned long color, SurfaceID surf_no); +void EndTextObject(void); diff --git a/src/Ending.cpp b/src/Ending.cpp new file mode 100644 index 0000000..ed9fe38 --- /dev/null +++ b/src/Ending.cpp @@ -0,0 +1,579 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Ending.h" + +#include +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "Draw.h" +#include "Escape.h" +#include "Flags.h" +#include "Generic.h" +#include "KeyControl.h" +#include "Main.h" +#include "MycParam.h" +#include "Organya.h" +#include "Stage.h" +#include "TextScr.h" + +enum CREDIT_MODE +{ + CREDIT_MODE_STOP, + CREDIT_MODE_SCROLL_READ, + CREDIT_MODE_SCROLL_WAIT +}; + +enum ILLUSTRATION_ACTION +{ + ILLUSTRATION_ACTION_IDLE, + ILLUSTRATION_ACTION_SLIDE_IN, + ILLUSTRATION_ACTION_SLIDE_OUT +}; + +struct CREDIT +{ + long size; + char *pData; + int offset; + int wait; + CREDIT_MODE mode; + int start_x; +}; + +struct STRIP +{ + int flag; + int x; + int y; + int cast; + char str[0x40]; +}; + +struct ILLUSTRATION +{ + ILLUSTRATION_ACTION act_no; + int x; +}; + +struct ISLAND_SPRITE +{ + int x; + int y; +}; + +static CREDIT Credit; +static STRIP Strip[MAX_STRIP]; +static ILLUSTRATION Illust; + +// Update casts +void ActionStripper(void) +{ + int s; + + for (s = 0; s < MAX_STRIP; ++s) + { + // Move up + if (Strip[s].flag & 0x80 && Credit.mode != CREDIT_MODE_STOP) + Strip[s].y -= 0x100; + // Get removed when off-screen + if (Strip[s].y <= -16 * 0x200) + Strip[s].flag = 0; + } +} + +// Draw casts +void PutStripper(void) +{ + int s; + RECT rc; + + for (s = 0; s < MAX_STRIP; ++s) + { + if (Strip[s].flag & 0x80) + { + // Draw text + rc.left = 0; + rc.right = 320; + rc.top = s * 16; + rc.bottom = rc.top + 16; + + PutBitmap3(&grcFull, (Strip[s].x / 0x200) + ((WINDOW_WIDTH - 320) / 2), (Strip[s].y / 0x200), &rc, SURFACE_ID_CREDIT_CAST); + + // Draw character + rc.left = (Strip[s].cast % 13) * 24; + rc.right = rc.left + 24; + rc.top = (Strip[s].cast / 13) * 24; + rc.bottom = rc.top + 24; + + PutBitmap3(&grcFull, (Strip[s].x / 0x200) + ((WINDOW_WIDTH - 320) / 2) - 24, (Strip[s].y / 0x200) - 8, &rc, SURFACE_ID_CASTS); + } + } +} + +// Create a cast object +void SetStripper(int x, int y, const char *text, int cast) +{ + int s; + RECT rc; + + for (s = 0; s < MAX_STRIP; ++s) + if (!(Strip[s].flag & 0x80)) + break; + + if (s == MAX_STRIP) + return; + + // Initialize cast property + Strip[s].flag = 0x80; + Strip[s].x = x; + Strip[s].y = y; + Strip[s].cast = cast; + strcpy(Strip[s].str, text); + + // Draw text + rc.left = 0; + rc.right = 320; + rc.top = s * 16; + rc.bottom = rc.top + 16; + + CortBox2(&rc, 0, SURFACE_ID_CREDIT_CAST); + PutText2(0, rc.top, text, RGB(0xFF, 0xFF, 0xFE), SURFACE_ID_CREDIT_CAST); +} + +// Regenerate cast text +void RestoreStripper(void) +{ + int s; + RECT rc; + + for (s = 0; s < MAX_STRIP; ++s) + { + if (Strip[s].flag & 0x80) + { + rc.left = 0; + rc.right = 320; + rc.top = s * 16; + rc.bottom = rc.top + 16; + + CortBox2(&rc, 0, SURFACE_ID_CREDIT_CAST); + PutText2(0, rc.top, Strip[s].str, RGB(0xFF, 0xFF, 0xFE), SURFACE_ID_CREDIT_CAST); + } + } +} + +// Handle the illustration +void ActionIllust(void) +{ + switch (Illust.act_no) + { + case ILLUSTRATION_ACTION_IDLE: // Off-screen to the left + Illust.x = -160 * 0x200; + break; + + case ILLUSTRATION_ACTION_SLIDE_IN: // Move in from the left + Illust.x += 40 * 0x200; + if (Illust.x > 0) + Illust.x = 0; + break; + + case ILLUSTRATION_ACTION_SLIDE_OUT: // Move out from the right + Illust.x -= 40 * 0x200; + if (Illust.x < -160 * 0x200) + Illust.x = -160 * 0x200; + break; + } +} + +// Draw illustration +void PutIllust(void) +{ + RECT rcIllust = {0, 0, 160, 240}; +#if WINDOW_WIDTH != 320 || WINDOW_HEIGHT != 240 // TODO - Move this to CSE2EX + // Widescreen edit + RECT rcClip = {(WINDOW_WIDTH - 320) / 2, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + PutBitmap3(&rcClip, (Illust.x / 0x200) + ((WINDOW_WIDTH - 320) / 2), (WINDOW_HEIGHT - 240) / 2, &rcIllust, SURFACE_ID_CREDITS_IMAGE); +#else + PutBitmap3(&grcFull, (Illust.x / 0x200) + ((WINDOW_WIDTH - 320) / 2), (WINDOW_HEIGHT - 240) / 2, &rcIllust, SURFACE_ID_CREDITS_IMAGE); +#endif +} + +// Load illustration +void ReloadIllust(int a) +{ + char name[16]; + sprintf(name, "CREDIT%02d", a); + ReloadBitmap_Resource(name, SURFACE_ID_CREDITS_IMAGE); +} + +const char *credit_script = "Credit.tsc"; + +// Initialize and release credits +void InitCreditScript(void) +{ + // Clear script state and casts + memset(&Credit, 0, sizeof(CREDIT)); + memset(Strip, 0, sizeof(Strip)); +} + +void ReleaseCreditScript(void) +{ + if (Credit.pData != NULL) + { + // Free script data + free(Credit.pData); + Credit.pData = NULL; + } +} + +// Start playing credits +BOOL StartCreditScript(void) +{ + FILE *fp; + char path[MAX_PATH]; + + // Clear previously existing credits data + if (Credit.pData != NULL) + { + free(Credit.pData); + Credit.pData = NULL; + } + + // Open file + sprintf(path, "%s\\%s", gDataPath, credit_script); + + Credit.size = GetFileSizeLong(path); + if (Credit.size == INVALID_FILE_SIZE) + return FALSE; + + // Allocate buffer data + Credit.pData = (char*)malloc(Credit.size); + if (Credit.pData == NULL) + return FALSE; + + fp = fopen(path, "rb"); + if (fp == NULL) + { + free(Credit.pData); + return FALSE; + } + + // Read data + fread(Credit.pData, 1, Credit.size, fp); + +#ifdef FIX_MAJOR_BUGS + // The original game forgot to close the file + fclose(fp); +#endif + + EncryptionBinaryData2((unsigned char*)Credit.pData, Credit.size); + + // Reset credits + Credit.offset = 0; + Credit.wait = 0; + Credit.mode = CREDIT_MODE_SCROLL_READ; + Illust.x = -160 * 0x200; + Illust.act_no = ILLUSTRATION_ACTION_IDLE; + + // Modify cliprect + grcGame.left = WINDOW_WIDTH / 2; +#if WINDOW_WIDTH != 320 || WINDOW_HEIGHT != 240 // TODO - Move to CSE2EX + // These three are non-vanilla: for wide/tallscreen support + grcGame.right = ((WINDOW_WIDTH - 320) / 2) + 320; + grcGame.top = (WINDOW_HEIGHT - 240) / 2; + grcGame.bottom = ((WINDOW_HEIGHT - 240) / 2) + 240; +#endif + + // Reload casts + if (!ReloadBitmap_File("casts", SURFACE_ID_CASTS)) + return FALSE; + + // Clear casts + memset(Strip, 0, sizeof(Strip)); + return TRUE; +} + +// Get number from text (4 digit) +static int GetScriptNumber(const char *text) +{ + return (text[0] - '0') * 1000 + + (text[1] - '0') * 100 + + (text[2] - '0') * 10 + + (text[3] - '0') * 1; +} + +// Parse credits +static void ActionCredit_Read(void) +{ + int a, b, len; + char text[40]; + + while (1) + { + if (Credit.offset >= Credit.size) + break; + + switch (Credit.pData[Credit.offset]) + { + case '[': // Create cast + // Get the range for the cast text + Credit.offset += 1; + + a = Credit.offset; + + while (Credit.pData[a] != ']') + { + if (IsShiftJIS(Credit.pData[a])) + a += 2; + else + a += 1; + } + + len = a - Credit.offset; + + // Copy the text to the cast text + memcpy(text, &Credit.pData[Credit.offset], len); + text[len] = '\0'; + + // Get cast ID + Credit.offset = a; + Credit.offset += 1; + len = GetScriptNumber(&Credit.pData[Credit.offset]); + + // Create cast object + SetStripper(Credit.start_x, (WINDOW_HEIGHT + 8) * 0x200, text, len); + + // Change offset + Credit.offset += 4; + return; + + case '-': // Wait for X amount of frames + Credit.offset += 1; + Credit.wait = GetScriptNumber(&Credit.pData[Credit.offset]); + Credit.offset += 4; + Credit.mode = CREDIT_MODE_SCROLL_WAIT; + return; + + case '+': // Change casts x-position + Credit.offset += 1; + Credit.start_x = GetScriptNumber(&Credit.pData[Credit.offset]) * 0x200; + Credit.offset += 4; + return; + + case '/': // Stop credits + Credit.mode = CREDIT_MODE_STOP; + return; + + case '!': // Change music + Credit.offset += 1; + a = GetScriptNumber(&Credit.pData[Credit.offset]); + Credit.offset += 4; + ChangeMusic((MusicID)a); + return; + + case '~': // Start fading out music + Credit.offset += 1; + SetOrganyaFadeout(); + return; + + case 'j': // Jump to label + Credit.offset += 1; + + // Get number + b = GetScriptNumber(&Credit.pData[Credit.offset]); + + // Change offset + Credit.offset += 4; + + // Jump to specific label + if (1) // This appears to be a hacked-up duplicate of some code from the below 'f' condition + { + while (Credit.offset < Credit.size) + { + if (Credit.pData[Credit.offset] == 'l') + { + Credit.offset += 1; + a = GetScriptNumber(&Credit.pData[Credit.offset]); + Credit.offset += 4; + + if (b == a) + break; + } + else + { + if (IsShiftJIS(Credit.pData[Credit.offset])) + Credit.offset += 2; + else + Credit.offset += 1; + } + } + } + + return; + + case 'f': // Flag jump + Credit.offset += 1; + + // Read numbers XXXX:YYYY + a = GetScriptNumber(&Credit.pData[Credit.offset]); + Credit.offset += 5; + b = GetScriptNumber(&Credit.pData[Credit.offset]); + Credit.offset += 4; + + // If flag is set + if (GetNPCFlag(a)) + { + // Jump to label + while (Credit.offset < Credit.size) + { + if (Credit.pData[Credit.offset] == 'l') + { + Credit.offset += 1; + a = GetScriptNumber(&Credit.pData[Credit.offset]); + Credit.offset += 4; + + if (b == a) + break; + } + else + { + if (IsShiftJIS(Credit.pData[Credit.offset])) + Credit.offset += 2; + else + Credit.offset += 1; + } + } + } + return; + + default: + // Progress through file + Credit.offset += 1; + break; + } + } +} + +// Update credits +void ActionCredit(void) +{ + if (Credit.offset >= Credit.size) + return; + + // Update script, or if waiting, decrement the wait value + switch (Credit.mode) + { + case CREDIT_MODE_SCROLL_READ: + ActionCredit_Read(); + break; + + case CREDIT_MODE_SCROLL_WAIT: + if (--Credit.wait <= 0) + Credit.mode = CREDIT_MODE_SCROLL_READ; + break; + } +} + +// Change illustration +void SetCreditIllust(int a) +{ + ReloadIllust(a); + Illust.act_no = ILLUSTRATION_ACTION_SLIDE_IN; +} + +// Slide illustration off-screen +void CutCreditIllust(void) +{ + Illust.act_no = ILLUSTRATION_ACTION_SLIDE_OUT; +} + +// Scene of the island falling +int Scene_DownIsland(HWND hWnd, int mode) +{ + ISLAND_SPRITE sprite; + int wait; + + // Setup background + RECT rc_frame = {(WINDOW_WIDTH / 2) - 80, (WINDOW_HEIGHT / 2) - 40, (WINDOW_WIDTH / 2) + 80, (WINDOW_HEIGHT / 2) + 40}; + RECT rc_sky = {0, 0, 160, 80}; + RECT rc_ground = {160, 48, 320, 80}; + + // Setup island + RECT rc_sprite = {160, 0, 200, 24}; + + sprite.x = 168 * 0x200; + sprite.y = 64 * 0x200; + + for (wait = 0; wait < 900; ++wait) + { + // Get pressed keys + GetTrg(); + + // Escape menu + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(hWnd)) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; + } + } + + switch (mode) + { + case 0: + // Move down + sprite.y += 0x200 / 10; + break; + + case 1: + if (wait < 350) + { + // Move down at normal speed + sprite.y += 0x200 / 10; + } + else if (wait < 500) + { + // Move down slower + sprite.y += 0x200 / 20; + } + else if (wait < 600) + { + // Move down slow + sprite.y += 0x200 / 40; + } + else if (wait == 750) + { + // End scene + wait = 900; + } + + break; + } + + // Draw scene + CortBox(&grcFull, 0); + PutBitmap3(&rc_frame, 80 + ((WINDOW_WIDTH - 320) / 2), 80 + ((WINDOW_HEIGHT - 240) / 2), &rc_sky, SURFACE_ID_LEVEL_SPRITESET_1); + PutBitmap3(&rc_frame, (sprite.x / 0x200) - 20 + ((WINDOW_WIDTH - 320) / 2), (sprite.y / 0x200) - 12 + ((WINDOW_HEIGHT - 240) / 2), &rc_sprite, SURFACE_ID_LEVEL_SPRITESET_1); + PutBitmap3(&rc_frame, 80 + ((WINDOW_WIDTH - 320) / 2), 128 + ((WINDOW_HEIGHT - 240) / 2), &rc_ground, SURFACE_ID_LEVEL_SPRITESET_1); + PutTimeCounter(16, 8); + + // Draw window + PutFramePerSecound(); + if (!Flip_SystemTask(hWnd)) + return enum_ESCRETURN_exit; + } + + return enum_ESCRETURN_continue; +} diff --git a/src/Ending.h b/src/Ending.h new file mode 100644 index 0000000..d6de3d6 --- /dev/null +++ b/src/Ending.h @@ -0,0 +1,29 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" + +#define MAX_STRIP ((WINDOW_HEIGHT / 16) + 1) + +void ActionStripper(void); +void PutStripper(void); +void SetStripper(int x, int y, const char *text, int cast); +void RestoreStripper(void); +void ActionIllust(void); +void PutIllust(void); +void ReloadIllust(int a); +void InitCreditScript(void); +void ReleaseCreditScript(void); +BOOL StartCreditScript(void); +void ActionCredit(void); +void SetCreditIllust(int a); +void CutCreditIllust(void); +int Scene_DownIsland(HWND hWnd, int mode); diff --git a/src/Escape.cpp b/src/Escape.cpp new file mode 100644 index 0000000..f3e9d03 --- /dev/null +++ b/src/Escape.cpp @@ -0,0 +1,56 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Escape.h" + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "KeyControl.h" +#include "Main.h" + +int Call_Escape(HWND hWnd) +{ + RECT rc = {0, 128, 208, 144}; + + while (1) + { + // Get pressed keys + GetTrg(); + + if (gKeyTrg & KEY_ESCAPE) // Escape is pressed, quit game + { + gKeyTrg = 0; + return enum_ESCRETURN_exit; + } + if (gKeyTrg & KEY_F1) // F1 is pressed, continue + { + gKeyTrg = 0; + return enum_ESCRETURN_continue; + } + if (gKeyTrg & KEY_F2) // F2 is pressed, reset + { + gKeyTrg = 0; + return enum_ESCRETURN_restart; + } + + // Draw screen + CortBox(&grcFull, 0x000000); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 104, (WINDOW_HEIGHT / 2) - 8, &rc, SURFACE_ID_TEXT_BOX); + PutFramePerSecound(); + + if (!Flip_SystemTask(hWnd)) + { + // Quit if window is closed + gKeyTrg = 0; + return enum_ESCRETURN_exit; + } + } + + return enum_ESCRETURN_exit; +} diff --git a/src/Escape.h b/src/Escape.h new file mode 100644 index 0000000..2a88c56 --- /dev/null +++ b/src/Escape.h @@ -0,0 +1,19 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +enum enum_ESCRETURN +{ + enum_ESCRETURN_exit, + enum_ESCRETURN_continue, + enum_ESCRETURN_restart +}; + +int Call_Escape(HWND hWnd); diff --git a/src/Fade.cpp b/src/Fade.cpp new file mode 100644 index 0000000..7d24b0f --- /dev/null +++ b/src/Fade.cpp @@ -0,0 +1,262 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Fade.h" + +#include + +#include "WindowsWrapper.h" + +#include "Draw.h" + +FADE gFade; + +static unsigned long mask_color; + +void InitFade(void) +{ + memset(&gFade, 0, sizeof(FADE)); + mask_color = GetCortBoxColor(RGB(0, 0, 0x20)); +} + +void SetFadeMask(void) +{ + gFade.bMask = TRUE; +} + +void ClearFade(void) +{ + gFade.bMask = FALSE; + gFade.mode = 0; +} + +void StartFadeOut(signed char dir) +{ + int x, y; + + gFade.mode = 2; + gFade.count = 0; + gFade.dir = dir; + gFade.bMask = FALSE; + + for (y = 0; y < FADE_HEIGHT; ++y) + { + for (x = 0; x < FADE_WIDTH; ++x) + { + gFade.ani_no[y][x] = 0; + gFade.flag[y][x] = FALSE; + } + } +} + +void StartFadeIn(signed char dir) +{ + int x, y; + + gFade.mode = 1; + gFade.count = 0; + gFade.dir = dir; + gFade.bMask = TRUE; + + for (y = 0; y < FADE_HEIGHT; ++y) + { + for (x = 0; x < FADE_WIDTH; ++x) + { + gFade.ani_no[y][x] = 15; + gFade.flag[y][x] = FALSE; + } + } + + x = x; // This probably doesn't match the original source code, but it produces the same assembly +} + +void ProcFade(void) +{ + int x, y; + + switch (gFade.mode) + { + case 2: + switch (gFade.dir) + { + case 0: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if ((FADE_WIDTH - 1) - gFade.count == x) + gFade.flag[y][x] = TRUE; + + break; + + case 2: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if (gFade.count == x) + gFade.flag[y][x] = TRUE; + + break; + + case 1: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if ((FADE_HEIGHT - 1) - gFade.count == y) + gFade.flag[y][x] = TRUE; + + break; + + case 3: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if (gFade.count == y) + gFade.flag[y][x] = TRUE; + + break; + + case 4: + for (y = 0; y < (FADE_HEIGHT / 2); ++y) + for (x = 0; x < (FADE_WIDTH / 2); ++x) + if (gFade.count == x + y) + gFade.flag[y][x] = TRUE; + + for (y = 0; y < (FADE_HEIGHT / 2); ++y) + for (x = (FADE_WIDTH / 2); x < FADE_WIDTH; ++x) + if (gFade.count == y + ((FADE_WIDTH - 1) - x)) + gFade.flag[y][x] = TRUE; + + for (y = (FADE_HEIGHT / 2); y < FADE_HEIGHT; ++y) + for (x = 0; x < (FADE_WIDTH / 2); ++x) + if (gFade.count == x + ((FADE_HEIGHT - 1) - y)) + gFade.flag[y][x] = TRUE; + + for (y = (FADE_HEIGHT / 2); y < FADE_HEIGHT; ++y) + for (x = (FADE_WIDTH / 2); x < FADE_WIDTH; ++x) + if (gFade.count == ((FADE_WIDTH - 1) - x) + ((FADE_HEIGHT - 1) - y)) + gFade.flag[y][x] = TRUE; + + break; + } + + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if (gFade.ani_no[y][x] < 15 && gFade.flag[y][x]) + ++gFade.ani_no[y][x]; + + if (++gFade.count > ((FADE_WIDTH > FADE_HEIGHT) ? FADE_WIDTH : FADE_HEIGHT) + 16) + { + gFade.bMask = TRUE; + gFade.mode = 0; + } + + break; + + case 1: + gFade.bMask = FALSE; + + switch (gFade.dir) + { + case 0: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if ((FADE_WIDTH - 1) - gFade.count == x) + gFade.flag[y][x] = TRUE; + + break; + + case 2: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if (gFade.count == x) + gFade.flag[y][x] = TRUE; + + break; + + case 1: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if ((FADE_HEIGHT - 1) - gFade.count == y) + gFade.flag[y][x] = TRUE; + + break; + + case 3: + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if (gFade.count == y) + gFade.flag[y][x] = TRUE; + + break; + + case 4: + for (y = 0; y < (FADE_HEIGHT / 2); ++y) + for (x = 0; x < (FADE_WIDTH / 2); ++x) + if ((FADE_WIDTH - 1) - gFade.count == x + y) + gFade.flag[y][x] = TRUE; + + for (y = 0; y < (FADE_HEIGHT / 2); ++y) + for (x = (FADE_WIDTH / 2); x < FADE_WIDTH; ++x) + if ((FADE_WIDTH - 1) - gFade.count == y + ((FADE_WIDTH - 1) - x)) + gFade.flag[y][x] = TRUE; + + for (y = (FADE_HEIGHT / 2); y < FADE_HEIGHT; ++y) + for (x = 0; x < (FADE_WIDTH / 2); ++x) + if ((FADE_WIDTH - 1) - gFade.count == x + ((FADE_HEIGHT - 1) - y)) + gFade.flag[y][x] = TRUE; + + for (y = (FADE_HEIGHT / 2); y < FADE_HEIGHT; ++y) + for (x = (FADE_WIDTH / 2); x < FADE_WIDTH; ++x) + if ((FADE_WIDTH - 1) - gFade.count == ((FADE_WIDTH - 1) - x) + ((FADE_HEIGHT - 1) - y)) + gFade.flag[y][x] = TRUE; + + break; + } + + for (y = 0; y < FADE_HEIGHT; ++y) + for (x = 0; x < FADE_WIDTH; ++x) + if (gFade.ani_no[y][x] > 0 && gFade.flag[y][x]) + --gFade.ani_no[y][x]; + + if (++gFade.count > ((FADE_WIDTH > FADE_HEIGHT) ? FADE_WIDTH : FADE_HEIGHT) + 16) + gFade.mode = 0; + + break; + } +} + +void PutFade(void) +{ + int x, y; + + RECT rect; + rect.top = 0; + rect.bottom = 16; + + if (gFade.bMask) + { + CortBox(&grcGame, mask_color); + return; + } + + if (gFade.mode == 0) + return; + + for (y = 0; y < FADE_HEIGHT; ++y) + { + for (x = 0; x < FADE_WIDTH; ++x) + { + rect.left = gFade.ani_no[y][x] * 16; + rect.right = rect.left + 16; + PutBitmap3(&grcGame, x * 16, y * 16, &rect, SURFACE_ID_FADE); + } + } +} + +BOOL GetFadeActive(void) +{ + if (gFade.mode == 0) + return FALSE; + else + return TRUE; +} diff --git a/src/Fade.h b/src/Fade.h new file mode 100644 index 0000000..94d2a7c --- /dev/null +++ b/src/Fade.h @@ -0,0 +1,35 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "CommonDefines.h" +#include "WindowsWrapper.h" + +#define FADE_WIDTH (((WINDOW_WIDTH - 1) / 16) + 1) +#define FADE_HEIGHT (((WINDOW_HEIGHT - 1) / 16) + 1) + +struct FADE +{ + int mode; + BOOL bMask; + int count; + signed char ani_no[FADE_HEIGHT][FADE_WIDTH]; + signed char flag[FADE_HEIGHT][FADE_WIDTH]; // Not a BOOLEAN (those are unsigned) + signed char dir; +}; + +extern FADE gFade; + +void InitFade(void); +void SetFadeMask(void); +void ClearFade(void); +void StartFadeOut(signed char dir); +void StartFadeIn(signed char dir); +void ProcFade(void); +void PutFade(void); +BOOL GetFadeActive(void); diff --git a/src/Flags.cpp b/src/Flags.cpp new file mode 100644 index 0000000..49d48a3 --- /dev/null +++ b/src/Flags.cpp @@ -0,0 +1,70 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Flags.h" + +#include + +#include "WindowsWrapper.h" + +// Macros for setting, un-setting and getting flags +// Each flag is stored in a bit, so we can use the exact same macros we'd use for bits +#define SET_FLAG(x, i) ((x)[(i) / 8] |= 1 << ((i) % 8)) +#define UNSET_FLAG(x, i) ((x)[(i) / 8] &= ~(1 << ((i) % 8))) +#define GET_FLAG(x, i) ((x)[(i) / 8] & (1 << ((i) % 8))) + +unsigned char gFlagNPC[1000]; +unsigned char gSkipFlag[8]; + +// Flag initializers +void InitFlags(void) +{ + memset(gFlagNPC, 0, sizeof(gFlagNPC)); +} + +void InitSkipFlags(void) +{ + memset(gSkipFlag, 0, sizeof(gSkipFlag)); +} + +// NPC flags +void SetNPCFlag(long a) +{ + SET_FLAG(gFlagNPC, a); +} + +void CutNPCFlag(long a) +{ + UNSET_FLAG(gFlagNPC, a); +} + +BOOL GetNPCFlag(long a) +{ + if (GET_FLAG(gFlagNPC, a)) + return TRUE; + else + return FALSE; +} + +// Skip flags +void SetSkipFlag(long a) +{ + SET_FLAG(gSkipFlag, a); +} + +void CutSkipFlag(long a) +{ + UNSET_FLAG(gSkipFlag, a); +} + +BOOL GetSkipFlag(long a) +{ + if (GET_FLAG(gSkipFlag, a)) + return TRUE; + else + return FALSE; +} diff --git a/src/Flags.h b/src/Flags.h new file mode 100644 index 0000000..9b34d5e --- /dev/null +++ b/src/Flags.h @@ -0,0 +1,22 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +extern unsigned char gFlagNPC[1000]; +extern unsigned char gSkipFlag[8]; + +void InitFlags(void); +void InitSkipFlags(void); +void SetNPCFlag(long a); +void CutNPCFlag(long a); +BOOL GetNPCFlag(long a); +void SetSkipFlag(long a); +void CutSkipFlag(long a); +BOOL GetSkipFlag(long a); diff --git a/src/Flash.cpp b/src/Flash.cpp new file mode 100644 index 0000000..af56d9c --- /dev/null +++ b/src/Flash.cpp @@ -0,0 +1,177 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Flash.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "WindowsWrapper.h" + +static struct +{ + FlashMode mode; + int act_no; + BOOL flag; + int cnt; + int width; + int x; + int y; + RECT rect1; + RECT rect2; +} flash; + +unsigned long gFlashColor; + +void InitFlash(void) +{ + gFlashColor = GetCortBoxColor(RGB(0xFF, 0xFF, 0xFE)); +} + +void SetFlash(int x, int y, FlashMode mode) +{ + flash.act_no = 0; + flash.flag = TRUE; + flash.x = x; + flash.y = y; + flash.mode = mode; + flash.cnt = 0; + flash.width = 0; +} + +void ActFlash_Explosion(int flx, int fly) +{ + int left, top, right, bottom; + + switch (flash.act_no) + { + case 0: // Expand + flash.cnt += 0x200; + flash.width += flash.cnt; + + left = (flash.x - flx - flash.width) / 0x200; + top = (flash.y - fly - flash.width) / 0x200; + right = (flash.x - flx + flash.width) / 0x200; + bottom = (flash.y - fly + flash.width) / 0x200; + + if (left < 0) + left = 0; + if (top < 0) + top = 0; + if (right > WINDOW_WIDTH) + right = WINDOW_WIDTH; + if (bottom > WINDOW_HEIGHT) + bottom = WINDOW_HEIGHT; + + // The tall part of the explosion + flash.rect1.left = left; + flash.rect1.right = right; + flash.rect1.top = 0; + flash.rect1.bottom = WINDOW_HEIGHT; + + // The wide part of the explosion + flash.rect2.left = 0; + flash.rect2.right = WINDOW_WIDTH; + flash.rect2.top = top; + flash.rect2.bottom = bottom; + + if (flash.width > WINDOW_WIDTH * 0x200 * 4) // I guess in theory this means that the explosion would take longer in widescreen... + { + flash.act_no = 1; + flash.cnt = 0; + flash.width = WINDOW_HEIGHT * 0x200; + } + + break; + + case 1: // Shrink + flash.width -= flash.width / 8; + + if ((flash.width / 0x100) == 0) + flash.flag = FALSE; + + top = (flash.y - fly - flash.width) / 0x200; + if (top < 0) + top = 0; + + bottom = (flash.y - fly + flash.width) / 0x200; + if (bottom > WINDOW_HEIGHT) + bottom = WINDOW_HEIGHT; + + // The tall part of the explosion + flash.rect1.left = 0; + flash.rect1.right = 0; + flash.rect1.top = 0; + flash.rect1.bottom = 0; + + // The wide part of the explosion + flash.rect2.top = top; + flash.rect2.bottom = bottom; + flash.rect2.left = 0; + flash.rect2.right = WINDOW_WIDTH; + + break; + } +} + +void ActFlash_Flash(void) +{ + ++flash.cnt; + + flash.rect1.left = 0; + flash.rect1.right = 0; + flash.rect1.top = 0; + flash.rect1.bottom = 0; + + if (flash.cnt / 2 % 2) + { + flash.rect2.top = 0; + flash.rect2.bottom = WINDOW_HEIGHT; + flash.rect2.left = 0; + flash.rect2.right = WINDOW_WIDTH; + } + else + { + flash.rect2.left = 0; + flash.rect2.right = 0; + flash.rect2.top = 0; + flash.rect2.bottom = 0; + } + + if (flash.cnt > 20) + flash.flag = FALSE; +} + +void ActFlash(int flx, int fly) +{ + if (!flash.flag) + return; + + switch (flash.mode) + { + case FLASH_MODE_EXPLOSION: + ActFlash_Explosion(flx, fly); + break; + + case FLASH_MODE_FLASH: + ActFlash_Flash(); + break; + } +} + +void PutFlash(void) +{ + if (!flash.flag) + return; + + CortBox(&flash.rect1, gFlashColor); + CortBox(&flash.rect2, gFlashColor); +} + +void ResetFlash(void) +{ + flash.flag = FALSE; +} diff --git a/src/Flash.h b/src/Flash.h new file mode 100644 index 0000000..5af18d9 --- /dev/null +++ b/src/Flash.h @@ -0,0 +1,24 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +enum FlashMode +{ + FLASH_MODE_EXPLOSION = 1, + FLASH_MODE_FLASH = 2 +}; + +extern unsigned long gFlashColor; + +void InitFlash(void); +void SetFlash(int x, int y, FlashMode mode); +void ActFlash_Explosion(int flx, int fly); +void ActFlash_Flash(void); +void ActFlash(int flx, int fly); +void PutFlash(void); +void ResetFlash(void); diff --git a/src/Frame.cpp b/src/Frame.cpp new file mode 100644 index 0000000..0e3c3ea --- /dev/null +++ b/src/Frame.cpp @@ -0,0 +1,158 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Frame.h" + +#include "Boss.h" +#include "CommonDefines.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" + +FRAME gFrame; + +void MoveFrame3(void) +{ + short map_w, map_l; + GetMapData(0, &map_w, &map_l); + + gFrame.x += (*gFrame.tgt_x - (WINDOW_WIDTH * 0x200 / 2) - gFrame.x) / gFrame.wait; + gFrame.y += (*gFrame.tgt_y - (WINDOW_HEIGHT * 0x200 / 2) - gFrame.y) / gFrame.wait; + + if (gFrame.x / 0x200 < 0) + gFrame.x = 0; + if (gFrame.y / 0x200 < 0) + gFrame.y = 0; + + if (gFrame.x > (((map_w - 1) * 16) - WINDOW_WIDTH) * 0x200) + gFrame.x = (((map_w - 1) * 16) - WINDOW_WIDTH) * 0x200; + if (gFrame.y > (((map_l - 1) * 16) - WINDOW_HEIGHT) * 0x200) + gFrame.y = (((map_l - 1) * 16) - WINDOW_HEIGHT) * 0x200; + + // Quake + if (gFrame.quake2) + { + gFrame.x += (Random(-5, 5) * 0x200); + gFrame.y += (Random(-3, 3) * 0x200); + --gFrame.quake2; + } + else if (gFrame.quake) + { + gFrame.x += (Random(-1, 1) * 0x200); + gFrame.y += (Random(-1, 1) * 0x200); + --gFrame.quake; + } + + // This code exists in the Linux port (v1.0.0.4), but not the Windows version (v1.0.0.6) or the Mac port +/* if (gFrame.x / 0x200 < 0) + gFrame.x = 0; + if (gFrame.y / 0x200 < 0) + gFrame.y = 0;*/ +} + +void GetFramePosition(int *fx, int *fy) +{ + *fx = gFrame.x; + *fy = gFrame.y; +} + +void SetFramePosition(int fx, int fy) +{ + short map_w, map_l; + + // End quake + gFrame.quake = 0; + gFrame.quake2 = 0; + + // Move frame position + GetMapData(0, &map_w, &map_l); + + gFrame.x = fx; + gFrame.y = fy; + + // Keep in bounds + if (gFrame.x / 0x200 < 0) + gFrame.x = 0; + if (gFrame.y / 0x200 < 0) + gFrame.y = 0; + + if (gFrame.x > (((map_w - 1) * 16) - WINDOW_WIDTH) * 0x200) + gFrame.x = (((map_w - 1) * 16) - WINDOW_WIDTH) * 0x200; + if (gFrame.y > (((map_l - 1) * 16) - WINDOW_HEIGHT) * 0x200) + gFrame.y = (((map_l - 1) * 16) - WINDOW_HEIGHT) * 0x200; +} + +void SetFrameMyChar(void) +{ + int mc_x, mc_y; + short map_w, map_l; + + // Move frame position + GetMyCharPosition(&mc_x, &mc_y); + + GetMapData(0, &map_w, &map_l); + + gFrame.x = mc_x - ((WINDOW_WIDTH / 2) * 0x200); + gFrame.y = mc_y - ((WINDOW_HEIGHT / 2) * 0x200); + + // Keep in bounds + if (gFrame.x / 0x200 < 0) + gFrame.x = 0; + if (gFrame.y / 0x200 < 0) + gFrame.y = 0; + + if (gFrame.x > (((map_w - 1) * 16) - WINDOW_WIDTH) * 0x200) + gFrame.x = (((map_w - 1) * 16) - WINDOW_WIDTH) * 0x200; + if (gFrame.y > (((map_l - 1) * 16) - WINDOW_HEIGHT) * 0x200) + gFrame.y = (((map_l - 1) * 16) - WINDOW_HEIGHT) * 0x200; +} + +void SetFrameTargetMyChar(int wait) +{ + gFrame.tgt_x = &gMC.tgt_x; + gFrame.tgt_y = &gMC.tgt_y; + gFrame.wait = wait; +} + +void SetFrameTargetNpChar(int event, int wait) +{ + int i; + for (i = 0; i < NPC_MAX; ++i) + if (gNPC[i].code_event == event) + break; + + if (i == NPC_MAX) + return; + + gFrame.tgt_x = &gNPC[i].x; + gFrame.tgt_y = &gNPC[i].y; + gFrame.wait = wait; +} + +void SetFrameTargetBoss(int no, int wait) +{ + gFrame.tgt_x = &gBoss[no].x; + gFrame.tgt_y = &gBoss[no].y; + gFrame.wait = wait; +} + +void SetQuake(int time) +{ + gFrame.quake = time; +} + +void SetQuake2(int time) +{ + gFrame.quake2 = time; +} + +void ResetQuake(void) +{ + gFrame.quake = 0; + gFrame.quake2 = 0; +} diff --git a/src/Frame.h b/src/Frame.h new file mode 100644 index 0000000..c1f19f9 --- /dev/null +++ b/src/Frame.h @@ -0,0 +1,32 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +typedef struct FRAME +{ + int x; + int y; + int *tgt_x; + int *tgt_y; + int wait; + int quake; + int quake2; +} FRAME; + +extern FRAME gFrame; + +void MoveFrame3(void); +void GetFramePosition(int *fx, int *fy); +void SetFramePosition(int fx, int fy); +void SetFrameMyChar(void); +void SetFrameTargetMyChar(int wait); +void SetFrameTargetNpChar(int event, int wait); +void SetFrameTargetBoss(int no, int wait); +void SetQuake(int time); +void SetQuake2(int time); +void ResetQuake(void); diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 0000000..76c6eb2 --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,747 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Game.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "Back.h" +#include "Boss.h" +#include "BossLife.h" +#include "BulHit.h" +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Draw.h" +#include "Ending.h" +#include "Escape.h" +#include "Fade.h" +#include "Flags.h" +#include "Flash.h" +#include "Frame.h" +#include "Generic.h" +#include "GenericLoad.h" +#include "KeyControl.h" +#include "Main.h" +#include "Map.h" +#include "MapName.h" +#include "MiniMap.h" +#include "MyChar.h" +#include "MycHit.h" +#include "MycParam.h" +#include "NpChar.h" +#include "NpcHit.h" +#include "NpcTbl.h" +#include "Profile.h" +#include "SelStage.h" +#include "Shoot.h" +#include "Sound.h" +#include "Stage.h" +#include "Star.h" +#include "TextScr.h" +#include "ValueView.h" + +int g_GameFlags; +int gCounter; + +static BOOL bContinue; + +int Random(int min, int max) +{ + const int range = max - min + 1; + return (rand() % range) + min; +} + +void PutNumber4(int x, int y, int value, BOOL bZero) +{ + // Define rects + RECT rcClient = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + + RECT rect[10] = { + {0, 56, 8, 64}, + {8, 56, 16, 64}, + {16, 56, 24, 64}, + {24, 56, 32, 64}, + {32, 56, 40, 64}, + {40, 56, 48, 64}, + {48, 56, 56, 64}, + {56, 56, 64, 64}, + {64, 56, 72, 64}, + {72, 56, 80, 64}, + }; + + // Digits + int tbl[4] = {1000, 100, 10, 1}; + + int a; + int sw; + int offset; + + // Limit value + if (value > 9999) + value = 9999; + + // Go through number and draw digits + offset = 0; + sw = 0; + while (offset < 4) + { + // Get the digit that this is + a = 0; + + while (value >= tbl[offset]) + { + value -= tbl[offset]; + ++a; + ++sw; + } + + // Draw digit + if ((bZero && offset == 2) || sw != 0 || offset == 3) + PutBitmap3(&rcClient, x + 8 * offset, y, &rect[a], SURFACE_ID_TEXT_BOX); + + // Go to next digit + ++offset; + } +} + +static int ModeOpening(HWND hWnd) +{ + int frame_x; + int frame_y; + unsigned int wait; + + InitNpChar(); + InitCaret(); + InitStar(); + InitFade(); + InitFlash(); + InitBossLife(); + ChangeMusic(MUS_SILENCE); + TransferStage(72, 100, 3, 3); + SetFrameTargetMyChar(16); + SetFadeMask(); + + // Reset cliprect and flags + grcGame.left = 0; +#if WINDOW_WIDTH != 320 || WINDOW_HEIGHT != 240 + // Non-vanilla: these three lines are widescreen-related + grcGame.top = 0; + grcGame.right = WINDOW_WIDTH; + grcGame.bottom = WINDOW_HEIGHT; +#endif + + g_GameFlags = 3; + + CutNoise(); + + wait = 0; + while (wait < 500) + { + // Increase timer + ++wait; + + // Get pressed keys + GetTrg(); + + // Escape menu + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + } + + // Skip intro if OK is pressed + if (gKey & gKeyOk) + break; + + // Update everything + ActNpChar(); + ActBossChar(); + ActBack(); + ResetMyCharFlag(); + HitMyCharMap(); + HitMyCharNpChar(); + HitMyCharBoss(); + HitNpCharMap(); + HitBossMap(); + HitBossBullet(); + ActCaret(); + MoveFrame3(); + ProcFade(); + + // Draw everything + CortBox(&grcFull, 0x000000); + + GetFramePosition(&frame_x, &frame_y); + PutBack(frame_x, frame_y); + PutStage_Back(frame_x, frame_y); + PutBossChar(frame_x, frame_y); + PutNpChar(frame_x, frame_y); + PutMapDataVector(frame_x, frame_y); + PutStage_Front(frame_x, frame_y); + PutFront(frame_x, frame_y); + PutCaret(frame_x, frame_y); + PutFade(); + + // Update Text Script + switch (TextScriptProc()) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + + PutMapName(FALSE); + PutTextScript(); + PutFramePerSecound(); + + if (!Flip_SystemTask(ghWnd)) + return 0; + + ++gCounter; + } + + wait = GetTickCount(); + while (GetTickCount() < wait + 500) + { + CortBox(&grcGame, 0x000000); + PutFramePerSecound(); + if (!Flip_SystemTask(ghWnd)) + return 0; + } + return 2; +} + +static int ModeTitle(HWND hWnd) +{ + // Set rects + RECT rcTitle = {0, 0, 144, 40}; + RECT rcPixel = {0, 0, 160, 16}; + RECT rcNew = {144, 0, 192, 16}; + RECT rcContinue = {144, 16, 192, 32}; + + RECT rcVersion = {152, 80, 208, 88}; + RECT rcPeriod = {152, 88, 208, 96}; + + // Character rects + RECT rcMyChar[4] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {0, 16, 16, 32}, + {32, 16, 48, 32}, + }; + + RECT rcCurly[4] = { + {0, 112, 16, 128}, + {16, 112, 32, 128}, + {0, 112, 16, 128}, + {32, 112, 48, 128}, + }; + + RECT rcToroko[4] = { + {64, 80, 80, 96}, + {80, 80, 96, 96}, + {64, 80, 80, 96}, + {96, 80, 112, 96}, + }; + + RECT rcKing[4] = { + {224, 48, 240, 64}, + {288, 48, 304, 64}, + {224, 48, 240, 64}, + {304, 48, 320, 64}, + }; + + RECT rcSu[4] = { + {0, 16, 16, 32}, + {32, 16, 48, 32}, + {0, 16, 16, 32}, + {48, 16, 64, 32}, + }; + + unsigned int wait; + + int anime; + int v1, v2, v3, v4; + + RECT char_rc; + int char_type; + int time_counter; + int char_y; + SurfaceID char_surf; + unsigned long back_color; + + // Reset everything + InitCaret(); + InitStar(); + CutNoise(); + + // Create variables + anime = 0; + char_type = 0; + time_counter = 0; + back_color = GetCortBoxColor(RGB(0x20, 0x20, 0x20)); + + GetCompileVersion(&v1, &v2, &v3, &v4); + + // Set state + if (IsProfile()) + bContinue = TRUE; + else + bContinue = FALSE; + + // Set character + time_counter = LoadTimeCounter(); + + if (time_counter && time_counter < 6 * 60 * 50) // 6 minutes + char_type = 1; + if (time_counter && time_counter < 5 * 60 * 50) // 5 minutes + char_type = 2; + if (time_counter && time_counter < 4 * 60 * 50) // 4 minutes + char_type = 3; + if (time_counter && time_counter < 3 * 60 * 50) // 3 minutes + char_type = 4; + + // Set music to character's specific music + if (char_type == 1) + ChangeMusic(MUS_RUNNING_HELL); + else if (char_type == 2) + ChangeMusic(MUS_TOROKOS_THEME); + else if (char_type == 3) + ChangeMusic(MUS_WHITE); + else if (char_type == 4) + ChangeMusic(MUS_SAFETY); + else + ChangeMusic(MUS_CAVE_STORY); + + // Reset cliprect, flags, and give the player the Nikumaru counter + grcGame.left = 0; +#if WINDOW_WIDTH != 320 || WINDOW_HEIGHT != 240 + // Non-vanilla: these three lines are widescreen-related + grcGame.top = 0; + grcGame.right = WINDOW_WIDTH; + grcGame.bottom = WINDOW_HEIGHT; +#endif + + g_GameFlags = 0; + gMC.equip |= EQUIP_NIKUMARU_COUNTER; // Give the player the Nikumaru Counter so the timer appears on-screen + + // Start loop + wait = 0; + + while (1) + { + // Don't accept selection for 10 frames + if (wait < 10) + ++wait; + + // Get pressed keys + GetTrg(); + + // Quit when OK is pressed + if (wait >= 10) + { + if (gKeyTrg & gKeyOk) + { + PlaySoundObject(18, SOUND_MODE_PLAY); + break; + } + } + + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + } + + // Move cursor + if (gKeyTrg & (gKeyUp | gKeyDown)) + { + PlaySoundObject(1, SOUND_MODE_PLAY); + + if (bContinue) + bContinue = FALSE; + else + bContinue = TRUE; + } + + // Update carets + ActCaret(); + + // Animate character cursor + if (++anime >= 40) + anime = 0; + + // Draw title + CortBox(&grcGame, back_color); + + // Draw version + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 60, WINDOW_HEIGHT - 24, &rcVersion, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 4, WINDOW_HEIGHT - 24, &rcPeriod, SURFACE_ID_TEXT_BOX); + + PutNumber4((WINDOW_WIDTH / 2) - 20, WINDOW_HEIGHT - 24, v1, FALSE); + PutNumber4((WINDOW_WIDTH / 2) - 4, WINDOW_HEIGHT - 24, v2, FALSE); + PutNumber4((WINDOW_WIDTH / 2) + 12, WINDOW_HEIGHT - 24, v3, FALSE); + PutNumber4((WINDOW_WIDTH / 2) + 28, WINDOW_HEIGHT - 24, v4, FALSE); + + // Draw main title + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 72, 40, &rcTitle, SURFACE_ID_TITLE); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 24, (WINDOW_HEIGHT / 2) + 8, &rcNew, SURFACE_ID_TITLE); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 24, (WINDOW_HEIGHT / 2) + 28, &rcContinue, SURFACE_ID_TITLE); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 80, WINDOW_HEIGHT - 48, &rcPixel, SURFACE_ID_PIXEL); + + // Draw character cursor + switch (char_type) + { + case 0: + char_rc = rcMyChar[anime / 10 % 4]; + char_surf = SURFACE_ID_MY_CHAR; + break; + case 1: + char_rc = rcCurly[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + case 2: + char_rc = rcToroko[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + case 3: + char_rc = rcKing[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + case 4: + char_rc = rcSu[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + } + + if (!bContinue) + char_y = (WINDOW_HEIGHT / 2) + 7; + else + char_y = (WINDOW_HEIGHT / 2) + 27; + + // Pixel being redundant + if (!bContinue) + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 44, char_y, &char_rc, char_surf); + else + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 44, char_y, &char_rc, char_surf); + + // Draw carets + PutCaret(0, 0); + + if (time_counter) + PutTimeCounter(16, 8); + + PutFramePerSecound(); + + if (!Flip_SystemTask(ghWnd)) + return 0; + } + + ChangeMusic(MUS_SILENCE); + + // Black screen when option is selected + wait = GetTickCount(); + while (GetTickCount() < wait + 1000) + { + CortBox(&grcGame, 0); + PutFramePerSecound(); + if (!Flip_SystemTask(ghWnd)) + return 0; + } + + return 3; +} + +static int ModeAction(HWND hWnd) +{ + int frame_x; + int frame_y; + + unsigned int swPlay; + unsigned long color = GetCortBoxColor(RGB(0, 0, 0x20)); + + swPlay = 1; + + // Reset stuff + gCounter = 0; + grcGame.left = 0; +#if WINDOW_WIDTH != 320 || WINDOW_HEIGHT != 240 + // Non-vanilla: these three lines are widescreen-related + grcGame.top = 0; + grcGame.right = WINDOW_WIDTH; + grcGame.bottom = WINDOW_HEIGHT; +#endif + g_GameFlags = 3; + + // Initialize everything + InitMyChar(); + InitNpChar(); + InitBullet(); + InitCaret(); + InitStar(); + InitFade(); + InitFlash(); + ClearArmsData(); + ClearItemData(); + ClearPermitStage(); + StartMapping(); + InitFlags(); + InitBossLife(); + + if (bContinue) + { + if (!LoadProfile(NULL) && !InitializeGame(hWnd)) + return 0; + } + else + { + if (!InitializeGame(hWnd)) + return 0; + } + + while (1) + { + // Get pressed keys + GetTrg(); + + // Escape menu + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + } + + if (swPlay % 2 && g_GameFlags & 1) // The "swPlay % 2" part is always true + { + if (g_GameFlags & 2) + ActMyChar(TRUE); + else + ActMyChar(FALSE); + + ActStar(); + ActNpChar(); + ActBossChar(); + ActValueView(); + ActBack(); + ResetMyCharFlag(); + HitMyCharMap(); + HitMyCharNpChar(); + HitMyCharBoss(); + HitNpCharMap(); + HitBossMap(); + HitBulletMap(); + HitNpCharBullet(); + HitBossBullet(); + if (g_GameFlags & 2) + ShootBullet(); + ActBullet(); + ActCaret(); + MoveFrame3(); +#ifdef FIX_MAJOR_BUGS + // ActFlash uses frame_x and frame_y uninitialised + GetFramePosition(&frame_x, &frame_y); +#endif + ActFlash(frame_x, frame_y); + + if (g_GameFlags & 2) + AnimationMyChar(TRUE); + else + AnimationMyChar(FALSE); + } + + if (g_GameFlags & 8) + { + ActionCredit(); + ActionIllust(); + ActionStripper(); + } + + ProcFade(); + CortBox(&grcFull, color); + GetFramePosition(&frame_x, &frame_y); + PutBack(frame_x, frame_y); + PutStage_Back(frame_x, frame_y); + PutBossChar(frame_x, frame_y); + PutNpChar(frame_x, frame_y); + PutBullet(frame_x, frame_y); + PutMyChar(frame_x, frame_y); + PutStar(frame_x, frame_y); + PutMapDataVector(frame_x, frame_y); + PutStage_Front(frame_x, frame_y); + PutFront(frame_x, frame_y); + PutFlash(); + PutCaret(frame_x, frame_y); + PutValueView(frame_x, frame_y); + PutBossLife(); + PutFade(); + + if (!(g_GameFlags & 4)) + { + // Open inventory + if (gKeyTrg & gKeyItem) + { + BackupSurface(SURFACE_ID_SCREEN_GRAB, &grcGame); + + switch (CampLoop()) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + + gMC.cond &= ~1; + } + else if (gMC.equip & EQUIP_MAP && gKeyTrg & gKeyMap) + { + BackupSurface(SURFACE_ID_SCREEN_GRAB, &grcGame); + + switch (MiniMapLoop()) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + } + } + + if (g_GameFlags & 2) + { + if (gKeyTrg & gKeyArms) + RotationArms(); + else if (gKeyTrg & gKeyArmsRev) + RotationArmsRev(); + } + + if (swPlay % 2) // This is always true + { + switch (TextScriptProc()) + { + case enum_ESCRETURN_exit: + return 0; + + case enum_ESCRETURN_restart: + return 1; + } + } + + PutMapName(FALSE); + PutTimeCounter(16, 8); + + if (g_GameFlags & 2) + { + PutMyLife(TRUE); + PutArmsEnergy(TRUE); + PutMyAir((WINDOW_WIDTH / 2) - 40, (WINDOW_HEIGHT / 2) - 16); + PutActiveArmsList(); + } + + if (g_GameFlags & 8) + { + PutIllust(); + PutStripper(); + } + + PutTextScript(); + + PutFramePerSecound(); + + if (!Flip_SystemTask(ghWnd)) + return 0; + + ++gCounter; + } + + return 0; +} + +BOOL Game(HWND hWnd) +{ + int mode; + + if (!LoadGenericData()) + { + #if !defined(JAPANESE) && defined(FIX_BUGS) // The Aeon Genesis translation didn't translate this + MessageBoxA(hWnd, "Couldn't read general purpose files", "Error", MB_OK); + #else + MessageBoxA(hWnd, "\x94\xC4\x97\x70\x83\x74\x83\x40\x83\x43\x83\x8B\x82\xAA\x93\xC7\x82\xDF\x82\xC8\x82\xA2", "\x83\x47\x83\x89\x81\x5B", MB_OK); /* '汎用ファイルが読めない' and 'エラー' in Shift-JIS */ + #endif + return FALSE; + } + + PlaySoundObject(7, SOUND_MODE_PLAY_LOOP); + + char path[MAX_PATH]; + sprintf(path, "%s\\npc.tbl", gDataPath); + + if (!LoadNpcTable(path)) + { + #if !defined(JAPANESE) && defined(FIX_BUGS) // The Aeon Genesis translation didn't translate this + MessageBoxA(hWnd, "Couldn't read the NPC table", "Error", MB_OK); + #else + MessageBoxA(hWnd, "\x4E\x50\x43\x83\x65\x81\x5B\x83\x75\x83\x8B\x82\xAA\x93\xC7\x82\xDF\x82\xC8\x82\xA2", "\x83\x47\x83\x89\x81\x5B", MB_OK); /* 'NPCテーブルが読めない' and 'エラー' in Shift-JIS */ + #endif + return FALSE; + } + + InitTextScript2(); + InitSkipFlags(); + InitMapData2(); + InitCreditScript(); + + mode = 1; + while (mode) + { + if (mode == 1) + mode = ModeOpening(hWnd); + if (mode == 2) + mode = ModeTitle(hWnd); + if (mode == 3) + mode = ModeAction(hWnd); + } + + PlaySoundObject(7, SOUND_MODE_STOP); + + EndMapData(); + EndTextScript(); + ReleaseNpcTable(); + ReleaseCreditScript(); + + if (!bFullscreen) + SaveWindowRect(hWnd, "window.rect"); + + return TRUE; +} diff --git a/src/Game.h b/src/Game.h new file mode 100644 index 0000000..519a57d --- /dev/null +++ b/src/Game.h @@ -0,0 +1,42 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +enum GameFlagsValues +{ + // To be continued + + /** + * While this bit is NOT set, the game will : + * - Disable manual movement of the character + * - Disable shooting bullets + * - Disable shooting Curly's nemesis + * - Disable changing weapons + * - Disable speeding up the display of text in TSC scripts + * - Disable damage of the character + * - Not display the HUD (Life, EXP, air, weapons) + * - Disable animation of the character + * - Disable movement of the inventory cursor + * - Disable getting out of the inventory while on the item section + * - Create a bullet if some other conditions are fullfilled while iterating over the stars in ActStar (If you have any idea of how that actually works, you may + * want to replace this line with a better explanation) + */ + GAME_FLAG_IS_CONTROL_ENABLED = 2 + + // To be continued +}; + +extern int g_GameFlags; +extern int gCounter; + +int Random(int min, int max); +void PutNumber4(int x, int y, int value, BOOL bZero); + +BOOL Game(HWND hWnd); diff --git a/src/Generic.cpp b/src/Generic.cpp new file mode 100644 index 0000000..2df2e03 --- /dev/null +++ b/src/Generic.cpp @@ -0,0 +1,449 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Generic.h" + +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "Main.h" + +void GetCompileDate(int *year, int *month, int *day) +{ + int i; + char strMonth[0x10]; + + const char *table[13] = { + "XXX", + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + }; + + sscanf(__DATE__, "%s %d %d", strMonth, day, year); // The expansion of __DATE__ is not reproductible. TODO : Think about changing this to be reproductible + + for (i = 0; i < 12; ++i) // This being 12 instead of 13 might be a bug, but it works anyway by accident + if (!memcmp(&strMonth, table[i], 3)) + break; + + *month = i; +} + +// TODO - Inaccurate stack frame +BOOL GetCompileVersion(int *v1, int *v2, int *v3, int *v4) +{ + unsigned int puLen; + VS_FIXEDFILEINFO *lpBuffer; + DWORD dwHandle; + DWORD dwLen; + char path[MAX_PATH]; + LPVOID lpData; + BOOL bResult; + + lpData = NULL; + bResult = FALSE; + + GetModuleFileNameA(NULL, path, sizeof(path)); + dwLen = GetFileVersionInfoSizeA(path, &dwHandle); + + if (dwLen == 0) + goto fail; + + lpData = malloc(dwLen); + + if (lpData == NULL) + goto fail; + + if (!GetFileVersionInfoA(path, 0, dwLen, lpData)) + goto fail; + + if (!VerQueryValueA(lpData, "\\", (LPVOID*)&lpBuffer, &puLen)) + goto fail; + + *v1 = (unsigned short)(lpBuffer->dwFileVersionMS >> 16); + *v2 = (unsigned short)(lpBuffer->dwFileVersionMS & 0xFFFF); + *v3 = (unsigned short)(lpBuffer->dwFileVersionLS >> 16); + *v4 = (unsigned short)(lpBuffer->dwFileVersionLS & 0xFFFF); + bResult = TRUE; + +fail: + + if (lpData != NULL) + free(lpData); + + return bResult; +} + +// This seems to be broken in recent Windows (Sndvol32.exe was renamed 'SndVol.exe') +// TODO - Inaccurate stack frame +BOOL OpenSoundVolume(HWND hWnd) +{ +#ifdef FIX_BUGS + char path[MAX_PATH]; + char path2[MAX_PATH]; + char path3[MAX_PATH]; + INT_PTR error; + size_t i; + + GetSystemDirectoryA(path, sizeof(path)); + GetSystemDirectoryA(path2, sizeof(path2)); + + i = strlen(path2); + while (path2[i] != '\\') + --i; + + path2[i] = '\0'; + + sprintf(path3, "%s\\Sndvol32.exe", path); + error = (INT_PTR)ShellExecuteA(hWnd, "open", path3, NULL, NULL, SW_SHOW); + if (error > 32) + return TRUE; + + sprintf(path3, "%s\\Sndvol32.exe", path2); + error = (INT_PTR)ShellExecuteA(hWnd, "open", path3, NULL, NULL, SW_SHOW); + if (error > 32) + return TRUE; + + sprintf(path3, "%s\\Sndvol.exe", path); + error = (INT_PTR)ShellExecuteA(hWnd, "open", path3, NULL, NULL, SW_SHOW); + if (error > 32) + return TRUE; + + sprintf(path3, "%s\\Sndvol.exe", path2); + error = (INT_PTR)ShellExecuteA(hWnd, "open", path3, NULL, NULL, SW_SHOW); + if (error > 32) + return TRUE; + + return FALSE; +#else + char path[MAX_PATH]; + char path2[MAX_PATH]; + char path3[MAX_PATH]; + INT_PTR error1; + INT_PTR error2; + size_t i; + + GetSystemDirectoryA(path, sizeof(path)); + sprintf(path2, "%s\\Sndvol32.exe", path); + + i = strlen(path); + while (path[i] != '\\') + --i; + + path[i] = '\0'; + sprintf(path3, "%s\\Sndvol32.exe", path); + + error1 = (INT_PTR)ShellExecuteA(hWnd, "open", path2, NULL, NULL, SW_SHOW); + error2 = (INT_PTR)ShellExecuteA(hWnd, "open", path3, NULL, NULL, SW_SHOW); + + if (error1 <= 32 && error2 <= 32) + return FALSE; + else + return TRUE; +#endif +} + +void DeleteLog(void) +{ + char path[MAX_PATH]; + + sprintf(path, "%s\\debug.txt", gModulePath); + DeleteFileA(path); +} + +BOOL WriteLog(const char *string, int value1, int value2, int value3) +{ + char path[MAX_PATH]; + FILE *fp; + + sprintf(path, "%s\\debug.txt", gModulePath); + fp = fopen(path, "a+t"); + + if (fp == NULL) + return FALSE; + + fprintf(fp, "%s,%d,%d,%d\n", string, value1, value2, value3); + fclose(fp); + return TRUE; +} + +/* +This function is a mystery. It seems to check if the system time is within +a certain range, specified by the two parameters. Nothing in the original game +uses this code. + +This is just speculation, but this *might* have been used in those prototypes +Pixel released to testers, to prevent them from running after a certain date. +*/ +int GetDateLimit(SYSTEMTIME *system_time_low, SYSTEMTIME *system_time_high) +{ + FILETIME FileTime1; + FILETIME FileTime2; + SYSTEMTIME SystemTime; + + GetSystemTime(&SystemTime); + SystemTimeToFileTime(&SystemTime, &FileTime1); + SystemTimeToFileTime(system_time_low, &FileTime2); + + if (CompareFileTime(&FileTime2, &FileTime1) >= 0) + return -1; // Return if actual time is lower than system_time_low + + SystemTimeToFileTime(system_time_high, &FileTime2); + + if (CompareFileTime(&FileTime2, &FileTime1) <= 0) + return 1; // Return if actual time is higher than system_time_high + + return 0; +} + +BOOL IsKeyFile(const char *name) +{ + char path[MAX_PATH]; + FILE *fp; + + sprintf(path, "%s\\%s", gModulePath, name); + + fp = fopen(path, "rb"); + + if (fp == NULL) + return FALSE; + + fclose(fp); + return TRUE; +} + +long GetFileSizeLong(const char *path) +{ + DWORD len; + HANDLE hFile; + + len = 0; + + hFile = CreateFileA(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return INVALID_FILE_SIZE; + + len = GetFileSize(hFile, NULL); + CloseHandle(hFile); + return len; +} + +BOOL ErrorLog(const char *string, int value) +{ + char path[MAX_PATH]; + FILE *fp; + + sprintf(path, "%s\\%s", gModulePath, "error.log"); + + if (GetFileSizeLong(path) > 0x19000) // Purge the error log if it gets too big, I guess + DeleteFileA(path); + + fp = fopen(path, "a+t"); + if (fp == NULL) + return FALSE; + + fprintf(fp, "%s,%d\n", string, value); + fclose(fp); + return TRUE; +} + +BOOL IsShiftJIS(unsigned char c) +{ + if (c >= 0x81 && c <= 0x9F) + return TRUE; + + if (c >= 0xE0 && c <= 0xEF) + return TRUE; + + return FALSE; +} + +// TODO - Inaccurate stack frame +BOOL CenteringWindowByParent(HWND hWnd) +{ + RECT window_rect; + HWND parent_hwnd; + RECT parent_rect; + int x; + int y; + RECT child_rect; + + SystemParametersInfoA(SPI_GETWORKAREA, 0, &child_rect, 0); + + GetWindowRect(hWnd, &window_rect); + + parent_hwnd = GetParent(hWnd); + if (parent_hwnd != NULL) + GetWindowRect(parent_hwnd, &parent_rect); + else + SystemParametersInfoA(SPI_GETWORKAREA, 0, &parent_rect, 0); + + x = parent_rect.left + ((parent_rect.right - parent_rect.left) - (window_rect.right - window_rect.left)) / 2; + y = parent_rect.top + ((parent_rect.bottom - parent_rect.top) - (window_rect.bottom - window_rect.top)) / 2; + + if (x < child_rect.left) + x = child_rect.left; + + if (y < child_rect.top) + y = child_rect.top; + + if (x + (window_rect.right - window_rect.left) > child_rect.right) + x = child_rect.right - (window_rect.right - window_rect.left); + + if (y + (window_rect.bottom - window_rect.top) > child_rect.bottom) + y = child_rect.bottom - (window_rect.bottom - window_rect.top); + + return SetWindowPos(hWnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); +} + +// TODO - Inaccurate stack frame +BOOL LoadWindowRect(HWND hWnd, const char *filename, BOOL unknown) +{ + char path[MAX_PATH]; + int min_window_width; + int min_window_height; + int max_window_width; + int max_window_height; + FILE *fp; + RECT Rect; + int showCmd; + RECT pvParam; + + showCmd = SW_SHOWNORMAL; + + sprintf(path, "%s\\%s", gModulePath, filename); + + fp = fopen(path, "rb"); + if (fp != NULL) + { + fread(&Rect, sizeof(RECT), 1, fp); + fread(&showCmd, sizeof(int), 1, fp); + fclose(fp); + + SystemParametersInfoA(SPI_GETWORKAREA, 0, &pvParam, 0); + + max_window_width = GetSystemMetrics(SM_CXMAXIMIZED); + max_window_height = GetSystemMetrics(SM_CYMAXIMIZED); + min_window_width = GetSystemMetrics(SM_CXMIN); + min_window_height = GetSystemMetrics(SM_CYMIN); + + if (Rect.right - Rect.left < min_window_width) + Rect.right = Rect.left + min_window_width; + if (Rect.bottom - Rect.top < min_window_height) + Rect.bottom = Rect.top + min_window_height; + if (Rect.right - Rect.left > max_window_width) + Rect.right = Rect.left + max_window_width; + if (Rect.bottom - Rect.top > max_window_height) + Rect.bottom = Rect.top + max_window_width; + + if (Rect.left < pvParam.left) + { + Rect.right += pvParam.left - Rect.left; + Rect.left = pvParam.left; + } + if (Rect.top < pvParam.top) + { + Rect.bottom += pvParam.top - Rect.top; + Rect.top = pvParam.top; + } + if (Rect.right > pvParam.right) + { + Rect.left -= Rect.right - pvParam.right; + Rect.right -= Rect.right - pvParam.right; + } + if (Rect.bottom > pvParam.bottom) + { + Rect.top -= Rect.bottom - pvParam.bottom; + Rect.bottom -= Rect.bottom - pvParam.bottom; + } + + if (unknown) + MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, 0); + else + SetWindowPos(hWnd, HWND_TOP, Rect.left, Rect.top, 0, 0, SWP_NOSIZE); + } + + if (showCmd == SW_MAXIMIZE) + { + if (!ShowWindow(hWnd, SW_MAXIMIZE)) + return FALSE; + } + else + { + ShowWindow(hWnd, SW_SHOWNORMAL); + } + + return TRUE; +} + +BOOL SaveWindowRect(HWND hWnd, const char *filename) +{ + char path[MAX_PATH]; + WINDOWPLACEMENT wndpl; + FILE *fp; + RECT rect; + + if (!GetWindowPlacement(hWnd, &wndpl)) + return FALSE; + + if (wndpl.showCmd == SW_SHOWNORMAL) + { + if (!GetWindowRect(hWnd, &rect)) + return FALSE; + + wndpl.rcNormalPosition = rect; + } + + sprintf(path, "%s\\%s", gModulePath, filename); + + fp = fopen(path, "wb"); + if (fp == NULL) + return FALSE; + + fwrite(&wndpl.rcNormalPosition, sizeof(RECT), 1, fp); + fwrite(&wndpl.showCmd, sizeof(int), 1, fp); + fclose(fp); + + return TRUE; +} + +static const char* const extra_text = "(C)Pixel"; + +BOOL IsEnableBitmap(const char *path) +{ + FILE *fp; + long len; + char str[16]; + + len = (long)strlen(extra_text); + + fp = fopen(path, "rb"); + + if (fp == NULL) + return FALSE; + + fseek(fp, len * -1, SEEK_END); + fread(str, 1, len, fp); + fclose(fp); + + if (memcmp(str, extra_text, len)) + return FALSE; + + return TRUE; +} diff --git a/src/Generic.h b/src/Generic.h new file mode 100644 index 0000000..8a181e4 --- /dev/null +++ b/src/Generic.h @@ -0,0 +1,25 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +void GetCompileDate(int *year, int *month, int *day); +BOOL GetCompileVersion(int *v1, int *v2, int *v3, int *v4); +BOOL OpenSoundVolume(HWND hWnd); +void DebugLog(void); +BOOL WriteLog(const char *string, int value1, int value2, int value3); +int GetDateLimit(SYSTEMTIME *system_time_low, SYSTEMTIME *system_time_high); +BOOL IsKeyFile(const char *name); +long GetFileSizeLong(const char *path); +BOOL ErrorLog(const char *string, int value); +BOOL IsShiftJIS(unsigned char c); +BOOL CenteringWindowByParent(HWND hWnd); +BOOL LoadWindowRect(HWND hWnd, const char *filename, BOOL unknown); +BOOL SaveWindowRect(HWND hWnd, const char *filename); +BOOL IsEnableBitmap(const char *path); diff --git a/src/GenericLoad.cpp b/src/GenericLoad.cpp new file mode 100644 index 0000000..b3ba189 --- /dev/null +++ b/src/GenericLoad.cpp @@ -0,0 +1,309 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "GenericLoad.h" + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Ending.h" +#include "PixTone.h" +#include "Sound.h" + +const PIXTONEPARAMETER gPtpTable[139] = +{ + {1, 5000, {5, 10.0, 32, 0}, {4, 4.0, 32, 0}, {0, 0.0, 63, 0}, 63, 6, 63, 45, 8, 119, 46}, + {1, 1000, {0, 4.0, 32, 0}, {3, 1.0, 63, 0}, {0, 0.0, 63, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 10000, {0, 30.0, 32, 0}, {3, 1.0, 32, 0}, {0, 0.0, 63, 0}, 0, 19, 44, 111, 13, 198, 9}, + {1, 10000, {5, 2.0, 31, 0}, {3, 1.0, 57, 219}, {0, 2.0, 32, 0}, 0, 19, 44, 111, 13, 198, 9}, + {1, 4000, {5, 0.4, 32, 0}, {3, 1.0, 53, 0}, {0, 0.0, 63, 0}, 12, 19, 63, 111, 21, 198, 18}, + {1, 1000, {1, 12.0, 32, 0}, {2, 1.0, 63, 0}, {0, 0.0, 63, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 1000, {5, 1.0, 32, 0}, {3, 1.0, 63, 0}, {0, 0.0, 63, 0}, 0, 28, 63, 53, 31, 210, 31}, + {1, 1000, {1, 5.0, 32, 0}, {3, 1.0, 63, 0}, {0, 0.0, 0, 0}, 63, 64, 63, 128, 31, 255, 0}, + {1, 3000, {1, 17.0, 34, 0}, {3, 2.0, 40, 0}, {4, 1.0, 31, 0}, 63, 64, 63, 225, 63, 255, 0}, + {1, 6000, {1, 930.0, 22, 0}, {0, 0.7, 53, 0}, {0, 7.0, 32, 0}, 63, 64, 63, 202, 63, 255, 0}, + {1, 6000, {1, 918.0, 23, 0}, {0, 0.7, 53, 0}, {0, 7.0, 32, 0}, 63, 64, 63, 202, 63, 255, 0}, + {1, 10000, {2, 200.0, 32, 0}, {0, 1.0, 51, 0}, {1, 20.0, 31, 0}, 63, 64, 63, 89, 30, 208, 28}, + {1, 10000, {5, 23.0, 16, 0}, {0, 1.0, 58, 0}, {1, 17.0, 32, 0}, 63, 64, 63, 96, 51, 202, 31}, + {1, 20000, {2, 100.0, 21, 0}, {0, 1.0, 46, 0}, {1, 40.0, 32, 0}, 63, 64, 63, 128, 63, 162, 0}, + {1, 20000, {5, 5.0, 21, 0}, {0, 1.0, 51, 0}, {1, 40.0, 32, 0}, 63, 64, 63, 128, 63, 162, 28}, + {1, 10000, {5, 20.0, 23, 0}, {3, 0.7, 26, 235}, {5, 1.0, 9, 0}, 63, 38, 55, 87, 32, 98, 29}, + {1, 2000, {1, 20.0, 32, 0}, {3, 2.0, 63, 0}, {4, 1.0, 29, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 15000, {5, 10.0, 32, 0}, {3, 0.7, 26, 235}, {0, 0.0, 63, 0}, 63, 38, 55, 187, 15, 255, 0}, + {1, 4000, {1, 20.0, 32, 0}, {3, 2.0, 63, 0}, {4, 1.0, 29, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 22000, {5, 6.0, 32, 0}, {3, 0.7, 26, 246}, {0, 0.0, 63, 0}, 63, 38, 55, 187, 15, 255, 0}, + {1, 8000, {0, 20.0, 32, 0}, {3, 2.0, 63, 0}, {4, 1.0, 29, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 10000, {4, 400.0, 13, 0}, {0, 0.8, 63, 0}, {4, 8.0, 31, 0}, 63, 64, 63, 191, 32, 255, 0}, + {1, 10000, {4, 800.0, 14, 0}, {0, 0.8, 63, 0}, {4, 8.0, 30, 125}, 63, 64, 63, 128, 63, 166, 0}, + {1, 5000, {2, 50.0, 39, 0}, {3, 0.5, 40, 217}, {1, 0.0, 32, 0}, 63, 64, 63, 128, 34, 198, 32}, + {1, 5000, {5, 10.0, 39, 0}, {3, 0.5, 24, 217}, {1, 4.0, 32, 0}, 0, 4, 63, 128, 34, 198, 32}, + {1, 40000, {5, 10.0, 32, 0}, {3, 1.0, 32, 241}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 40000, {5, 20.0, 32, 0}, {0, 0.0, 32, 0}, {5, 0.1, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 30000, {2, 400.0, 32, 0}, {3, 0.3, 60, 250}, {0, 20.0, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 10000, {4, 400.0, 13, 0}, {0, 0.8, 63, 0}, {4, 8.0, 50, 0}, 63, 64, 63, 191, 32, 255, 0}, + {1, 10000, {4, 800.0, 5, 0}, {0, 0.8, 63, 0}, {4, 8.0, 63, 125}, 63, 64, 63, 128, 63, 166, 0}, + {1, 6000, {3, 123.0, 32, 0}, {4, 1.0, 16, 222}, {4, 4.0, 37, 0}, 0, 6, 63, 104, 25, 255, 0}, + {1, 4000, {5, 4.5, 32, 0}, {3, 1.0, 46, 102}, {3, 2.5, 47, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 5000, {4, 40.0, 52, 0}, {2, 1.0, 63, 0}, {3, 10.0, 63, 0}, 63, 47, 27, 47, 29, 255, 0}, + {1, 3000, {0, 99.0, 32, 0}, {2, 1.0, 55, 197}, {5, 0.0, 0, 0}, 63, 0, 63, 164, 28, 255, 0}, + {1, 10000, {1, 601.0, 32, 0}, {4, 0.5, 15, 235}, {0, 10.0, 54, 0}, 63, 0, 63, 0, 63, 255, 0}, + {1, 8000, {5, 10.0, 15, 0}, {4, 0.5, 16, 239}, {4, 0.0, 50, 0}, 63, 0, 63, 96, 17, 255, 0}, + {1, 20000, {1, 832.0, 32, 0}, {2, 1.0, 46, 0}, {0, 27.0, 63, 0}, 63, 0, 63, 140, 10, 255, 0}, + {1, 20000, {1, 918.0, 32, 0}, {2, 1.0, 46, 0}, {0, 21.0, 63, 0}, 63, 0, 63, 140, 10, 255, 0}, + {1, 4000, {1, 54.0, 32, 0}, {5, 0.1, 33, 0}, {0, 0.0, 32, 0}, 53, 57, 44, 128, 24, 255, 0}, + {1, 10000, {1, 246.0, 23, 0}, {4, 0.6, 22, 239}, {4, 6.0, 63, 0}, 0, 11, 63, 13, 63, 255, 0}, + {1, 10000, {1, 294.0, 23, 0}, {4, 0.6, 22, 247}, {4, 6.0, 63, 140}, 0, 15, 63, 17, 63, 255, 0}, + {1, 22050, {0, 117.0, 63, 0}, {5, 2.0, 18, 0}, {5, 0.0, 0, 0}, 63, 0, 63, 64, 19, 255, 0}, + {1, 5000, {0, 28.0, 32, 0}, {3, 3.0, 27, 0}, {5, 0.0, 0, 0}, 63, 0, 63, 0, 63, 255, 0}, + {1, 10000, {0, 322.0, 32, 0}, {2, 8.0, 37, 0}, {2, 0.0, 0, 0}, 0, 13, 63, 106, 11, 255, 0}, + {1, 10000, {5, 7.3, 32, 0}, {5, 0.2, 29, 0}, {0, 0.0, 32, 0}, 63, 91, 63, 149, 25, 255, 0}, + {1, 1000, {0, 6.0, 32, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 20000, {2, 186.0, 32, 0}, {0, 4.0, 13, 98}, {3, 4.0, 5, 0}, 63, 64, 28, 255, 0, 255, 0}, + {1, 20000, {2, 285.0, 19, 0}, {3, 4.0, 21, 0}, {3, 4.0, 33, 130}, 63, 64, 63, 255, 0, 255, 0}, + {1, 10000, {0, 970.0, 32, 0}, {2, 1.0, 35, 195}, {0, 31.0, 31, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 20000, {5, 6.0, 32, 0}, {3, 1.0, 54, 239}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 35}, + {1, 40000, {5, 4.0, 32, 0}, {3, 0.0, 32, 230}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 40000, {1, 238.0, 32, 0}, {3, 1.0, 14, 0}, {4, 30.0, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 3000, {2, 62.0, 32, 0}, {2, 3.0, 63, 0}, {3, 3.0, 14, 0}, 63, 0, 63, 210, 32, 255, 0}, + {1, 5000, {2, 58.0, 32, 0}, {2, 3.0, 63, 0}, {2, 3.0, 32, 0}, 63, 0, 63, 49, 27, 255, 0}, + {1, 3000, {0, 13.0, 24, 0}, {3, 2.0, 40, 0}, {4, 1.0, 31, 0}, 63, 64, 63, 225, 63, 255, 0}, + {1, 3000, {5, 6.0, 32, 0}, {5, 1.0, 32, 0}, {3, 0.0, 0, 0}, 0, 0, 63, 45, 23, 255, 0}, + {1, 20000, {1, 477.0, 40, 0}, {5, 93.0, 39, 0}, {4, 17.0, 19, 0}, 0, 64, 63, 128, 63, 255, 0}, + {1, 6000, {5, 11.0, 32, 0}, {5, 1.0, 32, 0}, {3, 3.0, 32, 0}, 63, 0, 63, 0, 63, 255, 0}, + {1, 6000, {1, 329.0, 20, 0}, {2, 2.0, 47, 77}, {3, 3.0, 63, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 8000, {4, 2000.0, 32, 0}, {2, 1.0, 0, 0}, {0, 0.0, 32, 0}, 43, 21, 7, 255, 0, 255, 0}, + {1, 5000, {1, 231.0, 32, 0}, {4, 1.0, 32, 65}, {3, 2.0, 32, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 3000, {0, 107.0, 32, 0}, {4, 1.0, 15, 0}, {0, 0.0, 17, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 20000, {5, 4.0, 32, 0}, {5, 1.0, 32, 170}, {5, 0.0, 32, 0}, 63, 38, 22, 255, 0, 255, 0}, + {1, 5000, {1, 16.0, 32, 0}, {3, 1.0, 32, 238}, {0, 0.0, 0, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 20000, {5, 4.0, 32, 0}, {0, 0.7, 61, 43}, {3, 1.0, 22, 224}, 63, 64, 63, 204, 46, 255, 0}, + {1, 5000, {0, 880.0, 19, 0}, {0, 0.0, 32, 0}, {0, 8.0, 32, 0}, 0, 11, 63, 34, 25, 255, 0}, + {1, 2000, {5, 3.0, 16, 0}, {3, 2.0, 12, 0}, {3, 1.0, 37, 0}, 0, 51, 63, 132, 24, 255, 0}, + {1, 22050, {1, 400.0, 32, 0}, {0, 20.0, 10, 0}, {3, 10.0, 8, 0}, 0, 6, 63, 60, 21, 255, 0}, + {1, 2000, {5, 2.0, 32, 0}, {2, 3.0, 54, 0}, {0, 0.0, 32, 0}, 0, 17, 63, 98, 22, 255, 0}, + {1, 8000, {1, 814.0, 32, 0}, {2, 11.0, 32, 0}, {3, 16.0, 32, 0}, 63, 23, 63, 74, 12, 255, 0}, + {1, 10000, {5, 21.0, 21, 0}, {0, 5.0, 32, 178}, {0, 3.0, 33, 181}, 63, 38, 63, 104, 20, 255, 0}, + {1, 6000, {5, 1.0, 28, 0}, {3, 6.0, 56, 0}, {0, 8.0, 32, 0}, 63, 57, 63, 98, 20, 255, 0}, + {1, 4000, {5, 6.0, 32, 0}, {3, 2.0, 32, 0}, {3, 2.0, 32, 0}, 63, 26, 30, 66, 29, 255, 0}, + {1, 22050, {5, 711.0, 32, 0}, {5, 7.0, 32, 0}, {0, 0.0, 32, 0}, 0, 13, 0, 17, 63, 255, 0}, + {1, 2000, {5, 2.0, 32, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 62050, {5, 40.0, 32, 0}, {5, 1.0, 32, 0}, {5, 0.0, 0, 0}, 0, 17, 63, 36, 63, 255, 0}, + {1, 8000, {0, 77.0, 32, 0}, {3, 3.0, 56, 189}, {0, 0.0, 17, 0}, 0, 38, 63, 140, 28, 255, 0}, + {1, 8000, {5, 8.0, 32, 0}, {3, 3.0, 54, 189}, {3, 3.0, 32, 0}, 63, 38, 42, 140, 21, 255, 0}, + {1, 9050, {5, 9.0, 26, 0}, {0, 1.0, 32, 209}, {0, 0.0, 32, 0}, 63, 64, 63, 132, 63, 255, 0}, + {1, 9050, {2, 43.0, 32, 0}, {3, 1.0, 47, 172}, {0, 0.0, 32, 0}, 63, 64, 63, 198, 63, 255, 0}, + {1, 22050, {1, 754.0, 32, 0}, {2, 0.5, 14, 126}, {4, 18.0, 17, 0}, 0, 64, 63, 128, 63, 255, 0}, + {1, 22050, {0, 597.0, 12, 0}, {2, 0.5, 14, 126}, {4, 18.0, 17, 0}, 0, 64, 40, 128, 41, 255, 0}, + {1, 6000, {2, 217.0, 32, 0}, {0, 0.7, 16, 0}, {3, 0.0, 32, 0}, 0, 32, 63, 49, 15, 255, 0}, + {1, 5000, {5, 1.0, 32, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 0, 64, 63, 81, 28, 255, 0}, + {1, 10000, {5, 11.0, 32, 0}, {2, 4.0, 32, 0}, {0, 3.0, 32, 0}, 0, 64, 63, 128, 30, 255, 0}, + {1, 10000, {5, 1.0, 32, 0}, {4, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 32, 128, 33, 255, 0}, + {1, 10000, {2, 168.0, 32, 0}, {0, 0.5, 29, 173}, {0, 0.0, 32, 0}, 0, 13, 63, 68, 35, 255, 0}, + {1, 10000, {2, 50.0, 32, 0}, {0, 0.5, 29, 173}, {2, 100.0, 32, 0}, 0, 13, 63, 68, 35, 255, 0}, + {1, 4000, {5, 11.0, 25, 0}, {3, 3.0, 32, 0}, {0, 0.0, 32, 0}, 0, 9, 63, 128, 14, 255, 0}, + {1, 4000, {5, 3.0, 27, 0}, {3, 3.0, 32, 0}, {0, 0.0, 32, 0}, 0, 9, 63, 128, 14, 255, 0}, + {1, 3000, {4, 9.0, 20, 0}, {3, 3.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 3000, {4, 18.0, 20, 0}, {3, 3.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 0}, + {1, 3000, {5, 4.0, 32, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 0, 64, 63, 128, 63, 255, 0}, + {1, 12000, {5, 2.0, 32, 0}, {3, 1.7, 53, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 162, 25, 255, 0}, + {1, 12000, {3, 77.0, 32, 0}, {3, 1.0, 61, 200}, {0, 19.0, 22, 0}, 63, 64, 63, 172, 25, 255, 0}, + {1, 5000, {0, 16.0, 63, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 166, 35, 255, 0}, + {1, 1000, {5, 1.0, 16, 0}, {0, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 91, 28, 255, 0}, + {1, 5000, {0, 20.0, 30, 0}, {3, 1.0, 44, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 111, 19, 255, 0}, + {1, 10000, {5, 14.0, 41, 0}, {5, 3.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 18, 91, 12, 255, 0}, + {1, 1000, {5, 48.0, 30, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 166, 27, 255, 0}, + {1, 10000, {5, 48.0, 30, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 43, 166, 41, 255, 7}, + {1, 4000, {5, 35.0, 30, 0}, {3, 35.0, 32, 0}, {0, 0.0, 32, 0}, 63, 53, 21, 166, 13, 255, 0}, + {1, 10000, {1, 63.0, 32, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 39, 91, 20, 255, 0}, + {1, 22050, {5, 52.0, 22, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 3, 23, 23, 57, 10, 255, 0}, + {1, 22050, {5, 80.0, 22, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 23, 23, 57, 10, 255, 0}, + {1, 44100, {5, 54.0, 12, 0}, {5, 1.0, 32, 0}, {5, 1.0, 27, 0}, 40, 64, 63, 128, 38, 255, 63}, + {1, 44100, {5, 119.0, 9, 0}, {5, 2.0, 32, 0}, {0, 0.0, 32, 0}, 61, 64, 39, 128, 60, 255, 28}, + {1, 4000, {5, 11.0, 32, 0}, {5, 1.0, 17, 197}, {0, 0.0, 32, 0}, 51, 100, 63, 100, 0, 255, 0}, + {1, 4000, {5, 21.0, 32, 0}, {5, 1.0, 17, 197}, {0, 0.0, 32, 0}, 0, 119, 0, 117, 63, 255, 0}, + {1, 5000, {2, 143.0, 25, 0}, {3, 0.5, 40, 217}, {1, 0.0, 32, 0}, 63, 64, 63, 128, 34, 198, 32}, + {1, 5000, {5, 10.0, 23, 0}, {3, 0.5, 24, 217}, {1, 4.0, 32, 0}, 0, 4, 63, 128, 34, 198, 32}, + {1, 4000, {5, 6.0, 32, 0}, {3, 2.0, 32, 0}, {3, 2.0, 32, 0}, 63, 26, 30, 66, 29, 255, 0}, + {1, 4000, {0, 150.0, 32, 0}, {0, 0.0, 32, 0}, {3, 2.0, 32, 0}, 63, 26, 30, 66, 29, 255, 0}, + {1, 40050, {4, 100.0, 32, 0}, {3, 8.0, 22, 0}, {3, 8.0, 8, 0}, 63, 28, 44, 81, 23, 255, 0}, + {1, 40050, {4, 150.0, 32, 0}, {3, 8.0, 22, 0}, {3, 8.0, 8, 0}, 63, 28, 44, 81, 23, 255, 0}, + {1, 40050, {4, 294.0, 32, 0}, {3, 8.0, 22, 0}, {3, 8.0, 8, 0}, 63, 28, 44, 81, 23, 255, 0}, + {1, 5000, {3, 621.0, 32, 0}, {2, 2.0, 22, 0}, {3, 6.0, 32, 0}, 0, 4, 63, 77, 30, 255, 0}, + {1, 30000, {5, 28.0, 44, 0}, {3, 1.0, 45, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 208, 63, 255, 0}, + {1, 30000, {2, 101.0, 44, 0}, {2, 0.5, 63, 118}, {0, 0.0, 32, 0}, 63, 64, 63, 176, 63, 255, 0}, + {1, 30000, {2, 86.0, 44, 0}, {2, 0.5, 63, 118}, {0, 0.0, 32, 0}, 63, 64, 63, 176, 63, 255, 0}, + {1, 2000, {5, 1.0, 32, 0}, {0, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 2000, {3, 99.0, 12, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 63, 64, 63, 128, 63, 255, 63}, + {1, 6000, {3, 388.0, 22, 0}, {0, 0.7, 53, 0}, {0, 7.0, 32, 0}, 25, 64, 63, 202, 63, 255, 0}, + {1, 6000, {1, 918.0, 23, 0}, {0, 0.7, 53, 0}, {0, 7.0, 32, 0}, 63, 64, 63, 202, 63, 255, 0}, + {1, 10000, {5, 118.0, 19, 0}, {3, 1.0, 63, 0}, {0, 3.0, 32, 0}, 0, 19, 63, 66, 41, 255, 0}, + {1, 10000, {5, 6.0, 24, 0}, {3, 1.0, 32, 208}, {2, 8.0, 12, 0}, 63, 64, 63, 128, 38, 255, 0}, + {1, 400, {1, 20.0, 12, 0}, {0, 0.0, 32, 0}, {0, 0.0, 32, 0}, 0, 43, 63, 193, 63, 255, 0}, + {1, 400, {1, 30.0, 12, 0}, {0, 0.0, 32, 0}, {0, 0.0, 32, 0}, 0, 43, 63, 193, 63, 255, 0}, + {1, 400, {1, 40.0, 12, 0}, {0, 0.0, 32, 0}, {0, 0.0, 32, 0}, 0, 43, 63, 193, 63, 255, 0}, + {1, 8000, {3, 800.0, 24, 0}, {0, 8.0, 4, 0}, {0, 0.0, 32, 0}, 0, 13, 63, 138, 63, 255, 0}, + {1, 8000, {5, 53.0, 12, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 0, 0, 63, 68, 63, 255, 0}, + {1, 8000, {3, 400.0, 24, 0}, {0, 8.0, 4, 0}, {0, 0.0, 32, 0}, 0, 13, 63, 138, 63, 255, 0}, + {1, 8000, {5, 53.0, 12, 0}, {5, 1.0, 32, 0}, {0, 0.0, 32, 0}, 0, 0, 63, 68, 63, 255, 0}, + {1, 8000, {3, 200.0, 32, 0}, {0, 8.0, 4, 0}, {0, 0.0, 32, 0}, 0, 13, 63, 138, 63, 255, 0}, + {1, 8000, {5, 25.0, 17, 0}, {3, 1.0, 32, 0}, {0, 0.0, 32, 0}, 0, 0, 63, 68, 63, 255, 0}, + {1, 8000, {4, 800.0, 32, 0}, {4, 2.0, 21, 0}, {4, 8.0, 32, 0}, 0, 106, 63, 130, 27, 255, 0}, + {1, 3000, {4, 31.0, 10, 0}, {3, 2.0, 40, 0}, {4, 1.0, 31, 0}, 0, 9, 63, 94, 63, 255, 0}, + {1, 5000, {2, 168.0, 32, 0}, {0, 0.5, 29, 173}, {0, 0.0, 32, 0}, 0, 13, 63, 68, 35, 255, 0}, + {1, 1000, {0, 20.0, 0, 0}, {0, 0.0, 0, 0}, {0, 0.0, 0, 0}, 0, 64, 0, 128, 0, 255, 0} +}; + +BOOL LoadGenericData(void) +{ + int pt_size; + BOOL bError; + + MakeSurface_Resource("PIXEL", SURFACE_ID_PIXEL); + + bError = FALSE; + if (!MakeSurface_File("MyChar", SURFACE_ID_MY_CHAR)) + bError = TRUE; + if (!MakeSurface_File("Title", SURFACE_ID_TITLE)) + bError = TRUE; + if (!MakeSurface_File("ArmsImage", SURFACE_ID_ARMS_IMAGE)) + bError = TRUE; + if (!MakeSurface_File("Arms", SURFACE_ID_ARMS)) + bError = TRUE; + if (!MakeSurface_File("ItemImage", SURFACE_ID_ITEM_IMAGE)) + bError = TRUE; + if (!MakeSurface_File("StageImage", SURFACE_ID_STAGE_ITEM)) + bError = TRUE; + if (!MakeSurface_File("Npc\\NpcSym", SURFACE_ID_NPC_SYM)) + bError = TRUE; + if (!MakeSurface_File("Npc\\NpcRegu", SURFACE_ID_NPC_REGU)) + bError = TRUE; + if (!MakeSurface_File("TextBox", SURFACE_ID_TEXT_BOX)) + bError = TRUE; + if (!MakeSurface_File("Caret", SURFACE_ID_CARET)) + bError = TRUE; + if (!MakeSurface_File("Bullet", SURFACE_ID_BULLET)) + bError = TRUE; + if (!MakeSurface_File("Face", SURFACE_ID_FACE)) + bError = TRUE; + if (!MakeSurface_File("Fade", SURFACE_ID_FADE)) + bError = TRUE; + + MakeSurface_Resource("CREDIT01", SURFACE_ID_CREDITS_IMAGE); + + if (bError) + return FALSE; + + MakeSurface_Generic(WINDOW_WIDTH, WINDOW_HEIGHT, SURFACE_ID_SCREEN_GRAB, TRUE); + MakeSurface_Generic(320, 240, SURFACE_ID_LEVEL_BACKGROUND, FALSE); + MakeSurface_Generic(WINDOW_WIDTH, WINDOW_HEIGHT, SURFACE_ID_MAP, TRUE); + MakeSurface_Generic(320, 240, SURFACE_ID_CASTS, FALSE); + MakeSurface_Generic(256, 256, SURFACE_ID_LEVEL_TILESET, FALSE); + MakeSurface_Generic(160, 16, SURFACE_ID_ROOM_NAME, FALSE); + MakeSurface_Generic(40, 240, SURFACE_ID_VALUE_VIEW, FALSE); + MakeSurface_Generic(320, 240, SURFACE_ID_LEVEL_SPRITESET_1, FALSE); + MakeSurface_Generic(320, 240, SURFACE_ID_LEVEL_SPRITESET_2, FALSE); + MakeSurface_Generic(320, 16 * (MAX_STRIP - 1), SURFACE_ID_CREDIT_CAST, FALSE); + + pt_size = 0; + pt_size += MakePixToneObject(&gPtpTable[0], 2, 32); + pt_size += MakePixToneObject(&gPtpTable[2], 2, 33); + pt_size += MakePixToneObject(&gPtpTable[4], 2, 34); + pt_size += MakePixToneObject(&gPtpTable[6], 1, 15); + pt_size += MakePixToneObject(&gPtpTable[7], 1, 24); + pt_size += MakePixToneObject(&gPtpTable[8], 1, 23); + pt_size += MakePixToneObject(&gPtpTable[9], 2, 50); + pt_size += MakePixToneObject(&gPtpTable[11], 2, 51); + pt_size += MakePixToneObject(&gPtpTable[33], 1, 1); + pt_size += MakePixToneObject(&gPtpTable[38], 1, 2); + pt_size += MakePixToneObject(&gPtpTable[56], 1, 29); + pt_size += MakePixToneObject(&gPtpTable[61], 1, 43); + pt_size += MakePixToneObject(&gPtpTable[62], 3, 44); + pt_size += MakePixToneObject(&gPtpTable[65], 1, 45); + pt_size += MakePixToneObject(&gPtpTable[66], 1, 46); + pt_size += MakePixToneObject(&gPtpTable[68], 1, 47); + pt_size += MakePixToneObject(&gPtpTable[49], 3, 35); + pt_size += MakePixToneObject(&gPtpTable[52], 3, 39); + pt_size += MakePixToneObject(&gPtpTable[13], 2, 52); + pt_size += MakePixToneObject(&gPtpTable[28], 2, 53); + pt_size += MakePixToneObject(&gPtpTable[15], 2, 70); + pt_size += MakePixToneObject(&gPtpTable[17], 2, 71); + pt_size += MakePixToneObject(&gPtpTable[19], 2, 72); + pt_size += MakePixToneObject(&gPtpTable[30], 1, 5); + pt_size += MakePixToneObject(&gPtpTable[32], 1, 11); + pt_size += MakePixToneObject(&gPtpTable[35], 1, 4); + pt_size += MakePixToneObject(&gPtpTable[46], 2, 25); + pt_size += MakePixToneObject(&gPtpTable[48], 1, 27); + pt_size += MakePixToneObject(&gPtpTable[54], 2, 28); + pt_size += MakePixToneObject(&gPtpTable[39], 1, 14); + pt_size += MakePixToneObject(&gPtpTable[23], 2, 16); + pt_size += MakePixToneObject(&gPtpTable[25], 3, 17); + pt_size += MakePixToneObject(&gPtpTable[34], 1, 18); + pt_size += MakePixToneObject(&gPtpTable[36], 2, 20); + pt_size += MakePixToneObject(&gPtpTable[31], 1, 22); + pt_size += MakePixToneObject(&gPtpTable[41], 2, 26); + pt_size += MakePixToneObject(&gPtpTable[43], 1, 21); + pt_size += MakePixToneObject(&gPtpTable[44], 2, 12); + pt_size += MakePixToneObject(&gPtpTable[57], 2, 38); + pt_size += MakePixToneObject(&gPtpTable[59], 1, 31); + pt_size += MakePixToneObject(&gPtpTable[60], 1, 42); + pt_size += MakePixToneObject(&gPtpTable[69], 1, 48); + pt_size += MakePixToneObject(&gPtpTable[70], 2, 49); + pt_size += MakePixToneObject(&gPtpTable[72], 1, 100); + pt_size += MakePixToneObject(&gPtpTable[73], 3, 101); + pt_size += MakePixToneObject(&gPtpTable[76], 2, 54); + pt_size += MakePixToneObject(&gPtpTable[78], 2, 102); + pt_size += MakePixToneObject(&gPtpTable[80], 2, 103); + pt_size += MakePixToneObject(&gPtpTable[81], 1, 104); + pt_size += MakePixToneObject(&gPtpTable[82], 1, 105); + pt_size += MakePixToneObject(&gPtpTable[83], 2, 106); + pt_size += MakePixToneObject(&gPtpTable[85], 1, 107); + pt_size += MakePixToneObject(&gPtpTable[86], 1, 30); + pt_size += MakePixToneObject(&gPtpTable[87], 1, 108); + pt_size += MakePixToneObject(&gPtpTable[88], 1, 109); + pt_size += MakePixToneObject(&gPtpTable[89], 1, 110); + pt_size += MakePixToneObject(&gPtpTable[90], 1, 111); + pt_size += MakePixToneObject(&gPtpTable[91], 1, 112); + pt_size += MakePixToneObject(&gPtpTable[92], 1, 113); + pt_size += MakePixToneObject(&gPtpTable[93], 2, 114); + pt_size += MakePixToneObject(&gPtpTable[95], 2, 150); + pt_size += MakePixToneObject(&gPtpTable[97], 2, 151); + pt_size += MakePixToneObject(&gPtpTable[99], 1, 152); + pt_size += MakePixToneObject(&gPtpTable[100], 1, 153); + pt_size += MakePixToneObject(&gPtpTable[101], 2, 154); + pt_size += MakePixToneObject(&gPtpTable[111], 2, 155); + pt_size += MakePixToneObject(&gPtpTable[103], 2, 56); + pt_size += MakePixToneObject(&gPtpTable[105], 2, 40); + pt_size += MakePixToneObject(&gPtpTable[105], 2, 41); + pt_size += MakePixToneObject(&gPtpTable[107], 2, 37); + pt_size += MakePixToneObject(&gPtpTable[109], 2, 57); + pt_size += MakePixToneObject(&gPtpTable[113], 3, 115); + pt_size += MakePixToneObject(&gPtpTable[116], 1, 104); + pt_size += MakePixToneObject(&gPtpTable[117], 3, 116); + pt_size += MakePixToneObject(&gPtpTable[120], 2, 58); + pt_size += MakePixToneObject(&gPtpTable[122], 2, 55); + pt_size += MakePixToneObject(&gPtpTable[124], 2, 117); + pt_size += MakePixToneObject(&gPtpTable[126], 1, 59); + pt_size += MakePixToneObject(&gPtpTable[127], 1, 60); + pt_size += MakePixToneObject(&gPtpTable[128], 1, 61); + pt_size += MakePixToneObject(&gPtpTable[129], 2, 62); + pt_size += MakePixToneObject(&gPtpTable[131], 2, 63); + pt_size += MakePixToneObject(&gPtpTable[133], 2, 64); + pt_size += MakePixToneObject(&gPtpTable[135], 1, 65); + pt_size += MakePixToneObject(&gPtpTable[136], 1, 3); + pt_size += MakePixToneObject(&gPtpTable[137], 1, 6); + pt_size += MakePixToneObject(&gPtpTable[138], 1, 7); + + char str[0x40]; + sprintf(str, "PixTone = %d byte", pt_size); + // There must have once been a 'OutputDebugStringA' call here or something. + // See 'EnumDevices_Callback' in 'Input.cpp' for an example of this. + + return TRUE; +} diff --git a/src/GenericLoad.h b/src/GenericLoad.h new file mode 100644 index 0000000..432a127 --- /dev/null +++ b/src/GenericLoad.h @@ -0,0 +1,16 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "PixTone.h" + +extern const PIXTONEPARAMETER gPtpTable[139]; + +BOOL LoadGenericData(void); diff --git a/src/Input.cpp b/src/Input.cpp new file mode 100644 index 0000000..0835d37 --- /dev/null +++ b/src/Input.cpp @@ -0,0 +1,246 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Input.h" + +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // Newer versions of Visual Studio don't support anything earlier than DirectInput8 +#define DIRECTINPUT_VERSION 0x800 +#else +#define DIRECTINPUT_VERSION 0x500 +#endif +#include + +#include "WindowsWrapper.h" + +typedef struct DirectInputPair +{ + LPDIRECTINPUTA lpDI; + LPDIRECTINPUTDEVICE2A device; +} DirectInputPair; + +// The original names for these variables are unknown +static LPDIRECTINPUTA lpDI = NULL; +static LPDIRECTINPUTDEVICE2A joystick = NULL; +static int joystick_neutral_x = 0; +static int joystick_neutral_y = 0; + +void ReleaseDirectInput(void) +{ + if (joystick != NULL) + { + joystick->Release(); + joystick = NULL; + } + + if (lpDI != NULL) + { + lpDI->Release(); + lpDI = NULL; + } +} + +// The original name for this function's variables are unknown +BOOL ActivateDirectInput(BOOL aquire) +{ + if (aquire == TRUE) + { + if (joystick != NULL) + joystick->Acquire(); + } + else + { + if (joystick != NULL) + joystick->Unacquire(); + } + + return TRUE; +} + +// It looks like Pixel declared his functions early, so he could forward-reference +BOOL FindAndOpenDirectInputDevice(HWND hWnd); +BOOL CALLBACK EnumDevices_Callback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef); + +BOOL InitDirectInput(HINSTANCE hinst, HWND hWnd) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1500 + if (DirectInput8Create(hinst, DIRECTINPUT_VERSION, IID_IDirectInput8A, (LPVOID*)&lpDI, NULL) != DI_OK) +#else + if (DirectInputCreateA(hinst, DIRECTINPUT_VERSION, &lpDI, NULL) != DI_OK) +#endif + return FALSE; + + if (!FindAndOpenDirectInputDevice(hWnd)) + return FALSE; + + return TRUE; +} + +// The original name for this function and its variables are unknown. +// This function finds and hooks the first available DirectInput device. +BOOL FindAndOpenDirectInputDevice(HWND hWnd) +{ + DirectInputPair directinput_objects; + + directinput_objects.device = NULL; + directinput_objects.lpDI = lpDI; + + directinput_objects.lpDI->AddRef(); + +#if defined(_MSC_VER) && _MSC_VER >= 1500 + lpDI->EnumDevices(DI8DEVTYPE_JOYSTICK, EnumDevices_Callback, &directinput_objects, DIEDFL_ATTACHEDONLY); +#else + lpDI->EnumDevices(DIDEVTYPE_JOYSTICK, EnumDevices_Callback, &directinput_objects, DIEDFL_ATTACHEDONLY); +#endif + + if (directinput_objects.lpDI != NULL) + { + directinput_objects.lpDI->Release(); + directinput_objects.lpDI = NULL; + } + + if (directinput_objects.device == NULL) + return FALSE; + + joystick = directinput_objects.device; + + if (joystick->SetDataFormat(&c_dfDIJoystick) != DI_OK) // c_dfDIJoystick might be incorrect + return FALSE; + + if (joystick->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND) != DI_OK) + return FALSE; + + joystick->Acquire(); + + return TRUE; +} + +// The original names for this function and its variables are unknown +BOOL CALLBACK EnumDevices_Callback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) +{ + static int already_ran; + static DirectInputPair *directinput_objects; + + if (!(already_ran & 1)) + { + already_ran |= 1; + directinput_objects = (DirectInputPair*)pvRef; + } + + static LPDIRECTINPUTDEVICEA device; + if (directinput_objects->lpDI->CreateDevice(lpddi->guidInstance, &device, NULL) != DI_OK) + { + directinput_objects->device = NULL; + return DIENUM_CONTINUE; + } + + static LPDIRECTINPUTDEVICE2A _joystick; + HRESULT res = device->QueryInterface(IID_IDirectInputDevice2A, (LPVOID*)&_joystick); + + if (FAILED(res)) + { + joystick = NULL; + return DIENUM_CONTINUE; + } + + if (device != NULL) + { + device->Release(); + device = NULL; + } + + directinput_objects->device = _joystick; + + // This is interesting: there are at least two places in the game + // where it seems like there's meant to be a debug print just like + // this one: these are the 'out' function in 'Draw.cpp', and the + // 'LoadGenericData' function in 'GenericLoad.cpp'. + // Perhaps Pixel kept them wrapped in '#ifdef DEBUG' blocks, and + // simply forgot to do the same here. + + char str[0x100]; +#ifdef FIX_MAJOR_BUGS + sprintf(str, "DeviceGUID = %08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", lpddi->guidInstance.Data1, lpddi->guidInstance.Data2, lpddi->guidInstance.Data3, lpddi->guidInstance.Data4[0], lpddi->guidInstance.Data4[1], lpddi->guidInstance.Data4[2], lpddi->guidInstance.Data4[3], lpddi->guidInstance.Data4[4], lpddi->guidInstance.Data4[5], lpddi->guidInstance.Data4[6], lpddi->guidInstance.Data4[7]); +#else + sprintf(str, "DeviceGUID = %x\n", lpddi->guidInstance); // Tries to print a struct as an int +#endif + OutputDebugStringA(str); + + return DIENUM_STOP; +} + +BOOL GetJoystickStatus(DIRECTINPUTSTATUS *status) +{ + DIJOYSTATE joystate; + + if (joystick == NULL) + return FALSE; + + if (joystick->Poll() != DI_OK) + return FALSE; + + HRESULT res = joystick->GetDeviceState(sizeof(DIJOYSTATE), &joystate); + if (res != DI_OK) + { + if (res == DIERR_INPUTLOST) + ActivateDirectInput(FALSE); + else + return FALSE; + } + + for (int i = 0; i < 32; ++i) + { + if (joystate.rgbButtons[i] & 0x80) + status->bButton[i] = TRUE; + else + status->bButton[i] = FALSE; + } + + status->bDown = FALSE; + status->bRight = FALSE; + status->bUp = FALSE; + status->bLeft = FALSE; + + if (joystate.lX < joystick_neutral_x - 10000) + status->bLeft = TRUE; + else if (joystate.lX > joystick_neutral_x + 10000) + status->bRight = TRUE; + + if (joystate.lY < joystick_neutral_y - 10000) + status->bUp = TRUE; + else if (joystate.lY > joystick_neutral_y + 10000) + status->bDown = TRUE; + + return TRUE; +} + +BOOL ResetJoystickStatus(void) +{ + DIJOYSTATE joystate; + + if (joystick == NULL) + return FALSE; + + if (joystick->Poll() != DI_OK) + return FALSE; + + HRESULT res = joystick->GetDeviceState(sizeof(DIJOYSTATE), &joystate); + if (res != DI_OK) + { + if (res == DIERR_INPUTLOST) + ActivateDirectInput(FALSE); + else + return FALSE; + } + + joystick_neutral_x = joystate.lX; + joystick_neutral_y = joystate.lY; + + return TRUE; +} diff --git a/src/Input.h b/src/Input.h new file mode 100644 index 0000000..d149488 --- /dev/null +++ b/src/Input.h @@ -0,0 +1,24 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +struct DIRECTINPUTSTATUS +{ + BOOL bLeft; + BOOL bRight; + BOOL bUp; + BOOL bDown; + BOOL bButton[32]; // 32 is the number of buttons in DirectInput's `DIJOYSTATE` struct +}; + +void ReleaseDirectInput(void); +BOOL InitDirectInput(HINSTANCE hinst, HWND hWnd); +BOOL GetJoystickStatus(DIRECTINPUTSTATUS *status); +BOOL ResetJoystickStatus(void); diff --git a/src/KeyControl.cpp b/src/KeyControl.cpp new file mode 100644 index 0000000..5a5cb75 --- /dev/null +++ b/src/KeyControl.cpp @@ -0,0 +1,34 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "KeyControl.h" + +long gKey; +long gKeyTrg; + +long gKeyJump = KEY_Z; +long gKeyShot = KEY_X; +long gKeyArms = KEY_ARMS; +long gKeyArmsRev = KEY_ARMSREV; +long gKeyItem = KEY_ITEM; +long gKeyMap = KEY_MAP; + +long gKeyOk = KEY_Z; +long gKeyCancel = KEY_X; + +long gKeyLeft = KEY_LEFT; +long gKeyUp = KEY_UP; +long gKeyRight = KEY_RIGHT; +long gKeyDown = KEY_DOWN; + +void GetTrg(void) +{ + static int key_old; + gKeyTrg = gKey ^ key_old; + gKeyTrg = gKey & gKeyTrg; + key_old = gKey; +} diff --git a/src/KeyControl.h b/src/KeyControl.h new file mode 100644 index 0000000..08aac00 --- /dev/null +++ b/src/KeyControl.h @@ -0,0 +1,62 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +enum KeyBind +{ + //The movement keys go in the order of left, right, up and down + KEY_LEFT = 0x00000001, + KEY_RIGHT = 0x00000002, + KEY_UP = 0x00000004, + KEY_DOWN = 0x00000008, + //Map key + KEY_MAP = 0x00000010, + //Okay and cancel / Jump and Shoot keys + KEY_X = 0x00000020, + KEY_Z = 0x00000040, + //Left and right weapon switch keys + KEY_ARMS = 0x00000080, + KEY_ARMSREV = 0x00000100, + //Unused? + KEY_SHIFT = 0x00000200, + //Function keys + KEY_F1 = 0x00000400, + KEY_F2 = 0x00000800, + //Inventory + KEY_ITEM = 0x00001000, + //Escape key + KEY_ESCAPE = 0x00008000, + //The alt movement keys go in the order of left, up, right and down + KEY_ALT_LEFT = 0x00010000, + KEY_ALT_DOWN = 0x00020000, + KEY_ALT_RIGHT = 0x00040000, + KEY_ALT_UP = 0x00180000, + //Alt up actually has 2 seperate keys, but they're kind of merged together + KEY_L = 0x00080000, + KEY_PLUS = 0x00100000 +}; + +extern long gKey; +extern long gKeyTrg; + +extern long gKeyJump; +extern long gKeyShot; +extern long gKeyArms; +extern long gKeyArmsRev; +extern long gKeyItem; +extern long gKeyMap; + +extern long gKeyOk; +extern long gKeyCancel; + +extern long gKeyLeft; +extern long gKeyUp; +extern long gKeyRight; +extern long gKeyDown; + +void GetTrg(void); diff --git a/src/Main.cpp b/src/Main.cpp new file mode 100644 index 0000000..c7addf8 --- /dev/null +++ b/src/Main.cpp @@ -0,0 +1,821 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Main.h" + +#include +#include +#include + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Config.h" +#include "Dialog.h" +#include "Draw.h" +#include "Game.h" +#include "Generic.h" +#include "Input.h" +#include "KeyControl.h" +#include "MyChar.h" +#include "Organya.h" +#include "Profile.h" +#include "Sound.h" +#include "Triangle.h" + +LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); + +char gModulePath[MAX_PATH]; +char gDataPath[MAX_PATH]; + +HWND ghWnd; +BOOL bFullscreen; +BOOL gbUseJoystick = FALSE; + +int gJoystickButtonTable[8]; + +static BOOL bActive = TRUE; +static BOOL bFPS = FALSE; + +static HANDLE hObject; +static HANDLE hMutex; +static HINSTANCE ghInstance; + +static int windowWidth; +static int windowHeight; + +static const char* const mutex_name = "Doukutsu"; + +#ifdef JAPANESE +static const char* const lpWindowName = "\x93\xB4\x8C\x41\x95\xA8\x8C\xEA"; // '洞窟物語' (Cave Story) in Shift-JIS +#else +static const char* const lpWindowName = "Cave Story ~ Doukutsu Monogatari"; +#endif + +// The original name for this function is unknown +void SetWindowName(HWND hWnd) +{ + char window_name[0x100]; + + sprintf(window_name, "%s", lpWindowName); + SetWindowTextA(hWnd, window_name); +} + +// Framerate stuff +static unsigned long CountFramePerSecound(void) +{ + unsigned long current_tick; // The original name for this variable is unknown + static BOOL first = TRUE; + static unsigned long max_count; + static unsigned long count; + static unsigned long wait; + + if (first) + { + wait = GetTickCount(); + first = FALSE; + } + + current_tick = GetTickCount(); + ++count; + + if (wait + 1000 <= current_tick) + { + wait += 1000; + max_count = count; + count = 0; + } + + return max_count; +} + +void PutFramePerSecound(void) +{ + if (bFPS) + { + const unsigned long fps = CountFramePerSecound(); + PutNumber4(WINDOW_WIDTH - 40, 8, fps, FALSE); + } +} + +// TODO - Inaccurate stack frame +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + (void)hPrevInstance; + (void)lpCmdLine; + (void)nShowCmd; + + int i; + + hObject = OpenMutexA(MUTEX_ALL_ACCESS, 0, mutex_name); + if (hObject != NULL) + { + CloseHandle(hObject); + return 0; + } + + hMutex = CreateMutexA(NULL, FALSE, mutex_name); + + ghInstance = hInstance; + + // Get executable's path + GetModuleFileNameA(NULL, gModulePath, MAX_PATH); + PathRemoveFileSpecA(gModulePath); + + // Get path of the data folder + strcpy(gDataPath, gModulePath); + strcat(gDataPath, "\\data"); + + CONFIGDATA conf; + if (!LoadConfigData(&conf)) + DefaultConfigData(&conf); + + // Apply keybinds + // Swap X and Z buttons + switch (conf.attack_button_mode) + { + case 0: + gKeyJump = KEY_Z; + gKeyShot = KEY_X; + break; + + case 1: + gKeyJump = KEY_X; + gKeyShot = KEY_Z; + break; + } + + // Swap Okay and Cancel buttons + switch (conf.ok_button_mode) + { + case 0: + gKeyOk = gKeyJump; + gKeyCancel = gKeyShot; + break; + + case 1: + gKeyOk = gKeyShot; + gKeyCancel = gKeyJump; + break; + } + + // Swap left and right weapon switch keys + if (IsKeyFile("s_reverse")) + { + gKeyArms = KEY_ARMSREV; + gKeyArmsRev = KEY_ARMS; + } + + // Alternate movement keys + switch (conf.move_button_mode) + { + case 0: + gKeyLeft = KEY_LEFT; + gKeyUp = KEY_UP; + gKeyRight = KEY_RIGHT; + gKeyDown = KEY_DOWN; + break; + + case 1: + gKeyLeft = KEY_ALT_LEFT; + gKeyUp = KEY_ALT_UP; + gKeyRight = KEY_ALT_RIGHT; + gKeyDown = KEY_ALT_DOWN; + break; + } + + // Set gamepad inputs + for (i = 0; i < 8; ++i) + { + switch (conf.joystick_button[i]) + { + case 1: + gJoystickButtonTable[i] = gKeyJump; + break; + + case 2: + gJoystickButtonTable[i] = gKeyShot; + break; + + case 3: + gJoystickButtonTable[i] = gKeyArms; + break; + + case 6: + gJoystickButtonTable[i] = gKeyArmsRev; + break; + + case 4: + gJoystickButtonTable[i] = gKeyItem; + break; + + case 5: + gJoystickButtonTable[i] = gKeyMap; + break; + } + } + + RECT unused_rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + + WNDCLASSEXA wndclassex; + memset(&wndclassex, 0, sizeof(WNDCLASSEXA)); + wndclassex.cbSize = sizeof(WNDCLASSEXA); + wndclassex.lpfnWndProc = WindowProcedure; + wndclassex.hInstance = hInstance; + wndclassex.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); // This is what gives the window's undrawn regions its grey colour + wndclassex.lpszClassName = lpWindowName; + wndclassex.hCursor = LoadCursorA(hInstance, "CURSOR_NORMAL"); + wndclassex.hIcon = LoadIconA(hInstance, "0"); + wndclassex.hIconSm = LoadIconA(hInstance, "ICON_MINI"); + + HWND hWnd; + HMENU hMenu; + int nWidth; + int nHeight; + int x; + int y; + + switch (conf.display_mode) + { + case 1: + case 2: + wndclassex.lpszMenuName = "MENU_MAIN"; + + if (RegisterClassExA(&wndclassex) == 0) + { + ReleaseMutex(hMutex); + return 0; + } + + // Set window dimensions + if (conf.display_mode == 1) + { + windowWidth = WINDOW_WIDTH; + windowHeight = WINDOW_HEIGHT; + } + else + { + windowWidth = WINDOW_WIDTH * 2; + windowHeight = WINDOW_HEIGHT * 2; + } + + nWidth = (GetSystemMetrics(SM_CXFIXEDFRAME) * 2) + windowWidth + 2; + nHeight = (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) + windowHeight + 2; + x = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2; + y = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2; + + SetClientOffset(GetSystemMetrics(SM_CXFIXEDFRAME) + 1, GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) + 1); + + hWnd = CreateWindowExA(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, lpWindowName, lpWindowName, WS_MINIMIZEBOX | WS_SYSMENU | WS_BORDER | WS_DLGFRAME | WS_VISIBLE, x, y, nWidth, nHeight, NULL, NULL, hInstance, NULL); + ghWnd = hWnd; + + if (hWnd == NULL) + { + ReleaseMutex(hMutex); + return 0; + } + + hMenu = GetMenu(hWnd); + + #ifdef FIX_MAJOR_BUGS + if (conf.display_mode == 1) + { + if (!StartDirectDraw(hWnd, 0, 0)) + { + ReleaseMutex(hMutex); + return 0; + } + } + else + { + if (!StartDirectDraw(hWnd, 1, 0)) + { + ReleaseMutex(hMutex); + return 0; + } + } + #else + // Doesn't handle StartDirectDraw failing + if (conf.display_mode == 1) + StartDirectDraw(hWnd, 0, 0); + else + StartDirectDraw(hWnd, 1, 0); + #endif + + break; + + case 0: + case 3: + case 4: + if (RegisterClassExA(&wndclassex) == 0) + { + ReleaseMutex(hMutex); + return 0; + } + + // Set window dimensions + windowWidth = WINDOW_WIDTH * 2; + windowHeight = WINDOW_HEIGHT * 2; + + SetClientOffset(0, 0); + + hWnd = CreateWindowExA(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, lpWindowName, lpWindowName, WS_SYSMENU | WS_VISIBLE | WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL); + ghWnd = hWnd; + + if (hWnd == NULL) + { + ReleaseMutex(hMutex); + return 0; + } + + // Set colour depth + int depth; + + switch (conf.display_mode) + { + case 0: + depth = 16; + break; + case 3: + depth = 24; + break; + case 4: + depth = 32; + break; + } + + #ifdef FIX_MAJOR_BUGS + if (!StartDirectDraw(hWnd, 2, depth)) + { + ReleaseMutex(hMutex); + return 0; + } + #else + // Doesn't handle StartDirectDraw failing + StartDirectDraw(hWnd, 2, depth); + #endif + + bFullscreen = TRUE; + + ShowCursor(FALSE); + break; + } + + // Set rects + RECT rcLoading = {0, 0, 64, 8}; + RECT rcFull = {0, 0, 0, 0}; + rcFull.right = WINDOW_WIDTH; + rcFull.bottom = WINDOW_HEIGHT; + + // Load the "LOADING" text + BOOL b = MakeSurface_File("Loading", SURFACE_ID_LOADING); + + // Draw loading screen + CortBox(&rcFull, 0x000000); + PutBitmap3(&rcFull, (WINDOW_WIDTH / 2) - 32, (WINDOW_HEIGHT / 2) - 4, &rcLoading, SURFACE_ID_LOADING); + + // Draw to screen + if (!Flip_SystemTask(ghWnd)) + { + ReleaseMutex(hMutex); + return 1; + } + + // Initialize sound + InitDirectSound(hWnd); + + // Initialize joystick + if (conf.bJoystick && InitDirectInput(hInstance, hWnd)) + { + ResetJoystickStatus(); + gbUseJoystick = TRUE; + } + + // Initialize stuff + InitTextObject(conf.font_name); + InitTriangleTable(); + + // Run game code + Game(hWnd); + + // End stuff + EndTextObject(); + EndDirectSound(); + EndDirectDraw(hWnd); + + ReleaseMutex(hMutex); + + return 1; +} + +void InactiveWindow(void) +{ + if (bActive) + { + bActive = FALSE; + StopOrganyaMusic(); + SleepNoise(); + } + + PlaySoundObject(7, SOUND_MODE_STOP); +} + +void ActiveWindow(void) +{ + if (!bActive) + { + bActive = TRUE; + StopOrganyaMusic(); + PlayOrganyaMusic(); + ResetNoise(); + } + + PlaySoundObject(7, SOUND_MODE_PLAY_LOOP); +} + +// Turns out you could drag-and-drop a save file onto the +// window to load it, but this behavior is dummied-out. +BOOL DragAndDropHandler(HWND hWnd, WPARAM wParam) +{ + char path[MAX_PATH]; + HDROP hDrop = (HDROP)wParam; + + if (DragQueryFileA(hDrop, 0xFFFFFFFF, NULL, 0) != 0) + { + DragQueryFileA(hDrop, 0, path, sizeof(path)); + LoadProfile(path); + } + + DragFinish(hDrop); + + return TRUE; +} + +// TODO - Inaccurate stack frame +LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + BOOL window_focus; + HMENU hMenu; + + switch (Msg) + { + case WM_CREATE: + hMenu = GetMenu(hWnd); + #ifdef DEBUG_SAVE + if (!IsKeyFile("save")) // Chances are a line like this used to exist + #endif + DeleteMenu(hMenu, 40005, MF_BYCOMMAND); + DrawMenuBar(hWnd); + + hMenu = GetMenu(hWnd); + if (!IsKeyFile("mute")) + DeleteMenu(hMenu, 40007, MF_BYCOMMAND); + DrawMenuBar(hWnd); + + if (IsKeyFile("fps")) + bFPS = TRUE; + + if (!bFullscreen) + LoadWindowRect(hWnd, "window.rect", FALSE); + + SetWindowName(hWnd); + + #ifdef DEBUG_SAVE + DragAcceptFiles(hWnd, TRUE); + #endif + + break; + + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_MONITORPOWER: + break; + + case SC_KEYMENU: + break; + + case SC_SCREENSAVE: + break; + + default: + DefWindowProcA(hWnd, Msg, wParam, lParam); + break; + } + + break; + + case WM_IME_NOTIFY: + if (wParam == IMN_SETOPENSTATUS) + { + HIMC hImc = ImmGetContext(hWnd); + ImmSetOpenStatus(hImc, 0); + ImmReleaseContext(hWnd, hImc); + } + + break; + + case WM_KEYDOWN: + switch (wParam) + { + case VK_ESCAPE: + gKey |= KEY_ESCAPE; + break; + + case 'W': + gKey |= KEY_MAP; + break; + + case VK_LEFT: + gKey |= KEY_LEFT; + break; + + case VK_RIGHT: + gKey |= KEY_RIGHT; + break; + + case VK_UP: + gKey |= KEY_UP; + break; + + case VK_DOWN: + gKey |= KEY_DOWN; + break; + + case 'X': + gKey |= KEY_X; + break; + + case 'Z': + gKey |= KEY_Z; + break; + + case 'S': + gKey |= KEY_ARMS; + break; + + case 'A': + gKey |= KEY_ARMSREV; + break; + + case VK_SHIFT: + gKey |= KEY_SHIFT; + break; + + case VK_F1: + gKey |= KEY_F1; + break; + + case VK_F2: + gKey |= KEY_F2; + break; + + case 'Q': + gKey |= KEY_ITEM; + break; + + case VK_OEM_COMMA: + gKey |= KEY_ALT_LEFT; + break; + + case VK_OEM_PERIOD: + gKey |= KEY_ALT_DOWN; + break; + + case VK_OEM_2: + gKey |= KEY_ALT_RIGHT; + break; + + case 'L': + gKey |= KEY_L; + break; + + case VK_OEM_PLUS: + gKey |= KEY_PLUS; + break; + + case VK_F5: + gbUseJoystick = FALSE; + break; + } + + break; + + case WM_KEYUP: + switch (wParam) + { + case VK_ESCAPE: + gKey &= ~KEY_ESCAPE; + break; + + case 'W': + gKey &= ~KEY_MAP; + break; + + case VK_LEFT: + gKey &= ~KEY_LEFT; + break; + + case VK_RIGHT: + gKey &= ~KEY_RIGHT; + break; + + case VK_UP: + gKey &= ~KEY_UP; + break; + + case VK_DOWN: + gKey &= ~KEY_DOWN; + break; + + case 'X': + gKey &= ~KEY_X; + break; + + case 'Z': + gKey &= ~KEY_Z; + break; + + case 'S': + gKey &= ~KEY_ARMS; + break; + + case 'A': + gKey &= ~KEY_ARMSREV; + break; + + case VK_SHIFT: + gKey &= ~KEY_SHIFT; + break; + + case VK_F1: + gKey &= ~KEY_F1; + break; + + case VK_F2: + gKey &= ~KEY_F2; + break; + + case 'Q': + gKey &= ~KEY_ITEM; + break; + + case VK_OEM_COMMA: + gKey &= ~KEY_ALT_LEFT; + break; + + case VK_OEM_PERIOD: + gKey &= ~KEY_ALT_DOWN; + break; + + case VK_OEM_2: + gKey &= ~KEY_ALT_RIGHT; + break; + + case 'L': + gKey &= ~KEY_L; + break; + + case VK_OEM_PLUS: + gKey &= ~KEY_PLUS; + break; + } + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case 40001: + if (DialogBoxParamA(ghInstance, "DLG_YESNO", hWnd, QuitDialog, (LPARAM)"Quit?") == 1) + PostMessageA(hWnd, WM_CLOSE, 0, 0); + break; + + case 40002: + DialogBoxParamA(ghInstance, "DLG_ABOUT", hWnd, VersionDialog, 0); + break; + + case 40004: + if (!OpenSoundVolume(hWnd)) + MessageBoxA(hWnd, "\x83\x7B\x83\x8A\x83\x85\x81\x5B\x83\x80\x90\xDD\x92\xE8\x82\xF0\x8B\x4E\x93\xAE\x82\xC5\x82\xAB\x82\xDC\x82\xB9\x82\xF1\x82\xC5\x82\xB5\x82\xBD", lpWindowName, 0); // 'ボリューム設定を起動できませんでした' (Could not launch volume configuration) in Shift-JIS + break; + + case 40005: + DialogBoxParamA(ghInstance, "DLG_SAVE", hWnd, DebugSaveDialog, 0); + break; + + case 40007: + DialogBoxParamA(ghInstance, "DLG_MUTE", hWnd, DebugMuteDialog, 0); + break; + } + + break; + + case WM_DROPFILES: + DragAndDropHandler(hWnd, wParam); + break; + + case WM_ACTIVATE: + switch (LOWORD(wParam)) + { + case WA_INACTIVE: + window_focus = FALSE; + break; + + case WA_ACTIVE: + case WA_CLICKACTIVE: + if (HIWORD(wParam) != 0) + window_focus = FALSE; + else + window_focus = TRUE; + + break; + } + + if (window_focus) + ActiveWindow(); + else + InactiveWindow(); + + break; + + case WM_CLOSE: + StopOrganyaMusic(); + PostQuitMessage(0); + break; + + default: + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + + return 1; +} + +void JoystickProc(void); + +BOOL SystemTask(void) +{ + MSG Msg; + + while (PeekMessageA(&Msg, NULL, 0, 0, PM_NOREMOVE) || !bActive) + { + if (!GetMessageA(&Msg, NULL, 0, 0)) + return FALSE; + + TranslateMessage(&Msg); + DispatchMessageA(&Msg); + } + + // Run joystick code + if (gbUseJoystick) + JoystickProc(); + + return TRUE; +} + +void JoystickProc(void) +{ + int i; + DIRECTINPUTSTATUS status; + + if (!GetJoystickStatus(&status)) + return; + + gKey &= (KEY_ESCAPE | KEY_F1 | KEY_F2); + + // Set movement buttons + if (status.bLeft) + gKey |= gKeyLeft; + else + gKey &= ~gKeyLeft; + + if (status.bRight) + gKey |= gKeyRight; + else + gKey &= ~gKeyRight; + + if (status.bUp) + gKey |= gKeyUp; + else + gKey &= ~gKeyUp; + + if (status.bDown) + gKey |= gKeyDown; + else + gKey &= ~gKeyDown; + + // Clear held buttons + for (i = 0; i < 8; ++i) + gKey &= ~gJoystickButtonTable[i]; + + // Set held buttons + for (i = 0; i < 8; ++i) + if (status.bButton[i]) + gKey |= gJoystickButtonTable[i]; +} diff --git a/src/Main.h b/src/Main.h new file mode 100644 index 0000000..8abf6e6 --- /dev/null +++ b/src/Main.h @@ -0,0 +1,23 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +extern char gModulePath[MAX_PATH]; +extern char gDataPath[MAX_PATH]; + +extern HWND ghWnd; +extern BOOL bFullscreen; +extern BOOL gbUseJoystick; + +extern int gJoystickButtonTable[8]; + +void PutFramePerSecound(void); + +BOOL SystemTask(void); diff --git a/src/Map.cpp b/src/Map.cpp new file mode 100644 index 0000000..7ed528e --- /dev/null +++ b/src/Map.cpp @@ -0,0 +1,308 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Map.h" + +#include +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Main.h" +#include "NpChar.h" + +#define PXM_BUFFER_SIZE 0x4B000 + +MAP_DATA gMap; + +const char *code_pxma = "PXM"; + +BOOL InitMapData2(void) +{ + gMap.data = (unsigned char*)malloc(PXM_BUFFER_SIZE); + return TRUE; +} + +BOOL LoadMapData2(const char *path_map) +{ + FILE *fp; + char check[3]; + char path[MAX_PATH]; + + // Get path + sprintf(path, "%s\\%s", gDataPath, path_map); + + // Open file + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Make sure file begins with "PXM" + fread(check, 1, 3, fp); + + if (memcmp(check, code_pxma, 3)) + { + fclose(fp); + return FALSE; + } + + unsigned char dum; + fread(&dum, 1, 1, fp); + // Get width and height + // This fails on big-endian hardware, and platforms where short is not two bytes long. + fread(&gMap.width, 2, 1, fp); + fread(&gMap.length, 2, 1, fp); + + if (gMap.data == NULL) + { + fclose(fp); + return FALSE; + } + + // Read tile data + fread(gMap.data, 1, gMap.width * gMap.length, fp); + fclose(fp); + return TRUE; +} + +BOOL LoadAttributeData(const char *path_atrb) +{ + FILE *fp; + char path[MAX_PATH]; + + // Open file + sprintf(path, "%s\\%s", gDataPath, path_atrb); + + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Read data + fread(gMap.atrb, 1, sizeof(gMap.atrb), fp); + fclose(fp); + return TRUE; +} + +void EndMapData(void) +{ + free(gMap.data); +} + +void ReleasePartsImage(void) +{ + ReleaseSurface(SURFACE_ID_LEVEL_TILESET); +} + +void GetMapData(unsigned char **data, short *mw, short *ml) +{ + if (data != NULL) + *data = gMap.data; + + if (mw != NULL) + *mw = gMap.width; + + if (ml != NULL) + *ml = gMap.length; +} + +unsigned char GetAttribute(int x, int y) +{ + size_t a; + + if (x < 0 || y < 0 || x >= gMap.width || y >= gMap.length) + return 0; + + a = *(gMap.data + x + (y * gMap.width)); // Yes, the original code really does do this instead of a regular array access + return gMap.atrb[a]; +} + +void DeleteMapParts(int x, int y) +{ + *(gMap.data + x + (y * gMap.width)) = 0; +} + +void ShiftMapParts(int x, int y) +{ + *(gMap.data + x + (y * gMap.width)) -= 1; +} + +BOOL ChangeMapParts(int x, int y, unsigned char no) +{ + int i; + + if (*(gMap.data + x + (y * gMap.width)) == no) + return FALSE; + + *(gMap.data + x + (y * gMap.width)) = no; + + for (i = 0; i < 3; ++i) + SetNpChar(4, x * 0x200 * 0x10, y * 0x200 * 0x10, 0, 0, 0, NULL, 0); + + return TRUE; +} + +void PutStage_Back(int fx, int fy) +{ + int i, j; + RECT rect; + int offset; + + // Get range to draw + int num_x = ((WINDOW_WIDTH + (16 - 1)) / 16) + 1; + int num_y = ((WINDOW_HEIGHT + (16 - 1)) / 16) + 1; + int put_x = ((fx / 0x200) + 8) / 16; + int put_y = ((fy / 0x200) + 8) / 16; + + int atrb; + + for (j = put_y; j < put_y + num_y; ++j) + { + for (i = put_x; i < put_x + num_x; ++i) + { + // Get attribute + offset = (j * gMap.width) + i; + atrb = GetAttribute(i, j); + + if (atrb >= 0x20) + continue; + + // Draw tile + rect.left = (gMap.data[offset] % 16) * 16; + rect.top = (gMap.data[offset] / 16) * 16; + rect.right = rect.left + 16; + rect.bottom = rect.top + 16; + + PutBitmap3(&grcGame, ((i * 16) - 8) - (fx / 0x200), ((j * 16) - 8) - (fy / 0x200), &rect, SURFACE_ID_LEVEL_TILESET); + } + } +} + +void PutStage_Front(int fx, int fy) +{ + RECT rcSnack = {256, 48, 272, 64}; + int i, j; + RECT rect; + int offset; + + // Get range to draw + int num_x = ((WINDOW_WIDTH + (16 - 1)) / 16) + 1; + int num_y = ((WINDOW_HEIGHT + (16 - 1)) / 16) + 1; + int put_x = ((fx / 0x200) + 8) / 16; + int put_y = ((fy / 0x200) + 8) / 16; + + int atrb; + + for (j = put_y; j < put_y + num_y; ++j) + { + for (i = put_x; i < put_x + num_x; ++i) + { + // Get attribute + offset = (j * gMap.width) + i; + atrb = GetAttribute(i, j); + + if (atrb < 0x40 || atrb >= 0x80) + continue; + + // Draw tile + rect.left = (gMap.data[offset] % 16) * 16; + rect.top = (gMap.data[offset] / 16) * 16; + rect.right = rect.left + 16; + rect.bottom = rect.top + 16; + + PutBitmap3(&grcGame, ((i * 16) - 8) - (fx / 0x200), ((j * 16) - 8) - (fy / 0x200), &rect, SURFACE_ID_LEVEL_TILESET); + + if (atrb == 0x43) + PutBitmap3(&grcGame, ((i * 16) - 8) - (fx / 0x200), ((j * 16) - 8) - (fy / 0x200), &rcSnack, SURFACE_ID_NPC_SYM); + } + } +} + +void PutMapDataVector(int fx, int fy) +{ + int i, j; + RECT rect; + int offset; + + int num_x; + int num_y; + int put_x; + int put_y; + + static unsigned char count = 0; + + int atrb; + + // Animate the wind + count += 2; + + // Get range to draw + num_x = ((WINDOW_WIDTH + (16 - 1)) / 16) + 1; + num_y = ((WINDOW_HEIGHT + (16 - 1)) / 16) + 1; + put_x = ((fx / 0x200) + 8) / 16; + put_y = ((fy / 0x200) + 8) / 16; + + for (j = put_y; j < put_y + num_y; ++j) + { + for (i = put_x; i < put_x + num_x; ++i) + { + // Get attribute + offset = (j * gMap.width) + i; + atrb = GetAttribute(i, j); + + if (atrb != 0x80 + && atrb != 0x81 + && atrb != 0x82 + && atrb != 0x83 + && atrb != 0xA0 + && atrb != 0xA1 + && atrb != 0xA2 + && atrb != 0xA3) + continue; + + switch (atrb) + { + case 128: + case 160: + rect.left = 224 + (count % 16); + rect.right = rect.left + 16; + rect.top = 48; + rect.bottom = rect.top + 16; + break; + + case 129: + case 161: + rect.left = 224; + rect.right = rect.left + 16; + rect.top = 48 + (count % 16); + rect.bottom = rect.top + 16; + break; + + case 130: + case 162: + rect.left = 240 - (count % 16); + rect.right = rect.left + 16; + rect.top = 48; + rect.bottom = rect.top + 16; + break; + + case 131: + case 163: + rect.left = 224; + rect.right = rect.left + 16; + rect.top = 64 - (count % 16); + rect.bottom = rect.top + 16; + break; + } + + PutBitmap3(&grcGame, ((i * 16) - 8) - (fx / 0x200), ((j * 16) - 8) - (fy / 0x200), &rect, SURFACE_ID_CARET); + } + } +} diff --git a/src/Map.h b/src/Map.h new file mode 100644 index 0000000..1075976 --- /dev/null +++ b/src/Map.h @@ -0,0 +1,34 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef struct MAP_DATA +{ + unsigned char *data; + unsigned char atrb[0x100]; + short width; + short length; +} MAP_DATA; + +extern MAP_DATA gMap; + +BOOL InitMapData2(void); +BOOL LoadMapData2(const char *path_map); +BOOL LoadAttributeData(const char *path_atrb); +void EndMapData(void); +void ReleasePartsImage(void); +void GetMapData(unsigned char **data, short *mw, short *ml); +unsigned char GetAttribute(int x, int y); +void DeleteMapParts(int x, int y); +void ShiftMapParts(int x, int y); +BOOL ChangeMapParts(int x, int y, unsigned char no); +void PutStage_Back(int fx, int fy); +void PutStage_Front(int fx, int fy); +void PutMapDataVector(int fx, int fy); diff --git a/src/MapName.cpp b/src/MapName.cpp new file mode 100644 index 0000000..bfece4d --- /dev/null +++ b/src/MapName.cpp @@ -0,0 +1,138 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "MapName.h" + +#include + +#include "CommonDefines.h" +#include "Draw.h" +#include "WindowsWrapper.h" + +MAP_NAME gMapName; + +static RECT rc = { 0, 0, 160, 12 }; + +void ReadyMapName(const char *str) +{ + int a; + + // Handle "Studio Pixel presents" text in the intro, using an obfuscated string + unsigned char presentText[] = { +#ifdef JAPANESE + // "開発室Pixel presents" + 0x8A - 1, // 開 + 0x4A - 1, + 0x94 - 1, // 発 + 0xAD - 1, + 0x8E - 1, // 室 + 0xBA - 1, + 'P' - 1, + 'i' - 1, + 'x' - 1, + 'e' - 1, + 'l' - 1, + ' ' - 1, + 'p' - 1, + 'r' - 1, + 'e' - 1, + 's' - 1, + 'e' - 1, + 'n' - 1, + 't' - 1, + 's' - 1, +#else + // " Studio Pixel presents" + ' ' - 1, + ' ' - 1, + 'S' - 1, + 't' - 1, + 'u' - 1, + 'd' - 1, + 'i' - 1, + 'o' - 1, + ' ' - 1, + 'P' - 1, + 'i' - 1, + 'x' - 1, + 'e' - 1, + 'l' - 1, + ' ' - 1, + 'p' - 1, + 'r' - 1, + 'e' - 1, + 's' - 1, + 'e' - 1, + 'n' - 1, + 't' - 1, + 's' - 1, +#endif + 0xFF + }; + + // Reset map name flags + gMapName.flag = FALSE; + gMapName.wait = 0; + + if (!strcmp(str, "u")) + { + for (a = 0; a < (int)sizeof(presentText); ++a) + presentText[a] = presentText[a] + 1; + + str = (char*)presentText; + } + + // Copy map's name to the global map name + strcpy(gMapName.name, str); + + // Draw the text to the surface + a = (int)strlen(gMapName.name); + CortBox2(&rc, 0, SURFACE_ID_ROOM_NAME); + PutText2(((160 - (a * 6)) / 2) + 6, 1, gMapName.name, RGB(0x11, 0x00, 0x22), SURFACE_ID_ROOM_NAME); + PutText2(((160 - (a * 6)) / 2) + 6, 0, gMapName.name, RGB(0xFF, 0xFF, 0xFE), SURFACE_ID_ROOM_NAME); +} + +void PutMapName(BOOL bMini) +{ + // 'unused_rect' isn't the original name. The Linux port optimised this out, so there's no known name for it. + RECT unused_rect = {0, 0, 160, 16}; + + if (bMini) + { + // Map system + RECT rcBack; + rcBack.left = 0; + rcBack.right = WINDOW_WIDTH; + rcBack.top = 7; + rcBack.bottom = 24; + + CortBox(&rcBack, 0x000000); + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 86, 10, &rc, SURFACE_ID_ROOM_NAME); + } + else if (gMapName.flag) + { + // MNA + PutBitmap3(&grcGame, (WINDOW_WIDTH / 2) - 86, (WINDOW_HEIGHT / 2) - 40, &rc, SURFACE_ID_ROOM_NAME); + if (++gMapName.wait > 160) + gMapName.flag = FALSE; + } +} + +void StartMapName(void) +{ + gMapName.flag = TRUE; + gMapName.wait = 0; +} + +void RestoreMapName(void) +{ + int a = (int)strlen(gMapName.name); + + CortBox2(&rc, 0, SURFACE_ID_ROOM_NAME); + PutText2(((160 - (a * 6)) / 2) + 6, 1, gMapName.name, RGB(0x11, 0x00, 0x22), SURFACE_ID_ROOM_NAME); + PutText2(((160 - (a * 6)) / 2) + 6, 0, gMapName.name, RGB(0xFF, 0xFF, 0xFE), SURFACE_ID_ROOM_NAME); +} diff --git a/src/MapName.h b/src/MapName.h new file mode 100644 index 0000000..c55bffe --- /dev/null +++ b/src/MapName.h @@ -0,0 +1,24 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef struct MAP_NAME +{ + BOOL flag; + int wait; + char name[0x20]; +} MAP_NAME; + +extern MAP_NAME gMapName; + +void ReadyMapName(const char *str); +void PutMapName(BOOL bMini); +void StartMapName(void); +void RestoreMapName(void); diff --git a/src/MiniMap.cpp b/src/MiniMap.cpp new file mode 100644 index 0000000..7026f4b --- /dev/null +++ b/src/MiniMap.cpp @@ -0,0 +1,240 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "MiniMap.h" + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Escape.h" +#include "KeyControl.h" +#include "Main.h" +#include "Map.h" +#include "MapName.h" +#include "MyChar.h" +#include "Stage.h" + +void WriteMiniMapLine(int line) +{ + int x; + unsigned char a; + + RECT rcLevel[4] = { + {240, 24, 241, 25}, + {241, 24, 242, 25}, + {242, 24, 243, 25}, + {243, 24, 244, 25}, + }; + + for (x = 0; x < gMap.width; ++x) + { + a = GetAttribute(x, line); + + // Yup, this really is an if/else chain. + // No switch here. + if (a == 0) + Surface2Surface(x, line, &rcLevel[0], SURFACE_ID_MAP, SURFACE_ID_TEXT_BOX); + else if (a == 68 || + a == 1 || + a == 64 || + a == 128 || + a == 129 || + a == 130 || + a == 131 || + a == 81 || + a == 82 || + a == 85 || + a == 86 || + a == 2 || + a == 96 || + a == 113 || + a == 114 || + a == 117 || + a == 118 || + a == 160 || + a == 161 || + a == 162 || + a == 163) + Surface2Surface(x, line, &rcLevel[1], SURFACE_ID_MAP, SURFACE_ID_TEXT_BOX); + else if (a == 67 || + a == 99 || + a == 80 || + a == 83 || + a == 84 || + a == 87 || + a == 96 || // This is already listed above, so this part of the expression is always false + a == 112 || + a == 115 || + a == 116 || + a == 119) + Surface2Surface(x, line, &rcLevel[2], SURFACE_ID_MAP, SURFACE_ID_TEXT_BOX); + else + Surface2Surface(x, line, &rcLevel[3], SURFACE_ID_MAP, SURFACE_ID_TEXT_BOX); + } +} + +int MiniMapLoop(void) +{ + int f, line; + RECT rcView; + RECT rcMiniMap; + + int my_x; + int my_y; + unsigned char my_wait; + RECT my_rect = {0, 57, 1, 58}; + + my_x = ((gMC.x / 0x200) + 8) / 16; + my_y = ((gMC.y / 0x200) + 8) / 16; + + for (f = 0; f <= 8; ++f) + { + GetTrg(); + + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; + } + } + + PutBitmap4(&grcGame, 0, 0, &grcGame, SURFACE_ID_SCREEN_GRAB); + + rcView.left = (WINDOW_WIDTH / 2) - (((gMap.width * f) / 8) / 2); + rcView.right = (WINDOW_WIDTH / 2) + (((gMap.width * f) / 8) / 2); + rcView.top = (WINDOW_HEIGHT / 2) - (((gMap.length * f) / 8) / 2); + rcView.bottom = (WINDOW_HEIGHT / 2) + (((gMap.length * f) / 8) / 2); + + PutMapName(TRUE); + CortBox(&rcView, 0); + + PutFramePerSecound(); + if (!Flip_SystemTask(ghWnd)) + return enum_ESCRETURN_exit; + } + + rcMiniMap.left = 0; + rcMiniMap.right = gMap.width; + rcMiniMap.top = 0; + rcMiniMap.bottom = gMap.length; + + rcView.left -= 1; + rcView.right = rcView.left + gMap.width + 2; + rcView.top -= 1; + rcView.bottom = rcView.top + gMap.length + 2; + CortBox2(&rcMiniMap, 0, SURFACE_ID_MAP); + + line = 0; + my_wait = 0; + while (1) + { + GetTrg(); + + if (gKeyTrg & (gKeyOk | gKeyCancel)) + break; + + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; + } + } + + PutBitmap4(&grcGame, 0, 0, &grcGame, SURFACE_ID_SCREEN_GRAB); + CortBox(&rcView, 0); + + if (line < gMap.length) + { + WriteMiniMapLine(line); + ++line; + } + // I guess Pixel duplicated this block of code because he + // wanted the minimap to draw faster? + if (line < gMap.length) + { + WriteMiniMapLine(line); + ++line; + } + + PutBitmap3(&grcGame, rcView.left + 1, rcView.top + 1, &rcMiniMap, SURFACE_ID_MAP); + + PutMapName(TRUE); + + if (++my_wait / 8 % 2) + PutBitmap3(&grcGame, my_x + rcView.left + 1, my_y + rcView.top + 1, &my_rect, SURFACE_ID_TEXT_BOX); + + PutFramePerSecound(); + if (!Flip_SystemTask(ghWnd)) + return enum_ESCRETURN_exit; + } + + for (f = 8; f >= -1; --f) + { + GetTrg(); + + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; + } + } + + PutBitmap4(&grcGame, 0, 0, &grcGame, SURFACE_ID_SCREEN_GRAB); + + rcView.left = (WINDOW_WIDTH / 2) - (((gMap.width * f) / 8) / 2); + rcView.right = (WINDOW_WIDTH / 2) + (((gMap.width * f) / 8) / 2); + rcView.top = (WINDOW_HEIGHT / 2) - (((gMap.length * f) / 8) / 2); + rcView.bottom = (WINDOW_HEIGHT / 2) + (((gMap.length * f) / 8) / 2); + + PutMapName(TRUE); + CortBox(&rcView, 0); + + PutFramePerSecound(); + if (!Flip_SystemTask(ghWnd)) + return enum_ESCRETURN_exit; + } + + return enum_ESCRETURN_continue; +} + +signed char gMapping[0x80]; + +BOOL IsMapping(void) +{ + if (!gMapping[gStageNo]) + return FALSE; + else + return TRUE; +} + +void StartMapping(void) +{ + memset(gMapping, FALSE, sizeof(gMapping)); +} + +void SetMapping(int a) +{ + gMapping[a] = TRUE; +} diff --git a/src/MiniMap.h b/src/MiniMap.h new file mode 100644 index 0000000..33d72d9 --- /dev/null +++ b/src/MiniMap.h @@ -0,0 +1,17 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +extern signed char gMapping[0x80]; + +int MiniMapLoop(void); +BOOL IsMapping(void); +void StartMapping(void); +void SetMapping(int a); diff --git a/src/MyChar.cpp b/src/MyChar.cpp new file mode 100644 index 0000000..25f9f72 --- /dev/null +++ b/src/MyChar.cpp @@ -0,0 +1,1051 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "MyChar.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Draw.h" +#include "Flags.h" +#include "Game.h" +#include "KeyControl.h" +#include "MycParam.h" +#include "NpChar.h" +#include "Sound.h" +#include "Star.h" +#include "TextScr.h" +#include "ValueView.h" + +MYCHAR gMC; + +void InitMyChar(void) +{ + memset(&gMC, 0, sizeof(MYCHAR)); + gMC.cond = 0x80; + gMC.direct = 2; + + gMC.view.back = 8 * 0x200; + gMC.view.top = 8 * 0x200; + gMC.view.front = 8 * 0x200; + gMC.view.bottom = 8 * 0x200; + + gMC.hit.back = 5 * 0x200; + gMC.hit.top = 8 * 0x200; + gMC.hit.front = 5 * 0x200; + gMC.hit.bottom = 8 * 0x200; + + gMC.life = 3; + gMC.max_life = 3; + gMC.unit = 0; +} + +void AnimationMyChar(BOOL bKey) +{ + RECT rcLeft[12] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {0, 0, 16, 16}, + {32, 0, 48, 16}, + {0, 0, 16, 16}, + {48, 0, 64, 16}, + {64, 0, 80, 16}, + {48, 0, 64, 16}, + {80, 0, 96, 16}, + {48, 0, 64, 16}, + {96, 0, 112, 16}, + {112, 0, 128, 16}, + }; + + RECT rcRight[12] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {0, 16, 16, 32}, + {32, 16, 48, 32}, + {0, 16, 16, 32}, + {48, 16, 64, 32}, + {64, 16, 80, 32}, + {48, 16, 64, 32}, + {80, 16, 96, 32}, + {48, 16, 64, 32}, + {96, 16, 112, 32}, + {112, 16, 128, 32}, + }; + + if (gMC.cond & 2) + return; + + if (gMC.flag & 8) + { + if (gMC.cond & 1) + { + gMC.ani_no = 11; + } + else if (gKey & gKeyUp && gKey & (gKeyLeft | gKeyRight) && bKey) + { + gMC.cond |= 4; + + if (++gMC.ani_wait > 4) + { + gMC.ani_wait = 0; + + if (++gMC.ani_no == 7 || gMC.ani_no == 9) + PlaySoundObject(24, SOUND_MODE_PLAY); + } + + if (gMC.ani_no > 9 || gMC.ani_no < 6) + gMC.ani_no = 6; + } + else if (gKey & (gKeyLeft | gKeyRight) && bKey) + { + gMC.cond |= 4; + + if (++gMC.ani_wait > 4) + { + gMC.ani_wait = 0; + + if (++gMC.ani_no == 2 || gMC.ani_no == 4) + PlaySoundObject(24, SOUND_MODE_PLAY); + } + + if (gMC.ani_no > 4 || gMC.ani_no < 1) + gMC.ani_no = 1; + } + else if (gKey & gKeyUp && bKey) + { + if (gMC.cond & 4) + PlaySoundObject(24, SOUND_MODE_PLAY); + + gMC.cond &= ~4; + gMC.ani_no = 5; + } + else + { + if (gMC.cond & 4) + PlaySoundObject(24, SOUND_MODE_PLAY); + + gMC.cond &= ~4; + gMC.ani_no = 0; + } + } + else if (gMC.up) + { + gMC.ani_no = 6; + } + else if (gMC.down) + { + gMC.ani_no = 10; + } + else + { + if (gMC.ym > 0) + gMC.ani_no = 1; + else + gMC.ani_no = 3; + } + + if (gMC.direct == 0) + gMC.rect = rcLeft[gMC.ani_no]; + else + gMC.rect = rcRight[gMC.ani_no]; +} + +void ShowMyChar(BOOL bShow) +{ + if (bShow) + gMC.cond &= ~2; + else + gMC.cond |= 2; +} + +void PutMyChar(int fx, int fy) +{ + int arms_offset_y; + + if (!(gMC.cond & 0x80) || gMC.cond & 2) + return; + + // Draw weapon + gMC.rect_arms.left = (gArmsData[gSelectedArms].code % 13) * 24; + gMC.rect_arms.right = gMC.rect_arms.left + 24; + gMC.rect_arms.top = (gArmsData[gSelectedArms].code / 13) * 96; + gMC.rect_arms.bottom = gMC.rect_arms.top + 16; + + if (gMC.direct == 2) + { + gMC.rect_arms.top += 16; + gMC.rect_arms.bottom += 16; + } + + if (gMC.up) + { + arms_offset_y = -4; + gMC.rect_arms.top += 32; + gMC.rect_arms.bottom += 32; + } + else if (gMC.down) + { + arms_offset_y = 4; + gMC.rect_arms.top += 64; + gMC.rect_arms.bottom += 64; + } + else + { + arms_offset_y = 0; + } + + if (gMC.ani_no == 1 || gMC.ani_no == 3 || gMC.ani_no == 6 || gMC.ani_no == 8) + ++gMC.rect_arms.top; + + if (gMC.direct == 0) + PutBitmap3( + &grcGame, + ((gMC.x - gMC.view.front) / 0x200) - (fx / 0x200) - 8, + ((gMC.y - gMC.view.top) / 0x200) - (fy / 0x200) + arms_offset_y, + &gMC.rect_arms, + SURFACE_ID_ARMS); + else + PutBitmap3( + &grcGame, + ((gMC.x - gMC.view.front) / 0x200) - (fx / 0x200), + ((gMC.y - gMC.view.top) / 0x200) - (fy / 0x200) + arms_offset_y, + &gMC.rect_arms, + SURFACE_ID_ARMS); + + if (gMC.shock / 2 % 2) + return; + + // Draw player + RECT rect = gMC.rect; + if (gMC.equip & EQUIP_MIMIGA_MASK) + { + rect.top += 32; + rect.bottom += 32; + } + + PutBitmap3(&grcGame, ((gMC.x - gMC.view.front) / 0x200) - (fx / 0x200), ((gMC.y - gMC.view.top) / 0x200) - (fy / 0x200), &rect, SURFACE_ID_MY_CHAR); + + // Draw air tank + RECT rcBubble[2] = { + {56, 96, 80, 120}, + {80, 96, 104, 120}, + }; + + ++gMC.bubble; + if (gMC.equip & EQUIP_AIR_TANK && gMC.flag & 0x100) + PutBitmap3(&grcGame, (gMC.x / 0x200) - 12 - (fx / 0x200), (gMC.y / 0x200) - 12 - (fy / 0x200), &rcBubble[gMC.bubble / 2 % 2], SURFACE_ID_CARET); + else if (gMC.unit == 1) + PutBitmap3(&grcGame, (gMC.x / 0x200) - 12 - (fx / 0x200), (gMC.y / 0x200) - 12 - (fy / 0x200), &rcBubble[gMC.bubble / 2 % 2], SURFACE_ID_CARET); +} + +void ActMyChar_Normal(BOOL bKey) +{ + // Get speeds and accelerations + int max_move; // Unused + int max_dash; + int gravity1; + int gravity2; + int jump; + int dash1; + int dash2; + int resist; + + int a, x; + + if (gMC.cond & 2) + return; + + if (gMC.flag & 0x100) + { + max_dash = 0x32C / 2; + max_move = 0x5FF / 2; + gravity1 = 0x50 / 2; + gravity2 = 0x20 / 2; + jump = 0x500 / 2; + dash1 = 0x200 / 6 / 2; + dash2 = 0x200 / 16 / 2; + resist = 0x200 / 10 / 2; + } + else + { + max_dash = 0x32C; + max_move = 0x5FF; + gravity1 = 0x50; + gravity2 = 0x20; + jump = 0x500; + dash1 = 0x200 / 6; + dash2 = 0x200 / 16; + resist = 0x200 / 10; + } + + // Don't create "?" effect + gMC.ques = FALSE; + + // If can't control player, stop boosting + if (!bKey) + gMC.boost_sw = 0; + + // Movement on the ground + if (gMC.flag & 8 || gMC.flag & 0x10 || gMC.flag & 0x20) + { + // Stop boosting and refuel + gMC.boost_sw = 0; + + if (gMC.equip & EQUIP_BOOSTER_0_8) + { + gMC.boost_cnt = 50; + } + else if (gMC.equip & EQUIP_BOOSTER_2_0) + { + gMC.boost_cnt = 50; + } + else + { + gMC.boost_cnt = 0; + } + + // Move in direction held + if (bKey) + { + if (gKeyTrg == gKeyDown && gKey == gKeyDown && !(gMC.cond & 1) && !(g_GameFlags & 4)) + { + gMC.cond |= 1; + gMC.ques = TRUE; + } + else if (gKey == gKeyDown) + { + // There probably used to be commented-out code here + } + else + { + if (gKey & gKeyLeft && gMC.xm > -max_dash) + gMC.xm -= dash1; + if (gKey & gKeyRight && gMC.xm < max_dash) + gMC.xm += dash1; + + if (gKey & gKeyLeft) + gMC.direct = 0; + if (gKey & gKeyRight) + gMC.direct = 2; + } + } + + // Friction + if (!(gMC.cond & 0x20)) + { + if (gMC.xm < 0) + { + if (gMC.xm > -resist) + gMC.xm = 0; + else + gMC.xm += resist; + } + if (gMC.xm > 0) + { + if (gMC.xm < resist) + gMC.xm = 0; + else + gMC.xm -= resist; + } + } + } + else + { + // Start boosting + if (bKey) + { + if (gMC.equip & (EQUIP_BOOSTER_0_8 | EQUIP_BOOSTER_2_0) && gKeyTrg & gKeyJump && gMC.boost_cnt != 0) + { + // Booster 0.8 + if (gMC.equip & EQUIP_BOOSTER_0_8) + { + gMC.boost_sw = 1; + + if (gMC.ym > 0x100) + gMC.ym /= 2; + } + + // Booster 2.0 + if (gMC.equip & EQUIP_BOOSTER_2_0) + { + if (gKey & gKeyUp) + { + gMC.boost_sw = 2; + gMC.xm = 0; + gMC.ym = -0x5FF; + } + else if (gKey & gKeyLeft) + { + gMC.boost_sw = 1; + gMC.ym = 0; + gMC.xm = -0x5FF; + } + else if (gKey & gKeyRight) + { + gMC.boost_sw = 1; + gMC.ym = 0; + gMC.xm = 0x5FF; + } + else if (gKey & gKeyDown) + { + gMC.boost_sw = 3; + gMC.xm = 0; + gMC.ym = 0x5FF; + } + else + { + gMC.boost_sw = 2; + gMC.xm = 0; + gMC.ym = -0x5FF; + } + } + } + + // Move left and right + if (gKey & gKeyLeft && gMC.xm > -max_dash) + gMC.xm -= dash2; + if (gKey & gKeyRight && gMC.xm < max_dash) + gMC.xm += dash2; + + if (gKey & gKeyLeft) + gMC.direct = 0; + if (gKey & gKeyRight) + gMC.direct = 2; + } + + // Slow down when stopped boosting (Booster 2.0) + if (gMC.equip & EQUIP_BOOSTER_2_0 && gMC.boost_sw != 0 && (!(gKey & gKeyJump) || gMC.boost_cnt == 0)) + { + if (gMC.boost_sw == 1) + gMC.xm /= 2; + else if (gMC.boost_sw == 2) + gMC.ym /= 2; + } + + // Stop boosting + if (gMC.boost_cnt == 0 || !(gKey & gKeyJump)) + gMC.boost_sw = 0; + } + + // Jumping + if (bKey) + { + // Look up and down + if (gKey & gKeyUp) + gMC.up = TRUE; + else + gMC.up = FALSE; + + if (gKey & gKeyDown && !(gMC.flag & 8)) + gMC.down = TRUE; + else + gMC.down = FALSE; + + if (gKeyTrg & gKeyJump && (gMC.flag & 8 || gMC.flag & 0x10 || gMC.flag & 0x20)) + { + if (gMC.flag & 0x2000) + { + // Another weird empty case needed for accurate assembly. + // There probably used to be some commented-out code here. + } + else + { + gMC.ym = -jump; + PlaySoundObject(15, SOUND_MODE_PLAY); + } + } + } + + // Stop interacting when moved + if (bKey && gKey & (gKeyLeft | gKeyRight | gKeyUp | gKeyJump | gKeyShot)) + gMC.cond &= ~1; + + // Booster losing fuel + if (gMC.boost_sw != 0 && gMC.boost_cnt != 0) + --gMC.boost_cnt; + + // Wind / current forces + if (gMC.flag & 0x1000) + gMC.xm -= 0x88; + if (gMC.flag & 0x2000) + gMC.ym -= 0x80; + if (gMC.flag & 0x4000) + gMC.xm += 0x88; + if (gMC.flag & 0x8000) + gMC.ym += 0x55; + + // Booster 2.0 forces and effects + if (gMC.equip & EQUIP_BOOSTER_2_0 && gMC.boost_sw != 0) + { + if (gMC.boost_sw == 1) + { + // Go up when going into a wall + if (gMC.flag & 5) + gMC.ym = -0x100; + + // Move in direction facing + if (gMC.direct == 0) + gMC.xm -= 0x20; + if (gMC.direct == 2) + gMC.xm += 0x20; + + // Boost particles (and sound) + if (gKeyTrg & gKeyJump || gMC.boost_cnt % 3 == 1) + { + if (gMC.direct == 0) + SetCaret(gMC.x + (2 * 0x200), gMC.y + (2 * 0x200), CARET_EXHAUST, DIR_RIGHT); + if (gMC.direct == 2) + SetCaret(gMC.x - (2 * 0x200), gMC.y + (2 * 0x200), CARET_EXHAUST, DIR_LEFT); + + PlaySoundObject(113, SOUND_MODE_PLAY); + } + } + else if (gMC.boost_sw == 2) + { + // Move upwards + gMC.ym -= 0x20; + + // Boost particles (and sound) + if (gKeyTrg & gKeyJump || gMC.boost_cnt % 3 == 1) + { + SetCaret(gMC.x, gMC.y + (6 * 0x200), CARET_EXHAUST, DIR_DOWN); + PlaySoundObject(113, SOUND_MODE_PLAY); + } + } + else if (gMC.boost_sw == 3 && (gKeyTrg & gKeyJump || gMC.boost_cnt % 3 == 1)) + { + // Boost particles (and sound) + SetCaret(gMC.x, gMC.y - (6 * 0x200), CARET_EXHAUST, DIR_UP); + PlaySoundObject(113, SOUND_MODE_PLAY); + } + } + // Upwards wind/current + else if (gMC.flag & 0x2000) + { + gMC.ym += gravity1; + } + // Booster 0.8 + else if (gMC.equip & EQUIP_BOOSTER_0_8 && gMC.boost_sw != 0 && gMC.ym > -0x400) + { + // Upwards force + gMC.ym -= 0x20; + + if (gMC.boost_cnt % 3 == 0) + { + SetCaret(gMC.x, gMC.y + (gMC.hit.bottom / 2), CARET_EXHAUST, DIR_DOWN); + PlaySoundObject(113, SOUND_MODE_PLAY); + } + + // Bounce off of ceiling + if (gMC.flag & 2) + gMC.ym = 0x200; + } + // Gravity while jump is held + else if (gMC.ym < 0 && bKey && gKey & gKeyJump) + { + gMC.ym += gravity2; + } + // Normal gravity + else + { + gMC.ym += gravity1; + } + + // Keep player on slopes + if (!bKey || !(gKeyTrg & gKeyJump)) + { + if (gMC.flag & 0x10 && gMC.xm < 0) + gMC.ym = -gMC.xm; + if (gMC.flag & 0x20 && gMC.xm > 0) + gMC.ym = gMC.xm; + if (gMC.flag & 8 && gMC.flag & 0x80000 && gMC.xm < 0) + gMC.ym = 0x400; + if (gMC.flag & 8 && gMC.flag & 0x10000 && gMC.xm > 0) + gMC.ym = 0x400; + if (gMC.flag & 8 && gMC.flag & 0x20000 && gMC.flag & 0x40000) + gMC.ym = 0x400; + } + + if (0) + { + // There used to be an if-statement here that didn't do anything, but the compiler optimised it out. + // We only know this was here because empty if-statements affect the register usage. + // Since there's no code, we have no idea what the original condition actually was. + } + + // Limit speed + if (gMC.flag & 0x100 && !(gMC.flag & 0xF000)) + { + if (gMC.xm < -0x2FF) + gMC.xm = -0x2FF; + if (gMC.xm > 0x2FF) + gMC.xm = 0x2FF; + if (gMC.ym < -0x2FF) + gMC.ym = -0x2FF; + if (gMC.ym > 0x2FF) + gMC.ym = 0x2FF; + } + else + { + if (gMC.xm < -0x5FF) + gMC.xm = -0x5FF; + if (gMC.xm > 0x5FF) + gMC.xm = 0x5FF; + if (gMC.ym < -0x5FF) + gMC.ym = -0x5FF; + if (gMC.ym > 0x5FF) + gMC.ym = 0x5FF; + } + + // Water splashing + if (!gMC.sprash && gMC.flag & 0x100) + { + int dir; + + if (gMC.flag & 0x800) + dir = 2; + else + dir = 0; + + if (!(gMC.flag & 8) && gMC.ym > 0x200) + { + for (a = 0; a < 8; ++a) + { + x = gMC.x + (Random(-8, 8) * 0x200); + SetNpChar(73, x, gMC.y, gMC.xm + Random(-0x200, 0x200), Random(-0x200, 0x80) - (gMC.ym / 2), dir, NULL, 0); + } + + PlaySoundObject(56, SOUND_MODE_PLAY); + } + else + { + if (gMC.xm > 0x200 || gMC.xm < -0x200) + { + for (a = 0; a < 8; ++a) + { + x = gMC.x + (Random(-8, 8) * 0x200); + SetNpChar(73, x, gMC.y, gMC.xm + Random(-0x200, 0x200), Random(-0x200, 0x80), dir, NULL, 0); + } + + PlaySoundObject(56, SOUND_MODE_PLAY); + } + } + + gMC.sprash = TRUE; + } + + if (!(gMC.flag & 0x100)) + gMC.sprash = FALSE; + + // Spike damage + if (gMC.flag & 0x400) + DamageMyChar(10); + + // Camera + if (gMC.direct == 0) + { + gMC.index_x -= 0x200; + if (gMC.index_x < -0x8000) + gMC.index_x = -0x8000; + } + else + { + gMC.index_x += 0x200; + if (gMC.index_x > 0x8000) + gMC.index_x = 0x8000; + } + if (gKey & gKeyUp && bKey) + { + gMC.index_y -= 0x200; + if (gMC.index_y < -0x8000) + gMC.index_y = -0x8000; + } + else if (gKey & gKeyDown && bKey) + { + gMC.index_y += 0x200; + if (gMC.index_y > 0x8000) + gMC.index_y = 0x8000; + } + else + { + if (gMC.index_y > 0x200) + gMC.index_y -= 0x200; + if (gMC.index_y < -0x200) + gMC.index_y += 0x200; + } + + gMC.tgt_x = gMC.x + gMC.index_x; + gMC.tgt_y = gMC.y + gMC.index_y; + + // Change position + if (gMC.xm <= resist && gMC.xm >= -resist) + { + // This case is completely empty. This is most likely the result of commented-out code or some other change (so this is most likely inaccurate to the original source code) + } + else + { + gMC.x += gMC.xm; + } + + gMC.y += gMC.ym; +} + +void ActMyChar_Stream(BOOL bKey) +{ + gMC.up = FALSE; + gMC.down = FALSE; + + if (bKey) + { + if (gKey & (gKeyLeft | gKeyRight)) + { + if (gKey & gKeyLeft) + gMC.xm -= 0x100; + + if (gKey & gKeyRight) + gMC.xm += 0x100; + } + else if (gMC.xm < 0x80 && gMC.xm > -0x80) + { + gMC.xm = 0; + } + else if (gMC.xm > 0) + { + gMC.xm -= 0x80; + } + else if (gMC.xm < 0) + { + gMC.xm += 0x80; + } + + if (gKey & (gKeyUp | gKeyDown)) + { + if (gKey & gKeyUp) + gMC.ym -= 0x100; + + if (gKey & gKeyDown) + gMC.ym += 0x100; + } + else if (gMC.ym < 0x80 && gMC.ym > -0x80) + { + gMC.ym = 0; + } + else if (gMC.ym > 0) + { + gMC.ym -= 0x80; + } + else if (gMC.ym < 0) + { + gMC.ym += 0x80; + } + } + else + { + if (gMC.xm < 0x80 && gMC.xm > -0x40) + gMC.xm = 0; + else if (gMC.xm > 0) + gMC.xm -= 0x80; + else if (gMC.xm < 0) + gMC.xm += 0x80; + + if (gMC.ym < 0x80 && gMC.ym > -0x40) + gMC.ym = 0; + else if (gMC.ym > 0) + gMC.ym -= 0x80; + else if (gMC.ym < 0) + gMC.ym += 0x80; + } + + if (gMC.ym < -0x200 && gMC.flag & 2) + SetCaret(gMC.x, gMC.y - gMC.hit.top, CARET_TINY_PARTICLES, DIR_OTHER); + if (gMC.ym > 0x200 && gMC.flag & 8) + SetCaret(gMC.x, gMC.y + gMC.hit.bottom, CARET_TINY_PARTICLES, DIR_OTHER); + + if (gMC.xm > 0x400) + gMC.xm = 0x400; + if (gMC.xm < -0x400) + gMC.xm = -0x400; + + if (gMC.ym > 0x400) + gMC.ym = 0x400; + if (gMC.ym < -0x400) + gMC.ym = -0x400; + + if ((gKey & (gKeyLeft | gKeyUp)) == (gKeyLeft | gKeyUp)) + { + if (gMC.xm < -780) + gMC.xm = -780; + if (gMC.ym < -780) + gMC.ym = -780; + } + + if ((gKey & (gKeyRight | gKeyUp)) == (gKeyRight | gKeyUp)) + { + if (gMC.xm > 780) + gMC.xm = 780; + if (gMC.ym < -780) + gMC.ym = -780; + } + + if ((gKey & (gKeyLeft | gKeyDown)) == (gKeyLeft | gKeyDown)) + { + if (gMC.xm < -780) + gMC.xm = -780; + if (gMC.ym > 780) + gMC.ym = 780; + } + + if ((gKey & (gKeyRight | gKeyDown)) == (gKeyRight | gKeyDown)) + { + if (gMC.xm > 780) + gMC.xm = 780; + if (gMC.ym > 780) + gMC.ym = 780; + } + + gMC.x += gMC.xm; + gMC.y += gMC.ym; +} + +void AirProcess(void) +{ + if (gMC.equip & EQUIP_AIR_TANK) + { + gMC.air = 1000; + gMC.air_get = 0; + } + else + { + if (!(gMC.flag & 0x100)) + { + gMC.air = 1000; + } + else + { + if (--gMC.air <= 0) + { + if (GetNPCFlag(4000)) + { + // Core cutscene + StartTextScript(1100); + } + else + { + // Drown + StartTextScript(41); + + if (gMC.direct == 0) + SetCaret(gMC.x, gMC.y, CARET_DROWNED_QUOTE, DIR_LEFT); + else + SetCaret(gMC.x, gMC.y, CARET_DROWNED_QUOTE, DIR_RIGHT); + + gMC.cond &= ~0x80; + } + } + } + + if (gMC.flag & 0x100) + { + gMC.air_get = 60; + } + else + { + if (gMC.air_get != 0) + --gMC.air_get; + } + } +} + +void ActMyChar(BOOL bKey) +{ + if (!(gMC.cond & 0x80)) + return; + + if (gMC.exp_wait != 0) + --gMC.exp_wait; + + if (gMC.shock != 0) + { + --gMC.shock; + } + else if (gMC.exp_count != 0) + { + SetValueView(&gMC.x, &gMC.y, gMC.exp_count); + gMC.exp_count = 0; + } + + switch (gMC.unit) + { + case 0: + if (!(g_GameFlags & 4) && bKey) + AirProcess(); + + ActMyChar_Normal(bKey); + break; + + case 1: + ActMyChar_Stream(bKey); + break; + } + + gMC.cond &= ~0x20; +} + +void GetMyCharPosition(int *x, int *y) +{ + *x = gMC.x; + *y = gMC.y; +} + +void SetMyCharPosition(int x, int y) +{ + gMC.x = x; + gMC.y = y; + gMC.tgt_x = gMC.x; + gMC.tgt_y = gMC.y; + gMC.index_x = 0; + gMC.index_y = 0; + gMC.xm = 0; + gMC.ym = 0; + gMC.cond &= ~1; + InitStar(); +} + +void MoveMyChar(int x, int y) +{ + gMC.x = x; + gMC.y = y; +} + +void ZeroMyCharXMove(void) +{ + gMC.xm = 0; +} + +int GetUnitMyChar(void) +{ + return gMC.unit; +} + +void SetMyCharDirect(unsigned char dir) +{ + int i; + + if (dir == 3) + { + gMC.cond |= 1; + } + else + { + gMC.cond &= ~1; + + if (dir < 10) + { + gMC.direct = dir; + } + else + { + for (i = 0; i < NPC_MAX; ++i) + if (gNPC[i].code_event == dir) + break; + + if (i == NPC_MAX) + return; + + if (gMC.x > gNPC[i].x) + gMC.direct = 0; + else + gMC.direct = 2; + } + } + + gMC.xm = 0; + AnimationMyChar(FALSE); +} + +void ChangeMyUnit(unsigned char a) +{ + gMC.unit = a; +} + +void PitMyChar(void) +{ + gMC.y += 2 * 0x10 * 0x200; // Shove player two tiles down. I wonder what this was meant for? +} + +void EquipItem(int flag, BOOL b) +{ + if (b) + gMC.equip |= flag; + else + gMC.equip &= ~flag; +} + +void ResetCheck(void) +{ + gMC.cond &= ~1; +} + +static int noise_no; +static unsigned int noise_freq; + +void SetNoise(int no, int freq) +{ + noise_freq = freq; + noise_no = no; + + switch (noise_no) + { + case 1: + ChangeSoundFrequency(40, noise_freq); + ChangeSoundFrequency(41, noise_freq + 100); + PlaySoundObject(40, SOUND_MODE_PLAY_LOOP); + PlaySoundObject(41, SOUND_MODE_PLAY_LOOP); + break; + + case 2: + PlaySoundObject(58, SOUND_MODE_PLAY_LOOP); + break; + } +} + +void CutNoise(void) +{ + noise_no = 0; + PlaySoundObject(40, SOUND_MODE_STOP); + PlaySoundObject(41, SOUND_MODE_STOP); + PlaySoundObject(58, SOUND_MODE_STOP); +} + +void ResetNoise(void) +{ + switch (noise_no) + { + case 1: + ChangeSoundFrequency(40, noise_freq); + ChangeSoundFrequency(41, noise_freq + 100); + PlaySoundObject(40, SOUND_MODE_PLAY_LOOP); + PlaySoundObject(41, SOUND_MODE_PLAY_LOOP); + break; + + case 2: + PlaySoundObject(58, SOUND_MODE_PLAY_LOOP); + break; + } +} + +void SleepNoise(void) +{ + PlaySoundObject(40, SOUND_MODE_STOP); + PlaySoundObject(41, SOUND_MODE_STOP); + PlaySoundObject(58, SOUND_MODE_STOP); +} diff --git a/src/MyChar.h b/src/MyChar.h new file mode 100644 index 0000000..7c49365 --- /dev/null +++ b/src/MyChar.h @@ -0,0 +1,96 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" + +// TODO - When I add bitmask constants for gMC.flags... +// 0x100 is a 'player is underwater' flag + +// gMC.equip +enum +{ + EQUIP_BOOSTER_0_8 = 1, + EQUIP_MAP = 2, + EQUIP_ARMS_BARRIER = 4, + EQUIP_TURBOCHARGE = 8, + EQUIP_AIR_TANK = 0x10, + EQUIP_BOOSTER_2_0 = 0x20, + EQUIP_MIMIGA_MASK = 0x40, + EQUIP_WHIMSICAL_STAR = 0x80, + EQUIP_NIKUMARU_COUNTER = 0x100 +}; + +typedef struct MYCHAR +{ + unsigned char cond; + unsigned int flag; + int direct; + BOOL up; + BOOL down; + int unit; + int equip; + int x; + int y; + int tgt_x; + int tgt_y; + int index_x; + int index_y; + int xm; + int ym; + int ani_wait; + int ani_no; + OTHER_RECT hit; + OTHER_RECT view; + RECT rect; + RECT rect_arms; + int level; + int exp_wait; + int exp_count; + unsigned char shock; + unsigned char no_life; + unsigned char rensha; + unsigned char bubble; + short life; + short star; + short max_life; + short a; + int lifeBr; + int lifeBr_count; + int air; + int air_get; + signed char sprash; // This is explicitly a char, but used like a BOOL + signed char ques; // Same for this variable as well + signed char boost_sw; + int boost_cnt; +} MYCHAR; + +extern MYCHAR gMC; + +void InitMyChar(void); +void AnimationMyChar(BOOL bKey); +void ShowMyChar(BOOL bShow); +void PutMyChar(int fx, int fy); +void ActMyChar_Normal(BOOL bKey); +void ActMyChar(BOOL bKey); +void GetMyCharPosition(int *x, int *y); +void SetMyCharPosition(int x, int y); +void MoveMyChar(int x, int y); +void ZeroMyCharXMove(void); +int GetUnitMyChar(void); +void SetMyCharDirect(unsigned char dir); +void ChangeMyUnit(unsigned char a); +void PitMyChar(void); +void EquipItem(int flag, BOOL b); +void ResetCheck(void); +void SetNoise(int no, int freq); +void CutNoise(void); +void ResetNoise(void); +void SleepNoise(void); diff --git a/src/MycHit.cpp b/src/MycHit.cpp new file mode 100644 index 0000000..0e57142 --- /dev/null +++ b/src/MycHit.cpp @@ -0,0 +1,925 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "MycHit.h" + +#include "WindowsWrapper.h" + +#include "Back.h" +#include "Boss.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Game.h" +#include "KeyControl.h" +#include "Map.h" +#include "MyChar.h" +#include "MycParam.h" +#include "NpChar.h" +#include "Sound.h" +#include "TextScr.h" + +void ResetMyCharFlag(void) +{ + gMC.flag = 0; +} + +static void PutlittleStar(void) +{ + if (!(gMC.cond & 2) && gMC.ym < -0x200) + { + PlaySoundObject(3, SOUND_MODE_PLAY); + SetCaret(gMC.x, gMC.y - gMC.hit.top, CARET_TINY_PARTICLES, DIR_LEFT); + SetCaret(gMC.x, gMC.y - gMC.hit.top, CARET_TINY_PARTICLES, DIR_LEFT); + } +} + +int JudgeHitMyCharBlock(int x, int y) +{ + int hit = 0; + + // Left wall + if (gMC.y - gMC.hit.top < (y * 0x10 + 4) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 4) * 0x200 + && gMC.x - gMC.hit.back < (x * 0x10 + 8) * 0x200 + && gMC.x - gMC.hit.back > x * 0x10 * 0x200) + { + // Clip + gMC.x = ((x * 0x10 + 8) * 0x200) + gMC.hit.back; + + // Halt momentum + if (gMC.xm < -0x180) + gMC.xm = -0x180; + if (!(gKey & gKeyLeft) && gMC.xm < 0) + gMC.xm = 0; + + // Set that a left wall was hit + hit |= 1; + } + + // Right wall + if (gMC.y - gMC.hit.top < (y * 0x10 + 4) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 4) * 0x200 + && gMC.x + gMC.hit.back > (x * 0x10 - 8) * 0x200 + && gMC.x + gMC.hit.back < x * 0x10 * 0x200) + { + // Clip + gMC.x = ((x * 0x10 - 8) * 0x200) - gMC.hit.back; + + // Halt momentum + if (gMC.xm > 0x180) + gMC.xm = 0x180; + if (!(gKey & gKeyRight) && gMC.xm > 0) + gMC.xm = 0; + + // Set that a right wall was hit + hit |= 4; + } + + // Ceiling + if (gMC.x - gMC.hit.back < (x * 0x10 + 5) * 0x200 + && gMC.x + gMC.hit.back > (x * 0x10 - 5) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 + 8) * 0x200 + && gMC.y - gMC.hit.top > y * 0x10 * 0x200) + { + // Clip + gMC.y = ((y * 0x10 + 8) * 0x200) + gMC.hit.top; + + // Halt momentum + if (!(gMC.cond & 2) && gMC.ym < -0x200) + PutlittleStar(); + if (gMC.ym < 0) + gMC.ym = 0; + + // Set that a ceiling was hit + hit |= 2; + } + + // Floor + if (gMC.x - gMC.hit.back < (x * 0x10 + 5) * 0x200 + && gMC.x + gMC.hit.back > ((x * 0x10 - 5) * 0x200) + && gMC.y + gMC.hit.bottom > (y * 0x10 - 8) * 0x200 + && gMC.y + gMC.hit.bottom < y * 0x10 * 0x200) + { + // Clip + gMC.y = ((y * 0x10 - 8) * 0x200) - gMC.hit.bottom; + + // Halt momentum + if (gMC.ym > 0x400) + PlaySoundObject(23, SOUND_MODE_PLAY); + if (gMC.ym > 0) + gMC.ym = 0; + + // Set that a floor was hit + hit |= 8; + } + + return hit; +} + +int JudgeHitMyCharTriangleA(int x, int y) +{ + int hit = 0; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 * 0x200) - (gMC.x - x * 0x10 * 0x200) / 2 + 0x800 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 + gMC.hit.top; + + // Halt momentum + if (!(gMC.cond & 2) && gMC.ym < -0x200) + PutlittleStar(); + if (gMC.ym < 0) + gMC.ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + return hit; +} + +int JudgeHitMyCharTriangleB(int x, int y) +{ + int hit = 0; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 + gMC.hit.top; + + // Halt momentum + if (!(gMC.cond & 2) && gMC.ym < -0x200) + PutlittleStar(); + if (gMC.ym < 0) + gMC.ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + return hit; +} + +int JudgeHitMyCharTriangleC(int x, int y) +{ + int hit = 0; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 + gMC.hit.top; + + // Halt momentum + if (!(gMC.cond & 2) && gMC.ym < -0x200) + PutlittleStar(); + if (gMC.ym < 0) + gMC.ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + return hit; +} + +int JudgeHitMyCharTriangleD(int x, int y) +{ + int hit = 0; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 + gMC.hit.top; + + // Halt momentum + if (!(gMC.cond & 2) && gMC.ym < -0x200) + PutlittleStar(); + if (gMC.ym < 0) + gMC.ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + return hit; +} + +int JudgeHitMyCharTriangleE(int x, int y) +{ + int hit = 0; + + hit |= 0x10000; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 + && gMC.y - gMC.hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 - gMC.hit.bottom; + + // Halt momentum + if (gMC.ym > 0x400) + PlaySoundObject(23, SOUND_MODE_PLAY); + if (gMC.ym > 0) + gMC.ym = 0; + + // Set that hit this slope + hit |= 0x28; + } + + return hit; +} + +int JudgeHitMyCharTriangleF(int x, int y) +{ + int hit = 0; + + hit |= 0x20000; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 + && gMC.y - gMC.hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) + ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 - gMC.hit.bottom; + + // Halt momentum + if (gMC.ym > 0x400) + PlaySoundObject(23, SOUND_MODE_PLAY); + if (gMC.ym > 0) + gMC.ym = 0; + + // Set that hit this slope + hit |= 0x28; + } + + return hit; +} + +int JudgeHitMyCharTriangleG(int x, int y) +{ + int hit = 0; + + hit |= 0x40000; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 + && gMC.y - gMC.hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) + 0x800 - gMC.hit.bottom; + + // Halt momentum + if (gMC.ym > 0x400) + PlaySoundObject(23, SOUND_MODE_PLAY); + if (gMC.ym > 0) + gMC.ym = 0; + + // Set that hit this slope + hit |= 0x18; + } + + return hit; +} + +int JudgeHitMyCharTriangleH(int x, int y) +{ + int hit = 0; + + hit |= 0x80000; + + if (gMC.x < (x * 0x10 + 8) * 0x200 + && gMC.x > (x * 0x10 - 8) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 + && gMC.y - gMC.hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + gMC.y = (y * 0x10 * 0x200) - ((gMC.x - x * 0x10 * 0x200) / 2) - 0x800 - gMC.hit.bottom; + + // Halt momentum + if (gMC.ym > 0x400) + PlaySoundObject(23, SOUND_MODE_PLAY); + if (gMC.ym > 0) + gMC.ym = 0; + + // Set that hit this slope + hit |= 0x18; + } + + return hit; +} + +int JudgeHitMyCharWater(int x, int y) +{ + int hit = 0; + + if (gMC.x - gMC.hit.back < (x * 0x10 + 5) * 0x200 + && gMC.x + gMC.hit.back > ((x * 0x10 - 5) * 0x200) + && gMC.y - gMC.hit.top < ((y * 0x10 + 5) * 0x200) + && gMC.y + gMC.hit.bottom > y * 0x10 * 0x200) + hit |= 0x100; + + return hit; +} + +int JudgeHitMyCharDamage(int x, int y) +{ + int hit = 0; + + if (gMC.x - 0x800 < (x * 0x10 + 4) * 0x200 + && gMC.x + 0x800 > (x * 0x10 - 4) * 0x200 + && gMC.y - 0x800 < (y * 0x10 + 3) * 0x200 + && gMC.y + 0x800 > (y * 0x10 - 3) * 0x200) + hit |= 0x400; + + return hit; +} + +int JudgeHitMyCharDamageW(int x, int y) +{ + int hit = 0; + + if (gMC.x - 0x800 < (x * 0x10 + 4) * 0x200 + && gMC.x + 0x800 > (x * 0x10 - 4) * 0x200 + && gMC.y - 0x800 < (y * 0x10 + 3) * 0x200 + && gMC.y + 0x800 > (y * 0x10 - 3) * 0x200) + hit |= 0xD00; + + return hit; +} + +int JudgeHitMyCharVectLeft(int x, int y) +{ + int hit = 0; + if (gMC.x - gMC.hit.back < (x * 0x10 + 6) * 0x200 + && gMC.x + gMC.hit.back > (x * 0x10 - 6) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 + 6) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 6) * 0x200) + hit |= 0x1000; + + return hit; +} + +int JudgeHitMyCharVectUp(int x, int y) +{ + int hit = 0; + if (gMC.x - gMC.hit.back < (x * 0x10 + 6) * 0x200 + && gMC.x + gMC.hit.back > (x * 0x10 - 6) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 + 6) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 6) * 0x200) + hit |= 0x2000; + + return hit; +} + +int JudgeHitMyCharVectRight(int x, int y) +{ + int hit = 0; + if (gMC.x - gMC.hit.back < (x * 0x10 + 6) * 0x200 + && gMC.x + gMC.hit.back > (x * 0x10 - 6) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 + 6) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 6) * 0x200) + hit |= 0x4000; + + return hit; +} + +int JudgeHitMyCharVectDown(int x, int y) +{ + int hit = 0; + if (gMC.x - gMC.hit.back < (x * 0x10 + 6) * 0x200 + && gMC.x + gMC.hit.back > (x * 0x10 - 6) * 0x200 + && gMC.y - gMC.hit.top < (y * 0x10 + 6) * 0x200 + && gMC.y + gMC.hit.bottom > (y * 0x10 - 6) * 0x200) + hit |= 0x8000; + + return hit; +} + +void HitMyCharMap(void) +{ + int x, y; + int i; + unsigned char atrb[4]; + + x = gMC.x / 0x10 / 0x200; + y = gMC.y / 0x10 / 0x200; + + int offx[4]; + int offy[4]; + + offx[0] = 0; + offx[1] = 1; + offx[2] = 0; + offx[3] = 1; + + offy[0] = 0; + offy[1] = 0; + offy[2] = 1; + offy[3] = 1; + + for (i = 0; i < 4; ++i) + { + atrb[i] = GetAttribute(x + offx[i], y + offy[i]); + + switch (atrb[i]) + { + // Block + case 0x05: + case 0x41: + case 0x43: + case 0x46: + gMC.flag |= JudgeHitMyCharBlock(x + offx[i], y + offy[i]); + break; + + // Slopes + case 0x50: + gMC.flag |= JudgeHitMyCharTriangleA(x + offx[i], y + offy[i]); + break; + + case 0x51: + gMC.flag |= JudgeHitMyCharTriangleB(x + offx[i], y + offy[i]); + break; + + case 0x52: + gMC.flag |= JudgeHitMyCharTriangleC(x + offx[i], y + offy[i]); + break; + + case 0x53: + gMC.flag |= JudgeHitMyCharTriangleD(x + offx[i], y + offy[i]); + break; + + case 0x54: + gMC.flag |= JudgeHitMyCharTriangleE(x + offx[i], y + offy[i]); + break; + + case 0x55: + gMC.flag |= JudgeHitMyCharTriangleF(x + offx[i], y + offy[i]); + break; + + case 0x56: + gMC.flag |= JudgeHitMyCharTriangleG(x + offx[i], y + offy[i]); + break; + + case 0x57: + gMC.flag |= JudgeHitMyCharTriangleH(x + offx[i], y + offy[i]); + break; + + // Spikes + case 0x42: + gMC.flag |= JudgeHitMyCharDamage(x + offx[i], y + offy[i]); + break; + + // Water spikes + case 0x62: + gMC.flag |= JudgeHitMyCharDamageW(x + offx[i], y + offy[i]); + break; + + // Wind + case 0x80: + gMC.flag |= JudgeHitMyCharVectLeft(x + offx[i], y + offy[i]); + break; + + case 0x81: + gMC.flag |= JudgeHitMyCharVectUp(x + offx[i], y + offy[i]); + break; + + case 0x82: + gMC.flag |= JudgeHitMyCharVectRight(x + offx[i], y + offy[i]); + break; + + case 0x83: + gMC.flag |= JudgeHitMyCharVectDown(x + offx[i], y + offy[i]); + break; + + // Water + case 0x02: + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + // Water and water blocks (same as the previous case) + case 0x60: + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x61: + gMC.flag |= JudgeHitMyCharBlock(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + // Water slopes + case 0x70: + gMC.flag |= JudgeHitMyCharTriangleA(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x71: + gMC.flag |= JudgeHitMyCharTriangleB(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x72: + gMC.flag |= JudgeHitMyCharTriangleC(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x73: + gMC.flag |= JudgeHitMyCharTriangleD(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x74: + gMC.flag |= JudgeHitMyCharTriangleE(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x75: + gMC.flag |= JudgeHitMyCharTriangleF(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x76: + gMC.flag |= JudgeHitMyCharTriangleG(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0x77: + gMC.flag |= JudgeHitMyCharTriangleH(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + // Water current + case 0xA0: + gMC.flag |= JudgeHitMyCharVectLeft(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0xA1: + gMC.flag |= JudgeHitMyCharVectUp(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0xA2: + gMC.flag |= JudgeHitMyCharVectRight(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + + case 0xA3: + gMC.flag |= JudgeHitMyCharVectDown(x + offx[i], y + offy[i]); + gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]); + break; + } + } + + if (gMC.y > gWaterY + (4 * 0x200)) + gMC.flag |= 0x100; +} + +int JudgeHitMyCharNPC(NPCHAR *npc) +{ + int hit = 0; + + if (gMC.y - gMC.hit.top < npc->y + npc->hit.bottom - (3 * 0x200) + && gMC.y + gMC.hit.bottom > npc->y - npc->hit.top + (3 * 0x200) + && gMC.x - gMC.hit.back < npc->x + npc->hit.back + && gMC.x - gMC.hit.back > npc->x) + { + if (gMC.xm < 0x200) + gMC.xm += 0x200; + hit |= 1; + } + + if (gMC.y - gMC.hit.top < npc->y + npc->hit.bottom - (3 * 0x200) + && gMC.y + gMC.hit.bottom > npc->y - npc->hit.top + (3 * 0x200) + && gMC.x + gMC.hit.back - 0x200 > npc->x - npc->hit.back + && gMC.x + gMC.hit.back - 0x200 < npc->x) + { + if (gMC.xm > -0x200) + gMC.xm -= 0x200; + hit |= 4; + } + + if (gMC.x - gMC.hit.back < npc->x + npc->hit.back - (3 * 0x200) + && gMC.x + gMC.hit.back > npc->x - npc->hit.back + (3 * 0x200) + && gMC.y - gMC.hit.top < npc->y + npc->hit.bottom + && gMC.y - gMC.hit.top > npc->y) + { + if (gMC.ym < 0) + gMC.ym = 0; + hit |= 2; + } + + if (gMC.x - gMC.hit.back < npc->x + npc->hit.back - (3 * 0x200) + && gMC.x + gMC.hit.back > npc->x - npc->hit.back + (3 * 0x200) + && gMC.y + gMC.hit.bottom > npc->y - npc->hit.top + && gMC.hit.bottom + gMC.y < npc->y + (3 * 0x200)) + { + if (npc->bits & NPC_BOUNCY) + { + gMC.ym = npc->ym - 0x200; + hit |= 8; + } + else if (!(gMC.flag & 8) && gMC.ym > npc->ym) + { + gMC.y = npc->y - npc->hit.top - gMC.hit.bottom + 0x200; + gMC.ym = npc->ym; + gMC.x += npc->xm; + hit |= 8; + } + } + + return hit; +} + +unsigned char JudgeHitMyCharNPC3(NPCHAR *npc) +{ + if (npc->direct == 0) + { + if (gMC.x + (2 * 0x200) > npc->x - npc->hit.front + && gMC.x - (2 * 0x200) < npc->x + npc->hit.back + && gMC.y + (2 * 0x200) > npc->y - npc->hit.top + && gMC.y - (2 * 0x200) < npc->y + npc->hit.bottom) + return 1; + } + else + { + if (gMC.x + (2 * 0x200) > npc->x - npc->hit.back + && gMC.x - (2 * 0x200) < npc->x + npc->hit.front + && gMC.y + (2 * 0x200) > npc->y - npc->hit.top + && gMC.y - (2 * 0x200) < npc->y + npc->hit.bottom) + return 1; + } + + return 0; +} + +int JudgeHitMyCharNPC4(NPCHAR *npc) +{ + // TODO: comment this + int hit = 0; + + float fy1; + float fx1; + float fx2; + float fy2; + + if (npc->x > gMC.x) + fx1 = (float)(npc->x - gMC.x); + else + fx1 = (float)(gMC.x - npc->x); + + if (npc->y > gMC.y) + fy1 = (float)(npc->y - gMC.y); + else + fy1 = (float)(gMC.y - npc->y); + + fx2 = (float)npc->hit.back; + fy2 = (float)npc->hit.top; + + if (fx1 == 0.0f) + fx1 = 1.0f; + if (fx2 == 0.0f) + fx2 = 1.0f; + + if (fy1 / fx1 > fy2 / fx2) + { + if (gMC.x - gMC.hit.back < npc->x + npc->hit.back && gMC.x + gMC.hit.back > npc->x - npc->hit.back) + { + if (gMC.y - gMC.hit.top < npc->y + npc->hit.bottom && gMC.y - gMC.hit.top > npc->y) + { + if (gMC.ym < npc->ym) + { + gMC.y = npc->y + npc->hit.bottom + gMC.hit.top + 0x200; + gMC.ym = npc->ym; + } + else + { + if (gMC.ym < 0) + gMC.ym = 0; + } + + hit |= 2; + } + + if (gMC.y + gMC.hit.bottom > npc->y - npc->hit.top && gMC.hit.bottom + gMC.y < npc->y + (3 * 0x200)) + { + if (gMC.ym - npc->ym > 2 * 0x200) + PlaySoundObject(23, SOUND_MODE_PLAY); + + if (gMC.unit == 1) + { + gMC.y = npc->y - npc->hit.top - gMC.hit.bottom + 0x200; + hit |= 8; + } + else if (npc->bits & NPC_BOUNCY) + { + gMC.ym = npc->ym - 0x200; + hit |= 8; + } + else if (!(gMC.flag & 8) && gMC.ym > npc->ym) + { + gMC.y = npc->y - npc->hit.top - gMC.hit.bottom + 0x200; + gMC.ym = npc->ym; + gMC.x += npc->xm; + hit |= 8; + } + } + } + } + else + { + if (gMC.y - gMC.hit.top < npc->y + npc->hit.bottom && gMC.y + gMC.hit.bottom > npc->y - npc->hit.top) + { + if (gMC.x - gMC.hit.back < npc->x + npc->hit.back && gMC.x - gMC.hit.back > npc->x) + { + if (gMC.xm < npc->xm) + gMC.xm = npc->xm; + + gMC.x = npc->x + npc->hit.back + gMC.hit.back; + + hit |= 1; + } + + if (gMC.x + gMC.hit.back > npc->x - npc->hit.back && gMC.hit.back + gMC.x < npc->x) + { + if (gMC.xm > npc->xm) + gMC.xm = npc->xm; + + gMC.x = npc->x - npc->hit.back - gMC.hit.back; + + hit |= 4; + } + } + } + + return hit; +} + +void HitMyCharNpChar(void) +{ + int i; + int hit = 0; + + if (!(gMC.cond & 0x80) || gMC.cond & 2) + return; + + for (i = 0; i < NPC_MAX; ++i) + { + if (!(gNPC[i].cond & 0x80)) + continue; + + hit = 0; + + if (gNPC[i].bits & NPC_SOLID_SOFT) + { + hit = JudgeHitMyCharNPC(&gNPC[i]); + gMC.flag |= hit; + } + else if (gNPC[i].bits & NPC_SOLID_HARD) + { + hit = JudgeHitMyCharNPC4(&gNPC[i]); + gMC.flag |= hit; + } + else + { + hit = JudgeHitMyCharNPC3(&gNPC[i]); + } + + // Special NPCs (pickups) + if (hit != 0 && gNPC[i].code_char == 1) + { + PlaySoundObject(14, SOUND_MODE_PLAY); + AddExpMyChar(gNPC[i].exp); + gNPC[i].cond = 0; + } + + if (hit != 0 && gNPC[i].code_char == 86) + { + PlaySoundObject(42, SOUND_MODE_PLAY); + AddBulletMyChar(gNPC[i].code_event, gNPC[i].exp); + gNPC[i].cond = 0; + } + + if (hit != 0 && gNPC[i].code_char == 87) + { + PlaySoundObject(20, SOUND_MODE_PLAY); + AddLifeMyChar(gNPC[i].exp); + gNPC[i].cond = 0; + } + + // Run event on contact + if (!(g_GameFlags & 4) && hit != 0 && gNPC[i].bits & NPC_EVENT_WHEN_TOUCHED) + StartTextScript(gNPC[i].code_event); + + // NPC damage + if (g_GameFlags & 2 && !(gNPC[i].bits & NPC_INTERACTABLE)) + { + if (gNPC[i].bits & NPC_REAR_AND_TOP_DONT_HURT) + { + if (hit & 4 && gNPC[i].xm < 0) + DamageMyChar(gNPC[i].damage); + if (hit & 1 && gNPC[i].xm > 0) + DamageMyChar(gNPC[i].damage); + if (hit & 8 && gNPC[i].ym < 0) + DamageMyChar(gNPC[i].damage); + if (hit & 2 && gNPC[i].ym > 0) + DamageMyChar(gNPC[i].damage); + } + else if (hit != 0 && gNPC[i].damage && !(g_GameFlags & 4)) + { + DamageMyChar(gNPC[i].damage); + } + } + + // Interaction + if (!(g_GameFlags & 4) && hit != 0 && gMC.cond & 1 && gNPC[i].bits & NPC_INTERACTABLE) + { + StartTextScript(gNPC[i].code_event); + gMC.xm = 0; + gMC.ques = FALSE; + } + } + + // Create question mark when NPC hasn't been interacted with + if (gMC.ques) + SetCaret(gMC.x, gMC.y, CARET_QUESTION_MARK, DIR_LEFT); +} + +void HitMyCharBoss(void) +{ + int b; + int hit = 0; + + if (!(gMC.cond & 0x80) || gMC.cond & 2) + return; + + for (b = 0; b < BOSS_MAX; ++b) + { + if (!(gBoss[b].cond & 0x80)) + continue; + + hit = 0; + + if (gBoss[b].bits & NPC_SOLID_SOFT) + { + hit = JudgeHitMyCharNPC(&gBoss[b]); + gMC.flag |= hit; + } + else if (gBoss[b].bits & NPC_SOLID_HARD) + { + hit = JudgeHitMyCharNPC4(&gBoss[b]); + gMC.flag |= hit; + } + else + { + hit = JudgeHitMyCharNPC3(&gBoss[b]); + } + + if (!(g_GameFlags & 4) && hit != 0 && gBoss[b].bits & NPC_EVENT_WHEN_TOUCHED) + { + StartTextScript(gBoss[b].code_event); + gMC.ques = FALSE; + } + + if (gBoss[b].bits & NPC_REAR_AND_TOP_DONT_HURT) + { + if (hit & 4 && gBoss[b].xm < 0) + DamageMyChar(gBoss[b].damage); + if (hit & 1 && gBoss[b].xm > 0) + DamageMyChar(gBoss[b].damage); + } + else if (hit != 0 && gBoss[b].damage != 0 && !(g_GameFlags & 4)) + { + DamageMyChar(gBoss[b].damage); + } + + if (!(g_GameFlags & 4) && hit != 0 && gMC.cond & 1 && gBoss[b].bits & NPC_INTERACTABLE) + { + StartTextScript(gBoss[b].code_event); + gMC.xm = 0; + gMC.ques = FALSE; + } + } + + if (gMC.ques) + SetCaret(gMC.x, gMC.y, CARET_QUESTION_MARK, DIR_LEFT); +} diff --git a/src/MycHit.h b/src/MycHit.h new file mode 100644 index 0000000..2d1261b --- /dev/null +++ b/src/MycHit.h @@ -0,0 +1,13 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ResetMyCharFlag(void); +void HitMyCharMap(void); +void HitMyCharNpChar(void); +void HitMyCharBoss(void); diff --git a/src/MycParam.cpp b/src/MycParam.cpp new file mode 100644 index 0000000..6cddc45 --- /dev/null +++ b/src/MycParam.cpp @@ -0,0 +1,539 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "MycParam.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "CommonDefines.h" +#include "Caret.h" +#include "Draw.h" +#include "Game.h" +#include "Main.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "TextScr.h" +#include "ValueView.h" + +ARMS_LEVEL gArmsLevelTable[14] = +{ + {{0, 0, 100}}, + {{30, 40, 16}}, + {{10, 20, 10}}, + {{10, 20, 20}}, + {{30, 40, 10}}, + {{10, 20, 10}}, + {{10, 20, 30}}, + {{10, 20, 5}}, + {{10, 20, 100}}, + {{30, 60, 0}}, + {{30, 60, 10}}, + {{10, 20, 100}}, + {{1, 1, 1}}, + {{40, 60, 200}} +}; + +void AddExpMyChar(int x) +{ + int lv = gArmsData[gSelectedArms].level - 1; + int arms_code = gArmsData[gSelectedArms].code; + + gArmsData[gSelectedArms].exp += x; + + if (lv == 2) + { + if (gArmsData[gSelectedArms].exp >= gArmsLevelTable[arms_code].exp[lv]) + { + gArmsData[gSelectedArms].exp = gArmsLevelTable[arms_code].exp[lv]; + + if (gMC.equip & EQUIP_WHIMSICAL_STAR) + { + if (gMC.star < 3) + ++gMC.star; + } + } + } + else + { + for (; lv < 2; ++lv) + { + if (gArmsData[gSelectedArms].exp >= gArmsLevelTable[arms_code].exp[lv]) + { + ++gArmsData[gSelectedArms].level; + gArmsData[gSelectedArms].exp = 0; + + if (gArmsData[gSelectedArms].code != 13) + { + PlaySoundObject(27, SOUND_MODE_PLAY); + SetCaret(gMC.x, gMC.y, CARET_LEVEL_UP, DIR_LEFT); + } + } + } + } + + if (gArmsData[gSelectedArms].code != 13) + { + gMC.exp_count += x; + gMC.exp_wait = 30; + } + else + { + gMC.exp_wait = 10; + } +} + +void ZeroExpMyChar(void) +{ + gArmsData[gSelectedArms].level = 1; + gArmsData[gSelectedArms].exp = 0; +} + +BOOL IsMaxExpMyChar(void) +{ + int arms_code; + + if (gArmsData[gSelectedArms].level == 3) + { + arms_code = gArmsData[gSelectedArms].code; + + if (gArmsData[gSelectedArms].exp >= gArmsLevelTable[arms_code].exp[2]) + return TRUE; + } + + return FALSE; +} + +void DamageMyChar(int damage) +{ +#ifdef FIX_BUGS + if (!(g_GameFlags & 2)) +#else + // I'm preeeetty sure this is a typo. The Linux port optimised this entire check out. + if (!(g_GameFlags | 2)) +#endif + return; + + if (gMC.shock) + return; + + // Damage player + PlaySoundObject(16, SOUND_MODE_PLAY); + gMC.cond &= ~1; + gMC.shock = 128; + + if (gMC.unit == 1) + { + // Another weird case where there *has* to be an empty 'if' here to produce the same assembly. + // Chances are there used to be some commented-out code here. + } + else + { + gMC.ym = -0x400; + } + + gMC.life -= (short)damage; + + // Lose a whimsical star + if (gMC.equip & EQUIP_WHIMSICAL_STAR && gMC.star > 0) + gMC.star = (short)gMC.star - 1; // For some reason, this does a cast to short. Might not be accurate to the original source code (possibly, Pixel was just being careful about int size/conversion, or this is from some weird macro) + + // Lose experience + if (gMC.equip & EQUIP_ARMS_BARRIER) + gArmsData[gSelectedArms].exp -= damage; + else + gArmsData[gSelectedArms].exp -= damage * 2; + + while (gArmsData[gSelectedArms].exp < 0) + { + if (gArmsData[gSelectedArms].level > 1) + { + --gArmsData[gSelectedArms].level; + + int lv = gArmsData[gSelectedArms].level - 1; + int arms_code = gArmsData[gSelectedArms].code; + + gArmsData[gSelectedArms].exp = gArmsLevelTable[arms_code].exp[lv] + gArmsData[gSelectedArms].exp; + + if (gMC.life > 0 && gArmsData[gSelectedArms].code != 13) + SetCaret(gMC.x, gMC.y, CARET_LEVEL_UP, DIR_RIGHT); + } + else + { + gArmsData[gSelectedArms].exp = 0; + } + } + + // Tell player how much damage was taken + SetValueView(&gMC.x, &gMC.y, -damage); + + // Death + if (gMC.life <= 0) + { + PlaySoundObject(17, SOUND_MODE_PLAY); + gMC.cond = 0; + SetDestroyNpChar(gMC.x, gMC.y, 10 * 0x200, 0x40); + StartTextScript(40); + } +} + +void ZeroArmsEnergy_All(void) +{ + int a; + + for (a = 0; a < ARMS_MAX; a++) + { + gArmsData[a].level = 1; + gArmsData[a].exp = 0; + } +} + +void AddBulletMyChar(int no, int val) +{ + int a; + + // Missile Launcher + a = 0; + while (a < ARMS_MAX && gArmsData[a].code != 5) + ++a; + + if (a == ARMS_MAX) + { + // Super Missile Launcher + a = 0; + while (a < ARMS_MAX && gArmsData[a].code != 10) + ++a; + + if (a == ARMS_MAX) + return; + } + + gArmsData[a].num += val; + if (gArmsData[a].num > gArmsData[a].max_num) + gArmsData[a].num = gArmsData[a].max_num; +} + +void AddLifeMyChar(int x) +{ + gMC.life += (short)x; + if (gMC.life > gMC.max_life) + gMC.life = gMC.max_life; + gMC.lifeBr = gMC.life; +} + +void AddMaxLifeMyChar(int val) +{ + gMC.max_life += (short)val; + if (gMC.max_life > 232) + gMC.max_life = 232; + gMC.life += (short)val; + gMC.lifeBr = gMC.life; +} + +void PutArmsEnergy(BOOL flash) +{ + static unsigned char add_flash; + + RECT rcPer = {72, 48, 80, 56}; + RECT rcLv = {80, 80, 96, 88}; + RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + RECT rcNone = {80, 48, 96, 56}; + + if (gArmsEnergyX > 16) + gArmsEnergyX -= 2; + if (gArmsEnergyX < 16) + gArmsEnergyX += 2; + + // Draw max ammo + if (gArmsData[gSelectedArms].max_num) + { + PutNumber4(gArmsEnergyX + 32, 16, gArmsData[gSelectedArms].num, FALSE); + PutNumber4(gArmsEnergyX + 32, 24, gArmsData[gSelectedArms].max_num, FALSE); + } + else + { + PutBitmap3(&rcView, gArmsEnergyX + 48, 16, &rcNone, SURFACE_ID_TEXT_BOX); + PutBitmap3(&rcView, gArmsEnergyX + 48, 24, &rcNone, SURFACE_ID_TEXT_BOX); + } + + // Draw experience and ammo + if (flash == TRUE && (gMC.shock / 2) % 2) + return; + + PutBitmap3(&rcView, gArmsEnergyX + 32, 24, &rcPer, SURFACE_ID_TEXT_BOX); + PutBitmap3(&rcView, gArmsEnergyX, 32, &rcLv, SURFACE_ID_TEXT_BOX); + PutNumber4(gArmsEnergyX - 8, 32, gArmsData[gSelectedArms].level, FALSE); + + RECT rcExpBox = {0, 72, 40, 80}; + RECT rcExpVal = {0, 80, 0, 88}; + RECT rcExpMax = {40, 72, 80, 80}; + RECT rcExpFlash = {40, 80, 80, 88}; + + int lv = gArmsData[gSelectedArms].level - 1; + +#ifdef FIX_MAJOR_BUGS + // When the player has no weapons, the default level is 0, which becomes -1. + // Catch it, and set it to 0 instead, so the following array-accesses aren't + // out-of-bounds. + if (lv < 0) + lv = 0; +#endif + + int arms_code = gArmsData[gSelectedArms].code; + int exp_now = gArmsData[gSelectedArms].exp; + int exp_next = gArmsLevelTable[arms_code].exp[lv]; + + PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpBox, SURFACE_ID_TEXT_BOX); + + if (lv == 2 && gArmsData[gSelectedArms].exp == gArmsLevelTable[arms_code].exp[lv]) + { + PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpMax, SURFACE_ID_TEXT_BOX); + } + else + { + if (exp_next != 0) + rcExpVal.right += (exp_now * 40) / exp_next; + else + rcExpVal.right = 0; + + PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpVal, SURFACE_ID_TEXT_BOX); + } + + if (gMC.exp_wait && ((add_flash++ / 2) % 2)) + PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpFlash, SURFACE_ID_TEXT_BOX); +} + +void PutActiveArmsList(void) +{ + int x; + int a; + RECT rect = {0, 0, 0, 16}; + + int arms_num = 0; + while (gArmsData[arms_num].code != 0) + ++arms_num; + + if (arms_num == 0) + return; + + for (a = 0; a < arms_num; ++a) + { + // Get X position to draw at + x = ((a - gSelectedArms) * 16) + gArmsEnergyX; + + if (x < 8) + x += 48 + (arms_num * 16); + else if (x >= 24) + x += 48; + + if (x >= 72 + ((arms_num - 1) * 16)) + x -= 48 + (arms_num * 16); + if (x < 72 && x >= 24) + x -= 48; + + // Draw icon + rect.left = gArmsData[a].code * 16; + rect.right = rect.left + 16; + PutBitmap3(&grcGame, x, 16, &rect, SURFACE_ID_ARMS_IMAGE); + } +} + +void PutMyLife(BOOL flash) +{ + RECT rcCase = {0, 40, 232, 48}; + RECT rcLife = {0, 24, 232, 32}; + RECT rcBr = {0, 32, 232, 40}; + + if (flash == TRUE && gMC.shock / 2 % 2) + return; + + if (gMC.lifeBr < gMC.life) + gMC.lifeBr = gMC.life; + + if (gMC.lifeBr > gMC.life) + { + if (++gMC.lifeBr_count > 30) + --gMC.lifeBr; + } + else + { + gMC.lifeBr_count = 0; + } + + // Draw bar + rcCase.right = 64; + rcLife.right = ((gMC.life * 40) / gMC.max_life) - 1; + rcBr.right = ((gMC.lifeBr * 40) / gMC.max_life) - 1; + + PutBitmap3(&grcGame, 16, 40, &rcCase, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, 40, 40, &rcBr, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, 40, 40, &rcLife, SURFACE_ID_TEXT_BOX); + PutNumber4(8, 40, gMC.lifeBr, FALSE); +} + +void PutMyAir(int x, int y) +{ + RECT rcAir[2] = { + {112, 72, 144, 80}, + {112, 80, 144, 88}, + }; + + if (gMC.equip & EQUIP_AIR_TANK) + return; + + if (gMC.air_get != 0) + { + // Draw how much air is left + if (gMC.air_get % 6 < 4) + PutNumber4(x + 32, y, gMC.air / 10, FALSE); + + // Draw "AIR" text + if (gMC.air % 30 > 10) + PutBitmap3(&grcGame, x, y, &rcAir[0], SURFACE_ID_TEXT_BOX); + else + PutBitmap3(&grcGame, x, y, &rcAir[1], SURFACE_ID_TEXT_BOX); + } +} + +static int time_count; + +void PutTimeCounter(int x, int y) +{ + RECT rcTime[3] = { + {112, 104, 120, 112}, + {120, 104, 128, 112}, + {128, 104, 160, 112}, + }; + + if (gMC.equip & EQUIP_NIKUMARU_COUNTER) + { + // Draw clock and increase time + if (g_GameFlags & 2) + { + if (time_count < 100 * 60 * 50) // 100 minutes + ++time_count; + + if (time_count % 30 > 10) + PutBitmap3(&grcGame, x, y, &rcTime[0], SURFACE_ID_TEXT_BOX); + else + PutBitmap3(&grcGame, x, y, &rcTime[1], SURFACE_ID_TEXT_BOX); + } + else + { + PutBitmap3(&grcGame, x, y, &rcTime[0], SURFACE_ID_TEXT_BOX); + } + + // Draw time + PutNumber4(x, y, time_count / (60 * 50), FALSE); + PutNumber4(x + 20, y, time_count / 50 % 60, TRUE); + PutNumber4(x + 32, y, time_count / 5 % 10, FALSE); + PutBitmap3(&grcGame, x + 30, y, &rcTime[2], SURFACE_ID_TEXT_BOX); + } + else + { + time_count = 0; + } +} + +BOOL SaveTimeCounter(void) +{ + int i; + unsigned char *p; + REC rec; + FILE *fp; + char path[MAX_PATH]; + + // Quit if player doesn't have the Nikumaru Counter + if (!(gMC.equip & EQUIP_NIKUMARU_COUNTER)) + return TRUE; + + // Get last time + sprintf(path, "%s\\290.rec", gModulePath); + + fp = fopen(path, "rb"); + if (fp != NULL) + { + // Read data + fread(&rec, sizeof(REC), 1, fp); + fclose(fp); + + p = (unsigned char*)&rec.counter[0]; + p[0] -= rec.random[0]; + p[1] -= rec.random[0]; + p[2] -= rec.random[0]; + p[3] -= rec.random[0] / 2; + // If this is faster than our new time, quit + if (rec.counter[0] < time_count) + return TRUE; + } + + // Save new time + for (i = 0; i < 4; ++i) + { + rec.counter[i] = time_count; + rec.random[i] = Random(0, 250) + i; + + p = (unsigned char*)&rec.counter[i]; + p[0] += rec.random[i]; + p[1] += rec.random[i]; + p[2] += rec.random[i]; + p[3] += rec.random[i] / 2; + } + + fp = fopen(path, "wb"); + if (fp == NULL) + return FALSE; + + fwrite(&rec, sizeof(REC), 1, fp); + + fclose(fp); + return TRUE; +} + +int LoadTimeCounter(void) +{ + int i; + unsigned char *p; + REC rec; + FILE *fp; + char path[MAX_PATH]; + + // Open file + sprintf(path, "%s\\290.rec", gModulePath); + + fp = fopen(path, "rb"); + if (fp == NULL) + return 0; + + // Read data + fread(&rec, sizeof(REC), 1, fp); + fclose(fp); + + // Decode from checksum + for (i = 0; i < 4; ++i) + { + p = (unsigned char*)&rec.counter[i]; + p[0] -= rec.random[i]; + p[1] -= rec.random[i]; + p[2] -= rec.random[i]; + p[3] -= rec.random[i] / 2; + } + + // Verify checksum's result + if (rec.counter[0] != rec.counter[1] || rec.counter[0] != rec.counter[2]) + { + time_count = 0; + return 0; + } + + time_count = rec.counter[0]; + return time_count; +} diff --git a/src/MycParam.h b/src/MycParam.h new file mode 100644 index 0000000..4d2939f --- /dev/null +++ b/src/MycParam.h @@ -0,0 +1,39 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef struct ARMS_LEVEL +{ + int exp[3]; +} ARMS_LEVEL; + +typedef struct REC +{ + long counter[4]; + unsigned char random[4]; +} REC; + +extern ARMS_LEVEL gArmsLevelTable[14]; + +void AddExpMyChar(int x); +void ZeroExpMyChar(void); +BOOL IsMaxExpMyChar(void); +void DamageMyChar(int damage); +void ZeroArmsEnergy_All(void); +void AddBulletMyChar(int no, int val); +void AddLifeMyChar(int x); +void AddMaxLifeMyChar(int val); +void PutArmsEnergy(BOOL flash); +void PutActiveArmsList(void); +void PutMyLife(BOOL flash); +void PutMyAir(int x, int y); +void PutTimeCounter(int x, int y); +BOOL SaveTimeCounter(void); +int LoadTimeCounter(void); diff --git a/src/NpChar.cpp b/src/NpChar.cpp new file mode 100644 index 0000000..d9ad2cc --- /dev/null +++ b/src/NpChar.cpp @@ -0,0 +1,685 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpChar.h" + +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Draw.h" +#include "Flags.h" +#include "Game.h" +#include "Main.h" +#include "MyChar.h" +#include "NpcTbl.h" +#include "Sound.h" +#include "ValueView.h" + +NPCHAR gNPC[NPC_MAX]; +int gCurlyShoot_wait; +int gCurlyShoot_x; +int gCurlyShoot_y; +int gSuperXpos; +int gSuperYpos; + +const char* const gPassPixEve = "PXE"; + +static void SetUniqueParameter(NPCHAR *npc) +{ + int code = npc->code_char; + npc->surf = (SurfaceID)gNpcTable[code].surf; + npc->hit_voice = gNpcTable[code].hit_voice; + npc->destroy_voice = gNpcTable[code].destroy_voice; + npc->damage = gNpcTable[code].damage; + npc->size = gNpcTable[code].size; + npc->life = gNpcTable[code].life; + npc->hit.front = gNpcTable[code].hit.front * 0x200; + npc->hit.back = gNpcTable[code].hit.back * 0x200; + npc->hit.top = gNpcTable[code].hit.top * 0x200; + npc->hit.bottom = gNpcTable[code].hit.bottom * 0x200; + npc->view.front = gNpcTable[code].view.front * 0x200; + npc->view.back = gNpcTable[code].view.back * 0x200; + npc->view.top = gNpcTable[code].view.top * 0x200; + npc->view.bottom = gNpcTable[code].view.bottom * 0x200; +} + +void InitNpChar(void) +{ + memset(gNPC, 0, sizeof(gNPC)); +} + +BOOL LoadEvent(const char *path_event) +{ + int i, n; + FILE *fp; + int count; + char code[4]; + EVENT eve; + + char path[MAX_PATH]; + sprintf(path, "%s\\%s", gDataPath, path_event); + + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Read "PXE" check + fread(code, 1, 4, fp); + if (memcmp(code, gPassPixEve, 3) != 0) + { +#ifdef FIX_MAJOR_BUGS + // The original game forgot to close the file here + fclose(fp); +#endif + return FALSE; + } + + // Get amount of NPCs + fread(&count, 4, 1, fp); + + // Load NPCs + memset(gNPC, 0, sizeof(gNPC)); + + n = 170; + for (i = 0; i < count; ++i) + { + // Get data from file + fread(&eve, sizeof(EVENT), 1, fp); + + // Set NPC parameters + gNPC[n].direct = (eve.bits & NPC_SPAWN_IN_OTHER_DIRECTION) ? 2 : 0; + gNPC[n].code_char = eve.code_char; + gNPC[n].code_event = eve.code_event; + gNPC[n].code_flag = eve.code_flag; + gNPC[n].x = eve.x * 0x10 * 0x200; + gNPC[n].y = eve.y * 0x10 * 0x200; + gNPC[n].bits = eve.bits; + gNPC[n].bits |= gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = gNpcTable[gNPC[n].code_char].exp; + SetUniqueParameter(&gNPC[n]); + + // Check flags + if (gNPC[n].bits & NPC_APPEAR_WHEN_FLAG_SET) + { + if (GetNPCFlag(gNPC[n].code_flag) == TRUE) + gNPC[n].cond |= 0x80; + } + else if (gNPC[n].bits & NPC_HIDE_WHEN_FLAG_SET) + { + if (GetNPCFlag(gNPC[n].code_flag) == FALSE) + gNPC[n].cond |= 0x80; + } + else + { + gNPC[n].cond = 0x80; + } + + // Increase index + ++n; + } + + fclose(fp); + return TRUE; +} + +void SetNpChar(int code_char, int x, int y, int xm, int ym, int dir, NPCHAR *npc, int start_index) +{ + int n = start_index; + while (n < NPC_MAX && gNPC[n].cond) + ++n; + + if (n == NPC_MAX) + return; + + // Set NPC parameters + memset(&gNPC[n], 0, sizeof(NPCHAR)); + gNPC[n].cond |= 0x80; + gNPC[n].direct = dir; + gNPC[n].code_char = code_char; + gNPC[n].x = x; + gNPC[n].y = y; + gNPC[n].xm = xm; + gNPC[n].ym = ym; + gNPC[n].pNpc = npc; + gNPC[n].bits = gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = gNpcTable[gNPC[n].code_char].exp; + SetUniqueParameter(&gNPC[n]); +} + +void SetDestroyNpChar(int x, int y, int w, int num) +{ + int i; + int offset_x; + int offset_y; + + // Create smoke + w /= 0x200; + for (i = 0; i < num; ++i) + { + offset_x = Random(-w, w) * 0x200; + offset_y = Random(-w, w) * 0x200; + SetNpChar(NPC_SMOKE, x + offset_x, y + offset_y, 0, 0, 0, NULL, 0x100); + } + + // Flash effect + SetCaret(x, y, CARET_EXPLOSION, DIR_LEFT); +} + +void SetDestroyNpCharUp(int x, int y, int w, int num) +{ + int i; + int offset_x; + int offset_y; + + // Create smoke + w /= 0x200; + for (i = 0; i < num; ++i) + { + offset_x = Random(-w, w) * 0x200; + offset_y = Random(-w, w) * 0x200; + SetNpChar(4, x + offset_x, y + offset_y, 0, 0, 1, NULL, 0x100); + } + + // Flash effect + SetCaret(x, y, CARET_EXPLOSION, DIR_LEFT); +} + +void SetExpObjects(int x, int y, int exp) +{ + int n; + int sub_exp; + + n = 0x100; + while (exp) + { + while (n < NPC_MAX && gNPC[n].cond) + ++n; + + if (n == NPC_MAX) + break; + + memset(&gNPC[n], 0, sizeof(NPCHAR)); + + if (exp >= 20) + { + exp -= 20; + sub_exp = 20; + } + else if (exp >= 5) + { + exp -= 5; + sub_exp = 5; + } + else if (exp >= 1) + { + exp -= 1; + sub_exp = 1; + } + + gNPC[n].cond |= 0x80; + gNPC[n].direct = 0; + gNPC[n].code_char = 1; + gNPC[n].x = x; + gNPC[n].y = y; + gNPC[n].bits = gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = sub_exp; + + SetUniqueParameter(&gNPC[n]); + } +} + +BOOL SetBulletObject(int x, int y, int val) +{ + int n; + int bullet_no; // The Linux debug data claims there's a 3-line gap between this and the next variable declaration. Just enough space for an 'if' statement. + + // if (/* unknown */) + { // This is necessary for accurate ASM (stack frame layout) + int tamakazu_ari[10]; + int t = 0; + + memset(tamakazu_ari, 0, sizeof(tamakazu_ari)); + + for (n = 0; n < 8; ++n) + { + switch (gArmsData[n].code) + { + case 5: + tamakazu_ari[t++] = 0; + break; + + case 10: + tamakazu_ari[t++] = 1; + break; + + default: + tamakazu_ari[t] = 0; + break; + } + } + + if (t == 0) + return FALSE; + + n = Random(1, 10 * t); + bullet_no = tamakazu_ari[n % t]; + + n = 0x100; + while (n < NPC_MAX && gNPC[n].cond) + ++n; + + if (n == NPC_MAX) + return FALSE; + + memset(&gNPC[n], 0, sizeof(NPCHAR)); + gNPC[n].cond |= 0x80; + gNPC[n].direct = 0; + gNPC[n].code_event = bullet_no; + gNPC[n].code_char = 86; + gNPC[n].x = x; + gNPC[n].y = y; + gNPC[n].bits = gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = val; + SetUniqueParameter(&gNPC[n]); + } + + return TRUE; +} + +BOOL SetLifeObject(int x, int y, int val) +{ + int n = 0x100; + while (n < NPC_MAX && gNPC[n].cond) + ++n; + + if (n == NPC_MAX) + return FALSE; + + memset(&gNPC[n], 0, sizeof(NPCHAR)); + gNPC[n].cond |= 0x80; + gNPC[n].direct = 0; + gNPC[n].code_char = 87; + gNPC[n].x = x; + gNPC[n].y = y; + gNPC[n].bits = gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = val; + SetUniqueParameter(&gNPC[n]); + return TRUE; +} + +void VanishNpChar(NPCHAR *npc) +{ + int x, y; + + x = npc->x; + y = npc->y; + memset(npc, 0, sizeof(NPCHAR)); + npc->count1 = 0; + npc->x = x; + npc->y = y; + npc->cond |= 0x80; + npc->direct = 0; + npc->code_char = 3; + npc->bits = gNpcTable[npc->code_char].bits; + npc->exp = gNpcTable[npc->code_char].exp; + SetUniqueParameter(npc); +} + +void PutNpChar(int fx, int fy) +{ + int n; + signed char a = 0; + + int side; + + for (n = 0; n < NPC_MAX; ++n) + { + if (gNPC[n].cond & 0x80) + { + if (gNPC[n].shock) + { + a = 2 * ((gNPC[n].shock / 2) % 2) - 1; + } + else + { + a = 0; + if (gNPC[n].bits & NPC_SHOW_DAMAGE && gNPC[n].damage_view) + { + SetValueView(&gNPC[n].x, &gNPC[n].y, gNPC[n].damage_view); + gNPC[n].damage_view = 0; + } + } + + if (gNPC[n].direct == 0) + side = gNPC[n].view.front; + else + side = gNPC[n].view.back; + + PutBitmap3( + &grcGame, + (gNPC[n].x - side) / 0x200 - fx / 0x200 + a, + (gNPC[n].y - gNPC[n].view.top) / 0x200 - fy / 0x200, + &gNPC[n].rect, + (SurfaceID)gNPC[n].surf); + } + } +} + +void ActNpChar(void) +{ + int i; + int code_char; + + for (i = 0; i < NPC_MAX; ++i) + { + if (gNPC[i].cond & 0x80) + { + code_char = gNPC[i].code_char; + + gpNpcFuncTbl[code_char](&gNPC[i]); + + if (gNPC[i].shock) + --gNPC[i].shock; + } + } +} + +void ChangeNpCharByEvent(int code_event, int code_char, int dir) +{ + int n; + + for (n = 0; n < NPC_MAX; ++n) + { + if ((gNPC[n].cond & 0x80) && gNPC[n].code_event == code_event) + { + gNPC[n].bits &= ~(NPC_SOLID_SOFT | NPC_IGNORE_TILE_44 | NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_BOUNCY | NPC_SHOOTABLE | NPC_SOLID_HARD | NPC_REAR_AND_TOP_DONT_HURT | NPC_SHOW_DAMAGE); // Clear these flags + gNPC[n].code_char = code_char; + gNPC[n].bits |= gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = gNpcTable[gNPC[n].code_char].exp; + SetUniqueParameter(&gNPC[n]); + gNPC[n].cond |= 0x80; + gNPC[n].act_no = 0; + gNPC[n].act_wait = 0; + gNPC[n].count1 = 0; + gNPC[n].count2 = 0; + gNPC[n].ani_no = 0; + gNPC[n].ani_wait = 0; + gNPC[n].xm = 0; + gNPC[n].ym = 0; + + if (dir == 5) + { + // Another empty case that has to exist for the same assembly to be generated + } + else if (dir == 4) + { + if (gNPC[n].x < gMC.x) + gNPC[n].direct = 2; + else + gNPC[n].direct = 0; + } + else + { + gNPC[n].direct = dir; + } + + gpNpcFuncTbl[code_char](&gNPC[n]); + } + } +} + +void ChangeCheckableNpCharByEvent(int code_event, int code_char, int dir) +{ + int n; + + for (n = 0; n < NPC_MAX; ++n) + { + if (!(gNPC[n].cond & 0x80) && gNPC[n].code_event == code_event) + { + gNPC[n].bits &= ~(NPC_SOLID_SOFT | NPC_IGNORE_TILE_44 | NPC_INVULNERABLE | NPC_IGNORE_SOLIDITY | NPC_BOUNCY | NPC_SHOOTABLE | NPC_SOLID_HARD | NPC_REAR_AND_TOP_DONT_HURT | NPC_SHOW_DAMAGE); // Clear these flags + gNPC[n].bits |= NPC_INTERACTABLE; + gNPC[n].code_char = code_char; + gNPC[n].bits |= gNpcTable[gNPC[n].code_char].bits; + gNPC[n].exp = gNpcTable[gNPC[n].code_char].exp; + SetUniqueParameter(&gNPC[n]); + gNPC[n].cond |= 0x80; + gNPC[n].act_no = 0; + gNPC[n].act_wait = 0; + gNPC[n].count1 = 0; + gNPC[n].count2 = 0; + gNPC[n].ani_no = 0; + gNPC[n].ani_wait = 0; + gNPC[n].xm = 0; + gNPC[n].ym = 0; + + if (dir == 5) + { + // Another empty case that has to exist for the same assembly to be generated + } + else if (dir == 4) + { + if (gNPC[n].x < gMC.x) + gNPC[n].direct = 2; + else + gNPC[n].direct = 0; + } + else + { + gNPC[n].direct = (signed char)dir; + } + + gpNpcFuncTbl[code_char](&gNPC[n]); + } + } +} + +void SetNpCharActionNo(int code_event, int act_no, int dir) +{ + int n = 0; + while (n < NPC_MAX) + { + if ((gNPC[n].cond & 0x80) && gNPC[n].code_event == code_event) + break; + + ++n; + } + + if (n == NPC_MAX) + return; + + gNPC[n].act_no = act_no; + + if (dir == 5) + { + // Another empty case that has to exist for the same assembly to be generated + } + else if (dir == 4) + { + if (gNPC[n].x < gMC.x) + gNPC[n].direct = 2; + else + gNPC[n].direct = 0; + } + else + { + gNPC[n].direct = dir; + } +} + +void MoveNpChar(int code_event, int x, int y, int dir) +{ + int n = 0; + while (n < NPC_MAX) + { + if ((gNPC[n].cond & 0x80) && gNPC[n].code_event == code_event) + break; + + ++n; + } + + if (n == NPC_MAX) + return; + + gNPC[n].x = x; + gNPC[n].y = y; + + if (dir == 5) + { + // Another empty case that has to exist for the same assembly to be generated + } + else if (dir == 4) + { + if (gNPC[n].x < gMC.x) + gNPC[n].direct = 2; + else + gNPC[n].direct = 0; + } + else + { + gNPC[n].direct = (signed char)dir; + } +} + +void BackStepMyChar(int code_event) +{ + int n = 0; + + gMC.cond &= ~1; + gMC.ym = -0x200; + + if (code_event == 0) + { + gMC.direct = 0; + gMC.xm = 0x200; + } + else if (code_event == 2) + { + gMC.direct = 2; + gMC.xm = -0x200; + } + else + { + while (n < NPC_MAX) + { + if ((gNPC[n].cond & 0x80) && gNPC[n].code_event == code_event) + break; + + ++n; + } + + if (n == NPC_MAX) + return; + + if (gNPC[n].x < gMC.x) + { + gMC.direct = 0; + gMC.xm = 0x200; + } + else + { + gMC.direct = 2; + gMC.xm = -0x200; + } + } +} + +void DeleteNpCharEvent(int code) +{ + int i; + + for (i = 0; i < NPC_MAX; ++i) + { + if ((gNPC[i].cond & 0x80) && gNPC[i].code_event == code) + { + gNPC[i].cond = 0; + SetNPCFlag(gNPC[i].code_flag); + } + } +} + +void DeleteNpCharCode(int code, BOOL bSmoke) +{ + int n; + + for (n = 0; n < NPC_MAX; ++n) + { + if ((gNPC[n].cond & 0x80) && gNPC[n].code_char == code) + { + gNPC[n].cond = 0; + SetNPCFlag(gNPC[n].code_flag); + + if (bSmoke) + { + PlaySoundObject(gNPC[n].destroy_voice, SOUND_MODE_PLAY); + + switch (gNPC[n].size) + { + case 1: + SetDestroyNpChar(gNPC[n].x, gNPC[n].y, gNPC[n].view.back, 4); + break; + + case 2: + SetDestroyNpChar(gNPC[n].x, gNPC[n].y, gNPC[n].view.back, 8); + break; + + case 3: + SetDestroyNpChar(gNPC[n].x, gNPC[n].y, gNPC[n].view.back, 16); + break; + } + } + } + } +} + +void GetNpCharPosition(int *x, int *y, int i) +{ + *x = gNPC[i].x; + *y = gNPC[i].y; +} + +BOOL IsNpCharCode(int code) +{ + int i; + + for (i = 0; i < NPC_MAX; ++i) + if ((gNPC[i].cond & 0x80) && gNPC[i].code_char == code) + return TRUE; + + return FALSE; +} + +BOOL GetNpCharAlive(int code_event) +{ + int i; + + for (i = 0; i < NPC_MAX; ++i) + if ((gNPC[i].cond & 0x80) && gNPC[i].code_event == code_event) + break; + + if (i < NPC_MAX) + return TRUE; + else + return FALSE; +} + +int CountAliveNpChar(void) +{ + int n; + int count = 0; + + for (n = 0; n < NPC_MAX; ++n) + if (gNPC[n].cond & 0x80) + ++count; + + return count; +} diff --git a/src/NpChar.h b/src/NpChar.h new file mode 100644 index 0000000..14d9fd7 --- /dev/null +++ b/src/NpChar.h @@ -0,0 +1,140 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" + +#define NPC_MAX 0x200 + +enum NPCCond +{ + NPCCOND_DAMAGE_BOSS = 0x10, // (gBoss npc exclusive) When set, damage the main boss + NPCCOND_ALIVE = 0x80 // Whether the NPC is alive or not +}; + +// Be careful when changing these: they're baked into the 'npc.tbl' file +enum NPCFlags +{ + NPC_SOLID_SOFT = 1<<0, // Pushes Quote out + NPC_IGNORE_TILE_44 = 1<<1, // Ignores tile 44, which normally blocks NPCs + NPC_INVULNERABLE = 1<<2, // Can't be hurt + NPC_IGNORE_SOLIDITY = 1<<3, // Doesn't collide with anything + NPC_BOUNCY = 1<<4, // Quote bounces on top of NPC + NPC_SHOOTABLE = 1<<5, // Can be shot + NPC_SOLID_HARD = 1<<6, // Essentially acts as level tiles + NPC_REAR_AND_TOP_DONT_HURT = 1<<7, // Rear and top don't hurt when touched + NPC_EVENT_WHEN_TOUCHED = 1<<8, // Run event when touched + NPC_EVENT_WHEN_KILLED = 1<<9, // Run event when killed + NPC_APPEAR_WHEN_FLAG_SET = 1<<11, // Only appear when flag is set + NPC_SPAWN_IN_OTHER_DIRECTION = 1<<12, // Spawn facing to the right (or however the NPC interprets the direction) + NPC_INTERACTABLE = 1<<13, // Run event when interacted with + NPC_HIDE_WHEN_FLAG_SET = 1<<14, // Hide when flag is set + NPC_SHOW_DAMAGE = 1<<15 // Show the number of damage taken when harmed +}; + +enum NPCNames +{ + NPC_NULL = 0, + NPC_EXP = 1, + NPC_ENEMY_BEHEMOTH = 2, + NPC_DAMAGE_TEXT_HOLDER = 3, + NPC_SMOKE = 4, + // To be continued + NPC_ENEMY_FROG = 104, + NPC_SPEECH_BALLOON_HEY_LOW = 105, + NPC_SPEECH_BALLOON_HEY_HIGH = 106, + NPC_MALCO_UNDAMAGED = 107, + NPC_PROJECTILE_BALFROG_SPITBALL = 108, + NPC_MALCO_DAMAGED = 109, + NPC_ENEMY_PUCHI = 110, + // To be continued + NPC_KINGS_SWORD = 145 +}; + +typedef struct NPCHAR +{ + unsigned char cond; + int flag; + int x; + int y; + int xm; + int ym; + int xm2; + int ym2; + int tgt_x; + int tgt_y; + int code_char; + int code_flag; + int code_event; + SurfaceID surf; + int hit_voice; + int destroy_voice; + int life; + int exp; + int size; + int direct; + unsigned short bits; + RECT rect; + int ani_wait; + int ani_no; + int count1; + int count2; + int act_no; + int act_wait; + OTHER_RECT hit; + OTHER_RECT view; + unsigned char shock; + int damage_view; + int damage; + struct NPCHAR *pNpc; +} NPCHAR; + +struct EVENT +{ + short x; + short y; + short code_flag; + short code_event; + short code_char; + unsigned short bits; +}; + +extern NPCHAR gNPC[NPC_MAX]; +extern int gCurlyShoot_wait; +extern int gCurlyShoot_x; +extern int gCurlyShoot_y; +extern int gSuperXpos; +extern int gSuperYpos; + +extern const char* const gPassPixEve; + +void InitNpChar(void); +BOOL LoadEvent(const char *path_event); +void SetNpChar(int code_char, int x, int y, int xm, int ym, int dir, NPCHAR *npc, int start_index); +void SetDestroyNpChar(int x, int y, int w, int num); +void SetDestroyNpCharUp(int x, int y, int w, int num); +void SetExpObjects(int x, int y, int exp); +BOOL SetBulletObject(int x, int y, int val); +BOOL SetLifeObject(int x, int y, int val); +void VanishNpChar(NPCHAR *npc); +void PutNpChar(int fx, int fy); +void ActNpChar(void); +void ChangeNpCharByEvent(int code_event, int code_char, int dir); +void ChangeCheckableNpCharByEvent(int code_event, int code_char, int dir); +void SetNpCharActionNo(int code_event, int act_no, int dir); +void MoveNpChar(int code_event, int x, int y, int dir); +void BackStepMyChar(int code_event); +void DeleteNpCharEvent(int code); +void DeleteNpCharCode(int code, BOOL bSmoke); +void GetNpCharPosition(int *x, int *y, int i); +BOOL IsNpCharCode(int code); +BOOL GetNpCharAlive(int code_event); +int CountAliveNpChar(void); diff --git a/src/NpcAct.h b/src/NpcAct.h new file mode 100644 index 0000000..4240491 --- /dev/null +++ b/src/NpcAct.h @@ -0,0 +1,372 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "NpChar.h" + +void ActNpc000(NPCHAR *npc); +void ActNpc001(NPCHAR *npc); +void ActNpc002(NPCHAR *npc); +void ActNpc003(NPCHAR *npc); +void ActNpc004(NPCHAR *npc); +void ActNpc005(NPCHAR *npc); +void ActNpc006(NPCHAR *npc); +void ActNpc007(NPCHAR *npc); +void ActNpc008(NPCHAR *npc); +void ActNpc009(NPCHAR *npc); +void ActNpc010(NPCHAR *npc); +void ActNpc011(NPCHAR *npc); +void ActNpc012(NPCHAR *npc); +void ActNpc013(NPCHAR *npc); +void ActNpc014(NPCHAR *npc); +void ActNpc015(NPCHAR *npc); +void ActNpc016(NPCHAR *npc); +void ActNpc017(NPCHAR *npc); +void ActNpc018(NPCHAR *npc); +void ActNpc019(NPCHAR *npc); +void ActNpc020(NPCHAR *npc); +void ActNpc021(NPCHAR *npc); +void ActNpc022(NPCHAR *npc); +void ActNpc023(NPCHAR *npc); +void ActNpc024(NPCHAR *npc); +void ActNpc025(NPCHAR *npc); +void ActNpc026(NPCHAR *npc); +void ActNpc027(NPCHAR *npc); +void ActNpc028(NPCHAR *npc); +void ActNpc029(NPCHAR *npc); +void ActNpc030(NPCHAR *npc); +void ActNpc031(NPCHAR *npc); +void ActNpc032(NPCHAR *npc); +void ActNpc033(NPCHAR *npc); +void ActNpc034(NPCHAR *npc); +void ActNpc035(NPCHAR *npc); +void ActNpc036(NPCHAR *npc); +void ActNpc037(NPCHAR *npc); +void ActNpc038(NPCHAR *npc); +void ActNpc039(NPCHAR *npc); +void ActNpc040(NPCHAR *npc); +void ActNpc041(NPCHAR *npc); +void ActNpc042(NPCHAR *npc); +void ActNpc043(NPCHAR *npc); +void ActNpc044(NPCHAR *npc); +void ActNpc045(NPCHAR *npc); +void ActNpc046(NPCHAR *npc); +void ActNpc047(NPCHAR *npc); +void ActNpc048(NPCHAR *npc); +void ActNpc049(NPCHAR *npc); +void ActNpc050(NPCHAR *npc); +void ActNpc051(NPCHAR *npc); +void ActNpc052(NPCHAR *npc); +void ActNpc053(NPCHAR *npc); +void ActNpc054(NPCHAR *npc); +void ActNpc055(NPCHAR *npc); +void ActNpc056(NPCHAR *npc); +void ActNpc057(NPCHAR *npc); +void ActNpc058(NPCHAR *npc); +void ActNpc059(NPCHAR *npc); +void ActNpc060(NPCHAR *npc); +void ActNpc061(NPCHAR *npc); +void ActNpc062(NPCHAR *npc); +void ActNpc063(NPCHAR *npc); +void ActNpc064(NPCHAR *npc); +void ActNpc065(NPCHAR *npc); +void ActNpc066(NPCHAR *npc); +void ActNpc067(NPCHAR *npc); +void ActNpc068(NPCHAR *npc); +void ActNpc069(NPCHAR *npc); +void ActNpc070(NPCHAR *npc); +void ActNpc071(NPCHAR *npc); +void ActNpc072(NPCHAR *npc); +void ActNpc073(NPCHAR *npc); +void ActNpc074(NPCHAR *npc); +void ActNpc075(NPCHAR *npc); +void ActNpc076(NPCHAR *npc); +void ActNpc077(NPCHAR *npc); +void ActNpc078(NPCHAR *npc); +void ActNpc079(NPCHAR *npc); +void ActNpc080(NPCHAR *npc); +void ActNpc081(NPCHAR *npc); +void ActNpc082(NPCHAR *npc); +void ActNpc083(NPCHAR *npc); +void ActNpc084(NPCHAR *npc); +void ActNpc085(NPCHAR *npc); +void ActNpc086(NPCHAR *npc); +void ActNpc087(NPCHAR *npc); +void ActNpc088(NPCHAR *npc); +void ActNpc089(NPCHAR *npc); +void ActNpc090(NPCHAR *npc); +void ActNpc091(NPCHAR *npc); +void ActNpc092(NPCHAR *npc); +void ActNpc093(NPCHAR *npc); +void ActNpc094(NPCHAR *npc); +void ActNpc095(NPCHAR *npc); +void ActNpc096(NPCHAR *npc); +void ActNpc097(NPCHAR *npc); +void ActNpc098(NPCHAR *npc); +void ActNpc099(NPCHAR *npc); +void ActNpc100(NPCHAR *npc); +void ActNpc101(NPCHAR *npc); +void ActNpc102(NPCHAR *npc); +void ActNpc103(NPCHAR *npc); +void ActNpc104(NPCHAR *npc); +void ActNpc105(NPCHAR *npc); +void ActNpc106(NPCHAR *npc); +void ActNpc107(NPCHAR *npc); +void ActNpc108(NPCHAR *npc); +void ActNpc109(NPCHAR *npc); +void ActNpc110(NPCHAR *npc); +void ActNpc111(NPCHAR *npc); +void ActNpc112(NPCHAR *npc); +void ActNpc113(NPCHAR *npc); +void ActNpc114(NPCHAR *npc); +void ActNpc115(NPCHAR *npc); +void ActNpc116(NPCHAR *npc); +void ActNpc117(NPCHAR *npc); +void ActNpc118(NPCHAR *npc); +void ActNpc119(NPCHAR *npc); +void ActNpc120(NPCHAR *npc); +void ActNpc121(NPCHAR *npc); +void ActNpc122(NPCHAR *npc); +void ActNpc123(NPCHAR *npc); +void ActNpc124(NPCHAR *npc); +void ActNpc125(NPCHAR *npc); +void ActNpc126(NPCHAR *npc); +void ActNpc127(NPCHAR *npc); +void ActNpc128(NPCHAR *npc); +void ActNpc129(NPCHAR *npc); +void ActNpc130(NPCHAR *npc); +void ActNpc131(NPCHAR *npc); +void ActNpc132(NPCHAR *npc); +void ActNpc133(NPCHAR *npc); +void ActNpc134(NPCHAR *npc); +void ActNpc135(NPCHAR *npc); +void ActNpc136(NPCHAR *npc); +void ActNpc137(NPCHAR *npc); +void ActNpc138(NPCHAR *npc); +void ActNpc139(NPCHAR *npc); +void ActNpc140(NPCHAR *npc); +void ActNpc141(NPCHAR *npc); +void ActNpc142(NPCHAR *npc); +void ActNpc143(NPCHAR *npc); +void ActNpc144(NPCHAR *npc); +void ActNpc145(NPCHAR *npc); +void ActNpc146(NPCHAR *npc); +void ActNpc147(NPCHAR *npc); +void ActNpc148(NPCHAR *npc); +void ActNpc149(NPCHAR *npc); +void ActNpc150(NPCHAR *npc); +void ActNpc151(NPCHAR *npc); +void ActNpc152(NPCHAR *npc); +void ActNpc153(NPCHAR *npc); +void ActNpc154(NPCHAR *npc); +void ActNpc155(NPCHAR *npc); +void ActNpc156(NPCHAR *npc); +void ActNpc157(NPCHAR *npc); +void ActNpc158(NPCHAR *npc); +void ActNpc159(NPCHAR *npc); +void ActNpc160(NPCHAR *npc); +void ActNpc161(NPCHAR *npc); +void ActNpc162(NPCHAR *npc); +void ActNpc163(NPCHAR *npc); +void ActNpc164(NPCHAR *npc); +void ActNpc165(NPCHAR *npc); +void ActNpc166(NPCHAR *npc); +void ActNpc167(NPCHAR *npc); +void ActNpc168(NPCHAR *npc); +void ActNpc169(NPCHAR *npc); +void ActNpc170(NPCHAR *npc); +void ActNpc171(NPCHAR *npc); +void ActNpc172(NPCHAR *npc); +void ActNpc173(NPCHAR *npc); +void ActNpc174(NPCHAR *npc); +void ActNpc175(NPCHAR *npc); +void ActNpc176(NPCHAR *npc); +void ActNpc177(NPCHAR *npc); +void ActNpc178(NPCHAR *npc); +void ActNpc179(NPCHAR *npc); +void ActNpc180(NPCHAR *npc); +void ActNpc181(NPCHAR *npc); +void ActNpc182(NPCHAR *npc); +void ActNpc183(NPCHAR *npc); +void ActNpc184(NPCHAR *npc); +void ActNpc185(NPCHAR *npc); +void ActNpc186(NPCHAR *npc); +void ActNpc187(NPCHAR *npc); +void ActNpc188(NPCHAR *npc); +void ActNpc189(NPCHAR *npc); +void ActNpc190(NPCHAR *npc); +void ActNpc191(NPCHAR *npc); +void ActNpc192(NPCHAR *npc); +void ActNpc193(NPCHAR *npc); +void ActNpc194(NPCHAR *npc); +void ActNpc195(NPCHAR *npc); +void ActNpc196(NPCHAR *npc); +void ActNpc197(NPCHAR *npc); +void ActNpc198(NPCHAR *npc); +void ActNpc199(NPCHAR *npc); +void ActNpc200(NPCHAR *npc); +void ActNpc201(NPCHAR *npc); +void ActNpc202(NPCHAR *npc); +void ActNpc203(NPCHAR *npc); +void ActNpc204(NPCHAR *npc); +void ActNpc205(NPCHAR *npc); +void ActNpc206(NPCHAR *npc); +void ActNpc207(NPCHAR *npc); +void ActNpc208(NPCHAR *npc); +void ActNpc209(NPCHAR *npc); +void ActNpc210(NPCHAR *npc); +void ActNpc211(NPCHAR *npc); +void ActNpc212(NPCHAR *npc); +void ActNpc213(NPCHAR *npc); +void ActNpc214(NPCHAR *npc); +void ActNpc215(NPCHAR *npc); +void ActNpc216(NPCHAR *npc); +void ActNpc217(NPCHAR *npc); +void ActNpc218(NPCHAR *npc); +void ActNpc219(NPCHAR *npc); +void ActNpc220(NPCHAR *npc); +void ActNpc221(NPCHAR *npc); +void ActNpc222(NPCHAR *npc); +void ActNpc223(NPCHAR *npc); +void ActNpc224(NPCHAR *npc); +void ActNpc225(NPCHAR *npc); +void ActNpc226(NPCHAR *npc); +void ActNpc227(NPCHAR *npc); +void ActNpc228(NPCHAR *npc); +void ActNpc229(NPCHAR *npc); +void ActNpc230(NPCHAR *npc); +void ActNpc231(NPCHAR *npc); +void ActNpc232(NPCHAR *npc); +void ActNpc233(NPCHAR *npc); +void ActNpc234(NPCHAR *npc); +void ActNpc235(NPCHAR *npc); +void ActNpc236(NPCHAR *npc); +void ActNpc237(NPCHAR *npc); +void ActNpc238(NPCHAR *npc); +void ActNpc239(NPCHAR *npc); +void ActNpc240(NPCHAR *npc); +void ActNpc241(NPCHAR *npc); +void ActNpc242(NPCHAR *npc); +void ActNpc243(NPCHAR *npc); +void ActNpc244(NPCHAR *npc); +void ActNpc245(NPCHAR *npc); +void ActNpc246(NPCHAR *npc); +void ActNpc247(NPCHAR *npc); +void ActNpc248(NPCHAR *npc); +void ActNpc249(NPCHAR *npc); +void ActNpc250(NPCHAR *npc); +void ActNpc251(NPCHAR *npc); +void ActNpc252(NPCHAR *npc); +void ActNpc253(NPCHAR *npc); +void ActNpc254(NPCHAR *npc); +void ActNpc255(NPCHAR *npc); +void ActNpc256(NPCHAR *npc); +void ActNpc257(NPCHAR *npc); +void ActNpc258(NPCHAR *npc); +void ActNpc259(NPCHAR *npc); +void ActNpc260(NPCHAR *npc); +void ActNpc261(NPCHAR *npc); +void ActNpc262(NPCHAR *npc); +void ActNpc263(NPCHAR *npc); +void ActNpc264(NPCHAR *npc); +void ActNpc265(NPCHAR *npc); +void ActNpc266(NPCHAR *npc); +void ActNpc267(NPCHAR *npc); +void ActNpc268(NPCHAR *npc); +void ActNpc269(NPCHAR *npc); +void ActNpc270(NPCHAR *npc); +void ActNpc271(NPCHAR *npc); +void ActNpc272(NPCHAR *npc); +void ActNpc273(NPCHAR *npc); +void ActNpc274(NPCHAR *npc); +void ActNpc275(NPCHAR *npc); +void ActNpc276(NPCHAR *npc); +void ActNpc277(NPCHAR *npc); +void ActNpc278(NPCHAR *npc); +void ActNpc279(NPCHAR *npc); +void ActNpc280(NPCHAR *npc); +void ActNpc281(NPCHAR *npc); +void ActNpc282(NPCHAR *npc); +void ActNpc283(NPCHAR *npc); +void ActNpc284(NPCHAR *npc); +void ActNpc285(NPCHAR *npc); +void ActNpc286(NPCHAR *npc); +void ActNpc287(NPCHAR *npc); +void ActNpc288(NPCHAR *npc); +void ActNpc289(NPCHAR *npc); +void ActNpc290(NPCHAR *npc); +void ActNpc291(NPCHAR *npc); +void ActNpc292(NPCHAR *npc); +void ActNpc293(NPCHAR *npc); +void ActNpc294(NPCHAR *npc); +void ActNpc295(NPCHAR *npc); +void ActNpc296(NPCHAR *npc); +void ActNpc297(NPCHAR *npc); +void ActNpc298(NPCHAR *npc); +void ActNpc299(NPCHAR *npc); +void ActNpc300(NPCHAR *npc); +void ActNpc301(NPCHAR *npc); +void ActNpc302(NPCHAR *npc); +void ActNpc303(NPCHAR *npc); +void ActNpc304(NPCHAR *npc); +void ActNpc305(NPCHAR *npc); +void ActNpc306(NPCHAR *npc); +void ActNpc307(NPCHAR *npc); +void ActNpc308(NPCHAR *npc); +void ActNpc309(NPCHAR *npc); +void ActNpc310(NPCHAR *npc); +void ActNpc311(NPCHAR *npc); +void ActNpc312(NPCHAR *npc); +void ActNpc313(NPCHAR *npc); +void ActNpc314(NPCHAR *npc); +void ActNpc315(NPCHAR *npc); +void ActNpc316(NPCHAR *npc); +void ActNpc317(NPCHAR *npc); +void ActNpc318(NPCHAR *npc); +void ActNpc319(NPCHAR *npc); +void ActNpc320(NPCHAR *npc); +void ActNpc321(NPCHAR *npc); +void ActNpc322(NPCHAR *npc); +void ActNpc323(NPCHAR *npc); +void ActNpc324(NPCHAR *npc); +void ActNpc325(NPCHAR *npc); +void ActNpc326(NPCHAR *npc); +void ActNpc327(NPCHAR *npc); +void ActNpc328(NPCHAR *npc); +void ActNpc329(NPCHAR *npc); +void ActNpc330(NPCHAR *npc); +void ActNpc331(NPCHAR *npc); +void ActNpc332(NPCHAR *npc); +void ActNpc333(NPCHAR *npc); +void ActNpc334(NPCHAR *npc); +void ActNpc335(NPCHAR *npc); +void ActNpc336(NPCHAR *npc); +void ActNpc337(NPCHAR *npc); +void ActNpc338(NPCHAR *npc); +void ActNpc339(NPCHAR *npc); +void ActNpc340(NPCHAR *npc); +void ActNpc341(NPCHAR *npc); +void ActNpc342(NPCHAR *npc); +void ActNpc343(NPCHAR *npc); +void ActNpc344(NPCHAR *npc); +void ActNpc345(NPCHAR *npc); +void ActNpc346(NPCHAR *npc); +void ActNpc347(NPCHAR *npc); +void ActNpc348(NPCHAR *npc); +void ActNpc349(NPCHAR *npc); +void ActNpc350(NPCHAR *npc); +void ActNpc351(NPCHAR *npc); +void ActNpc352(NPCHAR *npc); +void ActNpc353(NPCHAR *npc); +void ActNpc354(NPCHAR *npc); +void ActNpc355(NPCHAR *npc); +void ActNpc356(NPCHAR *npc); +void ActNpc357(NPCHAR *npc); +void ActNpc358(NPCHAR *npc); +void ActNpc359(NPCHAR *npc); +void ActNpc360(NPCHAR *npc); diff --git a/src/NpcAct000.cpp b/src/NpcAct000.cpp new file mode 100644 index 0000000..95976a4 --- /dev/null +++ b/src/NpcAct000.cpp @@ -0,0 +1,1799 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Back.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Null +void ActNpc000(NPCHAR *npc) +{ + RECT rect = {0, 0, 16, 16}; + + if (npc->act_no == 0) + { + npc->act_no = 1; + + if (npc->direct == 2) + npc->y += 16 * 0x200; + } + + npc->rect = rect; +} + +// Experience +void ActNpc001(NPCHAR *npc) +{ + // In wind + if (gBack.type == BACKGROUND_TYPE_AUTOSCROLL || gBack.type == BACKGROUND_TYPE_CLOUDS_WINDY) + { + if (npc->act_no == 0) + { + // Set state + npc->act_no = 1; + + // Set random speed + npc->ym = Random(-0x80, 0x80); + npc->xm = Random(0x7F, 0x100); + } + + // Blow to the left + npc->xm -= 8; + + // Destroy when off-screen + if (npc->x < 80 * 0x200) + npc->cond = 0; + +#ifdef FIX_BUGS + // Limit speed + if (npc->xm < -0x600) + npc->xm = -0x600; +#else + // Limit speed (except Pixel applied it to the X position) + if (npc->x < -0x600) + npc->x = -0x600; +#endif + + // Bounce off walls + if (npc->flag & 1) + npc->xm = 0x100; + if (npc->flag & 2) + npc->ym = 0x40; + if (npc->flag & 8) + npc->ym = -0x40; + } + // When not in wind + else + { + if (npc->act_no == 0) + { + // Set state + npc->act_no = 1; + npc->ani_no = Random(0, 4); + + // Random speed + npc->xm = Random(-0x200, 0x200); + npc->ym = Random(-0x400, 0); + + // Random direction (reverse animation or not) + if (Random(0, 1) != 0) + npc->direct = 0; + else + npc->direct = 2; + } + + // Gravity + if (npc->flag & 0x100) + npc->ym += 0x15; + else + npc->ym += 0x2A; + + // Bounce off walls + if (npc->flag & 1 && npc->xm < 0) + npc->xm *= -1; + if (npc->flag & 4 && npc->xm > 0) + npc->xm *= -1; + + // Bounce off ceiling + if (npc->flag & 2 && npc->ym < 0) + npc->ym *= -1; + + // Bounce off floor + if (npc->flag & 8) + { + PlaySoundObject(45, SOUND_MODE_PLAY); + npc->ym = -0x280; + npc->xm = 2 * npc->xm / 3; + } + + // Play bounce song (and try to clip out of floor if stuck) + if (npc->flag & 0xD) + { + PlaySoundObject(45, SOUND_MODE_PLAY); + if (++npc->count2 > 2) + npc->y -= 1 * 0x200; + } + else + { + npc->count2 = 0; + } + + // Limit speed + if (npc->xm < -0x5FF) + npc->xm = -0x5FF; + if (npc->xm > 0x5FF) + npc->xm = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + } + + // Move + npc->y += npc->ym; + npc->x += npc->xm; + + // Get framerects + RECT rect[6] = { + { 0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + {48, 16, 64, 32}, + {64, 16, 80, 32}, + {80, 16, 96, 32}, + }; + + RECT rcNo = {0, 0, 0, 0}; + + // Animate + ++npc->ani_wait; + + if (npc->direct == 0) + { + if (npc->ani_wait > 2) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 5) + npc->ani_no = 0; + } + } + else + { + if (npc->ani_wait > 2) + { + npc->ani_wait = 0; + + if (--npc->ani_no < 0) + npc->ani_no = 5; + } + } + + npc->rect = rect[npc->ani_no]; + + // Size + if (npc->act_no != 0) + { + switch (npc->exp) + { + case 5: + npc->rect.top += 16; + npc->rect.bottom += 16; + break; + + case 20: + npc->rect.top += 32; + npc->rect.bottom += 32; + break; + } + + npc->act_no = 1; + } + + // Delete after 500 frames + if (++npc->count1 > 500 && npc->ani_no == 5 && npc->ani_wait == 2) + npc->cond = 0; + + // Blink after 400 frames + if (npc->count1 > 400) + if (npc->count1 / 2 % 2) + npc->rect = rcNo; +} + +// Behemoth +void ActNpc002(NPCHAR *npc) +{ + // Rects + RECT rcLeft[7] = { + { 32, 0, 64, 24}, + { 0, 0, 32, 24}, + { 32, 0, 64, 24}, + { 64, 0, 96, 24}, + { 96, 0, 128, 24}, + {128, 0, 160, 24}, + {160, 0, 192, 24}, + }; + + RECT rcRight[7] = { + { 32, 24, 64, 48}, + { 0, 24, 32, 48}, + { 32, 24, 64, 48}, + { 64, 24, 96, 48}, + { 96, 24, 128, 48}, + {128, 24, 160, 48}, + {160, 24, 192, 48}, + }; + + // Turn when touching a wall + if (npc->flag & 1) + npc->direct = 2; + else if (npc->flag & 4) + npc->direct = 0; + + switch (npc->act_no) + { + case 0: // Walking + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + if (npc->shock) + { + npc->count1 = 0; + npc->act_no = 1; + npc->ani_no = 4; + } + + break; + + case 1: // Shot + npc->xm = (npc->xm * 7) / 8; + + if (++npc->count1 > 40) + { + if (npc->shock) + { + npc->count1 = 0; + npc->act_no = 2; + npc->ani_no = 6; + npc->ani_wait = 0; + npc->damage = 5; + } + else + { + npc->act_no = 0; + npc->ani_wait = 0; + } + } + break; + + case 2: // Charge + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + if (++npc->count1 > 200) + { + npc->act_no = 0; + npc->damage = 1; + } + + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + { + npc->ani_no = 5; + // These three lines are missing in the Linux port, because it's based on v1.0.0.4: + // https://www.cavestory.org/forums/threads/version-1-0-0-5-really-different-than-1-0-0-6.102/#post-3231 + PlaySoundObject(26, SOUND_MODE_PLAY); + SetNpChar(4, npc->x, npc->y + (3 * 0x200), 0, 0, 0, NULL, 0x100); + SetQuake(8); + } + break; + } + + // Gravity + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + // Move + npc->x += npc->xm; + npc->y += npc->ym; + + // Set framerect + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Dead enemy (to make sure the damage-value doesn't teleport to a newly-loaded NPC) +void ActNpc003(NPCHAR *npc) +{ + if (++npc->count1 > 100) + npc->cond = 0; + + RECT rect = {0, 0, 0, 0}; + npc->rect = rect; +} + +// Smoke +void ActNpc004(NPCHAR *npc) +{ + RECT rcLeft[8] = { + { 16, 0, 17, 1}, + { 16, 0, 32, 16}, + { 32, 0, 48, 16}, + { 48, 0, 64, 16}, + { 64, 0, 80, 16}, + { 80, 0, 96, 16}, + { 96, 0, 112, 16}, + {112, 0, 128, 16}, + }; + + RECT rcUp[8] = { + {16, 0, 17, 1}, + {80, 48, 96, 64}, + { 0, 128, 16, 144}, + {16, 128, 32, 144}, + {32, 128, 48, 144}, + {48, 128, 64, 144}, + {64, 128, 80, 144}, + {80, 128, 96, 144}, + }; + + unsigned char deg; + + if (npc->act_no == 0) + { + // Move in random direction at random speed + if (npc->direct == 0 || npc->direct == 1) + { + deg = Random(0, 0xFF); + npc->xm = GetCos(deg) * Random(0x200, 0x5FF) / 0x200; + npc->ym = GetSin(deg) * Random(0x200, 0x5FF) / 0x200; + } + + // Set state + npc->ani_no = Random(0, 4); + npc->ani_wait = Random(0, 3); + npc->act_no = 1; + } + else + { + // Slight drag + npc->xm = (npc->xm * 20) / 21; + npc->ym = (npc->ym * 20) / 21; + + // Move + npc->x += npc->xm; + npc->y += npc->ym; + } + + // Animate + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + // Set framerect + if (npc->ani_no > 7) + { + // Destroy if over + npc->cond = 0; + } + else + { + if (npc->direct == 1) + npc->rect = rcUp[npc->ani_no]; + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + if (npc->direct == 2) + npc->rect = rcLeft[npc->ani_no]; + } +} + +// Critter (Green, Egg Corridor) +void ActNpc005(NPCHAR *npc) +{ + RECT rcLeft[3] = { + { 0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + }; + + RECT rcRight[3] = { + { 0, 64, 16, 80}, + {16, 64, 32, 80}, + {32, 64, 48, 80}, + }; + + switch (npc->act_no) + { + case 0: // Initialize + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: // Waiting + // Look at player + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + // Open eyes near player + if (npc->act_wait >= 8 && npc->x - (112 * 0x200) < gMC.x && npc->x + (112 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (80 * 0x200) > gMC.y) + { + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + // Jump if attacked + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + // Jump if player is nearby + if (npc->act_wait >= 8 && npc->x - (48 * 0x200) < gMC.x && npc->x + (48 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 2: // Going to jump + if (++npc->act_wait > 8) + { + // Set jump state + npc->act_no = 3; + npc->ani_no = 2; + + // Jump + npc->ym = -0x5FF; + PlaySoundObject(30, SOUND_MODE_PLAY); + + // Jump in facing direction + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + + break; + + case 3: // Jumping + // Land + if (npc->flag & 8) + { + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + } + + // Gravity + npc->ym += 64; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + // Move + npc->x += npc->xm; + npc->y += npc->ym; + + // Set framerect + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Beetle (Goes left and right, Egg Corridor) +void ActNpc006(NPCHAR *npc) +{ + RECT rcLeft[5] = { + { 0, 80, 16, 96}, + {16, 80, 32, 96}, + {32, 80, 48, 96}, + {48, 80, 64, 96}, + {64, 80, 80, 96}, + }; + + RECT rcRight[5] = { + { 0, 96, 16, 112}, + {16, 96, 32, 112}, + {32, 96, 48, 112}, + {48, 96, 64, 112}, + {64, 96, 80, 112}, + }; + + switch (npc->act_no) + { + case 0: // Initialize + npc->act_no = 1; + + if (npc->direct == 0) + npc->act_no = 1; + else + npc->act_no = 3; + break; + + case 1: + // Accelerate to the left + npc->xm -= 0x10; + if (npc->xm < -0x400) + npc->xm = -0x400; + + // Move + if (npc->shock) + npc->x += npc->xm / 2; + else + npc->x += npc->xm; + + // Animate + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + // Stop when hitting a wall + if (npc->flag & 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 0; + npc->xm = 0; + npc->direct = 2; + } + break; + + case 2: + // Wait 60 frames then move to the right + if (++npc->act_wait > 60) + { + npc->act_no = 3; + npc->ani_wait = 0; + npc->ani_no = 1; + } + break; + + case 3: + // Accelerate to the right + npc->xm += 0x10; + if (npc->xm > 0x400) + npc->xm = 0x400; + + // Move + if (npc->shock) + npc->x += npc->xm / 2; + else + npc->x += npc->xm; + + // Animate + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + // Stop when hitting a wall + if (npc->flag & 4) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 0; + npc->xm = 0; + npc->direct = 0; + } + break; + + case 4: + // Wait 60 frames then move to the left + if (++npc->act_wait > 60) + { + npc->act_no = 1; + npc->ani_wait = 0; + npc->ani_no = 1; + } + break; + } + + // Set framerect + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Basil +void ActNpc007(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {256, 64, 288, 80}, + {256, 80, 288, 96}, + {256, 96, 288, 112}, + }; + + RECT rcRight[3] = { + {288, 64, 320, 80}, + {288, 80, 320, 96}, + {288, 96, 320, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->x = gMC.x; // Spawn beneath player + + if (npc->direct == 0) + npc->act_no = 1; + else + npc->act_no = 2; + + break; + + case 1: // Going left + npc->xm -= 0x40; + + // Turn around if far enough away from the player + if (npc->x < gMC.x - (192 * 0x200)) + npc->act_no = 2; + + // Turn around if touching a wall + if (npc->flag & 1) + { + npc->xm = 0; + npc->act_no = 2; + } + + break; + + case 2: // Going right + npc->xm += 0x40; + + // Turn around if far enough away from the player + if (npc->x > gMC.x + (192 * 0x200)) + npc->act_no = 1; + + // Turn around if touching a wall + if (npc->flag & 4) + { + npc->xm = 0; + npc->act_no = 1; + } + + break; + } + + // Face direction Bazil is moving + if (npc->xm < 0) + npc->direct = 0; + else + npc->direct = 2; + + // Cap speed + if (npc->xm > 0x5FF) + npc->xm = 0x5FF; + if (npc->xm < -0x5FF) + npc->xm = -0x5FF; + + // Apply momentum + npc->x += npc->xm; + + // Increment animation + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + // Loop animation + if (npc->ani_no > 2) + npc->ani_no = 0; + + // Update sprite + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Beetle (Follows you, Egg Corridor) +void ActNpc008(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {80, 80, 96, 96}, + {96, 80, 112, 96}, + }; + + RECT rcRight[2] = { + {80, 96, 96, 112}, + {96, 96, 112, 112}, + }; + + switch (npc->act_no) + { + case 0: + if (gMC.x < npc->x + (16 * 0x200) && gMC.x > npc->x - (16 * 0x200)) + { + npc->bits |= NPC_SHOOTABLE; + npc->ym = -0x100; + npc->tgt_y = npc->y; + npc->act_no = 1; + npc->damage = 2; + + if (npc->direct == 0) + { + npc->x = gMC.x + (256 * 0x200); + npc->xm = -0x2FF; + } + else + { + npc->x = gMC.x - (256 * 0x200); + npc->xm = 0x2FF; + } + } + else + { + npc->bits &= ~NPC_SHOOTABLE; + npc->rect.right = 0; + npc->damage = 0; + npc->xm = 0; + npc->ym = 0; + return; + } + + break; + + case 1: + if (npc->x > gMC.x) + { + npc->direct = 0; + npc->xm -= 0x10; + } + else + { + npc->direct = 2; + npc->xm += 0x10; + } + + if (npc->xm > 0x2FF) + npc->xm = 0x2FF; + if (npc->xm < -0x2FF) + npc->xm = -0x2FF; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + + if (npc->shock) + { + npc->x += npc->xm / 2; + npc->y += npc->ym / 2; + } + else + { + npc->x += npc->xm; + npc->y += npc->ym; + } + + break; + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Balrog (drop-in) +void ActNpc009(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 2; + // Fallthrough + case 1: + npc->ym += 0x20; + + if (npc->count1 < 40) + { + ++npc->count1; + } + else + { + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->bits |= NPC_SOLID_SOFT; + } + + if (npc->flag & 8) + { + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->act_no = 2; + npc->ani_no = 1; + npc->act_wait = 0; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + } + + break; + + case 2: + if (++npc->act_wait > 16) + { + npc->act_no = 3; + npc->ani_no = 0; + npc->ani_wait = 0; + } + + break; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[3] = { + {0, 0, 40, 24}, + {80, 0, 120, 24}, + {120, 0, 160, 24}, + }; + + RECT rect_right[3] = { + {0, 24, 40, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Balrog (shooting) (super-secret unused version from the prototype) +void ActNpc010(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->act_wait > 12) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->count1 = 3; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 16) + { + --npc->count1; + npc->act_wait = 0; + + deg = GetArktan(npc->x - gMC.x, npc->y + (4 * 0x200) - gMC.y); + deg += (unsigned char)Random(-0x10, 0x10); + ym = GetSin(deg); + xm = GetCos(deg); + SetNpChar(11, npc->x, npc->y + (4 * 0x200), xm, ym, 0, NULL, 0x100); + + PlaySoundObject(39, SOUND_MODE_PLAY); + + if (npc->count1 == 0) + { + npc->act_no = 3; + npc->act_wait = 0; + } + } + + break; + + case 3: + if (++npc->act_wait > 3) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->xm = (gMC.x - npc->x) / 100; + npc->ym = -0x600; + npc->ani_no = 3; + } + + break; + + case 4: + if (npc->flag & 5) + npc->xm = 0; + + if (npc->y + (16 * 0x200) < gMC.y) + npc->damage = 5; + else + npc->damage = 0; + + if (npc->flag & 8) + { + npc->act_no = 5; + npc->act_wait = 0; + npc->ani_no = 2; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + npc->damage = 0; + } + + break; + + case 5: + npc->xm = 0; + + if (++npc->act_wait > 3) + { + npc->act_no = 1; + npc->act_wait = 0; + } + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[4] = { + {0, 0, 40, 24}, + {40, 0, 80, 24}, + {80, 0, 120, 24}, + {120, 0, 160, 24}, + }; + + RECT rect_right[4] = { + {0, 24, 40, 48}, + {40, 24, 80, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + }; + + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Proto-Balrog's projectile +void ActNpc011(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[3] = { + {208, 104, 224, 120}, + {224, 104, 240, 120}, + {240, 104, 256, 120}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 2) + npc->ani_no = 0; + } + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 150) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } +} + +// Balrog (cutscene) +void ActNpc012(NPCHAR *npc) +{ + int i; + int x, y; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 4) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->act_no = 1; + npc->ani_no = 0; + // Fallthrough + case 1: + if (Random(0, 100) == 0) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 16) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + if (npc->direct == 4) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->act_no = 11; + npc->ani_no = 2; + npc->act_wait = 0; + npc->tgt_x = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 30) + { + npc->act_no = 12; + npc->act_wait = 0; + npc->ani_no = 3; + npc->ym = -0x800; + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + break; + + case 12: + if (npc->flag & 5) + npc->xm = 0; + + if (npc->y < 0) + { + npc->code_char = 0; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + } + + break; + + case 20: + if (npc->direct == 4) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->act_no = 21; + npc->ani_no = 5; + npc->act_wait = 0; + npc->count1 = 0; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + PlaySoundObject(72, SOUND_MODE_PLAY); + // Fallthrough + case 21: + npc->tgt_x = 1; + + if (npc->flag & 8) + ++npc->act_wait; + + if (++npc->count1 / 2 % 2) + npc->x += 1 * 0x200; + else + npc->x -= 1 * 0x200; + + if (npc->act_wait > 100) + { + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 2; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + break; + + case 30: + npc->ani_no = 4; + + if (++npc->act_wait > 100) + { + npc->act_no = 0; + npc->ani_no = 0; + } + + break; + + case 40: + if (npc->direct == 4) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->act_no = 41; + npc->act_wait = 0; + npc->ani_no = 5; + // Fallthrough + case 41: + if (++npc->ani_wait / 2 % 2) + npc->ani_no = 5; + else + npc->ani_no = 6; + + break; + + case 42: + if (npc->direct == 4) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->act_no = 43; + npc->act_wait = 0; + npc->ani_no = 6; + // Fallthrough + case 43: + if (++npc->ani_wait / 2 % 2) + npc->ani_no = 7; + else + npc->ani_no = 6; + + break; + + case 50: + npc->ani_no = 8; + npc->xm = 0; + break; + + case 60: + npc->act_no = 61; + npc->ani_no = 9; + npc->ani_wait = 0; + // Fallthrough + case 61: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + + if (++npc->ani_no == 10 || npc->ani_no == 11) + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + if (npc->ani_no > 12) + npc->ani_no = 9; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + break; + + case 70: + npc->act_no = 71; + npc->act_wait = 64; + PlaySoundObject(29, SOUND_MODE_PLAY); + npc->ani_no = 13; + // Fallthrough + case 71: + if (--npc->act_wait == 0) + npc->cond = 0; + + break; + + case 80: + npc->count1 = 0; + npc->act_no = 81; + // Fallthrough + case 81: + if (++npc->count1 / 2 % 2) + npc->x += 1 * 0x200; + else + npc->x -= 1 * 0x200; + + npc->ani_no = 5; + npc->xm = 0; + npc->ym += 0x20; + + break; + + case 100: + npc->act_no = 101; + npc->act_wait = 0; + npc->ani_no = 2; + // Fallthrough + case 101: + if (++npc->act_wait > 20) + { + npc->act_no = 102; + npc->act_wait = 0; + npc->ani_no = 3; + npc->ym = -0x800; + npc->bits |= NPC_IGNORE_SOLIDITY; + DeleteNpCharCode(150, FALSE); + DeleteNpCharCode(117, FALSE); + SetNpChar(355, 0, 0, 0, 0, 0, npc, 0x100); + SetNpChar(355, 0, 0, 0, 0, 1, npc, 0x100); + } + + break; + + case 102: + { + x = npc->x / 0x200 / 0x10; + y = npc->y / 0x200 / 0x10; + + if (y >= 0 && y < 35 && ChangeMapParts(x, y, 0)) + { + ChangeMapParts(x - 1, y, 0); + ChangeMapParts(x + 1, y, 0); + PlaySoundObject(44, SOUND_MODE_PLAY); + SetQuake2(10); + } + + if (npc->y < -32 * 0x200) + { + npc->code_char = 0; + SetQuake(30); + } + + break; + } + } + + if (npc->tgt_x && Random(0, 10) == 0) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[14] = { + {0, 0, 40, 24}, + {160, 0, 200, 24}, + {80, 0, 120, 24}, + {120, 0, 160, 24}, + {240, 0, 280, 24}, + {200, 0, 240, 24}, + {280, 0, 320, 24}, + {0, 0, 0, 0}, + {80, 48, 120, 72}, + {0, 48, 40, 72}, + {0, 0, 40, 24}, + {40, 48, 80, 72}, + {0, 0, 40, 24}, + {280, 0, 320, 24}, + }; + + RECT rect_right[14] = { + {0, 24, 40, 48}, + {160, 24, 200, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + {240, 24, 280, 48}, + {200, 24, 240, 48}, + {280, 24, 320, 48}, + {0, 0, 0, 0}, + {80, 72, 120, 96}, + {0, 72, 40, 96}, + {0, 24, 40, 48}, + {40, 72, 80, 96}, + {0, 24, 40, 48}, + {280, 24, 320, 48}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; + + if (npc->act_no == 71) + { + npc->rect.bottom = npc->rect.top + npc->act_wait / 2; + + if (npc->act_wait % 2) + ++npc->rect.left; + } +} + +// Forcefield +void ActNpc013(NPCHAR *npc) +{ + RECT rect[4] = { + {128, 0, 144, 16}, + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + }; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Santa's Key +void ActNpc014(NPCHAR *npc) +{ + RECT rect[3] = { + {192, 0, 208, 16}, + {208, 0, 224, 16}, + {224, 0, 240, 16}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 2) + { + npc->ym = -0x200; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + break; + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} + +// Chest (closed) +void ActNpc015(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {240, 0, 256, 16}, + {256, 0, 272, 16}, + {272, 0, 288, 16}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->bits |= NPC_INTERACTABLE; + + if (npc->direct == 2) + { + npc->ym = -0x200; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + // Fallthrough + case 1: + npc->ani_no = 0; + + if (Random(0, 30) == 0) + npc->act_no = 2; + + break; + + case 2: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + { + npc->ani_no = 0; + npc->act_no = 1; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + npc->rect = rcLeft[npc->ani_no]; +} + +// Save point +void ActNpc016(NPCHAR *npc) +{ + RECT rect[8] = { + {96, 16, 112, 32}, + {112, 16, 128, 32}, + {128, 16, 144, 32}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + {192, 16, 208, 32}, + {208, 16, 224, 32}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->bits |= NPC_INTERACTABLE; + npc->act_no = 1; + + if (npc->direct == 2) + { + npc->bits &= ~NPC_INTERACTABLE; + npc->ym = -0x200; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + // Fallthrough + case 1: + if (npc->flag & 8) + npc->bits |= NPC_INTERACTABLE; + + break; + } + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 0; + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} + +// Health refill +void ActNpc017(NPCHAR *npc) +{ + RECT rect[2] = { + {288, 0, 304, 16}, + {304, 0, 320, 16}, + }; + + int a; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 2) + { + npc->ym = -0x200; + + for (a = 0; a < 4; ++a) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + // Fallthrough + case 1: + a = Random(0, 30); + + if (a < 10) + npc->act_no = 2; + else if (a < 25) + npc->act_no = 3; + else + npc->act_no = 4; + + npc->act_wait = Random(0x10, 0x40); + npc->ani_wait = 0; + break; + + case 2: + npc->rect = rect[0]; + + if (--npc->act_wait == 0) + npc->act_no = 1; + + break; + + case 3: + if (++npc->ani_wait % 2) + npc->rect = rect[0]; + else + npc->rect = rect[1]; + + if (--npc->act_wait == 0) + npc->act_no = 1; + + break; + + case 4: + npc->rect = rect[1]; + + if (--npc->act_wait == 0) + npc->act_no = 1; + + break; + } + + npc->ym += 0x40; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; +} + +// Door +void ActNpc018(NPCHAR *npc) +{ + int i; + + RECT rect[2] = { + {224, 16, 240, 40}, + {192, 112, 208, 136}, + }; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 0) + npc->rect = rect[0]; + else + npc->rect = rect[1]; + + break; + + case 1: + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->act_no = 0; + npc->rect = rect[0]; + break; + } +} + +// Balrog (burst) +void ActNpc019(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + for (i = 0; i < 0x10; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->y += 10 * 0x200; + npc->act_no = 1; + npc->ani_no = 3; + npc->ym = -0x100; + PlaySoundObject(12, SOUND_MODE_PLAY); + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + // Fallthrough + case 1: + npc->ym += 0x10; + + if (npc->ym > 0 && npc->flag & 8) + { + npc->act_no = 2; + npc->ani_no = 2; + npc->act_wait = 0; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + } + + break; + + case 2: + if (++npc->act_wait > 0x10) + { + npc->act_no = 3; + npc->ani_no = 0; + npc->ani_wait = 0; + } + + break; + + case 3: + if (Random(0, 100) == 0) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 4: + if (++npc->act_wait > 0x10) + { + npc->act_no = 3; + npc->ani_no = 0; + } + + break; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[4] = { + {0, 0, 40, 24}, + {160, 0, 200, 24}, + {80, 0, 120, 24}, + {120, 0, 160, 24}, + }; + + RECT rect_right[4] = { + {0, 24, 40, 48}, + {160, 24, 200, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} diff --git a/src/NpcAct020.cpp b/src/NpcAct020.cpp new file mode 100644 index 0000000..87a0e3a --- /dev/null +++ b/src/NpcAct020.cpp @@ -0,0 +1,1359 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Game.h" +#include "Frame.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Computer +void ActNpc020(NPCHAR *npc) +{ + RECT rcLeft = {288, 16, 320, 40}; + + RECT rcRight[3] = { + {288, 40, 320, 64}, + {288, 40, 320, 64}, + {288, 64, 320, 88}, + }; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rcLeft; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Chest (open) +void ActNpc021(NPCHAR *npc) +{ + if (npc->act_no == 0) + { + npc->act_no = 1; + + if (npc->direct == 2) + npc->y += 16 * 0x200; + } + + RECT rect = {224, 40, 240, 48}; + + npc->rect = rect; +} + +// Teleporter +void ActNpc022(NPCHAR *npc) +{ + RECT rect[2] = { + {240, 16, 264, 48}, + {248, 152, 272, 184}, + }; + + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + break; + + case 1: + if (++npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Teleporter lights +void ActNpc023(NPCHAR *npc) +{ + RECT rect[8] = { + {264, 16, 288, 20}, + {264, 20, 288, 24}, + {264, 24, 288, 28}, + {264, 28, 288, 32}, + {264, 32, 288, 36}, + {264, 36, 288, 40}, + {264, 40, 288, 44}, + {264, 44, 288, 48}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Power Critter +void ActNpc024(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {0, 0, 24, 24}, + {24, 0, 48, 24}, + {48, 0, 72, 24}, + {72, 0, 96, 24}, + {96, 0, 120, 24}, + {120, 0, 144, 24}, + }; + + RECT rcRight[6] = { + {0, 24, 24, 48}, + {24, 24, 48, 48}, + {48, 24, 72, 48}, + {72, 24, 96, 48}, + {96, 24, 120, 48}, + {120, 24, 144, 48}, + }; + + switch (npc->act_no) + { + case 0: + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->act_wait >= 8 && npc->x - (128 * 0x200) < gMC.x && npc->x + (128 * 0x200) > gMC.x && npc->y - (128 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + if (npc->act_wait >= 8 && npc->x - (96 * 0x200) < gMC.x && npc->x + (96 * 0x200) > gMC.x && npc->y - (96 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 3; + npc->ani_no = 2; + npc->ym = -0x5FF; + PlaySoundObject(108, SOUND_MODE_PLAY); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + + break; + + case 3: + if (npc->ym > 0x200) + { + npc->tgt_y = npc->y; + npc->act_no = 4; + npc->ani_no = 3; + npc->act_wait = 0; + npc->act_wait = 0; // Pixel duplicated this line + } + + break; + + case 4: + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + ++npc->act_wait; + + if (npc->flag & 7 || npc->act_wait > 100) + { + npc->damage = 12; + npc->act_no = 5; + npc->ani_no = 2; + npc->xm /= 2; + break; + } + + if (npc->act_wait % 4 == 1) + PlaySoundObject(110, SOUND_MODE_PLAY); + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 3; + + break; + + case 5: + if (npc->flag & 8) + { + npc->damage = 2; + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + } + + break; + } + + if (npc->act_no != 4) + { + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + } + else + { + if (npc->x < gMC.x) + npc->xm += 0x20; + else + npc->xm -= 0x20; + + if (npc->y > npc->tgt_y) + npc->ym -= 0x10; + else + npc->ym += 0x10; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Egg Corridor lift +void ActNpc025(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {256, 64, 288, 80}, + {256, 80, 288, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->x += 8 * 0x200; + // Fallthrough + case 1: + if (++npc->act_wait > 150) + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 2: // Identical to case 4 + if (++npc->act_wait <= 0x40) + { + npc->y -= 1 * 0x200; + } + else + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 3: + if (++npc->act_wait > 150) + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 4: // Identical to case 2 + if (++npc->act_wait <= 0x40) + { + npc->y -= 1 * 0x200; + } + else + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 5: + if (++npc->act_wait > 150) + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 6: + if (++npc->act_wait <= 0x40) + { + npc->y += 1 * 0x200; + } + else + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 7: + if (++npc->act_wait > 150) + { + npc->act_wait = 0; + ++npc->act_no; + } + + break; + + case 8: + if (++npc->act_wait <= 0x40) + { + npc->y += 1 * 0x200; + } + else + { + npc->act_wait = 0; + npc->act_no = 1; + } + + break; + } + + switch (npc->act_no) + { + case 2: + case 4: + case 6: + case 8: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Bat (Grasstown, flying) +void ActNpc026(NPCHAR *npc) +{ + unsigned char deg; + + switch (npc->act_no) + { + case 0: + deg = Random(0, 0xFF); + npc->xm = GetCos(deg); + deg += 0x40; + npc->tgt_x = npc->x + (GetCos(deg) * 8); + + deg = Random(0, 0xFF); + npc->ym = GetSin(deg); + deg += 0x40; + npc->tgt_y = npc->y + (GetSin(deg) * 8); + + npc->act_no = 1; + npc->count1 = 120; + // Fallthrough + case 1: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_x < npc->x) + npc->xm -= 0x10; + if (npc->tgt_x > npc->x) + npc->xm += 0x10; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->count1 < 120) + { + ++npc->count1; + break; + } + + if (npc->x - (8 * 0x200) < gMC.x && npc->x + (8 * 0x200) > gMC.x && npc->y < gMC.y && npc->y + (96 * 0x200) > gMC.y) + { + npc->xm /= 2; + npc->ym = 0; + npc->act_no = 3; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + } + + break; + + case 3: + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->flag & 8) + { + npc->ym = 0; + npc->xm *= 2; + npc->count1 = 0; + npc->act_no = 1; + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[4] = { + {32, 80, 48, 96}, + {48, 80, 64, 96}, + {64, 80, 80, 96}, + {80, 80, 96, 96}, + }; + + RECT rect_right[4] = { + {32, 96, 48, 112}, + {48, 96, 64, 112}, + {64, 96, 80, 112}, + {80, 96, 96, 112}, + }; + + if (npc->act_no == 3) + { + npc->ani_no = 3; + } + else + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + } + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Death trap +void ActNpc027(NPCHAR *npc) +{ + RECT rcLeft[1] = { + {96, 64, 128, 88} + }; + + npc->rect = rcLeft[npc->ani_no]; +} + +// Flying Critter (Grasstown) +void ActNpc028(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + {48, 48, 64, 64}, + {64, 48, 80, 64}, + {80, 48, 96, 64}, + }; + + RECT rcRight[6] = { + {0, 64, 16, 80}, + {16, 64, 32, 80}, + {32, 64, 48, 80}, + {48, 64, 64, 80}, + {64, 64, 80, 80}, + {80, 64, 96, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->act_wait >= 8 && npc->x - (128 * 0x200) < gMC.x && npc->x + (128 * 0x200) > gMC.x && npc->y - (128 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + if (npc->act_wait >= 8 && npc->x - (96 * 0x200) < gMC.x && npc->x + (96 * 0x200) > gMC.x && npc->y - (96 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 3; + npc->ani_no = 2; + npc->ym = -0x4CC; + PlaySoundObject(30, SOUND_MODE_PLAY); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + + break; + + case 3: + if (npc->ym > 0x100) + { + npc->tgt_y = npc->y; + npc->act_no = 4; + npc->ani_no = 3; + npc->act_wait = 0; + npc->act_wait = 0; // Pixel duplicated this line + } + + break; + + case 4: + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + ++npc->act_wait; + + if (npc->flag & 7 || npc->act_wait > 100) + { + npc->damage = 3; + npc->act_no = 5; + npc->ani_no = 2; + npc->xm /= 2; + break; + } + + if (npc->act_wait % 4 == 1) + PlaySoundObject(109, SOUND_MODE_PLAY); + + if (npc->flag & 8) + npc->ym = -0x200; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 3; + + break; + + case 5: + if (npc->flag & 8) + { + npc->damage = 2; + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + } + + if (npc->act_no != 4) + { + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + } + else + { + if (npc->x < gMC.x) + npc->xm += 0x20; + else + npc->xm -= 0x20; + + if (npc->y > npc->tgt_y) + npc->ym -= 0x10; + else + npc->ym += 0x10; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Cthulhu +void ActNpc029(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 192, 16, 216}, + {16, 192, 32, 216}, + }; + + RECT rcRight[2] = { + {0, 216, 16, 240}, + {16, 216, 32, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (npc->x - (48 * 0x200) < gMC.x && npc->x + (48 * 0x200) > gMC.x && npc->y - (48 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + npc->ani_no = 1; + else + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Gunsmith +void ActNpc030(NPCHAR *npc) +{ + RECT rc[3] = { + {48, 0, 64, 16}, + {48, 16, 64, 32}, + {0, 32, 16, 48}, + }; + + if (npc->direct == 0) + { + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + } + else + { + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->y += 16 * 0x200; + npc->ani_no = 2; + } + + if (++npc->act_wait > 100) + { + npc->act_wait = 0; + SetCaret(npc->x, npc->y - (2 * 0x200), CARET_ZZZ, DIR_LEFT); + } + } + + npc->rect = rc[npc->ani_no]; +} + +// Bat (Grasstown, hanging) +void ActNpc031(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + {32, 80, 48, 96}, + {48, 80, 64, 96}, + {64, 80, 80, 96}, + }; + + RECT rcRight[5] = { + {0, 96, 16, 112}, + {16, 96, 32, 112}, + {32, 96, 48, 112}, + {48, 96, 64, 112}, + {64, 96, 80, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (8 * 0x200) < gMC.x && npc->x + (8 * 0x200) > gMC.x && npc->y - (8 * 0x200) < gMC.y && npc->y + (96 * 0x200) > gMC.y) + { + npc->ani_no = 0; + npc->act_no = 3; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->ani_no = 0; + + if (npc->shock || npc->x - (20 * 0x200) > gMC.x || npc->x + (20 * 0x200) < gMC.x) + { + npc->ani_no = 1; + npc->ani_wait = 0; + npc->act_no = 4; + npc->act_wait = 0; + } + + break; + + case 4: + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (++npc->act_wait < 20 && !(npc->flag & 8)) + break; + + if (npc->flag & 8 || npc->y > gMC.y - (16 * 0x200)) + { + npc->ani_wait = 0; + npc->ani_no = 2; + npc->act_no = 5; + npc->tgt_y = npc->y; + + if (npc->flag & 8) + npc->ym = -0x200; + } + + break; + + case 5: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 2; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (gMC.x < npc->x) + npc->xm -= 0x10; + if (gMC.x > npc->x) + npc->xm += 0x10; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->flag & 8) + npc->ym = -0x200; + if (npc->flag & 2) + npc->ym = 0x200; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Life capsule +void ActNpc032(NPCHAR *npc) +{ + RECT rect[2] = { + {32, 96, 48, 112}, + {48, 96, 64, 112}, + }; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Balrog bouncing projectile +void ActNpc033(NPCHAR *npc) +{ + if (npc->flag & 5) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + else if (npc->flag & 8) + { + npc->ym = -0x400; + } + + npc->ym += 0x2A; + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[2] = { + {240, 64, 256, 80}, + {240, 80, 256, 96}, + }; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + } + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->act_wait > 250) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } +} + +// Bed +void ActNpc034(NPCHAR *npc) +{ + RECT rcLeft = {192, 48, 224, 64}; + RECT rcRight = {192, 184, 224, 200}; + + if (npc->direct == 0) + npc->rect = rcLeft; + else + npc->rect = rcRight; +} + +// Mannan +void ActNpc035(NPCHAR *npc) +{ + if (npc->act_no < 3 && npc->life < 90) + { + PlaySoundObject(71, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + SetExpObjects(npc->x, npc->y, npc->exp); + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 2; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + } + + switch (npc->act_no) + { + case 0: + case 1: + if (npc->shock) + { + if (npc->direct == 0) + SetNpChar(103, npc->x - (8 * 0x200), npc->y + (8 * 0x200), 0, 0, npc->direct, NULL, 0x100); + else + SetNpChar(103, npc->x + (8 * 0x200), npc->y + (8 * 0x200), 0, 0, npc->direct, NULL, 0x100); + + npc->ani_no = 1; + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 20) + { + npc->act_wait = 0; + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + if (++npc->act_wait == 50 || npc->act_wait == 60) + npc->ani_no = 3; + + if (npc->act_wait == 53 || npc->act_wait == 63) + npc->ani_no = 2; + + if (npc->act_wait > 100) + npc->act_no = 4; + + break; + } + + RECT rcLeft[4] = { + {96, 64, 120, 96}, + {120, 64, 144, 96}, + {144, 64, 168, 96}, + {168, 64, 192, 96}, + }; + + RECT rcRight[4] = { + {96, 96, 120, 128}, + {120, 96, 144, 128}, + {144, 96, 168, 128}, + {168, 96, 192, 128}, + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Balrog (hover) +void ActNpc036(NPCHAR *npc) +{ + int i; + unsigned char deg; + int xm, ym; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->act_wait > 12) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->count1 = 3; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 16) + { + --npc->count1; + npc->act_wait = 0; + + deg = GetArktan(npc->x - gMC.x, npc->y + (4 * 0x200) - gMC.y); + deg += (unsigned char)Random(-0x10, 0x10); + ym = GetSin(deg); + xm = GetCos(deg); + + SetNpChar(11, npc->x, npc->y + 0x800, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + + if (npc->count1 == 0) + { + npc->act_no = 3; + npc->act_wait = 0; + } + } + + break; + + case 3: + if (++npc->act_wait > 3) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->xm = (gMC.x - npc->x) / 100; + npc->ym = -0x600; + npc->ani_no = 3; + } + + break; + + case 4: + if (npc->ym > -0x200) + { + if (npc->life > 60) + { + npc->act_no = 5; + npc->ani_no = 4; + npc->ani_wait = 0; + npc->act_wait = 0; + npc->tgt_y = npc->y; + } + else + { + npc->act_no = 6; + } + } + + break; + + case 5: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + { + npc->ani_no = 4; + PlaySoundObject(47, SOUND_MODE_PLAY); + } + + if (++npc->act_wait > 100) + { + npc->act_no = 6; + npc->ani_no = 3; + } + + if (npc->y < npc->tgt_y) + npc->ym += 0x40; + else + npc->ym -= 0x40; + + if (npc->ym < -0x200) + npc->ym = -0x200; + if (npc->ym > 0x200) + npc->ym = 0x200; + + break; + + case 6: + if (npc->y + (16 * 0x200) < gMC.y) + npc->damage = 10; + else + npc->damage = 0; + + if (npc->flag & 8) + { + npc->act_no = 7; + npc->act_wait = 0; + npc->ani_no = 2; + PlaySoundObject(26, SOUND_MODE_PLAY); + PlaySoundObject(25, SOUND_MODE_PLAY); + SetQuake(30); + npc->damage = 0; + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + for (i = 0; i < 8; ++i) + SetNpChar(33, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-0x400, 0x400), Random(-0x400, 0), 0, NULL, 0x100); + } + + break; + + case 7: + npc->xm = 0; + + if (++npc->act_wait > 3) + { + npc->act_no = 1; + npc->act_wait = 0; + } + + break; + } + + if (npc->act_no != 5) + { + npc->ym += 0x200 / 10; + + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[6] = { + {0, 0, 40, 24}, + {40, 0, 80, 24}, + {80, 0, 120, 24}, + {120, 0, 160, 24}, + {160, 48, 200, 72}, + {200, 48, 240, 72}, + }; + + RECT rect_right[6] = { + {0, 24, 40, 48}, + {40, 24, 80, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + {160, 72, 200, 96}, + {200, 72, 240, 96}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Signpost +void ActNpc037(NPCHAR *npc) +{ + RECT rect[2] = { + {192, 64, 208, 80}, + {208, 64, 224, 80}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Fireplace +void ActNpc038(NPCHAR *npc) +{ + RECT rect[4] = { + {128, 64, 144, 80}, + {144, 64, 160, 80}, + {160, 64, 176, 80}, + {176, 64, 192, 80}, + }; + + switch (npc->act_no) + { + case 0: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; + break; + + case 10: + npc->act_no = 11; + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + // Fallthrough + case 11: + npc->rect.left = 0; + npc->rect.right = 0; + break; + } +} + +// Save sign +void ActNpc039(NPCHAR *npc) +{ + RECT rect[2] = { + {224, 64, 240, 80}, + {240, 64, 256, 80}, + }; + + if (npc->direct == 0) + npc->ani_no = 0; + else + npc->ani_no = 1; + + npc->rect = rect[npc->ani_no]; +} diff --git a/src/NpcAct040.cpp b/src/NpcAct040.cpp new file mode 100644 index 0000000..de82ff1 --- /dev/null +++ b/src/NpcAct040.cpp @@ -0,0 +1,2028 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Santa +void ActNpc040(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {0, 32, 16, 48}, + {16, 32, 32, 48}, + {32, 32, 48, 48}, + {0, 32, 16, 48}, + {48, 32, 64, 48}, + {0, 32, 16, 48}, + {64, 32, 80, 48}, + }; + + RECT rcRight[7] = { + {0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + {0, 48, 16, 64}, + {48, 48, 64, 64}, + {0, 48, 16, 64}, + {64, 48, 80, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + npc->ani_no++; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + break; + + case 5: + npc->ani_no = 6; + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Busted Door +void ActNpc041(NPCHAR *npc) +{ + RECT rect = {0, 80, 48, 112}; + + if (npc->act_no == 0) + { + ++npc->act_no; + npc->y -= 1 * 0x10 * 0x200; // Move one tile up + } + + npc->rect = rect; +} + +// Sue +void ActNpc042(NPCHAR *npc) +{ + int n; + + RECT rcLeft[13] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + {0, 0, 16, 16}, + {48, 0, 64, 16}, + {0, 0, 16, 16}, + {64, 0, 80, 16}, + {80, 32, 96, 48}, + {96, 32, 112, 48}, + {128, 32, 144, 48}, + {0, 0, 16, 16}, + {112, 32, 128, 48}, + {160, 32, 176, 48}, + }; + + RECT rcRight[13] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + {0, 16, 16, 32}, + {48, 16, 64, 32}, + {0, 16, 16, 32}, + {64, 16, 80, 32}, + {80, 48, 96, 64}, + {96, 48, 112, 64}, + {128, 48, 144, 64}, + {0, 16, 16, 32}, + {112, 48, 128, 64}, + {160, 48, 176, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + break; + + case 5: + npc->ani_no = 6; + npc->xm = 0; + break; + + case 6: + PlaySoundObject(50, SOUND_MODE_PLAY); + npc->act_wait = 0; + npc->act_no = 7; + npc->ani_no = 7; + // Fallthrough + case 7: + if (++npc->act_wait > 10) + npc->act_no = 0; + + break; + + case 8: + PlaySoundObject(50, SOUND_MODE_PLAY); + npc->act_wait = 0; + npc->act_no = 9; + npc->ani_no = 7; + npc->ym = -0x200; + + if (npc->direct == 0) + npc->xm = 0x400; + else + npc->xm = -0x400; + + // Fallthrough + case 9: + if (++npc->act_wait > 3 && npc->flag & 8) + { + npc->act_no = 10; + + if (npc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + break; + + case 10: + npc->xm = 0; + npc->ani_no = 8; + break; + + case 11: + npc->act_no = 12; + npc->act_wait = 0; + npc->ani_no = 9; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 12: + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 10) + npc->ani_no = 9; + + break; + + case 13: + npc->ani_no = 11; + npc->xm = 0; + npc->ym = 0; + npc->act_no = 14; + + for (n = 0; n < NPC_MAX; ++n) + if (gNPC[n].code_event == 501) + break; + + if (n == NPC_MAX) + { + npc->act_no = 0; + break; + } + + npc->pNpc = &gNPC[n]; + // Fallthrough + case 14: + if (npc->pNpc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + + if (npc->pNpc->direct == 0) + npc->x = npc->pNpc->x - (6 * 0x200); + else + npc->x = npc->pNpc->x + (6 * 0x200); + + npc->y = npc->pNpc->y + (4 * 0x200); + + if (npc->pNpc->ani_no == 2 || npc->pNpc->ani_no == 4) + npc->y -= 1 * 0x200; + + break; + + case 15: + npc->act_no = 16; + SetNpChar(257, npc->x + (128 * 0x200), npc->y, 0, 0, 0, NULL, 0); + SetNpChar(257, npc->x + (128 * 0x200), npc->y, 0, 0, 2, NULL, 0x80); + npc->xm = 0; + npc->ani_no = 0; + // Fallthrough + case 16: + gSuperXpos = npc->x - (24 * 0x200); + gSuperYpos = npc->y - (8 * 0x200); + break; + + case 17: + npc->xm = 0; + npc->ani_no = 12; + gSuperXpos = npc->x; + gSuperYpos = npc->y - (8 * 0x200); + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 21: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + if (npc->x < gMC.x - (8 * 0x200)) + { + npc->direct = 2; + npc->act_no = 0; + } + + break; + + case 30: + npc->act_no = 31; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 31: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + break; + + case 40: + npc->act_no = 41; + npc->ani_no = 9; + npc->ym = -0x400; + break; + } + + if (npc->act_no != 14) + { + npc->ym += 0x40; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Chalkboard +void ActNpc043(NPCHAR *npc) +{ + RECT rcLeft = {128, 80, 168, 112}; + RECT rcRight = {168, 80, 208, 112}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 1 * 0x10 * 0x200; + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft; + else + npc->rect = rcRight; +} + +// Polish +void ActNpc044(NPCHAR *npc) +{ + // Yeah, Pixel defined these backwards for some reason. + RECT rcRight[3] = { + {0, 0, 32, 32}, + {32, 0, 64, 32}, + {64, 0, 96, 32}, + }; + + RECT rcLeft[3] = { + {0, 0, 32, 32}, + {96, 0, 128, 32}, + {128, 0, 160, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + npc->ani_no = 0; + + if (npc->direct == 0) + npc->act_no = 8; + else + npc->act_no = 2; + // Fallthrough + case 2: + npc->ym += 0x20; + + if (npc->ym > 0 && npc->flag & 8) + { + npc->ym = -0x100; + npc->xm += 0x100; + } + + if (npc->flag & 4) + npc->act_no = 3; + + break; + + case 3: + npc->xm += 0x20; + + if (npc->xm > 0 && npc->flag & 4) + { + npc->xm = -0x100; + npc->ym -= 0x100; + } + + if (npc->flag & 2) + npc->act_no = 4; + + break; + + case 4: + npc->ym -= 0x20; + + if (npc->ym < 0 && npc->flag & 2) + { + npc->ym = 0x100; + npc->xm -= 0x100; + } + + if (npc->flag & 1) + npc->act_no = 5; + + break; + + case 5: + npc->xm -= 0x20; + + if (npc->xm < 0 && npc->flag & 1) + { + npc->xm = 0x100; + npc->ym += 0x100; + } + + if (npc->flag & 8) + npc->act_no = 2; + + break; + + case 6: + npc->ym += 0x20; + + if (npc->ym > 0 && npc->flag & 8) + { + npc->ym = -0x100; + npc->xm -= 0x100; + } + + if (npc->flag & 1) + npc->act_no = 7; + + break; + + case 7: + npc->xm -= 0x20; + + if (npc->xm < 0 && npc->flag & 1) + { + npc->xm = 0x100; + npc->ym -= 0x100; + } + + if (npc->flag & 2) + npc->act_no = 8; + + break; + + case 8: + npc->ym -= 0x20; + + if (npc->ym < 0 && npc->flag & 2) + { + npc->ym = 0x100; + npc->xm += 0x100; + } + + if (npc->flag & 4) + npc->act_no = 9; + + break; + + case 9: + npc->xm += 0x20; + + if (npc->xm > 0 && npc->flag & 4) + { + npc->xm = -0x100; + npc->ym += 0x100; + } + + if (npc->flag & 8) + npc->act_no = 6; + + break; + } + + if (npc->life <= 100) + { + int i; + + for (i = 0; i < 10; ++i) + SetNpChar(45, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + PlaySoundObject(25, SOUND_MODE_PLAY); + npc->cond = 0; + } + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->shock) + { + npc->x += npc->xm / 2; + npc->y += npc->ym / 2; + } + else + { + npc->x += npc->xm; + npc->y += npc->ym; + } + + if (npc->act_no >= 2 && npc->act_no <= 9 && ++npc->ani_no > 2) + npc->ani_no = 1; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Baby +void ActNpc045(NPCHAR *npc) +{ + RECT rect[3] = { + {0, 32, 16, 48}, + {16, 32, 32, 48}, + {32, 32, 48, 48}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 2; + + if (Random(0, 1)) + npc->xm = Random(-0x200, -0x100); + else + npc->xm = Random(0x100, 0x200); + + if (Random(0, 1)) + npc->ym = Random(-0x200, -0x100); + else + npc->ym = Random(0x100, 0x200); + + npc->xm2 = npc->xm; + npc->ym2 = npc->ym; + // Fallthrough + case 1: + case 2: + if (++npc->ani_no > 2) + npc->ani_no = 1; + + break; + } + + if (npc->xm2 < 0 && npc->flag & 1) + npc->xm2 *= -1; + if (npc->xm2 > 0 && npc->flag & 4) + npc->xm2 *= -1; + + if (npc->ym2 < 0 && npc->flag & 2) + npc->ym2 *= -1; + if (npc->ym2 > 0 && npc->flag & 8) + npc->ym2 *= -1; + + if (npc->xm2 > 0x200) + npc->xm2 = 0x200; + if (npc->xm2 < -0x200) + npc->xm2 = -0x200; + + if (npc->ym2 > 0x200) + npc->ym2 = 0x200; + if (npc->ym2 < -0x200) + npc->ym2 = -0x200; + + if (npc->shock) + { + npc->x += npc->xm2 / 2; + npc->y += npc->ym2 / 2; + } + else + { + npc->x += npc->xm2; + npc->y += npc->ym2; + } + + npc->rect = rect[npc->ani_no]; +} + +// H/V Trigger +void ActNpc046(NPCHAR *npc) +{ + RECT rect = {0, 0, 16, 16}; + + npc->bits |= NPC_EVENT_WHEN_TOUCHED; + + if (npc->direct == 0) + { + if (npc->x < gMC.x) + npc->x += 0x5FF; + else + npc->x -= 0x5FF; + } + else + { + if (npc->y < gMC.y) + npc->y += 0x5FF; + else + npc->y -= 0x5FF; + } + + npc->rect = rect; +} + +// Sandcroc +void ActNpc047(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + npc->act_no = 1; + npc->act_wait = 0; + npc->tgt_y = npc->y; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + npc->bits &= ~NPC_SOLID_SOFT; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + // Fallthrough + case 1: + if (gMC.x > npc->x - (8 * 0x200) && gMC.x < npc->x + (8 * 0x200) && gMC.y > npc->y && gMC.y < npc->y + (8 * 0x200)) + { + npc->act_no = 2; + npc->act_wait = 0; + PlaySoundObject(102, SOUND_MODE_PLAY); + } + + if (npc->x < gMC.x) + npc->x += 2 * 0x200; + + if (npc->x > gMC.x) + npc->x -= 2 * 0x200; + + break; + + case 2: + if (++npc->ani_wait > 3) + { + ++npc->ani_no; + npc->ani_wait = 0; + } + + if (npc->ani_no == 3) + npc->damage = 10; + + if (npc->ani_no == 4) + { + npc->bits |= NPC_SHOOTABLE; + npc->act_no = 3; + npc->act_wait = 0; + } + + break; + + case 3: + npc->bits |= NPC_SOLID_SOFT; + npc->damage = 0; + ++npc->act_wait; + + if (npc->shock) + { + npc->act_no = 4; + npc->act_wait = 0; + } + + break; + + case 4: + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->y += 1 * 0x200; + + if (++npc->act_wait == 32) + { + npc->bits &= ~NPC_SOLID_SOFT; + npc->bits &= ~NPC_SHOOTABLE; + npc->act_no = 5; + npc->act_wait = 0; + } + + break; + + case 5: + if (npc->act_wait < 100) + { + ++npc->act_wait; + } + else + { + npc->y = npc->tgt_y; + npc->ani_no = 0; + npc->act_no = 0; + } + + break; + } + + RECT rect[5] = { + {0, 48, 48, 80}, + {48, 48, 96, 80}, + {96, 48, 144, 80}, + {144, 48, 192, 80}, + {192, 48, 240, 80}, + }; + + npc->rect = rect[npc->ani_no]; +} + +// Omega projectiles +void ActNpc048(NPCHAR *npc) +{ + if (npc->flag & 1 && npc->xm < 0) + { + npc->xm *= -1; + } + else if (npc->flag & 4 && npc->xm > 0) + { + npc->xm *= -1; + } + else if (npc->flag & 8) + { + if (++npc->count1 > 2 || npc->direct == 2) + { + VanishNpChar(npc); + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + else + { + npc->ym = -0x100; + } + } + + if (npc->direct == 2) + { + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + } + + npc->ym += 5; + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rcLeft[2] = { + {288, 88, 304, 104}, + {304, 88, 320, 104}, + }; + + RECT rcRight[2] = { + {288, 104, 304, 120}, + {304, 104, 320, 120}, + }; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + if (++npc->ani_no > 1) + npc->ani_no = 0; + } + + if (++npc->act_wait > 750) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Skullhead +void ActNpc049(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + if (npc->act_no >= 10 && npc->pNpc->code_char == 3) + { + npc->act_no = 3; + npc->xm = 0; + npc->ym = 0; + npc->count2 = 1; + } + + if (npc->flag & 1) + { + npc->direct = 2; + npc->xm = 0x100; + } + + if (npc->flag & 4) + { + npc->direct = 0; + npc->xm = -0x100; + } + + switch (npc->act_no) + { + case 0: + if (npc->pNpc != NULL) + npc->act_no = 10; + else + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->act_wait > 3) + { + npc->ym = -0x400; + npc->act_no = 3; + npc->ani_no = 2; + + if (npc->count2 != 0) + { + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + } + else + { + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + } + + npc->ani_no = 1; + break; + + case 3: + if (npc->flag & 8) + { + npc->act_no = 1; + npc->act_wait = 0; + npc->xm = 0; + } + + if (npc->flag & 8 || npc->ym > 0) + npc->ani_no = 1; + else + npc->ani_no = 2; + + break; + + case 10: + if (npc->count1 < 50) + { + ++npc->count1; + } + else + { + if (npc->x - (128 * 0x200) < gMC.x && npc->x + (128 * 0x200) > gMC.x && npc->y - (96 * 0x200) < gMC.y && npc->y + (96 * 0x200) > gMC.y) + { + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 2; + } + } + + break; + + case 11: + if (++npc->act_wait == 30 || npc->act_wait == 35) + { + deg = GetArktan(npc->x - gMC.x, npc->y + (4 * 0x200) - gMC.y); + ym = GetSin(deg) * 2; + xm = GetCos(deg) * 2; + SetNpChar(50, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 50) + { + npc->count1 = 0; + npc->act_no = 10; + npc->ani_no = 1; + } + + break; + } + + if (npc->act_no >= 10) + { + npc->x = npc->pNpc->x; + npc->y = npc->pNpc->y + (16 * 0x200); + npc->direct = npc->pNpc->direct; + --npc->pNpc->count1; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rcLeft[3] = { + {0, 80, 32, 104}, + {32, 80, 64, 104}, + {64, 80, 96, 104}, + }; + + RECT rcRight[3] = { + {0, 104, 32, 128}, + {32, 104, 64, 128}, + {64, 104, 96, 128}, + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Skeleton projectile +void ActNpc050(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->act_no = 2; + // Fallthrough + case 1: + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 1) + { + npc->act_no = 2; + npc->xm = 0x200; + ++npc->count1; + } + + if (npc->flag & 4) + { + npc->act_no = 2; + npc->xm = -0x200; + ++npc->count1; + } + + if (npc->flag & 2) + { + npc->act_no = 2; + npc->ym = 0x200; + ++npc->count1; + } + + if (npc->flag & 8) + { + npc->act_no = 2; + npc->ym = -0x200; + ++npc->count1; + } + + break; + + case 2: + npc->ym += 0x40; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 8) + { + if (++npc->count1 > 1) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + } + + break; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + RECT rect[4] = { + {48, 32, 64, 48}, + {64, 32, 80, 48}, + {80, 32, 96, 48}, + {96, 32, 112, 48}, + }; + + if (npc->direct == 0) + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + } + else + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + --npc->ani_no; + } + + if (npc->ani_no < 0) + npc->ani_no = 3; + } + + npc->rect = rect[npc->ani_no]; +} + +// Crow & Skullhead +void ActNpc051(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + if (npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) < gMC.x && npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) > gMC.x && npc->y - (((WINDOW_HEIGHT / 2) + 200) * 0x200) < gMC.y && npc->y + (((WINDOW_HEIGHT / 2) + 200) * 0x200) > gMC.y) + { + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + + if (npc->direct == 0) // Completely redundant as both the conditions are the same + npc->ym = 0x400; + else + npc->ym = 0x400; + + npc->act_no = 1; + SetNpChar(49, 0, 0, 0, 0, 0, npc, 0); + } + else + { + break; + } + + // Fallthrough + case 1: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_y < npc->y) + npc->ym -= 10; + if (npc->tgt_y > npc->y) + npc->ym += 10; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->count1 < 10) + ++npc->count1; + else + npc->act_no = 2; + + break; + + case 2: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->y > gMC.y + (32 * 0x200)) + { + if (gMC.x < npc->x) + npc->xm += 0x10; + if (gMC.x > npc->x) + npc->xm -= 0x10; + } + else + { + if (gMC.x < npc->x) + npc->xm -= 0x10; + if (gMC.x > npc->x) + npc->xm += 0x10; + } + + if (gMC.y < npc->y) + npc->ym -= 0x10; + if (gMC.y > npc->y) + npc->ym += 0x10; + + if (npc->shock) + { + npc->ym += 0x20; + npc->xm = 0; + } + + break; + } + + if (npc->xm < 0 && npc->flag & 1) + npc->xm = 0x100; + if (npc->xm > 0 && npc->flag & 4) + npc->xm = -0x100; + + if (npc->ym < 0 && npc->flag & 2) + npc->ym = 0x100; + if (npc->ym > 0 && npc->flag & 8) + npc->ym = -0x100; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[5] = { + {96, 80, 128, 112}, + {128, 80, 160, 112}, + {160, 80, 192, 112}, + {192, 80, 224, 112}, + {224, 80, 256, 112}, + }; + + RECT rect_right[5] = { + {96, 112, 128, 144}, + {128, 112, 160, 144}, + {160, 112, 192, 144}, + {192, 112, 224, 144}, + {224, 112, 256, 144}, + }; + + if (npc->shock) + { + npc->ani_no = 4; + } + else if (npc->act_no == 2 && npc->y < gMC.y - (32 * 0x200)) + { + npc->ani_no = 0; + } + else + { + if (npc->act_no != 0) + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + } + } + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Blue robot (sitting) +void ActNpc052(NPCHAR *npc) +{ + RECT rect = {240, 96, 256, 112}; + + npc->rect = rect; +} + +// Skullstep leg +void ActNpc053(NPCHAR *npc) +{ + unsigned char deg; + + RECT rcLeft[2] = { + {0, 128, 24, 144}, + {24, 128, 48, 144}, + }; + + RECT rcRight[2] = { + {48, 128, 72, 144}, + {72, 128, 96, 144}, + }; + + if (npc->pNpc->code_char == 3) + { + VanishNpChar(npc); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 4); + return; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->count1 = 10; + // Fallthrough + case 1: + if (npc->direct == 0 && npc->flag & 0x20) + { + npc->pNpc->y -= 2 * 0x200; + npc->pNpc->ym -= 0x100; + } + + if (npc->direct == 2 && npc->flag & 0x10) + { + npc->pNpc->y -= 2 * 0x200; + npc->pNpc->ym -= 0x100; + } + + if (npc->flag & 8) + { + npc->pNpc->y -= 2 * 0x200; + npc->pNpc->ym -= 0x100; + + if (npc->pNpc->direct == 0) + npc->pNpc->xm -= 0x80; + else + npc->pNpc->xm += 0x80; + } + + deg = (unsigned char)npc->xm + (unsigned char)npc->pNpc->count2; + npc->x = npc->pNpc->x + npc->count1 * GetCos(deg); + npc->y = npc->pNpc->y + npc->count1 * GetSin(deg); + + npc->direct = npc->pNpc->direct; + + break; + } + + npc->direct = npc->pNpc->direct; + + if (deg >= 20 && deg <= 108) + npc->ani_no = 0; + else + npc->ani_no = 1; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Skullstep +void ActNpc054(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 80, 32, 104}, + {32, 80, 64, 104}, + {64, 80, 96, 104}, + }; + + RECT rcRight[3] = { + {0, 104, 32, 128}, + {32, 104, 64, 128}, + {64, 104, 96, 128}, + }; + + unsigned char deg; + + switch (npc->act_no) + { + case 0: + SetNpChar(53, 0, 0, 0, 0, npc->direct, npc, 0x100); + SetNpChar(53, 0, 0, 128, 0, npc->direct, npc, 0); + npc->act_no = 1; + npc->ani_no = 1; + // Fallthrough + case 1: + deg = npc->count2; + + if (npc->direct == 0) + deg -= 6; + else + deg += 6; + + npc->count2 = deg; + + if (npc->flag & 8) + { + npc->xm = (npc->xm * 3) / 4; + + if (++npc->act_wait > 60) + { + npc->act_no = 2; + npc->act_wait = 0; + } + } + else + { + npc->act_wait = 0; + } + + if (npc->direct == 0 && npc->flag & 1) + { + if (++npc->count1 > 8) + { + npc->direct = 2; + npc->xm *= -1; + } + } + else if (npc->direct == 2 && npc->flag & 4) + { + if (++npc->count1 > 8) + { + npc->direct = 0; + npc->xm *= -1; + } + } + else + { + npc->count1 = 0; + } + + break; + + case 2: + ++npc->act_wait; + npc->shock += (unsigned char)npc->act_wait; + + if (npc->act_wait > 50) + { + VanishNpChar(npc); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + PlaySoundObject(25, SOUND_MODE_PLAY); + } + + break; + } + + npc->ym += 0x80; + + if (npc->xm > 0x2FF) + npc->xm = 0x2FF; + if (npc->xm < -0x2FF) + npc->xm = -0x2FF; + + if (npc->ym > 0x2FF) + npc->ym = 0x2FF; + if (npc->ym < -0x2FF) + npc->ym = -0x2FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Kazuma +void ActNpc055(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {192, 192, 208, 216}, + {208, 192, 224, 216}, + {192, 192, 208, 216}, + {224, 192, 240, 216}, + {192, 192, 208, 216}, + {240, 192, 256, 216}, + }; + + RECT rcRight[6] = { + {192, 216, 208, 240}, + {208, 216, 224, 240}, + {192, 216, 208, 240}, + {224, 216, 240, 240}, + {192, 216, 208, 240}, + {240, 216, 256, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + break; + + case 5: + npc->ani_no = 5; + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Beetle (Sand Zone) +void ActNpc056(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 144, 16, 160}, + {16, 144, 32, 160}, + {32, 144, 48, 160}, + }; + + RECT rcRight[3] = { + {0, 160, 16, 176}, + {16, 160, 32, 176}, + {32, 160, 48, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + npc->act_no = 1; + else + npc->act_no = 3; + + break; + + case 1: + npc->xm -= 0x10; + + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->shock) + npc->x += npc->xm / 2; + else + npc->x += npc->xm; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + if (npc->flag & 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 0; + npc->xm = 0; + npc->direct = 2; + } + + break; + + case 2: + if (npc->x < gMC.x && npc->x > gMC.x - (16 * 0x10 * 0x200) && npc->y < gMC.y + (8 * 0x200) && npc->y > gMC.y - (8 * 0x200)) + { + npc->act_no = 3; + npc->ani_wait = 0; + npc->ani_no = 1; + } + + break; + + case 3: + npc->xm += 0x10; + + if (npc->xm > 0x400) + npc->xm = 0x400; + + if (npc->shock) + npc->x += npc->xm / 2; + else + npc->x += npc->xm; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + if (npc->flag & 4) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 0; + npc->xm = 0; + npc->direct = 0; + } + + break; + + case 4: + if (npc->x < gMC.x + (16 * 0x10 * 0x200) && npc->x > gMC.x && npc->y < gMC.y + (8 * 0x200) && npc->y > gMC.y - (8 * 0x200)) + { + npc->act_no = 1; + npc->ani_wait = 0; + npc->ani_no = 1; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Crow +void ActNpc057(NPCHAR *npc) +{ + unsigned char deg; + + switch (npc->act_no) + { + case 0: + deg = Random(0, 0xFF); + npc->xm = GetCos(deg); + deg += 0x40; + npc->tgt_x = npc->x + (GetCos(deg) * 8); + + deg = Random(0, 0xFF); + npc->ym = GetSin(deg); + deg += 0x40; + npc->tgt_y = npc->y + (GetSin(deg) * 8); + + npc->act_no = 1; + npc->count1 = 120; + npc->ani_no = Random(0, 1); + npc->ani_wait = Random(0, 4); + // Fallthrough + case 1: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_x < npc->x) + npc->xm -= 0x10; + if (npc->tgt_x > npc->x) + npc->xm += 0x10; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->shock) + { + npc->act_no = 2; + npc->act_wait = 0; + + if (npc->direct == 2) + npc->xm = -0x200; + else + npc->xm = 0x200; + + npc->ym = 0; + } + + break; + + case 2: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->y > gMC.y + (48 * 0x200)) + { + if (gMC.x < npc->x) + npc->xm += 0x10; + if (gMC.x > npc->x) + npc->xm -= 0x10; + } + else + { + if (gMC.x < npc->x) + npc->xm -= 0x10; + if (gMC.x > npc->x) + npc->xm += 0x10; + } + + if (gMC.y < npc->y) + npc->ym -= 0x10; + if (gMC.y > npc->y) + npc->ym += 0x10; + + if (npc->shock) + { + npc->ym += 0x20; + npc->xm = 0; + } + + if (npc->xm < 0 && npc->flag & 1) + npc->xm = 0x200; + if (npc->xm > 0 && npc->flag & 4) + npc->xm = -0x200; + + if (npc->ym < 0 && npc->flag & 2) + npc->ym = 0x200; + if (npc->ym > 0 && npc->flag & 8) + npc->ym = -0x200; + + if (npc->xm > 0x5FF) + npc->xm = 0x5FF; + if (npc->xm < -0x5FF) + npc->xm = -0x5FF; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[5] = { + {96, 80, 128, 112}, + {128, 80, 160, 112}, + {160, 80, 192, 112}, + {192, 80, 224, 112}, + {224, 80, 256, 112}, + }; + + RECT rect_right[5] = { + {96, 112, 128, 144}, + {128, 112, 160, 144}, + {160, 112, 192, 144}, + {192, 112, 224, 144}, + {224, 112, 256, 144}, + }; + + if (npc->shock) + { + npc->ani_no = 4; + } + else + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + } + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Basu (Egg Corridor) +void ActNpc058(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {192, 0, 216, 24}, + {216, 0, 240, 24}, + {240, 0, 264, 24}, + }; + + RECT rcRight[3] = { + {192, 24, 216, 48}, + {216, 24, 240, 48}, + {240, 24, 264, 48}, + }; + + switch (npc->act_no) + { + case 0: + if (gMC.x < npc->x + (16 * 0x200) && gMC.x > npc->x - (16 * 0x200)) + { + npc->bits |= NPC_SHOOTABLE; + npc->ym = -0x100; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->act_no = 1; + npc->act_wait = 0; + npc->count1 = npc->direct; + npc->count2 = 0; + npc->damage = 6; + + if (npc->direct == 0) + { + npc->x = gMC.x + (16 * 0x10 * 0x200); + npc->xm = -0x2FF; + } + else + { + npc->x = gMC.x - (16 * 0x10 * 0x200); + npc->xm = 0x2FF; + } + + return; + } + + npc->rect.right = 0; + npc->damage = 0; + npc->xm = 0; + npc->ym = 0; + npc->bits &= ~NPC_SHOOTABLE; + + return; + + case 1: + if (npc->x > gMC.x) + { + npc->direct = 0; + npc->xm -= 0x10; + } + else + { + npc->direct = 2; + npc->xm += 0x10; + } + + if (npc->flag & 1) + npc->xm = 0x200; + + if (npc->flag & 4) + npc->xm = -0x200; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + if (npc->xm > 0x2FF) + npc->xm = 0x2FF; + if (npc->xm < -0x2FF) + npc->xm = -0x2FF; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + + if (npc->shock) + { + npc->x += npc->xm / 2; + npc->y += npc->ym / 2; + } + else + { + npc->x += npc->xm; + npc->y += npc->ym; + } + + if (gMC.x > npc->x + (400 * 0x200) || gMC.x < npc->x - (400 * 0x200)) // TODO: Maybe do something about this for widescreen + { + npc->act_no = 0; + npc->xm = 0; + npc->direct = npc->count1; + npc->x = npc->tgt_x; + npc->rect.right = 0; + npc->damage = 0; + return; + } + + break; + } + + if (npc->act_no != 0) // This is always true + { + if (npc->act_wait < 150) + ++npc->act_wait; + + if (npc->act_wait == 150) + { + if ((++npc->count2 % 8) == 0 && npc->x < gMC.x + (160 * 0x200) && npc->x > gMC.x - (160 * 0x200)) // TODO: Maybe do something about this for widescreen + { + unsigned char deg; + int xm; + int ym; + + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg) * 2; + xm = GetCos(deg) * 2; + SetNpChar(84, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (npc->count2 > 8) + { + npc->act_wait = 0; + npc->count2 = 0; + } + } + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->act_wait > 120 && npc->act_wait / 2 % 2 == 1 && npc->ani_no == 1) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Eye door +void ActNpc059(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {224, 16, 240, 40}, + {208, 80, 224, 104}, + {224, 80, 240, 104}, + {240, 80, 256, 104}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->x - (64 * 0x200) < gMC.x && npc->x + (64 * 0x200) > gMC.x && npc->y - (64 * 0x200) < gMC.y && npc->y + (64 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_wait = 0; + } + + break; + + case 2: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no == 2) + npc->act_no = 3; + + break; + + case 3: + if (npc->x - (64 * 0x200) < gMC.x && npc->x + (64 * 0x200) > gMC.x && npc->y - (64 * 0x200) < gMC.y && npc->y + (64 * 0x200) > gMC.y) + { + // There probably used to be some commented-out code here + } + else + { + npc->act_no = 4; + npc->ani_wait = 0; + } + + break; + + case 4: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + --npc->ani_no; + } + + if (npc->ani_no == 0) + npc->act_no = 1; + + break; + } + + if (npc->shock) + npc->rect = rcLeft[3]; + else + npc->rect = rcLeft[npc->ani_no]; +} diff --git a/src/NpcAct060.cpp b/src/NpcAct060.cpp new file mode 100644 index 0000000..6a3bc9f --- /dev/null +++ b/src/NpcAct060.cpp @@ -0,0 +1,1847 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "MycParam.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Toroko +void ActNpc060(NPCHAR *npc) +{ + RECT rcLeft[8] = { + {0, 64, 16, 80}, + {16, 64, 32, 80}, + {32, 64, 48, 80}, + {16, 64, 32, 80}, + {48, 64, 64, 80}, + {16, 64, 32, 80}, + {112, 64, 128, 80}, + {128, 64, 144, 80}, + }; + + RECT rcRight[8] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + {32, 80, 48, 96}, + {16, 80, 32, 96}, + {48, 80, 64, 96}, + {16, 80, 32, 96}, + {112, 80, 128, 96}, + {128, 80, 144, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (16 * 0x200) < gMC.x && npc->x + (16 * 0x200) > gMC.x && npc->y - (16 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + if (npc->flag & 1) + { + npc->direct = 2; + npc->xm = 0x200; + } + + if (npc->flag & 4) + { + npc->direct = 0; + npc->xm = -0x200; + } + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + break; + + case 6: + npc->act_no = 7; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ani_wait = 0; + npc->ym = -0x400; + // Fallthrough + case 7: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (npc->act_wait++ != 0 && npc->flag & 8) + npc->act_no = 3; + + break; + + case 8: + npc->ani_no = 1; + npc->act_wait = 0; + npc->act_no = 9; + npc->ym = -0x200; + // Fallthrough + case 9: + if (npc->act_wait++ != 0 && npc->flag & 8) + npc->act_no = 0; + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 6; + npc->ym = -0x400; + PlaySoundObject(50, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + break; + + case 11: + if (npc->act_wait++ != 0 && npc->flag & 8) + { + npc->act_no = 12; + npc->ani_no = 7; + npc->bits |= NPC_INTERACTABLE; + } + + break; + + case 12: + npc->xm = 0; + break; + } + + npc->ym += 0x40; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// King +void ActNpc061(NPCHAR *npc) +{ + int i; + + RECT rcLeft[11] = { + // NpcRegu + {224, 32, 240, 48}, // 0 - Stood + {240, 32, 256, 48}, // 1 - Blinking + {256, 32, 272, 48}, // 2 - Injured - falling backwards + {272, 32, 288, 48}, // 3 - Lying down + {288, 32, 304, 48}, // 4 - Walking - frame 1 + {224, 32, 240, 48}, // 5 - Walking - frame 2 + {304, 32, 320, 48}, // 6 - Walking - frame 3 + {224, 32, 240, 48}, // 7 - Walking - frame 4 + {272, 32, 288, 48}, // 8 - Dying - frame 1 + {0, 0, 0, 0}, // 9 - Dying - frame 2 + // NpcSym + {112, 32, 128, 48}, // 10 - King's sword + }; + + RECT rcRight[11] = { + // NpcRegu + {224, 48, 240, 64}, // 0 - Stood + {240, 48, 256, 64}, // 1 - Blinking + {256, 48, 272, 64}, // 2 - Injured - falling backwards + {272, 48, 288, 64}, // 3 - Lying down + {288, 48, 304, 64}, // 4 - Walking - frame 1 + {224, 48, 240, 64}, // 5 - Walking - frame 2 + {304, 48, 320, 64}, // 6 - Walking - frame 3 + {224, 48, 240, 64}, // 7 - Walking - frame 4 + {272, 48, 288, 64}, // 8 - Dying - frame 1 + {0, 0, 0, 0}, // 9 - Dying - frame 2 + // NpcSym + {112, 32, 128, 48}, // 10 - King's sword + }; + + switch (npc->act_no) + { + case 0: // Stood + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: // Blink + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 5: // Lying down + npc->ani_no = 3; + npc->xm = 0; + break; + + case 6: // Being knocked-back + npc->act_no = 7; + npc->act_wait = 0; + npc->ani_wait = 0; + npc->ym = -0x400; + // Fallthrough + case 7: + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + // If touching ground, enter 'lying down' state (the `act_wait` check is probably + // so he doesn't do it before he even leaves the ground in the first place) + if (npc->act_wait++ != 0 && npc->flag & 8) + npc->act_no = 5; + + break; + + case 8: // Walking + npc->act_no = 9; + npc->ani_no = 4; + npc->ani_wait = 0; + // Fallthrough + case 9: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 4; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + break; + + case 10: // Running + npc->act_no = 11; + npc->ani_no = 4; + npc->ani_wait = 0; + // Fallthrough + case 11: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 4; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + break; + + case 20: // Spawn his sword, before entering his 'idle' state + SetNpChar(NPC_KINGS_SWORD, 0, 0, 0, 0, 2, npc, 0x100); + npc->ani_no = 0; + npc->act_no = 0; + break; + + case 30: // Flying through air after being attacked by Misery + npc->act_no = 31; + npc->act_wait = 0; + npc->ani_wait = 0; + npc->ym = 0; + // Fallthrough + case 31: + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x600; + else + npc->xm = 0x600; + + if (npc->flag & 1) + { + npc->direct = 2; + npc->act_no = 7; + npc->act_wait = 0; + npc->ani_wait = 0; + npc->ym = -0x400; + npc->xm = 0x200; + PlaySoundObject(71, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, 0x800, 4); + } + + break; + + case 40: // Dying + npc->act_no = 42; + npc->act_wait = 0; + npc->ani_no = 8; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 42: + if (++npc->ani_no > 9) + npc->ani_no = 8; + + if (++npc->act_wait > 100) + { + for (i = 0; i < 4; ++i) + SetNpChar(NPC_SMOKE, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->act_no = 50; + npc->surf = SURFACE_ID_NPC_SYM; + npc->ani_no = 10; + } + + break; + + case 60: // Leap (used to attack Balrog in the Sand Zone storehouse) + npc->ani_no = 6; + npc->act_no = 61; + npc->ym = -0x5FF; + npc->xm = 0x400; + npc->count2 = 1; + break; + + case 61: // Leap - part 2 + npc->ym += 0x40; + + if (npc->flag & 8) + { + npc->act_no = 0; + npc->count2 = 0; + npc->xm = 0; + } + + break; + } + + // Apply gravity and speed-caps during most states + if (npc->act_no < 30 || npc->act_no >= 40) + { + npc->ym += 0x40; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Kazuma at computer +void ActNpc062(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {272, 192, 288, 216}, + {288, 192, 304, 216}, + {304, 192, 320, 216}, + }; + + switch (npc->act_no) + { + case 0: + npc->x -= 4 * 0x200; + npc->y += 16 * 0x200; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (Random(0, 80) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (Random(0, 120) == 10) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 2; + } + + break; + + case 2: + if (++npc->act_wait > 40) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 2; + } + + break; + + case 3: + if (++npc->act_wait > 80) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Toroko with stick +void ActNpc063(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {64, 64, 80, 80}, + {80, 64, 96, 80}, + {64, 64, 80, 80}, + {96, 64, 112, 80}, + {112, 64, 128, 80}, + {128, 64, 144, 80}, + }; + + RECT rcRight[6] = { + {64, 80, 80, 96}, + {80, 80, 96, 96}, + {64, 80, 80, 96}, + {96, 80, 112, 96}, + {112, 80, 128, 96}, + {128, 80, 144, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = 0; + npc->ani_wait = 0; + npc->ym = -0x400; + // Fallthrough + case 1: + if (npc->ym > 0) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (npc->act_wait++ != 0 && npc->flag & 8) + npc->act_no = 2; + + break; + + case 2: + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 3: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + if (++npc->act_wait > 50) + { + npc->act_wait = 40; + npc->xm *= -1; + + if (npc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + if (npc->act_wait > 35) + npc->bits |= NPC_SHOOTABLE; + + if (npc->direct == 0) + npc->xm -= 0x40; + else + npc->xm += 0x40; + + if (npc->shock) + { + npc->act_no = 4; + npc->ani_no = 4; + npc->ym = -0x400; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + } + + break; + + case 4: + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (npc->act_wait++ != 0 && npc->flag & 8) + { + npc->act_no = 5; + npc->bits |= NPC_INTERACTABLE; + } + + break; + + case 5: + npc->xm = 0; + npc->ani_no = 5; + break; + } + + npc->ym += 0x40; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// First Cave Critter +void ActNpc064(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + }; + + RECT rcRight[3] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + }; + + switch (npc->act_no) + { + case 0: // Initialize + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: // Waiting + // Look at player + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_x < 100) + ++npc->tgt_x; + + // Open eyes near player + if (npc->act_wait >= 8 && npc->x - (112 * 0x200) < gMC.x && npc->x + (112 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (80 * 0x200) > gMC.y) + { + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + // Jump if attacked + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + // Jump if player is nearby + if (npc->act_wait >= 8 && npc->tgt_x >= 100 && npc->x - (64 * 0x200) < gMC.x && npc->x + (64 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + break; + + case 2: // Going to jump + if (++npc->act_wait > 8) + { + // Set jump state + npc->act_no = 3; + npc->ani_no = 2; + + // Jump + npc->ym = -0x5FF; + PlaySoundObject(30, SOUND_MODE_PLAY); + + // Jump in facing direction + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + break; + + case 3: // Jumping + // Land + if (npc->flag & 8) + { + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + break; + } + + // Gravity + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + // Move + npc->x += npc->xm; + npc->y += npc->ym; + + // Set framerect + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// First Cave Bat +void ActNpc065(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->count1 = 120; + npc->act_no = 1; + npc->act_wait = Random(0, 50); + // Fallthrough + + case 1: + if (++npc->act_wait < 50) + break; + + npc->act_wait = 0; + npc->act_no = 2; + npc->ym = 0x300; + + break; + + case 2: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->ym > 0x300) + npc->ym = 0x300; + if (npc->ym < -0x300) + npc->ym = -0x300; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[4] = { + {32, 32, 48, 48}, + {48, 32, 64, 48}, + {64, 32, 80, 48}, + {80, 32, 96, 48}, + }; + + RECT rect_right[4] = { + {32, 48, 48, 64}, + {48, 48, 64, 64}, + {64, 48, 80, 64}, + {80, 48, 96, 64}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Misery bubble +void ActNpc066(NPCHAR *npc) +{ + RECT rect[4] = { + {32, 192, 56, 216}, + {56, 192, 80, 216}, + {32, 216, 56, 240}, + {56, 216, 80, 240}, + }; + + switch (npc->act_no) + { + case 0: + int a; + for (a = 0; a < NPC_MAX; ++a) + if (gNPC[a].code_event == 1000) + break; + + if (a == NPC_MAX) + break; + + npc->tgt_x = gNPC[a].x; + npc->tgt_y = gNPC[a].y; + npc->count1 = a; + + unsigned char deg; + deg = GetArktan(npc->x - npc->tgt_x, npc->y - npc->tgt_y); + npc->xm = GetCos(deg) * 2; + npc->ym = GetSin(deg) * 2; + + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->x - (3 * 0x200) < npc->tgt_x && npc->x + (3 * 0x200) > npc->tgt_x && npc->y - (3 * 0x200) < npc->tgt_y && npc->y + (3 * 0x200) > npc->tgt_y) + { + npc->act_no = 2; + npc->ani_no = 2; + gNPC[npc->count1].cond = 0; + PlaySoundObject(21, SOUND_MODE_PLAY); + } + + break; + + case 2: + npc->xm -= 0x20; + npc->ym -= 0x20; + + if (npc->xm < -0x5FF) + npc->xm = -0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + if (npc->y < -8 * 0x200) + npc->cond = 0; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} + +// Misery (floating) +void ActNpc067(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->ani_no = 0; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 1: + npc->x = npc->tgt_x + (Random(-1, 1) * 0x200); + + if (++npc->act_wait == 0x20) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ym = 0x200; + // Fallthrough + + case 11: + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + + break; + + case 13: + npc->ani_no = 1; + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->flag & 8) + { + PlaySoundObject(23, SOUND_MODE_PLAY); + npc->ym = 0; + npc->act_no = 14; + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->ani_no = 2; + } + + break; + + case 15: + npc->act_no = 16; + npc->act_wait = 0; + npc->ani_no = 4; + // Fallthrough + case 16: + if (++npc->act_wait == 30) + { + PlaySoundObject(21, SOUND_MODE_PLAY); + SetNpChar(66, npc->x, npc->y - (16 * 0x200), 0, 0, 0, npc, 0); + } + + if (npc->act_wait == 50) + npc->act_no = 14; + + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 0; + npc->ym = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 21: + npc->ym -= 0x20; + + if (npc->y < -8 * 0x200) + npc->cond = 0; + + break; + + case 25: + npc->act_no = 26; + npc->act_wait = 0; + npc->ani_no = 5; + npc->ani_wait = 0; + // Fallthrough + case 26: + if (++npc->ani_no > 7) + npc->ani_no = 5; + + if (++npc->act_wait == 30) + { + PlaySoundObject(101, SOUND_MODE_PLAY); + SetFlash(0, 0, FLASH_MODE_FLASH); + npc->act_no = 27; + npc->ani_no = 7; + } + + break; + + case 27: + if (++npc->act_wait == 50) + npc->act_no = 14; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rcLeft[8] = { + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {112, 0, 128, 16}, + {128, 0, 144, 16}, + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + {144, 0, 160, 16}, + }; + + RECT rcRight[8] = { + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {112, 16, 128, 32}, + {128, 16, 144, 32}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + {144, 16, 160, 32}, + }; + + if (npc->act_no == 11) + { + if (npc->ani_wait != 0) + { + --npc->ani_wait; + npc->ani_no = 1; + } + else + { + if (Random(0, 100) == 1) + npc->ani_wait = 30; + + npc->ani_no = 0; + } + } + + if (npc->act_no == 14) + { + if (npc->ani_wait != 0) + { + --npc->ani_wait; + npc->ani_no = 3; + } + else + { + if (Random(0, 100) == 1) + npc->ani_wait = 30; + + npc->ani_no = 2; + } + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 1 && npc->ani_wait < 32) + npc->rect.bottom = (++npc->ani_wait / 2) + npc->rect.bottom - 16; +} + +// Balrog (running) +void ActNpc068(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->act_wait = 30; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 1: + if (--npc->act_wait) + break; + + npc->act_no = 2; + ++npc->count1; + + break; + + case 2: + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 3: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + + if (++npc->ani_no == 2 || npc->ani_no == 4) + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + if (npc->direct == 0) + npc->xm -= 0x10; + else + npc->xm += 0x10; + + if (npc->act_wait >= 8 && npc->x - (12 * 0x200) < gMC.x && npc->x + (12 * 0x200) > gMC.x && npc->y - (12 * 0x200) < gMC.y && npc->y + (8 * 0x200) > gMC.y) + { + npc->act_no = 10; + npc->ani_no = 5; + gMC.cond |= 2; + DamageMyChar(2); + break; + } + + ++npc->act_wait; + + if (npc->flag & 5 || npc->act_wait > 75) + { + npc->act_no = 9; + npc->ani_no = 0; + break; + } + + if ((npc->count1 % 3) == 0 && npc->act_wait > 25) + { + npc->act_no = 4; + npc->ani_no = 7; + npc->ym = -0x400; + break; + } + + break; + + case 4: + if (npc->flag & 8) + { + npc->act_no = 9; + npc->ani_no = 8; + SetQuake(30); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + if (npc->act_wait >= 8 && npc->x - (12 * 0x200) < gMC.x && npc->x + (12 * 0x200) > gMC.x && npc->y - (12 * 0x200) < gMC.y && npc->y + (8 * 0x200) > gMC.y) + { + npc->act_no = 10; + npc->ani_no = 5; + gMC.cond |= 2; + DamageMyChar(2); + } + + break; + + case 9: + npc->xm = (npc->xm * 4) / 5; + + if (npc->xm != 0) + break; + + npc->act_no = 0; + + break; + + case 10: + gMC.x = npc->x; + gMC.y = npc->y; + + npc->xm = (npc->xm * 4) / 5; + + if (npc->xm != 0) + break; + + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 5; + npc->ani_wait = 0; + + break; + + case 11: + gMC.x = npc->x; + gMC.y = npc->y; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 5; + + if (++npc->act_wait > 100) + npc->act_no = 20; + + break; + + case 20: + PlaySoundObject(25, SOUND_MODE_PLAY); + gMC.cond &= ~2; + + if (npc->direct == 0) + { + gMC.x += 4 * 0x200; + gMC.y -= 8 * 0x200; + gMC.xm = 0x5FF; + gMC.ym = -0x200; + gMC.direct = 2; + npc->direct = 2; + } + else + { + gMC.x -= 4 * 0x200; + gMC.y -= 8 * 0x200; + gMC.xm = -0x5FF; + gMC.ym = -0x200; + gMC.direct = 0; + npc->direct = 0; + } + + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 7; + // Fallthrough + case 21: + if (++npc->act_wait < 50) + break; + + npc->act_no = 0; + break; + } + + npc->ym += 0x20; + + if (npc->xm < -0x400) + npc->xm = -0x400; + if (npc->xm > 0x400) + npc->xm = 0x400; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[9] = { + {0, 0, 40, 24}, + {0, 48, 40, 72}, + {0, 0, 40, 24}, + {40, 48, 80, 72}, + {0, 0, 40, 24}, + {80, 48, 120, 72}, + {120, 48, 160, 72}, + {120, 0, 160, 24}, + {80, 0, 120, 24}, + }; + + RECT rect_right[9] = { + {0, 24, 40, 48}, + {0, 72, 40, 96}, + {0, 24, 40, 48}, + {40, 72, 80, 96}, + {0, 24, 40, 48}, + {80, 72, 120, 96}, + {120, 72, 160, 96}, + {120, 24, 160, 48}, + {80, 24, 120, 48}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Pignon +void ActNpc069(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {48, 0, 64, 16}, + {64, 0, 80, 16}, + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {48, 0, 64, 16}, + {112, 0, 128, 16}, + }; + + RECT rcRight[6] = { + {48, 16, 64, 32}, + {64, 16, 80, 32}, + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {48, 16, 64, 32}, + {112, 16, 128, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 100) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + break; + } + + if (Random(0, 150) == 1) + { + if (npc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + if (Random(0, 150) == 1) + { + npc->act_no = 3; + npc->act_wait = 50; + npc->ani_no = 0; + break; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (--npc->act_wait == 0) + npc->act_no = 0; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 2; + + if (npc->flag & 1) + { + npc->direct = 2; + npc->xm = 0x200; + } + + if (npc->flag & 4) + { + npc->direct = 0; + npc->xm = -0x200; + } + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + break; + + case 5: + if (npc->flag & 8) + npc->act_no = 0; + + break; + } + + switch (npc->act_no) + { + case 1: + case 2: + case 4: + if (npc->shock) + { + npc->ym = -0x200; + npc->ani_no = 5; + npc->act_no = 5; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Sparkle +void ActNpc070(NPCHAR *npc) +{ + RECT rect[4] = { + {96, 48, 112, 64}, + {112, 48, 128, 64}, + {128, 48, 144, 64}, + {144, 48, 160, 64}, + }; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Chinfish +void ActNpc071(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->ym = 0x80; + // Fallthrough + case 1: + if (npc->tgt_y < npc->y) + npc->ym -= 8; + if (npc->tgt_y > npc->y) + npc->ym += 8; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rcLeft[3] = { + {64, 32, 80, 48}, + {80, 32, 96, 48}, + {96, 32, 112, 48}, + }; + + RECT rcRight[3] = { + {64, 48, 80, 64}, + {80, 48, 96, 64}, + {96, 48, 112, 64}, + }; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->shock) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Sprinkler +void ActNpc072(NPCHAR *npc) +{ + if (npc->direct == 0) + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + { + npc->ani_no = 0; + return; + } + + if (gMC.x < npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.x > npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.y < npc->y + (((WINDOW_HEIGHT / 2) + 120) * 0x200) && gMC.y > npc->y - (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + { + if (++npc->act_no % 2) + SetNpChar(73, npc->x, npc->y, Random(-0x200, 0x200) * 2, Random(-0x200, 0x80) * 3, 0, NULL, 0x100); + + SetNpChar(73, npc->x, npc->y, Random(-0x200, 0x200) * 2, Random(-0x200, 0x80) * 3, 0, NULL, 0x100); + } + } + + RECT rect[2] = { + {224, 48, 240, 64}, + {240, 48, 256, 64}, + }; + + npc->rect = rect[npc->ani_no]; +} + +// Water droplet +void ActNpc073(NPCHAR *npc) +{ + RECT rect[5] = { + {72, 16, 74, 18}, + {74, 16, 76, 18}, + {76, 16, 78, 18}, + {78, 16, 80, 18}, + {80, 16, 82, 18}, + }; + + npc->ym += 0x20; + npc->ani_no = Random(0, 4); + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; + + if (npc->direct == 2) + { + npc->rect.top += 2; + npc->rect.bottom += 2; + } + + if (++npc->act_wait > 10) + { + if (npc->flag & 1) + npc->cond = 0; + if (npc->flag & 4) + npc->cond = 0; + if (npc->flag & 8) + npc->cond = 0; + if (npc->flag & 0x100) + npc->cond = 0; + } + + if (npc->y > gMap.length * 0x200 * 0x10) + npc->cond = 0; +} + +// Jack +void ActNpc074(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {64, 0, 80, 16}, + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {64, 0, 80, 16}, + {112, 0, 128, 16}, + {64, 0, 80, 16}, + }; + + RECT rcRight[6] = { + {64, 16, 80, 32}, + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {64, 16, 80, 32}, + {112, 16, 128, 32}, + {64, 16, 80, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 8: + npc->act_no = 9; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 9: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + break; + } + + npc->ym += 0x40; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Kanpachi (fishing) +void ActNpc075(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {272, 32, 296, 56}, + {296, 32, 320, 56}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (npc->x - (48 * 0x200) < gMC.x && npc->x + (48 * 0x200) > gMC.x && npc->y - (48 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + npc->ani_no = 1; + else + npc->ani_no = 0; + + break; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Flowers +void ActNpc076(NPCHAR *npc) +{ + npc->rect.left = npc->code_event * 16; + npc->rect.top = 0; + npc->rect.right = npc->rect.left + 16; + npc->rect.bottom = 16; +} + +// Yamashita +void ActNpc077(NPCHAR *npc) +{ + RECT rc[3] = { + {0, 16, 48, 48}, + {48, 16, 96, 48}, + {96, 16, 144, 48}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rc[npc->ani_no]; + else + npc->rect = rc[2]; +} + +// Pot +void ActNpc078(NPCHAR *npc) +{ + RECT rc[2] = { + {160, 48, 176, 64}, + {176, 48, 192, 64}, + }; + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Mahin +void ActNpc079(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + }; + + RECT rcRight[3] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 2; + npc->ani_wait = 0; + break; + + case 2: + npc->ani_no = 0; + + if (Random(0, 120) == 10) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 3: + if (++npc->act_wait > 8) + { + npc->act_no = 2; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} diff --git a/src/NpcAct080.cpp b/src/NpcAct080.cpp new file mode 100644 index 0000000..889fdac --- /dev/null +++ b/src/NpcAct080.cpp @@ -0,0 +1,1906 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Back.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Gravekeeper +void ActNpc080(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {0, 64, 24, 88}, + {24, 64, 48, 88}, + {0, 64, 24, 88}, + {48, 64, 72, 88}, + {72, 64, 96, 88}, + {96, 64, 120, 88}, + {120, 64, 144, 88}, + }; + + RECT rcRight[7] = { + {0, 88, 24, 112}, + {24, 88, 48, 112}, + {0, 88, 24, 112}, + {48, 88, 72, 112}, + {72, 88, 96, 112}, + {96, 88, 120, 112}, + {120, 88, 144, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SHOOTABLE; + npc->act_no = 1; + npc->damage = 0; + npc->hit.front = 4 * 0x200; + // Fallthrough + case 1: + npc->ani_no = 0; + + if (npc->x - (128 * 0x200) < gMC.x && npc->x + (128 * 0x200) > gMC.x && npc->y - (48 * 0x200) < gMC.y && npc->y + (32 * 0x200) > gMC.y) + { + npc->ani_wait = 0; + npc->act_no = 2; + } + + if (npc->shock) + { + npc->ani_no = 1; + npc->ani_wait = 0; + npc->act_no = 2; + npc->bits &= ~NPC_SHOOTABLE; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 2: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + if (npc->x - (16 * 0x200) < gMC.x && npc->x + (16 * 0x200) > gMC.x) + { + npc->hit.front = (18 * 0x200); + npc->act_wait = 0; + npc->act_no = 3; + npc->bits |= NPC_SHOOTABLE; + PlaySoundObject(34, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + } + + if (gMC.x < npc->x) + { + npc->direct = 0; + npc->xm = -0x100; + } + else + { + npc->direct = 2; + npc->xm = 0x100; + } + + break; + + case 3: + npc->xm = 0; + + if (++npc->act_wait > 40) + { + npc->act_wait = 0; + npc->act_no = 4; + PlaySoundObject(106, SOUND_MODE_PLAY); + } + + npc->ani_no = 4; + break; + + case 4: + npc->damage = 10; + + if (++npc->act_wait > 2) + { + npc->act_wait = 0; + npc->act_no = 5; + } + + npc->ani_no = 5; + break; + + case 5: + npc->ani_no = 6; + + if (++npc->act_wait > 60) + npc->act_no = 0; + + break; + } + + if (npc->xm < 0 && npc->flag & 1) + npc->xm = 0; + if (npc->xm > 0 && npc->flag & 4) + npc->xm = 0; + + npc->ym += 0x20; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + +#ifdef FIX_BUGS + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; +#else + // Caps npc->xm instead of npc->ym + if (npc->ym > 0x5FF) + npc->xm = 0x5FF; + if (npc->ym < -0x5FF) + npc->xm = -0x5FF; +#endif + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Giant pignon +void ActNpc081(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {144, 64, 168, 88}, + {168, 64, 192, 88}, + {192, 64, 216, 88}, + {216, 64, 240, 88}, + {144, 64, 168, 88}, + {240, 64, 264, 88}, + }; + + RECT rcRight[6] = { + {144, 88, 168, 112}, + {168, 88, 192, 112}, + {192, 88, 216, 112}, + {216, 88, 240, 112}, + {144, 88, 168, 112}, + {240, 88, 264, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 100) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + break; + } + + if (Random(0, 150) == 1) + { + if (npc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + if (Random(0, 150) == 1) + { + npc->act_no = 3; + npc->act_wait = 50; + npc->ani_no = 0; + break; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (--npc->act_wait == 0) + npc->act_no = 0; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 2; + + if (npc->flag & 1) + { + npc->direct = 2; + npc->xm = 0x200; + } + + if (npc->flag & 4) + { + npc->direct = 0; + npc->xm = -0x200; + } + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + break; + + case 5: + if (npc->flag & 8) + npc->act_no = 0; + + break; + } + + switch (npc->act_no) + { + case 1: + case 2: + case 4: + if (npc->shock) + { + npc->ym = -0x200; + npc->ani_no = 5; + npc->act_no = 5; + + if (npc->x < gMC.x) + npc->xm = 0x100; + else + npc->xm = -0x100; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Misery (standing) +void ActNpc082(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 2; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 3; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 2; + } + + break; + + case 15: + npc->act_no = 16; + npc->act_wait = 0; + npc->ani_no = 4; + // Fallthrough + case 16: + if (++npc->act_wait == 30) + { + PlaySoundObject(21, SOUND_MODE_PLAY); + SetNpChar(66, npc->x, npc->y - (16 * 0x200), 0, 0, 0, npc, 0); + } + + if (npc->act_wait == 50) + npc->act_no = 14; + + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 0; + npc->ym = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 21: + npc->ym -= 0x20; + + if (npc->y < -8 * 0x200) + npc->cond = 0; + + break; + + case 25: + npc->act_no = 26; + npc->act_wait = 0; + npc->ani_no = 5; + npc->ani_wait = 0; + // Fallthrough + case 26: + if (++npc->ani_no > 7) + npc->ani_no = 5; + + if (++npc->act_wait == 30) + { + PlaySoundObject(101, SOUND_MODE_PLAY); + SetFlash(0, 0, FLASH_MODE_FLASH); + npc->act_no = 27; + npc->ani_no = 7; + } + + break; + + case 27: + if (++npc->act_wait == 50) + { + npc->act_no = 0; + npc->ani_no = 0; + } + + break; + + case 30: + npc->act_no = 31; + npc->ani_no = 3; + npc->ani_wait = 0; + // Fallthrough + case 31: + if (++npc->ani_wait > 10) + { + npc->act_no = 32; + npc->ani_no = 4; + npc->ani_wait = 0; + } + + break; + + case 32: + if (++npc->ani_wait > 100) + { + npc->act_no = 1; + npc->ani_no = 2; + } + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + // Fallthrough + case 41: + npc->ani_no = 4; + + switch (++npc->act_wait) + { + case 30: + case 40: + case 50: + SetNpChar(11, npc->x + (8 * 0x200), npc->y - (8 * 0x200), 0x600, Random(-0x200, 0), 0, NULL, 0x100); + PlaySoundObject(33, SOUND_MODE_PLAY); + break; + } + + if (npc->act_wait > 50) + npc->act_no = 0; + + break; + + case 50: + npc->ani_no = 8; + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rcLeft[9] = { + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {112, 0, 128, 16}, + {128, 0, 144, 16}, + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + {144, 0, 160, 16}, + {208, 64, 224, 80}, + }; + + RECT rcRight[9] = { + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {112, 16, 128, 32}, + {128, 16, 144, 32}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + {144, 16, 160, 32}, + {208, 80, 224, 96}, + }; + + if (npc->act_no == 11) + { + if (npc->ani_wait != 0) + { + --npc->ani_wait; + npc->ani_no = 1; + } + else + { + if (Random(0, 100) == 1) + npc->ani_wait = 30; + + npc->ani_no = 0; + } + } + + if (npc->act_no == 14) + { + if (npc->ani_wait != 0) + { + --npc->ani_wait; + npc->ani_no = 3; + } + else + { + if (Random(0, 100) == 1) + npc->ani_wait = 30; + + npc->ani_no = 2; + } + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Igor (cutscene) +void ActNpc083(NPCHAR *npc) +{ + RECT rcLeft[8] = { + {0, 0, 40, 40}, + {40, 0, 80, 40}, + {80, 0, 120, 40}, + {0, 0, 40, 40}, + {120, 0, 160, 40}, + {0, 0, 40, 40}, + {160, 0, 200, 40}, + {200, 0, 240, 40}, + }; + + RECT rcRight[8] = { + {0, 40, 40, 80}, + {40, 40, 80, 80}, + {80, 40, 120, 80}, + {0, 40, 40, 80}, + {120, 40, 160, 80}, + {0, 40, 40, 80}, + {160, 40, 200, 80}, + {200, 40, 240, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->xm = 0; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + + case 2: + npc->act_no = 3; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 3: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + break; + + case 4: + npc->xm = 0; + npc->act_no = 5; + npc->act_wait = 0; + npc->ani_no = 6; + // Fallthrough + case 5: + if (++npc->act_wait > 10) + { + npc->act_wait = 0; + npc->act_no = 6; + npc->ani_no = 7; + PlaySoundObject(70, SOUND_MODE_PLAY); + } + + break; + + case 6: + if (++npc->act_wait > 8) + { + npc->act_no = 0; + npc->ani_no = 0; + } + + break; + + case 7: + npc->act_no = 1; + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Basu projectile (Egg Corridor) +void ActNpc084(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[4] = { + {48, 48, 64, 64}, + {64, 48, 80, 64}, + {48, 64, 64, 80}, + {64, 64, 80, 80}, + }; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } +} + +// Terminal +void ActNpc085(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {256, 96, 272, 120}, + {256, 96, 272, 120}, + {272, 96, 288, 120}, + }; + + RECT rcRight[3] = { + {256, 96, 272, 120}, + {288, 96, 304, 120}, + {304, 96, 320, 120}, + }; + + switch(npc->act_no) + { + case 0: + npc->ani_no = 0; + + if (npc->x - (8 * 0x200) < gMC.x && npc->x + (8 * 0x200) > gMC.x && npc->y - (16 * 0x200) < gMC.y && npc->y + (8 * 0x200) > gMC.y) + { + PlaySoundObject(43, SOUND_MODE_PLAY); + npc->act_no = 1; + } + + break; + + case 1: + if (++npc->ani_no > 2) + npc->ani_no = 1; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Missile +void ActNpc086(NPCHAR *npc) +{ + RECT rect1[2] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + }; + + RECT rect3[2] = { + {0, 112, 16, 128}, + {16, 112, 32, 128}, + }; + + RECT rcLast = {16, 0, 32, 16}; + + if (npc->direct == 0) + { + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + } + + if (gBack.type == BACKGROUND_TYPE_AUTOSCROLL || gBack.type == BACKGROUND_TYPE_CLOUDS_WINDY) + { + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->ym = Random(-0x20, 0x20); + npc->xm = Random(0x7F, 0x100); + } + + npc->xm -= 8; + + if (npc->x < 80 * 0x200) + npc->cond = 0; + + if (npc->x < -3 * 0x200) + npc->x = -3 * 0x200; + + if (npc->flag & 1) + npc->xm = 0x100; + + if (npc->flag & 2) + npc->ym = 0x40; + + if (npc->flag & 8) + npc->ym = -0x40; + + npc->x += npc->xm; + npc->y += npc->ym; + } + + switch (npc->exp) + { + case 1: + npc->rect = rect1[npc->ani_no]; + break; + + case 3: + npc->rect = rect3[npc->ani_no]; + break; + } + + if (npc->direct == 0) + ++npc->count1; + + if (npc->count1 > 550) + npc->cond = 0; + + if (npc->count1 > 500 && npc->count1 / 2 % 2) + npc->rect.right = 0; + + if (npc->count1 > 547) + npc->rect = rcLast; +} + +// Heart +void ActNpc087(NPCHAR *npc) +{ + RECT rect2[2] = { + {32, 80, 48, 96}, + {48, 80, 64, 96}, + }; + + RECT rect6[2] = { + {64, 80, 80, 96}, + {80, 80, 96, 96}, + }; + + RECT rcLast = {16, 0, 32, 16}; + + if (npc->direct == 0) + { + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + } + + if (gBack.type == BACKGROUND_TYPE_AUTOSCROLL || gBack.type == BACKGROUND_TYPE_CLOUDS_WINDY) + { + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->ym = Random(-0x20, 0x20); + npc->xm = Random(0x7F, 0x100); + } + + npc->xm -= 8; + + if (npc->x < 80 * 0x200) + npc->cond = 0; + + if (npc->x < -3 * 0x200) + npc->x = -3 * 0x200; + + if (npc->flag & 1) + npc->xm = 0x100; + + if (npc->flag & 2) + npc->ym = 0x40; + + if (npc->flag & 8) + npc->ym = -0x40; + + npc->x += npc->xm; + npc->y += npc->ym; + } + + switch (npc->exp) + { + case 2: + npc->rect = rect2[npc->ani_no]; + break; + + case 6: + npc->rect = rect6[npc->ani_no]; + break; + } + + if (npc->direct == 0) + ++npc->count1; + + if (npc->count1 > 550) + npc->cond = 0; + + if (npc->count1 > 500 && npc->count1 / 2 % 2) + npc->rect.right = 0; + + if (npc->count1 > 547) + npc->rect = rcLast; +} + +// Igor (boss) +void ActNpc088(NPCHAR *npc) +{ + int i; + unsigned char deg; + int xm, ym; + + RECT rcLeft[12] = { + {0, 0, 40, 40}, + {40, 0, 80, 40}, + {80, 0, 120, 40}, + {0, 0, 40, 40}, + {120, 0, 160, 40}, + {0, 0, 40, 40}, + {160, 0, 200, 40}, + {200, 0, 240, 40}, + {0, 80, 40, 120}, + {40, 80, 80, 120}, + {240, 0, 280, 40}, + {280, 0, 320, 40}, + }; + + RECT rcRight[12] = { + {0, 40, 40, 80}, + {40, 40, 80, 80}, + {80, 40, 120, 80}, + {0, 40, 40, 80}, + {120, 40, 160, 80}, + {0, 40, 40, 80}, + {160, 40, 200, 80}, + {200, 40, 240, 80}, + {120, 80, 160, 120}, + {160, 80, 200, 120}, + {240, 40, 280, 80}, + {280, 40, 320, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->xm = 0; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 50) + npc->act_no = 2; + + break; + + case 2: + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 2; + npc->ani_wait = 0; + + if (++npc->count1 < 3 || npc->life > 150) + { + npc->count2 = 0; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + } + else + { + npc->count2 = 1; + + if (gMC.x < npc->x) + npc->direct = 2; + else + npc->direct = 0; + } + // Fallthrough + case 3: + ++npc->act_wait; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + if (npc->count2) + { + if (npc->act_wait > 16) + { + npc->act_no = 9; + npc->xm = 0; + npc->ani_no = 10; + break; + } + } + else if (npc->act_wait > 50) + { + npc->ani_no = 8; + npc->ym = -0x400; + npc->act_no = 7; + npc->act_wait = 0; + npc->xm = (npc->xm * 3) / 2; + npc->damage = 2; + break; + } + else + { + if (npc->direct == 0) + { + if (npc->x - (24 * 0x200) < gMC.x) + npc->act_no = 4; + } + else + { + if (npc->x + (24 * 0x200) > gMC.x) + npc->act_no = 4; + } + } + + break; + + case 4: + npc->xm = 0; + npc->act_no = 5; + npc->act_wait = 0; + npc->ani_no = 6; + // Fallthrough + case 5: + if (++npc->act_wait > 12) + { + npc->act_wait = 0; + npc->act_no = 6; + npc->ani_no = 7; + PlaySoundObject(70, SOUND_MODE_PLAY); + npc->damage = 5; + npc->hit.front = 24 * 0x200; + npc->hit.top = 1; + } + + break; + + case 6: + if (++npc->act_wait > 10) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->damage = 0; + npc->hit.front = 8 * 0x200; + npc->hit.top = 16 * 0x200; + } + + break; + + case 7: + if (npc->flag & 8) + { + npc->act_no = 8; + npc->ani_no = 9; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(30); + npc->damage = 0; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + break; + + case 8: + npc->xm = 0; + + if (++npc->act_wait > 10) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->damage = 0; + } + + break; + + case 9: + npc->act_no = 10; + npc->act_wait = 0; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + // Fallthrough + case 10: + if (++npc->act_wait > 100 && npc->act_wait % 6 == 1) + { + if (npc->direct == 0) + deg = 0x88; + else + deg = 0xF8; + + deg += (unsigned char)Random(-0x10, 0x10); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + SetNpChar(11, npc->x, npc->y + (4 * 0x200), xm, ym, 0, NULL, 0x100); + + PlaySoundObject(12, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 50 && npc->act_wait / 2 % 2) + npc->ani_no = 11; + else + npc->ani_no = 10; + + if (npc->act_wait > 132) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->count1 = 0; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Igor (defeated) +void ActNpc089(NPCHAR *npc) +{ + int i; + + RECT rcLeft[4] = { + {80, 80, 120, 120}, + {240, 80, 264, 104}, + {264, 80, 288, 104}, + {288, 80, 312, 104}, + }; + + RECT rcRight[4] = { + {200, 80, 240, 120}, + {240, 104, 264, 128}, + {264, 104, 288, 128}, + {288, 104, 312, 128}, + }; + + switch (npc->act_no) + { + case 0: + PlaySoundObject(72, SOUND_MODE_PLAY); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->act_wait > 100) + { + npc->act_wait = 0; + npc->act_no = 2; + } + + if (npc->act_wait % 5 == 0) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + if (npc->direct == 0) + npc->rect = rcLeft[0]; + else + npc->rect = rcRight[0]; + + if (npc->act_wait / 2 % 2) + --npc->rect.left; + + break; + + case 2: + if (++npc->act_wait / 2 % 2 && npc->act_wait < 100) + { + npc->ani_no = 0; + npc->view.back = 20 * 0x200; + npc->view.front = 20 * 0x200; + npc->view.top = 20 * 0x200; + } + else + { + npc->ani_no = 1; + npc->view.back = 12 * 0x200; + npc->view.front = 12 * 0x200; + npc->view.top = 8 * 0x200; + } + + if (npc->act_wait > 150) + { + npc->act_wait = 0; + npc->act_no = 3; + npc->ani_no = 1; + } + + if (npc->act_wait % 9 == 0) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + break; + + case 3: + if (++npc->ani_wait > 50) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no == 3) + npc->act_no = 4; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; +} + +// Background +void ActNpc090(NPCHAR *npc) +{ + RECT rect = {280, 80, 296, 104}; + + npc->rect = rect; +} + +// Cage +void ActNpc091(NPCHAR *npc) +{ + RECT rect = {96, 88, 128, 112}; + + if (npc->act_no == 0) + { + ++npc->act_no; + npc->y += 16 * 0x200; + } + + npc->rect = rect; +} + +// Sue at PC +void ActNpc092(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {272, 216, 288, 240}, + {288, 216, 304, 240}, + {304, 216, 320, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->x -= 4 * 0x200; + npc->y += 16 * 0x200; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (Random(0, 80) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (Random(0, 120) == 10) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 2; + } + + break; + + case 2: + if (++npc->act_wait > 40) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 2; + } + + break; + + case 3: + if (++npc->act_wait > 80) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Chaco +void ActNpc093(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {128, 0, 144, 16}, + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {128, 0, 144, 16}, + {176, 0, 192, 16}, + {128, 0, 144, 16}, + {32, 32, 48, 48}, + }; + + RECT rcRight[7] = { + {128, 16, 144, 32}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {128, 16, 144, 32}, + {176, 16, 192, 32}, + {128, 16, 144, 32}, + {32, 32, 48, 48}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + break; + + case 10: + npc->ani_no = 6; + + if (++npc->act_wait > 200) + { + npc->act_wait = 0; + SetCaret(npc->x, npc->y, CARET_ZZZ, DIR_LEFT); + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Kulala +void ActNpc094(NPCHAR *npc) +{ + RECT rect[5] = { + {272, 0, 320, 24}, + {272, 24, 320, 48}, + {272, 48, 320, 72}, + {272, 72, 320, 96}, + {272, 96, 320, 120}, + }; + + switch (npc->act_no) + { + case 0: + npc->ani_no = 4; + + if (npc->shock) + { + npc->ani_no = 0; + npc->act_no = 10; + npc->act_wait = 0; + } + + break; + + case 10: + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + + if (++npc->act_wait > 40) + { + npc->act_wait = 0; + npc->ani_wait = 0; + npc->act_no = 11; + } + + break; + + case 11: + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + { + npc->act_no = 12; + npc->ani_no = 3; + } + + break; + + case 12: + npc->ym = -0x155; + + if (++npc->act_wait > 20) + { + npc->act_wait = 0; + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + + case 20: + npc->xm /= 2; + npc->ym += 0x20; + + if (npc->shock == 0) + { + npc->act_wait = 30; + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + } + + if (npc->shock) + { + if (++npc->count2 > 12) + { + npc->act_no = 20; + npc->ani_no = 4; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + } + } + else + { + npc->count2 = 0; + } + + if (npc->act_no >= 10) + { + if (npc->flag & 1) + { + npc->count1 = 50; + npc->direct = 2; + } + + if (npc->flag & 4) + { + npc->count1 = 50; + npc->direct = 0; + } + + if (npc->count1 != 0) + { + --npc->count1; + + if (npc->direct == 0) + npc->xm -= 0x80; + else + npc->xm += 0x80; + } + else + { + npc->count1 = 50; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->ym += 0x10; + + if (npc->flag & 8) + npc->ym = -0x400; + } + + if (npc->xm > 0x100) + npc->xm = 0x100; + if (npc->xm < -0x100) + npc->xm = -0x100; + + if (npc->ym > 0x300) + npc->ym = 0x300; + if (npc->ym < -0x300) + npc->ym = -0x300; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} + +// Jelly +void ActNpc095(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {208, 64, 224, 80}, + {224, 64, 240, 80}, + {240, 64, 256, 80}, + {256, 64, 272, 80}, + }; + + RECT rcRight[4] = { + {208, 80, 224, 96}, + {224, 80, 240, 96}, + {240, 80, 256, 96}, + {256, 80, 272, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(0, 50); + npc->tgt_y = npc->y; + npc->tgt_x = npc->x; + + if (npc->direct == 0) + npc->xm = 0x200; + else + npc->xm = -0x200; + // Fallthrough + case 1: + if (--npc->act_wait > 0) + break; + + npc->act_no = 10; + // Fallthrough + case 10: + if (++npc->act_wait > 10) + { + npc->act_wait = 0; + npc->ani_wait = 0; + npc->act_no = 11; + } + + break; + + case 11: + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no == 2) + { + if (npc->direct == 0) + npc->xm -= 0x100; + else + npc->xm += 0x100; + + npc->ym -= 0x200; + } + + if (npc->ani_no > 2) + { + npc->act_no = 12; + npc->ani_no = 3; + } + + break; + + case 12: + ++npc->act_wait; + + if (npc->y > npc->tgt_y && npc->act_wait > 10) + { + npc->act_wait = 0; + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + } + + if (npc->x > npc->tgt_x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->flag & 1) + { + npc->count1 = 50; + npc->direct = 2; + } + + if (npc->flag & 4) + { + npc->count1 = 50; + npc->direct = 0; + } + + npc->ym += 0x20; + + if (npc->flag & 8) + npc->ym = -0x400; + + if (npc->xm > 0x100) + npc->xm = 0x100; + if (npc->xm < -0x100) + npc->xm = -0x100; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->shock) + { + npc->x += npc->xm / 2; + npc->y += npc->ym / 2; + } + else + { + npc->x += npc->xm; + npc->y += npc->ym; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Fan (left) +void ActNpc096(NPCHAR *npc) +{ + RECT rc[3] = { + {272, 120, 288, 136}, + {288, 120, 304, 136}, + {304, 120, 320, 136}, + }; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->act_no = 2; + else + npc->ani_no = 1; + + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 2: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (gMC.x > npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.x < npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.y > npc->y - (((WINDOW_HEIGHT / 2) + 120) * 0x200) && gMC.y < npc->y + (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + { + if (Random(0, 5) == 1) + SetNpChar(199, npc->x, npc->y + (Random(-8, 8) * 0x200), 0, 0, 0, NULL, 0x100); + } + + if (gMC.y < npc->y + (8 * 0x200) && gMC.y > npc->y - (8 * 0x200) && gMC.x < npc->x && gMC.x > npc->x - (96 * 0x200)) + { + gMC.xm -= 0x88; + gMC.cond |= 0x20; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Fan (up) +void ActNpc097(NPCHAR *npc) +{ + RECT rc[3] = { + {272, 136, 288, 152}, + {288, 136, 304, 152}, + {304, 136, 320, 152}, + }; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->act_no = 2; + else + npc->ani_no = 1; + + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 2: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (gMC.x > npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.x < npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.y > npc->y - (((WINDOW_HEIGHT / 2) + 120) * 0x200) && gMC.y < npc->y + (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + { + if (Random(0, 5) == 1) + SetNpChar(199, npc->x + (Random(-8, 8) * 0x200), npc->y, 0, 0, 1, NULL, 0x100); + } + + if (gMC.x < npc->x + (8 * 0x200) && gMC.x > npc->x - (8 * 0x200) && gMC.y < npc->y && gMC.y > npc->y - (96 * 0x200)) + gMC.ym -= 0x88; + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Fan (right) +void ActNpc098(NPCHAR *npc) +{ + RECT rc[3] = { + {272, 152, 288, 168}, + {288, 152, 304, 168}, + {304, 152, 320, 168}, + }; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->act_no = 2; + else + npc->ani_no = 1; + + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 2: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (gMC.x > npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.x < npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.y > npc->y - (((WINDOW_HEIGHT / 2) + 120) * 0x200) && gMC.y < npc->y + (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + { + if (Random(0, 5) == 1) + SetNpChar(199, npc->x, npc->y + (Random(-8, 8) * 0x200), 0, 0, 2, NULL, 0x100); + } + + if (gMC.y < npc->y + (8 * 0x200) && gMC.y > npc->y - (8 * 0x200) && gMC.x < npc->x + (96 * 0x200) && gMC.x > npc->x) + { + gMC.xm += 0x88; + gMC.cond |= 0x20; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Fan (down) +void ActNpc099(NPCHAR *npc) +{ + RECT rc[3] = { + {272, 168, 288, 184}, + {288, 168, 304, 184}, + {304, 168, 320, 184}, + }; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->act_no = 2; + else + npc->ani_no = 1; + + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 2: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (gMC.x > npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.x < npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.y > npc->y - (((WINDOW_HEIGHT / 2) + 120) * 0x200) && gMC.y < npc->y + (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + { + if (Random(0, 5) == 1) + SetNpChar(199, npc->x + (Random(-8, 8) * 0x200), npc->y, 0, 0, 3, NULL, 0x100); + } + + if (gMC.x < npc->x + (8 * 0x200) && gMC.x > npc->x - (8 * 0x200) && gMC.y < npc->y + (96 * 0x200) && gMC.y > npc->y) + gMC.ym += 0x88; + + break; + } + + npc->rect = rc[npc->ani_no]; +} diff --git a/src/NpcAct100.cpp b/src/NpcAct100.cpp new file mode 100644 index 0000000..0f3bd34 --- /dev/null +++ b/src/NpcAct100.cpp @@ -0,0 +1,1738 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" + +// Grate +void ActNpc100(NPCHAR *npc) +{ + RECT rc[2] = { + {272, 48, 288, 64}, + {272, 48, 288, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->y += 16 * 0x200; + npc->act_no = 1; + break; + } + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Malco computer screen +void ActNpc101(NPCHAR *npc) +{ + RECT rect[3] = { + {240, 136, 256, 152}, + {240, 136, 256, 152}, + {256, 136, 272, 152}, + }; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Malco computer wave +void ActNpc102(NPCHAR *npc) +{ + RECT rect[4] = { + {208, 120, 224, 136}, + {224, 120, 240, 136}, + {240, 120, 256, 136}, + {256, 120, 272, 136}, + }; + + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->y += 8 * 0x200; + } + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Mannan projectile +void ActNpc103(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {192, 96, 208, 120}, + {208, 96, 224, 120}, + {224, 96, 240, 120}, + }; + + RECT rcRight[3] = { + {192, 120, 208, 144}, + {208, 120, 224, 144}, + {224, 120, 240, 144}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->direct == 0) + npc->xm -= 0x20; + else + npc->xm += 0x20; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + break; + } + + npc->x += npc->xm; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (++npc->count1 > 100) + npc->cond = 0; + + if (npc->count1 % 4 == 1) + PlaySoundObject(46, SOUND_MODE_PLAY); +} + +// Frog +void ActNpc104(NPCHAR *npc) +{ + BOOL bJump; + + RECT rcLeft[3] = { + {0, 112, 32, 144}, + {32, 112, 64, 144}, + {64, 112, 96, 144}, + }; + + RECT rcRight[3] = { + {0, 144, 32, 176}, + {32, 144, 64, 176}, + {64, 144, 96, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + + if (npc->direct == 4) + { + if (Random(0, 1)) + npc->direct = 0; + else + npc->direct = 2; + + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->ani_no = 2; + npc->act_no = 3; + break; + } + + npc->bits &= ~NPC_IGNORE_SOLIDITY; + // Fallthrough + case 1: + ++npc->act_wait; + + if (Random(0, 50) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ani_wait = 0; + break; + } + + break; + + case 2: + ++npc->act_wait; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->act_wait > 18) + { + npc->act_no = 1; + npc->act_no = 1; // Duplicate line + } + + break; + + case 3: + if (++npc->act_wait > 40) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->flag & 8) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 10: + npc->act_no = 11; + // Fallthrough + case 11: + if (npc->flag & 1 && npc->xm < 0) + { + npc->xm *= -1; + npc->direct = 2; + } + + if (npc->flag & 4 && npc->xm > 0) + { + npc->xm *= -1; + npc->direct = 0; + } + + if (npc->flag & 8) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + } + + bJump = FALSE; + + if (npc->act_no < 10 && npc->act_no != 3 && npc->act_wait > 10) + { + if (npc->shock) + bJump = TRUE; + + if (npc->x < gMC.x - (160 * 0x200) || npc->x > gMC.x + (160 * 0x200) || npc->y < gMC.y - (64 * 0x200) || npc->y > gMC.y + (64 * 0x200)) + { + // This blank space is needed for the function to produce the same assembly. + // Chances are there used to be some commented-out code here. + } + else + { + if (Random(0, 50) == 2) + bJump = TRUE; + } + } + + if (bJump) + { + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + npc->act_no = 10; + npc->ani_no = 2; + npc->ym = -0x5FF; + + if (!(gMC.cond & 2)) + PlaySoundObject(30, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + } + + npc->ym += 0x80; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// "HEY!" speech bubble (low) +void ActNpc105(NPCHAR *npc) +{ + RECT rect[2] = { + {128, 32, 144, 48}, + {128, 32, 128, 32}, + }; + + if (++npc->act_wait > 30) + npc->cond = 0; + + if (npc->act_wait < 5) + npc->y -= 1 * 0x200; + + npc->rect = rect[npc->ani_no]; +} + +// "HEY!" speech bubble (high) +void ActNpc106(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + SetNpChar(105, npc->x, npc->y - (8 * 0x200), 0, 0, 0, NULL, 0x180); + npc->act_no = 1; + break; + } +} + +// Malco +void ActNpc107(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 2) + npc->ani_no = 5; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_wait = 0; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + // Fallthrough + case 11: + if (++npc->ani_wait > 1) + { + PlaySoundObject(43, SOUND_MODE_PLAY); + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 100) + npc->act_no = 12; + + break; + + case 12: + npc->act_no = 13; + npc->act_wait = 0; + npc->ani_no = 1; + // Fallthrough + case 13: + if (++npc->act_wait > 50) + npc->act_no = 14; + + break; + + case 14: + npc->act_no = 15; + npc->act_wait = 0; + // Fallthrough + case 15: + if (npc->act_wait / 2 % 2) + { + npc->x += 1 * 0x200; + PlaySoundObject(11, SOUND_MODE_PLAY); + } + else + { + npc->x -= 1 * 0x200; + } + + if (++npc->act_wait > 50) + npc->act_no = 16; + + break; + + case 16: + npc->act_no = 17; + npc->act_wait = 0; + npc->ani_no = 2; + PlaySoundObject(12, SOUND_MODE_PLAY); + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + // Fallthrough + case 17: + if (++npc->act_wait > 150) + npc->act_no = 18; + + break; + + case 18: + npc->act_no = 19; + npc->act_wait = 0; + npc->ani_no = 3; + npc->ani_wait = 0; + // Fallthrough + case 19: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + { + PlaySoundObject(11, SOUND_MODE_PLAY); + npc->ani_no = 3; + } + + if (++npc->act_wait > 100) + { + npc->act_no = 20; + PlaySoundObject(12, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + break; + + case 20: + npc->ani_no = 4; + break; + + case 21: + npc->act_no = 22; + npc->ani_no = 5; + PlaySoundObject(51, SOUND_MODE_PLAY); + break; + + case 100: + npc->act_no = 101; + npc->ani_no = 6; + npc->ani_wait = 0; + // Fallthrough + case 101: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 9) + npc->ani_no = 6; + + break; + + case 110: + SetDestroyNpChar(npc->x, npc->y, 0x2000, 16); + npc->cond = 0; + break; + } + + RECT rcPoweron[10] = { + {144, 0, 160, 24}, + {160, 0, 176, 24}, + {176, 0, 192, 24}, + {192, 0, 208, 24}, + {208, 0, 224, 24}, + {224, 0, 240, 24}, + {176, 0, 192, 24}, + {192, 0, 208, 24}, + {208, 0, 224, 24}, + {192, 0, 208, 24}, + }; + + npc->rect = rcPoweron[npc->ani_no]; +} + +// Balfrog projectile +void ActNpc108(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[3] = { + {96, 48, 112, 64}, + {112, 48, 128, 64}, + {128, 48, 144, 64}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } +} + +// Malco (broken) +void ActNpc109(NPCHAR *npc) +{ + int i; + + RECT rcLeft[2] = { + {240, 0, 256, 24}, + {256, 0, 272, 24}, + }; + + RECT rcRight[2] = { + {240, 24, 256, 48}, + {256, 24, 272, 48}, + }; + + switch (npc->act_no) + { + case 0: + if (--npc->act_wait != 0) + npc->act_no = 1; + + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 0; + PlaySoundObject(12, SOUND_MODE_PLAY); + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Puchi +void ActNpc110(NPCHAR *npc) +{ + BOOL bJump; + + RECT rcLeft[3] = { + {96, 128, 112, 144}, + {112, 128, 128, 144}, + {128, 128, 144, 144}, + }; + + RECT rcRight[3] = { + {96, 144, 112, 160}, + {112, 144, 128, 160}, + {128, 144, 144, 160}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + + if (npc->direct == 4) + { + if (Random(0, 1)) + npc->direct = 0; + else + npc->direct = 2; + + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->ani_no = 2; + npc->act_no = 3; + + break; + } + + npc->bits &= ~NPC_IGNORE_SOLIDITY; + // Fallthrough + case 1: + ++npc->act_wait; + + if (Random(0, 50) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ani_wait = 0; + break; + } + + break; + + case 2: + ++npc->act_wait; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->act_wait > 18) + { + npc->act_no = 1; + npc->act_no = 1; // Duplicate line + } + + break; + + case 3: + if (++npc->act_wait > 40) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->flag & 8) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 10: + npc->act_no = 11; + // Fallthrough + case 11: + if (npc->flag & 1 && npc->xm < 0) + { + npc->xm *= -1; + npc->direct = 2; + } + + if (npc->flag & 4 && npc->xm > 0) + { + npc->xm *= -1; + npc->direct = 0; + } + + if (npc->flag & 8) + { + npc->act_no = 0; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + } + + bJump = FALSE; + + if (npc->act_no < 10 && npc->act_no != 3 && npc->act_wait > 10) + { + if (npc->shock) + bJump = TRUE; + + if (npc->x < gMC.x - (160 * 0x200) || npc->x > gMC.x + (160 * 0x200) || npc->y < gMC.y - (64 * 0x200) || npc->y > gMC.y + (64 * 0x200)) + { + // This blank space is needed for the function to produce the same assembly. + // Chances are there used to be some commented-out code here. + } + else + { + if (Random(0, 50) == 2) + bJump = TRUE; + } + } + + if (bJump) + { + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + npc->act_no = 10; + npc->ani_no = 2; + npc->ym = -0x2FF; + PlaySoundObject(6, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + + npc->ym += 0x80; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Quote (teleport out) +void ActNpc111(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + }; + + RECT rcRight[2] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->y -= 16 * 0x200; + break; + + case 1: + if (++npc->act_wait > 20) + { + npc->act_wait = 0; + npc->act_no = 2; + npc->ani_no = 1; + npc->ym = -0x2FF; + } + + break; + + case 2: + if (npc->ym > 0) + npc->hit.bottom = 16 * 0x200; + + if (npc->flag & 8) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 0; + } + + break; + + case 3: + if (++npc->act_wait > 40) + { + npc->act_no = 4; + npc->act_wait = 64; + PlaySoundObject(29, SOUND_MODE_PLAY); + } + + break; + + case 4: + --npc->act_wait; + npc->ani_no = 0; + + if (npc->act_wait == 0) + npc->cond = 0; + + break; + } + + npc->ym += 0x40; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + // Use a different sprite if the player is wearing the Mimiga Mask + if (gMC.equip & EQUIP_MIMIGA_MASK) + { + npc->rect.top += 32; + npc->rect.bottom += 32; + } + + if (npc->act_no == 4) + { + npc->rect.bottom = npc->rect.top + (npc->act_wait / 4); + + if (npc->act_wait / 2 % 2) + ++npc->rect.left; + } +} + +// Quote (teleport in) +void ActNpc112(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + }; + + RECT rcRight[2] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->x += 16 * 0x200; + npc->y += 8 * 0x200; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 1: + if (++npc->act_wait == 64) + { + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 20) + { + npc->act_no = 3; + npc->ani_no = 1; + npc->hit.bottom = 8 * 0x200; + } + + break; + + case 3: + if (npc->flag & 8) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + // Use a different sprite if the player is wearing the Mimiga Mask + if (gMC.equip & EQUIP_MIMIGA_MASK) + { + npc->rect.top += 32; + npc->rect.bottom += 32; + } + + if (npc->act_no == 1) + { + npc->rect.bottom = npc->rect.top + (npc->act_wait / 4); + + if (npc->act_wait / 2 % 2) + ++npc->rect.left; + } +} + +// Professor Booster +void ActNpc113(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {224, 0, 240, 16}, + {240, 0, 256, 16}, + {256, 0, 272, 16}, + {224, 0, 240, 16}, + {272, 0, 288, 16}, + {224, 0, 240, 16}, + {288, 0, 304, 16}, + }; + + RECT rcRight[7] = { + {224, 16, 240, 32}, + {240, 16, 256, 32}, + {256, 16, 272, 32}, + {224, 16, 240, 32}, + {272, 16, 288, 32}, + {224, 16, 240, 32}, + {288, 16, 304, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->act_no = 4; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + break; + + case 5: + npc->ani_no = 6; + break; + + case 30: + npc->act_no = 31; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->hit.bottom = 16 * 0x200; + npc->x -= 16 * 0x200; + npc->y += 8 * 0x200; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 31: + if (++npc->act_wait == 64) + { + npc->act_no = 32; + npc->act_wait = 0; + } + + break; + + case 32: + if (++npc->act_wait > 20) + { + npc->act_no = 33; + npc->ani_no = 1; + npc->hit.bottom = 8 * 0x200; + } + + break; + + case 33: + if (npc->flag & 8) + { + npc->act_no = 34; + npc->act_wait = 0; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 31) + { + npc->rect.bottom = npc->rect.top + (npc->act_wait / 4); + + if (npc->act_wait / 2 % 2) + ++npc->rect.left; + } +} + +// Press +void ActNpc114(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {144, 112, 160, 136}, + {160, 112, 176, 136}, + {176, 112, 192, 136}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 4 * 0x200; + // Fallthrough + case 1: + if (npc->flag & 8) + { + // Chances are there used to be commented-out code here + } + else + { + npc->act_no = 10; + npc->ani_wait = 0; + npc->ani_no = 1; + } + + break; + + case 10: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 2; + + if (gMC.y > npc->y) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->damage = 0x7F; + } + else + { + npc->bits |= NPC_SOLID_HARD; + npc->damage = 0; + } + + if (npc->flag & 8) + { + if (npc->ani_no > 1) + { + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(10); + } + + npc->act_no = 1; + npc->ani_no = 0; + npc->damage = 0; + npc->bits |= NPC_SOLID_HARD; + } + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + npc->rect = rcLeft[npc->ani_no]; +} + +// Ravil +void ActNpc115(NPCHAR *npc) +{ + int i; + + RECT rcLeft[6] = { + {0, 120, 24, 144}, + {24, 120, 48, 144}, + {48, 120, 72, 144}, + {72, 120, 96, 144}, + {96, 120, 120, 144}, + {120, 120, 144, 144}, + }; + + RECT rcRight[6] = { + {0, 144, 24, 168}, + {24, 144, 48, 168}, + {48, 144, 72, 168}, + {72, 144, 96, 168}, + {96, 144, 120, 168}, + {120, 144, 144, 168}, + }; + + switch (npc->act_no) + { + case 0: + npc->xm = 0; + npc->act_no = 1; + npc->act_wait = 0; + npc->count1 = 0; + // Fallthrough + case 1: + if (gMC.x < npc->x + (96 * 0x200) && gMC.x > npc->x - (96 * 0x200) && gMC.y < npc->y + (32 * 0x200) && gMC.y > npc->y - (96 * 0x200)) + npc->act_no = 10; + + if (npc->shock) + npc->act_no = 10; + + break; + + case 10: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 1; + + if (++npc->act_wait > 20) + { + npc->act_wait = 0; + npc->act_no = 20; + } + + break; + + case 20: + npc->damage = 0; + npc->xm = 0; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + if (++npc->count1 > 2) + { + npc->count1 = 0; + npc->ani_no = 4; + npc->act_no = 21; + npc->ym = -0x400; + npc->xm *= 2; + npc->damage = 5; + PlaySoundObject(102, SOUND_MODE_PLAY); + } + else + { + npc->act_no = 21; + npc->ym = -0x400; + PlaySoundObject(30, SOUND_MODE_PLAY); + } + } + + break; + + case 21: + if (npc->flag & 8) + { + PlaySoundObject(23, SOUND_MODE_PLAY); + npc->act_no = 20; + npc->ani_no = 1; + npc->ani_wait = 0; + npc->damage = 0; + + if (gMC.x > npc->x + (144 * 0x200) || gMC.x < npc->x - (144 * 0x200) || gMC.y > npc->y + (48 * 0x200) || gMC.y < npc->y - (144 * 0x200)) + npc->act_no = 0; + } + + break; + + case 30: + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->ani_no = 0; + npc->act_no = 0; + + break; + + case 50: + npc->act_no = 51; + npc->ani_no = 4; + npc->damage = 0; + npc->ym = -0x200; + npc->bits &= ~(NPC_SOLID_SOFT | NPC_SHOOTABLE); + PlaySoundObject(51, SOUND_MODE_PLAY); + // Fallthrough + case 51: + if (npc->flag & 8) + { + PlaySoundObject(23, SOUND_MODE_PLAY); + npc->act_no = 52; + npc->ani_no = 5; + npc->xm = 0; + } + + break; + } + + if (npc->act_no > 50) + npc->ym += 0x20; + else + npc->ym += 0x40; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Red petals +void ActNpc116(NPCHAR *npc) +{ + RECT rc = {272, 184, 320, 200}; + + npc->rect = rc; +} + +// Curly +void ActNpc117(NPCHAR *npc) +{ + RECT rcLeft[10] = { + {0, 96, 16, 112}, + {16, 96, 32, 112}, + {0, 96, 16, 112}, + {32, 96, 48, 112}, + {0, 96, 16, 112}, + {176, 96, 192, 112}, + {112, 96, 128, 112}, + {160, 96, 176, 112}, + {144, 96, 160, 112}, + {48, 96, 64, 112}, + }; + + RECT rcRight[10] = { + {0, 112, 16, 128}, + {16, 112, 32, 128}, + {0, 112, 16, 128}, + {32, 112, 48, 128}, + {0, 112, 16, 128}, + {176, 112, 192, 128}, + {112, 112, 128, 128}, + {160, 112, 176, 128}, + {144, 112, 160, 128}, + {48, 112, 64, 128}, + }; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 4) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + npc->xm = 0; + npc->ym += 0x40; + break; + + case 3: + if (0) + { + // There used to be an if-statement here that didn't do anything, but the compiler optimised it out. + // We only know this was here because empty if-statements affect the assembly's register usage. + // Since there's no code, we have no idea what the original condition actually was. + } + + if (0) + { + // Another empty if-statement + } + + npc->act_no = 4; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 4: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + npc->ym += 0x40; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + break; + + case 5: + npc->act_no = 6; + npc->ani_no = 5; + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + break; + + case 6: + if (0) + { + // There used to be an if-statement here that didn't do anything, but the compiler optimised it out. + // We only know this was here because empty if-statements affect the assembly's register usage. + // Since there's no code, we have no idea what the original condition actually was. + } + + npc->ani_no = 5; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->ani_wait = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + // Fallthrough + case 11: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + if (gMC.x < npc->x + (20 * 0x200) && gMC.x > npc->x - (20 * 0x200)) + npc->act_no = 0; + + break; + + case 20: + npc->xm = 0; + npc->ani_no = 6; + break; + + case 21: + npc->xm = 0; + npc->ani_no = 9; + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->ym = -0x400; + // Fallthrough + case 31: + npc->ani_no = 7; + + if (npc->direct == 0) + npc->xm = 0x200; + else + npc->xm = -0x200; + + npc->ym += 0x40; + + if (npc->act_wait++ != 0 && npc->flag & 8) + npc->act_no = 32; + + break; + + case 32: + npc->ym += 0x40; + npc->ani_no = 8; + npc->xm = 0; + break; + + case 70: + npc->act_no = 71; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 71: + if (npc->direct == 0) + npc->x += 0x100; + else + npc->x -= 0x100; + + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + break; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Curly (boss) +void ActNpc118(NPCHAR *npc) +{ + BOOL bUpper; + + RECT rcLeft[9] = { + {0, 32, 32, 56}, + {32, 32, 64, 56}, + {64, 32, 96, 56}, + {96, 32, 128, 56}, + {0, 32, 32, 56}, + {128, 32, 160, 56}, + {0, 32, 32, 56}, + {0, 32, 32, 56}, + {160, 32, 192, 56}, + }; + + RECT rcRight[9] = { + {0, 56, 32, 80}, + {32, 56, 64, 80}, + {64, 56, 96, 80}, + {96, 56, 128, 80}, + {0, 56, 32, 80}, + {128, 56, 160, 80}, + {0, 56, 32, 80}, + {0, 56, 32, 80}, + {160, 56, 192, 80}, + }; + + bUpper = FALSE; + + if (npc->direct == 0 && npc->x < gMC.x) + bUpper = TRUE; + if (npc->direct == 2 && npc->x > gMC.x) + bUpper = TRUE; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = Random(50, 100); + npc->ani_no = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + // Fallthrough + case 11: + if (npc->act_wait != 0) + --npc->act_wait; + else + npc->act_no = 13; + + break; + + case 13: + npc->act_no = 14; + npc->ani_no = 3; + npc->act_wait = Random(50, 100); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 14: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 3; + + if (npc->direct == 0) + npc->xm -= 0x40; + else + npc->xm += 0x40; + + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->bits |= NPC_SHOOTABLE; + npc->act_no = 20; + npc->act_wait = 0; + PlaySoundObject(103, SOUND_MODE_PLAY); + } + + break; + + case 20: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->xm = (npc->xm * 8) / 9; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 50) + { + npc->act_no = 21; + npc->act_wait = 0; + } + + break; + + case 21: + if (++npc->act_wait % 4 == 1) + { + if (npc->direct == 0) + { + if (bUpper) + { + npc->ani_no = 2; + SetNpChar(123, npc->x, npc->y - (8 * 0x200), 0, 0, 1, NULL, 0x100); + } + else + { + npc->ani_no = 0; + SetNpChar(123, npc->x - (8 * 0x200), npc->y + (4 * 0x200), 0, 0, 0, NULL, 0x100); + npc->x += 1 * 0x200; + } + } + else + { + if (bUpper) + { + npc->ani_no = 2; + SetNpChar(123, npc->x, npc->y - (8 * 0x200), 0, 0, 1, NULL, 0x100); + } + else + { + npc->ani_no = 0; + SetNpChar(123, npc->x + (8 * 0x200), npc->y + (4 * 0x200), 0, 0, 2, NULL, 0x100); + npc->x -= 1 * 0x200; + } + } + } + + if (npc->act_wait > 30) + npc->act_no = 10; + + break; + + case 30: + if (++npc->ani_no > 8) + npc->ani_no = 7; + + if (++npc->act_wait > 30) + { + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + } + + if (npc->act_no > 10 && npc->act_no < 30 && CountArmsBullet(6)) + { + npc->act_wait = 0; + npc->act_no = 30; + npc->ani_no = 7; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + npc->xm = 0; + } + + npc->ym += 0x20; + + if (npc->xm > 0x1FF) + npc->xm = 0x1FF; + if (npc->xm < -0x1FF) + npc->xm = -0x1FF; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + npc->x += npc->xm; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Table and chair +void ActNpc119(NPCHAR *npc) +{ + RECT rc = {248, 184, 272, 200}; + + npc->rect = rc; +} diff --git a/src/NpcAct120.cpp b/src/NpcAct120.cpp new file mode 100644 index 0000000..c35e25a --- /dev/null +++ b/src/NpcAct120.cpp @@ -0,0 +1,1482 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "KeyControl.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Colon (1) +void ActNpc120(NPCHAR *npc) +{ + RECT rect[2] = { + {64, 0, 80, 16}, + {64, 16, 80, 32}, + }; + + if (npc->direct == 0) + npc->rect = rect[0]; + else + npc->rect = rect[1]; +} + +// Colon (2) +void ActNpc121(NPCHAR *npc) +{ + RECT rect[3] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {112, 0, 128, 16}, + }; + + if (npc->direct == 0) + { + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->rect = rect[npc->ani_no]; + } + else + { + npc->rect = rect[2]; + + if (++npc->act_wait > 100) + { + npc->act_wait = 0; + SetCaret(npc->x, npc->y, CARET_ZZZ, DIR_LEFT); + } + } +} + +// Colon (attacking) +void ActNpc122(NPCHAR *npc) +{ + RECT rcLeft[10] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + {0, 0, 16, 16}, + {48, 0, 64, 16}, + {0, 0, 16, 16}, + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {112, 0, 128, 16}, + {128, 0, 144, 16}, + }; + + RECT rcRight[10] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + {0, 16, 16, 32}, + {48, 16, 64, 32}, + {0, 16, 16, 32}, + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {112, 16, 128, 32}, + {128, 16, 144, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->life = 1000; + npc->act_no = 11; + npc->act_wait = Random(0, 50); + npc->ani_no = 0; + npc->damage = 0; + // Fallthrough + case 11: + if (npc->act_wait != 0) + --npc->act_wait; + else + npc->act_no = 13; + + break; + + case 13: + npc->act_no = 14; + npc->act_wait = Random(0, 50); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 14: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm -= 0x40; + else + npc->xm += 0x40; + + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->bits |= NPC_SHOOTABLE; + npc->act_no = 15; + npc->ani_no = 2; + npc->ym = -0x200; + npc->damage = 2; + } + + break; + + case 15: + if (npc->flag & 8) + { + npc->bits |= NPC_SHOOTABLE; + npc->xm = 0; + npc->act_no = 10; + npc->damage = 0; + } + + break; + + case 20: + if (npc->flag & 8) + { + npc->xm = 0; + npc->act_no = 21; + npc->damage = 0; + + if (npc->ani_no == 6) + npc->ani_no = 8; + else + npc->ani_no = 9; + + npc->act_wait = Random(300, 400); + } + + break; + + case 21: + if (npc->act_wait) + { + --npc->act_wait; + } + else + { + npc->bits |= NPC_SHOOTABLE; + npc->life = 1000; + npc->act_no = 11; + npc->act_wait = Random(0, 50); + npc->ani_no = 0; + } + + break; + } + + if (npc->act_no > 10 && npc->act_no < 20 && npc->life != 1000) + { + npc->act_no = 20; + npc->ym = -0x200; + npc->ani_no = Random(6, 7); + npc->bits &= ~NPC_SHOOTABLE; + } + + npc->ym += 0x20; + + if (npc->xm > 0x1FF) + npc->xm = 0x1FF; + if (npc->xm < -0x1FF) + npc->xm = -0x1FF; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + npc->x += npc->xm; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Curly boss projectile +void ActNpc123(NPCHAR *npc) +{ + RECT rect[4] = { + {192, 0, 208, 16}, + {208, 0, 224, 16}, + {224, 0, 240, 16}, + {240, 0, 256, 16}, + }; + + BOOL bBreak = FALSE; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + SetCaret(npc->x, npc->y, CARET_SHOOT, DIR_LEFT); + PlaySoundObject(32, SOUND_MODE_PLAY); + + switch (npc->direct) + { + case 0: + npc->xm = -0x1000; + npc->ym = Random(-0x80, 0x80); + break; + + case 1: + npc->ym = -0x1000; + npc->xm = Random(-0x80, 0x80); + break; + + case 2: + npc->xm = 0x1000; + npc->ym = Random(-0x80, 0x80); + break; + + case 3: + npc->ym = 0x1000; + npc->xm = Random(-0x80, 0x80); + break; + } + + break; + + case 1: + switch (npc->direct) + { + case 0: + if (npc->flag & 1) + bBreak = TRUE; + break; + + case 1: + if (npc->flag & 2) + bBreak = TRUE; + break; + + case 2: + if (npc->flag & 4) + bBreak = TRUE; + break; + + case 3: + if (npc->flag & 8) + bBreak = TRUE; + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + break; + } + + if (bBreak) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_RIGHT); + PlaySoundObject(28, SOUND_MODE_PLAY); + npc->cond = 0; + } + + npc->rect = rect[npc->direct]; +} + +// Sunstone +void ActNpc124(NPCHAR *npc) +{ + RECT rect[2] = { + {160, 0, 192, 32}, + {192, 0, 224, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->x += 8 * 0x200; + npc->y += 8 * 0x200; + // Fallthrough + case 1: + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->ani_no = 0; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->act_wait = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 11: + switch (npc->direct) + { + case 0: + npc->x -= 0x80; + break; + + case 1: + npc->y -= 0x80; + break; + + case 2: + npc->x += 0x80; + break; + + case 3: + npc->y += 0x80; + break; + } + if (++npc->act_wait % 8 == 0) + PlaySoundObject(26, SOUND_MODE_PLAY); + + SetQuake(20); + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Hidden item +void ActNpc125(NPCHAR *npc) +{ + if (npc->life < 990) + { + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + PlaySoundObject(70, SOUND_MODE_PLAY); + + if (npc->direct == 0) + SetNpChar(87, npc->x, npc->y, 0, 0, 2, NULL, 0); + else + SetNpChar(86, npc->x, npc->y, 0, 0, 2, NULL, 0); + + npc->cond = 0; + } + + RECT rc[2] = { + {0, 96, 16, 112}, + {16, 96, 32, 112}, + }; + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Puppy (running) +void ActNpc126(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {48, 144, 64, 160}, + {64, 144, 80, 160}, + {48, 144, 64, 160}, + {80, 144, 96, 160}, + {96, 144, 112, 160}, + {112, 144, 128, 160}, + }; + + RECT rcRight[6] = { + {48, 160, 64, 176}, + {64, 160, 80, 176}, + {48, 160, 64, 176}, + {80, 160, 96, 176}, + {96, 160, 112, 176}, + {112, 160, 128, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (96 * 0x200) < gMC.x && npc->x + (96 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + npc->act_no = 10; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 4; + npc->ani_wait = 0; + // Fallthrough + case 11: + if (npc->flag & 8) + { + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 4; + } + else + { + npc->ani_no = 5; + npc->ani_wait = 0; + } + + if (npc->xm < 0 && npc->flag & 1) + { + npc->xm /= -2; + npc->direct = 2; + } + + if (npc->xm > 0 && npc->flag & 4) + { + npc->xm /= -2; + npc->direct = 0; + } + + if (npc->direct == 0) + npc->xm -= 0x40; + else + npc->xm += 0x40; + + if (npc->xm > 0x5FF) + npc->xm = 0x400; + + if (npc->xm < -0x5FF) + npc->xm = -0x400; + + break; + } + + if (gKeyTrg & gKeyDown) + npc->bits |= NPC_INTERACTABLE; + else + npc->bits &= ~NPC_INTERACTABLE; + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Machine gun trail (Level 2) +void ActNpc127(NPCHAR *npc) +{ + RECT rcV[3] = { + {112, 48, 128, 64}, + {112, 64, 128, 80}, + {112, 80, 128, 96}, + }; + + RECT rcH[3] = { + {64, 80, 80, 96}, + {80, 80, 96, 96}, + {96, 80, 112, 96}, + }; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 2) + { + npc->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcH' and 'rcV', even though it's now too high + #endif + } + } + + if (npc->direct == 0) + npc->rect = rcH[npc->ani_no]; + else + npc->rect = rcV[npc->ani_no]; +} + +// Machine gun trail (Level 3) +void ActNpc128(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {0, 0, 0, 0}, + {176, 16, 184, 32}, + {184, 16, 192, 32}, + {192, 16, 200, 32}, + {200, 16, 208, 32}, + }; + + RECT rcRight[5] = { + {0, 0, 0, 0}, + {232, 16, 240, 32}, + {224, 16, 232, 32}, + {216, 16, 224, 32}, + {208, 16, 216, 32}, + }; + + RECT rcUp[5] = { + {0, 0, 0, 0}, + {176, 32, 192, 40}, + {176, 40, 192, 48}, + {192, 32, 208, 40}, + {192, 40, 208, 48}, + }; + + RECT rcDown[5] = { + {0, 0, 0, 0}, + {208, 32, 224, 40}, + {208, 40, 224, 48}, + {224, 32, 232, 40}, + {224, 40, 232, 48}, + }; + + if (npc->act_no == 0) + { + npc->act_no = 1; + + if (npc->direct == 0 || npc->direct == 2) + { + npc->view.front = 4 * 0x200; + npc->view.top = 8 * 0x200; + } + else + { + npc->view.front = 8 * 0x200; + npc->view.top = 4 * 0x200; + } + } + + if (++npc->ani_no > 4) + { + npc->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rcLeft' and co., even though it's now too high + #endif + } + + switch (npc->direct) + { + case 0: + npc->rect = rcLeft[npc->ani_no]; + break; + + case 1: + npc->rect = rcUp[npc->ani_no]; + break; + + case 2: + npc->rect = rcRight[npc->ani_no]; + break; + + case 3: + npc->rect = rcDown[npc->ani_no]; + break; + } +} + +// Fireball trail (Level 2 & 3) +void ActNpc129(NPCHAR *npc) +{ + RECT rect[18] = { + {128, 48, 144, 64}, + {144, 48, 160, 64}, + {160, 48, 176, 64}, + + {128, 64, 144, 80}, + {144, 64, 160, 80}, + {160, 64, 176, 80}, + + {128, 80, 144, 96}, + {144, 80, 160, 96}, + {160, 80, 176, 96}, + + {176, 48, 192, 64}, + {192, 48, 208, 64}, + {208, 48, 224, 64}, + + {176, 64, 192, 80}, + {192, 64, 208, 80}, + {208, 64, 224, 80}, + + {176, 80, 192, 96}, + {192, 80, 208, 96}, + {208, 80, 224, 96}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 2) + { + npc->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + } + + npc->y += npc->ym; + + npc->rect = rect[(npc->direct * 3) + npc->ani_no]; +} + +// Puppy (sitting, wagging tail) +void ActNpc130(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {48, 144, 64, 160}, + {64, 144, 80, 160}, + {48, 144, 64, 160}, + {80, 144, 96, 160}, + }; + + RECT rcRight[4] = { + {48, 160, 64, 176}, + {64, 160, 80, 176}, + {48, 160, 64, 176}, + {80, 160, 96, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->bits |= NPC_INTERACTABLE; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (64 * 0x200) < gMC.x && npc->x + (64 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + } + + if (npc->x - (96 * 0x200) < gMC.x && npc->x + (96 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Puppy (sleeping) +void ActNpc131(NPCHAR *npc) +{ + RECT rcLeft[1] = { + {144, 144, 160, 160} + }; + + RECT rcRight[1] = { + {144, 160, 160, 176} + }; + + if (++npc->act_wait > 100) + { + npc->act_wait = 0; + SetCaret(npc->x, npc->y, CARET_ZZZ, DIR_LEFT); + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Puppy (barking) +void ActNpc132(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {48, 144, 64, 160}, + {64, 144, 80, 160}, + {96, 144, 112, 160}, + {96, 144, 112, 160}, + {128, 144, 144, 160}, + }; + + RECT rcRight[5] = { + {48, 160, 64, 176}, + {64, 160, 80, 176}, + {96, 160, 112, 176}, + {96, 160, 112, 176}, + {128, 160, 144, 176}, + }; + + if (npc->act_no < 100) + { + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (64 * 0x200) < gMC.x && npc->x + (64 * 0x200) > gMC.x && npc->y - (16 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 2; + + if (npc->ani_no == 4 && npc->ani_wait == 0) + PlaySoundObject(105, SOUND_MODE_PLAY); + } + else + { + if (npc->ani_no == 4) + npc->ani_no = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 11: + if (Random(0, 120) == 10) + { + npc->act_no = 12; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 12: + if (++npc->act_wait > 8) + { + npc->act_no = 11; + npc->ani_no = 0; + } + + break; + + case 100: + npc->act_no = 101; + npc->count1 = 0; + // Fallthrough + case 101: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + { + if (npc->count1 < 3) + { + npc->ani_no = 2; + ++npc->count1; + } + else + { + npc->ani_no = 0; + npc->count1 = 0; + } + } + + if (npc->ani_no == 4 && npc->ani_wait == 0) + PlaySoundObject(105, SOUND_MODE_PLAY); + + break; + + case 120: + npc->ani_no = 0; + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Jenka +void ActNpc133(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {176, 32, 192, 48}, + {192, 32, 208, 48}, + }; + + RECT rcRight[2] = { + {176, 48, 192, 64}, + {192, 48, 208, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Armadillo +void ActNpc134(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {224, 0, 256, 16}, + {256, 0, 288, 16}, + {288, 0, 320, 16}, + }; + + RECT rcRight[3] = { + {224, 16, 256, 32}, + {256, 16, 288, 32}, + {288, 16, 320, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 2; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + // Fallthrough + case 1: + if (gMC.x > npc->x - (320 * 0x200) && gMC.x < npc->x + (320 * 0x200) && gMC.y > npc->y - (160 * 0x200) && gMC.y < npc->y + (64 * 0x200)) // TODO: Maybe do something about this for widescreen/tallscreen? + { + npc->act_no = 10; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + } + + break; + + case 10: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->direct == 0 && npc->flag & 1) + npc->direct = 2; + if (npc->direct == 2 && npc->flag & 4) + npc->direct = 0; + + if (npc->direct == 0) + npc->x -= 0x100; + else + npc->x += 0x100; + + if (CountArmsBullet(6)) + { + npc->act_no = 20; + npc->act_wait = 0; + npc->ani_no = 2; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + } + + break; + + case 20: + if (++npc->act_wait > 100) + { + npc->act_no = 10; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Skeleton +void ActNpc135(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + RECT rcLeft[2] = { + {256, 32, 288, 64}, + {288, 32, 320, 64}, + }; + + RECT rcRight[2] = { + {256, 64, 288, 96}, + {288, 64, 320, 96}, + }; + + if (gMC.x < npc->x - (352 * 0x200) || gMC.x > npc->x + (352 * 0x200) || gMC.y < npc->y - (160 * 0x200) || gMC.y > npc->y + (64 * 0x200)) + npc->act_no = 0; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->xm = 0; + // Fallthrough + case 1: + if (gMC.x > npc->x - (320 * 0x200) && gMC.x < npc->x + (320 * 0x200) && gMC.y > npc->y - (160 * 0x200) && gMC.y < npc->y + (64 * 0x200)) + npc->act_no = 10; + + if (npc->flag & 8) + npc->ani_no = 0; + + break; + + case 10: + npc->xm = 0; + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 0; + // Fallthrough + case 11: + if (++npc->act_wait >= 5 && npc->flag & 8) + { + npc->act_no = 20; + npc->ani_no = 1; + npc->count1 = 0; + npc->ym = -0x200 * Random(1, 3); + + if (npc->shock) + { + if (npc->x < gMC.x) + npc->xm -= 0x100; + else + npc->xm += 0x100; + } + else + { + if (npc->x < gMC.x) + npc->xm += 0x100; + else + npc->xm -= 0x100; + } + } + + break; + + case 20: + if (npc->ym > 0 && npc->count1 == 0) + { + ++npc->count1; + deg = GetArktan(npc->x - gMC.x, npc->y + (4 * 0x200) - gMC.y); + ym = GetSin(deg) * 2; + xm = GetCos(deg) * 2; + SetNpChar(50, npc->x, npc->y, xm, ym, 0, NULL, 0x180); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (npc->flag & 8) + { + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + } + + if (npc->act_no >= 10) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + npc->ym += 0x200 / 10; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->xm > 0x5FF) + npc->xm = 0x5FF; + if (npc->xm < -0x5FF) + npc->xm = -0x5FF; + + npc->y += npc->ym; + npc->x += npc->xm; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Puppy (carried) +void ActNpc136(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {48, 144, 64, 160}, + {64, 144, 80, 160}, + }; + + RECT rcRight[2] = { + {48, 160, 64, 176}, + {64, 160, 80, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_INTERACTABLE; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (gMC.direct == 0) + npc->direct = 0; + else + npc->direct = 2; + + npc->y = gMC.y - (10 * 0x200); + + if (npc->direct == 0) + { + npc->x = gMC.x + (4 * 0x200); + npc->rect = rcLeft[npc->ani_no]; + } + else + { + npc->x = gMC.x - (4 * 0x200); + npc->rect = rcRight[npc->ani_no]; + } + + if (gMC.ani_no % 2) + ++npc->rect.top; +} + +// Large door (frame) +void ActNpc137(NPCHAR *npc) +{ + RECT rc = {96, 136, 128, 188}; + + npc->rect = rc; +} + +// Large door +void ActNpc138(NPCHAR *npc) +{ + RECT rcLeft = {96, 112, 112, 136}; + RECT rcRight = {112, 112, 128, 136}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + { + npc->rect = rcLeft; + npc->x += 8 * 0x200; + } + else + { + npc->rect = rcRight; + npc->x -= 8 * 0x200; + } + + npc->tgt_x = npc->x; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->act_wait = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 11: + if (++npc->act_wait % 8 == 0) + PlaySoundObject(26, SOUND_MODE_PLAY); + + if (npc->direct == 0) + { + npc->rect = rcLeft; + npc->rect.left += npc->act_wait / 8; + } + else + { + npc->x = npc->tgt_x + ((npc->act_wait / 8) * 0x200); + npc->rect = rcRight; + npc->rect.right -= npc->act_wait / 8; + } + + if (npc->act_wait == 104) + npc->cond = 0; + + break; + } +} + +// Doctor +void ActNpc139(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 128, 24, 160}, + {24, 128, 48, 160}, + {48, 128, 72, 160}, + }; + + RECT rcRight[3] = { + {0, 160, 24, 192}, + {24, 160, 48, 192}, + {48, 160, 72, 192}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->xm = 0; + npc->ym = 0; + npc->y -= 8 * 0x200; + // Fallthrough + case 1: + if (npc->flag & 8) + npc->ani_no = 0; + else + npc->ani_no = 2; + + npc->ym += 0x40; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->ani_wait = 0; + npc->count1 = 0; + // Fallthrough + case 11: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + { + npc->ani_no = 0; + ++npc->count1; + } + + if (npc->count1 > 8) + { + npc->ani_no = 0; + npc->act_no = 1; + } + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 2; + npc->tgt_y = npc->y - (32 * 0x200); + // Fallthrough + case 21: + if (npc->y < npc->tgt_y) + npc->ym += 0x20; + else + npc->ym -= 0x20; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + break; + + case 30: + npc->act_no = 31; + npc->xm = 0; + npc->ym = 0; + npc->act_wait = (npc->rect.bottom - npc->rect.top) * 2; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 31: + --npc->act_wait; + npc->ani_no = 0; + + if (npc->act_wait == 0) + npc->cond = 0; + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 41: + npc->ani_no = 2; + + if (++npc->act_wait < 64) + break; + + npc->act_no = 20; + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 31 || npc->act_no == 41) + { + npc->rect.bottom = npc->rect.top + (npc->act_wait / 2); + + if (npc->act_wait / 2 % 2) + ++npc->rect.left; + } +} diff --git a/src/NpcAct140.cpp b/src/NpcAct140.cpp new file mode 100644 index 0000000..cffabf2 --- /dev/null +++ b/src/NpcAct140.cpp @@ -0,0 +1,2023 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Flash.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Toroko (frenzied) +void ActNpc140(NPCHAR *npc) +{ + int i; + + RECT rcLeft[14] = { + {0, 0, 32, 32}, + {32, 0, 64, 32}, + {64, 0, 96, 32}, + {96, 0, 128, 32}, + {128, 0, 160, 32}, + {160, 0, 192, 32}, + {192, 0, 224, 32}, + {224, 0, 256, 32}, + {0, 64, 32, 96}, + {32, 64, 64, 96}, + {64, 64, 96, 96}, + {96, 64, 128, 96}, + {128, 64, 160, 96}, + {0, 0, 0, 0}, + }; + + RECT rcRight[14] = { + {0, 32, 32, 64}, + {32, 32, 64, 64}, + {64, 32, 96, 64}, + {96, 32, 128, 64}, + {128, 32, 160, 64}, + {160, 32, 192, 64}, + {192, 32, 224, 64}, + {224, 32, 256, 64}, + {0, 96, 32, 128}, + {32, 96, 64, 128}, + {64, 96, 96, 128}, + {96, 96, 128, 128}, + {128, 96, 160, 128}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 9; + npc->act_wait = 0; + npc->bits &= ~NPC_INTERACTABLE; + // Fallthrough + case 1: + if (++npc->act_wait > 50) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 8; + } + + break; + + case 2: + if (++npc->ani_no > 10) + npc->ani_no = 9; + + if (++npc->act_wait > 50) + { + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 0; + } + + break; + + case 3: + if (++npc->act_wait > 50) + { + npc->act_no = 10; + npc->bits |= NPC_SHOOTABLE; + } + + break; + + case 10: + npc->bits = npc->bits; // Chances are this line isn't accurate to the original source code, but it produces the same assembly + npc->act_no = 11; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->act_wait = Random(20, 130); + npc->xm = 0; + // Fallthrough + case 11: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (CountArmsBullet(6) || CountArmsBullet(3) > 3) + npc->act_no = 20; + + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + if (Random(0, 99) % 2) + npc->act_no = 20; + else + npc->act_no = 50; + } + + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 2; + npc->act_wait = 0; + // Fallthrough + case 21: + if (++npc->act_wait > 10) + { + npc->act_no = 22; + npc->act_wait = 0; + npc->ani_no = 3; + npc->ym = -0x5FF; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + } + + break; + + case 22: + if (++npc->act_wait > 10) + { + npc->act_no = 23; + npc->act_wait = 0; + npc->ani_no = 6; + SetNpChar(141, 0, 0, 0, 0, 0, npc, 0); + } + + break; + + case 23: + if (++npc->act_wait > 30) + { + npc->act_no = 24; + npc->act_wait = 0; + npc->ani_no = 7; + } + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 24: + if (++npc->act_wait > 3) + { + npc->act_no = 25; + npc->ani_no = 3; + } + + break; + + case 25: + if (npc->flag & 8) + { + npc->act_no = 26; + npc->act_wait = 0; + npc->ani_no = 2; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(20); + } + + break; + + case 26: + npc->xm = (npc->xm * 8) / 9; + + if (++npc->act_wait > 20) + { + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 0; + npc->ani_no = 4; + SetNpChar(141, 0, 0, 0, 0, 0, npc, 0); + // Fallthrough + case 51: + if (++npc->act_wait > 30) + { + npc->act_no = 52; + npc->act_wait = 0; + npc->ani_no = 5; + } + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 52: + if (++npc->act_wait > 3) + { + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + + case 100: + npc->ani_no = 3; + npc->act_no = 101; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + break; + + case 101: + if (npc->flag & 8) + { + npc->act_no = 102; + npc->act_wait = 0; + npc->ani_no = 2; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(20); + } + + break; + + case 102: + npc->xm = (npc->xm * 8) / 9; + + if (++npc->act_wait > 50) + { + npc->act_no = 103; + npc->act_wait = 0; + npc->ani_no = 10; + } + + break; + + case 103: + if (++npc->act_wait > 50) + { + npc->ani_no = 9; + npc->act_no = 104; + npc->act_wait = 0; + } + + break; + + case 104: + if (++npc->ani_no > 10) + npc->ani_no = 9; + + if (++npc->act_wait > 100) + { + npc->act_wait = 0; + npc->ani_no = 9; + npc->act_no = 105; + } + + break; + + case 105: + if (++npc->act_wait > 50) + { + npc->ani_wait = 0; + npc->act_no = 106; + npc->ani_no = 11; + } + + break; + + case 106: + if (++npc->ani_wait > 50) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 12) + npc->ani_no = 12; + + break; + + case 140: + npc->act_no = 141; + npc->act_wait = 0; + npc->ani_no = 12; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 141: + if (++npc->ani_no > 13) + npc->ani_no = 12; + + if (++npc->act_wait > 100) + { + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->cond = 0; + } + + break; + } + + if (npc->act_no > 100 && npc->act_no < 105 && npc->act_wait % 9 == 0) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->ym += 0x20; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Toroko block projectile +void ActNpc141(NPCHAR *npc) +{ + int i; + unsigned char deg; + + RECT rect[2] = { + {288, 32, 304, 48}, + {304, 32, 320, 48}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = 0; + // Fallthrough + case 1: + if (npc->pNpc->direct == 0) + npc->x = npc->pNpc->x + (10 * 0x200); + else + npc->x = npc->pNpc->x - (10 * 0x200); + + npc->y = npc->pNpc->y - (8 * 0x200); + + if (npc->pNpc->act_no == 24 || npc->pNpc->act_no == 52) + { + npc->act_no = 10; + + if (npc->pNpc->direct == 0) + npc->x = npc->pNpc->x - (16 * 0x200); + else + npc->x = npc->pNpc->x + (16 * 0x200); + + npc->y = npc->pNpc->y; + + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + npc->ym = GetSin(deg) * 4; + npc->xm = GetCos(deg) * 4; + + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + break; + + case 10: + if (npc->flag & 0xF) + { + npc->act_no = 20; + npc->act_wait = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + PlaySoundObject(12, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-0x200, 0x200), Random(-0x200, 0x200), 0, NULL, 0x100); + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + break; + + case 20: + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->act_wait > 4) + { + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-0x200, 0x200), Random(-0x200, 0x200), 0, NULL, 0x100); + + npc->code_char = 142; + npc->ani_no = 0; + npc->act_no = 20; + npc->xm = 0; + npc->bits &= ~NPC_INVULNERABLE; + npc->bits |= NPC_SHOOTABLE; + npc->damage = 1; + } + + break; + } + + if (++npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rect[npc->ani_no]; +} + +// Flower Cub +void ActNpc142(NPCHAR *npc) +{ + RECT rect[5] = { + {0, 128, 16, 144}, + {16, 128, 32, 144}, + {32, 128, 48, 144}, + {48, 128, 64, 144}, + {64, 128, 80, 144}, + }; + + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->act_wait = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 30) + { + npc->act_no = 12; + npc->ani_no = 1; + npc->ani_wait = 0; + } + + break; + + case 12: + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no == 3) + { + npc->act_no = 20; + npc->ym = -0x200; + + if (gMC.x < npc->x) + npc->xm = -0x200; + else + npc->xm = 0x200; + } + + break; + + case 20: + if (npc->ym > -0x80) + npc->ani_no = 4; + else + npc->ani_no = 3; + + if (npc->flag & 8) + { + npc->ani_no = 2; + npc->act_no = 21; + npc->act_wait = 0; + npc->xm = 0; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + + case 21: + if (++npc->act_wait > 10) + { + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} + +// Jenka (collapsed) +void ActNpc143(NPCHAR *npc) +{ + RECT rcLeft[1] = { + {208, 32, 224, 48} + }; + + RECT rcRight[1] = { + {208, 48, 224, 64} + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Toroko (teleporting in) +void ActNpc144(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {0, 64, 16, 80}, + {16, 64, 32, 80}, + {32, 64, 48, 80}, + {16, 64, 32, 80}, + {128, 64, 144, 80}, + }; + + RECT rcRight[5] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + {32, 80, 48, 96}, + {16, 80, 32, 96}, + {128, 80, 144, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->tgt_x = npc->x; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 1: + if (++npc->act_wait == 64) + { + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + if (npc->flag & 8) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 4; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 11: + if (Random(0, 120) == 10) + { + npc->act_no = 12; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 12: + if (++npc->act_wait > 8) + { + npc->act_no = 11; + npc->ani_no = 0; + } + + break; + } + + if (npc->act_no > 1) + { + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 1) + { + npc->rect.bottom = npc->rect.top + npc->act_wait / 4; + + if (npc->act_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + (1 * 0x200); + } +} + +// King's sword +void ActNpc145(NPCHAR *npc) +{ + RECT rcLeft[1] = { + {96, 32, 112, 48} + }; + + RECT rcRight[1] = { + {112, 32, 128, 48} + }; + + switch (npc->act_no) + { + case 0: + if (npc->pNpc->count2 == 0) + { + if (npc->pNpc->direct == 0) + npc->direct = 0; + else + npc->direct = 2; + } + else + { + if (npc->pNpc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + if (npc->direct == 0) + npc->x = npc->pNpc->x - (10 * 0x200); + else + npc->x = npc->pNpc->x + (10 * 0x200); + + npc->y = npc->pNpc->y; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Lightning +void ActNpc146(NPCHAR *npc) +{ + RECT rect[5] = { + {0, 0, 0, 0}, + {256, 0, 272, 240}, + {272, 0, 288, 240}, + {288, 0, 304, 240}, + {304, 0, 320, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 2) + SetFlash(0, 0, FLASH_MODE_FLASH); + // Fallthrough + case 1: + if (++npc->act_wait > 10) + { + npc->act_no = 2; + PlaySoundObject(101, SOUND_MODE_PLAY); + } + + break; + + case 2: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no == 2) + npc->damage = 10; + + if (npc->ani_no > 4) + { + SetDestroyNpChar(npc->x, npc->y, 0x1000, 8); + npc->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Critter (purple) +void ActNpc147(NPCHAR *npc) +{ + int xm, ym; + unsigned char deg; + + RECT rcLeft[6] = { + {0, 96, 16, 112}, + {16, 96, 32, 112}, + {32, 96, 48, 112}, + {48, 96, 64, 112}, + {64, 96, 80, 112}, + {80, 96, 96, 112}, + }; + + RECT rcRight[6] = { + {0, 112, 16, 128}, + {16, 112, 32, 128}, + {32, 112, 48, 128}, + {48, 112, 64, 128}, + {64, 112, 80, 128}, + {80, 112, 96, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->act_wait >= 8 && npc->x - (96 * 0x200) < gMC.x && npc->x + (96 * 0x200) > gMC.x && npc->y - (96 * 0x200) < gMC.y && npc->y + (32 * 0x200) > gMC.y) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + if (npc->act_wait >= 8 && npc->x - (48 * 0x200) < gMC.x && npc->x + (48 * 0x200) > gMC.x && npc->y - (96 * 0x200) < gMC.y && npc->y + (32 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 3; + npc->ani_no = 2; + npc->ym = -0x5FF; + PlaySoundObject(30, SOUND_MODE_PLAY); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 3: + if (npc->ym > 0x100) + { + npc->tgt_y = npc->y; + npc->act_no = 4; + npc->ani_no = 3; + npc->act_wait = 0; + npc->act_wait = 0; // Duplicate line + } + + break; + + case 4: + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + ++npc->act_wait; + + if (npc->flag & 7 || npc->act_wait > 60) + { + npc->damage = 3; + npc->act_no = 5; + npc->ani_no = 2; + break; + } + + if (npc->act_wait % 4 == 1) + PlaySoundObject(109, SOUND_MODE_PLAY); + + if (npc->flag & 8) + npc->ym = -0x200; + + if (npc->act_wait % 30 == 6) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + + SetNpChar(148, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 3; + + break; + + case 5: + if (npc->flag & 8) + { + npc->damage = 2; + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + } + + if (npc->act_no != 4) + { + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + } + else + { + if (npc->y > npc->tgt_y) + npc->ym -= 0x10; + else + npc->ym += 0x10; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Purple Critter's projectile +void ActNpc148(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[2] = { + {96, 96, 104, 104}, + {104, 96, 112, 104}, + }; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } +} + +// Moving block (horizontal) +void ActNpc149(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->x += 8 * 0x200; + npc->y += 8 * 0x200; + + if (npc->direct == 0) + npc->act_no = 10; + else + npc->act_no = 20; + + npc->xm = 0; + npc->ym = 0; + + npc->bits |= NPC_SOLID_HARD; + break; + + case 10: + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + + if (gMC.x < npc->x + (25 * 0x200) && gMC.x > npc->x - (25 * 0x10 * 0x200) && gMC.y < npc->y + (25 * 0x200) && gMC.y > npc->y - (25 * 0x200)) + { + npc->act_no = 11; + npc->act_wait = 0; + } + + break; + + case 11: + if (++npc->act_wait % 10 == 6) + PlaySoundObject(107, SOUND_MODE_PLAY); + + if (npc->flag & 1) + { + npc->xm = 0; + npc->direct = 2; + npc->act_no = 20; + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x - (16 * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + break; + } + + if (gMC.flag & 1) + { + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 100; + } + else + { + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + } + + npc->xm -= 0x20; + + break; + + case 20: + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + + if (gMC.x > npc->x - (25 * 0x200) && gMC.x < npc->x + (25 * 0x10 * 0x200) && gMC.y < npc->y + (25 * 0x200) && gMC.y > npc->y - (25 * 0x200)) + { + npc->act_no = 21; + npc->act_wait = 0; + } + + break; + + case 21: + if (++npc->act_wait % 10 == 6) + PlaySoundObject(107, SOUND_MODE_PLAY); + + if (npc->flag & 4) + { + npc->xm = 0; + npc->direct = 0; + npc->act_no = 10; + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (16 * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + break; + } + + if (gMC.flag & 4) + { + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 100; + } + else + { + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + } + + npc->xm += 0x20; + + break; + } + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + npc->x += npc->xm; + + RECT rect = {16, 0, 48, 32}; + npc->rect = rect; +} + +// Quote +void ActNpc150(NPCHAR *npc) +{ + int i; + + RECT rcLeft[9] = { + {0, 0, 16, 16}, + {48, 0, 64, 16}, + {144, 0, 160, 16}, + {16, 0, 32, 16}, + {0, 0, 16, 16}, + {32, 0, 48, 16}, + {0, 0, 16, 16}, + {160, 0, 176, 16}, + {112, 0, 128, 16}, + }; + + RECT rcRight[9] = { + {0, 16, 16, 32}, + {48, 16, 64, 32}, + {144, 16, 160, 32}, + {16, 16, 32, 32}, + {0, 16, 16, 32}, + {32, 16, 48, 32}, + {0, 16, 16, 32}, + {160, 16, 176, 32}, + {112, 16, 128, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + + if (npc->direct > 10) + { + npc->x = gMC.x; + npc->y = gMC.y; + npc->direct -= 10; + } + break; + + case 2: + npc->ani_no = 1; + break; + + case 10: + npc->act_no = 11; + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-0x155, 0x155), Random(-0x600, 0), 0, NULL, 0x100); + + PlaySoundObject(71, SOUND_MODE_PLAY); + // Fallthrough + case 11: + npc->ani_no = 2; + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 64; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 21: + if (--npc->act_wait == 0) + npc->cond = 0; + + break; + + case 50: + npc->act_no = 51; + npc->ani_no = 3; + npc->ani_wait = 0; + // Fallthrough + case 51: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 3; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + break; + + case 60: + npc->act_no = 61; + npc->ani_no = 7; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + // Fallthrough + case 61: + npc->tgt_y += 0x100; + npc->x = npc->tgt_x + (Random(-1, 1) * 0x200); + npc->y = npc->tgt_y + (Random(-1, 1) * 0x200); + break; + + case 70: + npc->act_no = 71; + npc->act_wait = 0; + npc->ani_no = 3; + npc->ani_wait = 0; + // Fallthrough + case 71: + if (npc->direct == 0) + npc->x += 0x100; + else + npc->x -= 0x100; + + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 3; + + break; + + case 80: + npc->ani_no = 8; + break; + + case 99: + case 100: + npc->act_no = 101; + npc->ani_no = 3; + npc->ani_wait = 0; + // Fallthrough + case 101: + npc->ym += 0x40; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->flag & 8) + { + npc->ym = 0; + npc->act_no = 102; + } + + npc->y += npc->ym; + break; + + case 102: + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 3; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 21) + { + npc->rect.bottom = npc->rect.top + (npc->act_wait / 4); + + if (npc->act_wait / 2 % 2) + ++npc->rect.left; + } + + // Use a different sprite if the player is wearing the Mimiga Mask + if (gMC.equip & EQUIP_MIMIGA_MASK) + { + npc->rect.top += 32; + npc->rect.bottom += 32; + } +} + +// Blue robot (standing) +void ActNpc151(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {192, 0, 208, 16}, + {208, 0, 224, 16}, + }; + + RECT rcRight[2] = { + {192, 16, 208, 32}, + {208, 16, 224, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + + case 1: + if (Random(0, 100) == 0) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 16) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Shutter stuck +void ActNpc152(NPCHAR *npc) +{ + RECT rc = {0, 0, 0, 0}; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->y += 16 * 0x200; + + npc->act_no = 1; + break; + } + + npc->rect = rc; +} + +const RECT grcKitL[21] = { + {0, 0, 24, 24}, + {24, 0, 48, 24}, + {48, 0, 72, 24}, + {0, 0, 24, 24}, + {72, 0, 96, 24}, + {0, 0, 24, 24}, + {96, 0, 120, 24}, + {120, 0, 144, 24}, + {144, 0, 168, 24}, + {168, 0, 192, 24}, + {192, 0, 216, 24}, + {216, 0, 240, 24}, + {240, 0, 264, 24}, + {264, 0, 288, 24}, + {0, 48, 24, 72}, + {24, 48, 48, 72}, + {48, 48, 72, 72}, + {72, 48, 96, 72}, + {288, 0, 312, 24}, + {24, 48, 48, 72}, + {96, 48, 120, 72} +}; + +const RECT grcKitR[21] = { + {0, 24, 24, 48}, + {24, 24, 48, 48}, + {48, 24, 72, 48}, + {0, 24, 24, 48}, + {72, 24, 96, 48}, + {0, 24, 24, 48}, + {96, 24, 120, 48}, + {120, 24, 144, 48}, + {144, 24, 168, 48}, + {168, 24, 192, 48}, + {192, 24, 216, 48}, + {216, 24, 240, 48}, + {240, 24, 264, 48}, + {264, 24, 288, 48}, + {0, 72, 24, 96}, + {24, 72, 48, 96}, + {48, 72, 72, 96}, + {72, 72, 96, 96}, + {288, 24, 312, 48}, + {24, 72, 48, 96}, + {96, 72, 120, 96} +}; + +// Gaudi +void ActNpc153(NPCHAR *npc) +{ + if (npc->x > gMC.x + (((WINDOW_WIDTH / 2) + 160) * 0x200) || npc->x < gMC.x - (((WINDOW_WIDTH / 2) + 160) * 0x200) || npc->y > gMC.y + (((WINDOW_HEIGHT / 2) + 120) * 0x200) || npc->y < gMC.y - (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + return; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->xm = 0; + npc->ani_no = 0; + npc->y += 3 * 0x200; + // Fallthrough + case 1: + if (Random(0, 100) == 1) + { + npc->act_no = 2; + npc->ani_no = 1; + npc->act_wait = 0; + } + + if (Random(0, 100) == 1) + { + if (npc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + if (Random(0, 100) == 1) + npc->act_no = 10; + + break; + + case 2: + if (++npc->act_wait > 20) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = Random(25, 100); + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 11: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->act_no = 1; + npc->ani_no = 0; + npc->xm = 0; + } + + if (npc->direct == 0 && npc->flag & 1) + { + npc->ani_no = 2; + npc->ym = -0x5FF; + npc->act_no = 20; + + if (!(gMC.cond & 2)) + PlaySoundObject(30, SOUND_MODE_PLAY); + } + else if (npc->direct == 2 && npc->flag & 4) + { + npc->ani_no = 2; + npc->ym = -0x5FF; + npc->act_no = 20; + + if (!(gMC.cond & 2)) + PlaySoundObject(30, SOUND_MODE_PLAY); + } + + break; + + case 20: + if (npc->direct == 0 && npc->flag & 1) + ++npc->count1; + else if (npc->direct == 2 && npc->flag & 4) + ++npc->count1; + else + npc->count1 = 0; + + if (npc->count1 > 10) + { + if (npc->direct == 0) + npc->direct = 2; + else + npc->direct = 0; + } + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (npc->flag & 8) + { + npc->act_no = 21; + npc->ani_no = 20; + npc->act_wait = 0; + npc->xm = 0; + + if (!(gMC.cond & 2)) + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + + case 21: + if (++npc->act_wait > 10) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = grcKitL[npc->ani_no]; + else + npc->rect = grcKitR[npc->ani_no]; + + if (npc->life <= 985) + { + npc->code_char = 154; + npc->act_no = 0; + } +} + +// Gaudi (dead) +void ActNpc154(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SHOOTABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->damage = 0; + npc->act_no = 1; + npc->ani_no = 9; + npc->ym = -0x200; + + if (npc->direct == 0) + npc->xm = 0x100; + else + npc->xm = -0x100; + + PlaySoundObject(53, SOUND_MODE_PLAY); + break; + + case 1: + if (npc->flag & 8) + { + npc->ani_no = 10; + npc->ani_wait = 0; + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + npc->xm = (npc->xm * 8) / 9; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 11) + npc->ani_no = 10; + + if (++npc->act_wait > 50) + npc->cond |= 8; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = grcKitL[npc->ani_no]; + else + npc->rect = grcKitR[npc->ani_no]; +} + +// Gaudi (flying) +void ActNpc155(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + if (npc->x > gMC.x + (((WINDOW_WIDTH / 2) + 160) * 0x200) || npc->x < gMC.x - (((WINDOW_WIDTH / 2) + 160) * 0x200) || npc->y > gMC.y + (((WINDOW_HEIGHT / 2) + 120) * 0x200) || npc->y < gMC.y - (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + return; + + switch (npc->act_no) + { + case 0: + deg = Random(0, 0xFF); + npc->xm = GetCos(deg); + deg += 0x40; + npc->tgt_x = npc->x + (GetCos(deg) * 8); + + deg = Random(0, 0xFF); + npc->ym = GetSin(deg); + deg += 0x40; + npc->tgt_y = npc->y + (GetSin(deg) * 8); + + npc->act_no = 1; + npc->count1 = 120; + npc->act_wait = Random(70, 150); + npc->ani_no = 14; + // Fallthrough + case 1: + if (++npc->ani_no > 15) + npc->ani_no = 14; + + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->act_no = 2; + npc->ani_no = 18; + } + + break; + + case 2: + if (++npc->ani_no > 19) + npc->ani_no = 18; + + if (++npc->act_wait > 30) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + SetNpChar(156, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + + if (!(gMC.cond & 2)) + PlaySoundObject(39, SOUND_MODE_PLAY); + + npc->act_no = 1; + npc->act_wait = Random(70, 150); + npc->ani_no = 14; + npc->ani_wait = 0; + } + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_x < npc->x) + npc->xm -= 0x10; + if (npc->tgt_x > npc->x) + npc->xm += 0x10; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = grcKitL[npc->ani_no]; + else + npc->rect = grcKitR[npc->ani_no]; + + if (npc->life <= 985) + { + npc->code_char = 154; + npc->act_no = 0; + } +} + +// Gaudi projectile +void ActNpc156(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[3] = { + {96, 112, 112, 128}, + {112, 112, 128, 128}, + {128, 112, 144, 128}, + }; + + if (++npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } +} + +// Moving block (vertical) +void ActNpc157(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->x += 8 * 0x200; + npc->y += 8 * 0x200; + + if (npc->direct == 0) + npc->act_no = 10; + else + npc->act_no = 20; + + npc->xm = 0; + npc->ym = 0; + npc->bits |= NPC_SOLID_HARD; + + break; + + case 10: + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + + if (gMC.y < npc->y + (25 * 0x200) && gMC.y > npc->y - (25 * 0x10 * 0x200) && gMC.x < npc->x + (25 * 0x200) && gMC.x > npc->x - (25 * 0x200)) + { + npc->act_no = 11; + npc->act_wait = 0; + } + + break; + + case 11: + if (++npc->act_wait % 10 == 6) + PlaySoundObject(107, SOUND_MODE_PLAY); + + if (npc->flag & 2) + { + npc->ym = 0; + npc->direct = 2; + npc->act_no = 20; + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y - (16 * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + break; + } + + if (gMC.flag & 2) + { + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 100; + } + else + { + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + } + + npc->ym -= 0x20; + + break; + + case 20: + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + + if (gMC.y > npc->y - (25 * 0x200) && gMC.y < npc->y + (25 * 0x10 * 0x200) && gMC.x < npc->x + (25 * 0x200) && gMC.x > npc->x - (25 * 0x200)) + { + npc->act_no = 21; + npc->act_wait = 0; + } + + break; + + case 21: + if (++npc->act_wait % 10 == 6) + PlaySoundObject(107, SOUND_MODE_PLAY); + + if (npc->flag & 8) + { + npc->ym = 0; + npc->direct = 0; + npc->act_no = 10; + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (16 * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + break; + } + + if (gMC.flag & 8) + { + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 100; + } + else + { + npc->bits &= ~NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 0; + } + + npc->ym += 0x20; + + break; + } + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->y += npc->ym; + + RECT rect = {16, 0, 48, 32}; + npc->rect = rect; +} + +// Fish Missile +void ActNpc158(NPCHAR *npc) +{ + int dir; + + RECT rect[8] = { + {0, 224, 16, 240}, + {16, 224, 32, 240}, + {32, 224, 48, 240}, + {48, 224, 64, 240}, + {64, 224, 80, 240}, + {80, 224, 96, 240}, + {96, 224, 112, 240}, + {112, 224, 128, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + switch (npc->direct) + { + case 0: + npc->count1 = 0xA0; + break; + + case 1: + npc->count1 = 0xE0; + break; + + case 2: + npc->count1 = 0x20; + break; + + case 3: + npc->count1 = 0x60; + break; + } + // Fallthrough + case 1: + npc->xm = 2 * GetCos(npc->count1); + npc->ym = 2 * GetSin(npc->count1); + npc->y += npc->ym; + npc->x += npc->xm; + dir = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + + if (dir < npc->count1) + { + if (npc->count1 - dir < 0x80) + --npc->count1; + else + ++npc->count1; + } + else + { + if (dir - npc->count1 < 0x80) + ++npc->count1; + else + --npc->count1; + } + + if (npc->count1 > 0xFF) + npc->count1 -= 0x100; + if (npc->count1 < 0) + npc->count1 += 0x100; + + break; + } + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + SetCaret(npc->x, npc->y, CARET_EXHAUST, DIR_AUTO); + } + + npc->ani_no = (npc->count1 + 0x10) / 0x20; + + if (npc->ani_no > 7) + npc->ani_no = 7; + + npc->rect = rect[npc->ani_no]; +} + +// Monster X (defeated) +void ActNpc159(NPCHAR *npc) +{ + int i; + + RECT rect = {144, 128, 192, 200}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x + (Random(-16, 16) * 0x200), npc->y + (Random(-16, 16) * 0x200), Random(-341, 341), Random(-341, 341), 0, NULL, 0x100); + // Fallthrough + case 1: + if (++npc->act_wait > 50) + { + npc->act_no = 2; + npc->xm = -0x100; + } + + if (npc->act_wait / 2 % 2) + npc->x += 0x200; + else + npc->x -= 0x200; + + break; + + case 2: + ++npc->act_wait; + npc->ym += 0x40; + + if (npc->y > 40 * 0x10 * 0x200) + npc->cond = 0; + + break; + } + + npc->y += npc->ym; + npc->x += npc->xm; + + npc->rect = rect; + + if (npc->act_wait % 8 == 1) + SetNpChar(4, npc->x + (Random(-16, 16) * 0x200), npc->y + (Random(-16, 16) * 0x200), Random(-341, 341), Random(-341, 341), 0, NULL, 0x100); +} diff --git a/src/NpcAct160.cpp b/src/NpcAct160.cpp new file mode 100644 index 0000000..1aa537e --- /dev/null +++ b/src/NpcAct160.cpp @@ -0,0 +1,1653 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "MycParam.h" +#include "NpChar.h" +#include "NpcHit.h" +#include "Sound.h" +#include "Triangle.h" + +// Puu Black +void ActNpc160(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SOLID_SOFT; + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + npc->ym = 0xA00; + + if (npc->y < 128 * 0x200) + { + ++npc->count1; + } + else + { + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->act_no = 2; + } + + break; + + case 2: + npc->ym = 0xA00; + + if (npc->flag & 8) + { + DeleteNpCharCode(161, TRUE); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->act_no = 3; + npc->act_wait = 0; + SetQuake(30); + PlaySoundObject(26, SOUND_MODE_PLAY); + PlaySoundObject(72, SOUND_MODE_PLAY); + } + + if (npc->y < gMC.y && gMC.flag & 8) + npc->damage = 20; + else + npc->damage = 0; + + break; + + case 3: + npc->damage = 20; // Overwritten by the following line + npc->damage = 0; + + if (++npc->act_wait > 24) + { + npc->act_no = 4; + npc->count1 = 0; + npc->count2 = 0; + } + + break; + + case 4: + gSuperXpos = npc->x; + gSuperYpos = npc->y; + + if (npc->shock % 2 == 1) + { + SetNpChar(161, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-0x600, 0x600), Random(-0x600, 0x600), 0, NULL, 0x100); + + if (++npc->count1 > 30) + { + npc->count1 = 0; + npc->act_no = 5; + npc->ym = -0xC00; + npc->bits |= NPC_IGNORE_SOLIDITY; + } + } + + break; + + case 5: + gSuperXpos = npc->x; + gSuperYpos = npc->y; + + if (++npc->count1 > 60) + { + npc->count1 = 0; + npc->act_no = 6; + } + + break; + + case 6: + gSuperXpos = gMC.x; + gSuperYpos = 400 * 0x10 * 0x200; + + if (++npc->count1 > 110) + { + npc->count1 = 10; + npc->x = gMC.x; + npc->y = 0; + npc->ym = 0x5FF; + npc->act_no = 1; + } + + break; + } + + npc->y += npc->ym; + + switch (npc->act_no) + { + case 0: + case 1: + npc->ani_no = 3; + break; + + case 2: + npc->ani_no = 3; + break; + + case 3: + npc->ani_no = 2; + break; + + case 4: + npc->ani_no = 0; + break; + + case 5: + npc->ani_no = 3; + break; + + case 6: + npc->ani_no = 3; + break; + } + + RECT rect_left[4] = { + {0, 0, 40, 24}, + {40, 0, 80, 24}, + {80, 0, 120, 24}, + {120, 0, 160, 24}, + }; + + RECT rect_right[4] = { + {0, 24, 40, 48}, + {40, 24, 80, 48}, + {80, 24, 120, 48}, + {120, 24, 160, 48}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Puu Black projectile +void ActNpc161(NPCHAR *npc) +{ + npc->exp = 0; + + if (npc->x < gSuperXpos) + npc->xm += 0x40; + else + npc->xm -= 0x40; + + if (npc->y < gSuperYpos) + npc->ym += 0x40; + else + npc->ym -= 0x40; + + if (npc->xm < -4605) + npc->xm = -4605; + if (npc->xm > 4605) + npc->xm = 4605; + + if (npc->ym < -4605) + npc->ym = -4605; + if (npc->ym > 4605) + npc->ym = 4605; + + if (npc->life < 100) + { + npc->bits &= ~NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + npc->damage = 0; + npc->ani_no = 2; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->ani_no < 2) + { + if (Random(0, 10) == 2) + npc->ani_no = 0; + else + npc->ani_no = 1; + } + + RECT rect[3] = { + {0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + }; + + npc->rect = rect[npc->ani_no]; +} + +// Puu Black (dead) +void ActNpc162(NPCHAR *npc) +{ + int i; + + RECT rect_left = {40, 0, 80, 24}; + RECT rect_right = {40, 24, 80, 48}; + RECT rect_end = {0, 0, 0, 0}; + + switch (npc->act_no) + { + case 0: + DeleteNpCharCode(161, TRUE); + PlaySoundObject(72, SOUND_MODE_PLAY); + + for (i = 0; i < 10; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-0x600, 0x600), Random(-0x600, 0x600), 0, NULL, 0x100); + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->rect = rect_left; + else + npc->rect = rect_right; + + npc->count1 = 0; + npc->act_no = 1; + // Fallthrough + case 1: + ++npc->count1; + + if (npc->count1 % 4 == 0) + SetNpChar(161, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), 0, 0, 0, NULL, 0x100); + + if (npc->count1 > 160) + { + npc->count1 = 0; + npc->act_no = 2; + npc->tgt_y = npc->y; + } + + break; + + case 2: + SetQuake(2); + + ++npc->count1; + + if (npc->count1 <= 240) + { + if (npc->direct == 0) + npc->rect = rect_left; + else + npc->rect = rect_right; + + npc->rect.top += npc->count1 / 8; + npc->y = npc->tgt_y + ((npc->count1 / 8) * 0x200); + npc->rect.left -= (npc->count1 / 2) % 2; + } + else + { + npc->rect = rect_end; + + npc->count1 = 0; + npc->act_no = 3; + } + + if (npc->count1 % 3 == 2) + SetNpChar(161, npc->x + (Random(-12, 12) * 0x200), npc->y - (12 * 0x200), Random(-0x200, 0x200), 0x100, 0, NULL, 0x100); + + if (npc->count1 % 4 == 2) + PlaySoundObject(21, SOUND_MODE_PLAY); + + break; + + case 3: + if (++npc->count1 < 60) + break; + + DeleteNpCharCode(161, TRUE); + npc->cond = 0; + + break; + + } + + gSuperXpos = npc->x; + gSuperYpos = -1000 * 0x200; +} + +// Dr Gero +void ActNpc163(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {192, 0, 208, 16}, + {208, 0, 224, 16}, + }; + + RECT rcRight[2] = { + {192, 16, 208, 32}, + {208, 16, 224, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Nurse Hasumi +void ActNpc164(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {224, 0, 240, 16}, + {240, 0, 256, 16}, + }; + + RECT rcRight[2] = { + {224, 16, 240, 32}, + {240, 16, 256, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Curly (collapsed) +void ActNpc165(NPCHAR *npc) +{ + RECT rcRight[2] = { + {192, 96, 208, 112}, + {208, 96, 224, 112}, + }; + + RECT rcLeft = {144, 96, 160, 112}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 10 * 0x200; + // Fallthrough + case 1: + if (npc->direct == 2 && gMC.x > npc->x - (32 * 0x200) && gMC.x < npc->x + (32 * 0x200) && gMC.y > npc->y - (16 * 0x200) && gMC.y < npc->y + (16 * 0x200)) + npc->ani_no = 1; + else + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Chaba +void ActNpc166(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {144, 104, 184, 128}, + {184, 104, 224, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Professor Booster (falling) +void ActNpc167(NPCHAR *npc) +{ + int i; + + RECT rect[3] = { + {304, 0, 320, 16}, + {304, 16, 320, 32}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 1; + break; + + case 10: + npc->ani_no = 0; + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 0; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 21: + if (++npc->ani_no > 2) + npc->ani_no = 1; + + if (++npc->act_wait > 100) + { + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (Random(-12, 12) * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + npc->cond = 0; + } + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Boulder +void ActNpc168(NPCHAR *npc) +{ + RECT rect = {264, 56, 320, 96}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->tgt_x = npc->x; + // Fallthrough + case 11: + ++npc->act_wait; + npc->x = npc->tgt_x; + + if (npc->act_wait / 3 % 2) + npc->x += 1 * 0x200; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + npc->ym = -0x400; + npc->xm = 0x100; + PlaySoundObject(25, SOUND_MODE_PLAY); + // Fallthrough + case 21: + npc->ym += 0x10; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->act_wait && npc->flag & 8) + { + PlaySoundObject(35, SOUND_MODE_PLAY); + SetQuake(40); + npc->act_no = 0; + } + + if (npc->act_wait == 0) + ++npc->act_wait; + + break; + } + + npc->rect = rect; +} + +// Balrog (missile) +void ActNpc169(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->act_wait = 30; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 1: + if (--npc->act_wait != 0) + break; + + npc->act_no = 2; + ++npc->count1; + break; + + case 2: + npc->act_no = 3; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 3: + ++npc->ani_wait; + + if (npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + + if (npc->ani_no == 2 || npc->ani_no == 4) + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + if (npc->ani_no > 4) + npc->ani_no = 1; + + if (npc->direct == 0) + npc->xm -= 0x20; + else + npc->xm += 0x20; + + if (npc->act_wait >= 8 && npc->x - (12 * 0x200) < gMC.x && npc->x + (12 * 0x200) > gMC.x && npc->y - (12 * 0x200) < gMC.y && npc->y + (8 * 0x200) > gMC.y) + { + npc->act_no = 10; + npc->ani_no = 5; + gMC.cond |= 2; + DamageMyChar(5); + break; + } + + ++npc->act_wait; + + if (npc->act_wait > 75) + { + npc->act_no = 9; + npc->ani_no = 0; + break; + } + + if (npc->flag & 5) + { + if (npc->count2 < 5) + { + ++npc->count2; + } + else + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 7; + npc->ym = -0x5FF; + } + } + else + { + npc->count2 = 0; + } + + if (npc->count1 % 2 == 0 && npc->act_wait > 25) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 7; + npc->ym = -0x5FF; + break; + } + + break; + + case 4: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + ++npc->act_wait; + + if (npc->act_wait < 30 && npc->act_wait % 6 == 1) + { + PlaySoundObject(39, SOUND_MODE_PLAY); + SetNpChar(170, npc->x, npc->y, 0, 0, npc->direct, NULL, 0x100); + } + + if (npc->flag & 8) + { + npc->act_no = 9; + npc->ani_no = 8; + SetQuake(30); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + if (npc->act_wait >= 8 && npc->x - (12 * 0x200) < gMC.x && npc->x + (12 * 0x200) > gMC.x && npc->y - (12 * 0x200) < gMC.y && npc->y + (8 * 0x200) > gMC.y) + { + npc->act_no = 10; + npc->ani_no = 5; + gMC.cond |= 2; + DamageMyChar(10); + } + + break; + + case 9: + npc->xm = (npc->xm * 4) / 5; + + if (npc->xm != 0) + break; + + npc->act_no = 0; + break; + + case 10: + gMC.x = npc->x; + gMC.y = npc->y; + + npc->xm = (npc->xm * 4) / 5; + + if (npc->xm != 0) + break; + + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 5; + npc->ani_wait = 0; + break; + + case 11: + gMC.x = npc->x; + gMC.y = npc->y; + + ++npc->ani_wait; + + if (npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 5; + + ++npc->act_wait; + + if (npc->act_wait > 100) + npc->act_no = 20; + + break; + + case 20: + PlaySoundObject(25, SOUND_MODE_PLAY); + gMC.cond &= ~2; + + if (npc->direct == 0) + { + gMC.x += 4 * 0x200; + gMC.y -= 8 * 0x200; + gMC.xm = 0x5FF; + gMC.ym = -0x200; + gMC.direct = 2; + npc->direct = 2; + } + else + { + gMC.x -= 4 * 0x200; + gMC.y -= 8 * 0x200; + gMC.xm = -0x5FF; + gMC.ym = -0x200; + gMC.direct = 0; + npc->direct = 0; + } + + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 7; + // Fallthrough + case 21: + ++npc->act_wait; + + if (npc->act_wait < 50) + break; + + npc->act_no = 0; + break; + } + + npc->ym += 0x20; + + if (npc->xm < -0x300) + npc->xm = -0x300; + if (npc->xm > 0x300) + npc->xm = 0x300; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[9] = { + {0, 0, 40, 24}, + {0, 48, 40, 72}, + {0, 0, 40, 24}, + {40, 48, 80, 72}, + {0, 0, 40, 24}, + {80, 48, 120, 72}, + {120, 48, 160, 72}, + {120, 0, 160, 24}, + {80, 0, 120, 24}, + }; + + RECT rect_right[9] = { + {0, 24, 40, 48}, + {0, 72, 40, 96}, + {0, 24, 40, 48}, + {40, 72, 80, 96}, + {0, 24, 40, 48}, + {80, 72, 120, 96}, + {120, 72, 160, 96}, + {120, 24, 160, 48}, + {80, 24, 120, 48}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Balrog missile +void ActNpc170(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {112, 96, 128, 104}, + {128, 96, 144, 104}, + }; + + RECT rcRight[2] = { + {112, 104, 128, 112}, + {128, 104, 144, 112}, + }; + + BOOL bHit = FALSE; + + if (npc->direct == 0 && npc->flag & 1) + bHit = TRUE; + if (npc->direct == 2 && npc->flag & 4) + bHit = TRUE; + + if (bHit) + { + PlaySoundObject(44, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, 0, 3); + VanishNpChar(npc); + return; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + npc->xm = Random(1, 2) * 0x200; + else + npc->xm = Random(-2, -1) * 0x200; + + npc->ym = Random(-2, 0) * 0x200; + // Fallthrough + case 1: + ++npc->count1; + + if (npc->direct == 0) + { + npc->xm -= 0x20; + + if (npc->count1 % 3 == 1) + SetCaret(npc->x + (8 * 0x200), npc->y, CARET_EXHAUST, DIR_RIGHT); + } + else + { + npc->xm += 0x20; + + if (npc->count1 % 3 == 1) + SetCaret(npc->x - (8 * 0x200), npc->y, CARET_EXHAUST, DIR_LEFT); + } + + if (npc->count1 < 50) + { + if (npc->y < gMC.y) + npc->ym += 0x20; + else + npc->ym -= 0x20; + } + else + { + npc->ym = 0; + } + + if (++npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + if (npc->xm < -0x400) + npc->xm = -0x600; + if (npc->xm > 0x400) + npc->xm = 0x600; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Fire Whirrr +void ActNpc171(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {120, 48, 152, 80}, + {152, 48, 184, 80}, + }; + + RECT rcRight[2] = { + {184, 48, 216, 80}, + {216, 48, 248, 80}, + }; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(0, 50); + npc->tgt_y = npc->y; + // Fallthrough + case 1: + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->act_no = 10; + npc->ym = 0x200; + } + // Fallthrough + case 10: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->y < npc->tgt_y) + npc->ym += 0x10; + else + npc->ym -= 0x10; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->y += npc->ym; + + if (npc->direct == 0) + { + if (gMC.y < npc->y + (80 * 0x200) && gMC.y > npc->y - (80 * 0x200) && gMC.x < npc->x && gMC.x > npc->x - (160 * 0x200)) + ++npc->count1; + } + else + { + if (gMC.y < npc->y + (80 * 0x200) && gMC.y > npc->y - (80 * 0x200) && gMC.x < npc->x + (160 * 0x200) && gMC.x > npc->x) + ++npc->count1; + } + + if (npc->count1 > 20) + { + SetNpChar(172, npc->x, npc->y, 0, 0, npc->direct, NULL, 0x100); + npc->count1 = -100; + gCurlyShoot_wait = Random(80, 100); + gCurlyShoot_x = npc->x; + gCurlyShoot_y = npc->y; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Fire Whirr projectile +void ActNpc172(NPCHAR *npc) +{ + RECT rect[3] = { + {248, 48, 264, 80}, + {264, 48, 280, 80}, + {280, 48, 296, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->x -= 1 * 0x200; + else + npc->x += 1 * 0x200; + + if (npc->flag & 1 || npc->flag & 4) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + VanishNpChar(npc); + return; + } + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Gaudi (armoured) +void ActNpc173(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + RECT rcLeft[4] = { + {0, 128, 24, 152}, + {24, 128, 48, 152}, + {48, 128, 72, 152}, + {72, 128, 96, 152}, + }; + + RECT rcRight[4] = { + {0, 152, 24, 176}, + {24, 152, 48, 176}, + {48, 152, 72, 176}, + {72, 152, 96, 176}, + }; + + if (npc->x > gMC.x + (((WINDOW_WIDTH / 2) + 160) * 0x200) || npc->x < gMC.x - (((WINDOW_WIDTH / 2) + 160) * 0x200) || npc->y > gMC.y + (((WINDOW_HEIGHT / 2) + 120) * 0x200) || npc->y < gMC.y - (((WINDOW_HEIGHT / 2) + 120) * 0x200)) + return; + + switch (npc->act_no) + { + case 0: + npc->tgt_x = npc->x; + npc->act_no = 1; + // Fallthrough + case 1: + npc->ani_no = 0; + npc->xm = 0; + + if (npc->act_wait < 5) + { + ++npc->act_wait; + } + else + { + if (npc->x - (192 * 0x200) < gMC.x && npc->x + (192 * 0x200) > gMC.x && npc->y - (160 * 0x200) < gMC.y && npc->y + (160 * 0x200) > gMC.y) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + } + + break; + + case 10: + if (++npc->act_wait > 3) + { + if (++npc->count1 == 3) + { + PlaySoundObject(30, SOUND_MODE_PLAY); + npc->count1 = 0; + npc->act_no = 25; + npc->act_wait = 0; + npc->ani_no = 2; + npc->ym = -0x600; + + if (npc->x < npc->tgt_x) + npc->xm = 0x80; + else + npc->xm = -0x80; + } + else + { + PlaySoundObject(30, SOUND_MODE_PLAY); + npc->act_no = 20; + npc->ani_no = 2; + npc->ym = -0x200; + + if (npc->x < npc->tgt_x) + npc->xm = 0x200; + else + npc->xm = -0x200; + } + } + + break; + + case 20: + ++npc->act_wait; + + if (npc->flag & 8) + { + PlaySoundObject(23, SOUND_MODE_PLAY); + npc->ani_no = 1; + npc->act_no = 30; + npc->act_wait = 0; + } + + break; + + case 25: + if (++npc->act_wait == 30 || npc->act_wait == 40) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + + SetNpChar(174, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + + PlaySoundObject(39, SOUND_MODE_PLAY); + npc->ani_no = 3; + + gCurlyShoot_wait = Random(80, 100); + gCurlyShoot_x = npc->x; + gCurlyShoot_y = npc->y; + } + + if (npc->act_wait == 35 || npc->act_wait == 45) + npc->ani_no = 2; + + if (npc->flag & 8) + { + PlaySoundObject(23, SOUND_MODE_PLAY); + npc->ani_no = 1; + npc->act_no = 30; + npc->act_wait = 0; + } + + break; + + case 30: + npc->xm = 7 * npc->xm / 8; + + if (++npc->act_wait > 3) + { + npc->ani_no = 0; + npc->act_no = 1; + npc->act_wait = 0; + } + + break; + } + + npc->ym += 51; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->life <= 985) + { + SetDestroyNpChar(npc->x, npc->y, 0, 2); + npc->code_char = 154; + npc->act_no = 0; + } +} + +// Armoured-Gaudi projectile +void ActNpc174(NPCHAR *npc) +{ + BOOL bHit; + + switch (npc->act_no) + { + case 0: + if (npc->direct == 2) + npc->act_no = 2; + // Fallthrough + case 1: + npc->x += npc->xm; + npc->y += npc->ym; + + bHit = FALSE; + + if (npc->flag & 1) + { + bHit = TRUE; + npc->xm = 0x200; + } + + if (npc->flag & 4) + { + bHit = TRUE; + npc->xm = -0x200; + } + + if (npc->flag & 2) + { + bHit = TRUE; + npc->ym = 0x200; + } + + if (npc->flag & 8) + { + bHit = TRUE; + npc->ym = -0x200; + } + + if (bHit) + { + npc->act_no = 2; + ++npc->count1; + PlaySoundObject(31, SOUND_MODE_PLAY); + } + + break; + + case 2: + npc->ym += 0x40; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 8) + { + if (++npc->count1 > 1) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + } + + break; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + RECT rect_left[3] = { + {120, 80, 136, 96}, + {136, 80, 152, 96}, + {152, 80, 168, 96}, + }; + + if (++npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; +} + +// Gaudi egg +void ActNpc175(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {168, 80, 192, 104}, + {192, 80, 216, 104}, + }; + + RECT rcRight[2] = { + {216, 80, 240, 104}, + {240, 80, 264, 104}, + }; + + if (npc->act_no < 3 && npc->life < 90) + { + LoseNpChar(npc, FALSE); + npc->act_no = 10; + npc->ani_no = 1; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + } + + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + npc->act_no = 1; + break; + } + + if (npc->direct == 0) + npc->ym += 0x20; + else + npc->ym -= 0x20; + + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// BuyoBuyo Base +void ActNpc176(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {96, 128, 128, 144}, + {128, 128, 160, 144}, + {160, 128, 192, 144}, + }; + + RECT rcRight[3] = { + {96, 144, 128, 160}, + {128, 144, 160, 160}, + {160, 144, 192, 160}, + }; + + if (npc->act_no < 3 && npc->life < 940) + { + LoseNpChar(npc, FALSE); + npc->act_no = 10; + npc->ani_no = 2; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (npc->direct == 0) + { + if (npc->x < gMC.x + (160 * 0x200) && npc->x > gMC.x - (160 * 0x200) && npc->y < gMC.y + (160 * 0x200) && npc->y > gMC.y - (16 * 0x200)) + ++npc->count1; + } + else + { + if (npc->x < gMC.x + (160 * 0x200) && npc->x > gMC.x - (160 * 0x200) && npc->y < gMC.y + (16 * 0x200) && npc->y > gMC.y - (160 * 0x200)) + ++npc->count1; + } + + if (npc->count1 > 10) + { + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 10) + { + if (++npc->count2 > 2) + { + npc->count2 = 0; + npc->count1 = -90; + } + else + { + npc->count1 = -10; + } + + if (npc->direct == 0) + SetNpChar(177, npc->x, npc->y - (8 * 0x200), 0, 0, 0, NULL, 0x100); + else + SetNpChar(177, npc->x, npc->y + (8 * 0x200), 0, 0, 2, NULL, 0x100); + + PlaySoundObject(39, SOUND_MODE_PLAY); + + npc->act_no = 0; + npc->ani_no = 0; + + gCurlyShoot_wait = Random(80, 100); + gCurlyShoot_x = npc->x; + gCurlyShoot_y = npc->y; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// BuyoBuyo +void ActNpc177(NPCHAR *npc) +{ + RECT rc[2] = { + {192, 128, 208, 144}, + {208, 128, 224, 144}, + }; + + if (npc->flag & 0xFF) + { + SetCaret(npc->x, npc->y, CARET_SHOOT, DIR_LEFT); + npc->cond = 0; + return; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + npc->ym = -0x600; + else + npc->ym = 0x600; + // Fallthrough + case 1: + if (npc->y < gMC.y + (16 * 0x200) && npc->y > gMC.y - (16 * 0x200)) + { + npc->act_no = 10; + + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->xm = ((Random(0, 1) * 0x200) - 0x100) * 2; + npc->ym = ((Random(0, 1) * 0x200) - 0x100) * 2; + } + + break; + + case 10: + if (npc->x < npc->tgt_x) + npc->xm += 0x20; + else + npc->xm -= 0x20; + + if (npc->y < npc->tgt_y) + npc->ym += 0x20; + else + npc->ym -= 0x20; + + if (++npc->act_wait > 300) + { + SetCaret(npc->x, npc->y, CARET_SHOOT, DIR_LEFT); + npc->cond = 0; + return; + } + + if (npc->direct == 0) + npc->tgt_x -= 1 * 0x200; + else + npc->tgt_x += 1 * 0x200; + + break; + } + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x400) + npc->ym = 0x400; + if (npc->ym < -0x400) + npc->ym = -0x400; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Core blade projectile +void ActNpc178(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + npc->cond = 0; + } + + if (npc->flag & 0x100) + { + npc->y += npc->ym / 2; + npc->x += npc->xm / 2; + } + else + { + npc->y += npc->ym; + npc->x += npc->xm; + } + + RECT rect_left[3] = { + {0, 224, 16, 240}, + {16, 224, 32, 240}, + {32, 224, 48, 240}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 150) + { + VanishNpChar(npc); + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } +} + +// Core wisp projectile +void ActNpc179(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + + npc->xm -= 0x20; + npc->ym = 0; + + if (npc->xm < -0x400) + npc->xm = -0x400; + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[3] = { + {48, 224, 72, 240}, + {72, 224, 96, 240}, + {96, 224, 120, 240}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + VanishNpChar(npc); + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } +} diff --git a/src/NpcAct180.cpp b/src/NpcAct180.cpp new file mode 100644 index 0000000..c43e4f6 --- /dev/null +++ b/src/NpcAct180.cpp @@ -0,0 +1,1448 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Back.h" +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Flags.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "NpcHit.h" +#include "Sound.h" +#include "Triangle.h" + +// Curly AI +void ActNpc180(NPCHAR *npc) +{ + int xx, yy; + + RECT rcLeft[11] = { + {0, 96, 16, 112}, + {16, 96, 32, 112}, + {0, 96, 16, 112}, + {32, 96, 48, 112}, + {0, 96, 16, 112}, + {48, 96, 64, 112}, + {64, 96, 80, 112}, + {48, 96, 64, 112}, + {80, 96, 96, 112}, + {48, 96, 64, 112}, + {144, 96, 160, 112}, + }; + + RECT rcRight[11] = { + {0, 112, 16, 128}, + {16, 112, 32, 128}, + {0, 112, 16, 128}, + {32, 112, 48, 128}, + {0, 112, 16, 128}, + {48, 112, 64, 128}, + {64, 112, 80, 128}, + {48, 112, 64, 128}, + {80, 112, 96, 128}, + {48, 112, 64, 128}, + {144, 112, 160, 128}, + }; + + if (npc->y < gMC.y - (10 * 0x10 * 0x200)) + { + if (npc->y < 16 * 0x10 * 0x200) + { + npc->tgt_x = 320 * 0x10 * 0x200; + npc->tgt_y = npc->y; + } + else + { + npc->tgt_x = 0; + npc->tgt_y = npc->y; + } + } + else + { + if (gCurlyShoot_wait != 0) + { + npc->tgt_x = gCurlyShoot_x; + npc->tgt_y = gCurlyShoot_y; + } + else + { + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y; + } + } + + if (npc->xm < 0 && npc->flag & 1) + npc->xm = 0; + if (npc->xm > 0 && npc->flag & 4) + npc->xm = 0; + + switch (npc->act_no) + { + case 20: + npc->x = gMC.x; + npc->y = gMC.y; + npc->act_no = 100; + npc->ani_no = 0; + SetNpChar(183, 0, 0, 0, 0, 0, npc, 0x100); + + if (GetNPCFlag(563)) + SetNpChar(182, 0, 0, 0, 0, 0, npc, 0x100); + else + SetNpChar(181, 0, 0, 0, 0, 0, npc, 0x100); + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + npc->ani_no = 10; + // Fallthrough + case 41: + if (++npc->act_wait == 750) + { + npc->bits &= ~NPC_INTERACTABLE; + npc->ani_no = 0; + } + + if (npc->act_wait > 1000) + { + npc->act_no = 100; + npc->ani_no = 0; + SetNpChar(183, 0, 0, 0, 0, 0, npc, 0x100); + + if (GetNPCFlag(563)) + SetNpChar(182, 0, 0, 0, 0, 0, npc, 0x100); + else + SetNpChar(181, 0, 0, 0, 0, 0, npc, 0x100); + } + + break; + + case 100: + npc->ani_no = 0; + npc->xm = (npc->xm * 7) / 8; + npc->count1 = 0; + + if (npc->x > npc->tgt_x + (16 * 0x200)) + { + npc->act_no = 200; + npc->ani_no = 1; + npc->direct = 0; + npc->act_wait = Random(20, 60); + } + else if (npc->x < npc->tgt_x - (16 * 0x200)) + { + npc->act_no = 300; + npc->ani_no = 1; + npc->direct = 2; + npc->act_wait = Random(20, 60); + } + + break; + + case 200: + npc->xm -= 0x20; + npc->direct = 0; + + if (npc->flag & 1) + ++npc->count1; + else + npc->count1 = 0; + + break; + + case 210: + npc->xm -= 0x20; + npc->direct = 0; + + if (npc->flag & 8) + npc->act_no = 100; + + break; + + case 300: + npc->xm += 0x20; + npc->direct = 2; + + if (npc->flag & 4) + ++npc->count1; + else + npc->count1 = 0; + + break; + + case 310: + npc->xm += 0x20; + npc->direct = 2; + + if (npc->flag & 8) + npc->act_no = 100; + + break; + } + + if (gCurlyShoot_wait != 0) + --gCurlyShoot_wait; + + if (gCurlyShoot_wait == 70) + npc->count2 = 10; + + if (gCurlyShoot_wait == 60 && npc->flag & 8 && Random(0, 2)) + { + npc->count1 = 0; + npc->ym = -0x600; + npc->ani_no = 1; + PlaySoundObject(15, SOUND_MODE_PLAY); + + if (npc->x > npc->tgt_x) + npc->act_no = 210; + else + npc->act_no = 310; + } + + xx = npc->x - npc->tgt_x; + yy = npc->y - npc->tgt_y; + + if (xx < 0) + xx *= -1; + + if (npc->act_no == 100) + { + if (xx + (2 * 0x200) < yy) + npc->ani_no = 5; + else + npc->ani_no = 0; + } + + if (npc->act_no == 210 || npc->act_no == 310) + { + if (xx + (2 * 0x200) < yy) + npc->ani_no = 6; + else + npc->ani_no = 1; + } + + if (npc->act_no == 200 || npc->act_no == 300) + { + ++npc->ani_wait; + + if (xx + (2 * 0x200) < yy) + npc->ani_no = 6 + (npc->ani_wait / 4 % 4); + else + npc->ani_no = 1 + (npc->ani_wait / 4 % 4); + + if (npc->act_wait) + { + --npc->act_wait; + +#ifdef FIX_BUGS + // I assume this is what was intended + if (npc->flag & 8 && npc->count1 > 10) +#else + if (npc->flag && 8 && npc->count1 > 10) +#endif + { + npc->count1 = 0; + npc->ym = -0x600; + npc->act_no += 10; + npc->ani_no = 1; + PlaySoundObject(15, SOUND_MODE_PLAY); + } + } + else + { + npc->act_no = 100; + npc->ani_no = 0; + } + } + + if (npc->act_no >= 100 && npc->act_no < 500) + { + if (npc->x < gMC.x - (80 * 0x200) || npc->x > gMC.x + (80 * 0x200)) + { +#ifdef FIX_BUGS + if (npc->flag & 5) +#else + if (npc->flag && 5) +#endif + npc->ym += 0x200 / 32; + else + npc->ym += 0x200 / 10; + } + else + { + npc->ym += 0x200 / 10; + } + } + + if (npc->xm > 0x300) + npc->xm = 0x300; + if (npc->xm < -0x300) + npc->xm = -0x300; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->act_no >= 100 && !(npc->flag & 8)) + { + switch (npc->ani_no) + { + case 1000: + break; + + default: + if (xx + (2 * 0x200) < yy) + npc->ani_no = 6; + else + npc->ani_no = 1; + + break; + } + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Curly AI Machine Gun +void ActNpc181(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {216, 152, 232, 168}, + {232, 152, 248, 168}, + }; + + RECT rcRight[2] = { + {216, 168, 232, 184}, + {232, 168, 248, 184}, + }; + + if (npc->pNpc == NULL) + return; + + if (npc->pNpc->ani_no < 5) + { + if (npc->pNpc->direct == 0) + { + npc->direct = 0; + npc->x = npc->pNpc->x - (8 * 0x200); + } + else + { + npc->direct = 2; + npc->x = npc->pNpc->x + (8 * 0x200); + } + + npc->y = npc->pNpc->y; + npc->ani_no = 0; + } + else + { + if (npc->pNpc->direct == 0) + { + npc->direct = 0; + npc->x = npc->pNpc->x; + } + else + { + npc->direct = 2; + npc->x = npc->pNpc->x; + } + + npc->y = npc->pNpc->y - (10 * 0x200); + npc->ani_no = 1; + } + + if (npc->pNpc->ani_no == 1 || npc->pNpc->ani_no == 3 || npc->pNpc->ani_no == 6 || npc->pNpc->ani_no == 8) + npc->y -= 1 * 0x200; + + switch (npc->act_no) + { + case 0: + if (npc->pNpc->count2 == 10) + { + npc->pNpc->count2 = 0; + npc->act_no = 10; + npc->act_wait = 0; + } + + break; + + case 10: + if (++npc->act_wait % 6 == 1) + { + if (npc->ani_no == 0) + { + if (npc->direct == 0) + { + SetBullet(12, npc->x - (4 * 0x200), npc->y + (3 * 0x200), 0); + SetCaret(npc->x - (4 * 0x200), npc->y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(12, npc->x + (4 * 0x200), npc->y + (3 * 0x200), 2); + SetCaret(npc->x + (4 * 0x200), npc->y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (npc->direct == 0) + { + SetBullet(12, npc->x - (2 * 0x200), npc->y - (4 * 0x200), 1); + SetCaret(npc->x - (2 * 0x200), npc->y - (4 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(12, npc->x + (2 * 0x200), npc->y - (4 * 0x200), 1); + SetCaret(npc->x + (2 * 0x200), npc->y - (4 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + } + + if (npc->act_wait == 60) + npc->act_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Curly AI Polar Star +void ActNpc182(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {184, 152, 200, 168}, + {200, 152, 216, 168}, + }; + + RECT rcRight[2] = { + {184, 168, 200, 184}, + {200, 168, 216, 184}, + }; + + if (npc->pNpc == NULL) + return; + + if (npc->pNpc->ani_no < 5) + { + if (npc->pNpc->direct == 0) + { + npc->direct = 0; + npc->x = npc->pNpc->x - (8 * 0x200); + } + else + { + npc->direct = 2; + npc->x = npc->pNpc->x + (8 * 0x200); + } + + npc->y = npc->pNpc->y; + npc->ani_no = 0; + } + else + { + if (npc->pNpc->direct == 0) + { + npc->direct = 0; + npc->x = npc->pNpc->x; + } + else + { + npc->direct = 2; + npc->x = npc->pNpc->x; + } + + npc->y = npc->pNpc->y - (10 * 0x200); + npc->ani_no = 1; + } + + if (npc->pNpc->ani_no == 1 || npc->pNpc->ani_no == 3 || npc->pNpc->ani_no == 6 || npc->pNpc->ani_no == 8) + npc->y -= 1 * 0x200; + + switch (npc->act_no) + { + case 0: + if (npc->pNpc->count2 == 10) + { + npc->pNpc->count2 = 0; + npc->act_no = 10; + npc->act_wait = 0; + } + + break; + + case 10: + if (++npc->act_wait % 12 == 1) + { + if (npc->ani_no == 0) + { + if (npc->direct == 0) + { + SetBullet(6, npc->x - (4 * 0x200), npc->y + (3 * 0x200), 0); + SetCaret(npc->x - (4 * 0x200), npc->y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(6, npc->x + (4 * 0x200), npc->y + (3 * 0x200), 2); + SetCaret(npc->x + (4 * 0x200), npc->y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (npc->direct == 0) + { + SetBullet(6, npc->x - (2 * 0x200), npc->y - (4 * 0x200), 1); + SetCaret(npc->x - (2 * 0x200), npc->y - (4 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(6, npc->x + (2 * 0x200), npc->y - (4 * 0x200), 1); + SetCaret(npc->x + (2 * 0x200), npc->y - (4 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + } + + if (npc->act_wait == 60) + npc->act_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Curly Air Tank Bubble +void ActNpc183(NPCHAR *npc) +{ + RECT rect[2] = { + {56, 96, 80, 120}, + {80, 96, 104, 120}, + }; + + if (npc->pNpc == NULL) + return; + + switch (npc->act_no) + { + case 0: + npc->x = npc->pNpc->x; + npc->y = npc->pNpc->y; + npc->act_no = 1; + break; + } + + npc->x += (npc->pNpc->x - npc->x) / 2; + npc->y += (npc->pNpc->y - npc->y) / 2; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->pNpc->flag & 0x100) + npc->rect = rect[npc->ani_no]; + else + npc->rect.right = 0; +} + +// Big Shutter +void ActNpc184(NPCHAR *npc) +{ + int i; + + RECT rc[4] = { + {0, 64, 32, 96}, + {32, 64, 64, 96}, + {64, 64, 96, 96}, + {32, 64, 64, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->x += 8 * 0x200; + npc->y += 8 * 0x200; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->act_wait = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 11: + switch (npc->direct) + { + case 0: + npc->x -= 0x80; + break; + + case 1: + npc->y -= 0x80; + break; + + case 2: + npc->x += 0x80; + break; + + case 3: + npc->y += 0x80; + break; + } + + if ((++npc->act_wait % 8) == 0) + PlaySoundObject(26, SOUND_MODE_PLAY); + + SetQuake(20); + break; + + case 20: + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (16 * 0x200), Random(-0x155, 0x155), Random(-0x600, 0), 0, NULL, 0x100); + + npc->act_no = 1; + break; + } + + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Small Shutter +void ActNpc185(NPCHAR *npc) +{ + RECT rc = {96, 64, 112, 96}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 8 * 0x200; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->act_wait = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 11: + switch (npc->direct) + { + case 0: + npc->x -= 0x80; + break; + + case 1: + npc->y -= 0x80; + break; + + case 2: + npc->x += 0x80; + break; + + case 3: + npc->y += 0x80; + break; + } + + ++npc->act_wait; + break; + + case 20: + npc->y -= 24 * 0x200; + npc->act_no = 1; + break; + } + + npc->rect = rc; +} + +// Lift block +void ActNpc186(NPCHAR *npc) +{ + RECT rc[4] = { + {48, 48, 64, 64}, + {64, 48, 80, 64}, + {80, 48, 96, 64}, + {64, 48, 80, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->act_wait = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 11: + switch (npc->direct) + { + case 0: + npc->x -= 0x80; + break; + + case 1: + npc->y -= 0x80; + break; + + case 2: + npc->x += 0x80; + break; + + case 3: + npc->y += 0x80; + break; + } + + ++npc->act_wait; + break; + } + + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Fuzz Core +void ActNpc187(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->count1 = 120; + npc->act_wait = Random(0, 50); + + for (i = 0; i < 5; ++i) + SetNpChar(188, 0, 0, 0, 0, 51 * i, npc, 0x100); + // Fallthrough + case 1: + if (++npc->act_wait < 50) + break; + + npc->act_wait = 0; + npc->act_no = 2; + npc->ym = 0x300; + break; + + case 2: + npc->count1 += 4; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->ym > 0x355) + npc->ym = 0x355; + if (npc->ym < -0x355) + npc->ym = -0x355; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[2] = { + {224, 104, 256, 136}, + {256, 104, 288, 136}, + }; + + RECT rect_right[2] = { + {224, 136, 256, 168}, + {256, 136, 288, 168}, + }; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Fuzz +void ActNpc188(NPCHAR *npc) +{ + unsigned char deg; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->count1 = npc->direct; + // Fallthrough + case 1: + if (npc->pNpc->code_char == 187 && npc->pNpc->cond & 0x80) + { + deg = (npc->pNpc->count1 + npc->count1) % 0x100; + npc->x = npc->pNpc->x + (GetSin(deg) * 20); + npc->y = npc->pNpc->y + (GetCos(deg) * 0x20); + } + else + { + npc->xm = Random(-0x200, 0x200); + npc->ym = Random(-0x200, 0x200); + npc->act_no = 10; + } + + break; + + case 10: + if (gMC.x < npc->x) + npc->xm -= 0x20; + else + npc->xm += 0x20; + + if (gMC.y < npc->y) + npc->ym -= 0x20; + else + npc->ym += 0x20; + + if (npc->xm > 0x800) + npc->xm = 0x800; + if (npc->xm < -0x800) + npc->xm = -0x800; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->x += npc->xm; + npc->y += npc->ym; + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + RECT rect_left[2] = { + {288, 104, 304, 120}, + {304, 104, 320, 120}, + }; + + RECT rect_right[2] = { + {288, 120, 304, 136}, + {304, 120, 320, 136}, + }; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Unused homing flame object (possibly related to the Core?) +void ActNpc189(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->xm = -0x40; + // Fallthrough + case 1: + npc->y += npc->ym; + + if (++npc->act_wait > 0x100) + npc->act_no = 10; + + break; + + case 10: + if (gMC.x < npc->x) + npc->xm -= 8; + else + npc->xm += 8; + + if (gMC.y < npc->y) + npc->ym -= 8; + else + npc->ym += 8; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x400) + npc->ym = 0x400; + if (npc->ym < -0x400) + npc->ym = -0x400; + + npc->x += npc->xm; + npc->y += npc->ym; + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + RECT rect[3] = { + {224, 184, 232, 200}, + {232, 184, 240, 200}, + {240, 184, 248, 200}, + }; + + npc->rect = rect[npc->ani_no]; +} + +// Broken robot +void ActNpc190(NPCHAR *npc) +{ + RECT rect[2] = { + {192, 32, 208, 48}, + {208, 32, 224, 48}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + break; + + case 10: + PlaySoundObject(72, SOUND_MODE_PLAY); + + for (i = 0; i < 8; ++i) + SetNpChar(4, npc->x, npc->y + (Random(-8, 8) * 0x200), Random(-8, -2) * 0x200, Random(-3, 3) * 0x200, 0, NULL, 0x100); + + npc->cond = 0; + break; + + case 20: + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Water level +void ActNpc191(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->tgt_y = npc->y; + npc->ym = 0x200; + // Fallthrough + case 10: + if (npc->y < npc->tgt_y) + npc->ym += 4; + else + npc->ym -= 4; + + if (npc->ym < -0x100) + npc->ym = -0x100; + if (npc->ym > 0x100) + npc->ym = 0x100; + + npc->y += npc->ym; + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + // Fallthrough + case 21: + if (npc->y < npc->tgt_y) + npc->ym += 4; + else + npc->ym -= 4; + + if (npc->ym < -0x200) + npc->ym = -0x200; + if (npc->ym > 0x200) + npc->ym = 0x200; + + npc->y += npc->ym; + + if (++npc->act_wait > 1000) + npc->act_no = 22; + + break; + + case 22: + if (npc->y < 0) + npc->ym += 4; + else + npc->ym -= 4; + + if (npc->ym < -0x200) + npc->ym = -0x200; + if (npc->ym > 0x200) + npc->ym = 0x200; + + npc->y += npc->ym; + + if (npc->y < 64 * 0x200 || gSuperYpos != 0) + { + npc->act_no = 21; + npc->act_wait = 0; + } + break; + + case 30: + if (npc->y < 0) + npc->ym += 4; + else + npc->ym -= 4; + + if (npc->ym < -0x200) + npc->ym = -0x200; + if (npc->ym > 0x100) + npc->ym = 0x100; + + npc->y += npc->ym; + break; + } + + gWaterY = npc->y; + + npc->rect.right = 0; + npc->rect.bottom = 0; +} + +// Scooter +void ActNpc192(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->view.back = 16 * 0x200; + npc->view.front = 16 * 0x200; + npc->view.top = 8 * 0x200; + npc->view.bottom = 8 * 0x200; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 1; + npc->view.top = 16 * 0x200; + npc->view.bottom = 16 * 0x200; + npc->y -= 5 * 0x200; + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + // Fallthrough + case 21: + npc->x = npc->tgt_x + (Random(-1, 1) * 0x200); + npc->y = npc->tgt_y + (Random(-1, 1) * 0x200); + + if (++npc->act_wait > 30) + npc->act_no = 30; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 1; + npc->xm = -0x800; + npc->x = npc->tgt_x; + npc->y = npc->tgt_y; + PlaySoundObject(44, SOUND_MODE_PLAY); + // Fallthrough + case 31: + npc->xm += 0x20; + npc->x += npc->xm; + ++npc->act_wait; + npc->y = npc->tgt_y + (Random(-1, 1) * 0x200); + + if (npc->act_wait > 10) + npc->direct = 2; + + if (npc->act_wait > 200) + npc->act_no = 40; + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 2; + npc->direct = 0; + npc->y -= 48 * 0x200; + npc->xm = -0x1000; + // Fallthrough + case 41: + npc->x += npc->xm; + npc->y += npc->ym; + + npc->act_wait += 2; + + if (npc->act_wait > 1200) + npc->cond = 0; + + break; + } + + if (npc->act_wait % 4 == 0 && npc->act_no >= 20) + { + PlaySoundObject(34, SOUND_MODE_PLAY); + + if (npc->direct == 0) + SetCaret(npc->x + (10 * 0x200), npc->y + (10 * 0x200), CARET_EXHAUST, DIR_RIGHT); + else + SetCaret(npc->x - (10 * 0x200), npc->y + (10 * 0x200), CARET_EXHAUST, DIR_LEFT); + } + + RECT rcLeft[2] = { + {224, 64, 256, 80}, + {256, 64, 288, 96}, + }; + + RECT rcRight[2] = { + {224, 80, 256, 96}, + {288, 64, 320, 96}, + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Scooter (broken) +void ActNpc193(NPCHAR *npc) +{ + RECT rc = {256, 96, 320, 112}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y = npc->y; // This line probably isn't accurate to the original source code, but it produces the same assembly + npc->x += 24 * 0x200; + break; + } + + npc->rect = rc; +} + +// Blue robot (broken) +void ActNpc194(NPCHAR *npc) +{ + RECT rc = {192, 120, 224, 128}; + + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->y += 4 * 0x200; + } + + npc->rect = rc; +} + +// Grate +void ActNpc195(NPCHAR *npc) +{ + RECT rc = {112, 64, 128, 80}; + npc->rect = rc; +} + +// Ironhead motion wall +void ActNpc196(NPCHAR *npc) +{ + RECT rcLeft = {112, 64, 144, 80}; + RECT rcRight = {112, 80, 144, 96}; + + npc->x -= 6 * 0x200; + + if (npc->x <= 19 * 0x10 * 0x200) + npc->x += 22 * 0x10 * 0x200; + + if (npc->direct == 0) + npc->rect = rcLeft; + else + npc->rect = rcRight; +} + +// Porcupine Fish +void ActNpc197(NPCHAR *npc) +{ + RECT rc[4] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + {48, 0, 64, 16}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->ani_wait = 0; + npc->ym = Random(-0x200, 0x200); + npc->xm = 0x800; + // Fallthrough + case 10: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->xm < 0) + { + npc->damage = 3; + npc->act_no = 20; + } + + break; + + case 20: + npc->damage = 3; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + if (npc->x < 48 * 0x200) + { + npc->destroy_voice = 0; + LoseNpChar(npc, TRUE); + } + + break; + } + + if (npc->flag & 2) + npc->ym = 0x200; + if (npc->flag & 8) + npc->ym = -0x200; + + npc->xm -= 12; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Ironhead projectile +void ActNpc198(NPCHAR *npc) +{ + RECT rcRight[3] = { + {208, 48, 224, 72}, + {224, 48, 240, 72}, + {240, 48, 256, 72}, + }; + + switch (npc->act_no) + { + case 0: + if (++npc->act_wait > 20) + { + npc->act_no = 1; + npc->xm = 0; + npc->ym = 0; + npc->count1 = 0; + } + + break; + + case 1: + npc->xm += 0x20; + break; + } + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rcRight[npc->ani_no]; + + if (++npc->count1 > 100) + npc->cond = 0; + + if (npc->count1 % 4 == 1) + PlaySoundObject(46, SOUND_MODE_PLAY); +} + +// Water/wind particles +void ActNpc199(NPCHAR *npc) +{ + RECT rect[5] = { + {72, 16, 74, 18}, + {74, 16, 76, 18}, + {76, 16, 78, 18}, + {78, 16, 80, 18}, + {80, 16, 82, 18}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = Random(0, 2); + + switch (npc->direct) + { + case 0: + npc->xm = -1; + break; + + case 1: + npc->ym = -1; + break; + + case 2: + npc->xm = 1; + break; + + case 3: + npc->ym = 1; + break; + } + + npc->xm *= (Random(4, 8) * 0x200) / 2; + npc->ym *= (Random(4, 8) * 0x200) / 2; + break; + } + + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + { + npc->cond = 0; + #ifdef FIX_MAJOR_BUGS + return; // The code below will use 'ani_no' to access 'rect', even though it's now too high + #endif + } + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} diff --git a/src/NpcAct200.cpp b/src/NpcAct200.cpp new file mode 100644 index 0000000..639d561 --- /dev/null +++ b/src/NpcAct200.cpp @@ -0,0 +1,1514 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Dragon Zombie +void ActNpc200(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + RECT rcLeft[6] = { + {0, 0, 40, 40}, + {40, 0, 80, 40}, + {80, 0, 120, 40}, + {120, 0, 160, 40}, + {160, 0, 200, 40}, + {200, 0, 240, 40}, + }; + + RECT rcRight[6] = { + {0, 40, 40, 80}, + {40, 40, 80, 80}, + {80, 40, 120, 80}, + {120, 40, 160, 80}, + {160, 40, 200, 80}, + {200, 40, 240, 80}, + }; + + if (npc->act_no < 100 && npc->life < 950) + { + PlaySoundObject(72, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + SetExpObjects(npc->x, npc->y, npc->exp); + npc->act_no = 100; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->count1 = 0; + // Fallthrough + case 10: + if (++npc->ani_wait > 30) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->count1) + --npc->count1; + + if (npc->count1 == 0 && gMC.x > npc->x - (112 * 0x200) && gMC.x < npc->x + (112 * 0x200)) + npc->act_no = 20; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + // Fallthrough + case 21: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 2; + else + npc->ani_no = 3; + + if (npc->act_wait > 30) + npc->act_no = 30; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->ani_no = 4; + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y; + // Fallthrough + case 31: + if (++npc->act_wait < 40 && npc->act_wait % 8 == 1) + { + if (npc->direct == 0) + deg = GetArktan(npc->x - (14 * 0x200) - npc->tgt_x, npc->y - npc->tgt_y); + else + deg = GetArktan(npc->x + (14 * 0x200) - npc->tgt_x, npc->y - npc->tgt_y); + + deg += (unsigned char)Random(-6, 6); + + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + + if (npc->direct == 0) + SetNpChar(202, npc->x - (14 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + else + SetNpChar(202, npc->x + (14 * 0x200), npc->y, xm, ym, 0, NULL, 0x100); + + if (!(gMC.cond & 2)) + PlaySoundObject(33, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 60) + { + npc->act_no = 10; + npc->count1 = Random(100, 200); + npc->ani_wait = 0; + } + + break; + + case 100: + npc->ani_no = 5; + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Dragon Zombie (dead) +void ActNpc201(NPCHAR *npc) +{ + RECT rcLeft[1] = { + {200, 0, 240, 40} + }; + + RECT rcRight[1] = { + {200, 40, 240, 80} + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Dragon Zombie projectile +void ActNpc202(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[3] = { + {184, 216, 200, 240}, + {200, 216, 216, 240}, + {216, 216, 232, 240}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } +} + +// Critter (destroyed Egg Corridor) +void ActNpc203(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + {32, 80, 48, 96}, + }; + + RECT rcRight[3] = { + {0, 96, 16, 112}, + {16, 96, 32, 112}, + {32, 96, 48, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->act_wait >= 8 && npc->x - (112 * 0x200) < gMC.x && npc->x + (112 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (80 * 0x200) > gMC.y) + { + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + if (npc->act_wait >= 8 && npc->x - (48 * 0x200) < gMC.x && npc->x + (48 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (48 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 3; + npc->ani_no = 2; + npc->ym = -0x5FF; + + if (!(gMC.cond & 2)) + PlaySoundObject(30, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + } + + break; + + case 3: + if (npc->flag & 8) + { + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + + if (!(gMC.cond & 2)) + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Falling spike (small) +void ActNpc204(NPCHAR *npc) +{ + RECT rc[2] = { + {240, 80, 256, 96}, + {240, 144, 256, 160}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + // Fallthrough + case 1: + if (gMC.x > npc->x - (12 * 0x200) && gMC.x < npc->x + (12 * 0x200) && gMC.y > npc->y) + npc->act_no = 2; + + break; + + case 2: + if (++npc->act_wait / 6 % 2) + npc->x = npc->tgt_x - (1 * 0x200); + else + npc->x = npc->tgt_x; + + if (npc->act_wait > 30) + { + npc->act_no = 3; + npc->ani_no = 1; + } + + break; + + case 3: + npc->ym += 0x20; + + if (npc->flag & 0xFF) + { + if (!(gMC.cond & 2)) + PlaySoundObject(12, SOUND_MODE_PLAY); + + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 4); + npc->cond = 0; + return; + } + + break; + } + + if (npc->ym > 0xC00) + npc->ym = 0xC00; + + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Falling spike (large) +void ActNpc205(NPCHAR *npc) +{ + RECT rc[2] = { + {112, 80, 128, 112}, + {128, 80, 144, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->y += 4 * 0x200; + // Fallthrough + case 1: + if (gMC.x > npc->x - (12 * 0x200) && gMC.x < npc->x + (12 * 0x200) && gMC.y > npc->y) + npc->act_no = 2; + + break; + + case 2: + if (++npc->act_wait / 6 % 2) + npc->x = npc->tgt_x - (1 * 0x200); + else + npc->x = npc->tgt_x; + + if (npc->act_wait > 30) + { + npc->act_no = 3; + npc->ani_no = 1; + npc->act_wait = 0; + } + + break; + + case 3: + npc->ym += 0x20; + + if (gMC.y > npc->y) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->damage = 0x7F; + } + else + { + npc->bits |= NPC_SOLID_HARD; + npc->damage = 0; + } + + if (++npc->act_wait > 8 && npc->flag & 0xFF) + { + npc->bits |= NPC_SOLID_HARD; + npc->act_no = 4; + npc->act_wait = 0; + npc->ym = 0; + npc->damage = 0; + PlaySoundObject(12, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 4); + SetBullet(24, npc->x, npc->y, 0); + return; + } + + break; + + case 4: + if (++npc->act_wait > 4) + { + npc->act_no = 5; + npc->bits |= NPC_SHOOTABLE; + } + + break; + } + + if (npc->ym > 0xC00) + npc->ym = 0xC00; + + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Counter Bomb +void ActNpc206(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->count1 = 120; + npc->act_wait = Random(0, 50); + // Fallthrough + case 1: + if (++npc->act_wait < 50) + break; + + npc->act_wait = 0; + npc->act_no = 2; + npc->ym = 0x300; + break; + + case 2: + if (gMC.x > npc->x - (80 * 0x200) && gMC.x < npc->x + (80 * 0x200)) + { + npc->act_wait = 0; + npc->act_no = 3; + } + + if (npc->shock) + { + npc->act_wait = 0; + npc->act_no = 3; + } + + break; + + case 3: + switch (npc->act_wait) + { + // Interestingly, this NPC counts down at 60 frames + // per second, while NPC322 (Deleet) counts at 50. + case 60 * 0: + SetNpChar(207, npc->x + (16 * 0x200), npc->y + (4 * 0x200), 0, 0, 0, NULL, 0x100); + break; + + case 60 * 1: + SetNpChar(207, npc->x + (16 * 0x200), npc->y + (4 * 0x200), 0, 0, 1, NULL, 0x100); + break; + + case 60 * 2: + SetNpChar(207, npc->x + (16 * 0x200), npc->y + (4 * 0x200), 0, 0, 2, NULL, 0x100); + break; + + case 60 * 3: + SetNpChar(207, npc->x + (16 * 0x200), npc->y + (4 * 0x200), 0, 0, 3, NULL, 0x100); + break; + + case 60 * 4: + SetNpChar(207, npc->x + (16 * 0x200), npc->y + (4 * 0x200), 0, 0, 4, NULL, 0x100); + break; + + case 60 * 5: + npc->hit.back = 128 * 0x200; + npc->hit.front = 128 * 0x200; + npc->hit.top = 100 * 0x200; + npc->hit.bottom = 100 * 0x200; + npc->damage = 30; + PlaySoundObject(35, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, 0x10000, 100); + SetQuake(20); + npc->cond |= 8; + break; + } + + ++npc->act_wait; + break; + } + + if (npc->act_no > 1) + { + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[3] = { + {80, 80, 120, 120}, + {120, 80, 160, 120}, + {160, 80, 200, 120}, + }; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; +} + +// Counter Bomb's countdown +void ActNpc207(NPCHAR *npc) +{ + RECT rc[5] = { + {0, 144, 16, 160}, + {16, 144, 32, 160}, + {32, 144, 48, 160}, + {48, 144, 64, 160}, + {64, 144, 80, 160}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = npc->direct; + PlaySoundObject(43, SOUND_MODE_PLAY); + // Fallthrough + case 1: + npc->x += 1 * 0x200; + + if (++npc->act_wait > 8) + { + npc->act_wait = 0; + npc->act_no = 2; + } + + break; + + case 2: + if (++npc->act_wait > 30) + { + npc->cond = 0; + return; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Basu (destroyed Egg Corridor) +void ActNpc208(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {248, 80, 272, 104}, + {272, 80, 296, 104}, + {296, 80, 320, 104}, + }; + + RECT rcRight[3] = { + {248, 104, 272, 128}, + {272, 104, 296, 128}, + {296, 104, 320, 128}, + }; + + switch (npc->act_no) + { + case 0: + if (gMC.x < npc->x + (16 * 0x200) && gMC.x > npc->x - (16 * 0x200)) + { + npc->bits |= NPC_SHOOTABLE; + npc->ym = -0x200; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->act_no = 1; + npc->act_wait = 0; + npc->count1 = npc->direct; + npc->count2 = 0; + npc->damage = 6; + + if (npc->direct == 0) + { + npc->x = gMC.x + (256 * 0x200); + npc->xm = -0x2FF; + } + else + { + npc->x = gMC.x - (256 * 0x200); + npc->xm = 0x2FF; + } + + return; + } + + npc->rect.right = 0; + npc->damage = 0; + npc->xm = 0; + npc->ym = 0; + npc->bits &= ~NPC_SHOOTABLE; + return; + + case 1: + if (npc->x > gMC.x) + { + npc->direct = 0; + npc->xm -= 0x10; + } + else + { + npc->direct = 2; + npc->xm += 0x10; + } + + if (npc->flag & 1) + npc->xm = 0x200; + if (npc->flag & 4) + npc->xm = -0x200; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + if (npc->xm > 0x2FF) + npc->xm = 0x2FF; + if (npc->xm < -0x2FF) + npc->xm = -0x2FF; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->shock) + { + npc->x += npc->xm / 2; + npc->y += npc->ym / 2; + } + else + { + npc->x += npc->xm; + npc->y += npc->ym; + } + + if (gMC.x > npc->x + (400 * 0x200) || gMC.x < npc->x - (400 * 0x200)) + { + npc->act_no = 0; + npc->xm = 0; + npc->direct = npc->count1; + npc->x = npc->tgt_x; + npc->rect.right = 0; + npc->damage = 0; + return; + } + + break; + } + + if (npc->act_no != 0) + { + if (npc->act_wait < 150) + ++npc->act_wait; + + if (npc->act_wait == 150) + { + if (++npc->count2 % 8 == 0 && npc->x < gMC.x + (160 * 0x200) && npc->x > gMC.x - (160 * 0x200)) + { + unsigned char deg; + int xm; + int ym; + + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-6, 6); + ym = GetSin(deg) * 3; + xm = GetCos(deg) * 3; + SetNpChar(209, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (npc->count2 > 16) + { + npc->act_wait = 0; + npc->count2 = 0; + } + } + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->act_wait > 120 && npc->act_wait / 2 % 2 == 1 && npc->ani_no == 1) + npc->ani_no = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Basu projectile (destroyed Egg Corridor) +void ActNpc209(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[4] = { + {232, 96, 248, 112}, + {200, 112, 216, 128}, + {216, 112, 232, 128}, + {232, 112, 248, 128}, + }; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } +} + +// Beetle (destroyed Egg Corridor) +void ActNpc210(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 112, 16, 128}, + {16, 112, 32, 128}, + }; + + RECT rcRight[2] = { + {32, 112, 48, 128}, + {48, 112, 64, 128}, + }; + + switch (npc->act_no) + { + case 0: + if (gMC.x < npc->x + (16 * 0x200) && gMC.x > npc->x - (16 * 0x200)) + { + npc->bits |= NPC_SHOOTABLE; + npc->ym = -0x200; + npc->tgt_y = npc->y; + npc->act_no = 1; + npc->damage = 2; + + if (npc->direct == 0) + { + npc->x = gMC.x + (256 * 0x200); + npc->xm = -0x2FF; + } + else + { + npc->x = gMC.x - (256 * 0x200); + npc->xm = 0x2FF; + } + } + else + { + npc->bits &= ~NPC_SHOOTABLE; + npc->rect.right = 0; + npc->damage = 0; + npc->xm = 0; + npc->ym = 0; + return; + } + + break; + + case 1: + if (npc->x > gMC.x) + { + npc->direct = 0; + npc->xm -= 0x10; + } + else + { + npc->direct = 2; + npc->xm += 0x10; + } + + if (npc->xm > 0x2FF) + npc->xm = 0x2FF; + if (npc->xm < -0x2FF) + npc->xm = -0x2FF; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->shock) + { + npc->x += npc->xm / 2; + npc->y += npc->ym / 2; + } + else + { + npc->x += npc->xm; + npc->y += npc->ym; + } + + break; + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Spikes (small) +void ActNpc211(NPCHAR *npc) +{ + RECT rects[4] = { + {256, 200, 272, 216}, + {272, 200, 288, 216}, + {288, 200, 304, 216}, + {304, 200, 320, 216}, + }; + + npc->rect = rects[npc->code_event]; +} + +// Sky Dragon +void ActNpc212(NPCHAR *npc) +{ + RECT rcRight[4] = { + {160, 152, 200, 192}, + {200, 152, 240, 192}, + {240, 112, 280, 152}, + {280, 112, 320, 152}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 4 * 0x200; + // Fallthrough + case 1: + if (++npc->ani_wait > 30) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 2; + npc->ani_wait = 0; + npc->tgt_y = npc->y - (16 * 0x200); + npc->tgt_x = npc->x - (6 * 0x200); + npc->ym = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 11: + if (npc->x < npc->tgt_x) + npc->xm += 8; + else + npc->xm -= 8; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + break; + + case 20: + npc->act_no = 21; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 21: + if (npc->y < npc->tgt_y) + npc->ym += 0x10; + else + npc->ym -= 0x10; + + npc->xm += 0x20; + + if (npc->xm > 0x600) + npc->xm = 0x600; + if (npc->xm < -0x600) + npc->xm = -0x600; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + break; + + case 30: + npc->act_no = 31; + SetNpChar(297, 0, 0, 0, 0, 0, npc, 0x100); + break; + } + + npc->rect = rcRight[npc->ani_no]; + + // Use different sprite if player is wearing the Mimiga Mask + if (gMC.equip & EQUIP_MIMIGA_MASK) + { + if (npc->ani_no > 1) + { + npc->rect.top += 40; + npc->rect.bottom += 40; + } + } +} + +// Night Spirit +void ActNpc213(NPCHAR *npc) +{ + RECT rect[10] = { + {0, 0, 0, 0}, + {0, 0, 48, 48}, + {48, 0, 96, 48}, + {96, 0, 144, 48}, + {144, 0, 192, 48}, + {192, 0, 240, 48}, + {240, 0, 288, 48}, + {0, 48, 48, 96}, + {48, 48, 96, 96}, + {96, 48, 144, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + // Fallthrough + case 1: + if (gMC.y > npc->y - (8 * 0x200) && gMC.y < npc->y + (8 * 0x200)) + { + if (npc->direct == 0) + npc->y -= 240 * 0x200; + else + npc->y += 240 * 0x200; + + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ym = 0; + npc->bits |= NPC_SHOOTABLE; + } + + break; + + case 10: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 1; + + if (++npc->act_wait > 200) + { + npc->act_no = 20; + npc->act_wait = 0; + npc->ani_no = 4; + } + + break; + + case 20: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 4; + + if (++npc->act_wait > 50) + { + npc->act_no = 30; + npc->act_wait = 0; + npc->ani_no = 7; + } + + break; + + case 30: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 9) + npc->ani_no = 7; + + if (++npc->act_wait % 5 == 1) + { + SetNpChar(214, npc->x, npc->y, (Random(2, 12) * 0x200) / 4, Random(-0x200, 0x200), 0, NULL, 0x100); + PlaySoundObject(21, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 50) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 40: + if (npc->y < npc->tgt_y) + npc->ym += 0x40; + else + npc->ym -= 0x40; + + if (npc->ym < -0x400) + npc->ym = -0x400; + if (npc->ym > 0x400) + npc->ym = 0x400; + + if (npc->shock) + npc->y += npc->ym / 2; + else + npc->y += npc->ym; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->ani_no = 4; + + if (gMC.y < npc->tgt_y + (240 * 0x200) && gMC.y > npc->tgt_y - (240 * 0x200)) + { + npc->act_no = 20; + npc->act_wait = 0; + npc->ani_no = 4; + } + + break; + } + + if (npc->act_no >= 10 && npc->act_no <= 30) + { + if (npc->y < gMC.y) + npc->ym += 25; + else + npc->ym -= 25; + + if (npc->ym < -0x400) + npc->ym = -0x400; + if (npc->ym > 0x400) + npc->ym = 0x400; + + if (npc->flag & 2) + npc->ym = 0x200; + if (npc->flag & 8) + npc->ym = -0x200; + + if (npc->shock) + npc->y += npc->ym / 2; + else + npc->y += npc->ym; + + if (gMC.y > npc->tgt_y + (240 * 0x200) || gMC.y < npc->tgt_y - (240 * 0x200)) + npc->act_no = 40; + } + + npc->rect = rect[npc->ani_no]; +} + +// Night Spirit projectile +void ActNpc214(NPCHAR *npc) +{ + RECT rect[3] = { + {144, 48, 176, 64}, + {176, 48, 208, 64}, + {208, 48, 240, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 1: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->xm -= 25; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->xm < 0) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->flag & 0xFF) + { + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 4); + PlaySoundObject(28, SOUND_MODE_PLAY); + npc->cond = 0; + } + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Sandcroc (Outer Wall) +void ActNpc215(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->ani_no = 0; + npc->act_no = 1; + npc->act_wait = 0; + npc->tgt_y = npc->y; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + npc->bits &= ~NPC_SOLID_SOFT; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + // Fallthrough + case 1: + if (gMC.x > npc->x - (12 * 0x200) && gMC.x < npc->x + (12 * 0x200) && gMC.y > npc->y && gMC.y < npc->y + (8 * 0x200)) + { + npc->act_no = 15; + npc->act_wait = 0; + } + + break; + + case 15: + if (++npc->act_wait > 10) + { + PlaySoundObject(102, SOUND_MODE_PLAY); + npc->act_no = 20; + } + + break; + + case 20: + if (++npc->ani_wait > 3) + { + ++npc->ani_no; + npc->ani_wait = 0; + } + + if (npc->ani_no == 3) + npc->damage = 15; + + if (npc->ani_no == 4) + { + npc->bits |= NPC_SHOOTABLE; + npc->act_no = 30; + npc->act_wait = 0; + } + + break; + + case 30: + npc->bits |= NPC_SOLID_SOFT; + npc->damage = 0; + ++npc->act_wait; + + if (npc->shock) + { + npc->act_no = 40; + npc->act_wait = 0; + } + + break; + + case 40: + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->y += 1 * 0x200; + + if (++npc->act_wait == 32) + { + npc->bits &= ~NPC_SOLID_SOFT; + npc->bits &= ~NPC_SHOOTABLE; + npc->act_no = 50; + npc->act_wait = 0; + } + + break; + + case 50: + if (npc->act_wait < 100) + { + ++npc->act_wait; + } + else + { + npc->y = npc->tgt_y; + npc->ani_no = 0; + npc->act_no = 0; + } + + break; + } + + RECT rect[5] = { + {0, 0, 0, 0}, + {0, 96, 48, 128}, + {48, 96, 96, 128}, + {96, 96, 144, 128}, + {144, 96, 192, 128}, + }; + + npc->rect = rect[npc->ani_no]; +} + +// Debug Cat +void ActNpc216(NPCHAR *npc) +{ + RECT rect = {256, 192, 272, 216}; + + npc->rect = rect; +} + +// Itoh +void ActNpc217(NPCHAR *npc) +{ + RECT rect[8] = { + {144, 64, 160, 80}, + {160, 64, 176, 80}, + {176, 64, 192, 80}, + {192, 64, 208, 80}, + {144, 80, 160, 96}, + {160, 80, 176, 96}, + {144, 80, 160, 96}, + {176, 80, 192, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->ani_no = 2; + npc->xm = 0; + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 2; + npc->xm += 0x200; + npc->ym -= 0x400; + break; + + case 21: + if (npc->flag & 8) + { + npc->ani_no = 3; + npc->act_no = 30; + npc->act_wait = 0; + npc->xm = 0; + npc->tgt_x = npc->x; + } + + break; + + case 30: + npc->ani_no = 3; + + if (++npc->act_wait / 2 % 2) + npc->x = npc->tgt_x + (1 * 0x200); + else + npc->x = npc->tgt_x; + + break; + + case 40: + npc->act_no = 41; + npc->ym = -0x200; + npc->ani_no = 2; + // Fallthrough + case 41: + if (npc->flag & 8) + { + npc->act_no = 42; + npc->ani_no = 4; + } + + break; + + case 42: + npc->xm = 0; + npc->ani_no = 4; + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 0; + // Fallthrough + case 51: + if (++npc->act_wait > 32) + npc->act_no = 42; + + npc->xm = 0x200; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 4; + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rect[npc->ani_no]; +} + +// Core giant energy ball projectile +void ActNpc218(NPCHAR *npc) +{ + RECT rc[2] = { + {256, 120, 288, 152}, + {288, 120, 320, 152}, + }; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->act_wait > 200) + npc->cond = 0; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Smoke generator +void ActNpc219(NPCHAR *npc) +{ + RECT rc = {0, 0, 0, 0}; + + if (npc->direct == 0) + { + if (Random(0, 40) == 1) + SetNpChar(4, npc->x + (Random(-20, 20) * 0x200), npc->y, 0, -0x200, 0, NULL, 0x100); + } + else + { + SetNpChar(199, npc->x + (Random(-0xA0, 0xA0) * 0x200), npc->y + (Random(-0x80, 0x80) * 0x200), 0, 0, 2, NULL, 0x100); + } + + npc->rect = rc; +} diff --git a/src/NpcAct220.cpp b/src/NpcAct220.cpp new file mode 100644 index 0000000..c03e841 --- /dev/null +++ b/src/NpcAct220.cpp @@ -0,0 +1,1314 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Game.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Shovel Brigade +void ActNpc220(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 64, 16, 80}, + {16, 64, 32, 80}, + }; + + RECT rcRight[2] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Shovel Brigade (walking) +void ActNpc221(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {0, 64, 16, 80}, + {16, 64, 32, 80}, + {32, 64, 48, 80}, + {0, 64, 16, 80}, + {48, 64, 64, 80}, + {0, 64, 16, 80}, + }; + + RECT rcRight[6] = { + {0, 80, 16, 96}, + {16, 80, 32, 96}, + {32, 80, 48, 96}, + {0, 80, 16, 96}, + {48, 80, 64, 96}, + {0, 80, 16, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 60) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (Random(0, 60) == 1) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = Random(0, 16); + npc->ani_no = 2; + npc->ani_wait = 0; + + if (Random(0, 9) % 2) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 11: + if (npc->direct == 0 && npc->flag & 1) + npc->direct = 2; + else if (npc->direct == 2 && npc->flag & 4) + npc->direct = 0; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (++npc->act_wait > 32) + npc->act_no = 0; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Prison bars +void ActNpc222(NPCHAR *npc) +{ + RECT rc = {96, 168, 112, 200}; + + if (npc->act_no == 0) + { + ++npc->act_no; + npc->y -= 8 * 0x200; + } + + npc->rect = rc; +} + +// Momorin +void ActNpc223(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {80, 192, 96, 216}, + {96, 192, 112, 216}, + {112, 192, 128, 216}, + }; + + RECT rcRight[3] = { + {80, 216, 96, 240}, + {96, 216, 112, 240}, + {112, 216, 128, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 3: + npc->ani_no = 2; + break; + } + + if (npc->act_no < 2 && gMC.y < npc->y + (16 * 0x200) && gMC.y > npc->y - (16 * 0x200)) + { + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Chie +void ActNpc224(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {112, 32, 128, 48}, + {128, 32, 144, 48}, + }; + + RECT rcRight[2] = { + {112, 48, 128, 64}, + {128, 48, 144, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->act_no < 2 && gMC.y < npc->y + (16 * 0x200) && gMC.y > npc->y - (16 * 0x200)) + { + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Megane +void ActNpc225(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {64, 64, 80, 80}, + {80, 64, 96, 80}, + }; + + RECT rcRight[2] = { + {64, 80, 80, 96}, + {80, 80, 96, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Kanpachi +void ActNpc226(NPCHAR *npc) +{ + RECT rcRight[7] = { + {256, 56, 272, 80}, + {272, 56, 288, 80}, + {288, 56, 304, 80}, + {256, 56, 272, 80}, + {304, 56, 320, 80}, + {256, 56, 272, 80}, + {240, 56, 256, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 60) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 11: + npc->xm = 0x200; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + ++npc->act_wait; + + break; + + case 20: + npc->xm = 0; + npc->ani_no = 6; + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rcRight[npc->ani_no]; +} + +// Bucket +void ActNpc227(NPCHAR *npc) +{ + RECT rc = {208, 32, 224, 48}; + npc->rect = rc; +} + +// Droll (guard) +void ActNpc228(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {0, 0, 32, 40}, + {32, 0, 64, 40}, + {64, 0, 96, 40}, + {96, 0, 128, 40}, + }; + + RECT rcRight[4] = { + {0, 40, 32, 80}, + {32, 40, 64, 80}, + {64, 40, 96, 80}, + {96, 40, 128, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + // Fallthrough + case 1: + npc->xm = 0; + npc->act_no = 2; + npc->ani_no = 0; + // Fallthrough + case 2: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 50) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 2; + npc->act_wait = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 10) + { + npc->act_no = 12; + npc->ani_no = 3; + npc->ym = -0x600; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + } + + break; + + case 12: + if (npc->flag & 8) + { + npc->ani_no = 2; + npc->act_no = 13; + npc->act_wait = 0; + } + + break; + + case 13: + npc->xm /= 2; + + if (++npc->act_wait > 10) + npc->act_no = 1; + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Red Flowers (sprouts) +void ActNpc229(NPCHAR *npc) +{ + RECT rc[2] = { + {0, 96, 48, 112}, + {0, 112, 48, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 16 * 0x200; + break; + } + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Red Flowers (blooming) +void ActNpc230(NPCHAR *npc) +{ + RECT rc[2] = { + {48, 96, 96, 128}, + {96, 96, 144, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->x -= 16 * 0x200; + npc->y -= 16 * 0x200; + break; + } + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Rocket +void ActNpc231(NPCHAR *npc) +{ + int i; + + RECT rc[2] = { + {176, 32, 208, 48}, + {176, 48, 208, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + // Fallthrough + case 11: + ++npc->act_wait; + npc->ym += 8; + + if (npc->flag & 8) + { + if (npc->act_wait < 10) + npc->act_no = 12; + else + npc->act_no = 1; + } + + break; + + case 12: + npc->bits &= ~NPC_INTERACTABLE; + npc->act_no = 13; + npc->act_wait = 0; + npc->ani_no = 1; + + for (i = 0; i < 10; ++i) + { + SetNpChar(4, npc->x + (Random(-16, 16) * 0x200), npc->y + (Random(-8, 8) * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(12, SOUND_MODE_PLAY); // Wait, it does this in a loop? + } + // Fallthrough + case 13: + npc->ym -= 8; + + ++npc->act_wait; + + if (npc->act_wait % 2 == 0) + SetCaret(npc->x - (10 * 0x200), npc->y + (8 * 0x200), CARET_EXHAUST, DIR_DOWN); + if (npc->act_wait % 2 == 1) + SetCaret(npc->x + (10 * 0x200), npc->y + (8 * 0x200), CARET_EXHAUST, DIR_DOWN); + + if (npc->act_wait % 4 == 1) + PlaySoundObject(34, SOUND_MODE_PLAY); + + if (npc->flag & 2 || gMC.flag & 2 || npc->act_wait > 450) + { + if (npc->flag & 2 || gMC.flag & 2) + npc->ym = 0; + + npc->act_no = 15; + + for (i = 0; i < 6; ++i) + { + SetNpChar(4, npc->x + (Random(-16, 16) * 0x200), npc->y + (Random(-8, 8) * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(12, SOUND_MODE_PLAY); // Here it does it again... + } + } + + break; + + case 15: + npc->ym += 8; + ++npc->act_wait; + + if (npc->ym < 0) + { + if (npc->act_wait % 8 == 0) + SetCaret(npc->x - (10 * 0x200), npc->y + (8 * 0x200), CARET_EXHAUST, DIR_DOWN); + + if (npc->act_wait % 8 == 4) + SetCaret(npc->x + (10 * 0x200), npc->y + (8 * 0x200), CARET_EXHAUST, DIR_DOWN); + + if (npc->act_wait % 16 == 1) + PlaySoundObject(34, SOUND_MODE_PLAY); + } + + if (npc->flag & 8) + { + npc->bits |= NPC_INTERACTABLE; + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Orangebell +void ActNpc232(NPCHAR *npc) +{ + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->ym = 0x200; + + for (i = 0; i < 8; ++i) + SetNpChar(233, npc->x, npc->y, 0, 0, npc->direct, npc, 0x100); + // Fallthrough + case 1: + if (npc->xm < 0 && npc->flag & 1) + npc->direct = 2; + if (npc->xm > 0 && npc->flag & 4) + npc->direct = 0; + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + break; + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rcLeft[3] = { + {128, 0, 160, 32}, + {160, 0, 192, 32}, + {192, 0, 224, 32}, + }; + + RECT rcRight[3] = { + {128, 32, 160, 64}, + {160, 32, 192, 64}, + {192, 32, 224, 64}, + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Orangebell bat +void ActNpc233(NPCHAR *npc) +{ + unsigned char deg; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + deg = Random(0, 0xFF); + npc->xm = GetCos(deg); + deg = Random(0, 0xFF); + npc->ym = GetSin(deg); + + npc->count1 = 120; + npc->count2 = Random(-0x20, 0x20) * 0x200; + // Fallthrough + case 1: + if (npc->pNpc->code_char == 232) + { + npc->tgt_x = npc->pNpc->x; + npc->tgt_y = npc->pNpc->y; + npc->direct = npc->pNpc->direct; + } + + if (npc->tgt_x < npc->x) + npc->xm -= 8; + if (npc->tgt_x > npc->x) + npc->xm += 8; + + if (npc->tgt_y + npc->count2 < npc->y) + npc->ym -= 0x20; + if (npc->tgt_y + npc->count2 > npc->y) + npc->ym += 0x20; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x400) + npc->ym = 0x400; + if (npc->ym < -0x400) + npc->ym = -0x400; + + if (npc->count1 < 120) + { + ++npc->count1; + break; + } + + if (npc->x - (8 * 0x200) < gMC.x && npc->x + (8 * 0x200) > gMC.x && npc->y < gMC.y && npc->y + (176 * 0x200) > gMC.y) + { + npc->xm /= 4; + npc->ym = 0; + npc->act_no = 3; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + } + + break; + + case 3: + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->flag & 8) + { + npc->ym = 0; + npc->xm *= 2; + npc->count1 = 0; + npc->act_no = 1; + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rcLeft[4] = { + {256, 0, 272, 16}, + {272, 0, 288, 16}, + {288, 0, 304, 16}, + {304, 0, 320, 16}, + }; + + RECT rcRight[4] = { + {256, 16, 272, 32}, + {272, 16, 288, 32}, + {288, 16, 304, 32}, + {304, 16, 320, 32}, + }; + + if (npc->act_no == 3) + { + npc->ani_no = 3; + } + else + { + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Red Flowers (picked) +void ActNpc234(NPCHAR *npc) +{ + RECT rc[2] = { + {144, 96, 192, 112}, + {144, 112, 192, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 16 * 0x200; + break; + } + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Midorin +void ActNpc235(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {192, 96, 208, 112}, + {208, 96, 224, 112}, + {224, 96, 240, 112}, + {192, 96, 208, 112}, + }; + + RECT rcRight[4] = { + {192, 112, 208, 128}, + {208, 112, 224, 128}, + {224, 112, 240, 128}, + {192, 112, 208, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 30) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (Random(0, 30) == 1) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = Random(0, 16); + npc->ani_no = 2; + npc->ani_wait = 0; + + if (Random(0, 9) % 2) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 11: + if (npc->direct == 0 && npc->flag & 1) + npc->direct = 2; + else if (npc->direct == 2 && npc->flag & 4) + npc->direct = 0; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + if (++npc->act_wait > 64) + npc->act_no = 0; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->ani_no == 2) + npc->hit.top = 5 * 0x200; + else + npc->hit.top = 4 * 0x200; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Gunfish +void ActNpc236(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {128, 64, 152, 88}, + {152, 64, 176, 88}, + {176, 64, 200, 88}, + {200, 64, 224, 88}, + {224, 64, 248, 88}, + {248, 64, 272, 88}, + }; + + RECT rcRight[6] = { + {128, 88, 152, 112}, + {152, 88, 176, 112}, + {176, 88, 200, 112}, + {200, 88, 224, 112}, + {224, 88, 248, 112}, + {248, 88, 272, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(0, 50); + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->ym = 0; + // Fallthrough + case 1: + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->ym = 0x200; + npc->act_no = 2; + } + + break; + + case 2: + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + if (gMC.x < npc->x + (128 * 0x200) && gMC.x > npc->x - (128 * 0x200) && gMC.y < npc->y + (32 * 0x200) && gMC.y > npc->y - (160 * 0x200)) + ++npc->act_wait; + + if (npc->act_wait > 80) + { + npc->act_no = 10; + npc->act_wait = 0; + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + + case 10: + if (++npc->act_wait > 20) + { + npc->act_wait = 0; + npc->act_no = 20; + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + break; + + case 20: + if (++npc->act_wait > 60) + { + npc->act_wait = 0; + npc->act_no = 2; + } + + if (npc->act_wait % 10 == 3) + { + PlaySoundObject(39, SOUND_MODE_PLAY); + + if (npc->direct == 0) + SetNpChar(237, npc->x - (8 * 0x200), npc->y - (8 * 0x200), -0x400, -0x400, 0, NULL, 0x100); + else + SetNpChar(237, npc->x + (8 * 0x200), npc->y - (8 * 0x200), 0x400, -0x400, 0, NULL, 0x100); + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 4; + + break; + } + + if (npc->y < npc->tgt_y) + npc->ym += 0x10; + else + npc->ym -= 0x10; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Gunfish projectile +void ActNpc237(NPCHAR *npc) +{ + RECT rc = {312, 32, 320, 40}; + + int i; + BOOL bHit; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + bHit = FALSE; + + ++npc->act_wait; + + if (npc->flag & 0xFF) + bHit = TRUE; + + if (npc->act_wait > 10 && npc->flag & 0x100) + bHit = TRUE; + + if (bHit) + { + for (i = 0; i < 5; ++i) + SetCaret(npc->x, npc->y, CARET_BUBBLE, DIR_LEFT); + + PlaySoundObject(21, SOUND_MODE_PLAY); + npc->cond = 0; + return; + } + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rc; +} + +// Press (sideways) +void ActNpc238(NPCHAR *npc) +{ + int i; + + RECT rc[3] = { + {184, 200, 208, 216}, + {208, 200, 232, 216}, + {232, 200, 256, 216}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->view.front = 16 * 0x200; + npc->view.back = 8 * 0x200; + // Fallthrough + case 1: + if (npc->direct == 0 && gMC.x < npc->x && gMC.x > npc->x - (192 * 0x200) && gMC.y > npc->y - (4 * 0x200) && gMC.y < npc->y + (8 * 0x200)) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 2; + } + + if (npc->direct == 2 && gMC.x > npc->x && gMC.x < npc->x + (192 * 0x200) && gMC.y > npc->y - (4 * 0x200) && gMC.y < npc->y + (8 * 0x200)) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 2; + } + + break; + + case 10: + npc->damage = 0x7F; + + if (npc->direct == 0) + npc->x -= 6 * 0x200; + else + npc->x += 6 * 0x200; + + if (++npc->act_wait == 8) + { + npc->act_no = 20; + npc->act_wait = 0; + + for (i = 0; i < 4; ++i) + { + SetNpChar(4, npc->x + (Random(-16, 16) * 0x200), npc->y + (Random(-8, 8) * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(12, SOUND_MODE_PLAY); + } + } + + break; + + case 20: + npc->damage = 0; + + if (++npc->act_wait > 50) + { + npc->act_wait = 0; + npc->act_no = 30; + } + + break; + + case 30: + npc->damage = 0; + npc->ani_no = 1; + + if (++npc->act_wait == 12) + { + npc->act_no = 1; + npc->act_wait = 0; + npc->ani_no = 0; + } + + if (npc->direct == 0) + npc->x += 4 * 0x200; + else + npc->x -= 4 * 0x200; + + break; + } + + if (npc->direct == 0 && gMC.x < npc->x) + npc->hit.back = 16 * 0x200; + else if (npc->direct == 2 && gMC.x > npc->x) + npc->hit.back = 16 * 0x200; + else + npc->hit.back = 8 * 0x200; + + npc->rect = rc[npc->ani_no]; +} + +// Cage bars +void ActNpc239(NPCHAR *npc) +{ + RECT rcLeft = {192, 48, 256, 80}; + RECT rcRight = {96, 112, 144, 144}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + { + npc->x += 8 * 0x200; + npc->y += 16 * 0x200; + } + else + { + npc->view.front = 24 * 0x200; + npc->view.back = 24 * 0x200; + npc->view.top = 8 * 0x200; + npc->view.back = 24 * 0x200; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft; + else + npc->rect = rcRight; +} diff --git a/src/NpcAct240.cpp b/src/NpcAct240.cpp new file mode 100644 index 0000000..81f2414 --- /dev/null +++ b/src/NpcAct240.cpp @@ -0,0 +1,1460 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Mimiga (jailed) +void ActNpc240(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {160, 64, 176, 80}, + {176, 64, 192, 80}, + {192, 64, 208, 80}, + {160, 64, 176, 80}, + {208, 64, 224, 80}, + {160, 64, 176, 80}, + }; + + RECT rcRight[6] = { + {160, 80, 176, 96}, + {176, 80, 192, 96}, + {192, 80, 208, 96}, + {160, 80, 176, 96}, + {208, 80, 224, 96}, + {160, 80, 176, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 60) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (Random(0, 60) == 1) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = Random(0, 16); + npc->ani_no = 2; + npc->ani_wait = 0; + + if (Random(0, 9) % 2) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 11: + if (npc->direct == 0 && npc->flag & 1) + npc->direct = 2; + else if (npc->direct == 2 && npc->flag & 4) + npc->direct = 0; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + if (++npc->act_wait > 32) + npc->act_no = 0; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Critter (Last Cave) +void ActNpc241(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + }; + + RECT rcRight[3] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->y += 3 * 0x200; + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->act_wait >= 8 && npc->x - (144 * 0x200) < gMC.x && npc->x + (144 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (80 * 0x200) > gMC.y) + { + npc->ani_no = 1; + } + else + { + if (npc->act_wait < 8) + ++npc->act_wait; + + npc->ani_no = 0; + } + + if (npc->shock) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + if (npc->act_wait >= 8 && npc->x - (96 * 0x200) < gMC.x && npc->x + (96 * 0x200) > gMC.x && npc->y - (80 * 0x200) < gMC.y && npc->y + (96 * 0x200) > gMC.y) + { + npc->act_no = 2; + npc->ani_no = 0; + npc->act_wait = 0; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 3; + npc->ani_no = 2; + npc->ym = -0x5FF; + PlaySoundObject(30, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + } + + break; + + case 3: + if (npc->flag & 8) + { + npc->xm = 0; + npc->act_wait = 0; + npc->ani_no = 0; + npc->act_no = 1; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + } + + npc->ym += 0x55; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Bat (Last Cave) +void ActNpc242(NPCHAR *npc) +{ + if (npc->x < 0 || npc->x > gMap.width * 0x10 * 0x200) + { + VanishNpChar(npc); + return; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->act_wait = Random(0, 50); + // Fallthrough + case 1: + if (npc->act_wait != 0) + { + --npc->act_wait; + break; + } + + npc->act_no = 2; + npc->ym = 0x400; + // Fallthrough + case 2: + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->ym > 0x300) + npc->ym = 0x300; + if (npc->ym < -0x300) + npc->ym = -0x300; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rect_left[4] = { + {32, 32, 48, 48}, + {48, 32, 64, 48}, + {64, 32, 80, 48}, + {80, 32, 96, 48}, + }; + + RECT rect_right[4] = { + {32, 48, 48, 64}, + {48, 48, 64, 64}, + {64, 48, 80, 64}, + {80, 48, 96, 64}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (npc->direct == 0) + npc->rect = rect_left[npc->ani_no]; + else + npc->rect = rect_right[npc->ani_no]; +} + +// Bat generator (Last Cave) +void ActNpc243(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(0, 500); + // Fallthrough + case 1: + if (npc->act_wait != 0) + { + --npc->act_wait; + } + else + { + npc->act_no = 0; + SetNpChar(242, npc->x, npc->y + (Random(-0x20, 0x20) * 0x200), 0, 0, npc->direct, NULL, 0x100); + } + + break; + } +} + +// Lava drop +void ActNpc244(NPCHAR *npc) +{ + RECT rc = {96, 0, 104, 16}; + BOOL bHit; + + int i; + + npc->ym += 0x40; + + bHit = FALSE; + + if (npc->flag & 0xFF) + bHit = TRUE; + + if (npc->act_wait > 10 && npc->flag & 0x100) + bHit = TRUE; + + if (bHit) + { + for (i = 0; i < 3; ++i) + SetCaret(npc->x, npc->y + (4 * 0x200), CARET_BUBBLE, DIR_RIGHT); + + if (npc->x > gMC.x - (256 * 0x200) && npc->x < gMC.x + (256 * 0x200) && npc->y > gMC.y - (160 * 0x200) && npc->y < gMC.y + (160 * 0x200)) + PlaySoundObject(21, SOUND_MODE_PLAY); + + npc->cond = 0; + } + else + { + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + npc->rect = rc; + } +} + +// Lava drop generator +void ActNpc245(NPCHAR *npc) +{ + RECT rc[4] = { + {0, 0, 0, 0}, + {104, 0, 112, 16}, + {112, 0, 120, 16}, + {120, 0, 128, 16}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->act_wait = npc->code_event; + // Fallthrough + case 1: + npc->ani_no = 0; + + if (npc->act_wait != 0) + { + --npc->act_wait; + return; + } + + npc->act_no = 10; + npc->ani_wait = 0; + break; + + case 10: + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + { + npc->ani_no = 0; + npc->act_no = 1; + npc->act_wait = npc->code_flag; + SetNpChar(244, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + } + + break; + } + + if (npc->ani_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + 0x200; + + npc->rect = rc[npc->ani_no]; +} + +// Press (proximity) +void ActNpc246(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {144, 112, 160, 136}, + {160, 112, 176, 136}, + {176, 112, 192, 136}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 4 * 0x200; + // Fallthrough + case 1: + if (gMC.x < npc->x + (8 * 0x200) && gMC.x > npc->x - (8 * 0x200) && gMC.y > npc->y + (8 * 0x200) && gMC.y < npc->y + (128 * 0x200)) + npc->act_no = 5; + + break; + + case 5: + if (npc->flag & 8) + { + // Another place where this blank space is needed for ASM-accuracy. + // Chances are there used to be commented-out code here. + } + else + { + npc->act_no = 10; + npc->ani_wait = 0; + npc->ani_no = 1; + } + + break; + + case 10: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 2; + + if (gMC.y > npc->y) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->damage = 0x7F; + } + else + { + npc->bits |= NPC_SOLID_HARD; + npc->damage = 0; + } + + if (npc->flag & 8) + { + if (npc->ani_no > 1) + { + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x, npc->y, Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(10); + } + + npc->act_no = 20; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->bits |= NPC_SOLID_HARD; + npc->damage = 0; + } + + break; + } + + if (npc->act_no >= 5) + { + npc->ym += 0x80; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Misery (boss) +void ActNpc247(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + RECT rcLeft[9] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + {32, 0, 48, 16}, + {48, 0, 64, 16}, + {64, 0, 80, 16}, + {80, 0, 96, 16}, + {96, 0, 112, 16}, + {0, 0, 0, 0}, + {112, 0, 128, 16}, + }; + + RECT rcRight[9] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + {48, 16, 64, 32}, + {64, 16, 80, 32}, + {80, 16, 96, 32}, + {96, 16, 112, 32}, + {0, 0, 0, 0}, + {112, 16, 128, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 6 * 0x200; + npc->tgt_y = 64 * 0x200; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 20: + npc->xm = 0; + npc->ym += 0x40; + + if (npc->flag & 8) + { + npc->act_no = 21; + npc->ani_no = 2; + } + + break; + + case 21: + if (Random(0, 120) == 10) + { + npc->act_no = 22; + npc->act_wait = 0; + npc->ani_no = 3; + } + + break; + + case 22: + if (++npc->act_wait > 8) + { + npc->act_no = 21; + npc->ani_no = 2; + } + + break; + + case 100: + npc->act_no = 101; + npc->act_wait = 0; + npc->ani_no = 0; + npc->xm = 0; + npc->bits |= NPC_SHOOTABLE; + npc->count2 = npc->life; + // Fallthrough + case 101: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->y < npc->tgt_y) + npc->ym += 0x20; + else + npc->ym -= 0x20; + + if (npc->ym < -0x200) + npc->ym = -0x200; + if (npc->ym > 0x200) + npc->ym = 0x200; + + if (++npc->act_wait > 200 || npc->life <= npc->count2 - 80) + { + npc->act_wait = 0; + npc->act_no = 110; + } + + break; + + case 110: + npc->act_no = 111; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + npc->bits &= ~NPC_SHOOTABLE; + // Fallthrough + case 111: + if (++npc->act_wait % 2) + npc->ani_no = 5; + else + npc->ani_no = 6; + + if (npc->act_wait > 30) + { + npc->act_wait = 0; + + if (++npc->count1 % 3 == 0) + npc->act_no = 113; + else + npc->act_no = 112; + + npc->ani_no = 4; + } + + break; + + case 112: + if (++npc->act_wait % 6 == 0) + { + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-4, 4); + ym = GetSin(deg) * 4; + xm = GetCos(deg) * 4; + + SetNpChar(248, npc->x, npc->y + (4 * 0x200), xm, ym, 0, NULL, 0x100); + PlaySoundObject(34, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 30) + { + npc->act_wait = 0; + npc->act_no = 150; + } + + break; + + case 113: + if (++npc->act_wait == 10) + { + ym = gMC.y - (64 * 0x200); + SetNpChar(279, gMC.x, ym, 0, 0, 1, NULL, 0x100); + } + + if (npc->act_wait > 30) + { + npc->act_wait = 0; + npc->act_no = 150; + } + + break; + + case 150: + npc->act_no = 151; + npc->act_wait = 0; + npc->ani_no = 7; + + SetNpChar(249, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(249, npc->x, npc->y, 0, 0, 2, NULL, 0x100); + + npc->tgt_x = Random(9, 31) * 0x200 * 0x10; + npc->tgt_y = Random(5, 7) * 0x200 * 0x10; + + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 151: + if (++npc->act_wait == 42) + { + SetNpChar(249, npc->tgt_x + (16 * 0x200), npc->tgt_y, 0, 0, 0, NULL, 0x100); + SetNpChar(249, npc->tgt_x - (16 * 0x200), npc->tgt_y, 0, 0, 2, NULL, 0x100); + } + + if (npc->act_wait > 50) + { + npc->act_wait = 0; + npc->ym = -0x200; + npc->bits |= NPC_SHOOTABLE; + npc->x = npc->tgt_x; + npc->y = npc->tgt_y; + + if (npc->life < 340) + { + SetNpChar(252, 0, 0, 0, 0, 0, npc, 0x100); + SetNpChar(252, 0, 0, 0, 0, 0x80, npc, 0x100); + } + + if (npc->life < 180) + { + SetNpChar(252, 0, 0, 0, 0, 0x40, npc, 0x100); + SetNpChar(252, 0, 0, 0, 0, 0xC0, npc, 0x100); + } + + if (gMC.x < npc->x - (112 * 0x200) || gMC.x > npc->x + (112 * 0x200)) + npc->act_no = 160; + else + npc->act_no = 100; + } + + break; + + case 160: + npc->act_no = 161; + npc->act_wait = 0; + npc->ani_no = 4; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 161: + if (npc->y < npc->tgt_y) + npc->ym += 0x20; + else + npc->ym -= 0x20; + + if (npc->ym < -0x200) + npc->ym = -0x200; + if (npc->ym > 0x200) + npc->ym = 0x200; + + if (++npc->act_wait % 24 == 0) + { + SetNpChar(250, npc->x, npc->y + (4 * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(34, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 72) + { + npc->act_wait = 0; + npc->act_no = 100; + } + + break; + + case 1000: + npc->bits &= ~NPC_SHOOTABLE; + npc->act_no = 1001; + npc->act_wait = 0; + npc->ani_no = 4; + + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + + npc->xm = 0; + npc->ym = 0; + + DeleteNpCharCode(252, TRUE); + + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + // Fallthrough + case 1001: + if (++npc->act_wait / 2 % 2) + npc->x = npc->tgt_x + (1 * 0x200); + else + npc->x = npc->tgt_x; + + break; + + case 1010: + npc->ym += 0x10; + + if (npc->flag & 8) + { + npc->act_no = 1020; + npc->ani_no = 8; + } + + break; + } + + if (npc->xm < -0x200) + npc->xm = -0x200; + if (npc->xm > 0x200) + npc->xm = 0x200; + + if (npc->ym < -0x400) + npc->ym = -0x400; + if (npc->ym > 0x400) + npc->ym = 0x400; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Boss Misery (vanishing) +void ActNpc248(NPCHAR *npc) +{ + if (npc->flag & 0xFF) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + + npc->y += npc->ym; + npc->x += npc->xm; + + RECT rect_left[3] = { + {0, 48, 16, 64}, + {16, 48, 32, 64}, + {32, 48, 48, 64}, + }; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 2) + npc->ani_no = 0; + } + + npc->rect = rect_left[npc->ani_no]; + + if (++npc->count1 > 300) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } +} + +// Boss Misery energy shot +void ActNpc249(NPCHAR *npc) +{ + RECT rc[2] = { + {48, 48, 64, 64}, + {64, 48, 80, 64}, + }; + + if (++npc->act_wait > 8) + npc->cond = 0; + + if (npc->direct == 0) + { + npc->rect = rc[0]; + npc->x -= 2 * 0x200; + } + else + { + npc->rect = rc[1]; + npc->x += 2 * 0x200; + } +} + +// Boss Misery lightning ball +void ActNpc250(NPCHAR *npc) +{ + RECT rc[3] = { + {0, 32, 16, 48}, + {16, 32, 32, 48}, + {32, 32, 48, 48}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_y = npc->y; + npc->xm = 0; + npc->ym = -0x200; + // Fallthrough + case 1: + if (npc->x < gMC.x) + npc->xm += 0x10; + else + npc->xm -= 0x10; + + if (npc->y < npc->tgt_y) + npc->ym += 0x20; + else + npc->ym -= 0x20; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (gMC.x > npc->x - (8 * 0x200) && gMC.x < npc->x + (8 * 0x200) && gMC.y > npc->y) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 10) + { + SetNpChar(251, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + PlaySoundObject(101, SOUND_MODE_PLAY); + npc->cond = 0; + return; + } + + if (npc->act_wait / 2 % 2) + npc->ani_no = 2; + else + npc->ani_no = 1; + } + + npc->rect = rc[npc->ani_no]; +} + +// Boss Misery lightning +void ActNpc251(NPCHAR *npc) +{ + RECT rc[2] = { + {80, 32, 96, 64}, + {96, 32, 112, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->ani_no > 1) + npc->ani_no = 0; + + npc->y += 8 * 0x200; + + if (npc->flag & 0xFF) + { + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 3); + npc->cond = 0; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Boss Misery bats +void ActNpc252(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {48, 32, 64, 48}, + {112, 32, 128, 48}, + {128, 32, 144, 48}, + {144, 32, 160, 48}, + }; + + RECT rcRight[4] = { + {48, 32, 64, 48}, + {112, 48, 128, 64}, + {128, 48, 144, 64}, + {144, 48, 160, 64}, + }; + + unsigned char deg; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = 0; + npc->count1 = npc->direct; + // Fallthrough + case 1: + npc->count1 += 2; + npc->count1 %= 0x100; + + deg = npc->count1; + + if (npc->act_wait < 192) + ++npc->act_wait; + + npc->x = npc->pNpc->x + (GetCos(deg) * npc->act_wait) / 4; + npc->y = npc->pNpc->y + (GetSin(deg) * npc->act_wait) / 4; + + if (npc->pNpc->act_no == 151) + { + npc->act_no = 10; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-3, 3); + npc->xm = GetCos(deg); + npc->ym = GetSin(deg); + + npc->ani_no = 1; + npc->ani_wait = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 11: + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 0xFF) + { + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + npc->cond = 0; + } + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 1; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// EXP capsule +void ActNpc253(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + if (npc->life <= 100) + { + SetExpObjects(npc->x, npc->y, npc->code_flag); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + PlaySoundObject(25, SOUND_MODE_PLAY); + npc->cond = 0; + } + + RECT rc[2] = { + {0, 64, 16, 80}, + {16, 64, 32, 80}, + }; + + npc->rect = rc[npc->ani_no]; +} + +// Helicopter +void ActNpc254(NPCHAR *npc) +{ + RECT rc[2] = { + {0, 0, 128, 64}, + {0, 64, 128, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + SetNpChar(255, npc->x + (18 * 0x200), npc->y - (57 * 0x200), 0, 0, 0, npc, 0x100); + SetNpChar(255, npc->x - (32 * 0x200), npc->y - (52 * 0x200), 0, 0, 2, npc, 0x100); + break; + + case 20: + npc->act_wait = 0; + npc->count1 = 60; + npc->act_no = 21; + break; + + case 30: + npc->act_no = 21; + SetNpChar(223, npc->x - (11 * 0x200), npc->y - (14 * 0x200), 0, 0, 0, NULL, 0x100); + break; + + case 40: + npc->act_no = 21; + SetNpChar(223, npc->x - (9 * 0x200), npc->y - (14 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(40, npc->x - (22 * 0x200), npc->y - (14 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(93, npc->x - (35 * 0x200), npc->y - (14 * 0x200), 0, 0, 0, NULL, 0x100); + break; + } + + if (npc->direct == 0) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Helicopter blades +void ActNpc255(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {128, 0, 240, 16}, + {128, 16, 240, 32}, + {128, 32, 240, 48}, + {128, 16, 240, 32}, + }; + + RECT rcRight[4] = { + {240, 0, 320, 16}, + {240, 16, 320, 32}, + {240, 32, 320, 48}, + {240, 16, 320, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + { + npc->view.front = (56 * 0x200); + npc->view.back = (56 * 0x200); + } + else + { + npc->view.front = (40 * 0x200); + npc->view.back = (40 * 0x200); + } + // Fallthrough + case 1: + if (npc->pNpc->act_no >= 20) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + // Fallthrough + case 11: + if (++npc->ani_no > 3) + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + { + npc->x = npc->pNpc->x + (18 * 0x200); + npc->y = npc->pNpc->y - (57 * 0x200); + } + else + { + npc->x = npc->pNpc->x - (32 * 0x200); + npc->y = npc->pNpc->y - (52 * 0x200); + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Doctor (facing away) +void ActNpc256(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {48, 160, 72, 192}, + {72, 160, 96, 192}, + {0, 128, 24, 160}, + {24, 128, 48, 160}, + {0, 160, 24, 192}, + {24, 160, 48, 192}, + }; + + switch (npc->act_no) + { + case 0: + gSuperXpos = 0; + npc->act_no = 1; + npc->y -= 8 * 0x200; + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 10: + npc->act_no = 11; + npc->ani_wait = 0; + npc->ani_no = 0; + npc->count1 = 0; + // Fallthrough + case 11: + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + { + npc->ani_no = 0; + ++npc->count1; + } + + if (npc->count1 > 5) + npc->act_no = 1; + + break; + + case 20: + npc->act_no = 21; + // Fallthrough + case 21: + npc->ani_no = 2; + break; + + case 40: + npc->act_no = 41; + SetNpChar(257, npc->x - (14 * 0x200), npc->y - (16 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(257, npc->x - (14 * 0x200), npc->y - (16 * 0x200), 0, 0, 2, NULL, 0xAA); + // Fallthrough + case 41: + npc->ani_no = 4; + break; + + case 50: + npc->act_no = 51; + npc->ani_wait = 0; + npc->ani_no = 4; + npc->count1 = 0; + // Fallthrough + case 51: + if (++npc->ani_wait > 5) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + { + npc->ani_no = 4; + ++npc->count1; + } + + if (npc->count1 > 5) + npc->act_no = 41; + + break; + } + + npc->rect = rcLeft[npc->ani_no]; +} + +// Red crystal +void ActNpc257(NPCHAR *npc) +{ + RECT rc[3] = { + {176, 32, 184, 48}, + {184, 32, 192, 48}, + {0, 0, 0, 0}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (gSuperXpos != 0) + npc->act_no = 10; + + break; + + case 10: + if (npc->x < gSuperXpos) + npc->xm += 0x55; + if (npc->x > gSuperXpos) + npc->xm -= 0x55; + + if (npc->y < gSuperYpos) + npc->ym += 0x55; + if (npc->y > gSuperYpos) + npc->ym -= 0x55; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x400) + npc->ym = 0x400; + if (npc->ym < -0x400) + npc->ym = -0x400; + + npc->x += npc->xm; + npc->y += npc->ym; + + break; + } + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->direct == 0 && npc->xm > 0) + npc->ani_no = 2; + if (npc->direct == 2 && npc->xm < 0) + npc->ani_no = 2; + + npc->rect = rc[npc->ani_no]; +} + +// Mimiga (sleeping) +void ActNpc258(NPCHAR *npc) +{ + RECT rc = {48, 32, 64, 48}; + npc->rect = rc; +} + +// Curly (carried and unconcious) +void ActNpc259(NPCHAR *npc) +{ + RECT rcLeft = {224, 96, 240, 112}; + RECT rcRight = {224, 112, 240, 128}; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_INTERACTABLE; + npc->act_no = 1; + // Fallthrough + case 1: + if (gMC.direct == 0) + npc->direct = 0; + else + npc->direct = 2; + + npc->y = gMC.y - (4 * 0x200); + + if (npc->direct == 0) + { + npc->x = gMC.x + (3 * 0x200); + npc->rect = rcLeft; + } + else + { + npc->x = gMC.x - (3 * 0x200); + npc->rect = rcRight; + } + + if (gMC.ani_no % 2) + ++npc->rect.top; + + break; + + case 10: + npc->act_no = 11; + npc->xm = 0x40; + npc->ym = -0x20; + + npc->rect = rcLeft; + break; + + case 11: + if (npc->y < (64 * 0x200)) + npc->ym = 0x20; + + npc->x += npc->xm; + npc->y += npc->ym; + break; + + case 20: + VanishNpChar(npc); + SetDestroyNpCharUp(npc->x, npc->y, 0x2000, 0x40); + break; + } +} diff --git a/src/NpcAct260.cpp b/src/NpcAct260.cpp new file mode 100644 index 0000000..349d465 --- /dev/null +++ b/src/NpcAct260.cpp @@ -0,0 +1,2270 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "MycParam.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Shovel Brigade (caged) +void ActNpc260(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {128, 64, 144, 80}, + {144, 64, 160, 80}, + {224, 64, 240, 80}, + }; + + RECT rcRight[3] = { + {128, 80, 144, 96}, + {144, 80, 160, 96}, + {224, 80, 240, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->x += 0x200; + npc->y -= 0x400; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 2; + SetNpChar(87, npc->x, npc->y - (16 * 0x200), 0, 0, 0, NULL, 0x100); + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Chie (caged) +void ActNpc261(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {112, 32, 128, 48}, + {128, 32, 144, 48}, + }; + + RECT rcRight[2] = { + {112, 48, 128, 64}, + {128, 48, 144, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->x -= 1 * 0x200; + npc->y -= 2 * 0x200; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Chaco (caged) +void ActNpc262(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {128, 0, 144, 16}, + {144, 0, 160, 16}, + }; + + RECT rcRight[2] = { + {128, 16, 144, 32}, + {144, 16, 160, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->x -= 1 * 0x200; + npc->y -= 2 * 0x200; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Doctor (boss) +void ActNpc263(NPCHAR *npc) +{ + int deg; + int xm, ym; + + RECT rcLeft[9] = { + {0, 0, 24, 32}, + {24, 0, 48, 32}, + {48, 0, 72, 32}, + {0, 0, 0, 0}, + {72, 0, 96, 32}, + {96, 0, 120, 32}, + {120, 0, 144, 32}, + {144, 0, 168, 32}, + {264, 0, 288, 32}, + }; + + RECT rcRight[9] = { + {0, 32, 24, 64}, + {24, 32, 48, 64}, + {48, 32, 72, 64}, + {0, 0, 0, 0}, + {72, 32, 96, 64}, + {96, 32, 120, 64}, + {120, 32, 144, 64}, + {144, 32, 168, 64}, + {264, 32, 288, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 8 * 0x200; + npc->ani_no = 3; + break; + + case 2: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 0; + else + npc->ani_no = 3; + + if (npc->act_wait > 50) + npc->act_no = 10; + + break; + + case 10: + npc->ym += 0x80; + npc->bits |= NPC_SHOOTABLE; + npc->damage = 3; + + if (npc->flag & 8) + { + npc->act_no = 20; + npc->act_wait = 0; + npc->ani_no = 0; + npc->count2 = npc->life; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 20: + if (++npc->act_wait < 50 && npc->life < npc->count2 - 20) + npc->act_wait = 50; + + if (npc->act_wait == 50) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 4; + } + + if (npc->act_wait == 80) + { + npc->ani_no = 5; + PlaySoundObject(25, SOUND_MODE_PLAY); + + if (npc->direct == 0) + { + SetNpChar(264, npc->x - (16 * 0x200), npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(264, npc->x - (16 * 0x200), npc->y, 0, 0, 0x400, NULL, 0x100); + } + else + { + SetNpChar(264, npc->x + (16 * 0x200), npc->y, 0, 0, 2, NULL, 0x100); + SetNpChar(264, npc->x + (16 * 0x200), npc->y, 0, 0, 2 + 0x400, NULL, 0x100); + } + } + + if (npc->act_wait == 120) + npc->ani_no = 0; + + if (npc->act_wait > 130 && npc->life < npc->count2 - 50) + npc->act_wait = 161; + + if (npc->act_wait > 160) + { + npc->act_no = 100; + npc->ani_no = 0; + } + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->ani_no = 6; + npc->tgt_x = npc->x; + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 31: + if (++npc->act_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + 0x200; + + if (npc->act_wait > 50) + { + npc->act_no = 32; + npc->act_wait = 0; + npc->ani_no = 7; + PlaySoundObject(101, SOUND_MODE_PLAY); + + for (deg = 8; deg < 0x100; deg += 0x10) + { + xm = GetCos(deg) * 2; + ym = GetSin(deg) * 2; + SetNpChar(266, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + } + } + + break; + + case 32: + if (++npc->act_wait > 50) + npc->act_no = 100; + + break; + + case 100: + npc->act_no = 101; + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + npc->act_wait = 0; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 101: + npc->act_wait += 2; + + if (npc->act_wait > 16) + { + npc->act_no = 102; + npc->act_wait = 0; + npc->ani_no = 3; + npc->tgt_x = Random(5, 35) * 0x200 * 0x10; + npc->tgt_y = Random(5, 7) * 0x200 * 0x10; + } + + break; + + case 102: + if (++npc->act_wait > 40) + { + npc->act_no = 103; + npc->act_wait = 16; + npc->ani_no = 2; + npc->ym = 0; + npc->x = npc->tgt_x; + npc->y = npc->tgt_y; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 103: + npc->act_wait -= 2; + + if (npc->act_wait <= 0) + { + npc->bits |= NPC_SHOOTABLE; + npc->damage = 3; + + if (npc->count1 < 3) + { + ++npc->count1; + npc->act_no = 10; + } + else + { + npc->count1 = 0; + npc->act_no = 30; + } + } + + break; + + case 500: + npc->bits &= ~NPC_SHOOTABLE; + npc->ani_no = 6; + npc->ym += 0x10; + + if (npc->flag & 8) + { + npc->act_no = 501; + npc->act_wait = 0; + npc->tgt_x = npc->x; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 501: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 8; + + if (++npc->act_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + (1 * 0x200); + + break; + } + + if (npc->act_no >= 10) + { + if (npc->act_no == 102) + { + gSuperXpos = npc->tgt_x; + gSuperYpos = npc->tgt_y; + } + else + { + gSuperXpos = npc->x; + gSuperYpos = npc->y; + } + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 101 || npc->act_no == 103) + { + npc->rect.top += npc->act_wait; + npc->rect.bottom -= npc->act_wait; + npc->view.top = (16 - npc->act_wait) * 0x200; + } + else + { + npc->view.top = 16 * 0x200; + } +} + +// Doctor red wave (projectile) +void ActNpc264(NPCHAR *npc) +{ + RECT rc = {288, 0, 304, 16}; + unsigned char deg; + + if (npc->x < 0 || npc->x > gMap.width * 0x10 * 0x200) + { + VanishNpChar(npc); + return; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->count1 = npc->direct / 8; + npc->direct %= 8; + // Fallthrough + case 1: + npc->count1 += 6; + npc->count1 %= 0x100; + deg = npc->count1; + + if (npc->act_wait < 128) + ++npc->act_wait; + + if (npc->direct == 0) + npc->xm -= 21; + else + npc->xm += 21; + + npc->tgt_x += npc->xm; + + npc->x = npc->tgt_x + (GetCos(deg) * npc->act_wait) / 2 / 4; + npc->y = npc->tgt_y + (GetSin(deg) * npc->act_wait) / 2; + + SetNpChar(265, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + + break; + } + + npc->rect = rc; +} + +// Doctor red ball projectile +void ActNpc265(NPCHAR *npc) +{ + RECT rc[3] = { + {288, 16, 304, 32}, + {288, 32, 304, 48}, + {288, 48, 304, 64}, + }; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->cond = 0; + else + npc->rect = rc[npc->ani_no]; +} + +// Doctor red ball projectile (bouncing) +void ActNpc266(NPCHAR *npc) +{ + RECT rc[2] = { + {304, 16, 320, 32}, + {304, 32, 320, 48}, + }; + + if (npc->flag & 1) + npc->xm *= -1; + if (npc->flag & 4) + npc->xm *= -1; + + if (npc->flag & 2) + npc->ym = 0x200; + if (npc->flag & 8) + npc->ym = -0x200; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; + + if (++npc->act_wait % 4 == 1) + SetNpChar(265, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + + if (npc->act_wait > 250) + VanishNpChar(npc); +} + +// Muscle Doctor +void ActNpc267(NPCHAR *npc) +{ + RECT rcLeft[10] = { + {0, 0, 0, 0}, + {0, 64, 40, 112}, + {40, 64, 80, 112}, + {80, 64, 120, 112}, + {120, 64, 160, 112}, + {160, 64, 200, 112}, + {200, 64, 240, 112}, + {240, 64, 280, 112}, + {280, 64, 320, 112}, + {0, 160, 40, 208}, + }; + + RECT rcRight[10] = { + {0, 0, 0, 0}, + {0, 112, 40, 160}, + {40, 112, 80, 160}, + {80, 112, 120, 160}, + {120, 112, 160, 160}, + {160, 112, 200, 160}, + {200, 112, 240, 160}, + {240, 112, 280, 160}, + {280, 112, 320, 160}, + {40, 160, 80, 208}, + }; + + int xm, ym; + int i; + + switch (npc->act_no) + { + case 0: + if (gSuperXpos > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->x = gSuperXpos - (6 * 0x200); + else + npc->x = gSuperXpos + (6 * 0x200); + + npc->y = gSuperYpos; + // Fallthrough + case 1: + npc->act_no = 2; + // Fallthrough + case 2: + npc->ym += 0x80; + + if (++npc->act_wait / 2 % 2) + npc->ani_no = 0; + else + npc->ani_no = 3; + + break; + + case 5: + npc->act_no = 6; + npc->ani_no = 1; + npc->ani_wait = 0; + // Fallthrough + case 6: + npc->ym += 0x80; + + if (++npc->ani_wait > 40) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + break; + + case 7: + npc->act_no = 8; + npc->act_wait = 0; + npc->ani_no = 3; + // Fallthrough + case 8: + npc->ym += 0x40; + + if (++npc->act_wait > 40) + npc->act_no = 10; + + break; + + case 10: + npc->bits |= NPC_INVULNERABLE; + npc->xm = 0; + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ani_wait = 0; + npc->count2 = npc->life; + // Fallthrough + case 11: + npc->ym += 0x80; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->flag & 8) + { + if (npc->life < npc->count2 - 20) + { + if (gMC.flag & 8 && gMC.x > npc->x - (48 * 0x200) && gMC.x < npc->x + (48 * 0x200) && npc->ani_no != 6) + { + npc->ani_no = 6; + DamageMyChar(5); + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + gMC.ym = -0x400; + + if (npc->x > gMC.x) + gMC.xm = -0x5FF; + else + gMC.xm = 0x5FF; + + for (i = 0; i < 100; ++i) + SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y + (Random(-0x10, 0x10) * 0x200), Random(-0x200, 0x200) * 3, Random(-0x200, 0x200) * 3, 3, NULL, 0xAA); + } + } + else + { + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 2) + npc->ani_no = 1; + } + } + } + else + { + npc->ani_no = 4; + } + + if (++npc->act_wait > 30 || npc->life < npc->count2 - 20) + { + if (++npc->count1 > 10) + npc->count1 = 0; + + switch (npc->count1) + { + case 8: + npc->act_no = 20; + break; + + case 2: + case 7: + npc->act_no = 100; + break; + + case 3: + case 6: + npc->act_no = 30; + break; + + case 1: + case 9: + npc->act_no = 40; + break; + + default: + npc->act_no = 15; + npc->act_wait = 0; + break; + } + } + + break; + + case 15: + npc->ani_no = 3; + ++npc->act_wait; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->act_wait > 20) + { + npc->act_no = 16; + npc->ani_no = 4; + npc->ani_wait = 0; + npc->ym = -0x600; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + } + + break; + + case 16: + npc->ym += 0x40; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 4; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->ym > 0 && npc->flag & 8) + npc->act_no = 17; + + break; + + case 17: + npc->act_no = 18; + npc->act_wait = 0; + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + // Fallthrough + case 18: + npc->ani_no = 3; + ++npc->act_wait; + + npc->xm = (npc->xm * 7) / 8; + npc->ym += 0x80; + + if (npc->act_wait > 10) + npc->act_no = 10; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + // Fallthrough + case 21: + ++npc->act_wait; + npc->ani_no = 6; + + if (npc->act_wait > 20 && npc->act_wait % 3 == 1) + { + ym = Random(-0x200, 0x200); + xm = Random(0x100, 0x200) * 4; + + if (npc->direct == 0) + SetNpChar(269, npc->x - 0x1000, npc->y - 0x800, -xm, ym, 0, NULL, 0x100); + else + SetNpChar(269, npc->x + 0x1000, npc->y - 0x800, xm, ym, 2, NULL, 0x100); + + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + if (npc->act_wait > 90) + npc->act_no = 10; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->bits |= NPC_SOLID_SOFT; + npc->bits &= ~NPC_SHOOTABLE; + // Fallthrough + case 31: + npc->ani_no = 3; + + if (++npc->act_wait > 20) + { + npc->act_no = 32; + npc->act_wait = 0; + npc->ani_no = 7; + npc->bits |= NPC_REAR_AND_TOP_DONT_HURT; + npc->damage = 10; + PlaySoundObject(25, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->xm = -0x5FF; + else + npc->xm = 0x5FF; + } + + break; + + case 32: + ++npc->act_wait; + npc->ym = 0; + + if (npc->act_wait / 2 % 2) + npc->ani_no = 7; + else + npc->ani_no = 8; + + if (npc->act_wait > 30) + { + npc->act_wait = 0; + npc->act_no = 18; + npc->damage = 5; + npc->bits &= ~(NPC_SOLID_SOFT | NPC_REAR_AND_TOP_DONT_HURT); + npc->bits |= NPC_SHOOTABLE; + } + + if (npc->flag & 1 || npc->flag & 4) + { + npc->act_no = 15; + npc->act_wait = 0; + npc->damage = 5; + npc->bits &= ~(NPC_SOLID_SOFT | NPC_REAR_AND_TOP_DONT_HURT); + npc->bits |= NPC_SHOOTABLE; + } + + break; + + case 40: + npc->ani_no = 3; + ++npc->act_wait; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->act_wait > 20) + { + npc->act_no = 41; + npc->ani_no = 4; + npc->ani_wait = 0; + npc->ym = -0x800; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + } + + break; + + case 41: + npc->ym += 0x40; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 4; + + if (gMC.y > npc->y && gMC.x > npc->x - (8 * 0x200) && gMC.x < npc->x + (8 * 0x200)) + { + npc->act_no = 16; + npc->ym = 0x5FF; + npc->xm = 0; + } + + if (npc->ym > 0 && npc->flag & 8) + npc->act_no = 17; + + break; + + case 100: + npc->act_no = 101; + npc->act_wait = 0; + npc->bits &= ~(NPC_INVULNERABLE | NPC_SHOOTABLE); + npc->damage = 0; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 101: + npc->act_wait += 2; + + if (npc->act_wait > 28) + { + npc->act_no = 102; + npc->act_wait = 0; + npc->ani_no = 0; + + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y - (32 * 0x200); + + if (npc->tgt_y < (64 * 0x200)) + npc->tgt_y = (64 * 0x200); + + if (npc->tgt_x < (64 * 0x200)) + npc->tgt_x = (64 * 0x200); + if (npc->tgt_x > (576 * 0x200)) + npc->tgt_x = (576 * 0x200); + } + + break; + + case 102: + if (++npc->act_wait > 40) + { + npc->act_no = 103; + npc->act_wait = 28; + npc->ani_no = 4; + npc->ym = 0; + npc->x = npc->tgt_x; + npc->y = npc->tgt_y; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 103: + npc->act_wait -= 2; + + if (npc->act_wait <= 0) + { + npc->bits |= (NPC_INVULNERABLE | NPC_SHOOTABLE); + npc->damage = 5; + npc->act_no = 16; + npc->ym = -0x200; + npc->xm = 0; + } + + break; + + case 500: + DeleteNpCharCode(269, TRUE); + npc->bits &= ~NPC_SHOOTABLE; + npc->ani_no = 4; + npc->ym += 0x20; + npc->xm = 0; + + if (npc->flag & 8) + { + npc->act_no = 501; + npc->act_wait = 0; + npc->tgt_x = npc->x; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 501: + npc->ani_no = 9; + + if (++npc->act_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + (1 * 0x200); + + break; + + case 510: + npc->act_no = 511; + npc->act_wait = 0; + npc->ani_no = 9; + npc->tgt_x = npc->x; + npc->y += 16 * 0x200; + npc->bits |= NPC_IGNORE_SOLIDITY; + // Fallthrough + case 511: + SetQuake(2); + + if (++npc->act_wait % 6 == 3) + PlaySoundObject(25, SOUND_MODE_PLAY); + + if (npc->act_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + (1 * 0x200); + + if (npc->act_wait > 352) + { + npc->ani_no = 0; + npc->act_no = 0x200; + } + + break; + + case 520: + npc->damage = 0; + gSuperYpos = -32 * 0x200; + break; + } + + if (npc->act_no >= 11 && npc->act_no < 501) + { + if (npc->act_no == 102) + { + gSuperXpos = npc->tgt_x; + gSuperYpos = npc->tgt_y; + } + else + { + gSuperXpos = npc->x; + gSuperYpos = npc->y; + } + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->act_no >= 512) + { + // There probably used to be some commented-out code here + } + else if (npc->act_no < 510) + { + if (npc->act_no != 102 && npc->act_no != 103 && Random(0, 3) == 2) + SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y + (Random(-8, 4) * 0x200), npc->xm, 0, 3, 0, 0x100); + } + else + { + SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - (((336 - npc->act_wait) / 8) * 0x200), Random(-0x200, 0x200), Random(-0x200, 0) * 2, 3, NULL, 0xAA); + SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - (((336 - npc->act_wait) / 8) * 0x200), Random(-0x200, 0x200), Random(-0x200, 0) * 2, 3, NULL, 0xAA); + SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - (((336 - npc->act_wait) / 8) * 0x200), 0, 2 * Random(-0x200, 0), 3, NULL, 0xAA); + SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - (((336 - npc->act_wait) / 8) * 0x200), 0, 2 * Random(-0x200, 0), 3, NULL, 0xAA); + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 511) + { + npc->rect.top += npc->act_wait / 8; + npc->view.top = (44 - (npc->act_wait / 8)) * 0x200; + npc->view.bottom = 4 * 0x200; + } + else if (npc->act_no == 101 || npc->act_no == 103) + { + npc->rect.top += npc->act_wait; + npc->rect.bottom -= npc->act_wait; + npc->view.top = (28 - npc->act_wait) * 0x200; + } + else + { + npc->view.top = 28 * 0x200; + } +} + +// Igor (enemy) +void ActNpc268(NPCHAR *npc) +{ + unsigned char deg; + int xm, ym; + + RECT rcLeft[10] = { + {0, 0, 40, 40}, + {40, 0, 80, 40}, + {80, 0, 120, 40}, + {0, 0, 40, 40}, + {120, 0, 160, 40}, + {0, 0, 40, 40}, + {40, 80, 80, 120}, + {0, 80, 40, 120}, + {240, 0, 280, 40}, + {280, 0, 320, 40}, + }; + + RECT rcRight[10] = { + {0, 40, 40, 80}, + {40, 40, 80, 80}, + {80, 40, 120, 80}, + {0, 40, 40, 80}, + {120, 40, 160, 80}, + {0, 40, 40, 80}, + {160, 80, 200, 120}, + {120, 80, 160, 120}, + {240, 40, 280, 80}, + {280, 40, 320, 80}, + }; + + if (npc->x < gMC.x - (320 * 0x200) || npc->x > gMC.x + (320 * 0x200) || npc->y < gMC.y - (240 * 0x200) || npc->y > gMC.y + (240 * 0x200)) + npc->act_no = 1; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 8 * 0x200; + // Fallthrough + case 1: + if (++npc->ani_wait > 20) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + +#ifdef FIX_BUGS + if (npc->x < gMC.x + (112 * 0x200) && npc->x > gMC.x - (112 * 0x200) && npc->y < gMC.y + (48 * 0x200) && npc->y > gMC.y - (112 * 0x200)) +#else + // Instead of checking the X and Y coordinates, this checks the X coordinates twice + if (npc->x < gMC.x + (112 * 0x200) && npc->x > gMC.x - (112 * 0x200) && npc->x < gMC.x + (48 * 0x200) && npc->x > gMC.x - (112 * 0x200)) +#endif + npc->act_no = 10; + + if (npc->shock) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ani_wait = 0; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 11: + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + if (npc->x < gMC.x + (64 * 0x200) && npc->x > gMC.x - (64 * 0x200)) + { + npc->act_no = 20; + npc->act_wait = 0; + } + + if (npc->xm < 0 && npc->flag & 1) + { + npc->act_no = 20; + npc->act_wait = 0; + } + + if (npc->xm > 0 && npc->flag & 4) + { + npc->act_no = 20; + npc->act_wait = 0; + } + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + break; + + case 20: + npc->xm = 0; + npc->ani_no = 6; + + if (++npc->act_wait > 10) + { + npc->act_no = 30; + npc->ym = -0x5FF; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + PlaySoundObject(108, SOUND_MODE_PLAY); + } + + break; + + case 30: + npc->ani_no = 7; + + if (npc->flag & 8) + { + npc->act_no = 40; + npc->act_wait = 0; + SetQuake(20); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + break; + + case 40: + npc->xm = 0; + npc->ani_no = 6; + + if (++npc->act_wait > 30) + npc->act_no = 50; + + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 0; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 51: + if (++npc->act_wait > 30 && npc->act_wait % 4 == 1) + { + if (npc->direct == 0) + deg = 0x88; + else + deg = 0xF8; + + deg += (unsigned char)Random(-0x10, 0x10); + ym = GetSin(deg) * 5; + xm = GetCos(deg) * 5; + SetNpChar(11, npc->x, npc->y + (4 * 0x200), xm, ym, 0, NULL, 0x100); + PlaySoundObject(12, SOUND_MODE_PLAY); + } + + if (npc->act_wait < 50 && npc->act_wait / 2 % 2) + npc->ani_no = 9; + else + npc->ani_no = 8; + + if (npc->act_wait > 82) + { + npc->act_no = 10; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + } + + npc->ym += 0x200 / 10; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Red Bat (bouncing) +void ActNpc269(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {232, 0, 248, 16}, + {248, 0, 264, 16}, + {248, 16, 264, 32}, + }; + + RECT rcRight[3] = { + {232, 32, 248, 48}, + {248, 32, 264, 48}, + {248, 48, 264, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->xm2 = npc->xm; + npc->ym2 = npc->ym; + // Fallthrough + case 1: + if (npc->xm2 < 0 && npc->flag & 1) + { + npc->direct = 2; + npc->xm2 *= -1; + } + else if (npc->xm2 > 0 && npc->flag & 4) + { + npc->direct = 0; + npc->xm2 *= -1; + } + else if (npc->ym2 < 0 && npc->flag & 2) + { + npc->ym2 *= -1; + } + else if (npc->ym2 > 0 && npc->flag & 8) + { + npc->ym2 *= -1; + } + + npc->x += npc->xm2; + npc->y += npc->ym2; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Doctor's blood (or """"red energy"""") +void ActNpc270(NPCHAR *npc) +{ + RECT rc[2] = { + {170, 34, 174, 38}, + {170, 42, 174, 46}, + }; + + if (npc->direct == 3 || npc->direct == 1) + { + if (npc->direct == 3) + npc->ym += 0x40; + if (npc->direct == 1) + npc->ym -= 0x40; + + ++npc->act_wait; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->act_wait > 50) + npc->cond = 0; + + if (npc->flag & 0xFF) + npc->cond = 0; + } + else if (npc->direct == 2) + { + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->bits |= NPC_IGNORE_SOLIDITY; + + npc->xm = Random(-0x200, 0x200) * 3; + npc->ym = Random(-0x200, 0x200) * 3; + + npc->count1 = Random(0x10, 0x33); + npc->count2 = Random(0x80, 0x100); + + break; + } + + if (npc->x < npc->pNpc->x) + npc->xm += 0x200 / npc->count1; + if (npc->x > npc->pNpc->x) + npc->xm -= 0x200 / npc->count1; + + if (npc->y < npc->pNpc->y) + npc->ym += 0x200 / npc->count1; + if (npc->y > npc->pNpc->y) + npc->ym -= 0x200 / npc->count1; + + if (npc->xm > npc->count2 * 2) + npc->xm = npc->count2 * 2; + if (npc->xm < -npc->count2 * 2) + npc->xm = -npc->count2 * 2; + + if (npc->ym > npc->count2 * 3) + npc->ym = npc->count2 * 3; + if (npc->ym < -npc->count2 * 3) + npc->ym = -npc->count2 * 3; + + npc->x += npc->xm; + npc->y += npc->ym; + } + + npc->rect = rc[Random(0, 1)]; +} + +// Ironhead block +void ActNpc271(NPCHAR *npc) +{ + int a; + + if (npc->xm < 0 && npc->x < -16 * 0x200) + { + VanishNpChar(npc); + return; + } + + if (npc->xm > 0 && npc->x > (gMap.width * 0x200 * 0x10) + (1 * 0x200 * 0x10)) + { + VanishNpChar(npc); + return; + } + + if (npc->act_no == 0) + { + npc->act_no = 1; + + a = Random(0, 9); + + if (a == 9) + { + npc->rect.left = 0; + npc->rect.right = 0x20; + npc->rect.top = 0x40; + npc->rect.bottom = 0x60; + + npc->view.front = 16 * 0x200; + npc->view.back = 16 * 0x200; + npc->view.top = 16 * 0x200; + npc->view.bottom = 16 * 0x200; + + npc->hit.front = 12 * 0x200; + npc->hit.back = 12 * 0x200; + npc->hit.top = 12 * 0x200; + npc->hit.bottom = 12 * 0x200; + } + else + { + npc->rect.left = ((a % 3) * 16) + (7 * 16); + npc->rect.top = (a / 3) * 16; + npc->rect.right = npc->rect.left + 16; + npc->rect.bottom = npc->rect.top + 16; + } + + if (npc->direct == 0) + npc->xm = Random(0x100, 0x200) * -2; + else + npc->xm = Random(0x100, 0x200) * 2; + + npc->ym = Random(-0x200, 0x200); + } + + if (npc->ym < 0 && npc->y - npc->hit.top < 8 * 0x200) + { + npc->ym *= -1; + SetCaret(npc->x, npc->y - (8 * 0x200), CARET_TINY_PARTICLES, DIR_LEFT); + SetCaret(npc->x, npc->y - (8 * 0x200), CARET_TINY_PARTICLES, DIR_LEFT); + } + + if (npc->ym > 0 && npc->y + npc->hit.bottom > 232 * 0x200) + { + npc->ym *= -1; + SetCaret(npc->x, npc->y + (8 * 0x200), CARET_TINY_PARTICLES, DIR_LEFT); + SetCaret(npc->x, npc->y + (8 * 0x200), CARET_TINY_PARTICLES, DIR_LEFT); + } + + npc->x += npc->xm; + npc->y += npc->ym; +} + +// Ironhead block generator +void ActNpc272(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(0, 200); + // Fallthrough + case 1: + if (npc->act_wait) + { + --npc->act_wait; + } + else + { + npc->act_no = 0; + SetNpChar(271, npc->x, npc->y + (Random(-32, 32) * 0x200), 0, 0, npc->direct, NULL, 0x100); + } + + break; + } +} + +// Droll projectile +void ActNpc273(NPCHAR *npc) +{ + RECT rc[3] = { + {248, 40, 272, 64}, + {272, 40, 296, 64}, + {296, 40, 320, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 0xFF) + { + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + VanishNpChar(npc); + return; + } + + if (++npc->act_wait % 5 == 0) + PlaySoundObject(110, SOUND_MODE_PLAY); + + if (++npc->ani_no > 2) + npc->ani_no = 0; + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Droll +void ActNpc274(NPCHAR *npc) +{ + RECT rcLeft[6] = { + {0, 0, 32, 40}, + {32, 0, 64, 40}, + {64, 0, 96, 40}, + {64, 80, 96, 120}, + {96, 80, 128, 120}, + {96, 0, 128, 40}, + }; + + RECT rcRight[6] = { + {0, 40, 32, 80}, + {32, 40, 64, 80}, + {64, 40, 96, 80}, + {64, 120, 96, 160}, + {96, 120, 128, 160}, + {96, 40, 128, 80}, + }; + + unsigned char deg; + int xm, ym; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + npc->tgt_x = npc->x; + // Fallthrough + case 1: + npc->xm = 0; + npc->act_no = 2; + npc->ani_no = 0; + // Fallthrough + case 2: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 40) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->shock) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 2; + npc->act_wait = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 10) + { + npc->act_no = 12; + npc->ani_no = 3; + npc->ym = -0x600; + npc->count1 = 0; + + if (npc->tgt_x > npc->x) + npc->xm = 0x200; + else + npc->xm = -0x200; + } + + break; + + case 12: + if (npc->ym > 0) + { + npc->ani_no = 4; + + if (npc->count1 == 0) + { + ++npc->count1; + deg = GetArktan(npc->x - gMC.x, npc->y - (10 * 0x200) - gMC.y); + ym = GetSin(deg) * 4; + xm = GetCos(deg) * 4; + SetNpChar(273, npc->x, npc->y - (10 * 0x200), xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + } + } + + if (npc->ym > 0x200) + npc->ani_no = 5; + + if (npc->flag & 8) + { + npc->ani_no = 2; + npc->act_no = 13; + npc->act_wait = 0; + npc->xm = 0; + } + + break; + + case 13: + npc->xm /= 2; + + if (++npc->act_wait > 10) + npc->act_no = 1; + + break; + } + + npc->ym += 0x55; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Puppy (plantation) +void ActNpc275(NPCHAR *npc) +{ + RECT rcRight[4] = { + {272, 80, 288, 96}, + {288, 80, 304, 96}, + {272, 80, 288, 96}, + {304, 80, 320, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (64 * 0x200) < gMC.x && npc->x + (64 * 0x200) > gMC.x && npc->y - (32 * 0x200) < gMC.y && npc->y + (16 * 0x200) > gMC.y) + { + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rcRight[npc->ani_no]; +} + +// Red Demon +void ActNpc276(NPCHAR *npc) +{ + RECT rcLeft[9] = { + {0, 64, 32, 104}, + {32, 64, 64, 104}, + {64, 64, 96, 104}, + {96, 64, 128, 104}, + {128, 64, 160, 104}, + {160, 64, 192, 104}, + {192, 64, 224, 104}, + {224, 64, 256, 104}, + {256, 64, 288, 104}, + }; + + RECT rcRight[9] = { + {0, 104, 32, 144}, + {32, 104, 64, 144}, + {64, 104, 96, 144}, + {96, 104, 128, 144}, + {128, 104, 160, 144}, + {160, 104, 192, 144}, + {192, 104, 224, 144}, + {224, 104, 256, 144}, + {256, 104, 288, 144}, + }; + + unsigned char deg; + int xm, ym; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + // Fallthrough + case 1: + npc->xm = 0; + npc->act_no = 2; + npc->ani_no = 0; + // Fallthrough + case 2: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 20) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->shock) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 3; + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 11: + switch (++npc->act_wait) + { + case 30: + case 40: + case 50: + npc->ani_no = 4; + + deg = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + ym = GetSin(deg) * 4; + xm = GetCos(deg) * 4; + + SetNpChar(277, npc->x, npc->y, xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + + break; + + case 34: + case 44: + case 54: + npc->ani_no = 3; + break; + } + + if (npc->act_wait > 60) + { + npc->act_no = 20; + npc->act_wait = 0; + npc->ani_no = 2; + } + + break; + + case 20: + if (++npc->act_wait > 20) + { + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 5; + npc->ym = -0x5FF; + + if (npc->x < gMC.x) + npc->xm = 0x100; + else + npc->xm = -0x100; + } + + break; + + case 21: + switch (++npc->act_wait) + { + case 30: + case 40: + case 50: + npc->ani_no = 6; + + deg = GetArktan(npc->x - gMC.x, npc->y - (10 * 0x200) - gMC.y); + ym = GetSin(deg) * 4; + xm = GetCos(deg) * 4; + + SetNpChar(277, npc->x, npc->y - (10 * 0x200), xm, ym, 0, NULL, 0x100); + PlaySoundObject(39, SOUND_MODE_PLAY); + + break; + + case 34: + case 44: + npc->ani_no = 5; + break; + } + + if (npc->act_wait > 53) + npc->ani_no = 7; + + if (npc->flag & 8) + { + npc->act_no = 22; + npc->act_wait = 0; + npc->ani_no = 2; + SetQuake(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + break; + + case 22: + npc->xm /= 2; + + if (++npc->act_wait > 22) + npc->act_no = 10; + + break; + + case 50: + npc->bits &= ~NPC_SHOOTABLE; + npc->damage = 0; + + if (npc->flag & 8) + { + npc->act_no = 51; + npc->ani_no = 2; + SetQuake(10); + SetExpObjects(npc->x, npc->y, 19); + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 8); + PlaySoundObject(72, SOUND_MODE_PLAY); + } + + break; + + case 51: + npc->xm = (npc->xm * 7) / 8; + npc->ani_no = 8; + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->act_no < 50) + { + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Red Demon projectile +void ActNpc277(NPCHAR *npc) +{ + RECT rc[3] = { + {128, 0, 152, 24}, + {152, 0, 176, 24}, + {176, 0, 200, 24}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 0xFF) + { + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + VanishNpChar(npc); + return; + } + + if (++npc->act_wait % 5 == 0) + PlaySoundObject(110, SOUND_MODE_PLAY); + + if (++npc->ani_no > 2) + npc->ani_no = 0; + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Little family +void ActNpc278(NPCHAR *npc) +{ + RECT rcPapa[2] = { + {0, 120, 8, 128}, + {8, 120, 16, 128}, + }; + + RECT rcMama[2] = { + {16, 120, 24, 128}, + {24, 120, 32, 128}, + }; + + RECT rcKodomo[2] = { // Japanese for 'child' + {32, 120, 40, 128}, + {40, 120, 48, 128}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->xm = 0; + // Fallthrough + case 1: + if (Random(0, 60) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (Random(0, 60) == 1) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = Random(0, 16); + npc->ani_no = 0; + npc->ani_wait = 0; + + if (Random(0, 9) % 2) + npc->direct = 0; + else + npc->direct = 2; + + // Fallthrough + case 11: + if (npc->direct == 0 && npc->flag & 1) + npc->direct = 2; + else if (npc->direct == 2 && npc->flag & 4) + npc->direct = 0; + + if (npc->direct == 0) + npc->xm = -0x100; + else + npc->xm = 0x100; + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 0x20) + npc->act_no = 0; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + + switch (npc->code_event) + { + case 200: + npc->rect = rcPapa[npc->ani_no]; + break; + + case 210: + npc->rect = rcMama[npc->ani_no]; + break; + + default: + npc->rect = rcKodomo[npc->ani_no]; + break; + } +} + +// Falling block (large) +void ActNpc279(NPCHAR *npc) +{ + RECT rc[2] = { + {0, 16, 32, 48}, + {16, 0, 32, 16}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + switch (npc->direct) + { + case 0: + npc->act_no = 100; + npc->bits |= NPC_INVULNERABLE; + npc->ani_no = 0; + break; + + case 2: + npc->act_no = 100; + npc->bits |= NPC_INVULNERABLE; + npc->ani_no = 1; + + npc->view.back = 8 * 0x200; + npc->view.front = 8 * 0x200; + npc->view.top = 8 * 0x200; + npc->view.bottom = 8 * 0x200; + + npc->hit.back = 8 * 0x200; + npc->hit.front = 8 * 0x200; + npc->hit.top = 8 * 0x200; + npc->hit.bottom = 8 * 0x200; + + break; + + case 1: + npc->ani_no = 0; + npc->act_no = 10; + break; + } + + if (npc->direct != 1) + break; + // Fallthrough + case 10: + npc->act_no = 11; + npc->act_wait = 16; + // Fallthrough + case 11: + npc->act_wait -= 2; + + if (npc->act_wait <= 0) + { + npc->act_no = 100; + npc->bits |= NPC_INVULNERABLE; + } + + break; + + case 100: + npc->ym += 0x40; + if (npc->ym > 0x700) + npc->ym = 0x700; + + if (npc->y > 128 * 0x200) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->flag & 8) + { + npc->ym = -0x200; + npc->act_no = 110; + npc->bits |= NPC_IGNORE_SOLIDITY; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetQuake(10); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (16 * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + break; + + case 110: + npc->ym += 0x40; + + if (npc->y > (gMap.length * 0x200 * 0x10) + (2 * 0x200 * 0x10)) + { + npc->cond = 0; + return; + } + + break; + } + + if (gMC.y > npc->y) + npc->damage = 10; + else + npc->damage = 0; + + npc->y += npc->ym; + npc->rect = rc[npc->ani_no]; + + if (npc->act_no == 11) + { + npc->rect.top += npc->act_wait; + npc->rect.bottom -= npc->act_wait; + npc->view.top = (16 - npc->act_wait) * 0x200; + } +} diff --git a/src/NpcAct280.cpp b/src/NpcAct280.cpp new file mode 100644 index 0000000..1afbcb1 --- /dev/null +++ b/src/NpcAct280.cpp @@ -0,0 +1,1782 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Sue (being teleported by Misery) +void ActNpc280(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {112, 32, 128, 48}, + {144, 32, 160, 48}, + }; + + RECT rcRight[2] = { + {112, 48, 128, 64}, + {144, 48, 160, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->x += 6 * 0x200; + npc->tgt_x = npc->x; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 1: + if (++npc->act_wait == 64) + { + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + npc->ani_no = 0; + + if (npc->flag & 8) + { + npc->act_no = 4; + npc->act_wait = 0; + npc->ani_no = 1; + PlaySoundObject(23, SOUND_MODE_PLAY); + } + + break; + } + + if (npc->act_no > 1) + { + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 1) + { + npc->rect.bottom = npc->rect.top + npc->act_wait / 4; + + if (npc->act_wait / 2 % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + (1 * 0x200); + } +} + +// Doctor (red energy form) +void ActNpc281(NPCHAR *npc) +{ + RECT rc = {0, 0, 0, 0}; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + // Fallthrough + case 11: + ++npc->act_wait; + + SetNpChar(270, npc->x, npc->y + (128 * 0x200), 0, 0, 2, npc, 0x100); + + if (npc->act_wait > 150) + npc->act_no = 12; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + // Fallthrough + case 21: + if (++npc->act_wait > 250) + { + DeleteNpCharCode(270, FALSE); + npc->act_no = 22; + } + + break; + } + + npc->rect = rc; +} + +// Mini Undead Core (active) +void ActNpc282(NPCHAR *npc) +{ + // Yes, Pixel spelt this wrong (should be 'rc') + RECT tc[3] = { + {256, 80, 320, 120}, + {256, 0, 320, 40}, + {256, 120, 320, 160}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 20; + npc->tgt_y = npc->y; + + if (Random(0, 100) % 2) + npc->ym = -0x100; + else + npc->ym = 0x100; + // Fallthrough + case 20: + npc->xm = -0x200; + + if (npc->x < -64 * 0x200) + npc->cond = 0; + + if (npc->tgt_y < npc->y) + npc->ym -= 0x10; + if (npc->tgt_y > npc->y) + npc->ym += 0x10; + + if (npc->ym > 0x100) + npc->ym = 0x100; + if (npc->ym < -0x100) + npc->ym = -0x100; + + if (gMC.flag & 8 && gMC.y < npc->y - (4 * 0x200) && gMC.x > npc->x - (24 * 0x200) && gMC.x < npc->x + (24 * 0x200)) + { + npc->tgt_y = 144 * 0x200; + npc->ani_no = 2; + } + else if (npc->ani_no != 1) + { + npc->ani_no = 0; + } + + if (gMC.flag & 1 && gMC.x < npc->x - npc->hit.back && gMC.x > npc->x - npc->hit.back - (8 * 0x200) && gMC.y + gMC.hit.bottom > npc->y - npc->hit.top && gMC.y - gMC.hit.top < npc->y + npc->hit.bottom) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->ani_no = 1; + } + else if (gMC.flag & 4 && gMC.x > npc->x + npc->hit.back && gMC.x < npc->x + npc->hit.back + (8 * 0x200) && gMC.y + gMC.hit.bottom > npc->y - npc->hit.top && gMC.y - gMC.hit.top < npc->y + npc->hit.bottom) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->ani_no = 1; + } + else if (gMC.flag & 2 && gMC.y < npc->y - npc->hit.top && gMC.y > npc->y - npc->hit.top - (8 * 0x200) && gMC.x + gMC.hit.front > npc->x - npc->hit.back && gMC.x - gMC.hit.back < npc->x + npc->hit.front) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->ani_no = 1; + } + else if (gMC.flag & 8 && gMC.y > npc->y + npc->hit.bottom - (4 * 0x200) && gMC.y < npc->y + npc->hit.bottom + (12 * 0x200) && gMC.x + gMC.hit.front > npc->x - npc->hit.back - (4 * 0x200) && gMC.x - gMC.hit.back < npc->x + npc->hit.front + (4 * 0x200)) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->ani_no = 1; + } + } + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = tc[npc->ani_no]; +} + +// Misery (transformed) +void ActNpc283(NPCHAR *npc) +{ + int x, y, direct; + + RECT rcLeft[11] = { + {0, 64, 32, 96}, + {32, 64, 64, 96}, + {64, 64, 96, 96}, + {96, 64, 128, 96}, + {128, 64, 160, 96}, + {160, 64, 192, 96}, + {192, 64, 224, 96}, + {224, 64, 256, 96}, + {0, 0, 0, 0}, + {256, 64, 288, 96}, + {288, 64, 320, 96}, + }; + + RECT rcRight[11] = { + {0, 96, 32, 128}, + {32, 96, 64, 128}, + {64, 96, 96, 128}, + {96, 96, 128, 128}, + {128, 96, 160, 128}, + {160, 96, 192, 128}, + {192, 96, 224, 128}, + {224, 96, 256, 128}, + {0, 0, 0, 0}, + {256, 96, 288, 128}, + {288, 96, 320, 128}, + }; + + if (npc->act_no < 100 && (gBoss[0].cond == 0 || npc->life < 400)) + npc->act_no = 100; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 1: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 9; + else + npc->ani_no = 0; + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 9; + break; + + case 20: + gSuperXpos = 0; + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 21: + npc->xm = 7 * npc->xm / 8; + npc->ym = 7 * npc->ym / 8; + + if (++npc->ani_wait > 20) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 100) + npc->act_no = 30; + + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->ani_no = 2; + npc->count2 = npc->life; + // Fallthrough + case 31: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + if (npc->flag & 8) + npc->ym = -0x200; + + if (npc->x > gBoss[0].x) + npc->xm -= 0x20; + else + npc->xm += 0x20; + + if (npc->y > gMC.y) + npc->ym -= 0x10; + else + npc->ym += 0x10; + + if (npc->xm > 0x200) + npc->xm = 0x200; + if (npc->xm < -0x200) + npc->xm = -0x200; + + if (npc->ym > 0x200) + npc->ym = 0x200; + if (npc->ym < -0x200) + npc->ym = -0x200; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->act_wait > 150 && (npc->life < npc->count2 - 20 || gSuperXpos)) + { + gSuperXpos = 0; + npc->act_no = 40; + } + + if (gBoss[0].ani_no && npc->act_wait > 250) + npc->act_no = 50; + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + PlaySoundObject(103, SOUND_MODE_PLAY); + + if (gMC.y < 160 * 0x200) + npc->count2 = 290; + else + npc->count2 = 289; + // Fallthrough + case 41: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 4; + else + npc->ani_no = 5; + + if (npc->act_wait % 6 == 1) + { + if (npc->count2 == 289) + { + x = npc->x + (Random(-0x40, 0x40) * 0x200); + y = npc->y + (Random(-0x20, 0x20) * 0x200); + } + else + { + x = npc->x + (Random(-0x20, 0x20) * 0x200); + y = npc->y + (Random(-0x40, 0x40) * 0x200); + } + + if (x < 32 * 0x200) + x = 32 * 0x200; + if (x > (gMap.width - 2) * 0x200 * 0x10) + x = (gMap.width - 2) * 0x200 * 0x10; + + if (y < 32 * 0x200) + y = 32 * 0x200; + if (y > (gMap.length - 2) * 0x200 * 0x10) + y = (gMap.length - 2) * 0x200 * 0x10; + + PlaySoundObject(39, SOUND_MODE_PLAY); + SetNpChar(npc->count2, x, y, 0, 0, 0, NULL, 0x100); + } + + if (npc->act_wait > 50) + { + npc->act_no = 42; + npc->act_wait = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 42: + ++npc->act_wait; + npc->ani_no = 6; + + if (npc->act_wait > 50) + { + npc->ym = -0x200; + + if (npc->direct == 0) + npc->xm = 0x200; + else + npc->xm = -0x200; + + npc->act_no = 30; + } + + break; + + case 50: + npc->act_no = 51; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + PlaySoundObject(103, SOUND_MODE_PLAY); + // Fallthrough + case 51: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 4; + else + npc->ani_no = 5; + + if (gMC.equip & EQUIP_BOOSTER_2_0) + { + if (npc->act_wait % 10 == 1) + { + if (npc->direct == 0) + { + x = npc->x + (10 * 0x200); + y = npc->y; + + switch (npc->act_wait / 6 % 4) + { + case 0: + direct = 0xD8; + break; + + case 1: + direct = 0xEC; + break; + + case 2: + direct = 0x14; + break; + + case 3: + direct = 0x28; + break; + } + } + else + { + x = npc->x - (10 * 0x200); + y = npc->y; + + switch (npc->act_wait / 6 % 4) + { + case 0: + direct = 0x58; + break; + + case 1: + direct = 0x6C; + break; + + case 2: + direct = 0x94; + break; + + case 3: + direct = 0xA8; + break; + } + } + + PlaySoundObject(39, SOUND_MODE_PLAY); + SetNpChar(301, x, y, 0, 0, direct, NULL, 0x100); + } + } + else if (npc->act_wait % 24 == 1) + { + if (npc->direct == 0) + { + x = npc->x + (10 * 0x200); + y = npc->y; + + switch (npc->act_wait / 6 % 4) + { + case 0: + direct = 0xD8; + break; + + case 1: + direct = 0xEC; + break; + + case 2: + direct = 0x14; + break; + + case 3: + direct = 0x28; + break; + } + } + else + { + x = npc->x - (10 * 0x200); + y = npc->y; + + switch (npc->act_wait / 6 % 4) + { + case 0: + direct = 0x58; + break; + + case 1: + direct = 0x6C; + break; + + case 2: + direct = 0x94; + break; + + case 3: + direct = 0xA8; + break; + } + } + + PlaySoundObject(39, SOUND_MODE_PLAY); + SetNpChar(301, x, y, 0, 0, direct, NULL, 0x100); + } + + if (npc->act_wait > 50) + { + npc->act_no = 42; + npc->act_wait = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 99: + npc->xm = 0; + npc->ym = 0; + npc->ani_no = 9; + npc->bits &= ~NPC_SHOOTABLE; + break; + + case 100: + npc->act_no = 101; + npc->ani_no = 9; + npc->damage = 0; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->ym = -0x200; + npc->shock += 50; + npc->hit.bottom = 12 * 0x200; + ++gBoss[0].ani_no; + // Fallthrough + case 101: + npc->ym += 0x20; + + if (npc->y > (216 * 0x200) - npc->hit.bottom) + { + npc->y = (216 * 0x200) - npc->hit.bottom; + npc->act_no = 102; + npc->ani_no = 10; + npc->xm = 0; + npc->ym = 0; + } + + break; + } + + npc->y += npc->ym; + + if (npc->shock) + npc->x += npc->xm / 2; + else + npc->x += npc->xm; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Sue (transformed) +void ActNpc284(NPCHAR *npc) +{ + unsigned char deg; + + RECT rcLeft[13] = { + {0, 128, 32, 160}, + {32, 128, 64, 160}, + {64, 128, 96, 160}, + {96, 128, 128, 160}, + {128, 128, 160, 160}, + {160, 128, 192, 160}, + {192, 128, 224, 160}, + {224, 128, 256, 160}, + {0, 0, 0, 0}, + {256, 128, 288, 160}, + {288, 128, 320, 160}, + {224, 64, 256, 96}, + {208, 32, 224, 48}, + }; + + RECT rcRight[13] = { + {0, 160, 32, 192}, + {32, 160, 64, 192}, + {64, 160, 96, 192}, + {96, 160, 128, 192}, + {128, 160, 160, 192}, + {160, 160, 192, 192}, + {192, 160, 224, 192}, + {224, 160, 256, 192}, + {0, 0, 0, 0}, + {256, 160, 288, 192}, + {288, 160, 320, 192}, + {224, 96, 256, 128}, + {208, 48, 224, 64}, + }; + + if (npc->act_no < 100 && (gBoss[0].cond == 0|| npc->life < 500)) + npc->act_no = 100; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 4 * 0x200; + PlaySoundObject(29, SOUND_MODE_PLAY); + npc->count2 = npc->life; + // Fallthrough + case 1: + if (++npc->act_wait / 2 % 2) + { + npc->view.top = 16 * 0x200; + npc->view.back = 16 * 0x200; + npc->view.front = 16 * 0x200; + npc->ani_no = 11; + } + else + { + npc->view.top = 3 * 0x200; + npc->view.back = 8 * 0x200; + npc->view.front = 8 * 0x200; + npc->ani_no = 12; + } + + if (npc->act_wait > 50) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 11; + npc->view.top = 16 * 0x200; + npc->view.back = 16 * 0x200; + npc->view.front = 16 * 0x200; + DeleteNpCharCode(257, TRUE); + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->damage = 0; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + // Fallthrough + case 21: + npc->xm = (npc->xm * 7) / 8; + npc->ym = (npc->ym * 7) / 8; + + if (++npc->ani_wait > 20) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 80) + npc->act_no = 30; + + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + + if (npc->life < npc->count2 - 50) + { + npc->count2 = npc->life; + gSuperXpos = 10; + } + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->ani_no = 2; + npc->xm = 0; + npc->ym = 0; + // Fallthrough + case 31: + if (++npc->act_wait > 16) + { + ++npc->count1; + npc->count1 %= 4; + + switch (npc->count1) + { + case 1: + case 3: + npc->act_no = 34; + break; + + case 0: // Identical to case 2 + npc->act_no = 32; + break; + + case 2: // Identical to case 0 + npc->act_no = 32; + break; + } + } + + break; + + case 32: + npc->act_no = 33; + npc->act_wait = 0; + npc->bits &= ~NPC_SHOOTABLE; + + if (gMC.x < npc->x) + npc->tgt_x = gMC.x - (160 * 0x200); + else + npc->tgt_x = gMC.x + (160 * 0x200); + + npc->tgt_y = gMC.y; + + deg = GetArktan(npc->x - npc->tgt_x, npc->y - npc->tgt_y); + npc->xm = 3 * GetCos(deg); + npc->ym = 3 * GetSin(deg); + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->x < (gMap.width * 0x200 * 0x10) / 2 && npc->xm > 0) + { + if (npc->y < (gMap.length * 0x200 * 0x10) / 2 && npc->ym > 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + if (npc->y > (gMap.length * 0x200 * 0x10) / 2 && npc->ym < 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + } + if (npc->x > (gMap.width * 0x200 * 0x10) / 2 && npc->xm < 0) + { + if (npc->y < (gMap.length * 0x200 * 0x10) / 2 && npc->ym > 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + if (npc->y > (gMap.length * 0x200 * 0x10) / 2 && npc->ym < 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + if (npc->xm > 0) + npc->direct = 2; + else + npc->direct = 0; + // Fallthrough + case 33: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 3; + else + npc->ani_no = 8; + + if (npc->act_wait > 50 || npc->flag & 5) + npc->act_no = 20; + + break; + + case 34: + npc->act_no = 35; + npc->act_wait = 0; + npc->damage = 4; + + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y; + + deg = GetArktan(npc->x - npc->tgt_x, npc->y - npc->tgt_y); + npc->ym = 3 * GetSin(deg); + npc->xm = 3 * GetCos(deg); + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->x < (gMap.width * 0x200 * 0x10) / 2 && npc->xm > 0) + { + if (npc->y < (gMap.length * 0x200 * 0x10) / 2 && npc->ym > 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + if (npc->y > (gMap.length * 0x200 * 0x10) / 2 && npc->ym < 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + if (npc->x > (gMap.width * 0x200 * 0x10) / 2 && npc->xm < 0) + { + if (npc->y < (gMap.length * 0x200 * 0x10) / 2 && npc->ym > 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + if (npc->y > (gMap.length * 0x200 * 0x10) / 2 && npc->ym < 0) + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + if (npc->xm > 0) + npc->direct = 2; + else + npc->direct = 0; + // Fallthrough + case 35: + if (++npc->act_wait > 20 && npc->shock) + npc->act_no = 40; + else if (npc->act_wait > 50 || npc->flag & 5) + npc->act_no = 20; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + npc->ani_no = 4; + + if (npc->act_wait % 5 == 1) + PlaySoundObject(109, SOUND_MODE_PLAY); + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + npc->ani_no = 2; + npc->damage = 0; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + // Fallthrough + case 41: + npc->xm = (npc->xm * 7) / 8; + npc->ym = (npc->ym * 7) / 8; + + if (++npc->act_wait > 6) + { + npc->act_no = 42; + npc->act_wait = 0; + npc->ym = -0x200; + + if (npc->direct == 0) + npc->xm = 0x200; + else + npc->xm = -0x200; + } + + break; + + case 42: + npc->ani_no = 9; + + if (npc->flag & 8) + { + npc->act_no = 43; + npc->act_wait = 0; + npc->ani_no = 2; + + if (npc->x < gMC.x) + npc->direct = 2; + else + npc->direct = 0; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + break; + + case 43: + if (++npc->act_wait > 16) + npc->act_no = 20; + + break; + + case 99: + npc->xm = 0; + npc->ym = 0; + npc->ani_no = 9; + npc->bits &= ~NPC_SHOOTABLE; + break; + + case 100: + npc->act_no = 101; + npc->ani_no = 9; + npc->damage = 0; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->ym = -0x200; + npc->shock += 50; + ++gBoss[0].ani_no; + // Fallthrough + case 101: + npc->ym += 0x20; + + if (npc->y > (216 * 0x200) - npc->hit.bottom) + { + npc->y = (216 * 0x200) - npc->hit.bottom; + npc->act_no = 102; + npc->ani_no = 10; + npc->xm = 0; + npc->ym = 0; + } + + break; + } + + npc->y += npc->ym; + + if (npc->shock) + npc->x += npc->xm / 2; + else + npc->x += npc->xm; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Undead Core spiral projectile +void ActNpc285(NPCHAR *npc) +{ + RECT rc = {232, 104, 248, 120}; + unsigned char deg; + + if (npc->x < 0 || npc->x > gMap.width * 0x10 * 0x200) + { + VanishNpChar(npc); + return; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + npc->count1 = npc->direct / 8; + npc->direct %= 8; + // Fallthrough + case 1: + npc->count1 += 24; + npc->count1 %= 0x100; + + deg = npc->count1; + + if (npc->act_wait < 128) + ++npc->act_wait; + + if (npc->direct == 0) + npc->xm -= 21; + else + npc->xm += 21; + + npc->tgt_x += npc->xm; + + npc->x = npc->tgt_x + (GetCos(deg) * 4); + npc->y = npc->tgt_y + (GetSin(deg) * 6); + + SetNpChar(286, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + + break; + } + + npc->rect = rc; +} + +// Undead Core spiral shot trail +void ActNpc286(NPCHAR *npc) +{ + RECT rc[3] = { + {232, 120, 248, 136}, + {232, 136, 248, 152}, + {232, 152, 248, 168}, + }; + + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->cond = 0; + else + npc->rect = rc[npc->ani_no]; +} + +// Orange smoke +void ActNpc287(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {0, 224, 16, 240}, + {16, 224, 32, 240}, + {32, 224, 48, 240}, + {48, 224, 64, 240}, + {64, 224, 80, 240}, + {80, 224, 96, 240}, + {96, 224, 112, 240}, + }; + + if (npc->act_no == 0) + { + npc->xm = Random(-4, 4) * 0x200; + npc->act_no = 1; + } + else + { + npc->xm = (npc->xm * 20) / 21; + npc->ym = (npc->ym * 20) / 21; + + npc->x += npc->xm; + npc->y += npc->ym; + } + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + npc->cond = 0; + else + npc->rect = rcLeft[npc->ani_no]; +} + +// Undead Core exploding rock +void ActNpc288(NPCHAR *npc) +{ + RECT rc[5] = { + {232, 72, 248, 88}, + {232, 88, 248, 104}, + {232, 0, 256, 24}, + {232, 24, 256, 48}, + {232, 48, 256, 72}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->xm = -0x200; + // Fallthrough + case 1: + if (npc->direct == 1) + { + npc->ym -= 0x20; + if (npc->ym < -0x5FF) + npc->ym = -0x5FF; + + if (npc->flag & 2) + npc->act_no = 2; + } + else if (npc->direct == 3) + { + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->flag & 8) + npc->act_no = 2; + } + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + + case 2: + PlaySoundObject(44, SOUND_MODE_PLAY); + npc->act_no = 3; + npc->act_wait = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->ym = 0; + + if (npc->x > gMC.x) + npc->xm = -0x400; + else + npc->xm = 0x400; + + npc->view.back = 12 * 0x200; + npc->view.front = 12 * 0x200; + npc->view.top = 12 * 0x200; + npc->view.bottom = 12 * 0x200; + // Fallthrough + case 3: + if (++npc->ani_no > 4) + npc->ani_no = 2; + + if (++npc->act_wait % 4 == 1) + { + if (npc->direct == 1) + SetNpChar(287, npc->x, npc->y, 0, 0x400, 0, NULL, 0x100); + else + SetNpChar(287, npc->x, npc->y, 0, -0x400, 0, NULL, 0x100); + } + + if (npc->x < 1 * 0x200 * 0x10 || npc->x > (gMap.width * 0x200 * 0x10) - (1 * 0x200 * 0x10)) + npc->cond = 0; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Critter (orange, Misery) +void ActNpc289(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {160, 32, 176, 48}, + {176, 32, 192, 48}, + {192, 32, 208, 48}, + }; + + RECT rcRight[3] = { + {160, 48, 176, 64}, + {176, 48, 192, 64}, + {192, 48, 208, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 2; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 1: + if (++npc->act_wait > 16) + { + npc->act_no = 10; + npc->view.top = 8 * 0x200; + npc->view.bottom = 8 * 0x200; + npc->damage = 2; + npc->bits |= NPC_SHOOTABLE; + } + + break; + + case 10: + if (npc->flag & 8) + { + npc->act_no = 11; + npc->ani_no = 0; + npc->act_wait = 0; + npc->xm = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 11: + if (++npc->act_wait > 10) + { + if (++npc->count1 > 4) + npc->act_no = 12; + else + npc->act_no = 10; + + PlaySoundObject(30, SOUND_MODE_PLAY); + npc->ym = -0x600; + + if (npc->direct == 0) + npc->xm = -0x200; + else + npc->xm = 0x200; + + npc->ani_no = 2; + } + + break; + + case 12: + npc->bits |= NPC_IGNORE_SOLIDITY; + + if (npc->y > gMap.length * 0x200 * 0x10) + { + VanishNpChar(npc); + return; + } + + break; + } + + if (npc->act_no >= 10) + npc->ym += 0x40; + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 1) + { + npc->rect.top += 8 - (npc->act_wait / 2); + npc->rect.bottom -= 8 + (npc->act_wait / 2); + npc->view.top = (npc->act_wait * 0x200) / 2; + npc->view.bottom = (npc->act_wait * 0x200) / 2; + } +} + +// Bat (Misery) +void ActNpc290(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {112, 32, 128, 48}, + {128, 32, 144, 48}, + {144, 32, 160, 48}, + }; + + RECT rcRight[3] = { + {112, 48, 128, 64}, + {128, 48, 144, 64}, + {144, 48, 160, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 2; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 1: + if (++npc->act_wait > 16) + { + npc->act_no = 10; + npc->view.top = 8 * 0x200; + npc->view.bottom = 8 * 0x200; + npc->damage = 2; + npc->bits |= NPC_SHOOTABLE; + npc->tgt_y = npc->y; + npc->ym = 0x400; + } + + break; + + case 10: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (npc->y < npc->tgt_y) + npc->ym += 0x40; + else + npc->ym -= 0x40; + + if (npc->direct == 0) + npc->xm -= 0x10; + else + npc->xm += 0x10; + + if (npc->x < 0 || npc->y < 0 || npc->x > gMap.width * 0x200 * 0x10 || npc->y > gMap.length * 0x200 * 0x10) + { + VanishNpChar(npc); + return; + } + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 1) + { + npc->rect.top += 8 - (npc->act_wait / 2); + npc->rect.bottom -= 8 + (npc->act_wait / 2); + npc->view.top = (npc->act_wait * 0x200) / 2; + npc->view.bottom = (npc->act_wait * 0x200) / 2; + } +} + +// Mini Undead Core (inactive) +void ActNpc291(NPCHAR *npc) +{ + RECT tc[2] = { + {256, 80, 320, 120}, + {256, 0, 320, 40}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 20; + + if (npc->direct == 2) + { + npc->bits &= ~NPC_SOLID_HARD; + npc->ani_no = 1; + } + + break; + } + + npc->rect = tc[npc->ani_no]; +} + +// Quake +void ActNpc292(NPCHAR *npc) +{ + (void)npc; + + SetQuake(10); +} + +// Undead Core giant energy shot +void ActNpc293(NPCHAR *npc) +{ + RECT rect[2] = { + {240, 200, 280, 240}, + {280, 200, 320, 240}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->ani_no > 1) + npc->ani_no = 0; + + SetNpChar(4, npc->x + (Random(0, 0x10) * 0x200), npc->y + (Random(-0x10, 0x10) * 0x200), 0, 0, 0, NULL, 0x100); + + npc->x -= 8 * 0x200; + + if (npc->x < -32 * 0x200) + npc->cond = 0; + + break; + } + + npc->rect = rect[npc->ani_no]; +} + +// Quake + falling block generator +void ActNpc294(NPCHAR *npc) +{ + int x, y, dir; + + switch (npc->act_no) + { + case 0: + if (gMC.x < (gMap.width - 6) * 0x200 * 0x10) + { + npc->act_no = 1; + npc->act_wait = 0; + } + + break; + + case 1: + ++npc->act_wait; + + if (gMC.equip & EQUIP_BOOSTER_2_0) + { + npc->x = gMC.x + (64 * 0x200); + + if (npc->x < 416 * 0x200) + npc->x = 416 * 0x200; + } + else + { + npc->x = gMC.x + (96 * 0x200); + + if (npc->x < 368 * 0x200) + npc->x = 368 * 0x200; + } + + if (npc->x > (gMap.width - 10) * 0x200 * 0x10) + npc->x = (gMap.width - 10) * 0x200 * 0x10; + + if (npc->act_wait > 24) + { + if (gMC.equip & EQUIP_BOOSTER_2_0) + x = npc->x + (Random(-14, 14) * 0x200 * 0x10); + else + x = npc->x + (Random(-11, 11) * 0x200 * 0x10); + + y = gMC.y - (224 * 0x200); + + if (Random(0, 10) % 2) // Because just doing 'Random(0, 1)' is too hard + dir = 0; + else + dir = 2; + + SetNpChar(279, x, y, 0, 0, dir, NULL, 0x100); + + npc->act_wait = Random(0, 15); + } + + break; + } +} + +// Cloud +void ActNpc295(NPCHAR *npc) +{ + RECT rc[4] = { + {0, 0, 208, 64}, + {32, 64, 144, 96}, + {32, 96, 104, 0x80}, + {104, 96, 144, 0x80}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = npc->direct % 4; + switch (npc->direct) + { + case 0: + npc->ym = -1000; + npc->view.back = 104 * 0x200; + npc->view.front = 104 * 0x200; + break; + + case 1: + npc->ym = -0x800; + npc->view.back = 56 * 0x200; + npc->view.front = 56 * 0x200; + break; + + case 2: + npc->ym = -0x400; + npc->view.back = 32 * 0x200; + npc->view.front = 32 * 0x200; + break; + + case 3: + npc->ym = -0x200; + npc->view.back = 20 * 0x200; + npc->view.front = 20 * 0x200; + break; + + case 4: + npc->xm = -0x400; + npc->view.back = 104 * 0x200; + npc->view.front = 104 * 0x200; + break; + + case 5: + npc->xm = -0x200; + npc->view.back = 56 * 0x200; + npc->view.front = 56 * 0x200; + break; + + case 6: + npc->xm = -0x100; + npc->view.back = 32 * 0x200; + npc->view.front = 32 * 0x200; + break; + + case 7: + npc->xm = -0x80; + npc->view.back = 20 * 0x200; + npc->view.front = 20 * 0x200; + break; + } + + break; + + case 1: + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->x < -64 * 0x200) + npc->cond = 0; + if (npc->y < -32 * 0x200) + npc->cond = 0; + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Cloud generator +void ActNpc296(NPCHAR *npc) +{ + int x, y, dir, pri; + + if (++npc->act_wait > 16) + { + npc->act_wait = Random(0, 16); + dir = Random(0, 100) % 4; + + if (npc->direct == 0) + { + switch (dir) + { + case 0: + pri = 0x180; + break; + + case 1: + pri = 0x80; + break; + + case 2: + pri = 0x40; + break; + + case 3: + pri = 0x00; + break; + } + + x = Random(-10, 10) * 0x200 * 0x10 + npc->x; + y = npc->y; + SetNpChar(295, x, y, 0, 0, dir, NULL, pri); + } + else + { + switch (dir) + { + case 0: + pri = 0x80; + break; + + case 1: + pri = 0x55; + break; + + case 2: + pri = 0x40; + break; + + case 3: + pri = 0x00; + break; + } + + x = npc->x; + y = Random(-7, 7) * 0x200 * 0x10 + npc->y; + SetNpChar(295, x, y, 0, 0, dir + 4, NULL, pri); + } + } +} + +// Sue in dragon's mouth +void ActNpc297(NPCHAR *npc) +{ + RECT rc = {112, 48, 0x80, 64}; + + npc->x = npc->pNpc->x + (16 * 0x200); + npc->y = npc->pNpc->y + (8 * 0x200); + + npc->rect = rc; +} + +// Doctor (opening) +void ActNpc298(NPCHAR *npc) +{ + RECT rc[8] = { + {72, 0x80, 88, 160}, + {88, 0x80, 104, 160}, + {104, 0x80, 120, 160}, + {72, 0x80, 88, 160}, + {120, 0x80, 136, 160}, + {72, 0x80, 88, 160}, + {104, 160, 120, 192}, + {120, 160, 136, 192}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + // Fallthrough + + case 1: + npc->ani_no = 0; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->count1 = 0; + // Fallthrough + + case 11: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + { + npc->ani_no = 0; + + if (++npc->count1 > 7) + { + npc->ani_no = 0; + npc->act_no = 1; + } + } + + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + + case 21: + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 5) + npc->ani_no = 2; + + npc->x += 0x100; + + break; + + case 30: + npc->ani_no = 6; + break; + + case 40: + npc->act_no = 41; + npc->ani_no = 6; + npc->ani_wait = 0; + npc->count1 = 0; + // Fallthrough + + case 41: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 7) + { + npc->ani_no = 6; + + if (++npc->count1 > 7) + { + npc->ani_no = 6; + npc->act_no = 30; + } + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Balrog/Misery (opening) +void ActNpc299(NPCHAR *npc) +{ + RECT rc[2] = { + {0, 0, 48, 48}, + {48, 0, 96, 48}, + }; + + if (npc->act_no == 0) + { + npc->act_no = 1; + + if (npc->direct == 0) + { + npc->ani_no = 1; + npc->act_wait = 25; + npc->y -= 0x40 * (50 / 2); + } + else + { + npc->ani_no = 0; + npc->act_wait = 0; + } + } + + if (++npc->act_wait / 50 % 2) + npc->y += 0x40; + else + npc->y -= 0x40; + + npc->rect = rc[npc->ani_no]; +} diff --git a/src/NpcAct300.cpp b/src/NpcAct300.cpp new file mode 100644 index 0000000..afce8a0 --- /dev/null +++ b/src/NpcAct300.cpp @@ -0,0 +1,1918 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Boss.h" +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Demon crown (opening) +void ActNpc300(NPCHAR *npc) +{ + RECT rc = {192, 80, 208, 96}; + + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->y += 6 * 0x200; + } + + if (++npc->ani_wait % 8 == 1) + SetCaret(npc->x + (Random(-8, 8) * 0x200), npc->y + (8 * 0x200), CARET_TINY_PARTICLES, DIR_UP); + + npc->rect = rc; +} + +// Fish missile (Misery) +void ActNpc301(NPCHAR *npc) +{ + int dir; + + RECT rect[8] = { + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + {192, 0, 208, 16}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + {192, 16, 208, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->count1 = npc->direct; + // Fallthrough + case 1: + npc->xm = GetCos(npc->count1) * 2; + npc->ym = GetSin(npc->count1) * 2; + + npc->y += npc->ym; + npc->x += npc->xm; + + dir = GetArktan(npc->x - gMC.x, npc->y - gMC.y); + + if (dir < npc->count1) + { + if (npc->count1 - dir < 0x80) + --npc->count1; + else + ++npc->count1; + } + else + { + if (dir - npc->count1 < 0x80) + ++npc->count1; + else + --npc->count1; + } + + if (npc->count1 > 0xFF) + npc->count1 -= 0x100; + if (npc->count1 < 0) + npc->count1 += 0x100; + + break; + } + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + SetCaret(npc->x, npc->y, CARET_EXHAUST, DIR_AUTO); + } + + npc->ani_no = (npc->count1 + 0x10) / 0x20; + if (npc->ani_no > 7) + npc->ani_no = 7; + + npc->rect = rect[npc->ani_no]; +} + +// Camera focus marker +void ActNpc302(NPCHAR *npc) +{ + int n; + + switch (npc->act_no) + { + case 10: + npc->x = gMC.x; + npc->y = gMC.y - 32 * 0x200; + break; + + case 20: + switch (npc->direct) + { + case 0: + npc->x -= 2 * 0x200; + break; + + case 1: + npc->y -= 2 * 0x200; + break; + + case 2: + npc->x += 2 * 0x200; + break; + + case 3: + npc->y += 2 * 0x200; + break; + } + + gMC.x = npc->x; + gMC.y = npc->y; + break; + + case 30: + npc->x = gMC.x; + npc->y = gMC.y + (80 * 0x200); + break; + + case 100: + npc->act_no = 101; + + if (npc->direct != 0) + { + for (n = 0xAA; n < NPC_MAX; ++n) + { + if (gNPC[n].cond & 0x80 && gNPC[n].code_event == npc->direct) + { + npc->pNpc = &gNPC[n]; + break; + } + } + + if (n == NPC_MAX) + { + npc->cond = 0; + break; + } + } + else + { + npc->pNpc = gBoss; + } + // Fallthrough + case 101: + npc->x = (gMC.x + npc->pNpc->x) / 2; + npc->y = (gMC.y + npc->pNpc->y) / 2; + break; + } +} + +// Curly's machine gun +void ActNpc303(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {216, 152, 232, 168}, + {232, 152, 248, 168}, + }; + + RECT rcRight[2] = { + {216, 168, 232, 184}, + {232, 168, 248, 184}, + }; + + if (npc->pNpc == NULL) + return; + + // Set position + if (npc->pNpc->direct == 0) + { + npc->direct = 0; + npc->x = npc->pNpc->x - (8 * 0x200); + } + else + { + npc->direct = 2; + npc->x = npc->pNpc->x + (8 * 0x200); + } + + npc->y = npc->pNpc->y; + + // Animation + npc->ani_no = 0; + if (npc->pNpc->ani_no == 3 || npc->pNpc->ani_no == 5) + npc->y -= 1 * 0x200; + + // Set framerect + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Gaudi in hospital +void ActNpc304(NPCHAR *npc) +{ + RECT rc[4] = { + {0, 176, 24, 192}, + {24, 176, 48, 192}, + {48, 176, 72, 192}, + {72, 176, 96, 192}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y += 10 * 0x200; + // Fallthrough + case 1: + npc->ani_no = 0; + break; + + case 10: + npc->ani_no = 1; + break; + + case 20: + npc->act_no = 21; + npc->ani_no = 2; + // Fallthrough + case 21: + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 2; + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Small puppy +void ActNpc305(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {160, 144, 176, 160}, + {176, 144, 192, 160}, + }; + + RECT rcRight[2] = { + {160, 160, 176, 176}, + {176, 160, 192, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 16 * 0x200; + npc->ani_wait = Random(0, 6); + // Fallthrough + + case 1: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Balrog (nurse) +void ActNpc306(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {240, 96, 280, 128}, + {280, 96, 320, 128}, + }; + + RECT rcRight[2] = { + {160, 152, 200, 184}, + {200, 152, 240, 184}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->y += 4 * 0x200; + // Fallthrough + case 1: + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Caged Santa +void ActNpc307(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 32, 16, 48}, + {16, 32, 32, 48}, + }; + + RECT rcRight[2] = { + {0, 48, 16, 64}, + {16, 48, 32, 64}, + }; + + switch (npc->act_no) + { + case 0: + npc->x += 1 * 0x200; + npc->y -= 2 * 0x200; + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + // Fallthrough + case 1: + if (Random(0, 160) == 1) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 2: + if (++npc->act_wait > 12) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Stumpy +void ActNpc308(NPCHAR *npc) +{ + unsigned char deg; + + RECT rcLeft[2] = { + {128, 112, 144, 128}, + {144, 112, 160, 128}, + }; + + RECT rcRight[2] = { + {128, 128, 144, 144}, + {144, 128, 160, 144}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (gMC.x < npc->x + (240 * 0x200) && gMC.x > npc->x - (240 * 0x200) && gMC.y < npc->y + (192 * 0x200) && gMC.y > npc->y - (192 * 0x200)) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->xm2 = 0; + npc->ym2 = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 11: + if (++npc->act_wait > 50) + npc->act_no = 20; + + ++npc->ani_wait; + + if (npc->act_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + } + + if (gMC.x > npc->x + (320 * 0x200) || gMC.x < npc->x - (320 * 0x200) || gMC.y > npc->y + (240 * 0x200) || gMC.y < npc->y - (240 * 0x200)) + npc->act_no = 0; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + + deg = (unsigned char)GetArktan(npc->x - gMC.x, npc->y - gMC.y); + deg += (unsigned char)Random(-3, 3); + npc->ym2 = GetSin(deg) * 2; + npc->xm2 = GetCos(deg) * 2; + + if (npc->xm2 < 0) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 21: + if (npc->xm2 < 0 && npc->flag & 1) + { + npc->direct = 2; + npc->xm2 *= -1; + } + + if (npc->xm2 > 0 && npc->flag & 4) + { + npc->direct = 0; + npc->xm2 *= -1; + } + + if (npc->ym2 < 0 && npc->flag & 2) + npc->ym2 *= -1; + if (npc->ym2 > 0 && npc->flag & 8) + npc->ym2 *= -1; + + if (npc->flag & 0x100) + npc->ym2 = -0x200; + + npc->x += npc->xm2; + npc->y += npc->ym2; + + if (++npc->act_wait > 50) + npc->act_no = 10; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Bute +void ActNpc309(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {0, 0, 16, 16}, + {16, 0, 32, 16}, + }; + + RECT rcRight[2] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->direct == 0) + { + if (gMC.x > npc->x - (288 * 0x200) && gMC.x < npc->x - (272 * 0x200)) + { + npc->act_no = 10; + break; + } + } + else + { + if (gMC.x < npc->x + (288 * 0x200) && gMC.x > npc->x + (272 * 0x200)) + { + npc->act_no = 10; + break; + } + } + + return; + + case 10: + npc->act_no = 11; + npc->bits |= NPC_SHOOTABLE; + npc->damage = 5; + // Fallthrough + case 11: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->direct == 0) + npc->xm2 -= 0x10; + else + npc->xm2 += 0x10; + + if (npc->y > gMC.y) + npc->ym2 -= 0x10; + else + npc->ym2 += 0x10; + + if (npc->xm2 < 0 && npc->flag & 1) + npc->xm2 *= -1; + if (npc->xm2 > 0 && npc->flag & 4) + npc->xm2 *= -1; + + if (npc->ym2 < 0 && npc->flag & 2) + npc->ym2 *= -1; + if (npc->ym2 > 0 && npc->flag & 8) + npc->ym2 *= -1; + + if (npc->xm2 < -0x5FF) + npc->xm2 = -0x5FF; + if (npc->xm2 > 0x5FF) + npc->xm2 = 0x5FF; + + if (npc->ym2 < -0x5FF) + npc->ym2 = -0x5FF; + if (npc->ym2 > 0x5FF) + npc->ym2 = 0x5FF; + + npc->x += npc->xm2; + npc->y += npc->ym2; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->life <= 996) + { + npc->code_char = 316; + npc->act_no = 0; + } +} + +// Bute (with sword) +void ActNpc310(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {32, 0, 56, 16}, + {56, 0, 80, 16}, + {80, 0, 104, 16}, + {104, 0, 128, 16}, + {128, 0, 152, 16}, + }; + + RECT rcRight[5] = { + {32, 16, 56, 32}, + {56, 16, 80, 32}, + {80, 16, 104, 32}, + {104, 16, 128, 32}, + {128, 16, 152, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + npc->damage = 0; + // Fallthrough + case 1: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 0; + + if (gMC.x > npc->x - (128 * 0x200) && gMC.x < npc->x + (128 * 0x200) && gMC.y > npc->y - (128 * 0x200) && gMC.y < npc->y + (16 * 0x200)) + npc->act_no = 10; + + break; + + case 10: + npc->xm = 0; + npc->act_no = 11; + npc->act_wait = 0; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + npc->damage = 0; + npc->ani_no = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 30) + npc->act_no = 20; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + npc->bits &= ~NPC_INVULNERABLE; + npc->bits |= NPC_SHOOTABLE; + npc->damage = 0; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 21: + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (++npc->act_wait > 50) + npc->act_no = 10; + + if (npc->x < gMC.x + (40 * 0x200) && npc->x > gMC.x - (40 * 0x200)) + { + npc->ym = -0x300; + npc->xm /= 2; + npc->ani_no = 2; + npc->act_no = 30; + PlaySoundObject(30, SOUND_MODE_PLAY); + } + + break; + + case 30: + if (npc->ym > -0x80) + { + npc->act_no = 31; + npc->ani_wait = 0; + npc->ani_no = 3; + npc->damage = 9; + } + + break; + + case 31: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + npc->ani_no = 4; + } + + if (npc->flag & 8) + { + npc->act_no = 32; + npc->act_wait = 0; + npc->xm = 0; + npc->damage = 3; + } + + break; + + case 32: + if (++npc->act_wait > 30) + { + npc->act_no = 10; + npc->damage = 0; + } + + break; + } + + npc->ym += 0x20; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->life <= 996) + { + npc->code_char = 316; + npc->act_no = 0; + } +} + +// Bute archer +void ActNpc311(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {0, 32, 24, 56}, + {24, 32, 48, 56}, + {48, 32, 72, 56}, + {72, 32, 96, 56}, + {96, 32, 120, 56}, + {120, 32, 144, 56}, + {144, 32, 168, 56}, + }; + + RECT rcRight[7] = { + {0, 56, 24, 80}, + {24, 56, 48, 80}, + {48, 56, 72, 80}, + {72, 56, 96, 80}, + {96, 56, 120, 80}, + {120, 56, 144, 80}, + {144, 56, 168, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->direct == 0) + { + if (gMC.x > npc->x - (320 * 0x200) && gMC.x < npc->x && gMC.y > npc->y - (160 * 0x200) && gMC.y < npc->y + (160 * 0x200)) + npc->act_no = 10; + } + else + { + if (gMC.x > npc->x && gMC.x < npc->x + (320 * 0x200) && gMC.y > npc->y - (160 * 0x200) && gMC.y < npc->y + (160 * 0x200)) + npc->act_no = 10; + } + + break; + + case 10: + npc->act_no = 11; + // Fallthrough + case 11: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (gMC.x > npc->x - (224 * 0x200) && gMC.x < npc->x + (224 * 0x200) && gMC.y > npc->y - (8 * 0x200)) + { + npc->ani_no = 1; + npc->count1 = 0; + } + else + { + npc->ani_no = 4; + npc->count1 = 1; + } + + if (++npc->act_wait > 10) + npc->act_no = 20; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + // Fallthrough + case 21: + if (npc->count1 == 0) + { + if (++npc->ani_no > 2) + npc->ani_no = 1; + } + else + { + if (++npc->ani_no > 5) + npc->ani_no = 4; + } + + if (++npc->act_wait > 30) + npc->act_no = 30; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + + if (npc->count1 == 0) + { + if (npc->direct == 0) + SetNpChar(312, npc->x, npc->y, -0x600, 0, 0, NULL, 0x100); + else + SetNpChar(312, npc->x, npc->y, 0x600, 0, 2, NULL, 0x100); + + npc->ani_no = 3; + } + else + { + if (npc->direct == 0) + SetNpChar(312, npc->x, npc->y, -0x600, -0x600, 0, NULL, 0x100); + else + SetNpChar(312, npc->x, npc->y, 0x600, -0x600, 2, NULL, 0x100); + + npc->ani_no = 6; + } + // Fallthrough + case 31: + if (++npc->act_wait > 30) + { + npc->act_no = 40; + npc->act_wait = Random(0, 100); + } + + break; + + case 40: + npc->ani_no = 0; + + if (++npc->act_wait > 150) + npc->act_no = 10; + + if (gMC.x < npc->x - (352 * 0x200) || gMC.x > npc->x + (352 * 0x200) || gMC.y < npc->y - (240 * 0x200) || gMC.y > npc->y + (240 * 0x200)) + { + npc->act_no = 40; + npc->act_wait = 0; + } + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->life <= 992) + { + npc->code_char = 316; + npc->act_no = 0; + } +} + +// Bute arrow projectile +void ActNpc312(NPCHAR *npc) +{ + RECT rcLeft[5] = { + {0, 160, 16, 176}, + {16, 160, 32, 176}, + {32, 160, 48, 176}, + {48, 160, 64, 176}, + {64, 160, 80, 176}, + }; + + RECT rcRight[5] = { + {0, 176, 16, 192}, + {16, 176, 32, 192}, + {32, 176, 48, 192}, + {48, 176, 64, 192}, + {64, 176, 80, 192}, + }; + + if (npc->act_no > 0 && npc->act_no < 20 && npc->flag & 0xFF) + npc->act_no = 20; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = 0; + + if (npc->xm < 0) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->ym < 0) + npc->ani_no = 0; + else + npc->ani_no = 2; + // Fallthrough + case 1: + ++npc->act_wait; + + if (npc->act_wait == 4) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->act_wait > 10) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->ani_wait = 0; + npc->xm = 3 * npc->xm / 4; + npc->ym = 3 * npc->ym / 4; + // Fallthrough + case 11: + npc->ym += 0x20; + + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 4; + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + npc->damage = 0; + // Fallthrough + case 21: + if (++npc->act_wait > 30) + npc->act_no = 30; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + // Fallthrough + case 31: + if (++npc->act_wait > 30) + { + npc->cond = 0; + return; + } + + break; + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->act_no == 31) + { + if (npc->act_wait / 2 % 2) + { + npc->rect.left = 0; + npc->rect.right = 0; + } + } +} + +// Ma Pignon +void ActNpc313(NPCHAR *npc) +{ + RECT rcLeft[14] = { + {128, 0, 144, 16}, + {144, 0, 160, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + {192, 0, 208, 16}, + {208, 0, 224, 16}, + {224, 0, 240, 16}, + {240, 0, 256, 16}, + {256, 0, 272, 16}, + {272, 0, 288, 16}, + {288, 0, 304, 16}, + {128, 0, 144, 16}, + {176, 0, 192, 16}, + {304, 0, 320, 16}, + }; + + RECT rcRight[14] = { + {128, 16, 144, 32}, + {144, 16, 160, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + {192, 16, 208, 32}, + {208, 16, 224, 32}, + {224, 16, 240, 32}, + {240, 16, 256, 32}, + {256, 16, 272, 32}, + {272, 16, 288, 32}, + {288, 16, 304, 32}, + {128, 16, 144, 32}, + {176, 16, 192, 32}, + {304, 16, 320, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = 0; + npc->ani_wait = 0; + npc->y += 4 * 0x200; + // Fallthrough + case 1: + npc->ym += 0x40; + + if (Random(0, 120) == 10) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ani_no = 1; + } + + if (npc->x - (32 * 0x200) < gMC.x && npc->x + (32 * 0x200) > gMC.x) + { + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 2: + if (++npc->act_wait > 8) + { + npc->act_no = 1; + npc->ani_no = 0; + } + + break; + + case 100: + npc->act_no = 110; + npc->act_wait = 0; + npc->count1 = 0; + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 110: + npc->damage = 1; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 0; + + if (++npc->act_wait > 4) + { + npc->act_wait = 0; + npc->act_no = 120; + + if (++npc->count2 > 12) + { + npc->count2 = 0; + npc->act_no = 300; + } + } + + break; + + case 120: + npc->ani_no = 2; + + if (++npc->act_wait > 4) + { + npc->act_no = 130; + npc->ani_no = 3; + npc->xm = 2 * Random(-0x200, 0x200); + npc->ym = -0x800; + PlaySoundObject(30, SOUND_MODE_PLAY); + ++npc->count1; + } + + break; + + case 130: + npc->ym += 0x80; + + if (npc->y > 128 * 0x200) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->xm < 0 && npc->flag & 1) + npc->xm *= -1; + if (npc->xm > 0 && npc->flag & 4) + npc->xm *= -1; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->ym < -0x200) + npc->ani_no = 3; + else if (npc->ym > 0x200) + npc->ani_no = 4; + else + npc->ani_no = 0; + + if (npc->flag & 8) + { + npc->act_no = 140; + npc->act_wait = 0; + npc->ani_no = 2; + npc->xm = 0; + } + + if (npc->count1 > 4 && gMC.y < npc->y + (4 * 0x200)) + { + npc->act_no = 200; + npc->act_wait = 0; + npc->xm = 0; + npc->ym = 0; + } + + break; + + case 140: + npc->ani_no = 2; + + if (++npc->act_wait > 4) + npc->act_no = 110; + + break; + + case 200: + npc->ani_no = 5; + + if (++npc->act_wait > 10) + { + npc->act_no = 210; + npc->ani_no = 6; + + if (npc->direct == 0) + npc->xm = -0x5FF; + else + npc->xm = 0x5FF; + + PlaySoundObject(25, SOUND_MODE_PLAY); + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + npc->damage = 10; + } + + break; + + case 210: + if (++npc->ani_no > 7) + npc->ani_no = 6; + + if (npc->xm < 0 && npc->flag & 1) + npc->act_no = 220; + if (npc->xm > 0 && npc->flag & 4) + npc->act_no = 220; + + break; + + case 220: + npc->act_no = 221; + npc->act_wait = 0; + SetQuake(16); + PlaySoundObject(26, SOUND_MODE_PLAY); + npc->damage = 4; + // Fallthrough + case 221: + if (++npc->ani_no > 7) + npc->ani_no = 6; + + if (++npc->act_wait % 6 == 0) + SetNpChar(314, Random(4, 16) * 0x200 * 0x10, 1 * 0x200 * 0x10, 0, 0, 0, NULL, 0x100); + + if (npc->act_wait > 30) + { + npc->count1 = 0; + npc->act_no = 130; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + npc->damage = 3; + } + + break; + + case 300: + npc->act_no = 301; + npc->ani_no = 9; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + // Fallthrough + case 301: + if (++npc->ani_no > 11) + npc->ani_no = 9; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + + if (gMC.x > npc->x - (4 * 0x200) && gMC.x < npc->x + (4 * 0x200)) + { + npc->act_no = 310; + npc->act_wait = 0; + npc->ani_no = 2; + npc->xm = 0; + } + + break; + + case 310: + npc->ani_no = 2; + + if (++npc->act_wait > 4) + { + npc->act_no = 320; + npc->ani_no = 12; + npc->ym = -0x800; + PlaySoundObject(25, SOUND_MODE_PLAY); + npc->bits |= NPC_IGNORE_SOLIDITY; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + npc->damage = 10; + } + + break; + + case 320: + if (++npc->ani_no > 13) + npc->ani_no = 12; + + if (npc->y < (16 * 0x200)) + npc->act_no = 330; + + break; + + case 330: + npc->ym = 0; + npc->act_no = 331; + npc->act_wait = 0; + SetQuake(16); + PlaySoundObject(26, SOUND_MODE_PLAY); + // Fallthrough + case 331: + if (++npc->ani_no > 13) + npc->ani_no = 12; + + if (++npc->act_wait % 6 == 0) + SetNpChar(315, Random(4, 16) * 0x200 * 0x10, 0, 0, 0, 0, NULL, 0x100); + + if (npc->act_wait > 30) + { + npc->count1 = 0; + npc->act_no = 130; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + npc->damage = 3; + } + + break; + + case 500: + npc->bits &= ~NPC_SHOOTABLE; + npc->act_no = 501; + npc->act_wait = 0; + npc->ani_no = 8; + npc->tgt_x = npc->x; + npc->damage = 0; + DeleteNpCharCode(315, TRUE); + // Fallthrough + case 501: + npc->ym += 0x20; + + if (++npc->act_wait % 2) + npc->x = npc->tgt_x; + else + npc->x = npc->tgt_x + (1 * 0x200); + + break; + } + + if (npc->act_no > 100 && npc->act_no < 500 && npc->act_no != 210 && npc->act_no != 320) + { + if (IsActiveSomeBullet()) + { + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + } + else + { + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + } + } + + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Ma Pignon rock +void ActNpc314(NPCHAR *npc) +{ + RECT rc[3] = { + {64, 64, 80, 80}, + {80, 64, 96, 80}, + {96, 64, 112, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->count2 = 0; + npc->act_no = 100; + npc->bits |= NPC_INVULNERABLE; + npc->ani_no = Random(0, 2); + // Fallthrough + case 100: + npc->ym += 0x40; + + if (npc->ym > 0x700) + npc->ym = 0x700; + + if (npc->y > 128 * 0x200) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->flag & 8) + { + int i; + + npc->ym = -0x200; + npc->act_no = 110; + npc->bits |= NPC_IGNORE_SOLIDITY; + PlaySoundObject(12, SOUND_MODE_PLAY); + SetQuake(10); + + for (i = 0; i < 2; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (16 * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + break; + + case 110: + npc->ym += 0x40; + + if (npc->y > (gMap.length * 0x200 * 0x10) + (2 * 0x200 * 0x10)) + { + npc->cond = 0; + return; + } + + break; + } + + if (++npc->ani_wait > 6) + { + ++npc->ani_wait; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (gMC.y > npc->y) + npc->damage = 10; + else + npc->damage = 0; + + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Ma Pignon clone +void ActNpc315(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {128, 0, 144, 16}, + {160, 0, 176, 16}, + {176, 0, 192, 16}, + {192, 0, 208, 16}, + }; + + RECT rcRight[4] = { + {128, 16, 144, 32}, + {160, 16, 176, 32}, + {176, 16, 192, 32}, + {192, 16, 208, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->ani_no = 3; + npc->ym += 0x80; + + if (npc->y > 128 * 0x200) + { + npc->act_no = 130; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + } + + break; + + case 100: + npc->act_no = 110; + npc->act_wait = 0; + npc->count1 = 0; + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 110: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + npc->ani_no = 0; + + if (++npc->act_wait > 4) + { + npc->act_wait = 0; + npc->act_no = 120; + } + + break; + + case 120: + npc->ani_no = 1; + + if (++npc->act_wait > 4) + { + npc->act_no = 130; + npc->ani_no = 3; + npc->xm = 2 * Random(-0x200, 0x200); + npc->ym = -0x800; + PlaySoundObject(30, SOUND_MODE_PLAY); + } + + break; + + case 130: + npc->ym += 0x80; + + if (npc->xm < 0 && npc->flag & 1) + npc->xm *= -1; + if (npc->xm > 0 && npc->flag & 4) + npc->xm *= -1; + + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (npc->ym < -0x200) + npc->ani_no = 2; + else if (npc->ym > 0x200) + npc->ani_no = 0; + else + npc->ani_no = 3; + + if (npc->flag & 8) + { + npc->act_no = 140; + npc->act_wait = 0; + npc->ani_no = 1; + npc->xm = 0; + } + + break; + + case 140: + npc->ani_no = 1; + + if (++npc->act_wait > 4) + { + npc->act_no = 110; + npc->bits |= NPC_SHOOTABLE; + } + + break; + } + + if (npc->act_no > 100) + { + if (IsActiveSomeBullet()) + { + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + } + else + { + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_INVULNERABLE; + } + } + + if (++npc->count2 > 300) + { + VanishNpChar(npc); + } + else + { + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + } +} + +// Bute (dead) +void ActNpc316(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {248, 32, 272, 56}, + {272, 32, 296, 56}, + {296, 32, 320, 56}, + }; + + RECT rcRight[3] = { + {248, 56, 272, 80}, + {272, 56, 296, 80}, + {296, 56, 320, 80}, + }; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SHOOTABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->damage = 0; + npc->act_no = 1; + npc->ani_no = 0; + npc->view.front = 12 * 0x200; + npc->view.back = 12 * 0x200; + npc->view.top = 12 * 0x200; + npc->ym = -0x200; + + if (npc->direct == 0) + npc->xm = 0x100; + else + npc->xm = -0x100; + + PlaySoundObject(50, SOUND_MODE_PLAY); + + break; + + case 1: + if (npc->flag & 8) + { + npc->ani_no = 1; + npc->ani_wait = 0; + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + npc->xm = 8 * npc->xm / 9; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + if (++npc->act_wait > 50) + npc->cond |= 8; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Mesa +void ActNpc317(NPCHAR *npc) +{ + RECT rcLeft[4] = { + {0, 80, 32, 120}, + {32, 80, 64, 120}, + {64, 80, 96, 120}, + {96, 80, 128, 120}, + }; + + RECT rcRight[4] = { + {0, 120, 32, 160}, + {32, 120, 64, 160}, + {64, 120, 96, 160}, + {96, 120, 128, 160}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + npc->tgt_x = npc->x; + // Fallthrough + case 1: + npc->xm = 0; + npc->act_no = 2; + npc->ani_no = 0; + npc->count1 = 0; + // Fallthrough + case 2: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (++npc->ani_wait > 40) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (gMC.x > npc->x - (320 * 0x200) && gMC.x < npc->x + (320 * 0x200) && gMC.y > npc->y - (160 * 0x200) && gMC.y < npc->y + (160 * 0x200) && ++npc->count1 > 50) + npc->act_no = 10; + + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + npc->ani_no = 2; + SetNpChar(319, npc->x, npc->y, 0, 0, 0, npc, 0x100); + // Fallthrough + case 11: + if (++npc->act_wait > 50) + { + npc->act_wait = 0; + npc->act_no = 12; + npc->ani_no = 3; + PlaySoundObject(39, SOUND_MODE_PLAY); + } + + break; + + case 12: + if (++npc->act_wait > 20) + npc->act_no = 1; + + break; + } + + npc->ym += 0x55; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + if (npc->life <= 936) + { + npc->code_char = 318; + npc->act_no = 0; + } +} + +// Mesa (dead) +void ActNpc318(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {224, 80, 256, 120}, + {256, 80, 288, 120}, + {288, 80, 320, 120}, + }; + + RECT rcRight[3] = { + {224, 120, 256, 160}, + {256, 120, 288, 160}, + {288, 120, 320, 160}, + }; + + switch (npc->act_no) + { + case 0: + npc->bits &= ~NPC_SHOOTABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->bits &= ~NPC_SOLID_SOFT; + npc->damage = 0; + npc->act_no = 1; + npc->ani_no = 0; + npc->ym = -0x200; + + if (npc->direct == 0) + npc->xm = 0x40; + else + npc->xm = -0x40; + + PlaySoundObject(54, SOUND_MODE_PLAY); + break; + + case 1: + if (npc->flag & 8) + { + npc->ani_no = 1; + npc->ani_wait = 0; + npc->act_no = 2; + npc->act_wait = 0; + } + + break; + + case 2: + npc->xm = 8 * npc->xm / 9; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + if (++npc->act_wait > 50) + npc->cond |= 8; + + break; + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Mesa block +void ActNpc319(NPCHAR *npc) +{ + RECT rc[3] = { + {16, 0, 32, 16}, + {16, 0, 32, 16}, + {96, 80, 112, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->y = npc->pNpc->y + (10 * 0x200); + + if (npc->pNpc->direct == 0) + npc->x = npc->pNpc->x + (7 * 0x200); + else + npc->x = npc->pNpc->x - (7 * 0x200); + + if (npc->pNpc->code_char == 318) + { + SetDestroyNpChar(npc->x, npc->y, 0, 3); + npc->cond = 0; + return; + } + + if (npc->pNpc->ani_no != 2) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->ym = -0x400; + npc->y = npc->pNpc->y - (4 * 0x200); + + if (npc->pNpc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + } + + break; + + case 2: + if (++npc->act_wait == 4) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + npc->ym += 0x2A; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 8) + { + PlaySoundObject(12, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, 0, 3); + npc->cond = 0; + } + + break; + } + + if (++npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; +} diff --git a/src/NpcAct320.cpp b/src/NpcAct320.cpp new file mode 100644 index 0000000..cb4f4f1 --- /dev/null +++ b/src/NpcAct320.cpp @@ -0,0 +1,1159 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Frame.h" +#include "Game.h" +#include "KeyControl.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" + +// Curly (carried, shooting) +void ActNpc320(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {16, 96, 32, 112}, + {48, 96, 64, 112}, + {96, 96, 112, 112}, + }; + + RECT rcRight[3] = { + {16, 112, 32, 128}, + {48, 112, 64, 128}, + {96, 112, 112, 128}, + }; + + if (npc->act_no == 0) + { + npc->act_no = 1; + npc->x = gMC.x; + npc->y = gMC.y; + SetNpChar(321, 0, 0, 0, 0, 0, npc, 0x100); + } + + if (gMC.flag & 8) + { + if (gMC.up) + { + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y - (10 * 0x200); + npc->ani_no = 1; + } + else + { + npc->ani_no = 0; + + if (gMC.direct == 0) + { + npc->tgt_x = gMC.x + (7 * 0x200); + npc->tgt_y = gMC.y - (3 * 0x200); + } + else + { + npc->tgt_x = gMC.x - (7 * 0x200); + npc->tgt_y = gMC.y - (3 * 0x200); + } + } + } + else + { + if (gMC.up) + { + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y + (8 * 0x200); + npc->ani_no = 2; + } + else if (gMC.down) + { + npc->tgt_x = gMC.x; + npc->tgt_y = gMC.y - (8 * 0x200); + npc->ani_no = 1; + } + else + { + npc->ani_no = 0; + + if (gMC.direct == 0) + { + npc->tgt_x = gMC.x + (7 * 0x200); + npc->tgt_y = gMC.y - (3 * 0x200); + } + else + { + npc->tgt_x = gMC.x - (7 * 0x200); + npc->tgt_y = gMC.y - (3 * 0x200); + } + } + } + + npc->x += (npc->tgt_x - npc->x) / 2; + npc->y += (npc->tgt_y - npc->y) / 2; + + if (gMC.ani_no % 2) + npc->y -= 1 * 0x200; + + if (gMC.direct == 0) + npc->rect = rcRight[npc->ani_no]; + else + npc->rect = rcLeft[npc->ani_no]; +} + +// Curly's Nemesis +void ActNpc321(NPCHAR *npc) +{ + RECT rcLeft[3] = { + {136, 152, 152, 168}, + {152, 152, 168, 168}, + {168, 152, 184, 168}, + }; + + RECT rcRight[3] = { + {136, 168, 152, 184}, + {152, 168, 168, 184}, + {168, 168, 184, 184}, + }; + + int direct; + + if (npc->pNpc == NULL) + return; + + switch (npc->pNpc->ani_no) + { + case 0: + if (gMC.direct == 0) + { + npc->x = npc->pNpc->x + (8 * 0x200); + direct = 2; + } + else + { + npc->x = npc->pNpc->x - (8 * 0x200); + direct = 0; + } + + npc->y = npc->pNpc->y; + break; + + case 1: + if (gMC.direct == 0) // Does the same thing whether this is false or true + npc->x = npc->pNpc->x; + else + npc->x = npc->pNpc->x; + + direct = 1; + npc->y = npc->pNpc->y - (10 * 0x200); + break; + + case 2: + if (gMC.direct == 0) // Does the same thing whether this is false or true + npc->x = npc->pNpc->x; + else + npc->x = npc->pNpc->x; + + direct = 3; + npc->y = npc->pNpc->y + (10 * 0x200); + break; + } + + npc->ani_no = npc->pNpc->ani_no; + + if (g_GameFlags & 2 && CountBulletNum(43) < 2 && gKeyTrg & gKeyShot) + { + SetBullet(43, npc->pNpc->x, npc->pNpc->y, direct); + SetCaret(npc->pNpc->x, npc->pNpc->y, CARET_SHOOT, DIR_LEFT); + PlaySoundObject(117, SOUND_MODE_PLAY); + } + + if (gMC.direct == 0) + npc->rect = rcRight[npc->ani_no]; + else + npc->rect = rcLeft[npc->ani_no]; +} + +// Deleet +void ActNpc322(NPCHAR *npc) +{ + RECT rc[3] = { + {272, 216, 296, 240}, + {296, 216, 320, 240}, + {160, 216, 184, 240}, + }; + + if (npc->act_no < 2 && npc->life <= 968) + { + npc->act_no = 2; + npc->act_wait = 0; + npc->bits &= ~NPC_SHOOTABLE; + npc->bits |= NPC_INVULNERABLE; + PlaySoundObject(22, SOUND_MODE_PLAY); + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + npc->y += 8 * 0x200; + else + npc->x += 8 * 0x200; + // Fallthrough + case 1: + if (npc->shock) + ++npc->count1; + else + npc->count1 = 0; + + npc->rect = rc[npc->count1 / 2 % 2]; + break; + + case 2: + npc->ani_no = 2; + + switch (npc->act_wait) + { + // Interestingly, this NPC counts down at 50 frames per second, + // while NPC206 (the Egg Corridor Counter Bomb), counts at 60. + case 50 * 0: + SetNpChar(207, npc->x + (4 * 0x200), npc->y, 0, 0, 0, NULL, 0x180); + break; + + case 50 * 1: + SetNpChar(207, npc->x + (4 * 0x200), npc->y, 0, 0, 1, NULL, 0x180); + break; + + case 50 * 2: + SetNpChar(207, npc->x + (4 * 0x200), npc->y, 0, 0, 2, NULL, 0x180); + break; + + case 50 * 3: + SetNpChar(207, npc->x + (4 * 0x200), npc->y, 0, 0, 3, NULL, 0x180); + break; + + case 50 * 4: + SetNpChar(207, npc->x + (4 * 0x200), npc->y, 0, 0, 4, NULL, 0x180); + break; + + case 50 * 5: + npc->hit.back = 48 * 0x200; + npc->hit.front = 48 * 0x200; + npc->hit.top = 48 * 0x200; + npc->hit.bottom = 48 * 0x200; + npc->damage = 12; + PlaySoundObject(26, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y, 0x6000, 40); + SetQuake(10); + + if (npc->direct == 0) + { + DeleteMapParts(npc->x / 0x200 / 0x10, (npc->y - (8 * 0x200)) / 0x200 / 0x10); + DeleteMapParts(npc->x / 0x200 / 0x10, (npc->y + (8 * 0x200)) / 0x200 / 0x10); + } + else + { + DeleteMapParts((npc->x - (8 * 0x200)) / 0x200 / 0x10, npc->y / 0x200 / 0x10); + DeleteMapParts((npc->x + (8 * 0x200)) / 0x200 / 0x10, npc->y / 0x200 / 0x10); + } + + npc->cond |= 8; + break; + } + + ++npc->act_wait; + npc->rect = rc[2]; + break; + } +} + +// Bute (spinning) +void ActNpc323(NPCHAR *npc) +{ + RECT rc[4] = { + {216, 32, 232, 56}, + {232, 32, 248, 56}, + {216, 56, 232, 80}, + {232, 56, 248, 80}, + }; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 3) + npc->ani_no = 0; + } + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + switch (npc->direct) + { + case 0: + npc->xm = -0x600; + break; + + case 2: + npc->xm = 0x600; + break; + + case 1: + npc->ym = -0x600; + break; + + case 3: + npc->ym = 0x600; + break; + } + // Fallthrough + case 1: + if (++npc->act_wait == 16) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->flag & 0xFF) + npc->act_no = 10; + + if (npc->act_wait > 20) + { + switch (npc->direct) + { + case 0: + if (npc->x <= gMC.x + (32 * 0x200)) + npc->act_no = 10; + break; + + case 2: + if (npc->x >= gMC.x - (32 * 0x200)) + npc->act_no = 10; + break; + + case 1: + if (npc->y <= gMC.y + (32 * 0x200)) + npc->act_no = 10; + break; + + case 3: + if (npc->y >= gMC.y - (32 * 0x200)) + npc->act_no = 10; + break; + } + } + + break; + } + + if (npc->act_no == 10) + { + npc->code_char = 309; + npc->ani_no = 0; + npc->act_no = 11; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->damage = 5; + npc->view.top = 8 * 0x200; + } + + npc->rect = rc[npc->ani_no]; +} + +// Bute generator +void ActNpc324(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 10: + npc->act_no = 11; + npc->act_wait = 0; + // Fallthrough + case 11: + if (++npc->act_wait % 50 == 1) + SetNpChar(323, npc->x, npc->y, 0, 0, npc->direct, NULL, 0x100); + + if (npc->act_wait > 351) + npc->act_no = 0; + + break; + } +} + +// Heavy Press lightning +void ActNpc325(NPCHAR *npc) +{ + RECT rc[7] = { + {240, 96, 272, 128}, + {272, 96, 304, 128}, + {240, 128, 272, 160}, + {240, 0, 256, 96}, + {256, 0, 272, 96}, + {272, 0, 288, 96}, + {288, 0, 304, 96}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 1: + if (++npc->ani_wait > 0) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + if (++npc->act_wait > 50) + { + npc->act_no = 10; + npc->ani_wait = 0; + npc->ani_no = 3; + npc->damage = 10; + npc->view.front = 8 * 0x200; + npc->view.top = 12 * 0x200; + PlaySoundObject(101, SOUND_MODE_PLAY); + SetDestroyNpChar(npc->x, npc->y + (84 * 0x200), 0, 3); + } + + break; + + case 10: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 6) + { + npc->cond = 0; + return; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Sue/Itoh becoming human +void ActNpc326(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + npc->x += 16 * 0x200; + npc->ani_no = 0; + // Fallthrough + case 1: + if (++npc->act_wait > 80) + { + npc->act_no = 10; + npc->act_wait = 0; + break; + } + + if (npc->direct == 0) + { + if (npc->act_wait == 30) + npc->ani_no = 1; + if (npc->act_wait == 40) + npc->ani_no = 0; + } + else + { + if (npc->act_wait == 50) + npc->ani_no = 1; + if (npc->act_wait == 60) + npc->ani_no = 0; + } + + break; + + case 10: + if (++npc->act_wait > 50) + { + npc->act_no = 15; + npc->ani_no = 4; + + if (npc->direct == 0) + npc->act_wait = 0; + else + npc->act_wait = -20; + + break; + } + + if (npc->act_wait / 2 % 2) + npc->ani_no = 2; + else + npc->ani_no = 3; + + break; + + case 15: + if (++npc->act_wait > 40) + { + npc->act_wait = 0; + npc->act_no = 20; + } + + break; + + case 20: + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + + if (++npc->act_wait > 50) + { + npc->act_no = 30; + npc->act_wait = 0; + npc->ani_no = 6; + + if (npc->direct == 0) + SetNpChar(327, npc->x, npc->y - (16 * 0x200), 0, 0, 0, npc, 0x100); + else + SetNpChar(327, npc->x, npc->y - (8 * 0x200), 0, 0, 0, npc, 0x100); + + break; + } + + break; + + case 30: + if (++npc->act_wait == 30) + npc->ani_no = 7; + + if (npc->act_wait == 40) + npc->act_no = 40; + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + npc->ani_no = 0; + // Fallthrough + case 41: + if (++npc->act_wait == 30) + npc->ani_no = 1; + + if (npc->act_wait == 40) + npc->ani_no = 0; + + break; + } + + RECT rcItoh[8] = { + {0, 128, 16, 152}, + {16, 128, 32, 152}, + {32, 128, 48, 152}, + {48, 128, 64, 152}, + {64, 128, 80, 152}, + {80, 128, 96, 152}, + {96, 128, 112, 152}, + {112, 128, 128, 152}, + }; + + RECT rcSu[8] = { + {128, 128, 144, 152}, + {144, 128, 160, 152}, + {160, 128, 176, 152}, + {176, 128, 192, 152}, + {192, 128, 208, 152}, + {208, 128, 224, 152}, + {224, 128, 240, 152}, + {32, 152, 48, 176}, + }; + + if (npc->direct == 0) + npc->rect = rcItoh[npc->ani_no]; + else + npc->rect = rcSu[npc->ani_no]; +} + +// Sneeze +void ActNpc327(NPCHAR *npc) +{ + RECT rc[2] = { + {240, 80, 256, 96}, + {256, 80, 272, 96}, + }; + + ++npc->act_wait; + + switch (npc->act_no) + { + case 0: + if (npc->act_wait < 4) + npc->y -= 2 * 0x200; + + if (npc->pNpc->ani_no == 7) + { + npc->ani_no = 1; + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + } + break; + + case 1: + if (npc->act_wait < 48) + { + npc->x = npc->tgt_x + (Random(-1, 1) * 0x200); + npc->y = npc->tgt_y + (Random(-1, 1) * 0x200); + } + else + { + npc->x = npc->tgt_x; + npc->y = npc->tgt_y; + } + break; + } + + if (npc->act_wait > 70) + npc->cond = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Thingy that turns Sue and Itoh into humans for 4 seconds +void ActNpc328(NPCHAR *npc) +{ + RECT rc = {96, 0, 128, 48}; + npc->rect = rc; +} + +// Laboratory fan +void ActNpc329(NPCHAR *npc) +{ + RECT rc[2] = { + {48, 0, 64, 16}, + {64, 0, 80, 16}, + }; + + if (++npc->ani_wait / 2 % 2) + npc->rect = rc[0]; + else + npc->rect = rc[1]; +} + +// Rolling +void ActNpc330(NPCHAR *npc) +{ + RECT rc[3] = { + {144, 136, 160, 152}, + {160, 136, 176, 152}, + {176, 136, 192, 152}, + }; + + switch (npc->act_no) + { + case 0: + ChangeMapParts(npc->x / 0x200 / 0x10, npc->y / 0x200 / 0x10, 0); + + if (npc->direct == 0) + npc->act_no = 10; + else + npc->act_no = 30; + + break; + + case 10: + npc->xm -= 0x40; + npc->ym = 0; + + if (npc->flag & 1) + npc->act_no = 20; + + break; + + case 20: + npc->xm = 0; + npc->ym -= 0x40; + + if (npc->flag & 2) + npc->act_no = 30; + + break; + + case 30: + npc->xm += 0x40; + npc->ym = 0; + + if (npc->flag & 4) + npc->act_no = 40; + + break; + + case 40: + npc->xm = 0; + npc->ym += 0x40; + + if (npc->flag & 8) + npc->act_no = 10; + + break; + } + + if (npc->xm < -0x400) + npc->xm = -0x400; + if (npc->xm > 0x400) + npc->xm = 0x400; + + if (npc->ym < -0x400) + npc->ym = -0x400; + if (npc->ym > 0x400) + npc->ym = 0x400; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Ballos bone projectile +void ActNpc331(NPCHAR *npc) +{ + RECT rc[4] = { + {288, 80, 304, 96}, + {304, 80, 320, 96}, + {288, 96, 304, 112}, + {304, 96, 320, 112}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (npc->flag & 8) + { + npc->ym = -0x200; + npc->act_no = 10; + } + + break; + + case 10: + if (npc->flag & 8) + { + npc->cond = 0; + SetCaret(npc->x, npc->y, CARET_PROJECTILE_DISSIPATION, DIR_LEFT); + } + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->y += npc->ym; + npc->x += npc->xm; + + if (++npc->ani_wait > 3) + { + npc->ani_wait = 0; + + if (npc->direct == 0) + ++npc->ani_no; + else + --npc->ani_no; + + if (npc->ani_no < 0) + npc->ani_no += 4; + if (npc->ani_no > 3) + npc->ani_no -= 4; + } + + npc->rect = rc[npc->ani_no]; +} + +// Ballos shockwave +void ActNpc332(NPCHAR *npc) +{ + RECT rc[3] = { + {144, 96, 168, 120}, + {168, 96, 192, 120}, + {192, 96, 216, 120}, + }; + + int xm; + + switch (npc->act_no) + { + case 0: + PlaySoundObject(44, SOUND_MODE_PLAY); + npc->act_no = 1; + + if (npc->direct == 0) + npc->xm = -0x400; + else + npc->xm = 0x400; + // Fallthrough + case 1: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 2) + npc->ani_no = 0; + } + + if (++npc->act_wait % 6 == 1) + { + if (npc->direct == 0) + xm = (Random(-0x10, -4) * 0x200) / 8; + else + xm = (Random(4, 0x10) * 0x200) / 8; + + SetNpChar(331, npc->x, npc->y, xm, -0x400, 0, 0, 0x100); + + PlaySoundObject(12, SOUND_MODE_PLAY); + } + + break; + } + + if (npc->flag & 1) + npc->cond = 0; + if (npc->flag & 4) + npc->cond = 0; + + npc->x += npc->xm; + + npc->rect = rc[npc->ani_no]; +} + +// Ballos lightning +void ActNpc333(NPCHAR *npc) +{ + RECT rc[2] = { + {80, 120, 104, 144}, + {104, 120, 128, 144}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->tgt_x = npc->x; + npc->tgt_y = npc->y; + PlaySoundObject(103, SOUND_MODE_PLAY); + npc->y = gMC.y; + // Fallthrough + case 1: + if (++npc->act_wait / 2 % 2) + npc->ani_no = 0; + else + npc->ani_no = 1; + + if (npc->direct == 0 && npc->act_wait == 20) + SetNpChar(146, npc->tgt_x, npc->tgt_y, 0, 0, 0, NULL, 0x100); + + if (npc->act_wait > 40) + npc->cond = 0; + + break; + + } + + npc->rect = rc[npc->ani_no]; +} + +// Sweat +void ActNpc334(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {160, 184, 168, 200}, + {168, 184, 176, 200}, + }; + + RECT rcRight[2] = { + {176, 184, 184, 200}, + {184, 184, 192, 200}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + + if (npc->direct == 0) + { + npc->x += 10 * 0x200; + npc->y -= 18 * 0x200; + } + else + { + npc->x = gMC.x - (10 * 0x200); + npc->y = gMC.y - (2 * 0x200); + } + // Fallthrough + case 10: + if (++npc->act_wait / 8 % 2) + npc->ani_no = 0; + else + npc->ani_no = 1; + + if (npc->act_wait >= 64) + npc->cond = 0; + + break; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Ikachan +void ActNpc335(NPCHAR *npc) +{ + RECT rc[3] = { + {0, 16, 16, 32}, + {16, 16, 32, 32}, + {32, 16, 48, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(3, 20); + // Fallthrough + case 1: + if (--npc->act_wait <= 0) + { + npc->act_no = 2; + npc->act_wait = Random(10, 50); + npc->ani_no = 1; + npc->xm = 0x600; + } + + break; + + case 2: + if (--npc->act_wait <= 0) + { + npc->act_no = 3; + npc->act_wait = Random(40, 50); + npc->ani_no = 2; + npc->ym = Random(-0x100, 0x100); + } + + break; + + case 3: + if (--npc->act_wait <= 0) + { + npc->act_no = 1; + npc->act_wait = 0; + npc->ani_no = 0; + } + + break; + } + + npc->xm -= 0x10; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Ikachan generator +void ActNpc336(NPCHAR *npc) +{ + int y; + + switch (npc->act_no) + { + case 0: + if (gMC.shock) + npc->cond = 0; + + break; + + case 10: + if (++npc->act_wait % 4 == 1) + { + y = npc->y + (Random(0, 13) * 0x200 * 0x10); + SetNpChar(335, npc->x, y, 0, 0, 0, 0, 0); + } + + break; + } +} + +// Numhachi +void ActNpc337(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {256, 112, 288, 152}, + {288, 112, 320, 152}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->y -= 8 * 0x200; + // Fallthrough + case 1: + npc->xm = 0; + npc->act_no = 2; + npc->ani_no = 0; + // Fallthrough + case 2: + if (++npc->ani_wait > 50) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + } + + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rcLeft[npc->ani_no]; +} + +// Green Devil +void ActNpc338(NPCHAR *npc) +{ + RECT rcLeft[2] = { + {288, 0, 304, 16}, + {304, 0, 320, 16}, + }; + + RECT rcRight[2] = { + {288, 16, 304, 32}, + {304, 16, 320, 32}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->view.top = 8 * 0x200; + npc->view.bottom = 8 * 0x200; + npc->damage = 3; + npc->bits |= NPC_SHOOTABLE; + npc->tgt_y = npc->y; + npc->ym = (Random(-10, 10) * 0x200) / 2; + // Fallthrough + case 1: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + if (npc->y < npc->tgt_y) + npc->ym += 0x80; + else + npc->ym -= 0x80; + + if (npc->direct == 0) + npc->xm -= 0x20; + else + npc->xm += 0x20; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->x < 0 || npc->y < 0 || npc->x > gMap.width * 0x200 * 0x10 || npc->y > gMap.length * 0x200 * 0x10) + { + VanishNpChar(npc); + return; + } + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Green Devil generator +void ActNpc339(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->act_wait = Random(0, 40); + // Fallthrough + case 1: + if (npc->act_wait) + { + --npc->act_wait; + } + else + { + npc->act_no = 0; + SetNpChar(338, npc->x, npc->y + (Random(-0x10, 0x10) * 0x200), 0, 0, npc->direct, NULL, 0x100); + } + + break; + } +} diff --git a/src/NpcAct340.cpp b/src/NpcAct340.cpp new file mode 100644 index 0000000..e8b7bc9 --- /dev/null +++ b/src/NpcAct340.cpp @@ -0,0 +1,1996 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcAct.h" + +#include + +#include "WindowsWrapper.h" + +#include "Caret.h" +#include "CommonDefines.h" +#include "Draw.h" +#include "Flash.h" +#include "Flags.h" +#include "Frame.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "Triangle.h" + +// Ballos +void ActNpc340(NPCHAR *npc) +{ + int i; + int x; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->cond = 0x80; + npc->exp = 1; + npc->direct = 0; + npc->y -= 6 * 0x200; + npc->damage = 0; + SetNpChar(341, npc->x, npc->y - (16 * 0x200), 0, 0, 0, npc, 0x100); + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + // Fallthrough + case 11: + if (++npc->act_wait > 100) + npc->act_no = 100; + + break; + + case 100: + npc->act_no = 110; + npc->act_wait = 0; + npc->ani_no = 1; + npc->ani_wait = 0; + npc->damage = 4; + npc->bits |= NPC_SHOOTABLE; + // Fallthrough + case 110: + npc->act_no = 111; + npc->damage = 3; + npc->tgt_x = npc->life; + // Fallthrough + case 111: + if (++npc->ani_wait > 10) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 2) + npc->ani_no = 1; + + ++npc->act_wait; + + if (npc->life < npc->tgt_x - 50 || npc->act_wait > 150) + { + switch (npc->count2 % 5) + { + case 0: + case 1: + case 2: + case 3: + npc->act_no = 200; + break; + + case 4: + npc->act_no = 300; + break; + } + + ++npc->count2; + } + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + break; + + case 200: + npc->act_no = 201; + npc->count1 = 0; + // Fallthrough + case 201: + if (npc->xm == 0) + npc->act_no = 202; + else + npc->act_no = 203; + + npc->act_wait = 0; + npc->ani_no = 3; + npc->damage = 3; + ++npc->count1; + // Fallthrough + case 202: + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + npc->xm = 8 * npc->xm / 9; + npc->ym = 8 * npc->ym / 9; + + if (++npc->act_wait > 20) + npc->act_no = 210; + + break; + + case 203: + npc->xm = 8 * npc->xm / 9; + npc->ym = 8 * npc->ym / 9; + + if (++npc->act_wait > 20) + { + if (gMC.y < npc->y + (12 * 0x200)) + npc->act_no = 220; + else + npc->act_no = 230; + } + + break; + + case 210: + npc->act_no = 211; + npc->act_wait = 0; + npc->ani_no = 6; + npc->ani_wait = 0; + npc->ym = 0; + npc->damage = 10; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + PlaySoundObject(25, SOUND_MODE_PLAY); + // Fallthrough + case 211: + if (npc->direct == 0) + npc->xm = -0x800; + else + npc->xm = 0x800; + + if (++npc->act_wait / 2 % 2) + npc->ani_no = 6; + else + npc->ani_no = 7; + + if (npc->direct == 0 && npc->flag & 1) + { + npc->act_no = 212; + npc->act_wait = 0; + npc->damage = 3; + SetQuake2(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + if (npc->direct == 2 && npc->flag & 4) + { + npc->act_no = 212; + npc->act_wait = 0; + npc->damage = 3; + SetQuake2(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + if (npc->count1 < 4 && gMC.x > npc->x - (16 * 0x200) && gMC.x < npc->x + (16 * 0x200)) + npc->act_no = 201; + + break; + + case 212: + ++npc->act_wait; + npc->xm = 0; + npc->ani_no = 6; + + if (npc->act_wait > 30) + { + if (npc->count1 > 3) + npc->act_no = 240; + else + npc->act_no = 201; + } + + break; + + case 220: + npc->act_no = 221; + npc->act_wait = 0; + npc->ani_no = 8; + npc->ani_wait = 0; + npc->xm = 0; + npc->damage = 10; + npc->direct = 0; + PlaySoundObject(25, SOUND_MODE_PLAY); + // Fallthrough + case 221: + npc->ym = -0x800; + + if (++npc->act_wait / 2 % 2) + npc->ani_no = 8; + else + npc->ani_no = 9; + + if (npc->y < (48 * 0x200)) + { + npc->y = (48 * 0x200); + npc->ym = 0; + npc->act_no = 222; + npc->act_wait = 0; + npc->damage = 3; + + for (i = 0; i < 8; ++i) + { + x = npc->x + (Random(-0x10, 0x10) * 0x200); + SetNpChar(4, x, npc->y - (10 * 0x200), 0, 0, 0, NULL, 0x100); + } + + SetNpChar(332, npc->x - (12 * 0x200), npc->y - (12 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(332, npc->x + (12 * 0x200), npc->y - (12 * 0x200), 0, 0, 2, NULL, 0x100); + SetQuake2(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + if (npc->count1 < 4 && gMC.y > npc->y - (16 * 0x200) && gMC.y < npc->y + (16 * 0x200)) + npc->act_no = 201; + + break; + + case 222: + ++npc->act_wait; + npc->xm = 0; + npc->ani_no = 8; + + if (npc->act_wait > 30) + { + if (npc->count1 > 3) + npc->act_no = 240; + else + npc->act_no = 201; + } + + break; + + case 230: + npc->act_no = 231; + npc->act_wait = 0; + npc->ani_no = 8; + npc->ani_wait = 0; + npc->xm = 0; + npc->damage = 10; + npc->direct = 2; + PlaySoundObject(25, SOUND_MODE_PLAY); + // Fallthrough + case 231: + npc->ym = 0x800; + + if (++npc->act_wait / 2 % 2) + npc->ani_no = 8; + else + npc->ani_no = 9; + + if (npc->flag & 8) + { + npc->act_no = 232; + npc->act_wait = 0; + npc->damage = 3; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + + for (i = 0; i < 8; ++i) + { + x = npc->x + (Random(-0x10, 0x10) * 0x200); + SetNpChar(4, x, npc->y + (10 * 0x200), 0, 0, 0, NULL, 0x100); + } + + SetNpChar(332, npc->x - (12 * 0x200), npc->y + (12 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(332, npc->x + (12 * 0x200), npc->y + (12 * 0x200), 0, 0, 2, NULL, 0x100); + SetQuake2(10); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + if (npc->count1 < 4 && gMC.y > npc->y - (16 * 0x200) && gMC.y < npc->y + (16 * 0x200)) + npc->act_no = 201; + + break; + + case 232: + ++npc->act_wait; + npc->xm = 0; + npc->ani_no = 3; + + if (npc->act_wait > 30) + { + if (npc->count1 > 3) + npc->act_no = 242; + else + npc->act_no = 201; + } + + break; + + case 240: + npc->act_no = 241; + npc->direct = 0; + // Fallthrough + case 241: + npc->ym += 0x80; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (++npc->ani_wait / 2 % 2) + npc->ani_no = 4; + else + npc->ani_no = 5; + + if (npc->flag & 8) + { + npc->act_no = 242; + npc->act_wait = 0; + npc->ani_no = 3; + + if (gMC.x < npc->x) + npc->direct = 0; + else + npc->direct = 2; + } + + break; + + case 242: + npc->xm = 3 * npc->xm / 4; + npc->ani_no = 3; + + if (++npc->act_wait > 10) + npc->act_no = 110; + + break; + + case 300: + npc->act_no = 310; + npc->act_wait = 0; + npc->ym = -0x600; + + if (npc->x > 320 * 0x200) + { + npc->direct = 2; + npc->tgt_x = gMC.x; + npc->tgt_y = 176 * 0x200; + } + else + { + npc->direct = 0; + npc->tgt_x = gMC.x; + npc->tgt_y = 176 * 0x200; + } + + npc->ani_wait = 0; + // Fallthrough + case 310: + ++npc->ani_wait; + + if (++npc->act_wait > 200 && npc->ani_wait < 20) + npc->direct = 2; + else + npc->direct = 0; + + if (npc->ani_wait / 2 % 2) + npc->ani_no = 4; + else + npc->ani_no = 5; + + if (npc->x < npc->tgt_x) + npc->xm += 0x40; + else + npc->xm -= 0x40; + + if (npc->y < npc->tgt_y) + npc->ym += 0x40; + else + npc->ym -= 0x40; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x400) + npc->ym = 0x400; + if (npc->ym < -0x400) + npc->ym = -0x400; + + if (npc->act_wait > 200 && npc->act_wait % 40 == 1) + { + npc->ani_wait = 0; + SetNpChar(333, gMC.x, 304 * 0x200, 0, 0, 0, NULL, 0x100); + } + + if (npc->act_wait > 480) + { + npc->act_no = 320; + npc->act_wait = 0; + } + + break; + + case 320: + npc->xm = 0; + npc->ym = 0; + npc->direct = 2; + + if (++npc->act_wait == 40) + SetFlash(0, 0, FLASH_MODE_FLASH); + + if (npc->act_wait > 50 && npc->act_wait % 10 == 1) + { + x = ((4 * npc->act_wait - 200) / 10 + 2) * 0x200 * 0x10; + SetNpChar(333, x, 304 * 0x200, 0, 0, 0, NULL, 0x100); + } + + if (npc->act_wait > 140) + npc->act_no = 240; + + if (++npc->ani_wait / 2 % 2) + npc->ani_no = 4; + else + npc->ani_no = 5; + + break; + + case 1000: + npc->act_no = 1001; + npc->act_wait = 0; + npc->ani_no = 10; + npc->tgt_x = npc->x; + npc->xm = 0; + npc->bits &= ~NPC_SHOOTABLE; + SetDestroyNpChar(npc->x, npc->y, 0x10, 0x10); + PlaySoundObject(72, SOUND_MODE_PLAY); + // Fallthrough + case 1001: + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (++npc->act_wait / 2 % 2) + npc->x = npc->tgt_x + 0x200; + else + npc->x = npc->tgt_x - 0x200; + + if (npc->flag & 8) + { + npc->act_no = 1002; + npc->act_wait = 0; + } + + break; + + case 1002: + if (++npc->act_wait > 150) + { + npc->act_wait = 0; + npc->act_no = 1003; + npc->ani_no = 3; + } + + if (npc->act_wait / 2 % 2) + npc->x = npc->tgt_x + 0x200; + else + npc->x = npc->tgt_x - 0x200; + + break; + + case 1003: + if (++npc->act_wait > 30) + { + npc->act_wait = 0; + npc->act_no = 1004; + npc->ani_no = 3; + npc->ym -= 0xA00; + npc->direct = 0; + npc->bits |= NPC_IGNORE_SOLIDITY; + } + + break; + + case 1004: + if (npc->y < 0) + { + npc->xm = 0; + npc->ym = 0; + npc->act_no = 1005; + npc->act_wait = 0; + SetFlash(0, 0, FLASH_MODE_FLASH); + PlaySoundObject(29, SOUND_MODE_PLAY); + } + + if (++npc->act_wait / 2 % 2) + npc->ani_no = 8; + else + npc->ani_no = 9; + + break; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + RECT rcLeft[11] = { + {0, 0, 48, 40}, + {48, 0, 96, 40}, + {96, 0, 144, 40}, + {144, 0, 192, 40}, + {192, 0, 240, 40}, + {240, 0, 288, 40}, + {0, 80, 48, 120}, + {48, 80, 96, 120}, + {96, 80, 144, 120}, + {144, 80, 192, 120}, + {192, 80, 240, 120}, + }; + + RECT rcRight[11] = { + {0, 40, 48, 80}, + {48, 40, 96, 80}, + {96, 40, 144, 80}, + {144, 40, 192, 80}, + {192, 40, 240, 80}, + {240, 40, 288, 80}, + {0, 120, 48, 160}, + {48, 120, 96, 160}, + {96, 120, 144, 160}, + {144, 120, 192, 160}, + {192, 120, 240, 160}, + }; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Ballos 1 head +void ActNpc341(NPCHAR *npc) +{ + RECT rc[3] = { + {288, 32, 320, 48}, + {288, 48, 320, 64}, + {288, 64, 320, 80}, + }; + + if (npc->pNpc->act_no == 11 && npc->pNpc->act_wait > 50) + ++npc->ani_wait; + + if (npc->ani_wait > 4) + { + npc->ani_wait = 0; + + if (npc->ani_no < 2) + ++npc->ani_no; + } + + if (npc->pNpc->ani_no) + npc->cond = 0; + + npc->rect = rc[npc->ani_no]; +} + +// Ballos 3 eye +void ActNpc342(NPCHAR *npc) +{ + static int flash; + + RECT rc[3] = { + {240, 48, 280, 88}, + {240, 88, 280, 128}, + {280, 48, 320, 88}, + }; + + unsigned char deg; + + if (npc->act_no < 1000 && npc->pNpc->act_no >= 1000) + npc->act_no = 1000; + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->count1 = (npc->direct & 0xFF) * 2; + npc->direct >>= 8; + npc->count2 = 0xC0; + npc->damage = 14; + // Fallthrough + case 10: + if (npc->count2 < 320) + npc->count2 += 8; + else + npc->act_no = 11; + + break; + + case 11: + if (npc->count2 > 304) + npc->count2 -= 4; + else + npc->act_no = 12; + + break; + + case 12: + if (npc->pNpc->act_no == 311) + npc->act_no = 20; + + break; + + case 20: + npc->act_no = 21; + npc->bits |= NPC_SHOOTABLE; + npc->life = 1000; + // Fallthrough + case 21: + npc->count1 -= 2; + + if (npc->count1 < 0) + npc->count1 += 0x200; + + if (npc->shock) + { + if (++flash / 2 % 2) + npc->ani_no = 1; + else + npc->ani_no = 0; + } + else + { + npc->ani_no = 0; + } + + if (npc->life < 900) + { + npc->act_no = 22; + npc->bits &= ~NPC_SHOOTABLE; + SetDestroyNpChar(npc->x, npc->y, 0x2000, 0x20); + PlaySoundObject(71, SOUND_MODE_PLAY); + } + + npc->pNpc->count1 = 4; + + if (npc->pNpc->act_no == 401) + npc->act_no = 23; + + break; + + case 22: + npc->ani_no = 2; + npc->count1 -= 2; + + if (npc->count1 < 0) + npc->count1 += 0x200; + + if (npc->pNpc->act_no == 401) + npc->act_no = 23; + + break; + + case 23: + npc->ani_no = 2; + npc->count1 -= 4; + + if (npc->count1 < 0) + npc->count1 += 0x200; + + if (npc->pNpc->act_no == 420) + npc->act_no = 30; + + break; + + case 30: + npc->act_no = 31; + npc->life = 1000; + npc->damage = 10; + + if (npc->direct == 0) + npc->bits |= NPC_SHOOTABLE; + + npc->ym = 0; + // Fallthrough + case 31: + ++npc->count1; + npc->count1 %= 0x200; + + if (npc->count2 > 0x100) + --npc->count2; + + if (npc->bits & NPC_SHOOTABLE) + { + if (npc->shock) + { + if (++flash / 2 % 2) + npc->ani_no = 1; + else + npc->ani_no = 0; + } + else + { + npc->ani_no = 0; + } + } + else + { + npc->ani_no = 2; + } + + if (npc->life < 900) + npc->act_no = 40; + + break; + + case 40: + npc->act_no = 41; + npc->xm = 0; + npc->ym = 0; + npc->ani_no = 2; + npc->damage = 5; + npc->bits &= ~(NPC_IGNORE_SOLIDITY | NPC_SHOOTABLE); + SetDestroyNpChar(npc->x, npc->y, 0x2000, 0x20); + PlaySoundObject(71, SOUND_MODE_PLAY); + // Fallthrough + case 41: + if (npc->flag & 1) + npc->xm = 0x100; + + if (npc->flag & 4) + npc->xm = -0x100; + + if (npc->flag & 8) + { + if (npc->xm == 0) + { + if (gMC.x < npc->x) + npc->xm = 0x100; + else + npc->xm = -0x100; + } + + npc->ym = -0x800; + PlaySoundObject(26, SOUND_MODE_PLAY); + } + + npc->ym += 0x20; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + break; + + case 1000: + npc->act_no = 1001; + npc->xm = 0; + npc->ym = 0; + npc->ani_no = 2; + npc->bits &= ~(NPC_IGNORE_SOLIDITY | NPC_SHOOTABLE); + npc->damage = 0; + npc->count1 /= 4; + npc->exp = 0; + // Fallthrough + case 1001: + if (npc->count1 > 0) + { + if (--npc->count1 / 2 % 2) + npc->ani_no = 1; + else + npc->ani_no = 0; + } + else + { + SetDestroyNpChar(npc->x, npc->y, 0x2000, 0x20); + PlaySoundObject(71, SOUND_MODE_PLAY); + VanishNpChar(npc); + return; + } + + break; + } + + if (npc->act_no == 21 || npc->act_no == 22) + { + switch (npc->pNpc->direct) + { + case 0: + if (npc->count1 == 140) + { + SetNpChar(4, npc->x + (8 * 0x200), npc->y + 0x1800, 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x - (8 * 0x200), npc->y + 0x1800, 0, 0, 0, NULL, 0x100); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + break; + + case 1: + if (npc->count1 == 268) + { + SetNpChar(4, npc->x - (12 * 0x200), npc->y + (8 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x - (12 * 0x200), npc->y - (8 * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + break; + + case 2: + if (npc->count1 == 396) + { + SetNpChar(4, npc->x + (8 * 0x200), npc->y - (12 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x - (8 * 0x200), npc->y - (12 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(345, npc->x - (8 * 0x200), npc->y - (12 * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + break; + + case 3: + if (npc->count1 == 12) + { + SetNpChar(4, npc->x + (12 * 0x200), npc->y + (8 * 0x200), 0, 0, 0, NULL, 0x100); + SetNpChar(4, npc->x + (12 * 0x200), npc->y - (8 * 0x200), 0, 0, 0, NULL, 0x100); + PlaySoundObject(26, SOUND_MODE_PLAY); + } + break; + } + } + + if (npc->act_no < 40) + { + deg = npc->count1 / 2; + + npc->tgt_x = npc->pNpc->x + npc->count2 * GetCos(deg) / 4; + npc->tgt_y = npc->pNpc->y + npc->count2 * GetSin(deg) / 4; + + npc->xm = npc->tgt_x - npc->x; + npc->ym = npc->tgt_y - npc->y; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Ballos 2 cutscene +void ActNpc343(NPCHAR *npc) +{ + RECT rc = {0, 0, 120, 120}; + + npc->rect = rc; + + if (++npc->act_wait > 100) + npc->cond = 0; + + npc->x = npc->pNpc->x; + npc->y = npc->pNpc->y; +} + +// Ballos 2 eyes +void ActNpc344(NPCHAR *npc) +{ + RECT rc[2] = { + {272, 0, 296, 16}, + {296, 0, 320, 16}, + }; + + if (npc->direct == 0) + { + npc->rect = rc[0]; + npc->x = npc->pNpc->x - (24 * 0x200); + } + else + { + npc->rect = rc[1]; + npc->x = npc->pNpc->x + (24 * 0x200); + } + + if (++npc->act_wait > 100) + npc->cond = 0; + + npc->y = npc->pNpc->y - (36 * 0x200); +} + +// Ballos skull projectile +void ActNpc345(NPCHAR *npc) +{ + RECT rc[4] = { + {128, 176, 144, 192}, + {144, 176, 160, 192}, + {160, 176, 176, 192}, + {176, 176, 192, 192}, + }; + + int i; + + switch (npc->act_no) + { + case 0: + npc->act_no = 100; + npc->ani_no = Random(0, 16) % 4; + // Fallthrough + case 100: + npc->ym += 0x40; + if (npc->ym > 0x700) + npc->ym = 0x700; + + if (npc->y > 128 * 0x200) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + if (npc->act_wait++ / 2 % 2) + SetNpChar(4, npc->x, npc->y, 0, 0, 0, NULL, 0x100); + + if (npc->flag & 8) + { + npc->ym = -0x200; + npc->act_no = 110; + npc->bits |= NPC_IGNORE_SOLIDITY; + PlaySoundObject(12, SOUND_MODE_PLAY); + SetQuake(10); + + for (i = 0; i < 4; ++i) + SetNpChar(4, npc->x + (Random(-12, 12) * 0x200), npc->y + (16 * 0x200), Random(-341, 341), Random(-0x600, 0), 0, NULL, 0x100); + } + + break; + + case 110: + npc->ym += 0x40; + + if (npc->y > (gMap.length * 0x200 * 0x10) + (2 * 0x200 * 0x10)) + { + npc->cond = 0; + return; + } + + break; + } + + if (++npc->ani_wait > 8) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 3) + npc->ani_no = 0; + + npc->y += npc->ym; + + npc->rect = rc[npc->ani_no]; +} + +// Ballos 4 orbiting platform +void ActNpc346(NPCHAR *npc) +{ + RECT rc = {240, 0, 272, 16}; + unsigned char deg; + + if (npc->act_no < 1000 && npc->pNpc->act_no >= 1000) + npc->act_no = 1000; + + switch (npc->act_no) + { + case 0: + npc->act_no = 10; + npc->count1 = npc->direct * 4; + npc->count2 = 192; + npc->ani_no = 0; + // Fallthrough + case 10: + if (npc->count2 < 448) + npc->count2 += 8; + else + npc->act_no = 11; + + break; + + case 11: + if (npc->pNpc->act_no == 411) + npc->act_no = 20; + + break; + + case 20: + if (--npc->count1 < 0) + npc->count1 += 0x400; + + if (npc->pNpc->act_no == 421) + npc->act_no = 40; + if (npc->pNpc->act_no == 423) + npc->act_no = 100; + + break; + + case 30: + ++npc->count1; + npc->count1 %= 0x400; + + if (npc->pNpc->act_no == 425) + npc->act_no = 50; + if (npc->pNpc->act_no == 427) + npc->act_no = 100; + + break; + + case 40: + npc->count1 -= 2; + + if (npc->count1 < 0) + npc->count1 += 0x400; + + if (npc->pNpc->act_no == 422) + npc->act_no = 20; + + break; + + case 50: + npc->count1 += 2; + npc->count1 %= 0x400; + + if (npc->pNpc->act_no == 426) + npc->act_no = 30; + + break; + + case 100: + npc->ani_no = 0; + + if (npc->pNpc->act_no == 424) + npc->act_no = 30; + if (npc->pNpc->act_no == 428) + npc->act_no = 20; + + break; + + case 1000: + npc->act_no = 1001; + npc->xm = 0; + npc->ym = 0; + npc->bits &= ~NPC_SOLID_HARD; + // Fallthrough + case 1001: + npc->ym += 0x40; + + if (npc->y > gMap.length * 0x10 * 0x200) + npc->cond = 0; + + break; + } + + if (npc->act_no < 1000) + { + if (gMC.y > npc->y - 0x1000 && gMC.ym < 0) + npc->bits &= ~NPC_SOLID_HARD; + else + npc->bits |= NPC_SOLID_HARD; + + deg = npc->count1 / 4; + npc->tgt_x = npc->pNpc->x + npc->count2 * GetCos(deg) / 4; + npc->tgt_y = npc->pNpc->y + (16 * 0x200) + npc->count2 * GetSin(deg) / 4; + + npc->xm = npc->tgt_x - npc->x; + + if (npc->act_no == 20 || npc->act_no == 30) + { + if (npc->count1 % 4 == 0) + npc->ani_no = (npc->tgt_y - npc->y) / 4; + } + else if (npc->act_no == 40 || npc->act_no == 50) + { + if ((npc->count1 / 2 % 2) == 0) + npc->ani_no = (npc->tgt_y - npc->y) / 2; + } + else + { + npc->ani_no = npc->tgt_y - npc->y; + } + + npc->ym = npc->ani_no; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + npc->rect = rc; +} + +// Hoppy +void ActNpc347(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + npc->ani_no = 0; + + if (gMC.y < npc->y + (128 * 0x200) && gMC.y > npc->y - (128 * 0x200)) + { + npc->act_no = 10; + npc->act_wait = 0; + npc->ani_no = 1; + } + + break; + + case 10: + if (++npc->act_wait == 4) + npc->ani_no = 2; + + if (npc->act_wait > 12) + { + npc->act_no = 12; + npc->xm = 0x700; + PlaySoundObject(6, SOUND_MODE_PLAY); + npc->ani_no = 3; + } + + break; + + case 12: + if (gMC.y < npc->y) + npc->ym = -0xAA; + else + npc->ym = 0xAA; + + if (npc->flag & 1) + { + npc->act_no = 13; + npc->act_wait = 0; + npc->ani_no = 2; + npc->xm = 0; + npc->ym = 0; + break; + } + + npc->xm -= 42; + + if (npc->xm < -0x5FF) + npc->xm = -0x5FF; + + npc->x += npc->xm; + npc->y += npc->ym; + break; + + case 13: + ++npc->act_wait; + + if (npc->act_wait == 2) + npc->ani_no = 1; + + if (npc->act_wait == 6) + npc->ani_no = 0; + + if (npc->act_wait > 16) + npc->act_no = 1; + + break; + } + + RECT rc[4] = { + {256, 48, 272, 64}, + {272, 48, 288, 64}, + {288, 48, 304, 64}, + {304, 48, 320, 64}, + }; + + npc->rect = rc[npc->ani_no]; +} + +// Ballos 4 spikes +void ActNpc348(NPCHAR *npc) +{ + RECT rc[2] = { + {128, 152, 160, 176}, + {160, 152, 192, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + // Fallthrough + case 1: + if (++npc->act_wait < 0x80) + { + npc->y -= 0x80; + + if (npc->act_wait / 2 % 2) + npc->ani_no = 1; + else + npc->ani_no = 0; + } + else + { + npc->act_no = 10; + npc->ani_no = 0; + npc->damage = 2; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Statue +void ActNpc349(NPCHAR *npc) +{ + RECT rect = {0, 0, 16, 16}; + + if (npc->act_no == 0) + { + npc->act_no = 1; + + if (npc->direct == 0) + npc->x += 8 * 0x200; + if (npc->direct == 2) + npc->y += 16 * 0x200; + } + + npc->rect = rect; +} + +// Flying Bute archer +void ActNpc350(NPCHAR *npc) +{ + RECT rcLeft[7] = { + {0, 160, 24, 184}, + {24, 160, 48, 184}, + {48, 160, 72, 184}, + {72, 160, 96, 184}, + {96, 160, 120, 184}, + {120, 160, 144, 184}, + {144, 160, 168, 184}, + }; + + RECT rcRight[7] = { + {0, 184, 24, 208}, + {24, 184, 48, 208}, + {48, 184, 72, 208}, + {72, 184, 96, 208}, + {96, 184, 120, 208}, + {120, 184, 144, 208}, + {144, 184, 168, 208}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + if (npc->direct == 0) + npc->tgt_x = npc->x - (128 * 0x200); + else + npc->tgt_x = npc->x + (128 * 0x200); + + npc->tgt_y = npc->y; + npc->ym = Random(-0x200, 0x200) * 2; + npc->xm = Random(-0x200, 0x200) * 2; + // Fallthrough + case 1: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + } + + if (npc->direct == 0) + { + if (npc->x < npc->tgt_x) + npc->act_no = 20; + } + else + { + if (npc->x > npc->tgt_x) + npc->act_no = 20; + } + + break; + + case 20: + npc->act_no = 21; + npc->act_wait = Random(0, 150); + npc->ani_no = 2; + npc->ani_wait = 0; + // Fallthrough + case 21: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 3) + npc->ani_no = 2; + } + + if (++npc->act_wait > 300) + npc->act_no = 30; + + if (gMC.x < npc->x + (112 * 0x200) && gMC.x > npc->x - (112 * 0x200) && gMC.y < npc->y + (16 * 0x200) && gMC.y > npc->y - (16 * 0x200)) + npc->act_no = 30; + + break; + + case 30: + npc->act_no = 31; + npc->act_wait = 0; + npc->ani_wait = 0; + // Fallthrough + case 31: + if (++npc->ani_wait / 2 % 2) + npc->ani_no = 3; + else + npc->ani_no = 4; + + if (++npc->act_wait > 30) + { + npc->act_no = 40; + npc->ani_no = 5; + + if (npc->direct == 0) + SetNpChar(312, npc->x, npc->y, -0x800, 0, 0, NULL, 0x199); + else + SetNpChar(312, npc->x, npc->y, 0x800, 0, 2, NULL, 0x199); + } + + break; + + case 40: + npc->act_no = 41; + npc->act_wait = 0; + npc->ani_wait = 0; + // Fallthrough + case 41: + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 6) + npc->ani_no = 5; + } + + if (++npc->act_wait > 40) + { + npc->act_no = 50; + npc->ani_no = 0; + npc->xm = 0; + npc->ym = 0; + } + + break; + + case 50: + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + } + + if (npc->direct == 0) + npc->xm -= 0x20; + else + npc->xm += 0x20; + + if (npc->x < 0 || npc->x > gMap.width * 0x200 * 0x10) + { + VanishNpChar(npc); + return; + } + + break; + } + + if (npc->act_no < 50) + { + if (npc->x < npc->tgt_x) + npc->xm += 0x2A; + if (npc->x > npc->tgt_x) + npc->xm -= 0x2A; + + if (npc->y < npc->tgt_y) + npc->ym += 0x2A; + if (npc->y > npc->tgt_y) + npc->ym -= 0x2A; + + if (npc->xm > 0x400) + npc->xm = 0x400; + if (npc->xm < -0x400) + npc->xm = -0x400; + + if (npc->ym > 0x400) + npc->ym = 0x400; + if (npc->ym < -0x400) + npc->ym = -0x400; + } + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; +} + +// Statue (shootable) +void ActNpc351(NPCHAR *npc) +{ + RECT rc[9] = { + {0, 96, 32, 136}, + {32, 96, 64, 136}, + {64, 96, 96, 136}, + {96, 96, 128, 136}, + {128, 96, 160, 136}, + {0, 176, 32, 216}, + {32, 176, 64, 216}, + {64, 176, 96, 216}, + {96, 176, 128, 216}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + npc->ani_no = npc->direct / 10; + npc->x += 8 * 0x200; + npc->y += 12 * 0x200; + break; + + case 10: + if (GetNPCFlag(npc->code_flag)) + { + npc->act_no = 20; + } + else + { + npc->act_no = 11; + npc->bits |= NPC_SHOOTABLE; + } + // Fallthrough + case 11: + if (npc->life <= 900) + { + SetNpChar(351, npc->x - (8 * 0x200), npc->y - (12 * 0x200), 0, 0, (npc->ani_no + 4) * 10, NULL, 0); + npc->cond |= 8; + } + + break; + + case 20: + npc->ani_no += 4; + npc->act_no = 1; + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Ending characters +void ActNpc352(NPCHAR *npc) +{ + switch (npc->act_no) + { + case 0: + // Set state + npc->act_no = 1; + npc->ani_no = 0; + npc->count1 = npc->direct / 100; + npc->direct %= 100; + + // Set surfaces / offset + switch (npc->count1) + { + case 7: + case 8: + case 9: + case 12: + case 13: + npc->surf = SURFACE_ID_LEVEL_SPRITESET_1; + break; + } + + switch (npc->count1) + { + case 2: + case 4: + case 9: + case 12: + npc->view.top = 16 * 0x200; + break; + } + + // Balrog + if (npc->count1 == 9) + { + npc->view.back = 20 * 0x200; + npc->view.front = 20 * 0x200; + npc->x -= 1 * 0x200; + } + + // Spawn King's sword + if (npc->count1 == 0) + SetNpChar(145, 0, 0, 0, 0, 2, npc, 0x100); + // Fallthrough + case 1: + npc->ym += 0x40; + if (npc->ym > 0x5FF) + npc->ym = 0x5FF; + + if (npc->flag & 8) + { + npc->ym = 0; + npc->act_no = 2; + npc->ani_no = 1; + } + + npc->y += npc->ym; + + break; + } + + RECT rc[28] = { + {304, 48, 320, 64}, + {224, 48, 240, 64}, + {32, 80, 48, 96}, + {0, 80, 16, 96}, + {224, 216, 240, 240}, + {192, 216, 208, 240}, + {48, 16, 64, 32}, + {0, 16, 16, 32}, + {112, 192, 128, 216}, + {80, 192, 96, 216}, + {304, 0, 320, 16}, + {224, 0, 240, 16}, + {176, 32, 192, 48}, + {176, 32, 192, 48}, + {240, 16, 256, 32}, + {224, 16, 240, 32}, + {208, 16, 224, 32}, + {192, 16, 208, 32}, + {280, 128, 320, 152}, + {280, 152, 320, 176}, + {32, 112, 48, 128}, + {0, 112, 16, 128}, + {80, 0, 96, 16}, + {112, 0, 128, 16}, + {16, 152, 32, 176}, + {0, 152, 16, 176}, + {48, 16, 64, 32}, + {48, 0, 64, 16} + }; + + npc->rect = rc[npc->ani_no + (npc->count1 * 2)]; +} + +// Bute with sword (flying) +void ActNpc353(NPCHAR *npc) +{ + RECT rc[4] = { + {168, 160, 184, 184}, + {184, 160, 200, 184}, + {168, 184, 184, 208}, + {184, 184, 200, 208}, + }; + + RECT rcLeft[2] = { + {200, 160, 216, 176}, + {216, 160, 232, 176}, + }; + + RECT rcRight[2] = { + {200, 176, 216, 192}, + {216, 176, 232, 192}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 1; + + switch (npc->direct) + { + case 0: + npc->xm = -0x600; + break; + + case 2: + npc->xm = 0x600; + break; + + case 1: + npc->ym = -0x600; + break; + + case 3: + npc->ym = 0x600; + break; + } + // Fallthrough + case 1: + ++npc->act_wait; + + if (npc->act_wait == 8) + npc->bits &= ~NPC_IGNORE_SOLIDITY; + + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->act_wait == 0x10) + npc->act_no = 10; + + if (++npc->ani_wait > 2) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 3) + npc->ani_no = 0; + } + + npc->rect = rc[npc->ani_no]; + break; + + case 10: + npc->act_no = 11; + npc->ani_no = 0; + npc->bits |= NPC_SHOOTABLE; + npc->bits &= ~NPC_IGNORE_SOLIDITY; + npc->damage = 5; + npc->view.top = 8 * 0x200; + // Fallthrough + case 11: + if (npc->x > gMC.x) + npc->direct = 0; + else + npc->direct = 2; + + if (gMC.y - (24 * 0x200) > npc->y) + { + if (npc->direct == 0) + npc->xm2 += 0x10; + else + npc->xm2 -= 0x10; + } + else + { + if (npc->direct == 0) + npc->xm2 -= 0x10; + else + npc->xm2 += 0x10; + } + + if (npc->y > gMC.y) + npc->ym2 -= 0x10; + else + npc->ym2 += 0x10; + + if (npc->xm2 < 0 && npc->flag & 1) + npc->xm2 *= -1; + if (npc->xm2 > 0 && npc->flag & 4) + npc->xm2 *= -1; + + if (npc->ym2 < 0 && npc->flag & 2) + npc->ym2 *= -1; + if (npc->ym2 > 0 && npc->flag & 8) + npc->ym2 *= -1; + + if (npc->xm2 < -0x5FF) + npc->xm2 = -0x5FF; + if (npc->xm2 > 0x5FF) + npc->xm2 = 0x5FF; + + if (npc->ym2 < -0x5FF) + npc->ym2 = -0x5FF; + if (npc->ym2 > 0x5FF) + npc->ym2 = 0x5FF; + + npc->x += npc->xm2; + npc->y += npc->ym2; + + if (++npc->ani_wait > 1) + { + npc->ani_wait = 0; + + if (++npc->ani_no > 1) + npc->ani_no = 0; + } + + if (npc->direct == 0) + npc->rect = rcLeft[npc->ani_no]; + else + npc->rect = rcRight[npc->ani_no]; + + break; + } +} + +// Invisible deathtrap wall +void ActNpc354(NPCHAR *npc) +{ + int i, x, y; + + switch (npc->act_no) + { + case 0: + npc->hit.bottom = 280 * 0x200; + break; + + case 10: + npc->act_no = 11; + npc->act_wait = 0; + + if (npc->direct == 0) + npc->x += 16 * 0x200; + else + npc->x -= 16 * 0x200; + // Fallthrough + case 11: + if (++npc->act_wait > 100) + { + npc->act_wait = 0; + SetQuake(20); + PlaySoundObject(26, SOUND_MODE_PLAY); + PlaySoundObject(12, SOUND_MODE_PLAY); + + if (npc->direct == 0) + npc->x -= 16 * 0x200; + else + npc->x += 16 * 0x200; + + for (i = 0; i < 20; ++i) + { + x = (npc->x / 0x200 / 0x10); + y = (npc->y / 0x200 / 0x10) + i; + ChangeMapParts(x, y, 109); + } + } + + break; + } +} + +// Quote and Curly on Balrog's back +void ActNpc355(NPCHAR *npc) +{ + RECT rc[4] = { + {80, 16, 96, 32}, + {80, 96, 96, 112}, + {128, 16, 144, 32}, + {208, 96, 224, 112}, + }; + + switch (npc->act_no) + { + case 0: + switch (npc->direct) + { + case 0: + npc->surf = SURFACE_ID_MY_CHAR; + npc->ani_no = 0; + npc->x = npc->pNpc->x - (14 * 0x200); + npc->y = npc->pNpc->y + (10 * 0x200); + break; + + case 1: + npc->surf = SURFACE_ID_NPC_REGU; + npc->ani_no = 1; + npc->x = npc->pNpc->x + (14 * 0x200); + npc->y = npc->pNpc->y + (10 * 0x200); + break; + + case 2: + npc->surf = SURFACE_ID_MY_CHAR; + npc->ani_no = 2; + npc->x = npc->pNpc->x - (7 * 0x200); + npc->y = npc->pNpc->y - (19 * 0x200); + break; + + case 3: + npc->surf = SURFACE_ID_NPC_REGU; + npc->ani_no = 3; + npc->x = npc->pNpc->x + (4 * 0x200); + npc->y = npc->pNpc->y - (19 * 0x200); + break; + } + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Balrog rescue +void ActNpc356(NPCHAR *npc) +{ + RECT rcRight[2] = { + {240, 128, 280, 152}, + {240, 152, 280, 176}, + }; + + switch (npc->act_no) + { + case 0: + npc->act_no = 11; + npc->ani_wait = 0; + npc->tgt_y = npc->y - (16 * 0x200); + npc->tgt_x = npc->x - (6 * 0x200); + npc->ym = 0; + SetNpChar(355, 0, 0, 0, 0, 3, npc, 0xAA); + SetNpChar(355, 0, 0, 0, 0, 2, npc, 0xAA); + // Fallthrough + case 11: + if (npc->x < npc->tgt_x) + npc->xm += 8; + else + npc->xm -= 8; + + if (npc->y < npc->tgt_y) + npc->ym += 8; + else + npc->ym -= 8; + + npc->x += npc->xm; + npc->y += npc->ym; + + break; + + case 20: + npc->act_no = 21; + npc->xm = -0x400; + npc->ym = 0x200; + // Fallthrough + case 21: + ++npc->ani_wait; + npc->xm += 0x10; + npc->ym -= 8; + npc->x += npc->xm; + npc->y += npc->ym; + + if (npc->x > 60 * 0x10 * 0x200) + npc->act_no = 22; + + break; + + case 22: + npc->xm = 0; + npc->ym = 0; + break; + } + + if (++npc->ani_wait > 4) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + npc->rect = rcRight[npc->ani_no]; +} + +// Puppy ghost +void ActNpc357(NPCHAR *npc) +{ + RECT rc = {224, 136, 240, 152}; + + switch (npc->act_no) + { + case 0: + npc->rect = rc; + ++npc->act_wait; + break; + + case 10: + npc->act_wait = 0; + npc->act_no = 11; + PlaySoundObject(29, SOUND_MODE_PLAY); + // Fallthrough + case 11: + ++npc->act_wait; + npc->rect = rc; + + if (npc->act_wait / 2 % 2) + npc->rect.right = npc->rect.left; + + if (npc->act_wait > 50) + npc->cond = 0; + + break; + } + + if (npc->act_wait % 8 == 1) + SetCaret(npc->x + (Random(-8, 8) * 0x200), npc->y + 0x1000, CARET_TINY_PARTICLES, DIR_UP); +} + +// Misery (stood in the wind during the credits) +void ActNpc358(NPCHAR *npc) +{ + RECT rc[5] = { + {208, 8, 224, 32}, + {224, 8, 240, 32}, + {240, 8, 256, 32}, + {256, 8, 272, 32}, + {272, 8, 288, 32}, + }; + + switch (npc->act_no) + { + case 0: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 1) + npc->ani_no = 0; + + break; + + case 10: + if (++npc->ani_wait > 6) + { + npc->ani_wait = 0; + ++npc->ani_no; + } + + if (npc->ani_no > 4) + npc->ani_no = 3; + + break; + } + + npc->rect = rc[npc->ani_no]; +} + +// Water droplet generator +void ActNpc359(NPCHAR *npc) +{ + int x; + + if (gMC.x < npc->x + (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.x > npc->x - (((WINDOW_WIDTH / 2) + 160) * 0x200) && gMC.y < npc->y + (((WINDOW_HEIGHT / 2) + 200) * 0x200) && gMC.y > npc->y - (((WINDOW_HEIGHT / 2) + 40) * 0x200) && Random(0, 100) == 2) + { + x = npc->x + (Random(-6, 6) * 0x200); + SetNpChar(73, x, npc->y - (7 * 0x200), 0, 0, 0, 0, 0); + } +} + +// "Thank you" message at the end of the credits +void ActNpc360(NPCHAR *npc) +{ + RECT rc = {0, 176, 48, 184}; + + if (npc->act_no == 0) + { + ++npc->act_no; + npc->x -= 8 * 0x200; + npc->y -= 8 * 0x200; + } + + npc->rect = rc; +} diff --git a/src/NpcHit.cpp b/src/NpcHit.cpp new file mode 100644 index 0000000..97c2546 --- /dev/null +++ b/src/NpcHit.cpp @@ -0,0 +1,638 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcHit.h" + +#include "WindowsWrapper.h" + +#include "Back.h" +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "Flags.h" +#include "Game.h" +#include "Map.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Sound.h" +#include "TextScr.h" +#include "ValueView.h" + +void JadgeHitNpCharBlock(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + if (npc->y - npc->hit.top < (y * 0x10 + 5) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 - 5) * 0x200 + && npc->x - npc->hit.back < (x * 0x10 + 8) * 0x200 + && npc->x - npc->hit.back > x * 0x10 * 0x200) + { + npc->x = ((x * 0x10 + 8) * 0x200) + npc->hit.back; + hit |= 1; + } + + if (npc->y - npc->hit.top < (y * 0x10 + 5) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 - 5) * 0x200 + && npc->x + npc->hit.back > (x * 0x10 - 8) * 0x200 + && npc->x + npc->hit.back < x * 0x10 * 0x200) + { + npc->x = ((x * 0x10 - 8) * 0x200) - npc->hit.back; + hit |= 4; + } + + if (npc->x - npc->hit.back < (x * 0x10 + 5) * 0x200 + && npc->x + npc->hit.back > (x * 0x10 - 5) * 0x200 + && npc->y - npc->hit.top < (y * 0x10 + 8) * 0x200 + && npc->y - npc->hit.top > y * 0x10 * 0x200) + { + npc->y = ((y * 0x10 + 8) * 0x200) + npc->hit.top; + npc->ym = 0; + hit |= 2; + } + + if (npc->x - npc->hit.back < (x * 0x10 + 5) * 0x200 + && npc->x + npc->hit.back > (x * 0x10 - 5) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 - 8) * 0x200 + && npc->y + npc->hit.bottom < y * 0x10 * 0x200) + { + npc->y = ((y * 0x10 - 8) * 0x200) - npc->hit.bottom; + npc->ym = 0; + hit |= 8; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleA(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y - npc->hit.top < (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 + && npc->y + npc->hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 + npc->hit.top; + + // Halt momentum + if (npc->ym < 0) + npc->ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleB(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y - npc->hit.top < (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 + && npc->y + npc->hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 + npc->hit.top; + + // Halt momentum + if (npc->ym < 0) + npc->ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleC(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y - npc->hit.top < (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 + && npc->y + npc->hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 + npc->hit.top; + + // Halt momentum + if (npc->ym < 0) + npc->ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleD(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y - npc->hit.top < (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 + && npc->y + npc->hit.bottom > (y * 0x10 - 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 + npc->hit.top; + + // Halt momentum + if (npc->ym < 0) + npc->ym = 0; + + // Set that hit a ceiling + hit |= 2; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleE(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + hit |= 0x10000; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 + && npc->y - npc->hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 - npc->hit.bottom; + + // Halt momentum + if (npc->ym > 0) + npc->ym = 0; + + // Set that hit this slope + hit |= 0x28; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleF(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + hit |= 0x20000; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x >= (x * 0x10 - 8) * 0x200 // Note that this function uses '>='. I'm not sure if this is a bug. + && npc->y + npc->hit.bottom > (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 + && npc->y - npc->hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) + ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 - npc->hit.bottom; + + // Halt momentum + if (npc->ym > 0) + npc->ym = 0; + + // Set that hit this slope + hit |= 0x28; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleG(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + hit |= 0x40000; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 + && npc->y - npc->hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) + 0x800 - npc->hit.bottom; + + // Halt momentum + if (npc->ym > 0) + npc->ym = 0; + + // Set that hit this slope + hit |= 0x18; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharTriangleH(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + hit |= 0x80000; + + if (npc->x < (x * 0x10 + 8) * 0x200 + && npc->x > (x * 0x10 - 8) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 + && npc->y - npc->hit.top < (y * 0x10 + 8) * 0x200) + { + // Clip + npc->y = (y * 0x10 * 0x200) - ((npc->x - (x * 0x10 * 0x200)) / 2) - 0x800 - npc->hit.bottom; + + // Halt momentum + if (npc->ym > 0) + npc->ym = 0; + + // Set that hit this slope + hit |= 0x18; + } + + npc->flag |= hit; +} + +void JudgeHitNpCharWater(NPCHAR *npc, int x, int y) +{ + int hit = 0; + + if (npc->x - npc->hit.back < (x * 0x10 + 6) * 0x200 + && npc->x + npc->hit.back > (x * 0x10 - 6) * 0x200 + && npc->y - npc->hit.top < (y * 0x10 + 6) * 0x200 + && npc->y + npc->hit.bottom > (y * 0x10 - 6) * 0x200) + hit |= 0x100; + + npc->flag |= hit; +} + +void HitNpCharMap(void) +{ + int x, y; + int judg; + + int offx[9]; + int offy[9]; + + int i, j; + + offx[0] = 0; + offx[1] = 1; + offx[2] = 0; + offx[3] = 1; + offx[4] = 2; + offx[5] = 2; + offx[6] = 2; + offx[7] = 0; + offx[8] = 1; + + offy[0] = 0; + offy[1] = 0; + offy[2] = 1; + offy[3] = 1; + offy[4] = 0; + offy[5] = 1; + offy[6] = 2; + offy[7] = 2; + offy[8] = 2; + + for (i = 0; i < NPC_MAX; ++i) + { + if (!(gNPC[i].cond & 0x80)) + continue; + + if (gNPC[i].bits & NPC_IGNORE_SOLIDITY) + continue; + + if (gNPC[i].size >= 3) + { + judg = 9; + x = (gNPC[i].x - 0x1000) / 0x10 / 0x200; + y = (gNPC[i].y - 0x1000) / 0x10 / 0x200; + } + else + { + judg = 4; + x = gNPC[i].x / 0x10 / 0x200; + y = gNPC[i].y / 0x10 / 0x200; + } + + gNPC[i].flag = 0; + + for (j = 0; j < judg; ++j) + { + switch (GetAttribute(x + offx[j], y + offy[j])) + { + // No NPC block + case 0x44: + if (gNPC[i].bits & NPC_IGNORE_TILE_44) + break; + // Fallthrough + // Block + case 0x03: + case 0x05: + case 0x41: + case 0x43: + JadgeHitNpCharBlock(&gNPC[i], x + offx[j], y + offy[j]); + break; + + // Slopes + case 0x50: + JudgeHitNpCharTriangleA(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x51: + JudgeHitNpCharTriangleB(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x52: + JudgeHitNpCharTriangleC(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x53: + JudgeHitNpCharTriangleD(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x54: + JudgeHitNpCharTriangleE(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x55: + JudgeHitNpCharTriangleF(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x56: + JudgeHitNpCharTriangleG(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x57: + JudgeHitNpCharTriangleH(&gNPC[i], x + offx[j], y + offy[j]); + break; + + // Water + case 0x02: + case 0x60: + case 0x62: + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + // Water block + case 0x04: + case 0x61: + case 0x64: + JadgeHitNpCharBlock(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + // Water slopes + case 0x70: + JudgeHitNpCharTriangleA(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x71: + JudgeHitNpCharTriangleB(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x72: + JudgeHitNpCharTriangleC(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x73: + JudgeHitNpCharTriangleD(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x74: + JudgeHitNpCharTriangleE(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x75: + JudgeHitNpCharTriangleF(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x76: + JudgeHitNpCharTriangleG(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0x77: + JudgeHitNpCharTriangleH(&gNPC[i], x + offx[j], y + offy[j]); + JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]); + break; + + case 0xA0: + gNPC[i].flag |= 0x100; + // Fallthrough + case 0x80: + gNPC[i].flag |= 0x1000; + break; + + case 0xA1: + gNPC[i].flag |= 0x100; + // Fallthrough + case 0x81: + gNPC[i].flag |= 0x2000; + break; + + case 0xA2: + gNPC[i].flag |= 0x100; + // Fallthrough + case 0x82: + gNPC[i].flag |= 0x4000; + break; + + case 0xA3: + gNPC[i].flag |= 0x100; + // Fallthrough + case 0x83: + gNPC[i].flag |= 0x8000; + break; + } + + if (gNPC[i].y > gWaterY + 0x800) + gNPC[i].flag |= 0x100; + } + } +} + +void LoseNpChar(NPCHAR *npc, BOOL bVanish) +{ + int val; + + // Play death sound + PlaySoundObject(npc->destroy_voice, SOUND_MODE_PLAY); + + // Create smoke + switch (npc->size) + { + case 1: + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 3); + break; + + case 2: + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 7); + break; + + case 3: + SetDestroyNpChar(npc->x, npc->y, npc->view.back, 12); + break; + } + + // Create drop + if (npc->exp != 0) + { + switch (Random(1, 5)) + { + case 1: + // Spawn health + if (npc->exp > 6) + val = 6; + else + val = 2; + + SetLifeObject(npc->x, npc->y, val); + + break; + + case 2: + // Spawn missile launcher ammo + if (npc->exp > 6) + val = 3; + else + val = 1; + + if (SetBulletObject(npc->x, npc->y, val)) + break; + + // Fallthrough + default: + // Spawn weapon energy + SetExpObjects(npc->x, npc->y, npc->exp); + break; + } + } + + // Set flag + SetNPCFlag(npc->code_flag); + + // Create value view + if (npc->bits & NPC_SHOW_DAMAGE) + { + if ((npc->bits & NPC_SHOW_DAMAGE) && npc->damage_view) // npc->bits & NPC_SHOW_DAMAGE is already verified at this point, so this is redundant + SetValueView(&npc->x, &npc->y, npc->damage_view); + if (bVanish) + VanishNpChar(npc); + } + else + { + npc->cond = 0; + } +} + +void HitNpCharBullet(void) +{ + int n, b; + BOOL bHit; + + for (n = 0; n < NPC_MAX; ++n) + { + if (!(gNPC[n].cond & 0x80)) + continue; + + if (gNPC[n].bits & NPC_SHOOTABLE && gNPC[n].bits & NPC_INTERACTABLE) + continue; + + for (b = 0; b < BULLET_MAX; ++b) + { + if (!(gBul[b].cond & 0x80)) + continue; + + if (gBul[b].damage == -1) + continue; + + // Check if bullet touches npc + bHit = FALSE; + if (gNPC[n].bits & NPC_SHOOTABLE + && gNPC[n].x - gNPC[n].hit.back < gBul[b].x + gBul[b].enemyXL + && gNPC[n].x + gNPC[n].hit.back > gBul[b].x - gBul[b].enemyXL + && gNPC[n].y - gNPC[n].hit.top < gBul[b].y + gBul[b].enemyYL + && gNPC[n].y + gNPC[n].hit.bottom > gBul[b].y - gBul[b].enemyYL) + bHit = TRUE; + else if (gNPC[n].bits & NPC_INVULNERABLE + && gNPC[n].x - gNPC[n].hit.back < gBul[b].x + gBul[b].blockXL + && gNPC[n].x + gNPC[n].hit.back > gBul[b].x - gBul[b].blockXL + && gNPC[n].y - gNPC[n].hit.top < gBul[b].y + gBul[b].blockYL + && gNPC[n].y + gNPC[n].hit.bottom > gBul[b].y - gBul[b].blockYL) + bHit = TRUE; + + if (bHit) + { + // Damage NPC + if (gNPC[n].bits & NPC_SHOOTABLE) + { + gNPC[n].life -= gBul[b].damage; + + if (gNPC[n].life < 1) + { + gNPC[n].life = 0; + + if (gNPC[n].bits & NPC_SHOW_DAMAGE) + gNPC[n].damage_view -= gBul[b].damage; + + if ((gMC.cond & 0x80) && gNPC[n].bits & NPC_EVENT_WHEN_KILLED) + StartTextScript(gNPC[n].code_event); + else + gNPC[n].cond |= 8; + } + else + { + if (gNPC[n].shock < 14) + { + SetCaret((gBul[b].x + gNPC[n].x) / 2, (gBul[b].y + gNPC[n].y) / 2, CARET_HURT_PARTICLES, DIR_LEFT); + SetCaret((gBul[b].x + gNPC[n].x) / 2, (gBul[b].y + gNPC[n].y) / 2, CARET_HURT_PARTICLES, DIR_LEFT); + SetCaret((gBul[b].x + gNPC[n].x) / 2, (gBul[b].y + gNPC[n].y) / 2, CARET_HURT_PARTICLES, DIR_LEFT); + PlaySoundObject(gNPC[n].hit_voice, SOUND_MODE_PLAY); + gNPC[n].shock = 16; + } + + if (gNPC[n].bits & NPC_SHOW_DAMAGE) + gNPC[n].damage_view -= gBul[b].damage; + } + } + else if (gBul[b].code_bullet == 13 + || gBul[b].code_bullet == 14 + || gBul[b].code_bullet == 15 + || gBul[b].code_bullet == 28 + || gBul[b].code_bullet == 29 + || gBul[b].code_bullet == 30) + { + // Strange empty case that's needed for accurate assembly + } + else if (!(gBul[b].bbits & 0x10)) + { + // Hit invulnerable NPC + SetCaret((gBul[b].x + gNPC[n].x) / 2, (gBul[b].y + gNPC[n].y) / 2, CARET_PROJECTILE_DISSIPATION, DIR_RIGHT); + PlaySoundObject(31, SOUND_MODE_PLAY); + gBul[b].life = 0; + continue; + } + + --gBul[b].life; + } + } + + if (gNPC[n].cond & 8) + LoseNpChar(&gNPC[n], TRUE); + } +} diff --git a/src/NpcHit.h b/src/NpcHit.h new file mode 100644 index 0000000..7e82913 --- /dev/null +++ b/src/NpcHit.h @@ -0,0 +1,26 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "NpChar.h" + +void JadgeHitNpCharBlock(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleA(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleB(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleC(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleD(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleE(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleF(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleG(NPCHAR *npc, int x, int y); +void JudgeHitNpCharTriangleH(NPCHAR *npc, int x, int y); +void JudgeHitNpCharWater(NPCHAR *npc, int x, int y); +void HitNpCharMap(void); +void LoseNpChar(NPCHAR *npc, BOOL bVanish); +void HitNpCharBullet(void); diff --git a/src/NpcTbl.cpp b/src/NpcTbl.cpp new file mode 100644 index 0000000..86c60fd --- /dev/null +++ b/src/NpcTbl.cpp @@ -0,0 +1,443 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "NpcTbl.h" + +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "Generic.h" +#include "NpcAct.h" + +// Npc function table +const NPCFUNCTION gpNpcFuncTbl[] = { + ActNpc000, + ActNpc001, + ActNpc002, + ActNpc003, + ActNpc004, + ActNpc005, + ActNpc006, + ActNpc007, + ActNpc008, + ActNpc009, + ActNpc010, + ActNpc011, + ActNpc012, + ActNpc013, + ActNpc014, + ActNpc015, + ActNpc016, + ActNpc017, + ActNpc018, + ActNpc019, + ActNpc020, + ActNpc021, + ActNpc022, + ActNpc023, + ActNpc024, + ActNpc025, + ActNpc026, + ActNpc027, + ActNpc028, + ActNpc029, + ActNpc030, + ActNpc031, + ActNpc032, + ActNpc033, + ActNpc034, + ActNpc035, + ActNpc036, + ActNpc037, + ActNpc038, + ActNpc039, + ActNpc040, + ActNpc041, + ActNpc042, + ActNpc043, + ActNpc044, + ActNpc045, + ActNpc046, + ActNpc047, + ActNpc048, + ActNpc049, + ActNpc050, + ActNpc051, + ActNpc052, + ActNpc053, + ActNpc054, + ActNpc055, + ActNpc056, + ActNpc057, + ActNpc058, + ActNpc059, + ActNpc060, + ActNpc061, + ActNpc062, + ActNpc063, + ActNpc064, + ActNpc065, + ActNpc066, + ActNpc067, + ActNpc068, + ActNpc069, + ActNpc070, + ActNpc071, + ActNpc072, + ActNpc073, + ActNpc074, + ActNpc075, + ActNpc076, + ActNpc077, + ActNpc078, + ActNpc079, + ActNpc080, + ActNpc081, + ActNpc082, + ActNpc083, + ActNpc084, + ActNpc085, + ActNpc086, + ActNpc087, + ActNpc088, + ActNpc089, + ActNpc090, + ActNpc091, + ActNpc092, + ActNpc093, + ActNpc094, + ActNpc095, + ActNpc096, + ActNpc097, + ActNpc098, + ActNpc099, + ActNpc100, + ActNpc101, + ActNpc102, + ActNpc103, + ActNpc104, + ActNpc105, + ActNpc106, + ActNpc107, + ActNpc108, + ActNpc109, + ActNpc110, + ActNpc111, + ActNpc112, + ActNpc113, + ActNpc114, + ActNpc115, + ActNpc116, + ActNpc117, + ActNpc118, + ActNpc119, + ActNpc120, + ActNpc121, + ActNpc122, + ActNpc123, + ActNpc124, + ActNpc125, + ActNpc126, + ActNpc127, + ActNpc128, + ActNpc129, + ActNpc130, + ActNpc131, + ActNpc132, + ActNpc133, + ActNpc134, + ActNpc135, + ActNpc136, + ActNpc137, + ActNpc138, + ActNpc139, + ActNpc140, + ActNpc141, + ActNpc142, + ActNpc143, + ActNpc144, + ActNpc145, + ActNpc146, + ActNpc147, + ActNpc148, + ActNpc149, + ActNpc150, + ActNpc151, + ActNpc152, + ActNpc153, + ActNpc154, + ActNpc155, + ActNpc156, + ActNpc157, + ActNpc158, + ActNpc159, + ActNpc160, + ActNpc161, + ActNpc162, + ActNpc163, + ActNpc164, + ActNpc165, + ActNpc166, + ActNpc167, + ActNpc168, + ActNpc169, + ActNpc170, + ActNpc171, + ActNpc172, + ActNpc173, + ActNpc174, + ActNpc175, + ActNpc176, + ActNpc177, + ActNpc178, + ActNpc179, + ActNpc180, + ActNpc181, + ActNpc182, + ActNpc183, + ActNpc184, + ActNpc185, + ActNpc186, + ActNpc187, + ActNpc188, + ActNpc189, + ActNpc190, + ActNpc191, + ActNpc192, + ActNpc193, + ActNpc194, + ActNpc195, + ActNpc196, + ActNpc197, + ActNpc198, + ActNpc199, + ActNpc200, + ActNpc201, + ActNpc202, + ActNpc203, + ActNpc204, + ActNpc205, + ActNpc206, + ActNpc207, + ActNpc208, + ActNpc209, + ActNpc210, + ActNpc211, + ActNpc212, + ActNpc213, + ActNpc214, + ActNpc215, + ActNpc216, + ActNpc217, + ActNpc218, + ActNpc219, + ActNpc220, + ActNpc221, + ActNpc222, + ActNpc223, + ActNpc224, + ActNpc225, + ActNpc226, + ActNpc227, + ActNpc228, + ActNpc229, + ActNpc230, + ActNpc231, + ActNpc232, + ActNpc233, + ActNpc234, + ActNpc235, + ActNpc236, + ActNpc237, + ActNpc238, + ActNpc239, + ActNpc240, + ActNpc241, + ActNpc242, + ActNpc243, + ActNpc244, + ActNpc245, + ActNpc246, + ActNpc247, + ActNpc248, + ActNpc249, + ActNpc250, + ActNpc251, + ActNpc252, + ActNpc253, + ActNpc254, + ActNpc255, + ActNpc256, + ActNpc257, + ActNpc258, + ActNpc259, + ActNpc260, + ActNpc261, + ActNpc262, + ActNpc263, + ActNpc264, + ActNpc265, + ActNpc266, + ActNpc267, + ActNpc268, + ActNpc269, + ActNpc270, + ActNpc271, + ActNpc272, + ActNpc273, + ActNpc274, + ActNpc275, + ActNpc276, + ActNpc277, + ActNpc278, + ActNpc279, + ActNpc280, + ActNpc281, + ActNpc282, + ActNpc283, + ActNpc284, + ActNpc285, + ActNpc286, + ActNpc287, + ActNpc288, + ActNpc289, + ActNpc290, + ActNpc291, + ActNpc292, + ActNpc293, + ActNpc294, + ActNpc295, + ActNpc296, + ActNpc297, + ActNpc298, + ActNpc299, + ActNpc300, + ActNpc301, + ActNpc302, + ActNpc303, + ActNpc304, + ActNpc305, + ActNpc306, + ActNpc307, + ActNpc308, + ActNpc309, + ActNpc310, + ActNpc311, + ActNpc312, + ActNpc313, + ActNpc314, + ActNpc315, + ActNpc316, + ActNpc317, + ActNpc318, + ActNpc319, + ActNpc320, + ActNpc321, + ActNpc322, + ActNpc323, + ActNpc324, + ActNpc325, + ActNpc326, + ActNpc327, + ActNpc328, + ActNpc329, + ActNpc330, + ActNpc331, + ActNpc332, + ActNpc333, + ActNpc334, + ActNpc335, + ActNpc336, + ActNpc337, + ActNpc338, + ActNpc339, + ActNpc340, + ActNpc341, + ActNpc342, + ActNpc343, + ActNpc344, + ActNpc345, + ActNpc346, + ActNpc347, + ActNpc348, + ActNpc349, + ActNpc350, + ActNpc351, + ActNpc352, + ActNpc353, + ActNpc354, + ActNpc355, + ActNpc356, + ActNpc357, + ActNpc358, + ActNpc359, + ActNpc360, +}; + +NPC_TABLE *gNpcTable; + +BOOL LoadNpcTable(const char *path) +{ + FILE *fp; + int n; + size_t size; + int num; + + size = GetFileSizeLong(path); // TODO - Investigate whether GetFileSizeLong actually returns an unsigned long or not + if (size == INVALID_FILE_SIZE) + return FALSE; + + num = (int)(size / 0x18); + + gNpcTable = (NPC_TABLE*)malloc(num * sizeof(NPC_TABLE)); + if (gNpcTable == NULL) + return FALSE; + + fp = fopen(path, "rb"); + if (fp == NULL) + { + free(gNpcTable); + gNpcTable = NULL; + return FALSE; + } + + for (n = 0; n < num; ++n) // bits + fread(&gNpcTable[n].bits, 2, 1, fp); + for (n = 0; n < num; ++n) // life + fread(&gNpcTable[n].life, 2, 1, fp); + for (n = 0; n < num; ++n) // surf + fread(&gNpcTable[n].surf, 1, 1, fp); + for (n = 0; n < num; ++n) // destroy_voice + fread(&gNpcTable[n].destroy_voice, 1, 1, fp); + for (n = 0; n < num; ++n) // hit_voice + fread(&gNpcTable[n].hit_voice, 1, 1, fp); + for (n = 0; n < num; ++n) // size + fread(&gNpcTable[n].size, 1, 1, fp); + for (n = 0; n < num; ++n) // exp + fread(&gNpcTable[n].exp, 4, 1, fp); + for (n = 0; n < num; ++n) // damage + fread(&gNpcTable[n].damage, 4, 1, fp); + for (n = 0; n < num; ++n) // hit + fread(&gNpcTable[n].hit, 4, 1, fp); + for (n = 0; n < num; ++n) // view + fread(&gNpcTable[n].view, 4, 1, fp); + + fclose(fp); + return TRUE; +} + +void ReleaseNpcTable(void) +{ + if (gNpcTable != NULL) + { + free(gNpcTable); + gNpcTable = NULL; + } +} diff --git a/src/NpcTbl.h b/src/NpcTbl.h new file mode 100644 index 0000000..9280c5f --- /dev/null +++ b/src/NpcTbl.h @@ -0,0 +1,43 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "NpChar.h" + +struct NPC_TBL_RECT +{ + unsigned char front; + unsigned char top; + unsigned char back; + unsigned char bottom; +}; + +struct NPC_TABLE +{ + unsigned short bits; + unsigned short life; + unsigned char surf; + unsigned char hit_voice; + unsigned char destroy_voice; + unsigned char size; + long exp; + long damage; + NPC_TBL_RECT hit; + NPC_TBL_RECT view; +}; + +extern NPC_TABLE *gNpcTable; + +BOOL LoadNpcTable(const char *path); +void ReleaseNpcTable(void); + +// NPC Function table +typedef void (*NPCFUNCTION)(NPCHAR*); +extern const NPCFUNCTION gpNpcFuncTbl[]; diff --git a/src/Organya.cpp b/src/Organya.cpp new file mode 100644 index 0000000..b27ef13 --- /dev/null +++ b/src/Organya.cpp @@ -0,0 +1,1080 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +// Some of the original source code for this file can be found here: +// https://github.com/shbow/organya/blob/master/source/OrgFile.cpp +// https://github.com/shbow/organya/blob/master/source/OrgPlay.cpp +// https://github.com/shbow/organya/blob/master/source/Sound.cpp +// https://github.com/shbow/organya/blob/master/source/WinTimer.cpp + +#include "Organya.h" + +#include +#include +#include + +#ifdef FIX_BUGS +// The original source code forgot to set this (you can tell because, in the original EXE, +// the DSBUFFERDESC structs in this file have a different size to the ones in Sound.cpp) +#define DIRECTSOUND_VERSION 0x500 +#endif +#include + +#include "WindowsWrapper.h" + +#include "Sound.h" + +#define PANDUMMY 0xFF +#define VOLDUMMY 0xFF +#define KEYDUMMY 0xFF + +#define ALLOCNOTE 4096 + +#define DEFVOLUME 200//255はVOLDUMMY。MAXは254 +#define DEFPAN 6 + +//曲情報をセットする時のフラグ +#define SETALL 0xffffffff//全てをセット +#define SETWAIT 0x00000001 +#define SETGRID 0x00000002 +#define SETALLOC 0x00000004 +#define SETREPEAT 0x00000008 +#define SETFREQ 0x00000010 +#define SETWAVE 0x00000020 +#define SETPIPI 0x00000040 + +typedef struct ORGANYATRACK +{ + unsigned short freq; // +α周波数(1000がDefault) (+ α frequency (1000 is Default)) + unsigned char wave_no; // 波形No (Waveform No) + unsigned char pipi; // ☆ + unsigned short note_num; // 音符の数 (Number of notes) +} ORGANYATRACK; + +typedef struct ORGANYADATA +{ + unsigned short wait; + unsigned char line; + unsigned char dot; + long repeat_x; // リピート (repeat) + long end_x; // 曲の終わり(リピートに戻る) (End of song (return to repeat)) + ORGANYATRACK tdata[MAXTRACK]; +} ORGANYADATA; + +// Below are Organya song data structures +typedef struct NOTELIST +{ + NOTELIST *from; // Previous address + NOTELIST *to; // Next address + + long x; // Position + unsigned char length; // Sound length + unsigned char y; // Sound height + unsigned char volume; // Volume + unsigned char pan; +} NOTELIST; + +// Track data * 8 +typedef struct TRACKDATA +{ + unsigned short freq; // Frequency (1000 is default) + unsigned char wave_no; // Waveform No. + signed char pipi; + + NOTELIST *note_p; + NOTELIST *note_list; +} TRACKDATA; + +// Unique information held in songs +typedef struct MUSICINFO +{ + unsigned short wait; + unsigned char line; // Number of lines in one measure + unsigned char dot; // Number of dots per line + unsigned short alloc_note; // Number of allocated notes + long repeat_x; // Repeat + long end_x; // End of song (Return to repeat) + TRACKDATA tdata[MAXTRACK]; +} MUSICINFO; + +// メインクラス。このアプリケーションの中心。(クラスってやつを初めて使う) (Main class. The heart of this application. (Class is used for the first time)) +typedef struct OrgData +{ + OrgData(); // コンストラクタ (Constructor) +// ~OrgData(); // デストラクタ (Destructor) + MUSICINFO info; + char track; + char mute[MAXTRACK]; + unsigned char def_pan; + unsigned char def_volume; + void InitOrgData(void); + void GetMusicInfo(MUSICINFO *mi); // 曲情報を取得 (Get song information) + // 曲情報を設定。flagは設定アイテムを指定 (Set song information. flag specifies the setting item) + BOOL SetMusicInfo(MUSICINFO *mi,unsigned long flag); + BOOL NoteAlloc(unsigned short note_num); // 指定の数だけNoteDataの領域を確保 (Allocate the specified number of NoteData areas.) + void ReleaseNote(void); // NoteDataを開放 (Release NoteData) + // 以下は再生 (The following is playback) + void PlayData(void); + void SetPlayPointer(long x); // 再生ポインターを指定の位置に設定 (Set playback pointer to specified position) + // 以下はファイル関係 (The following are related to files) + BOOL InitMusicData(const char *path); +} ORGDATA; + +LPDIRECTSOUNDBUFFER lpORGANBUFFER[8][8][2] = {NULL}; + +///////////////////////////////////////////// +//■オルガーニャ■■■■■■■■■■■■/////// (Organya) +///////////////////// + +// Wave playing and loading +typedef struct +{ + short wave_size; + short oct_par; + short oct_size; +} OCTWAVE; + +OCTWAVE oct_wave[8] = +{ + { 256, 1, 4 }, // 0 Oct + { 256, 2, 8 }, // 1 Oct + { 128, 4, 12 }, // 2 Oct + { 128, 8, 16 }, // 3 Oct + { 64, 16, 20 }, // 4 Oct + { 32, 32, 24 }, // 5 Oct + { 16, 64, 28 }, // 6 Oct + { 8,128, 32 }, // 7 Oct +}; + +WAVEFORMATEX format_tbl2 = {WAVE_FORMAT_PCM, 1, 22050, 22050, 1, 8, 0}; // 22050HzのFormat + +// In the original source code, format_tbl2 was a raw array of bytes, as seen below +// BYTE format_tbl2[] = {0x01,0x00,0x01,0x00,0x22,0x56,0x00,0x00,0x22,0x56,0x00,0x00,0x01,0x00,0x08,0x00,0x00,0x00}; // 22050HzのFormat + +BOOL MakeSoundObject8(signed char *wavep, signed char track, signed char pipi) +{ + DWORD i,j,k; + unsigned long wav_tp; // WAVテーブルをさすポインタ (Pointer to WAV table) + DWORD wave_size; // 256; + DWORD data_size; + BYTE *wp; + BYTE *wp_sub; + int work; + // セカンダリバッファの生成 (Create secondary buffer) + DSBUFFERDESC dsbd; + + if (lpDS == NULL) + return FALSE; + + for (j = 0; j < 8; j++) + { + for (k = 0; k < 2; k++) + { + wave_size = oct_wave[j].wave_size; + + if (pipi) + data_size = wave_size * oct_wave[j].oct_size; + else + data_size = wave_size; + + ZeroMemory(&dsbd, sizeof(dsbd)); + + dsbd.dwSize = sizeof(dsbd); + dsbd.dwBufferBytes = data_size; + dsbd.lpwfxFormat = &format_tbl2; + dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + + if(lpDS->CreateSoundBuffer(&dsbd, &lpORGANBUFFER[track][j][k], NULL) != DS_OK) // j = se_no + return FALSE; + + // Get wave data + wp = (BYTE*)malloc(data_size); + wp_sub = wp; + wav_tp = 0; + + for (i = 0; i < data_size; i++) + { + work = *(wavep + wav_tp); + work += 0x80; + + *wp_sub = (BYTE)work; + + wav_tp += 0x100 / wave_size; + if (wav_tp > 0xFF) + wav_tp -= 0x100; + + wp_sub++; + } + + // データの転送 (Data transfer) + LPVOID lpbuf1, lpbuf2; + DWORD dwbuf1, dwbuf2=0; + HRESULT hr; + + hr = lpORGANBUFFER[track][j][k]->Lock(0, data_size, &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0); + + if (hr != DS_OK) + { + #ifdef FIX_MAJOR_BUGS + free(wp); // The updated Organya source code includes this fix + #endif + return FALSE; + } + + CopyMemory(lpbuf1, (BYTE*)wp, dwbuf1); + + if (dwbuf2 != 0) + CopyMemory(lpbuf2, (BYTE*)wp+dwbuf1, dwbuf2); + + lpORGANBUFFER[track][j][k]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2); + lpORGANBUFFER[track][j][k]->SetCurrentPosition(0); + free(wp); + } + } + + return TRUE; +} + +short freq_tbl[12] = {262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494}; + +void ChangeOrganFrequency(unsigned char key, signed char track, long a) +{ + if (lpDS == NULL) + return; + + for (int j = 0; j < 8; j++) + for (int i = 0; i < 2; i++) + lpORGANBUFFER[track][j][i]->SetFrequency(((oct_wave[j].wave_size * freq_tbl[key]) * oct_wave[j].oct_par) / 8 + (a - 1000)); // 1000を+αのデフォルト値とする (1000 is the default value for + α) +} + +BOOL g_mute[MAXTRACK]; // Used by the debug Mute menu +short pan_tbl[13] = {0, 43, 86, 129, 172, 215, 256, 297, 340, 383, 426, 469, 512}; +unsigned char old_key[MAXTRACK] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 再生中の音 (Sound being played) +unsigned char key_on[MAXTRACK]; // キースイッチ (Key switch) +unsigned char key_twin[MAXTRACK]; // 今使っているキー(連続時のノイズ防止の為に二つ用意) (Currently used keys (prepared for continuous noise prevention)) + +void ChangeOrganPan(unsigned char key, unsigned char pan, signed char track) // 512がMAXで256がノーマル (512 is MAX and 256 is normal) +{ + if (lpDS == NULL) + return; + + if (old_key[track] != KEYDUMMY) + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetPan((pan_tbl[pan] - 0x100) * 10); +} + +void ChangeOrganVolume(int no, long volume, signed char track) // 300がMAXで300がノーマル (300 is MAX and 300 is normal) +{ + if (lpDS == NULL) + return; + + if (old_key[track] != KEYDUMMY) + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetVolume((volume - 0xFF) * 8); +} + +// サウンドの再生 (Play sound) +void PlayOrganObject(unsigned char key, int mode, signed char track, long freq) +{ + if (lpDS == NULL) + return; + + if (lpORGANBUFFER[track][key / 12][key_twin[track]] != NULL) + { + switch (mode) + { + case 0: // 停止 (Stop) + if (old_key[track] != 0xFF) + { + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Stop(); + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetCurrentPosition(0); + } + break; + + case 1: // 再生 (Playback) + break; + + case 2: // 歩かせ停止 (Stop playback) + if (old_key[track] != 0xFF) + { + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0); + old_key[track] = 0xFF; + } + break; + + case -1: + if (old_key[track] == 0xFF) // 新規鳴らす (New sound) + { + ChangeOrganFrequency(key % 12, track, freq); // 周波数を設定して (Set the frequency) + lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING); + old_key[track] = key; + key_on[track] = 1; + } + else if (key_on[track] == 1 && old_key[track] == key) // 同じ音 (Same sound) + { + // 今なっているのを歩かせ停止 (Stop playback now) + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0); + key_twin[track]++; + if (key_twin[track] > 1) + key_twin[track] = 0; + lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING); + } + else // 違う音を鳴らすなら (If you make a different sound) + { + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(0, 0, 0); // 今なっているのを歩かせ停止 (Stop playback now) + key_twin[track]++; + if (key_twin[track] > 1) + key_twin[track] = 0; + ChangeOrganFrequency(key % 12, track, freq); // 周波数を設定して (Set the frequency) + lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(0, 0, DSBPLAY_LOOPING); + old_key[track] = key; + } + + break; + } + } +} + +// オルガーニャオブジェクトを開放 (Open Organya object) +void ReleaseOrganyaObject(signed char track) +{ + if (lpDS == NULL) + return; + + for (int i = 0; i < 8; i++) + { + if (lpORGANBUFFER[track][i][0] != NULL) + { + lpORGANBUFFER[track][i][0]->Release(); + lpORGANBUFFER[track][i][0] = NULL; + } + if (lpORGANBUFFER[track][i][1] != NULL) + { + lpORGANBUFFER[track][i][1]->Release(); + lpORGANBUFFER[track][i][1] = NULL; + } + } +} + +// 波形データをロード (Load waveform data) +signed char wave_data[100][0x100]; + +BOOL InitWaveData100(void) +{ + HRSRC hrscr; + DWORD *lpdword; // リソースのアドレス (Resource address) + + if (lpDS == NULL) + return FALSE; + + // リソースの検索 (Search for resources) + hrscr = FindResourceA(NULL, "WAVE100", "WAVE"); + + if (hrscr == NULL) + return FALSE; + + // リソースのアドレスを取得 (Get resource address) + lpdword = (DWORD*)LockResource(LoadResource(NULL, hrscr)); + memcpy(wave_data, lpdword, 100 * 0x100); + + return TRUE; +} + +// 波形を100個の中から選択して作成 (Select from 100 waveforms to create) +BOOL MakeOrganyaWave(signed char track, signed char wave_no, signed char pipi) +{ + if (lpDS == NULL) + return FALSE; + + if (wave_no > 99) + return FALSE; + + ReleaseOrganyaObject(track); + MakeSoundObject8(wave_data[wave_no], track, pipi); + + return TRUE; +} + +///////////////////////////////////////////// +//■オルガーニャドラムス■■■■■■■■/////// (Organya drums) +///////////////////// + +void ChangeDramFrequency(unsigned char key, signed char track) +{ + if (lpDS == NULL) + return; + + lpSECONDARYBUFFER[150 + track]->SetFrequency(key * 800 + 100); +} + +void ChangeDramPan(unsigned char pan, signed char track) +{ + if (lpDS == NULL) + return; + + lpSECONDARYBUFFER[150 + track]->SetPan((pan_tbl[pan] - 0x100) * 10); +} + +void ChangeDramVolume(long volume, signed char track) +{ + if (lpDS == NULL) + return; + + lpSECONDARYBUFFER[150 + track]->SetVolume((volume - 0xFF) * 8); +} + +// サウンドの再生 (Play sound) +void PlayDramObject(unsigned char key, int mode, signed char track) +{ + if (lpDS == NULL) + return; + + if (lpSECONDARYBUFFER[150 + track] != NULL) + { + switch (mode) + { + case 0: // 停止 (Stop) + lpSECONDARYBUFFER[150 + track]->Stop(); + lpSECONDARYBUFFER[150 + track]->SetCurrentPosition(0); + break; + + case 1: // 再生 (Playback) + lpSECONDARYBUFFER[150 + track]->Stop(); + lpSECONDARYBUFFER[150 + track]->SetCurrentPosition(0); + ChangeDramFrequency(key, track); // 周波数を設定して (Set the frequency) + lpSECONDARYBUFFER[150 + track]->Play(0, 0, 0); + break; + + case 2: // 歩かせ停止 (Stop playback) + break; + + case -1: + break; + } + } +} + +ORGDATA org_data; + +OrgData::OrgData(void) +{ + for (int i = 0; i < MAXTRACK; i++) + { + info.tdata[i].note_list = NULL; + info.tdata[i].note_p = NULL; + } +} + +void OrgData::InitOrgData(void) +{ + track = 0; + info.alloc_note = ALLOCNOTE; // とりあえず10000個確保 (For the time being, secure 10,000 pieces) + info.dot = 4; + info.line = 4; + info.wait = 128; + info.repeat_x = info.dot * info.line * 0; + info.end_x = info.dot * info.line * 255; + + for (int i = 0; i < MAXTRACK; i++) + { + info.tdata[i].freq = 1000; + info.tdata[i].wave_no = 0; + info.tdata[i].pipi = 0; + } + + NoteAlloc(info.alloc_note); + SetMusicInfo(&info, SETALL); + + def_pan = DEFPAN; + def_volume = DEFVOLUME; +} + +// 曲情報を設定。flagはアイテムを指定 (Set song information. flag specifies an item) +BOOL OrgData::SetMusicInfo(MUSICINFO *mi, unsigned long flag) +{ + char str[32]; // Leftover debug junk + int i; + + if (flag & SETGRID) // グリッドを有効に (Enable grid) + { + info.dot = mi->dot; + info.line = mi->line; + } + + if (flag & SETWAIT) + { + info.wait = mi->wait; + itoa(mi->wait, str, 10); // Leftover debug junk + } + + if (flag & SETREPEAT) + { + info.repeat_x = mi->repeat_x; + info.end_x = mi->end_x; + } + + if (flag & SETFREQ) + { + for (i = 0; i < MAXMELODY; i++) + { + info.tdata[i].freq = mi->tdata[i].freq; + info.tdata[i].pipi = info.tdata[i].pipi; // Just sets info.tdata[i].pipi to itself (SETPIPI already sets pipi, so maybe this line shouldn't be here in the first place) + } + } + + if (flag & SETWAVE) + for (i = 0; i < MAXTRACK; i++) + info.tdata[i].wave_no = mi->tdata[i].wave_no; + + if (flag & SETPIPI) + for (i = 0; i < MAXTRACK; i++) + info.tdata[i].pipi = mi->tdata[i].pipi; + + return TRUE; +} + +// 指定の数だけNoteDataの領域を確保(初期化) (Allocate the specified number of NoteData areas (initialization)) +BOOL OrgData::NoteAlloc(unsigned short alloc) +{ + int i,j; + + for (j = 0; j < MAXTRACK; j++) + { + info.tdata[j].wave_no = 0; + info.tdata[j].note_list = NULL; // コンストラクタにやらせたい (I want the constructor to do it) + info.tdata[j].note_p = (NOTELIST*)malloc(sizeof(NOTELIST) * alloc); + + if (info.tdata[j].note_p == NULL) + { + for (i = 0; i < MAXTRACK; i++) + { + if (info.tdata[i].note_p != NULL) + { + free(info.tdata[i].note_p); + #ifdef FIX_BUGS + info.tdata[i].note_p = NULL; + #else + info.tdata[j].note_p = NULL; // Uses j instead of i + #endif + } + } + + return FALSE; + } + + for (i = 0; i < alloc; i++) + { + (info.tdata[j].note_p + i)->from = NULL; + (info.tdata[j].note_p + i)->to = NULL; + (info.tdata[j].note_p + i)->length = 0; + (info.tdata[j].note_p + i)->pan = PANDUMMY; + (info.tdata[j].note_p + i)->volume = VOLDUMMY; + (info.tdata[j].note_p + i)->y = KEYDUMMY; + } + } + + for (j = 0; j < MAXMELODY; j++) + MakeOrganyaWave(j, info.tdata[j].wave_no, info.tdata[j].pipi); + + track = 0; // 今はここに書いておく (Write here now) + + return TRUE; +} + +// NoteDataを開放 (Release NoteData) +void OrgData::ReleaseNote(void) +{ + for (int i = 0; i < MAXTRACK; i++) + { + if (info.tdata[i].note_p != NULL) + { + free(info.tdata[i].note_p); + info.tdata[i].note_p = NULL; + } + } +} + +char pass[7] = "Org-01"; +char pass2[7] = "Org-02"; // Pipi + +BOOL OrgData::InitMusicData(const char *path) +{ + ORGANYADATA org_data; + NOTELIST *np; + int i,j; + char pass_check[6]; + char ver = 0; + + HRSRC hrscr = FindResourceA(NULL, path, "ORG"); + if (hrscr == NULL) + return FALSE; + + unsigned char *p = (unsigned char*)LockResource(LoadResource(0, hrscr)); + + memcpy(&pass_check[0], p, 6); + p += 6; + + if(memcmp(pass_check, pass, 6) == 0) + ver = 1; + if(memcmp(pass_check, pass2, 6) == 0) + ver = 2; + + if(ver == 0) + return FALSE; + + // 曲情報の読み込み (Loading song information) + memcpy(&org_data, p, sizeof(ORGANYADATA)); + p += sizeof(ORGANYADATA); + + // 曲の情報を設定 (Set song information) + info.wait = org_data.wait; + info.line = org_data.line; + info.dot = org_data.dot; + info.repeat_x = org_data.repeat_x; + info.end_x = org_data.end_x; + + for (i = 0; i < MAXTRACK; i++) + { + info.tdata[i].freq = org_data.tdata[i].freq; + + if (ver == 1) + info.tdata[i].pipi = 0; + else + info.tdata[i].pipi = org_data.tdata[i].pipi; + + info.tdata[i].wave_no = org_data.tdata[i].wave_no; + } + + // 音符のロード (Loading notes) + for (j = 0; j < MAXTRACK; j++) + { + // 最初の音符はfromがNULLとなる (The first note has from as NULL) + if (org_data.tdata[j].note_num == 0) + { + info.tdata[j].note_list = NULL; + continue; + } + + // リストを作る (Make a list) + np = info.tdata[j].note_p; + info.tdata[j].note_list = info.tdata[j].note_p; + np->from = NULL; + np->to = (np + 1); + np++; + + for (i = 1; i < org_data.tdata[j].note_num; i++) + { + np->from = (np - 1); + np->to = (np + 1); + np++; + } + + // 最後の音符のtoはNULL (The last note to is NULL) + np--; + np->to = NULL; + + // 内容を代入 (Assign content) + np = info.tdata[j].note_p; // X座標 (X coordinate) + for (i = 0; i < org_data.tdata[j].note_num; i++) + { + memcpy(&np->x, p, sizeof(long)); + p += sizeof(long); + np++; + } + + np = info.tdata[j].note_p; // Y座標 (Y coordinate) + for (i = 0; i < org_data.tdata[j].note_num; i++) + { + memcpy(&np->y, p, sizeof(unsigned char)); + p += sizeof(unsigned char); + np++; + } + + np = info.tdata[j].note_p; // 長さ (Length) + for (i = 0; i < org_data.tdata[j].note_num; i++) + { + memcpy(&np->length, p, sizeof(unsigned char)); + p += sizeof(unsigned char); + np++; + } + + np = info.tdata[j].note_p; // ボリューム (Volume) + for (i = 0; i < org_data.tdata[j].note_num; i++) + { + memcpy(&np->volume, p, sizeof(unsigned char)); + p += sizeof(unsigned char); + np++; + } + + np = info.tdata[j].note_p; // パン (Pan) + for (i = 0; i < org_data.tdata[j].note_num; i++) + { + memcpy(&np->pan, p, sizeof(unsigned char)); + p += sizeof(unsigned char); + np++; + } + } + + // データを有効に (Enable data) + for (j = 0; j < MAXMELODY; j++) + MakeOrganyaWave(j,info.tdata[j].wave_no, info.tdata[j].pipi); + + // Pixel ripped out some code so he could use PixTone sounds as drums, but he left this dead code + for (j = MAXMELODY; j < MAXTRACK; j++) + { + i = info.tdata[j].wave_no; + //InitDramObject(dram_name[i], j - MAXMELODY); + } + + SetPlayPointer(0); // 頭出し (Cue) + + return TRUE; +} + +// 曲情報を取得 (Get song information) +void OrgData::GetMusicInfo(MUSICINFO *mi) +{ + mi->dot = info.dot; + mi->line = info.line; + mi->alloc_note = info.alloc_note; + mi->wait = info.wait; + mi->repeat_x = info.repeat_x; + mi->end_x = info.end_x; + + for (int i = 0; i < MAXTRACK; i++) + { + mi->tdata[i].freq = info.tdata[i].freq; + mi->tdata[i].wave_no = info.tdata[i].wave_no; + mi->tdata[i].pipi = info.tdata[i].pipi; + } +} + +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +//プロトタイプ宣言 (prototype declaration) +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ + +BOOL InitMMTimer(); +BOOL StartTimer(DWORD dwTimer); +//VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2); // The original code used the wrong types +VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2); +BOOL QuitMMTimer(); + +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +//グローバル変数 (Global variable) +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +UINT ExactTime = 13; // 最小精度 (Minimum accuracy) +UINT TimerID; +BOOL bTimer; + +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +// タイマー精度を設定する。 (Set timer accuracy.) +// この関数はアプリケーション初期化時に一度呼び出す。 (This function is called once when the application is initialized.) +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +BOOL InitMMTimer(void) +{ + TIMECAPS tc; + MMRESULT ret; + + // タイマーの精度情報を取得する (Get timer accuracy information) + ret = timeGetDevCaps(&tc,sizeof(TIMECAPS)); + if (ret != TIMERR_NOERROR) + return FALSE; + + if (ExactTime < tc.wPeriodMin) + ExactTime = tc.wPeriodMin; + + // この精度で初期化する (Initialize with this precision) + ret = timeBeginPeriod(ExactTime); + if (ret != TIMERR_NOERROR) + return FALSE; + + return TRUE; +} + +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +// タイマーを起動する。 (Start the timer.) +// dwTimer 設定するタイマー間隔 (dwTimer Timer interval to be set) +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +BOOL StartTimer(DWORD dwTimer) +{ + MMRESULT ret = MMSYSERR_NOERROR; + ExactTime = dwTimer; + + // タイマーを生成する (Generate timer) + TimerID = timeSetEvent + ( + dwTimer, // タイマー時間 (Timer time) + 10, // 許容できるタイマー精度 (Acceptable timer accuracy) + TimerProc, // コールバックプロシージャ (Callback procedure) + 0, // ユーザーがコールバック関数のdwUserに送る情報値 (Information value sent by user to dwUser in callback function) + TIME_PERIODIC // タイマー時間毎にイベントを発生させる (Generate an event every timer time) + ); + + if (ret != TIMERR_NOERROR) + return FALSE; + + bTimer = TRUE; + + return TRUE; +} + +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +// タイマーのコールバック関数 (Timer callback function) +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +//VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2) // The original code used the wrong types +VOID CALLBACK TimerProc(UINT uTID,UINT uMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2) +{ + (void)uTID; + (void)uMsg; + (void)dwUser; + (void)dwParam1; + (void)dwParam2; + + DWORD dwNowTime; + dwNowTime = timeGetTime(); + //=================================================================================== + // ここにユーザー定義のソースを書く。 (Write user-defined source here.) + // 基本的に関数を呼び出すだけで処理は他の関数でするべきだろう。 (Basically just call a function and the process should be another function.) + //=================================================================================== + org_data.PlayData(); +} + +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +// タイマーリソースを開放する。 (Release timer resources.) +// アプリケーション終了時に一度呼び出す。 (Call once when the application ends.) +/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/ +BOOL QuitMMTimer(void) +{ + MMRESULT ret; + + if (!bTimer) + return FALSE; + + if(TimerID != TIMERR_NOERROR) + { + // タイマーを使用中なら終了させる (Terminate timer if in use) + ret = timeKillEvent(TimerID); + if (ret != TIMERR_NOERROR) + return FALSE; + } + + // タイマーリソースを開放する (Release timer resources) + ret = timeEndPeriod(ExactTime); + if (ret != TIMERR_NOERROR) + return FALSE; + + bTimer = FALSE; + + return TRUE; +} + +// Play data +long PlayPos; // Called 'play_p' in the source code release +NOTELIST *np[MAXTRACK]; +long now_leng[MAXMELODY]; + +int Volume = 100; +int TrackVol[MAXTRACK]; +BOOL bFadeout = FALSE; + +void OrgData::PlayData(void) +{ + int i; + + // Handle fading out + if (bFadeout && Volume) + Volume -= 2; + if (Volume < 0) + Volume = 0; + + // メロディの再生 (Play melody) + for (i = 0; i < MAXMELODY; i++) + { + if (np[i] != NULL && PlayPos == np[i]->x) + { + if (!g_mute[i] && np[i]->y != KEYDUMMY) // 音が来た。 (The sound has come.) + { + PlayOrganObject(np[i]->y, -1, i, info.tdata[i].freq); + now_leng[i] = np[i]->length; + } + + if (np[i]->pan != PANDUMMY) + ChangeOrganPan(np[i]->y, np[i]->pan, i); + if (np[i]->volume != VOLDUMMY) + TrackVol[i] = np[i]->volume; + + np[i] = np[i]->to; // 次の音符を指す (Points to the next note) + } + + if (now_leng[i] == 0) + PlayOrganObject(0, 2, i, info.tdata[i].freq); + + if (now_leng[i] > 0) + now_leng[i]--; + + if (np[i]) + ChangeOrganVolume(np[i]->y, TrackVol[i] * Volume / 0x7F, i); + } + + // ドラムの再生 (Drum playback) + for (i = MAXMELODY; i < MAXTRACK; i++) + { + if (np[i] != NULL && PlayPos == np[i]->x) // 音が来た。 (The sound has come.) + { + if (np[i]->y != KEYDUMMY && !g_mute[i]) // ならす (Tame) + PlayDramObject(np[i]->y, 1, i - MAXMELODY); + + if (np[i]->pan != PANDUMMY) + ChangeDramPan(np[i]->pan, i - MAXMELODY); + if (np[i]->volume != VOLDUMMY) + TrackVol[i] = np[i]->volume; + + np[i] = np[i]->to; // 次の音符を指す (Points to the next note) + } + + if (np[i]) + ChangeDramVolume(TrackVol[i] * Volume / 0x7F, i - MAXMELODY); + } + + // Looping + PlayPos++; + if (PlayPos >= info.end_x) + { + PlayPos = info.repeat_x; + SetPlayPointer(PlayPos); + } +} + +void OrgData::SetPlayPointer(long x) +{ + for (int i = 0; i < MAXTRACK; i++) + { + np[i] = info.tdata[i].note_list; + while (np[i] != NULL && np[i]->x < x) + np[i] = np[i]->to; // 見るべき音符を設定 (Set note to watch) + } + + PlayPos = x; +} + +// Start and end organya +BOOL StartOrganya(LPDIRECTSOUND _lpDS, const char *path_wave) // Both arguments are ignored for some reason +{ + if (lpDS == NULL) + return FALSE; + + if (!InitWaveData100()) + return FALSE; + + org_data.InitOrgData(); + + return TRUE; +} + +// Load organya file +BOOL LoadOrganya(const char *name) +{ + if (lpDS == NULL) + return FALSE; + + if (!org_data.InitMusicData(name)) + return FALSE; + + Volume = 100; + bFadeout = 0; + +#ifdef FIX_BUGS + return TRUE; +#else + return FALSE; // Err... isn't this meant to be 'TRUE'? +#endif +} + +void SetOrganyaPosition(unsigned int x) +{ + if (lpDS == NULL) + return; + + org_data.SetPlayPointer(x); + Volume = 100; + bFadeout = FALSE; +} + +unsigned int GetOrganyaPosition(void) +{ + if (lpDS == NULL) + return 0; + + return PlayPos; +} + +void PlayOrganyaMusic(void) +{ + if (lpDS == NULL) + return; + + QuitMMTimer(); + InitMMTimer(); + StartTimer(org_data.info.wait); +} + +BOOL ChangeOrganyaVolume(signed int volume) +{ + if (lpDS == NULL) + return FALSE; + + if (volume < 0 || volume > 100) + return FALSE; + + Volume = volume; + return TRUE; +} + +void StopOrganyaMusic(void) +{ + if (lpDS == NULL) + return; + + // Stop timer + QuitMMTimer(); + + // Stop notes + for (int i = 0; i < MAXMELODY; i++) + PlayOrganObject(0, 2, i, 0); + + memset(old_key, 255, sizeof(old_key)); + memset(key_on, 0, sizeof(key_on)); + memset(key_twin, 0, sizeof(key_twin)); + + // Put the main thread to sleep for 100 milliseconds... but why? + // Really, what's the point? All this does is cause an annoying + // stutter when a new song loads. + // I'd guess it avoids a race-condition with the Organya thread, + // but the earlier QuitMMTimer call already disables it. + Sleep(100); +} + +void SetOrganyaFadeout(void) +{ + bFadeout = TRUE; +} + +void EndOrganya(void) +{ + if (lpDS == NULL) + return; + + // End timer + QuitMMTimer(); + + // Release everything related to org + org_data.ReleaseNote(); + + for (int i = 0; i < MAXMELODY; i++) + { + PlayOrganObject(0, 0, i, 0); + ReleaseOrganyaObject(i); + } +} diff --git a/src/Organya.h b/src/Organya.h new file mode 100644 index 0000000..9f3437c --- /dev/null +++ b/src/Organya.h @@ -0,0 +1,36 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#ifdef FIX_BUGS +// The original source code forgot to set this (you can tell because, in the original EXE, +// the DSBUFFERDESC structs in Organya.cpp have a different size to the ones in Sound.cpp) +#define DIRECTSOUND_VERSION 0x500 +#endif +#include + +#include "WindowsWrapper.h" + +#define MAXTRACK 16 +#define MAXMELODY 8 +#define MAXDRAM 8 + +extern BOOL g_mute[MAXTRACK]; // Used by the debug Mute menu + +BOOL MakeOrganyaWave(signed char track, signed char wave_no, signed char pipi); +void OrganyaPlayData(void); +void SetPlayPointer(long x); +BOOL LoadOrganya(const char *name); +void SetOrganyaPosition(unsigned int x); +unsigned int GetOrganyaPosition(void); +void PlayOrganyaMusic(void); +BOOL ChangeOrganyaVolume(signed int volume); +void StopOrganyaMusic(void); +void SetOrganyaFadeout(void); +BOOL StartOrganya(LPDIRECTSOUND lpDS, const char *wave_filename); +void EndOrganya(void); diff --git a/src/PixTone.cpp b/src/PixTone.cpp new file mode 100644 index 0000000..a358e14 --- /dev/null +++ b/src/PixTone.cpp @@ -0,0 +1,173 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "PixTone.h" + +#include +#include + +#include "WindowsWrapper.h" + +signed char gWaveModelTable[6][0x100]; + +void MakeWaveTables(void) +{ + int i; + + int a; + + // Sine wave + for (i = 0; i < 0x100; ++i) + { + gWaveModelTable[0][i] = (signed char)(sin((i * 6.283184) / 256.0) * 64.0); + a = gWaveModelTable[0][i]; // I have no idea what this line was meant to do + } + + // Triangle wave + for (a = 0, i = 0; i < 0x40; ++i) + { + // Upwards + gWaveModelTable[1][i] = (a * 0x40) / 0x40; + ++a; + } + for (a = 0; i < 0xC0; ++i) + { + // Downwards + gWaveModelTable[1][i] = 0x40 - ((a * 0x40) / 0x40); + ++a; + } + for (a = 0; i < 0x100; ++i) + { + // Back up + gWaveModelTable[1][i] = ((a * 0x40) / 0x40) - 0x40; + ++a; + } + + // Saw up wave + for (i = 0; i < 0x100; ++i) + gWaveModelTable[2][i] = (i / 2) - 0x40; + + // Saw down wave + for (i = 0; i < 0x100; ++i) + gWaveModelTable[3][i] = 0x40 - (i / 2); + + // Square wave + for (i = 0; i < 0x80; ++i) + gWaveModelTable[4][i] = 0x40; + for (; i < 0x100; ++i) + gWaveModelTable[4][i] = -0x40; + + // White noise wave + srand(0); + for (i = 0; i < 0x100; ++i) + gWaveModelTable[5][i] = (signed char)(rand() & 0xFF) / 2; +} + +//BOOL wave_tables_made; + +BOOL MakePixelWaveData(const PIXTONEPARAMETER *ptp, unsigned char *pData) +{ + int i; + int a, b, c, d; + + double dPitch; + double dMain; + double dVolume; + + double dEnvelope; + signed char envelopeTable[0x100]; + + double d1, d2, d3; + + // The Linux port added a cute optimisation here, where MakeWaveTables is only called once during the game's execution + //if (wave_tables_made != TRUE) + //{ + MakeWaveTables(); + // wave_tables_made = TRUE; + //} + + memset(envelopeTable, 0, sizeof(envelopeTable)); + + i = 0; + + dEnvelope = ptp->initial; + while (i < ptp->pointAx) + { + envelopeTable[i] = (signed char)dEnvelope; + dEnvelope = (((double)ptp->pointAy - ptp->initial) / ptp->pointAx) + dEnvelope; + ++i; + } + + dEnvelope = ptp->pointAy; + while (i < ptp->pointBx) + { + envelopeTable[i] = (signed char)dEnvelope; + dEnvelope = (((double)ptp->pointBy - ptp->pointAy) / (double)(ptp->pointBx - ptp->pointAx)) + dEnvelope; + ++i; + } + + dEnvelope = ptp->pointBy; + while (i < ptp->pointCx) + { + envelopeTable[i] = (signed char)dEnvelope; + dEnvelope = ((double)ptp->pointCy - ptp->pointBy) / (double)(ptp->pointCx - ptp->pointBx) + dEnvelope; + ++i; + } + + dEnvelope = ptp->pointCy; + while (i < 0x100) + { + envelopeTable[i] = (signed char)dEnvelope; + dEnvelope = dEnvelope - (ptp->pointCy / (double)(0x100 - ptp->pointCx)); + ++i; + } + + dPitch = ptp->oPitch.offset; + dMain = ptp->oMain.offset; + dVolume = ptp->oVolume.offset; + + if (ptp->oMain.num == 0.0) + d1 = 0.0; + else + d1 = 256.0 / (ptp->size / ptp->oMain.num); + + if (ptp->oPitch.num == 0.0) + d2 = 0.0; + else + d2 = 256.0 / (ptp->size / ptp->oPitch.num); + + if (ptp->oVolume.num == 0.0) + d3 = 0.0; + else + d3 = 256.0 / (ptp->size / ptp->oVolume.num); + + for (i = 0; i < ptp->size; ++i) + { + a = (int)dMain % 0x100; + b = (int)dPitch % 0x100; + c = (int)dVolume % 0x100; + d = (int)((double)(i * 0x100) / ptp->size); + pData[i] = gWaveModelTable[ptp->oMain.model][a] + * ptp->oMain.top + / 64 + * (((gWaveModelTable[ptp->oVolume.model][c] * ptp->oVolume.top) / 64) + 64) + / 64 + * envelopeTable[d] + / 64 + + 128; + + if (gWaveModelTable[ptp->oPitch.model][b] < 0) + dMain += d1 - d1 * 0.5 * -gWaveModelTable[ptp->oPitch.model][b] * ptp->oPitch.top / 64.0 / 64.0; + else + dMain += d1 + d1 * 2.0 * gWaveModelTable[ptp->oPitch.model][b] * ptp->oPitch.top / 64.0 / 64.0; + + dPitch += d2; + dVolume += d3; + } + + return TRUE; +} diff --git a/src/PixTone.h b/src/PixTone.h new file mode 100644 index 0000000..c8e63c8 --- /dev/null +++ b/src/PixTone.h @@ -0,0 +1,39 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef struct PIXTONEPARAMETER2 +{ + int model; + double num; + int top; + int offset; +} PIXTONEPARAMETER2; + +typedef struct PIXTONEPARAMETER +{ + int use; + int size; + PIXTONEPARAMETER2 oMain; + PIXTONEPARAMETER2 oPitch; + PIXTONEPARAMETER2 oVolume; + int initial; + int pointAx; + int pointAy; + int pointBx; + int pointBy; + int pointCx; + int pointCy; +} PIXTONEPARAMETER; + +extern signed char gWaveModelTable[6][0x100]; + +void MakeWaveTables(void); +BOOL MakePixelWaveData(const PIXTONEPARAMETER *ptp, unsigned char *pData); diff --git a/src/Profile.cpp b/src/Profile.cpp new file mode 100644 index 0000000..a0c7a88 --- /dev/null +++ b/src/Profile.cpp @@ -0,0 +1,208 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Profile.h" + +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "BossLife.h" +#include "Fade.h" +#include "Flags.h" +#include "Frame.h" +#include "Game.h" +#include "Main.h" +#include "MiniMap.h" +#include "MyChar.h" +#include "NpChar.h" +#include "SelStage.h" +#include "Stage.h" +#include "Star.h" +#include "ValueView.h" + +const char* const gDefaultName = "Profile.dat"; +const char* const gProfileCode = "Do041220"; + +BOOL IsProfile(void) +{ + char path[MAX_PATH]; + sprintf(path, "%s\\%s", gModulePath, gDefaultName); + + HANDLE hFile = CreateFileA(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + CloseHandle(hFile); + return TRUE; +} + +BOOL SaveProfile(const char *name) +{ + FILE *fp; + PROFILEDATA profile; + const char *FLAG = "FLAG"; + + char path[MAX_PATH]; + + // Get path + if (name != NULL) + sprintf(path, "%s\\%s", gModulePath, name); + else + sprintf(path, "%s\\%s", gModulePath, gDefaultName); + + // Open file + fp = fopen(path, "wb"); + if (fp == NULL) + return FALSE; + + // Set up profile + memset(&profile, 0, sizeof(PROFILEDATA)); + memcpy(profile.code, gProfileCode, sizeof(profile.code)); + memcpy(profile.FLAG, FLAG, sizeof(profile.FLAG)); + profile.stage = gStageNo; + profile.music = gMusicNo; + profile.x = gMC.x; + profile.y = gMC.y; + profile.direct = gMC.direct; + profile.max_life = gMC.max_life; + profile.life = gMC.life; + profile.star = gMC.star; + profile.select_arms = gSelectedArms; + profile.select_item = gSelectedItem; + profile.equip = gMC.equip; + profile.unit = gMC.unit; + profile.counter = gCounter; + memcpy(profile.arms, gArmsData, sizeof(profile.arms)); + memcpy(profile.items, gItemData, sizeof(profile.items)); + memcpy(profile.permitstage, gPermitStage, sizeof(profile.permitstage)); + memcpy(profile.permit_mapping, gMapping, sizeof(profile.permit_mapping)); + memcpy(profile.flags, gFlagNPC, sizeof(profile.flags)); + + // Write to file + fwrite(&profile, sizeof(PROFILEDATA), 1, fp); + + fclose(fp); + return TRUE; +} + +BOOL LoadProfile(const char *name) +{ + FILE *fp; + PROFILEDATA profile; + char path[MAX_PATH]; + + // Get path + if (name != NULL) + sprintf(path, "%s", name); + else + sprintf(path, "%s\\%s", gModulePath, gDefaultName); + + // Open file + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Check header code + fread(profile.code, 8, 1, fp); + if (memcmp(profile.code, gProfileCode, 8) != 0) + { +#ifdef FIX_BUGS + fclose(fp); // The original game forgets to close the file +#endif + return FALSE; + } + + // Read data + fseek(fp, 0, SEEK_SET); + memset(&profile, 0, sizeof(PROFILEDATA)); + fread(&profile, sizeof(PROFILEDATA), 1, fp); + fclose(fp); + + // Set things + gSelectedArms = profile.select_arms; + gSelectedItem = profile.select_item; + gCounter = profile.counter; + + memcpy(gArmsData, profile.arms, sizeof(gArmsData)); + memcpy(gItemData, profile.items, sizeof(gItemData)); + memcpy(gPermitStage, profile.permitstage, sizeof(gPermitStage)); + memcpy(gMapping, profile.permit_mapping, sizeof(gMapping)); + memcpy(gFlagNPC, profile.flags, sizeof(gFlagNPC)); + + // Load stage + ChangeMusic(profile.music); + InitMyChar(); + if (!TransferStage(profile.stage, 0, 0, 1)) + return FALSE; + + // Set character properties + gMC.equip = profile.equip; + gMC.unit = profile.unit; + gMC.direct = profile.direct; + gMC.max_life = profile.max_life; + gMC.life = profile.life; + gMC.star = profile.star; + gMC.cond = 0x80; + gMC.air = 1000; + gMC.lifeBr = profile.life; + gMC.x = profile.x; + gMC.y = profile.y; + + gMC.rect_arms.left = (gArmsData[gSelectedArms].code % 10) * 24; + gMC.rect_arms.right = gMC.rect_arms.left + 24; + gMC.rect_arms.top = (gArmsData[gSelectedArms].code / 10) * 32; + gMC.rect_arms.bottom = gMC.rect_arms.top + 16; + + // Reset stuff + ClearFade(); + SetFrameMyChar(); + SetFrameTargetMyChar(16); + InitBossLife(); + CutNoise(); + InitStar(); + ClearValueView(); + gCurlyShoot_wait = 0; + + return TRUE; +} + +BOOL InitializeGame(HWND hWnd) +{ + InitMyChar(); + gSelectedArms = 0; + gSelectedItem = 0; + gCounter = 0; + ClearArmsData(); + ClearItemData(); + ClearPermitStage(); + StartMapping(); + InitFlags(); + if (!TransferStage(13, 200, 10, 8)) + { + #if !defined(JAPANESE) && defined(FIX_BUGS) // The Aeon Genesis translation didn't translate this + MessageBoxA(hWnd, "Failed to load stage", "Error", MB_OK); + #else + MessageBoxA(hWnd, "\x83\x58\x83\x65\x81\x5B\x83\x57\x82\xCC\x93\xC7\x82\xDD\x8D\x9E\x82\xDD\x82\xC9\x8E\xB8\x94\x73", "\x83\x47\x83\x89\x81\x5B", MB_OK); /* 'ステージの読み込みに失敗' and 'エラー' in Shift-JIS */ + #endif + return FALSE; + } + + ClearFade(); + SetFrameMyChar(); + SetFrameTargetMyChar(16); + InitBossLife(); + CutNoise(); + ClearValueView(); + gCurlyShoot_wait = 0; + SetFadeMask(); + SetFrameTargetMyChar(16); + return TRUE; +} diff --git a/src/Profile.h b/src/Profile.h new file mode 100644 index 0000000..9e6f1c2 --- /dev/null +++ b/src/Profile.h @@ -0,0 +1,47 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "SelStage.h" +#include "Stage.h" + +typedef struct PROFILEDATA +{ + char code[8]; + int stage; + MusicID music; + int x; + int y; + int direct; + short max_life; + short star; + short life; + short a; + int select_arms; + int select_item; + int equip; + int unit; + int counter; + ARMS arms[8]; + ITEM items[32]; + PERMIT_STAGE permitstage[8]; + signed char permit_mapping[0x80]; + char FLAG[4]; + unsigned char flags[1000]; +} PROFILEDATA; + +extern const char* const gDefaultName; +extern const char* const gProfileCode; + +BOOL IsProfile(void); +BOOL SaveProfile(const char *name); +BOOL LoadProfile(const char *name); +BOOL InitializeGame(HWND hWnd); diff --git a/src/SelStage.cpp b/src/SelStage.cpp new file mode 100644 index 0000000..2748fa9 --- /dev/null +++ b/src/SelStage.cpp @@ -0,0 +1,239 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "SelStage.h" + +#include + +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Draw.h" +#include "Escape.h" +#include "KeyControl.h" +#include "Main.h" +#include "Sound.h" +#include "TextScr.h" + +PERMIT_STAGE gPermitStage[STAGE_MAX]; + +int gSelectedStage; +int gStageSelectTitleY; + +void ClearPermitStage(void) +{ + memset(gPermitStage, 0, sizeof(gPermitStage)); +} + +BOOL AddPermitStage(int index, int event) +{ + int i = 0; + + while (i < STAGE_MAX) + { + if (gPermitStage[i].index == index) + break; + + if (gPermitStage[i].index == 0) + break; + + ++i; + } + + if (i == STAGE_MAX) + return FALSE; + + gPermitStage[i].index = index; + gPermitStage[i].event = event; + + return TRUE; +} + +BOOL SubPermitStage(int index) +{ + int i; + + for (i = 0; i < STAGE_MAX; ++i) + if (gPermitStage[i].index == index) + break; + +#ifdef FIX_BUGS + if (i == STAGE_MAX) +#else + if (i == 32) // Same value as 'ITEM_MAX' +#endif + return FALSE; + + for (++i; i < STAGE_MAX; ++i) + gPermitStage[i - 1] = gPermitStage[i]; + + gPermitStage[i - 1].index = 0; + gPermitStage[i - 1].event = 0; + + return TRUE; +} + +void MoveStageSelectCursor(void) +{ + int stage_num; + int stage_x; + + stage_num = 0; + while (gPermitStage[stage_num].index != 0) + ++stage_num; + + stage_x = (WINDOW_WIDTH - (stage_num * 40)) / 2; // Unused + + if (stage_num == 0) + return; + + if (gKeyTrg & gKeyLeft) + --gSelectedStage; + + if (gKeyTrg & gKeyRight) + ++gSelectedStage; + + if (gSelectedStage < 0) + gSelectedStage = stage_num - 1; + + if (gSelectedStage > stage_num - 1) + gSelectedStage = 0; + + if (gKeyTrg & (gKeyLeft | gKeyRight)) + StartTextScript(gPermitStage[gSelectedStage].index + 1000); + + if (gKeyTrg & (gKeyLeft | gKeyRight)) + PlaySoundObject(1, SOUND_MODE_PLAY); +} + +void PutStageSelectObject(void) +{ + static unsigned int flash; + + int i; + RECT rcStage; + + RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + + RECT rcCur[2] = { + {80, 88, 112, 104}, + {80, 104, 112, 120}, + }; + + RECT rcTitle1 = {80, 64, 144, 72}; + + int stage_num; + int stage_x; + + if (gStageSelectTitleY > (WINDOW_HEIGHT / 2) - 74) + --gStageSelectTitleY; + + PutBitmap3(&rcView, (WINDOW_WIDTH / 2) - 32, gStageSelectTitleY, &rcTitle1, SURFACE_ID_TEXT_BOX); + + stage_num = 0; + while (gPermitStage[stage_num].index) + ++stage_num; + + ++flash; + + if (stage_num != 0) + { + stage_x = (WINDOW_WIDTH - (stage_num * 40)) / 2; + + PutBitmap3(&rcView, stage_x + (gSelectedStage * 40), (WINDOW_HEIGHT / 2) - 56, &rcCur[flash / 2 % 2], SURFACE_ID_TEXT_BOX); + + for (i = 0; i < STAGE_MAX; ++i) + { + if (gPermitStage[i].index == 0) + break; + + // Interestingly, there's code for reading multiple rows of icons + // from the 'StageImage.pbm' file when there are more than 8 stages, + // despite only 6 icons ever being used. + rcStage.left = (gPermitStage[i].index % 8) * 32; + rcStage.right = rcStage.left + 32; + rcStage.top = (gPermitStage[i].index / 8) * 16; + rcStage.bottom = rcStage.top + 16; + + PutBitmap3(&rcView, stage_x + (i * 40), (WINDOW_HEIGHT / 2) - 56, &rcStage, SURFACE_ID_STAGE_ITEM); + } + } +} + +int StageSelectLoop(int *p_event) +{ + char old_script_path[MAX_PATH]; + + RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + + gSelectedStage = 0; + BackupSurface(SURFACE_ID_SCREEN_GRAB, &grcFull); + GetTextScriptPath(old_script_path); + LoadTextScript2("StageSelect.tsc"); + gStageSelectTitleY = (WINDOW_HEIGHT / 2) - 66; + StartTextScript(gPermitStage[gSelectedStage].index + 1000); + + for (;;) + { + GetTrg(); + + if (gKey & KEY_ESCAPE) + { + switch (Call_Escape(ghWnd)) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; + } + } + + MoveStageSelectCursor(); + + switch (TextScriptProc()) + { + case enum_ESCRETURN_exit: + return enum_ESCRETURN_exit; + + case enum_ESCRETURN_restart: + return enum_ESCRETURN_restart; + } + +#ifdef FIX_BUGS + PutBitmap4(&rcView, 0, 0, &rcView, SURFACE_ID_SCREEN_GRAB); +#else + // The original accidentally drew the screencap with transparency enabled + PutBitmap3(&rcView, 0, 0, &rcView, SURFACE_ID_SCREEN_GRAB); +#endif + PutStageSelectObject(); + PutTextScript(); + + if (gKeyTrg & gKeyOk) + { + StopTextScript(); + break; + } + + if (gKeyTrg & gKeyCancel) + { + StopTextScript(); + LoadTextScript_Stage(old_script_path); + *p_event = 0; + return enum_ESCRETURN_continue; + } + + PutFramePerSecound(); + + if (!Flip_SystemTask(ghWnd)) + return enum_ESCRETURN_exit; + } + + LoadTextScript_Stage(old_script_path); + *p_event = gPermitStage[gSelectedStage].event; + return enum_ESCRETURN_continue; +} diff --git a/src/SelStage.h b/src/SelStage.h new file mode 100644 index 0000000..1551e37 --- /dev/null +++ b/src/SelStage.h @@ -0,0 +1,30 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#define STAGE_MAX 8 // Note that Cave Story only has 5 stages + +typedef struct PERMIT_STAGE +{ + int index; + int event; +} PERMIT_STAGE; + +extern PERMIT_STAGE gPermitStage[STAGE_MAX]; + +extern int gSelectedStage; +extern int gStageSelectTitleY; + +void ClearPermitStage(void); +BOOL AddPermitStage(int index, int event); +BOOL SubPermitStage(int index); +void MoveStageSelectCursor(void); +void PutStageSelectObject(void); +int StageSelectLoop(int *p_event); diff --git a/src/Shoot.cpp b/src/Shoot.cpp new file mode 100644 index 0000000..73001b8 --- /dev/null +++ b/src/Shoot.cpp @@ -0,0 +1,1161 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Shoot.h" + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "Bullet.h" +#include "Caret.h" +#include "CommonDefines.h" +#include "KeyControl.h" +#include "MyChar.h" +#include "MycParam.h" +#include "Sound.h" + +static int empty; + +void ShootBullet_Frontia1(int level) +{ + int bul_no; + + switch (level) + { + case 1: + bul_no = 1; + break; + + case 2: + bul_no = 2; + break; + + case 3: + bul_no = 3; + break; + } + + if (CountArmsBullet(1) > 3) + return; + + if (gKeyTrg & gKeyShot) + { + if (!UseArmsEnergy(1)) + { + ChangeToFirstArms(); + } + else + { + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y - (10 * 0x200), 1); + SetCaret(gMC.x - (3 * 0x200), gMC.y - (10 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y - (10 * 0x200), 1); + SetCaret(gMC.x + (3 * 0x200), gMC.y - (10 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y + (10 * 0x200), 3); + SetCaret(gMC.x - (3 * 0x200), gMC.y + (10 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y + (10 * 0x200), 3); + SetCaret(gMC.x + (3 * 0x200), gMC.y + (10 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y + (2 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y + (2 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + PlaySoundObject(33, SOUND_MODE_PLAY); + } + } +} + +void ShootBullet_PoleStar(int level) +{ + int bul_no; + + switch (level) + { + case 1: + bul_no = 4; + break; + + case 2: + bul_no = 5; + break; + + case 3: + bul_no = 6; + break; + } + + if (CountArmsBullet(2) > 1) + return; + + if (gKeyTrg & gKeyShot) + { + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + } + else + { + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y + (3 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y + (3 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + if (level == 3) + PlaySoundObject(49, SOUND_MODE_PLAY); + else + PlaySoundObject(32, SOUND_MODE_PLAY); + } + } +} + +void ShootBullet_FireBall(int level) +{ + int bul_no; + + switch (level) + { + case 1: + if (CountArmsBullet(3) > 1) + return; + + bul_no = 7; + break; + + case 2: + if (CountArmsBullet(3) > 2) + return; + + bul_no = 8; + break; + + case 3: + if (CountArmsBullet(3) > 3) + return; + + bul_no = 9; + break; + } + + if (gKeyTrg & gKeyShot) + { + if (!UseArmsEnergy(1)) + { + ChangeToFirstArms(); + } + else + { + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (4 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (4 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (4 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (4 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (4 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (4 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (4 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (4 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y + (2 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y + (2 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + PlaySoundObject(34, SOUND_MODE_PLAY); + } + } +} + +void ShootBullet_Machinegun1(int level) +{ + int bul_no; + static int wait; + + if (CountArmsBullet(4) > 4) + return; + + switch (level) + { + case 1: + bul_no = 10; + break; + + case 2: + bul_no = 11; + break; + + case 3: + bul_no = 12; + break; + } + + if (!(gKey & gKeyShot)) + gMC.rensha = 6; + + if (gKey & gKeyShot) + { + if (++gMC.rensha < 6) + return; + + gMC.rensha = 0; + + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + + if (empty == 0) + { + SetCaret(gMC.x, gMC.y, CARET_EMPTY, DIR_LEFT); + empty = 50; + } + + return; + } + + if (gMC.up) + { + if (level == 3) + gMC.ym += 0x100; + + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (3 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (3 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (level == 3) + { + if (gMC.ym > 0) + gMC.ym /= 2; + + if (gMC.ym > -0x400) + { + gMC.ym -= 0x200; + if (gMC.ym < -0x400) + gMC.ym = -0x400; + } + } + + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (3 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (3 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (12 * 0x200), gMC.y + (3 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (12 * 0x200), gMC.y + (3 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + if (level == 3) + PlaySoundObject(49, SOUND_MODE_PLAY); + else + PlaySoundObject(32, SOUND_MODE_PLAY); + } + else + { + ++wait; + + if (gMC.equip & EQUIP_TURBOCHARGE) + { + if (wait > 1) + { + wait = 0; + ChargeArmsEnergy(1); + } + } + else + { + if (wait > 4) + { + wait = 0; + ChargeArmsEnergy(1); + } + } + } +} + +void ShootBullet_Missile(int level, BOOL bSuper) +{ + int bul_no; + + if (bSuper) + { + switch (level) + { + case 1: + bul_no = 28; + break; + + case 2: + bul_no = 29; + break; + + case 3: + bul_no = 30; + break; + } + + switch (level) + { + case 1: + if (CountArmsBullet(10) > 0) + return; + + if (CountArmsBullet(11) > 0) + return; + + break; + + case 2: + if (CountArmsBullet(10) > 1) + return; + + if (CountArmsBullet(11) > 1) + return; + + break; + + case 3: + if (CountArmsBullet(10) > 3) + return; + + if (CountArmsBullet(11) > 3) + return; + + break; + } + + } + else + { + switch (level) + { + case 1: + bul_no = 13; + break; + + case 2: + bul_no = 14; + break; + + case 3: + bul_no = 15; + break; + } + + switch (level) + { + case 1: + if (CountArmsBullet(5) > 0) + return; + + if (CountArmsBullet(6) > 0) + return; + + break; + + case 2: + if (CountArmsBullet(5) > 1) + return; + + if (CountArmsBullet(6) > 1) + return; + + break; + + case 3: + if (CountArmsBullet(5) > 3) + return; + + if (CountArmsBullet(6) > 3) + return; + + break; + } + } + + if (gKeyTrg & gKeyShot) + { + if (level < 3) + { + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + + if (empty == 0) + { + SetCaret(gMC.x, gMC.y, CARET_EMPTY, DIR_LEFT); + empty = 50; + } + + return; + } + + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y, 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y, CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y, 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y, CARET_SHOOT, DIR_LEFT); + } + } + } + else + { + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + + if (empty == 0) + { + SetCaret(gMC.x, gMC.y, CARET_EMPTY, DIR_LEFT); + empty = 50; + } + + return; + } + + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y, 1); + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y, 1); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y, 1); + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y, 1); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y, 3); + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y, 3); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + SetBullet(bul_no, gMC.x - (3 * 0x200), gMC.y, 3); + SetBullet(bul_no, gMC.x + (3 * 0x200), gMC.y, 3); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y + (1 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (1 * 0x200), CARET_SHOOT, DIR_LEFT); + SetBullet(bul_no, gMC.x, gMC.y - (8 * 0x200), 0); + SetBullet(bul_no, gMC.x + (4 * 0x200), gMC.y - (1 * 0x200), 0); + } + else + { + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y + (1 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (1 * 0x200), CARET_SHOOT, DIR_LEFT); + SetBullet(bul_no, gMC.x, gMC.y - (8 * 0x200), 2); + SetBullet(bul_no, gMC.x - (4 * 0x200), gMC.y - (1 * 0x200), 2); + } + } + } + + PlaySoundObject(32, SOUND_MODE_PLAY); + } +} + +void ShootBullet_Bubblin1(void) +{ + static int wait; + + if (CountArmsBullet(7) > 3) + return; + + if (gKeyTrg & gKeyShot) + { + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + + if (empty == 0) + { + SetCaret(gMC.x, gMC.y, CARET_EMPTY, DIR_LEFT); + empty = 50; + } + + return; + } + + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(19, gMC.x - (1 * 0x200), gMC.y - (2 * 0x200), 1); + SetCaret(gMC.x - (1 * 0x200), gMC.y - (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(19, gMC.x + (1 * 0x200), gMC.y - (2 * 0x200), 1); + SetCaret(gMC.x + (1 * 0x200), gMC.y - (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(19, gMC.x - (1 * 0x200), gMC.y + (2 * 0x200), 3); + SetCaret(gMC.x - (1 * 0x200), gMC.y + (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(19, gMC.x + (1 * 0x200), gMC.y + (2 * 0x200), 3); + SetCaret(gMC.x + (1 * 0x200), gMC.y + (2 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(19, gMC.x - (6 * 0x200), gMC.y + (3 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(19, gMC.x + (6 * 0x200), gMC.y + (3 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + PlaySoundObject(48, SOUND_MODE_PLAY); + } + else if (++wait > 20) + { + wait = 0; + ChargeArmsEnergy(1); + } +} + +void ShootBullet_Bubblin2(int level) +{ + static int wait; + + if (CountArmsBullet(7) > 15) + return; + + level += 18; + + if (!(gKey & gKeyShot)) + gMC.rensha = 6; + + if (gKey & gKeyShot) + { + if (++gMC.rensha < 7) + return; + + gMC.rensha = 0; + + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + + if (empty == 0) + { + SetCaret(gMC.x, gMC.y, CARET_EMPTY, DIR_LEFT); + empty = 50; + } + + return; + } + + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(level, gMC.x - (3 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (3 * 0x200), gMC.y - (16 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(level, gMC.x + (3 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (3 * 0x200), gMC.y - (16 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(level, gMC.x - (3 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (3 * 0x200), gMC.y + (16 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(level, gMC.x + (3 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (3 * 0x200), gMC.y + (16 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(level, gMC.x - (6 * 0x200), gMC.y + (3 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(level, gMC.x + (6 * 0x200), gMC.y + (3 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + PlaySoundObject(48, SOUND_MODE_PLAY); + } + else if (++wait > 1) + { + wait = 0; + ChargeArmsEnergy(1); + } +} + +void ShootBullet_Sword(int level) +{ + int bul_no; + + if (CountArmsBullet(9) > 0) + return; + + switch (level) + { + case 1: + bul_no = 25; + break; + + case 2: + bul_no = 26; + break; + + case 3: + bul_no = 27; + break; + } + + if (gKeyTrg & gKeyShot) + { + if (gMC.up) + { + if (gMC.direct == 0) + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y + (4 * 0x200), 1); + else + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y + (4 * 0x200), 1); + } + else if (gMC.down) + { + if (gMC.direct == 0) + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y - (6 * 0x200), 3); + else + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y - (6 * 0x200), 3); + } + else + { + if (gMC.direct == 0) + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y - (3 * 0x200), 0); + else + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y - (3 * 0x200), 2); + } + + PlaySoundObject(34, SOUND_MODE_PLAY); + } +} + +void ShootBullet_Nemesis(int level) +{ + int bul_no; + + switch (level) + { + case 1: + bul_no = 34; + break; + + case 2: + bul_no = 35; + break; + + case 3: + bul_no = 36; + break; + } + + if (CountArmsBullet(12) > 1) + return; + + if (gKeyTrg & gKeyShot) + { + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + } + else + { + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y - (12 * 0x200), 1); + SetCaret(gMC.x - (1 * 0x200), gMC.y - (12 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y - (12 * 0x200), 1); + SetCaret(gMC.x + (1 * 0x200), gMC.y - (12 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y + (12 * 0x200), 3); + SetCaret(gMC.x - (1 * 0x200), gMC.y + (12 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y + (12 * 0x200), 3); + SetCaret(gMC.x + (1 * 0x200), gMC.y + (12 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (22 * 0x200), gMC.y + (3 * 0x200), 0); + SetCaret(gMC.x - (16 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (22 * 0x200), gMC.y + (3 * 0x200), 2); + SetCaret(gMC.x + (16 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + switch (level) + { + case 1: + PlaySoundObject(117, SOUND_MODE_PLAY); + break; + + case 2: + PlaySoundObject(49, SOUND_MODE_PLAY); + break; + + case 3: + PlaySoundObject(60, SOUND_MODE_PLAY); + break; + } + } + } +} + +int spur_charge; + +void ResetSpurCharge(void) +{ + spur_charge = 0; + + if (gArmsData[gSelectedArms].code == 13) + ZeroExpMyChar(); +} + +void ShootBullet_Spur(int level) +{ + int bul_no; + BOOL bShot; + static BOOL bMax; + + bShot = FALSE; + + if (gKey & gKeyShot) + { + if (gMC.equip & EQUIP_TURBOCHARGE) + AddExpMyChar(3); + else + AddExpMyChar(2); + + if (++spur_charge / 2 % 2) + { + switch (level) + { + case 1: + PlaySoundObject(59, SOUND_MODE_PLAY); + break; + + case 2: + PlaySoundObject(60, SOUND_MODE_PLAY); + break; + + case 3: + if (!IsMaxExpMyChar()) + PlaySoundObject(61, SOUND_MODE_PLAY); + + break; + } + } + } + else + { + if (spur_charge) + bShot = TRUE; + + spur_charge = 0; + } + + if (IsMaxExpMyChar()) + { + if (!bMax) + { + bMax = TRUE; + PlaySoundObject(65, SOUND_MODE_PLAY); + } + } + else + { + bMax = FALSE; + } + + if (!(gKey & gKeyShot)) + ZeroExpMyChar(); + + switch (level) + { + case 1: + bul_no = 6; + bShot = FALSE; + break; + + case 2: + bul_no = 37; + break; + + case 3: + if (bMax) + bul_no = 39; + else + bul_no = 38; + + break; + } + + if (CountArmsBullet(13) > 0 || CountArmsBullet(14) > 0) + return; + + if (gKeyTrg & gKeyShot || bShot) + { + if (!UseArmsEnergy(1)) + { + PlaySoundObject(37, SOUND_MODE_PLAY); + } + else + { + if (gMC.up) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x - (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), 1); + SetCaret(gMC.x + (1 * 0x200), gMC.y - (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else if (gMC.down) + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x - (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), 3); + SetCaret(gMC.x + (1 * 0x200), gMC.y + (8 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + else + { + if (gMC.direct == 0) + { + SetBullet(bul_no, gMC.x - (6 * 0x200), gMC.y + (3 * 0x200), 0); + SetCaret(gMC.x - (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + else + { + SetBullet(bul_no, gMC.x + (6 * 0x200), gMC.y + (3 * 0x200), 2); + SetCaret(gMC.x + (12 * 0x200), gMC.y + (3 * 0x200), CARET_SHOOT, DIR_LEFT); + } + } + + switch (bul_no) + { + case 6: + PlaySoundObject(49, SOUND_MODE_PLAY); + break; + + case 37: + PlaySoundObject(62, SOUND_MODE_PLAY); + break; + + case 38: + PlaySoundObject(63, SOUND_MODE_PLAY); + break; + + case 39: + PlaySoundObject(64, SOUND_MODE_PLAY); + break; + } + } + } +} + +void ShootBullet(void) +{ + static int soft_rensha; // 'rensha' is Japanese for 'rapid-fire', apparently + + if (empty != 0) + --empty; + + // Only let the player shoot every 4 frames + if (soft_rensha != 0) + --soft_rensha; + + if (gKeyTrg & gKeyShot) + { + if (soft_rensha != 0) + return; + + soft_rensha = 4; + } + + // Run functions + if (gMC.cond & 2) + return; + + switch (gArmsData[gSelectedArms].code) + { + case 1: + ShootBullet_Frontia1(gArmsData[gSelectedArms].level); + break; + + case 2: + ShootBullet_PoleStar(gArmsData[gSelectedArms].level); + break; + + case 3: + ShootBullet_FireBall(gArmsData[gSelectedArms].level); + break; + + case 4: + ShootBullet_Machinegun1(gArmsData[gSelectedArms].level); + break; + + case 5: + ShootBullet_Missile(gArmsData[gSelectedArms].level, FALSE); + break; + + case 7: + switch (gArmsData[gSelectedArms].level) + { + case 1: + ShootBullet_Bubblin1(); + break; + + case 2: + ShootBullet_Bubblin2(2); + break; + + case 3: + ShootBullet_Bubblin2(3); + break; + } + + break; + + case 9: + switch (gArmsData[gSelectedArms].level) + { + case 1: + ShootBullet_Sword(1); + break; + + case 2: + ShootBullet_Sword(2); + break; + + case 3: + ShootBullet_Sword(3); + break; + } + + break; + + case 10: + ShootBullet_Missile(gArmsData[gSelectedArms].level, TRUE); + break; + + case 12: + ShootBullet_Nemesis(gArmsData[gSelectedArms].level); + break; + + case 13: + ShootBullet_Spur(gArmsData[gSelectedArms].level); + break; + } +} diff --git a/src/Shoot.h b/src/Shoot.h new file mode 100644 index 0000000..6018df3 --- /dev/null +++ b/src/Shoot.h @@ -0,0 +1,11 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void ResetSpurCharge(void); +void ShootBullet(void); diff --git a/src/Sound.cpp b/src/Sound.cpp new file mode 100644 index 0000000..72020dd --- /dev/null +++ b/src/Sound.cpp @@ -0,0 +1,442 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +// Some of the original source code for this file can be found here: +// https://github.com/shbow/organya/blob/master/source/Sound.cpp + +/* +TODO - Code style +Pixel's code was *extremely* Windows-centric, to the point of using +things like ZeroMemory and LPCSTR instead of standard things like +memset and const char*. For now, the decompilation is accurate despite +not using these since they're just macros that evaluate to the portable +equivalents. +*/ + +#include "Sound.h" + +#include +#include +#include +#include + +#define DIRECTSOUND_VERSION 0x500 +#include + +#include "WindowsWrapper.h" + +#include "Main.h" +#include "Organya.h" +#include "PixTone.h" + +LPDIRECTSOUND lpDS; // DirectSoundオブジェクト (DirectSound object) +LPDIRECTSOUNDBUFFER lpPRIMARYBUFFER; // 一時バッファ (Temporary buffer) +LPDIRECTSOUNDBUFFER lpSECONDARYBUFFER[SE_MAX]; + +// DirectSoundの開始 (Starting DirectSound) +BOOL InitDirectSound(HWND hwnd) +{ + int i; + DSBUFFERDESC dsbd; + + // DirectDrawの初期化 (DirectDraw initialization) + if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK) + { + lpDS = NULL; + #ifndef FIX_BUGS + // This makes absolutely no sense here + StartOrganya(lpDS, "Org\\Wave.dat"); + #endif + return FALSE; + } + + lpDS->SetCooperativeLevel(hwnd, DSSCL_EXCLUSIVE); + + // 一次バッファの初期化 (Initializing the primary buffer) + ZeroMemory(&dsbd, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME; + lpDS->CreateSoundBuffer(&dsbd, &lpPRIMARYBUFFER, NULL); + + for (i = 0; i < SE_MAX; i++) + lpSECONDARYBUFFER[i] = NULL; + + StartOrganya(lpDS, "Org\\Wave.dat"); + + return TRUE; +} + +// DirectSoundの終了 (Exit DirectSound) +void EndDirectSound(void) +{ + int i; + + if (lpDS == NULL) + return; + + EndOrganya(); + + for (i = 0; i < SE_MAX; i++) + if (lpSECONDARYBUFFER[i] != NULL) + lpSECONDARYBUFFER[i]->Release(); + + if (lpPRIMARYBUFFER != NULL) + lpPRIMARYBUFFER->Release(); + + if (lpDS != NULL) + lpDS->Release(); + + lpDS = NULL; +} + +// Below are two completely unused functions for loading .wav files as sound effects. +// Some say that sounds heard in CS Beta footage don't sound like PixTone... + +// There's a bit of a problem with this code: it hardcodes the offsets of various bits +// of data in the WAV header - this makes the code only compatible with very specific +// .wav files. You can check the prototype OrgView EXEs for examples of those. + +// サウンドの設定 (Sound settings) +BOOL InitSoundObject(LPCSTR resname, int no) +{ + HRSRC hrscr; + DSBUFFERDESC dsbd; + DWORD *lpdword; // リソースのアドレス (Resource address) + + if (lpDS == NULL) + return TRUE; + + // リソースの検索 (Search for resources) + if ((hrscr = FindResourceA(NULL, resname, "WAVE")) == NULL) + return FALSE; + + // リソースのアドレスを取得 (Get resource address) + lpdword = (DWORD*)LockResource(LoadResource(NULL, hrscr)); + + // 二次バッファの生成 (Create secondary buffer) + ZeroMemory(&dsbd, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + dsbd.dwBufferBytes = *(DWORD*)((BYTE*)lpdword+0x36); // WAVEデータのサイズ (WAVE data size) + dsbd.lpwfxFormat = (LPWAVEFORMATEX)(lpdword+5); + + if (lpDS->CreateSoundBuffer(&dsbd, &lpSECONDARYBUFFER[no], NULL) != DS_OK) + return FALSE; + + LPVOID lpbuf1, lpbuf2; + DWORD dwbuf1, dwbuf2; + + // 二次バッファのロック (Secondary buffer lock) + lpSECONDARYBUFFER[no]->Lock(0, *(DWORD*)((BYTE*)lpdword+0x36), &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0); + + // 音源データの設定 (Sound source data settings) + CopyMemory(lpbuf1, (BYTE*)lpdword+0x3A, dwbuf1); + + if (dwbuf2 != 0) + CopyMemory(lpbuf2, (BYTE*)lpdword+0x3A+dwbuf1, dwbuf2); + + // 二次バッファのロック解除 (Unlock secondary buffer) + lpSECONDARYBUFFER[no]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2); + + return TRUE; +} + +BOOL LoadSoundObject(LPCSTR file_name, int no) +{ + char path[MAX_PATH]; + DWORD i; + DWORD file_size = 0; + char check_box[58]; + FILE *fp; + HANDLE hFile; + + sprintf(path, "%s\\%s", gModulePath, file_name); + + if (lpDS == NULL) + return TRUE; + + hFile = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + file_size = GetFileSize(hFile, NULL); + CloseHandle(hFile); + + if ((fp = fopen(path, "rb")) == NULL) + return FALSE; + + for (i = 0; i < 58; i++) + fread(&check_box[i], sizeof(char), 1, fp); // Holy hell, this is inefficient + +#ifdef FIX_MAJOR_BUGS + // The original code forgets to close 'fp' + if (check_box[0] != 'R' || check_box[1] != 'I' || check_box[2] != 'F' || check_box[3] != 'F') + { + fclose(fp); + return FALSE; + } +#else + if (check_box[0] != 'R') + return FALSE; + if (check_box[1] != 'I') + return FALSE; + if (check_box[2] != 'F') + return FALSE; + if (check_box[3] != 'F') + return FALSE; +#endif + + DWORD *wp; + wp = (DWORD*)malloc(file_size); // ファイルのワークスペースを作る (Create a file workspace) + +#ifdef FIX_MAJOR_BUGS + if (wp == NULL) + { + fclose(fp); + return FALSE; + } +#endif + + fseek(fp, 0, SEEK_SET); + + for (i = 0; i < file_size; i++) + fread((BYTE*)wp+i, sizeof(BYTE), 1, fp); // Pixel, stahp + + fclose(fp); + + // セカンダリバッファの生成 (Create secondary buffer) + DSBUFFERDESC dsbd; + ZeroMemory(&dsbd, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + dsbd.dwBufferBytes = *(DWORD*)((BYTE*)wp+0x36); // WAVEデータのサイズ (WAVE data size) + dsbd.lpwfxFormat = (LPWAVEFORMATEX)(wp+5); + + if (lpDS->CreateSoundBuffer(&dsbd, &lpSECONDARYBUFFER[no], NULL) != DS_OK) + { +#ifdef FIX_MAJOR_BUGS + free(wp); // The updated Organya source code includes this fix +#endif + return FALSE; + } + + LPVOID lpbuf1, lpbuf2; + DWORD dwbuf1, dwbuf2; + + HRESULT hr; + hr = lpSECONDARYBUFFER[no]->Lock(0, *(DWORD*)((BYTE*)wp+0x36), &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0); + + if (hr != DS_OK) + { +#ifdef FIX_MAJOR_BUGS + free(wp); // The updated Organya source code includes this fix +#endif + return FALSE; + } + + CopyMemory(lpbuf1, (BYTE*)wp+0x3A, dwbuf1); // +3aはデータの頭 (+ 3a is the head of the data) + + if (dwbuf2 != 0) + CopyMemory(lpbuf2, (BYTE*)wp+0x3A+dwbuf1, dwbuf2); + + lpSECONDARYBUFFER[no]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2); + + free(wp); + + return TRUE; +} + +void PlaySoundObject(int no, SoundMode mode) +{ + if (lpDS == NULL) + return; + + if (lpSECONDARYBUFFER[no] != NULL) + { + switch (mode) + { + case SOUND_MODE_STOP: // 停止 (Stop) + lpSECONDARYBUFFER[no]->Stop(); + break; + + case SOUND_MODE_PLAY: // 再生 (Playback) + lpSECONDARYBUFFER[no]->Stop(); + lpSECONDARYBUFFER[no]->SetCurrentPosition(0); + lpSECONDARYBUFFER[no]->Play(0, 0, 0); + break; + + case SOUND_MODE_PLAY_LOOP:// ループ再生 (Loop playback) + lpSECONDARYBUFFER[no]->Play(0, 0, DSBPLAY_LOOPING); + break; + } + } +} + +void ChangeSoundFrequency(int no, DWORD rate) // 100がMIN9999がMAXで2195?がノーマル (100 is MIN, 9999 is MAX, and 2195 is normal) +{ + if (lpDS == NULL) + return; + + lpSECONDARYBUFFER[no]->SetFrequency((rate * 10) + 100); +} + +void ChangeSoundVolume(int no, long volume) // 300がMAXで300がノーマル (300 is MAX and 300 is normal) +{ + if (lpDS == NULL) + return; + + lpSECONDARYBUFFER[no]->SetVolume((volume - 300) * 8); +} + +void ChangeSoundPan(int no, long pan) // 512がMAXで256がノーマル (512 is MAX and 256 is normal) +{ + if (lpDS == NULL) + return; + + lpSECONDARYBUFFER[no]->SetPan((pan - 256) * 10); +} + +// TODO - The stack frame for this function is inaccurate +int MakePixToneObject(const PIXTONEPARAMETER *ptp, int ptp_num, int no) +{ + // For some reason, this function creates an entire WAV file header, + // when it only needs a WAVEFORMATEX. + // From what I can tell, there's no struct like this in the Windows + // headers, so Pixel must have defined it manually, just like this: + typedef struct WavHeader + { + FOURCC riff_id; + DWORD riff_size; + FOURCC wave_id; + FOURCC fmt_id; + DWORD fmt_size; + PCMWAVEFORMAT format; + FOURCC data_id; + DWORD data_size; + } WavHeader; + + int sample_count; + int i, j; + DSBUFFERDESC dsbd; + WavHeader wav_header; + const PIXTONEPARAMETER *ptp_pointer; + unsigned char *pcm_buffer; + unsigned char *mixed_pcm_buffer; + + if (lpDS == NULL) + return 0; + + const char *riff = "RIFF"; + const char *fmt = "fmt "; + const char *wave = "WAVE"; + const char *data = "data"; + + wav_header.format.wBitsPerSample = 8; + wav_header.format.wf.nSamplesPerSec = 22050; + wav_header.format.wf.nChannels = 1; + wav_header.format.wf.wFormatTag = WAVE_FORMAT_PCM; + wav_header.fmt_size = sizeof(wav_header.format); + memcpy(&wav_header.riff_id, riff, sizeof(FOURCC)); + memcpy(&wav_header.fmt_id, fmt, sizeof(FOURCC)); + memcpy(&wav_header.wave_id, wave, sizeof(FOURCC)); + memcpy(&wav_header.data_id, data, sizeof(FOURCC)); + wav_header.format.wf.nBlockAlign = (wav_header.format.wBitsPerSample / 8) * wav_header.format.wf.nChannels; + wav_header.format.wf.nAvgBytesPerSec = (wav_header.format.wBitsPerSample / 8) * wav_header.format.wf.nChannels * wav_header.format.wf.nSamplesPerSec; + wav_header.data_size = wav_header.format.wf.nBlockAlign * ptp->size; // Note that this uses ptp->size, not sample_count. If this header were ever used, it would be incorrect. + wav_header.riff_size = sizeof(wav_header) - 8 + wav_header.data_size; + + ptp_pointer = ptp; + sample_count = 0; + + for (i = 0; i < ptp_num; i++) + { + if (ptp_pointer->size > sample_count) + sample_count = ptp_pointer->size; + + ++ptp_pointer; + } + + ZeroMemory(&dsbd, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + dsbd.dwBufferBytes = sample_count; + dsbd.lpwfxFormat = (LPWAVEFORMATEX)&wav_header.format; + + if (lpDS->CreateSoundBuffer(&dsbd, &lpSECONDARYBUFFER[no], 0) != DS_OK) + return -1; + + pcm_buffer = mixed_pcm_buffer = NULL; + + pcm_buffer = (unsigned char*)malloc(sample_count); + mixed_pcm_buffer = (unsigned char*)malloc(sample_count); + + if (pcm_buffer == NULL || mixed_pcm_buffer == NULL) + { + if (pcm_buffer != NULL) + free(pcm_buffer); + + if (mixed_pcm_buffer != NULL) + free(mixed_pcm_buffer); + + return -1; + } + + memset(pcm_buffer, 0x80, sample_count); + memset(mixed_pcm_buffer, 0x80, sample_count); + + ptp_pointer = ptp; + + for (i = 0; i < ptp_num; i++) + { + if (!MakePixelWaveData(ptp_pointer, pcm_buffer)) + { + if (pcm_buffer != NULL) // This is always true + free(pcm_buffer); + + if (mixed_pcm_buffer != NULL) // This is always true + free(mixed_pcm_buffer); + + return -1; + } + + for (j = 0; j < ptp_pointer->size; j++) + { + if (pcm_buffer[j] + mixed_pcm_buffer[j] - 0x100 < -0x7F) + mixed_pcm_buffer[j] = 0; + else if (pcm_buffer[j] + mixed_pcm_buffer[j] - 0x100 > 0x7F) + mixed_pcm_buffer[j] = 0xFF; + else + mixed_pcm_buffer[j] = mixed_pcm_buffer[j] + pcm_buffer[j] - 0x80; + } + + ++ptp_pointer; + } + + // This is self-assignment, so redundant. Maybe this used to be something to prevent audio popping ? + mixed_pcm_buffer[0] = mixed_pcm_buffer[0]; + mixed_pcm_buffer[sample_count - 1] = mixed_pcm_buffer[sample_count - 1]; + + LPVOID lpbuf1, lpbuf2; + DWORD dwbuf1, dwbuf2; + + lpSECONDARYBUFFER[no]->Lock(0, sample_count, &lpbuf1, &dwbuf1, &lpbuf2, &dwbuf2, 0); + + CopyMemory(lpbuf1, mixed_pcm_buffer, dwbuf1); + + if (dwbuf2 != 0) + CopyMemory(lpbuf2, mixed_pcm_buffer + dwbuf1, dwbuf2); + + lpSECONDARYBUFFER[no]->Unlock(lpbuf1, dwbuf1, lpbuf2, dwbuf2); + + if (pcm_buffer != NULL) + free(pcm_buffer); + + if (mixed_pcm_buffer != NULL) + free(mixed_pcm_buffer); + + return sample_count; +} diff --git a/src/Sound.h b/src/Sound.h new file mode 100644 index 0000000..de1802b --- /dev/null +++ b/src/Sound.h @@ -0,0 +1,58 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#ifndef DIRECTSOUND_VERSION +#define DIRECTSOUND_VERSION 0x500 +#endif +#include + +#include "WindowsWrapper.h" + +#include "PixTone.h" + +#define SE_MAX 160 // According to the Organya source code release, this is the real name for this constant + +enum SoundEffectNames +{ + SND_YES_NO_CHANGE_CHOICE = 1, + SND_MESSAGE_TYPING = 2, + SND_QUOTE_BUMP_HEAD = 3, + SND_SWITCH_WEAPON = 4, + SND_YES_NO_PROMPT = 5, + // To be continued + SND_SILLY_EXPLOSION = 25, + SND_LARGE_OBJECT_HIT_GROUND = 26, + // To be continued + SND_ENEMY_SHOOT_PROJECTILE = 39, + // To be continued + SND_BEHEMOTH_LARGE_HURT = 52, + // To be continued + SND_EXPLOSION = 72 + // To be continued +}; + +enum SoundMode +{ + SOUND_MODE_PLAY_LOOP = -1, + SOUND_MODE_STOP = 0, + SOUND_MODE_PLAY = 1 +}; + +extern LPDIRECTSOUND lpDS; +extern LPDIRECTSOUNDBUFFER lpSECONDARYBUFFER[SE_MAX]; + +BOOL InitDirectSound(HWND hwnd); +void EndDirectSound(void); +BOOL InitSoundObject(LPCSTR resname, int no); +BOOL LoadSoundObject(LPCSTR file_name, int no); +void PlaySoundObject(int no, SoundMode mode); +void ChangeSoundFrequency(int no, DWORD rate); +void ChangeSoundVolume(int no, long volume); +void ChangeSoundPan(int no, long pan); +int MakePixToneObject(const PIXTONEPARAMETER *ptp, int ptp_num, int no); diff --git a/src/Stage.cpp b/src/Stage.cpp new file mode 100644 index 0000000..ef00eae --- /dev/null +++ b/src/Stage.cpp @@ -0,0 +1,294 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Stage.h" + +#include +#include + +#include "WindowsWrapper.h" + +#include "Back.h" +#include "Boss.h" +#include "Bullet.h" +#include "Caret.h" +#include "Draw.h" +#include "Flash.h" +#include "Frame.h" +#include "Map.h" +#include "MapName.h" +#include "MyChar.h" +#include "NpChar.h" +#include "Organya.h" +#include "TextScr.h" +#include "ValueView.h" + +#ifdef JAPANESE +#define STAGE_ENTRY(parts, map, bkType, back, npc, boss, boss_no, name_en, name_jp) {parts, map, bkType, back, npc, boss, boss_no, name_jp} +#else +#define STAGE_ENTRY(parts, map, bkType, back, npc, boss, boss_no, name_en, name_jp) {parts, map, bkType, back, npc, boss, boss_no, name_en} +#endif + +int gStageNo; +MusicID gMusicNo; +unsigned int gOldPos; +MusicID gOldNo; + +// Note: Pixel made numerous capitalisation errors when creating this table. +// This isn't a problem for Windows, because of its case-insensitive filesystem. +const STAGE_TABLE gTMT[] = { + STAGE_ENTRY("0", "0", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "0", 0, "Null", "\x96\xB3"), /* 無 */ + STAGE_ENTRY("Pens", "Pens1", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Arthur's House", "\x83\x41\x81\x5B\x83\x54\x81\x5B\x82\xCC\x89\xC6"), /* アーサーの家 */ + STAGE_ENTRY("Eggs", "Eggs", BACKGROUND_TYPE_MOVE_DISTANT, "BkGreen", "Eggs1", "Ravil", 0, "Egg Corridor", "\x83\x5E\x83\x7D\x83\x53\x89\xF1\x98\x4C"), /* タマゴ回廊 */ + STAGE_ENTRY("EggX", "EggX", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Egg No. 00", "\x83\x5E\x83\x7D\x83\x53\x20\x4E\x6F\x2E\x30\x30"), /* タマゴ No.00 */ + STAGE_ENTRY("EggIn", "Egg6", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Egg No. 06", "\x83\x5E\x83\x7D\x83\x53\x20\x4E\x6F\x2E\x30\x36"), /* タマゴ No.06 */ + STAGE_ENTRY("Store", "EggR", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Egg Observation Room", "\x83\x5E\x83\x7D\x83\x53\x8A\xC4\x8E\x8B\x8E\xBA"), /* タマゴ監視室 */ + STAGE_ENTRY("Weed", "Weed", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Weed", "0", 0, "Grasstown", "\x83\x4E\x83\x54\x83\x80\x83\x89"), /* クサムラ */ + STAGE_ENTRY("Barr", "Santa", BACKGROUND_TYPE_BLACK, "bk0", "Weed", "0", 0, "Santa's House", "\x83\x54\x83\x93\x83\x5E\x82\xCC\x89\xC6"), /* サンタの家 */ + STAGE_ENTRY("Barr", "Chako", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Chaco's House", "\x83\x60\x83\x83\x83\x52\x82\xCC\x89\xC6"), /* チャコの家 */ + STAGE_ENTRY("Maze", "MazeI", BACKGROUND_TYPE_BLACK, "bk0", "Maze", "0", 0, "Labyrinth I", "\x96\xC0\x8B\x7B\x82\x68"), /* 迷宮I */ + STAGE_ENTRY("Sand", "Sand", BACKGROUND_TYPE_MOVE_DISTANT, "BkGreen", "Sand", "Omg", 1, "Sand Zone", "\x8D\xBB\x8B\xE6"), /* 砂区 */ + STAGE_ENTRY("Mimi", "Mimi", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Mimiga Village", "\x83\x7E\x83\x7E\x83\x4B\x81\x5B\x82\xCC\x91\xBA"), /* ミミガーの村 */ + STAGE_ENTRY("Cave", "Cave", BACKGROUND_TYPE_BLACK, "bk0", "Cemet", "0", 0, "First Cave", "\x8D\xC5\x8F\x89\x82\xCC\x93\xB4\x8C\x41"), /* 最初の洞窟 */ + STAGE_ENTRY("Cave", "Start", BACKGROUND_TYPE_BLACK, "bk0", "Cemet", "0", 0, "Start Point", "\x83\x58\x83\x5E\x81\x5B\x83\x67\x92\x6E\x93\x5F"), /* スタート地点 */ + STAGE_ENTRY("Mimi", "Barr", BACKGROUND_TYPE_BLACK, "bk0", "Cemet", "Bllg", 0, "Shack", "\x83\x6F\x83\x89\x83\x62\x83\x4E\x8F\xAC\x89\xAE"), /* バラック小屋 */ + STAGE_ENTRY("Mimi", "Pool", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Reservoir", "\x92\x99\x90\x85\x92\x72"), /* 貯水池 */ + STAGE_ENTRY("Mimi", "Cemet", BACKGROUND_TYPE_BLACK, "bk0", "Cemet", "0", 0, "Graveyard", "\x82\xCD\x82\xA9\x82\xCE"), /* はかば */ + STAGE_ENTRY("Mimi", "Plant", BACKGROUND_TYPE_MOVE_DISTANT, "BkGreen", "Plant", "0", 0, "Yamashita Farm", "\x8E\x52\x89\xBA\x94\x5F\x89\x80"), /* 山下農園 */ + STAGE_ENTRY("Store", "Shelt", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Shelter", "\x83\x56\x83\x46\x83\x8B\x83\x5E\x81\x5B"), /* シェルター */ + STAGE_ENTRY("Pens", "Comu", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Assembly Hall", "\x8F\x57\x89\xEF\x8F\xEA"), /* 集会場 */ + STAGE_ENTRY("Mimi", "MiBox", BACKGROUND_TYPE_BLACK, "bk0", "0", "0", 0, "Save Point", "\x83\x5A\x81\x5B\x83\x75\x83\x7C\x83\x43\x83\x93\x83\x67"), /* セーブポイント */ + STAGE_ENTRY("Store", "EgEnd1", BACKGROUND_TYPE_BLACK, "bk0", "0", "0", 0, "Side Room", "\x83\x5E\x83\x7D\x83\x53\x89\xF1\x98\x4C\x82\xCC\x8C\xC2\x8E\xBA"), /* タマゴ回廊の個室 */ + STAGE_ENTRY("Store", "Cthu", BACKGROUND_TYPE_BLACK, "bk0", "0", "0", 0, "Cthulhu's Abode", "\x83\x4E\x83\x67\x83\x44\x83\x8B\x81\x5B\x82\xCC\x8F\x5A\x8F\x88"), /* クトゥルーの住処 */ + STAGE_ENTRY("EggIn", "Egg1", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Egg No. 01", "\x83\x5E\x83\x7D\x83\x53\x20\x4E\x6F\x2E\x30\x31"), /* タマゴ No.01 */ + STAGE_ENTRY("Pens", "Pens2", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Arthur's House", "\x83\x41\x81\x5B\x83\x54\x81\x5B\x82\xCC\x89\xC6"), /* アーサーの家 */ + STAGE_ENTRY("Barr", "Malco", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Weed", "Bllg", 0, "Power Room", "\x93\x64\x8C\xB9\x8E\xBA"), /* 電源室 */ + STAGE_ENTRY("Barr", "WeedS", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "0", "0", 0, "Save Point", "\x83\x5A\x81\x5B\x83\x75\x83\x7C\x83\x43\x83\x93\x83\x67"), /* セーブポイント */ + STAGE_ENTRY("Store", "WeedD", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "0", "0", 0, "Execution Chamber", "\x8F\x88\x8C\x59\x8E\xBA"), /* 処刑室 */ + STAGE_ENTRY("Weed", "Frog", BACKGROUND_TYPE_MOVE_NEAR, "BkGreen", "Weed", "Frog", 2, "Gum", "\x83\x4B\x83\x80"), /* ガム */ + STAGE_ENTRY("Sand", "Curly", BACKGROUND_TYPE_BLACK, "bk0", "Sand", "Curly", 0, "Sand Zone Residence", "\x8D\xBB\x8B\xE6\x92\x93\x8D\xDD\x8F\x8A"), /* 砂区駐在所 */ + STAGE_ENTRY("Pens", "WeedB", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Ravil", "0", 0, "Grasstown Hut", "\x83\x4E\x83\x54\x83\x80\x83\x89\x82\xCC\x8F\xAC\x89\xAE"), /* クサムラの小屋 */ + STAGE_ENTRY("River", "Stream", BACKGROUND_TYPE_AUTOSCROLL, "BkBlue", "Stream", "IronH", 5, "Main Artery", "\x91\xE5\x93\xAE\x96\xAC"), /* 大動脈 */ + STAGE_ENTRY("Pens", "CurlyS", BACKGROUND_TYPE_BLACK, "bk0", "Sand", "Curly", 0, "Small Room", "\x8F\xAC\x95\x94\x89\xAE"), /* 小部屋 */ + STAGE_ENTRY("Barr", "Jenka1", BACKGROUND_TYPE_BLACK, "bk0", "Sand", "Bllg", 0, "Jenka's House", "\x83\x57\x83\x46\x83\x93\x83\x4A\x82\xCC\x89\xC6"), /* ジェンカの家 */ + STAGE_ENTRY("Sand", "Dark", BACKGROUND_TYPE_MOVE_DISTANT, "bkBlack", "Sand", "0", 0, "Deserted House", "\x94\x70\x89\xAE"), /* 廃屋 */ + STAGE_ENTRY("Gard", "Gard", BACKGROUND_TYPE_MOVE_DISTANT, "BkGard", "Toro", "Bllg", 0, "Sand Zone Storehouse", "\x8D\xBB\x8B\xE6\x91\x71\x8C\xC9"), /* 砂区倉庫 */ + STAGE_ENTRY("Barr", "Jenka2", BACKGROUND_TYPE_BLACK, "bk0", "Sand", "Bllg", 0, "Jenka's House", "\x83\x57\x83\x46\x83\x93\x83\x4A\x82\xCC\x89\xC6"), /* ジェンカの家 */ + STAGE_ENTRY("Sand", "SandE", BACKGROUND_TYPE_MOVE_DISTANT, "BkGreen", "Sand", "Bllg", 0, "Sand Zone", "\x8D\xBB\x8B\xE6"), /* 砂区 */ + STAGE_ENTRY("Maze", "MazeH", BACKGROUND_TYPE_BLACK, "bk0", "Maze", "0", 0, "Labyrinth H", "\x96\xC0\x8B\x7B\x82\x67"), /* 迷宮H */ + STAGE_ENTRY("Maze", "MazeW", BACKGROUND_TYPE_MOVE_DISTANT, "BkMaze", "Maze", "X", 3, "Labyrinth W", "\x96\xC0\x8B\x7B\x82\x76"), /* 迷宮W */ + STAGE_ENTRY("Maze", "MazeO", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "0", 0, "Camp", "\x83\x4C\x83\x83\x83\x93\x83\x76"), /* キャンプ */ + STAGE_ENTRY("Maze", "MazeD", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "Dark", 0, "Clinic Ruins", "\x90\x66\x97\xC3\x8F\x8A\x90\xD5"), /* 診療所跡 */ + STAGE_ENTRY("Store", "MazeA", BACKGROUND_TYPE_BLACK, "bk0", "Maze", "0", 0, "Labyrinth Shop", "\x96\xC0\x8B\x7B\x82\xCC\x93\x58"), /* 迷宮の店 */ + STAGE_ENTRY("Maze", "MazeB", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Maze", "0", 0, "Labyrinth B", "\x96\xC0\x8B\x7B\x82\x61"), /* 迷宮B */ + STAGE_ENTRY("Maze", "MazeS", BACKGROUND_TYPE_MOVE_NEAR, "BkGray", "Maze", "Bllg", 0, "Boulder Chamber", "\x91\xE5\x90\xCE\x82\xCC\x8D\xC7\x82\xAE\x8F\x8A"), /* 大石の塞ぐ所 */ + STAGE_ENTRY("Maze", "MazeM", BACKGROUND_TYPE_MOVE_DISTANT, "BkRed", "Maze", "0", 0, "Labyrinth M", "\x96\xC0\x8B\x7B\x82\x6C"), /* 迷宮M */ + STAGE_ENTRY("Cave", "Drain", BACKGROUND_TYPE_WATER, "BkWater", "Cemet", "0", 0, "Dark Place", "\x88\xC3\x82\xA2\x8F\x8A"), /* 暗い所 */ + STAGE_ENTRY("Almond", "Almond", BACKGROUND_TYPE_WATER, "BkWater", "Cemet", "Almo1", 4, "Core", "\x83\x52\x83\x41"), /* コア */ + STAGE_ENTRY("River", "River", BACKGROUND_TYPE_MOVE_NEAR, "bkGreen", "Weed", "0", 0, "Waterway", "\x90\x85\x98\x48"), /* 水路 */ + STAGE_ENTRY("Eggs", "Eggs2", BACKGROUND_TYPE_MOVE_DISTANT, "BkGreen", "Eggs2", "0", 0, "Egg Corridor?", "\x83\x5E\x83\x7D\x83\x53\x89\xF1\x98\x4C\x81\x48"), /* タマゴ回廊? */ + STAGE_ENTRY("Store", "Cthu2", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Cthulhu's Abode?", "\x83\x4E\x83\x67\x83\x44\x83\x8B\x81\x5B\x82\xCC\x8F\x5A\x8F\x88\x81\x48"), /* クトゥルーの住処? */ + STAGE_ENTRY("Store", "EggR2", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "TwinD", 6, "Egg Observation Room?", "\x83\x5E\x83\x7D\x83\x53\x8A\xC4\x8E\x8B\x8E\xBA\x81\x48"), /* タマゴ監視室? */ + STAGE_ENTRY("EggX", "EggX2", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Egg No. 00", "\x83\x5E\x83\x7D\x83\x53\x20\x4E\x6F\x2E\x30\x30"), /* タマゴ No.00 */ + STAGE_ENTRY("Oside", "Oside", BACKGROUND_TYPE_CLOUDS_WINDY, "BkMoon", "Moon", "0", 0, "Outer Wall", "\x8A\x4F\x95\xC7"), /* 外壁 */ + STAGE_ENTRY("Store", "EgEnd2", BACKGROUND_TYPE_BLACK, "bk0", "Eggs1", "0", 0, "Side Room", "\x83\x5E\x83\x7D\x83\x53\x89\xF1\x98\x4C\x82\xCC\x8C\xC2\x8E\xBA"), /* タマゴ回廊の個室 */ + STAGE_ENTRY("Store", "Itoh", BACKGROUND_TYPE_MOVE_NEAR, "bkBlue", "Guest", "0", 0, "Storehouse", "\x91\x71\x8C\xC9"), /* 倉庫 */ + STAGE_ENTRY("Cent", "Cent", BACKGROUND_TYPE_MOVE_DISTANT, "bkGreen", "Guest", "Cent", 0, "Plantation", "\x91\xE5\x94\x5F\x89\x80"), /* 大農園 */ + STAGE_ENTRY("Jail", "Jail1", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "Cent", 0, "Jail No. 1", "\x91\xE6\x82\x50\x98\x53"), /* 第1牢 */ + STAGE_ENTRY("Jail", "Momo", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "0", 0, "Hideout", "\x83\x4A\x83\x4E\x83\x8C\x83\x4B"), /* カクレガ */ + STAGE_ENTRY("Jail", "lounge", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "0", 0, "Rest Area", "\x8B\x78\x8C\x65\x8F\x8A"), /* 休憩所 */ + STAGE_ENTRY("Store", "CentW", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "Cent", 0, "Teleporter", "\x93\x5D\x91\x97\x8E\xBA"), /* 転送室 */ + STAGE_ENTRY("Store", "Jail2", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "Cent", 0, "Jail No. 2", "\x91\xE6\x82\x51\x98\x53"), /* 第2牢 */ + STAGE_ENTRY("White", "Blcny1", BACKGROUND_TYPE_CLOUDS, "BkFog", "Ravil", "Heri", 0, "Balcony", "\x83\x6F\x83\x8B\x83\x52\x83\x6A\x81\x5B"), /* バルコニー */ + STAGE_ENTRY("Jail", "Priso1", BACKGROUND_TYPE_BLACK, "BkGray", "Red", "0", 0, "Final Cave", "\x8D\xC5\x8C\xE3\x82\xCC\x93\xB4\x8C\x41"), /* 最後の洞窟 */ + STAGE_ENTRY("White", "Ring1", BACKGROUND_TYPE_CLOUDS, "BkFog", "Guest", "Miza", 0, "Throne Room", "\x89\xA4\x82\xCC\x8B\xCA\x8D\xC0"), /* 王の玉座 */ + STAGE_ENTRY("White", "Ring2", BACKGROUND_TYPE_CLOUDS, "BkFog", "Guest", "Dr", 0, "The King's Table", "\x89\xA4\x82\xCC\x90\x48\x91\xEC"), /* 王の食卓 */ + STAGE_ENTRY("Pens", "Prefa1", BACKGROUND_TYPE_BLACK, "Bk0", "0", "0", 0, "Prefab Building", "\x83\x76\x83\x8C\x83\x6E\x83\x75"), /* プレハブ */ + STAGE_ENTRY("Jail", "Priso2", BACKGROUND_TYPE_BLACK, "BkGray", "Red", "0", 0, "Last Cave (Hidden)", "\x8D\xC5\x8C\xE3\x82\xCC\x93\xB4\x8C\x41\x81\x45\x97\xA0"), /* 最後の洞窟・裏 */ + STAGE_ENTRY("White", "Ring3", BACKGROUND_TYPE_BLACK, "Bk0", "Miza", "Almo2", 7, "Black Space", "\x8D\x95\x82\xA2\x8D\x4C\x8A\xD4"), /* 黒い広間 */ + STAGE_ENTRY("Pens", "Little", BACKGROUND_TYPE_MOVE_NEAR, "BkBlue", "Guest", "0", 0, "Little House", "\x83\x8A\x83\x67\x83\x8B\x89\xC6"), /* リトル家 */ + STAGE_ENTRY("White", "Blcny2", BACKGROUND_TYPE_CLOUDS, "BkFog", "Ravil", "Heri", 0, "Balcony", "\x83\x6F\x83\x8B\x83\x52\x83\x6A\x81\x5B"), /* バルコニー */ + STAGE_ENTRY("Fall", "Fall", BACKGROUND_TYPE_MOVE_DISTANT, "BkFall", "Guest", "Heri", 0, "Fall", "\x97\x8E\x89\xBA"), /* 落下 */ + STAGE_ENTRY("White", "Kings", BACKGROUND_TYPE_BLACK, "Bk0", "Kings", "0", 0, "u", "\x75"), /* u */ + STAGE_ENTRY("Pens", "Pixel", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Guest", "0", 0, "Waterway Cabin", "\x90\x85\x98\x48\x82\xCC\x8F\xAC\x95\x94\x89\xAE"), /* 水路の小部屋 */ + STAGE_ENTRY("Maze", "e_Maze", BACKGROUND_TYPE_MOVE_DISTANT, "BkMaze", "Guest", "Maze", 3, "", ""), + STAGE_ENTRY("Barr", "e_Jenk", BACKGROUND_TYPE_BLACK, "bk0", "Sand", "Bllg", 0, "", ""), + STAGE_ENTRY("Barr", "e_Malc", BACKGROUND_TYPE_MOVE_DISTANT, "BkBlue", "Weed", "Bllg", 0, "", ""), + STAGE_ENTRY("Mimi", "e_Ceme", BACKGROUND_TYPE_BLACK, "bk0", "Plant", "0", 0, "", ""), + STAGE_ENTRY("Fall", "e_Sky", BACKGROUND_TYPE_MOVE_DISTANT, "BkFall", "Guest", "Heri", 0, "", ""), + STAGE_ENTRY("Pens", "Prefa2", BACKGROUND_TYPE_BLACK, "Bk0", "0", "0", 0, "Prefab House", "\x83\x76\x83\x8C\x83\x6E\x83\x75"), /* プレハブ */ + STAGE_ENTRY("Hell", "Hell1", BACKGROUND_TYPE_MOVE_NEAR, "bkRed", "Hell", "0", 0, "Sacred Ground - B1", "\x90\xB9\x88\xE6\x92\x6E\x89\xBA\x82\x50\x8A\x4B"), /* 聖域地下1階 */ + STAGE_ENTRY("Hell", "Hell2", BACKGROUND_TYPE_MOVE_NEAR, "bkRed", "Hell", "0", 0, "Sacred Ground - B2", "\x90\xB9\x88\xE6\x92\x6E\x89\xBA\x82\x51\x8A\x4B"), /* 聖域地下2階 */ + STAGE_ENTRY("Hell", "Hell3", BACKGROUND_TYPE_MOVE_DISTANT, "bkRed", "Hell", "Press", 8, "Sacred Ground - B3", "\x90\xB9\x88\xE6\x92\x6E\x89\xBA\x82\x52\x8A\x4B"), /* 聖域地下3階 */ + STAGE_ENTRY("Cave", "Mapi", BACKGROUND_TYPE_MOVE_NEAR, "bk0", "Cemet", "0", 0, "Storage", "\x95\xA8\x92\x75"), /* 物置 */ + STAGE_ENTRY("Hell", "Hell4", BACKGROUND_TYPE_BLACK, "bk0", "Hell", "0", 0, "Passage?", "\x92\xCA\x98\x48\x81\x48"), /* 通路? */ + STAGE_ENTRY("Hell", "Hell42", BACKGROUND_TYPE_BLACK, "bk0", "Hell", "Press", 8, "Passage?", "\x92\xCA\x98\x48\x81\x48"), /* 通路? */ + STAGE_ENTRY("Hell", "Statue", BACKGROUND_TYPE_MOVE_DISTANT, "bkBlue", "0", "Cent", 0, "Statue Chamber", "\x90\xCE\x91\x9C\x82\xCC\x8A\xD4"), /* 石像の間 */ + STAGE_ENTRY("Hell", "Ballo1", BACKGROUND_TYPE_MOVE_NEAR, "bkBlue", "Priest", "Ballos", 9, "Seal Chamber", "\x95\x95\x88\xF3\x82\xCC\x8A\xD4"), /* 封印の間 */ + STAGE_ENTRY("White", "Ostep", BACKGROUND_TYPE_CLOUDS, "BkFog", "0", "0", 0, "Corridor", "\x82\xED\x82\xBD\x82\xE8\x98\x4C\x89\xBA"), /* わたり廊下 */ + STAGE_ENTRY("Labo", "e_Labo", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "0", 0, "", ""), + STAGE_ENTRY("Cave", "Pole", BACKGROUND_TYPE_BLACK, "bk0", "Guest", "0", 0, "Hermit Gunsmith", "\x82\xCD\x82\xAE\x82\xEA\x8F\x65\x92\x62\x96\xE8"), /* はぐれ銃鍛冶 */ + STAGE_ENTRY("0", "Island", BACKGROUND_TYPE_BLACK, "bk0", "Island", "0", 0, "", ""), + STAGE_ENTRY("Hell", "Ballo2", BACKGROUND_TYPE_MOVE_NEAR, "bkBlue", "Priest", "Bllg", 9, "Seal Chamber", "\x95\x95\x88\xF3\x82\xCC\x8A\xD4"), /* 封印の間 */ + STAGE_ENTRY("White", "e_Blcn", BACKGROUND_TYPE_CLOUDS, "BkFog", "Miza", "0", 9, "", ""), + STAGE_ENTRY("Oside", "Clock", BACKGROUND_TYPE_CLOUDS_WINDY, "BkMoon", "Moon", "0", 0, "Clock Room", "\x8E\x9E\x8C\x76\x89\xAE") /* 時計屋 */ +}; + +BOOL TransferStage(int no, int w, int x, int y) +{ + char path[MAX_PATH]; + char path_dir[20]; + BOOL bError; + + // Move character + SetMyCharPosition(x * 0x10 * 0x200, y * 0x10 * 0x200); + + bError = FALSE; + + // Get path + strcpy(path_dir, "Stage"); + + // Load tileset + sprintf(path, "%s\\Prt%s", path_dir, gTMT[no].parts); + if (!ReloadBitmap_File(path, SURFACE_ID_LEVEL_TILESET)) + bError = TRUE; + + sprintf(path, "%s\\%s.pxa", path_dir, gTMT[no].parts); + if (!LoadAttributeData(path)) + bError = TRUE; + + // Load tilemap + sprintf(path, "%s\\%s.pxm", path_dir, gTMT[no].map); + if (!LoadMapData2(path)) + bError = TRUE; + + // Load NPCs + sprintf(path, "%s\\%s.pxe", path_dir, gTMT[no].map); + if (!LoadEvent(path)) + bError = TRUE; + + // Load script + sprintf(path, "%s\\%s.tsc", path_dir, gTMT[no].map); + if (!LoadTextScript_Stage(path)) + bError = TRUE; + + // Load background + sprintf(path, "%s", gTMT[no].back); + if (!InitBack(path, gTMT[no].bkType)) + bError = TRUE; + + // Get path + strcpy(path_dir, "Npc"); + + // Load NPC sprite sheets + sprintf(path, "%s\\Npc%s", path_dir, gTMT[no].npc); + if (!ReloadBitmap_File(path, SURFACE_ID_LEVEL_SPRITESET_1)) + bError = TRUE; + + sprintf(path, "%s\\Npc%s", path_dir, gTMT[no].boss); + if (!ReloadBitmap_File(path, SURFACE_ID_LEVEL_SPRITESET_2)) + bError = TRUE; + + if (bError) + return FALSE; + + // Load map name + ReadyMapName(gTMT[no].name); + + StartTextScript(w); + SetFrameMyChar(); + ClearBullet(); + InitCaret(); + ClearValueView(); + ResetQuake(); + InitBossChar(gTMT[no].boss_no); + ResetFlash(); + gStageNo = no; + + return TRUE; +} + +// Music +const char* const gMusicTable[] = { + "XXXX", + "WANPAKU", + "ANZEN", + "GAMEOVER", + "GRAVITY", + "WEED", + "MDOWN2", + "FIREEYE", + "VIVI", + "MURA", + "FANFALE1", + "GINSUKE", + "CEMETERY", + "PLANT", + "KODOU", + "FANFALE3", + "FANFALE2", + "DR", + "ESCAPE", + "JENKA", + "MAZE", + "ACCESS", + "IRONH", + "GRAND", + "Curly", // Uses the original filename instead of the internal allcaps one + "OSIDE", + "REQUIEM", + "WANPAK2", + "QUIET", + "LASTCAVE", + "BALCONY", + "LASTBTL", + "LASTBT3", + "ENDING", + "ZONBIE", + "BDOWN", + "HELL", + "JENKA2", + "MARINE", + "BALLOS", + "TOROKO", + "WHITE" +}; + +void ChangeMusic(MusicID no) +{ + if (no != MUS_SILENCE && no == gMusicNo) + return; + + // Stop and keep track of old song + gOldPos = GetOrganyaPosition(); + gOldNo = gMusicNo; + StopOrganyaMusic(); + + // Load .org + LoadOrganya(gMusicTable[no]); + + // Reset position, volume, and then play the song + ChangeOrganyaVolume(100); + SetOrganyaPosition(0); + PlayOrganyaMusic(); + gMusicNo = no; +} + +void ReCallMusic(void) +{ + // Stop old song + StopOrganyaMusic(); + + // Load .org that was playing before + LoadOrganya(gMusicTable[gOldNo]); + + // Reset position, volume, and then play the song + SetOrganyaPosition(gOldPos); + ChangeOrganyaVolume(100); + PlayOrganyaMusic(); + gMusicNo = gOldNo; +} diff --git a/src/Stage.h b/src/Stage.h new file mode 100644 index 0000000..51e8b82 --- /dev/null +++ b/src/Stage.h @@ -0,0 +1,81 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef enum MusicID +{ + MUS_SILENCE = 0x0, + MUS_MISCHIEVOUS_ROBOT = 0x1, + MUS_SAFETY = 0x2, + MUS_GAME_OVER = 0x3, + MUS_GRAVITY = 0x4, + MUS_ON_TO_GRASSTOWN = 0x5, + MUS_MELTDOWN2 = 0x6, + MUS_EYES_OF_FLAME = 0x7, + MUS_GESTATION = 0x8, + MUS_MIMIGA_TOWN = 0x9, + MUS_GOT_ITEM = 0xA, + MUS_BALROGS_THEME = 0xB, + MUS_CEMETERY = 0xC, + MUS_PLANT = 0xD, + MUS_PULSE = 0xE, + MUS_VICTORY = 0xF, + MUS_GET_HEART_TANK = 0x10, + MUS_TYRANT = 0x11, + MUS_RUN = 0x12, + MUS_JENKA1 = 0x13, + MUS_LABYRINTH_FIGHT = 0x14, + MUS_ACCESS = 0x15, + MUS_OPPRESSION = 0x16, + MUS_GEOTHERMAL = 0x17, + MUS_CAVE_STORY = 0x18, + MUS_MOONSONG = 0x19, + MUS_HEROS_END = 0x1A, + MUS_SCORCHING_BACK = 0x1B, + MUS_QUIET = 0x1C, + MUS_LAST_CAVE = 0x1D, + MUS_BALCONY = 0x1E, + MUS_CHARGE = 0x1F, + MUS_LAST_BATTLE = 0x20, + MUS_THE_WAY_BACK_HOME = 0x21, + MUS_ZOMBIE = 0x22, + MUS_BREAK_DOWN = 0x23, + MUS_RUNNING_HELL = 0x24, + MUS_JENKA2 = 0x25, + MUS_LIVING_WATERWAY = 0x26, + MUS_SEAL_CHAMBER = 0x27, + MUS_TOROKOS_THEME = 0x28, + MUS_WHITE = 0x29 +} MusicID; + +typedef struct STAGE_TABLE +{ + char parts[0x20]; + char map[0x20]; + int bkType; + char back[0x20]; + char npc[0x20]; + char boss[0x20]; + signed char boss_no; + char name[0x20]; +} STAGE_TABLE; + +extern int gStageNo; +extern MusicID gMusicNo; +extern unsigned int gOldPos; +extern MusicID gOldNo; + +extern const STAGE_TABLE gTMT[95]; + +extern const char* const gMusicTable[42]; + +BOOL TransferStage(int no, int w, int x, int y); +void ChangeMusic(MusicID no); +void ReCallMusic(void); diff --git a/src/Star.cpp b/src/Star.cpp new file mode 100644 index 0000000..cc2cbdb --- /dev/null +++ b/src/Star.cpp @@ -0,0 +1,146 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Star.h" + +#include + +#include "WindowsWrapper.h" + +#include "Bullet.h" +#include "Draw.h" +#include "Game.h" +#include "MyChar.h" + +static struct +{ + int cond; + int code; + int direct; + int x; + int y; + int xm; + int ym; + int act_no; + int act_wait; + int ani_no; + int ani_wait; + int view_left; + int view_top; + RECT rect; +} star[3]; + +void InitStar(void) +{ + // Clear stars + memset(star, 0, sizeof(star)); + + // Position + star[0].x = gMC.x; + star[0].y = gMC.y; + + star[1].x = gMC.x; + star[1].y = gMC.y; + + star[2].x = gMC.x; + star[2].y = gMC.y; + + // Speed + star[0].xm = 0x400; + star[0].ym = -0x200; + + star[1].xm = -0x200; + star[1].ym = 0x400; + + star[2].xm = 0x200; + star[2].ym = 0x200; +} + +void ActStar(void) +{ + int i; + static int a; + + ++a; + a %= 3; + + for (i = 0; i < 3; ++i) + { + if (i != 0) + { + if (star[i - 1].x < star[i].x) + star[i].xm -= 0x80; + else + star[i].xm += 0x80; + + if (star[i - 1].y < star[i].y) + star[i].ym -= 0xAA; + else + star[i].ym += 0xAA; + } + else + { + if (gMC.x < star[i].x) + star[i].xm -= 0x80; + else + star[i].xm += 0x80; + + if (gMC.y < star[i].y) + star[i].ym -= 0xAA; + else + star[i].ym += 0xAA; + } + + if (star[i].xm > 0xA00) + star[i].xm = 0xA00; + if (star[i].xm < -0xA00) + star[i].xm = -0xA00; + + if (star[i].ym > 0xA00) + star[i].ym = 0xA00; + if (star[i].ym < -0xA00) + star[i].ym = -0xA00; + + // Duplicate of the past 8 lines of code + if (star[i].xm > 0xA00) + star[i].xm = 0xA00; + if (star[i].xm < -0xA00) + star[i].xm = -0xA00; + + if (star[i].ym > 0xA00) + star[i].ym = 0xA00; + if (star[i].ym < -0xA00) + star[i].ym = -0xA00; + + star[i].x += star[i].xm; + star[i].y += star[i].ym; + + if (i < gMC.star && (gMC.equip & EQUIP_WHIMSICAL_STAR) && (g_GameFlags & 2) && a == i) + SetBullet(45, star[a].x, star[a].y, 0); + } +} + +void PutStar(int fx, int fy) +{ + RECT rc[3] = { + {192, 0, 200, 8}, + {192, 8, 200, 16}, + {192, 16, 200, 24}, + }; + + int i; + + if (gMC.cond & 2) + return; + + if (!(gMC.equip & EQUIP_WHIMSICAL_STAR)) + return; + + for (i = 0; i < 3; ++i) + if (i < gMC.star) + PutBitmap3(&grcGame, (star[i].x / 0x200) - (fx / 0x200) - 4, (star[i].y / 0x200) - (fy / 0x200) - 4, &rc[i], SURFACE_ID_MY_CHAR); +} diff --git a/src/Star.h b/src/Star.h new file mode 100644 index 0000000..e107f34 --- /dev/null +++ b/src/Star.h @@ -0,0 +1,12 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +void InitStar(void); +void ActStar(void); +void PutStar(int fx, int fy); diff --git a/src/Tags.h b/src/Tags.h new file mode 100644 index 0000000..95e166c --- /dev/null +++ b/src/Tags.h @@ -0,0 +1,11 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +// Apparently this used to contain a bunch of structs? +// For now, the structs are in header files matching their purpose. diff --git a/src/TextScr.cpp b/src/TextScr.cpp new file mode 100644 index 0000000..1af2698 --- /dev/null +++ b/src/TextScr.cpp @@ -0,0 +1,1557 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "TextScr.h" + +#include +#include +#include +#include + +#include "WindowsWrapper.h" + +#include "ArmsItem.h" +#include "Boss.h" +#include "BossLife.h" +#include "CommonDefines.h" +#include "Draw.h" +#include "Ending.h" +#include "Escape.h" +#include "Fade.h" +#include "Flags.h" +#include "Flash.h" +#include "Frame.h" +#include "Game.h" +#include "Generic.h" +#include "KeyControl.h" +#include "Main.h" +#include "Map.h" +#include "MapName.h" +#include "MiniMap.h" +#include "MyChar.h" +#include "MycParam.h" +#include "NpChar.h" +#include "Organya.h" +#include "Profile.h" +#include "SelStage.h" +#include "Sound.h" +#include "Stage.h" + +// This limits the size of a .tsc script to 0x5000 bytes (the game will crash above this) +#define TSC_BUFFER_SIZE 0x5000 + +#define TEXT_LEFT (WINDOW_WIDTH / 2 - 108) + +#define IS_COMMAND(c1, c2, c3) (gTS.data[gTS.p_read + 1] == (c1) && gTS.data[gTS.p_read + 2] == (c2) && gTS.data[gTS.p_read + 3] == (c3)) + +TEXT_SCRIPT gTS; + +static char text[4][0x40]; + +const RECT gRect_line = {0, 0, 216, 16}; + +#ifdef FIX_BUGS +static unsigned long nod_color; +#endif + +// Initialize and end tsc +BOOL InitTextScript2(void) +{ + int i; + +#ifdef FIX_BUGS + nod_color = GetCortBoxColor(RGB(0xFF, 0xFF, 0xFE)); +#endif + + // Clear flags + gTS.mode = 0; + g_GameFlags &= ~4; + + // Create line surfaces + for (i = 0; i < 4; ++i) + MakeSurface_Generic(gRect_line.right, gRect_line.bottom, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i), FALSE); + + // Clear text + memset(text, 0, sizeof(text)); + + // Allocate script buffer + gTS.data = (char*)malloc(TSC_BUFFER_SIZE); + + if (gTS.data == NULL) + return FALSE; + else + return TRUE; +} + +void EndTextScript(void) +{ + int i; + + // Free TSC buffer + free(gTS.data); + + // Release buffers + ReleaseSurface(SURFACE_ID_TEXT_BOX); + + for (i = 0; i < 4; ++i) + ReleaseSurface((SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); +} + +// Decrypt .tsc +void EncryptionBinaryData2(unsigned char *pData, long size) +{ + int i; + int work; + + int half; + int val1; + + half = size / 2; + + if (pData[half] == 0) + val1 = -7; + else + val1 = (pData[half] % 0x100) * -1; + + for (i = 0; i < size; ++i) + { + work = pData[i]; + work += val1; + + if (i != half) + pData[i] = work % 0x100; + } +} + +// Load generic .tsc +BOOL LoadTextScript2(const char *name) +{ + FILE *fp; + char path[MAX_PATH]; + + // Get path + sprintf(path, "%s\\%s", gDataPath, name); + + gTS.size = GetFileSizeLong(path); + if (gTS.size == INVALID_FILE_SIZE) + return FALSE; + + // Open file + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Read data. Note that gTS.size may exceed the size of 'gTS.data' (TSC_BUFFER_SIZE) + fread(gTS.data, 1, gTS.size, fp); + gTS.data[gTS.size] = '\0'; + fclose(fp); + + // Set path + strcpy(gTS.path, name); + + // Decrypt data + EncryptionBinaryData2((unsigned char*)gTS.data, gTS.size); + + return TRUE; +} + +// Load stage .tsc +BOOL LoadTextScript_Stage(const char *name) +{ + FILE *fp; + char path[MAX_PATH]; + long head_size; + long body_size; + + // Open Head.tsc + sprintf(path, "%s\\%s", gDataPath, "Head.tsc"); + + head_size = GetFileSizeLong(path); + if (head_size == INVALID_FILE_SIZE) + return FALSE; + +#ifdef FIX_BUGS + // The original doesn't check for any kind of buffer overflow here, so feeding in a 1 MiB Head.tsc + // (assuming an unchanged TSC_BUFFER_SIZE) would be sure to crash the game, for example. + if (head_size > TSC_BUFFER_SIZE) + return FALSE; +#endif + + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Read Head.tsc. Note that head_size may exceed the size of 'gTS.data' (TSC_BUFFER_SIZE) + fread(gTS.data, 1, head_size, fp); + EncryptionBinaryData2((unsigned char*)gTS.data, head_size); + gTS.data[head_size] = '\0'; + fclose(fp); + + // Open stage's .tsc + sprintf(path, "%s\\%s", gDataPath, name); + + body_size = GetFileSizeLong(path); + if (body_size == INVALID_FILE_SIZE) + return FALSE; + +#ifdef FIX_BUGS + // Same as above: the original doesn't bother checking, and may crash on large-enough input + if (head_size + body_size > TSC_BUFFER_SIZE) + return FALSE; +#endif + + fp = fopen(path, "rb"); + if (fp == NULL) + return FALSE; + + // Read stage's tsc. Note that head_size + body_size may exceed the size of 'gTS.data' (TSC_BUFFER_SIZE) + fread(&gTS.data[head_size], 1, body_size, fp); + EncryptionBinaryData2((unsigned char*)&gTS.data[head_size], body_size); + gTS.data[head_size + body_size] = '\0'; + fclose(fp); + + // Set parameters + gTS.size = head_size + body_size; + strcpy(gTS.path, name); + + return TRUE; +} + +// Get current path +void GetTextScriptPath(char *path) +{ + strcpy(path, gTS.path); +} + +// Get 4 digit number from TSC data +int GetTextScriptNo(int a) +{ + int b = 0; + b += (gTS.data[a++] - '0') * 1000; + b += (gTS.data[a++] - '0') * 100; + b += (gTS.data[a++] - '0') * 10; + b += gTS.data[a] - '0'; + return b; +} + +// Start TSC event +BOOL StartTextScript(int no) +{ + //int i; + + // Reset state + gTS.mode = 1; + g_GameFlags |= 5; + gTS.line = 0; + gTS.p_write = 0; + gTS.wait = 4; + gTS.flags = 0; + gTS.wait_beam = 0; + gTS.face = 0; + gTS.item = 0; + gTS.offsetY = 0; + + gMC.shock = 0; + + gTS.rcText.left = TEXT_LEFT; + gTS.rcText.top = WINDOW_HEIGHT - 56; + gTS.rcText.right = WINDOW_WIDTH - TEXT_LEFT; + gTS.rcText.bottom = gTS.rcText.top + 48; + + /* This is present in the Linux port, but not the Windows version (1.0.0.6, at least) + // Clear text lines + for (i = 0; i < 4; ++i) + { + gTS.ypos_line[i] = i * 16; + CortBox2(&gRect_line, 0x000000, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); + memset(text[i], 0, sizeof(text[0])); + }*/ + + // Find where event starts + gTS.p_read = 0; + while (1) + { + // Check if we are still in the proper range + if (gTS.data[gTS.p_read] == '\0') + return FALSE; + + // Check if we are at an event + if (gTS.data[gTS.p_read] == '#') + { + // Check if this is our event + int event_no = GetTextScriptNo(++gTS.p_read); + + if (no == event_no) + break; + if (no < event_no) + return FALSE; + } + + ++gTS.p_read; + } + + // Advance until new-line + while (gTS.data[gTS.p_read] != '\n') + ++gTS.p_read; + ++gTS.p_read; + + return TRUE; +} + +BOOL JumpTextScript(int no) +{ + int i; + + // Set state + gTS.mode = 1; + g_GameFlags |= 4; + gTS.line = 0; + gTS.p_write = 0; + gTS.wait = 4; + gTS.wait_beam = 0; + + // Clear text lines + for (i = 0; i < 4; ++i) + { + gTS.ypos_line[i] = i * 16; + CortBox2(&gRect_line, 0x000000, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); + memset(text[i], 0, sizeof(text[0])); + } + + // Find where event starts + gTS.p_read = 0; + + while(1) + { + // Check if we are still in the proper range + if (gTS.data[gTS.p_read] == '\0') + return FALSE; + + // Check if we are at an event + if (gTS.data[gTS.p_read] == '#') + { + // Check if this is our event + int event_no = GetTextScriptNo(++gTS.p_read); + + if (no == event_no) + break; + if (no < event_no) + return FALSE; + } + + ++gTS.p_read; + } + + // Advance until new-line + while (gTS.data[gTS.p_read] != '\n') + ++gTS.p_read; + + ++gTS.p_read; + + return TRUE; +} + +// End event +void StopTextScript(void) +{ + // End TSC and reset flags + gTS.mode = 0; + g_GameFlags &= ~4; + g_GameFlags |= 3; + gTS.flags = 0; +} + +// Prepare a new line +void CheckNewLine(void) +{ + if (gTS.ypos_line[gTS.line % 4] == 48) + { + gTS.mode = 3; + g_GameFlags |= 4; + CortBox2(&gRect_line, 0, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + (gTS.line % 4))); + memset(text[gTS.line % 4], 0, sizeof(text[0])); + } +} + +int gNumberTextScript[4]; + +// Type a number into the text buffer +void SetNumberTextScript(int index) +{ + char str[5]; + BOOL bZero; + int a; + int b; + int offset; + int i; + + // Get digit table + int table[3]; + table[0] = 1000; + table[1] = 100; + table[2] = 10; + + // Get number to print + a = gNumberTextScript[index]; + + bZero = FALSE; + offset = 0; + + // Trim leading zeroes + for (i = 0; i < 3; ++i) + { + if (a / table[i] || bZero) + { + b = a / table[i]; + str[offset] = '0' + (char)b; + bZero = TRUE; + a -= b * table[i]; + ++offset; + } + } + + // Set last digit of string, and add null terminator + str[offset] = '0' + (char)a; + str[offset + 1] = '\0'; + + // Append number to line + PutText2(gTS.p_write * 6, 0, str, RGB(0xFF, 0xFF, 0xFE), (SurfaceID)(SURFACE_ID_TEXT_LINE1 + (gTS.line % 4))); + strcat(text[gTS.line % 4], str); + + // Play sound and reset blinking cursor + PlaySoundObject(2, SOUND_MODE_PLAY); + gTS.wait_beam = 0; + + // Check if should move to next line (prevent a memory overflow, come on guys, this isn't a leftover of pixel trying to make text wrapping) + gTS.p_write += (int)strlen(str); + + if (gTS.p_write >= 35) + { + gTS.p_write = 0; + ++gTS.line; + CheckNewLine(); + } +} + +// Clear text lines +void ClearTextLine(void) +{ + int i; + + gTS.line = 0; + gTS.p_write = 0; + gTS.offsetY = 0; + + for (i = 0; i < 4; ++i) + { + gTS.ypos_line[i] = i * 16; + CortBox2(&gRect_line, 0x000000, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); + memset(text[i], 0, sizeof(text[0])); + } +} + +// Draw textbox and whatever else +void PutTextScript(void) +{ + int i; + RECT rect; + int text_offset; + + if (gTS.mode == 0) + return; + + if ((gTS.flags & 1) == 0) + return; + + // Set textbox position + if (gTS.flags & 0x20) + { + gTS.rcText.top = 32; + gTS.rcText.bottom = gTS.rcText.top + 48; + } + else + { + gTS.rcText.top = WINDOW_HEIGHT - 56; + gTS.rcText.bottom = gTS.rcText.top + 48; + } + + // Draw textbox + if (gTS.flags & 2) + { + RECT rcFrame1 = {0, 0, 244, 8}; + RECT rcFrame2 = {0, 8, 244, 16}; + RECT rcFrame3 = {0, 16, 244, 24}; + + PutBitmap3(&grcFull, WINDOW_WIDTH / 2 - 122, gTS.rcText.top - 10, &rcFrame1, SURFACE_ID_TEXT_BOX); + for (i = 1; i < 7; ++i) + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 122, (i * 8) + gTS.rcText.top - 10, &rcFrame2, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 122, (i * 8) + gTS.rcText.top - 10, &rcFrame3, SURFACE_ID_TEXT_BOX); + } + + // Draw face picture + RECT rcFace; + rcFace.left = (gTS.face % 6) * 48; + rcFace.top = (gTS.face / 6) * 48; + rcFace.right = rcFace.left + 48; + rcFace.bottom = rcFace.top + 48; + + if (gTS.face_x < (TEXT_LEFT * 0x200)) + gTS.face_x += 0x1000; + +#ifdef FIX_BUGS + gTS.rcText.top -= 2; + PutBitmap3(&gTS.rcText, gTS.face_x / 0x200, gTS.rcText.top, &rcFace, SURFACE_ID_FACE); + gTS.rcText.top += 2; +#else + // The top few rows of pixels are cut off by the clip rectangle, and the facepic is off-centre + PutBitmap3(&gTS.rcText, gTS.face_x / 0x200, gTS.rcText.top - 3, &rcFace, SURFACE_ID_FACE); +#endif + + // Draw text + if (gTS.face != 0) + text_offset = 56; + else + text_offset = 0; + + for (i = 0; i < 4; ++i) + PutBitmap3(&gTS.rcText, TEXT_LEFT + text_offset, gTS.offsetY + gTS.ypos_line[i] + gTS.rcText.top, &gRect_line, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); + + // Draw NOD cursor + if ((gTS.wait_beam++ % 20 > 12) && gTS.mode == 2) + { + rect.left = TEXT_LEFT + (gTS.p_write * 6) + text_offset; + rect.top = gTS.ypos_line[gTS.line % 4] + gTS.rcText.top + gTS.offsetY; + rect.right = rect.left + 5; + rect.bottom = rect.top + 11; +#ifdef FIX_BUGS + CortBox(&rect, nod_color); + + // This is how the Linux port fixed this, but it isn't done + // the way Pixel would do it (he only calls GetCortBoxColor + // once, during init functions, so our fix does it that way + // instead). + // CortBox(&rect, GetCortBoxColor(RGB(0xFF, 0xFF, 0xFE)); +#else + // This accidentally uses a BGR value directly, without + // running it though GetCortBoxColor first + CortBox(&rect, RGB(0xFF, 0xFF, 0xFE)); +#endif + } + + // Draw GIT + RECT rcItemBox1 = {0, 0, 72, 16}; + RECT rcItemBox2 = {0, 8, 72, 24}; + RECT rcItemBox3 = {240, 0, 244, 8}; + RECT rcItemBox4 = {240, 8, 244, 16}; + RECT rcItemBox5 = {240, 16, 244, 24}; + + if (gTS.item != 0) + { + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 40, WINDOW_HEIGHT - 112, &rcItemBox1, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 40, WINDOW_HEIGHT - 96, &rcItemBox2, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) + 32, WINDOW_HEIGHT - 112, &rcItemBox3, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) + 32, WINDOW_HEIGHT - 104, &rcItemBox4, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) + 32, WINDOW_HEIGHT - 96, &rcItemBox4, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) + 32, WINDOW_HEIGHT - 88, &rcItemBox5, SURFACE_ID_TEXT_BOX); + + if (gTS.item_y < WINDOW_HEIGHT - 104) + ++gTS.item_y; + + if (gTS.item < 1000) + { + rect.left = (gTS.item % 16) * 16; + rect.right = rect.left + 16; + rect.top = (gTS.item / 16) * 16; + rect.bottom = rect.top + 16; + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 12, gTS.item_y, &rect, SURFACE_ID_ARMS_IMAGE); + } + else + { + rect.left = 32 * ((gTS.item - 1000) % 8); + rect.right = rect.left + 32; + rect.top = 16 * ((gTS.item - 1000) / 8); + rect.bottom = rect.top + 16; + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) - 20, gTS.item_y, &rect, SURFACE_ID_ITEM_IMAGE); + } + } + + // Draw Yes / No selection + RECT rect_yesno = {152, 48, 244, 80}; + RECT rect_cur = {112, 88, 128, 104}; + + if (gTS.mode == 6) + { + if (gTS.wait < 2) + i = (WINDOW_HEIGHT - 96) + (2 - gTS.wait) * 4; + else + i = WINDOW_HEIGHT - 96; + + PutBitmap3(&grcFull, (WINDOW_WIDTH / 2) + 56, i, &rect_yesno, SURFACE_ID_TEXT_BOX); + if (gTS.wait == 16) + PutBitmap3(&grcFull, (gTS.select * 41) + (WINDOW_WIDTH / 2) + 51, WINDOW_HEIGHT - 86, &rect_cur, SURFACE_ID_TEXT_BOX); + } +} + +// Parse TSC +int TextScriptProc(void) +{ + int i; + char c[3]; + char str[72]; + int w, x, y, z; + + BOOL bExit; + + RECT rcSymbol = {64, 48, 72, 56}; + + switch (gTS.mode) + { + case 1: // PARSE + // Type out (faster if ok or cancel are held) + ++gTS.wait; + + if (!(g_GameFlags & 2) && gKey & (gKeyOk | gKeyCancel)) + gTS.wait += 4; + + if (gTS.wait < 4) + break; + + gTS.wait = 0; + + // Parsing time + bExit = FALSE; + + while (!bExit) + { + if (gTS.data[gTS.p_read] == '<') + { + if (IS_COMMAND('E','N','D')) + { + gTS.mode = 0; + gMC.cond &= ~1; + g_GameFlags |= 3; + gTS.face = 0; + bExit = TRUE; + } + else if (IS_COMMAND('L','I','+')) + { + x = GetTextScriptNo(gTS.p_read + 4); + AddLifeMyChar(x); + gTS.p_read += 8; + } + else if (IS_COMMAND('M','L','+')) + { + z = GetTextScriptNo(gTS.p_read + 4); + AddMaxLifeMyChar(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('A','E','+')) + { + FullArmsEnergy(); + gTS.p_read += 4; + } + else if (IS_COMMAND('I','T','+')) + { + x = GetTextScriptNo(gTS.p_read + 4); + PlaySoundObject(38, SOUND_MODE_PLAY); + AddItemData(x); + gTS.p_read += 8; + } + else if (IS_COMMAND('I','T','-')) + { + z = GetTextScriptNo(gTS.p_read + 4); + SubItemData(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('E','Q','+')) + { + z = GetTextScriptNo(gTS.p_read + 4); + EquipItem(z, TRUE); + gTS.p_read += 8; + } + else if (IS_COMMAND('E','Q','-')) + { + z = GetTextScriptNo(gTS.p_read + 4); + EquipItem(z, FALSE); + gTS.p_read += 8; + } + else if (IS_COMMAND('A','M','+')) + { + w = GetTextScriptNo(gTS.p_read + 4); + x = GetTextScriptNo(gTS.p_read + 9); + + gNumberTextScript[0] = x; + #ifndef FIX_MAJOR_BUGS + // z is uninitialised. Probably a leftover from copypasting this from elsewhere. + gNumberTextScript[1] = z; + #endif + + PlaySoundObject(38, SOUND_MODE_PLAY); + AddArmsData(w, x); + gTS.p_read += 13; + } + else if (IS_COMMAND('A','M','-')) + { + z = GetTextScriptNo(gTS.p_read + 4); + SubArmsData(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('Z','A','M')) + { + ZeroArmsEnergy_All(); + gTS.p_read += 4; + } + else if (IS_COMMAND('T','A','M')) + { + x = GetTextScriptNo(gTS.p_read + 4); + y = GetTextScriptNo(gTS.p_read + 9); + z = GetTextScriptNo(gTS.p_read + 14); + TradeArms(x, y, z); + gTS.p_read += 18; + } + else if (IS_COMMAND('P','S','+')) + { + x = GetTextScriptNo(gTS.p_read + 4); + y = GetTextScriptNo(gTS.p_read + 9); + AddPermitStage(x, y); + gTS.p_read += 13; + } + else if (IS_COMMAND('M','P','+')) + { + x = GetTextScriptNo(gTS.p_read + 4); + SetMapping(x); + gTS.p_read += 8; + } + else if (IS_COMMAND('U','N','I')) + { + z = GetTextScriptNo(gTS.p_read + 4); + ChangeMyUnit(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('S','T','C')) + { + SaveTimeCounter(); + gTS.p_read += 4; + } + else if (IS_COMMAND('T','R','A')) + { + z = GetTextScriptNo(gTS.p_read + 4); + w = GetTextScriptNo(gTS.p_read + 9); + x = GetTextScriptNo(gTS.p_read + 14); + y = GetTextScriptNo(gTS.p_read + 19); + + if (!TransferStage(z, w, x, y)) + { + #if !defined(JAPANESE) && defined(FIX_BUGS) // The Aeon Genesis translation didn't translate this + MessageBoxA(ghWnd, "Failed to load stage", "Error", MB_OK); + #else + MessageBoxA(ghWnd, "\x83\x58\x83\x65\x81\x5B\x83\x57\x82\xCC\x93\xC7\x82\xDD\x8D\x9E\x82\xDD\x82\xC9\x8E\xB8\x94\x73", "\x83\x47\x83\x89\x81\x5B", MB_OK); /* 'ステージの読み込みに失敗' and 'エラー' in Shift-JIS */ + #endif + return enum_ESCRETURN_exit; + } + } + else if (IS_COMMAND('M','O','V')) + { + x = GetTextScriptNo(gTS.p_read + 4); + y = GetTextScriptNo(gTS.p_read + 9); + SetMyCharPosition(x * 0x200 * 0x10, y * 0x200 * 0x10); + gTS.p_read += 13; + } + else if (IS_COMMAND('H','M','C')) + { + ShowMyChar(FALSE); + gTS.p_read += 4; + } + else if (IS_COMMAND('S','M','C')) + { + ShowMyChar(TRUE); + gTS.p_read += 4; + } + else if (IS_COMMAND('F','L','+')) + { + z = GetTextScriptNo(gTS.p_read + 4); + SetNPCFlag(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('F','L','-')) + { + z = GetTextScriptNo(gTS.p_read + 4); + CutNPCFlag(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('S','K','+')) + { + z = GetTextScriptNo(gTS.p_read + 4); + SetSkipFlag(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('S','K','-')) + { + z = GetTextScriptNo(gTS.p_read + 4); + CutSkipFlag(z); + gTS.p_read += 8; + } + else if (IS_COMMAND('K','E','Y')) + { + g_GameFlags &= ~2; + g_GameFlags |= 1; + gMC.up = FALSE; + gMC.shock = 0; + gTS.p_read += 4; + } + else if (IS_COMMAND('P','R','I')) + { + g_GameFlags &= ~3; + gMC.shock = 0; + gTS.p_read += 4; + } + else if (IS_COMMAND('F','R','E')) + { + g_GameFlags |= 3; + gTS.p_read += 4; + } + else if (IS_COMMAND('N','O','D')) + { + gTS.mode = 2; + gTS.p_read += 4; + bExit = TRUE; + } + else if (IS_COMMAND('C','L','R')) + { + ClearTextLine(); + gTS.p_read += 4; + } + else if (IS_COMMAND('M','S','G')) + { + ClearTextLine(); + gTS.flags |= 0x03; + gTS.flags &= ~0x30; + if (gTS.flags & 0x40) + gTS.flags |= 0x10; + gTS.p_read += 4; + bExit = TRUE; + } + else if (IS_COMMAND('M','S','2')) + { + ClearTextLine(); + gTS.flags &= ~0x12; + gTS.flags |= 0x21; + if (gTS.flags & 0x40) + gTS.flags |= 0x10; + gTS.face = 0; + gTS.p_read += 4; + bExit = TRUE; + } + else if (IS_COMMAND('M','S','3')) + { + ClearTextLine(); + gTS.flags &= ~0x10; + gTS.flags |= 0x23; + if (gTS.flags & 0x40) + gTS.flags |= 0x10; + gTS.p_read += 4; + bExit = TRUE; + } + else if (IS_COMMAND('W','A','I')) + { + gTS.mode = 4; + gTS.wait_next = GetTextScriptNo(gTS.p_read + 4); + gTS.p_read += 8; + bExit = TRUE; + } + else if (IS_COMMAND('W','A','S')) + { + gTS.mode = 7; + gTS.p_read += 4; + bExit = TRUE; + } + else if (IS_COMMAND('T','U','R')) + { + gTS.p_read += 4; + gTS.flags |= 0x10; + } + else if (IS_COMMAND('S','A','T')) + { + gTS.p_read += 4; + gTS.flags |= 0x40; + } + else if (IS_COMMAND('C','A','T')) + { + gTS.p_read += 4; + gTS.flags |= 0x40; + } + else if (IS_COMMAND('C','L','O')) + { + gTS.flags &= ~0x33; + gTS.p_read += 4; + } + else if (IS_COMMAND('E','V','E')) + { + z = GetTextScriptNo(gTS.p_read + 4); + JumpTextScript(z); + } + else if (IS_COMMAND('Y','N','J')) + { + gTS.next_event = GetTextScriptNo(gTS.p_read + 4); + gTS.p_read += 8; + gTS.mode = 6; + PlaySoundObject(5, SOUND_MODE_PLAY); + gTS.wait = 0; + gTS.select = 0; + bExit = TRUE; + } + else if (IS_COMMAND('F','L','J')) + { + x = GetTextScriptNo(gTS.p_read + 4); + z = GetTextScriptNo(gTS.p_read + 9); + + #ifdef FIX_MAJOR_BUGS + // Some versions of the Waterway TSC script contain a bug: + // = 35) + CheckNewLine(); + + bExit = TRUE; + } + else + { + // Get text to print + c[0] = gTS.data[gTS.p_read]; + + if (c[0] & 0x80) + { + c[1] = gTS.data[gTS.p_read + 1]; + c[2] = '\0'; + } + else + { + c[1] = '\0'; + } + + // Print text + if (c[0] == '=') + { + Surface2Surface(gTS.p_write * 6, 2, &rcSymbol, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + (gTS.line % 4)), SURFACE_ID_TEXT_BOX); + } + else + { + PutText2(gTS.p_write * 6, 0, c, RGB(0xFF, 0xFF, 0xFE), (SurfaceID)(SURFACE_ID_TEXT_LINE1 + (gTS.line % 4))); + } + + strcat(text[gTS.line % 4], c); + PlaySoundObject(2, SOUND_MODE_PLAY); + gTS.wait_beam = 0; + + // Offset read and write positions + if (c[0] & 0x80) + { + gTS.p_read += 2; + gTS.p_write += 2; + } + else + { + gTS.p_read += 1; + gTS.p_write += 1; + } + + if (gTS.p_write >= 35) + { + CheckNewLine(); + gTS.p_write = 0; + ++gTS.line; + CheckNewLine(); + } + + bExit = TRUE; + } + } + } + break; + + case 2: // NOD + if (gKeyTrg & (gKeyOk | gKeyCancel)) + gTS.mode = 1; + break; + + case 3: // NEW LINE + for (i = 0; i < 4; ++i) + { + gTS.ypos_line[i] -= 4; + + if (gTS.ypos_line[i] == 0) + gTS.mode = 1; + + if (gTS.ypos_line[i] == -16) + gTS.ypos_line[i] = 48; + } + break; + + case 4: // WAI + if (gTS.wait_next == 9999) + break; + + if (gTS.wait != 9999) + ++gTS.wait; + + if (gTS.wait < gTS.wait_next) + break; + + gTS.mode = 1; + gTS.wait_beam = 0; + break; + + case 5: // FAI/FAO + if (GetFadeActive()) + break; + + gTS.mode = 1; + gTS.wait_beam = 0; + break; + + case 7: // WAS + if ((gMC.flag & 8) == 0) + break; + + gTS.mode = 1; + gTS.wait_beam = 0; + break; + + case 6: // YNJ + if (gTS.wait < 16) + { + ++gTS.wait; + } + else + { + // Select option + if (gKeyTrg & gKeyOk) + { + PlaySoundObject(18, SOUND_MODE_PLAY); + + if (gTS.select == 1) + { + JumpTextScript(gTS.next_event); + } + else + { + gTS.mode = 1; + gTS.wait_beam = 0; + } + } + // Yes + else if (gKeyTrg & gKeyLeft) + { + gTS.select = 0; + PlaySoundObject(1, SOUND_MODE_PLAY); + } + // No + else if (gKeyTrg & gKeyRight) + { + gTS.select = 1; + PlaySoundObject(1, SOUND_MODE_PLAY); + } + } + break; + } + + if (gTS.mode == 0) + g_GameFlags &= ~4; + else + g_GameFlags |= 4; + + return enum_ESCRETURN_continue; +} + +void RestoreTextScript(void) +{ + int i; + + for (i = 0; i < 4; ++i) + { + CortBox2(&gRect_line, 0x000000, (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); + PutText2(0, 0, text[i], RGB(0xFF, 0xFF, 0xFE), (SurfaceID)(SURFACE_ID_TEXT_LINE1 + i)); + } +} diff --git a/src/TextScr.h b/src/TextScr.h new file mode 100644 index 0000000..00fd6b8 --- /dev/null +++ b/src/TextScr.h @@ -0,0 +1,77 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +typedef struct TEXT_SCRIPT +{ + // Path (reload when exit teleporter menu/inventory) + char path[MAX_PATH]; + + // Script buffer + long size; + char *data; + + // Mode (ex. NOD, WAI) + signed char mode; + + // Flags + signed char flags; + + // Current positions (read position in buffer, x position in line) + int p_read; + int p_write; + + // Current line to write to + int line; + + // Line y positions + int ypos_line[4]; + + // Event stuff + int wait; + int wait_next; + int next_event; + + // Yes/no selected + signed char select; + + // Current face + int face; + int face_x; + + // Current item + int item; + int item_y; + + // Text rect + RECT rcText; + + // ..? + int offsetY; + + // NOD cursor blink + unsigned char wait_beam; +} TEXT_SCRIPT; + +extern TEXT_SCRIPT gTS; + +extern const RECT gRect_line; + +BOOL InitTextScript2(void); +void EndTextScript(void); +void EncryptionBinaryData2(unsigned char *pData, long size); +BOOL LoadTextScript2(const char *name); +BOOL LoadTextScript_Stage(const char *name); +void GetTextScriptPath(char *path); +BOOL StartTextScript(int no); +void StopTextScript(void); +void PutTextScript(void); +int TextScriptProc(void); +void RestoreTextScript(void); diff --git a/src/Triangle.cpp b/src/Triangle.cpp new file mode 100644 index 0000000..0ad3919 --- /dev/null +++ b/src/Triangle.cpp @@ -0,0 +1,130 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "Triangle.h" + +#include + +int gSin[0x100]; +short gTan[0x21]; + +void InitTriangleTable(void) +{ + int i; + + // Sine + for (i = 0; i < 0x100; ++i) + gSin[i] = (int)(sin(i * 6.2831998 / 256.0) * 512.0); + + float a, b; + + // Tangent + for (i = 0; i < 0x21; ++i) + { + a = (float)(i * 6.2831855f / 256.0f); + b = (float)sin(a) / (float)cos(a); + gTan[i] = (short)(b * 8192.0f); + } +} + +int GetSin(unsigned char deg) +{ + return gSin[deg]; +} + +int GetCos(unsigned char deg) +{ + deg += 0x40; + return gSin[deg]; +} + +unsigned char GetArktan(int x, int y) +{ + short k; + unsigned char a; + + x *= -1; + y *= -1; + + a = 0; + + if (x > 0) + { + if (y > 0) + { + if (x > y) + { + k = (y * 0x2000) / x; + while (k > gTan[a]) + ++a; + } + else + { + k = (x * 0x2000) / y; + while (k > gTan[a]) + ++a; + a = 0x40 - a; + } + } + else + { + if (x > -y) + { + k = (-y * 0x2000) / x; + while (k > gTan[a]) + ++a; + a = 0x100 - a; + } + else + { + k = (x * 0x2000) / -y; + while (k > gTan[a]) + ++a; + a = 0x100 - 0x40 + a; + } + } + } + else + { + if (y > 0) + { + if (-x > y) + { + k = (y * 0x2000) / -x; + while (k > gTan[a]) + ++a; + a = 0x80 - a; + } + else + { + k = (-x * 0x2000) / y; + while (k > gTan[a]) + ++a; + a = 0x40 + a; + } + } + else + { + if (-x > -y) + { + k = (-y * 0x2000) / -x; + while (k > gTan[a]) + ++a; + a = 0x80 + a; + } + else + { + k = (-x * 0x2000) / -y; + while (k > gTan[a]) + ++a; + a = 0x100 - 0x40 - a; + } + } + } + + return a; +} diff --git a/src/Triangle.h b/src/Triangle.h new file mode 100644 index 0000000..99a6917 --- /dev/null +++ b/src/Triangle.h @@ -0,0 +1,16 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +extern int gSin[0x100]; +extern short gTan[0x21]; + +void InitTriangleTable(void); +int GetSin(unsigned char deg); +int GetCos(unsigned char deg); +unsigned char GetArktan(int x, int y); diff --git a/src/ValueView.cpp b/src/ValueView.cpp new file mode 100644 index 0000000..a82e7bd --- /dev/null +++ b/src/ValueView.cpp @@ -0,0 +1,207 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#include "ValueView.h" + +#include + +#include "WindowsWrapper.h" + +#include "Draw.h" + +VALUEVIEW gVV[VALUEVIEW_MAX]; +int gVVIndex; + +void ClearValueView(void) +{ + memset(gVV, 0, sizeof(gVV)); + gVVIndex = 0; +} + +void SetValueView(int *px, int *py, int value) +{ + BOOL minus; + int v; + + int index; + int i; + + for (i = 0; i < VALUEVIEW_MAX; ++i) + { + if (gVV[i].flag && gVV[i].px == px) + { + if (gVV[i].value < 0 && value < 0) + break; + + if (gVV[i].value > 0 && value > 0) + break; + } + } + + if (i == VALUEVIEW_MAX) + { + index = gVVIndex++; + + if (gVVIndex == VALUEVIEW_MAX) + gVVIndex = 0; + + gVV[index].count = 0; + gVV[index].offset_y = 0; + gVV[index].value = value; + } + else + { + index = i; + + gVV[index].count = 32; + gVV[index].value += value; + value = gVV[index].value; + } + + // Get if negative or not + if (value < 0) + { + value *= -1; + minus = TRUE; + } + else + { + minus = FALSE; + } + + // Get width + v = value; + + int width; + + if (value > 999) + width = 40; + else if (value > 99) + width = 32; + else if (value > 9) + width = 24; + else + width = 16; + + // Set properties + gVV[index].flag = TRUE; + gVV[index].px = px; + gVV[index].py = py; + gVV[index].rect.left = 40 - width; + gVV[index].rect.top = 8 * index; + gVV[index].rect.right = 40; + gVV[index].rect.bottom = 8 * (index + 1); + + RECT rect[20] = { + {0, 56, 8, 64}, + {8, 56, 16, 64}, + {16, 56, 24, 64}, + {24, 56, 32, 64}, + {32, 56, 40, 64}, + {40, 56, 48, 64}, + {48, 56, 56, 64}, + {56, 56, 64, 64}, + {64, 56, 72, 64}, + {72, 56, 80, 64}, + {0, 64, 8, 72}, + {8, 64, 16, 72}, + {16, 64, 24, 72}, + {24, 64, 32, 72}, + {32, 64, 40, 72}, + {40, 64, 48, 72}, + {48, 64, 56, 72}, + {56, 64, 64, 72}, + {64, 64, 72, 72}, + {72, 64, 80, 72}, + }; + + // Get digits + int dig[4]; + int fig[4]; + dig[0] = 1; + dig[1] = 10; + dig[2] = 100; + dig[3] = 1000; + + for (i = 3; i >= 0; --i) + { + fig[i] = 0; + + while (v >= dig[i]) + { + v -= dig[i]; + ++fig[i]; + } + } + + BOOL sw = FALSE; + + RECT rcPlus = {32, 48, 40, 56}; + RECT rcMinus = {40, 48, 48, 56}; + + // Draw value + CortBox2(&gVV[index].rect, 0x000000, SURFACE_ID_VALUE_VIEW); + + if (minus) + Surface2Surface(gVV[index].rect.left, gVV[index].rect.top, &rcMinus, SURFACE_ID_VALUE_VIEW, SURFACE_ID_TEXT_BOX); + else + Surface2Surface(gVV[index].rect.left, gVV[index].rect.top, &rcPlus, SURFACE_ID_VALUE_VIEW, SURFACE_ID_TEXT_BOX); + + for (i = 3; i >= 0; i--) + { + if (!sw && i != 0 && fig[i] == 0) + continue; + + sw = TRUE; + + if (minus) + fig[i] += 10; + + Surface2Surface(((3 - i) * 8) + 8, gVV[index].rect.top, &rect[fig[i]], SURFACE_ID_VALUE_VIEW, SURFACE_ID_TEXT_BOX); + } +} + +void ActValueView(void) +{ + int v; + + for (v = 0; v < VALUEVIEW_MAX; ++v) + { + if (gVV[v].flag == FALSE) + continue; + + if (++gVV[v].count < 32) + gVV[v].offset_y -= 0x100; + + if (gVV[v].count > 72) + ++gVV[v].rect.top; + + if (gVV[v].count > 80) + gVV[v].flag = FALSE; + } +} + +void PutValueView(int flx, int fly) +{ + int offset_x; + int v; + + for (v = 0; v < VALUEVIEW_MAX; ++v) + { + if (gVV[v].flag == FALSE) + continue; + + offset_x = (gVV[v].rect.right - gVV[v].rect.left) / 2; + + PutBitmap3( + &grcGame, + (*gVV[v].px / 0x200) - offset_x - (flx / 0x200), + (*gVV[v].py / 0x200) + (gVV[v].offset_y / 0x200) - 4 - (fly / 0x200), + &gVV[v].rect, + SURFACE_ID_VALUE_VIEW); + } +} diff --git a/src/ValueView.h b/src/ValueView.h new file mode 100644 index 0000000..7e72a7c --- /dev/null +++ b/src/ValueView.h @@ -0,0 +1,31 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include "WindowsWrapper.h" + +#define VALUEVIEW_MAX 0x10 + +typedef struct VALUEVIEW +{ + BOOL flag; + int *px; + int *py; + int offset_y; + int value; + int count; + RECT rect; +} VALUEVIEW; + +extern VALUEVIEW gVV[VALUEVIEW_MAX]; +extern int gVVIndex; + +void ClearValueView(void); +void SetValueView(int *px, int *py, int value); +void ActValueView(void); +void PutValueView(int flx, int fly); diff --git a/src/WindowsWrapper.h b/src/WindowsWrapper.h new file mode 100644 index 0000000..d9a0302 --- /dev/null +++ b/src/WindowsWrapper.h @@ -0,0 +1,38 @@ +// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. +// +// The original code belongs to Daisuke "Pixel" Amaya. +// +// Modifications and custom code are under the MIT licence. +// See LICENCE.txt for details. + +#pragma once + +#include + +// Visual Studio 6 is missing these, so define them here +#if defined(_MSC_VER) && _MSC_VER <= 1200 + #ifndef VK_OEM_PLUS + #define VK_OEM_PLUS 0xBB + #endif + + #ifndef VK_OEM_COMMA + #define VK_OEM_COMMA 0xBC + #endif + + #ifndef VK_OEM_PERIOD + #define VK_OEM_PERIOD 0xBE + #endif + + #ifndef VK_OEM_2 + #define VK_OEM_2 0xBF + #endif + + #ifndef DWORD_PTR + #define DWORD_PTR DWORD + #endif + + // DLGPROC went from returning BOOL to INT_PTR in later versions, and VC6 doesn't like that + #define DLGPROC_RET BOOL +#else + #define DLGPROC_RET INT_PTR +#endif diff --git a/vs2003/CSE2.sln b/vs2003/CSE2.sln new file mode 100644 index 0000000..6958b47 --- /dev/null +++ b/vs2003/CSE2.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CSE2", "CSE2.vcproj", "{6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Debug (Japanese) = Debug (Japanese) + Release = Release + Release (Japanese) = Release (Japanese) + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Debug.ActiveCfg = Debug|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Debug.Build.0 = Debug|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Debug (Japanese).ActiveCfg = Debug (Japanese)|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Debug (Japanese).Build.0 = Debug (Japanese)|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Release.ActiveCfg = Release|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Release.Build.0 = Release|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Release (Japanese).ActiveCfg = Release (Japanese)|Win32 + {6B8CC57F-5656-4C4B-8FCB-B0C326FCB4D4}.Release (Japanese).Build.0 = Release (Japanese)|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/vs2003/CSE2.vcproj b/vs2003/CSE2.vcproj new file mode 100644 index 0000000..68cf93b --- /dev/null +++ b/vs2003/CSE2.vcproj @@ -0,0 +1,867 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +