Blizzard Particle Effects+Spell casting preparation and implementation. Added Skeleton Frost Mage. Release Build 12481.
Some checks failed
Emscripten Build / Build_and_Deploy_Web_Build (push) Failing after 5m17s

This commit is contained in:
sigonasr2 2026-02-09 15:15:16 -06:00
parent 68b9330569
commit d384478792
31 changed files with 284 additions and 66 deletions

View File

@ -396,7 +396,7 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="Blizzard.h" />
<ClInclude Include="BlizzardSnowEmitter.h" />
<ClInclude Include="BombBoom.h">
<SubType>
</SubType>
@ -415,7 +415,8 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="FriendlyTag.h" />
<ClInclude Include="FallEffect.h" />
<ClInclude Include="FriendlyType.h" />
<ClInclude Include="HurtDamageInfo.h">
<SubType>
</SubType>
@ -824,6 +825,11 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Blizzard.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="BlizzardSnowEmitter.cpp" />
<ClCompile Include="Boar.cpp">
<SubType>
</SubType>

View File

@ -726,12 +726,15 @@
<ClInclude Include="MonsterAbility.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Blizzard.h">
<Filter>Source Files\Effects</Filter>
</ClInclude>
<ClInclude Include="FriendlyTag.h">
<ClInclude Include="FriendlyType.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BlizzardSnowEmitter.h">
<Filter>Source Files\Emitters</Filter>
</ClInclude>
<ClInclude Include="FallEffect.h">
<Filter>Source Files\Effects</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Player.cpp">
@ -1355,6 +1358,12 @@
<ClCompile Include="SkeletonFireMage.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
<ClCompile Include="BlizzardSnowEmitter.cpp">
<Filter>Header Files</Filter>
</ClCompile>
<ClCompile Include="Blizzard.cpp">
<Filter>Source Files\Effects</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

View File

@ -811,7 +811,7 @@ void AiL::UpdateEffects(float fElapsedTime){
e->Update(fElapsedTime);
}
std::erase_if(EMITTER_LIST,[](std::unique_ptr<Emitter>&e){return e->dead;});
std::erase_if(EMITTER_LIST,[](std::unique_ptr<IEmitter>&e){return e->dead;});
std::erase_if(backgroundEffects,[](std::unique_ptr<Effect>&e){return e->dead;});
std::erase_if(foregroundEffects,[](std::unique_ptr<Effect>&e){return e->dead;});
std::erase_if(DAMAGENUMBER_LIST,[](std::shared_ptr<DamageNumber>&n){return n->IsDead();});

View File

@ -0,0 +1,59 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2026 Amy 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<ranges>
INCLUDE_game
Blizzard::Blizzard(const vf2d pos,const float radius, const float lifetime,const int damage,const float tickRate,const Range snowSizeRange,const float emitterFreq,const bool upperLevel,const FriendlyType friendly)
:damage(damage),tickRate(tickRate),tickTimer(tickRate),radius(radius),friendly(friendly),Effect(pos,lifetime,"aiming_target.png",upperLevel,(radius*2/100)*vf2d{1.f,1.f},0.5f,{},{199,247,239,128},0.f,0.f,true)
,snow(std::make_unique<BlizzardSnowEmitter>(pos,"circle.png",radius,snowSizeRange,emitterFreq,lifetime,upperLevel)){
for(int i:std::ranges::iota_view(0,100))snow->Emit();
}
bool Blizzard::Update(float fElapsedTime){
tickTimer-=fElapsedTime;
if(tickTimer<=0.f){
tickTimer+=tickRate;
game->Hurt(pos,radius,damage,OnUpperLevel(),z,friendly?HurtType::MONSTER:HurtType::PLAYER);
}
snow->Update(fElapsedTime);
}
void Blizzard::Draw(const Pixel blendCol)const{
}

View File

