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.
This commit is contained in:
parent
e5e69f12e4
commit
2c54e9a9c7
@ -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…
x
Reference in New Issue
Block a user