Fix Firebolt and Lightning bolt crashing the game. Implemented cat animation override for Nine Lives enchant. Implemented Nine Lives Enchant. Release Build 11130.

pull/65/head
sigonasr2 3 months ago
parent f87aad6558
commit a90c7d3c5d
  1. 44
      Adventures in Lestoria Tests/EnchantTests.cpp
  2. 45
      Adventures in Lestoria/AdventuresInLestoria.cpp
  3. 23
      Adventures in Lestoria/Animation.cpp
  4. 6
      Adventures in Lestoria/DamageNumber.cpp
  5. 2
      Adventures in Lestoria/FireBolt.cpp
  6. 2
      Adventures in Lestoria/LightningBolt.cpp
  7. 2
      Adventures in Lestoria/Pixel.h
  8. 55
      Adventures in Lestoria/Player.cpp
  9. 9
      Adventures in Lestoria/Player.h
  10. 1
      Adventures in Lestoria/PlayerTimerType.h
  11. 2
      Adventures in Lestoria/StoneGolem.cpp
  12. 2
      Adventures in Lestoria/Version.h
  13. 6
      Adventures in Lestoria/Witch.cpp
  14. 1
      Adventures in Lestoria/assets/config/Player.txt
  15. BIN
      Adventures in Lestoria/assets/gamepack.pak
  16. BIN
      Adventures in Lestoria/assets/nico-witch.png
  17. BIN
      Adventures in Lestoria/assets/nico-witch.xcf
  18. 4
      Adventures in Lestoria/olcPixelGameEngine.h
  19. BIN
      x64/Release/Adventures in Lestoria.exe

@ -1197,5 +1197,49 @@ namespace EnchantTests
Assert::AreEqual(986,newMonster.GetHealth(),L"Monster 1 should have been hit. Since we can have 4 bounces, this got hit twice. Damage should be halved.");
Assert::AreEqual(986,newMonster2.GetHealth(),L"Monster 2 should have been hit. Since we can have 4 bounces, this got hit twice. Damage should be halved.");
}
TEST_METHOD(NineLivesNoEnchantCheck){
testKey->bHeld=true; //Force the key to be held down for testing purposes.
game->ChangePlayerClass(WITCH);
player=game->GetPlayer();
Assert::AreEqual("Witch.Right Click Ability.Cooldown"_F,player->GetRightClickAbility().GetCooldownTime(),L"Cooldown time should be normal.");
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
game->SetElapsedTime(10.f);
game->OnUserUpdate(10.f);
player->Hurt(10,player->OnUpperLevel(),player->GetZ());
Assert::AreEqual(70,player->GetHealth(),L"Player should take normal damage when cat form expires.");
}
TEST_METHOD(NineLivesEnchantCheck){
testKey->bHeld=true; //Force the key to be held down for testing purposes.
game->ChangePlayerClass(WITCH);
player=game->GetPlayer();
std::weak_ptr<Item>nullRing{Inventory::AddItem("Null Ring"s)};
Inventory::EquipItem(nullRing,EquipSlot::RING1);
nullRing.lock()->EnchantItem("Nine Lives");
Assert::AreEqual("Nine Lives"_ENC["TRANSFORM COOLDOWN"],player->GetRightClickAbility().GetCooldownTime(),L"Cooldown time should be drastically increased.");
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Assert::AreEqual(player->GetRightClickAbility().cooldown,"Nine Lives"_ENC["TRANSFORM COOLDOWN"],L"Cooldown time should be 20s when not in cat form already.");
game->SetElapsedTime(10.f);
game->OnUserUpdate(10.f);
player->Hurt(10,player->OnUpperLevel(),player->GetZ());
Assert::AreEqual(80,player->GetHealth(),L"Player should absorb the damage since they were in cat form.");
player->Hurt(10,player->OnUpperLevel(),player->GetZ());
Assert::AreEqual(70,player->GetHealth(),L"Now player should take normal damage after reverting forms.");
}
TEST_METHOD(NineLivesCooldownReducedInCatFormEnchantCheck){
testKey->bHeld=true; //Force the key to be held down for testing purposes.
game->ChangePlayerClass(WITCH);
player=game->GetPlayer();
std::weak_ptr<Item>nullRing{Inventory::AddItem("Null Ring"s)};
Inventory::EquipItem(nullRing,EquipSlot::RING1);
nullRing.lock()->EnchantItem("Nine Lives");
Assert::AreEqual("Nine Lives"_ENC["TRANSFORM COOLDOWN"],player->GetRightClickAbility().GetCooldownTime(),L"Cooldown time should be drastically increased.");
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Assert::AreEqual(player->GetRightClickAbility().cooldown,"Nine Lives"_ENC["TRANSFORM COOLDOWN"],L"Cooldown time should be 20s when not in cat form already.");
player->GetRightClickAbility().charges=1;
game->SetElapsedTime(1.f);
game->OnUserUpdate(1.f);
player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
Assert::AreEqual("Witch.Right Click Ability.Cooldown"_F,player->GetRightClickAbility().cooldown,L"Cooldown time should be 8s when already in cat form.");
}
};
}

@ -1106,8 +1106,11 @@ void AiL::RenderWorld(float fElapsedTime){
if(player->IsInvisible())return;
vf2d playerScale=vf2d(player->GetSizeMult(),player->GetSizeMult());
int count=0;
std::reference_wrapper<const Animate2D::Frame>animationFrame{player->GetFrame()};
if(player->CatFormActive())animationFrame=player->GetCatFrame();
for(vf2d&pos:player->ghostPositions){
view.DrawPartialRotatedDecal(pos,player->GetFrame().GetSourceImage()->Decal(),player->GetSpinAngle(),{12,12},player->GetFrame().GetSourceRect().pos,player->GetFrame().GetSourceRect().size,playerScale,{0,0,0,uint8_t(float(count)/player->RETREAT_GHOST_FRAMES*255)});
view.DrawPartialRotatedDecal(pos,animationFrame.get().GetSourceImage()->Decal(),player->GetSpinAngle(),{12,12},animationFrame.get().GetSourceRect().pos,animationFrame.get().GetSourceRect().size,playerScale,{0,0,0,uint8_t(float(count)/player->RETREAT_GHOST_FRAMES*255)});
count++;
}
if(player->teleportAnimationTimer>0){
@ -1123,10 +1126,12 @@ void AiL::RenderWorld(float fElapsedTime){
if(attackBuffs.size()>0)playerCol={255,uint8_t(255*abs(sin(1.4f*attackBuffs[0].duration))),uint8_t(255*abs(sin(1.4f*attackBuffs[0].duration)))};
else if(adrenalineRushBuffs.size()>0)playerCol={uint8_t(255*abs(sin(6.f*adrenalineRushBuffs[0].duration))),255,uint8_t(255*abs(sin(6.f*adrenalineRushBuffs[0].duration)))};
else if(movespeedBuffs.size()>0)playerCol={uint8_t(255*abs(sin(2.f*movespeedBuffs[0].duration))),255,uint8_t(255*abs(sin(2.f*movespeedBuffs[0].duration)))};
if(damageReductionBuffs.size()>0)view.DrawPartialSquishedRotatedDecal(pos+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)},player->playerOutline.Decal(),player->GetSpinAngle(),{12,12},player->GetFrame().GetSourceRect().pos,player->GetFrame().GetSourceRect().size,playerScale*scale+0.1f,{1.f,player->ySquishFactor},{210,210,210,uint8_t(util::lerp(0,255,abs(sin((PI*GetRunTime())/1.25f))))});
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});
if(damageReductionBuffs.size()>0)view.DrawPartialSquishedRotatedDecal(pos+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)},player->playerOutline.Decal(),player->GetSpinAngle(),{12,12},animationFrame.get().GetSourceRect().pos,animationFrame.get().GetSourceRect().size,playerScale*scale+0.1f,{1.f,player->ySquishFactor},{210,210,210,uint8_t(util::lerp(0,255,abs(sin((PI*GetRunTime())/1.25f))))});
view.DrawPartialSquishedRotatedDecal(pos+vf2d{0,-player->GetZ()*(std::signbit(scale.y)?-1:1)},animationFrame.get().GetSourceImage()->Decal(),player->GetSpinAngle(),{12,12},animationFrame.get().GetSourceRect().pos,animationFrame.get().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()},Pixel{0xFFDCDA});
SetDecalMode(DecalMode::NORMAL);
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());
@ -1960,7 +1965,6 @@ void AiL::RenderHud(){
const vf2d&bossIndicator=bossIndicatorPos.value();
const bool BossIsOutsideView=!geom2d::overlaps(geom2d::rect<float>{view.GetWorldTL(),view.GetWorldVisibleArea()},bossIndicator);
if(BossIsOutsideView){
const bool flicker=sinf(GetRunTime())>0.5f&&sinf(GetRunTime())<0.55f;
#pragma region Side Indicators
@ -2011,8 +2015,7 @@ void AiL::RenderHud(){
if(GetPlayer()->GetCastInfo().castTimer>0){
RenderCastbar(GetPlayer()->GetCastInfo());
}else
if(GetPlayer()->GetEndZoneStandTime()>0){
}else if(GetPlayer()->GetEndZoneStandTime()>0){
RenderCastbar(CastInfo{"Exiting Level...",GetPlayer()->GetEndZoneStandTime(),"Player.End Zone Wait Time"_F});
}
@ -2041,20 +2044,20 @@ void AiL::RenderHud(){
DrawShadowStringPropDecal({24,23},text_mana,manaCounter.GetDisplayColor(),BLACK,{1.5f,1.5f},{1.45f,1.45f},INFINITE);
#pragma region Show Max Health/Max Mana
if(GameSettings::ShowMaxHealth()){
vf2d healthTextSize=GetTextSizeProp(text)*vf2d{2.f,2.f};
if(GameSettings::ShowMaxHealth()){
vf2d healthTextSize=GetTextSizeProp(text)*vf2d{2.f,2.f};
std::string maxHealthText="/"+std::to_string(int(player->GetMaxHealth()));
float maxHealthTextHeight=GetTextSizeProp(maxHealthText).y;
DrawShadowStringPropDecal(vf2d{20,3}+healthTextSize+vf2d{1.f,-maxHealthTextHeight},maxHealthText,{200,200,200,255},healthOutlineCol,{1.f,1.f},{1.f,1.f},INFINITE);
}
if(GameSettings::ShowMaxMana()){
vf2d manaTextSize=GetTextSizeProp(text_mana)*vf2d{1.5f,1.5f};
std::string maxHealthText="/"+std::to_string(int(player->GetMaxHealth()));
float maxHealthTextHeight=GetTextSizeProp(maxHealthText).y;
DrawShadowStringPropDecal(vf2d{20,3}+healthTextSize+vf2d{1.f,-maxHealthTextHeight},maxHealthText,{200,200,200,255},healthOutlineCol,{1.f,1.f},{1.f,1.f},INFINITE);
}
if(GameSettings::ShowMaxMana()){
vf2d manaTextSize=GetTextSizeProp(text_mana)*vf2d{1.5f,1.5f};
std::string maxManaText="/"+std::to_string(player->GetMaxMana());
float maxManaTextHeight=GetTextSizeProp(maxManaText).y;
DrawShadowStringPropDecal(vf2d{24,23}+manaTextSize+vf2d{1.f,-maxManaTextHeight},maxManaText,{200,200,255,255},BLACK,{1.f,1.f},{1.f,1.f},INFINITE);
}
std::string maxManaText="/"+std::to_string(player->GetMaxMana());
float maxManaTextHeight=GetTextSizeProp(maxManaText).y;
DrawShadowStringPropDecal(vf2d{24,23}+manaTextSize+vf2d{1.f,-maxManaTextHeight},maxManaText,{200,200,255,255},BLACK,{1.f,1.f},{1.f,1.f},INFINITE);
}
#pragma endregion
if(player->notEnoughManaDisplay.second>0){
@ -2170,7 +2173,7 @@ void AiL::RenderCooldowns(){
if(itemAmt>0){
std::string amtString="x"+std::to_string(itemAmt);
vf2d qtySize=vf2d{GetTextSize(amtString)}*vf2d{0.5f,0.75f};
DrawShadowStringDecal(pos+vf2d{20,20}-qtySize/2,amtString,0xE0E0E0,BLACK,{0.5f,0.75f},{0.5f,0.75f});
DrawShadowStringDecal(pos+vf2d{20,20}-qtySize/2,amtString,Pixel{0xE0E0E0},BLACK,{0.5f,0.75f},{0.5f,0.75f});
}else{
DrawDecal(pos,GFX["square_skill_overlay_icon_empty.png"].Decal(),{1,1},DARK_RED);
shortNameCol=RED;

@ -48,7 +48,6 @@ INCLUDE_GFX
void sig::Animation::InitializeAnimations(){
ANIMATION_DATA.Reset();
auto CreateStillAnimation=[&](std::string imgName,vf2d size,AnimationData data={}){
Animate2D::FrameSequence anim(data.frameDuration,data.style);
anim.AddFrame({&GFX[imgName],{{0,0},size}});
@ -347,6 +346,28 @@ void sig::Animation::InitializeAnimations(){
ANIMATION_DATA["WITCH_TRANSFORM_W"]=pl_witch_transform_w;
ANIMATION_DATA["WITCH_TRANSFORM_E"]=pl_witch_transform_e;
Animate2D::FrameSequence pl_witch_cat_walk_s(0.2f);
for(int i=0;i<2;i++){
pl_witch_cat_walk_s.AddFrame({&GFX["nico-witch.png"],{vi2d{0+i,4}*24,{24,24}}});
}
ANIMATION_DATA["WITCH_CAT_WALK_S"]=pl_witch_cat_walk_s;
Animate2D::FrameSequence pl_witch_cat_walk_n(0.2f);
for(int i=0;i<2;i++){
pl_witch_cat_walk_n.AddFrame({&GFX["nico-witch.png"],{vi2d{0+i,5}*24,{24,24}}});
}
ANIMATION_DATA["WITCH_CAT_WALK_N"]=pl_witch_cat_walk_n;
Animate2D::FrameSequence pl_witch_cat_walk_w(0.2f);
for(int i=0;i<2;i++){
pl_witch_cat_walk_w.AddFrame({&GFX["nico-witch.png"],{vi2d{0+i,6}*24,{24,24}}});
}
ANIMATION_DATA["WITCH_CAT_WALK_W"]=pl_witch_cat_walk_w;
Animate2D::FrameSequence pl_witch_cat_walk_e(0.2f);
for(int i=0;i<2;i++){
pl_witch_cat_walk_e.AddFrame({&GFX["nico-witch.png"],{vi2d{0+i,7}*24,{24,24}}});
}
ANIMATION_DATA["WITCH_CAT_WALK_E"]=pl_witch_cat_walk_e;
CreateHorizontalAnimationSequence("ground-slam-attack-back.png",5,{64,64},{0.02f,Animate2D::Style::OneShot});
CreateHorizontalAnimationSequence("ground-slam-attack-front.png",5,{64,64},{0.02f,Animate2D::Style::OneShot});
CreateHorizontalAnimationSequence("battlecry_effect.png",5,{84,84},{0.02f,Animate2D::Style::OneShot});

@ -127,15 +127,15 @@ void DamageNumber::Draw(){
}break;
case DOT:{
std::string text=std::to_string(damage);
DrawDamageNumber(NormalNumber,text,{0xE1BEE7,0x1F083A},{0xDCE775,0x37320A});
DrawDamageNumber(NormalNumber,text,std::pair<Pixel,Pixel>{0xE1BEE7,0x1F083A},std::pair<Pixel,Pixel>{0xDCE775,0x37320A});
}break;
case BACKSTAB:{
std::string text=std::to_string(damage);
DrawDamageNumber(NumberScalesWithDamage,text,{0x888093,0x150035},{BLACK,{0,0,0,0}});
DrawDamageNumber(NumberScalesWithDamage,text,std::pair<Pixel,Pixel>{0x888093,0x150035},{BLACK,{0,0,0,0}});
}break;
case SHIELD_LOSS:{
std::string text=std::to_string(damage);
DrawDamageNumber(NumberScalesWithDamage,text,{DARK_BLUE,0x68d7ef},{BLUE,0x4141be});
DrawDamageNumber(NumberScalesWithDamage,text,std::pair<Pixel,Pixel>{DARK_BLUE,0x68d7ef},std::pair<Pixel,Pixel>{BLUE,0x4141be});
}break;
default:ERR(std::format("Damage Number Type {} is not implemented! THIS SHOULD NOT BE HAPPENING!",int(type)));
}

@ -55,7 +55,7 @@ void FireBolt::Update(float fElapsedTime){
lastParticleSpawn="Wizard.Ability 1.ParticleFrequency"_F;
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Ability 1.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Ability 1.ParticleSizeRange"_FRange,"Wizard.Ability 1.ParticleFadeoutTime"_F,vf2d{"Wizard.Ability 1.ParticleXSpeedRange"_FRange,"Wizard.Ability 1.ParticleYSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.ParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.ParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.ParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.ParticleAlphaRange"_FRange)}));
}
if(distanceTraveled>"Wizard.Ability 1.Range"_F&&IsActivated()){
if(distanceTraveled>"Wizard.Ability 1.Max Range"_F&&IsActivated()){
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));

@ -72,7 +72,7 @@ void LightningBolt::Update(float fElapsedTime){
}break;
}
}
if(distanceTraveled>"Wizard.Ability 2.Range"_F&&IsActivated()){
if(distanceTraveled>"Wizard.Ability 2.Max Range"_F&&IsActivated()){
fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F;
}
}

@ -74,7 +74,7 @@ namespace olc{
Pixel();
Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = nDefaultAlpha);
//Hex Implicit Constructor!! ALPHA IS ASSUMED TO BE 255! If you need access to modifying the raw value, use PixelRaw()
Pixel(uint32_t hex);
explicit Pixel(uint32_t hex);
Pixel& operator = (const Pixel& v) = default;
bool operator ==(const Pixel& p) const;
bool operator !=(const Pixel& p) const;

@ -122,6 +122,7 @@ void Player::Initialize(){
afterImage.Decal()->Update();
playerOutline.Create(24,24);
shield.reserve(SHIELD_CAPACITY);
DeactivateCatForm();
}
void Player::OnLevelStart(){
@ -442,14 +443,14 @@ void Player::Update(float fElapsedTime){
if(lastAnimationFlip==0){
lastAnimationFlip=0.03f;
facingDirection=DOWN;
animation.ChangeState(internal_animState,"WARRIOR_WALK_S");
UpdateAnimation("WARRIOR_WALK_S");
}
}break;
case DOWN:{
if(lastAnimationFlip==0){
lastAnimationFlip=0.03f;
facingDirection=UP;
animation.ChangeState(internal_animState,"WARRIOR_WALK_N");
UpdateAnimation("WARRIOR_WALK_N");
}
}break;
}
@ -499,7 +500,7 @@ void Player::Update(float fElapsedTime){
if(lastAnimationFlip>0){
lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime);
}
animation.UpdateState(internal_animState,fElapsedTime);
UpdateAnimationStates();
}break;
case State::BLOCK:{
if(blockTimer<=0){
@ -524,7 +525,7 @@ void Player::Update(float fElapsedTime){
}break;
}
}
animation.UpdateState(internal_animState,fElapsedTime);
UpdateAnimationStates();
}break;
case State::TELEPORT:{
teleportAnimationTimer=std::max(0.f,teleportAnimationTimer-fElapsedTime);
@ -532,7 +533,7 @@ void Player::Update(float fElapsedTime){
ForceSetPos(teleportTarget);
SetState(State::NORMAL);
}
animation.UpdateState(internal_animState,fElapsedTime);
UpdateAnimationStates();
}break;
case State::ROLL:{
footstepTimer-=fElapsedTime;
@ -584,11 +585,11 @@ void Player::Update(float fElapsedTime){
}
SetZ((sin((1.f/totalLeapTime)*PI*leapTimer)/2.f)*"Witch.Right Click Ability.Leap Max Z"_F);
SetVelocity(vf2d{"Witch.Right Click Ability.Leap Velocity"_F/100.f*24,transformTargetDir}.cart());
animation.UpdateState(internal_animState,fElapsedTime);
UpdateAnimationStates();
}break;
default:{
//Update animations normally.
animation.UpdateState(internal_animState,fElapsedTime);
UpdateAnimationStates();
}
}
@ -947,7 +948,11 @@ bool Player::Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag dama
if(tookLethalDamage&&survivedHitDueToDefiance)ApplyIframes("Death Defiance"_ENC["LETHAL DAMAGE SURVIVE IFRAME TIME"]);
else{
if(GetShield()>0){
if(CatFormActive()){
tookShieldDamage=true;
if(PlayHitSoundEffect)SoundEffect::PlaySFX("Warrior Block Hit",SoundEffect::CENTERED);
DeactivateCatForm();
}else if(GetShield()>0){
tookShieldDamage=true;
if(PlayHitSoundEffect)SoundEffect::PlaySFX("Warrior Block Hit",SoundEffect::CENTERED);
SubtractShield(mod_dmg);
@ -1009,13 +1014,18 @@ void Player::AddAnimation(std::string state){
void Player::UpdateAnimation(std::string animState,int specificClass, const float frameMult){
if(specificClass==ANY||specificClass&GetClass()){
animation.ChangeState(internal_animState,animState,frameMult);
animation.ChangeState(internal_catAnimState,std::format("WITCH_CAT_WALK_{}",animState[animState.length()-1]),frameMult);
}
}
Animate2D::Frame Player::GetFrame(){
const Animate2D::Frame&Player::GetFrame()const{
return animation.GetFrame(internal_animState);
}
const Animate2D::Frame&Player::GetCatFrame()const{
return animation.GetFrame(internal_catAnimState);
}
void Player::SetFacingDirection(Key direction){
facingDirection=direction;
}
@ -1117,6 +1127,7 @@ void Player::UpdateIdleAnimation(Key direction){
}
SetFacingDirection(direction);
UpdateAnimation(anim);
animation.ChangeState(internal_catAnimState,std::format("WITCH_CAT_WALK_{}",anim[anim.length()-1]),0.f);
}
void Player::AddBuff(BuffType type,float duration,float intensity){
@ -1514,6 +1525,10 @@ void Player::RecalculateEquipStats(){
}
}
if(GetClass()&WITCH){
if(HasEnchant("Nine Lives"))GetRightClickAbility().COOLDOWN_TIME="Nine Lives"_ENC["TRANSFORM COOLDOWN"];
}
for(const std::reference_wrapper<Ability>&a:GetAbilities()){
if(a.get().itemAbility)continue;
if(a.get().charges<a.get().MAX_CHARGES&&a.get().cooldown==0.f)a.get().cooldown=a.get().GetCooldownTime();
@ -2019,11 +2034,11 @@ const bool Player::HasEnchant(const std::string_view enchantName)const{
}
void Player::OnAbilityUse(const Ability&ability){
if(ability.itemAbility||ability.name==GetRightClickAbility().name)return;
if(ability.itemAbility)return;
const auto UsedAbility=[&ability](const std::string_view abilityName){return ability.name==abilityName;};
if(HasEnchant("Wizard's Soul")){
if(HasEnchant("Wizard's Soul")&&ability.name!=GetRightClickAbility().name){
const auto ReduceCooldown=[this,&ability](Ability&a){
if(ability.name==a.name)return;
a.cooldown-="Wizard's Soul"_ENC["ABILITY COOLDOWN AMOUNT"];
@ -2052,6 +2067,10 @@ void Player::OnAbilityUse(const Ability&ability){
CancelTimer(PlayerTimerType::DEADLY_MIRAGE_SECOND_CAST);
}
}
if(UsedAbility("Transform")&&HasEnchant("Nine Lives")){
if(HasTimer(PlayerTimerType::CAT_FORM_ALREADY_ACTIVE)&&GetTimer(PlayerTimerType::CAT_FORM_ALREADY_ACTIVE).IsRunning())Witch::rightClickAbility.cooldown="Witch.Right Click Ability.Cooldown"_F;
}
}
Ability&Player::GetItem1(){
@ -2210,4 +2229,18 @@ void Player::NotEnoughManaDisplay(const std::string_view text,const float displa
}
void Player::NotificationDisplay(const std::string_view text,const float displayTime){
notificationDisplay=std::pair<std::string,float>{text,displayTime};
}
void Player::DeactivateCatForm(){
catForm=false;
}
void Player::ActivateCatForm(){
catForm=true;
}
const bool Player::CatFormActive()const{
return catForm;
}
void Player::UpdateAnimationStates(){
animation.UpdateState(internal_animState,game->GetElapsedTime());
animation.UpdateState(internal_catAnimState,game->GetElapsedTime());
}

@ -211,7 +211,8 @@ public:
bool Heal(int damage,bool suppressDamageNumber=false);
//specificClass is a bitwise-combination of classes from the Class enum. It makes sure certain animations only play if you are a certain class.=
void UpdateAnimation(std::string animState,int specificClass=ANY,const float frameMult=1.f);
Animate2D::Frame GetFrame();
const Animate2D::Frame&GetFrame()const;
const Animate2D::Frame&GetCatFrame()const;
float GetSwordSwingTimer();
bool OnUpperLevel();
void ResetLastCombatTime();
@ -328,6 +329,9 @@ public:
void OnLevelStart();
void NotEnoughManaDisplay(const std::string_view text,const float displayTime); //Red text for displayTime seconds.
void NotificationDisplay(const std::string_view text,const float displayTime); //Blue text for displayTime seconds.
void DeactivateCatForm();
const bool CatFormActive()const;
void UpdateAnimationStates();
private:
const int SHIELD_CAPACITY{32};
int hp="Warrior.BaseHealth"_I;
@ -418,6 +422,7 @@ private:
void UpdatePlayerOutline();
void OnBuffAdd(Buff&newBuff);
std::vector<std::pair<PlayerTimerType,ShieldAmount>>shield;
bool catForm{false};
protected:
const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F;
const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F;
@ -460,6 +465,7 @@ protected:
size_t cooldownSoundInstance=std::numeric_limits<size_t>::max();
Renderable afterImage;
Animate2D::AnimationState internal_animState;
Animate2D::AnimationState internal_catAnimState;
float removeLineTimer{};
const float TIME_BETWEEN_LINE_REMOVALS{0.025f};
uint8_t scanLine{24}; //0-23.
@ -470,6 +476,7 @@ protected:
float totalLeapTime{};
vf2d leapStartingPos{};
float poisonArrowReadyTimer{};
void ActivateCatForm();
};
#pragma region Warrior

@ -43,4 +43,5 @@ enum class PlayerTimerType{
PLAYER_OUTLINE_TIMER,
OPPORTUNITY_SHOT_RANDOM_SPECIAL_MARK,
ADVANCE_SHIELD_TIMER,
CAT_FORM_ALREADY_ACTIVE,
};

@ -254,7 +254,7 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
}break;
case SHOCKWAVE:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
Pixel newCol{PixelLerp(m.I(A::SHOCKWAVE_COLOR),BLACK,sin(geom2d::pi*game->GetRunTime()*2)/2.f+0.5f)};
Pixel newCol{PixelLerp(Pixel{uint32_t(m.I(A::SHOCKWAVE_COLOR))},BLACK,sin(geom2d::pi*game->GetRunTime()*2)/2.f+0.5f)};
newCol.a=util::lerp(255.f,210.f,sin(geom2d::pi*game->GetRunTime()*2)/2.f+0.5f);
game->SetWorldColor(newCol);

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 3
#define VERSION_BUILD 11108
#define VERSION_BUILD 11130
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -108,7 +108,7 @@ bool Witch::AutoAttack(){
float angleToCursor=atan2(GetWorldAimingLocation().y-GetPos().y,GetWorldAimingLocation().x-GetPos().x);
int damage{int(GetAttack()*"Witch.Auto Attack.DamageMult"_F)};
if(HasEnchant("Bouncing Orb"))damage*="Bouncing Orb"_ENC["ORB DAMAGE"]/100.f;
CreateBullet(PurpleEnergyBall)(GetPos(),"Witch.Auto Attack.Radius"_F/100*12,"Witch.Auto Attack.Homing Range"_F/100*24,damage,upperLevel,{cos(angleToCursor)*"Witch.Auto Attack.Speed"_F,sin(angleToCursor)*"Witch.Auto Attack.Speed"_F},false,INFINITE,true)EndBullet;
CreateBullet(PurpleEnergyBall)(GetPos(),"Witch.Auto Attack.Radius"_F/100*12,"Witch.Auto Attack.Homing Range"_F/100*24,damage,upperLevel,{cos(angleToCursor)*"Witch.Auto Attack.Speed"_F,sin(angleToCursor)*"Witch.Auto Attack.Speed"_F},INFINITE,true)EndBullet;
BULLET_LIST.back()->SetIsPlayerAutoAttackProjectile();
SoundEffect::PlaySFX("Witch Attack",SoundEffect::CENTERED);
return true;
@ -126,6 +126,10 @@ void Witch::InitializeClassAbilities(){
p->SetAnimationBasedOnTargetingDirection("TRANSFORM",p->transformTargetDir);
p->ApplyIframes("Witch.Right Click Ability.Leap Max Range Time"_F+0.1f);
p->SetState(State::LEAP);
if(p->HasEnchant("Nine Lives")){
if(p->CatFormActive())p->AddTimer(PlayerTimerType::CAT_FORM_ALREADY_ACTIVE,Timer{"Cat Form Active Already Notification",1.f,[](){}});
p->ActivateCatForm();
}
SoundEffect::PlaySFX("Meow",p->GetPos());
return true;
};

@ -100,6 +100,7 @@ Player
PLAYER_ANIMATION[23] = WITCH_CAST
PLAYER_ANIMATION[24] = WITCH_IDLE
PLAYER_ANIMATION[25] = WITCH_TRANSFORM
PLAYER_ANIMATION[26] = WITCH_CAT_WALK
}
PlayerXP

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 11 KiB

@ -1594,7 +1594,7 @@ namespace olc
{
width = w; height = h;
pColData.resize(width * height);
pColData.resize(width * height, nDefaultPixel);
pColData.resize(width * height, Pixel{nDefaultPixel});
}
Sprite::~Sprite()
@ -1604,7 +1604,7 @@ namespace olc
{
width = w; height = h;
pColData.resize(width * height);
pColData.resize(width * height, nDefaultPixel);
pColData.resize(width * height, Pixel{nDefaultPixel});
}
void Sprite::SetSampleMode(olc::Sprite::Mode mode)

Loading…
Cancel
Save