Update effects containers to use shared pointers instead of reference wrappers for upcoming ThunderOrb referencing code requirements with LightningBolt effects. Release Build 13018.
Some checks are pending
Emscripten Build / Build_and_Deploy_Web_Build (push) Waiting to run

This commit is contained in:
AMay 2026-03-16 16:01:51 -05:00
parent c0686783d4
commit 9d969bcca8
46 changed files with 160 additions and 177 deletions

View File

@ -810,22 +810,19 @@ void AiL::UpdateCamera(float fElapsedTime){
}
void AiL::UpdateEffects(float fElapsedTime){
for(auto it=EMITTER_LIST.begin();it!=EMITTER_LIST.end();++it){
auto ptr=(*it).get();
ptr->Update(fElapsedTime);
}
for(std::vector<std::unique_ptr<Effect>>::iterator it=backgroundEffects.begin();it!=backgroundEffects.end();++it){
Effect*e=(*it).get();
e->Update(fElapsedTime);
}
for(std::vector<std::unique_ptr<Effect>>::iterator it=foregroundEffects.begin();it!=foregroundEffects.end();++it){
Effect*e=(*it).get();
e->Update(fElapsedTime);
}
std::ranges::for_each(EMITTER_LIST,[&fElapsedTime](const std::unique_ptr<IEmitter>&emitter){
emitter->Update(fElapsedTime);
});
std::ranges::for_each(backgroundEffects,[&fElapsedTime](const std::shared_ptr<Effect>&effect){
effect->Update(fElapsedTime);
});
std::ranges::for_each(foregroundEffects,[&fElapsedTime](const std::shared_ptr<Effect>&effect){
effect->Update(fElapsedTime);
});
std::erase_if(EMITTER_LIST,[](std::unique_ptr<IEmitter>&e){return e->dead;});
std::erase_if(backgroundEffects,[](std::unique_ptr<Effect>&e){return e->dead;});
std::erase_if(foregroundEffects,[](std::unique_ptr<Effect>&e){return e->dead;});
std::erase_if(backgroundEffects,[](std::shared_ptr<Effect>&e){return e->dead;});
std::erase_if(foregroundEffects,[](std::shared_ptr<Effect>&e){return e->dead;});
std::erase_if(DAMAGENUMBER_LIST,[](std::shared_ptr<DamageNumber>&n){return n->IsDead();});
for(auto it=foregroundEffectsToBeInserted.begin();it!=foregroundEffectsToBeInserted.end();++it){
@ -989,8 +986,8 @@ void AiL::PopulateRenderLists(){
std::ranges::sort(MONSTER_LIST,[](std::shared_ptr<Monster>&m1,std::shared_ptr<Monster>&m2){return m1->GetPos().y<m2->GetPos().y;});
std::ranges::sort(ItemDrop::drops,[](ItemDrop&id1,ItemDrop&id2){return id1.GetPos().y<id2.GetPos().y;});
std::ranges::sort(BULLET_LIST,[](std::unique_ptr<IBullet>&b1,std::unique_ptr<IBullet>&b2){return b1->pos.y<b2->pos.y;});
std::ranges::sort(foregroundEffects,[](std::unique_ptr<Effect>&e1,std::unique_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;});
std::ranges::sort(backgroundEffects,[](std::unique_ptr<Effect>&e1,std::unique_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;});
std::ranges::sort(foregroundEffects,[](std::shared_ptr<Effect>&e1,std::shared_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;});
std::ranges::sort(backgroundEffects,[](std::shared_ptr<Effect>&e1,std::shared_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;});
}
void AiL::RenderTile(vi2d pos,TilesheetData tileSheet,int tileSheetIndex,vi2d tileSheetPos){
@ -1066,10 +1063,10 @@ void AiL::RenderWorld(float fElapsedTime){
auto dropsAfterLower{ItemDrop::drops|std::views::filter([&pl](const ItemDrop&drop){return drop.GetPos().y>=pl->GetPos().y&&!drop.OnUpperLevel();})};
auto bulletsUpper{BULLET_LIST|std::views::filter([](const std::unique_ptr<IBullet>&bullet){return bullet->OnUpperLevel();})};
auto bulletsLower{BULLET_LIST|std::views::filter([](const std::unique_ptr<IBullet>&bullet){return !bullet->OnUpperLevel();})};
auto foregroundEffectsUpper{foregroundEffects|std::views::filter([](const std::unique_ptr<Effect>&effect){return effect->OnUpperLevel();})};
auto foregroundEffectsLower{foregroundEffects|std::views::filter([](const std::unique_ptr<Effect>&effect){return !effect->OnUpperLevel();})};
auto backgroundEffectsUpper{backgroundEffects|std::views::filter([](const std::unique_ptr<Effect>&effect){return effect->OnUpperLevel();})};
auto backgroundEffectsLower{backgroundEffects|std::views::filter([](const std::unique_ptr<Effect>&effect){return !effect->OnUpperLevel();})};
auto foregroundEffectsUpper{foregroundEffects|std::views::filter([](const std::shared_ptr<Effect>&effect){return effect->OnUpperLevel();})};
auto foregroundEffectsLower{foregroundEffects|std::views::filter([](const std::shared_ptr<Effect>&effect){return !effect->OnUpperLevel();})};
auto backgroundEffectsUpper{backgroundEffects|std::views::filter([](const std::shared_ptr<Effect>&effect){return effect->OnUpperLevel();})};
auto backgroundEffectsLower{backgroundEffects|std::views::filter([](const std::shared_ptr<Effect>&effect){return !effect->OnUpperLevel();})};
auto upperEndZones{GetActiveZonesForCurrentMap()["EndZone"]|std::views::filter([](const ZoneData&zone){return zone.isUpper;})};
auto endZones{GetActiveZonesForCurrentMap()["EndZone"]|std::views::filter([](const ZoneData&zone){return !zone.isUpper;})};
#pragma endregion
@ -1115,8 +1112,9 @@ void AiL::RenderWorld(float fElapsedTime){
if(player->PoisonArrowAutoAttackReady()&&player->poisonArrowLastParticleTimer==0.f){
const float particleSize{fmod(game->GetRunTime(),0.4f)<0.2f?1.f:1.5f};
game->AddEffect(std::make_unique<Effect>(player->GetPos()-vf2d{0,4.f}-player->GetFacingDirVector()*6.f,0.2f,"energy_particle.png",player->OnUpperLevel(),vf2d{particleSize,particleSize}*1.2f,0.05f,vf2d{},Pixel{0,255,255,120},util::random(2*PI),0.f,true));
game->AddEffect(std::make_unique<Effect>(player->GetPos()-vf2d{0,4.f}-player->GetFacingDirVector()*6.f,0.2f,"energy_particle.png",player->OnUpperLevel(),vf2d{particleSize,particleSize},0.05f,vf2d{},DARK_GREEN,util::random(2*PI)));
game->AddEffect(Effect{player->GetPos()-vf2d{0,4.f}-player->GetFacingDirVector()*6.f,0.2f,"energy_particle.png",player->OnUpperLevel(),vf2d{particleSize,particleSize}*1.2f,0.05f,vf2d{},Pixel{0,255,255,120},util::random(2*PI),0.f,true});
game->AddEffect(Effect{player->GetPos()-vf2d{0,4.f}-player->GetFacingDirVector()*6.f,0.2f,"energy_particle.png",player->OnUpperLevel(),vf2d{particleSize,particleSize},0.05f,vf2d{},DARK_GREEN,util::random(2*PI)});
player->poisonArrowLastParticleTimer=0.15f;
}
@ -1547,7 +1545,7 @@ void AiL::RenderWorld(float fElapsedTime){
m.Draw();
++monstersBeforeLowerIt;
}
for(std::unique_ptr<Effect>&e:backgroundEffectsLower){
for(std::shared_ptr<Effect>&e:backgroundEffectsLower){
e->_Draw();
}
while(dropsBeforeLowerIt!=dropsBeforeLower.end()){
@ -1578,7 +1576,7 @@ void AiL::RenderWorld(float fElapsedTime){
for(std::unique_ptr<IBullet>&b:bulletsLower){
b->_Draw();
}
for(std::unique_ptr<Effect>&e:foregroundEffectsLower){
for(std::shared_ptr<Effect>&e:foregroundEffectsLower){
e->_Draw();
}
#pragma endregion
@ -1854,7 +1852,7 @@ void AiL::RenderWorld(float fElapsedTime){
m.Draw();
++monstersBeforeUpperIt;
}
for(std::unique_ptr<Effect>&e:backgroundEffectsUpper){
for(std::shared_ptr<Effect>&e:backgroundEffectsUpper){
e->_Draw();
}
while(dropsBeforeUpperIt!=dropsBeforeUpper.end()){
@ -1883,7 +1881,7 @@ void AiL::RenderWorld(float fElapsedTime){
for(std::unique_ptr<IBullet>&b:bulletsUpper){
b->_Draw();
}
for(std::unique_ptr<Effect>&e:foregroundEffectsUpper){
for(std::shared_ptr<Effect>&e:foregroundEffectsUpper){
e->_Draw();
}
#pragma endregion
@ -2245,22 +2243,13 @@ void AiL::RenderCooldowns(){
drawutil::DrawAbilityTooltipAtMouseCursor(this);
}
std::pair<ForegroundWrapper,BackgroundWrapper>AiL::AddEffect(std::unique_ptr<Effect>foreground,std::unique_ptr<Effect> background){
ForegroundWrapper foregroundRef{*foreground};
BackgroundWrapper backgroundRef{*background};
AddEffect(std::move(background),true);
AddEffect(std::move(foreground));
return {foregroundRef,backgroundRef};
std::pair<ForegroundWrapper,BackgroundWrapper>AiL::AddEffect(Effect&&foreground,Effect&&background){
return {AddEffect(std::move(foreground)),AddEffect(std::move(background),true)};
}
Effect&AiL::AddEffect(std::unique_ptr<Effect> foreground,bool back){
ForegroundWrapper effectRef{*foreground};
if(back){
backgroundEffectsToBeInserted.emplace_back(std::move(foreground));
} else {
foregroundEffectsToBeInserted.emplace_back(std::move(foreground));
}
return effectRef;
std::weak_ptr<Effect>AiL::AddEffect(Effect&&effect,bool back){
if(back)return backgroundEffectsToBeInserted.emplace_back(std::make_shared<Effect>(effect));
else return foregroundEffectsToBeInserted.emplace_back(std::make_shared<Effect>(effect));
}
vf2d AiL::GetWorldMousePos(){
@ -4548,23 +4537,16 @@ void AiL::AddToSpecialMarkedTargetList(std::tuple<std::weak_ptr<Monster>,StackCo
lockOnSpecialTargets.emplace_back(markData);
}
std::vector<Effect*>AiL::GetForegroundEffects()const{
std::vector<Effect*>outputVec;
std::for_each(foregroundEffects.begin(),foregroundEffects.end(),[&outputVec](const std::unique_ptr<Effect>&eff){outputVec.emplace_back(eff.get());});
return outputVec;
const std::vector<std::shared_ptr<Effect>>&AiL::GetForegroundEffects()const{
return foregroundEffects;
}
std::vector<Effect*>AiL::GetBackgroundEffects()const{
std::vector<Effect*>outputVec;
std::for_each(backgroundEffects.begin(),backgroundEffects.end(),[&outputVec](const std::unique_ptr<Effect>&eff){outputVec.emplace_back(eff.get());});
return outputVec;
const std::vector<std::shared_ptr<Effect>>&AiL::GetBackgroundEffects()const{
return backgroundEffects;
}
[[nodiscard]]std::vector<Effect*>AiL::GetAllEffects()const{
std::vector<Effect*>outputVec;
std::vector<Effect*>foregroundEffects{GetForegroundEffects()};
std::vector<Effect*>backgroundEffects{GetBackgroundEffects()};
std::copy(foregroundEffects.begin(),foregroundEffects.end(),std::back_inserter(outputVec));
std::copy(backgroundEffects.begin(),backgroundEffects.end(),std::back_inserter(outputVec));
return outputVec;
[[nodiscard]]std::vector<std::shared_ptr<Effect>>AiL::GetAllEffects()const{
std::vector<std::shared_ptr<Effect>>allEffects{};
std::ranges::merge(GetForegroundEffects(),GetBackgroundEffects(),std::back_inserter(allEffects));
return allEffects;
}
void AiL::InitializeCamera(){
@ -4631,7 +4613,6 @@ void AiL::ResetLevelStates(){
GetPlayer()->ResetTimers();
}
void AiL::Notification::Update(const float fElapsedTime){
time-=fElapsedTime;
}
@ -4652,12 +4633,10 @@ void AiL::AddNotification(const Notification&n){
AiL::Notification::Notification(const std::string_view message,const float time,const Pixel col)
:message(message),time(time),col(col){}
const std::vector<Effect*>AiL::GetEffect(EffectType type){
std::vector<Effect*>effects{GetAllEffects()};
std::vector<Effect*>matchingEffects{};
std::copy_if(effects.begin(),effects.end(),std::back_inserter(matchingEffects),[&type](const Effect*effect){return effect->GetType()==type;});
return matchingEffects;
const std::vector<std::shared_ptr<Effect>>AiL::GetEffect(EffectType type){
return GetAllEffects()|std::views::filter([&type](const std::shared_ptr<Effect>effect){return effect->GetType()==type;})|std::ranges::to<std::vector>();
}
void AiL::PrecacheNewLevels(){
datafile::INITIAL_SETUP_COMPLETE=false;
datafile cacheTimestampsData;

View File

@ -81,8 +81,8 @@ using HurtListItem=std::pair<std::variant<Monster*,Player*>,HurtReturnValue>;
using HurtList=std::vector<HurtListItem>;
using StackCount=uint8_t;
using MarkTime=float;
using ForegroundWrapper=std::reference_wrapper<Effect>;
using BackgroundWrapper=std::reference_wrapper<Effect>;
using ForegroundWrapper=std::weak_ptr<Effect>;
using BackgroundWrapper=std::weak_ptr<Effect>;
enum class KnockbackCondition{
KNOCKBACK_HURT_TARGETS, //Knockback only targets that took damage.
@ -199,10 +199,10 @@ public:
void RenderHud();
void RenderMenu();
bool MenuClicksDeactivated()const;
std::pair<ForegroundWrapper,BackgroundWrapper>AddEffect(std::unique_ptr<Effect>foreground,std::unique_ptr<Effect>background);
//If back is true, places the effect in the background
Effect&AddEffect(std::unique_ptr<Effect>foreground,bool back=false);
const std::vector<Effect*>GetEffect(EffectType type);
std::pair<ForegroundWrapper,BackgroundWrapper>AddEffect(Effect&&foreground,Effect&&background);
//If back is true, places the effect in the background.
std::weak_ptr<Effect>AddEffect(Effect&&effect,bool back=false);
const std::vector<std::shared_ptr<Effect>>GetEffect(EffectType type);
std::vector<Entity>GetTargetsInRange(vf2d pos,float radius,bool upperLevel,float z,const HurtType hurtTargets)const;
const HurtList Hurt(vf2d pos,float radius,int damage,bool upperLevel,float z,const HurtType hurtTargets,HurtFlag::HurtFlag hurtFlags=HurtFlag::NONE)const;
const HurtList HurtMonsterType(vf2d pos,float radius,int damage,bool upperLevel,float z,const std::string_view monsterName,HurtFlag::HurtFlag hurtFlags=HurtFlag::NONE)const;
@ -339,9 +339,9 @@ public:
void ResetLevelStates();
std::vector<Effect*>GetForegroundEffects()const;
std::vector<Effect*>GetBackgroundEffects()const;
std::vector<Effect*>GetAllEffects()const; //Foreground and background effects in one vector.
const std::vector<std::shared_ptr<Effect>>&GetForegroundEffects()const;
const std::vector<std::shared_ptr<Effect>>&GetBackgroundEffects()const;
std::vector<std::shared_ptr<Effect>>GetAllEffects()const; //Foreground and background effects in one vector.
struct TileGroupData{
vi2d tilePos;
@ -354,7 +354,7 @@ public:
void PrecacheNewLevels();
bool savingFile=false;
private:
std::vector<std::unique_ptr<Effect>>foregroundEffects,backgroundEffects,foregroundEffectsToBeInserted,backgroundEffectsToBeInserted;
std::vector<std::shared_ptr<Effect>>foregroundEffects,backgroundEffects,foregroundEffectsToBeInserted,backgroundEffectsToBeInserted;
std::vector<TileRenderData*>tilesWithCollision,tilesWithoutCollision;
std::vector<vf2d>circleCooldownPoints;
std::vector<vf2d>squareCircleCooldownPoints;

View File

@ -94,7 +94,7 @@ const vf2d Arrow::PointToBestTargetPath(const uint8_t perceptionLevel){
BulletDestroyState Arrow::PlayerHit(Player*player)
{
fadeOutTime=0.2f;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),0.25));
game->AddEffect(Effect{player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),0.25});
if(poisonArrow)player->AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,"Poisonous Arrow"_ENC["POISON DURATION"],damage*("Poisonous Arrow"_ENC["POISON TICK DAMAGE"]/100.f),1.f);
return BulletDestroyState::KEEP_ALIVE;
}
@ -102,7 +102,7 @@ BulletDestroyState Arrow::PlayerHit(Player*player)
BulletDestroyState Arrow::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{
fadeOutTime=0.2f;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25));
game->AddEffect(Effect{monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25});
if(poisonArrow)monster.AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,"Poisonous Arrow"_ENC["POISON DURATION"],damage*("Poisonous Arrow"_ENC["POISON TICK DAMAGE"]/100.f),1.f);
if(game->GetPlayer()->HasEnchant("Burning Arrow")&&markStacksBeforeHit>0&&monster.GetBuffs(BuffType::BURNING_ARROW_BURN).size()<"Burning Arrow"_ENC["MAX BURN STACK"])monster.AddBuff(BuffType::BURNING_ARROW_BURN,BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,"Burning Arrow"_ENC["BURN DURATION"],game->GetPlayer()->GetAttack()*"Burning Arrow"_ENC["BURN DAMAGE"]/100.f,2.f);
return BulletDestroyState::KEEP_ALIVE;

View File

@ -57,5 +57,5 @@ void BlizzardSnowEmitter::Emit(){
const float colorInterpolation{util::random(1)};
const Pixel baseCol{104,215,239};
const uint8_t alpha{uint8_t(util::random_range(96,255))};
game->AddEffect(std::make_unique<FallEffect>(pos+vf2d{xSpd*timeToFall,0.f}+vf2d{dist,angle}.cart(),startingZ,gravity,img_filename,upperLevel,scale*vf2d{1.f,1.f},0.5f,vf2d{xSpd,0.f},Pixel{uint8_t(util::lerp(float(baseCol.r),255.f,colorInterpolation)),uint8_t(util::lerp(float(baseCol.g),255.f,colorInterpolation)),uint8_t(util::lerp(float(baseCol.b),255.f,colorInterpolation)),alpha},util::degToRad(util::random_range(0,360)),util::degToRad(util::random_range(-1.f,1.f)),true,EffectType::BLIZZARD_SNOW));
game->AddEffect(FallEffect{pos+vf2d{xSpd*timeToFall,0.f}+vf2d{dist,angle}.cart(),startingZ,gravity,img_filename,upperLevel,scale*vf2d{1.f,1.f},0.5f,vf2d{xSpd,0.f},Pixel{uint8_t(util::lerp(float(baseCol.r),255.f,colorInterpolation)),uint8_t(util::lerp(float(baseCol.g),255.f,colorInterpolation)),uint8_t(util::lerp(float(baseCol.b),255.f,colorInterpolation)),alpha},util::degToRad(util::random_range(0,360)),util::degToRad(util::random_range(-1.f,1.f)),true,EffectType::BLIZZARD_SNOW});
}

View File

@ -66,7 +66,7 @@ void Bomb::Update(float fElapsedTime){
if(fadeOutTime==0.f){
z=0; //Force the bomb to be grounded.
fadeOutTime=bombFadeoutTime;
game->AddEffect(std::make_unique<BombBoom>(pos,0.f,OnUpperLevel(),vf2d{explosionRadius,explosionRadius}/12.f/1.5f/*Upscale 24x24 to 36x36*/,1.f,vf2d{},WHITE,0.f,0.f,true));
game->AddEffect(BombBoom{pos,0.f,OnUpperLevel(),vf2d{explosionRadius,explosionRadius}/12.f/1.5f/*Upscale 24x24 to 36x36*/,1.f,vf2d{},WHITE,0.f,0.f,true});
SoundEffect::PlaySFX("Bomb Explode",pos);
float distToPlayer=geom2d::line<float>(pos,game->GetPlayer()->GetPos()).length();
if(friendly){

View File

@ -61,7 +61,7 @@ struct FireBolt:public Bullet{
BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
void ModifyOutgoingDamageData(HurtDamageInfo&data)override;
private:
std::optional<std::reference_wrapper<TrailEffect>>flameTrail;
std::weak_ptr<TrailEffect>flameTrail;
};
struct LightningBolt:public Bullet{

View File

@ -61,7 +61,7 @@ void ChargedArrow::Update(float fElapsedTime){
const float normalBeamRadius{12*"Ranger.Ability 2.Radius"_F/100/5};
float laserWidth{radius/normalBeamRadius};
game->AddEffect(std::make_unique<Effect>(midpoint,0.1f,laserGraphic,upperLevel,vf2d{laserWidth,dist*2},0.3f,vf2d{},Pixel{192,128,238},atan2(pos.y-lastLaserPos.y,pos.x-lastLaserPos.x)+PI/2,0,true));
game->AddEffect(Effect{midpoint,0.1f,laserGraphic,upperLevel,vf2d{laserWidth,dist*2},0.3f,vf2d{},Pixel{192,128,238},atan2(pos.y-lastLaserPos.y,pos.x-lastLaserPos.x)+PI/2,0,true});
lastLaserPos=pos;
}
}

View File

@ -87,13 +87,13 @@ void DaggerSlash::Update(float fElapsedTime){
#pragma endregion
}
BulletDestroyState DaggerSlash::PlayerHit(Player*player){
game->AddEffect(std::make_unique<Effect>(pos,0,"lightning_splash_effect.png",upperLevel,player->GetSizeMult()*0.25f,0.25,vf2d{}));
game->AddEffect(Effect{pos,0,"lightning_splash_effect.png",upperLevel,player->GetSizeMult()*0.25f,0.25,vf2d{}});
player->Knockback(util::pointTo(sourceMonster.GetPos(),player->GetPos())*knockbackAmt);
Deactivate();
return BulletDestroyState::KEEP_ALIVE;
}
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(Effect{pos,0,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult()*0.25f,0.25,vf2d{}});
monster.Knockback(util::pointTo(sourceMonster.GetPos(),monster.GetPos())*knockbackAmt);
Deactivate();
return BulletDestroyState::KEEP_ALIVE;

View File

@ -93,13 +93,13 @@ void DaggerStab::Update(float fElapsedTime){
#pragma endregion
}
BulletDestroyState DaggerStab::PlayerHit(Player*player){
game->AddEffect(std::make_unique<Effect>(pos,0,"lightning_splash_effect.png",upperLevel,player->GetSizeMult()*0.25f,0.25,vf2d{}));
game->AddEffect(Effect{pos,0,"lightning_splash_effect.png",upperLevel,player->GetSizeMult()*0.25f,0.25,vf2d{}});
player->Knockback(util::pointTo(sourceMonster.GetPos(),player->GetPos())*knockbackAmt);
Deactivate();
return BulletDestroyState::KEEP_ALIVE;
}
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(Effect{pos,0,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult()*0.25f,0.25,vf2d{}});
monster.Knockback(util::pointTo(sourceMonster.GetPos(),monster.GetPos())*knockbackAmt);
Deactivate();
return BulletDestroyState::KEEP_ALIVE;

View File

@ -56,8 +56,9 @@ class LightningBoltEmitter:public IEmitter{
vf2d startPos,endPos;
bool upperLevel;
void DrawLightningBolt();
void Emit()override;
public:
virtual ~LightningBoltEmitter()=default;
LightningBoltEmitter(vf2d startPos,vf2d endPos,float frequency,float timer,bool upperLevel);
void SetStartEndPos(vf2d startPos,vf2d endPos);
void Emit()override;
};

View File

@ -51,7 +51,7 @@ void EnergyBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){
lastParticleSpawn="Wizard.Auto Attack.ParticleFrequency"_F;
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Auto Attack.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Auto Attack.ParticleSizeRange"_FRange,"Wizard.Auto Attack.ParticleFadeoutTime"_F,vf2d{"Wizard.Auto Attack.ParticleSpeedRange"_FRange,"Wizard.Auto Attack.ParticleSpeedRange"_FRange}));
game->AddEffect(Effect{pos,"Wizard.Auto Attack.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Auto Attack.ParticleSizeRange"_FRange,"Wizard.Auto Attack.ParticleFadeoutTime"_F,vf2d{"Wizard.Auto Attack.ParticleSpeedRange"_FRange,"Wizard.Auto Attack.ParticleSpeedRange"_FRange}});
}
if(distanceTraveled>"Wizard.Auto Attack.Range"_F&&IsActivated()){
fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
@ -61,14 +61,14 @@ void EnergyBolt::Update(float fElapsedTime){
BulletDestroyState EnergyBolt::PlayerHit(Player*player)
{
fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F));
game->AddEffect(Effect{player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F});
return BulletDestroyState::KEEP_ALIVE;
}
BulletDestroyState EnergyBolt::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
{
if(!game->GetPlayer()->HasEnchant("Piercing Bolt"))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(Effect{monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F});
if(hitList.size()==1)damage=ceil(damage*"Piercing Bolt"_ENC["MULTI TARGET DAMAGE"]/100.f);
return BulletDestroyState::KEEP_ALIVE;
}

View File

@ -103,9 +103,8 @@ void ExplosiveTrap::Detonate(){
}
}
std::unique_ptr<Effect>explodeEffect{std::make_unique<Effect>(pos,ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration()-0.2f,"explosionframes.png",OnUpperLevel(),scale*2.f,0.2f,vf2d{0,-6.f},WHITE,util::random(2*PI),0.f)};
explodeEffect->scaleSpd={0.125f,0.125f};
game->AddEffect(std::move(explodeEffect));
std::weak_ptr<Effect>explodeEffect{game->AddEffect(Effect{pos,ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration()-0.2f,"explosionframes.png",OnUpperLevel(),scale*2.f,0.2f,vf2d{0,-6.f},WHITE,util::random(2*PI),0.f})};
explodeEffect.lock()->scaleSpd={0.125f,0.125f};
SoundEffect::PlaySFX("Explosion",pos);
explosionCount--;
if(explosionCount>0)rearmTime=0.6f;

View File

@ -52,7 +52,7 @@ bool FadeInOutEffect::Update(float fElapsedTime){
particleSpawnTimer-=fElapsedTime;
if(particleSpawnTimer<=0.f){
particleSpawnTimer+=originalParticleSpawnTimer;
game->AddEffect(std::make_unique<Effect>(particleGenerator(*this)));
game->AddEffect(Effect{particleGenerator(*this)});
}
}
pos=posOscillator.Update(fElapsedTime);

View File

@ -71,12 +71,12 @@ void FallingBullet::Update(float fElapsedTime){
}
}
game->ProximityKnockback(pos,collisionRadius,knockbackAmt,HurtType::PLAYER|HurtType::MONSTER);
for(int i:std::ranges::iota_view(0,30))game->AddEffect(std::make_unique<Effect>(pos-vf2d{0.f,GetZ()},util::random_range(0.05f,0.2f),"circle_outline.png",OnUpperLevel(),util::random_range(0.5f,1.f),0.2f,vf2d{util::random_range(-10.f,10.f),util::random_range(-3.f,0.f)},PixelLerp(BLACK,col,util::random(1.f)),0.f,0.f,true));
for(int i:std::ranges::iota_view(0,30))game->AddEffect(Effect{pos-vf2d{0.f,GetZ()},util::random_range(0.05f,0.2f),"circle_outline.png",OnUpperLevel(),util::random_range(0.5f,1.f),0.2f,vf2d{util::random_range(-10.f,10.f),util::random_range(-3.f,0.f)},PixelLerp(BLACK,col,util::random(1.f)),0.f,0.f,true});
Deactivate();
}
}else{
if(lastTrailEffect<=0.f){
game->AddEffect(std::make_unique<Effect>(pos-vf2d{0.f,GetZ()},util::random_range(0.05f,0.2f),"circle_outline.png",OnUpperLevel(),util::random_range(0.5f,1.f),0.2f,vf2d{util::random_range(-3.f,3.f),util::random_range(-3.f,3.f)},PixelLerp(BLACK,col,util::random(1.f)),0.f,0.f,true));
game->AddEffect(Effect{pos-vf2d{0.f,GetZ()},util::random_range(0.05f,0.2f),"circle_outline.png",OnUpperLevel(),util::random_range(0.5f,1.f),0.2f,vf2d{util::random_range(-3.f,3.f),util::random_range(-3.f,3.f)},PixelLerp(BLACK,col,util::random(1.f)),0.f,0.f,true});
}
}
indicator.Update(fElapsedTime);

View File

@ -49,7 +49,7 @@ INCLUDE_MONSTER_LIST
FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,FriendlyType friendly,Pixel col)
:Bullet(pos,vel,radius,damage,
"energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){
if(game->GetPlayer()->HasEnchant("Trail of Fire")&&friendly)flameTrail=dynamic_cast<TrailEffect&>(game->AddEffect(std::make_unique<TrailEffect>(pos,"Trail of Fire"_ENC["TRAIL DURATION"],"FlamesTexture.png","Trail of Fire"_ENC["TRAIL DAMAGE"]/100.f*game->GetPlayer()->GetAttack(),"Trail of Fire"_ENC["TRAIL TICK FREQUENCY"],upperLevel,1.f,vf2d{1.f,2.f},30000.f,Oscillator<Pixel>{{255,0,0,128},Pixel(0xE74F30),2.f},EffectType::TRAIL_OF_FIRE,true),true));
if(game->GetPlayer()->HasEnchant("Trail of Fire")&&friendly)flameTrail=DYNAMIC_POINTER_CAST<TrailEffect>(game->AddEffect(TrailEffect{pos,"Trail of Fire"_ENC["TRAIL DURATION"],"FlamesTexture.png",int("Trail of Fire"_ENC["TRAIL DAMAGE"]/100.f*game->GetPlayer()->GetAttack()),"Trail of Fire"_ENC["TRAIL TICK FREQUENCY"],upperLevel,1.f,vf2d{1.f,2.f},30000.f,Oscillator<Pixel>{{255,0,0,128},Pixel(0xE74F30),2.f},EffectType::TRAIL_OF_FIRE,true},true));
SoundEffect::PlaySFX("Wizard Fire Bolt Shoot",SoundEffect::CENTERED);
}
@ -57,33 +57,33 @@ void FireBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){
lastParticleSpawn="Wizard.Ability 1.ParticleFrequency"_F;
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Ability 1.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Ability 1.ParticleSizeRange"_FRange,"Wizard.Ability 1.ParticleFadeoutTime"_F,vf2d{"Wizard.Ability 1.ParticleXSpeedRange"_FRange,"Wizard.Ability 1.ParticleYSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.ParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.ParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.ParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.ParticleAlphaRange"_FRange)}));
game->AddEffect(Effect{pos,"Wizard.Ability 1.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Ability 1.ParticleSizeRange"_FRange,"Wizard.Ability 1.ParticleFadeoutTime"_F,vf2d{"Wizard.Ability 1.ParticleXSpeedRange"_FRange,"Wizard.Ability 1.ParticleYSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.ParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.ParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.ParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.ParticleAlphaRange"_FRange)}});
}
if(distanceTraveled>"Wizard.Ability 1.Max Range"_F&&IsActivated()){
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
game->AddEffect(Effect{pos,"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}});
}
game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);
if(friendly)game->Hurt(pos,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,int("Wizard.Ability 1.BulletHitExplosionDamageMult"_F*game->GetPlayer()->GetAttack()),OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY);
else game->Hurt(pos,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,damage,OnUpperLevel(),0,HurtType::PLAYER);
game->AddEffect(std::make_unique<Effect>(pos,0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel));
game->AddEffect(Effect{pos,0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel});
SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
}
if(flameTrail)flameTrail.value().get().SetEndPos(pos);
if(!flameTrail.expired())flameTrail.lock()->SetEndPos(pos);
}
BulletDestroyState FireBolt::PlayerHit(Player*player)
{
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(player->GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
game->AddEffect(Effect{player->GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}});
game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);}
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,5,0.25,vf2d{},Pixel{240,120,60}));
game->AddEffect(Effect{player->GetPos(),0,"splash_effect.png",upperLevel,5,0.25,vf2d{},Pixel{240,120,60}});
SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
return BulletDestroyState::KEEP_ALIVE;
@ -93,11 +93,11 @@ BulletDestroyState FireBolt::MonsterHit(Monster&monster,const uint8_t markStacks
{
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
game->AddEffect(Effect{monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}});
}
game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);
game->Hurt(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,int("Wizard.Ability 1.BulletHitExplosionDamageMult"_F*game->GetPlayer()->GetAttack()),OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY);
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel));
game->AddEffect(Effect{monster.GetPos(),0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel});
SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
return BulletDestroyState::KEEP_ALIVE;

View File

@ -183,7 +183,7 @@ DEFINE_STRATEGY(GHOST_OF_PIRATE_CAPTAIN)
m.F(A::TOSS_COIN_WAIT_TIMER)=ConfigFloat("Coin Toss Pause Time");
m.V(A::TOSS_COIN_TARGET)=game->GetPlayer()->GetPos();
const bool OnLastCursePhase{Config("Curse Thresholds").GetValueCount()==m.I(A::CURSE_THRESHOLD_ARRAY_IND)};
if(!OnLastCursePhase)game->AddEffect(std::make_unique<FlipCoinEffect>(Oscillator<vf2d>{m.GetPos(),m.V(A::TOSS_COIN_TARGET),1.f/m.F(A::TOSS_COIN_WAIT_TIMER)/2.f},ConfigFloat("Coin Toss Rise Amount"),m.F(A::TOSS_COIN_WAIT_TIMER),"coin.png",m.OnUpperLevel(),3.f));
if(!OnLastCursePhase)game->AddEffect(FlipCoinEffect{Oscillator<vf2d>{m.GetPos(),m.V(A::TOSS_COIN_TARGET),1.f/m.F(A::TOSS_COIN_WAIT_TIMER)/2.f},ConfigFloat("Coin Toss Rise Amount"),m.F(A::TOSS_COIN_WAIT_TIMER),"coin.png",m.OnUpperLevel(),3.f});
#pragma region Determine a hiding spot
const auto&hidingSpots{game->GetActiveZonesForCurrentMap().at("Hiding Spot")};

View File

@ -48,7 +48,7 @@ void GhostSaber::Update(float fElapsedTime){
distFromTarget+=expandSpd*fElapsedTime;
if(particleTimer<=0.f){
particleTimer+=0.05f;
game->AddEffect(std::make_unique<ShineEffect>(pos,0.1f,0.1f,"pixel.png",2.f,vf2d{},Pixel{239,215,98,192},util::random(2*PI),0.f,true));
game->AddEffect(ShineEffect{pos,0.1f,0.1f,"pixel.png",2.f,vf2d{},Pixel{239,215,98,192},util::random(2*PI),0.f,true});
}
rot+=rotSpd*fElapsedTime;
if(!attachedMonster.expired()){

View File

@ -74,7 +74,7 @@ DEFINE_STRATEGY(GIANT_OCTOPUS)
m.SetStrategyDeathFunction([](GameEvent&event,Monster&m,const StrategyName strategy){
std::string takoyakiImgDir{"item_img_directory"_S+"Takoyaki.png"};
if(!GFX.count(takoyakiImgDir))ERR(std::format("WARNING! Could not find item image {}",takoyakiImgDir));
game->AddEffect(std::make_unique<Effect>(m.GetPos(),INFINITE,"item_img_directory"_S+"Takoyaki.png",m.OnUpperLevel(),1.f,0.f,vf2d{4.f,4.f},vf2d{},WHITE));
game->AddEffect(Effect{m.GetPos(),INFINITE,"item_img_directory"_S+"Takoyaki.png",m.OnUpperLevel(),1.f,0.f,vf2d{4.f,4.f},vf2d{},WHITE});
m.SetLifetime(4.f);
SETPHASE(DEAD);
return false;

View File

@ -51,8 +51,8 @@ void InkBullet::Update(float fElapsedTime){
else if(GetAliveTime()>=30.f)ERR(std::format("WARNING! An Ink Bullet did not resolve to target position {} in time! Last reported pos: {}! THE DISTANCE THRESHOLD FOR INK EXPLOSIONS IS LIKELY TOO HIGH! THIS SHOULD NOT BE HAPPENING!",targetPos.str(),pos.str())); //NOTE: THIS SHOULD NOT BE HAPPENING! If this does, then we probably just set the distance threshold WAY TOO LOW! Let's crash for now.
}
void InkBullet::Splat(){
game->AddEffect(std::make_unique<Effect>(pos,ANIMATION_DATA["inkbubble_explode.png"].GetTotalAnimationDuration(),"inkbubble_explode.png",OnUpperLevel(),vf2d{1.f,1.f},0.f,vf2d{},WHITE,0.f,0.f,additiveBlending));
game->AddEffect(std::make_unique<Ink>(pos,inkPuddleRadius,inkPuddleLifetime,inkSlowdownDuration,inkSlowdownPct,0.4f,0.4f,vf2d{1.f,1.f},WHITE,OnUpperLevel(),int(util::random_range(0,4.f))*PI/2),true);
game->AddEffect(Effect{pos,ANIMATION_DATA["inkbubble_explode.png"].GetTotalAnimationDuration(),"inkbubble_explode.png",OnUpperLevel(),vf2d{1.f,1.f},0.f,vf2d{},WHITE,0.f,0.f,additiveBlending});
game->AddEffect(Ink{pos,inkPuddleRadius,inkPuddleLifetime,inkSlowdownDuration,inkSlowdownPct,0.4f,0.4f,vf2d{1.f,1.f},WHITE,OnUpperLevel(),int(util::random_range(0,4.f))*PI/2},true);
lifetime=0.f;
}
BulletDestroyState InkBullet::PlayerHit(Player*player){

View File

@ -63,7 +63,7 @@ void LargeStone::Update(float fElapsedTime){
for(int i=0;i<100;i++){
const float randomDir{util::random(2*PI)};
game->AddEffect(std::make_unique<FallEffect>(pos+vf2d{radius,randomDir}.cart(),0.f,"circle.png",OnUpperLevel(),vf2d{1.5f,1.5f}*util::random(2.f),util::random(1.f),vf2d{vf2d{radius,randomDir}.cart().x,-util::random(30.f)-20.f},BLACK));
game->AddEffect(FallEffect{pos+vf2d{radius,randomDir}.cart(),0.f,"circle.png",OnUpperLevel(),vf2d{1.5f,1.5f}*util::random(2.f),util::random(1.f),vf2d{vf2d{radius,randomDir}.cart().x,-util::random(30.f)-20.f},BLACK});
}
const HurtList pillarList{game->HurtMonsterType(pos,radius,3,OnUpperLevel(),GetZ(),"Stone Golem Pillar")};

View File

@ -60,16 +60,16 @@ void LightningBolt::Update(float fElapsedTime){
uint8_t brightness=uint8_t("Wizard.Ability 2.ParticleColorRange"_FRange);
switch(util::random()%4){
case 0:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part1.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
game->AddEffect(Effect{pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part1.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}});
}break;
case 1:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part2.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
game->AddEffect(Effect{pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part2.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}});
}break;
case 2:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part3.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
game->AddEffect(Effect{pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part3.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}});
}break;
case 3:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part4.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
game->AddEffect(Effect{pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part4.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}});
}break;
}
}
@ -80,7 +80,7 @@ void LightningBolt::Update(float fElapsedTime){
BulletDestroyState LightningBolt::PlayerHit(Player*player){
fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,player->GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange));
game->AddEffect(Effect{player->GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,player->GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange});
SoundEffect::PlaySFX("Wizard Lightning Bolt Hit",pos);
return BulletDestroyState::KEEP_ALIVE;
@ -88,7 +88,7 @@ BulletDestroyState LightningBolt::PlayerHit(Player*player){
BulletDestroyState LightningBolt::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
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(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});
LightningBolt::ApplyLightningShock(monster,monster.OnUpperLevel());
@ -111,7 +111,7 @@ void LightningBolt::ApplyLightningShock(const Monster&monster,const bool onUpper
if(chainLightningRepeatCount>0)lightningChainDamage=int(game->GetPlayer()->GetAttack()*"Chain Lightning"_ENC["SHOCK DAMAGE"]/100.f);
if(m->Hurt(lightningChainDamage,onUpperLevel,0,HurtFlag::PLAYER_ABILITY)){
EMITTER_LIST.emplace_back(std::make_unique<LightningBoltEmitter>(LightningBoltEmitter(monster.GetPos(),m->GetPos(),"Wizard.Ability 2.LightningChainFrequency"_F,"Wizard.Ability 2.LightningChainLifetime"_F,onUpperLevel)));
game->AddEffect(std::make_unique<Effect>(m->GetPos(),"Wizard.Ability 2.LightningChainSplashLifetime"_F,"lightning_splash_effect.png",onUpperLevel,monster.GetSizeMult(),"Wizard.Ability 2.LightningChainSplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.LightningChainSplashRotationRange"_FRange));
game->AddEffect(Effect{m->GetPos(),"Wizard.Ability 2.LightningChainSplashLifetime"_F,"lightning_splash_effect.png",onUpperLevel,monster.GetSizeMult(),"Wizard.Ability 2.LightningChainSplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.LightningChainSplashRotationRange"_FRange});
int chainLightningRepeat{};
if(chainLightningRepeatCount>0)chainLightningRepeat=chainLightningRepeatCount-1;
else if(game->GetPlayer()->HasEnchant("Chain Lightning")&&chainLightningRepeatCount==ORIGINAL_BOLT)chainLightningRepeat=int("Chain Lightning"_ENC["REPEAT COUNT"]);

View File

@ -59,7 +59,7 @@ void LightningBoltEmitter::DrawLightningBolt(){
float targetDist=lineToTarget.length()*util::random(0.5f);
targetAngle+=util::random((PI/2))-PI/4;
geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist});
game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,"chain_lightning.png",upperLevel,vf2d{lightningLine.length(),0.2f},0.2f,vf2d{},WHITE,targetAngle,0,true));
game->AddEffect(Effect{lightningLine.upoint(0),0,"chain_lightning.png",upperLevel,vf2d{lightningLine.length(),0.2f},0.2f,vf2d{},WHITE,targetAngle,0,true});
int iterations=1;
currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist};
while(iterations<MAX_ITERATIONS&&geom2d::line<float>(currentPos,endPos).length()>1){
@ -68,7 +68,7 @@ void LightningBoltEmitter::DrawLightningBolt(){
float targetDist=lineToTarget.length()*util::random(0.5f);
targetAngle+=util::random((PI/2))-PI/4;
geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist});
game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,"chain_lightning.png",upperLevel,vf2d{lightningLine.length(),0.2f},0.2f,vf2d{},WHITE,targetAngle,0,true));
game->AddEffect(Effect{lightningLine.upoint(0),0,"chain_lightning.png",upperLevel,vf2d{lightningLine.length(),0.2f},0.2f,vf2d{},WHITE,targetAngle,0,true});
currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist};
iterations++;
}

