release v0.6.2

also contains preset search fix and NDS mem fix
This commit is contained in:
tildearrow 2024-04-01 00:44:42 -05:00
parent 90c628612e
commit 19ed900ef3
25 changed files with 233 additions and 59 deletions

View file

@ -16,7 +16,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_PROJECT_VERSION_MAJOR 0)
set(CMAKE_PROJECT_VERSION_MINOR 6)
set(CMAKE_PROJECT_VERSION_PATCH 1)
set(CMAKE_PROJECT_VERSION_PATCH 2)
set(BUILD_GUI_DEFAULT ON)
set(USE_SDL2_DEFAULT ON)
@ -137,19 +137,20 @@ else()
set(SYSTEM_SDL_MIN_VER 2.0.0)
endif()
if (WIN32)
# support Windows XP
if (SUPPORT_XP)
add_compile_definitions("_WIN32_WINNT=0x0501")
endif()
endif()
#list(APPEND DEPENDENCIES_INCLUDE_DIRS "extern/SAASound/include")
list(APPEND DEPENDENCIES_INCLUDE_DIRS "extern/vgsound_emu-modified")
find_package(Threads REQUIRED)
list(APPEND DEPENDENCIES_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
if (WIN32)
# support Windows XP
if (SUPPORT_XP)
list(APPEND DEPENDENCIES_DEFINES "_WIN32_WINNT=0x0501")
endif()
endif()
if (SYSTEM_FFTW)
find_package(PkgConfig REQUIRED)
pkg_check_modules(FFTW REQUIRED fftw3>=3.3)
@ -1045,7 +1046,6 @@ else()
endif()
target_include_directories(furnace SYSTEM PRIVATE ${DEPENDENCIES_INCLUDE_DIRS})
target_compile_definitions(furnace PRIVATE ${DEPENDENCIES_DEFINES})
target_compile_options(furnace PRIVATE ${DEPENDENCIES_COMPILE_OPTIONS})
target_link_libraries(furnace PRIVATE ${DEPENDENCIES_LIBRARIES})
if (PKG_CONFIG_FOUND AND (SYSTEM_FMT OR SYSTEM_LIBSNDFILE OR SYSTEM_ZLIB OR SYSTEM_SDL2 OR SYSTEM_RTMIDI OR WITH_JACK))
@ -1098,9 +1098,9 @@ if (NOT ANDROID OR TERMUX)
if (WITH_WAVETABLES)
install(DIRECTORY wavetables DESTINATION ${FURNACE_DATADIR})
endif()
add_compile_definitions(FURNACE_DATADIR="${FURNACE_DATADIR}")
list(APPEND DEPENDENCIES_DEFINES FURNACE_DATADIR="${FURNACE_DATADIR}")
if (SHOW_OPEN_ASSETS_MENU_ENTRY)
add_compile_definitions(SHOW_OPEN_ASSETS_MENU_ENTRY)
list(APPEND DEPENDENCIES_DEFINES SHOW_OPEN_ASSETS_MENU_ENTRY)
endif()
endif()
foreach(num 16 32 64 128 256 512)
@ -1131,3 +1131,5 @@ if (NOT ANDROID OR TERMUX)
include(CPack)
endif()
target_compile_definitions(furnace PRIVATE ${DEPENDENCIES_DEFINES})

View file

@ -84,6 +84,10 @@ for other operating systems, you may [build the source](#developer-info).
- **Game Boy**
- including SOFTWARE ENVELOPES (zombie mode)
- Virtual Boy
- Game Boy Advance
- DMA (direct memory access) two channel mode
- MinMod software driver by Natt Akuma
- Nintendo DS
- modern/fantasy:
- Commander X16 VERA
- tildearrow Sound Unit

View file

@ -15,8 +15,8 @@ android {
}
minSdkVersion 21
targetSdkVersion 26
versionCode 192
versionName "0.6.1"
versionCode 197
versionName "0.6.2"
externalNativeBuild {
cmake {
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON"

View file

@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.tildearrow.furnace"
android:versionCode="192"
android:versionName="0.6.1"
android:versionName="0.6.2"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->

View file

@ -76,6 +76,8 @@ the following instrument types are available:
- [C219](c219.md) - for use with C219 sample chip.
- [PowerNoise](powernoise.md) - for use with PowerNoise chip.
- [Dave](dave.md) - for use with Dave chip.
- [Game Boy Advance DMA](gbadma.md) - for use with Game Boy Advance in direct mode.
- [Game Boy Advance MinMod](gbaminmod.md) - for use with Game Boy Advance with the MinMod software mixing driver.
## macros

View file

@ -0,0 +1,17 @@
# GBA DMA instrument editor
the GBA DMA instrument editor contains two tabs: Sample and Macros.
## Sample
for sample settings, see [the Sample instrument editor](sample.md).
## Macros
- **Volume**: volume sequence.
- **Arpeggio**: pitch sequence.
- **Waveform**: waveform sequence.
- **Panning (left)**: output level for left channel.
- **Panning (right)**: output level for right channel.
- **Pitch**: fine pitch.
- **Phase Reset**: trigger restart of waveform.

View file

@ -0,0 +1,18 @@
# GBA MinMod instrument editor
the GBA MinMod instrument editor contains two tabs: Sample and Macros.
## Sample
for sample settings, see [the Sample instrument editor](sample.md).
## Macros
- **Volume**: volume sequence.
- **Arpeggio**: pitch sequence.
- **Waveform**: waveform sequence.
- **Panning (left)**: output level for left channel.
- **Panning (right)**: output level for right channel.
- **Pitch**: fine pitch.
- **Phase Reset**: trigger restart of waveform.
- **Special**: invert outputs.

17
doc/4-instrument/nds.md Normal file
View file

@ -0,0 +1,17 @@
# Nintendo DS instrument editor
the Nintendo DS instrument editor contains two tabs: Sample and Macros.
## Sample
for sample settings, see [the Sample instrument editor](sample.md).
## Macros
- **Volume**: volume sequence.
- **Arpeggio**: pitch sequence.
- **Duty**: pulse width sequence.
- only in PSG channels.
- **Panning**: left/right balance sequence.
- **Pitch**: fine pitch.
- **Phase Reset**: trigger restart of waveform.

View file

@ -73,6 +73,7 @@ this is the full list of chips that Furnace supports.
- [Konami SCC](scc.md)
- [FDS](fds.md)
- [Game Boy](game-boy.md)
- [Game Boy Advance](gba.md)
- [Generic PCM DAC](dac.md)
- [Irem GA20](ga20.md)
- [Bubble System WSG](bubblesystem.md)
@ -86,6 +87,7 @@ this is the full list of chips that Furnace supports.
- [Namco 163](n163.md)
- [Namco C140](c140.md)
- [Namco WSG/C15/C30](namco.md)
- [Nintendo DS](nds.md)
- [HuC6280](pce.md)
- [PC Speaker](pcspkr.md)
- [PET](pet.md)

30
doc/7-systems/gba.md Normal file
View file

@ -0,0 +1,30 @@
# Game Boy Advance
a portable video game console from Nintendo, succeeding the Game Boy.
it adds two stereo sample audio channels which can be used directly ("DMA", left/right) or used in a software mixing driver (most games do this) in order to have multiple voices.
# effects
- `10xx`: **change wave.**
## Game Boy Advance (MinMod)
this is the software mixing driver available in Furnace. it is written by Natt Akuma.
it features echo and up to 16 voices.
- `10xx`: **change wave.**
- `11xy`: **configure echo.**
- this effect is kinda odd. this is how it works:
> How do you echo on GBA
>
> Create an empty instrment and put a very high note of it in channel 1 then do 110x in effect column and set volume column to set feedback and do nothing else on it
- `12xy`: **toggle invert.**
- `x` left channel.
- `y` right channel.
## info
this chip uses the [GBA DMA](../4-instrument/gbadma.md) and [GBA MinMod](../4-instrument/gbaminmod.md) instrument editors.

18
doc/7-systems/nds.md Normal file
View file

@ -0,0 +1,18 @@
# Nintendo DS
this portable video game console succeeded the Game Boy Advance.
it has 16 channels of sampled sound, supporting 8-bit PCM, 16-bit PCM and IMA ADPCM.
additionally, the last 8 channels may be put in "PSG mode", featuring 6 channels of pulse with 8 duty cycles and 2 noise channels.
# effects
- `12xy`: **set duty cycle.**
- `0` to `7`.
- only works in PSG channels.
- `1Fxx`: **set global volume.**
## info
this chip uses the [Nintendo DS](../4-instrument/nds.md) instrument editor.

View file

@ -57,12 +57,14 @@ struct ImGui_ImplDX11_Data
ID3D11Buffer* pVertexConstantBuffer;
ID3D11PixelShader* pPixelShader;
ID3D11SamplerState* pFontSampler;
ID3D11SamplerState* pTexSampler;
ID3D11ShaderResourceView* pFontTextureView;
ID3D11RasterizerState* pRasterizerState;
ID3D11BlendState* pBlendState;
ID3D11DepthStencilState* pDepthStencilState;
int VertexBufferSize;
int IndexBufferSize;
bool SamplersSet;
ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};
@ -109,6 +111,7 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
ctx->PSSetShader(bd->pPixelShader, nullptr, 0);
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
bd->SamplersSet=false;
ctx->GSSetShader(nullptr, nullptr, 0);
ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
@ -283,6 +286,13 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
// Bind texture, Draw
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
if (texture_srv == bd->pFontTextureView && bd->SamplersSet) {
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
bd->SamplersSet=false;
} else if (texture_srv != bd->pFontTextureView && !bd->SamplersSet) {
ctx->PSSetSamplers(0, 1, &bd->pTexSampler);
bd->SamplersSet=true;
}
ctx->PSSetShaderResources(0, 1, &texture_srv);
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
}
@ -376,6 +386,21 @@ static void ImGui_ImplDX11_CreateFontsTexture()
desc.MaxLOD = 0.f;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
}
// Create other sampler
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSampler);
}
}
bool ImGui_ImplDX11_CreateDeviceObjects()
@ -550,6 +575,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects()
return;
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; }
if (bd->pTexSampler) { bd->pTexSampler->Release(); bd->pTexSampler = nullptr; }
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }

