diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index 7d78e3a8..5c2c7d87 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -804,6 +804,7 @@ void AiL::RenderWorld(float fElapsedTime){ if(player->teleportAnimationTimer>0){ playerScale.x=120*float(abs(pow(player->teleportAnimationTimer-"Wizard.Right Click Ability.AnimationTime"_F/2,3))); pos=player->teleportStartPosition.lerp(player->teleportTarget,("Wizard.Right Click Ability.AnimationTime"_F-player->teleportAnimationTimer)/"Wizard.Right Click Ability.AnimationTime"_F); + std::cout<attackBuffs=player->GetStatBuffs({"Attack","Attack %"}); view.DrawPartialRotatedDecal(pos+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)},player->GetFrame().GetSourceImage()->Decal(),player->GetSpinAngle(),{12,12},player->GetFrame().GetSourceRect().pos,player->GetFrame().GetSourceRect().size,playerScale*scale,attackBuffs.size()>0?Pixel{255,uint8_t(255*abs(sin(1.4*attackBuffs[0].duration))),uint8_t(255*abs(sin(1.4*attackBuffs[0].duration)))}:WHITE); @@ -957,11 +958,13 @@ void AiL::RenderWorld(float fElapsedTime){ for(int x2=0;x2<2;x2++){ vf2d tilePos=vf2d{float(x),float(y)}*24; vf2d gridPos=tilePos+pathfinder.gridSpacing*vf2d{float(x2),float(y2)}; - Pixel col=RED; - if(!pathfinder.nodes[gridPos].bObstacle&&!pathfinder.nodes[gridPos].bObstacleUpper){ - col=GREEN; + if(pathfinder.nodes.count(gridPos)){ + Pixel col=RED; + if(!pathfinder.nodes[gridPos].bObstacle&&!pathfinder.nodes[gridPos].bObstacleUpper){ + col=GREEN; + } + view.FillRectDecal(gridPos,pathfinder.gridSpacing,{col.r,col.g,col.b,128}); } - view.FillRectDecal(gridPos,pathfinder.gridSpacing,{col.r,col.g,col.b,128}); } } } diff --git a/Adventures in Lestoria/EnvironmentalAudio.cpp b/Adventures in Lestoria/EnvironmentalAudio.cpp index 9edad25e..b432c73b 100644 --- a/Adventures in Lestoria/EnvironmentalAudio.cpp +++ b/Adventures in Lestoria/EnvironmentalAudio.cpp @@ -92,7 +92,7 @@ void EnvironmentalAudio::Update(){ return; //Do not need to continue processing if the sound is not even going to be heard. } float distRatio=1-distanceFromPlayer/ACTIVATION_RANGE; //0-1 where 1 is full volume. - float xDistRatio=(pos.x-game->GetPlayer()->GetX())/ACTIVATION_RANGE; //0-1 where 1 is full volume. + float xDistRatio=(game->GetPlayer()->GetX()-pos.x)/ACTIVATION_RANGE; //0-1 where 1 is full volume. Audio::Engine().SetVolume(soundInstance,distRatio*SOUND_DATA[audioName].volume); Audio::Engine().SetPan(soundInstance,xDistRatio); diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index c7e38c2f..5b93d57e 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -113,7 +113,7 @@ void Monster::PerformShootAnimation(){ void Monster::PerformIdleAnimation(){ animation.ChangeState(internal_animState,MONSTER_DATA[name].GetIdleAnimation()); } -bool Monster::SetX(float x){ +bool Monster::_SetX(float x,const bool monsterInvoked){ vf2d newPos={x,pos.y}; vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth; geom2d::rectcollisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel); @@ -123,16 +123,27 @@ bool Monster::SetX(float x){ return true; } else { geom2d::rectcollision={collisionRect.pos,collisionRect.size}; + #pragma region lambdas + auto NoEnemyCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle(newPos,game->GetCurrentMapData().tilewidth/2*GetSizeMult()),collision);}; + #pragma endregion collision.pos+=tilePos; - if(!geom2d::overlaps(geom2d::circle(newPos,12*GetSizeMult()),collision)){ + if(NoEnemyCollisionWithTile()){ pos.x=std::clamp(x,game->GetCurrentMapData().tilewidth/2.f*GetSizeMult(),float(game->GetCurrentMapData().width*game->GetCurrentMapData().tilewidth-game->GetCurrentMapData().tilewidth/2.f*GetSizeMult())); Moved(); return true; + }else + if(monsterInvoked){ //If player invoked, we'll try the smart move system. + vf2d pushDir=geom2d::line(collision.middle(),pos).vector().norm(); + newPos={newPos.x,pos.y+pushDir.y*12}; + if(NoEnemyCollisionWithTile()){ + return _SetY(pos.y+pushDir.y,false); + } } } return false; } -bool Monster::SetY(float y){ + +bool Monster::_SetY(float y,const bool monsterInvoked){ vf2d newPos={pos.x,y}; vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth; geom2d::rectcollisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel); @@ -142,19 +153,39 @@ bool Monster::SetY(float y){ return true; } else { geom2d::rectcollision={collisionRect.pos,collisionRect.size}; + #pragma region lambdas + auto NoEnemyCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle(newPos,game->GetCurrentMapData().tilewidth/2*GetSizeMult()),collision);}; + #pragma endregion collision.pos+=tilePos; - if(!geom2d::overlaps(geom2d::circle(newPos,game->GetCurrentMapData().tilewidth/2*GetSizeMult()),collision)){ + if(NoEnemyCollisionWithTile()){ pos.y=std::clamp(y,game->GetCurrentMapData().tilewidth/2.f*GetSizeMult(),float(game->GetCurrentMapData().height*game->GetCurrentMapData().tilewidth-game->GetCurrentMapData().tilewidth/2.f*GetSizeMult())); Moved(); return true; + }else + if(monsterInvoked){ //If player invoked, we'll try the smart move system.{ + vf2d pushDir=geom2d::line(collision.middle(),pos).vector().norm(); + newPos={pos.x+pushDir.x*12,newPos.y}; + if(NoEnemyCollisionWithTile()){ + return _SetX(pos.x+pushDir.x,false); + } } } return false; } + +bool Monster::SetX(float x){ + return _SetX(x); +} + +bool Monster::SetY(float y){ + return _SetY(y); +} + bool Monster::Update(float fElapsedTime){ lastHitTimer=std::max(0.f,lastHitTimer-fElapsedTime); iframe_timer=std::max(0.f,iframe_timer-fElapsedTime); monsterHurtSoundCooldown=std::max(0.f,monsterHurtSoundCooldown-fElapsedTime); + lastHitPlayer=std::max(0.f,lastHitPlayer-fElapsedTime); if(size!=targetSize){ if(size>targetSize){ @@ -270,9 +301,9 @@ void Monster::DrawReflection(float drawRatioX,float multiplierX){ game->SetDecalMode(DecalMode::NORMAL); } void Monster::Collision(Player*p){ - if(MONSTER_DATA[name].GetCollisionDmg()>0&&!hasHitPlayer){ + if(MONSTER_DATA[name].GetCollisionDmg()>0&&lastHitPlayer==0.0f){ if(p->Hurt(MONSTER_DATA[name].GetCollisionDmg(),OnUpperLevel(),GetZ())){ - hasHitPlayer=true; + lastHitPlayer=1.0f; } } Collision(); @@ -419,7 +450,7 @@ void Monster::AddBuff(BuffType type,float duration,float intensity){ buffList.push_back(Buff{type,duration,intensity}); } -void Monster::StartPathfinding(float pathingTime){ +bool Monster::StartPathfinding(float pathingTime){ SetState(State::PATH_AROUND); path=game->pathfinder.Solve_WalkPath(pos,target,12,OnUpperLevel()); if(path.points.size()>0){ @@ -427,6 +458,7 @@ void Monster::StartPathfinding(float pathingTime){ //We gives this mob 5 seconds to figure out a path to the target. targetAcquireTimer=pathingTime; } + return path.points.size()>0; } void Monster::PathAroundBehavior(float fElapsedTime){ @@ -434,7 +466,12 @@ void Monster::PathAroundBehavior(float fElapsedTime){ //Move towards the new path. geom2d::line moveTowardsLine=geom2d::line(pos,path.GetSplinePoint(pathIndex).pos); if(moveTowardsLine.length()>2){ - SetPos(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult()); + if(!SetPos(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult())){ + //We are stuck, so stop pathfinding. + path.points.clear(); + pathIndex=0; + targetAcquireTimer=0; + } if(moveTowardsLine.vector().x>0){ facingDirection=RIGHT; } else { diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h index 54b94f6a..d0b79a59 100644 --- a/Adventures in Lestoria/Monster.h +++ b/Adventures in Lestoria/Monster.h @@ -150,7 +150,8 @@ public: void PerformIdleAnimation(); bool OnUpperLevel(); void Moved(); - void StartPathfinding(float pathingTime); + //Returns false if a path could not be found. + bool StartPathfinding(float pathingTime); void PathAroundBehavior(float fElapsedTime); void AddBuff(BuffType type,float duration,float intensity); std::vectorGetBuffs(BuffType buff); @@ -193,7 +194,7 @@ private: float monsterWalkSoundTimer; std::vectorbuffList; std::string GetDeathAnimationName(); - bool hasHitPlayer=false; + float lastHitPlayer=0.0f; bool canMove=true; //Set to false when stuck due to collisions. bool upperLevel=false; vf2d pathTarget={}; @@ -207,6 +208,16 @@ private: bool isBoss=false; void OnDeath(); ItemAttribute&Get(std::string_view attr); + //Returns false if the monster could not be moved to the requested location due to collision. + //If monsterInvoked is true, this means the monster was the one that instantiated this input, and it's not an extra movement done via collision. + //Set monsterInvoked to false when you don't want a movement loop due to collisions. + //Typical usage is monsterInvoked is true on first call, and monsterInvoked is false on all subsequent chained calls. + bool _SetX(float x,const bool monsterInvoked=true); + //Returns false if the monster could not be moved to the requested location due to collision. + //If monsterInvoked is true, this means the monster was the one that instantiated this input, and it's not an extra movement done via collision. + //Set monsterInvoked to false when you don't want a movement loop due to collisions. + //Typical usage is monsterInvoked is true on first call, and monsterInvoked is false on all subsequent chained calls. + bool _SetY(float y,const bool monsterInvoked=true); private: struct STRATEGY{ diff --git a/Adventures in Lestoria/Pathfinding.cpp b/Adventures in Lestoria/Pathfinding.cpp index d7c13a35..af7b8dae 100644 --- a/Adventures in Lestoria/Pathfinding.cpp +++ b/Adventures in Lestoria/Pathfinding.cpp @@ -49,6 +49,16 @@ void Pathfinding::Initialize(){ for (int x = 0; x < game->GetCurrentMapData().width*24; x+=gridSpacing.x) for (int y = 0; y < game->GetCurrentMapData().height*24; y+=gridSpacing.y) { + bool tileIsEmpty=true; + for(const LayerTag&layer:game->GetCurrentMap().LayerData){ + int tileID=layer.tiles[y/24][x/24]-1; + if(tileID!=-1){ + tileIsEmpty=false; + break; + } + } + if(tileIsEmpty)continue; //Don't add the node since it's outside the map. + sNode&node=nodes[{x,y}]; node.x = x; // ...because we give each node its own coordinates node.y = y; // ...because we give each node its own coordinates @@ -184,6 +194,7 @@ std::vector Pathfinding::Solve_AStar(vf2d startPos,vf2d endPos,float maxRa } Pathfinding::sSpline Pathfinding::Solve_WalkPath(vf2d startPos,vf2d endPos,float maxRange,bool upperLevel){ + maxRange*=(24/game->pathfinder.gridSpacing.x); Pathfinding::sSpline newSpline{}; newSpline.Initialize(Solve_AStar(startPos,endPos,maxRange,upperLevel)); return newSpline; diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index efec135f..6b8ee582 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -102,9 +102,10 @@ void Player::Initialize(){ void Player::ForceSetPos(vf2d pos){ this->pos=pos; + Moved(); } -bool Player::SetX(float x){ +bool Player::_SetX(float x,const bool playerInvoked){ vf2d newPos={x,pos.y}; vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth; geom2d::rectcollisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel); @@ -118,19 +119,26 @@ bool Player::SetX(float x){ } else { geom2d::rectcollision={collisionRect.pos,collisionRect.size}; #pragma region lambdas - auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(newPos,collision);}; + auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle(newPos,4),collision);}; #pragma endregion collision.pos+=tilePos; if(NoPlayerCollisionWithTile()){ pos.x=std::clamp(x,game->GetCurrentMapData().tilewidth/2.f*GetSizeMult(),float(game->GetCurrentMapData().width*game->GetCurrentMapData().tilewidth-game->GetCurrentMapData().tilewidth/2.f*GetSizeMult())); Moved(); return true; + }else + if(playerInvoked){ //If player invoked, we'll try the smart move system. + vf2d pushDir=geom2d::line(collision.middle(),pos).vector().norm(); + newPos={newPos.x,pos.y+pushDir.y*12}; + if(NoPlayerCollisionWithTile()){ + return _SetY(pos.y+pushDir.y,false); + } } } return false; }; -bool Player::SetY(float y){ +bool Player::_SetY(float y,const bool playerInvoked){ vf2d newPos={pos.x,y}; vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth; geom2d::rectcollisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel); @@ -144,18 +152,33 @@ bool Player::SetY(float y){ } else { geom2d::rectcollision={collisionRect.pos,collisionRect.size}; #pragma region lambdas - auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(newPos,collision);}; + auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle(newPos,4),collision);}; #pragma endregion collision.pos+=tilePos; if(NoPlayerCollisionWithTile()){ pos.y=std::clamp(y,game->GetCurrentMapData().tilewidth/2.f*GetSizeMult(),float(game->GetCurrentMapData().height*game->GetCurrentMapData().tilewidth-game->GetCurrentMapData().tilewidth/2.f*GetSizeMult())); Moved(); return true; + }else + if(playerInvoked){ //If player invoked, we'll try the smart move system.{ + vf2d pushDir=geom2d::line(collision.middle(),pos).vector().norm(); + newPos={pos.x+pushDir.x*12,newPos.y}; + if(NoPlayerCollisionWithTile()){ + return _SetX(pos.x+pushDir.x,false); + } } } return false; } +bool Player::SetX(float x){ + return _SetX(x); +} + +bool Player::SetY(float y){ + return _SetY(y); +} + void Player::SetZ(float z){ this->z=z; } @@ -824,6 +847,7 @@ CastInfo&Player::GetCastInfo(){ } bool Player::CanPathfindTo(vf2d pos,vf2d targetPos,float range){ + range*=(24/game->pathfinder.gridSpacing.x); if(targetPos.x<0||targetPos.y<0||targetPos.x>game->GetCurrentMapData().width*game->GetCurrentMapData().tilewidth||targetPos.y>game->GetCurrentMapData().height*game->GetCurrentMapData().tileheight)return false; std::vectorpathing=game->pathfinder.Solve_AStar(pos,targetPos,range,upperLevel); return pathing.size()>0&&pathing.size()=24.f*ConfigInt("Range")/100.f){ m.SetState(State::NORMAL); diff --git a/Adventures in Lestoria/RunTowards.cpp b/Adventures in Lestoria/RunTowards.cpp index 8155a3f9..822e0b00 100644 --- a/Adventures in Lestoria/RunTowards.cpp +++ b/Adventures in Lestoria/RunTowards.cpp @@ -39,6 +39,7 @@ All rights reserved. #include "DEFINES.h" #include "AdventuresInLestoria.h" #include "MonsterStrategyHelpers.h" +#include "util.h" INCLUDE_game INCLUDE_MONSTER_DATA @@ -56,14 +57,20 @@ void Monster::STRATEGY::RUN_TOWARDS(Monster&m,float fElapsedTime,std::string str m.target=desiredTargetLine.upoint(1.2f); } m.SetState(State::MOVE_TOWARDS); - m.hasHitPlayer=false; } switch(m.state){ case State::MOVE_TOWARDS:{ if(geom2d::line(m.pos,m.target).length()>100*fElapsedTime*m.GetMoveSpdMult()){ vf2d newPos=m.pos+geom2d::line(m.pos,m.target).vector().norm()*100*fElapsedTime*m.GetMoveSpdMult(); - if(!m.SetX(newPos.x)||!m.SetY(newPos.y)){ - m.StartPathfinding(4); + if(!m.SetPos(newPos)){ + bool pathFound=m.StartPathfinding(4); + if(!pathFound){ + m.SetState(State::MOVE_TOWARDS); + //Choose a random position around us and move towards it. + float randomAngle=util::random(2*PI); + float randomDist=util::random(24*6); + m.target=m.GetPos()+vf2d{sin(randomAngle),cos(randomAngle)}*randomDist; + } } m.PerformJumpAnimation(); } else { diff --git a/Adventures in Lestoria/ShootAfar.cpp b/Adventures in Lestoria/ShootAfar.cpp index 263c9f1b..2b664ed2 100644 --- a/Adventures in Lestoria/ShootAfar.cpp +++ b/Adventures in Lestoria/ShootAfar.cpp @@ -39,6 +39,7 @@ All rights reserved. #include "DEFINES.h" #include "AdventuresInLestoria.h" #include "MonsterStrategyHelpers.h" +#include "util.h" INCLUDE_BULLET_LIST INCLUDE_game @@ -86,7 +87,14 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,std::string stra m.canMove=movedX&&movedY; } if(!pathfindingDecision){ - m.StartPathfinding(2.5); + bool pathFound=m.StartPathfinding(2.5); + if(!pathFound){ + m.SetState(State::MOVE_TOWARDS); + //Choose a random position around us and move towards it. + float randomAngle=util::random(2*PI); + float randomDist=util::random(24*6); + m.target=m.GetPos()+vf2d{sin(randomAngle),cos(randomAngle)}*randomDist; + } }else if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f){ m.SetState(State::NORMAL); @@ -107,7 +115,14 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,std::string stra m.canMove=movedX&&movedY; } if(!pathfindingDecision&&m.targetAcquireTimer==0){ - m.StartPathfinding(2.5); + bool pathFound=m.StartPathfinding(2.5); + if(!pathFound){ + m.SetState(State::MOVE_TOWARDS); + //Choose a random position around us and move towards it. + float randomAngle=util::random(2*PI); + float randomDist=util::random(24*6); + m.target=m.GetPos()+vf2d{sin(randomAngle),cos(randomAngle)}*randomDist; + } }else if((m.path.points.size()==0&&!m.canMove)||line.length()>=24.f*ConfigInt("Range")/100.f){ m.SetState(State::NORMAL); diff --git a/Adventures in Lestoria/SoundEffect.cpp b/Adventures in Lestoria/SoundEffect.cpp index a4f739dc..1af94d0d 100644 --- a/Adventures in Lestoria/SoundEffect.cpp +++ b/Adventures in Lestoria/SoundEffect.cpp @@ -86,7 +86,7 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){ float distanceFromPlayer=geom2d::line(game->GetPlayer()->GetPos(),pos).length(); if(distanceFromPlayerGetPlayer()->GetX())/soundActivationRange; //0-1 where 1 is full volume. + float xDistRatio=(game->GetPlayer()->GetX()-pos.x)/soundActivationRange; //0-1 where 1 is full volume. float vol=distRatio*sfx.vol; float pan=xDistRatio; diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 77e42156..f33202d1 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 5682 +#define VERSION_BUILD 5724 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Wizard.cpp b/Adventures in Lestoria/Wizard.cpp index ce98750a..6871e26b 100644 --- a/Adventures in Lestoria/Wizard.cpp +++ b/Adventures in Lestoria/Wizard.cpp @@ -121,11 +121,22 @@ void Wizard::InitializeClassAbilities(){ dist-=4; teleportPoint=p->GetPos()+pointTowardsMouse*dist; } - if(dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,float("Wizard.Right Click Ability.TilesMax"_I))){ + vi2d tilePos=vi2d(teleportPoint/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth; + geom2d::rectcollisionRect=game->GetTileCollision(game->GetCurrentLevel(),teleportPoint,p->OnUpperLevel()); + #pragma region lambdas + auto NoTileCollisionExistsHere=[&](){return collisionRect.pos==game->NO_COLLISION.pos&&collisionRect.size==game->NO_COLLISION.size;}; + #pragma endregion + collisionRect.pos+=tilePos; + #pragma region lambdas + auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle(teleportPoint,4),collisionRect);}; + #pragma endregion + if(dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,float("Wizard.Right Click Ability.TilesMax"_I)) + &&(NoTileCollisionExistsHere()||NoPlayerCollisionWithTile())){ p->SetState(State::TELEPORT); p->teleportAnimationTimer="Wizard.Right Click Ability.AnimationTime"_F; p->teleportTarget=teleportPoint; p->teleportStartPosition=p->GetPos(); + std::cout<<"Start Position: "<<(p->teleportStartPosition)<iframe_time="Wizard.Right Click Ability.IframeTime"_F; for(int i=0;i<"Wizard.Right Click Ability.ParticleCount"_I;i++){ game->AddEffect(std::make_unique(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)); diff --git a/Adventures in Lestoria/assets/config/items/items.txt b/Adventures in Lestoria/assets/config/items/items.txt index 86694c8a..ac3cb67c 100644 --- a/Adventures in Lestoria/assets/config/items/items.txt +++ b/Adventures in Lestoria/assets/config/items/items.txt @@ -28,7 +28,7 @@ ItemDrop Item Drop Suction Range = 360 # Item drop suction strength - Item Drop Suction Strength = 5000 + Item Drop Suction Strength = 8000 # Item drop initial rise speed Item Drop Initial Rise Speed = 10 diff --git a/Adventures in Lestoria/olcUTIL_Geometry2D.h b/Adventures in Lestoria/olcUTIL_Geometry2D.h index 6a3130b9..7b23f534 100644 --- a/Adventures in Lestoria/olcUTIL_Geometry2D.h +++ b/Adventures in Lestoria/olcUTIL_Geometry2D.h @@ -311,7 +311,12 @@ namespace olc // Linearly interpolate between this vector, and another vector, given normalised parameter 't' inline constexpr v_2d lerp(const v_2d& v1, const double t) const { - return (T(1.0 - t)) + (v1 * T(t)); + return this->operator*(T(1.0 - t)) + (v1 * T(t)); + } + + inline constexpr v_2d operator * (const T& rhs) const + { + return v_2d(this->x * rhs, this->y * rhs); } // Compare if this vector is numerically equal to another