Implemented Concussive Trap enchant.

pull/65/head
sigonasr2 3 months ago
parent 9005771f77
commit 60175a20d2
  1. 37
      Adventures in Lestoria Tests/EnchantTests.cpp
  2. 1
      Adventures in Lestoria Tests/ItemTests.cpp
  3. 1
      Adventures in Lestoria Tests/MonsterTests.cpp
  4. 1
      Adventures in Lestoria Tests/PlayerTests.cpp
  5. 102
      Adventures in Lestoria/AdventuresInLestoria.cpp
  6. 2
      Adventures in Lestoria/AdventuresInLestoria.h
  7. 1
      Adventures in Lestoria/Buff.h
  8. 2
      Adventures in Lestoria/BulletTypes.h
  9. 18
      Adventures in Lestoria/ExplosiveTrap.cpp
  10. 1
      Adventures in Lestoria/Player.cpp
  11. 4
      Adventures in Lestoria/Trapper.cpp
  12. 2
      Adventures in Lestoria/Version.h
  13. 1
      Adventures in Lestoria/Warrior.cpp

@ -974,5 +974,42 @@ namespace EnchantTests
} }
Assert::AreEqual(size_t(1),newMonster.GetBuffs(BuffType::SPECIAL_MARK).size(),L"A special mark should spawned with the enchant."); Assert::AreEqual(size_t(1),newMonster.GetBuffs(BuffType::SPECIAL_MARK).size(),L"A special mark should spawned with the enchant.");
} }
TEST_METHOD(ConcussiveTrapEnchantCheck){
testKey->bHeld=true; //Force the key to be held down for testing purposes.
game->ChangePlayerClass(TRAPPER);
player=game->GetPlayer();
player->SetPos({120,120});
player->CheckAndPerformAbility(player->GetAbility3(),testKeyboardInput);
game->SetElapsedTime(0.5f);
game->OnUserUpdate(0.5f);
Assert::AreEqual(size_t(1),BULLET_LIST.size(),L"An Explosive Trap now exists");
Monster&newMonster{game->SpawnMonster({},MONSTER_DATA["TestName"])};
game->OnUserUpdate(0.f);
BULLET_LIST.front()->MonsterHit(newMonster,newMonster.GetMarkStacks());
Assert::AreEqual(929,newMonster.GetHealth(),L"Monster takes 71 damage from an Explosive Trap normally.");
game->SetElapsedTime(5.5f);
game->OnUserUpdate(5.5f);
game->SetElapsedTime(5.5f);
game->OnUserUpdate(5.5f);
game->SetElapsedTime(0.5f);
game->OnUserUpdate(0.5f);
Assert::AreEqual(size_t(0),BULLET_LIST.size(),L"An Explosive Trap is gone.");
std::weak_ptr<Item>nullRing{Inventory::AddItem("Null Ring"s)};
Inventory::EquipItem(nullRing,EquipSlot::RING1);
nullRing.lock()->EnchantItem("Concussive Trap");
player->GetAbility3().charges=1;
player->CheckAndPerformAbility(player->GetAbility3(),testKeyboardInput);
game->SetElapsedTime(0.5f);
game->OnUserUpdate(0.5f);
Assert::AreEqual(size_t(1),BULLET_LIST.size(),L"An Explosive Trap now exists");
game->SetElapsedTime(5.5f);
game->OnUserUpdate(5.5f);
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->SetElapsedTime(5.5f);
game->OnUserUpdate(5.5f);
Assert::AreEqual(size_t(0),BULLET_LIST.size(),L"Explosive Trap detonates later.");
}
}; };
} }

@ -79,6 +79,7 @@ namespace ItemTests
GameState::Initialize(); GameState::Initialize();
GameState::STATE=GameState::states.at(States::State::GAME_RUN); GameState::STATE=GameState::states.at(States::State::GAME_RUN);
testGame->ResetLevelStates();
#pragma region Setup a fake test map and test monster #pragma region Setup a fake test map and test monster
game->MAP_DATA["CAMPAIGN_1_1"]; game->MAP_DATA["CAMPAIGN_1_1"];
ItemDrop::ClearDrops(); ItemDrop::ClearDrops();

