Skip to content

Commit

Permalink
improve: Attached Effect
Browse files Browse the repository at this point in the history
- support dynamic effect
- add move method
- add set & get direction
- bounce system
  • Loading branch information
mehah authored Jan 17, 2024
1 parent 8e76d56 commit 0ac938e
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 21 deletions.
67 changes: 56 additions & 11 deletions modules/game_attachedeffects/effects.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
duration, loop, transform, hideOwner, size{width, height}
offset{x, y, onTop}, dirOffset[dir]{x, y, onTop},
light { color, intensity}, drawOrder(only for tiles),
bounce{minHeight, height, speed}
onAttach, onDetach
}
]] --
]]
--
AttachedEffectManager.register(1, 'Spoke Lighting', 12, ThingCategoryEffect, {
speed = 0.5,
onAttach = function(effect, owner)
Expand All @@ -23,11 +25,18 @@ AttachedEffectManager.register(2, 'Bat Wings', 307, ThingCategoryCreature, {
disableWalkAnimation = true,
shader = 'Outfit - Rainbow',
dirOffset = {
[North] = {0, -10, true},
[East] = {5, -5},
[South] = {-5, 0},
[West] = {-10, -5, true}
}
[North] = { 0, -10, true },
[East] = { 5, -5 },
[South] = { -5, 0 },
[West] = { -10, -5, true }
},
onAttach = function(effect, owner)
owner:setBounce(0, 10, 1000)
effect:setBounce(0, 10, 1000)
end,
onDetach = function(effect, oldOwner)
oldOwner:setBounce(0, 0)
end
})

AttachedEffectManager.register(3, 'Angel Light', 50, ThingCategoryEffect, {
Expand Down Expand Up @@ -82,16 +91,52 @@ AttachedEffectManager.register(6, 'Lake Monster', 34, ThingCategoryEffect, {
})

AttachedEffectManager.register(7, 'Pentagram Aura', '/images/game/effects/pentagram', ThingExternalTexture, {
size = {128, 128},
offset = {50, 45}
size = { 128, 128 },
offset = { 50, 45 }
})

AttachedEffectManager.register(8, 'Ki', '/images/game/effects/ki', ThingExternalTexture, {
size = {140, 110},
offset = {60, 75, true}
size = { 140, 110 },
offset = { 60, 75, true }
})

AttachedEffectManager.register(9, 'Thunder', '/images/game/effects/thunder', ThingExternalTexture, {
loop = 1,
offset = {215, 230}
offset = { 215, 230 }
})

AttachedEffectManager.register(10, 'Dynamic Effect', 0, 0, {
duration = 500,
onAttach = function(effect, owner)
local spriteSize = g_gameConfig.getSpriteSize()
local length = 3

local missile = AttachedEffect.create(38, ThingCategoryMissile)
missile:setDuration(effect:getDuration())
missile:setDirection(5)
missile:setOffset(spriteSize * length, 0)
missile:setBounce(10, 500)
missile:move(Position.translated(owner:getPosition(), -length, 0), owner:getPosition())
effect:attachEffect(missile)

missile = AttachedEffect.create(38, ThingCategoryMissile)
missile:setDuration(effect:getDuration())
missile:setDirection(3)
missile:setOffset(-(spriteSize * length), 0)
missile:setBounce(10, 500)
missile:move(Position.translated(owner:getPosition(), length, 0), owner:getPosition())

effect:attachEffect(missile)
end,
onDetach = function(effect, oldOwner)
local e = Effect.create()
e:setId(50)
oldOwner:getTile():addThing(e)
end
})

AttachedEffectManager.register(11, 'Bat', 307, ThingCategoryCreature, {
speed = 0.5,
offset = { 0, 0 },
bounce = { 20, 20, 2000 }
})
4 changes: 4 additions & 0 deletions modules/game_attachedeffects/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ local executeConfig = function(attachedEffect, config)
attachedEffect:setDrawOrder(config.drawOrder)
end

if config.bounce then
attachedEffect:setBounce(config.bounce[1], config.bounce[2], config.bounce[3] or 1000)
end

if config.duration ~= nil and config.duration > 0 then
attachedEffect:setDuration(config.duration)
end
Expand Down
14 changes: 14 additions & 0 deletions modules/gamelib/position.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ function Position.manhattanDistance(pos1, pos2)
return math.abs(pos2.x - pos1.x) + math.abs(pos2.y - pos1.y)
end

function Position.translated(pos, dx, dy, dz)
local newPos = {
x = pos.x,
y = pos.y,
z = pos.z
}

newPos.x = newPos.x + dx
newPos.y = newPos.y + dy
newPos.z = newPos.z + (dz or 0)

return newPos
end

function Position.translatedToDirection(pos, direction)
local newPos = {
x = pos.x,
Expand Down
20 changes: 16 additions & 4 deletions src/client/attachableobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ void AttachableObject::attachEffect(const AttachedEffectPtr& obj)
++m_ownerHidden;

if (obj->getDuration() > 0) {
g_dispatcher.scheduleEvent([self = std::static_pointer_cast<AttachableObject>(shared_from_this()), effectId = obj->getId()]() {
self->detachEffectById(effectId);
g_dispatcher.scheduleEvent([self = std::static_pointer_cast<AttachableObject>(shared_from_this()), effect = obj]() {
self->detachEffect(effect);
}, obj->getDuration());
}

Expand All @@ -67,6 +67,18 @@ void AttachableObject::attachEffect(const AttachedEffectPtr& obj)
});
}

bool AttachableObject::detachEffect(const AttachedEffectPtr& obj) {
const auto it = std::find(m_attachedEffects.begin(), m_attachedEffects.end(), obj);

if (it == m_attachedEffects.end())
return false;

onDetachEffect(*it);
m_attachedEffects.erase(it);

return true;
}

bool AttachableObject::detachEffectById(uint16_t id)
{
const auto it = std::find_if(m_attachedEffects.begin(), m_attachedEffects.end(),
Expand Down Expand Up @@ -138,8 +150,8 @@ void AttachableObject::drawAttachedEffect(const Point& dest, LightView* lightVie
for (const auto& effect : m_attachedEffects) {
effect->draw(dest, isOnTop, lightView);
if (effect->getLoop() == 0) {
g_dispatcher.addEvent([self = std::static_pointer_cast<AttachableObject>(shared_from_this()), effectId = effect->getId()]() {
self->detachEffectById(effectId);
g_dispatcher.addEvent([self = std::static_pointer_cast<AttachableObject>(shared_from_this()), effect]() {
self->detachEffect(effect);
});
}
}
Expand Down
1 change: 1 addition & 0 deletions src/client/attachableobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class AttachableObject : public LuaObject
void clearTemporaryAttachedEffects();
void clearPermanentAttachedEffects();
bool detachEffectById(uint16_t id);
bool detachEffect(const AttachedEffectPtr& obj);
AttachedEffectPtr getAttachedEffectById(uint16_t id);

virtual void onStartAttachEffect(const AttachedEffectPtr& effect) { };
Expand Down
35 changes: 32 additions & 3 deletions src/client/attachedeffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
#include <framework/graphics/animatedtexture.h>
#include <framework/graphics/shadermanager.h>

AttachedEffectPtr AttachedEffect::create(uint16_t thingId, ThingCategory category) {
if (!g_things.isValidDatId(thingId, category)) {
g_logger.error(stdext::format("AttachedEffectManager::getInstance(%d, %d): invalid thing with id or category.", thingId, static_cast<uint8_t>(category)));
return nullptr;
}

const auto& obj = std::make_shared<AttachedEffect>();
obj->m_thingId = thingId;
obj->m_thingCategory = category;
obj->m_thingType = g_things.getThingType(obj->m_thingId, obj->m_thingCategory).get();
return obj;
}

AttachedEffectPtr AttachedEffect::clone()
{
auto obj = std::make_shared<AttachedEffect>();
Expand Down Expand Up @@ -61,7 +74,18 @@ void AttachedEffect::draw(const Point& dest, bool isOnTop, LightView* lightView)
if (m_shader) g_drawPool.setShaderProgram(m_shader, true);
if (m_opacity < 100) g_drawPool.setOpacity(getOpacity(), true);

const auto& point = dest - (dirControl.offset * g_drawPool.getScaleFactor());
auto point = dest - (dirControl.offset * g_drawPool.getScaleFactor());
if (!m_toPoint.isNull()) {
const float fraction = std::min<float>(m_animationTimer.ticksElapsed() / static_cast<float>(m_duration), 1.f);
point += m_toPoint * fraction * g_drawPool.getScaleFactor();
}

if (m_bounce.height > 0 && m_bounce.speed > 0) {
const auto minHeight = m_bounce.minHeight * g_drawPool.getScaleFactor();
const auto height = m_bounce.height * g_drawPool.getScaleFactor();
point -= (minHeight * 1.f) + std::abs((m_bounce.speed / 2) - g_clock.millis() % m_bounce.speed) / (m_bounce.speed * 1.f) * height;
}

if (lightView && m_light.intensity > 0)
lightView->addLightSource(dest, m_light);

Expand All @@ -71,7 +95,7 @@ void AttachedEffect::draw(const Point& dest, bool isOnTop, LightView* lightView)
const auto& rect = Rect(Point(), texture->getSize());
g_drawPool.addTexturedRect(Rect(point, size), texture, rect, Color::white, { .order = getDrawOrder() });
} else {
m_thingType->draw(point, 0, m_direction, 0, 0, animation, Color::white, true, lightView, {.order = getDrawOrder()});
m_thingType->draw(point, 0, m_direction, 0, 0, animation, Color::white, true, lightView, { .order = getDrawOrder() });
}
}

Expand Down Expand Up @@ -108,4 +132,9 @@ int AttachedEffect::getCurrentAnimationPhase()
return 0;
}

void AttachedEffect::setShader(const std::string_view name) { m_shader = g_shaders.getShader(name); }
void AttachedEffect::setShader(const std::string_view name) { m_shader = g_shaders.getShader(name); }

void AttachedEffect::move(const Position& fromPosition, const Position& toPosition) {
m_toPoint = Point(toPosition.x - fromPosition.x, toPosition.y - fromPosition.y) * g_gameConfig.getSpriteSize();
m_animationTimer.restart();
}
19 changes: 18 additions & 1 deletion src/client/attachedeffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
class AttachedEffect : public LuaObject
{
public:
static AttachedEffectPtr create(uint16_t thingId, ThingCategory category);

void draw(const Point& /*dest*/, bool /*isOnTop*/, LightView* = nullptr);

uint16_t getId() { return m_id; }
Expand Down Expand Up @@ -64,6 +66,10 @@ class AttachedEffect : public LuaObject
void setName(std::string_view n) { m_name = { n.data() }; }
std::string getName() { return m_name; }

Otc::Direction getDirection() { return m_direction; }
void setDirection(const Otc::Direction dir) { m_direction = std::min<Otc::Direction>(dir, Otc::NorthWest); }

void setBounce(uint8_t minHeight, uint8_t height, uint16_t speed) { m_bounce = { minHeight, height , speed }; }
void setOnTop(bool onTop) { for (auto& control : m_offsetDirections) control.onTop = onTop; }
void setOffset(int16_t x, int16_t y) { for (auto& control : m_offsetDirections) control.offset = { x, y }; }
void setOnTopByDir(Otc::Direction direction, bool onTop) { m_offsetDirections[direction].onTop = onTop; }
Expand All @@ -73,6 +79,8 @@ class AttachedEffect : public LuaObject
void setCanDrawOnUI(bool canDraw) { m_canDrawOnUI = canDraw; }
bool canDrawOnUI() { return m_canDrawOnUI; }

void move(const Position& fromPosition, const Position& toPosition);

void attachEffect(const AttachedEffectPtr& e) { m_effects.emplace_back(e); }

DrawOrder getDrawOrder() { return m_drawOrder; }
Expand Down Expand Up @@ -121,7 +129,14 @@ class AttachedEffect : public LuaObject

Otc::Direction m_direction{ Otc::North };

std::array<DirControl, Otc::Direction::West + 1> m_offsetDirections;
std::array<DirControl, Otc::Direction::NorthWest + 1> m_offsetDirections;

struct
{
uint8_t minHeight{ 0 };
uint8_t height{ 0 };
uint16_t speed{ 0 };
} m_bounce;

PainterShaderProgramPtr m_shader;
AnimatedTexturePtr m_texture;
Expand All @@ -130,6 +145,8 @@ class AttachedEffect : public LuaObject

std::vector<AttachedEffectPtr> m_effects;

Point m_toPoint;

friend class Thing;
friend class Creature;
friend class AttachedEffectManager;
Expand Down
4 changes: 4 additions & 0 deletions src/client/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ void Creature::internalDraw(Point dest, LightView* lightView, const Color& color
if (!m_jumpOffset.isNull()) {
const auto& jumpOffset = m_jumpOffset * g_drawPool.getScaleFactor();
dest -= Point(std::round(jumpOffset.x), std::round(jumpOffset.y));
} else if (m_bounce.height > 0 && m_bounce.speed > 0) {
const auto minHeight = m_bounce.minHeight * g_drawPool.getScaleFactor();
const auto height = m_bounce.height * g_drawPool.getScaleFactor();
dest -= (minHeight * 1.f) + std::abs((m_bounce.speed / 2) - g_clock.millis() % m_bounce.speed) / (m_bounce.speed * 1.f) * height;
}

const auto& datType = getThingType();
Expand Down
9 changes: 9 additions & 0 deletions src/client/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ class Creature : public Thing
}
}

void setBounce(uint8_t minHeight, uint8_t height, uint16_t speed) { m_bounce = { minHeight, height , speed }; }

#ifndef BOT_PROTECTION
void setText(const std::string& text, const Color& color);
std::string getText();
Expand Down Expand Up @@ -272,6 +274,13 @@ class Creature : public Thing
PointF m_jumpOffset;
Timer m_jumpTimer;

struct
{
uint8_t minHeight{ 0 };
uint8_t height{ 0 };
uint16_t speed{ 0 };
} m_bounce;

// Mount Shader
PainterShaderProgramPtr m_mountShader;
std::function<void()> m_mountShaderAction{ nullptr };
Expand Down
2 changes: 1 addition & 1 deletion src/client/gameconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GameConfig
void init();
void terminate();

uint8_t getSpriteSize() const { return m_spriteSize; }
uint8_t getSpriteSize() { return m_spriteSize; }
uint16_t getLastSupportedVersion() const { return m_lastSupportedVersion; }

Size getMapViewPort() const { return m_mapViewPort; }
Expand Down
11 changes: 10 additions & 1 deletion src/client/luafunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ void Client::registerLuaFunctions()

g_lua.registerSingletonClass("g_gameConfig");
g_lua.bindSingletonFunction("g_gameConfig", "loadFonts", &GameConfig::loadFonts, &g_gameConfig);
g_lua.bindSingletonFunction("g_gameConfig", "getSpriteSize", &GameConfig::getSpriteSize, &g_gameConfig);

g_lua.registerSingletonClass("g_client");
g_lua.bindSingletonFunction("g_client", "setEffectAlpha", &Client::setEffectAlpha, &g_client);
Expand Down Expand Up @@ -401,6 +402,7 @@ void Client::registerLuaFunctions()
g_lua.registerClass<AttachableObject>();
g_lua.bindClassMemberFunction<AttachableObject>("getAttachedEffects", &AttachableObject::getAttachedEffects);
g_lua.bindClassMemberFunction<AttachableObject>("attachEffect", &AttachableObject::attachEffect);
g_lua.bindClassMemberFunction<AttachableObject>("detachEffect", &AttachableObject::detachEffect);
g_lua.bindClassMemberFunction<AttachableObject>("detachEffectById", &AttachableObject::detachEffectById);
g_lua.bindClassMemberFunction<AttachableObject>("getAttachedEffectById", &AttachableObject::getAttachedEffectById);
g_lua.bindClassMemberFunction<AttachableObject>("clearAttachedEffects", &AttachableObject::clearAttachedEffects);
Expand Down Expand Up @@ -555,6 +557,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<Creature>("getTimedSquareColor", &Creature::getTimedSquareColor);
g_lua.bindClassMemberFunction<Creature>("isStaticSquareVisible", &Creature::isStaticSquareVisible);
g_lua.bindClassMemberFunction<Creature>("getStaticSquareColor", &Creature::getStaticSquareColor);
g_lua.bindClassMemberFunction<Creature>("setBounce", &Creature::setBounce);

#ifndef BOT_PROTECTION
g_lua.bindClassMemberFunction<Creature>("setText", &Creature::setText);
Expand Down Expand Up @@ -701,6 +704,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<Missile>("setPath", &Missile::setPath);

g_lua.registerClass<AttachedEffect>();
g_lua.bindClassStaticFunction<AttachedEffect>("create", &AttachedEffect::create);
g_lua.bindClassMemberFunction<AttachedEffect>("clone", &AttachedEffect::clone);
g_lua.bindClassMemberFunction<AttachedEffect>("getId", &AttachedEffect::getId);
g_lua.bindClassMemberFunction<AttachedEffect>("getSpeed", &AttachedEffect::getSpeed);
Expand All @@ -709,6 +713,7 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<AttachedEffect>("setDisableWalkAnimation", &AttachedEffect::setDisableWalkAnimation);
g_lua.bindClassMemberFunction<AttachedEffect>("setOpacity", &AttachedEffect::setOpacity);
g_lua.bindClassMemberFunction<AttachedEffect>("setDuration", &AttachedEffect::setDuration);
g_lua.bindClassMemberFunction<AttachedEffect>("getDuration", &AttachedEffect::getDuration);
g_lua.bindClassMemberFunction<AttachedEffect>("setHideOwner", &AttachedEffect::setHideOwner);
g_lua.bindClassMemberFunction<AttachedEffect>("setLoop", &AttachedEffect::setLoop);
g_lua.bindClassMemberFunction<AttachedEffect>("setPermanent", &AttachedEffect::setPermanent);
Expand All @@ -724,6 +729,10 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<AttachedEffect>("attachEffect", &AttachedEffect::attachEffect);
g_lua.bindClassMemberFunction<AttachedEffect>("setDrawOrder", &AttachedEffect::setDrawOrder);
g_lua.bindClassMemberFunction<AttachedEffect>("setLight", &AttachedEffect::setLight);
g_lua.bindClassMemberFunction<AttachedEffect>("setBounce", &AttachedEffect::setBounce);
g_lua.bindClassMemberFunction<AttachedEffect>("setDirection", &AttachedEffect::setDirection);
g_lua.bindClassMemberFunction<AttachedEffect>("getDirection", &AttachedEffect::getDirection);
g_lua.bindClassMemberFunction<AttachedEffect>("move", &AttachedEffect::move);

g_lua.registerClass<StaticText>();
g_lua.bindClassStaticFunction<StaticText>("create", [] { return std::make_shared<StaticText>(); });
Expand Down Expand Up @@ -970,4 +979,4 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIGraph>("setShowLabels", &UIGraph::setShowLabels);

g_lua.registerClass<UIMapAnchorLayout, UIAnchorLayout>();
}
}

0 comments on commit 0ac938e

Please sign in to comment.