View File

@ -127,17 +127,17 @@ bool Meteor::Update(float fElapsedTime){
float randomAngle="Wizard.Ability 3.MeteorImpactParticleAngleRange"_FRange;
float randomRange=100*size.x*(1-util::random("Wizard.Ability 3.MeteorImpactParticleRandomVariance"_F))*(1-util::random("Wizard.Ability 3.MeteorImpactParticleRandomVariance"_F));
vf2d effectPos=vf2d{cos(randomAngle),sin(randomAngle)}*randomRange+meteorOffset;
game->AddEffect(std::make_unique<Effect>(effectPos,0,"circle.png",OnUpperLevel(),vf2d{util::random(2)+1,util::random(3)+1},util::random(3)+1,vf2d{util::random(10)-5,-util::random(20)-5},Pixel{uint8_t(randomColorTintR),uint8_t(randomColorTintG),uint8_t(randomColorTintB),uint8_t("Wizard.Ability 3.MeteorImpactParticleAlphaRange"_FRange)},0,0,true),effectPos.y<meteorOffset.y);
game->AddEffect(Effect{effectPos,0,"circle.png",OnUpperLevel(),vf2d{util::random(2)+1,util::random(3)+1},util::random(3)+1,vf2d{util::random(10)-5,-util::random(20)-5},Pixel{uint8_t(randomColorTintR),uint8_t(randomColorTintG),uint8_t(randomColorTintB),uint8_t("Wizard.Ability 3.MeteorImpactParticleAlphaRange"_FRange)},0,0,true},effectPos.y<meteorOffset.y);
}
#define PLAYER_CASES default
switch(setting){
case SKELETON_MAGE:{
game->Hurt(pos,meteorRadius/1.25f,damage.first*damageMult,OnUpperLevel(),0,HurtType::PLAYER);
game->AddEffect(std::make_unique<PulsatingFire>(pos,fireRingLifetime,meteorRadius/1.25f,"fire_ring1.png",OnUpperLevel(),damage.second,PulsatingFire::SKELETON_MAGE,vf2d{meteorRadius/16,meteorRadius/16},"Wizard.Ability 3.FireRingFadeoutTime"_F),true);
game->AddEffect(PulsatingFire{pos,fireRingLifetime,meteorRadius/1.25f,"fire_ring1.png",OnUpperLevel(),damage.second,PulsatingFire::SKELETON_MAGE,vf2d{meteorRadius/16,meteorRadius/16},"Wizard.Ability 3.FireRingFadeoutTime"_F},true);
}break;
PLAYER_CASES:{ //Default cases are player cases. Handle all other enemy cases in their own statements.
game->Hurt(pos,meteorRadius,damage.first*damageMult,OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY);
game->AddEffect(std::make_unique<PulsatingFire>(pos,fireRingLifetime,meteorRadius,"fire_ring1.png",OnUpperLevel(),damage.second,PulsatingFire::PLAYER,vf2d{meteorRadius/12,meteorRadius/12},"Wizard.Ability 3.FireRingFadeoutTime"_F),true);
game->AddEffect(PulsatingFire{pos,fireRingLifetime,meteorRadius,"fire_ring1.png",OnUpperLevel(),damage.second,PulsatingFire::PLAYER,vf2d{meteorRadius/12,meteorRadius/12},"Wizard.Ability 3.FireRingFadeoutTime"_F},true);
}break;
}
#undef PLAYER_CASES

