diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index 5547dcf8..2ea9fc1c 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -839,6 +839,10 @@
+
+
+
+
@@ -852,6 +856,10 @@
+
+
+
+
@@ -1114,7 +1122,11 @@
-
+
+
+
+
+
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
index 0bdaca48..9dcc64d0 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
@@ -1304,9 +1304,18 @@
Source Files\Bullet Types
-
+
Source Files\Monster Strategies
+
+ Source Files\Monster Strategies
+
+
+ Source Files\Effects
+
+
+ Source Files\Effects
+
diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp
index 8dfbf4be..33f7ea41 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.cpp
+++ b/Adventures in Lestoria/AdventuresInLestoria.cpp
@@ -1069,7 +1069,7 @@ void AiL::RenderWorld(float fElapsedTime){
const std::vectordamageReductionBuffs{player->GetBuffs(BuffType::DAMAGE_REDUCTION)};
const std::vectorinkSlowdownDebuff{player->GetBuffs(BuffType::INK_SLOWDOWN)};
const std::vectorcurseDebuff{player->GetBuffs(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT)};
- const bool displayCoinSymbol{player->GetBuffs(BuffType::PIRATE_GHOST_CAPTAIN_CURSE).size()>0};
+ const bool displayCoinSymbol{player->GetBuffs(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN).size()>0};
Pixel playerCol{WHITE};
if(attackBuffs.size()>0)playerCol={255,uint8_t(255*abs(sin(1.4f*attackBuffs[0].duration))),uint8_t(255*abs(sin(1.4f*attackBuffs[0].duration)))};
@@ -1098,7 +1098,7 @@ void AiL::RenderWorld(float fElapsedTime){
}
if(displayCoinSymbol){
- view.DrawRotatedDecal(pos+vf2d{0,(-player->GetZ()-24.f-sinf(PI*GetRunTime())*4.f)*(std::signbit(scale.y)?-1:1)},GFX["coin.png"].Decal(),0.f,GFX["coin.png"].Sprite()->Size()/2,{0.5f,0.5f});
+ view.DrawRotatedDecal(pos+vf2d{0,(-player->GetZ()-16.f-sinf(PI*GetRunTime())*2.f)*(std::signbit(scale.y)?-1:1)},GFX["coin.png"].Decal(),0.f,GFX["coin.png"].Sprite()->Size()/2,{0.5f,0.5f});
}
};
@@ -4490,6 +4490,9 @@ void AiL::ComputeModeColors(TilesetData&tileset){
void AiL::UpdateEntities(){
UpdateEffects(GetElapsedTime());
+ for(std::shared_ptr&m:MONSTER_LIST){
+ m->B(Attribute::COLLIDED_WITH_PLAYER)=false;
+ }
GetPlayer()->Update(GetElapsedTime());
UpdateMonsters();
diff --git a/Adventures in Lestoria/Buff.h b/Adventures in Lestoria/Buff.h
index fb28536b..39d4b859 100644
--- a/Adventures in Lestoria/Buff.h
+++ b/Adventures in Lestoria/Buff.h
@@ -66,7 +66,8 @@ enum BuffType{
CURSE_OF_DEATH,
AFFECTED_BY_LIGHTNING_BOLT, //Intensity indicates number of repeats remaining.
INK_SLOWDOWN, //Intensity indicates % movespd slowdown.
- PIRATE_GHOST_CAPTAIN_CURSE, //A coin icon appears above the player's head.
+ PIRATE_GHOST_CAPTAIN_PRECURSE, //A coin icon appears above the player's head.
+ PIRATE_GHOST_CAPTAIN_CURSE_COIN, //A coin icon appears above the player's head.
PIRATE_GHOST_CAPTAIN_CURSE_DOT, //The same as above, but now is a damage over time as well.
};
enum class BuffRestorationType{
diff --git a/Adventures in Lestoria/CollectedCoinEffect.cpp b/Adventures in Lestoria/CollectedCoinEffect.cpp
new file mode 100644
index 00000000..2398f140
--- /dev/null
+++ b/Adventures in Lestoria/CollectedCoinEffect.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 "Effect.h"
+#include "AdventuresInLestoria.h"
+#include "DEFINES.h"
+#include "util.h"
+
+INCLUDE_game
+
+CollectCoinEffect::CollectCoinEffect(const Entity attachedTarget,float coinArcRiseZAmt,float lifetime,const std::string&imgFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
+ :Effect(attachedTarget.GetPos(),lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending),attachedTarget(attachedTarget),sizeFlipper(-1.f,1.f,lifetime*2.f),zRiser(0.f,coinArcRiseZAmt,1/lifetime){
+}
+bool CollectCoinEffect::Update(float fElapsedTime){
+ zRiser.Update(fElapsedTime);
+ pos=attachedTarget.GetPos()-vf2d{0,zRiser.get()}; //A hack, instead of using the built-in z (which would display a shadow, we instead manipulate the final position based on the zRiser output).
+ size.x=sizeFlipper.Update(fElapsedTime);
+ return Effect::Update(fElapsedTime);
+}
+void CollectCoinEffect::Draw(const Pixel blendCol)const{
+ Effect::Draw(blendCol);
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Effect.cpp b/Adventures in Lestoria/Effect.cpp
index 8788dd74..b37f9235 100644
--- a/Adventures in Lestoria/Effect.cpp
+++ b/Adventures in Lestoria/Effect.cpp
@@ -107,6 +107,10 @@ void Effect::_Draw()const{
}
void Effect::Draw(const Pixel blendCol)const{
+ if(GetZ()>0){
+ vf2d shadowScale=vf2d{8*size.x/3.f,1}/std::max(1.f,GetZ()/24);
+ game->view.DrawDecal(pos-vf2d{3,3}*shadowScale/2+vf2d{0,6*size.x},GFX["circle.png"].Decal(),shadowScale,BLACK);
+ }
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,blendCol);
}
diff --git a/Adventures in Lestoria/Effect.h b/Adventures in Lestoria/Effect.h
index 1eea2bc6..5b2e9e54 100644
--- a/Adventures in Lestoria/Effect.h
+++ b/Adventures in Lestoria/Effect.h
@@ -41,6 +41,7 @@ All rights reserved.
#include
#include
#include "Oscillator.h"
+#include "Entity.h"
class Monster;
class Player;
using HitList=std::unordered_set>;
@@ -224,4 +225,24 @@ private:
const float radius;
const float inkSlowdownDuration;
const float inkSlowdownAmount;
+};
+
+struct FlipCoinEffect:Effect{
+ //cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque
+ FlipCoinEffect(OscillatorstartEndPos,float coinArcRiseZAmt,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);
+ virtual bool Update(float fElapsedTime)override;
+ virtual void Draw(const Pixel blendCol)const override;
+ OscillatorstartEndPos;
+ OscillatorsizeFlipper;
+ OscillatorzRiser;
+};
+
+struct CollectCoinEffect:Effect{
+ //cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque
+ CollectCoinEffect(const Entity attachedTarget,float coinArcRiseZAmt,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);
+ virtual bool Update(float fElapsedTime)override;
+ virtual void Draw(const Pixel blendCol)const override;
+ const Entity attachedTarget;
+ OscillatorsizeFlipper;
+ OscillatorzRiser;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/FlipCoinEffect.cpp b/Adventures in Lestoria/FlipCoinEffect.cpp
new file mode 100644
index 00000000..b1c6caa9
--- /dev/null
+++ b/Adventures in Lestoria/FlipCoinEffect.cpp
@@ -0,0 +1,58 @@
+#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 "Effect.h"
+#include "AdventuresInLestoria.h"
+#include "DEFINES.h"
+#include "util.h"
+
+INCLUDE_game
+
+FlipCoinEffect::FlipCoinEffect(OscillatorstartEndPos,float coinArcRiseZAmt,float lifetime,const std::string&imgFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
+ :Effect(startEndPos.first,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending),startEndPos(startEndPos),sizeFlipper(-1.f,1.f,lifetime*2.f),zRiser(0.f,coinArcRiseZAmt,1/lifetime){
+}
+bool FlipCoinEffect::Update(float fElapsedTime){
+ zRiser.Update(fElapsedTime);
+ pos=startEndPos.Update(fElapsedTime);
+ size.y=sizeFlipper.Update(fElapsedTime);
+ z=zRiser.get();
+ return Effect::Update(fElapsedTime);
+}
+void FlipCoinEffect::Draw(const Pixel blendCol)const{
+ Effect::Draw(blendCol);
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/GhostOfPirateCaptain.cpp b/Adventures in Lestoria/GhostOfPirateCaptain.cpp
index b7b801d6..c3535a61 100644
--- a/Adventures in Lestoria/GhostOfPirateCaptain.cpp
+++ b/Adventures in Lestoria/GhostOfPirateCaptain.cpp
@@ -100,15 +100,25 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
}
m.F(A::GHOST_SABER_TIMER)-=fElapsedTime;
+ m.F(A::LAST_COLLISION_TIMER)-=fElapsedTime;
if(m.B(A::FIRST_WAVE_COMPLETE)){
- m.UpdateFacingDirection(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));
- m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*100.f*m.GetMoveSpdMult());
- const float distToPlayer{util::distance(m.GetPos(),game->GetPlayer()->GetPos())};
- if(m.F(A::GHOST_SABER_TIMER)<=0.f&&distToPlayer<=ConfigPixels("Ghost Saber Activation Range")){
- 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"),ConfigFloat("Ghost Saber Expand Spd"),ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")))EndBullet;
+ if(m.F(A::LAST_COLLISION_TIMER)<=0.f){
+ m.UpdateFacingDirection(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));
+ m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*100.f*m.GetMoveSpdMult());
+ const float distToPlayer{util::distance(m.GetPos(),game->GetPlayer()->GetPos())};
+ if(m.F(A::GHOST_SABER_TIMER)<=0.f&&distToPlayer<=ConfigPixels("Ghost Saber Activation Range")){
+ 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"),ConfigFloat("Ghost Saber Expand Spd"),ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")))EndBullet;
+ }
+ }
+ if(m.B(A::COLLIDED_WITH_PLAYER)){
+ m.PerformAnimation("SLASHING");
+ m.F(A::GHOST_SABER_SLASH_ANIMATION_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration();
+ m.F(A::LAST_COLLISION_TIMER)=ConfigFloat("Collision Recovery Time");
+ m.I(A::PREVIOUS_PHASE)=PHASE();
+ SETPHASE(GHOSTSABER_SLASH);
}
}
@@ -119,6 +129,12 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
SHRAPNEL_SHOT,
};
case INIT:{
+ m.SetStrategyDeathFunction([](GameEvent&ev,Monster&m,const std::string&strategy){
+ for(std::shared_ptr&m:MONSTER_LIST){
+ if(m->IsAlive())m->_DealTrueDamage(m->GetHealth(),HurtFlag::NONE);
+ }
+ return false;
+ });
for(int i:std::ranges::iota_view(0U,PHASE_COUNT)){
const int cannonCycle{DATA.GetProperty("MonsterStrategy.Ghost of Pirate Captain.Cannon Cycle").GetInt(i)};
m.VEC(A::CANNON_PHASES).emplace_back(cannonCycle);
@@ -183,8 +199,11 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
}
if(Config("Curse Thresholds").GetValueCount()>m.I(A::CURSE_THRESHOLD_ARRAY_IND)&&
- m.GetHealthRatio()<=ConfigFloatArr("Curse Thresholds",m.I(A::CURSE_THRESHOLD_ARRAY_IND))){
+ m.GetHealthRatio()<=ConfigFloatArr("Curse Thresholds",m.I(A::CURSE_THRESHOLD_ARRAY_IND))/100.f){
m.I(A::CURSE_THRESHOLD_ARRAY_IND)++;
+ m.F(A::TOSS_COIN_WAIT_TIMER)=ConfigFloat("Coin Toss Pause Time");
+ m.V(A::TOSS_COIN_TARGET)=game->GetPlayer()->GetPos();
+ game->AddEffect(std::make_unique(Oscillator{m.GetPos(),m.V(A::TOSS_COIN_TARGET),1.f/m.F(A::TOSS_COIN_WAIT_TIMER)/2.f},ConfigFloat("Coin Toss Rise Amount"),m.F(A::TOSS_COIN_WAIT_TIMER),"coin.png",m.OnUpperLevel(),3.f));
SETPHASE(TOSS_COIN);
}
}break;
@@ -203,9 +222,15 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
}
}break;
case TOSS_COIN:{
- const float curseDmgPctOverTime{ConfigFloat("Curse Damage")};
- game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE,ConfigFloat("Curse Damage Wait Time"),ceil(game->GetPlayer()->GetMaxHealth()*ConfigFloat("Curse Damage")/100.f)+1,[curseDmgPctOverTime](Player*attachedTarget,Buff&b){attachedTarget->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT,BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_PCT_DAMAGE_OVER_TIME,INFINITY,curseDmgPctOverTime,1.f);});
- SETPHASE(NORMAL);
+ m.F(A::TOSS_COIN_WAIT_TIMER)-=fElapsedTime;
+ if(m.F(A::TOSS_COIN_WAIT_TIMER)<=0.f){
+ const float curseDmgPctOverTime{ConfigFloat("Curse Damage")};
+ game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_PRECURSE,ConfigFloat("Curse Damage Wait Time"),ceil(game->GetPlayer()->GetMaxHealth()*ConfigFloat("Curse Damage")/100.f)+1,[curseDmgPctOverTime](Player*attachedTarget,Buff&b){
+ attachedTarget->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT,BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_PCT_DAMAGE_OVER_TIME,INFINITY,curseDmgPctOverTime,1.f);
+ });
+ game->SpawnMonster(m.V(A::TOSS_COIN_TARGET),MONSTER_DATA["Pirate's Coin"],m.OnUpperLevel());
+ SETPHASE(NORMAL);
+ }
}break;
}
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/HurtDamageInfo.h b/Adventures in Lestoria/HurtDamageInfo.h
index d2f444fb..df0613b7 100644
--- a/Adventures in Lestoria/HurtDamageInfo.h
+++ b/Adventures in Lestoria/HurtDamageInfo.h
@@ -39,9 +39,10 @@ All rights reserved.
namespace HurtFlag{
enum HurtFlag{
- NONE = 0b00,
- PLAYER_ABILITY = 0b01, //Specifically use this flag for player auto attacks or Abilities only! (Identifies these attacks for the Trapper class)
- DOT = 0b10, //Damage over time ability.
+ NONE = 0b000,
+ PLAYER_ABILITY = 0b001, //Specifically use this flag for player auto attacks or Abilities only! (Identifies these attacks for the Trapper class)
+ DOT = 0b010, //Damage over time ability.
+ NO_DAMAGE_NUMBER = 0b100, //This flag ensures no damage number appears.
};
}
diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp
index 35681627..6f0567b3 100644
--- a/Adventures in Lestoria/Monster.cpp
+++ b/Adventures in Lestoria/Monster.cpp
@@ -787,8 +787,7 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da
const Buff specialMarkBuff{GetBuffs(BuffType::SPECIAL_MARK)[0]};
if(game->GetPlayer()->HasEnchant("Opportunity Shot")&&specialMarkBuff.originalDuration-specialMarkBuff.duration<="Opportunity Shot"_ENC["MARK TRIGGER TIME"])Trapper::ability1.cooldown-="Opportunity Shot"_ENC["MARK COOLDOWN REDUCE"];
RemoveSpecialMarkStack();
- }else
- if(GetMarkStacks()>0){
+ }else if(GetMarkStacks()>0){
ApplyMarkEffects();
RemoveMarkStack();
}
@@ -811,33 +810,35 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da
if(GetBuffs(BuffType::CURSE_OF_DEATH).size()>0)accumulatedCurseOfDeathDamage+=mod_dmg;
- if(IsDOT){
- if(lastDotTimer>0){
- dotNumberPtr.get()->AddDamage(int(mod_dmg));
- }else{
- dotNumberPtr=std::make_shared(pos+vf2d{0,8.f},int(mod_dmg),false,DamageNumberType::DOT);
- DAMAGENUMBER_LIST.push_back(dotNumberPtr);
- }
- lastDotTimer=0.05f;
- }else{
- if(lastHitTimer>0){
- damageNumberPtr.get()->AddDamage(int(mod_dmg));
- damageNumberPtr.get()->SetPauseTimer(0.4f);
- }else{
- damageNumberPtr=std::make_shared(pos,int(mod_dmg));
- DAMAGENUMBER_LIST.push_back(damageNumberPtr);
- }
- #pragma region Change Label based on bonus conditions (Crit/Backstab)
- if(crit){
- damageNumberPtr.get()->SetType(DamageNumberType::CRIT);
+ if(!(hurtFlags&HurtFlag::NO_DAMAGE_NUMBER)){
+ if(IsDOT){
+ if(lastDotTimer>0){
+ dotNumberPtr.get()->AddDamage(int(mod_dmg));
+ }else{
+ dotNumberPtr=std::make_shared(pos+vf2d{0,8.f},int(mod_dmg),false,DamageNumberType::DOT);
+ DAMAGENUMBER_LIST.push_back(dotNumberPtr);
}
- if(damageNumberPtr.get()->GetType()==DamageNumberType::CRIT)goto doneChangingDamageNumberColors; //Crit number priority. Other colors should not apply if the crit has applied.
- if(backstabOccurred){
- damageNumberPtr.get()->SetType(DamageNumberType::BACKSTAB);
+ lastDotTimer=0.05f;
+ }else{
+ if(lastHitTimer>0){
+ damageNumberPtr.get()->AddDamage(int(mod_dmg));
+ damageNumberPtr.get()->SetPauseTimer(0.4f);
+ }else{
+ damageNumberPtr=std::make_shared(pos,int(mod_dmg));
+ DAMAGENUMBER_LIST.push_back(damageNumberPtr);
}
- doneChangingDamageNumberColors:
- #pragma endregion
- lastHitTimer=0.05f;
+ #pragma region Change Label based on bonus conditions (Crit/Backstab)
+ if(crit){
+ damageNumberPtr.get()->SetType(DamageNumberType::CRIT);
+ }
+ if(damageNumberPtr.get()->GetType()==DamageNumberType::CRIT)goto doneChangingDamageNumberColors; //Crit number priority. Other colors should not apply if the crit has applied.
+ if(backstabOccurred){
+ damageNumberPtr.get()->SetType(DamageNumberType::BACKSTAB);
+ }
+ doneChangingDamageNumberColors:
+ #pragma endregion
+ lastHitTimer=0.05f;
+ }
}
attackedByPlayer=true;
diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h
index faf26430..e2a1dec9 100644
--- a/Adventures in Lestoria/Monster.h
+++ b/Adventures in Lestoria/Monster.h
@@ -393,6 +393,7 @@ private:
static void OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string strategy);
static void GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std::string strategy);
static void PIRATES_TREASURE(Monster&m,float fElapsedTime,std::string strategy);
+ static void PIRATES_COIN(Monster&m,float fElapsedTime,std::string strategy);
};
bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame.
bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.
diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h
index bc389698..46d2e4ad 100644
--- a/Adventures in Lestoria/MonsterAttribute.h
+++ b/Adventures in Lestoria/MonsterAttribute.h
@@ -176,4 +176,8 @@ enum class Attribute{
GHOST_SABER_TIMER,
GHOST_SABER_SLASH_ANIMATION_TIMER,
CURSE_THRESHOLD_ARRAY_IND, //Which array index in the curse threshold strategy property we are currently at?
+ TOSS_COIN_WAIT_TIMER,
+ TOSS_COIN_TARGET,
+ LAST_COLLISION_TIMER,
+
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/Oscillator.h b/Adventures in Lestoria/Oscillator.h
index e65fbbfb..9d10a9c0 100644
--- a/Adventures in Lestoria/Oscillator.h
+++ b/Adventures in Lestoria/Oscillator.h
@@ -43,12 +43,12 @@ template
class Oscillator{
friend struct ThrownProjectile;
public:
- inline Oscillator()
- :Oscillator({},{},0.f){}
+ inline Oscillator():Oscillator({},{},0.f){}
+ inline Oscillator(std::pairvals,float cycleSpd):Oscillator(vals.first,vals.second,cycleSpd){}
inline Oscillator(T val1,T val2,float cycleSpd)
:val1(val1),val2(val2),first(this->val1),second(this->val2),cycleSpd(cycleSpd),currentVal(val1){}
inline const T&Update(const float fElapsedTime){
- currentVal=util::lerp(val1,val2,sin(PI*timer*cycleSpd)/2+0.5f);
+ currentVal=util::lerp(val1,val2,sin(2*PI*timer*cycleSpd-PI/2)/2+0.5);
timer+=fElapsedTime;
return get();
}
diff --git a/Adventures in Lestoria/Pirates_Coin.cpp b/Adventures in Lestoria/Pirates_Coin.cpp
new file mode 100644
index 00000000..001f8b56
--- /dev/null
+++ b/Adventures in Lestoria/Pirates_Coin.cpp
@@ -0,0 +1,55 @@
+#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 "AdventuresInLestoria.h"
+#include "MonsterStrategyHelpers.h"
+#include "Entity.h"
+
+using A=Attribute;
+
+INCLUDE_game
+
+void Monster::STRATEGY::PIRATES_COIN(Monster&m,float fElapsedTime,std::string strategy){
+ if(m.B(Attribute::COLLIDED_WITH_PLAYER)){
+ game->AddEffect(std::make_unique(game->GetPlayer(),ConfigFloat("Coin Collect Rise Amount"),ConfigFloat("Coin Rise Timer"),"coin.png",m.OnUpperLevel()),true);
+ game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN,INFINITY,1);
+ m._DealTrueDamage(m.GetHealth(),HurtFlag::NO_DAMAGE_NUMBER);
+ m.SetLifetime(0.f);
+ m.SetSize(0.f,false);
+ }
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/PiratesTreasure.cpp b/Adventures in Lestoria/Pirates_Treasure.cpp
similarity index 91%
rename from Adventures in Lestoria/PiratesTreasure.cpp
rename to Adventures in Lestoria/Pirates_Treasure.cpp
index 9333e164..39179a23 100644
--- a/Adventures in Lestoria/PiratesTreasure.cpp
+++ b/Adventures in Lestoria/Pirates_Treasure.cpp
@@ -45,8 +45,9 @@ void Monster::STRATEGY::PIRATES_TREASURE(Monster&m,float fElapsedTime,std::strin
const float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())};
if(distToPlayer<=ConfigFloat("Open Distance"))m.PerformAnimation("OPEN");
else m.PerformIdleAnimation();
- if(m.B(Attribute::COLLIDED_WITH_PLAYER)){
- game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE);
+ if(m.B(Attribute::COLLIDED_WITH_PLAYER)&&game->GetPlayer()->HasBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN)){
+ game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_PRECURSE);
+ game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN);
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT);
}
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/RUN_STRATEGY.cpp b/Adventures in Lestoria/RUN_STRATEGY.cpp
index fef25d79..c5a0a3fb 100644
--- a/Adventures in Lestoria/RUN_STRATEGY.cpp
+++ b/Adventures in Lestoria/RUN_STRATEGY.cpp
@@ -79,6 +79,7 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("Octopus Arm",Monster::STRATEGY::OCTOPUS_ARM);
STRATEGY_DATA.insert("Ghost of Pirate Captain",Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN);
STRATEGY_DATA.insert("Pirate's Treasure",Monster::STRATEGY::PIRATES_TREASURE);
+ STRATEGY_DATA.insert("Pirate's Coin",Monster::STRATEGY::PIRATES_COIN);
STRATEGY_DATA.SetInitialized();
}
diff --git a/Adventures in Lestoria/Ursule.cpp b/Adventures in Lestoria/Ursule.cpp
index bf2085ea..9bbb00d7 100644
--- a/Adventures in Lestoria/Ursule.cpp
+++ b/Adventures in Lestoria/Ursule.cpp
@@ -305,7 +305,6 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
m.F(A::CASTING_TIMER)=ConfigFloat("Phase 3.Charge Cast Time");
m.UpdateFacingDirection(geom2d::line(m.GetPos(),game->GetPlayer()->GetPos()).vector());
m.PerformAnimation("CHARGE");
- m.B(A::COLLIDED_WITH_PLAYER)=false;
}
}
if(m.F(A::CASTING_TIMER)>0.f){
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index e0de2e5c..87e53357 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 12049
+#define VERSION_BUILD 12094
#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 6f141e61..0c974b58 100644
--- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt
+++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt
@@ -1304,6 +1304,9 @@ MonsterStrategy
# Repeats at end of cycle.
Cannon Cycle = 0,0,0,0,0,0,0,0,1,2,1
+ # How much time to stand still before moving towards the player again.
+ Collision Recovery Time = 3s
+
Cannon Shot Delay = 0.4s
Cannon Shot Impact Time = 2.5s
Silence Time = 2s
@@ -1340,7 +1343,7 @@ MonsterStrategy
Ghost Saber Distance = 48px
Ghost Saber Radius = 8px
Ghost Saber Damage = 75
- Ghost Saber Rotation Spd = 210deg/s
+ Ghost Saber Rotation Spd = 140deg/s
Ghost Saber Knockback Amt = 100
# Amount of pixels/sec the ghost saber circle expands outwards.
Ghost Saber Expand Spd = 14px
@@ -1351,9 +1354,20 @@ MonsterStrategy
Curse Damage Wait Time = 10s
# How much % damage the curse does to the player every second.
Curse Damage = 1%/sec
+ # How much time to pause before moving again.
+ Coin Toss Pause Time = 2s
+ # Highest Z position the coin is tossed up.
+ Coin Toss Rise Amount = 72px
}
Pirate's Treasure
{
Open Distance = 64px
}
+ Pirate's Coin
+ {
+ # How much time the coin rises.
+ Coin Rise Timer = 2s
+ # Highest Z position the collected coin icon appears at.
+ Coin Collect Rise Amount = 36px
+ }
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/assets/config/Monsters.txt b/Adventures in Lestoria/assets/config/Monsters.txt
index b3458575..db3b4ed2 100644
--- a/Adventures in Lestoria/assets/config/Monsters.txt
+++ b/Adventures in Lestoria/assets/config/Monsters.txt
@@ -1906,6 +1906,51 @@ Monsters
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# DROP[0] = Octopus Ring,100%,1,1
+ Hurt Sound = Monster Hurt
+ Death Sound = Slime Dead
+ Walk Sound = Slime Walk
+ }
+ Pirate's Coin
+ {
+ Health = 1
+ Attack = 80
+
+ CollisionDmg = 0
+
+ Immovable = True
+ Invulnerable = True
+
+ Fadeout = False
+
+ Collision Radius = 64
+
+ MoveSpd = 0%
+ Size = 300%
+
+ XP = 0
+
+ Strategy = Pirate's Coin
+
+ #Size of each animation frame
+ SheetFrameSize = 24,24
+
+ # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST
+ 4-Way Spritesheet = False
+
+ Animations
+ {
+ # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse,ReverseOneShot)
+ # Animations must be defined in the same order as they are in their sprite sheets
+ # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
+ IDLE = 1, 1.0, OneShot
+ WALK = 1, 1.0, OneShot
+ SLASHING = 1, 1.0, OneShot
+ OPEN = 1, 1.0, OneShot
+ }
+
+ # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
+ # DROP[0] = Octopus Ring,100%,1,1
+
Hurt Sound = Monster Hurt
Death Sound = Slime Dead
Walk Sound = Slime Walk
diff --git a/Adventures in Lestoria/assets/gamepack.pak b/Adventures in Lestoria/assets/gamepack.pak
index 811e645d..6ee32347 100644
Binary files a/Adventures in Lestoria/assets/gamepack.pak and b/Adventures in Lestoria/assets/gamepack.pak differ
diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe
index 3fdc4706..72952115 100644
Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