Monsters get a 1-second cooldown on collision to avoid overwhelming the player through constant charging. Remove extra A* nodes that are not required during map loading. Reversed the surround sound directions so stuff on the right is heard from the right channel, and stuff on the left is heard from the left channel. Fix lerp function in olcPGEX geometry util.

pull/30/head
sigonasr2 1 year ago
parent e5e69f12e4
commit 2c54e9a9c7
  1. 11
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 2
      Adventures in Lestoria/EnvironmentalAudio.cpp
  3. 53
      Adventures in Lestoria/Monster.cpp
  4. 15
      Adventures in Lestoria/Monster.h
  5. 11
      Adventures in Lestoria/Pathfinding.cpp
  6. 32
      Adventures in Lestoria/Player.cpp
  7. 10
      Adventures in Lestoria/Player.h
  8. 23
      Adventures in Lestoria/RunAway.cpp
  9. 13
      Adventures in Lestoria/RunTowards.cpp
  10. 19
      Adventures in Lestoria/ShootAfar.cpp
  11. 2
      Adventures in Lestoria/SoundEffect.cpp
  12. 2
      Adventures in Lestoria/Version.h
  13. 13
      Adventures in Lestoria/Wizard.cpp
  14. 2
      Adventures in Lestoria/assets/config/items/items.txt
  15. 7
      Adventures in Lestoria/olcUTIL_Geometry2D.h

@ -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<<pos<<std::endl;
}
const std::vector<Buff>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});
}
}
}

@ -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);

@ -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::rect<float>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
@ -123,16 +123,27 @@ bool Monster::SetX(float x){
return true;
} else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
#pragma region lambdas
auto NoEnemyCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle<float>(newPos,game->GetCurrentMapData().tilewidth/2*GetSizeMult()),collision);};
#pragma endregion
collision.pos+=tilePos;
if(!geom2d::overlaps(geom2d::circle<float>(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<float>(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::rect<float>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
@ -142,19 +153,39 @@ bool Monster::SetY(float y){
return true;
} else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
#pragma region lambdas
auto NoEnemyCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle<float>(newPos,game->GetCurrentMapData().tilewidth/2*GetSizeMult()),collision);};
#pragma endregion
collision.pos+=tilePos;
if(!geom2d::overlaps(geom2d::circle<float>(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<float>(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 {

@ -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::vector<Buff>GetBuffs(BuffType buff);
@ -193,7 +194,7 @@ private:
float monsterWalkSoundTimer;
std::vector<Buff>buffList;
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{

@ -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<vf2d> 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;

@ -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::rect<float>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
@ -118,19 +119,26 @@ bool Player::SetX(float x){
} else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
#pragma region lambdas
auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(newPos,collision);};
auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle<float>(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<float>(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::rect<float>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
@ -144,18 +152,33 @@ bool Player::SetY(float y){
} else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
#pragma region lambdas
auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(newPos,collision);};
auto NoPlayerCollisionWithTile=[&](){return !geom2d::overlaps(geom2d::circle<float>(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<float>(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::vector<vf2d>pathing=game->pathfinder.Solve_AStar(pos,targetPos,range,upperLevel);
return pathing.size()>0&&pathing.size()<range;//We'll say 7 tiles or less is close enough to 650 range. Have a little bit of wiggle room.

@ -272,6 +272,16 @@ private:
uint32_t money="Player.Starting Money"_I;
EntityStats stats;
ItemAttribute&Get(std::string_view attr);
//Returns true if the move was valid and successful.
//If playerInvoked is true, this means the player was the one that instantiated this input, and it's not an extra movement done via collision.
//Set playerInvoked to false when you don't want a movement loop due to collisions.
//Typical usage is playerInvoked is true on first call, and playerInvoked is false on all subsequent chained calls.
bool _SetX(float x,const bool playerInvoked=true);
//Returns true if the move was valid and successful.
//If playerInvoked is true, this means the player was the one that instantiated this input, and it's not an extra movement done via collision.
//Set playerInvoked to false when you don't want a movement loop due to collisions.
//Typical usage is playerInvoked is true on first call, and playerInvoked is false on all subsequent chained calls.
bool _SetY(float y,const bool playerInvoked=true);
protected:
const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F;
const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F;

@ -39,6 +39,7 @@ All rights reserved.
#include "DEFINES.h"
#include "AdventuresInLestoria.h"
#include "MonsterStrategyHelpers.h"
#include "util.h"
INCLUDE_BULLET_LIST
INCLUDE_game
@ -73,11 +74,18 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate
vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
bool movedX=m.SetX(newPos.x);
bool movedY=m.SetY(newPos.y);
pathfindingDecision=movedX|movedY;
pathfindingDecision=movedX||movedY;
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);
@ -94,11 +102,18 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate
vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
bool movedX=m.SetX(newPos.x);
bool movedY=m.SetY(newPos.y);
pathfindingDecision=movedX|movedY;
pathfindingDecision=movedX||movedY;
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("Range")/100.f){
m.SetState(State::NORMAL);

@ -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 {

@ -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);

@ -86,7 +86,7 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){
float distanceFromPlayer=geom2d::line<float>(game->GetPlayer()->GetPos(),pos).length();
if(distanceFromPlayer<soundActivationRange){
float distRatio=1-distanceFromPlayer/soundActivationRange; //0-1 where 1 is full volume.
float xDistRatio=(pos.x-game->GetPlayer()->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;

@ -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

@ -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::rect<float>collisionRect=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<float>(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)<<std::endl;
p->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<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));

@ -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

@ -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

Loading…
Cancel
Save