View File

@ -1191,7 +1191,7 @@ void Monster::OnDeath(){
if(strategyDeathFunc)GameEvent::AddEvent(std::make_unique<MonsterStrategyGameEvent>(strategyDeathFunc,*this,MONSTER_DATA[name].GetAIStrategy()));
if(game->GetPlayer()->HasEnchant("Reaper of Souls"))game->AddEffect(std::make_unique<MonsterSoul>(GetPos(),0.3f,GetSizeMult(),vf2d{},WHITE,0.f,0.f,false));
if(game->GetPlayer()->HasEnchant("Reaper of Souls"))game->AddEffect(MonsterSoul{GetPos(),0.3f,GetSizeMult(),vf2d{},WHITE,0.f,0.f,false});
if(game->GetPlayer()->HasEnchant("Bloodlust")&&game->GetPlayer()->GetBuffs(BuffType::ADRENALINE_RUSH).size()>0){
Buff&adrenalineRushBuff{game->GetPlayer()->EditBuff(BuffType::ADRENALINE_RUSH,0)};
adrenalineRushBuff.lifetime+="Bloodlust"_ENC["BUFF TIMER INCREASE"];
@ -1226,7 +1226,7 @@ void Monster::OnDeath(){
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>(GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{100,0,155,uint8_t(util::random_range(0,120))},0.f,0.f),true);
game->AddEffect(Effect{geom2d::line<float>(GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{100,0,155,uint8_t(util::random_range(0,120))},0.f,0.f},true);
}
SoundEffect::PlaySFX("Curse of Pain",m->GetPos());
}
@ -1245,9 +1245,8 @@ void Monster::OnDeath(){
float targetScale{radius/24};
float startingScale{GetCollisionRadius()/24};
std::unique_ptr<Effect>explodeEffect{std::make_unique<Effect>(pos,ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration()-0.2f,"explosionframes.png",OnUpperLevel(),startingScale,0.2f,vf2d{0,-6.f},WHITE,util::random(2*PI),0.f)};
explodeEffect->scaleSpd={(targetScale-startingScale)/ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration(),(targetScale-startingScale)/ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration()};
game->AddEffect(std::move(explodeEffect));
std::weak_ptr<Effect>eff{game->AddEffect(Effect{pos,ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration()-0.2f,"explosionframes.png",OnUpperLevel(),startingScale,0.2f,vf2d{0,-6.f},WHITE,util::random(2*PI),0.f})};
eff.lock()->scaleSpd={(targetScale-startingScale)/ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration(),(targetScale-startingScale)/ANIMATION_DATA["explosionframes.png"].GetTotalAnimationDuration()};
SoundEffect::PlaySFX("Explosion",pos);
#pragma endregion
}
@ -1792,7 +1791,7 @@ const float Monster::GetHastePct()const{
void Monster::CastAbility(const MonsterAbilityData&data,const vf2d pos){
currentCast=CastInfo{.name=data.name,.castTimer=data.castTime,.castTotalTime=data.castTime,.castPos=(pos==vf2d{}?game->GetPlayer()->GetPos():pos),.mpCost=data.mpCost,.castRadius=data.radius};
PerformAnimation("CASTING");
if(currentCast->castRadius)game->AddEffect(std::make_unique<Effect>(currentCast->castPos,currentCast->castTotalTime,"aiming_target.png",upperLevel,(*currentCast->castRadius*2/100)*vf2d{1.f,1.f},0.5f,vf2d{},Pixel{247,183,82,128},0.f,0.f,true),true);
if(currentCast->castRadius)game->AddEffect(Effect{currentCast->castPos,currentCast->castTotalTime,"aiming_target.png",upperLevel,(*currentCast->castRadius*2/100)*vf2d{1.f,1.f},0.5f,vf2d{},Pixel{247,183,82,128},0.f,0.f,true},true);
}
void Monster::PerformSpell(const CastInfo&castData){

View File

@ -9,7 +9,7 @@ INCLUDE_game
std::unordered_map<std::string_view,std::function<MonsterAbility::SpellSucceededResult(SpellName,CastPos,CasterMonster&,const StrategyName&)>>MonsterAbility::SPELLS{
{"Meteor",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->SpellSucceededResult{
game->AddEffect(std::make_unique<Meteor>(pos,3.f,m.OnUpperLevel(),Meteor::SKELETON_MAGE,std::pair<MeteorDamage,PulsatingFireDamage>{int(m.GetAttack()*ConfigFloat("Meteor Damage Mult")),int(m.GetAttack()*ConfigFloat("Fire Ring Damage Mult"))},"Wizard.Ability 3.MeteorFadeoutTime"_F));
game->AddEffect(Meteor{pos,3.f,m.OnUpperLevel(),Meteor::SKELETON_MAGE,std::pair<MeteorDamage,PulsatingFireDamage>{int(m.GetAttack()*ConfigFloat("Meteor Damage Mult")),int(m.GetAttack()*ConfigFloat("Fire Ring Damage Mult"))},"Wizard.Ability 3.MeteorFadeoutTime"_F});
return SpellSucceededResult::SPELL_COMPLETED;
}},
{"Fire Bolt",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->SpellSucceededResult{
@ -17,7 +17,7 @@ std::unordered_map<std::string_view,std::function<MonsterAbility::SpellSucceeded
return SpellSucceededResult::SPELL_COMPLETED;
}},
{"Blizzard",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->SpellSucceededResult{
game->AddEffect(std::make_unique<Blizzard>(pos,ConfigPixels("Blizzard Radius"),ConfigFloat("Blizzard Duration"),m.GetAttack()*ConfigFloat("Blizzard Tick Damage Mult"),ConfigFloat("Blizzard Tick Rate"),std::pair<MinScale,MaxScale>{1.f,2.f},0.05f,m.OnUpperLevel(),NON_FRIENDLY));
game->AddEffect(Blizzard{pos,ConfigPixels("Blizzard Radius"),ConfigFloat("Blizzard Duration"),int(m.GetAttack()*ConfigFloat("Blizzard Tick Damage Mult")),ConfigFloat("Blizzard Tick Rate"),std::pair<MinScale,MaxScale>{1.f,2.f},0.05f,m.OnUpperLevel(),NON_FRIENDLY});
return SpellSucceededResult::SPELL_COMPLETED;
}},
{"Freeze Ground",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->SpellSucceededResult{
@ -32,7 +32,7 @@ std::unordered_map<std::string_view,std::function<MonsterAbility::SpellSucceeded
.stackRemovalRate=ConfigFloat("Freeze Ground Stack Removal Rate"),
.lifetime=ConfigFloat("Freeze Ground Lifetime"),
};
game->AddEffect(std::make_unique<FreezeGround>(pos,ConfigFloat("Freeze Ground Lifetime"),m.GetAttack(),settings,m.OnUpperLevel(),NON_FRIENDLY),true);
game->AddEffect(FreezeGround{pos,ConfigFloat("Freeze Ground Lifetime"),m.GetAttack(),settings,m.OnUpperLevel(),NON_FRIENDLY},true);
return SpellSucceededResult::SPELL_COMPLETED;
}},
{"Speed Up",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->SpellSucceededResult{
@ -45,7 +45,7 @@ std::unordered_map<std::string_view,std::function<MonsterAbility::SpellSucceeded
speedBoostBuff.lifetime=speedBoostBuff.originalDuration;
for(int i:std::ranges::iota_view(0,30)){
vf2d polarRandomCoord{util::random_range(0,24),util::degToRad(util::random(360))};
game->AddEffect(std::make_unique<Effect>(chosenEntity.GetPos()+polarRandomCoord.cart(),util::random_range(0,3),"circle.png",chosenEntity.OnUpperLevel(),util::random_range(0.5f,1.75f)*vf2d{1,1},1.f,vf2d{0.f,-util::random_range(3.f,10.f)},PixelLerp({255,255,255,uint8_t(util::random_range(128,255))},{0,255,0,uint8_t(util::random_range(128,255))},util::random(1)),util::random(2*PI),0.f,false));
game->AddEffect(Effect{chosenEntity.GetPos()+polarRandomCoord.cart(),util::random_range(0,3),"circle.png",chosenEntity.OnUpperLevel(),util::random_range(0.5f,1.75f)*vf2d{1,1},1.f,vf2d{0.f,-util::random_range(3.f,10.f)},PixelLerp({255,255,255,uint8_t(util::random_range(128,255))},{0,255,0,uint8_t(util::random_range(128,255))},util::random(1)),util::random(2*PI),0.f,false});
}
return SpellSucceededResult::SPELL_COMPLETED;
}

View File

@ -46,7 +46,7 @@ INCLUDE_game
DEFINE_STRATEGY(PIRATES_COIN)
if(m.B(Attribute::COLLIDED_WITH_PLAYER)){
game->AddEffect(std::make_unique<CollectCoinEffect>(game->GetPlayer(),ConfigFloat("Coin Collect Rise Amount"),ConfigFloat("Coin Rise Timer"),"coin.png",m.OnUpperLevel()),true);
game->AddEffect(CollectCoinEffect{game->GetPlayer(),ConfigFloat("Coin Collect Rise Amount"),ConfigFloat("Coin Rise Timer"),"coin.png",m.OnUpperLevel()},true);
game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN,INFINITY,1);
m._DealTrueDamage(m.GetHealth(),HurtFlag::NO_DAMAGE_NUMBER);
m.SetLifetime(0.f);

View File

@ -496,7 +496,7 @@ void Player::Update(float fElapsedTime){
monsterPtr->Knockback(vf2d{knockbackAmt,knockbackDir}.cart());
}
#pragma endregion
game->AddEffect(std::make_unique<Effect>(GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"ground-slam-attack-front.png",upperLevel,groundSlamVisualRange,"Warrior.Ability 2.EffectFadetime"_F),std::make_unique<Effect>(GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"ground-slam-attack-back.png",upperLevel,groundSlamVisualRange,"Warrior.Ability 2.EffectFadetime"_F));
game->AddEffect(Effect{GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"ground-slam-attack-front.png",upperLevel,groundSlamVisualRange,"Warrior.Ability 2.EffectFadetime"_F},Effect{GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"ground-slam-attack-back.png",upperLevel,groundSlamVisualRange,"Warrior.Ability 2.EffectFadetime"_F});
SoundEffect::PlaySFX("Warrior Ground Slam",SoundEffect::CENTERED);
}
if(lastAnimationFlip>0){

View File

@ -55,18 +55,18 @@ void PoisonBottle::OnGroundLand(){
float currentExplodeRadius{explodeRadius};
if(additionalBounceCount>0)currentExplodeRadius=bounceExplodeRadius;
game->AddEffect(std::make_unique<Effect>(pos,0.f,"poison_pool.png",game->GetPlayer()->OnUpperLevel(),0.5f,1.2f,vf2d{poisonCircleScale,poisonCircleScale},vf2d{},WHITE,0.f,0.f,false),true);
game->AddEffect(Effect{pos,0.f,"poison_pool.png",game->GetPlayer()->OnUpperLevel(),0.5f,1.2f,vf2d{poisonCircleScale,poisonCircleScale},vf2d{},WHITE,0.f,0.f,false},true);
for(int i:std::ranges::iota_view(0,200)){
float size{util::random_range(0.4f,0.8f)};
Pixel col{PixelLerp(VERY_DARK_GREEN,DARK_GREEN,util::random(1))};
col.a=util::random_range(60,200);
game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col));
game->AddEffect(Effect{pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col});
}
if(additionalBounceCount==0&&game->GetPlayer()->HasEnchant("Pooling Poison")){
game->AddEffect(std::make_unique<LingeringEffect>(pos,"poison_pool.png","Poison Pool",bounceExplodeRadius,game->GetPlayer()->GetAttack()*"Pooling Poison"_ENC["POISON POOL DAMAGE PCT"]/100.f,"Pooling Poison"_ENC["POISON POOL DAMAGE FREQUENCY"],friendly?HurtType::MONSTER:HurtType::PLAYER,"Pooling Poison"_ENC["SPLASH LINGER TIME"],0.5f,OnUpperLevel(),poisonCircleScale,vf2d{},WHITE,0.f,0.f,false,0.05f,[pos=pos,col=col,poisonCircleScale](const Effect&self){
game->AddEffect(LingeringEffect{pos,"poison_pool.png","Poison Pool",bounceExplodeRadius,int(game->GetPlayer()->GetAttack()*"Pooling Poison"_ENC["POISON POOL DAMAGE PCT"]/100.f),"Pooling Poison"_ENC["POISON POOL DAMAGE FREQUENCY"],friendly?HurtType::MONSTER:HurtType::PLAYER,"Pooling Poison"_ENC["SPLASH LINGER TIME"],0.5f,OnUpperLevel(),poisonCircleScale,vf2d{},WHITE,0.f,0.f,false,0.05f,[pos=pos,col=col,poisonCircleScale](const Effect&self){
float size{util::random_range(0.4f,0.8f)};
return Effect{pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col};
}),true);
}},true);
}
int poolDamage{damage};

View File

@ -63,7 +63,7 @@ bool PulsatingFire::Update(float fElapsedTime){
float randomRange=12*size.x*(1-util::random("Wizard.Ability 3.FireRingParticleRandomVariance"_F))*(1-util::random("Wizard.Ability 3.FireRingParticleRandomVariance"_F));
float randomColorTintG=128*(1-util::random("Wizard.Ability 3.FireRingParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.FireRingParticleColorGVariance"_F));
float randomColorTint="Wizard.Ability 3.FireRingParticleColorBlueRange"_FRange;
game->AddEffect(std::make_unique<Effect>(pos+vf2d{cos(randomAngle),sin(randomAngle)}*randomRange,0,"circle.png",OnUpperLevel(),vf2d{"Wizard.Ability 3.FireRingParticleXSizeRange"_FRange,"Wizard.Ability 3.FireRingParticleYSizeRange"_FRange},"Wizard.Ability 3.FireRingParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 3.FireRingParticleXSpeedRange"_FRange,"Wizard.Ability 3.FireRingParticleYSpeedRange"_FRange},Pixel{128,uint8_t(randomColorTintG),uint8_t(randomColorTint),uint8_t("Wizard.Ability 3.FireRingParticleAlphaRange"_FRange)}));
game->AddEffect(Effect{pos+vf2d{cos(randomAngle),sin(randomAngle)}*randomRange,0,"circle.png",OnUpperLevel(),vf2d{"Wizard.Ability 3.FireRingParticleXSizeRange"_FRange,"Wizard.Ability 3.FireRingParticleYSizeRange"_FRange},"Wizard.Ability 3.FireRingParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 3.FireRingParticleXSpeedRange"_FRange,"Wizard.Ability 3.FireRingParticleYSpeedRange"_FRange},Pixel{128,uint8_t(randomColorTintG),uint8_t(randomColorTint),uint8_t("Wizard.Ability 3.FireRingParticleAlphaRange"_FRange)}});
}
lastParticleTimer="Wizard.Ability 3.FireRingParticleFreqRange"_FRange;
}

