Add pair argument conversion for Oscillator class. Collided with player flag gets set to false each frame. Implement Pirate's Coin/Curse mechanic and spinning/debuff effects. Release Build 12094.

master
sigonasr2 5 days ago
parent 63a97958f7
commit dbf140e0bd
  1. 14
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 11
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 7
      Adventures in Lestoria/AdventuresInLestoria.cpp
  4. 3
      Adventures in Lestoria/Buff.h
  5. 57
      Adventures in Lestoria/CollectedCoinEffect.cpp
  6. 4
      Adventures in Lestoria/Effect.cpp
  7. 21
      Adventures in Lestoria/Effect.h
  8. 58
      Adventures in Lestoria/FlipCoinEffect.cpp
  9. 47
      Adventures in Lestoria/GhostOfPirateCaptain.cpp
  10. 7
      Adventures in Lestoria/HurtDamageInfo.h
  11. 55
      Adventures in Lestoria/Monster.cpp
  12. 1
      Adventures in Lestoria/Monster.h
  13. 4
      Adventures in Lestoria/MonsterAttribute.h
  14. 6
      Adventures in Lestoria/Oscillator.h
  15. 55
      Adventures in Lestoria/Pirates_Coin.cpp
  16. 5
      Adventures in Lestoria/Pirates_Treasure.cpp
  17. 1
      Adventures in Lestoria/RUN_STRATEGY.cpp
  18. 1
      Adventures in Lestoria/Ursule.cpp
  19. 2
      Adventures in Lestoria/Version.h
  20. 16
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  21. 45
      Adventures in Lestoria/assets/config/Monsters.txt
  22. BIN
      Adventures in Lestoria/assets/gamepack.pak
  23. BIN
      x64/Release/Adventures in Lestoria.exe

@ -839,6 +839,10 @@
</SubType>
</ClCompile>
<ClCompile Include="BurstBullet.cpp" />
<ClCompile Include="CollectedCoinEffect.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Crab.cpp" />
<ClCompile Include="Entity.cpp">
<SubType>
@ -852,6 +856,10 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="FlipCoinEffect.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="GhostSaber.cpp">
<SubType>
</SubType>
@ -1114,7 +1122,11 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="PiratesTreasure.cpp">
<ClCompile Include="Pirates_Treasure.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Pirates_Coin.cpp">
<SubType>
</SubType>
</ClCompile>

@ -1304,9 +1304,18 @@
<ClCompile Include="GhostSaber.cpp">
<Filter>Source Files\Bullet Types</Filter>
</ClCompile>
<ClCompile Include="PiratesTreasure.cpp">
<ClCompile Include="Pirates_Treasure.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
<ClCompile Include="Pirates_Coin.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
<ClCompile Include="FlipCoinEffect.cpp">
<Filter>Source Files\Effects</Filter>
</ClCompile>
<ClCompile Include="CollectedCoinEffect.cpp">
<Filter>Source Files\Effects</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

@ -1069,7 +1069,7 @@ void AiL::RenderWorld(float fElapsedTime){
const std::vector<Buff>damageReductionBuffs{player->GetBuffs(BuffType::DAMAGE_REDUCTION)};
const std::vector<Buff>inkSlowdownDebuff{player->GetBuffs(BuffType::INK_SLOWDOWN)};
const std::vector<Buff>curseDebuff{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<Monster>&m:MONSTER_LIST){
m->B(Attribute::COLLIDED_WITH_PLAYER)=false;
}
GetPlayer()->Update(GetElapsedTime());
UpdateMonsters();

@ -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{

@ -0,0 +1,57 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
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);
}

@ -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);
}

@ -41,6 +41,7 @@ All rights reserved.
#include <unordered_set>
#include <variant>
#include "Oscillator.h"
#include "Entity.h"
class Monster;
class Player;
using HitList=std::unordered_set<std::variant<Monster*,Player*>>;
@ -225,3 +226,23 @@ private:
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(Oscillator<vf2d>startEndPos,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;
Oscillator<vf2d>startEndPos;
Oscillator<float>sizeFlipper;
Oscillator<float>zRiser;
};
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;
Oscillator<float>sizeFlipper;
Oscillator<float>zRiser;
};

@ -0,0 +1,58 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
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(Oscillator<vf2d>startEndPos,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);
}

@ -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<Monster>&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<FlipCoinEffect>(Oscillator<vf2d>{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;
}
}

@ -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.
};
}

@ -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<DamageNumber>(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<DamageNumber>(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<DamageNumber>(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<DamageNumber>(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;

@ -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.

@ -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,
};

@ -43,12 +43,12 @@ template<class T>
class Oscillator{
friend struct ThrownProjectile;
public:
inline Oscillator()
:Oscillator({},{},0.f){}
inline Oscillator():Oscillator({},{},0.f){}
inline Oscillator(std::pair<T,T>vals,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();
}

@ -0,0 +1,55 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
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<CollectCoinEffect>(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);
}
}

@ -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);
}
}

@ -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();
}

@ -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<float>(m.GetPos(),game->GetPlayer()->GetPos()).vector());
m.PerformAnimation("CHARGE");
m.B(A::COLLIDED_WITH_PLAYER)=false;
}
}
if(m.F(A::CASTING_TIMER)>0.f){

@ -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

@ -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
}
}

@ -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

Loading…
Cancel
Save