Add RepeatingSoundEffect class to allow easy creation and handling of looping sound effects ingame. Add rock breaking, rock toss cast, pillar rise, dig sound effects. Fix typo on Hawk Feather item description key name. Placeholder item icons added. Add sound effects to Stone Elemental's attacks. Release Build 9656.

mac-build
sigonasr2 7 months ago
parent 3c48951bc4
commit 9f88460c0e
  1. 1
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 6
      Adventures in Lestoria/Attributable.h
  3. 2
      Adventures in Lestoria/DEFINES.h
  4. 3
      Adventures in Lestoria/LargeStone.cpp
  5. 5
      Adventures in Lestoria/Monster.cpp
  6. 3
      Adventures in Lestoria/MonsterAttribute.h
  7. 53
      Adventures in Lestoria/SoundEffect.cpp
  8. 14
      Adventures in Lestoria/SoundEffect.h
  9. 7
      Adventures in Lestoria/StoneGolem.cpp
  10. 14
      Adventures in Lestoria/Stone_Elemental.cpp
  11. 2
      Adventures in Lestoria/Version.h
  12. 36
      Adventures in Lestoria/assets/config/audio/events.txt
  13. 2
      Adventures in Lestoria/assets/config/items/ItemDatabase.txt
  14. BIN
      Adventures in Lestoria/assets/gamepack.pak
  15. BIN
      Adventures in Lestoria/assets/items/Bird's Treasure.png
  16. BIN
      Adventures in Lestoria/assets/items/Blackpowder.png
  17. BIN
      Adventures in Lestoria/assets/items/Boar Meat.png
  18. BIN
      Adventures in Lestoria/assets/items/Broken Bow.png
  19. BIN
      Adventures in Lestoria/assets/items/Broken Dagger.png
  20. BIN
      Adventures in Lestoria/assets/items/Hawk Feather.png
  21. BIN
      Adventures in Lestoria/assets/items/Stone Heart.png
  22. BIN
      Adventures in Lestoria/assets/items/Stone Ring.png
  23. BIN
      Adventures in Lestoria/assets/sounds/dig.ogg
  24. BIN
      Adventures in Lestoria/assets/sounds/pillar_rise.ogg
  25. BIN
      Adventures in Lestoria/assets/sounds/rise.ogg
  26. BIN
      Adventures in Lestoria/assets/sounds/rockbreak.ogg
  27. BIN
      Adventures in Lestoria/assets/sounds/rocktosscast.ogg
  28. BIN
      x64/Release/Adventures in Lestoria.exe

@ -2290,6 +2290,7 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){
ItemDrop::drops.clear();
GameEvent::events.clear();
Audio::SetBGMPitch(1.f);
RepeatingSoundEffect::StopAllSounds();
#ifdef __EMSCRIPTEN__
Audio::muted=true;
Audio::UpdateBGMVolume();

@ -80,4 +80,10 @@ public:
}
return std::get<std::vector<std::any>>(attributes[a]);
};
inline size_t&GetSizeT(Attribute a){
if(attributes.count(a)==0){
attributes[a]=size_t(0);
}
return std::get<size_t>(attributes[a]);
};
};

@ -72,7 +72,7 @@ using MonsterSpawnerID=int;
#define ACCESS_PLAYER Player*p=game->GetPlayer();
#define VARIANTS float,int,std::string,bool,vf2d,std::vector<std::any>
#define VARIANTS float,int,std::string,bool,vf2d,std::vector<std::any>,size_t
#undef INFINITE
#define INFINITE 999999

