Switch to storing unique pointers for the monsters list instead of objects. Added a source monster for frog tongues to remain attached to so they follow the monster that they originated from. Release Build 8734.

mac-build
sigonasr2 8 months ago
parent d85946f034
commit f9ffd026a9
  1. 68
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 8
      Adventures in Lestoria/Bear.cpp
  3. 3
      Adventures in Lestoria/BulletTypes.h
  4. 2
      Adventures in Lestoria/DEFINES.h
  5. 2
      Adventures in Lestoria/Frog.cpp
  6. 34
      Adventures in Lestoria/FrogTongue.cpp
  7. 12
      Adventures in Lestoria/LightningBolt.cpp
  8. 3
      Adventures in Lestoria/Minimap.cpp
  9. 14
      Adventures in Lestoria/Monster.cpp
  10. 24
      Adventures in Lestoria/Player.cpp
  11. 2
      Adventures in Lestoria/Version.h
  12. 18
      Adventures in Lestoria/Warrior.cpp
  13. BIN
      x64/Release/Adventures in Lestoria.exe

@ -92,7 +92,7 @@ bool _DEBUG_MAP_LOAD_INFO = false;
//360x240 //360x240
vi2d WINDOW_SIZE={24*15,24*10}; vi2d WINDOW_SIZE={24*15,24*10};
safemap<std::string,Animate2D::FrameSequence>ANIMATION_DATA; safemap<std::string,Animate2D::FrameSequence>ANIMATION_DATA;
std::vector<Monster>MONSTER_LIST; std::vector<std::unique_ptr<Monster>>MONSTER_LIST;
std::vector<MonsterSpawner>SPAWNER_LIST; std::vector<MonsterSpawner>SPAWNER_LIST;
std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST; std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST;
std::vector<std::unique_ptr<Bullet>>BULLET_LIST; std::vector<std::unique_ptr<Bullet>>BULLET_LIST;
@ -734,23 +734,23 @@ void AiL::UpdateBullets(float fElapsedTime){
b->distanceTraveled+=totalDistance/24.f*100.f; b->distanceTraveled+=totalDistance/24.f*100.f;
const auto CollisionCheck=[&](){ const auto CollisionCheck=[&](){
if(b->friendly){ if(b->friendly){
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(geom2d::overlaps(m.Hitbox(),geom2d::circle(b->pos,b->radius))){ if(geom2d::overlaps(m->Hitbox(),geom2d::circle(b->pos,b->radius))){
if(b->hitList.find(&m)==b->hitList.end()&&m.Hurt(b->damage,b->OnUpperLevel(),0)){ if(b->hitList.find(&*m)==b->hitList.end()&&m->Hurt(b->damage,b->OnUpperLevel(),0)){
if(!b->hitsMultiple){ if(!b->hitsMultiple){
if(b->MonsterHit(m)){ if(b->MonsterHit(*m)){
b->dead=true; b->dead=true;
} }
return false; return false;
} }
b->hitList.insert(&m); b->hitList.insert(&*m);
} }
} }
} }
} else { } else {
if(geom2d::overlaps(player->Hitbox(),geom2d::circle(b->pos,b->radius))){ if(geom2d::overlaps(player->Hitbox(),geom2d::circle(b->pos,b->radius))){
if(player->Hurt(b->damage,b->OnUpperLevel(),0)){ if(player->Hurt(b->damage,b->OnUpperLevel(),0)){
if(b->PlayerHit(player.get())){ if(b->PlayerHit(&*player)){
b->dead=true; b->dead=true;
} }
return false; return false;
@ -790,10 +790,10 @@ void AiL::UpdateBullets(float fElapsedTime){
} }
const MonsterHurtList AiL::HurtEnemies(vf2d pos,float radius,int damage,bool upperLevel,float z)const{ const MonsterHurtList AiL::HurtEnemies(vf2d pos,float radius,int damage,bool upperLevel,float z)const{
MonsterHurtList hitList; MonsterHurtList hitList;
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(geom2d::overlaps(geom2d::circle(pos,radius),geom2d::circle(m.GetPos(),12*m.GetSizeMult()))){ if(geom2d::overlaps(geom2d::circle(pos,radius),geom2d::circle(m->GetPos(),12*m->GetSizeMult()))){
HurtReturnValue returnVal=m.Hurt(damage,upperLevel,z); HurtReturnValue returnVal=m->Hurt(damage,upperLevel,z);
hitList.push_back({&m,returnVal}); hitList.push_back({&*m,returnVal});
} }
} }
return hitList; return hitList;
@ -801,11 +801,11 @@ const MonsterHurtList AiL::HurtEnemies(vf2d pos,float radius,int damage,bool upp
const MonsterHurtList AiL::HurtEnemiesNotHit(vf2d pos,float radius,int damage,HitList&hitList,bool upperLevel,float z){ const MonsterHurtList AiL::HurtEnemiesNotHit(vf2d pos,float radius,int damage,HitList&hitList,bool upperLevel,float z){
MonsterHurtList affectedList; MonsterHurtList affectedList;
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(!hitList.count(&m)&&geom2d::overlaps(geom2d::circle(pos,radius),geom2d::circle(m.GetPos(),12*m.GetSizeMult()))){ if(!hitList.count(&*m)&&geom2d::overlaps(geom2d::circle(pos,radius),geom2d::circle(m->GetPos(),12*m->GetSizeMult()))){
HurtReturnValue returnVal=m.Hurt(damage,upperLevel,z); HurtReturnValue returnVal=m->Hurt(damage,upperLevel,z);
affectedList.push_back({&m,returnVal}); affectedList.push_back({&*m,returnVal});
hitList.insert(&m); hitList.insert(&*m);
} }
} }
return affectedList; return affectedList;
@ -813,14 +813,14 @@ const MonsterHurtList AiL::HurtEnemiesNotHit(vf2d pos,float radius,int damage,Hi
const MonsterHurtList AiL::HurtEnemiesConeNotHit(vf2d pos,float radius,float angle,float sweepAngle,int damage,HitList&hitList,bool upperLevel,float z){ const MonsterHurtList AiL::HurtEnemiesConeNotHit(vf2d pos,float radius,float angle,float sweepAngle,int damage,HitList&hitList,bool upperLevel,float z){
MonsterHurtList affectedList; MonsterHurtList affectedList;
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(!hitList.count(&m)&&geom2d::overlaps(geom2d::circle(pos,radius),geom2d::circle(m.GetPos(),12*m.GetSizeMult()))){ if(!hitList.count(&*m)&&geom2d::overlaps(geom2d::circle(pos,radius),geom2d::circle(m->GetPos(),12*m->GetSizeMult()))){
float angleToMonster=geom2d::line<float>{pos,m.GetPos()}.vector().polar().y; float angleToMonster=geom2d::line<float>{pos,m->GetPos()}.vector().polar().y;
float angleDiff=util::angle_difference(angleToMonster,angle); float angleDiff=util::angle_difference(angleToMonster,angle);
if(abs(angleDiff)<=sweepAngle){ if(abs(angleDiff)<=sweepAngle){
HurtReturnValue returnVal=m.Hurt(damage,upperLevel,z); HurtReturnValue returnVal=m->Hurt(damage,upperLevel,z);
affectedList.push_back({&m,returnVal}); affectedList.push_back({&*m,returnVal});
hitList.insert(&m); hitList.insert(&*m);
} }
} }
} }
@ -851,14 +851,14 @@ void AiL::PopulateRenderLists(){
Player*pl=GetPlayer(); Player*pl=GetPlayer();
pl->rendered=false; pl->rendered=false;
std::sort(MONSTER_LIST.begin(),MONSTER_LIST.end(),[](Monster&m1,Monster&m2){return m1.GetPos().y<m2.GetPos().y;}); std::sort(MONSTER_LIST.begin(),MONSTER_LIST.end(),[](std::unique_ptr<Monster>&m1,std::unique_ptr<Monster>&m2){return m1->GetPos().y<m2->GetPos().y;});
std::sort(ItemDrop::drops.begin(),ItemDrop::drops.end(),[](ItemDrop&id1,ItemDrop&id2){return id1.GetPos().y<id2.GetPos().y;}); std::sort(ItemDrop::drops.begin(),ItemDrop::drops.end(),[](ItemDrop&id1,ItemDrop&id2){return id1.GetPos().y<id2.GetPos().y;});
std::sort(BULLET_LIST.begin(),BULLET_LIST.end(),[](std::unique_ptr<Bullet>&b1,std::unique_ptr<Bullet>&b2){return b1->pos.y<b2->pos.y;}); std::sort(BULLET_LIST.begin(),BULLET_LIST.end(),[](std::unique_ptr<Bullet>&b1,std::unique_ptr<Bullet>&b2){return b1->pos.y<b2->pos.y;});
std::sort(foregroundEffects.begin(),foregroundEffects.end(),[](std::unique_ptr<Effect>&e1,std::unique_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;}); std::sort(foregroundEffects.begin(),foregroundEffects.end(),[](std::unique_ptr<Effect>&e1,std::unique_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;});
std::sort(backgroundEffects.begin(),backgroundEffects.end(),[](std::unique_ptr<Effect>&e1,std::unique_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;}); std::sort(backgroundEffects.begin(),backgroundEffects.end(),[](std::unique_ptr<Effect>&e1,std::unique_ptr<Effect>&e2){return e1->pos.y<e2->pos.y;});
for(auto it=MONSTER_LIST.begin();it!=MONSTER_LIST.end();++it){ for(auto it=MONSTER_LIST.begin();it!=MONSTER_LIST.end();++it){
Monster&m=*it; Monster&m=**it;
if(m.GetPos().y<pl->GetPos().y){//This monster renders before the player does (behind the player) if(m.GetPos().y<pl->GetPos().y){//This monster renders before the player does (behind the player)
if(m.OnUpperLevel()){ if(m.OnUpperLevel()){
monstersBeforeUpper.push_back(&m); monstersBeforeUpper.push_back(&m);
@ -1021,8 +1021,8 @@ void AiL::RenderWorld(float fElapsedTime){
multiplierX*=(1-abs(cos(1.5f*reflectionStepTime))*"water_reflection_scale_factor"_F); multiplierX*=(1-abs(cos(1.5f*reflectionStepTime))*"water_reflection_scale_factor"_F);
float reflectionRatioX=abs(sin(reflectionStepTime))*"water_reflection_scale_factor"_F; float reflectionRatioX=abs(sin(reflectionStepTime))*"water_reflection_scale_factor"_F;
RenderPlayer(player->GetPos()+vf2d{reflectionRatioX*player->GetFrame().GetSourceRect().size.x,float(player->GetFrame().GetSourceRect().size.y)-8}*player->GetSizeMult(),{multiplierX,-1}); RenderPlayer(player->GetPos()+vf2d{reflectionRatioX*player->GetFrame().GetSourceRect().size.x,float(player->GetFrame().GetSourceRect().size.y)-8}*player->GetSizeMult(),{multiplierX,-1});
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
m.DrawReflection(reflectionRatioX,multiplierX); m->DrawReflection(reflectionRatioX,multiplierX);
} }
SetDecalMode(DecalMode::NORMAL); SetDecalMode(DecalMode::NORMAL);
} }
@ -1689,8 +1689,8 @@ void AiL::RenderWorld(float fElapsedTime){
} }
} }
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
m.strategyDrawOverlay(this,m,MONSTER_DATA[m.GetName()].GetAIStrategy()); m->strategyDrawOverlay(this,*m,MONSTER_DATA[m->GetName()].GetAIStrategy());
} }
#ifdef _DEBUG #ifdef _DEBUG
@ -2415,9 +2415,9 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){
LoadingScreen::AddPhase([&](){ LoadingScreen::AddPhase([&](){
for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){ for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
if(Unlock::IsUnlocked(data.unlockCondition)){ if(Unlock::IsUnlocked(data.unlockCondition)){
MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]}); MONSTER_LIST.push_back(std::make_unique<Monster>(data.spawnPos,MONSTER_DATA[data.name]));
MONSTER_LIST.back().iframe_timer=INFINITE; MONSTER_LIST.back()->iframe_timer=INFINITE;
MONSTER_LIST.back().npcData=data; MONSTER_LIST.back()->npcData=data;
} }
} }
return true; return true;
@ -3930,12 +3930,12 @@ rcode AiL::LoadResource(Renderable&renderable,std::string_view imgPath,bool filt
} }
void AiL::UpdateMonsters(){ void AiL::UpdateMonsters(){
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
m.Update(game->GetElapsedTime()); m->Update(game->GetElapsedTime());
} }
for(Monster&m:game->monstersToBeSpawned){ for(Monster&m:game->monstersToBeSpawned){
size_t prevCapacity=MONSTER_LIST.capacity(); size_t prevCapacity=MONSTER_LIST.capacity();
MONSTER_LIST.push_back(m); MONSTER_LIST.push_back(std::make_unique<Monster>(m));
if(MONSTER_LIST.capacity()>prevCapacity)LOG(std::format("WARNING! The monster list has automatically reserved more space and resized to {}! This caused one potential frame where bullet/effect hitlists that stored information on what monsters were hit to potentially be hit a second time or cause monsters that should've been hit to never be hit. Consider starting with a larger default reserved size for MONSTER_LIST if your intention was to have this many monsters!",MONSTER_LIST.capacity())); if(MONSTER_LIST.capacity()>prevCapacity)LOG(std::format("WARNING! The monster list has automatically reserved more space and resized to {}! This caused one potential frame where bullet/effect hitlists that stored information on what monsters were hit to potentially be hit a second time or cause monsters that should've been hit to never be hit. Consider starting with a larger default reserved size for MONSTER_LIST if your intention was to have this many monsters!",MONSTER_LIST.capacity()));
} }
game->monstersToBeSpawned.clear(); game->monstersToBeSpawned.clear();

@ -93,10 +93,10 @@ void Monster::STRATEGY::BEAR(Monster&m,float fElapsedTime,std::string strategy){
game->GetPlayer()->Knockback(playerDirVecNorm*ConfigFloat("Attack Knockback Amount")); game->GetPlayer()->Knockback(playerDirVecNorm*ConfigFloat("Attack Knockback Amount"));
} }
} }
for(Monster&otherM:MONSTER_LIST){ for(std::unique_ptr<Monster>&otherM:MONSTER_LIST){
if(!otherM.AttackAvoided(m.GetZ())&&&m!=&otherM&&geom2d::overlaps(attackCircle,otherM.Hitbox())){ if(!otherM->AttackAvoided(m.GetZ())&&&m!=otherM.get()&&geom2d::overlaps(attackCircle,otherM->Hitbox())){
otherM.Knockup(ConfigFloat("Attack Knockup Duration")); otherM->Knockup(ConfigFloat("Attack Knockup Duration"));
vf2d monsterDirVecNorm=geom2d::line<float>(m.GetPos(),otherM.GetPos()).vector().norm(); vf2d monsterDirVecNorm=geom2d::line<float>(m.GetPos(),otherM->GetPos()).vector().norm();
game->GetPlayer()->Knockback(monsterDirVecNorm*ConfigFloat("Attack Knockback Amount")); game->GetPlayer()->Knockback(monsterDirVecNorm*ConfigFloat("Attack Knockback Amount"));
} }
} }

@ -85,7 +85,8 @@ struct FrogTongue:public Bullet{
float tongueLength; float tongueLength;
float duration; float duration;
float knockbackStrength; float knockbackStrength;
FrogTongue(vf2d pos,vf2d targetPos,float lifetime,int damage,bool upperLevel,float knockbackStrength=1.0f,bool friendly=false,Pixel col=WHITE); Monster&sourceMonster;
FrogTongue(Monster&sourceMonster,vf2d targetPos,float lifetime,int damage,bool upperLevel,float knockbackStrength=1.0f,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
bool PlayerHit(Player*player)override; bool PlayerHit(Player*player)override;
bool MonsterHit(Monster&monster)override; bool MonsterHit(Monster&monster)override;

@ -42,7 +42,7 @@ All rights reserved.
using BackdropName=std::string; using BackdropName=std::string;
#define INCLUDE_ANIMATION_DATA extern safemap<std::string,Animate2D::FrameSequence>ANIMATION_DATA; #define INCLUDE_ANIMATION_DATA extern safemap<std::string,Animate2D::FrameSequence>ANIMATION_DATA;
#define INCLUDE_MONSTER_LIST extern std::vector<Monster>MONSTER_LIST; #define INCLUDE_MONSTER_LIST extern std::vector<std::unique_ptr<Monster>>MONSTER_LIST;
#define INCLUDE_SPAWNER_LIST extern std::vector<MonsterSpawner>SPAWNER_LIST; #define INCLUDE_SPAWNER_LIST extern std::vector<MonsterSpawner>SPAWNER_LIST;
#define INCLUDE_DAMAGENUMBER_LIST extern std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST; #define INCLUDE_DAMAGENUMBER_LIST extern std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST;
#define INCLUDE_game extern AiL*game; #define INCLUDE_game extern AiL*game;

@ -70,7 +70,7 @@ void Monster::STRATEGY::FROG(Monster&m,float fElapsedTime,std::string strategy){
m.F(A::LOCKON_WAITTIME)=ConfigFloat("Attack Duration"); m.F(A::LOCKON_WAITTIME)=ConfigFloat("Attack Duration");
vf2d tongueMaxRangePos=geom2d::line<float>(m.GetPos(),m.V(A::LOCKON_POS)).upoint(ConfigFloat("Tongue Max Range")/ConfigFloat("Range")); vf2d tongueMaxRangePos=geom2d::line<float>(m.GetPos(),m.V(A::LOCKON_POS)).upoint(ConfigFloat("Tongue Max Range")/ConfigFloat("Range"));
SoundEffect::PlaySFX("Slime Shoot",m.pos); SoundEffect::PlaySFX("Slime Shoot",m.pos);
CreateBullet(FrogTongue)(m.pos,tongueMaxRangePos,ConfigFloat("Attack Duration"),m.GetAttack(),m.OnUpperLevel(),ConfigFloat("Tongue Knockback Strength"),false,ConfigPixel("Tongue Color"))EndBullet; CreateBullet(FrogTongue)(m,tongueMaxRangePos,ConfigFloat("Attack Duration"),m.GetAttack(),m.OnUpperLevel(),ConfigFloat("Tongue Knockback Strength"),false,ConfigPixel("Tongue Color"))EndBullet;
m.PerformShootAnimation(); m.PerformShootAnimation();
m.I(A::PHASE)=2; m.I(A::PHASE)=2;
} }

@ -44,28 +44,32 @@ INCLUDE_game
INCLUDE_MONSTER_LIST INCLUDE_MONSTER_LIST
INCLUDE_GFX INCLUDE_GFX
FrogTongue::FrogTongue(vf2d pos,vf2d targetPos,float lifetime,int damage,bool upperLevel,float knockbackStrength,bool friendly,Pixel col) FrogTongue::FrogTongue(Monster&sourceMonster,vf2d targetPos,float lifetime,int damage,bool upperLevel,float knockbackStrength,bool friendly,Pixel col)
:Bullet(pos,{},0,damage,upperLevel,friendly,col),targetPos(targetPos),tongueLength(0.f),knockbackStrength(knockbackStrength){ :Bullet(sourceMonster.GetPos(),{},0,damage,upperLevel,friendly,col),targetPos(targetPos),tongueLength(0.f),knockbackStrength(knockbackStrength),sourceMonster(sourceMonster){
this->lifetime=lifetime; this->lifetime=lifetime;
duration=lifetime; duration=lifetime;
} }
void FrogTongue::Update(float fElapsedTime){ void FrogTongue::Update(float fElapsedTime){
geom2d::line<float>lineToTarget(pos,targetPos); pos=sourceMonster.GetPos();
vf2d drawVec=lineToTarget.vector().norm()*3;
if(sourceMonster.IsAlive()){
geom2d::line<float>lineToTarget(pos,targetPos);
vf2d drawVec=lineToTarget.vector().norm()*3;
tongueLength=util::lerp(0,lineToTarget.length(),pow(sin((lifetime*PI)/duration),20.f)); tongueLength=util::lerp(0,lineToTarget.length(),pow(sin((lifetime*PI)/duration),20.f));
vf2d tongueEndPos=geom2d::line<float>(pos+drawVec,targetPos).upoint(pow(sin((lifetime*PI)/duration),20.f)); vf2d tongueEndPos=geom2d::line<float>(pos+drawVec,targetPos).upoint(pow(sin((lifetime*PI)/duration),20.f));
geom2d::line<float>tongueLine(pos+drawVec,tongueEndPos); geom2d::line<float>tongueLine(pos+drawVec,tongueEndPos);
if(!friendly&&geom2d::overlaps(game->GetPlayer()->Hitbox(),tongueLine)){ if(!friendly&&geom2d::overlaps(game->GetPlayer()->Hitbox(),tongueLine)){
PlayerHit(game->GetPlayer()); PlayerHit(game->GetPlayer());
} }
if(friendly){ if(friendly){
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(hitList.find(&m)==hitList.end()&&geom2d::overlaps(m.Hitbox(),tongueLine)){ if(hitList.find(&*m)==hitList.end()&&geom2d::overlaps(m->Hitbox(),tongueLine)){
MonsterHit(m); MonsterHit(*m);
hitList.insert(&m); hitList.insert(&*m);
}
} }
} }
} }

@ -94,14 +94,14 @@ bool LightningBolt::MonsterHit(Monster& monster)
fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F; fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange));
int targetsHit=0; int targetsHit=0;
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(&m==&monster||monster.OnUpperLevel()!=m.OnUpperLevel())continue; if(&*m==&monster||monster.OnUpperLevel()!=m->OnUpperLevel())continue;
geom2d::line<float>lineToTarget=geom2d::line<float>(monster.GetPos(),m.GetPos()); geom2d::line<float>lineToTarget=geom2d::line<float>(monster.GetPos(),m->GetPos());
float dist=lineToTarget.length(); float dist=lineToTarget.length();
if(dist<="Wizard.Ability 2.LightningChainRadius"_F/100*24){ if(dist<="Wizard.Ability 2.LightningChainRadius"_F/100*24){
if(m.Hurt(int(game->GetPlayer()->GetAttack()*"Wizard.Ability 2.LightningChainDamageMult"_F),OnUpperLevel(),0)){ if(m->Hurt(int(game->GetPlayer()->GetAttack()*"Wizard.Ability 2.LightningChainDamageMult"_F),OnUpperLevel(),0)){
EMITTER_LIST.push_back(std::make_unique<LightningBoltEmitter>(LightningBoltEmitter(monster.GetPos(),m.GetPos(),"Wizard.Ability 2.LightningChainFrequency"_F,"Wizard.Ability 2.LightningChainLifetime"_F,upperLevel))); EMITTER_LIST.push_back(std::make_unique<LightningBoltEmitter>(LightningBoltEmitter(monster.GetPos(),m->GetPos(),"Wizard.Ability 2.LightningChainFrequency"_F,"Wizard.Ability 2.LightningChainLifetime"_F,upperLevel)));
game->AddEffect(std::make_unique<Effect>(m.GetPos(),"Wizard.Ability 2.LightningChainSplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.LightningChainSplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.LightningChainSplashRotationRange"_FRange)); game->AddEffect(std::make_unique<Effect>(m->GetPos(),"Wizard.Ability 2.LightningChainSplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.LightningChainSplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.LightningChainSplashRotationRange"_FRange));
targetsHit++; targetsHit++;
} }
} }