@ -0,0 +1,60 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2026 Amy 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"BlizzardSnowEmitter.h"
#include"AdventuresInLestoria.h"
#include"FallEffect.h"
INCLUDE_game
BlizzardSnowEmitter::BlizzardSnowEmitter(const vf2d pos,const std::string&img_filename,const float radius,Range scaleRange,float frequency,float timer,const bool upperLevel)
:pos(pos),img_filename(img_filename),radius(radius),scaleRange(scaleRange),upperLevel(upperLevel),IEmitter(frequency,timer){}
void BlizzardSnowEmitter::Emit(){
const float dist{util::random_range(0,radius)};
const float startingZ{util::random_range(0,100)};
const float gravity{util::random_range(10,40)};
const float scale{util::random_range(scaleRange.first,scaleRange.second)};
const float xSpd{-5.f};
const float timeToFall{startingZ/gravity};
const float colorInterpolation{util::random(1)};
const Pixel baseCol{104,215,239};
const uint8_t alpha{uint8_t(util::random_range(96,255))};
game->AddEffect(std::make_unique<FallEffect>(pos+vf2d{xSpd*timeToFall,0.f},startingZ,gravity,img_filename,upperLevel,scale*vf2d{1.f,1.f},0.5f,vf2d{xSpd,0.f},Pixel{uint8_t(util::lerp(float(baseCol.r),255.f,colorInterpolation)),uint8_t(util::lerp(float(baseCol.g),255.f,colorInterpolation)),uint8_t(util::lerp(float(baseCol.b),255.f,colorInterpolation)),alpha},util::degToRad(util::random_range(0,360)),util::degToRad(util::random_range(-1.f,1.f)),true,EffectType::BLIZZARD_SNOW));
}

View File

@ -36,9 +36,22 @@ All rights reserved.
*/
#pragma endregion
#pragma once
namespace Friendly{
enum FriendlyType{
FRIENDLY,
NON_FRIENDLY,
};
}
#include"Emitter.h"
#include"olcUTIL_Geometry2D.h"
using MinScale=float;
using MaxScale=float;
using Range=std::pair<MinScale,MaxScale>;
class BlizzardSnowEmitter:public IEmitter{
public:
BlizzardSnowEmitter(const olc::vf2d pos,const std::string&img_filename,const float radius,Range scaleRange,float frequency,float timer,const bool upperLevel);
virtual void Emit()override final;
private:
const olc::vf2d pos;
const float radius;
const Range scaleRange;
const std::string img_filename;
const bool upperLevel;
};

View File

@ -51,7 +51,7 @@ using MonsterSpawnerID=int;
#define INCLUDE_game extern AiL*game;
#define INCLUDE_MONSTER_DATA extern std::map<std::string,MonsterData>MONSTER_DATA;
#define INCLUDE_BULLET_LIST extern std::vector<std::unique_ptr<IBullet>>BULLET_LIST;
#define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<Emitter>>EMITTER_LIST;
#define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<IEmitter>>EMITTER_LIST;
#define INCLUDE_DATA extern utils::datafile DATA;
#define INCLUDE_STRATEGY_DATA extern safemap<std::string,std::function<void(Monster&,float,std::string)>>STRATEGY_DATA;
#define INCLUDE_TILE_ANIMATION_DATA extern std::map<int,std::vector<std::pair<int,float>>>TILE_ANIMATION_DATA;

View File

