diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj index cd62f091..99d0e85b 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj @@ -852,6 +852,10 @@ + + + + diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters index 2f30ab42..ae6acb9c 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters @@ -1301,6 +1301,9 @@ Source Files\Monster Strategies + + Source Files\Bullet Types + diff --git a/Adventures in Lestoria/Animation.cpp b/Adventures in Lestoria/Animation.cpp index 3bfeaeba..36779669 100644 --- a/Adventures in Lestoria/Animation.cpp +++ b/Adventures in Lestoria/Animation.cpp @@ -403,6 +403,7 @@ void sig::Animation::InitializeAnimations(){ CreateHorizontalAnimationSequence("large_tornado.png",4,{72,144},AnimationData{.frameDuration{0.1f},.style{Animate2D::Style::Repeat}}); CreateHorizontalAnimationSequence("sand_suction.png",4,{72,72},AnimationData{.frameDuration{0.2f},.style{Animate2D::Style::Repeat}}); CreateHorizontalAnimationSequence("bomb.png",4,{24,24},AnimationData{.frameDuration{0.2f},.style{Animate2D::Style::OneShot}}); + CreateHorizontalAnimationSequence("ghost_dagger.png",3,{24,24},{0.1f,Animate2D::Style::PingPong}); CreateStillAnimation("meteor.png",{192,192}); diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h index c1497bdb..d8bfb817 100644 --- a/Adventures in Lestoria/BulletTypes.h +++ b/Adventures in Lestoria/BulletTypes.h @@ -42,6 +42,7 @@ All rights reserved. #include "TrailEffect.h" #include "Entity.h" #include +#include struct EnergyBolt:public Bullet{ float lastParticleSpawn=0; @@ -441,4 +442,21 @@ private: const Entity target; const float rotateTowardsSpeed; const float rotateTowardsSpeedCoveredInInk; +}; + +struct GhostSaber:public Bullet{ + GhostSaber(const vf2d pos,const std::weak_ptrtarget,const float lifetime,const float distFromTarget,const float knockbackAmt,const float initialRot,const float radius,const int damage,const bool upperLevel,const float rotSpd,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1},const float image_angle=0.f); + 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 std::weak_ptrattachedMonster; + const float rotSpd; + const float distFromTarget; + float rot; + const float knockbackAmt; + float particleTimer{}; + float aliveTime{}; + OscillatoralphaOscillator{128U,255U,0.6f}; }; \ No newline at end of file diff --git a/Adventures in Lestoria/GhostOfPirateCaptain.cpp b/Adventures in Lestoria/GhostOfPirateCaptain.cpp index f9108b81..e73942bd 100644 --- a/Adventures in Lestoria/GhostOfPirateCaptain.cpp +++ b/Adventures in Lestoria/GhostOfPirateCaptain.cpp @@ -77,6 +77,7 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std m.B(A::FIRST_WAVE_COMPLETE)=true; m.ForceSetPos(m.spawnPos); m.SetupAfterImage(); + m.afterImagePos=m.GetPos(); m.SetCollisionRadius(0.f); m.F(A::CASTING_TIMER)=1.f; SETPHASE(AFTERIMAGE_FADEIN); @@ -96,6 +97,17 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std } } + m.F(A::GHOST_SABER_TIMER)-=fElapsedTime; + + if(m.B(A::FIRST_WAVE_COMPLETE)){ + m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())); + if(m.F(A::GHOST_SABER_TIMER)<=0.f){ + m.F(A::GHOST_SABER_TIMER)=ConfigFloat("Ghost Saber Cooldown"); + const float playerToMonsterAngle{util::pointTo(game->GetPlayer()->GetPos(),m.GetPos()).polar().y}; + CreateBullet(GhostSaber)(m.GetPos(),m.GetWeakPointer(),ConfigFloat("Ghost Saber Lifetime"),ConfigFloat("Ghost Saber Distance"),ConfigFloat("Ghost Saber Knockback Amt"),playerToMonsterAngle,ConfigFloat("Ghost Saber Radius"),ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")))EndBullet; + } + } + switch(PHASE()){ enum CannonPhaseType{ CANNON_SHOT, diff --git a/Adventures in Lestoria/GhostSaber.cpp b/Adventures in Lestoria/GhostSaber.cpp new file mode 100644 index 00000000..20bee8df --- /dev/null +++ b/Adventures in Lestoria/GhostSaber.cpp @@ -0,0 +1,75 @@ +#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" + +GhostSaber::GhostSaber(const vf2d pos,const std::weak_ptrtarget,const float lifetime,const float distFromTarget,const float knockbackAmt,const float initialRot,const float radius,const int damage,const bool upperLevel,const float rotSpd,const bool friendly,const Pixel col,const vf2d scale,const float image_angle) +:Bullet(target.lock()->GetPos()+vf2d{distFromTarget,initialRot}.cart(),{},radius,damage,"ghost_dagger.png",upperLevel,false,INFINITE,false,friendly,col,scale,image_angle),attachedMonster(target),rotSpd(rotSpd),distFromTarget(distFromTarget),rot(initialRot),aliveTime(lifetime),knockbackAmt(knockbackAmt){} +void GhostSaber::Update(float fElapsedTime){ + alphaOscillator.Update(fElapsedTime); + particleTimer-=fElapsedTime; + aliveTime-=fElapsedTime; + if(particleTimer<=0.f){ + particleTimer+=0.05f; + game->AddEffect(std::make_unique(pos,0.1f,0.1f,"pixel.png",2.f,vf2d{},Pixel{239,215,98,192},util::random(2*PI),0.f,true)); + } + rot+=rotSpd*fElapsedTime; + if(!attachedMonster.expired()){ + pos=attachedMonster.lock()->GetPos()+vf2d{distFromTarget,rot}.cart(); + } + if(aliveTime<=0.f&&!IsDeactivated()){ + Deactivate(); + fadeOutTime=0.5f; + } + col.a=alphaOscillator.get(); + image_angle=-rot*2; +}; + +BulletDestroyState GhostSaber::PlayerHit(Player*player){ + player->ApplyIframes(0.2f); + player->Knockback(vf2d{knockbackAmt,rot}.cart()); + return BulletDestroyState::KEEP_ALIVE; +} + +BulletDestroyState GhostSaber::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){ + monster.ApplyIframes(0.2f); + monster.Knockback(vf2d{knockbackAmt,rot}.cart()); + return BulletDestroyState::KEEP_ALIVE; +} + +void GhostSaber::ModifyOutgoingDamageData(HurtDamageInfo&data){} \ No newline at end of file diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h index f25fe2ec..34d3d26d 100644 --- a/Adventures in Lestoria/MonsterAttribute.h +++ b/Adventures in Lestoria/MonsterAttribute.h @@ -173,4 +173,5 @@ enum class Attribute{ LINE_SHOT_ANG, LAST_PLAYER_POS, FIRST_WAVE_COMPLETE, + GHOST_SABER_TIMER, }; \ No newline at end of file diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt index 7f1d8cd0..9b158eab 100644 --- a/Adventures in Lestoria/TODO.txt +++ b/Adventures in Lestoria/TODO.txt @@ -1,9 +1,10 @@ Ghost of Pirate Captain Boss Graphics Ghost of Pirate Captain Boss Implementation -Fix up Octopus Boss Facing Animations Add attack sound effects for Octopus boss Fight +On death and choosing to Try Again, the player should be given the Item Loadout screen in order to change strategies if they want to. + Arena Chapter 5 wont have a bonus boss instead there will be the endless arena. During the campaign there will be a 5 or 10 waves easy introduction after chapter 5 is cleared the endless mode unlocks. diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 330e0cd7..779d31cf 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 12003 +#define VERSION_BUILD 12016 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/config/MonsterStrategies.txt b/Adventures in Lestoria/assets/config/MonsterStrategies.txt index b4ebf316..863fff02 100644 --- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt +++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt @@ -1332,5 +1332,14 @@ MonsterStrategy Cannon Spell Circle Rotation Spd = -30 # Degrees/sec. Positive is CW, Negative is CCW. Cannon Spell Insignia Rotation Spd = 50 + + Ghost Saber Cooldown = 4s + Ghost Saber Lifetime = 4s + # Distance from the boss the ghost sabers should spin around. + Ghost Saber Distance = 56px + Ghost Saber Radius = 8px + Ghost Saber Damage = 75 + Ghost Saber Rotation Spd = 180deg/s + Ghost Saber Knockback Amt = 100 } } \ 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 2ed86532..74db792a 100644 --- a/Adventures in Lestoria/assets/config/gfx/gfx.txt +++ b/Adventures in Lestoria/assets/config/gfx/gfx.txt @@ -147,6 +147,7 @@ Images GFX_InkBubbleExplode = inkbubble_explode.png GFX_Ink = ink.png GFX_Cannonball = cannonball.png + GFX_GhostDagger = ghost_dagger.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 51632fc6..1086782a 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/ghost_dagger.png b/Adventures in Lestoria/assets/ghost_dagger.png new file mode 100644 index 00000000..11a04089 Binary files /dev/null and b/Adventures in Lestoria/assets/ghost_dagger.png differ diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index a30b7d61..47e26443 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