@ -78,8 +78,7 @@ void Minimap::Initialize(){
} }
} }
if(tileFound&&!collision){ if(tileFound&&!collision){
if(tileCol==BLANK)ERR("WARNING! A tile should not be blank as we should have handled all conditions that would've caused that in a different color! THIS SHOULD NOT BE HAPPENING!") minimap.Sprite()->SetPixel({x,y},{uint8_t(std::min(255.f,tileCol.r*1.5f)),uint8_t(std::min(255.f,tileCol.g*1.5f)),uint8_t(std::min(255.f,tileCol.b*1.5f))});
minimap.Sprite()->SetPixel({x,y},{uint8_t(std::min(255.f,tileCol.r*1.5f)),uint8_t(std::min(255.f,tileCol.g*1.5f)),uint8_t(std::min(255.f,tileCol.b*1.5f))});
}else }else
if(!tileFound){ if(!tileFound){
game->SetPixelMode(Pixel::ALPHA); game->SetPixelMode(Pixel::ALPHA);

@ -269,14 +269,14 @@ bool Monster::Update(float fElapsedTime){
} }
} }
if(!HasIframes()){ if(!HasIframes()){
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(&m==this)continue; if(&*m==this)continue;
if(!m.HasIframes()&&OnUpperLevel()==m.OnUpperLevel()&&abs(m.GetZ()-GetZ())<=1&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){ if(!m->HasIframes()&&OnUpperLevel()==m->OnUpperLevel()&&abs(m->GetZ()-GetZ())<=1&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m->GetPos(),12*m->GetSizeMult()/2))){
m.Collision(*this); m->Collision(*this);
geom2d::line line(pos,m.GetPos()); geom2d::line line(pos,m->GetPos());
float dist = line.length(); float dist = line.length();
m.SetPos(line.rpoint(dist*1.1f)); m->SetPos(line.rpoint(dist*1.1f));
if(m.IsAlive()){ if(m->IsAlive()){
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
} }

@ -482,19 +482,19 @@ void Player::Update(float fElapsedTime){
if(item3.cooldown<0){ if(item3.cooldown<0){
item3.cooldown=0; item3.cooldown=0;
} }
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(!HasIframes()&&abs(m.GetZ()-GetZ())<=1&&OnUpperLevel()==m.OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){ if(!HasIframes()&&abs(m->GetZ()-GetZ())<=1&&OnUpperLevel()==m->OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m->GetPos(),12*m->GetSizeMult()/2))){
if(m.IsAlive()){ if(m->IsAlive()){
m.Collision(this); m->Collision(this);
} }
geom2d::line line(pos,m.GetPos()); geom2d::line line(pos,m->GetPos());
float dist = line.length(); float dist = line.length();
if(dist<=0.001){ if(dist<=0.001){
m.SetPos(m.GetPos()+vf2d{util::random(2)-1,util::random(2)-1}); m->SetPos(m->GetPos()+vf2d{util::random(2)-1,util::random(2)-1});
}else{ }else{
m.SetPos(line.rpoint(dist*1.1f)); m->SetPos(line.rpoint(dist*1.1f));
} }
if(m.IsAlive()&&!m.IsNPC()){ //Don't set the knockback if this monster is actually an NPC. Let's just push them around. if(m->IsAlive()&&!m->IsNPC()){ //Don't set the knockback if this monster is actually an NPC. Let's just push them around.
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
} }
@ -1445,13 +1445,13 @@ const vf2d Player::GetAimingLocation(bool useWalkDir,bool invert){
}else{ }else{
//Find the closest monster target. //Find the closest monster target.
vf2d closestPoint={std::numeric_limits<float>::max(),std::numeric_limits<float>::max()}; vf2d closestPoint={std::numeric_limits<float>::max(),std::numeric_limits<float>::max()};
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(m.IsAlive()){ if(m->IsAlive()){
geom2d::line<float>aimingLine=geom2d::line<float>(GetPos(),m.GetPos()); geom2d::line<float>aimingLine=geom2d::line<float>(GetPos(),m->GetPos());
float distToMonster=aimingLine.length(); float distToMonster=aimingLine.length();
float distToClosestPoint=geom2d::line<float>(GetPos(),closestPoint).length(); float distToClosestPoint=geom2d::line<float>(GetPos(),closestPoint).length();
if(distToClosestPoint>distToMonster&&distToMonster<=operator""_Pixels("Player.Auto Aim Detection Distance"_F)){ if(distToClosestPoint>distToMonster&&distToMonster<=operator""_Pixels("Player.Auto Aim Detection Distance"_F)){
closestPoint=m.GetPos(); closestPoint=m->GetPos();
} }
} }
} }

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

@ -70,12 +70,12 @@ bool Warrior::AutoAttack(){
bool attack=false; bool attack=false;
Monster*closest=nullptr; Monster*closest=nullptr;
float closest_dist=999999; float closest_dist=999999;
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(m.IsAlive() if(m->IsAlive()&&
&&geom2d::overlaps(geom2d::circle<float>(GetPos(),attack_range*GetSizeMult()*12),geom2d::circle<float>(m.GetPos(),m.GetSizeMult()*12)) geom2d::overlaps(geom2d::circle<float>(GetPos(),attack_range*GetSizeMult()*12),geom2d::circle<float>(m->GetPos(),m->GetSizeMult()*12))&&
&&geom2d::line<float>(GetWorldAimingLocation(),m.GetPos()).length()<closest_dist){ geom2d::line<float>(GetWorldAimingLocation(),m->GetPos()).length()<closest_dist){
closest_dist=geom2d::line<float>(GetWorldAimingLocation(),m.GetPos()).length(); closest_dist=geom2d::line<float>(GetWorldAimingLocation(),m->GetPos()).length();
closest=&m; closest=&*m;
} }
} }
@ -121,9 +121,9 @@ void Warrior::InitializeClassAbilities(){
game->AddEffect(std::make_unique<Effect>(p->GetPos(),"Warrior.Ability 1.EffectLifetime"_F,"battlecry_effect.png",p->upperLevel,"Warrior.Ability 1.Range"_F/350,"Warrior.Ability 1.EffectFadetime"_F)); game->AddEffect(std::make_unique<Effect>(p->GetPos(),"Warrior.Ability 1.EffectLifetime"_F,"battlecry_effect.png",p->upperLevel,"Warrior.Ability 1.Range"_F/350,"Warrior.Ability 1.EffectFadetime"_F));
p->AddBuff(BuffType::STAT_UP,"Warrior.Ability 1.AttackUpDuration"_F,"Warrior.Ability 1.AttackIncrease"_F,{"Attack %"}); p->AddBuff(BuffType::STAT_UP,"Warrior.Ability 1.AttackUpDuration"_F,"Warrior.Ability 1.AttackIncrease"_F,{"Attack %"});
p->AddBuff(BuffType::DAMAGE_REDUCTION,"Warrior.Ability 1.DamageReductionDuration"_F,"Warrior.Ability 1.DamageReduction"_F); p->AddBuff(BuffType::DAMAGE_REDUCTION,"Warrior.Ability 1.DamageReductionDuration"_F,"Warrior.Ability 1.DamageReduction"_F);
for(Monster&m:MONSTER_LIST){ for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(m.GetSizeMult()>="Warrior.Ability 1.AffectedSizeRange"_f[0]&&m.GetSizeMult()<="Warrior.Ability 1.AffectedSizeRange"_f[1]&&geom2d::overlaps(geom2d::circle<float>(p->GetPos(),12*"Warrior.Ability 1.Range"_I/100.f),geom2d::circle<float>(m.GetPos(),m.GetSizeMult()*12))){ if(m->GetSizeMult()>="Warrior.Ability 1.AffectedSizeRange"_f[0]&&m->GetSizeMult()<="Warrior.Ability 1.AffectedSizeRange"_f[1]&&geom2d::overlaps(geom2d::circle<float>(p->GetPos(),12*"Warrior.Ability 1.Range"_I/100.f),geom2d::circle<float>(m->GetPos(),m->GetSizeMult()*12))){
m.AddBuff(BuffType::SLOWDOWN,"Warrior.Ability 1.SlowdownDuration"_F,"Warrior.Ability 1.SlowdownAmt"_F); m->AddBuff(BuffType::SLOWDOWN,"Warrior.Ability 1.SlowdownDuration"_F,"Warrior.Ability 1.SlowdownAmt"_F);
} }
} }
SoundEffect::PlaySFX("Warrior Battlecry",SoundEffect::CENTERED); SoundEffect::PlaySFX("Warrior Battlecry",SoundEffect::CENTERED);

Loading…
Cancel
Save