Added ghost saber expanding behavior. Fix Prediction bombardment pattern to properly use player's previous position. Release Build 12029.
This commit is contained in:
parent
fdef405ed8
commit
071e98aecd
@ -539,6 +539,9 @@ void AiL::HandleUserInput(float fElapsedTime){
|
|||||||
else Menu::OpenMenu(MenuType::PAUSE);
|
else Menu::OpenMenu(MenuType::PAUSE);
|
||||||
}
|
}
|
||||||
float animationSpd=0.f;
|
float animationSpd=0.f;
|
||||||
|
if(player->GetPreviousPos()!=player->GetPos()){
|
||||||
|
player->previousPos=player->GetPos();
|
||||||
|
}
|
||||||
player->movementVelocity={};
|
player->movementVelocity={};
|
||||||
if((player->GetVelocity().mag()<"Player.Move Allowed Velocity Lower Limit"_F&&player->CanMove())||(player->GetState()==State::ROLL&&"Thief.Right Click Ability.Roll Time"_F-player->rolling_timer>=0.2f)){
|
if((player->GetVelocity().mag()<"Player.Move Allowed Velocity Lower Limit"_F&&player->CanMove())||(player->GetState()==State::ROLL&&"Thief.Right Click Ability.Roll Time"_F-player->rolling_timer>=0.2f)){
|
||||||
auto GetPlayerStaircaseDirection=[&](){
|
auto GetPlayerStaircaseDirection=[&](){
|
||||||
|
@ -445,7 +445,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct GhostSaber:public Bullet{
|
struct GhostSaber:public Bullet{
|
||||||
GhostSaber(const vf2d pos,const std::weak_ptr<Monster>target,const float lifetime,const float distFromTarget,const float knockbackAmt,const float initialRot,const float radius,const int damage,const bool upperLevel,const float rotSpd,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1},const float image_angle=0.f);
|
GhostSaber(const vf2d pos,const std::weak_ptr<Monster>target,const float lifetime,const float distFromTarget,const float knockbackAmt,const float initialRot,const float radius,const float expandSpd,const int damage,const bool upperLevel,const float rotSpd,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1},const float image_angle=0.f);
|
||||||
void Update(float fElapsedTime)override;
|
void Update(float fElapsedTime)override;
|
||||||
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
|
BulletDestroyState PlayerHit(Player*player)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _PlayerHit()!!
|
||||||
BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
|
BulletDestroyState MonsterHit(Monster&monster,const uint8_t markStacksBeforeHit)override;//DO NOT CALL THIS DIRECTLY! INSTEAD USE _MonsterHit()!!
|
||||||
@ -453,10 +453,11 @@ struct GhostSaber:public Bullet{
|
|||||||
private:
|
private:
|
||||||
const std::weak_ptr<Monster>attachedMonster;
|
const std::weak_ptr<Monster>attachedMonster;
|
||||||
const float rotSpd;
|
const float rotSpd;
|
||||||
const float distFromTarget;
|
float distFromTarget;
|
||||||
float rot;
|
float rot;
|
||||||
const float knockbackAmt;
|
const float knockbackAmt;
|
||||||
float particleTimer{};
|
float particleTimer{};
|
||||||
float aliveTime{};
|
float aliveTime{};
|
||||||
|
float expandSpd{};
|
||||||
Oscillator<uint8_t>alphaOscillator{128U,255U,0.6f};
|
Oscillator<uint8_t>alphaOscillator{128U,255U,0.6f};
|
||||||
};
|
};
|
@ -68,7 +68,7 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
|||||||
|
|
||||||
const auto AdvanceCannonPhase{[&m,&strategy](){
|
const auto AdvanceCannonPhase{[&m,&strategy](){
|
||||||
m.GetFloat(A::CANNON_TIMER)=0.f;
|
m.GetFloat(A::CANNON_TIMER)=0.f;
|
||||||
//if(m.GetInt(A::CANNON_PHASE)+1>=PHASE_COUNT)m.GetInt(A::CANNON_SHOT_TYPE)=util::random()%5;
|
if(m.GetInt(A::CANNON_PHASE)+1>=PHASE_COUNT)m.GetInt(A::CANNON_SHOT_TYPE)=util::random()%5;
|
||||||
const int prevCannonPhase{m.I(A::CANNON_PHASE)};
|
const int prevCannonPhase{m.I(A::CANNON_PHASE)};
|
||||||
m.I(A::CANNON_PHASE)=(m.I(A::CANNON_PHASE)+1)%PHASE_COUNT;
|
m.I(A::CANNON_PHASE)=(m.I(A::CANNON_PHASE)+1)%PHASE_COUNT;
|
||||||
if(prevCannonPhase>m.I(A::CANNON_PHASE)){//Phase has wrapped around, reset cannon shot count.
|
if(prevCannonPhase>m.I(A::CANNON_PHASE)){//Phase has wrapped around, reset cannon shot count.
|
||||||
@ -101,10 +101,11 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
|||||||
|
|
||||||
if(m.B(A::FIRST_WAVE_COMPLETE)){
|
if(m.B(A::FIRST_WAVE_COMPLETE)){
|
||||||
m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos()));
|
m.SetVelocity(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos()));
|
||||||
if(m.F(A::GHOST_SABER_TIMER)<=0.f){
|
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");
|
m.F(A::GHOST_SABER_TIMER)=ConfigFloat("Ghost Saber Cooldown");
|
||||||
const float playerToMonsterAngle{util::pointTo(game->GetPlayer()->GetPos(),m.GetPos()).polar().y};
|
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"),ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")))EndBullet;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
|||||||
if(cannonCycle==CANNON_SHOT)TOTAL_CANNON_SHOTS++;
|
if(cannonCycle==CANNON_SHOT)TOTAL_CANNON_SHOTS++;
|
||||||
}
|
}
|
||||||
m.B(A::FIRST_WAVE_COMPLETE)=false;
|
m.B(A::FIRST_WAVE_COMPLETE)=false;
|
||||||
m.I(A::CANNON_SHOT_TYPE)=PREDICTION;
|
m.I(A::CANNON_SHOT_TYPE)=BOMBARDMENT;
|
||||||
m.ForceSetPos({-400.f,-400.f});
|
m.ForceSetPos({-400.f,-400.f});
|
||||||
SETPHASE(NORMAL);
|
SETPHASE(NORMAL);
|
||||||
}break;
|
}break;
|
||||||
@ -157,6 +158,7 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
|||||||
LOG(std::format("Previous Pos: {} Current: {}",game->GetPlayer()->GetPreviousPos().str(),game->GetPlayer()->GetPos().str()));
|
LOG(std::format("Previous Pos: {} Current: {}",game->GetPlayer()->GetPreviousPos().str(),game->GetPlayer()->GetPos().str()));
|
||||||
const float angle{util::angleTo(game->GetPlayer()->GetPreviousPos(),game->GetPlayer()->GetPos())};
|
const float angle{util::angleTo(game->GetPlayer()->GetPreviousPos(),game->GetPlayer()->GetPos())};
|
||||||
const float range{util::random_range(0,100.f*game->GetPlayer()->GetMoveSpdMult())*ConfigFloat("Cannon Shot Impact Time")};
|
const float range{util::random_range(0,100.f*game->GetPlayer()->GetMoveSpdMult())*ConfigFloat("Cannon Shot Impact Time")};
|
||||||
|
LOG(std::format("Range/Angle: {}",vf2d{range,angle}.str()));
|
||||||
const vf2d targetPos{game->GetPlayer()->GetPos()+vf2d{range,angle}.cart()};
|
const vf2d targetPos{game->GetPlayer()->GetPos()+vf2d{range,angle}.cart()};
|
||||||
CreateBullet(FallingBullet)("cannonball.png",targetPos,ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
CreateBullet(FallingBullet)("cannonball.png",targetPos,ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
||||||
}break;
|
}break;
|
||||||
|
@ -38,12 +38,13 @@ All rights reserved.
|
|||||||
|
|
||||||
#include "BulletTypes.h"
|
#include "BulletTypes.h"
|
||||||
|
|
||||||
GhostSaber::GhostSaber(const vf2d pos,const std::weak_ptr<Monster>target,const float lifetime,const float distFromTarget,const float knockbackAmt,const float initialRot,const float radius,const int damage,const bool upperLevel,const float rotSpd,const bool friendly,const Pixel col,const vf2d scale,const float image_angle)
|
GhostSaber::GhostSaber(const vf2d pos,const std::weak_ptr<Monster>target,const float lifetime,const float distFromTarget,const float knockbackAmt,const float initialRot,const float radius,const float expandSpd,const int damage,const bool upperLevel,const float rotSpd,const bool friendly,const Pixel col,const vf2d scale,const float image_angle)
|
||||||
:Bullet(target.lock()->GetPos()+vf2d{distFromTarget,initialRot}.cart(),{},radius,damage,"ghost_dagger.png",upperLevel,false,INFINITE,false,friendly,col,scale,image_angle),attachedMonster(target),rotSpd(rotSpd),distFromTarget(distFromTarget),rot(initialRot),aliveTime(lifetime),knockbackAmt(knockbackAmt){}
|
:Bullet(target.lock()->GetPos()+vf2d{distFromTarget,initialRot}.cart(),{},radius,damage,"ghost_dagger.png",upperLevel,false,INFINITE,false,friendly,col,scale,image_angle),attachedMonster(target),rotSpd(rotSpd),distFromTarget(distFromTarget),rot(initialRot),aliveTime(lifetime),knockbackAmt(knockbackAmt),expandSpd(expandSpd){}
|
||||||
void GhostSaber::Update(float fElapsedTime){
|
void GhostSaber::Update(float fElapsedTime){
|
||||||
alphaOscillator.Update(fElapsedTime);
|
alphaOscillator.Update(fElapsedTime);
|
||||||
particleTimer-=fElapsedTime;
|
particleTimer-=fElapsedTime;
|
||||||
aliveTime-=fElapsedTime;
|
aliveTime-=fElapsedTime;
|
||||||
|
distFromTarget+=expandSpd*fElapsedTime;
|
||||||
if(particleTimer<=0.f){
|
if(particleTimer<=0.f){
|
||||||
particleTimer+=0.05f;
|
particleTimer+=0.05f;
|
||||||
game->AddEffect(std::make_unique<ShineEffect>(pos,0.1f,0.1f,"pixel.png",2.f,vf2d{},Pixel{239,215,98,192},util::random(2*PI),0.f,true));
|
game->AddEffect(std::make_unique<ShineEffect>(pos,0.1f,0.1f,"pixel.png",2.f,vf2d{},Pixel{239,215,98,192},util::random(2*PI),0.f,true));
|
||||||
|
@ -282,6 +282,7 @@ void Monster::Update(const float fElapsedTime){
|
|||||||
specialMarkApplicationTimer=std::max(0.f,specialMarkApplicationTimer-fElapsedTime);
|
specialMarkApplicationTimer=std::max(0.f,specialMarkApplicationTimer-fElapsedTime);
|
||||||
lastFacingDirectionChange+=fElapsedTime;
|
lastFacingDirectionChange+=fElapsedTime;
|
||||||
timeSpentAlive+=fElapsedTime;
|
timeSpentAlive+=fElapsedTime;
|
||||||
|
floatOscillator.Update(fElapsedTime);
|
||||||
|
|
||||||
if(IsUnconscious()){
|
if(IsUnconscious()){
|
||||||
unconsciousTimer=std::max(0.f,unconsciousTimer-fElapsedTime);
|
unconsciousTimer=std::max(0.f,unconsciousTimer-fElapsedTime);
|
||||||
@ -501,7 +502,7 @@ void Monster::Draw()const{
|
|||||||
else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().duration)))};
|
else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().duration)))};
|
||||||
|
|
||||||
const vf2d hitTimerOffset=vf2d{sin(20*PI*lastHitTimer+randomFrameOffset),0.f}*2.f*GetSizeMult();
|
const vf2d hitTimerOffset=vf2d{sin(20*PI*lastHitTimer+randomFrameOffset),0.f}*2.f*GetSizeMult();
|
||||||
const vf2d zOffset=-vf2d{0,GetZ()};
|
const vf2d zOffset=-vf2d{0,GetZ()}+vf2d{0,(MONSTER_DATA[GetName()].IsFloating()?floatOscillator.get():0.f)};
|
||||||
|
|
||||||
const vf2d drawPos=GetPos()+zOffset+hitTimerOffset;
|
const vf2d drawPos=GetPos()+zOffset+hitTimerOffset;
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ All rights reserved.
|
|||||||
#include "MonsterData.h"
|
#include "MonsterData.h"
|
||||||
#include "Direction.h"
|
#include "Direction.h"
|
||||||
#include "HurtDamageInfo.h"
|
#include "HurtDamageInfo.h"
|
||||||
|
#include "Oscillator.h"
|
||||||
|
|
||||||
INCLUDE_ITEM_DATA
|
INCLUDE_ITEM_DATA
|
||||||
INCLUDE_MONSTER_DATA
|
INCLUDE_MONSTER_DATA
|
||||||
@ -344,6 +345,7 @@ private:
|
|||||||
const float TIME_BETWEEN_LINE_REMOVALS{0.025f};
|
const float TIME_BETWEEN_LINE_REMOVALS{0.025f};
|
||||||
uint8_t scanLine{24};
|
uint8_t scanLine{24};
|
||||||
vf2d afterImagePos{};
|
vf2d afterImagePos{};
|
||||||
|
Oscillator<float>floatOscillator{0.f,8.f,0.5f};
|
||||||
|
|
||||||
struct STRATEGY{
|
struct STRATEGY{
|
||||||
static std::string ERR;
|
static std::string ERR;
|
||||||
|
@ -202,6 +202,7 @@ void MonsterData::InitializeMonsterData(){
|
|||||||
if(DATA["Monsters"][MonsterName].HasProperty("ShowBossIndicator"))monster.hasArrowIndicator=DATA["Monsters"][MonsterName]["ShowBossIndicator"].GetBool();
|
if(DATA["Monsters"][MonsterName].HasProperty("ShowBossIndicator"))monster.hasArrowIndicator=DATA["Monsters"][MonsterName]["ShowBossIndicator"].GetBool();
|
||||||
|
|
||||||
if(DATA["Monsters"][MonsterName].HasProperty("Unconscious Time"))monster.totalUnconsciousTime=DATA["Monsters"][MonsterName]["Unconscious Time"].GetReal();
|
if(DATA["Monsters"][MonsterName].HasProperty("Unconscious Time"))monster.totalUnconsciousTime=DATA["Monsters"][MonsterName]["Unconscious Time"].GetReal();
|
||||||
|
if(DATA["Monsters"][MonsterName].HasProperty("Floating"))monster.floating=DATA["Monsters"][MonsterName]["Floating"].GetBool();
|
||||||
|
|
||||||
if(DATA["Monsters"][MonsterName].HasProperty("Rectangle Collision")){
|
if(DATA["Monsters"][MonsterName].HasProperty("Rectangle Collision")){
|
||||||
const datafile&rectData{DATA["Monsters"][MonsterName]["Rectangle Collision"]};
|
const datafile&rectData{DATA["Monsters"][MonsterName]["Rectangle Collision"]};
|
||||||
@ -482,3 +483,7 @@ const bool MonsterData::FaceTarget()const{
|
|||||||
const float MonsterData::UnconsciousTime()const{
|
const float MonsterData::UnconsciousTime()const{
|
||||||
return totalUnconsciousTime;
|
return totalUnconsciousTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool MonsterData::IsFloating()const{
|
||||||
|
return floating;
|
||||||
|
}
|
@ -109,6 +109,7 @@ public:
|
|||||||
const bool FadeoutWhenStandingBehind()const;
|
const bool FadeoutWhenStandingBehind()const;
|
||||||
const bool FaceTarget()const;
|
const bool FaceTarget()const;
|
||||||
const float UnconsciousTime()const;
|
const float UnconsciousTime()const;
|
||||||
|
const bool IsFloating()const; //A floating monster oscillates back and forth.
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
int hp;
|
int hp;
|
||||||
@ -142,4 +143,5 @@ private:
|
|||||||
bool hasArrowIndicator{false};
|
bool hasArrowIndicator{false};
|
||||||
std::optional<geom2d::rect<float>>rectCollision;
|
std::optional<geom2d::rect<float>>rectCollision;
|
||||||
float totalUnconsciousTime{};
|
float totalUnconsciousTime{};
|
||||||
|
bool floating{false};
|
||||||
};
|
};
|
@ -399,7 +399,7 @@ void Player::Update(float fElapsedTime){
|
|||||||
hpRecoveryTimer=std::max(0.f,hpRecoveryTimer-fElapsedTime);
|
hpRecoveryTimer=std::max(0.f,hpRecoveryTimer-fElapsedTime);
|
||||||
hp6RecoveryTimer=std::max(0.f,hp6RecoveryTimer-fElapsedTime);
|
hp6RecoveryTimer=std::max(0.f,hp6RecoveryTimer-fElapsedTime);
|
||||||
hp4RecoveryTimer=std::max(0.f,hp4RecoveryTimer-fElapsedTime);
|
hp4RecoveryTimer=std::max(0.f,hp4RecoveryTimer-fElapsedTime);
|
||||||
const vf2d previousPosTemp{GetPos()}; //The logic here is that the previous position must be a different value from the actual position and should only change when the position of the player actually changes, this means we must wait for the entire frame to resolve to see if any movement has occurred to update to the "new previous position". This variable is resolved at the bottom of this Update function.
|
|
||||||
RunTimers();
|
RunTimers();
|
||||||
|
|
||||||
PerformHPRecovery();
|
PerformHPRecovery();
|
||||||
@ -856,10 +856,6 @@ void Player::Update(float fElapsedTime){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
if(previousPosTemp!=GetPos()){
|
|
||||||
previousPos=previousPosTemp; //The logic here is that the previous position must be a different value from the actual position and should only change when the position of the player actually changes, this means we must wait for the entire frame to resolve to see if any movement has occurred to update to the "new previous position". The previous position temp variable is set at the top of this Update function.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Player::GetSwordSwingTimer(){
|
float Player::GetSwordSwingTimer(){
|
||||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 1
|
#define VERSION_MAJOR 1
|
||||||
#define VERSION_MINOR 3
|
#define VERSION_MINOR 3
|
||||||
#define VERSION_PATCH 0
|
#define VERSION_PATCH 0
|
||||||
#define VERSION_BUILD 12016
|
#define VERSION_BUILD 12029
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
@ -1333,13 +1333,16 @@ MonsterStrategy
|
|||||||
# Degrees/sec. Positive is CW, Negative is CCW.
|
# Degrees/sec. Positive is CW, Negative is CCW.
|
||||||
Cannon Spell Insignia Rotation Spd = 50
|
Cannon Spell Insignia Rotation Spd = 50
|
||||||
|
|
||||||
|
Ghost Saber Activation Range = 600
|
||||||
Ghost Saber Cooldown = 4s
|
Ghost Saber Cooldown = 4s
|
||||||
Ghost Saber Lifetime = 4s
|
Ghost Saber Lifetime = 4s
|
||||||
# Distance from the boss the ghost sabers should spin around.
|
# Distance from the boss the ghost sabers should spin around.
|
||||||
Ghost Saber Distance = 56px
|
Ghost Saber Distance = 48px
|
||||||
Ghost Saber Radius = 8px
|
Ghost Saber Radius = 8px
|
||||||
Ghost Saber Damage = 75
|
Ghost Saber Damage = 75
|
||||||
Ghost Saber Rotation Spd = 180deg/s
|
Ghost Saber Rotation Spd = 210deg/s
|
||||||
Ghost Saber Knockback Amt = 100
|
Ghost Saber Knockback Amt = 100
|
||||||
|
# Amount of pixels/sec the ghost saber circle expands outwards.
|
||||||
|
Ghost Saber Expand Spd = 14px
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1827,6 +1827,9 @@ Monsters
|
|||||||
# A flag to show an arrow indicator when the boss is off-screen.
|
# A flag to show an arrow indicator when the boss is off-screen.
|
||||||
ShowBossIndicator = True
|
ShowBossIndicator = True
|
||||||
|
|
||||||
|
# Adds a floating up-and-down animation. Only a visual effect.
|
||||||
|
Floating = True
|
||||||
|
|
||||||
Ignore Collisions = True
|
Ignore Collisions = True
|
||||||
|
|
||||||
Strategy = Ghost of Pirate Captain
|
Strategy = Ghost of Pirate Captain
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user