View File

@ -93,9 +93,8 @@ BulletDestroyState PurpleEnergyBall::PlayerHit(Player*player)
if(bounceCount<=0)fadeOutTime="Witch.Auto Attack.BulletHitFadeoutTime"_F;
else lastHitTimer=0.1f;
Deactivate();
std::unique_ptr<Effect>hitEffect{std::make_unique<Effect>(player->GetPos(),0,"purpleenergyball_hit.png",upperLevel,player->GetSizeMult(),"Witch.Auto Attack.SplashEffectFadeoutTime"_F,vf2d{},WHITE,util::random(2*PI),5*PI)};
hitEffect->scaleSpd={-0.3f,-0.3f};
game->AddEffect(std::move(hitEffect));
std::weak_ptr<Effect>hitEffect{game->AddEffect(Effect{player->GetPos(),0,"purpleenergyball_hit.png",upperLevel,player->GetSizeMult(),"Witch.Auto Attack.SplashEffectFadeoutTime"_F,vf2d{},WHITE,util::random(2*PI),5*PI})};
hitEffect.lock()->scaleSpd={-0.3f,-0.3f};
return BulletDestroyState::KEEP_ALIVE;
}
@ -108,8 +107,7 @@ BulletDestroyState PurpleEnergyBall::MonsterHit(Monster&monster,const uint8_t ma
if(bounceCount<=0)fadeOutTime="Witch.Auto Attack.BulletHitFadeoutTime"_F;
else lastHitTimer=0.1f;
Deactivate();
std::unique_ptr<Effect>hitEffect{std::make_unique<Effect>(monster.GetPos(),0,"purpleenergyball_hit.png",upperLevel,monster.GetSizeMult(),"Witch.Auto Attack.SplashEffectFadeoutTime"_F,vf2d{},WHITE,util::random(2*PI),5*PI)};
hitEffect->scaleSpd={-0.3f,-0.3f};
game->AddEffect(std::move(hitEffect));
std::weak_ptr<Effect>hitEffect{game->AddEffect(Effect{monster.GetPos(),0,"purpleenergyball_hit.png",upperLevel,monster.GetSizeMult(),"Witch.Auto Attack.SplashEffectFadeoutTime"_F,vf2d{},WHITE,util::random(2*PI),5*PI})};
hitEffect.lock()->scaleSpd={-0.3f,-0.3f};
return BulletDestroyState::KEEP_ALIVE;
}

