diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj index b526c42f..c405d679 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj @@ -425,6 +425,10 @@ + + + + @@ -815,6 +819,10 @@ + + + + diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters index c165d467..72947a95 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters @@ -642,6 +642,9 @@ Header Files + + Header Files + @@ -1061,6 +1064,12 @@ Source Files\Monster Strategies + + Source Files + + + Source Files + diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index 2c7616e5..f0f47662 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -156,8 +156,7 @@ InputGroup AiL::KEY_TOGGLE_MAP; float AiL::SIZE_CHANGE_SPEED=1; -AiL::AiL() -{ +AiL::AiL(){ debugLogger.open("debug.log"); utils::datafile::Read(DATA,"assets/config/configuration.txt"); std::filesystem::create_directories("save_file_path"_S); @@ -820,7 +819,6 @@ void AiL::PopulateRenderLists(){ monstersBeforeLower.clear(); monstersAfterLower.clear(); monstersBeforeUpper.clear(); - monstersAfterUpper.clear(); bulletsLower.clear(); bulletsUpper.clear(); backgroundEffectsLower.clear(); @@ -1266,64 +1264,56 @@ void AiL::RenderWorld(float fElapsedTime){ Monster&m=**it; m.strategyDraw(this,m,MONSTER_DATA[m.GetName()].GetAIStrategy()); } + + #pragma region Render Background Effects + { + auto it=backgroundEffectsLower.begin(); + while(it!=backgroundEffectsLower.end()){ + const Effect&e=**it; + e.Draw(); + ++it; + } + } + #pragma endregion + auto monstersBeforeLowerIt=monstersBeforeLower.begin(); + auto monstersAfterLowerIt=monstersAfterLower.begin(); + auto dropsBeforeLowerIt=dropsBeforeLower.begin(); + auto dropsAfterLowerIt=dropsAfterLower.begin(); #pragma region Rendering before Tile Depth Rendering if(tilesWithCollision.size()>0){ const float topTileY=(*tilesWithCollision.begin())->group->GetCollisionRange().middle().y; #pragma region Depth Ordered Rendering - { - auto it=monstersBeforeLower.begin(); - while(it!=monstersBeforeLower.end()){ - Monster&m=**it; - if(m.pos.yrendered&&!player->upperLevel&&player->GetPos().yrendered&&!player->upperLevel&&player->GetPos().yrendered=true; if(player->GetZ()>0){ vf2d shadowScale=vf2d{8*player->GetSizeMult()/3.f,1}/std::max(1.f,player->GetZ()/24); @@ -1331,44 +1321,23 @@ void AiL::RenderWorld(float fElapsedTime){ } RenderPlayer(player->GetPos(),{1,1}); } - { - auto it=monstersAfterLower.begin(); - while(it!=monstersAfterLower.end()){ - Monster&m=**it; - if(m.pos.ygroup->GetCollisionRange().middle().y){ - m.Draw(); - it=monstersBeforeLower.erase(it); - if(it==monstersBeforeLower.end())break; - continue; - } - break; - } - } - { - auto it=bulletsLower.begin(); - while(it!=bulletsLower.end()){ - const Bullet&b=**it; - if(b.pos.ygroup->GetCollisionRange().middle().y){ - b.Draw(); - it=bulletsLower.erase(it); - if(it==bulletsLower.end())break; - continue; - } - break; - } - } - { - auto it=backgroundEffectsLower.begin(); - while(it!=backgroundEffectsLower.end()){ - const Effect&e=**it; - if(e.pos.ygroup->GetCollisionRange().middle().y){ - e.Draw(); - it=backgroundEffectsLower.erase(it); - if(it==backgroundEffectsLower.end())break; - continue; - } - break; + if(!player->rendered&&!player->upperLevel&&player->GetPos().ygroup->GetCollisionRange().middle().y){ + //If we are supposed to render the player, everything else before must be rendered at this point. + while(monstersBeforeLowerIt!=monstersBeforeLower.end()){ + Monster&m=**monstersBeforeLowerIt; + m.Draw(); + ++monstersBeforeLowerIt; } - } - { - auto it=dropsBeforeLower.begin(); - while(it!=dropsBeforeLower.end()){ - const ItemDrop&drop=ItemDrop::drops[*it]; - if(drop.pos.ygroup->GetCollisionRange().middle().y){ - drop.Draw(); - it=dropsBeforeLower.erase(it); - if(it==dropsBeforeLower.end())break; - continue; - } - break; + while(dropsBeforeLowerIt!=dropsBeforeLower.end()){ + const ItemDrop&drop=ItemDrop::drops[*dropsBeforeLowerIt]; + drop.Draw(); + ++dropsBeforeLowerIt; } - } - if(!player->rendered&&!player->upperLevel&&player->GetPos().ygroup->GetCollisionRange().middle().y){ player->rendered=true; if(player->GetZ()>0){ vf2d shadowScale=vf2d{8*player->GetSizeMult()/3.f,1}/std::max(1.f,player->GetZ()/24); @@ -1436,44 +1364,23 @@ void AiL::RenderWorld(float fElapsedTime){ } RenderPlayer(player->GetPos(),{1,1}); } - { - auto it=monstersAfterLower.begin(); - while(it!=monstersAfterLower.end()){ - Monster&m=**it; - if(m.pos.ygroup->GetCollisionRange().middle().y){ - m.Draw(); - it=monstersAfterLower.erase(it); - if(it==monstersAfterLower.end())break; - continue; - } - break; - } - } - { - auto it=dropsAfterLower.begin(); - while(it!=dropsAfterLower.end()){ - const ItemDrop&drop=ItemDrop::drops[*it]; - if(drop.pos.ygroup->GetCollisionRange().middle().y){ - drop.Draw(); - it=dropsAfterLower.erase(it); - if(it==dropsAfterLower.end())break; - continue; - } - break; + while(monstersAfterLowerIt!=monstersAfterLower.end()){ + Monster&m=**monstersAfterLowerIt; + if(m.pos.ygroup->GetCollisionRange().middle().y){ + m.Draw(); + ++monstersAfterLowerIt; + continue; } + break; } - { - auto it=foregroundEffectsLower.begin(); - while(it!=foregroundEffectsLower.end()){ - const Effect&e=**it; - if(e.pos.ygroup->GetCollisionRange().middle().y){ - e.Draw(); - it=foregroundEffectsLower.erase(it); - if(it==foregroundEffectsLower.end())break; - continue; - } - break; + while(dropsAfterLowerIt!=dropsAfterLower.end()){ + const ItemDrop&drop=ItemDrop::drops[*dropsAfterLowerIt]; + if(drop.pos.ygroup->GetCollisionRange().middle().y){ + drop.Draw(); + ++dropsAfterLowerIt; + continue; } + break; } #pragma endregion RenderTile(*tile,{255,255,255,uint8_t(255-tile->tileOpacity/TileGroup::FADE_TIME*TileGroup::FADE_AMT)}); @@ -1503,9 +1410,6 @@ void AiL::RenderWorld(float fElapsedTime){ for(const Effect*const e:backgroundEffectsLower){ e->Draw(); } - for(const Bullet*const b:bulletsLower){ - b->Draw(); - } for(const int dropInd:dropsBeforeLower){ ItemDrop::drops[dropInd].Draw(); } @@ -1524,6 +1428,9 @@ void AiL::RenderWorld(float fElapsedTime){ for(const int dropInd:dropsAfterLower){ ItemDrop::drops[dropInd].Draw(); } + for(const Bullet*const b:bulletsLower){ + b->Draw(); + } for(const Effect*const e:foregroundEffectsLower){ e->Draw(); } @@ -1643,63 +1550,55 @@ void AiL::RenderWorld(float fElapsedTime){ m.strategyDraw(this,m,MONSTER_DATA[m.GetName()].GetAIStrategy()); } + #pragma region Render Background Effects + { + auto it=backgroundEffectsUpper.begin(); + while(it!=backgroundEffectsUpper.end()){ + const Effect&e=**it; + e.Draw(); + ++it; + } + } + #pragma endregion + + auto monstersBeforeUpperIt=monstersBeforeUpper.begin(); + auto monstersAfterUpperIt=monstersAfterUpper.begin(); + auto dropsBeforeUpperIt=dropsBeforeUpper.begin(); + auto dropsAfterUpperIt=dropsAfterUpper.begin(); #pragma region Rendering before Tile Depth Rendering if(tilesWithCollision.size()>0){ const float topTileY=(*tilesWithCollision.begin())->group->GetCollisionRange().middle().y; #pragma region Depth Ordered Rendering - { - auto it=monstersBeforeUpper.begin(); - while(it!=monstersBeforeUpper.end()){ - Monster&m=**it; - if(m.pos.yrendered&&!player->upperLevel&&player->GetPos().yrendered&&!player->upperLevel&&player->GetPos().yrendered=true; if(player->GetZ()>0){ vf2d shadowScale=vf2d{8*player->GetSizeMult()/3.f,1}/std::max(1.f,player->GetZ()/24); @@ -1707,45 +1606,22 @@ void AiL::RenderWorld(float fElapsedTime){ } RenderPlayer(player->GetPos(),{1,1}); } - { - auto it=monstersAfterUpper.begin(); - while(it!=monstersAfterUpper.end()){ - Monster&m=**it; - if(m.pos.ygroup->GetCollisionRange().middle().y){ - m.Draw(); - it=monstersBeforeUpper.erase(it); - if(it==monstersBeforeUpper.end())break; - continue; - } - break; + while(monstersBeforeUpperIt!=monstersBeforeUpper.end()){ + Monster&m=**monstersBeforeUpperIt; + if(m.pos.ygroup->GetCollisionRange().middle().y){ + m.Draw(); + ++monstersBeforeUpperIt; + continue; } + break; } - { - auto it=bulletsUpper.begin(); - while(it!=bulletsUpper.end()){ - const Bullet&b=**it; - if(b.pos.ygroup->GetCollisionRange().middle().y){ - b.Draw(); - it=bulletsUpper.erase(it); - if(it==bulletsUpper.end())break; - continue; - } - break; + while(dropsBeforeUpperIt!=dropsBeforeUpper.end()){ + const ItemDrop&drop=ItemDrop::drops[*dropsBeforeUpperIt]; + if(drop.pos.ygroup->GetCollisionRange().middle().y){ + drop.Draw(); + ++dropsBeforeUpperIt; + continue; } + break; } - { - auto it=backgroundEffectsUpper.begin(); - while(it!=backgroundEffectsUpper.end()){ - const Effect&e=**it; - if(e.pos.ygroup->GetCollisionRange().middle().y){ - e.Draw(); - it=backgroundEffectsUpper.erase(it); - if(it==backgroundEffectsUpper.end())break; - continue; - } - break; + if(!player->rendered&&player->upperLevel&&player->GetPos().ygroup->GetCollisionRange().middle().y){ + //If we are supposed to render the player, everything else before must be rendered at this point. + while(monstersBeforeUpperIt!=monstersBeforeUpper.end()){ + Monster&m=**monstersBeforeUpperIt; + m.Draw(); + ++monstersBeforeUpperIt; } - } - { - auto it=dropsBeforeUpper.begin(); - while(it!=dropsBeforeUpper.end()){ - const ItemDrop&drop=ItemDrop::drops[*it]; - if(drop.pos.ygroup->GetCollisionRange().middle().y){ - drop.Draw(); - it=dropsBeforeUpper.erase(it); - if(it==dropsBeforeUpper.end())break; - continue; - } - break; + while(dropsBeforeUpperIt!=dropsBeforeUpper.end()){ + const ItemDrop&drop=ItemDrop::drops[*dropsBeforeUpperIt]; + drop.Draw(); + ++dropsBeforeUpperIt; } - } - if(!player->rendered&&player->upperLevel&&player->GetPos().ygroup->GetCollisionRange().middle().y){ player->rendered=true; if(player->GetZ()>0){ vf2d shadowScale=vf2d{8*player->GetSizeMult()/3.f,1}/std::max(1.f,player->GetZ()/24); @@ -1813,44 +1666,23 @@ void AiL::RenderWorld(float fElapsedTime){ } RenderPlayer(player->GetPos(),{1,1}); } - { - auto it=monstersAfterUpper.begin(); - while(it!=monstersAfterUpper.end()){ - Monster&m=**it; - if(m.pos.ygroup->GetCollisionRange().middle().y){ - m.Draw(); - it=monstersAfterUpper.erase(it); - if(it==monstersAfterUpper.end())break; - continue; - } - break; - } - } - { - auto it=dropsAfterUpper.begin(); - while(it!=dropsAfterUpper.end()){ - const ItemDrop&drop=ItemDrop::drops[*it]; - if(drop.pos.ygroup->GetCollisionRange().middle().y){ - drop.Draw(); - it=dropsAfterUpper.erase(it); - if(it==dropsAfterUpper.end())break; - continue; - } - break; + while(monstersAfterUpperIt!=monstersAfterUpper.end()){ + Monster&m=**monstersAfterUpperIt; + if(m.pos.ygroup->GetCollisionRange().middle().y){ + m.Draw(); + ++monstersAfterUpperIt; + continue; } + break; } - { - auto it=foregroundEffectsUpper.begin(); - while(it!=foregroundEffectsUpper.end()){ - const Effect&e=**it; - if(e.pos.ygroup->GetCollisionRange().middle().y){ - e.Draw(); - it=foregroundEffectsUpper.erase(it); - if(it==foregroundEffectsUpper.end())break; - continue; - } - break; + while(dropsAfterUpperIt!=dropsAfterUpper.end()){ + const ItemDrop&drop=ItemDrop::drops[*dropsAfterUpperIt]; + if(drop.pos.ygroup->GetCollisionRange().middle().y){ + drop.Draw(); + ++dropsAfterUpperIt; + continue; } + break; } #pragma endregion RenderTile(*tile,{255,255,255,uint8_t(255-tile->tileOpacity/TileGroup::FADE_TIME*TileGroup::FADE_AMT)}); @@ -1872,9 +1704,6 @@ void AiL::RenderWorld(float fElapsedTime){ for(const Effect*const e:backgroundEffectsUpper){ e->Draw(); } - for(const Bullet*const b:bulletsUpper){ - b->Draw(); - } for(const int dropInd:dropsBeforeUpper){ ItemDrop::drops[dropInd].Draw(); } @@ -1893,6 +1722,9 @@ void AiL::RenderWorld(float fElapsedTime){ for(const int dropInd:dropsAfterUpper){ ItemDrop::drops[dropInd].Draw(); } + for(const Bullet*const b:bulletsUpper){ + b->Draw(); + } for(const Effect*const e:foregroundEffectsUpper){ e->Draw(); } @@ -2130,6 +1962,8 @@ void AiL::RenderHud(){ } #endif + hudOverlay.Draw(); + Pixel vignetteOverlayColor="Interface.Vignette Color"_Pixel; const float vignetteTotalDisplayTime="Interface.Vignette Appearance Time"_F+"Interface.Vignette Fadeout Time"_F; if(vignetteDisplayTime<"Interface.Vignette Fadeout Time"_F)vignetteOverlayColor.a=util::lerp(0,255,vignetteDisplayTime/"Interface.Vignette Fadeout Time"_F); @@ -2431,6 +2265,7 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){ MONSTER_LIST.clear(); BULLET_LIST.clear(); DAMAGENUMBER_LIST.clear(); + hudOverlay.Reset(); backgroundEffects.clear(); foregroundEffects.clear(); ItemDrop::drops.clear(); @@ -4430,4 +4265,12 @@ void AiL::AMonsterIsMarkedForDeletion(){ void AiL::SetBossIndicatorPos(const vf2d pos){ bossIndicatorPos=pos; +} + +Overlay&AiL::GetOverlay(){ + return hudOverlay; +} + +void AiL::SetOverlay(std::string animationName,Pixel overlayCol){ + hudOverlay=Overlay{animationName,overlayCol}; } \ No newline at end of file diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h index f1b2284a..fcbafcca 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.h +++ b/Adventures in Lestoria/AdventuresInLestoria.h @@ -57,7 +57,7 @@ All rights reserved. #include "DynamicCounter.h" #include "UndefKeys.h" #include "Minimap.h" - +#include "Overlay.h" class SteamKeyboardCallbackHandler; class SteamStatsReceivedHandler; @@ -208,6 +208,7 @@ private: SteamKeyboardCallbackHandler*steamKeyboardCallbackListener=nullptr; SteamStatsReceivedHandler*steamStatsReceivedHandlerListener=nullptr; std::optionalbossIndicatorPos{}; + Overlay hudOverlay{"pixel.png",BLANK}; public: AiL(); bool OnUserCreate() override; @@ -348,6 +349,8 @@ public: Minimap minimap; void AMonsterIsMarkedForDeletion(); //The way this is implemented is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop. void SetBossIndicatorPos(const vf2d pos); + void SetOverlay(std::string animationName,Pixel overlayCol); + Overlay&GetOverlay(); struct TileGroupData{ vi2d tilePos; diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index 975836d0..5a5fa170 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -384,6 +384,15 @@ Direction Monster::GetFacingDirection()const{ return facingDirection; } +void Monster::UpdateFacingDirection(Direction newFacingDir){ + if(HasFourWaySprites()){ + facingDirection=newFacingDir; + }else{ + if(newFacingDir==Direction::NORTH||newFacingDir==Direction::SOUTH)ERR(std::format("WARNING! Trying to set a facing direction of {} for Monster {}! Not possible because the monster does not have four-way facing sprites!",int(newFacingDir),GetDisplayName())); + facingDirection=newFacingDir; + } +} + void Monster::UpdateFacingDirection(vf2d facingTargetPoint){ if(Immovable())return; float facingAngle=util::angleTo(GetPos(),facingTargetPoint); diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h index 1456c80a..aada97b4 100644 --- a/Adventures in Lestoria/Monster.h +++ b/Adventures in Lestoria/Monster.h @@ -95,6 +95,7 @@ public: Direction GetFacingDirection()const; //Will make the monster face in the correct direction relative to a given target point to look at. void UpdateFacingDirection(vf2d facingTargetPoint); + void UpdateFacingDirection(Direction newFacingDir); void Draw()const; void DrawReflection(float drawRatioX,float multiplierX); void Collision(Player*p); @@ -262,7 +263,7 @@ private: static float _GetFloat(Monster&m,std::string param,std::string strategy,int index=0); static Pixel _GetPixel(Monster&m,std::string param,std::string strategy,int index=0); //Converts unit distances to pixels. (Every 100 units = 24 pixels) - static double _GetPixels(Monster&m,std::string param,std::string strategy,int index=0); + static float _GetPixels(Monster&m,std::string param,std::string strategy,int index=0); static vf2d _GetVec(Monster&m,std::string param,std::string strategy,int index=0); static const std::string&_GetString(Monster&m,std::string param,std::string strategy,int index=0); static const datafile&_Get(Monster&m,std::string param,std::string strategy); diff --git a/Adventures in Lestoria/Overlay.cpp b/Adventures in Lestoria/Overlay.cpp new file mode 100644 index 00000000..0a7e8851 --- /dev/null +++ b/Adventures in Lestoria/Overlay.cpp @@ -0,0 +1,68 @@ +#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 "DEFINES.h" +#include "AdventuresInLestoria.h" +#include "Overlay.h" + +INCLUDE_game +INCLUDE_ANIMATION_DATA + +Overlay::Overlay(std::string animationName,Pixel overlayCol) + :animationName(animationName),overlayCol(overlayCol){} +const Pixel&Overlay::GetOverlayCol()const{ + return overlayCol; +} +void Overlay::SetOverlayCol(Pixel newOverlayCol){ + overlayCol=newOverlayCol; +} +void Overlay::Enable(){ + enabled=true; +} +void Overlay::Disable(){ + enabled=false; +} +void Overlay::Draw(){ + if(!enabled)return; + const Animate2D::Frame&animationFrame{ANIMATION_DATA.at(animationName).GetFrame(game->GetRunTime())}; + game->DrawPartialDecal({},animationFrame.GetSourceRect().size,animationFrame.GetSourceImage()->Decal(),animationFrame.GetSourceRect().pos,animationFrame.GetSourceRect().size,overlayCol); +} +void Overlay::Reset(){ + animationName="pixel.png"; + overlayCol=BLANK; +} \ No newline at end of file diff --git a/Adventures in Lestoria/Overlay.h b/Adventures in Lestoria/Overlay.h new file mode 100644 index 00000000..c77ba4b9 --- /dev/null +++ b/Adventures in Lestoria/Overlay.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 "olcPixelGameEngine.h" + +class Overlay{ + friend class AiL; +public: + Overlay(std::string animationName,Pixel overlayCol); + const Pixel&GetOverlayCol()const; + void SetOverlayCol(Pixel newOverlayCol); + void Enable(); + void Disable(); +private /*AiL*/: + void Draw(); + void Reset(); +private: + bool enabled{true}; + std::string animationName; + Pixel overlayCol; +}; \ No newline at end of file diff --git a/Adventures in Lestoria/RUN_STRATEGY.cpp b/Adventures in Lestoria/RUN_STRATEGY.cpp index 5a5d007a..dac8ae29 100644 --- a/Adventures in Lestoria/RUN_STRATEGY.cpp +++ b/Adventures in Lestoria/RUN_STRATEGY.cpp @@ -154,7 +154,7 @@ Pixel Monster::STRATEGY::_GetPixel(Monster&m,std::string param,std::string strat } } -double Monster::STRATEGY::_GetPixels(Monster&m,std::string param,std::string strategy,int index){ +float Monster::STRATEGY::_GetPixels(Monster&m,std::string param,std::string strategy,int index){ if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){ return DATA["NPCs"][m.name].GetProperty(param).GetReal(index)/100.f*24; }else diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 5649b0b2..8d7517bf 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 2 #define VERSION_PATCH 3 -#define VERSION_BUILD 9473 +#define VERSION_BUILD 9482 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Zephy.cpp b/Adventures in Lestoria/Zephy.cpp index 2bf7e179..a2231f84 100644 --- a/Adventures in Lestoria/Zephy.cpp +++ b/Adventures in Lestoria/Zephy.cpp @@ -55,6 +55,8 @@ void Monster::STRATEGY::ZEPHY(Monster&m,float fElapsedTime,std::string strategy) FLY_ACROSS, TORNADO_ATTACK_PREPARE, TORNADO_ATTACK, + WIND_ATTACK_FLY, + WIND_ATTACK_LAND, WIND_ATTACK, HALFHEALTH_PHASE, }; @@ -70,14 +72,23 @@ void Monster::STRATEGY::ZEPHY(Monster&m,float fElapsedTime,std::string strategy) game->SpawnMonster(m.GetPos()+vf2d{ConfigFloat("Basic Hawk Spawn Radius"),randomDir}.cart(),MONSTER_DATA.at("Hawk_NOXP"),m.OnUpperLevel()); m.F(A::SPAWNER_TIMER)=ConfigFloat("Basic Hawk Spawn Time"); } + + #pragma region Flying Hover Effect + if(m.F(A::TARGET_FLYING_HEIGHT)==0.f)m.SetZ(std::max(m.F(A::FLYING_HEIGHT),0.f)); + else m.SetZ(std::max(m.F(A::FLYING_HEIGHT)+ConfigFloat("Flight Oscillation Amount")*sin((PI*m.TimeSpentAlive())/1.5f),0.f)); + #pragma endregion + if(m.F(A::FLYING_HEIGHT)-ConfigFloat("Flight Oscillation Amount"))m.F(A::FLYING_HEIGHT)=std::max(-ConfigFloat("Flight Oscillation Amount"),m.F(A::FLYING_HEIGHT)-ConfigPixels("Fly Rise/Fall Speed")*fElapsedTime); switch(m.phase){ case INITIALIZE:{ m.F(A::SPAWNER_TIMER)=ConfigFloat("Basic Hawk Spawn Time"); m.phase=IDLE; + game->SetOverlay(ConfigString("Wind Attack.Wind Overlay Sprite"),ConfigPixel("Wind Attack.Wind Overlay Color")); + game->GetOverlay().Disable(); }break; case IDLE:{ - const int randomAttackChoice=util::random()%2; + const int randomAttackChoice=util::random()%3; switch(randomAttackChoice){ case 0:{ @@ -94,10 +105,12 @@ void Monster::STRATEGY::ZEPHY(Monster&m,float fElapsedTime,std::string strategy) m.target=ConfigVec("Tornado Attack.Landing Area"); }break; case 2:{ - m.phase=WIND_ATTACK; - }break; - case 3:{ - m.phase=HALFHEALTH_PHASE; + m.phase=WIND_ATTACK_FLY; + m.F(A::TARGET_FLYING_HEIGHT)=ConfigPixels("Wind Attack.Fly Up Height"); + const bool LeftLandingSite=m.I(A::ATTACK_CHOICE)=util::random()%2; + if(LeftLandingSite)m.target=ConfigVec("Wind Attack.Left Landing Site"); + else m.target=ConfigVec("Wind Attack.Right Landing Site"); + }break; } }break; @@ -173,8 +186,24 @@ void Monster::STRATEGY::ZEPHY(Monster&m,float fElapsedTime,std::string strategy) m.F(A::CASTING_TIMER)-=fElapsedTime; if(m.F(A::CASTING_TIMER)<=0.f)m.phase=IDLE; }break; + case WIND_ATTACK_FLY:{ + m.targetAcquireTimer=20.f; + RUN_TOWARDS(m,fElapsedTime,"Run Towards"); + if(m.ReachedTargetPos()){ + m.phase=WIND_ATTACK_LAND; + m.F(A::TARGET_FLYING_HEIGHT)=0.f; + } + }break; + case WIND_ATTACK_LAND:{ + if(m.GetZ()==0.f){ + m.phase=WIND_ATTACK; + game->GetOverlay().Enable(); + } + }break; case WIND_ATTACK:{ - + const bool OnLeftLandingSite=m.I(A::ATTACK_CHOICE); + if(OnLeftLandingSite)m.PerformAnimation("ATTACK",Direction::EAST); + else m.PerformAnimation("ATTACK",Direction::WEST); }break; case HALFHEALTH_PHASE:{ diff --git a/Adventures in Lestoria/assets/config/MonsterStrategies.txt b/Adventures in Lestoria/assets/config/MonsterStrategies.txt index d5e7ff1d..5aee5342 100644 --- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt +++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt @@ -780,6 +780,11 @@ MonsterStrategy Basic Hawk Spawn Time = 10s Basic Hawk Spawn Radius = 1000 + # In units/sec + Fly Rise/Fall Speed = 400 + + Flight Oscillation Amount = 1.5px + Fly Across Attack { Poop Damage = 25 @@ -819,5 +824,16 @@ MonsterStrategy Ring 6 = 775, 18, -7 } } + Wind Attack + { + # In Units + Fly Up Height = 700 + + Left Landing Site = 1608, 1728 + Right Landing Site = 2472, 1728 + + Wind Overlay Sprite = "wind_vignette.png" + Wind Overlay Color = 64, 64, 64, 255 + } } } \ No newline at end of file diff --git a/Adventures in Lestoria/assets/config/gfx/gfx.txt b/Adventures in Lestoria/assets/config/gfx/gfx.txt index 26330e33..174d38c0 100644 --- a/Adventures in Lestoria/assets/config/gfx/gfx.txt +++ b/Adventures in Lestoria/assets/config/gfx/gfx.txt @@ -99,6 +99,7 @@ Images GFX_BossIndicator = bossIndicator.png GFX_BirdPoop = birdpoop.png GFX_Tornado = tornado2.png + GFX_WindOverlay = wind_vignette.png # Ability Icons GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png diff --git a/Adventures in Lestoria/assets/gamepack.pak b/Adventures in Lestoria/assets/gamepack.pak index 7c7e6c7b..e8983334 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/wind1.png b/Adventures in Lestoria/assets/wind1.png new file mode 100644 index 00000000..c9bba954 Binary files /dev/null and b/Adventures in Lestoria/assets/wind1.png differ diff --git a/Adventures in Lestoria/assets/wind2.png b/Adventures in Lestoria/assets/wind2.png new file mode 100644 index 00000000..65684da7 Binary files /dev/null and b/Adventures in Lestoria/assets/wind2.png differ diff --git a/Adventures in Lestoria/assets/wind_vignette.png b/Adventures in Lestoria/assets/wind_vignette.png new file mode 100644 index 00000000..3a011ab9 Binary files /dev/null and b/Adventures in Lestoria/assets/wind_vignette.png differ diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index a6392c87..6f9e2314 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