Fix boss text display for longer names. Add in GameEvent handling class. Finish second boss AI. Release build 6380.
This commit is contained in:
parent
f4700dc31d
commit
fed07eddd6
@ -369,6 +369,10 @@
|
||||
</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Error.h" />
|
||||
<ClInclude Include="GameEvent.h">
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FunctionPriming.h">
|
||||
<SubType>
|
||||
</SubType>
|
||||
@ -672,6 +676,10 @@
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameEvent.cpp">
|
||||
<SubType>
|
||||
</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="State_GameRun.cpp" />
|
||||
<ClCompile Include="State_LevelComplete.cpp">
|
||||
<SubType>
|
||||
|
@ -438,6 +438,9 @@
|
||||
<ClInclude Include="DynamicCounter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameEvent.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Player.cpp">
|
||||
@ -752,6 +755,9 @@
|
||||
<ClCompile Include="Wisp.cpp">
|
||||
<Filter>Source Files\Bullet Types</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameEvent.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
|
@ -1051,7 +1051,7 @@ void AiL::RenderWorld(float fElapsedTime){
|
||||
#pragma endregion
|
||||
|
||||
for(Monster&m:MONSTER_LIST){
|
||||
m.strategyDraw(this,m);
|
||||
m.strategyDraw(this,m,MONSTER_DATA[m.GetName()].GetAIStrategy());
|
||||
}
|
||||
|
||||
if(player->GetZ()>0){
|
||||
@ -1744,6 +1744,7 @@ void AiL::LoadLevel(MapName map){
|
||||
foregroundTileGroups.clear();
|
||||
upperForegroundTileGroups.clear();
|
||||
MONSTER_LIST.clear();
|
||||
GameEvent::events.clear();
|
||||
worldColor=WHITE;
|
||||
worldColorFunc=[&](vi2d pos){return game->worldColor;};
|
||||
currentLevel=map;
|
||||
@ -2475,6 +2476,7 @@ void AiL::DisplayBossEncounterInfo(){
|
||||
alpha=uint8_t((bossDisplayTimer)*255);
|
||||
}
|
||||
vf2d textScale={3,5};
|
||||
textScale.x=std::min(3.f,float(ScreenWidth())/GetTextSizeProp(displayText).x);
|
||||
DrawShadowStringPropDecal(vf2d{float(ScreenWidth()/2),float(ScreenHeight()/2)}-vf2d{GetTextSizeProp(displayText)}*textScale/2,displayText,{252, 186, 3, alpha},{128,0,0,alpha},textScale,std::numeric_limits<float>::max(),2);
|
||||
}
|
||||
if(InBossEncounter()){
|
||||
@ -2492,7 +2494,6 @@ void AiL::DisplayBossEncounterInfo(){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AiL::BossDamageDealt(int damage){
|
||||
totalDamageDealt+=damage;
|
||||
}
|
||||
|
@ -60,9 +60,9 @@ void Monster::STRATEGY::BEAR(Monster&m,float fElapsedTime,std::string strategy){
|
||||
m.PerformShootAnimation();
|
||||
m.F(A::CASTING_TIMER)=ConfigFloat("Chargeup Time");
|
||||
m.V(A::LOCKON_POS)=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).vector();
|
||||
m.SetStrategyDrawFunction([](AiL*game,Monster&m){
|
||||
m.SetStrategyDrawFunction([](AiL*game,Monster&m,const std::string&strategy){
|
||||
if(m.IsAlive()){
|
||||
game->view.DrawRotatedDecal(m.GetPos()+m.V(A::LOCKON_POS),GFX["range_indicator.png"].Decal(),0.f,{12.f,12.f},vf2d{_GetFloat(m,"Smash Attack Diameter",MONSTER_DATA[m.GetName()].GetAIStrategy()),_GetFloat(m,"Smash Attack Diameter",MONSTER_DATA[m.GetName()].GetAIStrategy())}/100.f,{255,255,0,160});
|
||||
game->view.DrawRotatedDecal(m.GetPos()+m.V(A::LOCKON_POS),GFX["range_indicator.png"].Decal(),0.f,{12.f,12.f},vf2d{ConfigFloat("Smash Attack Diameter"),ConfigFloat("Smash Attack Diameter")}/100.f,{255,255,0,160});
|
||||
}
|
||||
});
|
||||
m.RotateTowardsPos(m.GetPos()+m.V(A::LOCKON_POS));
|
||||
@ -99,7 +99,7 @@ void Monster::STRATEGY::BEAR(Monster&m,float fElapsedTime,std::string strategy){
|
||||
}
|
||||
m.spriteRot=0.f;
|
||||
game->SetupWorldShake(0.2f);
|
||||
m.SetStrategyDrawFunction([&](AiL*game,Monster&m){});
|
||||
m.SetStrategyDrawFunction([&](AiL*game,Monster&m,const std::string&strategy){});
|
||||
}
|
||||
}break;
|
||||
}
|
||||
|
73
Adventures in Lestoria/GameEvent.cpp
Normal file
73
Adventures in Lestoria/GameEvent.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#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 © 2023 The FreeType
|
||||
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
|
||||
All rights reserved.
|
||||
*/
|
||||
#pragma endregion
|
||||
|
||||
#include "GameEvent.h"
|
||||
#include "Monster.h"
|
||||
#include <map>
|
||||
|
||||
std::vector<std::unique_ptr<GameEvent>>GameEvent::events;
|
||||
|
||||
GameEvent::GameEvent(){}
|
||||
|
||||
GameEvent::~GameEvent(){}
|
||||
|
||||
GameEvent::GameEvent(std::function<bool(GameEvent&)>func)
|
||||
:runFunc(func){}
|
||||
|
||||
void GameEvent::Update(){
|
||||
isActive=runFunc(*this);
|
||||
}
|
||||
|
||||
void GameEvent::UpdateEvents(){
|
||||
for(const std::unique_ptr<GameEvent>&event:events){
|
||||
event->Update();
|
||||
}
|
||||
std::erase_if(events,[](const std::unique_ptr<GameEvent>&ev){return !ev->isActive;});
|
||||
}
|
||||
|
||||
void GameEvent::AddEvent(std::unique_ptr<GameEvent>event){
|
||||
events.push_back(std::move(event));
|
||||
}
|
||||
|
||||
MonsterStrategyGameEvent::MonsterStrategyGameEvent(std::function<bool(GameEvent&,Monster&,const std::string&)>func,Monster&m,const std::string&strategy)
|
||||
:runFunc(func),m(m),strategy(strategy){}
|
||||
|
||||
void MonsterStrategyGameEvent::Update(){
|
||||
INCLUDE_MONSTER_DATA
|
||||
isActive=runFunc(*this,this->m,this->strategy);
|
||||
}
|
70
Adventures in Lestoria/GameEvent.h
Normal file
70
Adventures in Lestoria/GameEvent.h
Normal file
@ -0,0 +1,70 @@
|
||||
#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 © 2023 The FreeType
|
||||
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
|
||||
All rights reserved.
|
||||
*/
|
||||
#pragma endregion
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class GameEvent{
|
||||
friend class AiL;
|
||||
std::function<bool(GameEvent&)>runFunc;
|
||||
static std::vector<std::unique_ptr<GameEvent>>events;
|
||||
protected:
|
||||
bool isActive=true;
|
||||
virtual void Update();
|
||||
public:
|
||||
GameEvent();
|
||||
GameEvent(std::function<bool(GameEvent&)>func);
|
||||
virtual ~GameEvent();
|
||||
static void UpdateEvents();
|
||||
static void AddEvent(std::unique_ptr<GameEvent>event);
|
||||
};
|
||||
|
||||
class Monster;
|
||||
|
||||
class MonsterStrategyGameEvent:public GameEvent{
|
||||
friend class AiL;
|
||||
protected:
|
||||
Monster&m;
|
||||
const std::string&strategy;
|
||||
std::function<bool(GameEvent&,Monster&,const std::string&)>runFunc;
|
||||
virtual void Update()final;
|
||||
public:
|
||||
MonsterStrategyGameEvent(std::function<bool(GameEvent&,Monster&,const std::string&)>func,Monster&m,const std::string&strategy);
|
||||
};
|
@ -133,7 +133,7 @@ bool Monster::_SetX(float x,const bool monsterInvoked){
|
||||
vf2d newPos={x,pos.y};
|
||||
vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth;
|
||||
geom2d::rect<float>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
|
||||
if(collisionRect==game->NO_COLLISION){
|
||||
if(isBoss||collisionRect==game->NO_COLLISION){
|
||||
pos.x=std::clamp(x,game->GetCurrentMapData().tilewidth/2.f*GetSizeMult(),float(game->GetCurrentMapData().width*game->GetCurrentMapData().tilewidth-game->GetCurrentMapData().tilewidth/2.f*GetSizeMult()));
|
||||
Moved();
|
||||
return true;
|
||||
@ -163,7 +163,7 @@ bool Monster::_SetY(float y,const bool monsterInvoked){
|
||||
vf2d newPos={pos.x,y};
|
||||
vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth;
|
||||
geom2d::rect<float>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
|
||||
if(collisionRect==game->NO_COLLISION){
|
||||
if(isBoss||collisionRect==game->NO_COLLISION){
|
||||
pos.y=std::clamp(y,game->GetCurrentMapData().tilewidth/2.f*GetSizeMult(),float(game->GetCurrentMapData().height*game->GetCurrentMapData().tilewidth-game->GetCurrentMapData().tilewidth/2.f*GetSizeMult()));
|
||||
Moved();
|
||||
return true;
|
||||
@ -646,7 +646,7 @@ void Monster::SetZ(float z){
|
||||
this->z=z;
|
||||
}
|
||||
|
||||
void Monster::SetStrategyDrawFunction(std::function<void(AiL*,Monster&)>func){
|
||||
void Monster::SetStrategyDrawFunction(std::function<void(AiL*,Monster&,const std::string&)>func){
|
||||
strategyDraw=func;
|
||||
}
|
||||
|
||||
@ -671,6 +671,10 @@ void Monster::OnDeath(){
|
||||
game->ReduceBossEncounterMobCount();
|
||||
}
|
||||
|
||||
if(hasStrategyDeathFunction){
|
||||
GameEvent::AddEvent(std::make_unique<MonsterStrategyGameEvent>(strategyDeathFunc,*this,MONSTER_DATA[name].GetAIStrategy()));
|
||||
}
|
||||
|
||||
SpawnDrops();
|
||||
|
||||
game->GetPlayer()->AddAccumulatedXP(MONSTER_DATA.at(name).GetXP());
|
||||
@ -752,3 +756,8 @@ const float Monster::GetCollisionDamage()const{
|
||||
if(collisionDmg>0)return collisionDmg;
|
||||
else return MONSTER_DATA[name].GetCollisionDmg();
|
||||
}
|
||||
|
||||
void Monster::SetStrategyDeathFunction(std::function<bool(GameEvent&,Monster&,const std::string&)>func){
|
||||
hasStrategyDeathFunction=true;
|
||||
strategyDeathFunc=func;
|
||||
}
|
@ -45,6 +45,7 @@ All rights reserved.
|
||||
#include "Item.h"
|
||||
#include "safemap.h"
|
||||
#include "Pathfinding.h"
|
||||
#include "GameEvent.h"
|
||||
|
||||
INCLUDE_ITEM_DATA
|
||||
|
||||
@ -95,7 +96,7 @@ struct MonsterData{
|
||||
const uint32_t GetXP()const;
|
||||
float GetMoveSpdMult();
|
||||
float GetSizeMult();
|
||||
std::string GetAIStrategy();
|
||||
const std::string&GetAIStrategy()const;
|
||||
int GetCollisionDmg();
|
||||
std::string GetIdleAnimation();
|
||||
std::string GetJumpAnimation();
|
||||
@ -113,6 +114,7 @@ struct MonsterData{
|
||||
static std::map<std::string,Renderable*>imgs;
|
||||
};
|
||||
|
||||
class GameEvent;
|
||||
|
||||
class Monster:IAttributable{
|
||||
friend struct STRATEGY;
|
||||
@ -171,8 +173,8 @@ public:
|
||||
const std::function<void(Monster&,float,std::string)>&GetStrategy()const;
|
||||
void SetSize(float newSize,bool immediate=true);
|
||||
geom2d::circle<float>Hitbox();
|
||||
void SetStrategyDrawFunction(std::function<void(AiL*,Monster&)>func);
|
||||
std::function<void(AiL*,Monster&)>strategyDraw=[](AiL*pge,Monster&m){};
|
||||
void SetStrategyDrawFunction(std::function<void(AiL*,Monster&,const std::string&)>func);
|
||||
std::function<void(AiL*,Monster&,const std::string&)>strategyDraw=[](AiL*pge,Monster&m,const std::string&strategy){};
|
||||
const ItemAttributable&GetStats()const;
|
||||
const EventName&GetHurtSound();
|
||||
const EventName&GetDeathSound();
|
||||
@ -228,6 +230,9 @@ private:
|
||||
float targetSize=0;
|
||||
bool isBoss=false;
|
||||
void OnDeath();
|
||||
bool hasStrategyDeathFunction=false;
|
||||
std::function<bool(GameEvent&,Monster&,const std::string&)>strategyDeathFunc;
|
||||
void SetStrategyDeathFunction(std::function<bool(GameEvent&,Monster&,const std::string&)>func);
|
||||
ItemAttribute&Get(std::string_view attr);
|
||||
//Returns false if the monster could not be moved to the requested location due to collision.
|
||||
//If monsterInvoked is true, this means the monster was the one that instantiated this input, and it's not an extra movement done via collision.
|
||||
|
@ -89,4 +89,5 @@ enum class Attribute{
|
||||
ENVIRONMENT_TIMER,
|
||||
ENVIRONMENT_PHASE,
|
||||
CHARGE_COOLDOWN,
|
||||
BULLETS_REMOVED,
|
||||
};
|
@ -221,7 +221,7 @@ float MonsterData::GetSizeMult(){
|
||||
int MonsterData::GetCollisionDmg(){
|
||||
return collisionDmg;
|
||||
}
|
||||
std::string MonsterData::GetAIStrategy(){
|
||||
const std::string&MonsterData::GetAIStrategy()const{
|
||||
return strategy;
|
||||
}
|
||||
std::string MonsterData::GetDisplayName(){
|
||||
|
@ -133,9 +133,9 @@ const void SaveFile::SaveGame(){
|
||||
}
|
||||
std::string contents=fileContents.str();
|
||||
emscripten_idb_async_store("/assets",("save_file_path"_S+std::format("save.{:04}",saveFileID)).c_str(),contents.data(),contents.length(),0,[](void*arg){
|
||||
std::cout<<"Success!"<<std::endl;
|
||||
std::cout<<"Successfully saved save file "<<saveFileID<<"!"<<std::endl;
|
||||
},[](void*arg){
|
||||
std::cout<<"Failed!"<<std::endl;
|
||||
std::cout<<"Failed to save save file "<<saveFileID<<"!"<<std::endl;
|
||||
});
|
||||
|
||||
file.close();
|
||||
@ -355,12 +355,14 @@ const void SaveFile::Server_SaveMetadataFile(std::function<void(std::string_view
|
||||
fileContents<<char(val);
|
||||
}
|
||||
}
|
||||
std::string contents=fileContents.str();
|
||||
emscripten_idb_async_store("/assets",("save_file_path"_S+"metadata.dat").c_str(),contents.data(),contents.length(),0,[](void*arg){
|
||||
std::cout<<"Success 2!"<<std::endl;
|
||||
},[](void*arg){
|
||||
std::cout<<"Failed 2!"<<std::endl;
|
||||
});
|
||||
#ifdef __EMSCRIPTEN__
|
||||
std::string contents=fileContents.str();
|
||||
emscripten_idb_async_store("/assets",("save_file_path"_S+"metadata.dat").c_str(),contents.data(),contents.length(),0,[](void*arg){
|
||||
std::cout<<"Saved metadata successfully!"<<std::endl;
|
||||
},[](void*arg){
|
||||
std::cout<<"Failed to save metadata!"<<std::endl;
|
||||
});
|
||||
#endif
|
||||
game->SendRequest("save_server"_S,CreateServerRequest(SaveFileOperation::SAVE_METADATA_FILE,fileContents.str()));
|
||||
game->responseCallback=respCallbackFunc;
|
||||
}
|
||||
|
@ -212,10 +212,10 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,std::string strat
|
||||
}
|
||||
m.SetZ(0);
|
||||
Landed(m.phase);
|
||||
m.SetStrategyDrawFunction([](AiL*game,Monster&m){});
|
||||
m.SetStrategyDrawFunction([](AiL*game,Monster&m,const std::string&strategy){});
|
||||
} else
|
||||
if(m.F(A::JUMP_LANDING_TIMER)<=ConfigFloat("JumpWarningIndicatorTime")){
|
||||
m.SetStrategyDrawFunction([](AiL*game,Monster&m){
|
||||
m.SetStrategyDrawFunction([](AiL*game,Monster&m,const std::string&strategy){
|
||||
Decal*dec=GFX["range_indicator.png"].Decal();
|
||||
game->view.DrawRotatedDecal(m.GetPos(),dec,0,dec->sprite->Size()/2,vf2d{m.GetSizeMult(),m.GetSizeMult()},RED);
|
||||
});
|
||||
|
@ -42,6 +42,7 @@ All rights reserved.
|
||||
#include "ItemDrop.h"
|
||||
#include "VisualNovel.h"
|
||||
#include "State_OverworldMap.h"
|
||||
#include "GameEvent.h"
|
||||
|
||||
INCLUDE_MONSTER_LIST
|
||||
INCLUDE_game
|
||||
@ -81,6 +82,7 @@ void State_GameRun::OnUserUpdate(AiL*game){
|
||||
game->HandleUserInput(game->GetElapsedTime());
|
||||
|
||||
game->UpdateEffects(game->GetElapsedTime());
|
||||
GameEvent::UpdateEvents();
|
||||
game->GetPlayer()->Update(game->GetElapsedTime());
|
||||
for(Monster&m:MONSTER_LIST){
|
||||
m.Update(game->GetElapsedTime());
|
||||
|
@ -53,15 +53,47 @@ INCLUDE_DATA
|
||||
using A=Attribute;
|
||||
|
||||
void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy){
|
||||
|
||||
switch(m.phase){
|
||||
case 0:{
|
||||
m.phase=ConfigInt("StartPhase");
|
||||
m.overlaySprite=ConfigString("Overlay Sprite");
|
||||
m.overlaySpriteTransparency=0U;
|
||||
|
||||
#pragma region Setup On Death Function
|
||||
m.SetStrategyDeathFunction([&](GameEvent&event,Monster&m,const std::string&strategy){
|
||||
if(!m.B(A::BULLETS_REMOVED)){
|
||||
for(const std::unique_ptr<Bullet>&b:BULLET_LIST){
|
||||
b->deactivated=true;
|
||||
b->fadeOutTime=ConfigFloat("Phase 4.End Wisp Fadeout Time");
|
||||
}
|
||||
m.B(A::BULLETS_REMOVED)=true;
|
||||
}
|
||||
m.F(A::ENVIRONMENT_TIMER)=std::max(0.f,m.F(A::ENVIRONMENT_TIMER)-game->GetElapsedTime());
|
||||
switch(m.I(A::ENVIRONMENT_PHASE)){
|
||||
case 0:{ //Fade out. Use the phase 2 environment fade-in color as the previous color to lerp out from.
|
||||
game->SetWorldColor(ConfigPixel("Phase 4.Environment Fade-in Color")*util::lerp(0.f,1.0f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 4.Environment Fade-out Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
game->SetWorldColor({0,0,0,255});
|
||||
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 4.Environment Fade-in Time");
|
||||
m.I(A::ENVIRONMENT_PHASE)++;
|
||||
game->SetWorldColorFunc([&](vi2d pos){return game->GetWorldColor();});
|
||||
}
|
||||
}break;
|
||||
case 1:{ //Fade in.
|
||||
Pixel fadeInCol=ConfigPixel("Phase 3.Environment Fade-in Color");
|
||||
|
||||
game->SetWorldColor(fadeInCol*util::lerp(1.f,0.f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 4.Environment Fade-in Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
game->SetWorldColor(fadeInCol);
|
||||
return false;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
#pragma endregion
|
||||
}break;
|
||||
case 1:{ //Run bear strategy in phase 1.
|
||||
|
||||
auto TransitionToPhase2=[&](){
|
||||
m.phase=2;
|
||||
m.PerformOtherAnimation(1);
|
||||
@ -125,14 +157,14 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 2.Environment Fade-in Time");
|
||||
m.I(A::ENVIRONMENT_PHASE)++;
|
||||
game->SetWorldColorFunc([&](vi2d pos){
|
||||
float fadeInRange=DATA["MonsterStrategy"]["Ursule"]["Phase 2"]["Environment Fade-In Range"].GetReal()/100.f*24.f;
|
||||
float fadeInRange=DATA["MonsterStrategy"]["Ursule"]["Phase 2"]["Environment Fade-in Range"].GetReal()/100.f*24.f;
|
||||
float distToPlayer=geom2d::line<float>(game->GetPlayer()->GetPos(),pos).length();
|
||||
return game->GetWorldColor()*std::min(1.0f,fadeInRange/distToPlayer);
|
||||
});
|
||||
}
|
||||
}break;
|
||||
case 1:{ //Fade in.
|
||||
Pixel fadeInCol=ConfigPixel("Phase 2.Environment Fade-In Color");
|
||||
Pixel fadeInCol=ConfigPixel("Phase 2.Environment Fade-in Color");
|
||||
|
||||
game->SetWorldColor(fadeInCol*util::lerp(1.f,0.f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 2.Environment Fade-in Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
@ -180,7 +212,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
|
||||
auto TransitionToPhase3=[&](){
|
||||
m.phase=3;
|
||||
game->SetWorldColor(ConfigPixel("Phase 3.Environment Fade-In Color"));
|
||||
game->SetWorldColor(ConfigPixel("Phase 3.Environment Fade-in Color"));
|
||||
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 3.Environment Fade-in Time");
|
||||
m.I(A::ENVIRONMENT_PHASE)=0;
|
||||
m.RemoveBuff(BARRIER_DAMAGE_REDUCTION);
|
||||
@ -204,7 +236,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
m.F(A::ENVIRONMENT_TIMER)=std::max(0.f,m.F(A::ENVIRONMENT_TIMER)-fElapsedTime);
|
||||
switch(m.I(A::ENVIRONMENT_PHASE)){
|
||||
case 0:{ //Fade out. Use the phase 2 environment fade-in color as the previous color to lerp out from.
|
||||
game->SetWorldColor(ConfigPixel("Phase 2.Environment Fade-In Color")*util::lerp(0.f,1.0f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 3.Environment Fade-out Time")));
|
||||
game->SetWorldColor(ConfigPixel("Phase 2.Environment Fade-in Color")*util::lerp(0.f,1.0f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 3.Environment Fade-out Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
game->SetWorldColor({0,0,0,255});
|
||||
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 3.Environment Fade-in Time");
|
||||
@ -213,7 +245,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
}
|
||||
}break;
|
||||
case 1:{ //Fade in.
|
||||
Pixel fadeInCol=ConfigPixel("Phase 3.Environment Fade-In Color");
|
||||
Pixel fadeInCol=ConfigPixel("Phase 3.Environment Fade-in Color");
|
||||
|
||||
game->SetWorldColor(fadeInCol*util::lerp(1.f,0.f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 3.Environment Fade-in Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
@ -233,7 +265,6 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
auto TransitionToPhase5=[&](){
|
||||
m.phase=5;
|
||||
m.PerformOtherAnimation(1);
|
||||
m.I(A::PHASE_REPEAT_COUNT)=ConfigInt("Phase 4.Wisp Pattern Spawn Count");
|
||||
SoundEffect::PlaySFX("Ursule Phase Transition",SoundEffect::CENTERED);
|
||||
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 4.Environment Fade-out Time");
|
||||
m.I(A::ENVIRONMENT_PHASE)=0;
|
||||
@ -273,6 +304,10 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
m.AddBuff(FIXED_COLLISION_DMG,10.f,ConfigFloat("Phase 3.Charge Attack Damage"));
|
||||
m.AddBuff(COLLISION_KNOCKBACK_STRENGTH,10.f,ConfigFloat("Phase 3.Charge Attack Knockback Strength"));
|
||||
m.target=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).upoint(2.0f);
|
||||
//It's possible the charge forces the bear outside the map, so it will attempt to run forever on the clamped edges.
|
||||
m.target.x=std::clamp(m.target.x,0.f,float(game->GetCurrentMap().MapData.width*game->GetCurrentMap().MapData.tilewidth));
|
||||
m.target.y=std::clamp(m.target.y,0.f,float(game->GetCurrentMap().MapData.height*game->GetCurrentMap().MapData.tileheight));
|
||||
m.F(A::TARGET_TIMER)=ConfigFloat("Phase 3.Charge Max Run Time");
|
||||
m.F(A::CHARGE_COOLDOWN)=ConfigFloat("Phase 3.Charge Attack Cooldown");
|
||||
m.PerformOtherAnimation(3);
|
||||
break;
|
||||
@ -284,6 +319,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
BEAR(m,fElapsedTime,"Bear");
|
||||
}break;
|
||||
case 4:{ //A charging phase.
|
||||
m.F(A::TARGET_TIMER)=std::max(0.f,m.F(A::TARGET_TIMER)-fElapsedTime);
|
||||
|
||||
if(geom2d::line(m.pos,m.target).length()>100*fElapsedTime*m.GetMoveSpdMult()){
|
||||
vf2d newPos=m.pos+geom2d::line(m.pos,m.target).vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
|
||||
@ -292,7 +328,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
|
||||
float distToTarget=geom2d::line<float>(m.target,m.GetPos()).length();
|
||||
|
||||
if(distToTarget<=4.f){
|
||||
if(distToTarget<=4.f||m.F(A::TARGET_TIMER)==0.f){
|
||||
m.phase=3;
|
||||
m.RemoveBuff(SPEEDBOOST);
|
||||
m.RemoveBuff(FIXED_COLLISION_DMG);
|
||||
@ -301,24 +337,27 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
|
||||
}
|
||||
}break;
|
||||
case 5:{ //Final boss phase.
|
||||
m.PerformOtherAnimation(2);
|
||||
m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime);
|
||||
|
||||
#pragma region Environment Color Change Handling
|
||||
m.F(A::ENVIRONMENT_TIMER)=std::max(0.f,m.F(A::ENVIRONMENT_TIMER)-fElapsedTime);
|
||||
switch(m.I(A::ENVIRONMENT_PHASE)){
|
||||
case 0:{ //Fade out. Use the phase 3 environment fade-in color as the previous color to lerp out from.
|
||||
game->SetWorldColor(ConfigPixel("Phase 3.Environment Fade-In Color")*util::lerp(0.f,1.0f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 4.Environment Fade-out Time")));
|
||||
game->SetWorldColor(ConfigPixel("Phase 3.Environment Fade-in Color")*util::lerp(0.f,1.0f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 4.Environment Fade-out Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
game->SetWorldColor({0,0,0,255});
|
||||
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 4.Environment Fade-in Time");
|
||||
m.I(A::ENVIRONMENT_PHASE)++;
|
||||
game->SetWorldColorFunc([&](vi2d pos){
|
||||
float fadeInRange=DATA["MonsterStrategy"]["Ursule"]["Phase 4"]["Environment Fade-In Range"].GetReal()/100.f*24.f;
|
||||
float fadeInRange=DATA["MonsterStrategy"]["Ursule"]["Phase 4"]["Environment Fade-in Range"].GetReal()/100.f*24.f;
|
||||
float distToPlayer=geom2d::line<float>(game->GetPlayer()->GetPos(),pos).length();
|
||||
return game->GetWorldColor()*std::min(1.0f,fadeInRange/distToPlayer);
|
||||
});
|
||||
}
|
||||
}break;
|
||||
case 1:{ //Fade in.
|
||||
Pixel fadeInCol=ConfigPixel("Phase 4.Environment Fade-In Color");
|
||||
Pixel fadeInCol=ConfigPixel("Phase 4.Environment Fade-in Color");
|
||||
game->SetWorldColor(fadeInCol*util::lerp(1.f,0.f,m.F(A::ENVIRONMENT_TIMER)/ConfigFloat("Phase 4.Environment Fade-in Time")));
|
||||
if(m.F(A::ENVIRONMENT_TIMER)==0.f){
|
||||
game->SetWorldColor(fadeInCol);
|
||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_BUILD 6336
|
||||
#define VERSION_BUILD 6380
|
||||
|
||||
#define stringify(a) stringify_(a)
|
||||
#define stringify_(a) #a
|
||||
|
@ -264,7 +264,7 @@
|
||||
<object id="2" name="Player Spawn" type="PlayerSpawnLocation" x="792" y="1248" width="24" height="24"/>
|
||||
<object id="3" name="Slime King Spawn Area" type="SpawnGroup" x="306" y="384" width="1110" height="834">
|
||||
<properties>
|
||||
<property name="Boss Title Display" value="Slime King"/>
|
||||
<property name="Boss Title Display" value="Ursule, Mother of Bears"/>
|
||||
</properties>
|
||||
<ellipse/>
|
||||
</object>
|
||||
|
@ -347,10 +347,10 @@ MonsterStrategy
|
||||
Environment Fade-in Time = 2.0s
|
||||
|
||||
# New fade-in environment color.
|
||||
Environment Fade-In Color = 87, 82, 255, 255
|
||||
Environment Fade-in Color = 87, 82, 255, 255
|
||||
|
||||
# The amount of range sight the player has with the new environment.
|
||||
Environment Fade-In Range = 400
|
||||
Environment Fade-in Range = 400
|
||||
|
||||
# Wisp size in pixels.
|
||||
Wisp Size = 24,24
|
||||
@ -389,13 +389,16 @@ MonsterStrategy
|
||||
Environment Fade-in Time = 2.0s
|
||||
|
||||
# New fade-in environment color.
|
||||
Environment Fade-In Color = 255, 255, 255, 255
|
||||
Environment Fade-in Color = 255, 255, 255, 255
|
||||
|
||||
# Minimum range the bear will decide to charge the player.
|
||||
Charge Range = 450
|
||||
|
||||
# Amount of time the bear spends preparing to charge.
|
||||
Charge Cast Time = 0.1s
|
||||
Charge Cast Time = 0.3s
|
||||
|
||||
# If for some reason the charge takes longer than this to reach the target, the charge will end.
|
||||
Charge Max Run Time = 5.0s
|
||||
|
||||
# Amount of speed to gain during the charge attack.
|
||||
Charge Speed Boost = 200%
|
||||
@ -424,10 +427,10 @@ MonsterStrategy
|
||||
Environment Fade-in Time = 2.0s
|
||||
|
||||
# New fade-in environment color.
|
||||
Environment Fade-In Color = 255, 82, 82, 255
|
||||
Environment Fade-in Color = 255, 82, 82, 255
|
||||
|
||||
# The amount of range sight the player has with the new environment.
|
||||
Environment Fade-In Range = 400
|
||||
Environment Fade-in Range = 400
|
||||
|
||||
# Wisp size in pixels.
|
||||
Wisp Size = 24,24
|
||||
@ -450,6 +453,9 @@ MonsterStrategy
|
||||
|
||||
# This value is either Bag or Random. Bag means every pattern gets selected once before re-cycling. Random is truly random with potential repeats.
|
||||
Wisp Pattern Random Selection = Random
|
||||
|
||||
# How long it takes for remaining wisps on the field to fade out when the boss dies.
|
||||
End Wisp Fadeout Time = 0.4s
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user