@ -82,6 +82,7 @@ namespace MonsterTests
GameState::Initialize(); GameState::Initialize();
GameState::STATE=GameState::states.at(States::State::GAME_RUN); GameState::STATE=GameState::states.at(States::State::GAME_RUN);
testGame->ResetLevelStates();
#pragma region Setup a fake test map #pragma region Setup a fake test map
game->MAP_DATA["CAMPAIGN_1_1"]; game->MAP_DATA["CAMPAIGN_1_1"];

@ -88,6 +88,7 @@ namespace PlayerTests
MonsterData testMonsterData{"TestName","Test Monster",1000,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f}; MonsterData testMonsterData{"TestName","Test Monster",1000,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
MONSTER_DATA["TestName"]=testMonsterData; MONSTER_DATA["TestName"]=testMonsterData;
#pragma endregion #pragma endregion
testGame->ResetLevelStates();
player=testGame->GetPlayer(); player=testGame->GetPlayer();
//Setup key "0" as a test input //Setup key "0" as a test input

@ -2387,55 +2387,7 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){
} }
#pragma endregion #pragma endregion
bossIndicatorPos.reset(); ResetLevelStates();
SPAWNER_LIST.clear();
SPAWNER_CONTROLLER={};
foregroundTileGroups.clear();
upperForegroundTileGroups.clear();
MONSTER_LIST.clear();
BULLET_LIST.clear();
DAMAGENUMBER_LIST.clear();
hudOverlay.Reset();
backgroundEffects.clear();
foregroundEffects.clear();
lockOnTargets.clear();
lockOnSpecialTargets.clear();
ItemDrop::drops.clear();
GameEvent::events.clear();
Audio::SetBGMPitch(1.f);
RepeatingSoundEffect::StopAllSounds();
#ifdef __EMSCRIPTEN__
Audio::muted=true;
Audio::UpdateBGMVolume();
#endif
zoomAdjustSpeed="Default Zoom Adjust Speed"_F;
targetZoom=1.f;
game->view.SetZoom(0.95f,game->view.WorldToScreen(game->camera.GetViewPosition()));
worldColor=WHITE;
worldColorFunc=[&](vi2d pos){return game->worldColor;};
levelTime=0;
bossName="";
bossDisplayTimer=0.f;
worldShakeTime=0.f;
encounterDuration=0;
totalDamageDealt=0;
encounterStarted=false;
totalBossEncounterMobs=0;
SetWindSpeed({});
Inventory::ResetLoadoutItemsUsed();
Input::StopVibration();
Input::SetLightbar({255,0,255});
GetPlayer()->hp=GetPlayer()->GetMaxHealth();
GetPlayer()->mana=GetPlayer()->GetMaxMana();
GetPlayer()->SetState(State::NORMAL);
GetPlayer()->GetCastInfo()={};
GetPlayer()->ResetAccumulatedXP();
GetPlayer()->_SetIframes(0.f);
GetPlayer()->SetInvisible(false);
GetPlayer()->ResetVelocity();
GetPlayer()->RemoveAllBuffs();
GetPlayer()->ResetTimers();
STEAMINPUT( //This is kind of a hack to refresh the in-game controls handle and button icons if for some reason it's not setup correctly. STEAMINPUT( //This is kind of a hack to refresh the in-game controls handle and button icons if for some reason it's not setup correctly.
Input::LoadSteamButtonIcons(); Input::LoadSteamButtonIcons();
@ -4619,3 +4571,55 @@ void AiL::InitializeCamera(){
camera.SetWorldBoundary({0,0},GetCurrentMap().MapData.MapSize*GetCurrentMap().MapData.TileSize); camera.SetWorldBoundary({0,0},GetCurrentMap().MapData.MapSize*GetCurrentMap().MapData.TileSize);
camera.EnableWorldBoundary(false); camera.EnableWorldBoundary(false);
} }
void AiL::ResetLevelStates(){
bossIndicatorPos.reset();
SPAWNER_LIST.clear();
SPAWNER_CONTROLLER={};
foregroundTileGroups.clear();
upperForegroundTileGroups.clear();
MONSTER_LIST.clear();
BULLET_LIST.clear();
DAMAGENUMBER_LIST.clear();
hudOverlay.Reset();
backgroundEffects.clear();
foregroundEffects.clear();
lockOnTargets.clear();
lockOnSpecialTargets.clear();
ItemDrop::drops.clear();
GameEvent::events.clear();
Audio::SetBGMPitch(1.f);
RepeatingSoundEffect::StopAllSounds();
#ifdef __EMSCRIPTEN__
Audio::muted=true;
Audio::UpdateBGMVolume();
#endif
zoomAdjustSpeed="Default Zoom Adjust Speed"_F;
targetZoom=1.f;
game->view.SetZoom(0.95f,game->view.WorldToScreen(game->camera.GetViewPosition()));
worldColor=WHITE;
worldColorFunc=[&](vi2d pos){return game->worldColor;};
levelTime=0;
bossName="";
bossDisplayTimer=0.f;
worldShakeTime=0.f;
encounterDuration=0;
totalDamageDealt=0;
encounterStarted=false;
totalBossEncounterMobs=0;
SetWindSpeed({});
Inventory::ResetLoadoutItemsUsed();
Input::StopVibration();
Input::SetLightbar({255,0,255});
GetPlayer()->hp=GetPlayer()->GetMaxHealth();
GetPlayer()->mana=GetPlayer()->GetMaxMana();
GetPlayer()->SetState(State::NORMAL);
GetPlayer()->GetCastInfo()={};
GetPlayer()->ResetAccumulatedXP();
GetPlayer()->_SetIframes(0.f);
GetPlayer()->SetInvisible(false);
GetPlayer()->ResetVelocity();
GetPlayer()->RemoveAllBuffs();
GetPlayer()->ResetTimers();
}

