diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index f2fc73c0..fbc3dcfc 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -408,6 +408,10 @@
+
+
+
+
@@ -836,6 +840,10 @@
+
+
+
+
@@ -1086,6 +1094,10 @@
+
+
+
+
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
index 5f4a2ef0..a477eff6 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
@@ -711,6 +711,9 @@
Header Files\Utils
+
+ Header Files\Utils
+
@@ -1274,6 +1277,12 @@
Source Files\Bullet Types
+
+ Source Files\Utils
+
+
+ Source Files\Bullet Types
+
diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp
index 8fa6ab7c..17fd5ae4 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.cpp
+++ b/Adventures in Lestoria/AdventuresInLestoria.cpp
@@ -100,7 +100,7 @@ safemapANIMATION_DATA;
std::vector>MONSTER_LIST;
std::unordered_mapSPAWNER_LIST;
std::vector>DAMAGENUMBER_LIST;
-std::vector>BULLET_LIST;
+std::vector>BULLET_LIST{MAX_BULLETS};
std::optional>SPAWNER_CONTROLLER;
safemapGFX;
utils::datafile DATA;
@@ -816,6 +816,7 @@ void AiL::UpdateBullets(float fElapsedTime){
IBullet*b=(*it).get();
b->_Update(fElapsedTime);
}
+ if(BULLET_LIST.size()>MAX_BULLETS)ERR(std::format("WARNING! Bullet list reached greater than maximum expected size: {}. Consider expanding!!!",MAX_BULLETS));
std::erase_if(BULLET_LIST,[](std::unique_ptr&b){return b->IsDead();});
}
diff --git a/Adventures in Lestoria/Animation.cpp b/Adventures in Lestoria/Animation.cpp
index 2b51a013..47b2181c 100644
--- a/Adventures in Lestoria/Animation.cpp
+++ b/Adventures in Lestoria/Animation.cpp
@@ -465,6 +465,8 @@ void sig::Animation::InitializeAnimations(){
CreateHorizontalAnimationSequence("portal.png",8,{24,24},AnimationData{.frameDuration{0.1f},.style{Animate2D::Style::Repeat}});
+ CreateHorizontalAnimationSequence("burstbullet.png",4,{24,24},AnimationData{.frameDuration{0.1f},.style{Animate2D::Style::OneShot}});
+
//!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//DO NOT CREATE MORE ANIMATION SEQUENCES UNDERNEATH HERE AS THE NEXT BLOCK WILL CREATE DEFAULT ANIMATIONS
//FOR ALL NON-SPECIFIED ANIMATION SEQUENCES!
diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h
index c61c0249..b40f7fa4 100644
--- a/Adventures in Lestoria/BulletTypes.h
+++ b/Adventures in Lestoria/BulletTypes.h
@@ -40,6 +40,8 @@ All rights reserved.
#include "Direction.h"
#include "Effect.h"
#include "TrailEffect.h"
+#include "Entity.h"
+#include
struct EnergyBolt:public Bullet{
float lastParticleSpawn=0;
@@ -383,11 +385,33 @@ private:
};
struct BurstBullet:public Bullet{
- BurstBullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col);
+ BurstBullet(vf2d pos,vf2d vel,const Entity target,const float explodeDist,const int extraBulletCount,const float extraBulletHeadingAngleChange,const float extraBulletRadius,const vf2d extraBulletScale,const float extraBulletStartSpeed,const float extraBulletAcc,float radius,int damage,bool upperLevel,bool friendly,Pixel col,vf2d scale);
+ void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(HurtDamageInfo&data);
private:
- const float bounceExplodeRadius;
- int additionalBounceCount;
+ void Explode();
+ const Entity target;
+ const float explodeDist;
+ OscillatorscaleOscillator;
+ bool activated{false};
+ float explodeTimer{0.f};
+ const int extraBulletCount;
+ const float extraBulletHeadingAngleChange; //In radians.
+ const float extraBulletRadius;
+ const vf2d extraBulletScale;
+ const float extraBulletAcc;
+ const float extraBulletStartSpeed;
+};
+
+struct RotateBullet:public Bullet{
+ //headingAngleChange determines how the startingAngle adjusts over time (in radians).
+ RotateBullet(vf2d pos,float startingAng,float startSpeed,float acc,float headingAngleChange,float radius,int damage,bool upperLevel,bool friendly,Pixel col);
+ void Update(float fElapsedTime)override;
+ BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
+ BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
+ void ModifyOutgoingDamageData(HurtDamageInfo&data);
+private:
+ const float headingAngleChange;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/BurstBullet.cpp b/Adventures in Lestoria/BurstBullet.cpp
index 01c16283..d336ba78 100644
--- a/Adventures in Lestoria/BurstBullet.cpp
+++ b/Adventures in Lestoria/BurstBullet.cpp
@@ -42,69 +42,61 @@ All rights reserved.
#include "util.h"
#include "SoundEffect.h"
#include "TrailEffect.h"
+#include
INCLUDE_game
INCLUDE_MONSTER_LIST
+INCLUDE_ANIMATION_DATA
-BurstBullet::BurstBullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
- :Bullet(pos,vel,radius,damage,"energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){
- if(game->GetPlayer()->HasEnchant("Trail of Fire"))flameTrail=dynamic_cast(game->AddEffect(std::make_unique(pos,"Trail of Fire"_ENC["TRAIL DURATION"],"FlamesTexture.png","Trail of Fire"_ENC["TRAIL DAMAGE"]/100.f*game->GetPlayer()->GetAttack(),"Trail of Fire"_ENC["TRAIL TICK FREQUENCY"],upperLevel,1.f,vf2d{1.f,2.f},30000.f,Oscillator{{255,0,0,128},Pixel(0xE74F30),2.f},EffectType::TRAIL_OF_FIRE,true),true));
+BurstBullet::BurstBullet(vf2d pos,vf2d vel,const Entity target,const float explodeDist,const int extraBulletCount,const float extraBulletHeadingAngleChange,const float extraBulletRadius,const vf2d extraBulletScale,const float extraBulletStartSpeed,const float extraBulletAcc,float radius,int damage,bool upperLevel,bool friendly,Pixel col,vf2d scale)
+ :Bullet(pos,vel,radius,damage,"burstrotatebullet.png",upperLevel,false,INFINITE,true,friendly,col,scale),extraBulletStartSpeed(extraBulletStartSpeed),extraBulletAcc(extraBulletAcc),extraBulletRadius(extraBulletRadius),extraBulletScale(extraBulletScale),extraBulletHeadingAngleChange(extraBulletHeadingAngleChange),extraBulletCount(extraBulletCount),target(target),explodeDist(explodeDist),scaleOscillator({0.85f,0.85f},{1.f,1.f},0.3f){
+ animation.mult=0.f; //Prevent animating.
}
-void BurstBullet::Update(float fElapsedTime){
- lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
- if(lastParticleSpawn==0){
- lastParticleSpawn="Wizard.Ability 1.ParticleFrequency"_F;
- game->AddEffect(std::make_unique(pos,"Wizard.Ability 1.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Ability 1.ParticleSizeRange"_FRange,"Wizard.Ability 1.ParticleFadeoutTime"_F,vf2d{"Wizard.Ability 1.ParticleXSpeedRange"_FRange,"Wizard.Ability 1.ParticleYSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.ParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.ParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.ParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.ParticleAlphaRange"_FRange)}));
- }
- if(distanceTraveled>"Wizard.Ability 1.Max Range"_F&&IsActivated()){
- fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
- for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
- game->AddEffect(std::make_unique(pos,"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
+void BurstBullet::Explode(){
+ fadeOutTime=0.1f;
+ HurtType targets{friendly?HurtType::MONSTER:HurtType::PLAYER};
+ for(const auto&[target,isHurt]:game->Hurt(pos,radius,damage,OnUpperLevel(),GetZ(),targets)){
+ if(isHurt){
+ Entity ent{target};
+ ent.SetIframeTime(0.3f);
}
- game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);
- if(friendly){
- game->Hurt(pos,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,int("Wizard.Ability 1.BulletHitExplosionDamageMult"_F*game->GetPlayer()->GetAttack()),OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY);
- }else{
- if(geom2d::overlaps(geom2d::circle{pos,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12},geom2d::circle{game->GetPlayer()->GetPos(),12.f})){
- game->GetPlayer()->Hurt(damage,OnUpperLevel(),0.f);
+ }
+ SoundEffect::PlaySFX("Burst Bullet Explode",pos);
+ for(int i:std::ranges::iota_view(0,extraBulletCount)){
+ const float angle{(360.f/extraBulletCount)*i};
+ const vf2d newPos{pos+vf2d{radius/2.f,angle}.cart()};
+ CreateBullet(RotateBullet)(newPos,angle,extraBulletStartSpeed,extraBulletAcc,extraBulletHeadingAngleChange,extraBulletRadius,damage,OnUpperLevel(),friendly,WHITE)EndBullet;
+ }
+ Deactivate();
+}
+
+void BurstBullet::Update(float fElapsedTime){
+ if(IsActivated()){
+ if(!activated){
+ scaleOscillator.Update(fElapsedTime);
+ if(util::distance(target.GetPos(),pos)<=explodeDist){
+ activated=true;
+ animation.mult=1.f;
+ explodeTimer=ANIMATION_DATA[animation.currentStateName].GetTotalAnimationDuration();
}
+ }else if(explodeTimer>0.f){
+ explodeTimer-=fElapsedTime;
+ if(explodeTimer<=0.f)Explode();
}
- game->AddEffect(std::make_unique(pos,0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel));
-
- SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
}
-
- if(flameTrail)flameTrail.value().get().SetEndPos(pos);
}
-BulletDestroyState BurstBullet::PlayerHit(Player*player)
-{
- fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
- for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
- game->AddEffect(std::make_unique(player->GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
-
- game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);}
- game->AddEffect(std::make_unique(player->GetPos(),0,"splash_effect.png",upperLevel,5,0.25,vf2d{},Pixel{240,120,60}));
-
- SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
+BulletDestroyState BurstBullet::PlayerHit(Player*player){
+ Explode();
return BulletDestroyState::KEEP_ALIVE;
}
-BulletDestroyState BurstBullet::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
-{
- fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
- for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
- game->AddEffect(std::make_unique(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
- }
- game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);
- game->Hurt(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,int("Wizard.Ability 1.BulletHitExplosionDamageMult"_F*game->GetPlayer()->GetAttack()),OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY);
- game->AddEffect(std::make_unique(monster.GetPos(),0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel));
-
- SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
+BulletDestroyState BurstBullet::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
+ Explode();
return BulletDestroyState::KEEP_ALIVE;
}
void BurstBullet::ModifyOutgoingDamageData(HurtDamageInfo&data){
- if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
+ data.damage=0; //Nullify the damage because proximity damage will occur instead.
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/DEFINES.h b/Adventures in Lestoria/DEFINES.h
index 273591ac..f11f5ec1 100644
--- a/Adventures in Lestoria/DEFINES.h
+++ b/Adventures in Lestoria/DEFINES.h
@@ -81,6 +81,8 @@ using MonsterSpawnerID=int;
#undef INFINITE
#define INFINITE 999999
+#define MAX_BULLETS size_t(512)
+
#define SETUP_CLASS(class) \
class::class() \
:Player::Player(){} \
diff --git a/Adventures in Lestoria/Entity.cpp b/Adventures in Lestoria/Entity.cpp
new file mode 100644
index 00000000..42af04b7
--- /dev/null
+++ b/Adventures in Lestoria/Entity.cpp
@@ -0,0 +1,57 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+
+#include "Entity.h"
+#include "Player.h"
+
+#define is(type) std::holds_alternative(entity)
+#define get(type) std::get(entity)
+
+Entity::Entity(Player*player):entity(player){}
+Entity::Entity(Monster*monster):entity(monster){}
+Entity::Entity(const std::variantent):entity(ent){}
+
+const vf2d Entity::GetPos()const{
+ if(is(Player*))return get(Player*)->GetPos();
+ if(is(Monster*))return get(Monster*)->GetPos();
+}
+
+void Entity::SetIframeTime(const float iframeTime){
+ if(is(Player*))get(Player*)->ApplyIframes(iframeTime);
+ else if(is(Monster*))get(Monster*)->ApplyIframes(iframeTime);
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Entity.h b/Adventures in Lestoria/Entity.h
new file mode 100644
index 00000000..afe5e0b3
--- /dev/null
+++ b/Adventures in Lestoria/Entity.h
@@ -0,0 +1,56 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#pragma once
+
+#include "olcUTIL_Geometry2D.h"
+#include
+
+class Player;
+class Monster;
+
+//A helper class to connect multiple entity types based on their commonalities without using inheritance shenanigans.
+class Entity{
+public:
+ Entity(Player*player);
+ Entity(Monster*monster);
+ Entity(const std::variantent);
+ const vf2d GetPos()const;
+ void SetIframeTime(const float iframeTime);
+private:
+ const std::variantentity;
+};
\ No newline at end of file
diff --git a/Adventures in Lestoria/GiantOctopus.cpp b/Adventures in Lestoria/GiantOctopus.cpp
index 3721e335..ea37e076 100644
--- a/Adventures in Lestoria/GiantOctopus.cpp
+++ b/Adventures in Lestoria/GiantOctopus.cpp
@@ -135,12 +135,15 @@ void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string s
}
if(m.F(A::SHOOT_TIMER)<=0.f){
if(m.I(A::ATTACK_COUNT)>=ConfigInt("Big Bullet Frequency")-1){
- CreateBullet(Bullet)(m.GetPos(),util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Big Bullet Speed"),ConfigFloat("Big Bullet Radius")*1.5f,ConfigFloat("Big Bullet Damage"),m.OnUpperLevel(),false,ConfigPixel("Big Bullet Color"),{ConfigFloat("Big Bullet Radius"),ConfigFloat("Big Bullet Radius")})EndBullet;
+ CreateBullet(BurstBullet)(m.GetPos(),util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Big Bullet Speed"),game->GetPlayer(),ConfigPixels("Big Bullet Detection Radius"),ConfigInt("Big Bullet Extra Bullet Count"),util::degToRad(ConfigFloat("Big Bullet Extra Bullet Rotate Speed")),ConfigFloat("Big Bullet Extra Bullet Radius"),vf2d{ConfigFloatArr("Big Bullet Extra Bullet Image Scale",0),ConfigFloatArr("Big Bullet Extra Bullet Image Scale",1)},ConfigFloat("Big Bullet Extra Bullet Speed"),ConfigFloat("Big Bullet Extra Bullet Acceleration"),ConfigFloat("Big Bullet Radius"),ConfigInt("Big Bullet Damage"),m.OnUpperLevel(),false,ConfigPixel("Big Bullet Color"),vf2d{ConfigFloat("Big Bullet Image Scale"),ConfigFloat("Big Bullet Image Scale")})EndBullet;
+ m.F(A::SHOOT_TIMER)=ConfigFloat("Big Bullet Boss Rest Time");
m.I(A::ATTACK_COUNT)=-1;
- }else CreateBullet(Bullet)(m.GetPos(),util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Bullet Speed"),ConfigFloat("Bullet Radius"),ConfigFloat("Bullet Damage"),m.OnUpperLevel(),false,ConfigPixel("Bullet Color"),{ConfigFloat("Bullet Radius"),ConfigFloat("Bullet Radius")})EndBullet;
+ }else{
+ m.F(A::SHOOT_TIMER)=ConfigFloat("Shoot Frequency");
+ CreateBullet(Bullet)(m.GetPos(),util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Bullet Speed"),ConfigFloat("Bullet Radius"),ConfigFloat("Bullet Damage"),m.OnUpperLevel(),false,ConfigPixel("Bullet Color"),{ConfigFloat("Bullet Radius"),ConfigFloat("Bullet Radius")})EndBullet;
+ }
m.PerformShootAnimation();
- m.F(A::SHOOT_TIMER)=ConfigFloat("Shoot Frequency");
m.I(A::ATTACK_COUNT)++;
}
}break;
diff --git a/Adventures in Lestoria/IBullet.cpp b/Adventures in Lestoria/IBullet.cpp
index 2d84da86..317a3736 100644
--- a/Adventures in Lestoria/IBullet.cpp
+++ b/Adventures in Lestoria/IBullet.cpp
@@ -143,6 +143,7 @@ void IBullet::_Update(const float fElapsedTime){
while(iterations>0){
iterations--;
if(IsPlayerAutoAttackProjectile()){pos+=(game->GetWindSpeed()*game->GetElapsedTime())/float(totalIterations);}
+ vel=vf2d{vel.polar().x+(acc*fElapsedTime/float(totalIterations)),vel.polar().y}.cart();
pos+=(vel*fElapsedTime)/float(totalIterations);
if(!CollisionCheck()){
goto DeadBulletCheck;
@@ -154,6 +155,7 @@ void IBullet::_Update(const float fElapsedTime){
}
}else{
if(IsPlayerAutoAttackProjectile()){pos+=game->GetWindSpeed()*game->GetElapsedTime();}
+ vel=vf2d{vel.polar().x+acc*fElapsedTime,vel.polar().y}.cart();
pos+=vel*fElapsedTime;
}
diff --git a/Adventures in Lestoria/IBullet.h b/Adventures in Lestoria/IBullet.h
index 36428477..1da0e480 100644
--- a/Adventures in Lestoria/IBullet.h
+++ b/Adventures in Lestoria/IBullet.h
@@ -60,6 +60,7 @@ enum class BulletDestroyState{
struct IBullet{
friend class AiL;
+ float acc{};
vf2d vel;
vf2d pos;
float radius;
diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp
index 42681564..885b033f 100644
--- a/Adventures in Lestoria/Monster.cpp
+++ b/Adventures in Lestoria/Monster.cpp
@@ -708,6 +708,7 @@ const bool Monster::AttackAvoided(const float attackZ)const{
}
bool Monster::Hurt(HurtDamageInfo damageData){
+ if(damageData.damage==0)return false; //Cancel the hit.
return _Hurt(damageData.damage,damageData.onUpperLevel,damageData.z,damageData.damageRule,damageData.hurtFlags);
}
diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp
index 65b8bb0d..eb18fc1c 100644
--- a/Adventures in Lestoria/Player.cpp
+++ b/Adventures in Lestoria/Player.cpp
@@ -892,6 +892,7 @@ bool Player::HasIframes(){
}
bool Player::Hurt(HurtDamageInfo damageData){
+ if(damageData.damage==0)return false; //Cancel the hit.
return Hurt(damageData.damage,damageData.onUpperLevel,damageData.z,damageData.damageRule,damageData.hurtFlags);
}
diff --git a/Adventures in Lestoria/RotateBullet.cpp b/Adventures in Lestoria/RotateBullet.cpp
new file mode 100644
index 00000000..3972abfe
--- /dev/null
+++ b/Adventures in Lestoria/RotateBullet.cpp
@@ -0,0 +1,65 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+
+#include "BulletTypes.h"
+
+
+RotateBullet::RotateBullet(vf2d pos,float startingAng,float startSpeed,float acc,float headingAngleChange,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
+ :Bullet(pos,vf2d{startSpeed,startingAng}.cart(),radius,damage,"burstrotatebullet.png",upperLevel,false,INFINITE,true,friendly,col),headingAngleChange(headingAngleChange){
+ this->acc=acc;
+}
+
+void RotateBullet::Update(float fElapsedTime){
+ const float currentAng{vel.polar().y};
+ const float newAng{currentAng+headingAngleChange*fElapsedTime};
+ vel=vf2d{vel.polar().x,newAng}.cart();
+}
+
+BulletDestroyState RotateBullet::PlayerHit(Player*player){
+ fadeOutTime=0.2f;
+ Deactivate();
+ return BulletDestroyState::KEEP_ALIVE;
+}
+
+BulletDestroyState RotateBullet::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
+ fadeOutTime=0.2f;
+ Deactivate();
+ return BulletDestroyState::KEEP_ALIVE;
+}
+
+void RotateBullet::ModifyOutgoingDamageData(HurtDamageInfo&data){}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index 2ac6ed55..e776c225 100644
--- a/Adventures in Lestoria/Version.h
+++ b/Adventures in Lestoria/Version.h
@@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_PATCH 0
-#define VERSION_BUILD 11871
+#define VERSION_BUILD 11878
#define stringify(a) stringify_(a)
#define stringify_(a) #a
diff --git a/Adventures in Lestoria/assets/burstbullet.png b/Adventures in Lestoria/assets/burstbullet.png
new file mode 100644
index 00000000..3d1ebe1b
Binary files /dev/null and b/Adventures in Lestoria/assets/burstbullet.png differ
diff --git a/Adventures in Lestoria/assets/burstrotatebullet.png b/Adventures in Lestoria/assets/burstrotatebullet.png
new file mode 100644
index 00000000..74beb97f
Binary files /dev/null and b/Adventures in Lestoria/assets/burstrotatebullet.png differ
diff --git a/Adventures in Lestoria/assets/config/MonsterStrategies.txt b/Adventures in Lestoria/assets/config/MonsterStrategies.txt
index 3ebdd2f9..b51f53ee 100644
--- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt
+++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt
@@ -1262,9 +1262,17 @@ MonsterStrategy
# Number of shots when a big bullet comes out instead.
Big Bullet Frequency = 6shots
Big Bullet Speed = 250
- Big Bullet Radius = 12px
+ Big Bullet Radius = 18px
+ Big Bullet Detection Radius = 200
Big Bullet Damage = 90
+ # xscale, yscale
+ Big Bullet Image Scale = 2,2
Big Bullet Extra Bullet Count = 10
+ Big Bullet Extra Bullet Radius = 8px
+ Big Bullet Extra Bullet Rotate Speed = 40deg/sec
+ Big Bullet Extra Bullet Image Scale = 1,1
+ Big Bullet Extra Bullet Speed = 120
+ Big Bullet Extra Bullet Acceleration = 50
Big Bullet Boss Rest Time = 2s
Big Bullet Color = 255r,0g,0b,255a
}
diff --git a/Adventures in Lestoria/assets/config/audio/events.txt b/Adventures in Lestoria/assets/config/audio/events.txt
index 821ffafe..7b2d6b5c 100644
--- a/Adventures in Lestoria/assets/config/audio/events.txt
+++ b/Adventures in Lestoria/assets/config/audio/events.txt
@@ -69,6 +69,11 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = burning.ogg, 100%
}
+ Burst Bullet Explode
+ {
+ # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
+ File[0] = burstexplode.ogg, 100%
+ }
Button Click
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
diff --git a/Adventures in Lestoria/assets/config/gfx/gfx.txt b/Adventures in Lestoria/assets/config/gfx/gfx.txt
index a7f8fcbe..38f2fa70 100644
--- a/Adventures in Lestoria/assets/config/gfx/gfx.txt
+++ b/Adventures in Lestoria/assets/config/gfx/gfx.txt
@@ -141,6 +141,8 @@ Images
GFX_SandSuction = sand_suction.png
GFX_Bomb = bomb.png
GFX_Molotov = molotov.png
+ GFX_BurstBullet = burstbullet.png
+ GFX_BurstRotateBullet = burstrotatebullet.png
GFX_Thief_Sheet = nico-thief.png
GFX_Trapper_Sheet = nico-trapper.png
diff --git a/Adventures in Lestoria/assets/gamepack.pak b/Adventures in Lestoria/assets/gamepack.pak
index 92996dc2..688f9bce 100644
Binary files a/Adventures in Lestoria/assets/gamepack.pak and b/Adventures in Lestoria/assets/gamepack.pak differ
diff --git a/Adventures in Lestoria/assets/sounds/burstexplode.ogg b/Adventures in Lestoria/assets/sounds/burstexplode.ogg
new file mode 100644
index 00000000..3faf7e10
Binary files /dev/null and b/Adventures in Lestoria/assets/sounds/burstexplode.ogg differ
diff --git a/Adventures in Lestoria/olcUTIL_Animate2D.h b/Adventures in Lestoria/olcUTIL_Animate2D.h
index de8bbb49..6452d11e 100644
--- a/Adventures in Lestoria/olcUTIL_Animate2D.h
+++ b/Adventures in Lestoria/olcUTIL_Animate2D.h
@@ -225,7 +225,7 @@ namespace olc::utils::Animate2D
{
public:
Animation() = default;
- float mult = 1.f;
+ float mult = 1.f; //Speed multiplier of the animation. Adjust to change the speed the animation plays at.
StatesEnum currentStateName;
inline bool ChangeState(AnimationState& state, const StatesEnum& sStateName, const float frameMult)
diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe
index 9ab82037..b5730341 100644
Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