@ -40,6 +40,7 @@ All rights reserved.
#include "AdventuresInLestoria.h"
#include "FallingDebris.h"
#include "util.h"
#include "SoundEffect.h"
INCLUDE_game
INCLUDE_MONSTER_LIST
@ -82,6 +83,8 @@ void LargeStone::Update(float fElapsedTime){
#pragma endregion
fadeOutTime=0.5f;
SoundEffect::PlaySFX("Large Rock Break",pos);
}else
if(z>0.f&&fadeOutTime>=0.f){
pos=startingPos.lerp(landingPos,(GetTimeAlive()-initialMoveWaitTime)/stoneThrowTime);

@ -823,6 +823,11 @@ std::map<ItemInfo*,uint16_t>Monster::SpawnDrops(){
void Monster::OnDeath(){
animation.ChangeState(internal_animState,GetDeathAnimationName());
if(GetSizeT(Attribute::LOOPING_SOUND_ID)!=std::numeric_limits<size_t>::max()){//Just make sure on death any looping sound effect has been discarded proper.
SoundEffect::StopLoopingSFX(GetSizeT(Attribute::LOOPING_SOUND_ID));
GetSizeT(Attribute::LOOPING_SOUND_ID)=std::numeric_limits<size_t>::max();
}
if(HasMountedMonster()){
for(DeathSpawnInfo&deathInfo:deathData){
deathInfo.Spawn(GetPos(),OnUpperLevel());

@ -39,6 +39,7 @@ All rights reserved.
#include <string>
#define F(attr) GetFloat(attr)
#define I(attr) GetInt(attr)
#define SIZET(attr) GetSizeT(attr)
#define S(attr) GetString(attr)
#define B(attr) GetBool(attr)
#define V(attr) GetVf2d(attr)
@ -121,4 +122,6 @@ enum class Attribute{
WIND_STRENGTH,
WIND_PHASE_TIMER,
MARKED_DEAD,
LOOPING_SOUND_ID,
PLAYED_FLAG,
};

@ -48,6 +48,15 @@ INCLUDE_game
std::multimap<EventName,SoundEffect>SoundEffect::SOUND_EFFECTS;
const vf2d SoundEffect::CENTERED={-8419.f,-3289.f};
std::unordered_set<size_t>RepeatingSoundEffect::playingSoundEffects;
void RepeatingSoundEffect::StopAllSounds(){
for(auto&id:playingSoundEffects){
Audio::Engine().Stop(id);
Audio::Engine().UnloadSound(id);
}
playingSoundEffects.clear();
}
SoundEffect::SoundEffect(const std::string_view filename,const float&vol,const float&minPitch,const float&maxPitch,const bool combatSound)
:filename(filename),vol(vol),minPitch(minPitch),maxPitch(maxPitch),combatSound(combatSound){
@ -79,18 +88,7 @@ void SoundEffect::Initialize(){
void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){
if(eventName.length()==0)return;
auto itr=SOUND_EFFECTS.equal_range(std::string(eventName));
size_t soundCount=std::distance(itr.first,itr.second);
if(soundCount==0)ERR("WARNING! Sound Effect "<<std::quoted(eventName)<<" does not have any sound effects loaded/doesn't exist!")
size_t soundEffectChoice=util::random()%soundCount;
int counter=0;
auto it=itr.first;
while(counter!=soundEffectChoice){
++counter;
++it;
}
const SoundEffect&sfx=(*it).second;
const SoundEffect&sfx=GetRandomSFXFromFile(eventName);
if(GameState::STATE==GameState::states[States::MAIN_MENU]&&sfx.combatSound)return; //Do not play combat sounds on the main menu.
@ -112,4 +110,35 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){
Audio::Engine().Play(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()),vol,pan,pitch);
}
}
}
size_t SoundEffect::PlayLoopingSFX(const std::string_view eventName,const vf2d&pos){
const SoundEffect&sfx=GetRandomSFXFromFile(eventName);
const size_t id=Audio::Engine().LoadSound(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()));
RepeatingSoundEffect::playingSoundEffects.insert(id);
Audio::Engine().Play(id,true);
return id;
}
void SoundEffect::StopLoopingSFX(const int id){
if(!RepeatingSoundEffect::playingSoundEffects.count(id))return; //Prevent crashes from stopping a sound more than once. Called by accident probably.
Audio::Engine().Stop(id);
Audio::Engine().UnloadSound(id);
RepeatingSoundEffect::playingSoundEffects.erase(id);
}
SoundEffect&SoundEffect::GetRandomSFXFromFile(const std::string_view eventName){
auto itr=SOUND_EFFECTS.equal_range(std::string(eventName));
size_t soundCount=std::distance(itr.first,itr.second);
if(soundCount==0)ERR("WARNING! Sound Effect "<<std::quoted(eventName)<<" does not have any sound effects loaded/doesn't exist!")
size_t soundEffectChoice=util::random()%soundCount;
int counter=0;
auto it=itr.first;
while(counter!=soundEffectChoice){
++counter;
++it;
}
return (*it).second;
}

@ -38,18 +38,30 @@ All rights reserved.
#pragma once
#include <string>
#include <map>
#include <unordered_set>
#include "Error.h"
using EventName=std::string;
class RepeatingSoundEffect{
friend class AiL;
friend class SoundEffect;
private:
static void StopAllSounds();
static std::unordered_set<size_t>playingSoundEffects;
};
class SoundEffect{
public:
SoundEffect(const std::string_view filename,const float&vol,const float&minPitch=0.9f,const float&maxPitch=1.1f,const bool combatSound=false);
static void PlaySFX(const std::string_view eventName,const vf2d&pos);
//Sets up a sound to be looped continuously.
static size_t PlayLoopingSFX(const std::string_view eventName,const vf2d&pos);
static void StopLoopingSFX(const int id);
static void Initialize();
static const vf2d CENTERED;
private:
static SoundEffect&GetRandomSFXFromFile(const std::string_view eventName);
static std::multimap<EventName,SoundEffect>SOUND_EFFECTS;
std::string filename;
float vol;

@ -42,6 +42,7 @@ All rights reserved.
#include "DEFINES.h"
#include "util.h"
#include "BulletTypes.h"
#include "SoundEffect.h"
INCLUDE_game
@ -67,6 +68,7 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
m.F(A::RECOVERY_TIME)-=fElapsedTime;
if(m.F(A::RECOVERY_TIME)<=0.f){
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
m.SIZET(A::LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos());
m.PerformAnimation("CAST",m.GetFacingDirectionToTarget(m.V(A::LOCKON_POS)));
game->AddEffect(std::make_unique<SpellCircle>(m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Insignia Rotation Spd"))),true);
m.F(A::CASTING_TIMER)=ConfigFloat("Beginning Phase.Pillar Cast Time");
@ -76,6 +78,8 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
case SPAWN_PILLAR_CAST:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)<=0.f){
SoundEffect::StopLoopingSFX(m.SIZET(A::LOOPING_SOUND_ID));
SoundEffect::PlaySFX("Pillar Rise",m.V(A::LOCKON_POS));
m.I(A::PATTERN_REPEAT_COUNT)--;
game->SpawnMonster(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Golem Pillar"),m.OnUpperLevel());
game->Hurt(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult(),MONSTER_DATA.at("Stone Golem Pillar").GetAttack(),m.OnUpperLevel(),0.f,HurtType::PLAYER);
@ -107,6 +111,8 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
//Physics!! Kinematic equation from https://openstax.org/books/physics/pages/3-2-representing-acceleration-with-equations-and-graphs a=(2d)/(t^2)
const float acc{(2*-ConfigFloat("Standard Attack.Stone Throw Height Offset"))/std::pow(stoneTossTime,2.f)};
m.SIZET(A::LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos());
CreateBullet(LargeStone)(m.GetPos()+vf2d{0,ConfigFloat("Standard Attack.Stone Throw Height Offset")/2.f},ConfigFloat("Standard Attack.Stone Throw Time"),m.V(A::LOCKON_POS),m.F(A::CASTING_TIMER),ConfigPixels("Standard Attack.Stone Radius"),ConfigFloat("Standard Attack.Stone Throw Height Offset"),acc,ConfigInt("Standard Attack.Stone Damage"),ConfigFloat("Standard Attack.Stone Throw Knockback Factor"),m.OnUpperLevel(),false,INFINITY,false,WHITE,vf2d{1,1}*m.GetSizeMult(),util::random(2*PI))EndBullet;
}
}
@ -114,6 +120,7 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
case STONE_THROW_CAST:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)<=0.f){
SoundEffect::StopLoopingSFX(m.SIZET(A::LOOPING_SOUND_ID));
m.PerformAnimation("TOSS ROCK");
m.F(A::RECOVERY_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration();
m.phase=STONE_THROW_FINISH_ANIMATION;

@ -41,6 +41,7 @@ All rights reserved.
#include "MonsterStrategyHelpers.h"
#include "BulletTypes.h"
#include "util.h"
#include "SoundEffect.h"
INCLUDE_game
INCLUDE_BULLET_LIST
@ -93,6 +94,7 @@ void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string
switch(randomAttackChoice){
case 0:{
m.PerformAnimation("STONE PILLAR CAST");
m.SIZET(A::LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos());
m.phase=STONE_PILLAR_CAST;
m.F(A::CASTING_TIMER)=ConfigFloat("Stone Pillar Cast Time");
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
@ -100,7 +102,9 @@ void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string
}break;
case 1:{
m.PerformAnimation("ROCK TOSS CAST");
m.SIZET(A::LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos());
m.phase=SHOOT_STONE_CAST;
m.B(A::PLAYED_FLAG)=false;
m.F(A::CASTING_TIMER)=ConfigFloat("Rock Toss Track Time")+ConfigFloat("Rock Toss Wait Time");
CreateBullet(LevitatingRock)(m,game->GetPlayer()->GetPos(),1.f,0.f,ConfigPixels("Rock Toss Max Spawn Distance"),ConfigFloat("Rock Toss Track Time"),ConfigFloat("Rock Toss Wait Time"),ConfigFloat("Rock Toss Bullet Speed"),ConfigFloat("Rock Radius"),std::max(1,ConfigInt("Rock Toss Damage")/5),m.OnUpperLevel(),false,WHITE,vf2d{1,1})EndBullet;
const int masterRockInd=BULLET_LIST.size()-1;
@ -115,6 +119,7 @@ void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string
}
}break;
case 2:{
SoundEffect::PlaySFX("Dig",m.GetPos());
m.PerformAnimation("BURROW UNDERGROUND");
m.phase=DIVE_UNDERGROUND_DIG;
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration();
@ -125,6 +130,8 @@ void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string
case STONE_PILLAR_CAST:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)<=0.f){
SoundEffect::StopLoopingSFX(m.SIZET(A::LOOPING_SOUND_ID));
SoundEffect::PlaySFX("Pillar Rise",m.V(A::LOCKON_POS));
game->SpawnMonster(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Pillar"),m.OnUpperLevel());
ReturnToWaitingPhase();
game->Hurt(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Pillar").GetSizeMult(),m.GetAttack(),m.OnUpperLevel(),0.f,HurtType::PLAYER);
@ -141,10 +148,16 @@ void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string
case SHOOT_STONE_CAST:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)>=ConfigFloat("Rock Toss Wait Time")-ConfigFloat("Rock Toss Track Time")){
SoundEffect::StopLoopingSFX(m.SIZET(A::LOOPING_SOUND_ID));
m.PerformAnimation("STONE PILLAR CAST");
m.UpdateFacingDirection(game->GetPlayer()->GetPos());
}
if(m.F(A::CASTING_TIMER)>=ConfigFloat("Rock Toss Track Time")&&!m.B(A::PLAYED_FLAG)){
SoundEffect::PlaySFX("Rock Break",m.GetPos());
m.B(A::PLAYED_FLAG)=true;
}
if(m.F(A::CASTING_TIMER)<=0.f){
SoundEffect::StopLoopingSFX(m.SIZET(A::LOOPING_SOUND_ID));
ReturnToWaitingPhase();
}
}break;
@ -180,6 +193,7 @@ void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string
if(m.F(A::CASTING_TIMER)<=0.f){
m.B(A::IGNORE_DEFAULT_ANIMATIONS)=false;
SoundEffect::PlaySFX("Rise",m.GetPos());
m.PerformAnimation("RISE FROM UNDERGROUND");
m.phase=DIVE_UNDERGROUND_SURFACE;
m.targetAcquireTimer=0;

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 3
#define VERSION_BUILD 9648
#define VERSION_BUILD 9656
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -49,6 +49,12 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = craft_equip.ogg, 70%
}
Dig
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = dig.ogg, 100%
}
Equip Armor
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
@ -115,6 +121,12 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = item_collect.ogg, 40%
}
Large Rock Break
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = rockbreak.ogg, 90%, 40%, 50%
}
Level Up
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
@ -138,6 +150,12 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = monster_hurt.ogg, 40%
}
Pillar Rise
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = pillar_rise.ogg, 90%
}
Player Hit
{
CombatSound = True
@ -176,6 +194,24 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = ranger_charged_shot.ogg, 70%
}
Rise
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = rise.ogg, 100%
}
Rock Break
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = rockbreak.ogg, 90%
}
Rock Toss Cast
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = rocktosscast.ogg, 100%
}
Slime Dead
{
CombatSound = True

@ -228,7 +228,7 @@ ItemDatabase
}
Hawk Feather
{
Desciption = A Feather of a Hawk. Sadly no longer in perfect condition.
Description = A Feather of a Hawk. Sadly no longer in perfect condition.
ItemCategory = Materials
SellValue = 7
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

Loading…
Cancel
Save