Add in map_range util function. Fix up FadeInOutEffect to still behave with its old behavior for Poison Pool while enabling new oscillating behaviors for size/color. Add in unit test for map_range. Implement Black Hole Enchant. Release Build 11250.

pull/65/head
sigonasr2 3 months ago
parent 94b324e7a2
commit 5b7c25df46
  1. 15
      Adventures in Lestoria Tests/EnchantTests.cpp
  2. 18
      Adventures in Lestoria Tests/EngineTests.cpp
  3. 4
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  4. 3
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  5. 58
      Adventures in Lestoria/BlackHole.h
  6. 4
      Adventures in Lestoria/Effect.cpp
  7. 13
      Adventures in Lestoria/Effect.h
  8. 14
      Adventures in Lestoria/FadeInOutEffect.cpp
  9. 2
      Adventures in Lestoria/ItemEnchant.h
  10. 19
      Adventures in Lestoria/Monster.cpp
  11. 2
      Adventures in Lestoria/Monster.h
  12. 2
      Adventures in Lestoria/PoisonBottle.cpp
  13. 2
      Adventures in Lestoria/PoisonPool.cpp
  14. 2
      Adventures in Lestoria/Version.h
  15. 11
      Adventures in Lestoria/Wizard.cpp
  16. BIN
      Adventures in Lestoria/assets/blackhole.png
  17. 3
      Adventures in Lestoria/assets/config/items/ItemEnchants.txt
  18. BIN
      Adventures in Lestoria/assets/gamepack.pak
  19. 1
      Adventures in Lestoria/util.cpp
  20. 5
      Adventures in Lestoria/util.h
  21. BIN
      x64/Release/Adventures in Lestoria.exe

@ -1210,5 +1210,20 @@ namespace EnchantTests
Assert::AreEqual(player->GetRightClickAbility().GetCooldownTime()-0.25f,player->GetRightClickAbility().cooldown,L"The cooldown should be normal again.");
Assert::AreEqual("Wizard.Right Click Ability.Mana Cost"_I,player->GetRightClickAbility().manaCost,L"The mana cost should be normal again.");
}
TEST_METHOD(BlackHoleNoEnchantCheck){
Game::ChangeClass(player,WIZARD);
player->SetTestScreenAimingLocation(player->GetPos()+vf2d{16.f,0.f});
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Game::Update(0.f);
Assert::AreEqual(size_t(0),game->GetBackgroundEffects().size(),L"There should be no background effects (i.e. Black Holes).");
}
TEST_METHOD(BlackHoleEnchantCheck){
Game::ChangeClass(player,WIZARD);
Game::GiveAndEquipEnchantedRing("Black Hole");
player->SetTestScreenAimingLocation(player->GetPos()+vf2d{16.f,0.f});
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Game::Update(0.f);
Assert::AreEqual(size_t(1),game->GetBackgroundEffects().size(),L"There should be a background effect (i.e. the Black Hole).");
}
};
}

@ -38,6 +38,7 @@ All rights reserved.
#include "CppUnitTest.h"
#include "AdventuresInLestoria.h"
#include "util.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
@ -105,5 +106,22 @@ namespace EngineTests
std::u32string u32middleColorCodeStr{middleColorCodeStr.begin(),middleColorCodeStr.end()};
Assert::AreEqual(WHITE.n,testGame->GetFinalRenderColor(WHITE,middleColorCodeStr).n,L"Should use source color since there's no leading HTML color code.");
}
TEST_METHOD(UtilMapRangeTest){
Assert::AreEqual(0.f,util::map_range<float>(0.f,0,100,0,100),L"0 in input range 0-100 output range 0-100 maps to 0");
Assert::AreEqual(100.f,util::map_range<float>(100.f,0,100,0,100),L"100 in input range 0-100 output range 0-100 maps to 100");
Assert::AreEqual(50.f,util::map_range<float>(50.f,0,100,0,100),L"50 in input range 0-100 output range 0-100 maps to 100");
Assert::AreEqual(0.f,util::map_range<float>(0.f,0,50,0,100),L"0 in input range 0-50 output range 0-100 maps to 0");
Assert::AreEqual(200.f,util::map_range<float>(100.f,0,50,0,100),L"100 in input range 0-50 output range 0-100 maps to 200");
Assert::AreEqual(100.f,util::map_range<float>(50.f,0,50,0,100),L"50 in input range 0-50 output range 0-100 maps to 100");
Assert::AreEqual(100.f,util::map_range<float>(0.f,0,100,100,200),L"0 in input range 0-100 output range 100-200 maps to 100");
Assert::AreEqual(200.f,util::map_range<float>(100.f,0,100,100,200),L"100 in input range 0-100 output range 100-200 maps to 200");
Assert::AreEqual(150.f,util::map_range<float>(50.f,0,100,100,200),L"50 in input range 0-100 output range 100-200 maps to 150");
Assert::AreEqual(0.f,util::map_range<float>(0.f,50,100,100,200),L"0 in input range 50-100 output range 100-200 maps to 0");
Assert::AreEqual(200.f,util::map_range<float>(100.f,50,100,100,200),L"100 in input range 50-100 output range 100-200 maps to 200");
Assert::AreEqual(100.f,util::map_range<float>(50.f,50,100,100,200),L"50 in input range 50-100 output range 100-200 maps to 100");
}
};
}

