1/*
2 * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "effect.h"
24#include "map.h"
25#include "game.h"
26#include <framework/core/eventdispatcher.h>
27#include <framework/util/extras.h>
28
29void Effect::draw(const Point& dest, int offsetX, int offsetY, bool animate, LightView* lightView)
30{
31 if(m_id == 0)
32 return;
33
34 if(animate) {
35 if(g_game.getFeature(Otc::GameEnhancedAnimations) && rawGetThingType()->getAnimator()) {
36 // This requires a separate getPhaseAt method as using getPhase would make all magic effects use the same phase regardless of their appearance time
37 m_animationPhase = std::max<int>(0, rawGetThingType()->getAnimator()->getPhaseAt(m_animationTimer, m_animationPhase));
38 } else {
39 // hack to fix some animation phases duration, currently there is no better solution
40 int ticks = EFFECT_TICKS_PER_FRAME;
41 if (m_id == 33) {
42 ticks <<= 2;
43 }
44
45 m_animationPhase = std::max<int>(0, std::min<int>((int)(m_animationTimer.ticksElapsed() / ticks), getAnimationPhases() - 1));
46 }
47 }
48
49 int xPattern = m_position.x % getNumPatternX();
50 if(xPattern < 0)
51 xPattern += getNumPatternX();
52
53 int yPattern = m_position.y % getNumPatternY();
54 if(yPattern < 0)
55 yPattern += getNumPatternY();
56
57 rawGetThingType()->draw(dest, 0, xPattern, yPattern, 0, m_animationPhase, Color::white, lightView);
58}
59
60void Effect::onAppear()
61{
62 m_animationTimer.restart();
63
64 int duration = 0;
65 if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
66 duration = getThingType()->getAnimator() ? getThingType()->getAnimator()->getTotalDuration() : 1000;
67 } else {
68 duration = EFFECT_TICKS_PER_FRAME;
69
70 // hack to fix some animation phases duration, currently there is no better solution
71 if(m_id == 33) {
72 duration <<= 2;
73 }
74
75 duration *= getAnimationPhases();
76 }
77
78 // schedule removal
79 auto self = asEffect();
80 g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, duration);
81}
82
83void Effect::setId(uint32 id)
84{
85 if(!g_things.isValidDatId(id, ThingCategoryEffect))
86 id = 0;
87 m_id = id;
88}
89
90const ThingTypePtr& Effect::getThingType()
91{
92 return g_things.getThingType(m_id, ThingCategoryEffect);
93}
94
95ThingType *Effect::rawGetThingType()
96{
97 return g_things.rawGetThingType(m_id, ThingCategoryEffect);
98}
99