View file

@ -6,7 +6,7 @@ when copying pattern data from Furnace, it's stored in the clipboard as plain te
org.tildearrow.furnace - Pattern Data (144)
```
this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6.1 is `192`.
this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6.2 is `197`.
the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from.
- `0`: note.

View file

@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are:
- 197: Furnace 0.6.2
- 192: Furnace 0.6.1
- 181: Furnace 0.6
- 180: Furnace 0.6pre18

View file

@ -15,17 +15,17 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>0.6.1</string>
<string>0.6.2</string>
<key>CFBundleName</key>
<string>Furnace</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6.1</string>
<string>0.6.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.6.1</string>
<string>0.6.2</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>NSHighResolutionCapable</key>

View file

@ -325,7 +325,7 @@ if __name__ == "__main__":
<h1>Furnace<br/>User Manual</h1>
</div>
<div>
<i>for version 0.6.1</i>
<i>for version 0.6.2</i>
</div>
</section>
<section id="authors">
@ -348,7 +348,7 @@ if __name__ == "__main__":
<p>this documentation is under the <a href="https://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported</a> license.</p>
<p>you may reproduce, modify and/or distribute this documentation provided this copyright notice (including license and attribution) is present and any necessary disclaimers whether modifications have been made.</p>
<p>this documentation is provided as-is and without warranty of any kind.</p>
<p>this manual is written for version 0.6.1 of Furnace.<br/>it may not necessarily apply to previous or future versions.</p>
<p>this manual is written for version 0.6.2 of Furnace.<br/>it may not necessarily apply to previous or future versions.</p>
</section>
<section id="index">
%s

View file

@ -18,7 +18,7 @@ if you find issues (e.g. bugs or annoyances), report them. links below.
- discussion: https://github.com/tildearrow/furnace/discussions
- Furnace on Discord: https://discord.gg/EfrwT2wq7z
- Furnace on Revolt: https://rvlt.gg/GRPS6tmc
- online manual: https://tildearrow.org/furnace/doc/v0.6.1/
- online manual: https://tildearrow.org/furnace/doc/v0.6.2/
# notes

View file

@ -28,7 +28,7 @@ if you find issues (e.g. bugs or annoyances), report them. links below.
- discussion: https://github.com/tildearrow/furnace/discussions
- Furnace on Discord: https://discord.gg/EfrwT2wq7z
- Furnace on Revolt: https://rvlt.gg/GRPS6tmc
- online manual: https://tildearrow.org/furnace/doc/v0.6.1/
- online manual: https://tildearrow.org/furnace/doc/v0.6.2/
# notes

View file

@ -18,7 +18,7 @@ if you find issues (e.g. bugs or annoyances), report them. links below.
- discussion: https://github.com/tildearrow/furnace/discussions
- Furnace on Discord: https://discord.gg/EfrwT2wq7z
- Furnace on Revolt: https://rvlt.gg/GRPS6tmc
- online manual: https://tildearrow.org/furnace/doc/v0.6.1/
- online manual: https://tildearrow.org/furnace/doc/v0.6.2/
# notes

View file

@ -54,8 +54,8 @@ class DivWorkPool;
#define DIV_UNSTABLE
#define DIV_VERSION "dev196"
#define DIV_ENGINE_VERSION 196
#define DIV_VERSION "0.6.2"
#define DIV_ENGINE_VERSION 197
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02

View file

@ -565,6 +565,7 @@ void DivPlatformNDS::setFlags(const DivConfig& flags) {
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;
}
memCompo.capacity=(isDSi?16777216:4194304);
}
int DivPlatformNDS::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {

View file

@ -18,7 +18,8 @@
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "dave.hpp"
#include <cmath>
#include <math.h>
#include <stdlib.h>
#define EP128EMU_UNLIKELY(x) x

View file

@ -93,6 +93,26 @@ void FurnaceGUI::drawSysDefs(std::vector<FurnaceGUISysDef>& category, bool& acce
}
}
void findInSubs(std::vector<FurnaceGUISysDef>& where, std::vector<FurnaceGUISysDef>& newSongSearchResults, String lowerCase) {
for (FurnaceGUISysDef& j: where) {
if (!j.orig.empty()) {
String lowerCase1=j.name;
for (char& i: lowerCase1) {
if (i>='A' && i<='Z') i+='a'-'A';
}
auto lastItem=std::remove_if(lowerCase1.begin(),lowerCase1.end(),[](char c) {
return (c==' ' || c=='_' || c=='-');
});
lowerCase1.erase(lastItem,lowerCase1.end());
if (lowerCase1.find(lowerCase)!=String::npos) {
newSongSearchResults.push_back(j);
newSongSearchResults[newSongSearchResults.size()-1].subDefs.clear();
}
}
findInSubs(j.subDefs,newSongSearchResults,lowerCase);
}
}
void FurnaceGUI::drawNewSong() {
bool accepted=false;
std::vector<int> sysDefStack;
@ -121,26 +141,30 @@ void FurnaceGUI::drawNewSong() {
newSongSearchResults.clear();
for (FurnaceGUISysCategory& i: sysCategories) {
for (FurnaceGUISysDef& j: i.systems) {
String lowerCase1=j.name;
for (char& i: lowerCase1) {
if (i>='A' && i<='Z') i+='a'-'A';
}
auto lastItem=std::remove_if(lowerCase1.begin(),lowerCase1.end(),[](char c) {
return (c==' ' || c=='_' || c=='-');
});
lowerCase1.erase(lastItem,lowerCase1.end());
if (lowerCase1.find(lowerCase)!=String::npos) {
newSongSearchResults.push_back(j);
if (!j.orig.empty()) {
String lowerCase1=j.name;
for (char& i: lowerCase1) {
if (i>='A' && i<='Z') i+='a'-'A';
}
auto lastItem=std::remove_if(lowerCase1.begin(),lowerCase1.end(),[](char c) {
return (c==' ' || c=='_' || c=='-');
});
lowerCase1.erase(lastItem,lowerCase1.end());
if (lowerCase1.find(lowerCase)!=String::npos) {
newSongSearchResults.push_back(j);
newSongSearchResults[newSongSearchResults.size()-1].subDefs.clear();
}
}
findInSubs(j.subDefs,newSongSearchResults,lowerCase);
}
std::sort(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
return strcmp(a.name.c_str(),b.name.c_str())<0;
});
auto lastItem=std::unique(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
return a.name==b.name;
});
newSongSearchResults.erase(lastItem,newSongSearchResults.end());
}
std::sort(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
return strcmp(a.name.c_str(),b.name.c_str())<0;
});
auto lastItem1=std::unique(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
return a.name==b.name;
});
newSongSearchResults.erase(lastItem1,newSongSearchResults.end());
}
if (ImGui::BeginTable("sysPicker",newSongQuery.empty()?2:1,ImGuiTableFlags_BordersInnerV)) {
if (newSongQuery.empty()) {

View file

@ -2430,8 +2430,10 @@ void FurnaceGUI::initSystemPresets() {
);
CATEGORY_END;
/*
CATEGORY_BEGIN("User","system presets that you have saved.");
CATEGORY_END;
*/
CATEGORY_BEGIN("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels).");
ENTRY(
@ -2837,7 +2839,7 @@ void FurnaceGUI::initSystemPresets() {
}
);
ENTRY(
"NDS", {
"Nintendo DS", {
CH(DIV_SYSTEM_NDS, 1.0f, 0, "")
}
);

View file

@ -26,7 +26,10 @@
#define TS FurnaceGUITutorialStep
#ifndef _WIN32
#ifdef _WIN32
#include <windows.h>
#include "../utfutils.h"
#else
#include <dirent.h>
#endif
@ -482,8 +485,8 @@ struct FurnaceCV {
static const char* cvText[]={
// intro
"Play demo songs?\n"
"- Down: no\n"
"- Up: yes",
"- Down: Play current song\n"
"- Up: Play demo songs",
"Well, well, well. You wanna\n"
"enable Serious Mode, right?\n",
@ -495,7 +498,8 @@ static const char* cvText[]={
"April 1st\n",
"The plot is left\n"
"as an exercise for the player.",
"as an exercise for the player.\n\n"
"X - Shoot Arrow Key - Move",
"GAME OVER",
@ -795,15 +799,18 @@ void FurnaceGUI::initRandomDemoSong() {
#ifdef _WIN32
WIN32_FIND_DATAW de;
demoPath+=DIR_SEPARATOR_STR;
HANDLE d=FindFirstFileW(utf8To16(demoPath.c_str()).c_str(),&de);
String realDemoPath=demoPath;
realDemoPath+=DIR_SEPARATOR_STR;
realDemoPath+="*";
HANDLE d=FindFirstFileW(utf8To16(realDemoPath.c_str()).c_str(),&de);
if (d==INVALID_HANDLE_VALUE) {
demoPath="..";
demoPath+=DIR_SEPARATOR_STR;
demoPath+="demos";
demoPath+=DIR_SEPARATOR_STR;
realDemoPath="..";
realDemoPath+=DIR_SEPARATOR_STR;
realDemoPath+="demos";
realDemoPath+=DIR_SEPARATOR_STR;
realDemoPath+="*";
logW("OH NO");
HANDLE d=FindFirstFileW(utf8To16(demoPath.c_str()).c_str(),&de);
HANDLE d=FindFirstFileW(utf8To16(realDemoPath.c_str()).c_str(),&de);
if (d==INVALID_HANDLE_VALUE) {
logW("dang it");
return;
@ -866,13 +873,14 @@ void FurnaceGUI::initRandomDemoSong() {
for (String& i: subDirs) {
#ifdef _WIN32
WIN32_FIND_DATAW de1;
i+=DIR_SEPARATOR_STR;
i+="*.fur";
HANDLE d1=FindFirstFileW(utf8To16(i.c_str()).c_str(),&de1);
String realI=i;
realI+=DIR_SEPARATOR_STR;
realI+="*.fur";
HANDLE d1=FindFirstFileW(utf8To16(realI.c_str()).c_str(),&de1);
if (d1==INVALID_HANDLE_VALUE) continue;
do {
String u8Name=utf16To8(de.cFileName);
String newPath=demoPath;
String newPath=i;
newPath+=DIR_SEPARATOR_STR;
newPath+=u8Name;
randomDemoSong.push_back(newPath);
@ -1983,6 +1991,7 @@ void FurnaceCVPlayer::collision(FurnaceCVObject* other) {
if (!invincible) {
dead=true;
cv->respawnTime=48;
cv->shotType=0;
cv->soundEffect(SE_DEATH_C1);
cv->soundEffect(SE_DEATH_C2);
cv->createObject<FurnaceCVExplMedium>(x-8,y);