From 60175a20d2983b303ce833139dcf29c95730f1ea Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Mon, 26 Aug 2024 12:04:38 -0500 Subject: [PATCH] Implemented Concussive Trap enchant. --- Adventures in Lestoria Tests/EnchantTests.cpp | 37 +++++++ Adventures in Lestoria Tests/ItemTests.cpp | 1 + Adventures in Lestoria Tests/MonsterTests.cpp | 1 + Adventures in Lestoria Tests/PlayerTests.cpp | 1 + .../AdventuresInLestoria.cpp | 104 +++++++++--------- Adventures in Lestoria/AdventuresInLestoria.h | 2 + Adventures in Lestoria/Buff.h | 1 + Adventures in Lestoria/BulletTypes.h | 2 + Adventures in Lestoria/ExplosiveTrap.cpp | 18 ++- Adventures in Lestoria/Player.cpp | 1 + Adventures in Lestoria/Trapper.cpp | 4 +- Adventures in Lestoria/Version.h | 2 +- Adventures in Lestoria/Warrior.cpp | 1 + 13 files changed, 118 insertions(+), 57 deletions(-) diff --git a/Adventures in Lestoria Tests/EnchantTests.cpp b/Adventures in Lestoria Tests/EnchantTests.cpp index c4b46d73..70cce9ca 100644 --- a/Adventures in Lestoria Tests/EnchantTests.cpp +++ b/Adventures in Lestoria Tests/EnchantTests.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."); } + 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_ptrnullRing{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."); + } }; } diff --git a/Adventures in Lestoria Tests/ItemTests.cpp b/Adventures in Lestoria Tests/ItemTests.cpp index 7885422f..165f87ef 100644 --- a/Adventures in Lestoria Tests/ItemTests.cpp +++ b/Adventures in Lestoria Tests/ItemTests.cpp @@ -79,6 +79,7 @@ namespace ItemTests GameState::Initialize(); GameState::STATE=GameState::states.at(States::State::GAME_RUN); + testGame->ResetLevelStates(); #pragma region Setup a fake test map and test monster game->MAP_DATA["CAMPAIGN_1_1"]; ItemDrop::ClearDrops(); diff --git a/Adventures in Lestoria Tests/MonsterTests.cpp b/Adventures in Lestoria Tests/MonsterTests.cpp index 1fccf69a..bfd7b533 100644 --- a/Adventures in Lestoria Tests/MonsterTests.cpp +++ b/Adventures in Lestoria Tests/MonsterTests.cpp @@ -82,6 +82,7 @@ namespace MonsterTests GameState::Initialize(); GameState::STATE=GameState::states.at(States::State::GAME_RUN); + testGame->ResetLevelStates(); #pragma region Setup a fake test map game->MAP_DATA["CAMPAIGN_1_1"]; diff --git a/Adventures in Lestoria Tests/PlayerTests.cpp b/Adventures in Lestoria Tests/PlayerTests.cpp index 190d1689..09bbc23d 100644 --- a/Adventures in Lestoria Tests/PlayerTests.cpp +++ b/Adventures in Lestoria Tests/PlayerTests.cpp @@ -88,6 +88,7 @@ namespace PlayerTests MonsterData testMonsterData{"TestName","Test Monster",1000,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f}; MONSTER_DATA["TestName"]=testMonsterData; #pragma endregion + testGame->ResetLevelStates(); player=testGame->GetPlayer(); //Setup key "0" as a test input diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index 98886ce4..c3baac9f 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -188,7 +188,7 @@ AiL::AiL(bool testingMode){ void InitializeGameConfigurations(){ DATA.Reset(); - + utils::datafile::Read(DATA,"assets/config/configuration.txt"); utils::datafile::DEBUG_ACCESS_OPTIONS="debug_access_options"_I; @@ -2387,55 +2387,7 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){ } #pragma endregion - 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(); + ResetLevelStates(); 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(); @@ -4618,4 +4570,56 @@ void AiL::InitializeCamera(){ camera.SetMode(olc::utils::Camera2D::Mode::LazyFollow); camera.SetWorldBoundary({0,0},GetCurrentMap().MapData.MapSize*GetCurrentMap().MapData.TileSize); 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(); } \ No newline at end of file diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h index 615793c0..16a7d53c 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.h +++ b/Adventures in Lestoria/AdventuresInLestoria.h @@ -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 InitializeCamera(); + void ResetLevelStates(); + std::vectorGetForegroundEffects()const; std::vectorGetBackgroundEffects()const; std::vectorGetAllEffects()const; //Foreground and background effects in one vector. diff --git a/Adventures in Lestoria/Buff.h b/Adventures in Lestoria/Buff.h index 2083ba5b..c596ed8e 100644 --- a/Adventures in Lestoria/Buff.h +++ b/Adventures in Lestoria/Buff.h @@ -61,6 +61,7 @@ enum BuffType{ DAMAGE_AMPLIFICATION, //Multiplies all incoming damage by this amount. LETHAL_TEMPO, BURNING_ARROW_BURN, + SWORD_ENCHANTMENT, }; 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. diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h index 3ad8a3da..3fd3b5c1 100644 --- a/Adventures in Lestoria/BulletTypes.h +++ b/Adventures in Lestoria/BulletTypes.h @@ -318,6 +318,8 @@ private: float automaticDetonationTime{}; float activationWaitTime{}; float lastBeepTime{}; + int explosionCount{1}; + float rearmTime{}; uint8_t beepCount{1U}; }; diff --git a/Adventures in Lestoria/ExplosiveTrap.cpp b/Adventures in Lestoria/ExplosiveTrap.cpp index acfbddb9..9d939d31 100644 --- a/Adventures in Lestoria/ExplosiveTrap.cpp +++ b/Adventures in Lestoria/ExplosiveTrap.cpp @@ -47,7 +47,7 @@ INCLUDE_ANIMATION_DATA 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) - :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; 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!"); @@ -58,7 +58,10 @@ void ExplosiveTrap::Update(float fElapsedTime){ if(IsDeactivated())return; - if(!trapActivated){ + if(rearmTime>0.f){ + rearmTime-=fElapsedTime; + if(rearmTime<=0.f)Detonate(); + }else if(!trapActivated){ activationWaitTime-=fElapsedTime; if(activationWaitTime<=0.f){ radius=activationRadius; @@ -89,8 +92,7 @@ BulletDestroyState ExplosiveTrap::PlayerHit(Player*player){ } void ExplosiveTrap::Detonate(){ - fadeOutTime=0.5f; - const HurtList list{game->HurtNotHit(pos,"Trapper.Ability 3.Explosion Radius"_F/100.f*24,damage,hitList,OnUpperLevel(),GetZ(),HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)}; + const HurtList list{game->Hurt(pos,"Trapper.Ability 3.Explosion Radius"_F/100.f*24,damage,OnUpperLevel(),GetZ(),HurtType::MONSTER,HurtFlag::PLAYER_ABILITY)}; for(const auto&[targetPtr,wasHit]:list){ if(wasHit){ std::get(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}; game->AddEffect(std::move(explodeEffect)); 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){ diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index 4321aaa0..07883859 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -335,6 +335,7 @@ float Player::GetSizeMult()const{ float Player::GetAttackRange(){ 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(GetBuffs(BuffType::SWORD_ENCHANTMENT).size()>0)finalAttackRange+=base_attack_range*"Sword Enchantment"_ENC["AUTO RANGE INCREASE"]/100.f; finalAttackRange*=GetSizeMult(); return finalAttackRange; } diff --git a/Adventures in Lestoria/Trapper.cpp b/Adventures in Lestoria/Trapper.cpp index 1bf8b251..11bd4424 100644 --- a/Adventures in Lestoria/Trapper.cpp +++ b/Adventures in Lestoria/Trapper.cpp @@ -126,7 +126,9 @@ void Trapper::InitializeClassAbilities(){ #pragma region Trapper Ability 3 (Explosive Trap) Trapper::ability3.action= [](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()); p->SetAnimationBasedOnTargetingDirection("SETTRAP",p->GetFacingDirection()); return true; diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 4df1f5ab..1fbf020d 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_PATCH 3 -#define VERSION_BUILD 11039 +#define VERSION_BUILD 11048 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Warrior.cpp b/Adventures in Lestoria/Warrior.cpp index c6a4d19c..8ae2bc1e 100644 --- a/Adventures in Lestoria/Warrior.cpp +++ b/Adventures in Lestoria/Warrior.cpp @@ -168,6 +168,7 @@ void Warrior::InitializeClassAbilities(){ } BULLET_LIST.push_back(std::make_unique(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); + if(p->HasEnchant("Sword Enchantment"))p->AddBuff(BuffType::SWORD_ENCHANTMENT,"Sword Enchantment"_ENC["INCREASE DURATION"],1); SoundEffect::PlaySFX("Warrior Sonic Slash",SoundEffect::CENTERED); return true; };