Fix Health and Mana display meters. Add shield damage number type. Fix shield display timer expiring the shield value. Fix unit tests relying on bad static ability state. Fix default attack range from being divided by 100. Force ChangePlayerClass to be called even if class is already set to same class due to additional side effects. Release Build 11074.

pull/65/head
sigonasr2 3 months ago
parent d224740fd4
commit ad02c7b59f
  1. 16
      Adventures in Lestoria Tests/EnchantTests.cpp
  2. 8
      Adventures in Lestoria Tests/PlayerTests.cpp
  3. 17
      Adventures in Lestoria/AdventuresInLestoria.cpp
  4. 4
      Adventures in Lestoria/DamageNumber.cpp
  5. 1
      Adventures in Lestoria/DamageNumber.h
  6. 9
      Adventures in Lestoria/Player.cpp
  7. 2
      Adventures in Lestoria/Player.h
  8. 2
      Adventures in Lestoria/PlayerTimerType.h
  9. 2
      Adventures in Lestoria/Version.h
  10. 9
      Adventures in Lestoria/Warrior.cpp
  11. BIN
      x64/Release/Adventures in Lestoria.exe

@ -1073,5 +1073,21 @@ namespace EnchantTests
player->Hurt(5,player->OnUpperLevel(),player->GetZ()); player->Hurt(5,player->OnUpperLevel(),player->GetZ());
Assert::AreEqual(100,player->GetHealth(),L"Player should still be blocking at this time with Heavy Guard."); Assert::AreEqual(100,player->GetHealth(),L"Player should still be blocking at this time with Heavy Guard.");
} }
TEST_METHOD(AdvanceShieldNoEnchantCheck){
testKey->bHeld=true; //Force the key to be held down for testing purposes.
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Assert::AreEqual(0U,player->GetShield(),L"Without the Advance Shield enchant, shield amount remains at 0.");
}
TEST_METHOD(AdvanceShieldEnchantCheck){
testKey->bHeld=true; //Force the key to be held down for testing purposes.
std::weak_ptr<Item>nullRing{Inventory::AddItem("Null Ring"s)};
Inventory::EquipItem(nullRing,EquipSlot::RING1);
nullRing.lock()->EnchantItem("Advance Shield");
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Assert::AreEqual(int(player->GetMaxHealth()*0.2f),int(player->GetShield()),L"The Advance Shield enchant provides a 20% health player shield.");
game->SetElapsedTime(9.f);
game->OnUserUpdate(9.f);
Assert::AreEqual(0U,player->GetShield(),L"The Advance Shield enchant shield lasts 9 seconds. It should have worn off after that time.");
}
}; };
} }