View File

@ -157,7 +157,7 @@ DEFINE_STRATEGY(RUN_TOWARDS)
float dist=lineToPlayer.length();
for(int i=0;i<m.GetSizeMult()*25;i++){
float randomDir=util::random(2*PI);
game->AddEffect(std::make_unique<FallEffect>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
game->AddEffect(FallEffect{m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK},true);
}
if(dist<12*m.GetSizeMult()){
int jumpDamage=0;

View File

@ -78,7 +78,7 @@ DEFINE_STRATEGY(SANDWORM)
if(m.ReachedTargetPos()){
m.PerformAnimation("EMERGE",game->GetPlayer()->GetPos());
m.F(A::RECOVERY_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration();
game->AddEffect(std::make_unique<Effect>(m.GetPos(),ConfigInt("Suction Duration"),"sand_suction.png",m.OnUpperLevel(),0.25f,0.25f,ConfigFloat("Suction Animation Size")/300.f*vf2d{1.f,1.f},vf2d{},WHITE,util::random(),-PI/8),true);
game->AddEffect(Effect{m.GetPos(),ConfigFloat("Suction Duration"),"sand_suction.png",m.OnUpperLevel(),0.25f,0.25f,ConfigFloat("Suction Animation Size")/300.f*vf2d{1.f,1.f},vf2d{},WHITE,float(util::random()),-PI/8},true);
SETPHASE(SURFACING);
m.F(A::SUCTION_TIMER)=ConfigFloat("Suction Duration")+0.25f;
}

View File

@ -200,7 +200,7 @@ DEFINE_STRATEGY(SLIMEKING)
float dist=lineToPlayer.length();
for(int i=0;i<200;i++){
float randomDir=util::random(2*PI);
game->AddEffect(std::make_unique<FallEffect>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
game->AddEffect(FallEffect{m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK},true);
}
if(dist<12*m.GetSizeMult()){
if(game->GetPlayer()->Hurt(ConfigInt("JumpAttackDamage"),m.OnUpperLevel(),m.GetZ())){

View File

@ -125,7 +125,7 @@ DEFINE_STRATEGY(STONE_GOLEM)
if(m.F(A::RESPAWN_RECOVERY_TIME)<=0.f){
m.V(A::RESPAWN_LOCKON_POS)=game->GetPlayer()->GetPos();
m.SIZET(A::RESPAWN_LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos());
game->AddEffect(std::make_unique<SpellCircle>(m.V(A::RESPAWN_LOCKON_POS),ConfigFloat("Pillar Respawns.Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Pillar Respawns.Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Pillar Respawns.Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Pillar Respawns.Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Pillar Respawns.Spell Insignia Rotation Spd"))),true);
game->AddEffect(SpellCircle{m.V(A::RESPAWN_LOCKON_POS),ConfigFloat("Pillar Respawns.Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Pillar Respawns.Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Pillar Respawns.Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Pillar Respawns.Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Pillar Respawns.Spell Insignia Rotation Spd"))},true);
m.F(A::RESPAWN_CASTING_TIMER)=ConfigFloat("Pillar Respawns.Cast Time");
m.I(A::RESPAWN_PHASE)=RESPAWN_PILLAR_CAST;
}
@ -174,7 +174,7 @@ DEFINE_STRATEGY(STONE_GOLEM)
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
m.SIZET(A::LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos());
m.PerformAnimation("CAST",m.GetFacingDirectionToTarget(m.V(A::LOCKON_POS)));
game->AddEffect(std::make_unique<SpellCircle>(m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Insignia Rotation Spd"))),true);
game->AddEffect(SpellCircle{m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Insignia Rotation Spd"))},true);
m.F(A::CASTING_TIMER)=ConfigFloat("Beginning Phase.Pillar Cast Time");
SETPHASE(SPAWN_PILLAR_CAST);
}
@ -222,7 +222,7 @@ DEFINE_STRATEGY(STONE_GOLEM)
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
m.PerformAnimation("TOSS ROCK CAST");
m.F(A::CASTING_TIMER)=ConfigFloat("Standard Attack.Stone Throw Cast Time");
game->AddEffect(std::make_unique<SpellCircle>(m.V(A::LOCKON_POS),ConfigFloat("Standard Attack.Stone Throw Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(ConfigPixels("Standard Attack.Stone Radius")/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Standard Attack.Stone Throw Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Standard Attack.Stone Throw Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(ConfigPixels("Standard Attack.Stone Radius")/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Standard Attack.Stone Throw Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Standard Attack.Stone Throw Spell Insignia Rotation Spd"))),true);
game->AddEffect(SpellCircle{m.V(A::LOCKON_POS),ConfigFloat("Standard Attack.Stone Throw Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(ConfigPixels("Standard Attack.Stone Radius")/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Standard Attack.Stone Throw Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Standard Attack.Stone Throw Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(ConfigPixels("Standard Attack.Stone Radius")/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Standard Attack.Stone Throw Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Standard Attack.Stone Throw Spell Insignia Rotation Spd"))},true);
//Use acceleration equation to determine how much time it takes for the stone to land based on gravity.
const float stoneTossTime{ConfigFloat("Standard Attack.Stone Throw Time")};
@ -287,7 +287,7 @@ DEFINE_STRATEGY(STONE_GOLEM)
monsterPtr->_DealTrueDamage(ConfigInt("Shockwave.Pillar Damage"));
});
SoundEffect::PlaySFX("Shockwave",m.GetPos());
game->AddEffect(std::make_unique<ExpandingRing>(m.GetPos(),ConfigFloat("Shockwave.Shockwave Ring Lifetime"),"finishring.png",m.OnUpperLevel(),vf2d{ConfigFloat("Shockwave.Ring Expand Speed"),ConfigFloat("Shockwave.Ring Expand Speed")},vf2d{1.f,1.f},ConfigFloat("Shockwave.Shockwave Fadeout Time"),vf2d{},ConfigPixel("Shockwave.Shockwave Color")),true);
game->AddEffect(ExpandingRing{m.GetPos(),ConfigFloat("Shockwave.Shockwave Ring Lifetime"),"finishring.png",m.OnUpperLevel(),vf2d{ConfigFloat("Shockwave.Ring Expand Speed"),ConfigFloat("Shockwave.Ring Expand Speed")},vf2d{1.f,1.f},ConfigFloat("Shockwave.Shockwave Fadeout Time"),vf2d{},ConfigPixel("Shockwave.Shockwave Color")},true);
SETPHASE(STANDARD);
game->SetWorldColor(WHITE);
}
@ -322,7 +322,7 @@ DEFINE_STRATEGY(STONE_GOLEM)
const datafile&throwPos{Config("Stone Rain.Stone Toss Initial Throw Pos")};
game->AddEffect(std::make_unique<RockLaunch>(m.GetPos()+vf2d{util::random_range(throwPos.GetReal(0),throwPos.GetReal(2)),util::random_range(throwPos.GetReal(1),throwPos.GetReal(3))},10.f,"rock.png",ConfigFloat("Stone Rain.Stone Toss Delay"),ConfigFloat("Stone Rain.Stone Toss Rock Size Mult"),0.1f,vf2d{0.f,-ConfigFloat("Stone Rain.Stone Toss Throw Speed")},WHITE,util::random(2*PI),0.f));
game->AddEffect(RockLaunch{m.GetPos()+vf2d{util::random_range(throwPos.GetReal(0),throwPos.GetReal(2)),util::random_range(throwPos.GetReal(1),throwPos.GetReal(3))},10.f,"rock.png",ConfigFloat("Stone Rain.Stone Toss Delay"),ConfigFloat("Stone Rain.Stone Toss Rock Size Mult"),0.1f,vf2d{0.f,-ConfigFloat("Stone Rain.Stone Toss Throw Speed")},WHITE,util::random(2*PI),0.f});
if(m.I(A::STONE_TOSS_COUNT)<=0){
SETPHASE(STONE_RAIN);

View File

@ -98,7 +98,7 @@ DEFINE_STRATEGY(STONE_ELEMENTAL)
SETPHASE(STONE_PILLAR_CAST);
m.F(A::CASTING_TIMER)=ConfigFloat("Stone Pillar Cast Time");
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
game->AddEffect(std::make_unique<SpellCircle>(m.V(A::LOCKON_POS),ConfigFloat("Stone Pillar Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Stone Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Stone Pillar Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Stone Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Stone Pillar Spell Insignia Rotation Spd"))),false);
game->AddEffect(SpellCircle{m.V(A::LOCKON_POS),ConfigFloat("Stone Pillar Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Stone Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Stone Pillar Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Stone Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Stone Pillar Spell Insignia Rotation Spd"))},false);
}break;
case 1:{
m.PerformAnimation("ROCK TOSS CAST");

View File

@ -97,7 +97,7 @@ bool Thief::AutoAttack(){
attack_cooldown_timer=ATTACK_COOLDOWN-GetAttackRecoveryRateReduction();
swordSwingTimer="Thief.Auto Attack.SwordAnimationSwingTime"_F;
game->AddEffect(std::make_unique<SwordSlash>(0.125f,"swordslash.png"s,"Thief.Auto Attack.DamageMult"_F,"Thief.Auto Attack.SwordSlashSweepAngle"_F,vf2d{0.9f,0.9f}*"Thief.Auto Attack.Range"_F/100.f,0.1f,vf2d{0.f,0.f},WHITE,targetDirection));
game->AddEffect(SwordSlash{0.125f,"swordslash.png"s,"Thief.Auto Attack.DamageMult"_F,"Thief.Auto Attack.SwordSlashSweepAngle"_F,vf2d{0.9f,0.9f}*"Thief.Auto Attack.Range"_F/100.f,0.1f,vf2d{0.f,0.f},WHITE,targetDirection});
SetState(State::SWING_SWORD);
SoundEffect::PlaySFX("Warrior Auto Attack",SoundEffect::CENTERED);
@ -157,7 +157,7 @@ void Thief::InitializeClassAbilities(){
#pragma region Thief Ability 2 (Deadly Dash)
Thief::ability2.action=
[](Player*p,vf2d pos={}){
game->AddEffect(std::make_unique<ShineEffect>(p->GetPos()+vf2d{4.f,4.f},0.5f,0.5f,"shine.png",1.5f,vf2d{},WHITE,util::random(2*PI),PI/2,true));
game->AddEffect(ShineEffect{p->GetPos()+vf2d{4.f,4.f},0.5f,0.5f,"shine.png",1.5f,vf2d{},WHITE,util::random(2*PI),PI/2,true});
p->ApplyIframes("Thief.Ability 2.Initial Wait"_F+"Thief.Ability 2.Ending Wait"_F+"Thief.Ability 2.Completed Dash Extra Iframe Time"_F);
SoundEffect::PlaySFX("Charge Up",p->GetPos());
p->SetState(State::DEADLYDASH);
@ -189,7 +189,7 @@ void Thief::InitializeClassAbilities(){
for(int i:std::ranges::iota_view(0,50)){
float size{util::random_range(0.4f,0.8f)};
game->AddEffect(std::make_unique<Effect>(p->GetPos()+vf2d{8,util::random(2*PI)}.cart(),util::random_range(0.1f,0.4f),"circle.png",p->OnUpperLevel(),vf2d{size,size},0.3f,vf2d{util::random_range(-6.f,6.f),util::random_range(-8.f,-1.f)},PixelLerp(WHITE,GREEN,util::random(1))));
game->AddEffect(Effect{p->GetPos()+vf2d{8,util::random(2*PI)}.cart(),util::random_range(0.1f,0.4f),"circle.png",p->OnUpperLevel(),vf2d{size,size},0.3f,vf2d{util::random_range(-6.f,6.f),util::random_range(-8.f,-1.f)},PixelLerp(WHITE,GREEN,util::random(1))});
}
return true;
};

View File

@ -41,6 +41,7 @@ All rights reserved.
#include <ranges>
#include "util.h"
#include "SoundEffect.h"
#include<memory>
INCLUDE_game
@ -52,15 +53,15 @@ ThrownProjectile::ThrownProjectile(vf2d pos,vf2d targetPos,const std::string&img
void ThrownProjectile::OnGroundLand(){
const HurtList hurtList{game->Hurt(pos,explodeRadius,damage,OnUpperLevel(),z,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)};
if(explodeEffect){
Effect&explosionEffect{game->AddEffect(std::make_unique<Effect>(explodeEffect.value()))};
explosionEffect.pos+=pos;
std::weak_ptr<Effect>explosionEffect{game->AddEffect(Effect{explodeEffect.value()})};
explosionEffect.lock()->pos+=pos;
}
if(explodeSoundEffect)SoundEffect::PlaySFX(explodeSoundEffect.value(),pos);
if(lingeringEffect){
LingeringEffect&lingerEffect{dynamic_cast<LingeringEffect&>(game->AddEffect(std::make_unique<LingeringEffect>(lingeringEffect.value())))};
lingerEffect.posOscillator.val1+=pos;
lingerEffect.posOscillator.val2+=pos;
lingerEffect.pos+=pos;
std::weak_ptr<LingeringEffect>lingerEffect{DYNAMIC_POINTER_CAST<LingeringEffect>(game->AddEffect(LingeringEffect{lingeringEffect.value()}).lock())};
lingerEffect.lock()->posOscillator.val1+=pos;
lingerEffect.lock()->posOscillator.val2+=pos;
lingerEffect.lock()->pos+=pos;
}
vel={};

View File

@ -48,7 +48,13 @@ void ThunderOrb::Update(float fElapsedTime){
lightning.SetStartEndPos(pos,lightningBoltRandomPos);
if((damageTickTimer-=fElapsedTime)<=0.f){
game->Hurt(pos,settings.range/100.f*24,damage*settings.attackMult,OnUpperLevel(),GetZ(),friendly?HurtType::MONSTER:HurtType::PLAYER);
const HurtList&hurtTargets{game->Hurt(pos,settings.range/100.f*24,damage*settings.attackMult,OnUpperLevel(),GetZ(),friendly?HurtType::MONSTER:HurtType::PLAYER)};
std::ranges::for_each(hurtTargets,[&lightning=lightning,&pos=pos](const auto&pair){
Entity target{pair.first};
lightning.SetStartEndPos(pos,target.GetPos());
lightning.Emit();
});
damageTickTimer+=settings.tickRate;
}

View File

@ -89,7 +89,7 @@ void Trapper::InitializeClassAbilities(){
p->AddBuff(BuffType::SPEEDBOOST,"Trapper.Right Click Ability.Movement Speed Buff"_f[1],"Trapper.Right Click Ability.Movement Speed Buff"_f[0]/100.f);
for(int i:std::ranges::iota_view(0,50)){
float size{util::random_range(0.4f,0.8f)};
game->AddEffect(std::make_unique<Effect>(p->GetPos()+vf2d{8,util::random(2*PI)}.cart(),util::random_range(0.1f,0.4f),"circle.png",p->OnUpperLevel(),vf2d{size,size},0.3f,vf2d{util::random_range(-6.f,6.f),util::random_range(-8.f,-1.f)},PixelLerp(BLACK,RED,util::random(1))));
game->AddEffect(Effect{p->GetPos()+vf2d{8,util::random(2*PI)}.cart(),util::random_range(0.1f,0.4f),"circle.png",p->OnUpperLevel(),vf2d{size,size},0.3f,vf2d{util::random_range(-6.f,6.f),util::random_range(-8.f,-1.f)},PixelLerp(BLACK,RED,util::random(1))});
}
return true;
};
@ -107,7 +107,7 @@ void Trapper::InitializeClassAbilities(){
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);
game->AddEffect(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;
}

View File

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 12989
#define VERSION_BUILD 13018
#define stringify(a) stringify_(a)
#define stringify_(a) #a

View File

@ -94,7 +94,7 @@ bool Warrior::AutoAttack(){
attack_cooldown_timer=ATTACK_COOLDOWN-GetAttackRecoveryRateReduction();
swordSwingTimer="Warrior.Auto Attack.SwordAnimationSwingTime"_F;
game->AddEffect(std::make_unique<SwordSlash>(0.125f,"swordslash.png"s,"Warrior.Auto Attack.DamageMult"_F,"Warrior.Auto Attack.SwordSlashSweepAngle"_F,vf2d{0.9f,0.9f}*GetAttackRange()/100.f,0.1f,vf2d{0.f,0.f},WHITE,targetDirection));
game->AddEffect(SwordSlash{0.125f,"swordslash.png"s,"Warrior.Auto Attack.DamageMult"_F,"Warrior.Auto Attack.SwordSlashSweepAngle"_F,vf2d{0.9f,0.9f}*GetAttackRange()/100.f,0.1f,vf2d{0.f,0.f},WHITE,targetDirection});
SetState(State::SWING_SWORD);
SoundEffect::PlaySFX("Warrior Auto Attack",SoundEffect::CENTERED);
@ -124,7 +124,7 @@ void Warrior::InitializeClassAbilities(){
#pragma region Warrior Ability 1 (Battlecry)
Warrior::ability1.action=
[](Player*p,vf2d pos={}){
game->AddEffect(std::make_unique<Effect>(p->GetPos(),"Warrior.Ability 1.EffectLifetime"_F,"battlecry_effect.png",p->upperLevel,"Warrior.Ability 1.Range"_F/350,"Warrior.Ability 1.EffectFadetime"_F));
game->AddEffect(Effect{p->GetPos(),"Warrior.Ability 1.EffectLifetime"_F,"battlecry_effect.png",p->upperLevel,"Warrior.Ability 1.Range"_F/350,"Warrior.Ability 1.EffectFadetime"_F});
p->AddBuff(BuffType::STAT_UP,"Warrior.Ability 1.AttackUpDuration"_F,"Warrior.Ability 1.AttackIncrease"_F,{"Attack %"});
p->AddBuff(BuffType::DAMAGE_REDUCTION,"Warrior.Ability 1.DamageReductionDuration"_F,"Warrior.Ability 1.DamageReduction"_F);
for(std::shared_ptr<Monster>&m:MONSTER_LIST){

View File

@ -50,13 +50,13 @@ void Wisp::Update(float fElapsedTime){
}
BulletDestroyState Wisp::PlayerHit(Player*player){
SoundEffect::PlaySFX("Wisp Hit",player->GetPos());
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),0.25,vf2d{},"MonsterStrategy.Ursule.Phase 2.Wisp Color"_Pixel));
game->AddEffect(Effect{player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),0.25,vf2d{},"MonsterStrategy.Ursule.Phase 2.Wisp Color"_Pixel});
fadeOutTime="MonsterStrategy.Ursule.Phase 2.Wisp Fadeout Time"_F;
return BulletDestroyState::KEEP_ALIVE;
}
BulletDestroyState Wisp::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){
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(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;
return BulletDestroyState::KEEP_ALIVE;
}

View File

@ -156,7 +156,7 @@ void Witch::InitializeClassAbilities(){
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);
game->AddEffect(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);
}
SoundEffect::PlaySFX("Curse of Pain",curseTarget.value().lock()->GetPos());
return true;
@ -189,7 +189,7 @@ void Witch::InitializeClassAbilities(){
float fadeInTime{i*0.05f};
float fadeOutTime{0.5f+i*0.05f};
float effectSize{util::random_range(0.6f,1.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{162,0,0,uint8_t(util::random_range(150,255))},0.f,0.f),true);
game->AddEffect(Effect{geom2d::line<float>(p->GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",p->OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{162,0,0,uint8_t(util::random_range(150,255))},0.f,0.f},true);
}
SoundEffect::PlaySFX("Curse of Death",curseTarget.value().lock()->GetPos());
return true;

View File

@ -141,12 +141,12 @@ void Wizard::InitializeClassAbilities(){
p->teleportStartPosition=p->GetPos();
p->ApplyIframes("Wizard.Right Click Ability.IframeTime"_F);
for(int i=0;i<"Wizard.Right Click Ability.ParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(p->GetPos()+vf2d{(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12,(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12},util::random("Wizard.Right Click Ability.ParticleLifetimeMax"_F)+"Wizard.Right Click Ability.ParticleLifetimeMin"_F,"circle.png",p->upperLevel,"Wizard.Right Click Ability.ParticleSize"_F,"Wizard.Right Click Ability.ParticleFadetime"_F,vf2d{util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F,util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F},"Wizard.Right Click Ability.ParticleColor"_Pixel));
game->AddEffect(Effect{p->GetPos()+vf2d{(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12,(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12},util::random("Wizard.Right Click Ability.ParticleLifetimeMax"_F)+"Wizard.Right Click Ability.ParticleLifetimeMin"_F,"circle.png",p->upperLevel,"Wizard.Right Click Ability.ParticleSize"_F,"Wizard.Right Click Ability.ParticleFadetime"_F,vf2d{util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F,util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F},"Wizard.Right Click Ability.ParticleColor"_Pixel});
}
SoundEffect::PlaySFX("Wizard Teleport",SoundEffect::CENTERED);
};
std::vector<Effect*>portals{game->GetEffect(EffectType::BLINK_PORTAL)};
std::vector<std::shared_ptr<Effect>>portals{game->GetEffect(EffectType::BLINK_PORTAL)};
if(portals.size()>0){
TeleportTo(portals[0]->pos);
portals[0]->lifetime=0.f;
@ -156,17 +156,17 @@ void Wizard::InitializeClassAbilities(){
if(game->TestingModeEnabled()||dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,float("Wizard.Right Click Ability.TilesMax"_I))
&&(NoTileCollisionExistsHere()||NoPlayerCollisionWithTile())){
if(p->HasEnchant("Blink Portal")){
Effect&eff{game->AddEffect(std::make_unique<FadeInOutEffect>(Oscillator<vf2d>{p->GetPos(),p->GetPos()+vf2d{0,-6.f},0.5f},"portal.png","Blink Portal"_ENC["REACTIVATION TIME"],p->OnUpperLevel(),Oscillator<vf2d>{{0.9f,0.9f},{1.1f,1.1f},0.5f},vf2d{},Oscillator<Pixel>{WHITE,Pixel(0x50196f),0.5f},0.f,0.f),true)};
eff.SetType(EffectType::BLINK_PORTAL);
std::weak_ptr<Effect>eff{game->AddEffect(FadeInOutEffect{Oscillator<vf2d>{p->GetPos(),p->GetPos()+vf2d{0,-6.f},0.5f},"portal.png","Blink Portal"_ENC["REACTIVATION TIME"],p->OnUpperLevel(),Oscillator<vf2d>{{0.9f,0.9f},{1.1f,1.1f},0.5f},vf2d{},Oscillator<Pixel>{WHITE,Pixel(0x50196f),0.5f},0.f,0.f},true)};
eff.lock()->SetType(EffectType::BLINK_PORTAL);
}
TeleportTo(teleportPoint);
p->lastPathfindingCooldown=0.1f;
if(p->HasEnchant("Black Hole")){
Effect&blackHoleEff{game->AddEffect(std::make_unique<BlackHole>(Oscillator<vf2d>{p->GetPos(),p->GetPos()+vf2d{0,-6.f},0.75f},"blackhole.png","Black Hole"_ENC["BLACK HOLE DURATION"],p->OnUpperLevel(),Oscillator<vf2d>{{3.4f,3.4f},{3.7f,3.7f},0.75f},vf2d{},Oscillator<Pixel>{WHITE,WHITE,0.75f},util::random(2*PI),PI/3,false,0.03f,[](const Effect&self){
game->AddEffect(BlackHole{Oscillator<vf2d>{p->GetPos(),p->GetPos()+vf2d{0,-6.f},0.75f},"blackhole.png","Black Hole"_ENC["BLACK HOLE DURATION"],p->OnUpperLevel(),Oscillator<vf2d>{{3.4f,3.4f},{3.7f,3.7f},0.75f},vf2d{},Oscillator<Pixel>{WHITE,WHITE,0.75f},util::random(2*PI),PI/3,false,0.03f,[](const Effect&self){
vf2d particlePos{self.pos+vf2d{"Black Hole"_ENC["PULL IN RADIUS"]/100.f*24,util::random(2*PI)}.cart()};
return Effect{particlePos,util::random_range(0.3f,0.5f),"pixel.png",self.OnUpperLevel(),util::random(2.f),0.1f,util::pointTo(particlePos,self.pos)*util::random_range(700,1000),PixelLerp(BLACK,Pixel(0x9859de),util::random(1.f)),0.f,0.f,false};
}),true)};
}},true);
}
return true;
@ -202,7 +202,7 @@ void Wizard::InitializeClassAbilities(){
if(p->HasEnchant("Summon Comet")&&p->HasEnchant("Solar Flare"))meteorType=Meteor::COMET_FLARE;
else if(p->HasEnchant("Summon Comet"))meteorType=Meteor::COMET;
else if(p->HasEnchant("Solar Flare"))meteorType=Meteor::SOLAR_FLARE;
game->AddEffect(std::make_unique<Meteor>(pos,3,p->OnUpperLevel(),meteorType,std::pair<MeteorDamage,PulsatingFireDamage>{p->GetAttack(),int(p->GetAttack()*"Wizard.Ability 3.FireRingDamageMult"_F)},"Wizard.Ability 3.MeteorFadeoutTime"_F));
game->AddEffect(Meteor{pos,3,p->OnUpperLevel(),meteorType,std::pair<MeteorDamage,PulsatingFireDamage>{p->GetAttack(),int(p->GetAttack()*"Wizard.Ability 3.FireRingDamageMult"_F)},"Wizard.Ability 3.MeteorFadeoutTime"_F});
return true;
};
#pragma endregion

View File

@ -288,7 +288,7 @@ DEFINE_STRATEGY(ZEPHY)
float windRotationSpd=util::random(util::degToRad(15.f));
if(!positiveWindRotation)windRotationSpd*=-1;
game->AddEffect(std::make_unique<ForegroundEffect>(randomScreenOffset,randomLifetime,windImageChoice,m.OnUpperLevel(),vf2d{1.f,1.f}*(util::random_range(0.25f,1.f)),1.f,randomSpeed,Pixel{randomColAmt,randomColAmt,randomColAmt,randomAlpha},util::random(2*PI),windRotationSpd,true));
game->AddEffect(ForegroundEffect{randomScreenOffset,randomLifetime,windImageChoice,m.OnUpperLevel(),vf2d{1.f,1.f}*(util::random_range(0.25f,1.f)),1.f,randomSpeed,Pixel{randomColAmt,randomColAmt,randomColAmt,randomAlpha},util::random(2*PI),windRotationSpd,true});
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Wind Attack.Wind Streak Spawn Rate");
}