diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj index bd120a85..f2fc73c0 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj @@ -834,6 +834,7 @@ + diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters index ecf5023c..5f4a2ef0 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters @@ -1271,6 +1271,9 @@ Source Files\Utils + + Source Files\Bullet Types + diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h index 022bfd13..c61c0249 100644 --- a/Adventures in Lestoria/BulletTypes.h +++ b/Adventures in Lestoria/BulletTypes.h @@ -380,4 +380,14 @@ struct PoisonBottle:public ThrownProjectile{ private: const float bounceExplodeRadius; int additionalBounceCount; +}; + +struct BurstBullet:public Bullet{ + BurstBullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col); + 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; }; \ No newline at end of file diff --git a/Adventures in Lestoria/BurstBullet.cpp b/Adventures in Lestoria/BurstBullet.cpp new file mode 100644 index 00000000..01c16283 --- /dev/null +++ b/Adventures in Lestoria/BurstBullet.cpp @@ -0,0 +1,110 @@ +#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" +#include "Effect.h" +#include "AdventuresInLestoria.h" +#include "DEFINES.h" +#include "util.h" +#include "SoundEffect.h" +#include "TrailEffect.h" + +INCLUDE_game +INCLUDE_MONSTER_LIST + +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)); +} + +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)})); + } + 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); + } + } + 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); + 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); + return BulletDestroyState::KEEP_ALIVE; +} + +void BurstBullet::ModifyOutgoingDamageData(HurtDamageInfo&data){ + if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY; +} \ No newline at end of file diff --git a/Adventures in Lestoria/GiantOctopus.cpp b/Adventures in Lestoria/GiantOctopus.cpp index 1d683971..3721e335 100644 --- a/Adventures in Lestoria/GiantOctopus.cpp +++ b/Adventures in Lestoria/GiantOctopus.cpp @@ -134,7 +134,7 @@ void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string s m.F(A::CASTING_TIMER)=util::random_range(ConfigFloatArr("Arm Move Timer",0),ConfigFloatArr("Arm Move Timer",1)); } if(m.F(A::SHOOT_TIMER)<=0.f){ - if(m.I(A::ATTACK_COUNT)>=ConfigInt("Big Bullet Frequency")){ + 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; 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;