Fix bug with multi-hit bullets not adding hit targets to the hit list before monster hit / player hit bullet callbacks. Implemented Piercing Bolt enchant. 199/199 unit tests passing. Release Build 11200.
This commit is contained in:
parent
6d4de7940b
commit
0288ccbd0c
@ -97,7 +97,7 @@ namespace EnchantTests
|
||||
|
||||
#pragma region Setup a fake test map and test monster
|
||||
game->MAP_DATA["CAMPAIGN_1_1"];
|
||||
game->MAP_DATA["CAMPAIGN_1_1"]._SetMapData(MapTag{50,50,24,24});
|
||||
game->MAP_DATA["CAMPAIGN_1_1"]._SetMapData(MapTag{24*24,24*24,24,24});
|
||||
ItemDrop::ClearDrops();
|
||||
MonsterData testMonsterData{"TestName","Test Monster",1000,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
|
||||
MONSTER_DATA["TestName"]=testMonsterData;
|
||||
@ -577,6 +577,7 @@ namespace EnchantTests
|
||||
}
|
||||
TEST_METHOD(TripleTossCheck){
|
||||
Game::ChangeClass(player,THIEF);
|
||||
player->SetTestScreenAimingLocation(player->GetPos()+vf2d{30.f,0.f});
|
||||
player->CheckAndPerformAbility(player->GetAbility1(),testKeyboardInput);
|
||||
Game::Update(0.5f);
|
||||
Assert::AreEqual(size_t(1),BULLET_LIST.size(),L"Only 1 dagger has spawned without the Triple Toss enchant.");
|
||||
@ -839,6 +840,7 @@ namespace EnchantTests
|
||||
Assert::AreEqual(size_t(1),BULLET_LIST.size(),L"An Explosive Trap still exists (in the process of detonating a few times)");
|
||||
Assert::AreEqual(721,newMonster.GetHealth(),L"Monster takes 104 + 104 damage from Concussive Trap bonus (Collision+Collateral Explosion).");
|
||||
Game::Update(5.5f);
|
||||
Game::Update(5.5f);
|
||||
Assert::AreEqual(size_t(0),BULLET_LIST.size(),L"Explosive Trap detonates later.");
|
||||
}
|
||||
TEST_METHOD(SwordEnchantmentNoEnchantCheck){
|
||||
@ -966,12 +968,13 @@ namespace EnchantTests
|
||||
}
|
||||
TEST_METHOD(BouncingOrbEnchantCheck){
|
||||
Game::ChangeClass(player,WITCH);
|
||||
player->ForceSetPos({50.f,0.f});
|
||||
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster2{game->SpawnMonster({50.f,0.f},MONSTER_DATA["TestName"])};
|
||||
player->ForceSetPos({20.f,50.f});
|
||||
Monster&newMonster{game->SpawnMonster({30.f,50.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster2{game->SpawnMonster({50.f,50.f},MONSTER_DATA["TestName"])};
|
||||
Game::GiveAndEquipEnchantedRing("Bouncing Orb");
|
||||
Assert::AreEqual(1000,newMonster.GetHealth(),L"Monster 1 is at 1000 HP.");
|
||||
Assert::AreEqual(1000,newMonster2.GetHealth(),L"Monster 2 is at 1000 HP.");
|
||||
player->SetTestScreenAimingLocation(player->GetPos()+vf2d{30.f,0.f});
|
||||
player->AutoAttack();
|
||||
for(int i:std::ranges::iota_view(0,50)){
|
||||
game->SetElapsedTime(0.1f);
|
||||
@ -1150,5 +1153,36 @@ namespace EnchantTests
|
||||
Assert::AreEqual(newMonster3.GetMaxHealth()-500,newMonster3.GetHealth(),L"Monster 3 takes collateral damage from Curse of Doom enchant based on the amount of damage dealt during Curse of Death debuff.");
|
||||
Assert::AreEqual(newMonster4.GetMaxHealth()-500,newMonster4.GetHealth(),L"Monster 4 takes collateral damage from Curse of Doom enchant based on the amount of damage dealt during Curse of Death debuff.");
|
||||
}
|
||||
TEST_METHOD(PiercingBoltNoEnchantCheck){
|
||||
Game::ChangeClass(player,WIZARD);
|
||||
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster2{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster3{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster4{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
player->SetTestScreenAimingLocation(player->GetPos()+vf2d{30.f,0.f});
|
||||
Game::Update(0.f);
|
||||
player->AutoAttack();
|
||||
Game::Update(0.5f);
|
||||
Assert::AreEqual(985,newMonster.GetHealth(),L"Monster 1 takes normal damage from Wizard auto attack.");
|
||||
Assert::AreEqual(1000,newMonster2.GetHealth(),L"Monster 2 should still be full health.");
|
||||
Assert::AreEqual(1000,newMonster3.GetHealth(),L"Monster 3 should still be full health.");
|
||||
Assert::AreEqual(1000,newMonster4.GetHealth(),L"Monster 4 should still be full health.");
|
||||
}
|
||||
TEST_METHOD(PiercingBoltEnchantCheck){
|
||||
Game::ChangeClass(player,WIZARD);
|
||||
Game::GiveAndEquipEnchantedRing("Piercing Bolt");
|
||||
Monster&newMonster{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster2{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster3{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
Monster&newMonster4{game->SpawnMonster({30.f,0.f},MONSTER_DATA["TestName"])};
|
||||
player->SetTestScreenAimingLocation(player->GetPos()+vf2d{30.f,0.f});
|
||||
Game::Update(0.f);
|
||||
player->AutoAttack();
|
||||
Game::Update(0.5f);
|
||||
Assert::AreEqual(985,newMonster.GetHealth(),L"Monster 1 takes normal damage from Wizard auto attack.");
|
||||
Assert::AreEqual(992,newMonster2.GetHealth(),L"Monster 2 should take half the damage the first target does with the Percing Bolt Enchant.");
|
||||
Assert::AreEqual(992,newMonster3.GetHealth(),L"Monster 3 should take half the damage the first target does with the Percing Bolt Enchant");
|
||||
Assert::AreEqual(992,newMonster4.GetHealth(),L"Monster 4 should take half the damage the first target does with the Percing Bolt Enchant");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -50,8 +50,8 @@ namespace Game{
|
||||
game->SetElapsedTime(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);
|
||||
inline void CastAbilityAtLocation(Ability&ability,const vf2d&worldLoc,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(worldLoc);
|
||||
game->GetPlayer()->PrepareCast(ability);
|
||||
game->GetPlayer()->CastSpell(ability);
|
||||
Game::Update(ability.precastInfo.castTime);
|
||||
|
||||
@ -45,7 +45,7 @@ INCLUDE_game
|
||||
|
||||
EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
|
||||
:Bullet(pos,vel,radius,damage,
|
||||
"energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){}
|
||||
"energy_bolt.png",upperLevel,game->GetPlayer()->HasEnchant("Piercing Bolt")?true:false,INFINITE,true,friendly,col){}
|
||||
|
||||
void EnergyBolt::Update(float fElapsedTime){
|
||||
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
|
||||
@ -67,8 +67,9 @@ BulletDestroyState EnergyBolt::PlayerHit(Player*player)
|
||||
|
||||
BulletDestroyState EnergyBolt::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)
|
||||
{
|
||||
fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
|
||||
if(!game->GetPlayer()->HasEnchant("Piercing Bolt"))fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
|
||||
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F));
|
||||
if(hitList.size()==1)damage=ceil(float(damage)/2);
|
||||
return BulletDestroyState::KEEP_ALIVE;
|
||||
}
|
||||
|
||||
|
||||
@ -96,8 +96,10 @@ void ExplosiveTrap::Detonate(){
|
||||
for(const auto&[targetPtr,wasHit]:list){
|
||||
if(wasHit){
|
||||
std::get<Monster*>(targetPtr)->ApplyMark("Trapper.Ability 3.Explosion Mark Stack Time"_F,"Trapper.Ability 3.Explosion Mark Stack Increase"_I);
|
||||
std::get<Monster*>(targetPtr)->ProximityKnockback(pos,"Trapper.Ability 3.Explosion Knockback Amount"_F);
|
||||
std::get<Monster*>(targetPtr)->Knockup("Trapper.Ability 3.Explosion Knockup Amount"_F);
|
||||
if(explosionCount==1)std::get<Monster*>(targetPtr)->ProximityKnockback(pos,"Trapper.Ability 3.Explosion Knockback Amount"_F);
|
||||
else std::get<Monster*>(targetPtr)->ProximityKnockback(pos,20.f);
|
||||
if(explosionCount==1)std::get<Monster*>(targetPtr)->Knockup("Trapper.Ability 3.Explosion Knockup Amount"_F);
|
||||
else std::get<Monster*>(targetPtr)->Knockup(0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,9 +121,6 @@ BulletDestroyState ExplosiveTrap::MonsterHit(Monster&monster,const uint8_t markS
|
||||
monster.Hurt(0,monster.OnUpperLevel(),monster.GetZ(),HurtFlag::PLAYER_ABILITY);//Triggers mark multiple times after the first mark.
|
||||
}
|
||||
|
||||
monster.ProximityKnockback(pos,"Trapper.Ability 3.Explosion Knockback Amount"_F);
|
||||
monster.Knockup("Trapper.Ability 3.Explosion Knockup Amount"_F);
|
||||
|
||||
Detonate();
|
||||
|
||||
return BulletDestroyState::KEEP_ALIVE;
|
||||
|
||||
@ -106,13 +106,13 @@ void IBullet::_Update(const float fElapsedTime){
|
||||
ModifyOutgoingDamageData(damageData);
|
||||
uint8_t markStacksBeforeHit{m->GetMarkStacks()};
|
||||
if(m->Hurt(damageData)){
|
||||
hitList.insert(&*m);
|
||||
if(!hitsMultiple){
|
||||
if(_MonsterHit(*m,markStacksBeforeHit)==BulletDestroyState::DESTROY){
|
||||
dead=true;
|
||||
}
|
||||
return false;
|
||||
}else _MonsterHit(*m,markStacksBeforeHit);
|
||||
hitList.insert(&*m);
|
||||
if(!CollisionCheckRequired())return false;
|
||||
}
|
||||
}
|
||||
@ -125,13 +125,13 @@ void IBullet::_Update(const float fElapsedTime){
|
||||
//NOTE: OnHurt() will potentially change the Damage Data, passing it along to bullet children that might need to modify the flags!
|
||||
ModifyOutgoingDamageData(damageData);
|
||||
if(game->GetPlayer()->Hurt(damageData)){
|
||||
hitList.insert(game->GetPlayer());
|
||||
if(!hitsMultiple){
|
||||
if(_PlayerHit(&*game->GetPlayer())==BulletDestroyState::DESTROY){
|
||||
dead=true;
|
||||
}
|
||||
return false;
|
||||
}else _PlayerHit(&*game->GetPlayer());
|
||||
hitList.insert(game->GetPlayer());
|
||||
if(!CollisionCheckRequired())return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1760,7 +1760,9 @@ void Player::Knockup(float duration){
|
||||
}
|
||||
|
||||
const vf2d Player::GetWorldAimingLocation(bool useWalkDir,bool invert){
|
||||
const vf2d screenAimingLoc{game->view.ScreenToWorld(GetAimingLocation(useWalkDir,invert))};
|
||||
vf2d screenAimingLoc{game->view.ScreenToWorld(GetAimingLocation(useWalkDir,invert))};
|
||||
|
||||
if(game->TestingModeEnabled())screenAimingLoc=testAimingLoc.value_or(GetPos()+vf2d{});
|
||||
|
||||
if(screenAimingLoc==GetPos())return GetPos()+vf2d{0,-1.f};
|
||||
else return screenAimingLoc;
|
||||
|
||||
@ -104,6 +104,7 @@ BulletDestroyState PurpleEnergyBall::MonsterHit(Monster&monster,const uint8_t ma
|
||||
bounceCount--;
|
||||
hitList.clear();
|
||||
lastHitTarget=monster.GetWeakPointer();
|
||||
hitList.emplace(&monster);
|
||||
if(bounceCount<=0)fadeOutTime="Witch.Auto Attack.BulletHitFadeoutTime"_F;
|
||||
else lastHitTimer=0.1f;
|
||||
Deactivate();
|
||||
|
||||
@ -39,7 +39,7 @@ All rights reserved.
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 2
|
||||
#define VERSION_PATCH 5
|
||||
#define VERSION_BUILD 11188
|
||||
#define VERSION_BUILD 11200
|
||||
|
||||
#define stringify(a) stringify_(a)
|
||||
#define stringify_(a) #a
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user