@ -387,6 +387,10 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="BlackHole.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="BombBoom.h">
<SubType>
</SubType>

@ -684,6 +684,9 @@
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BlackHole.h">
<Filter>Source Files\Effects</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Player.cpp">

@ -0,0 +1,58 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#include "AdventuresInLestoria.h"
#include "util.h"
INCLUDE_MONSTER_LIST
struct BlackHole:FadeInOutEffect{
inline BlackHole(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,OscillatorFloat size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect(const Effect&self)>&particleGenerator={})
:FadeInOutEffect(pos,img,lifetime,cycleSpd,onUpperLevel,size,spd,col,rotation,rotationSpd,additiveBlending,particleSpawnFreq,particleGenerator){}
inline bool Update(float fElapsedTime){
for(std::shared_ptr<Monster>&m:MONSTER_LIST){
float distToMonster{util::distance(pos,m->GetPos())};
if(distToMonster<="Black Hole"_ENC["PULL IN RADIUS"]/100.f*24){
float pullInForce{util::map_range<float>(distToMonster,0,"Black Hole"_ENC["PULL IN RADIUS"]/100.f*24,"Black Hole"_ENC["PULL IN FORCE MAX"],"Black Hole"_ENC["PULL IN FORCE MIN"])};
m->AddAddedVelocity(util::pointTo(m->GetPos(),pos)*pullInForce);
}
}
return FadeInOutEffect::Update(fElapsedTime);
}
};

