Add pair argument conversion for Oscillator class. Collided with player flag gets set to false each frame. Implement Pirate's Coin/Curse mechanic and spinning/debuff effects. Release Build 12094.
This commit is contained in:
parent
63a97958f7
commit
dbf140e0bd
@ -839,6 +839,10 @@
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BurstBullet.cpp" />
|
||||
<ClCompile Include="CollectedCoinEffect.cpp">
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Crab.cpp" />
|
||||
<ClCompile Include="Entity.cpp">
|
||||
<SubType>
|
||||
@ -852,6 +856,10 @@
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FlipCoinEffect.cpp">
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GhostSaber.cpp">
|
||||
<SubType>
|
||||
</SubType>
|
||||
@ -1114,7 +1122,11 @@
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PiratesTreasure.cpp">
|
||||
<ClCompile Include="Pirates_Treasure.cpp">
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Pirates_Coin.cpp">
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
|
@ -1304,9 +1304,18 @@
|
||||
<ClCompile Include="GhostSaber.cpp">
|
||||
<Filter>Source Files\Bullet Types</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PiratesTreasure.cpp">
|
||||
<ClCompile Include="Pirates_Treasure.cpp">
|
||||
<Filter>Source Files\Monster Strategies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Pirates_Coin.cpp">
|
||||
<Filter>Source Files\Monster Strategies</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FlipCoinEffect.cpp">
|
||||
<Filter>Source Files\Effects</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CollectedCoinEffect.cpp">
|
||||
<Filter>Source Files\Effects</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
|
@ -1069,7 +1069,7 @@ void AiL::RenderWorld(float fElapsedTime){
|
||||
const std::vector<Buff>damageReductionBuffs{player->GetBuffs(BuffType::DAMAGE_REDUCTION)};
|
||||
const std::vector<Buff>inkSlowdownDebuff{player->GetBuffs(BuffType::INK_SLOWDOWN)};
|
||||
const std::vector<Buff>curseDebuff{player->GetBuffs(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT)};
|
||||
const bool displayCoinSymbol{player->GetBuffs(BuffType::PIRATE_GHOST_CAPTAIN_CURSE).size()>0};
|
||||
const bool displayCoinSymbol{player->GetBuffs(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN).size()>0};
|
||||
|
||||
Pixel playerCol{WHITE};
|
||||
if(attackBuffs.size()>0)playerCol={255,uint8_t(255*abs(sin(1.4f*attackBuffs[0].duration))),uint8_t(255*abs(sin(1.4f*attackBuffs[0].duration)))};
|
||||
@ -1098,7 +1098,7 @@ void AiL::RenderWorld(float fElapsedTime){
|
||||
}
|
||||
|
||||
if(displayCoinSymbol){
|
||||
view.DrawRotatedDecal(pos+vf2d{0,(-player->GetZ()-24.f-sinf(PI*GetRunTime())*4.f)*(std::signbit(scale.y)?-1:1)},GFX["coin.png"].Decal(),0.f,GFX["coin.png"].Sprite()->Size()/2,{0.5f,0.5f});
|
||||
view.DrawRotatedDecal(pos+vf2d{0,(-player->GetZ()-16.f-sinf(PI*GetRunTime())*2.f)*(std::signbit(scale.y)?-1:1)},GFX["coin.png"].Decal(),0.f,GFX["coin.png"].Sprite()->Size()/2,{0.5f,0.5f});
|
||||
}
|
||||
};
|
||||
|
||||
@ -4490,6 +4490,9 @@ void AiL::ComputeModeColors(TilesetData&tileset){
|
||||
|
||||
void AiL::UpdateEntities(){
|
||||
UpdateEffects(GetElapsedTime());
|
||||
for(std::shared_ptr<Monster>&m:MONSTER_LIST){
|
||||
m->B(Attribute::COLLIDED_WITH_PLAYER)=false;
|
||||
}
|
||||
GetPlayer()->Update(GetElapsedTime());
|
||||
UpdateMonsters();
|
||||
|
||||
|
@ -66,7 +66,8 @@ enum BuffType{
|
||||
CURSE_OF_DEATH,
|
||||
AFFECTED_BY_LIGHTNING_BOLT, //Intensity indicates number of repeats remaining.
|
||||
INK_SLOWDOWN, //Intensity indicates % movespd slowdown.
|
||||
PIRATE_GHOST_CAPTAIN_CURSE, //A coin icon appears above the player's head.
|
||||
PIRATE_GHOST_CAPTAIN_PRECURSE, //A coin icon appears above the player's head.
|
||||
PIRATE_GHOST_CAPTAIN_CURSE_COIN, //A coin icon appears above the player's head.
|
||||
PIRATE_GHOST_CAPTAIN_CURSE_DOT, //The same as above, but now is a damage over time as well.
|
||||
};
|
||||
enum class BuffRestorationType{
|
||||
|
57
Adventures in Lestoria/CollectedCoinEffect.cpp
Normal file
57
Adventures in Lestoria/CollectedCoinEffect.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#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 "Effect.h"
|
||||
#include "AdventuresInLestoria.h"
|
||||
#include "DEFINES.h"
|
||||
#include "util.h"
|
||||
|
||||
INCLUDE_game
|
||||
|
||||
CollectCoinEffect::CollectCoinEffect(const Entity attachedTarget,float coinArcRiseZAmt,float lifetime,const std::string&imgFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
|
||||
:Effect(attachedTarget.GetPos(),lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending),attachedTarget(attachedTarget),sizeFlipper(-1.f,1.f,lifetime*2.f),zRiser(0.f,coinArcRiseZAmt,1/lifetime){
|
||||
}
|
||||
bool CollectCoinEffect::Update(float fElapsedTime){
|
||||
zRiser.Update(fElapsedTime);
|
||||
pos=attachedTarget.GetPos()-vf2d{0,zRiser.get()}; //A hack, instead of using the built-in z (which would display a shadow, we instead manipulate the final position based on the zRiser output).
|
||||
size.x=sizeFlipper.Update(fElapsedTime);
|
||||
return Effect::Update(fElapsedTime);
|
||||
}
|
||||
void CollectCoinEffect::Draw(const Pixel blendCol)const{
|
||||
Effect::Draw(blendCol);
|
||||
}
|
@ -107,6 +107,10 @@ void Effect::_Draw()const{
|
||||
}
|
||||
|
||||
void Effect::Draw(const Pixel blendCol)const{
|
||||
if(GetZ()>0){
|
||||
vf2d shadowScale=vf2d{8*size.x/3.f,1}/std::max(1.f,GetZ()/24);
|
||||
game->view.DrawDecal(pos-vf2d{3,3}*shadowScale/2+vf2d{0,6*size.x},GFX["circle.png"].Decal(),shadowScale,BLACK);
|
||||
}
|
||||
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,blendCol);
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ All rights reserved.
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
#include "Oscillator.h"
|
||||
#include "Entity.h"
|
||||
class Monster;
|
||||
class Player;
|
||||
using HitList=std::unordered_set<std::variant<Monster*,Player*>>;
|
||||
@ -224,4 +225,24 @@ private:
|
||||
const float radius;
|
||||
const float inkSlowdownDuration;
|
||||
const float inkSlowdownAmount;
|
||||
};
|
||||
|
||||
struct FlipCoinEffect:Effect{
|
||||
//cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque
|
||||
FlipCoinEffect(Oscillator<vf2d>startEndPos,float coinArcRiseZAmt,float lifetime,const std::string&imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
|
||||
virtual bool Update(float fElapsedTime)override;
|
||||
virtual void Draw(const Pixel blendCol)const override;
|
||||
Oscillator<vf2d>startEndPos;
|
||||
Oscillator<float>sizeFlipper;
|
||||
Oscillator<float>zRiser;
|
||||
};
|
||||
|
||||
struct CollectCoinEffect:Effect{
|
||||
//cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque
|
||||
CollectCoinEffect(const Entity attachedTarget,float coinArcRiseZAmt,float lifetime,const std::string&imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
|
||||
virtual bool Update(float fElapsedTime)override;
|
||||
virtual void Draw(const Pixel blendCol)const override;
|
||||
const Entity attachedTarget;
|
||||
Oscillator<float>sizeFlipper;
|
||||
Oscillator<float>zRiser;
|
||||
};
|
58
Adventures in Lestoria/FlipCoinEffect.cpp
Normal file
58
Adventures in Lestoria/FlipCoinEffect.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#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 "Effect.h"
|
||||
#include "AdventuresInLestoria.h"
|
||||
#include "DEFINES.h"
|
||||
#include "util.h"
|
||||
|
||||
INCLUDE_game
|
||||
|
||||
FlipCoinEffect::FlipCoinEffect(Oscillator<vf2d>startEndPos,float coinArcRiseZAmt,float lifetime,const std::string&imgFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
|
||||
:Effect(startEndPos.first,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending),startEndPos(startEndPos),sizeFlipper(-1.f,1.f,lifetime*2.f),zRiser(0.f,coinArcRiseZAmt,1/lifetime){
|
||||
}
|
||||
bool FlipCoinEffect::Update(float fElapsedTime){
|
||||
zRiser.Update(fElapsedTime);
|
||||
pos=startEndPos.Update(fElapsedTime);
|
||||
size.y=sizeFlipper.Update(fElapsedTime);
|
||||
z=zRiser.get();
|
||||
return Effect::Update(fElapsedTime);
|
||||
}
|
||||
void FlipCoinEffect::Draw(const Pixel blendCol)const{
|
||||
Effect::Draw(blendCol);
|
||||
}
|
@ -100,15 +100,25 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
}
|
||||
|
||||
m.F(A::GHOST_SABER_TIMER)-=fElapsedTime;
|
||||
m.F(A::LAST_COLLISION_TIMER)-=fElapsedTime;
|
||||
|
||||
if(m.B(A::FIRST_WAVE_COMPLETE)){
|
||||
m.UpdateFacingDirection(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));
|
||||
m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*100.f*m.GetMoveSpdMult());
|
||||
const float distToPlayer{util::distance(m.GetPos(),game->GetPlayer()->GetPos())};
|
||||
if(m.F(A::GHOST_SABER_TIMER)<=0.f&&distToPlayer<=ConfigPixels("Ghost Saber Activation Range")){
|
||||
m.F(A::GHOST_SABER_TIMER)=ConfigFloat("Ghost Saber Cooldown");
|
||||
const float playerToMonsterAngle{util::pointTo(game->GetPlayer()->GetPos(),m.GetPos()).polar().y};
|
||||
CreateBullet(GhostSaber)(m.GetPos(),m.GetWeakPointer(),ConfigFloat("Ghost Saber Lifetime"),ConfigFloat("Ghost Saber Distance"),ConfigFloat("Ghost Saber Knockback Amt"),playerToMonsterAngle,ConfigFloat("Ghost Saber Radius"),ConfigFloat("Ghost Saber Expand Spd"),ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")))EndBullet;
|
||||
if(m.F(A::LAST_COLLISION_TIMER)<=0.f){
|
||||
m.UpdateFacingDirection(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));
|
||||
m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*100.f*m.GetMoveSpdMult());
|
||||
const float distToPlayer{util::distance(m.GetPos(),game->GetPlayer()->GetPos())};
|
||||
if(m.F(A::GHOST_SABER_TIMER)<=0.f&&distToPlayer<=ConfigPixels("Ghost Saber Activation Range")){
|
||||
m.F(A::GHOST_SABER_TIMER)=ConfigFloat("Ghost Saber Cooldown");
|
||||
const float playerToMonsterAngle{util::pointTo(game->GetPlayer()->GetPos(),m.GetPos()).polar().y};
|
||||
CreateBullet(GhostSaber)(m.GetPos(),m.GetWeakPointer(),ConfigFloat("Ghost Saber Lifetime"),ConfigFloat("Ghost Saber Distance"),ConfigFloat("Ghost Saber Knockback Amt"),playerToMonsterAngle,ConfigFloat("Ghost Saber Radius"),ConfigFloat("Ghost Saber Expand Spd"),ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")))EndBullet;
|
||||
}
|
||||
}
|
||||
if(m.B(A::COLLIDED_WITH_PLAYER)){
|
||||
m.PerformAnimation("SLASHING");
|
||||
m.F(A::GHOST_SABER_SLASH_ANIMATION_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration();
|
||||
m.F(A::LAST_COLLISION_TIMER)=ConfigFloat("Collision Recovery Time");
|
||||
m.I(A::PREVIOUS_PHASE)=PHASE();
|
||||
SETPHASE(GHOSTSABER_SLASH);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,6 +129,12 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
SHRAPNEL_SHOT,
|
||||
};
|
||||
case INIT:{
|
||||
m.SetStrategyDeathFunction([](GameEvent&ev,Monster&m,const std::string&strategy){
|
||||
for(std::shared_ptr<Monster>&m:MONSTER_LIST){
|
||||
if(m->IsAlive())m->_DealTrueDamage(m->GetHealth(),HurtFlag::NONE);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
for(int i:std::ranges::iota_view(0U,PHASE_COUNT)){
|
||||
const int cannonCycle{DATA.GetProperty("MonsterStrategy.Ghost of Pirate Captain.Cannon Cycle").GetInt(i)};
|
||||
m.VEC(A::CANNON_PHASES).emplace_back(cannonCycle);
|
||||
@ -183,8 +199,11 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
}
|
||||
|
||||
if(Config("Curse Thresholds").GetValueCount()>m.I(A::CURSE_THRESHOLD_ARRAY_IND)&&
|
||||
m.GetHealthRatio()<=ConfigFloatArr("Curse Thresholds",m.I(A::CURSE_THRESHOLD_ARRAY_IND))){
|
||||
m.GetHealthRatio()<=ConfigFloatArr("Curse Thresholds",m.I(A::CURSE_THRESHOLD_ARRAY_IND))/100.f){
|
||||
m.I(A::CURSE_THRESHOLD_ARRAY_IND)++;
|
||||
m.F(A::TOSS_COIN_WAIT_TIMER)=ConfigFloat("Coin Toss Pause Time");
|
||||
m.V(A::TOSS_COIN_TARGET)=game->GetPlayer()->GetPos();
|
||||
game->AddEffect(std::make_unique<FlipCoinEffect>(Oscillator<vf2d>{m.GetPos(),m.V(A::TOSS_COIN_TARGET),1.f/m.F(A::TOSS_COIN_WAIT_TIMER)/2.f},ConfigFloat("Coin Toss Rise Amount"),m.F(A::TOSS_COIN_WAIT_TIMER),"coin.png",m.OnUpperLevel(),3.f));
|
||||
SETPHASE(TOSS_COIN);
|
||||
}
|
||||
}break;
|
||||
@ -203,9 +222,15 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
}
|
||||
}break;
|
||||
case TOSS_COIN:{
|
||||
const float curseDmgPctOverTime{ConfigFloat("Curse Damage")};
|
||||
game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE,ConfigFloat("Curse Damage Wait Time"),ceil(game->GetPlayer()->GetMaxHealth()*ConfigFloat("Curse Damage")/100.f)+1,[curseDmgPctOverTime](Player*attachedTarget,Buff&b){attachedTarget->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT,BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_PCT_DAMAGE_OVER_TIME,INFINITY,curseDmgPctOverTime,1.f);});
|
||||
SETPHASE(NORMAL);
|
||||
m.F(A::TOSS_COIN_WAIT_TIMER)-=fElapsedTime;
|
||||
if(m.F(A::TOSS_COIN_WAIT_TIMER)<=0.f){
|
||||
const float curseDmgPctOverTime{ConfigFloat("Curse Damage")};
|
||||
game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_PRECURSE,ConfigFloat("Curse Damage Wait Time"),ceil(game->GetPlayer()->GetMaxHealth()*ConfigFloat("Curse Damage")/100.f)+1,[curseDmgPctOverTime](Player*attachedTarget,Buff&b){
|
||||
attachedTarget->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT,BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_PCT_DAMAGE_OVER_TIME,INFINITY,curseDmgPctOverTime,1.f);
|
||||
});
|
||||
game->SpawnMonster(m.V(A::TOSS_COIN_TARGET),MONSTER_DATA["Pirate's Coin"],m.OnUpperLevel());
|
||||
SETPHASE(NORMAL);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
@ -39,9 +39,10 @@ All rights reserved.
|
||||
|
||||
namespace HurtFlag{
|
||||
enum HurtFlag{
|
||||
NONE = 0b00,
|
||||
PLAYER_ABILITY = 0b01, //Specifically use this flag for player auto attacks or Abilities only! (Identifies these attacks for the Trapper class)
|
||||
DOT = 0b10, //Damage over time ability.
|
||||
NONE = 0b000,
|
||||
PLAYER_ABILITY = 0b001, //Specifically use this flag for player auto attacks or Abilities only! (Identifies these attacks for the Trapper class)
|
||||
DOT = 0b010, //Damage over time ability.
|
||||
NO_DAMAGE_NUMBER = 0b100, //This flag ensures no damage number appears.
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -787,8 +787,7 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da
|
||||
const Buff specialMarkBuff{GetBuffs(BuffType::SPECIAL_MARK)[0]};
|
||||
if(game->GetPlayer()->HasEnchant("Opportunity Shot")&&specialMarkBuff.originalDuration-specialMarkBuff.duration<="Opportunity Shot"_ENC["MARK TRIGGER TIME"])Trapper::ability1.cooldown-="Opportunity Shot"_ENC["MARK COOLDOWN REDUCE"];
|
||||
RemoveSpecialMarkStack();
|
||||
}else
|
||||
if(GetMarkStacks()>0){
|
||||
}else if(GetMarkStacks()>0){
|
||||
ApplyMarkEffects();
|
||||
RemoveMarkStack();
|
||||
}
|
||||
@ -811,33 +810,35 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da
|
||||
|
||||
if(GetBuffs(BuffType::CURSE_OF_DEATH).size()>0)accumulatedCurseOfDeathDamage+=mod_dmg;
|
||||
|
||||
if(IsDOT){
|
||||
if(lastDotTimer>0){
|
||||
dotNumberPtr.get()->AddDamage(int(mod_dmg));
|
||||
}else{
|
||||
dotNumberPtr=std::make_shared<DamageNumber>(pos+vf2d{0,8.f},int(mod_dmg),false,DamageNumberType::DOT);
|
||||
DAMAGENUMBER_LIST.push_back(dotNumberPtr);
|
||||
}
|
||||
lastDotTimer=0.05f;
|
||||
}else{
|
||||
if(lastHitTimer>0){
|
||||
damageNumberPtr.get()->AddDamage(int(mod_dmg));
|
||||
damageNumberPtr.get()->SetPauseTimer(0.4f);
|
||||
}else{
|
||||
damageNumberPtr=std::make_shared<DamageNumber>(pos,int(mod_dmg));
|
||||
DAMAGENUMBER_LIST.push_back(damageNumberPtr);
|
||||
}
|
||||
#pragma region Change Label based on bonus conditions (Crit/Backstab)
|
||||
if(crit){
|
||||
damageNumberPtr.get()->SetType(DamageNumberType::CRIT);
|
||||
if(!(hurtFlags&HurtFlag::NO_DAMAGE_NUMBER)){
|
||||
if(IsDOT){
|
||||
if(lastDotTimer>0){
|
||||
dotNumberPtr.get()->AddDamage(int(mod_dmg));
|
||||
}else{
|
||||
dotNumberPtr=std::make_shared<DamageNumber>(pos+vf2d{0,8.f},int(mod_dmg),false,DamageNumberType::DOT);
|
||||
DAMAGENUMBER_LIST.push_back(dotNumberPtr);
|
||||
}
|
||||
if(damageNumberPtr.get()->GetType()==DamageNumberType::CRIT)goto doneChangingDamageNumberColors; //Crit number priority. Other colors should not apply if the crit has applied.
|
||||
if(backstabOccurred){
|
||||
damageNumberPtr.get()->SetType(DamageNumberType::BACKSTAB);
|
||||
lastDotTimer=0.05f;
|
||||
}else{
|
||||
if(lastHitTimer>0){
|
||||
damageNumberPtr.get()->AddDamage(int(mod_dmg));
|
||||
damageNumberPtr.get()->SetPauseTimer(0.4f);
|
||||
}else{
|
||||
damageNumberPtr=std::make_shared<DamageNumber>(pos,int(mod_dmg));
|
||||
DAMAGENUMBER_LIST.push_back(damageNumberPtr);
|
||||
}
|
||||
doneChangingDamageNumberColors:
|
||||
#pragma endregion
|
||||
lastHitTimer=0.05f;
|
||||
#pragma region Change Label based on bonus conditions (Crit/Backstab)
|
||||
if(crit){
|
||||
damageNumberPtr.get()->SetType(DamageNumberType::CRIT);
|
||||
}
|
||||
if(damageNumberPtr.get()->GetType()==DamageNumberType::CRIT)goto doneChangingDamageNumberColors; //Crit number priority. Other colors should not apply if the crit has applied.
|
||||
if(backstabOccurred){
|
||||
damageNumberPtr.get()->SetType(DamageNumberType::BACKSTAB);
|
||||
}
|
||||
doneChangingDamageNumberColors:
|
||||
#pragma endregion
|
||||
lastHitTimer=0.05f;
|
||||
}
|
||||
}
|
||||
|
||||
attackedByPlayer=true;
|
||||
|
@ -393,6 +393,7 @@ private:
|
||||
static void OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string strategy);
|
||||
static void GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std::string strategy);
|
||||
static void PIRATES_TREASURE(Monster&m,float fElapsedTime,std::string strategy);
|
||||
static void PIRATES_COIN(Monster&m,float fElapsedTime,std::string strategy);
|
||||
};
|
||||
bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame.
|
||||
bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.
|
||||
|
@ -176,4 +176,8 @@ enum class Attribute{
|
||||
GHOST_SABER_TIMER,
|
||||
GHOST_SABER_SLASH_ANIMATION_TIMER,
|
||||
CURSE_THRESHOLD_ARRAY_IND, //Which array index in the curse threshold strategy property we are currently at?
|
||||
TOSS_COIN_WAIT_TIMER,
|
||||
TOSS_COIN_TARGET,
|
||||
LAST_COLLISION_TIMER,
|
||||
|
||||
};
|
@ -43,12 +43,12 @@ template<class T>
|
||||
class Oscillator{
|
||||
friend struct ThrownProjectile;
|
||||
public:
|
||||
inline Oscillator()
|
||||
:Oscillator({},{},0.f){}
|
||||
inline Oscillator():Oscillator({},{},0.f){}
|
||||
inline Oscillator(std::pair<T,T>vals,float cycleSpd):Oscillator(vals.first,vals.second,cycleSpd){}
|
||||
inline Oscillator(T val1,T val2,float cycleSpd)
|
||||
:val1(val1),val2(val2),first(this->val1),second(this->val2),cycleSpd(cycleSpd),currentVal(val1){}
|
||||
inline const T&Update(const float fElapsedTime){
|
||||
currentVal=util::lerp(val1,val2,sin(PI*timer*cycleSpd)/2+0.5f);
|
||||
currentVal=util::lerp(val1,val2,sin(2*PI*timer*cycleSpd-PI/2)/2+0.5);
|
||||
timer+=fElapsedTime;
|
||||
return get();
|
||||
}
|
||||
|
55
Adventures in Lestoria/Pirates_Coin.cpp
Normal file
55
Adventures in Lestoria/Pirates_Coin.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#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 "MonsterStrategyHelpers.h"
|
||||
#include "Entity.h"
|
||||
|
||||
using A=Attribute;
|
||||
|
||||
INCLUDE_game
|
||||
|
||||
void Monster::STRATEGY::PIRATES_COIN(Monster&m,float fElapsedTime,std::string strategy){
|
||||
if(m.B(Attribute::COLLIDED_WITH_PLAYER)){
|
||||
game->AddEffect(std::make_unique<CollectCoinEffect>(game->GetPlayer(),ConfigFloat("Coin Collect Rise Amount"),ConfigFloat("Coin Rise Timer"),"coin.png",m.OnUpperLevel()),true);
|
||||
game->GetPlayer()->AddBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN,INFINITY,1);
|
||||
m._DealTrueDamage(m.GetHealth(),HurtFlag::NO_DAMAGE_NUMBER);
|
||||
m.SetLifetime(0.f);
|
||||
m.SetSize(0.f,false);
|
||||
}
|
||||
}
|
@ -45,8 +45,9 @@ void Monster::STRATEGY::PIRATES_TREASURE(Monster&m,float fElapsedTime,std::strin
|
||||
const float distToPlayer{util::distance(game->GetPlayer()->GetPos(),m.GetPos())};
|
||||
if(distToPlayer<=ConfigFloat("Open Distance"))m.PerformAnimation("OPEN");
|
||||
else m.PerformIdleAnimation();
|
||||
if(m.B(Attribute::COLLIDED_WITH_PLAYER)){
|
||||
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE);
|
||||
if(m.B(Attribute::COLLIDED_WITH_PLAYER)&&game->GetPlayer()->HasBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN)){
|
||||
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_PRECURSE);
|
||||
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_COIN);
|
||||
game->GetPlayer()->RemoveBuff(BuffType::PIRATE_GHOST_CAPTAIN_CURSE_DOT);
|
||||
}
|
||||
}
|
@ -79,6 +79,7 @@ void Monster::InitializeStrategies(){
|
||||
STRATEGY_DATA.insert("Octopus Arm",Monster::STRATEGY::OCTOPUS_ARM);
|
||||
STRATEGY_DATA.insert("Ghost of Pirate Captain",Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN);
|
||||
STRATEGY_DATA.insert("Pirate's Treasure",Monster::STRATEGY::PIRATES_TREASURE);
|
||||
STRATEGY_DATA.insert("Pirate's Coin",Monster::STRATEGY::PIRATES_COIN);
|
||||
|
||||
STRATEGY_DATA.SetInitialized();
|
||||
}
|
||||
|
@ -305,7 +305,6 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
m.F(A::CASTING_TIMER)=ConfigFloat("Phase 3.Charge Cast Time");
|
||||
m.UpdateFacingDirection(geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).vector());
|
||||
m.PerformAnimation("CHARGE");
|
||||
m.B(A::COLLIDED_WITH_PLAYER)=false;
|
||||
}
|
||||
}
|
||||
if(m.F(A::CASTING_TIMER)>0.f){
|
||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_BUILD 12049
|
||||
#define VERSION_BUILD 12094
|
||||
|
||||
#define stringify(a) stringify_(a)
|
||||
#define stringify_(a) #a
|
||||
|
@ -1304,6 +1304,9 @@ MonsterStrategy
|
||||
# Repeats at end of cycle.
|
||||
Cannon Cycle = 0,0,0,0,0,0,0,0,1,2,1
|
||||
|
||||
# How much time to stand still before moving towards the player again.
|
||||
Collision Recovery Time = 3s
|
||||
|
||||
Cannon Shot Delay = 0.4s
|
||||
Cannon Shot Impact Time = 2.5s
|
||||
Silence Time = 2s
|
||||
@ -1340,7 +1343,7 @@ MonsterStrategy
|
||||
Ghost Saber Distance = 48px
|
||||
Ghost Saber Radius = 8px
|
||||
Ghost Saber Damage = 75
|
||||
Ghost Saber Rotation Spd = 210deg/s
|
||||
Ghost Saber Rotation Spd = 140deg/s
|
||||
Ghost Saber Knockback Amt = 100
|
||||
# Amount of pixels/sec the ghost saber circle expands outwards.
|
||||
Ghost Saber Expand Spd = 14px
|
||||
@ -1351,9 +1354,20 @@ MonsterStrategy
|
||||
Curse Damage Wait Time = 10s
|
||||
# How much % damage the curse does to the player every second.
|
||||
Curse Damage = 1%/sec
|
||||
# How much time to pause before moving again.
|
||||
Coin Toss Pause Time = 2s
|
||||
# Highest Z position the coin is tossed up.
|
||||
Coin Toss Rise Amount = 72px
|
||||
}
|
||||
Pirate's Treasure
|
||||
{
|
||||
Open Distance = 64px
|
||||
}
|
||||
Pirate's Coin
|
||||
{
|
||||
# How much time the coin rises.
|
||||
Coin Rise Timer = 2s
|
||||
# Highest Z position the collected coin icon appears at.
|
||||
Coin Collect Rise Amount = 36px
|
||||
}
|
||||
}
|
@ -1906,6 +1906,51 @@ Monsters
|
||||
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
|
||||
# DROP[0] = Octopus Ring,100%,1,1
|
||||
|
||||
Hurt Sound = Monster Hurt
|
||||
Death Sound = Slime Dead
|
||||
Walk Sound = Slime Walk
|
||||
}
|
||||
Pirate's Coin
|
||||
{
|
||||
Health = 1
|
||||
Attack = 80
|
||||
|
||||
CollisionDmg = 0
|
||||
|
||||
Immovable = True
|
||||
Invulnerable = True
|
||||
|
||||
Fadeout = False
|
||||
|
||||
Collision Radius = 64
|
||||
|
||||
MoveSpd = 0%
|
||||
Size = 300%
|
||||
|
||||
XP = 0
|
||||
|
||||
Strategy = Pirate's Coin
|
||||
|
||||
#Size of each animation frame
|
||||
SheetFrameSize = 24,24
|
||||
|
||||
# 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,ReverseOneShot)
|
||||
# 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.
|
||||
IDLE = 1, 1.0, OneShot
|
||||
WALK = 1, 1.0, OneShot
|
||||
SLASHING = 1, 1.0, OneShot
|
||||
OPEN = 1, 1.0, OneShot
|
||||
}
|
||||
|
||||
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
|
||||
# DROP[0] = Octopus Ring,100%,1,1
|
||||
|
||||
Hurt Sound = Monster Hurt
|
||||
Death Sound = Slime Dead
|
||||
Walk Sound = Slime Walk
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user