Make player dot damage numbers fall instead of rise as well. Remove unused originalRiseSpd damage number member. Refactor buff repeat action system to instead use internal hard-coded restoration functions. Include the target of buffs inside the buff classes themselves so they know what to interact with. Updated Player and Monster AddBuff functions to represent new buff constructor requirements. Implemented Bear Trap ability. Refactored Monster Hit callback for bullets to send the amount of stacks a monster had before getting hit which is used as getting hurt removed a mark stack. Release Build 10300.

mac-build
sigonasr2 4 months ago
parent b3c5894be7
commit 2420d02f24
  1. 8
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 6
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 2
      Adventures in Lestoria/Animation.cpp
  4. 6
      Adventures in Lestoria/Arrow.cpp
  5. 76
      Adventures in Lestoria/BearTrap.cpp
  6. 4
      Adventures in Lestoria/Bomb.cpp
  7. 101
      Adventures in Lestoria/Buff.cpp
  8. 49
      Adventures in Lestoria/Buff.h
  9. 2
      Adventures in Lestoria/Bullet.cpp
  10. 2
      Adventures in Lestoria/Bullet.h
  11. 73
      Adventures in Lestoria/BulletTypes.h
  12. 6
      Adventures in Lestoria/ChargedArrow.cpp
  13. 4
      Adventures in Lestoria/DaggerSlash.cpp
  14. 4
      Adventures in Lestoria/DaggerStab.cpp
  15. 2
      Adventures in Lestoria/DamageNumber.cpp
  16. 1
      Adventures in Lestoria/DamageNumber.h
  17. 4
      Adventures in Lestoria/DeadlyDash.cpp
  18. 4
      Adventures in Lestoria/Debris.cpp
  19. 6
      Adventures in Lestoria/EnergyBolt.cpp
  20. 2
      Adventures in Lestoria/FallingStone.cpp
  21. 2
      Adventures in Lestoria/Feather.cpp
  22. 6
      Adventures in Lestoria/FireBolt.cpp
  23. 8
      Adventures in Lestoria/FrogTongue.cpp
  24. 1
      Adventures in Lestoria/HurtDamageInfo.h
  25. 19
      Adventures in Lestoria/IBullet.cpp
  26. 6
      Adventures in Lestoria/IBullet.h
  27. 51
      Adventures in Lestoria/Item.cpp
  28. 2
      Adventures in Lestoria/Item.h
  29. 4
      Adventures in Lestoria/LargeStone.cpp
  30. 4
      Adventures in Lestoria/LargeTornado.cpp
  31. 4
      Adventures in Lestoria/LevitatingRock.cpp
  32. 6
      Adventures in Lestoria/LightningBolt.cpp
  33. 25
      Adventures in Lestoria/Monster.cpp
  34. 1
      Adventures in Lestoria/Monster.h
  35. 21
      Adventures in Lestoria/Player.cpp
  36. 3
      Adventures in Lestoria/Player.h
  37. 4
      Adventures in Lestoria/Tornado.cpp
  38. 7
      Adventures in Lestoria/Trapper.cpp
  39. 2
      Adventures in Lestoria/Version.h
  40. 4
      Adventures in Lestoria/Wisp.cpp
  41. BIN
      Adventures in Lestoria/assets/bear_trap.png
  42. 12
      Adventures in Lestoria/assets/config/audio/events.txt
  43. 12
      Adventures in Lestoria/assets/config/classes/Trapper.txt
  44. 1
      Adventures in Lestoria/assets/config/gfx/gfx.txt
  45. 2
      Adventures in Lestoria/assets/config/items/ItemScript.txt
  46. BIN
      Adventures in Lestoria/assets/gamepack.pak
  47. BIN
      Adventures in Lestoria/assets/sounds/place_down.ogg
  48. BIN
      Adventures in Lestoria/assets/sounds/trap_hit.ogg
  49. BIN
      x64/Release/Adventures in Lestoria.exe

@ -732,6 +732,10 @@
<SubType> <SubType>
</SubType> </SubType>
</ClCompile> </ClCompile>
<ClCompile Include="BearTrap.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="BlacksmithCraftingWindow.cpp"> <ClCompile Include="BlacksmithCraftingWindow.cpp">
<SubType> <SubType>
</SubType> </SubType>
@ -748,6 +752,10 @@
<SubType> <SubType>
</SubType> </SubType>
</ClCompile> </ClCompile>
<ClCompile Include="Buff.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Bullet.cpp"> <ClCompile Include="Bullet.cpp">
<SubType> <SubType>
</SubType> </SubType>

@ -1139,6 +1139,12 @@
<ClCompile Include="Bullet.cpp"> <ClCompile Include="Bullet.cpp">
<Filter>Source Files\Bullet Types</Filter> <Filter>Source Files\Bullet Types</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="BearTrap.cpp">
<Filter>Source Files\Bullet Types</Filter>
</ClCompile>
<ClCompile Include="Buff.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="cpp.hint" /> <None Include="cpp.hint" />