@ -120,3 +120,7 @@ const float Effect::GetZ()const{
void Effect::SetType(const EffectType type){
this->type=type;
}
const bool&Effect::OnUpperLevel()const{
return upperLevel;
}

@ -45,13 +45,13 @@ class Player;
using HitList=std::unordered_set<std::variant<Monster*,Player*>>;
using OscillatorVf2d=std::pair<vf2d,vf2d>;
using OscillatorPixel=std::pair<Pixel,Pixel>;
using OscillatorFloat=std::pair<float,float>;
enum class EffectType{
NONE,
SPELL_CIRCLE,
MONSTER_SOUL,
BLINK_PORTAL,
BLACK_HOLE,
};
struct Effect{
@ -82,6 +82,7 @@ public:
bool OnUpperLevel();
const EffectType GetType()const;
const float GetZ()const;
const bool&OnUpperLevel()const;
void SetType(const EffectType type);
protected:
float original_fadeOutTime;
@ -172,23 +173,23 @@ public:
struct FadeInOutEffect:Effect{
//cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque
FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect()>&particleGenerator={});
FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect(const Effect&self)>&particleGenerator={});
//A version with oscillators for position and colors, for extra animation effects!
FadeInOutEffect(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect()>&particleGenerator={});
FadeInOutEffect(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,OscillatorFloat size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect(const Effect&self)>&particleGenerator={});
virtual bool Update(float fElapsedTime)override;
virtual void Draw()const override;
std::function<Effect()>particleGenerator;
std::function<Effect(const Effect&self)>particleGenerator;
const float particleSpawnFreq;
const float cycleSpd;
const OscillatorVf2d posOscillator;
const OscillatorFloat sizeOscillator;
const OscillatorPixel colOscillator;
float particleSpawnTimer{};
const float originalParticleSpawnTimer{};
};
struct PoisonPool:FadeInOutEffect{
PoisonPool(vf2d pos,const std::string&img,float radius,int damage,float damageFreq,const HurtType friendly,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect()>&particleGenerator={});
PoisonPool(vf2d pos,const std::string&img,float radius,int damage,float damageFreq,const HurtType friendly,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect(const Effect&self)>&particleGenerator={});
virtual bool Update(float fElapsedTime)override final;
const int damage;
float damageTimer{};

@ -39,25 +39,27 @@ All rights reserved.
#include "Effect.h"
#include "AdventuresInLestoria.h"
#include "DEFINES.h"
#include "util.h"
INCLUDE_game
FadeInOutEffect::FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function<Effect()>&particleGenerator)
:FadeInOutEffect({pos,pos},img,lifetime,cycleSpd,onUpperLevel,size,spd,{col,col},rotation,rotationSpd,additiveBlending,particleSpawnFreq,particleGenerator){}
FadeInOutEffect::FadeInOutEffect(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function<Effect()>&particleGenerator)
:particleSpawnFreq(particleSpawnFreq),particleGenerator(particleGenerator),cycleSpd(cycleSpd),particleSpawnTimer(particleSpawnFreq),originalParticleSpawnTimer(particleSpawnTimer),posOscillator(pos),colOscillator(col),Effect(pos.first,lifetime,img,onUpperLevel,size,0.25f,spd,col.first,rotation,rotationSpd,additiveBlending){}
FadeInOutEffect::FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function<Effect(const Effect&self)>&particleGenerator)
:FadeInOutEffect({pos,pos},img,lifetime,cycleSpd,onUpperLevel,{size,size},spd,{col,{col.r,col.g,col.b,0}},rotation,rotationSpd,additiveBlending,particleSpawnFreq,particleGenerator){}
FadeInOutEffect::FadeInOutEffect(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,OscillatorFloat size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function<Effect(const Effect&self)>&particleGenerator)
:particleSpawnFreq(particleSpawnFreq),particleGenerator(particleGenerator),cycleSpd(cycleSpd),particleSpawnTimer(particleSpawnFreq),originalParticleSpawnTimer(particleSpawnTimer),posOscillator(pos),colOscillator(col),sizeOscillator(size),Effect(pos.first,lifetime,img,onUpperLevel,size.first,0.25f,spd,col.first,rotation,rotationSpd,additiveBlending){}
bool FadeInOutEffect::Update(float fElapsedTime){
if(particleGenerator){
particleSpawnTimer-=fElapsedTime;
if(particleSpawnTimer<=0.f){
particleSpawnTimer+=originalParticleSpawnTimer;
game->AddEffect(std::make_unique<Effect>(particleGenerator()));
game->AddEffect(std::make_unique<Effect>(particleGenerator(*this)));
}
}
float t{float(abs(sin(PI*game->GetRunTime()*cycleSpd)))};
pos=posOscillator.first.lerp(posOscillator.second,t);
size={util::lerp(sizeOscillator.first,sizeOscillator.second,t),util::lerp(sizeOscillator.first,sizeOscillator.second,t)};
col=PixelLerp(colOscillator.first,colOscillator.second,t);
col.a=t*255;
col.a=util::lerp(colOscillator.first.a,colOscillator.second.a,t);
return Effect::Update(fElapsedTime);
}
void FadeInOutEffect::Draw()const{

@ -77,7 +77,7 @@ public:
const std::optional<AbilitySlot>&GetAbilitySlot()const;
const std::optional<Ability*>GetAbility()const; //Get the ability this enchant is tied to.
const float GetConfigValue(const std::string_view keyName)const;
const float operator[](const std::string& name)const;
const float operator[](const std::string&name)const;
private:
class ItemEnchantCategoryData{
friend class ItemEnchantInfo;

@ -325,10 +325,20 @@ bool Monster::Update(float fElapsedTime){
} else {
vel.y=std::min(0.f,vel.y+friction*fElapsedTime);
}
if(addedVel.x>0){
addedVel.x=std::max(0.f,addedVel.x-friction*fElapsedTime);
} else {
addedVel.x=std::min(0.f,addedVel.x+friction*fElapsedTime);
}
if(addedVel.y>0){
addedVel.y=std::max(0.f,addedVel.y-friction*fElapsedTime);
} else {
addedVel.y=std::min(0.f,addedVel.y+friction*fElapsedTime);
}
bumpedIntoTerrain=false;
if(vel!=vf2d{0,0}){
bumpedIntoTerrain|=SetX(pos.x+vel.x*fElapsedTime);
bumpedIntoTerrain|=SetY(pos.y+vel.y*fElapsedTime);
if(vel!=vf2d{0,0}||addedVel!=vf2d{0,0}){
bumpedIntoTerrain|=SetX(pos.x+vf2d{vel+addedVel}.x*fElapsedTime);
bumpedIntoTerrain|=SetY(pos.y+vf2d{vel+addedVel}.y*fElapsedTime);
}
if(IsAlive()){
@ -1611,3 +1621,6 @@ const bool Monster::FaceTarget()const{
void Monster::ResetCurseOfDeathDamage(){
accumulatedCurseOfDeathDamage=0;
}
void Monster::AddAddedVelocity(vf2d vel){
this->addedVel+=vel;
}

@ -110,6 +110,7 @@ public:
void Collision(Monster&p);
void Collision();
void SetVelocity(vf2d vel);
void AddAddedVelocity(vf2d vel); //NOTE: If a monster is trying to set its velocity internally, use SetVelocity() instead. This function is for external sources affecting this monster's velocity.
//Returns false if the monster could not be moved to the requested location due to collision.
bool SetPos(vf2d pos);
//Returns false if the monster could not be moved to the requested location due to collision.
@ -315,6 +316,7 @@ private:
void LongLastingMarkEffect(float&out_markDuration); //Modifies a given duration.
float stunTimer{};
int accumulatedCurseOfDeathDamage{};
vf2d addedVel{};
struct STRATEGY{
static std::string ERR;

@ -72,7 +72,7 @@ void PoisonBottle::Update(float fElapsedTime){
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));
}
if(additionalBounceCount==0&&game->GetPlayer()->HasEnchant("Pooling Poison")){
game->AddEffect(std::make_unique<PoisonPool>(pos,"poison_pool.png",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](){
game->AddEffect(std::make_unique<PoisonPool>(pos,"poison_pool.png",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){
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);

@ -42,7 +42,7 @@ All rights reserved.
INCLUDE_game
PoisonPool::PoisonPool(vf2d pos,const std::string&img,float radius,int damage,float damageFreq,const HurtType friendly,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function<Effect()>&particleGenerator)
PoisonPool::PoisonPool(vf2d pos,const std::string&img,float radius,int damage,float damageFreq,const HurtType friendly,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function<Effect(const Effect&self)>&particleGenerator)
:damage(damage),damageTimer(damageFreq),originalDamageTimer(damageTimer),radius(radius),friendly(friendly),poisonPoolSFXID(SoundEffect::PlayLoopingSFX("Poison Pool",pos)),FadeInOutEffect(pos,img,lifetime,cycleSpd,onUpperLevel,size,spd,col,rotation,rotationSpd,additiveBlending,particleSpawnFreq,particleGenerator){}
bool PoisonPool::Update(float fElapsedTime){

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 5
#define VERSION_BUILD 11230
#define VERSION_BUILD 11250
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -44,6 +44,7 @@ All rights reserved.
#include "config.h"
#include "util.h"
#include "SoundEffect.h"
#include "BlackHole.h"
INCLUDE_MONSTER_LIST
INCLUDE_BULLET_LIST
@ -155,11 +156,19 @@ 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>(OscillatorVf2d{p->GetPos(),p->GetPos()+vf2d{0,-6.f}},"portal.png","Blink Portal"_ENC["REACTIVATION TIME"],0.5f,p->OnUpperLevel(),1.f,vf2d{},OscillatorPixel{WHITE,0x50196f},0.f,0.f),true)};
Effect&eff{game->AddEffect(std::make_unique<FadeInOutEffect>(OscillatorVf2d{p->GetPos(),p->GetPos()+vf2d{0,-6.f}},"portal.png","Blink Portal"_ENC["REACTIVATION TIME"],0.5f,p->OnUpperLevel(),OscillatorFloat{0.9f,1.1f},vf2d{},OscillatorPixel{WHITE,0x50196f},0.f,0.f),true)};
eff.SetType(EffectType::BLINK_PORTAL);
}
TeleportTo(teleportPoint);
p->lastPathfindingCooldown=0.1f;
if(p->HasEnchant("Black Hole")){
Effect&blackHoleEff{game->AddEffect(std::make_unique<BlackHole>(OscillatorVf2d{p->GetPos(),p->GetPos()+vf2d{0,-6.f}},"blackhole.png","Black Hole"_ENC["BLACK HOLE DURATION"],0.75f,p->OnUpperLevel(),OscillatorFloat{3.4f,3.7f},vf2d{},OscillatorPixel{WHITE,WHITE},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)};
}
return true;
} else {
p->NotificationDisplay("Cannot Teleport to that location!",0.5f);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 B

After

Width:  |  Height:  |  Size: 5.3 KiB

@ -495,6 +495,9 @@ Item Enchants
Affects = Right Click Ability
BLACK HOLE DURATION = 4s
PULL IN FORCE MIN = 1
PULL IN FORCE MAX = 6
PULL IN RADIUS = 350
# Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0

@ -217,4 +217,3 @@ void util::turn_towards_direction(float&angle,float target,float rate)
std::wstring util::to_wstring(const std::string&str){
return {str.begin(),str.end()};
}

@ -73,6 +73,11 @@ namespace olc::util{
std::wstring wformat(std::string str,_Args&..._Vals){
return util::to_wstring(std::vformat(str,std::make_format_args(_Vals...)));
}
template<class T>
T map_range(T x, T in_min, T in_max, T out_min, T out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
}
template<class TL, class TR>

Loading…
Cancel
Save