Fix Firebolt and Lightning bolt crashing the game. Implemented cat animation override for Nine Lives enchant. Implemented Nine Lives Enchant. Release Build 11130.
This commit is contained in:
parent
f87aad6558
commit
a90c7d3c5d
@ -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.
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
@ -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)
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user