@ -394,6 +394,8 @@ public:
void _SetCurrentLevel(const MapName map); //NOTE: This will modify the currentLevel variable without triggering anything else in-game, this will normally mess up the state in the game. Ideally this is only used when initializing a test level. void _SetCurrentLevel(const MapName map); //NOTE: This will modify the currentLevel variable without triggering anything else in-game, this will normally mess up the state in the game. Ideally this is only used when initializing a test level.
void InitializeCamera(); void InitializeCamera();
void ResetLevelStates();
std::vector<Effect*>GetForegroundEffects()const; std::vector<Effect*>GetForegroundEffects()const;
std::vector<Effect*>GetBackgroundEffects()const; std::vector<Effect*>GetBackgroundEffects()const;
std::vector<Effect*>GetAllEffects()const; //Foreground and background effects in one vector. std::vector<Effect*>GetAllEffects()const; //Foreground and background effects in one vector.

@ -61,6 +61,7 @@ enum BuffType{
DAMAGE_AMPLIFICATION, //Multiplies all incoming damage by this amount. DAMAGE_AMPLIFICATION, //Multiplies all incoming damage by this amount.
LETHAL_TEMPO, LETHAL_TEMPO,
BURNING_ARROW_BURN, BURNING_ARROW_BURN,
SWORD_ENCHANTMENT,
}; };
enum class BuffRestorationType{ enum class BuffRestorationType{
ONE_OFF, //This is used as a hack fix for the RestoreDuringCast Item script since they require us to restore 1 tick immediately. Over time buffs do not apply a tick immediately. ONE_OFF, //This is used as a hack fix for the RestoreDuringCast Item script since they require us to restore 1 tick immediately. Over time buffs do not apply a tick immediately.

@ -318,6 +318,8 @@ private:
float automaticDetonationTime{}; float automaticDetonationTime{};
float activationWaitTime{}; float activationWaitTime{};
float lastBeepTime{}; float lastBeepTime{};
int explosionCount{1};
float rearmTime{};
uint8_t beepCount{1U}; uint8_t beepCount{1U};
}; };

@ -47,7 +47,7 @@ INCLUDE_ANIMATION_DATA
INCLUDE_game INCLUDE_game
ExplosiveTrap::ExplosiveTrap(vf2d pos,float radius,float explosionRadius,float automaticDetonationTime,int damage,float fadeinTime,float fadeoutTime,float activationWaitTime,bool upperLevel,bool hitsMultiple,float lifetime,bool friendly,Pixel col,vf2d scale) ExplosiveTrap::ExplosiveTrap(vf2d pos,float radius,float explosionRadius,float automaticDetonationTime,int damage,float fadeinTime,float fadeoutTime,float activationWaitTime,bool upperLevel,bool hitsMultiple,float lifetime,bool friendly,Pixel col,vf2d scale)
:activationWaitTime(activationWaitTime),automaticDetonationTime(automaticDetonationTime),activationRadius(radius),explosionRadius(explosionRadius),Bullet(pos,{},0.f,damage,"Ability Icons/explosive_trap.png",upperLevel,hitsMultiple,lifetime,false,friendly,col,scale,0.f,"Trap Hit"){ :activationWaitTime(activationWaitTime),automaticDetonationTime(automaticDetonationTime),activationRadius(radius),explosionRadius(explosionRadius),explosionCount(game->GetPlayer()->HasEnchant("Concussive Trap")?"Concussive Trap"_ENC["TRAP EXPLODE COUNT"]:1),Bullet(pos,{},0.f,damage,"Ability Icons/explosive_trap.png",upperLevel,hitsMultiple,INFINITE,false,friendly,col,scale,0.f,"Trap Hit"){
fadeInTime=fadeinTime; fadeInTime=fadeinTime;
animation.AddState("explosive_trap.png",ANIMATION_DATA["explosive_trap.png"]); animation.AddState("explosive_trap.png",ANIMATION_DATA["explosive_trap.png"]);
if(!friendly)ERR("WARNING! Trying to use unimplemented enemy version of the Explosive Trap Bullet!"); if(!friendly)ERR("WARNING! Trying to use unimplemented enemy version of the Explosive Trap Bullet!");
@ -58,7 +58,10 @@ void ExplosiveTrap::Update(float fElapsedTime){
if(IsDeactivated())return; if(IsDeactivated())return;
if(!trapActivated){ if(rearmTime>0.f){
rearmTime-=fElapsedTime;
if(rearmTime<=0.f)Detonate();
}else if(!trapActivated){
activationWaitTime-=fElapsedTime; activationWaitTime-=fElapsedTime;
if(activationWaitTime<=0.f){ if(activationWaitTime<=0.f){
radius=activationRadius; radius=activationRadius;
@ -89,8 +92,7 @@ BulletDestroyState ExplosiveTrap::PlayerHit(Player*player){
} }
void ExplosiveTrap::Detonate(){ void ExplosiveTrap::Detonate(){
fadeOutTime=0.5f; const HurtList list{game->Hurt(pos,"Trapper.Ability 3.Explosion Radius"_F/100.f*24,damage,OnUpperLevel(),GetZ(),HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)};
const HurtList list{game->HurtNotHit(pos,"Trapper.Ability 3.Explosion Radius"_F/100.f*24,damage,hitList,OnUpperLevel(),GetZ(),HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)};
for(const auto&[targetPtr,wasHit]:list){ for(const auto&[targetPtr,wasHit]:list){
if(wasHit){ 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)->ApplyMark("Trapper.Ability 3.Explosion Mark Stack Time"_F,"Trapper.Ability 3.Explosion Mark Stack Increase"_I);
@ -103,7 +105,13 @@ void ExplosiveTrap::Detonate(){
explodeEffect->scaleSpd={0.125f,0.125f}; explodeEffect->scaleSpd={0.125f,0.125f};
game->AddEffect(std::move(explodeEffect)); game->AddEffect(std::move(explodeEffect));
SoundEffect::PlaySFX("Explosion",pos); SoundEffect::PlaySFX("Explosion",pos);
Deactivate(); explosionCount--;
if(explosionCount>0)rearmTime=0.6f;
else{
fadeOutTime=0.5f;
Deactivate();
lifetime=0.f;
}
} }
BulletDestroyState ExplosiveTrap::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){ BulletDestroyState ExplosiveTrap::MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit){

@ -335,6 +335,7 @@ float Player::GetSizeMult()const{
float Player::GetAttackRange(){ float Player::GetAttackRange(){
float finalAttackRange{base_attack_range}; float finalAttackRange{base_attack_range};
if(HasEnchant("Adrenaline Stim")&&GetBuffs(BuffType::ADRENALINE_RUSH).size()>0)finalAttackRange+=base_attack_range*"Adrenaline Stim"_ENC["ATTACK RANGE INCREASE PCT"]/100.f; if(HasEnchant("Adrenaline Stim")&&GetBuffs(BuffType::ADRENALINE_RUSH).size()>0)finalAttackRange+=base_attack_range*"Adrenaline Stim"_ENC["ATTACK RANGE INCREASE PCT"]/100.f;
if(GetBuffs(BuffType::SWORD_ENCHANTMENT).size()>0)finalAttackRange+=base_attack_range*"Sword Enchantment"_ENC["AUTO RANGE INCREASE"]/100.f;
finalAttackRange*=GetSizeMult(); finalAttackRange*=GetSizeMult();
return finalAttackRange; return finalAttackRange;
} }

@ -126,7 +126,9 @@ void Trapper::InitializeClassAbilities(){
#pragma region Trapper Ability 3 (Explosive Trap) #pragma region Trapper Ability 3 (Explosive Trap)
Trapper::ability3.action= Trapper::ability3.action=
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
CreateBullet(ExplosiveTrap)(p->GetPos(),"Trapper.Ability 3.Trap Radius"_I,"Trapper.Ability 3.Explosion Radius"_F/100.f*24,"Trapper.Ability 3.Trap Auto Detonate Time"_F,"Trapper.Ability 3.DamageMult"_F*p->GetAttack(),0.2f,0.5f,"Trapper.Ability 3.Trap Activation Time"_F,p->OnUpperLevel(),false,INFINITE,true,WHITE,{1.f,1.f})EndBullet; float trapDamage{"Trapper.Ability 3.DamageMult"_F*p->GetAttack()};
if(p->HasEnchant("Concussive Trap"))trapDamage+=p->GetAttack()*"Concussive Trap"_ENC["ADDITIONAL EXPLOSION DAMAGE"]/100.f;
CreateBullet(ExplosiveTrap)(p->GetPos(),"Trapper.Ability 3.Trap Radius"_I,"Trapper.Ability 3.Explosion Radius"_F/100.f*24,"Trapper.Ability 3.Trap Auto Detonate Time"_F,trapDamage,0.2f,0.5f,"Trapper.Ability 3.Trap Activation Time"_F,p->OnUpperLevel(),false,INFINITE,true,WHITE,{1.f,1.f})EndBullet;
SoundEffect::PlaySFX("Place Down Trap",p->GetPos()); SoundEffect::PlaySFX("Place Down Trap",p->GetPos());
p->SetAnimationBasedOnTargetingDirection("SETTRAP",p->GetFacingDirection()); p->SetAnimationBasedOnTargetingDirection("SETTRAP",p->GetFacingDirection());
return true; return true;

@ -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 3 #define VERSION_PATCH 3
#define VERSION_BUILD 11039 #define VERSION_BUILD 11048
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -168,6 +168,7 @@ void Warrior::InitializeClassAbilities(){
} }
BULLET_LIST.push_back(std::make_unique<Bullet>(p->GetPos(),bulletVel,"Warrior.Ability 3.Radius"_F,p->GetAttack()*"Warrior.Ability 3.DamageMult"_F,"sonicslash.png",p->upperLevel,true,"Warrior.Ability 3.Lifetime"_F,true,true,WHITE,vf2d{"Warrior.Ability 3.Radius"_F/30,"Warrior.Ability 3.Radius"_F/30})); BULLET_LIST.push_back(std::make_unique<Bullet>(p->GetPos(),bulletVel,"Warrior.Ability 3.Radius"_F,p->GetAttack()*"Warrior.Ability 3.DamageMult"_F,"sonicslash.png",p->upperLevel,true,"Warrior.Ability 3.Lifetime"_F,true,true,WHITE,vf2d{"Warrior.Ability 3.Radius"_F/30,"Warrior.Ability 3.Radius"_F/30}));
game->SetupWorldShake("Warrior.Ability 3.ShakeTime"_F); game->SetupWorldShake("Warrior.Ability 3.ShakeTime"_F);
if(p->HasEnchant("Sword Enchantment"))p->AddBuff(BuffType::SWORD_ENCHANTMENT,"Sword Enchantment"_ENC["INCREASE DURATION"],1);
SoundEffect::PlaySFX("Warrior Sonic Slash",SoundEffect::CENTERED); SoundEffect::PlaySFX("Warrior Sonic Slash",SoundEffect::CENTERED);
return true; return true;
}; };

Loading…
Cancel
Save