@ -37,7 +37,7 @@ All rights reserved.
#pragma endregion
#pragma once
#include "olcUTIL_Geometry2D.h"
#include"FriendlyTag.h"
#include"FriendlyType.h"
namespace DamageNumberType{
enum DamageNumberType{

View File

@ -42,7 +42,8 @@ All rights reserved.
#include <variant>
#include "Oscillator.h"
#include "Entity.h"
#include"FriendlyTag.h"
#include"FriendlyType.h"
#include"BlizzardSnowEmitter.h"
class Monster;
class Player;
using HitList=std::unordered_set<std::variant<Monster*,Player*>>;
@ -53,6 +54,7 @@ enum class EffectType{
MONSTER_SOUL,
BLINK_PORTAL,
TRAIL_OF_FIRE,
BLIZZARD_SNOW,
};
struct Effect{
@ -258,4 +260,18 @@ struct CollectCoinEffect:Effect{
const Entity attachedTarget;
Oscillator<float>sizeFlipper;
Oscillator<float>zRiser;
};
struct Blizzard:Effect{
public:
Blizzard(const vf2d pos,const float radius,const float lifetime,const int damage,const float tickRate,const Range snowSizeRange,const float emitterFreq,const bool upperLevel,const FriendlyType friendly);
bool Update(float fElapsedTime)override;
void Draw(const Pixel blendCol)const override;
private:
const int damage;
const int tickRate;
int tickTimer;
const float radius;
const FriendlyType friendly;
const std::unique_ptr<BlizzardSnowEmitter>snow;
};

View File

@ -38,12 +38,12 @@ All rights reserved.
#include "Emitter.h"
#include <memory>
std::vector<std::unique_ptr<Emitter>>EMITTER_LIST;
std::vector<std::unique_ptr<IEmitter>>EMITTER_LIST;
Emitter::Emitter(float frequency,float timer)
IEmitter::IEmitter(float frequency,float timer)
:frequency(frequency),timer(timer){}
bool Emitter::Update(float fElapsedTime){
bool IEmitter::Update(float fElapsedTime){
lastEmit=std::max(lastEmit-fElapsedTime,0.f);
if(lastEmit==0){
lastEmit=frequency;

View File

@ -38,7 +38,7 @@ All rights reserved.
#pragma once
#include "olcUTIL_Geometry2D.h"
struct Emitter{
struct IEmitter{
friend class AiL;
float frequency;
float timer;
@ -46,13 +46,13 @@ struct Emitter{
private:
bool dead=false;
public:
virtual ~Emitter()=default;
Emitter(float frequency,float timer);
virtual ~IEmitter()=default;
IEmitter(float frequency,float timer);
bool Update(float fElapsedTime);
virtual void Emit()=0;
};
class LightningBoltEmitter:public Emitter{
class LightningBoltEmitter:public IEmitter{
vf2d startPos,endPos;
bool upperLevel;
void DrawLightningBolt();

View File

@ -35,29 +35,26 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include"AdventuresInLestoria.h"
#include"Emitter.h"
#include "Effect.h"
#include "DEFINES.h"
#include "safemap.h"
INCLUDE_game
INCLUDE_GFX
struct Blizzard:Effect{
//This class is used when you want an effect to start in mid-air and fall down. It disappears upon hitting the ground.
class FallEffect:public Effect{
public:
inline Blizzard(const vf2d pos,const float radius, const float lifetime,const int damage,const float tickRate,const bool upperLevel,const )
:damage(damage),tickRate(tickRate),tickTimer(tickRate),radius(radius),Effect(pos,lifetime,"aiming_target.png",upperLevel,(radius*2/100)*vf2d{1.f,1.f},0.5f,{},{199,247,239,128},0.f,0.f,true){}
inline bool Update(float fElapsedTime)override{
tickTimer-=fElapsedTime;
if(tickTimer<=0.f){
tickTimer+=tickRate;
game->Hurt(
}
inline FallEffect(vf2d pos,const float z,const float gravity,const std::string&imgFile, bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,const EffectType type=EffectType::NONE)
:gravity(gravity),Effect(pos,INFINITY,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){
this->z=z;
this->SetType(type);
}
inline void Draw(const Pixel blendCol)const override{
inline bool Update(float fElapsedTime)override{
z-=gravity*fElapsedTime;
if(z<=0.f)lifetime=0.f;
return Effect::Update(fElapsedTime);
}
private:
Emitter snow{;
const int damage;
const int tickRate;
int tickTimer;
const float radius;
const float gravity;
};

View File

@ -41,16 +41,16 @@ All rights reserved.
INCLUDE_GFX
class FallingDebris:public Effect{
const float GRAVITY=20;
class FallEffect:public Effect{
const float gravity=20;
public:
inline FallingDebris(vf2d pos, float lifetime, std::string imgFile, bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false)
inline FallEffect(vf2d pos, float lifetime,const std::string&imgFile, bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false)
:Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){
}
inline bool Update(float fElapsedTime)override{
spd.y+=GRAVITY*fElapsedTime;
spd.y+=gravity*fElapsedTime;
return Effect::Update(fElapsedTime);
}
};

View File

@ -40,7 +40,7 @@ All rights reserved.
#include "olcUTIL_Animate2D.h"
#include "Monster.h"
#include "DEFINES.h"
#include"FriendlyTag.h"
#include"FriendlyType.h"
using HitList=std::unordered_set<std::variant<Monster*,Player*>>;
enum class HurtType{

View File

@ -63,7 +63,7 @@ void LargeStone::Update(float fElapsedTime){
for(int i=0;i<100;i++){
const float randomDir{util::random(2*PI)};
game->AddEffect(std::make_unique<FallingDebris>(pos+vf2d{radius,randomDir}.cart(),0.f,"circle.png",OnUpperLevel(),vf2d{1.5f,1.5f}*util::random(2.f),util::random(1.f),vf2d{vf2d{radius,randomDir}.cart().x,-util::random(30.f)-20.f},BLACK));
game->AddEffect(std::make_unique<FallEffect>(pos+vf2d{radius,randomDir}.cart(),0.f,"circle.png",OnUpperLevel(),vf2d{1.5f,1.5f}*util::random(2.f),util::random(1.f),vf2d{vf2d{radius,randomDir}.cart().x,-util::random(30.f)-20.f},BLACK));
}
const HurtList pillarList{game->HurtMonsterType(pos,radius,3,OnUpperLevel(),GetZ(),"Stone Golem Pillar")};

View File

@ -44,7 +44,7 @@ All rights reserved.
INCLUDE_game
LightningBoltEmitter::LightningBoltEmitter(vf2d startPos,vf2d endPos,float frequency,float timer,bool upperLevel)
:startPos(startPos),endPos(endPos),Emitter(frequency,timer),upperLevel(upperLevel){}
:startPos(startPos),endPos(endPos),IEmitter(frequency,timer),upperLevel(upperLevel){}
void LightningBoltEmitter::Emit(){

View File

@ -1797,7 +1797,7 @@ void Monster::CastAbility(const MonsterAbilityData&data,const vf2d pos){
}
void Monster::PerformSpell(const CastInfo&castData){
MonsterAbility::SPELLS.at(castData.name)(castData.name,castData.castPos,GetWeakPointer());
MonsterAbility::SPELLS.at(castData.name)(castData.name,castData.castPos,*this,GetStrategyName());
PerformIdleAnimation();
mp-=castData.mpCost;
}

View File

@ -50,6 +50,7 @@ All rights reserved.
#include "Direction.h"
#include "HurtDamageInfo.h"
#include "Oscillator.h"
#include"MonsterStrategyHelpers.h"
INCLUDE_ITEM_DATA
INCLUDE_MONSTER_DATA
@ -61,8 +62,6 @@ enum class Attribute;
class GameEvent;
using StrategyName=std::string;
namespace MonsterTests{
class MonsterTest;
};

View File

@ -6,15 +6,15 @@
INCLUDE_game
std::unordered_map<std::string_view,std::function<void(SpellName,CastPos,CasterMonster)>>MonsterAbility::SPELLS{
{"Meteor",[](SpellName spellName,CastPos pos,CasterMonster monster)->void{
Monster&m{*(monster.lock())};
const std::string strategy{m.GetStrategyName()};
std::unordered_map<std::string_view,std::function<void(SpellName,CastPos,CasterMonster&,const StrategyName&)>>MonsterAbility::SPELLS{
{"Meteor",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->void{
game->AddEffect(std::make_unique<Meteor>(pos,3.f,m.OnUpperLevel(),Meteor::SKELETON_FIRE_MAGE,std::pair<MeteorDamage,PulsatingFireDamage>{int(m.GetAttack()*ConfigFloat("Meteor Damage Mult")),int(m.GetAttack()*ConfigFloat("Fire Ring Damage Mult"))},"Wizard.Ability 3.MeteorFadeoutTime"_F));
}},
{"Fire Bolt",[](SpellName spellName,CastPos pos,CasterMonster monster)->void{
Monster&m{*(monster.lock())};
const std::string strategy{m.GetStrategyName()};
{"Fire Bolt",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->void{
CreateBullet(FireBolt)(m.GetPos(),util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Fire Bolt Bullet Speed"),"Wizard.Ability 1.Radius"_F/100*12,m.GetAttack()*ConfigFloat("Fire Bolt Damage Mult"),m.OnUpperLevel())EndBullet;
}},
{"Blizzard",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->void{
}},
{"Freeze Ground",[](SpellName spellName,CastPos pos,CasterMonster&m,const StrategyName&strategy)->void{
}},
};

View File

@ -5,14 +5,15 @@
#include<unordered_map>
#include<functional>
#include"olcUTIL_Geometry2D.h"
#include"MonsterStrategyHelpers.h"
class Monster;
using SpellName=std::string;
using CastPos=vf2d;
using CasterMonster=std::weak_ptr<Monster>;
using CasterMonster=Monster;
class MonsterAbility{
public:
static std::unordered_map<std::string_view,std::function<void(SpellName,CastPos,CasterMonster)>>SPELLS;
static std::unordered_map<std::string_view,std::function<void(SpellName,CastPos,CasterMonster&,const StrategyName&)>>SPELLS;
};

View File

@ -42,6 +42,7 @@ All rights reserved.
#include "safemap.h"
#include "Item.h"
#include "AdventuresInLestoria.h"
#include"MonsterAbility.h"
INCLUDE_DATA
INCLUDE_STRATEGY_DATA
@ -216,6 +217,7 @@ void MonsterData::InitializeMonsterData(){
auto&abilityData{DATA["Monsters"][MonsterName]["Abilities"]};
for(auto&[key,size]:abilityData){
auto&ability{abilityData[key]};
if(!MonsterAbility::SPELLS.contains(key))ERR(std::format("WARNING! Monster Ability {} does not exist! Failed to add ability to Monster {}",key,MonsterName));
monster.abilities.emplace_back(MonsterAbilityData{.name=key,.mpCost=ability.GetInt(0),.pctCastChance=ability.GetReal(1)/100.f,.castTime=ability.GetReal(2)});
}
}

View File

@ -38,6 +38,8 @@ All rights reserved.
#include"MonsterAttribute.h"
using StrategyName=std::string;
#pragma once
#define ConfigInt(param) Monster::STRATEGY::_GetInt(m,param,strategy)
#define ConfigFloat(param) Monster::STRATEGY::_GetFloat(m,param,strategy)

View File

@ -158,7 +158,7 @@ void Monster::STRATEGY::RUN_TOWARDS(Monster&m,float fElapsedTime,std::string str
float dist=lineToPlayer.length();
for(int i=0;i<m.GetSizeMult()*25;i++){
float randomDir=util::random(2*PI);
game->AddEffect(std::make_unique<FallingDebris>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
game->AddEffect(std::make_unique<FallEffect>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
}
if(dist<12*m.GetSizeMult()){
int jumpDamage=0;

View File

@ -202,7 +202,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,std::string strat
float dist=lineToPlayer.length();
for(int i=0;i<200;i++){
float randomDir=util::random(2*PI);
game->AddEffect(std::make_unique<FallingDebris>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
game->AddEffect(std::make_unique<FallEffect>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
}
if(dist<12*m.GetSizeMult()){
if(game->GetPlayer()->Hurt(ConfigInt("JumpAttackDamage"),m.OnUpperLevel(),m.GetZ())){

View File

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 12458
#define VERSION_BUILD 12481
#define stringify(a) stringify_(a)
#define stringify_(a) #a

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.2" class="Map" orientation="orthogonal" renderorder="right-down" width="315" height="238" tilewidth="24" tileheight="24" infinite="0" nextlayerid="7" nextobjectid="16">
<map version="1.10" tiledversion="1.10.2" class="Map" orientation="orthogonal" renderorder="right-down" width="315" height="238" tilewidth="24" tileheight="24" infinite="0" nextlayerid="7" nextobjectid="17">
<properties>
<property name="Background Music" propertytype="BGM" value="undead_swamp"/>
<property name="Level Type" type="int" propertytype="LevelType" value="0"/>
@ -990,7 +990,7 @@
<object id="6" name="Monster Spawn Zone" type="SpawnGroup" x="438" y="4770" width="216" height="246">
<ellipse/>
</object>
<object id="15" template="../maps/Monsters/Skeleton Fire Mage.tx" x="582" y="4872">
<object id="16" template="../maps/Monsters/Skeleton Frost Mage.tx" x="612" y="4794">
<properties>
<property name="spawner" type="object" value="6"/>
</properties>

View File

@ -2217,6 +2217,55 @@ Monsters
Death Sound = Slime Dead
Walk Sound = Slime Walk
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
#DROP[0] = Broken Bow,30%,1,1
}
Skeleton Frost Mage
{
Health = 650
Attack = 41
CollisionDmg = 41
MoveSpd = 80%
Size = 90%
XP = 49
MP = 0
MP Recovery = 5mp/s
Abilities
{
#Ability Name = Mana cost, % chance to cast (every second), Cast Time (Instant = 0.0s)
Blizzard = 50mp, 60%, 1.5sec
Freeze Ground = 20mp, 10%, 1.0sec
}
Strategy = Skeleton Fire Mage
#Size of each animation frame
SheetFrameSize = 32,32
# 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 = 2, 0.6, Repeat
WALK = 3, 0.2, Repeat
ATTACK = 4, 0.1, Repeat
DEATH = 4, 0.15, OneShot
CASTING = 4, 0.1, Repeat
}
Hurt Sound = Monster Hurt
Death Sound = Slime Dead
Walk Sound = Slime Walk
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
#DROP[0] = Broken Bow,30%,1,1
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<tileset firstgid="1" source="../Monsters.tsx"/>
<object name="Skeleton Frost Mage" type="Monster" gid="40" width="48" height="48"/>
</template>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB