diff --git a/Adventures in Lestoria/BreakingPillar.cpp b/Adventures in Lestoria/BreakingPillar.cpp index 84c7275d..c0a07e69 100644 --- a/Adventures in Lestoria/BreakingPillar.cpp +++ b/Adventures in Lestoria/BreakingPillar.cpp @@ -43,6 +43,11 @@ All rights reserved. using A=Attribute; void Monster::STRATEGY::BREAKING_PILLAR(Monster&m,float fElapsedTime,std::string strategy){ + enum Phase{ + INITIALIZE, + RUN, + }; + if(m.GetHealthRatio()>=ConfigFloat("Break Phase 1 HP % Threshold")/100.f){ m.animation.ModifyDisplaySprite(m.internal_animState,ConfigString("Unbroken Animation Name")); }else @@ -50,6 +55,30 @@ void Monster::STRATEGY::BREAKING_PILLAR(Monster&m,float fElapsedTime,std::string m.animation.ModifyDisplaySprite(m.internal_animState,ConfigString("Break Phase 1 Animation Name")); }else m.animation.ModifyDisplaySprite(m.internal_animState,ConfigString("Break Phase 2 Animation Name")); + switch(m.phase){ + case INITIALIZE:{ + m.F(A::BREAK_TIME)=ConfigFloat("Break Time"); + m.F(A::SHAKE_TIMER)=0.2f; + m.phase=RUN; + }break; + case RUN:{ + m.F(A::BREAK_TIME)-=fElapsedTime; + if(m.F(A::BREAK_TIME)<=2.f){ + if(m.F(A::BREAK_TIME)<=0.f){ + m._DealTrueDamage(m.GetHealth()); //Kill the pillar, making it crumble. + break; + } + m.F(A::SHAKE_TIMER)-=fElapsedTime; + if(m.F(A::SHAKE_TIMER)<=0.f){ + m.F(A::SHAKE_TIMER)+=0.2f; + if(m.B(A::SHAKE_DIR))m.SetX(m.GetPos().x-2); + else m.SetX(m.GetPos().x+2); + m.B(A::SHAKE_DIR)=!m.B(A::SHAKE_DIR); + } + } + }break; + } + m.SetStrategyDeathFunction([&](GameEvent&deathEvent,Monster&m,const std::string&strategy){ m.lifetime=0.01f; m.B(A::MARKED_DEAD)=true; diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h index 26181654..643ebfcc 100644 --- a/Adventures in Lestoria/MonsterAttribute.h +++ b/Adventures in Lestoria/MonsterAttribute.h @@ -126,4 +126,9 @@ enum class Attribute{ PLAYED_FLAG, HEALTH_PCT_PHASE, //Used for tracking the percentage a mechanic was done in Stone Golem Fight. STAGE_POLYGONS, + NEXT_HEALTH_PCT_PILLAR_PHASE, + BAD_PILLAR_SPAWN_COUNT, + BREAK_TIME, + SHAKE_TIMER, + SHAKE_DIR, }; \ No newline at end of file diff --git a/Adventures in Lestoria/StoneGolem.cpp b/Adventures in Lestoria/StoneGolem.cpp index 4c7c4b3a..80e5ce13 100644 --- a/Adventures in Lestoria/StoneGolem.cpp +++ b/Adventures in Lestoria/StoneGolem.cpp @@ -55,7 +55,9 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str enum PhaseName{ INITIALIZE, SPAWN_PILLAR_PREPARE, + RESPAWN_PILLAR_PREPARE, SPAWN_PILLAR_CAST, + RESPAWN_PILLAR_CAST, STANDARD, STONE_THROW_CAST, STONE_THROW_FINISH_ANIMATION, @@ -114,7 +116,10 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str m.F(A::RECOVERY_TIME)=ConfigFloat("Beginning Phase.Pillar Cast Delay Time"); m.I(A::PATTERN_REPEAT_COUNT)=ConfigInt("Beginning Phase.Repeat Count"); m.F(A::HEALTH_PCT_PHASE)=1.f; + m.F(A::NEXT_HEALTH_PCT_PILLAR_PHASE)=ConfigFloat("Pillar Respawns.Start HP Threshold")/100.f; m.phase=SPAWN_PILLAR_PREPARE; + + if(ConfigIntArr("Pillar Respawns.Respawn Count",0)GetPlayer()->GetPos(); + m.SIZET(A::LOOPING_SOUND_ID)=SoundEffect::PlayLoopingSFX("Rock Toss Cast",m.GetPos()); + m.PerformAnimation("CAST",m.GetFacingDirectionToTarget(m.V(A::LOCKON_POS))); + game->AddEffect(std::make_unique(m.V(A::LOCKON_POS),ConfigFloat("Pillar Respawns.Cast Time"),"range_indicator.png","spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Pillar Respawns.Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Pillar Respawns.Spell Circle Rotation Spd")),false,vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Pillar Respawns.Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Pillar Respawns.Spell Insignia Rotation Spd"))),true); + m.F(A::CASTING_TIMER)=ConfigFloat("Pillar Respawns.Cast Time"); + m.phase=RESPAWN_PILLAR_CAST; + } + }break; case SPAWN_PILLAR_CAST:{ m.F(A::CASTING_TIMER)-=fElapsedTime; if(m.F(A::CASTING_TIMER)<=0.f){ @@ -144,18 +160,49 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str } } }break; + case RESPAWN_PILLAR_CAST:{ + m.F(A::CASTING_TIMER)-=fElapsedTime; + if(m.F(A::CASTING_TIMER)<=0.f){ + SoundEffect::StopLoopingSFX(m.SIZET(A::LOOPING_SOUND_ID)); + SoundEffect::PlaySFX("Pillar Rise",m.V(A::LOCKON_POS)); + if(m.I(A::BAD_PILLAR_SPAWN_COUNT)>0&& + (util::random_range(0,1)<0.5f||m.I(A::PATTERN_REPEAT_COUNT)<=m.I(A::BAD_PILLAR_SPAWN_COUNT))){ + Monster&badPillar{game->SpawnMonster(m.V(A::LOCKON_POS),MONSTER_DATA.at("Breaking Stone Golem Pillar"),m.OnUpperLevel())}; + badPillar._DealTrueDamage(badPillar.GetMaxHealth()-1U); //Force the health to be 1. + m.I(A::BAD_PILLAR_SPAWN_COUNT)--; + }else game->SpawnMonster(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Golem Pillar"),m.OnUpperLevel()); + m.I(A::PATTERN_REPEAT_COUNT)--; + game->Hurt(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult(),MONSTER_DATA.at("Stone Golem Pillar").GetAttack(),m.OnUpperLevel(),0.f,HurtType::PLAYER); + if(m.I(A::PATTERN_REPEAT_COUNT)<=0){ + m.phase=STANDARD; + }else{ + m.PerformIdleAnimation(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); + m.F(A::RECOVERY_TIME)=ConfigFloat("Pillar Respawns.Cast Delay Time"); + m.phase=RESPAWN_PILLAR_PREPARE; + } + } + }break; case STANDARD:{ BEAR(m,fElapsedTime,"Bear"); //Extending the bear script's variables to read the state of it... const bool SlamHasFinished=m.I(A::ATTACK_COUNT)!=m.I(A::BEAR_STOMP_COUNT); if(SlamHasFinished){ - if(m.F(A::HEALTH_PCT_PHASE)-m.GetHealthRatio()>=0.1f){ - m.F(A::HEALTH_PCT_PHASE)-=0.1f; + if(m.F(A::HEALTH_PCT_PHASE)-m.GetHealthRatio()>=ConfigFloat("Shockwave.Repeating Threshold")/100.f){ + m.F(A::HEALTH_PCT_PHASE)-=ConfigFloat("Shockwave.Repeating Threshold")/100.f; m.F(A::CASTING_TIMER)=ConfigFloat("Shockwave.Cast Time"); PrepareSafeAreas(); m.phase=SHOCKWAVE; break; } + if(m.F(A::NEXT_HEALTH_PCT_PILLAR_PHASE)>=m.GetHealthRatio()){ + m.F(A::NEXT_HEALTH_PCT_PILLAR_PHASE)-=ConfigFloat("Pillar Respawns.Repeating Threshold")/100.f; + + m.F(A::RECOVERY_TIME)=ConfigFloat("Pillar Respawns.Cast Delay Time"); + m.I(A::PATTERN_REPEAT_COUNT)=ConfigIntArr("Pillar Respawns.Respawn Count",0); + m.I(A::BAD_PILLAR_SPAWN_COUNT)=ConfigIntArr("Pillar Respawns.Respawn Count",1); + m.phase=RESPAWN_PILLAR_PREPARE; + break; + } const bool StoneThrowRollSucceeds=util::random(100.f)<=ConfigFloat("Standard Attack.Stone Throw Chance"); m.I(A::ATTACK_COUNT)=m.I(A::BEAR_STOMP_COUNT); //Make sure the slams are now reset if necessary. diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 2d140d65..90862489 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 9948 +#define VERSION_BUILD 9951 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/config/MonsterStrategies.txt b/Adventures in Lestoria/assets/config/MonsterStrategies.txt index 0667d12b..56d35777 100644 --- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt +++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt @@ -898,6 +898,25 @@ MonsterStrategy } Stone Golem { + Pillar Respawns + { + Start HP Threshold = 75% + # How much HP Pct separates each triple pillar respawn. + Repeating Threshold = 10% + # How many pillars to spawn each time. Optionally, the second argument indicates how many spawn damaged. + Respawn Count = 3,2 damaged + Cast Time = 2s + Cast Delay Time = 0.5s + + Spell Circle Color = 40, 40, 40, 80 + Spell Insignia Color = 144, 137, 160, 255 + # Degrees/sec. Positive is CW, Negative is CCW. + Spell Circle Rotation Spd = -30 + # Degrees/sec. Positive is CW, Negative is CCW. + Spell Insignia Rotation Spd = 50 + } + + Beginning Phase { # Number of pillars to spawn. @@ -933,6 +952,10 @@ MonsterStrategy } Shockwave { + Start HP Threshold = 90% + # How much HP Pct separates each shockwave attack. + Repeating Threshold = 10% + Cast Time = 3s Damage = 60 Pillar Damage = 1 @@ -953,6 +976,9 @@ MonsterStrategy Break Phase 2 HP % Threshold = 34% or below Break Phase 2 Animation Name = BREAK2 + # How long until the pillar breaks. When <2 seconds remains, it starts visually shaking to indicate it is about to disappear. + Break Time = 999999s + Death Ring Bullet Count = 24 Death Ring Bullet Speed = 140 Death Ring Bullet Damage = 15 diff --git a/Adventures in Lestoria/assets/config/Monsters.txt b/Adventures in Lestoria/assets/config/Monsters.txt index 06483a70..80962db8 100644 --- a/Adventures in Lestoria/assets/config/Monsters.txt +++ b/Adventures in Lestoria/assets/config/Monsters.txt @@ -1096,6 +1096,56 @@ Monsters # Death Sound = Slime Dead # Walk Sound = Slime Walk + # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity + # DROP[0] = Ring of the Bear,100%,1,1 + } + Breaking Stone Golem Pillar + { # Has three lives and breaks once all three health is lost. Changes sprite based on health. + Health = 3 + Attack = 40 + + CollisionDmg = 0 + + Immovable = True + Invulnerable = True + + MoveSpd = 0% + # The Pillar is supposed to be 350 radius. + Size = 600% + Collision Radius = 7 + # If provided, constructs a rectangular collision instance for this enemy. + # Args: Pos X,Pos Y,Width,Height. + # NOTE: Position coordinates are relative. + Rectangle Collision = -4,-4,8,8 + + XP = 0 + + Strategy = Breaking Pillar + + ## Breaking Pillar override + Break Time = 3s + + #Size of each animation frame + SheetFrameSize = 24,96 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False + + Animations + { + # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) + # Animations must be defined in the same order as they are in their sprite sheets + # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. + NORMAL = 4, 0.4, OneShot + BREAK1 = 4, 0.4, OneShot + BREAK2 = 4, 0.4, OneShot + CRUMBLE = 6, 0.3, OneShot + } + + Hurt Sound = Warrior Ground Slam + # Death Sound = Slime Dead + # Walk Sound = Slime Walk + # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # DROP[0] = Ring of the Bear,100%,1,1 } diff --git a/Adventures in Lestoria/assets/gamepack.pak b/Adventures in Lestoria/assets/gamepack.pak deleted file mode 100644 index 24ab9b74..00000000 Binary files a/Adventures in Lestoria/assets/gamepack.pak and /dev/null differ diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index dfe9243c..139a2c5c 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