@ -756,7 +756,7 @@ namespace PlayerTests
} }
TEST_METHOD(PlayerAddShieldCheck){ TEST_METHOD(PlayerAddShieldCheck){
player=testGame->GetPlayer(); player=testGame->GetPlayer();
player->AddShield(60U,5.f,PlayerTimerType::ADVANCED_SHIELD_TIMER); player->AddShield(60U,5.f,PlayerTimerType::ADVANCE_SHIELD_TIMER);
Assert::AreEqual(60U,player->GetShield(),L"Player has 60 shield points."); Assert::AreEqual(60U,player->GetShield(),L"Player has 60 shield points.");
testGame->SetElapsedTime(5.f); testGame->SetElapsedTime(5.f);
testGame->OnUserUpdate(5.f); testGame->OnUserUpdate(5.f);
@ -764,7 +764,7 @@ namespace PlayerTests
} }
TEST_METHOD(PlayerMultiShieldCheck){ TEST_METHOD(PlayerMultiShieldCheck){
player=testGame->GetPlayer(); player=testGame->GetPlayer();
player->AddShield(60U,5.f,PlayerTimerType::ADVANCED_SHIELD_TIMER); player->AddShield(60U,5.f,PlayerTimerType::ADVANCE_SHIELD_TIMER);
player->AddShield(100U,2.f,PlayerTimerType::PLAYER_OUTLINE_TIMER); player->AddShield(100U,2.f,PlayerTimerType::PLAYER_OUTLINE_TIMER);
Assert::AreEqual(160U,player->GetShield(),L"Player has 160 shield points."); Assert::AreEqual(160U,player->GetShield(),L"Player has 160 shield points.");
testGame->SetElapsedTime(2.f); testGame->SetElapsedTime(2.f);
@ -776,7 +776,7 @@ namespace PlayerTests
} }
TEST_METHOD(PlayerSubtractShieldCheck){ TEST_METHOD(PlayerSubtractShieldCheck){
player=testGame->GetPlayer(); player=testGame->GetPlayer();
player->AddShield(60U,5.f,PlayerTimerType::ADVANCED_SHIELD_TIMER); player->AddShield(60U,5.f,PlayerTimerType::ADVANCE_SHIELD_TIMER);
Assert::AreEqual(60U,player->GetShield(),L"Player has 60 shield points."); Assert::AreEqual(60U,player->GetShield(),L"Player has 60 shield points.");
player->SubtractShield(40U); player->SubtractShield(40U);
Assert::AreEqual(20U,player->GetShield(),L"Player has 20 shield points."); Assert::AreEqual(20U,player->GetShield(),L"Player has 20 shield points.");
@ -785,7 +785,7 @@ namespace PlayerTests
} }
TEST_METHOD(PlayerDamageShieldCheck){ TEST_METHOD(PlayerDamageShieldCheck){
player=testGame->GetPlayer(); player=testGame->GetPlayer();
player->AddShield(60U,5.f,PlayerTimerType::ADVANCED_SHIELD_TIMER); player->AddShield(60U,5.f,PlayerTimerType::ADVANCE_SHIELD_TIMER);
Assert::AreEqual(60U,player->GetShield(),L"Player has 60 shield points."); Assert::AreEqual(60U,player->GetShield(),L"Player has 60 shield points.");
player->Hurt(20U,player->OnUpperLevel(),player->GetZ()); player->Hurt(20U,player->OnUpperLevel(),player->GetZ());
Assert::AreEqual(40U,player->GetShield(),L"Player has 40 shield points."); Assert::AreEqual(40U,player->GetShield(),L"Player has 40 shield points.");

@ -181,6 +181,8 @@ AiL::AiL(bool testingMode){
DEBUG_PATHFINDING="debug_pathfinding"_I; DEBUG_PATHFINDING="debug_pathfinding"_I;
#pragma endregion #pragma endregion
Warrior::ResetToOriginalAbilities();
sAppName="GAME_NAME"_S; sAppName="GAME_NAME"_S;
game=this; game=this;
gameStarted=time(NULL); gameStarted=time(NULL);
@ -1126,7 +1128,7 @@ void AiL::RenderWorld(float fElapsedTime){
view.DrawPartialSquishedRotatedDecal(pos+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)},player->GetFrame().GetSourceImage()->Decal(),player->GetSpinAngle(),{12,12},player->GetFrame().GetSourceRect().pos,player->GetFrame().GetSourceRect().size,playerScale*scale,{1.f,player->ySquishFactor},playerCol); view.DrawPartialSquishedRotatedDecal(pos+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)},player->GetFrame().GetSourceImage()->Decal(),player->GetSpinAngle(),{12,12},player->GetFrame().GetSourceRect().pos,player->GetFrame().GetSourceRect().size,playerScale*scale,{1.f,player->ySquishFactor},playerCol);
DrawAfterImage:view.DrawRotatedDecal(player->afterImagePos,player->afterImage.Decal(),0.f,player->afterImage.Sprite()->Size()/2,{player->GetSizeMult(),player->GetSizeMult()},{0xFFDCDA}); DrawAfterImage:view.DrawRotatedDecal(player->afterImagePos,player->afterImage.Decal(),0.f,player->afterImage.Sprite()->Size()/2,{player->GetSizeMult(),player->GetSizeMult()},{0xFFDCDA});
SetDecalMode(DecalMode::NORMAL); SetDecalMode(DecalMode::NORMAL);
if(player->GetState()==State::BLOCK){ if(player->GetState()==State::BLOCK||player->GetShield()>0){
view.DrawDecal(player->GetPos()+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)}-vf2d{12,12},GFX["block.png"].Decal()); view.DrawDecal(player->GetPos()+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)}-vf2d{12,12},GFX["block.png"].Decal());
} }
@ -2027,9 +2029,11 @@ void AiL::RenderHud(){
DrawDecal({2,2},GFX["heart_outline.png"].Decal(),{1.f,1.f},healthOutlineCol); DrawDecal({2,2},GFX["heart_outline.png"].Decal(),{1.f,1.f},healthOutlineCol);
const Decal*heartImg{GFX["heart.png"].Decal()}; const Decal*heartImg{GFX["heart.png"].Decal()};
if(player->GetShield()>0)heartImg=GFX["shield_heart.png"].Decal(); if(player->GetShield()>0)heartImg=GFX["shield_heart.png"].Decal();
DrawPartialDecal({2,2+(15-15*player->GetHealthRatio())},const_cast<Decal*>(heartImg),{},{17,15*player->GetHealthRatio()}); float healthRatio{float(healthCounter.GetDisplayValue())/player->GetMaxHealth()};
float manaRatio{float(manaCounter.GetDisplayValue())/player->GetMaxMana()};
DrawPartialDecal({2,2+(15*(1-healthRatio))},const_cast<Decal*>(heartImg),{0.f,15*(1-healthRatio)},{17,15*healthRatio});
DrawDecal({2,20},GFX["mana_outline.png"].Decal()); DrawDecal({2,20},GFX["mana_outline.png"].Decal());
DrawPartialDecal({2,20+(15-15*player->GetManaRatio())},GFX["mana.png"].Decal(),{},{17,15*player->GetManaRatio()}); DrawPartialDecal({2,20+(15*(1-manaRatio))},GFX["mana.png"].Decal(),{0.f,15*(1-manaRatio)},{17,15*manaRatio});
std::string text=player->GetHealth()>0?std::to_string(healthCounter.GetDisplayValue()+shieldCounter.GetDisplayValue()):"X"; std::string text=player->GetHealth()>0?std::to_string(healthCounter.GetDisplayValue()+shieldCounter.GetDisplayValue()):"X";
std::string text_mana=std::to_string(manaCounter.GetDisplayValue()); std::string text_mana=std::to_string(manaCounter.GetDisplayValue());
@ -2911,7 +2915,6 @@ const MapName&AiL::GetCurrentLevel()const{
} }
void AiL::ChangePlayerClass(Class cl){ void AiL::ChangePlayerClass(Class cl){
if(game->GetPlayer()->GetClass()==cl)return;
Ability itemAbility1=player->useItem1; Ability itemAbility1=player->useItem1;
Ability itemAbility2=player->useItem2; Ability itemAbility2=player->useItem2;
Ability itemAbility3=player->useItem3; Ability itemAbility3=player->useItem3;
@ -4515,6 +4518,12 @@ void AiL::UsingSteamAPI(const bool usingSteam){
void AiL::InitializePlayer(){ void AiL::InitializePlayer(){
player=std::make_unique<Warrior>(); player=std::make_unique<Warrior>();
Player::moneyListeners.clear(); Player::moneyListeners.clear();
Warrior::ability4=Ability{};
Ranger::ability4=Ability{};
Wizard::ability4=Ability{};
Thief::ability4=Ability{};
Trapper::ability4=Ability{};
Witch::ability4=Ability{};
} }
void AiL::SetWorldZoom(float newZoomScale){ void AiL::SetWorldZoom(float newZoomScale){

@ -133,6 +133,10 @@ void DamageNumber::Draw(){
std::string text=std::to_string(damage); std::string text=std::to_string(damage);
DrawDamageNumber(NumberScalesWithDamage,text,{0x888093,0x150035},{BLACK,{0,0,0,0}}); DrawDamageNumber(NumberScalesWithDamage,text,{0x888093,0x150035},{BLACK,{0,0,0,0}});
}break; }break;
case SHIELD_LOSS:{
std::string text=std::to_string(damage);
DrawDamageNumber(NumberScalesWithDamage,text,{DARK_BLUE,0x68d7ef},{BLUE,0x4141be});
}break;
default:ERR(std::format("Damage Number Type {} is not implemented! THIS SHOULD NOT BE HAPPENING!",int(type))); default:ERR(std::format("Damage Number Type {} is not implemented! THIS SHOULD NOT BE HAPPENING!",int(type)));
} }
} }

