Trapper's Mark Target and Witch's Curse of Pain abilities should not go on cooldown if no target is found. Added purple glow/outline effect to monsters affected by Curse of Pain. Release Build 10363.

mac-build
sigonasr2 4 months ago
parent a35ea5b772
commit ede4bffa7a
  1. 1
      Adventures in Lestoria/Buff.h
  2. 31
      Adventures in Lestoria/Monster.cpp
  3. 3
      Adventures in Lestoria/Monster.h
  4. 7
      Adventures in Lestoria/Player.cpp
  5. 3
      Adventures in Lestoria/Player.h
  6. 17
      Adventures in Lestoria/Trapper.cpp
  7. 2
      Adventures in Lestoria/Version.h
  8. 24
      Adventures in Lestoria/Witch.cpp
  9. BIN
      x64/Release/Adventures in Lestoria.exe

@ -55,6 +55,7 @@ enum BuffType{
OVER_TIME,
ONE_OFF,
OVER_TIME_DURING_CAST,
GLOW_PURPLE,
};
enum class BuffRestorationType{
ONE_OFF,

@ -436,7 +436,14 @@ void Monster::UpdateFacingDirection(vf2d facingTargetPoint){
}
void Monster::Draw()const{
if(markedForDeletion)return;
Pixel blendCol=GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE;
Pixel blendCol{WHITE};
std::optional<std::reference_wrapper<Buff>>glowPurpleBuff;
if(GetBuffs(BuffType::GLOW_PURPLE).size()>0)glowPurpleBuff=GetBuffs(BuffType::GLOW_PURPLE)[0];
if(GetBuffs(BuffType::SLOWDOWN).size()>0)blendCol=Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))};
else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().get().duration)))};
const vf2d hitTimerOffset=vf2d{sin(20*PI*lastHitTimer+randomFrameOffset),0.f}*2.f*GetSizeMult();
const vf2d zOffset=-vf2d{0,GetZ()};
@ -461,12 +468,20 @@ void Monster::Draw()const{
blendCol.a=blendColAlpha;
const float finalSpriteRot=HasFourWaySprites()?0.f:spriteRot; //Prevent 4-way sprites from being rotated.
const vf2d imageScale{vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult())};
const vf2d glowPurpleImageScale{imageScale*1.1f};
game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol);
if(glowPurpleBuff.has_value())game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,glowPurpleImageScale,{43,0,66,blendCol.a});
game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,imageScale,blendCol);
if(overlaySprite.length()!=0){
game->view.DrawPartialRotatedDecal(drawPos,GFX[overlaySprite].Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency});
if(glowPurpleBuff.has_value())game->view.DrawPartialRotatedDecal(drawPos,GFX[overlaySprite].Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,glowPurpleImageScale,{43,0,66,overlaySpriteTransparency});
game->view.DrawPartialRotatedDecal(drawPos,GFX[overlaySprite].Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,imageScale,{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency});
}
if(HasMountedMonster()){
if(glowPurpleBuff.has_value())game->view.DrawPartialRotatedDecal(drawPos+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),finalSpriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,glowPurpleImageScale,{43,0,66,blendCol.a});
game->view.DrawPartialRotatedDecal(drawPos+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),finalSpriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,imageScale,blendCol);
}
if(HasMountedMonster())game->view.DrawPartialRotatedDecal(drawPos+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),finalSpriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol);
std::vector<Buff>shieldBuffs=GetBuffs(BARRIER_DAMAGE_REDUCTION);
if(shieldBuffs.size()>0){
@ -1307,6 +1322,10 @@ void Monster::AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeTyp
buffList.push_back(Buff{GetWeakPointer(),type,overTimeType,duration,intensity,timeBetweenTicks});
}
void Monster::AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallback){
buffList.push_back(Buff{GetWeakPointer(),type,overTimeType,duration,intensity,timeBetweenTicks,expireCallback});
}
const bool Monster::CanMove()const{
return knockUpTimer==0.f&&IsAlive();
}
@ -1315,8 +1334,8 @@ const std::weak_ptr<Monster>Monster::GetWeakPointer()const{
return weakPtr;
}
void Monster::ApplyDot(float duration,int damage,float timeBetweenTicks){
AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,duration,damage,timeBetweenTicks);
void Monster::ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallbackFunc){
AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,duration,damage,timeBetweenTicks,expireCallbackFunc);
}
void Monster::SetWeakPointer(std::shared_ptr<Monster>&sharedMonsterPtr){

@ -141,6 +141,7 @@ public:
//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(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallback);
std::vector<Buff>GetBuffs(BuffType buff)const;
//Removes all buffs of a given type.
void RemoveBuff(BuffType type);
@ -208,7 +209,7 @@ public:
const bool InUndamageableState(const bool onUpperLevel,const float z)const;
const bool CanMove()const;
const std::weak_ptr<Monster>GetWeakPointer()const;
void ApplyDot(float duration,int damage,float timeBetweenTicks);
void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallbackFunc=[](std::weak_ptr<Monster>m,Buff&b){});
private:
//NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
// The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.

