#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 "Animation.h" #include "IBullet.h" #include #include #include "Oscillator.h" class Monster; class Player; using HitList=std::unordered_set>; enum class EffectType{ NONE, SPELL_CIRCLE, MONSTER_SOUL, BLINK_PORTAL, TRAIL_OF_FIRE, }; struct Effect{ friend class AiL; friend struct FallingStone; vf2d pos={0,0}; float lifetime=0; float fadeout=0; float fadein{0.f}; vf2d size={1,1}; Pixel col=WHITE; vf2d spd={}; float rotation=0; float rotationSpd=0; vf2d scaleSpd{}; bool additiveBlending=false; float z{}; private: bool dead=false; public: Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); virtual bool Update(float fElapsedTime); Animate2D::Frame GetFrame()const; void _Draw()const; virtual void Draw(const Pixel blendCol)const; bool OnUpperLevel(); const EffectType GetType()const; const float GetZ()const; const bool&OnUpperLevel()const; void SetType(const EffectType type); protected: float original_fadeOutTime; float original_fadeInTime{}; EffectType type{EffectType::NONE}; Animate2D::Animationanimation; Animate2D::AnimationState internal_animState; private: bool upperLevel=false; double aliveTime{}; }; struct Meteor:Effect{ enum MeteorSetting{ METEOR, COMET, SOLAR_FLARE, }; Meteor(const vf2d pos,const float lifetime,const bool upperLevel,const MeteorSetting setting,const float fadeout=0.0f,const vf2d spd={},const Pixel col=WHITE,const float rotation=0,const float rotationSpd=0,const bool additiveBlending=false); float startLifetime=0; bool shakeField=false; bool Update(float fElapsedTime)override; void Draw(const Pixel blendCol)const override; private: int meteorImpactParticles{}; float randomColorTintR{}; float randomColorTintG{}; float randomColorTintB{}; float meteorRadius{}; float fallSpdMult{1.f}; float damageMult{1.f}; float fireRingLifetime{}; std::string meteorCrashSFX{}; }; struct PulsatingFire:Effect{ PulsatingFire(vf2d pos,float lifetime,const float radius,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); std::vectorpulsatingFireValues; float lastParticleTimer=0; float lastDamageTimer=0; float radius; bool Update(float fElapsedTime)override; void Draw(const Pixel blendCol)const override; }; struct SwordSlash:Effect{ SwordSlash(float lifetime,std::string imgFile,float damageMult, float swordSweepAngle,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); bool Update(float fElapsedTime)override; private: HitList hitList; const float damageMult; const float swordSweepAngle; }; //This draws effects using screen coordinates instead of world coordinates, useful for applying effects directly on the screen. struct ForegroundEffect:Effect{ ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); virtual void Draw(const Pixel blendCol)const override final; }; struct SpellCircle:Effect{ SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,float insigniaSize=1.0f,float insigniaFadeout=0.0f,vf2d insigniaSpd={},Pixel insigniaCol=WHITE,float insigniaRotation=0,float insigniaRotationSpd=0,bool insigniaAdditiveBlending=false); SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,vf2d insigniaSize={1,1},float insigniaFadeout=0.0f,vf2d insigniaSpd={},Pixel insigniaCol=WHITE,float insigniaRotation=0,float insigniaRotationSpd=0,bool insigniaAdditiveBlending=false); Effect spellInsignia{vf2d{},0.f,"spell_insignia.png",false,{}}; virtual bool Update(float fElapsedTime)override final; virtual void Draw(const Pixel blendCol)const override final; }; struct RockLaunch:Effect{ //The lifetime is for how long the effect lasts after it's launched. You don't have to calculate extra lifetime to compensate for the delayTime, it is done for you. RockLaunch(vf2d pos,float lifetime,std::string imgFile,float delayTime,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false); virtual bool Update(float fElapsedTime)override final; private: float delayTime; vf2d futureSpd; }; struct ShineEffect:Effect{ //An effect that starts invisible, becomes visible, then fades out again. ShineEffect(vf2d pos,float fadeinTime,float fadeoutTime,std::string imgFile,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false); virtual bool Update(float fElapsedTime)override final; private: float fadeinTime; const Pixel originalCol; }; //Spawns and moves towards the player after some amount of time. struct MonsterSoul:Effect{ MonsterSoul(vf2d pos,float fadeoutTime,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false); virtual bool Update(float fElapsedTime)override final; virtual void Draw(const Pixel blendCol)const override final; public: enum Phase{ RISING, TRACKING_PLAYER, DEAD, }; uint8_t alpha{0U}; Phase phase{RISING}; float moveSpd{24.f}; float fadeoutTime; }; struct FadeInOutEffect:Effect{ //cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function&particleGenerator={}); //A version with oscillators for position and colors, for extra animation effects! FadeInOutEffect(Oscillatorpos,const std::string&img,float lifetime,bool onUpperLevel,Oscillatorsize,vf2d spd,Oscillatorcol,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function&particleGenerator={}); virtual bool Update(float fElapsedTime)override; virtual void Draw(const Pixel blendCol)const override; std::functionparticleGenerator; const float particleSpawnFreq; OscillatorposOscillator; OscillatorsizeOscillator; OscillatorcolOscillator; float particleSpawnTimer{}; const float originalParticleSpawnTimer{}; }; struct PoisonPool:FadeInOutEffect{ PoisonPool(vf2d pos,const std::string&img,float radius,int damage,float damageFreq,const HurtType friendly,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function&particleGenerator={}); virtual bool Update(float fElapsedTime)override final; const int damage; float damageTimer{}; const float originalDamageTimer{}; const float radius; HurtType friendly; const size_t poisonPoolSFXID{}; };