@ -47,6 +47,7 @@ namespace DamageNumberType{
CRIT, CRIT,
DOT, DOT,
BACKSTAB, BACKSTAB,
SHIELD_LOSS,
}; };
} }

@ -942,9 +942,12 @@ bool Player::Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag dama
game->ShowDamageVignetteOverlay(vignetteOverlayCol); game->ShowDamageVignetteOverlay(vignetteOverlayCol);
} }
bool tookShieldDamage{false};
if(tookLethalDamage&&survivedHitDueToDefiance)ApplyIframes("Death Defiance"_ENC["LETHAL DAMAGE SURVIVE IFRAME TIME"]); if(tookLethalDamage&&survivedHitDueToDefiance)ApplyIframes("Death Defiance"_ENC["LETHAL DAMAGE SURVIVE IFRAME TIME"]);
else{ else{
if(GetShield()>0){ if(GetShield()>0){
tookShieldDamage=true;
if(PlayHitSoundEffect)SoundEffect::PlaySFX("Warrior Block Hit",SoundEffect::CENTERED); if(PlayHitSoundEffect)SoundEffect::PlaySFX("Warrior Block Hit",SoundEffect::CENTERED);
SubtractShield(mod_dmg); SubtractShield(mod_dmg);
} }
@ -971,9 +974,11 @@ bool Player::Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag dama
}else{ }else{
if(lastHitTimer>0){ if(lastHitTimer>0){
damageNumberPtr.get()->AddDamage(int(mod_dmg)); damageNumberPtr.get()->AddDamage(int(mod_dmg));
if(tookShieldDamage)damageNumberPtr->SetType(DamageNumberType::SHIELD_LOSS);
damageNumberPtr.get()->SetPauseTimer(0.4f); damageNumberPtr.get()->SetPauseTimer(0.4f);
}else{ }else{
damageNumberPtr=std::make_shared<DamageNumber>(pos,int(mod_dmg),true); damageNumberPtr=std::make_shared<DamageNumber>(pos,int(mod_dmg),true);
if(tookShieldDamage)damageNumberPtr->SetType(DamageNumberType::SHIELD_LOSS);
DAMAGENUMBER_LIST.push_back(damageNumberPtr); DAMAGENUMBER_LIST.push_back(damageNumberPtr);
} }
lastHitTimer=0.05f; lastHitTimer=0.05f;
@ -2163,13 +2168,13 @@ void Player::AddShield(const ShieldAmount shieldAmt,const float shieldTimer, con
if(HasTimer(shieldType)){ if(HasTimer(shieldType)){
auto shieldIt{std::find_if(shield.begin(),shield.end(),[&shieldType](const std::pair<PlayerTimerType,ShieldAmount>&shieldData){return shieldData.first==shieldType;})}; auto shieldIt{std::find_if(shield.begin(),shield.end(),[&shieldType](const std::pair<PlayerTimerType,ShieldAmount>&shieldData){return shieldData.first==shieldType;})};
if(shieldIt!=shield.end()){ if(shieldIt!=shield.end()){
std::pair<PlayerTimerType,ShieldAmount>shieldData{*shieldIt}; std::pair<PlayerTimerType,ShieldAmount>&shieldData{*shieldIt};
shieldData.second=std::max(shieldData.second,shieldAmt); shieldData.second=std::max(shieldData.second,shieldAmt);
}else ERR(std::format("WARNING! The shield type {} does not have a corresponding entry! All shields when generated should have made one! THIS SHOULD NOT BE HAPPENING!",int(shieldType))); }else ERR(std::format("WARNING! The shield type {} does not have a corresponding entry! All shields when generated should have made one! THIS SHOULD NOT BE HAPPENING!",int(shieldType)));
}else{ }else{
std::pair<PlayerTimerType,ShieldAmount>&newShield{shield.emplace_back(std::pair<PlayerTimerType,ShieldAmount>{shieldType,shieldAmt})}; std::pair<PlayerTimerType,ShieldAmount>&newShield{shield.emplace_back(std::pair<PlayerTimerType,ShieldAmount>{shieldType,shieldAmt})};
if(shield.capacity()>SHIELD_CAPACITY)ERR(std::format("WARNING! Shield capacity limit has been reached! If you need more than {} shields, please expand the SHIELD_CAPACITY property of player!",SHIELD_CAPACITY)); if(shield.capacity()>SHIELD_CAPACITY)ERR(std::format("WARNING! Shield capacity limit has been reached! If you need more than {} shields, please expand the SHIELD_CAPACITY property of player!",SHIELD_CAPACITY));
AddTimer(shieldType,Timer{std::format("Shield Type {}",int(shieldType)),shieldTimer,[newShield,this](){std::erase_if(shield,[&newShield](const std::pair<PlayerTimerType,ShieldAmount>&shieldData){return shieldData.first==newShield.first;});}}); AddTimer(shieldType,Timer{std::format("Shield Type {}",int(shieldType)),shieldTimer,[&newShield,this](){newShield.second=0U;}});
} }
} }
Player::ShieldAmount Player::SubtractShield(const ShieldAmount shieldDamage){ Player::ShieldAmount Player::SubtractShield(const ShieldAmount shieldDamage){

@ -411,7 +411,7 @@ private:
const vf2d GetAimingLocation(bool useWalkDir=false,bool invert=false); const vf2d GetAimingLocation(bool useWalkDir=false,bool invert=false);
std::unordered_map<PlayerTimerType,Timer>timers; std::unordered_map<PlayerTimerType,Timer>timers;
void RunTimers(); void RunTimers();
float base_attack_range="Warrior.Auto Attack.Range"_F/100.f; float base_attack_range="Warrior.Auto Attack.Range"_F;
Renderable playerOutline; Renderable playerOutline;
void UpdatePlayerOutline(); void UpdatePlayerOutline();
void OnBuffAdd(Buff&newBuff); void OnBuffAdd(Buff&newBuff);

@ -42,5 +42,5 @@ enum class PlayerTimerType{
ADRENALINE_STIM, ADRENALINE_STIM,
PLAYER_OUTLINE_TIMER, PLAYER_OUTLINE_TIMER,
OPPORTUNITY_SHOT_RANDOM_SPECIAL_MARK, OPPORTUNITY_SHOT_RANDOM_SPECIAL_MARK,
ADVANCED_SHIELD_TIMER, ADVANCE_SHIELD_TIMER,
}; };

@ -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 11062 #define VERSION_BUILD 11074
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -107,10 +107,15 @@ void Warrior::InitializeClassAbilities(){
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
if(p->GetState()==State::NORMAL||p->GetState()==State::CASTING){ if(p->GetState()==State::NORMAL||p->GetState()==State::CASTING){
rightClickAbility.cooldown=rightClickAbility.COOLDOWN_TIME; rightClickAbility.cooldown=rightClickAbility.COOLDOWN_TIME;
float blockTime{"Warrior.Right Click Ability.Duration"_F};
if(p->HasEnchant("Heavy Guard"))blockTime*="Heavy Guard"_ENC["BLOCK DURATION MULT"];
if(p->HasEnchant("Advance Shield")){
p->AddShield(p->GetMaxHealth()*"Advance Shield"_ENC["SHIELD AMOUNT"]/100.f,"Advance Shield"_ENC["SHIELD DURATION"],PlayerTimerType::ADVANCE_SHIELD_TIMER);
}else{
p->blockTimer=blockTime;
p->SetState(State::BLOCK); p->SetState(State::BLOCK);
p->blockTimer="Warrior.Right Click Ability.Duration"_F;
if(p->HasEnchant("Heavy Guard"))p->blockTimer*="Heavy Guard"_ENC["BLOCK DURATION MULT"];
p->AddBuff(BuffType::BLOCK_SLOWDOWN,p->blockTimer,"Warrior.Right Click Ability.SlowAmt"_F); p->AddBuff(BuffType::BLOCK_SLOWDOWN,p->blockTimer,"Warrior.Right Click Ability.SlowAmt"_F);
}
return true; return true;
} }
return false; return false;

Loading…
Cancel
Save