@ -341,6 +341,8 @@ void sig::Animation::InitializeAnimations(){
ANIMATION_DATA["target.png"]=targetAnim; ANIMATION_DATA["target.png"]=targetAnim;
#pragma endregion #pragma endregion
CreateHorizontalAnimationSequence("bear_trap.png",3,{24,24},AnimationData{.frameDuration{0.1f},.style{Animate2D::Style::PingPong}});
for(auto&dat:GFX){ for(auto&dat:GFX){
std::string imgFile=dat.first; std::string imgFile=dat.first;
if(!ANIMATION_DATA.count(imgFile)){ if(!ANIMATION_DATA.count(imgFile)){

@ -97,13 +97,13 @@ BulletDestroyState Arrow::PlayerHit(Player*player)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState Arrow::MonsterHit(Monster& monster) BulletDestroyState Arrow::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{ {
fadeOutTime=0.2f; fadeOutTime=0.2f;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25));
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void Arrow::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void Arrow::ModifyOutgoingDamageData(HurtDamageInfo&data){
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -0,0 +1,76 @@
#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 "BulletTypes.h"
#include "AdventuresInLestoria.h"
INCLUDE_ANIMATION_DATA
INCLUDE_game
BearTrap::BearTrap(vf2d pos,float radius,int damage,float fadeinTime,float fadeoutTime,bool upperLevel,bool hitsMultiple,float lifetime,bool friendly,Pixel col,vf2d scale)
:Bullet(pos,{},radius,damage,"Ability Icons/bear_trap.png",upperLevel,hitsMultiple,lifetime,false,friendly,col,scale,0.f,"Trap Hit"){
fadeInTime=fadeinTime;
animation.AddState("bear_trap.png",ANIMATION_DATA["bear_trap.png"]);
if(!friendly)ERR("WARNING! Trying to use unimplemented enemy version of the Bear Trap Bullet!");
}
void BearTrap::ModifyOutgoingDamageData(HurtDamageInfo&data){
data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
}
BulletDestroyState BearTrap::PlayerHit(Player*player){
fadeOutTime=0.5f;
animation.ChangeState(internal_animState,"bear_trap.png");
return BulletDestroyState::KEEP_ALIVE;
}
BulletDestroyState BearTrap::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
fadeOutTime=0.5f;
animation.ChangeState(internal_animState,"bear_trap.png");
const float bleedDamage{"Trapper.Ability 2.Marked Target Bleed"_f[0]/100.f*game->GetPlayer()->GetAttack()};
const float bleedDuration{"Trapper.Ability 2.Marked Target Bleed"_f[1]};
const float timeBetweenTicks{"Trapper.Ability 2.Marked Target Bleed"_f[2]};
if(markStacksBeforeHit>0){
const uint8_t resetStackCount{uint8_t("Trapper.Ability 2.Marked Target Stack Count Reset"_I)+1U}; //Add an additional stack because we know the target hit is about to lose one stack.
const uint8_t numberOfStacksToReplenish{uint8_t(resetStackCount-monster.GetMarkStacks())};
monster.ApplyMark("Trapper.Ability 2.Marked Target Reset Time"_F,numberOfStacksToReplenish);
monster.AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,bleedDuration,bleedDamage,timeBetweenTicks);
}
return BulletDestroyState::KEEP_ALIVE;
}

@ -97,7 +97,7 @@ void Bomb::Update(float fElapsedTime){
BulletDestroyState Bomb::PlayerHit(Player*player){ BulletDestroyState Bomb::PlayerHit(Player*player){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState Bomb::MonsterHit(Monster&monster){ BulletDestroyState Bomb::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
@ -106,4 +106,4 @@ void Bomb::Draw(const Pixel blendCol)const{
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},bomb_animation.GetFrame(animation).GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,bomb_animation.GetFrame(animation).GetSourceRect().size/2,bomb_animation.GetFrame(animation).GetSourceRect().pos,bomb_animation.GetFrame(animation).GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,uint8_t(util::lerp(col.a,0,1-((fadeOutTime-GetFadeoutTimer())/fadeOutTime)))}); game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},bomb_animation.GetFrame(animation).GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,bomb_animation.GetFrame(animation).GetSourceRect().size/2,bomb_animation.GetFrame(animation).GetSourceRect().pos,bomb_animation.GetFrame(animation).GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,uint8_t(util::lerp(col.a,0,1-((fadeOutTime-GetFadeoutTimer())/fadeOutTime)))});
} }
void Bomb::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void Bomb::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -0,0 +1,101 @@
#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 "Buff.h"
#include "Player.h"
#include "Monster.h"
Buff::Buff(std::variant<Player*,Monster*>attachedTarget,BuffType type,float duration,float intensity)
:attachedTarget(attachedTarget),type(type),duration(duration),intensity(intensity){}
Buff::Buff(std::variant<Player*,Monster*>attachedTarget,BuffType type,float duration,float intensity,std::set<ItemAttribute> attr)
:attachedTarget(attachedTarget),type(type),duration(duration),intensity(intensity),attr(attr){}
Buff::Buff(std::variant<Player*,Monster*>attachedTarget,BuffType type,float duration,float intensity,std::set<std::string> attr)
:attachedTarget(attachedTarget),type(type),duration(duration),intensity(intensity){
for(const std::string&s:attr){
this->attr.insert(ItemAttribute::attributes.at(s));
}
}
Buff::Buff(std::variant<Player*,Monster*>attachedTarget,BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks)
:attachedTarget(attachedTarget),type(type==BuffRestorationType::OVER_TIME||type==BuffRestorationType::ONE_OFF?OVER_TIME:OVER_TIME_DURING_CAST),duration(duration),intensity(intensity),nextTick(duration-timeBetweenTicks),timeBetweenTicks(timeBetweenTicks),overTimeType(overTimeType){}
void Buff::Update(AiL*game,float fElapsedTime){
duration-=fElapsedTime;
if(enabled&&overTimeType.has_value()&&nextTick>0&&duration<nextTick){
BuffTick(game,fElapsedTime);
nextTick-=timeBetweenTicks;
if(type==ONE_OFF)enabled=false;
}
}
void Buff::BuffTick(AiL*game,float fElapsedTime){
if(!overTimeType.has_value())ERR("WARNING! Trying to run BuffTick without a valid over time type provided! THIS SHOULD NOT BE HAPPENING!");
using enum BuffOverTimeType::BuffOverTimeType;
switch(int(overTimeType.value())){
case HP_RESTORATION:{
IfEntity(Player)GetEntity(Player)->Heal(intensity);
else IfEntity(Monster)GetEntity(Monster)->Heal(intensity);
else ERR("WARNING! Buff Over Time attached Target is somehow not a Player nor a Monster Pointer! THIS SHOULD NOT BE HAPPENING!")
}break;
case MP_RESTORATION:{
IfEntity(Player)GetEntity(Player)->RestoreMana(intensity);
else IfEntity(Monster)ERR("WARNING! Monsters don't have mana, this functionality is not supported!")
else ERR("WARNING! Buff Over Time attached Target is somehow not a Player nor a Monster Pointer! THIS SHOULD NOT BE HAPPENING!")
}break;
case HP_PCT_RESTORATION:{
IfEntity(Player)GetEntity(Player)->Heal(GetEntity(Player)->GetMaxHealth()*intensity/100.f);
else IfEntity(Monster)GetEntity(Monster)->Heal(GetEntity(Monster)->GetMaxHealth()*intensity/100.f);
else ERR("WARNING! Buff Over Time attached Target is somehow not a Player nor a Monster Pointer! THIS SHOULD NOT BE HAPPENING!")
}break;
case MP_PCT_RESTORATION:{
IfEntity(Player)GetEntity(Player)->RestoreMana(GetEntity(Player)->GetMaxMana()*intensity/100.f);
else IfEntity(Monster)ERR("WARNING! Monsters don't have mana, this functionality is not supported!")
else ERR("WARNING! Buff Over Time attached Target is somehow not a Player nor a Monster Pointer! THIS SHOULD NOT BE HAPPENING!")
}break;
case HP_DAMAGE_OVER_TIME:{
IfEntity(Player)GetEntity(Player)->Hurt(intensity,GetEntity(Player)->OnUpperLevel(),GetEntity(Player)->GetZ(),HurtFlag::DOT);
else IfEntity(Monster)GetEntity(Monster)->Hurt(intensity,GetEntity(Monster)->OnUpperLevel(),GetEntity(Monster)->GetZ(),HurtFlag::DOT);
else ERR("WARNING! Buff Over Time attached Target is somehow not a Player nor a Monster Pointer! THIS SHOULD NOT BE HAPPENING!")
}break;
case HP_PCT_DAMAGE_OVER_TIME:{
IfEntity(Player)GetEntity(Player)->Hurt(GetEntity(Player)->GetMaxHealth()*intensity/100.f,GetEntity(Player)->OnUpperLevel(),GetEntity(Player)->GetZ(),HurtFlag::DOT);
else IfEntity(Monster)GetEntity(Monster)->Hurt(GetEntity(Monster)->GetMaxHealth()*intensity/100.f,GetEntity(Monster)->OnUpperLevel(),GetEntity(Monster)->GetZ(),HurtFlag::DOT);
else ERR("WARNING! Buff Over Time attached Target is somehow not a Player nor a Monster Pointer! THIS SHOULD NOT BE HAPPENING!")
}break;
}
}

@ -44,8 +44,6 @@ enum BuffType{
DAMAGE_REDUCTION, DAMAGE_REDUCTION,
SLOWDOWN, SLOWDOWN,
BLOCK_SLOWDOWN, BLOCK_SLOWDOWN,
RESTORATION,
RESTORATION_DURING_CAST,
LOCKON_SPEEDBOOST, //Specifically used for wolves. LOCKON_SPEEDBOOST, //Specifically used for wolves.
SPEEDBOOST, SPEEDBOOST,
BARRIER_DAMAGE_REDUCTION, //Creates a visual barrier around the target BARRIER_DAMAGE_REDUCTION, //Creates a visual barrier around the target
@ -54,8 +52,30 @@ enum BuffType{
SELF_INFLICTED_SLOWDOWN, //Used for monsters and can't be applied by any player abilities. SELF_INFLICTED_SLOWDOWN, //Used for monsters and can't be applied by any player abilities.
ADRENALINE_RUSH, ADRENALINE_RUSH,
TRAPPER_MARK, TRAPPER_MARK,
DAMAGE_OVER_TIME,
OVER_TIME,
ONE_OFF,
OVER_TIME_DURING_CAST,
};
enum class BuffRestorationType{
ONE_OFF,
OVER_TIME,
OVER_TIME_DURING_CAST,
};
namespace BuffOverTimeType{
enum BuffOverTimeType{
HP_RESTORATION,
HP_PCT_RESTORATION,
MP_RESTORATION,
MP_PCT_RESTORATION,
HP_DAMAGE_OVER_TIME,
HP_PCT_DAMAGE_OVER_TIME,
};
}; };
#define IfEntity(type) if(std::holds_alternative<type*>(attachedTarget))
#define GetEntity(type) std::get<type*>(attachedTarget)
class AiL; class AiL;
struct Buff{ struct Buff{
@ -65,17 +85,16 @@ struct Buff{
float intensity=1; float intensity=1;
float nextTick=0; float nextTick=0;
std::set<ItemAttribute> attr; std::set<ItemAttribute> attr;
std::function<void(AiL*,int)>repeatAction; std::variant<Player*,Monster*>attachedTarget; //Who has this buff.
inline Buff(BuffType type,float duration,float intensity)
:type(type),duration(duration),intensity(intensity){} Buff(std::variant<Player*,Monster*>attachedTarget,BuffType type,float duration,float intensity);
inline Buff(BuffType type,float duration,float intensity,std::set<ItemAttribute> attr) Buff(std::variant<Player*,Monster*>attachedTarget,BuffType type,float duration,float intensity,std::set<ItemAttribute> attr);
:type(type),duration(duration),intensity(intensity),attr(attr){} Buff(std::variant<Player*,Monster*>attachedTarget,BuffType type,float duration,float intensity,std::set<std::string> attr);
inline Buff(BuffType type,float duration,float intensity,std::set<std::string> attr) Buff(std::variant<Player*,Monster*>attachedTarget,BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
:type(type),duration(duration),intensity(intensity){
for(const std::string&s:attr){ void Update(AiL*game,float fElapsedTime);
this->attr.insert(ItemAttribute::attributes.at(s)); private:
} bool enabled{true};
} std::optional<BuffOverTimeType::BuffOverTimeType>overTimeType;
inline Buff(BuffType type,float duration,float intensity,float timeBetweenTicks,std::function<void(AiL*,int)>repeatAction) void BuffTick(AiL*game,float fElapsedTime);
:type(type),duration(duration),intensity(intensity),nextTick(duration-timeBetweenTicks),timeBetweenTicks(timeBetweenTicks),repeatAction(repeatAction){}
}; };

@ -43,4 +43,4 @@ Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool fr
//Initializes a bullet with an animation. //Initializes a bullet with an animation.
Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,std::string animation,bool upperLevel,bool hitsMultiple,float lifetime,bool rotatesWithAngle,bool friendly,Pixel col,vf2d scale,float image_angle,std::string_view hitSound) Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,std::string animation,bool upperLevel,bool hitsMultiple,float lifetime,bool rotatesWithAngle,bool friendly,Pixel col,vf2d scale,float image_angle,std::string_view hitSound)
:IBullet(pos,vel,radius,damage,animation,upperLevel,hitsMultiple,lifetime,rotatesWithAngle,friendly,col,scale,image_angle,hitSound){} :IBullet(pos,vel,radius,damage,animation,upperLevel,hitsMultiple,lifetime,rotatesWithAngle,friendly,col,scale,image_angle,hitSound){}
void Bullet::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void Bullet::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -45,5 +45,5 @@ public:
//Initializes a bullet with an animation. //Initializes a bullet with an animation.
Bullet(vf2d pos,vf2d vel,float radius,int damage,std::string animation,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool rotatesWithAngle=false,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle=0.f,std::string_view hitSound=""); Bullet(vf2d pos,vf2d vel,float radius,int damage,std::string animation,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool rotatesWithAngle=false,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle=0.f,std::string_view hitSound="");
protected: protected:
virtual void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); virtual void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };

