Compare commits
80 Commits
@ -0,0 +1,113 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
#include "CppUnitTest.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "config.h" |
||||||
|
#include "ItemDrop.h" |
||||||
|
#include "Tutorial.h" |
||||||
|
#include "DamageNumber.h" |
||||||
|
#include "GameHelper.h" |
||||||
|
#include "SaveFile.h" |
||||||
|
#include <ranges> |
||||||
|
|
||||||
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework; |
||||||
|
using namespace olc::utils; |
||||||
|
|
||||||
|
INCLUDE_MONSTER_DATA |
||||||
|
INCLUDE_game |
||||||
|
INCLUDE_GFX |
||||||
|
INCLUDE_DAMAGENUMBER_LIST |
||||||
|
INCLUDE_MONSTER_LIST |
||||||
|
INCLUDE_INITIALIZEGAMECONFIGURATIONS |
||||||
|
|
||||||
|
namespace FileTests |
||||||
|
{ |
||||||
|
TEST_CLASS(FileTest) |
||||||
|
{ |
||||||
|
public: |
||||||
|
std::unique_ptr<AiL>testGame; |
||||||
|
#pragma region Setup Functions |
||||||
|
void SetupTest(){ |
||||||
|
InitializeGameConfigurations(); |
||||||
|
testGame.reset(new AiL(true)); |
||||||
|
ItemAttribute::Initialize(); |
||||||
|
ItemInfo::InitializeItems(); |
||||||
|
testGame->InitializeGraphics(); |
||||||
|
testGame->InitializeClasses(); |
||||||
|
sig::Animation::InitializeAnimations(); |
||||||
|
testGame->InitializeDefaultKeybinds(); |
||||||
|
testGame->InitializePlayer(); |
||||||
|
sig::Animation::SetupPlayerAnimations(); |
||||||
|
Menu::InitializeMenus(); |
||||||
|
Tutorial::Initialize(); |
||||||
|
Stats::InitializeDamageReductionTable(); |
||||||
|
|
||||||
|
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"]; |
||||||
|
game->_SetCurrentLevel("CAMPAIGN_1_1"); |
||||||
|
ItemDrop::ClearDrops(); |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
MonsterData testMonsterData{"TestName","Test Monster",30,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f}; |
||||||
|
MONSTER_DATA["TestName"]=testMonsterData; |
||||||
|
|
||||||
|
Menu::themes.SetInitialized(); |
||||||
|
GFX.SetInitialized(); |
||||||
|
DAMAGENUMBER_LIST.clear(); |
||||||
|
} |
||||||
|
void SetupMockMap(){ |
||||||
|
game->MAP_DATA["CAMPAIGN_1_1"]; |
||||||
|
ItemDrop::ClearDrops(); |
||||||
|
} |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
TEST_METHOD_INITIALIZE(FileTestInitialize){ |
||||||
|
SetupTest(); |
||||||
|
SetupMockMap(); |
||||||
|
} |
||||||
|
TEST_METHOD_CLEANUP(CleanupFileTests){ |
||||||
|
testGame->EndGame(); |
||||||
|
testGame->OnUserUpdate(0.f); |
||||||
|
testGame.reset(); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "Arc.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
Arc::Arc(const vf2d pos,const float radius,const float pointingAngle,const float sweepAngle) |
||||||
|
:pos(pos),radius(radius),pointingAngle(pointingAngle),sweepAngle(sweepAngle){ |
||||||
|
if(sweepAngle<0.f)ERR(std::format("WARNING! Sweep angle must be greater than or equal to 0! Provided Sweep Angle: {}",sweepAngle)); |
||||||
|
GenerateArc(); |
||||||
|
} |
||||||
|
void Arc::Draw(AiL*game,const Pixel col){ |
||||||
|
game->SetDecalStructure(DecalStructure::FAN); |
||||||
|
game->view.DrawPolygonDecal(nullptr,poly.pos,poly.pos,col); |
||||||
|
} |
||||||
|
const bool Arc::overlaps(const vf2d checkPos)const{ |
||||||
|
return geom2d::overlaps(checkPos,poly); |
||||||
|
} |
||||||
|
void Arc::GrowRadius(const float growAmt){ |
||||||
|
radius+=growAmt; |
||||||
|
GenerateArc(); |
||||||
|
} |
||||||
|
void Arc::GenerateArc(){ |
||||||
|
poly.pos.clear(); |
||||||
|
//Use cut-off point between two angles
|
||||||
|
poly.pos.emplace_back(pos); //Always add 0,0
|
||||||
|
float smallestAng{util::radToDeg(pointingAngle-sweepAngle)+90}; |
||||||
|
float largestAng{util::radToDeg(pointingAngle+sweepAngle)+90}; |
||||||
|
while(smallestAng<0.f)smallestAng+=360; |
||||||
|
while(largestAng<0.f)largestAng+=360; |
||||||
|
int startInd{int(std::fmod(smallestAng/4+1,90))}; |
||||||
|
int endInd{int(std::fmod(largestAng/4+1,90))}; |
||||||
|
if(startInd>endInd){ |
||||||
|
startInd=(startInd+3)%90; |
||||||
|
}else{ |
||||||
|
endInd=(endInd+3)%90; |
||||||
|
} |
||||||
|
for(int i=startInd;i!=endInd;i=(i+1)%game->circleCooldownPoints.size()){ |
||||||
|
poly.pos.emplace_back(pos+game->circleCooldownPoints[i]*radius); |
||||||
|
} |
||||||
|
poly.pos.emplace_back(pos); //Connect back to itself.
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include "olcUTIL_Geometry2D.h" |
||||||
|
#include "Pixel.h" |
||||||
|
|
||||||
|
class AiL; |
||||||
|
|
||||||
|
class Arc{ |
||||||
|
public: |
||||||
|
//Define a sweep angle such that each direction will arc that way. Example: PI/2 means a sweep angle from -PI/2 to PI/2. MUST BE POSITIVE
|
||||||
|
Arc(const vf2d pos,const float radius,const float pointingAngle,const float sweepAngle); |
||||||
|
void Draw(AiL*game,const Pixel col); |
||||||
|
const bool overlaps(const vf2d checkPos)const; |
||||||
|
void GrowRadius(const float growAmt); |
||||||
|
const vf2d pos; |
||||||
|
const float pointingAngle; |
||||||
|
const float sweepAngle; |
||||||
|
float radius; |
||||||
|
geom2d::polygon<float>poly; |
||||||
|
private: |
||||||
|
void GenerateArc(); |
||||||
|
}; |
@ -0,0 +1,118 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::CRAB(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
INIT, |
||||||
|
MOVE, |
||||||
|
PREPARE_CHARGE, |
||||||
|
CHARGE, |
||||||
|
}; |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case INIT:{ |
||||||
|
m.B(A::RANDOM_DIRECTION)=util::random()%2; |
||||||
|
m.F(A::RANDOM_RANGE)=util::random_range(ConfigPixelsArr("Random Direction Range",0),ConfigPixelsArr("Random Direction Range",1)); |
||||||
|
SETPHASE(MOVE); |
||||||
|
}break;
|
||||||
|
case MOVE:{ |
||||||
|
m.F(A::ATTACK_COOLDOWN)+=fElapsedTime; |
||||||
|
m.F(A::LAST_JUMP_TIMER)+=fElapsedTime; |
||||||
|
|
||||||
|
float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos()); |
||||||
|
|
||||||
|
const bool outsideMaxShootingRange=distToPlayer>=ConfigPixelsArr("Stand Still and Shoot Range",1); |
||||||
|
|
||||||
|
if(m.F(A::LAST_JUMP_TIMER)>=ConfigFloat("Stop Check Interval")){ |
||||||
|
if(util::random(100)<=ConfigFloat("Stop Percent")){ |
||||||
|
SETPHASE(PREPARE_CHARGE); |
||||||
|
m.PerformAnimation("CHARGEUP",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Charge Wait Time"); |
||||||
|
m.target=game->GetPlayer()->GetPos()+util::distance(m.GetPos(),game->GetPlayer()->GetPos())*util::pointTo(m.GetPos(),game->GetPlayer()->GetPos()); |
||||||
|
}else |
||||||
|
if(util::random(100)<=ConfigFloat("Change Direction Chance"))m.B(A::RANDOM_DIRECTION)=!m.B(A::RANDOM_DIRECTION); |
||||||
|
m.F(A::LAST_JUMP_TIMER)=0.f; |
||||||
|
}else |
||||||
|
if(outsideMaxShootingRange){ |
||||||
|
m.target=game->GetPlayer()->GetPos(); |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}else |
||||||
|
if(distToPlayer<ConfigPixels("Run Away Range")){ |
||||||
|
m.target=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).upoint(-1); |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}else |
||||||
|
if(distToPlayer>=ConfigPixelsArr("Random Direction Range",0)&&distToPlayer<ConfigPixelsArr("Random Direction Range",1)){ |
||||||
|
#define CW true |
||||||
|
#define CCW false |
||||||
|
//We are going to walk in a circular direction either CW or CCW (determined in windup phase)
|
||||||
|
float dirFromPlayer=util::angleTo(game->GetPlayer()->GetPos(),m.GetPos()); |
||||||
|
float targetDir=m.B(A::RANDOM_DIRECTION)==CW?dirFromPlayer+PI/4:dirFromPlayer-PI/4; |
||||||
|
m.target=game->GetPlayer()->GetPos()+vf2d{m.F(A::RANDOM_RANGE),targetDir}.cart(); |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards");
|
||||||
|
m.F(A::CHASE_TIMER)=1.f; |
||||||
|
} |
||||||
|
}break; |
||||||
|
case PREPARE_CHARGE:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f){ |
||||||
|
SETPHASE(CHARGE); |
||||||
|
m.F(A::CHASE_TIMER)=ConfigFloat("Charge Max Time"); |
||||||
|
m.PerformAnimation("PINCER"); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case CHARGE:{ |
||||||
|
m.F(A::CHASE_TIMER)-=fElapsedTime; |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
if(m.F(A::CHASE_TIMER)<=0.f||m.ReachedTargetPos()){ |
||||||
|
SETPHASE(MOVE); |
||||||
|
m.B(A::RANDOM_DIRECTION)=util::random()%2; |
||||||
|
m.F(A::RANDOM_RANGE)=util::random_range(ConfigPixelsArr("Random Direction Range",0),ConfigPixelsArr("Random Direction Range",1)); |
||||||
|
} |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::GIANT_CRAB(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
PREPARE_CHARGE, |
||||||
|
CHARGE, |
||||||
|
}; |
||||||
|
switch(PHASE()){ |
||||||
|
case PREPARE_CHARGE:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f){ |
||||||
|
m.AddBuff(BuffType::SPEEDBOOST,ConfigFloat("Charge Time"),0.f); |
||||||
|
m.F(A::SPEED_RAMPUP_TIMER)=0.1f; |
||||||
|
SETPHASE(CHARGE); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case CHARGE:{ |
||||||
|
m.F(A::CHASE_TIMER)+=fElapsedTime; |
||||||
|
m.F(A::SPEED_RAMPUP_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CHASE_TIMER)>=ConfigFloat("Charge Time")||m.ReachedTargetPos()){ |
||||||
|
m.F(A::CHASE_TIMER)=0.f; |
||||||
|
m.target=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).rpoint(util::distance(m.GetPos(),game->GetPlayer()->GetPos())+ConfigPixels("Charge Extend Distance")); |
||||||
|
m.RemoveBuff(BuffType::SPEEDBOOST); |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Charge Wait Time"); |
||||||
|
SETPHASE(PREPARE_CHARGE); |
||||||
|
} |
||||||
|
if(m.F(A::SPEED_RAMPUP_TIMER)<=0.f){ |
||||||
|
m.F(A::SPEED_RAMPUP_TIMER)=0.1f; |
||||||
|
if(m.HasBuff(BuffType::SPEEDBOOST)){ |
||||||
|
const float buffIntensity{m.GetBuffs(BuffType::SPEEDBOOST)[0].intensity}; |
||||||
|
m.EditBuff(BuffType::SPEEDBOOST,0).intensity=std::min(buffIntensity+ConfigFloat("Movespeed Rampup Final Amount")/100.f/(ConfigFloat("Movespeed Rampup Time")/0.1f),ConfigFloat("Movespeed Rampup Final Amount")/100.f); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
INCLUDE_MONSTER_LIST |
||||||
|
|
||||||
|
void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
IDENTIFY_ARMS, |
||||||
|
NORMAL, |
||||||
|
}; |
||||||
|
switch(PHASE()){ |
||||||
|
case IDENTIFY_ARMS:{ |
||||||
|
m.F(A::CASTING_TIMER)=util::random_range(ConfigFloatArr("Tentacle Move Timer",0),ConfigFloatArr("Tentacle Move Timer",1)); |
||||||
|
for(std::shared_ptr<Monster>&arm:MONSTER_LIST){ |
||||||
|
const std::string OCTOPUS_ARM_NAME{"Octopus Arm"}; |
||||||
|
if(arm->GetName()==OCTOPUS_ARM_NAME){ |
||||||
|
std::weak_ptr<Monster>armPtr{arm}; |
||||||
|
m.VEC(A::ARM_LIST).emplace_back(armPtr); |
||||||
|
m.VEC(A::ARM_LOCATIONS).emplace_back(armPtr.lock()->GetPos()); |
||||||
|
} |
||||||
|
} |
||||||
|
}break; |
||||||
|
case NORMAL:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f){ |
||||||
|
int deadMonsterCount{0}; |
||||||
|
std::vector<vf2d>tempArmLocs; |
||||||
|
for(size_t i=0U;std::any&arm:m.VEC(A::ARM_LIST)){ |
||||||
|
const std::weak_ptr<Monster>&m{std::any_cast<std::weak_ptr<Monster>>(arm)}; |
||||||
|
if(m.expired()||m.lock()->IsDead()){ |
||||||
|
deadMonsterCount++; |
||||||
|
tempArmLocs.emplace_back(std::any_cast<vf2d>(m.lock()->VEC(A::ARM_LOCATIONS))); |
||||||
|
} |
||||||
|
} |
||||||
|
if(deadMonsterCount>0){ |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
INCLUDE_ITEM_SCRIPTS |
||||||
|
INCLUDE_game |
||||||
|
INCLUDE_ANIMATION_DATA |
||||||
|
|
||||||
|
void ItemInfo::InitializeScripts(){ |
||||||
|
|
||||||
|
ITEM_SCRIPTS["Restore"]=[](AiL*game,std::optional<vf2d>targetingPos,ItemProps props){ |
||||||
|
for(const auto&[propName,buffType]:NameToBuffType){ |
||||||
|
int restoreAmt=props.GetInt(propName); |
||||||
|
|
||||||
|
game->GetPlayer()->AddBuff(BuffRestorationType::ONE_OFF,NameToBuffType.at(propName),0.01f,float(restoreAmt),0.0f); |
||||||
|
if(restoreAmt>0&&props.PropCount(propName)==3){ |
||||||
|
game->GetPlayer()->AddBuff(BuffRestorationType::OVER_TIME,NameToBuffType.at(propName),props.GetFloat(propName,2),float(restoreAmt),props.GetFloat(propName,1)); |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
}; |
||||||
|
|
||||||
|
for(auto&[key,value]:ItemAttribute::attributes){ |
||||||
|
if(!DATA.GetProperty("ItemScript.Buff").HasProperty(key)){ |
||||||
|
ERR("WARNING! Buff Item Script does not support Buff "<<std::quoted(value.Name())<<"!"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ITEM_SCRIPTS["Buff"]=[](AiL*game,std::optional<vf2d>targetingPos,ItemProps props){ |
||||||
|
for(auto&[key,value]:ItemAttribute::attributes){ |
||||||
|
float intensity=props.GetFloat(key,0); |
||||||
|
if(intensity==0.f)continue; |
||||||
|
if(ItemAttribute::Get(key).DisplayAsPercent())intensity/=100; |
||||||
|
game->GetPlayer()->AddBuff(BuffType::STAT_UP,props.GetFloat(key,1),intensity,{ItemAttribute::Get(key)}); |
||||||
|
} |
||||||
|
return true; |
||||||
|
}; |
||||||
|
ITEM_SCRIPTS["RestoreDuringCast"]=[](AiL*game,std::optional<vf2d>targetingPos,ItemProps props){ |
||||||
|
for(const auto&[propName,buffType]:NameToBuffType){ |
||||||
|
int restoreAmt=props.GetInt(propName); |
||||||
|
|
||||||
|
game->GetPlayer()->AddBuff(BuffRestorationType::ONE_OFF,NameToBuffType.at(propName),0.01f,float(restoreAmt),0.0f); |
||||||
|
if(restoreAmt>0&&props.PropCount(propName)==3){ |
||||||
|
game->GetPlayer()->AddBuff(BuffRestorationType::OVER_TIME_DURING_CAST,NameToBuffType.at(propName),props.GetFloat(propName,2),float(restoreAmt),props.GetFloat(propName,1)); |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
}; |
||||||
|
ITEM_SCRIPTS["Projectile"]=[](AiL*game,std::optional<vf2d>targetingPos,ItemProps props){ |
||||||
|
const int projectileDamage{props.GetInt("Base Damage")+int(game->GetPlayer()->GetAttack()*props.GetFloat("Player Damage Mult"))}; |
||||||
|
std::optional<LingeringEffect>lingeringEffect{}; |
||||||
|
if(props.GetFloat("Linger Time")>0.f){ |
||||||
|
const int damage{props.GetInt("Tick Base Damage")+int(props.GetFloat("Tick Player Damage Mult")*game->GetPlayer()->GetAttack())}; |
||||||
|
lingeringEffect.emplace(vf2d{},props.GetString("Lingering Effect"),props.GetString("Lingering Sound"),props.GetFloat("Linger Radius")/100.f*24,damage,props.GetFloat("Tick Rate"),HurtType::MONSTER,props.GetFloat("Linger Time"),5.f,game->GetPlayer()->OnUpperLevel(),1.f,vf2d{},DARK_RED,util::random(2*PI),0.f,false,0.2f, |
||||||
|
[](const Effect&self){ |
||||||
|
return Effect{self.pos,0.5f,"fire_ring.png",self.OnUpperLevel(),util::random_range(0.7f,1.f),0.1f,{},PixelLerp(Pixel(0xF7B752),Pixel(0xE74F30),util::random(1.f)),util::random(2*PI),0.f,true}; |
||||||
|
}); |
||||||
|
} |
||||||
|
CreateBullet(ThrownProjectile)(game->GetPlayer()->GetPos(),targetingPos.value(),props.GetString("Image"),props.GetFloat("Cast Size")/100.f*24,game->GetPlayer()->GetZ(),0.3f,8.f,projectileDamage,game->GetPlayer()->OnUpperLevel(),false,INFINITE,true,WHITE,props.GetFloat("Cast Size")/100.f*vf2d{1.f,1.f},0.f, |
||||||
|
Effect{vf2d{},ANIMATION_DATA.at("explosionframes.png").GetTotalAnimationDuration(),"explosionframes.png",game->GetPlayer()->OnUpperLevel(),props.GetFloat("Cast Size")/100.f*vf2d{1.f,1.f}},props.GetString("Explode Sound Effect"),lingeringEffect)EndBullet; |
||||||
|
return true; |
||||||
|
}; |
||||||
|
|
||||||
|
ITEM_SCRIPTS.SetInitialized(); |
||||||
|
LOG(ITEM_SCRIPTS.size()<<" item scripts have been loaded."); |
||||||
|
} |
@ -0,0 +1,179 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
#include "Arc.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
INCLUDE_MONSTER_LIST |
||||||
|
INCLUDE_MONSTER_DATA |
||||||
|
|
||||||
|
void Monster::STRATEGY::OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
INIT, |
||||||
|
RISE_ANIMATION, |
||||||
|
SEARCH, |
||||||
|
PREPARE_ATTACK, |
||||||
|
ATTACK_ANIMATION, |
||||||
|
ATTACK_RECOVERY, |
||||||
|
SUBMERGE, |
||||||
|
}; |
||||||
|
|
||||||
|
const auto GetAttackArc=[attackRadius=ConfigFloat("Attack Radius"),attackArc=ConfigFloat("Attack Arc")](const Monster&m){ |
||||||
|
return Arc{m.GetPos(),attackRadius/100.f*24,util::dirToAngle(m.GetFacingDirection()),util::degToRad(attackArc)}; |
||||||
|
}; |
||||||
|
|
||||||
|
if(m.ANY(A::STORED_ARC).has_value()){ |
||||||
|
game->DrawShadowStringDecal({100,100},std::format("Stored Arc Active: {}",std::any_cast<Arc>(m.ANY(A::STORED_ARC)).pos.str())); |
||||||
|
const float growthRate=((ConfigFloat("Attack Radius")/100.f*24)/ConfigFloat("Attack Effect Time"))*fElapsedTime; |
||||||
|
std::any_cast<Arc>(m.ANY(A::STORED_ARC)).GrowRadius(growthRate); |
||||||
|
m.F(A::ENVIRONMENT_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::ENVIRONMENT_TIMER)<=0.f)m.ANY(A::STORED_ARC).reset(); |
||||||
|
} |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case INIT:{ |
||||||
|
if(ConfigFloat("Attack Swing Damage Wait Time")>m.GetAnimation("ATTACKING").GetTotalAnimationDuration())ERR(std::format("The Attack Swing Damage Wait Time ({}s) should not be greater than the total attack time animation duration! ({}s)",ConfigFloat("Attack Swing Damage Wait Time"),m.GetAnimation("ATTACKING").GetTotalAnimationDuration())); |
||||||
|
m.PerformAnimation("RISE",game->GetPlayer()->GetPos()); |
||||||
|
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
SETPHASE(RISE_ANIMATION); |
||||||
|
m.SetStrategyDeathFunction([bossDamageOnDeath=ConfigInt("Boss Damage On Death")](GameEvent&event,Monster&m,const StrategyName&strategyName){ |
||||||
|
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){}); |
||||||
|
const std::string GIANT_OCTOPUS_NAME{"Giant Octopus"}; |
||||||
|
const std::string OCTOPUS_ARM_NAME{"Octopus Arm"}; |
||||||
|
|
||||||
|
if(!MONSTER_DATA.count(GIANT_OCTOPUS_NAME))ERR(std::format("WARNING! {} does not exist on the map! THIS SHOULD NOT BE HAPPENING!",GIANT_OCTOPUS_NAME)); |
||||||
|
|
||||||
|
auto boss{std::find_if(MONSTER_LIST.begin(),MONSTER_LIST.end(),[&GIANT_OCTOPUS_NAME](const std::shared_ptr<Monster>&m){ |
||||||
|
return m->GetName()==GIANT_OCTOPUS_NAME; |
||||||
|
})}; |
||||||
|
if(boss!=MONSTER_LIST.end()){ |
||||||
|
Monster&bossMonster{**boss}; |
||||||
|
bossMonster.Hurt(bossDamageOnDeath,m.OnUpperLevel(),m.GetZ()); |
||||||
|
} |
||||||
|
std::for_each(MONSTER_LIST.begin(),MONSTER_LIST.end(),[&OCTOPUS_ARM_NAME,&strategyName](const std::shared_ptr<Monster>&m){ |
||||||
|
if(m->GetName()==OCTOPUS_ARM_NAME){ |
||||||
|
m->PerformAnimation("SUBMERGE"); |
||||||
|
m->SetPhase(strategyName,SUBMERGE); |
||||||
|
m->GetFloat(A::RECOVERY_TIME)=m->GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
} |
||||||
|
}); |
||||||
|
return false; |
||||||
|
}); |
||||||
|
}break; |
||||||
|
case RISE_ANIMATION:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f){ |
||||||
|
m.PerformAnimation("IDLE",game->GetPlayer()->GetPos()); |
||||||
|
SETPHASE(SEARCH); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case SEARCH:{ |
||||||
|
if(util::distance(m.GetPos(),game->GetPlayer()->GetPos())<=ConfigFloat("Attack Radius")/100.f*24){ |
||||||
|
SETPHASE(PREPARE_ATTACK); |
||||||
|
|
||||||
|
m.F(A::ATTACK_COOLDOWN)=util::random_range(ConfigFloatArr("Attack Wiggle Time Range",0),ConfigFloatArr("Attack Wiggle Time Range",1)); |
||||||
|
m.PerformAnimation("ATTACK",game->GetPlayer()->GetPos()); |
||||||
|
|
||||||
|
Arc attackArc{GetAttackArc(m)}; |
||||||
|
|
||||||
|
m.SetStrategyDrawFunction([arc=attackArc,&storedArc=m.ANY(A::STORED_ARC),&alphaTimer=m.F(A::ENVIRONMENT_TIMER),attackEffectTime=ConfigFloat("Attack Effect Time")](AiL*game,Monster&monster,const std::string&strategy){ |
||||||
|
const float alphaTimer{float(std::fmod(game->GetRunTime(),2.f))}; |
||||||
|
uint8_t alpha{util::lerp(uint8_t(0),uint8_t(255),alphaTimer)}; |
||||||
|
if(alphaTimer>1.f)alpha=util::lerp(0,255,1-(alphaTimer-1)); |
||||||
|
const_cast<Arc&>(arc).Draw(game,{0,0,255,uint8_t(alpha)}); |
||||||
|
if(storedArc.has_value()){ |
||||||
|
const uint8_t effectAlpha{util::lerp(uint8_t(0),uint8_t(255),alphaTimer/attackEffectTime)}; |
||||||
|
std::any_cast<Arc>(storedArc).Draw(game,{255,255,255,effectAlpha}); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case PREPARE_ATTACK:{ |
||||||
|
m.F(A::ATTACK_COOLDOWN)-=fElapsedTime; |
||||||
|
if(m.F(A::ATTACK_COOLDOWN)<=0.f){ |
||||||
|
SETPHASE(ATTACK_ANIMATION); |
||||||
|
m.PerformAnimation("ATTACKING"); |
||||||
|
m.F(A::ENVIRONMENT_TIMER)=m.F(A::RECOVERY_TIME)=ConfigFloat("Attack Effect Time"); |
||||||
|
m.F(A::SWING_OCCURRED)=ConfigFloat("Attack Swing Damage Wait Time"); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case ATTACK_ANIMATION:{ |
||||||
|
m.F(A::SWING_OCCURRED)-=fElapsedTime; |
||||||
|
if(m.F(A::SWING_OCCURRED)<=0.f){ |
||||||
|
Arc attackArc{GetAttackArc(m)}; |
||||||
|
if(attackArc.overlaps(game->GetPlayer()->GetPos())){ |
||||||
|
game->GetPlayer()->Knockback(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Attack Knockback")); |
||||||
|
game->GetPlayer()->Hurt(m.GetAttack(),m.OnUpperLevel(),m.GetZ()); |
||||||
|
} |
||||||
|
m.F(A::RECOVERY_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
m.ANY(A::STORED_ARC)=GetAttackArc(m); |
||||||
|
m.SetStrategyDrawFunction([&storedArc=m.ANY(A::STORED_ARC),attackEffectTime=ConfigFloat("Attack Effect Time")](AiL*game,Monster&monster,const std::string&strategy){ |
||||||
|
const float alphaTimer{float(std::fmod(game->GetRunTime(),2.f))}; |
||||||
|
if(storedArc.has_value()){ |
||||||
|
const uint8_t effectAlpha{util::lerp(uint8_t(0),uint8_t(255),alphaTimer/attackEffectTime)}; |
||||||
|
std::any_cast<Arc>(storedArc).Draw(game,{255,255,255,effectAlpha}); |
||||||
|
} |
||||||
|
}); |
||||||
|
SETPHASE(ATTACK_RECOVERY); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case ATTACK_RECOVERY:{ |
||||||
|
m.F(A::RECOVERY_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::RECOVERY_TIME)<=0.f){ |
||||||
|
m.PerformIdleAnimation(); |
||||||
|
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){}); |
||||||
|
SETPHASE(SEARCH); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case SUBMERGE:{ |
||||||
|
m.F(A::RECOVERY_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::RECOVERY_TIME)<=0.f){ |
||||||
|
m.PerformAnimation("RISE"); |
||||||
|
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
SETPHASE(RISE_ANIMATION); |
||||||
|
} |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
Giant Octopus |
||||||
|
42000 HP |
||||||
|
Boss boss has a permanent 80% DMG reduction. |
||||||
|
|
||||||
|
Tentacle |
||||||
|
6000 HP |
||||||
|
When a Tentacle dies boss takes 6000 Dmg |
||||||
|
There are 8 Tentacles |
||||||
|
|
||||||
|
Base Damage |
||||||
|
Bullets: 40 |
||||||
|
Big bullet: 90 |
||||||
|
Tentacle: 50 |
||||||
|
|
||||||
|
Attack moves |
||||||
|
- Boss shots 1 bullet every second |
||||||
|
- Every 6. Shot Boss Shots a big bullet that explodes when i gets close to the Player and form a new ring of bullets flying away in a whirl instead of a straight line. (Boss rests for 2 seconds after big bullet) |
||||||
|
- Tentacels do a delayed attack |
||||||
|
- Every Tentacle and the boss get a 10% Attack buff on each Tentacle death |
||||||
|
|
||||||
|
Tentacles: |
||||||
|
- The Tentacles wiggle a bit around between attacks |
||||||
|
- Wiggle phase is 2-4 seconds. |
||||||
|
- Tentacle stopps moving for 1 sec before attacking, already indicating where it will attack. |
||||||
|
- The Tentacle rest on the floor for a short period after an attack ~1 sec (can vary a bit depending how animation looks smoother) |
||||||
|
- The Tentacle attacks with its entire wheight slaming the position where the player was when the movement stopped. |
||||||
|
|
||||||
|
Reference for Tentacle attack https://youtu.be/YtR521QdsNk?si=_TUxuH-3HLnwr_t9&t=475 (Should start at time stamp 07:55 with a bossfight) |
||||||
|
Instead of wiggling around the tentacles supmerge here in between attacks. |
||||||
|
Also instead of this piercing attack i would prefer if its closer to a slam. |
||||||
|
But i really like how the tentacle indicates that its about to attack in a specific direction. |
||||||
|
|
||||||
|
|
||||||
|
Phases |
||||||
|
12k missing Health on boss: |
||||||
|
- boss starts Shooting an Ink Bubble instead of a normal projectile every 15 seconds that explodes and leaves an ink area Lasting for 30 seconds. moving into the ink gives a -10 movespd debuff for 25 seconds. |
||||||
|
- 6 Attacks after first ink attack, every second small bullet has a different Color and has a homing effect. Homing effect is greatly reduced if Player is covered in ink |
||||||
|
|
||||||
|
30k missing Health |
||||||
|
Tentacles get +10% Speed on every animation or attack |
||||||
|
every Projectile get the homing effect |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
other stuff |
||||||
|
- On Tentacle death, all Tentacles submerge and recover 1k hp each. after 3 seconds tentacles ascend again one after another 0.25 seconds delay between each Tentacle |
||||||
|
Once the first Tentacle got defeated every 15-25 seconds a Tentacle far away from the Player submerges and appear 2 seconds later again in an area close to the Player, (Only Triggers if there is a free Tentacle spawn close to the Player) |
||||||
|
|
||||||
|
also: technically the limps of an Octopus arent called Tentacles... but whatever, dont feel like changing this in the entire document now. |
@ -0,0 +1,74 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::PARROT(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
RUN, |
||||||
|
FLY_AWAY, |
||||||
|
}; |
||||||
|
switch(PHASE()){ |
||||||
|
case RUN:{ |
||||||
|
if(!m.attachedTarget.expired()&&m.attachedTarget.lock()->IsAlive()){ |
||||||
|
m.PerformAnimation("FLYING"); |
||||||
|
HAWK(m,fElapsedTime,"Hawk"); |
||||||
|
}else{ |
||||||
|
m.lifetime=10.f; |
||||||
|
SETPHASE(FLY_AWAY); |
||||||
|
m.F(A::PATH_DIR)=1.f; |
||||||
|
if(util::random(1.f)<0.5f)m.F(A::PATH_DIR)=-1.f; |
||||||
|
m.manualIgnoreTerrain=true; |
||||||
|
} |
||||||
|
}break; |
||||||
|
case FLY_AWAY:{ |
||||||
|
if(m.F(A::PATH_DIR)>0.f)m.PerformAnimation("FLYING",Direction::EAST); |
||||||
|
else m.PerformAnimation("FLYING",Direction::WEST); |
||||||
|
m.z+=fElapsedTime*ConfigFloat("Fly Away Z Speed"); |
||||||
|
m.SetVelocity({m.F(A::PATH_DIR)*ConfigFloat("Fly Away Speed"),0.f}); |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,118 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::PIRATE_BUCCANEER(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
#pragma region Phase, Animation, and Helper function setup |
||||||
|
enum PhaseName{ |
||||||
|
MOVE, |
||||||
|
LOCKON, |
||||||
|
WINDUP, |
||||||
|
FIRE_ANIMATION, |
||||||
|
}; |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case MOVE:{ |
||||||
|
m.F(A::ATTACK_COOLDOWN)+=fElapsedTime; |
||||||
|
|
||||||
|
float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos()); |
||||||
|
|
||||||
|
const bool outsideMaxShootingRange=distToPlayer>=ConfigPixelsArr("Stand Still and Shoot Range",1); |
||||||
|
|
||||||
|
auto PrepareToShoot=[&](){ |
||||||
|
SETPHASE(WINDUP); |
||||||
|
m.F(A::SHOOT_TIMER)=ConfigFloat("Attack Windup Time"); |
||||||
|
m.PerformAnimation("SHOOT",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
}; |
||||||
|
|
||||||
|
if(outsideMaxShootingRange){ |
||||||
|
m.target=game->GetPlayer()->GetPos(); |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}else |
||||||
|
if(m.F(A::ATTACK_COOLDOWN)>=ConfigFloat("Attack Reload Time")){ |
||||||
|
PrepareToShoot(); |
||||||
|
}else |
||||||
|
if(distToPlayer<ConfigPixels("Run Away Range")){ |
||||||
|
m.target=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).upoint(-1); |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}else |
||||||
|
if(m.F(A::ATTACK_COOLDOWN)>=ConfigFloat("Attack Reload Time")/2.f){ //Only the stand still and shoot range remains, which is twice as fast...
|
||||||
|
PrepareToShoot(); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case WINDUP:{ |
||||||
|
m.F(A::SHOOT_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::SHOOT_TIMER)<=0){
|
||||||
|
m.F(A::ATTACK_COOLDOWN)=0.f; |
||||||
|
CreateBullet(ChargedArrow)("musket_bullet.png","musket_trail.png",m.GetPos(),util::pointTo(m.GetPos(),m.V(A::LOCKON_POS))*ConfigFloat("Arrow Spd"),ConfigFloat("Arrow Hitbox Radius"),m.GetAttack(),m.OnUpperLevel())EndBullet; |
||||||
|
m.PerformAnimation("SHOOTING",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){}); |
||||||
|
SETPHASE(FIRE_ANIMATION); |
||||||
|
m.F(A::SHOOT_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
}else |
||||||
|
if(m.F(A::SHOOT_TIMER)>=ConfigFloat("Attack Lockon Time")){ |
||||||
|
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos(); |
||||||
|
m.PerformAnimation("SHOOT",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
const float arrowHitboxRadius{ConfigFloat("Arrow Hitbox Radius")}; |
||||||
|
m.SetStrategyDrawFunction([arrowHitboxRadius](AiL*game,Monster&monster,const std::string&strategy){ |
||||||
|
vf2d midpoint{geom2d::line<float>(monster.GetPos(),monster.V(A::LOCKON_POS)).rpoint(800.f)}; |
||||||
|
float shootingAngle{util::angleTo(monster.GetPos(),monster.V(A::LOCKON_POS))+PI/2}; |
||||||
|
vf2d imgSize{arrowHitboxRadius*2.f,800.f}; |
||||||
|
game->view.DrawPartialRotatedDecal(midpoint,GFX["line_indicator.png"].Decal(),shootingAngle,GFX["line_indicator.png"].Sprite()->Size()/2,{},GFX["line_indicator.png"].Sprite()->Size(),imgSize/GFX["line_indicator.png"].Sprite()->Size()); |
||||||
|
}); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case FIRE_ANIMATION:{ |
||||||
|
m.F(A::SHOOT_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::SHOOT_TIMER)<=0.f){ |
||||||
|
m.PerformAnimation("IDLE",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
SETPHASE(MOVE); |
||||||
|
} |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,183 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
INCLUDE_ANIMATION_DATA |
||||||
|
|
||||||
|
void Monster::STRATEGY::PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
INIT, |
||||||
|
MOVE, |
||||||
|
PREPARE_SHOOT, |
||||||
|
SHOOT_RELOAD, |
||||||
|
DRINK_RUM, |
||||||
|
WINDUP, |
||||||
|
RECOVERY, |
||||||
|
}; |
||||||
|
|
||||||
|
enum AttackType{ |
||||||
|
STAB, |
||||||
|
SLASH |
||||||
|
}; |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case INIT:{ |
||||||
|
m.F(A::TARGET_TIMER)=ConfigFloat("Shooting Frequency"); |
||||||
|
m.F(A::PARROT_FLY_TIMER)=ConfigFloat("Parrot Fly Wait Time"); |
||||||
|
m.mounted_animation=Animate2D::Animation<std::string>{}; |
||||||
|
for(bool firstAnimation=true;const std::string&animation:Config("Imposed Monster Animations").GetValues()){ |
||||||
|
m.mounted_animation.value().AddState(animation,ANIMATION_DATA.at(animation)); |
||||||
|
|
||||||
|
if(firstAnimation)m.mounted_animation.value().ChangeState(m.internal_mounted_animState,animation); |
||||||
|
firstAnimation=false; |
||||||
|
} |
||||||
|
m.mountedSprOffset=ConfigVec("Imposed Monster Offset"); |
||||||
|
m.deathData.emplace_back(ConfigString("Spawned Monster"),1U); |
||||||
|
SETPHASE(MOVE); |
||||||
|
}break; |
||||||
|
case MOVE:{ |
||||||
|
if(m.F(A::PARROT_FLY_TIMER)>0.f){ |
||||||
|
m.F(A::PARROT_FLY_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::PARROT_FLY_TIMER)<=0.f){ |
||||||
|
m.mounted_animation.reset(); |
||||||
|
Monster&parrot{game->SpawnMonster(m.GetPos(),MONSTER_DATA.at("Parrot"),m.OnUpperLevel())}; |
||||||
|
parrot.attachedTarget=m.GetWeakPointer(); |
||||||
|
} |
||||||
|
} |
||||||
|
m.F(A::TARGET_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::TARGET_TIMER)<=0.f){ |
||||||
|
const float diceRoll{util::random(100)}; |
||||||
|
if(diceRoll<=ConfigFloat("Shooting Chance")){ |
||||||
|
const float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())}; |
||||||
|
if(distToPlayer<=ConfigFloat("Shoot Max Range")/100.f*24){ |
||||||
|
m.F(A::SHOOT_TIMER)=ConfigFloat("Shooting Delay"); |
||||||
|
SETPHASE(PREPARE_SHOOT); |
||||||
|
m.PerformAnimation("SHOOT",game->GetPlayer()->GetPos()); |
||||||
|
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos(); |
||||||
|
} |
||||||
|
} |
||||||
|
m.F(A::TARGET_TIMER)=ConfigFloat("Shooting Frequency"); |
||||||
|
}else |
||||||
|
if(m.GetHealth()<ConfigInt("Rum Drink Threshold")&&m.I(A::RUM_DRINK_COUNT)<ConfigInt("Rum Drink Count")){ |
||||||
|
m.PerformAnimation("DRINK"); |
||||||
|
m.F(A::BREAK_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
SETPHASE(DRINK_RUM); |
||||||
|
m.I(A::RUM_DRINK_COUNT)++; |
||||||
|
} |
||||||
|
else{ |
||||||
|
float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos()); |
||||||
|
if(distToPlayer>ConfigFloat("Attack Spacing")/100.f*24){ |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}else{ |
||||||
|
SETPHASE(WINDUP); |
||||||
|
m.I(A::ATTACK_TYPE)=util::random()%2; //Choose randomly between stab or slash.
|
||||||
|
switch(m.I(A::ATTACK_TYPE)){ |
||||||
|
case STAB:{ |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Stab Windup Time"); |
||||||
|
m.PerformAnimation("STAB",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
}break; |
||||||
|
case SLASH:{ |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Slash Windup Time"); |
||||||
|
m.PerformAnimation("SLASH",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
}break; |
||||||
|
default:ERR(std::format("WARNING! Invalid Attack type {} provided. THIS SHOULD NOT BE HAPPENING!",m.I(A::ATTACK_TYPE))); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}break; |
||||||
|
case PREPARE_SHOOT:{ |
||||||
|
m.F(A::SHOOT_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::SHOOT_TIMER)<=0.f){ |
||||||
|
CreateBullet(Bullet)(m.GetPos(),util::pointTo(m.GetPos(),m.V(A::LOCKON_POS))*ConfigFloat("Bullet Speed"),ConfigFloat("Bullet Radius"),m.GetAttack(),m.OnUpperLevel(),false,ConfigPixel("Bullet Color"),vf2d{1.f,1.f}*ConfigFloat("Bullet Radius")/3.f)EndBullet; |
||||||
|
m.PerformAnimation("SHOOTING"); |
||||||
|
m.F(A::SHOOT_ANIMATION_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
SETPHASE(SHOOT_RELOAD); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case SHOOT_RELOAD:{ |
||||||
|
m.F(A::SHOOT_ANIMATION_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::SHOOT_ANIMATION_TIME)<=0.f){ |
||||||
|
m.PerformAnimation("IDLE"); |
||||||
|
SETPHASE(MOVE); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case DRINK_RUM:{ |
||||||
|
m.F(A::BREAK_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::BREAK_TIME)<=0.f){ |
||||||
|
m.Heal(ConfigInt("Rum Health Recovery"),true); |
||||||
|
SETPHASE(MOVE); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case WINDUP:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0){ |
||||||
|
SETPHASE(RECOVERY); |
||||||
|
switch(m.I(A::ATTACK_TYPE)){ |
||||||
|
case STAB:{ |
||||||
|
vf2d stabTarget=game->GetPlayer()->GetPos(); |
||||||
|
m.PerformAnimation("STABBING"); |
||||||
|
CreateBullet(DaggerStab)(m,ConfigString("Dagger Stab Image"),ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Stab Knockback"),m.OnUpperLevel(),m.GetFacingDirection(),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Stab Distance"), |
||||||
|
DaggerStab::DirectionOffsets{ConfigVec("Dagger Up Offset"),ConfigVec("Dagger Down Offset"),ConfigVec("Dagger Right Offset"),ConfigVec("Dagger Left Offset")})EndBullet; |
||||||
|
}break; |
||||||
|
case SLASH:{ |
||||||
|
vf2d slashTarget=game->GetPlayer()->GetPos(); |
||||||
|
m.PerformAnimation("SLASHING"); |
||||||
|
CreateBullet(DaggerSlash)(m,ConfigString("Dagger Slash Image"),ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Slash Knockback"),m.OnUpperLevel(),m.GetFacingDirection(),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Slash Distance"))EndBullet; |
||||||
|
}break; |
||||||
|
default:ERR(std::format("WARNING! Invalid Attack type {} provided. THIS SHOULD NOT BE HAPPENING!",m.I(A::ATTACK_TYPE))); |
||||||
|
} |
||||||
|
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
m.F(A::RECOVERY_TIME)=ConfigFloat("Attack Recovery Time"); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case RECOVERY:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
m.F(A::RECOVERY_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0){m.PerformIdleAnimation(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));} |
||||||
|
if(m.F(A::RECOVERY_TIME)<=0)SETPHASE(MOVE); |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,175 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::PIRATE_MARAUDER(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
INIT, |
||||||
|
MOVE, |
||||||
|
WINDUP, |
||||||
|
RECOVERY, |
||||||
|
LEAP, |
||||||
|
PREPARE_WHIRLWIND, |
||||||
|
WHIRLWIND, |
||||||
|
}; |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case INIT:{ |
||||||
|
m.F(A::CHASE_TIMER)=ConfigFloat("Ability Choose Timer"); |
||||||
|
SETPHASE(MOVE); |
||||||
|
}break; |
||||||
|
case MOVE:{ |
||||||
|
float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos()); |
||||||
|
|
||||||
|
m.F(A::CHASE_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CHASE_TIMER)<=0.f){ |
||||||
|
m.I(A::ABILITY_COUNT)++; |
||||||
|
m.F(A::CHASE_TIMER)=ConfigFloat("Ability Choose Timer"); |
||||||
|
} |
||||||
|
|
||||||
|
if(m.I(A::ABILITY_COUNT)>0){ |
||||||
|
float roll{util::random_range(0.f,100.f)}; |
||||||
|
float distanceToPlayer{util::distance(m.GetPos(),game->GetPlayer()->GetPos())}; |
||||||
|
std::pair<float,float>jumpAttackRollRange{0.f,ConfigFloat("Jump Attack Chance")}; |
||||||
|
std::pair<float,float>whirlwindAttackRollRange{jumpAttackRollRange.second,jumpAttackRollRange.second+ConfigFloat("Whirlwind Attack Chance")}; |
||||||
|
|
||||||
|
if(roll<jumpAttackRollRange.second&&distanceToPlayer>=ConfigFloatArr("Jump Attack Ranges",0)/100.f*24.f&&distanceToPlayer<=ConfigFloatArr("Jump Attack Ranges",1)/100.f*24.f){ |
||||||
|
SETPHASE(LEAP); |
||||||
|
m.V(A::JUMP_TARGET_POS)=game->GetPlayer()->GetPos(); |
||||||
|
m.I(A::ABILITY_COUNT)--; |
||||||
|
const float impactArea{ConfigFloat("Jump Attack Impact Area")}; |
||||||
|
m.SetStrategyDrawFunction([impactArea](AiL*game,Monster&monster,const std::string&strategy){ |
||||||
|
game->view.DrawRotatedDecal(monster.V(A::JUMP_TARGET_POS),GFX["range_indicator.png"].Decal(),0.f,GFX["range_indicator.png"].Sprite()->Size()/2.f,vf2d{1,1}*(impactArea/100.f),{255,0,0,96}); |
||||||
|
}); |
||||||
|
m.F(A::JUMP_MOVE_TO_TARGET_TIMER)=0.f; |
||||||
|
m.V(A::PREV_POS)=m.GetPos(); |
||||||
|
m.PerformAnimation("LEAPING",m.V(A::JUMP_TARGET_POS)); |
||||||
|
break; |
||||||
|
}else |
||||||
|
if(roll>=whirlwindAttackRollRange.first&&roll<whirlwindAttackRollRange.second |
||||||
|
&&distanceToPlayer>=ConfigFloatArr("Whirlwind Attack Ranges",0)/100.f*24.f&&distanceToPlayer<=ConfigFloatArr("Whirlwind Attack Ranges",1)/100.f*24.f){ |
||||||
|
SETPHASE(PREPARE_WHIRLWIND); |
||||||
|
m.I(A::ABILITY_COUNT)--; |
||||||
|
vf2d aimingTarget{game->GetPlayer()->GetPos()}; |
||||||
|
if(aimingTarget==m.GetPos()){ //Handle edge case.
|
||||||
|
aimingTarget=m.GetPos()+vf2d{1.f,util::random(2*PI)}.cart(); |
||||||
|
} |
||||||
|
m.V(A::PATH_DIR)=util::pointTo(m.GetPos(),aimingTarget); |
||||||
|
m.PerformAnimation("SPIN",m.V(A::LOCKON_POS)); |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Whirlwind Chargeup Time"); |
||||||
|
m.AddBuff(BuffType::SPEEDBOOST,ConfigFloat("Whirlwind Spin Time"),ConfigFloat("Whirlwind Bonus Movespd")/100.f); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
NormalBehavior: |
||||||
|
if(distToPlayer>ConfigFloat("Attack Spacing")/100.f*24){ |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
}else{ |
||||||
|
SETPHASE(WINDUP); |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Slash Windup Time"); |
||||||
|
m.PerformAnimation("SLASH",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case WINDUP:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0){ |
||||||
|
SETPHASE(RECOVERY); |
||||||
|
vf2d slashTarget=game->GetPlayer()->GetPos(); |
||||||
|
m.PerformAnimation("SLASHING",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); |
||||||
|
CreateBullet(DaggerSlash)(m,ConfigString("Dagger Slash Image"),ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Slash Knockback"),m.OnUpperLevel(),m.GetFacingDirectionToTarget(slashTarget),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Slash Distance"))EndBullet; |
||||||
|
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
m.F(A::RECOVERY_TIME)=ConfigFloat("Attack Recovery Time"); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case RECOVERY:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
m.F(A::RECOVERY_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0){m.PerformIdleAnimation(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));} |
||||||
|
if(m.F(A::RECOVERY_TIME)<=0)SETPHASE(MOVE); |
||||||
|
}break; |
||||||
|
case LEAP:{ |
||||||
|
m.F(A::JUMP_MOVE_TO_TARGET_TIMER)+=fElapsedTime; |
||||||
|
const float halfJumpTime{ConfigFloat("Jump Attack Duration")/2.f}; |
||||||
|
if(m.F(A::JUMP_MOVE_TO_TARGET_TIMER)<halfJumpTime)m.SetZ(util::smoothstep(0,ConfigFloat("Jump Attack Height"),m.F(A::JUMP_MOVE_TO_TARGET_TIMER)/halfJumpTime)); |
||||||
|
else m.SetZ(util::smoothstep(ConfigFloat("Jump Attack Height"),0,(m.F(A::JUMP_MOVE_TO_TARGET_TIMER)-halfJumpTime)/halfJumpTime)); |
||||||
|
m.SetPos(m.V(A::PREV_POS).lerp(m.V(A::JUMP_TARGET_POS),m.F(A::JUMP_MOVE_TO_TARGET_TIMER)/ConfigFloat("Jump Attack Duration"))); |
||||||
|
if(m.F(A::JUMP_MOVE_TO_TARGET_TIMER)>=ConfigFloat("Jump Attack Duration")){ |
||||||
|
SoundEffect::PlaySFX("Leap Land",m.GetPos()); |
||||||
|
game->Hurt(m.GetPos(),ConfigFloat("Jump Attack Impact Area")/100.f*24.f,m.GetAttack(),m.OnUpperLevel(),m.GetZ(),HurtType::PLAYER); |
||||||
|
game->ProximityKnockback(m.GetPos(),ConfigFloat("Jump Attack Impact Area")/100.f*24.f,ConfigFloat("Jump Attack Knockback Amount"),HurtType::MONSTER|HurtType::PLAYER); |
||||||
|
m.SetZ(0.f); |
||||||
|
m.SetPos(m.V(A::JUMP_TARGET_POS)); |
||||||
|
SETPHASE(MOVE); |
||||||
|
m.PerformIdleAnimation(); |
||||||
|
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){}); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case PREPARE_WHIRLWIND:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f){ |
||||||
|
SETPHASE(WHIRLWIND); |
||||||
|
m.F(A::CHASE_TIMER)=0.f; |
||||||
|
m.PerformAnimation("SPINNING"); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case WHIRLWIND:{ |
||||||
|
m.F(A::CHASE_TIMER)+=fElapsedTime; |
||||||
|
if(m.F(A::CHASE_TIMER)>=ConfigFloat("Whirlwind Spin Time")){ |
||||||
|
SETPHASE(MOVE); |
||||||
|
m.PerformIdleAnimation(); |
||||||
|
} |
||||||
|
m.MoveForward(m.V(A::PATH_DIR),fElapsedTime); |
||||||
|
const HurtList hurtTargets{game->Hurt(m.GetPos(),ConfigFloat("Whirlwind Radius")/100.f*24.f,m.GetAttack(),m.OnUpperLevel(),m.GetZ(),HurtType::PLAYER)}; |
||||||
|
for(auto&[target,isHurt]:hurtTargets){ |
||||||
|
if(std::holds_alternative<Player*>(target)){ |
||||||
|
(std::get<Player*>(target))->ApplyIframes(0.5f); |
||||||
|
}else ERR("WARNING! Somehow ended up with a non-player entity for whirlwind damage check! THIS SHOULD NOT BE HAPPENING!") |
||||||
|
} |
||||||
|
game->ProximityKnockback(m.GetPos(),ConfigFloat("Whirlwind Radius")/100.f*24.f,ConfigFloat("Whirlwind Knockback Amount"),HurtType::MONSTER|HurtType::PLAYER); |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::SANDWORM(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
INITIALIZE, |
||||||
|
UNDERGROUND, |
||||||
|
SURFACING, |
||||||
|
ATTACK, |
||||||
|
SHOOTING, |
||||||
|
BURROWING, |
||||||
|
}; |
||||||
|
|
||||||
|
m.F(A::ATTACK_COOLDOWN)-=fElapsedTime; |
||||||
|
m.F(A::SUCTION_TIMER)-=fElapsedTime; |
||||||
|
const float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())}; |
||||||
|
if(m.F(A::SUCTION_TIMER)>0.f&&distToPlayer<=ConfigPixels("Suction Radius")){ |
||||||
|
game->GetPlayer()->AddVelocity(util::pointTo(game->GetPlayer()->GetPos(),m.GetPos())*100.f*ConfigFloat("Suction Pull Amount")/100.f); |
||||||
|
} |
||||||
|
|
||||||
|
const auto AcquireNewUndergroundTarget=[&](){ |
||||||
|
const float randomRange=util::random_range(0,ConfigPixels("Burrow Target Range")); |
||||||
|
m.target=game->GetPlayer()->GetPos()+vf2d{randomRange,util::random(2*PI)}.cart(); |
||||||
|
}; |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case INITIALIZE:{ |
||||||
|
SETPHASE(UNDERGROUND); |
||||||
|
AcquireNewUndergroundTarget(); |
||||||
|
}break; |
||||||
|
case UNDERGROUND:{ |
||||||
|
m.SetCollisionRadius(0.f); |
||||||
|
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); |
||||||
|
m.PerformAnimation("SWIM",m.GetFacingDirection()); |
||||||
|
if(m.ReachedTargetPos()){ |
||||||
|
m.PerformAnimation("EMERGE",game->GetPlayer()->GetPos()); |
||||||
|
m.F(A::RECOVERY_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
game->AddEffect(std::make_unique<Effect>(m.GetPos(),ConfigInt("Suction Duration"),"sand_suction.png",m.OnUpperLevel(),0.25f,0.25f,ConfigFloat("Suction Animation Size")/300.f*vf2d{1.f,1.f},vf2d{},WHITE,util::random(),-PI/8),true); |
||||||
|
SETPHASE(SURFACING); |
||||||
|
m.F(A::SUCTION_TIMER)=ConfigFloat("Suction Duration")+0.25f; |
||||||
|
} |
||||||
|
}break; |
||||||
|
case SURFACING:{ |
||||||
|
m.F(A::RECOVERY_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::RECOVERY_TIME)<=0.f){ |
||||||
|
SETPHASE(ATTACK); |
||||||
|
m.PerformAnimation("IDLE",game->GetPlayer()->GetPos()); |
||||||
|
m.SetCollisionRadius(m.GetOriginalCollisionRadius()); |
||||||
|
m.I(A::ATTACK_COUNT)=ConfigInt("Max Attack Count"); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case ATTACK:{ |
||||||
|
if(m.I(A::ATTACK_COUNT)<=0||distToPlayer>=ConfigPixels("Max Attack Range")){ |
||||||
|
m.SetCollisionRadius(0.f); |
||||||
|
m.PerformAnimation("BURROW"); |
||||||
|
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
SETPHASE(BURROWING); |
||||||
|
break; |
||||||
|
} |
||||||
|
if(m.F(A::ATTACK_COOLDOWN)<=0.f){ |
||||||
|
m.PerformAnimation("SAND ATTACK",game->GetPlayer()->GetPos()); |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Shoot Delay"); |
||||||
|
m.F(A::SHOOT_ANIMATION_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration(); |
||||||
|
m.B(A::BULLET_HAS_BEEN_SHOT)=false; |
||||||
|
SETPHASE(SHOOTING); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case SHOOTING:{ |
||||||
|
const auto ShootBullet=[&](){ |
||||||
|
m.B(A::BULLET_HAS_BEEN_SHOT)=true; |
||||||
|
m.I(A::ATTACK_COUNT)--; |
||||||
|
CreateBullet(Bullet)(m.GetPos(),vf2d{ConfigPixels("Bullet Speed"),util::angleTo(m.GetPos(),game->GetPlayer()->GetPos())}.cart(),ConfigFloat("Bullet Radius"),m.GetAttack(),m.OnUpperLevel(),false,ConfigPixel("Bullet Color"),ConfigFloat("Bullet Radius")*vf2d{1.f,1.f}/2.f)EndBullet; |
||||||
|
}; |
||||||
|
|
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
m.F(A::SHOOT_ANIMATION_TIME)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f&&!m.B(A::BULLET_HAS_BEEN_SHOT)){ |
||||||
|
ShootBullet(); |
||||||
|
} |
||||||
|
if(m.F(A::SHOOT_ANIMATION_TIME)<=0.f){ |
||||||
|
if(!m.B(A::BULLET_HAS_BEEN_SHOT))ShootBullet(); |
||||||
|
m.PerformAnimation("IDLE",game->GetPlayer()->GetPos()); |
||||||
|
SETPHASE(ATTACK); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case BURROWING:{ |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f){ |
||||||
|
AcquireNewUndergroundTarget(); |
||||||
|
SETPHASE(UNDERGROUND); |
||||||
|
} |
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
#pragma region License |
||||||
|
/*
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced in the documentation and/or other materials provided with the distribution. |
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may |
||||||
|
be used to endorse or promote products derived from this software without specific |
||||||
|
prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||||||
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||||||
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGE. |
||||||
|
|
||||||
|
Portions of this software are copyright © 2024 The FreeType |
||||||
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information. |
||||||
|
All rights reserved. |
||||||
|
*/ |
||||||
|
#pragma endregion |
||||||
|
|
||||||
|
#include "MonsterStrategyHelpers.h" |
||||||
|
#include "util.h" |
||||||
|
#include "AdventuresInLestoria.h" |
||||||
|
#include "SoundEffect.h" |
||||||
|
#include "BulletTypes.h" |
||||||
|
|
||||||
|
using A=Attribute; |
||||||
|
|
||||||
|
INCLUDE_game |
||||||
|
|
||||||
|
void Monster::STRATEGY::SEAGULL(Monster&m,float fElapsedTime,std::string strategy){ |
||||||
|
enum PhaseName{ |
||||||
|
CHILLING, |
||||||
|
STARTLED, |
||||||
|
FLY_AWAY, |
||||||
|
DISABLED, |
||||||
|
}; |
||||||
|
|
||||||
|
switch(PHASE()){ |
||||||
|
case CHILLING:{ |
||||||
|
m.PerformAnimation("IDLE",game->GetPlayer()->GetPos()); |
||||||
|
float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())}; |
||||||
|
if(distToPlayer<=ConfigFloat("Startled Range")/100.f*24){ |
||||||
|
SETPHASE(STARTLED); |
||||||
|
m.F(A::CASTING_TIMER)=ConfigFloat("Takeoff Time"); |
||||||
|
m.V(A::PREV_POS)=m.GetPos(); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case STARTLED:{ |
||||||
|
m.PerformAnimation("FLY",m.GetPos()+util::pointTo(game->GetPlayer()->GetPos(),m.GetPos())); |
||||||
|
m.F(A::CASTING_TIMER)-=fElapsedTime; |
||||||
|
if(m.F(A::CASTING_TIMER)<=0.f)SETPHASE(FLY_AWAY); |
||||||
|
}break; |
||||||
|
case FLY_AWAY:{ |
||||||
|
vf2d moveVec{m.GetPos()-game->GetPlayer()->GetPos()}; |
||||||
|
m.PerformAnimation("FLY",m.GetPos()+util::pointTo(game->GetPlayer()->GetPos(),m.GetPos())); |
||||||
|
m.MoveForward(moveVec,fElapsedTime); |
||||||
|
float distTraveled{util::distance(m.V(A::PREV_POS),m.GetPos())}; |
||||||
|
if(distTraveled>=ConfigFloat("Despawn Range")/100.f*24){ |
||||||
|
m.lifetime=1.f; |
||||||
|
SETPHASE(DISABLED); |
||||||
|
} |
||||||
|
}break; |
||||||
|
case DISABLED:{ |
||||||
|
//NO-OP
|
||||||
|
}break; |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue