Implement Poison Bounce enchant. Fix Poison Bounce physics when dealing with lower frame rates. Release Build 11180.
This commit is contained in:
parent
e8ead7e07b
commit
88dea6fa84
@ -1021,7 +1021,6 @@ namespace EnchantTests
|
|||||||
Monster&newMonster4{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName2"])};
|
Monster&newMonster4{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName2"])};
|
||||||
Game::Update(0.f);
|
Game::Update(0.f);
|
||||||
Game::CastAbilityAtLocation(player->GetAbility1(),player->GetPos()+vf2d{30.f,0.f});
|
Game::CastAbilityAtLocation(player->GetAbility1(),player->GetPos()+vf2d{30.f,0.f});
|
||||||
Game::Update(0.f);
|
|
||||||
Assert::IsTrue(newMonster.GetBuffs(BuffType::CURSE_OF_PAIN).size()>0,L"The first monster should have been targeted with Curse of Pain.");
|
Assert::IsTrue(newMonster.GetBuffs(BuffType::CURSE_OF_PAIN).size()>0,L"The first monster should have been targeted with Curse of Pain.");
|
||||||
Game::Update(3.f);
|
Game::Update(3.f);
|
||||||
Assert::IsTrue(newMonster.IsDead(),L"The first monster has died to Curse of Pain's tick.");
|
Assert::IsTrue(newMonster.IsDead(),L"The first monster has died to Curse of Pain's tick.");
|
||||||
@ -1046,7 +1045,6 @@ namespace EnchantTests
|
|||||||
Assert::AreEqual(size_t(0),newMonster3.GetBuffs(BuffType::CURSE_OF_PAIN).size(),L"If a target without Curse of Pain dies, it should not spread onto other targets.");
|
Assert::AreEqual(size_t(0),newMonster3.GetBuffs(BuffType::CURSE_OF_PAIN).size(),L"If a target without Curse of Pain dies, it should not spread onto other targets.");
|
||||||
Assert::AreEqual(size_t(0),newMonster4.GetBuffs(BuffType::CURSE_OF_PAIN).size(),L"If a target without Curse of Pain dies, it should not spread onto other targets.");
|
Assert::AreEqual(size_t(0),newMonster4.GetBuffs(BuffType::CURSE_OF_PAIN).size(),L"If a target without Curse of Pain dies, it should not spread onto other targets.");
|
||||||
Game::CastAbilityAtLocation(player->GetAbility1(),player->GetPos()+vf2d{30.f,0.f});
|
Game::CastAbilityAtLocation(player->GetAbility1(),player->GetPos()+vf2d{30.f,0.f});
|
||||||
Game::Update(0.f);
|
|
||||||
Assert::AreEqual(size_t(1),newMonster.GetBuffs(BuffType::CURSE_OF_PAIN).size(),L"The first monster should have been targeted with Curse of Pain.");
|
Assert::AreEqual(size_t(1),newMonster.GetBuffs(BuffType::CURSE_OF_PAIN).size(),L"The first monster should have been targeted with Curse of Pain.");
|
||||||
Game::Update(3.f);
|
Game::Update(3.f);
|
||||||
Assert::IsTrue(newMonster.IsDead(),L"The first monster has died to Curse of Pain's tick.");
|
Assert::IsTrue(newMonster.IsDead(),L"The first monster has died to Curse of Pain's tick.");
|
||||||
@ -1068,7 +1066,6 @@ namespace EnchantTests
|
|||||||
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||||
Game::Update(0.f);
|
Game::Update(0.f);
|
||||||
Game::CastAbilityAtLocation(player->GetAbility2(),player->GetPos()+vf2d{30.f,0.f});
|
Game::CastAbilityAtLocation(player->GetAbility2(),player->GetPos()+vf2d{30.f,0.f});
|
||||||
Game::Update(0.f);
|
|
||||||
while(BULLET_LIST.size()>0){
|
while(BULLET_LIST.size()>0){
|
||||||
Game::Update(1/30.f);
|
Game::Update(1/30.f);
|
||||||
}
|
}
|
||||||
@ -1082,7 +1079,6 @@ namespace EnchantTests
|
|||||||
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||||
Game::Update(0.f);
|
Game::Update(0.f);
|
||||||
Game::CastAbilityAtLocation(player->GetAbility2(),player->GetPos()+vf2d{30.f,0.f});
|
Game::CastAbilityAtLocation(player->GetAbility2(),player->GetPos()+vf2d{30.f,0.f});
|
||||||
Game::Update(0.f);
|
|
||||||
while(BULLET_LIST.size()>0){
|
while(BULLET_LIST.size()>0){
|
||||||
Game::Update(1/30.f);
|
Game::Update(1/30.f);
|
||||||
}
|
}
|
||||||
@ -1090,5 +1086,26 @@ namespace EnchantTests
|
|||||||
Game::Update(2.f);
|
Game::Update(2.f);
|
||||||
Assert::AreEqual(910,newMonster.GetHealth(),L"Monster should have lost an additional 15 health from lingering Pooling Poison.");
|
Assert::AreEqual(910,newMonster.GetHealth(),L"Monster should have lost an additional 15 health from lingering Pooling Poison.");
|
||||||
}
|
}
|
||||||
|
TEST_METHOD(PoisonBounceNoEnchantCheck){
|
||||||
|
Game::ChangeClass(player,WITCH);
|
||||||
|
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||||
|
Game::Update(0.f);
|
||||||
|
Game::CastAbilityAtLocation(player->GetAbility2(),player->GetPos()+vf2d{30.f,0.f});
|
||||||
|
while(BULLET_LIST.size()>0){
|
||||||
|
Game::Update(1/30.f);
|
||||||
|
}
|
||||||
|
Assert::AreEqual(925,newMonster.GetHealth(),L"Monster should have lost 75 health from Poison Pool.");
|
||||||
|
}
|
||||||
|
TEST_METHOD(PoisonBounceEnchantCheck){
|
||||||
|
Game::ChangeClass(player,WITCH);
|
||||||
|
Game::GiveAndEquipEnchantedRing("Poison Bounce");
|
||||||
|
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||||
|
Game::Update(0.f);
|
||||||
|
Game::CastAbilityAtLocation(player->GetAbility2(),player->GetPos()+vf2d{30.f,0.f});
|
||||||
|
while(BULLET_LIST.size()>0){
|
||||||
|
Game::Update(1/30.f);
|
||||||
|
}
|
||||||
|
Assert::AreEqual(895,newMonster.GetHealth(),L"Monster should have lost 105 health from Poison Pool.");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -42,15 +42,20 @@ All rights reserved.
|
|||||||
INCLUDE_game
|
INCLUDE_game
|
||||||
|
|
||||||
namespace Game{
|
namespace Game{
|
||||||
inline void CastAbilityAtLocation(Ability&ability,const vf2d&screenLoc){ //NOTE: screenLoc is the actual screen coordinates, NOT the world coordinates! You are defining the mouse position essentially.
|
enum class CastWaitProperty{
|
||||||
game->GetPlayer()->SetTestScreenAimingLocation(screenLoc);
|
WAIT_FOR_CAST_TIME,
|
||||||
game->GetPlayer()->PrepareCast(ability);
|
NO_WAIT,
|
||||||
game->GetPlayer()->CastSpell(ability);
|
};
|
||||||
}
|
|
||||||
inline void Update(const float fElapsedTime){
|
inline void Update(const float fElapsedTime){
|
||||||
game->SetElapsedTime(fElapsedTime);
|
game->SetElapsedTime(fElapsedTime);
|
||||||
game->OnUserUpdate(fElapsedTime);
|
game->OnUserUpdate(fElapsedTime);
|
||||||
}
|
}
|
||||||
|
inline void CastAbilityAtLocation(Ability&ability,const vf2d&screenLoc,const CastWaitProperty castWaitTime=CastWaitProperty::WAIT_FOR_CAST_TIME){ //NOTE: screenLoc is the actual screen coordinates, NOT the world coordinates! You are defining the mouse position essentially.
|
||||||
|
game->GetPlayer()->SetTestScreenAimingLocation(screenLoc);
|
||||||
|
game->GetPlayer()->PrepareCast(ability);
|
||||||
|
game->GetPlayer()->CastSpell(ability);
|
||||||
|
Game::Update(ability.precastInfo.castTime);
|
||||||
|
}
|
||||||
inline void ChangeClass(Player*&player_in,const Class&cl){
|
inline void ChangeClass(Player*&player_in,const Class&cl){
|
||||||
game->ChangePlayerClass(cl);
|
game->ChangePlayerClass(cl);
|
||||||
player_in=game->GetPlayer();
|
player_in=game->GetPlayer();
|
||||||
|
@ -339,7 +339,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PoisonBottle:public Bullet{
|
struct PoisonBottle:public Bullet{
|
||||||
PoisonBottle(vf2d pos,vf2d targetPos,float explodeRadius,float z,float totalFallTime,float totalRiseZAmt,int damage,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle={0.f});
|
PoisonBottle(vf2d pos,vf2d targetPos,float explodeRadius,float bounceExplodeRadius,float z,float totalFallTime,float totalRiseZAmt,int damage,int additionalBounceCount,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle={0.f});
|
||||||
void Update(float fElapsedTime)override;
|
void Update(float fElapsedTime)override;
|
||||||
void ModifyOutgoingDamageData(HurtDamageInfo&data);
|
void ModifyOutgoingDamageData(HurtDamageInfo&data);
|
||||||
private:
|
private:
|
||||||
@ -351,4 +351,6 @@ private:
|
|||||||
const float initialZ;
|
const float initialZ;
|
||||||
const float totalRiseZAmt;
|
const float totalRiseZAmt;
|
||||||
const float explodeRadius;
|
const float explodeRadius;
|
||||||
|
const float bounceExplodeRadius;
|
||||||
|
int additionalBounceCount;
|
||||||
};
|
};
|
@ -44,8 +44,8 @@ All rights reserved.
|
|||||||
|
|
||||||
INCLUDE_game
|
INCLUDE_game
|
||||||
|
|
||||||
PoisonBottle::PoisonBottle(vf2d pos,vf2d targetPos,float explodeRadius,float z,float totalFallTime,float totalRiseZAmt,int damage,bool upperLevel,bool hitsMultiple,float lifetime,bool friendly,Pixel col,vf2d scale,float image_angle)
|
PoisonBottle::PoisonBottle(vf2d pos,vf2d targetPos,float explodeRadius,float bounceExplodeRadius,float z,float totalFallTime,float totalRiseZAmt,int damage,int additionalBounceCount,bool upperLevel,bool hitsMultiple,float lifetime,bool friendly,Pixel col,vf2d scale,float image_angle)
|
||||||
:Bullet(pos,util::pointTo(pos,targetPos)*util::distance(pos,targetPos)/totalFallTime,0.f,damage,"poison_bottle.png",upperLevel,hitsMultiple,lifetime,false,friendly,col,scale,image_angle),initialZ(z),explodeRadius(explodeRadius),totalRiseZAmt(totalRiseZAmt),totalFallTime(totalFallTime),startingPos(pos),targetPos(targetPos),originalRisingTime(totalFallTime*0.25f),risingTime(originalRisingTime),originalFallingTime(totalFallTime*0.75f),fallingTime(originalFallingTime){
|
:Bullet(pos,util::pointTo(pos,targetPos)*util::distance(pos,targetPos)/totalFallTime,0.f,damage,"poison_bottle.png",upperLevel,hitsMultiple,lifetime,false,friendly,col,scale,image_angle),initialZ(z),explodeRadius(explodeRadius),bounceExplodeRadius(bounceExplodeRadius),totalRiseZAmt(totalRiseZAmt),totalFallTime(totalFallTime),startingPos(pos),targetPos(targetPos),originalRisingTime(totalFallTime*0.25f/(additionalBounceCount+1)),risingTime(originalRisingTime),originalFallingTime(totalFallTime*0.75f/(additionalBounceCount+1)),fallingTime(originalFallingTime),additionalBounceCount(additionalBounceCount){
|
||||||
this->z=z;
|
this->z=z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,12 @@ void PoisonBottle::Update(float fElapsedTime){
|
|||||||
z=0.f;
|
z=0.f;
|
||||||
SoundEffect::PlaySFX("Glass Break",pos);
|
SoundEffect::PlaySFX("Glass Break",pos);
|
||||||
SoundEffect::PlaySFX("Poison Pool",pos);
|
SoundEffect::PlaySFX("Poison Pool",pos);
|
||||||
const float poisonCircleScale{"Witch.Ability 2.Casting Size"_F/100.f};
|
float poisonCircleScale{"Witch.Ability 2.Casting Size"_F/100.f};
|
||||||
|
if(additionalBounceCount>0)poisonCircleScale="Poison Bounce"_ENC["BOUNCE EXPLODE RADIUS"]/100.f;
|
||||||
|
|
||||||
|
float currentExplodeRadius{explodeRadius};
|
||||||
|
if(additionalBounceCount>0)currentExplodeRadius=bounceExplodeRadius;
|
||||||
|
|
||||||
game->AddEffect(std::make_unique<Effect>(pos,0.f,"poison_pool.png",game->GetPlayer()->OnUpperLevel(),0.5f,1.2f,vf2d{poisonCircleScale,poisonCircleScale},vf2d{},WHITE,0.f,0.f,false),true);
|
game->AddEffect(std::make_unique<Effect>(pos,0.f,"poison_pool.png",game->GetPlayer()->OnUpperLevel(),0.5f,1.2f,vf2d{poisonCircleScale,poisonCircleScale},vf2d{},WHITE,0.f,0.f,false),true);
|
||||||
for(int i:std::ranges::iota_view(0,200)){
|
for(int i:std::ranges::iota_view(0,200)){
|
||||||
float size{util::random_range(0.4f,0.8f)};
|
float size{util::random_range(0.4f,0.8f)};
|
||||||
@ -66,13 +71,18 @@ void PoisonBottle::Update(float fElapsedTime){
|
|||||||
col.a=util::random_range(60,200);
|
col.a=util::random_range(60,200);
|
||||||
game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col));
|
game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col));
|
||||||
}
|
}
|
||||||
if(game->GetPlayer()->HasEnchant("Pooling Poison")){
|
if(additionalBounceCount==0&&game->GetPlayer()->HasEnchant("Pooling Poison")){
|
||||||
game->AddEffect(std::make_unique<PoisonPool>(pos,"poison_pool.png",explodeRadius,game->GetPlayer()->GetAttack()*"Pooling Poison"_ENC["POISON POOL DAMAGE PCT"]/100.f,"Pooling Poison"_ENC["POISON POOL DAMAGE FREQUENCY"],friendly?HurtType::MONSTER:HurtType::PLAYER,"Pooling Poison"_ENC["SPLASH LINGER TIME"],2.f,OnUpperLevel(),poisonCircleScale,vf2d{},WHITE,0.f,0.f,false,0.05f,[pos=pos,col=col,poisonCircleScale](){
|
game->AddEffect(std::make_unique<PoisonPool>(pos,"poison_pool.png",bounceExplodeRadius,game->GetPlayer()->GetAttack()*"Pooling Poison"_ENC["POISON POOL DAMAGE PCT"]/100.f,"Pooling Poison"_ENC["POISON POOL DAMAGE FREQUENCY"],friendly?HurtType::MONSTER:HurtType::PLAYER,"Pooling Poison"_ENC["SPLASH LINGER TIME"],0.5f,OnUpperLevel(),poisonCircleScale,vf2d{},WHITE,0.f,0.f,false,0.05f,[pos=pos,col=col,poisonCircleScale](){
|
||||||
float size{util::random_range(0.4f,0.8f)};
|
float size{util::random_range(0.4f,0.8f)};
|
||||||
return Effect{pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col};
|
return Effect{pos+vf2d{util::random(16)*poisonCircleScale,util::random(2*PI)}.cart(),util::random_range(1.f,4.f),"circle.png",game->GetPlayer()->OnUpperLevel(),vf2d{size,size},util::random_range(0.2f,0.5f),vf2d{util::random_range(-6.f,6.f),util::random_range(-12.f,-4.f)},col};
|
||||||
}),true);
|
}),true);
|
||||||
}
|
}
|
||||||
const HurtList hurtList{game->Hurt(pos,explodeRadius,damage,OnUpperLevel(),z,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)};
|
|
||||||
|
int poolDamage{damage};
|
||||||
|
if(additionalBounceCount>0)poolDamage=game->GetPlayer()->GetAttack()*"Poison Bounce"_ENC["BOUNCE DAMAGE"]/100.f;
|
||||||
|
|
||||||
|
const HurtList hurtList{game->Hurt(pos,bounceExplodeRadius,poolDamage,OnUpperLevel(),z,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)};
|
||||||
|
if(additionalBounceCount==0){
|
||||||
for(const auto&[targetPtr,wasHit]:hurtList){
|
for(const auto&[targetPtr,wasHit]:hurtList){
|
||||||
if(wasHit){
|
if(wasHit){
|
||||||
Monster*monsterPtr{std::get<Monster*>(targetPtr)};
|
Monster*monsterPtr{std::get<Monster*>(targetPtr)};
|
||||||
@ -83,9 +93,16 @@ void PoisonBottle::Update(float fElapsedTime){
|
|||||||
monsterPtr->ApplyDot(buffDuration,buffDamage,buffTimeBetweenTicks);
|
monsterPtr->ApplyDot(buffDuration,buffDamage,buffTimeBetweenTicks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(additionalBounceCount>0){
|
||||||
|
additionalBounceCount--;
|
||||||
|
risingTime=originalRisingTime;
|
||||||
|
fallingTime=originalFallingTime;
|
||||||
|
}else{
|
||||||
vel={};
|
vel={};
|
||||||
fadeOutTime=0.25f;
|
fadeOutTime=0.25f;
|
||||||
Deactivate();
|
Deactivate();
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
if(risingTime>0.f){
|
if(risingTime>0.f){
|
||||||
risingTime-=fElapsedTime;
|
risingTime-=fElapsedTime;
|
||||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 1
|
#define VERSION_MAJOR 1
|
||||||
#define VERSION_MINOR 2
|
#define VERSION_MINOR 2
|
||||||
#define VERSION_PATCH 5
|
#define VERSION_PATCH 5
|
||||||
#define VERSION_BUILD 11173
|
#define VERSION_BUILD 11180
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
@ -166,9 +166,10 @@ void Witch::InitializeClassAbilities(){
|
|||||||
#pragma region Witch Ability 2 (Throw Poison)
|
#pragma region Witch Ability 2 (Throw Poison)
|
||||||
Witch::ability2.action=
|
Witch::ability2.action=
|
||||||
[](Player*p,vf2d pos={}){
|
[](Player*p,vf2d pos={}){
|
||||||
const float totalFallTime{util::lerp(0.f,0.3f,util::distance(p->GetPos(),pos)/("Witch.Ability 2.Casting Range"_F/100.f*24))};
|
int additionalBounceCount{0};
|
||||||
|
if(p->HasEnchant("Poison Bounce"))additionalBounceCount+="Poison Bounce"_ENC["BOUNCE COUNT"];
|
||||||
CreateBullet(PoisonBottle)(p->GetPos(),pos,"Witch.Ability 2.Casting Size"_F/100.f*24,12.f,totalFallTime,"Witch.Ability 2.Toss Max Z"_F,p->GetAttack()*"Witch.Ability 2.Damage Mult"_F,p->OnUpperLevel(),false,INFINITE,true,WHITE,vf2d{1.f,1.f},util::random(2*PI))EndBullet;
|
const float totalFallTime{util::lerp(1/30.f*(additionalBounceCount+1),0.3f,util::distance(p->GetPos(),pos)/("Witch.Ability 2.Casting Range"_F/100.f*24))};
|
||||||
|
CreateBullet(PoisonBottle)(p->GetPos(),pos,"Witch.Ability 2.Casting Size"_F/100.f*24,"Poison Bounce"_ENC["BOUNCE EXPLODE RADIUS"]/100.f*24,12.f,totalFallTime,"Witch.Ability 2.Toss Max Z"_F,p->GetAttack()*"Witch.Ability 2.Damage Mult"_F,additionalBounceCount,p->OnUpperLevel(),false,INFINITE,true,WHITE,vf2d{1.f,1.f},util::random(2*PI))EndBullet;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
@ -438,6 +438,7 @@ Item Enchants
|
|||||||
|
|
||||||
BOUNCE COUNT = 2
|
BOUNCE COUNT = 2
|
||||||
BOUNCE DAMAGE = 100%
|
BOUNCE DAMAGE = 100%
|
||||||
|
BOUNCE EXPLODE RADIUS = 175
|
||||||
|
|
||||||
# Stat, Lowest, Highest Value
|
# Stat, Lowest, Highest Value
|
||||||
# Stat Modifier[0] = ..., 0, 0
|
# Stat Modifier[0] = ..., 0, 0
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user