@ -1082,6 +1082,9 @@ void Player::AddBuff(BuffType type,float duration,float intensity,std::set<std::
void Player::AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks){
buffList.push_back(Buff{this,type,overTimeType,duration,intensity,timeBetweenTicks});
}
void Player::AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc){
buffList.push_back(Buff{this,type,overTimeType,duration,intensity,timeBetweenTicks,expireCallbackFunc});
}
bool Player::OnUpperLevel(){
return upperLevel;
@ -1831,6 +1834,6 @@ void Player::SetupAfterImage(){
scanLine=1U;
}
void Player::ApplyDot(float duration,int damage,float timeBetweenTicks){
AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,duration,damage,timeBetweenTicks);
void Player::ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc){
AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,duration,damage,timeBetweenTicks,expireCallbackFunc);
}

@ -181,6 +181,7 @@ public:
//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(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc);
const std::vector<Buff>GetBuffs(BuffType buff)const;
const std::vector<Buff>GetStatBuffs(const std::vector<std::string>&attr)const;
@ -290,7 +291,7 @@ public:
const bool IsUsingAdditiveBlending()const;
vf2d MoveUsingPathfinding(vf2d targetPos);
const std::unordered_set<std::string>&GetMyClass()const;
void ApplyDot(float duration,int damage,float timeBetweenTicks);
void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc=[](Player*p,Buff&b){});
private:
int hp="Warrior.BaseHealth"_I;
int mana="Player.BaseMana"_I;

@ -101,15 +101,16 @@ void Trapper::InitializeClassAbilities(){
if(nearestMonster.has_value()){
targetPos=nearestMonster.value().lock()->GetPos();
nearestMonster.value().lock()->ApplyMark("Trapper.Ability 1.Duration"_F,"Trapper.Ability 1.Stack Count"_I);
for(int i:std::ranges::iota_view(0,int(util::distance(p->GetPos(),targetPos)/16))){
float drawDist{i*16.f};
float fadeInTime{i*0.05f};
float fadeOutTime{0.5f+i*0.05f};
float effectSize{util::random(0.4f)};
game->AddEffect(std::make_unique<Effect>(geom2d::line<float>(p->GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",p->OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{255,255,255,uint8_t(util::random_range(60,150))},0.f,0.f,true),true);
}
return true;
}
for(int i:std::ranges::iota_view(0,int(util::distance(p->GetPos(),targetPos)/16))){
float drawDist{i*16.f};
float fadeInTime{i*0.05f};
float fadeOutTime{0.5f+i*0.05f};
float effectSize{util::random(0.4f)};
game->AddEffect(std::make_unique<Effect>(geom2d::line<float>(p->GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",p->OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{255,255,255,uint8_t(util::random_range(60,150))},0.f,0.f,true),true);
}
return true;
return false;
};
#pragma endregion
#pragma region Trapper Ability 2 (Bear Trap)

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

@ -44,6 +44,7 @@ All rights reserved.
#include "SoundEffect.h"
#include "BulletTypes.h"
#include "util.h"
#include <ranges>
INCLUDE_MONSTER_LIST
INCLUDE_BULLET_LIST
@ -131,9 +132,26 @@ void Witch::InitializeClassAbilities(){
[](Player*p,vf2d pos={}){
std::optional<std::weak_ptr<Monster>>curseTarget{Monster::GetNearestMonster(pos,"Witch.Ability 1.Casting Range"_F/100.f*24,p->OnUpperLevel(),p->GetZ())};
if(curseTarget.has_value()&&!curseTarget.value().expired()){
curseTarget.value().lock()->ApplyDot("Witch.Ability 1.Curse Debuff"_f[2],p->GetAttack()*"Witch.Ability 1.Curse Debuff"_f[0],"Witch.Ability 1.Curse Debuff"_f[1]);
}
return true;
const float buffTimeBetweenTicks{"Witch.Ability 1.Curse Debuff"_f[1]};
const float buffDamageMult{"Witch.Ability 1.Curse Debuff"_f[0]};
const float buffDuration{"Witch.Ability 1.Curse Debuff"_f[2]};
curseTarget.value().lock()->ApplyDot(buffDuration,p->GetAttack()*buffDamageMult,buffTimeBetweenTicks,
[](std::weak_ptr<Monster>m,Buff&b){
expireCallbackFunc:
m.lock()->Hurt(game->GetPlayer()->GetAttack()*"Witch.Ability 1.Final Tick Damage"_F,m.lock()->OnUpperLevel(),m.lock()->GetZ(),HurtFlag::DOT);
}
);
curseTarget.value().lock()->AddBuff(BuffType::GLOW_PURPLE,buffDuration,1.f);
const vf2d targetPos{curseTarget.value().lock()->GetPos()};
for(int i:std::ranges::iota_view(0,int(util::distance(p->GetPos(),targetPos)/8))){
float drawDist{i*8.f};
float fadeInTime{i*0.05f};
float fadeOutTime{0.5f+i*0.05f};
float effectSize{util::random(0.2f)};
game->AddEffect(std::make_unique<Effect>(geom2d::line<float>(p->GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",p->OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{100,0,155,uint8_t(util::random_range(0,120))},0.f,0.f),true);
}
return true;
}else return false;
};
#pragma endregion
#pragma region Witch Ability 2 (???)

Loading…
Cancel
Save