@ -45,8 +45,8 @@ struct EnergyBolt:public Bullet{
EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE); EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct FireBolt:public Bullet{ struct FireBolt:public Bullet{
@ -54,8 +54,8 @@ struct FireBolt:public Bullet{
FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE); FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct LightningBolt:public Bullet{ struct LightningBolt:public Bullet{
@ -63,8 +63,8 @@ struct LightningBolt:public Bullet{
LightningBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE); LightningBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct Arrow:public Bullet{ struct Arrow:public Bullet{
@ -79,8 +79,8 @@ struct Arrow:public Bullet{
// The perception level can be a value from 0-90 indicating the sweep angle to check beyond the initial aiming angle. // The perception level can be a value from 0-90 indicating the sweep angle to check beyond the initial aiming angle.
const vf2d PointToBestTargetPath(const uint8_t perceptionLevel); const vf2d PointToBestTargetPath(const uint8_t perceptionLevel);
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct ChargedArrow:public Bullet{ struct ChargedArrow:public Bullet{
@ -88,8 +88,8 @@ struct ChargedArrow:public Bullet{
ChargedArrow(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE); ChargedArrow(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct FrogTongue:public Bullet{ struct FrogTongue:public Bullet{
@ -101,17 +101,17 @@ struct FrogTongue:public Bullet{
FrogTongue(Monster&sourceMonster,vf2d targetPos,float lifetime,int damage,bool upperLevel,float knockbackStrength=1.0f,bool friendly=false,Pixel col=WHITE); FrogTongue(Monster&sourceMonster,vf2d targetPos,float lifetime,int damage,bool upperLevel,float knockbackStrength=1.0f,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void Draw(const Pixel blendCol)const override; void Draw(const Pixel blendCol)const override;
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct Wisp:public Bullet{ struct Wisp:public Bullet{
Wisp(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE); Wisp(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
enum class HorizontalFlip{ enum class HorizontalFlip{
@ -139,8 +139,8 @@ struct DaggerStab:public Bullet{
DaggerStab(Monster&sourceMonster,float radius,int damage,const float knockbackAmt,bool upperLevel,const Direction facingDir,const float daggerFrameDuration,const float daggerStabDistance,const DirectionOffsets offsets,bool friendly=false,Pixel col=WHITE); DaggerStab(Monster&sourceMonster,float radius,int damage,const float knockbackAmt,bool upperLevel,const Direction facingDir,const float daggerFrameDuration,const float daggerStabDistance,const DirectionOffsets offsets,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct DaggerSlash:public Bullet{ struct DaggerSlash:public Bullet{
@ -152,8 +152,8 @@ struct DaggerSlash:public Bullet{
DaggerSlash(Monster&sourceMonster,float radius,int damage,const float knockbackAmt,bool upperLevel,const Direction facingDir,const float daggerFrameDuration,const float daggerSlashDistance,bool friendly=false,Pixel col=WHITE); DaggerSlash(Monster&sourceMonster,float radius,int damage,const float knockbackAmt,bool upperLevel,const Direction facingDir,const float daggerFrameDuration,const float daggerSlashDistance,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct Bomb:public Bullet{ struct Bomb:public Bullet{
@ -169,8 +169,8 @@ struct Bomb:public Bullet{
Bomb(const vf2d pos,const float z,const float gravity,const float detonationTime,const float bombFadeoutTime,float bombKnockbackFactor,const vf2d targetPos,const float explosionRadius,const int damage,const bool upperLevel,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1}); Bomb(const vf2d pos,const float z,const float gravity,const float detonationTime,const float bombFadeoutTime,float bombKnockbackFactor,const vf2d targetPos,const float explosionRadius,const int damage,const bool upperLevel,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1});
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
void Draw(const Pixel blendCol)const override; void Draw(const Pixel blendCol)const override;
}; };
@ -192,11 +192,11 @@ struct LevitatingRock:public Bullet{
LevitatingRock(const Monster&attachedTarget,const vf2d&attackingTarget,const float fadeInTime,const float facingRotOffset,const float distance,const float lockOnTime,const float waitTime,const float targetSpd,const float radius,const int damage,const bool upperLevel,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1}); LevitatingRock(const Monster&attachedTarget,const vf2d&attackingTarget,const float fadeInTime,const float facingRotOffset,const float distance,const float lockOnTime,const float waitTime,const float targetSpd,const float radius,const int damage,const bool upperLevel,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1});
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void Draw(const Pixel blendCol)const override; void Draw(const Pixel blendCol)const override;
void AssignMaster(LevitatingRock*masterRock); void AssignMaster(LevitatingRock*masterRock);
const bool IsMaster()const; const bool IsMaster()const;
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct Tornado:public Bullet{ struct Tornado:public Bullet{
@ -210,8 +210,8 @@ struct Tornado:public Bullet{
Tornado(vf2d centerPoint,float distance,float initialRot,float rotSpd,int damage,const float knockupAmt,const float knockbackAmt,const float lifetime,bool upperLevel,bool friendly=false,Pixel col=WHITE,const vf2d scale={1,1}); Tornado(vf2d centerPoint,float distance,float initialRot,float rotSpd,int damage,const float knockupAmt,const float knockbackAmt,const float lifetime,bool upperLevel,bool friendly=false,Pixel col=WHITE,const vf2d scale={1,1});
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct Debris:public Bullet{ struct Debris:public Bullet{
@ -221,8 +221,8 @@ struct Debris:public Bullet{
Debris(const vf2d pos,const vf2d vel,const int damage,const float radius,const float knockbackAmt,const float rotSpd,const float lifetime,bool upperLevel,bool friendly=false,Pixel col=WHITE,const vf2d scale={1,1}); Debris(const vf2d pos,const vf2d vel,const int damage,const float radius,const float knockbackAmt,const float rotSpd,const float lifetime,bool upperLevel,bool friendly=false,Pixel col=WHITE,const vf2d scale={1,1});
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
void Draw(const Pixel blendCol)const override; void Draw(const Pixel blendCol)const override;
}; };
@ -234,13 +234,13 @@ struct LargeTornado:public Bullet{
LargeTornado(vf2d pos,const float suctionAmt,const float knockupAmt,const float knockbackAmt,const int damage,const float radius,const float lifetime,bool upperLevel,bool friendly=false,Pixel col=WHITE,const vf2d scale={1,1}); LargeTornado(vf2d pos,const float suctionAmt,const float knockupAmt,const float knockbackAmt,const int damage,const float radius,const float lifetime,bool upperLevel,bool friendly=false,Pixel col=WHITE,const vf2d scale={1,1});
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct Feather:public Bullet{ struct Feather:public Bullet{
Feather(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle=0.f); Feather(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle=0.f);
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
}; };
struct LargeStone:public Bullet{ struct LargeStone:public Bullet{
@ -249,8 +249,8 @@ public:
protected: protected:
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!! BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
BulletDestroyState MonsterHit(Monster&monster)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
private: private:
const float gravity; const float gravity;
const float fixedTimeStep{1/30.f}; const float fixedTimeStep{1/30.f};
@ -270,7 +270,7 @@ struct FallingStone:public Bullet{
protected: protected:
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
void Draw(const Pixel blendCol)const override; void Draw(const Pixel blendCol)const override;
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
private: private:
const vf2d targetPos; const vf2d targetPos;
const float zVel{}; const float zVel{};
@ -285,7 +285,7 @@ struct DeadlyDash:public Bullet{
DeadlyDash(vf2d startPos,vf2d endPos,float radius,float afterImagesLingeringTime,int damage,float knockbackAmt,bool upperLevel,bool friendly,float afterImagesSpreadDist,const std::string&animation,Pixel col); DeadlyDash(vf2d startPos,vf2d endPos,float radius,float afterImagesLingeringTime,int damage,float knockbackAmt,bool upperLevel,bool friendly,float afterImagesSpreadDist,const std::string&animation,Pixel col);
protected: protected:
void Draw(const Pixel blendCol)const override; void Draw(const Pixel blendCol)const override;
void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags); void ModifyOutgoingDamageData(HurtDamageInfo&data);
private: private:
const vf2d startPos; const vf2d startPos;
const vf2d endPos; const vf2d endPos;
@ -295,3 +295,10 @@ private:
const float knockbackAmt; const float knockbackAmt;
std::string animation; std::string animation;
}; };
struct BearTrap:public Bullet{
BearTrap(vf2d pos,float radius,int damage,float fadeinTime,float fadeoutTime,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1});
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);
};

@ -64,11 +64,11 @@ BulletDestroyState ChargedArrow::PlayerHit(Player*player)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState ChargedArrow::MonsterHit(Monster& monster) BulletDestroyState ChargedArrow::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{ {
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void ChargedArrow::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void ChargedArrow::ModifyOutgoingDamageData(HurtDamageInfo&data){
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -92,11 +92,11 @@ BulletDestroyState DaggerSlash::PlayerHit(Player*player){
Deactivate(); Deactivate();
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState DaggerSlash::MonsterHit(Monster&monster){ BulletDestroyState DaggerSlash::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
game->AddEffect(std::make_unique<Effect>(pos,0,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult()*0.25f,0.25,vf2d{})); game->AddEffect(std::make_unique<Effect>(pos,0,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult()*0.25f,0.25,vf2d{}));
monster.Knockback(util::pointTo(sourceMonster.GetPos(),monster.GetPos())*knockbackAmt); monster.Knockback(util::pointTo(sourceMonster.GetPos(),monster.GetPos())*knockbackAmt);
Deactivate(); Deactivate();
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void DaggerSlash::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void DaggerSlash::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -98,11 +98,11 @@ BulletDestroyState DaggerStab::PlayerHit(Player*player){
Deactivate(); Deactivate();
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState DaggerStab::MonsterHit(Monster&monster){ BulletDestroyState DaggerStab::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
game->AddEffect(std::make_unique<Effect>(pos,0,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult()*0.25f,0.25,vf2d{})); game->AddEffect(std::make_unique<Effect>(pos,0,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult()*0.25f,0.25,vf2d{}));
monster.Knockback(util::pointTo(sourceMonster.GetPos(),monster.GetPos())*knockbackAmt); monster.Knockback(util::pointTo(sourceMonster.GetPos(),monster.GetPos())*knockbackAmt);
Deactivate(); Deactivate();
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void DaggerStab::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void DaggerStab::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -51,13 +51,11 @@ DamageNumber::DamageNumber()
DamageNumber::DamageNumber(vf2d pos,int damage,bool friendly,DamageNumberType::DamageNumberType type): DamageNumber::DamageNumber(vf2d pos,int damage,bool friendly,DamageNumberType::DamageNumberType type):
pos(pos),damage(damage),friendly(friendly),type(type),invertedDirection(type==INTERRUPT),riseSpd(20.f){ pos(pos),damage(damage),friendly(friendly),type(type),invertedDirection(type==INTERRUPT),riseSpd(20.f){
if(type==INTERRUPT||type==MANA_GAIN)riseSpd=40.f; if(type==INTERRUPT||type==MANA_GAIN)riseSpd=40.f;
originalRiseSpd=riseSpd;
RecalculateSize(); RecalculateSize();
} }
void DamageNumber::RecalculateSize(){ void DamageNumber::RecalculateSize(){
float damageMultRatio=damage/game->GetPlayer()->GetEquipStat("Attack")/2.f; float damageMultRatio=damage/game->GetPlayer()->GetEquipStat("Attack")/2.f;
riseSpd=originalRiseSpd;
if(!friendly){ if(!friendly){
float newSize=std::clamp(roundf(damageMultRatio),1.0f,4.0f); float newSize=std::clamp(roundf(damageMultRatio),1.0f,4.0f);

@ -60,7 +60,6 @@ struct DamageNumber{
bool invertedDirection=false; bool invertedDirection=false;
DamageNumberType::DamageNumberType type=DamageNumberType::HEALTH_LOSS; DamageNumberType::DamageNumberType type=DamageNumberType::HEALTH_LOSS;
const static float MOVE_UP_TIME; const static float MOVE_UP_TIME;
float originalRiseSpd=0.f;
DamageNumber(); DamageNumber();
//The friendly flag indicates if the number was for a friendly/player target or if it's for a monster target (set to false) //The friendly flag indicates if the number was for a friendly/player target or if it's for a monster target (set to false)
DamageNumber(vf2d pos,int damage,bool friendly=false,DamageNumberType::DamageNumberType type=DamageNumberType::HEALTH_LOSS); DamageNumber(vf2d pos,int damage,bool friendly=false,DamageNumberType::DamageNumberType type=DamageNumberType::HEALTH_LOSS);

@ -92,7 +92,7 @@ void DeadlyDash::Draw(const Pixel blendCol)const{
} }
} }
void DeadlyDash::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void DeadlyDash::ModifyOutgoingDamageData(HurtDamageInfo&data){
//NOTE: Despite it looking like we modify the damage here, the radius passed to Bullet is 0, so this shouldn't matter anyways, the damage happens in the check in Update() //NOTE: Despite it looking like we modify the damage here, the radius passed to Bullet is 0, so this shouldn't matter anyways, the damage happens in the check in Update()
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -53,7 +53,7 @@ BulletDestroyState Debris::PlayerHit(Player*player){
fadeOutTime=0.5f; fadeOutTime=0.5f;
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState Debris::MonsterHit(Monster&monster){ BulletDestroyState Debris::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
monster.Knockback(vel.norm()*knockbackAmt); monster.Knockback(vel.norm()*knockbackAmt);
fadeOutTime=0.5f; fadeOutTime=0.5f;
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
@ -62,4 +62,4 @@ void Debris::Draw(const Pixel blendCol)const{
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()}+drawOffsetY,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2+image_angle:image_angle,{12,12},vf2d{randomFrame*24.f,0.f},{24,24},scale,blendCol); game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()}+drawOffsetY,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2+image_angle:image_angle,{12,12},vf2d{randomFrame*24.f,0.f},{24,24},scale,blendCol);
} }
void Debris::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void Debris::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -65,13 +65,13 @@ BulletDestroyState EnergyBolt::PlayerHit(Player*player)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState EnergyBolt::MonsterHit(Monster& monster) BulletDestroyState EnergyBolt::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{ {
fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F; fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F));
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void EnergyBolt::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void EnergyBolt::ModifyOutgoingDamageData(HurtDamageInfo&data){
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -89,4 +89,4 @@ void FallingStone::Draw(const Pixel blendCol)const{
Bullet::Draw(blendCol); Bullet::Draw(blendCol);
} }
void FallingStone::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void FallingStone::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -44,4 +44,4 @@ Feather::Feather(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool
SetBulletType(BulletType::FEATHER); SetBulletType(BulletType::FEATHER);
} }
void Feather::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void Feather::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -87,7 +87,7 @@ BulletDestroyState FireBolt::PlayerHit(Player*player)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState FireBolt::MonsterHit(Monster& monster) BulletDestroyState FireBolt::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{ {
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F; fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){ for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
@ -101,6 +101,6 @@ BulletDestroyState FireBolt::MonsterHit(Monster& monster)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void FireBolt::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void FireBolt::ModifyOutgoingDamageData(HurtDamageInfo&data){
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -67,7 +67,7 @@ void FrogTongue::Update(float fElapsedTime){
if(friendly){ if(friendly){
for(std::unique_ptr<Monster>&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(hitList.find(&*m)==hitList.end()&&geom2d::overlaps(m->BulletCollisionHitbox(),tongueLine)){ if(hitList.find(&*m)==hitList.end()&&geom2d::overlaps(m->BulletCollisionHitbox(),tongueLine)){
_MonsterHit(*m); _MonsterHit(*m,m->GetMarkStacks());
hitList.insert(&*m); hitList.insert(&*m);
} }
} }
@ -83,7 +83,7 @@ BulletDestroyState FrogTongue::PlayerHit(Player*player){
} }
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState FrogTongue::MonsterHit(Monster&monster){ BulletDestroyState FrogTongue::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
monster.Hurt(damage,OnUpperLevel(),0); monster.Hurt(damage,OnUpperLevel(),0);
geom2d::line<float>lineToTarget(pos,targetPos); geom2d::line<float>lineToTarget(pos,targetPos);
vf2d drawVec=lineToTarget.vector().norm()*3; vf2d drawVec=lineToTarget.vector().norm()*3;
@ -100,6 +100,6 @@ void FrogTongue::Draw(const Pixel blendCol)const{
game->view.DrawRotatedDecal(tongueEndPos,GFX["tongue_end.png"].Decal(),drawVec.polar().y,{2.f,2.f},{1.f,1.f},col); game->view.DrawRotatedDecal(tongueEndPos,GFX["tongue_end.png"].Decal(),drawVec.polar().y,{2.f,2.f},{1.f,1.f},col);
} }
void FrogTongue::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void FrogTongue::ModifyOutgoingDamageData(HurtDamageInfo&data){
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -51,6 +51,7 @@ enum class TrueDamageFlag{
}; };
struct HurtDamageInfo{ struct HurtDamageInfo{
std::variant<Player*const,Monster*const>targetPtr;
int damage{}; int damage{};
bool onUpperLevel{false}; bool onUpperLevel{false};
float z{}; float z{};

@ -102,15 +102,16 @@ void IBullet::_Update(const float fElapsedTime){
for(std::unique_ptr<Monster>&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(geom2d::overlaps(m->BulletCollisionHitbox(),geom2d::circle(pos,radius))){ if(geom2d::overlaps(m->BulletCollisionHitbox(),geom2d::circle(pos,radius))){
if(hitList.find(&*m)==hitList.end()){ if(hitList.find(&*m)==hitList.end()){
HurtDamageInfo damageData{damage,OnUpperLevel(),z,HurtFlag::NONE}; HurtDamageInfo damageData{&*m,damage,OnUpperLevel(),z,HurtFlag::NONE};
ModifyOutgoingDamageData(damageData.damage,damageData.onUpperLevel,damageData.z,damageData.hurtFlags); ModifyOutgoingDamageData(damageData);
uint8_t markStacksBeforeHit{m->GetMarkStacks()};
if(m->Hurt(damageData)){ if(m->Hurt(damageData)){
if(!hitsMultiple){ if(!hitsMultiple){
if(_MonsterHit(*m)==BulletDestroyState::DESTROY){ if(_MonsterHit(*m,markStacksBeforeHit)==BulletDestroyState::DESTROY){
dead=true; dead=true;
} }
return false; return false;
}else _MonsterHit(*m); }else _MonsterHit(*m,markStacksBeforeHit);
hitList.insert(&*m); hitList.insert(&*m);
} }
} }
@ -119,9 +120,9 @@ void IBullet::_Update(const float fElapsedTime){
} else { } else {
if(geom2d::overlaps(game->GetPlayer()->Hitbox(),geom2d::circle(pos,radius))){ if(geom2d::overlaps(game->GetPlayer()->Hitbox(),geom2d::circle(pos,radius))){
if(hitList.find(game->GetPlayer())==hitList.end()){ if(hitList.find(game->GetPlayer())==hitList.end()){
HurtDamageInfo damageData{damage,OnUpperLevel(),z,HurtFlag::NONE}; HurtDamageInfo damageData{game->GetPlayer(),damage,OnUpperLevel(),z,HurtFlag::NONE};
//NOTE: OnHurt() will potentially change the Damage Data, passing it along to bullet children that might need to modify the flags! //NOTE: OnHurt() will potentially change the Damage Data, passing it along to bullet children that might need to modify the flags!
ModifyOutgoingDamageData(damageData.damage,damageData.onUpperLevel,damageData.z,damageData.hurtFlags); ModifyOutgoingDamageData(damageData);
if(game->GetPlayer()->Hurt(damageData)){ if(game->GetPlayer()->Hurt(damageData)){
if(!hitsMultiple){ if(!hitsMultiple){
if(_PlayerHit(&*game->GetPlayer())==BulletDestroyState::DESTROY){ if(_PlayerHit(&*game->GetPlayer())==BulletDestroyState::DESTROY){
@ -202,8 +203,8 @@ BulletDestroyState IBullet::_PlayerHit(Player*player){
if(hitSound)SoundEffect::PlaySFX(hitSound.value(),pos); if(hitSound)SoundEffect::PlaySFX(hitSound.value(),pos);
return destroyBullet; return destroyBullet;
} }
BulletDestroyState IBullet::_MonsterHit(Monster&monster){ BulletDestroyState IBullet::_MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
const BulletDestroyState destroyBullet=MonsterHit(monster); const BulletDestroyState destroyBullet=MonsterHit(monster,markStacksBeforeHit);
if(iframeTimerOnHit>0.f)monster.ApplyIframes(iframeTimerOnHit); if(iframeTimerOnHit>0.f)monster.ApplyIframes(iframeTimerOnHit);
if(hitSound)SoundEffect::PlaySFX(hitSound.value(),pos); if(hitSound)SoundEffect::PlaySFX(hitSound.value(),pos);
return destroyBullet; return destroyBullet;
@ -212,7 +213,7 @@ BulletDestroyState IBullet::PlayerHit(Player*player){
if(!hitsMultiple)fadeOutTime=0.15f; if(!hitsMultiple)fadeOutTime=0.15f;
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState IBullet::MonsterHit(Monster&monster){ BulletDestroyState IBullet::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
if(!hitsMultiple)fadeOutTime=0.15f; if(!hitsMultiple)fadeOutTime=0.15f;
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }

@ -93,7 +93,7 @@ private:
protected: protected:
float drawOffsetY{}; float drawOffsetY{};
BulletDestroyState _PlayerHit(Player*player); //Return true to destroy the bullet on hit, return false otherwise. THE BULLET HIT HAS ALREADY OCCURRED. BulletDestroyState _PlayerHit(Player*player); //Return true to destroy the bullet on hit, return false otherwise. THE BULLET HIT HAS ALREADY OCCURRED.
BulletDestroyState _MonsterHit(Monster&monster); //Return true to destroy the bullet on hit, return false otherwise. THE BULLET HIT HAS ALREADY OCCURRED. BulletDestroyState _MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit); //Return true to destroy the bullet on hit, return false otherwise. THE BULLET HIT HAS ALREADY OCCURRED.
const float&GetFadeoutTimer()const; const float&GetFadeoutTimer()const;
void SetBulletType(const BulletType type); void SetBulletType(const BulletType type);
const double GetTimeAlive()const; const double GetTimeAlive()const;
@ -114,7 +114,7 @@ public:
virtual BulletDestroyState PlayerHit(Player*player); virtual BulletDestroyState PlayerHit(Player*player);
//Used by special bullets to control custom despawning behavior! Return true when the bullet should be destroyed. Return false to handle it otherwise (like deactivating it instead). You become responsible for getting rid of the bullet. //Used by special bullets to control custom despawning behavior! Return true when the bullet should be destroyed. Return false to handle it otherwise (like deactivating it instead). You become responsible for getting rid of the bullet.
//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!! //DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
virtual BulletDestroyState MonsterHit(Monster&monster); virtual BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit);
Animate2D::Frame GetFrame()const; Animate2D::Frame GetFrame()const;
virtual void Draw(const Pixel blendCol)const; virtual void Draw(const Pixel blendCol)const;
bool OnUpperLevel(); bool OnUpperLevel();
@ -129,5 +129,5 @@ public:
const bool IsActivated()const; const bool IsActivated()const;
const bool IsDeactivated()const; const bool IsDeactivated()const;
const double GetAliveTime()const; const double GetAliveTime()const;
virtual void ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags)=0; virtual void ModifyOutgoingDamageData(HurtDamageInfo&data)=0;
}; };

@ -385,28 +385,24 @@ const uint32_t ItemProps::PropCount(const std::string&prop)const{
else return uint32_t((*scriptProps)[prop].GetValueCount()); else return uint32_t((*scriptProps)[prop].GetValueCount());
} }
const std::unordered_map<std::string,BuffOverTimeType::BuffOverTimeType>ItemInfo::NameToBuffType{
{"HP Restore",BuffOverTimeType::HP_RESTORATION},
{"HP % Restore",BuffOverTimeType::HP_PCT_RESTORATION},
{"MP Restore",BuffOverTimeType::MP_RESTORATION},
{"MP % Restore",BuffOverTimeType::MP_PCT_RESTORATION},
};
void ItemInfo::InitializeScripts(){ void ItemInfo::InitializeScripts(){
ITEM_SCRIPTS["Restore"]=[](AiL*game,ItemProps props){ ITEM_SCRIPTS["Restore"]=[](AiL*game,ItemProps props){
auto ParseItemScriptData=[&](const std::string&propName,std::function<void(AiL*,int)>action){ for(const auto&[propName,buffType]:NameToBuffType){
int restoreAmt=props.GetIntProp(propName); int restoreAmt=props.GetIntProp(propName);
action(game,restoreAmt);
game->GetPlayer()->AddBuff(BuffRestorationType::ONE_OFF,NameToBuffType.at(propName),0.01f,float(restoreAmt),0.0f);
if(restoreAmt>0&&props.PropCount(propName)==3){ if(restoreAmt>0&&props.PropCount(propName)==3){
game->GetPlayer()->AddBuff(RESTORATION,props.GetFloatProp(propName,2),float(restoreAmt),props.GetFloatProp(propName,1),action); game->GetPlayer()->AddBuff(BuffRestorationType::OVER_TIME,NameToBuffType.at(propName),props.GetFloatProp(propName,2),float(restoreAmt),props.GetFloatProp(propName,1));
}
} }
};
ParseItemScriptData("HP Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->Heal(restoreAmt);
});
ParseItemScriptData("HP % Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->Heal(int(game->GetPlayer()->GetMaxHealth()*restoreAmt/100.0f));
});
ParseItemScriptData("MP Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->RestoreMana(restoreAmt);
});
ParseItemScriptData("MP % Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->RestoreMana(int(game->GetPlayer()->GetMaxMana()*props.GetIntProp("MP % Restore")/100.f));
});
return true; return true;
}; };
@ -425,26 +421,15 @@ void ItemInfo::InitializeScripts(){
} }
return true; return true;
}; };
ITEM_SCRIPTS["RestoreDuringCast"]=[&](AiL*game,ItemProps props){ ITEM_SCRIPTS["RestoreDuringCast"]=[](AiL*game,ItemProps props){
auto ParseItemScriptData=[&](const std::string&propName,std::function<void(AiL*,int)>action){ for(const auto&[propName,buffType]:NameToBuffType){
int restoreAmt=props.GetIntProp(propName); int restoreAmt=props.GetIntProp(propName);
action(game,restoreAmt);
game->GetPlayer()->AddBuff(BuffRestorationType::ONE_OFF,NameToBuffType.at(propName),0.01f,float(restoreAmt),0.0f);
if(restoreAmt>0&&props.PropCount(propName)==3){ if(restoreAmt>0&&props.PropCount(propName)==3){
game->GetPlayer()->AddBuff(RESTORATION_DURING_CAST,props.GetFloatProp(propName,2),float(restoreAmt),props.GetFloatProp(propName,1),action); game->GetPlayer()->AddBuff(BuffRestorationType::OVER_TIME_DURING_CAST,NameToBuffType.at(propName),props.GetFloatProp(propName,2),float(restoreAmt),props.GetFloatProp(propName,1));
}
} }
};
ParseItemScriptData("HP Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->Heal(restoreAmt);
});
ParseItemScriptData("HP % Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->Heal(int(game->GetPlayer()->GetMaxHealth()*restoreAmt/100.0f));
});
ParseItemScriptData("MP Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->RestoreMana(restoreAmt);
});
ParseItemScriptData("MP % Restore",[&](AiL*game,int restoreAmt){
game->GetPlayer()->RestoreMana(int(game->GetPlayer()->GetMaxMana()*props.GetIntProp("MP % Restore")/100.f));
});
return true; return true;
}; };

@ -48,6 +48,7 @@ All rights reserved.
#include "FunctionPriming.h" #include "FunctionPriming.h"
#include "IT.h" #include "IT.h"
#include <unordered_set> #include <unordered_set>
#include "Buff.h"
class AiL; class AiL;
class ItemInfo; class ItemInfo;
@ -339,6 +340,7 @@ private:
static void InitializeSets(); static void InitializeSets();
static std::map<std::string,EquipSlot>nameToEquipSlot; static std::map<std::string,EquipSlot>nameToEquipSlot;
static std::vector<std::shared_ptr<Item>>craftableConsumables; static std::vector<std::shared_ptr<Item>>craftableConsumables;
const static std::unordered_map<std::string,BuffOverTimeType::BuffOverTimeType>NameToBuffType;
public: public:
static void InitializeItems(); static void InitializeItems();
ItemInfo(); ItemInfo();

@ -95,8 +95,8 @@ BulletDestroyState LargeStone::PlayerHit(Player*player){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState LargeStone::MonsterHit(Monster&monster){ BulletDestroyState LargeStone::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void LargeStone::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void LargeStone::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -64,7 +64,7 @@ BulletDestroyState LargeTornado::PlayerHit(Player*player){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState LargeTornado::MonsterHit(Monster&monster){ BulletDestroyState LargeTornado::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
if(monster.IgnoresTerrainCollision())return BulletDestroyState::KEEP_ALIVE; //All airborne enemy types won't care about this. if(monster.IgnoresTerrainCollision())return BulletDestroyState::KEEP_ALIVE; //All airborne enemy types won't care about this.
monster.Knockback(util::pointTo(pos,monster.GetPos())*knockbackAmt); monster.Knockback(util::pointTo(pos,monster.GetPos())*knockbackAmt);
@ -75,4 +75,4 @@ BulletDestroyState LargeTornado::MonsterHit(Monster&monster){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void LargeTornado::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void LargeTornado::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -93,7 +93,7 @@ BulletDestroyState LevitatingRock::PlayerHit(Player*player){
player->Knockback(vel/3.f); player->Knockback(vel/3.f);
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState LevitatingRock::MonsterHit(Monster&monster){ BulletDestroyState LevitatingRock::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
if(initialWaitTime>0.f)return BulletDestroyState::KEEP_ALIVE; if(initialWaitTime>0.f)return BulletDestroyState::KEEP_ALIVE;
fadeOutTime=0.5f; fadeOutTime=0.5f;
@ -114,4 +114,4 @@ const bool LevitatingRock::IsMaster()const{
return slaveRocks.size()>0; return slaveRocks.size()>0;
} }
void LevitatingRock::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void LevitatingRock::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -86,7 +86,7 @@ BulletDestroyState LightningBolt::PlayerHit(Player*player)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState LightningBolt::MonsterHit(Monster& monster) BulletDestroyState LightningBolt::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{ {
fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F; fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange));
@ -109,6 +109,6 @@ BulletDestroyState LightningBolt::MonsterHit(Monster& monster)
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void LightningBolt::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){ void LightningBolt::ModifyOutgoingDamageData(HurtDamageInfo&data){
if(friendly)hurtFlags|=HurtFlag::PLAYER_ABILITY; if(friendly)data.hurtFlags|=HurtFlag::PLAYER_ABILITY;
} }

@ -328,14 +328,8 @@ bool Monster::Update(float fElapsedTime){
} }
if(IsAlive()){ if(IsAlive()){
for(std::vector<Buff>::iterator it=buffList.begin();it!=buffList.end();++it){ std::for_each(buffList.begin(),buffList.end(),[&](Buff&b){b.Update(game,fElapsedTime);});
Buff&b=*it; std::erase_if(buffList,[](Buff&b){return b.duration<=0;});
b.duration-=fElapsedTime;
if(b.duration<=0){
it=buffList.erase(it);
if(it==buffList.end())break;
}
}
if(!HasIframes()){ if(!HasIframes()){
for(std::unique_ptr<Monster>&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
const float monsterRadius{GetCollisionRadius()}; const float monsterRadius{GetCollisionRadius()};
@ -674,7 +668,7 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da
dotNumberPtr.get()->RecalculateSize(); dotNumberPtr.get()->RecalculateSize();
}else{ }else{
dotNumberPtr=std::make_shared<DamageNumber>(pos-vf2d{0,GetCollisionRadius()/2.f},int(mod_dmg),false,DamageNumberType::DOT); dotNumberPtr=std::make_shared<DamageNumber>(pos-vf2d{0,GetCollisionRadius()/2.f},int(mod_dmg),false,DamageNumberType::DOT);
dotNumberPtr->riseSpd=dotNumberPtr->originalRiseSpd=-10.f; dotNumberPtr->riseSpd=-10.f;
DAMAGENUMBER_LIST.push_back(dotNumberPtr); DAMAGENUMBER_LIST.push_back(dotNumberPtr);
} }
lastDotTimer=0.05f; lastDotTimer=0.05f;
@ -759,17 +753,17 @@ const bool Monster::OnUpperLevel()const{
} }
void Monster::AddBuff(BuffType type,float duration,float intensity){ void Monster::AddBuff(BuffType type,float duration,float intensity){
buffList.push_back(Buff{type,duration,intensity}); buffList.push_back(Buff{this,type,duration,intensity});
} }
void Monster::AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr){ void Monster::AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr){
if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const ItemAttribute&attr){if(attr.ActualName()!="Health"&&attr.ActualName()!="Health %"&&attr.ActualName()!="Attack"&&attr.ActualName()!="Attack %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr.ActualName()));}); if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const ItemAttribute&attr){if(attr.ActualName()!="Health"&&attr.ActualName()!="Health %"&&attr.ActualName()!="Attack"&&attr.ActualName()!="Attack %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr.ActualName()));});
buffList.emplace_back(type,duration,intensity,attr); buffList.emplace_back(this,type,duration,intensity,attr);
} }
void Monster::AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr){ void Monster::AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr){
if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const std::string&attr){if(attr!="Health"&&attr!="Health %"&&attr!="Attack"&&attr!="Attack %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr));}); if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const std::string&attr){if(attr!="Health"&&attr!="Health %"&&attr!="Attack"&&attr!="Attack %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr));});
buffList.emplace_back(type,duration,intensity,attr); buffList.emplace_back(this,type,duration,intensity,attr);
} }
void Monster::RemoveBuff(BuffType type){ void Monster::RemoveBuff(BuffType type){
@ -956,6 +950,8 @@ void Monster::OnDeath(){
SpawnDrops(); SpawnDrops();
game->GetPlayer()->AddAccumulatedXP(MONSTER_DATA.at(name).GetXP()); game->GetPlayer()->AddAccumulatedXP(MONSTER_DATA.at(name).GetXP());
RemoveBuff(BuffType::TRAPPER_MARK);
} }
const ItemAttributable&Monster::GetStats()const{ const ItemAttributable&Monster::GetStats()const{
@ -1234,6 +1230,7 @@ const uint8_t Monster::GetMarkStacks()const{
} }
void Monster::RemoveMarkStack(){ void Monster::RemoveMarkStack(){
if(!IsAlive())return;
if(GetMarkStacks()<=0)ERR("WARNING! Tried to remove a mark stack, but no stacks exist. THIS SHOULD NOT BE HAPPENING!"); if(GetMarkStacks()<=0)ERR("WARNING! Tried to remove a mark stack, but no stacks exist. THIS SHOULD NOT BE HAPPENING!");
bool removeMarkDebuff{false}; bool removeMarkDebuff{false};
for(Buff&b:buffList){ for(Buff&b:buffList){
@ -1296,3 +1293,7 @@ std::optional<Monster*>Monster::GetNearestMonster(const vf2d point,const float m
const bool Monster::InUndamageableState(const bool onUpperLevel,const float z)const{ const bool Monster::InUndamageableState(const bool onUpperLevel,const float z)const{
return Invulnerable()||!IsAlive()||onUpperLevel!=OnUpperLevel()||AttackAvoided(z); return Invulnerable()||!IsAlive()||onUpperLevel!=OnUpperLevel()||AttackAvoided(z);
} }
void Monster::AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks){
buffList.push_back(Buff{this,type,overTimeType,duration,intensity,timeBetweenTicks});
}

@ -140,6 +140,7 @@ public:
void AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr); void AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr);
//NOTE: If adding a % increase stat, please use the percentage version! 100% = 1!! //NOTE: If adding a % increase stat, please use the percentage version! 100% = 1!!
void AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr); void AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr);
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
std::vector<Buff>GetBuffs(BuffType buff)const; std::vector<Buff>GetBuffs(BuffType buff)const;
//Removes all buffs of a given type. //Removes all buffs of a given type.
void RemoveBuff(BuffType type); void RemoveBuff(BuffType type);

@ -384,13 +384,7 @@ void Player::Update(float fElapsedTime){
manaTickTimer+=0.2f; manaTickTimer+=0.2f;
RestoreMana(1,true); RestoreMana(1,true);
} }
for(Buff&b:buffList){ std::for_each(buffList.begin(),buffList.end(),[&](Buff&b){b.Update(game,fElapsedTime);});
b.duration-=fElapsedTime;
if(b.nextTick>0&&b.duration<b.nextTick){
b.repeatAction(game,b.intensity);
b.nextTick-=b.timeBetweenTicks;
}
}
std::erase_if(buffList,[](Buff&b){return b.duration<=0;}); std::erase_if(buffList,[](Buff&b){return b.duration<=0;});
//Class-specific update events. //Class-specific update events.
OnUpdate(fElapsedTime); OnUpdate(fElapsedTime);
@ -878,6 +872,7 @@ bool Player::Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag dama
dotNumberPtr.get()->RecalculateSize(); dotNumberPtr.get()->RecalculateSize();
}else{ }else{
dotNumberPtr=std::make_shared<DamageNumber>(pos-vf2d{0,8.f},int(mod_dmg),false,DamageNumberType::DOT); dotNumberPtr=std::make_shared<DamageNumber>(pos-vf2d{0,8.f},int(mod_dmg),false,DamageNumberType::DOT);
dotNumberPtr->riseSpd=-10.f;
DAMAGENUMBER_LIST.push_back(dotNumberPtr); DAMAGENUMBER_LIST.push_back(dotNumberPtr);
} }
lastDotTimer=0.05f; lastDotTimer=0.05f;
@ -935,7 +930,7 @@ Key Player::GetFacingDirection(){
void Player::CancelCast(){ void Player::CancelCast(){
bool wasCasting=castInfo.castTimer>0; bool wasCasting=castInfo.castTimer>0;
castInfo={"",0}; castInfo={"",0};
std::erase_if(buffList,[](Buff&b){return b.type==RESTORATION_DURING_CAST;}); //Remove all buffs that would be applied during a cast, as we got interrupted. std::erase_if(buffList,[](Buff&b){return b.type==OVER_TIME_DURING_CAST;}); //Remove all buffs that would be applied during a cast, as we got interrupted.
if(wasCasting){ if(wasCasting){
DAMAGENUMBER_LIST.push_back(std::make_shared<DamageNumber>(GetPos(),0,true,DamageNumberType::INTERRUPT)); DAMAGENUMBER_LIST.push_back(std::make_shared<DamageNumber>(GetPos(),0,true,DamageNumberType::INTERRUPT));
} }
@ -1028,18 +1023,18 @@ void Player::UpdateIdleAnimation(Key direction){
} }
void Player::AddBuff(BuffType type,float duration,float intensity){ void Player::AddBuff(BuffType type,float duration,float intensity){
buffList.push_back(Buff{type,duration,intensity}); buffList.push_back(Buff{this,type,duration,intensity});
} }
void Player::AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr){ void Player::AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr){
if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const ItemAttribute&attr){if(attr.ActualName()!="Health"&&attr.ActualName()!="Health %"&&attr.ActualName()!="Attack"&&attr.ActualName()!="Attack %"&&attr.ActualName()!="Defense"&&attr.ActualName()!="Defense %"&&attr.ActualName()!="CDR"&&attr.ActualName()!="Move Spd %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr.ActualName()));}); if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const ItemAttribute&attr){if(attr.ActualName()!="Health"&&attr.ActualName()!="Health %"&&attr.ActualName()!="Attack"&&attr.ActualName()!="Attack %"&&attr.ActualName()!="Defense"&&attr.ActualName()!="Defense %"&&attr.ActualName()!="CDR"&&attr.ActualName()!="Move Spd %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr.ActualName()));});
buffList.push_back(Buff{type,duration,intensity,attr}); buffList.push_back(Buff{this,type,duration,intensity,attr});
} }
void Player::AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr){ void Player::AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr){
if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const std::string&attr){if(attr!="Health"&&attr!="Health %"&&attr!="Attack"&&attr!="Attack %"&&attr!="Defense"&&attr!="Defense %"&&attr!="CDR"&&attr!="Move Spd %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr));}); if(type==STAT_UP)std::for_each(attr.begin(),attr.end(),[](const std::string&attr){if(attr!="Health"&&attr!="Health %"&&attr!="Attack"&&attr!="Attack %"&&attr!="Defense"&&attr!="Defense %"&&attr!="CDR"&&attr!="Move Spd %")ERR(std::format("WARNING! Stat Up Attribute type {} is NOT IMPLEMENTED!",attr));});
buffList.push_back(Buff{type,duration,intensity,attr}); buffList.push_back(Buff{this,type,duration,intensity,attr});
} }
void Player::AddBuff(BuffType type,float duration,float intensity,float timeBetweenTicks,std::function<void(AiL*,int)>repeatAction){ void Player::AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks){
buffList.push_back(Buff{type,duration,intensity,timeBetweenTicks,repeatAction}); buffList.push_back(Buff{this,type,overTimeType,duration,intensity,timeBetweenTicks});
} }
bool Player::OnUpperLevel(){ bool Player::OnUpperLevel(){

@ -103,6 +103,7 @@ class Player{
friend struct Witch; friend struct Witch;
friend class State_GameRun; friend class State_GameRun;
friend class Inventory; friend class Inventory;
friend class ItemInfo;
friend void ItemOverlay::Draw(); friend void ItemOverlay::Draw();
friend class PlayerTests::PlayerTest; friend class PlayerTests::PlayerTest;
friend class ItemTests::ItemTest; friend class ItemTests::ItemTest;
@ -179,7 +180,7 @@ public:
void AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr); void AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr);
//NOTE: If adding a % increase stat, please use the percentage version! 100% = 1!! //NOTE: If adding a % increase stat, please use the percentage version! 100% = 1!!
void AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr); void AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr);
void AddBuff(BuffType type,float duration,float intensity,float timeBetweenTicks,std::function<void(AiL*,int)>repeatAction); void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
const std::vector<Buff>GetBuffs(BuffType buff)const; const std::vector<Buff>GetBuffs(BuffType buff)const;
const std::vector<Buff>GetStatBuffs(const std::vector<std::string>&attr)const; const std::vector<Buff>GetStatBuffs(const std::vector<std::string>&attr)const;

@ -66,7 +66,7 @@ BulletDestroyState Tornado::PlayerHit(Player*player){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState Tornado::MonsterHit(Monster&monster){ BulletDestroyState Tornado::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
if(monster.IgnoresTerrainCollision())return BulletDestroyState::KEEP_ALIVE; //All airborne enemy types won't care about this. if(monster.IgnoresTerrainCollision())return BulletDestroyState::KEEP_ALIVE; //All airborne enemy types won't care about this.
monster.Knockback(util::pointTo(centerPoint,monster.GetPos())*knockbackAmt); monster.Knockback(util::pointTo(centerPoint,monster.GetPos())*knockbackAmt);
@ -77,4 +77,4 @@ BulletDestroyState Tornado::MonsterHit(Monster&monster){
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void Tornado::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void Tornado::ModifyOutgoingDamageData(HurtDamageInfo&data){}

@ -112,10 +112,13 @@ void Trapper::InitializeClassAbilities(){
return true; return true;
}; };
#pragma endregion #pragma endregion
#pragma region Trapper Ability 2 (???) #pragma region Trapper Ability 2 (Bear Trap)
Trapper::ability2.action= Trapper::ability2.action=
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
return false; CreateBullet(BearTrap)(p->GetPos(),"Trapper.Ability 2.Trap Radius"_I,"Trapper.Ability 2.DamageMult"_F*p->GetAttack(),0.2f,0.5f,p->OnUpperLevel(),false,INFINITE,true,WHITE,{1.f,1.f})EndBullet;
SoundEffect::PlaySFX("Place Down Trap",p->GetPos());
p->SetAnimationBasedOnTargetingDirection("SETTRAP",p->GetFacingDirection());
return true;
}; };
#pragma endregion #pragma endregion
#pragma region Trapper Ability 3 (???) #pragma region Trapper Ability 3 (???)

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 3 #define VERSION_PATCH 3
#define VERSION_BUILD 10275 #define VERSION_BUILD 10300
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -54,11 +54,11 @@ BulletDestroyState Wisp::PlayerHit(Player*player){
fadeOutTime="MonsterStrategy.Ursule.Phase 2.Wisp Fadeout Time"_F; fadeOutTime="MonsterStrategy.Ursule.Phase 2.Wisp Fadeout Time"_F;
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
BulletDestroyState Wisp::MonsterHit(Monster&monster){ BulletDestroyState Wisp::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
SoundEffect::PlaySFX("Wisp Hit",monster.GetPos()); SoundEffect::PlaySFX("Wisp Hit",monster.GetPos());
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25,vf2d{},"MonsterStrategy.Ursule.Phase 2.Wisp Color"_Pixel)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25,vf2d{},"MonsterStrategy.Ursule.Phase 2.Wisp Color"_Pixel));
fadeOutTime="MonsterStrategy.Ursule.Phase 2.Wisp Fadeout Time"_F; fadeOutTime="MonsterStrategy.Ursule.Phase 2.Wisp Fadeout Time"_F;
return BulletDestroyState::KEEP_ALIVE; return BulletDestroyState::KEEP_ALIVE;
} }
void Wisp::ModifyOutgoingDamageData(int&damage,bool&onUpperLevel,float&z,HurtFlag::HurtFlag&hurtFlags){} void Wisp::ModifyOutgoingDamageData(HurtDamageInfo&data){}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

@ -186,6 +186,12 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = button_click2.ogg, 30%, 30%, 60% File[0] = button_click2.ogg, 30%, 30%, 60%
} }
Place Down Trap
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = place_down.ogg, 90%
}
Player Hit Player Hit
{ {
CombatSound = True CombatSound = True
@ -310,6 +316,12 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = toggle_off.ogg, 100% File[0] = toggle_off.ogg, 100%
} }
Trap Hit
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = trap_hit.ogg, 70%
}
Unequip Armor Unequip Armor
{ {
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)

@ -66,7 +66,7 @@ Trapper
Cooldown Bar Color 1 = 64, 0, 0, 192 Cooldown Bar Color 1 = 64, 0, 0, 192
Cooldown Bar Color 2 = 128, 0, 0, 192 Cooldown Bar Color 2 = 128, 0, 0, 192
Precast Time = 0 Precast Time = 0.1s
Casting Range = 1200 Casting Range = 1200
Casting Size = 100 Casting Size = 100
} }
@ -81,9 +81,13 @@ Trapper
# Whether or not this ability cancels casts. # Whether or not this ability cancels casts.
CancelCast = 0 CancelCast = 0
DamageMult = 2.5x
Marked Target Reset Time = 7s Marked Target Reset Time = 7s
Marked Target Hit Count Reset = 5 # What to reset the stack count to if a marked target runs into the trap.
Marked Target Bleed = 10%, 10s Marked Target Stack Count Reset = 5
# % of Attack, Duration, Time per tick
Marked Target Bleed = 10%, 10s, 1s
Trap Radius = 11px
#RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown. #RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown.
Cooldown Bar Color 1 = 64, 0, 0, 192 Cooldown Bar Color 1 = 64, 0, 0, 192
@ -104,7 +108,7 @@ Trapper
# Whether or not this ability cancels casts. # Whether or not this ability cancels casts.
CancelCast = 0 CancelCast = 0
Damage = 5.5x DamageMult = 5.5x
Explosion Radius = 200 Explosion Radius = 200
Trap Activation Time = 1.5s Trap Activation Time = 1.5s
Trap Auto Detonate Time = 5s Trap Auto Detonate Time = 5s

@ -111,6 +111,7 @@ Images
GFX_Shine = shine.png GFX_Shine = shine.png
GFX_TargetMark = target.png GFX_TargetMark = target.png
GFX_MarkTrail = mark_trail.png GFX_MarkTrail = mark_trail.png
GFX_BearTrap = bear_trap.png
GFX_Thief_Sheet = nico-thief.png GFX_Thief_Sheet = nico-thief.png
GFX_Trapper_Sheet = nico-trapper.png GFX_Trapper_Sheet = nico-trapper.png

@ -3,6 +3,8 @@ ItemScript
# Used with the Item Database. # Used with the Item Database.
# Any of these properties can be overwritten by specifying them in the main item. # Any of these properties can be overwritten by specifying them in the main item.
# If new scripts are added, please visit Item.cpp (ItemInfo::InitializeScripts()) to implement them.
# Restores stats. # Restores stats.
# Parameter 1: The amount to restore per tick. If parameter 2 is zero, restores this amount instantly. # Parameter 1: The amount to restore per tick. If parameter 2 is zero, restores this amount instantly.
# (Optional) Parameter 2: If non-zero, specifies the amount of time per tick of restoration. # (Optional) Parameter 2: If non-zero, specifies the amount of time per tick of restoration.

Loading…
Cancel
Save