SHARE
TWEET

Untitled

a guest Aug 18th, 2019 74 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include "creature.h"
  2. #include "thingtypemanager.h"
  3. #include "localplayer.h"
  4. #include "map.h"
  5. #include "tile.h"
  6. #include "item.h"
  7. #include "game.h"
  8. #include "effect.h"
  9. #include "luavaluecasts.h"
  10. #include "lightview.h"
  11.  
  12. #include <framework/graphics/graphics.h>
  13. #include <framework/core/eventdispatcher.h>
  14. #include <framework/core/clock.h>
  15.  
  16. #include <framework/graphics/paintershaderprogram.h>
  17. #include <framework/graphics/ogl/painterogl2_shadersources.h>
  18. #include <framework/graphics/texturemanager.h>
  19. #include <framework/graphics/framebuffermanager.h>
  20. #include "spritemanager.h"
  21.  
  22. Creature::Creature() : Thing()
  23. {
  24.     m_id = 0;
  25.     m_healthPercent = 100;
  26.     m_speed = 210;
  27.     m_direction = Otc::South;
  28.     m_walkAnimationPhase = 0;
  29.     m_walkedPixels = 0;
  30.     m_walkTurnDirection = Otc::InvalidDirection;
  31.     m_skull = Otc::SkullNone;
  32.     m_shield = Otc::ShieldNone;
  33.     m_emblem = Otc::EmblemNone;
  34.     m_type = Proto::CreatureTypeUnknown;
  35.     m_icon = Otc::NpcIconNone;
  36.     m_lastStepDirection = Otc::InvalidDirection;
  37.     m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
  38.     m_nameCache.setAlign(Fw::AlignTopCenter);
  39.     m_footStep = 0;
  40.     m_speedFormula.fill(-1);
  41.     m_outfitColor = Color::white;
  42. }
  43.  
  44. void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
  45. {
  46.     if(!canBeSeen())
  47.         return;
  48.  
  49.     Point animationOffset = animate ? m_walkOffset : Point(0,0);
  50.  
  51.     if(m_showTimedSquare && animate) {
  52.         g_painter->setColor(m_timedSquareColor);
  53.         g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));
  54.         g_painter->setColor(Color::white);
  55.     }
  56.  
  57.     if(m_showStaticSquare && animate) {
  58.         g_painter->setColor(m_staticSquareColor);
  59.         g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));
  60.         g_painter->setColor(Color::white);
  61.     }
  62.  
  63.     internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
  64.     m_footStepDrawn = true;
  65.  
  66.     if(lightView) {
  67.         Light light = rawGetThingType()->getLight();
  68.         if(m_light.intensity != light.intensity || m_light.color != light.color)
  69.             light = m_light;
  70.  
  71.         // local player always have a minimum light in complete darkness
  72.         if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
  73.             light.intensity = std::max<uint8>(light.intensity, 3);
  74.             if(light.color == 0 || light.color > 215)
  75.                 light.color = 215;
  76.         }
  77.  
  78.         if(light.intensity > 0)
  79.             lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
  80.     }
  81. }
  82.  
  83. void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
  84. {
  85.     g_painter->setColor(m_outfitColor);
  86.  
  87.     // outfit is a real creature
  88.     if(m_outfit.getCategory() == ThingCategoryCreature) {
  89.         int animationPhase = animateWalk ? m_walkAnimationPhase : 0;
  90.  
  91.         if(isAnimateAlways() && animateIdle) {
  92.             int ticksPerFrame = 1000 / getAnimationPhases();
  93.             animationPhase = (g_clock.millis() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
  94.         }
  95.  
  96.         // xPattern => creature direction
  97.         int xPattern;
  98.         if(direction == Otc::NorthEast || direction == Otc::SouthEast)
  99.             xPattern = Otc::East;
  100.         else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
  101.             xPattern = Otc::West;
  102.         else
  103.             xPattern = direction;
  104.  
  105.         int zPattern = 0;
  106.         if(m_outfit.getMount() != 0) {
  107.             auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
  108.             dest -= datType->getDisplacement() * scaleFactor;
  109.             datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
  110.             dest += getDisplacement() * scaleFactor;
  111.             zPattern = std::min<int>(1, getNumPatternZ() - 1);
  112.         }
  113.  
  114.         PointF jumpOffset = m_jumpOffset * scaleFactor;
  115.         dest -= Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));
  116.  
  117.         // yPattern => creature addon
  118.         for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
  119.  
  120.             // continue if we dont have this addon
  121.             if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
  122.                 continue;
  123.  
  124.             auto datType = rawGetThingType();
  125.             datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);
  126.  
  127.             if(getLayers() > 1) {
  128.                 Color oldColor = g_painter->getColor();
  129.                 Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
  130.                 g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
  131.                 g_painter->setColor(m_outfit.getHeadColor());
  132.                 datType->draw(dest, scaleFactor, SpriteMaskYellow, xPattern, yPattern, zPattern, animationPhase);
  133.                 g_painter->setColor(m_outfit.getBodyColor());
  134.                 datType->draw(dest, scaleFactor, SpriteMaskRed, xPattern, yPattern, zPattern, animationPhase);
  135.                 g_painter->setColor(m_outfit.getLegsColor());
  136.                 datType->draw(dest, scaleFactor, SpriteMaskGreen, xPattern, yPattern, zPattern, animationPhase);
  137.                 g_painter->setColor(m_outfit.getFeetColor());
  138.                 datType->draw(dest, scaleFactor, SpriteMaskBlue, xPattern, yPattern, zPattern, animationPhase);
  139.                 g_painter->setColor(oldColor);
  140.                 g_painter->setCompositionMode(oldComposition);
  141.             }
  142.         }
  143.     // outfit is a creature imitating an item or the invisible effect
  144.     } else  {
  145.         ThingType *type = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory());
  146.  
  147.         int animationPhase = 0;
  148.         int animationPhases = type->getAnimationPhases();
  149.         int animateTicks = Otc::ITEM_TICKS_PER_FRAME;
  150.  
  151.         // when creature is an effect we cant render the first and last animation phase,
  152.         // instead we should loop in the phases between
  153.         if(m_outfit.getCategory() == ThingCategoryEffect) {
  154.             animationPhases = std::max<int>(1, animationPhases-2);
  155.             animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
  156.         }
  157.  
  158.         if(animationPhases > 1) {
  159.             if(animateIdle)
  160.                 animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
  161.             else
  162.                 animationPhase = animationPhases-1;
  163.         }
  164.  
  165.         if(m_outfit.getCategory() == ThingCategoryEffect)
  166.             animationPhase = std::min<int>(animationPhase+1, animationPhases);
  167.  
  168.         type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
  169.     }
  170.  
  171.     g_painter->resetColor();
  172. }
  173.  
  174. void Creature::drawOutfit(const Rect& destRect, bool resize)
  175. {
  176.     int exactSize;
  177.     if(m_outfit.getCategory() == ThingCategoryCreature)
  178.         exactSize = getExactSize();
  179.     else
  180.         exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize();
  181.  
  182.     int frameSize;
  183.     if(!resize)
  184.         frameSize = std::max<int>(exactSize * 0.75f, 2 * Otc::TILE_PIXELS * 0.75f);
  185.     else if(!(frameSize = exactSize))
  186.         return;
  187.  
  188.     if(g_graphics.canUseFBO()) {
  189.         const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
  190.         outfitBuffer->resize(Size(frameSize, frameSize));
  191.         outfitBuffer->bind();
  192.         g_painter->setAlphaWriting(true);
  193.         g_painter->clear(Color::alpha);
  194.         internalDrawOutfit(Point(frameSize - Otc::TILE_PIXELS, frameSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
  195.         outfitBuffer->release();
  196.         outfitBuffer->draw(destRect, Rect(0,0,frameSize,frameSize));
  197.     } else {
  198.         float scaleFactor = destRect.width() / (float)frameSize;
  199.         Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor;
  200.         internalDrawOutfit(dest, scaleFactor, false, true, Otc::South);
  201.     }
  202. }
  203.  
  204. void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect, int drawFlags)
  205. {
  206.     if(m_healthPercent < 1) // creature is dead
  207.         return;
  208.  
  209.     Color fillColor = Color(96, 96, 96);
  210.  
  211.     if(!useGray)
  212.         fillColor = m_informationColor;
  213.  
  214.     // calculate main rects
  215.     Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4);
  216.     backgroundRect.bind(parentRect);
  217.  
  218.     Size nameSize = m_nameCache.getTextSize();
  219.     Rect textRect = Rect(point.x - nameSize.width() / 2.0, point.y-12, nameSize);
  220.     textRect.bind(parentRect);
  221.  
  222.     // distance them
  223.     uint32 offset = 12;
  224.     if(isLocalPlayer()) {
  225.         offset *= 2;
  226.     }
  227.  
  228.     if(textRect.top() == parentRect.top())
  229.         backgroundRect.moveTop(textRect.top() + offset);
  230.     if(backgroundRect.bottom() == parentRect.bottom())
  231.         textRect.moveTop(backgroundRect.top() - offset);
  232.  
  233.     // health rect is based on background rect, so no worries
  234.     Rect healthRect = backgroundRect.expanded(-1);
  235.     healthRect.setWidth((m_healthPercent / 100.0) * 25);
  236.  
  237.     // draw
  238.     //g_game.getFeature(Otc::GameBlueNpcNameColor) &&
  239.     if(isNpc() && m_healthPercent == 100 && !useGray)
  240.         if (getName() == "The Oracle") {
  241.         fillColor = Color(0xff, 0xEA, 0x00);
  242.         } else {
  243.         fillColor = Color(0x00, 0x64, 0xf8);
  244.         }
  245.  
  246.     if(drawFlags & Otc::DrawBars) {
  247.         g_painter->setColor(Color::black);
  248.         g_painter->drawFilledRect(backgroundRect);
  249.  
  250.         g_painter->setColor(fillColor);
  251.         g_painter->drawFilledRect(healthRect);
  252.  
  253.         if(drawFlags & Otc::DrawManaBar && isLocalPlayer()) {
  254.             LocalPlayerPtr player = g_game.getLocalPlayer();
  255.             if(player) {
  256.                 backgroundRect.moveTop(backgroundRect.bottom());
  257.  
  258.                 g_painter->setColor(Color::black);
  259.                 g_painter->drawFilledRect(backgroundRect);
  260.  
  261.                 Rect manaRect = backgroundRect.expanded(-1);
  262.                 double maxMana = player->getMaxMana();
  263.                 if(maxMana == 0) {
  264.                     manaRect.setWidth(25);
  265.                 } else {
  266.                     manaRect.setWidth(player->getMana() / (maxMana * 1.0) * 25);
  267.                 }
  268.  
  269.                 g_painter->setColor(Color::blue);
  270.                 g_painter->drawFilledRect(manaRect);
  271.             }
  272.         }
  273.     }
  274.  
  275.     if(drawFlags & Otc::DrawNames) {
  276.         if(g_painter->getColor() != fillColor)
  277.             g_painter->setColor(fillColor);
  278.         m_nameCache.draw(textRect);
  279.     }
  280.  
  281.     if(m_skull != Otc::SkullNone && m_skullTexture) {
  282.         g_painter->setColor(Color::white);
  283.         Rect skullRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_skullTexture->getSize());
  284.         g_painter->drawTexturedRect(skullRect, m_skullTexture);
  285.     }
  286.     if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
  287.         g_painter->setColor(Color::white);
  288.         Rect shieldRect = Rect(backgroundRect.x() + 13.5, backgroundRect.y() + 5, m_shieldTexture->getSize());
  289.         g_painter->drawTexturedRect(shieldRect, m_shieldTexture);
  290.     }
  291.     if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
  292.         g_painter->setColor(Color::white);
  293.         Rect emblemRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 16, m_emblemTexture->getSize());
  294.         g_painter->drawTexturedRect(emblemRect, m_emblemTexture);
  295.     }
  296.     if(m_type != Proto::CreatureTypeUnknown && m_typeTexture) {
  297.         g_painter->setColor(Color::white);
  298.         Rect typeRect = Rect(backgroundRect.x() + 13.5 + 12 + 12, backgroundRect.y() + 16, m_typeTexture->getSize());
  299.         g_painter->drawTexturedRect(typeRect, m_typeTexture);
  300.     }
  301.     if(m_icon != Otc::NpcIconNone && m_iconTexture) {
  302.         g_painter->setColor(Color::white);
  303.         Rect iconRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_iconTexture->getSize());
  304.         g_painter->drawTexturedRect(iconRect, m_iconTexture);
  305.     }
  306. }
  307.  
  308. void Creature::turn(Otc::Direction direction)
  309. {
  310.     // if is not walking change the direction right away
  311.     if(!m_walking)
  312.         setDirection(direction);
  313.     // schedules to set the new direction when walk ends
  314.     else
  315.         m_walkTurnDirection = direction;
  316. }
  317.  
  318. void Creature::walk(const Position& oldPos, const Position& newPos)
  319. {
  320.     if(oldPos == newPos)
  321.         return;
  322.  
  323.     // get walk direction
  324.     m_lastStepDirection = oldPos.getDirectionFromPosition(newPos);
  325.     m_lastStepFromPosition = oldPos;
  326.     m_lastStepToPosition = newPos;
  327.  
  328.     // set current walking direction
  329.     setDirection(m_lastStepDirection);
  330.  
  331.     // starts counting walk
  332.     m_walking = true;
  333.     m_walkTimer.restart();
  334.     m_walkedPixels = 0;
  335.  
  336.     if(m_walkFinishAnimEvent) {
  337.         m_walkFinishAnimEvent->cancel();
  338.         m_walkFinishAnimEvent = nullptr;
  339.     }
  340.  
  341.     // no direction need to be changed when the walk ends
  342.     m_walkTurnDirection = Otc::InvalidDirection;
  343.  
  344.     // starts updating walk
  345.     nextWalkUpdate();
  346. }
  347.  
  348. void Creature::stopWalk()
  349. {
  350.     if(!m_walking)
  351.         return;
  352.  
  353.     // stops the walk right away
  354.     terminateWalk();
  355. }
  356.  
  357. void Creature::jump(int height, int duration)
  358. {
  359.     if(!m_jumpOffset.isNull())
  360.         return;
  361.  
  362.     m_jumpTimer.restart();
  363.     m_jumpHeight = height;
  364.     m_jumpDuration = duration;
  365.  
  366.     updateJump();
  367. }
  368.  
  369. void Creature::updateJump()
  370. {
  371.     int t = m_jumpTimer.ticksElapsed();
  372.     double a = -4 * m_jumpHeight / (m_jumpDuration * m_jumpDuration);
  373.     double b = +4 * m_jumpHeight / (m_jumpDuration);
  374.  
  375.     double height = a*t*t + b*t;
  376.     int roundHeight = stdext::round(height);
  377.     int halfJumpDuration = m_jumpDuration / 2;
  378.  
  379.     // schedules next update
  380.     if(m_jumpTimer.ticksElapsed() < m_jumpDuration) {
  381.         m_jumpOffset = PointF(height, height);
  382.  
  383.         int diff = 0;
  384.         if(m_jumpTimer.ticksElapsed() < halfJumpDuration)
  385.             diff = 1;
  386.         else if(m_jumpTimer.ticksElapsed() > halfJumpDuration)
  387.             diff = -1;
  388.  
  389.         int nextT, i = 1;
  390.         do {
  391.             nextT = stdext::round((-b + std::sqrt(std::max<double>(b*b + 4*a*(roundHeight+diff*i), 0.0)) * diff) / (2*a));
  392.             ++i;
  393.  
  394.             if(nextT < halfJumpDuration)
  395.                 diff = 1;
  396.             else if(nextT > halfJumpDuration)
  397.                 diff = -1;
  398.         } while(nextT - m_jumpTimer.ticksElapsed() == 0 && i < 3);
  399.  
  400.         auto self = static_self_cast<Creature>();
  401.         g_dispatcher.scheduleEvent([self] {
  402.             self->updateJump();
  403.         }, nextT - m_jumpTimer.ticksElapsed());
  404.     }
  405.     else
  406.         m_jumpOffset = PointF(0, 0);
  407. }
  408.  
  409. void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
  410. {
  411.     callLuaField("onPositionChange", newPos, oldPos);
  412. }
  413.  
  414. void Creature::onAppear()
  415. {
  416.     // cancel any disappear event
  417.     if(m_disappearEvent) {
  418.         m_disappearEvent->cancel();
  419.         m_disappearEvent = nullptr;
  420.     }
  421.  
  422.     // creature appeared the first time or wasn't seen for a long time
  423.     if(m_removed) {
  424.         stopWalk();
  425.         m_removed = false;
  426.         callLuaField("onAppear");
  427.     // walk
  428.     } else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1) && m_allowAppearWalk) {
  429.         m_allowAppearWalk = false;
  430.         walk(m_oldPosition, m_position);
  431.         callLuaField("onWalk", m_oldPosition, m_position);
  432.     // teleport
  433.     } else if(m_oldPosition != m_position) {
  434.         stopWalk();
  435.         callLuaField("onDisappear");
  436.         callLuaField("onAppear");
  437.     } // else turn
  438. }
  439.  
  440. void Creature::onDisappear()
  441. {
  442.     if(m_disappearEvent)
  443.         m_disappearEvent->cancel();
  444.  
  445.     m_oldPosition = m_position;
  446.  
  447.     // a pair onDisappear and onAppear events are fired even when creatures walks or turns,
  448.     // so we must filter
  449.     auto self = static_self_cast<Creature>();
  450.     m_disappearEvent = g_dispatcher.addEvent([self] {
  451.         self->m_removed = true;
  452.         self->stopWalk();
  453.  
  454.         self->callLuaField("onDisappear");
  455.  
  456.         // invalidate this creature position
  457.         if(!self->isLocalPlayer())
  458.             self->setPosition(Position());
  459.         self->m_oldPosition = Position();
  460.         self->m_disappearEvent = nullptr;
  461.     });
  462. }
  463.  
  464. void Creature::onDeath()
  465. {
  466.     callLuaField("onDeath");
  467. }
  468.  
  469. void Creature::updateWalkAnimation(int totalPixelsWalked)
  470. {
  471.     // update outfit animation
  472.     if(m_outfit.getCategory() != ThingCategoryCreature)
  473.         return;
  474.  
  475.     int footAnimPhases = getAnimationPhases() - 1;
  476.     int footDelay = getStepDuration(true) / 3;
  477.     // Since mount is a different outfit we need to get the mount animation phases
  478.     if(m_outfit.getMount() != 0) {
  479.         ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
  480.         footAnimPhases = type->getAnimationPhases() - 1;
  481.     }
  482.     if(footAnimPhases == 0)
  483.         m_walkAnimationPhase = 0;
  484.     else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
  485.         m_footStep++;
  486.         m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
  487.         m_footStepDrawn = false;
  488.         m_footTimer.restart();
  489.     } else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
  490.         m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
  491.     }
  492.  
  493.     if(totalPixelsWalked == 32 && !m_walkFinishAnimEvent) {
  494.         auto self = static_self_cast<Creature>();
  495.         m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
  496.             if(!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true))
  497.                 self->m_walkAnimationPhase = 0;
  498.             self->m_walkFinishAnimEvent = nullptr;
  499.         }, std::min<int>(footDelay, 200));
  500.     }
  501.  
  502. }
  503.  
  504. void Creature::updateWalkOffset(int totalPixelsWalked)
  505. {
  506.     m_walkOffset = Point(0,0);
  507.     if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
  508.         m_walkOffset.y = 32 - totalPixelsWalked;
  509.     else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
  510.         m_walkOffset.y = totalPixelsWalked - 32;
  511.  
  512.     if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
  513.         m_walkOffset.x = totalPixelsWalked - 32;
  514.     else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
  515.         m_walkOffset.x = 32 - totalPixelsWalked;
  516. }
  517.  
  518. void Creature::updateWalkingTile()
  519. {
  520.     // determine new walking tile
  521.     TilePtr newWalkingTile;
  522.     Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
  523.                              Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
  524.                              Otc::TILE_PIXELS, Otc::TILE_PIXELS);
  525.     for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
  526.         for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
  527.             Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);
  528.  
  529.             // only render creatures where bottom right is inside tile rect
  530.             if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
  531.                 newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
  532.             }
  533.         }
  534.     }
  535.  
  536.     if(newWalkingTile != m_walkingTile) {
  537.         if(m_walkingTile)
  538.             m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
  539.         if(newWalkingTile) {
  540.             newWalkingTile->addWalkingCreature(static_self_cast<Creature>());
  541.  
  542.             // recache visible tiles in map views
  543.             if(newWalkingTile->isEmpty())
  544.                 g_map.notificateTileUpdate(newWalkingTile->getPosition());
  545.         }
  546.         m_walkingTile = newWalkingTile;
  547.     }
  548. }
  549.  
  550. void Creature::nextWalkUpdate()
  551. {
  552.     // remove any previous scheduled walk updates
  553.     if(m_walkUpdateEvent)
  554.         m_walkUpdateEvent->cancel();
  555.  
  556.     // do the update
  557.     updateWalk();
  558.  
  559.     // schedules next update
  560.     if(m_walking) {
  561.         auto self = static_self_cast<Creature>();
  562.         m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
  563.             self->m_walkUpdateEvent = nullptr;
  564.             self->nextWalkUpdate();
  565.         }, getStepDuration() / 32);
  566.     }
  567. }
  568.  
  569. void Creature::updateWalk()
  570. {
  571.     float walkTicksPerPixel = getStepDuration(true) / 32;
  572.     int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
  573.  
  574.     // needed for paralyze effect
  575.     m_walkedPixels = std::max<int>(m_walkedPixels, totalPixelsWalked);
  576.  
  577.     // update walk animation and offsets
  578.     updateWalkAnimation(totalPixelsWalked);
  579.     updateWalkOffset(m_walkedPixels);
  580.     updateWalkingTile();
  581.  
  582.     // terminate walk
  583.     if(m_walking && m_walkTimer.ticksElapsed() >= getStepDuration())
  584.         terminateWalk();
  585. }
  586.  
  587. void Creature::terminateWalk()
  588. {
  589.     // remove any scheduled walk update
  590.     if(m_walkUpdateEvent) {
  591.         m_walkUpdateEvent->cancel();
  592.         m_walkUpdateEvent = nullptr;
  593.     }
  594.  
  595.     // now the walk has ended, do any scheduled turn
  596.     if(m_walkTurnDirection != Otc::InvalidDirection)  {
  597.         setDirection(m_walkTurnDirection);
  598.         m_walkTurnDirection = Otc::InvalidDirection;
  599.     }
  600.  
  601.     if(m_walkingTile) {
  602.         m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
  603.         m_walkingTile = nullptr;
  604.     }
  605.  
  606.     m_walking = false;
  607.     m_walkedPixels = 0;
  608.  
  609.     // reset walk animation states
  610.     m_walkOffset = Point(0,0);
  611.     m_walkAnimationPhase = 0;
  612. }
  613.  
  614. void Creature::setName(const std::string& name)
  615. {
  616.     m_nameCache.setText(name);
  617.     m_name = name;
  618. }
  619.  
  620. void Creature::setHealthPercent(uint8 healthPercent)
  621. {
  622.     if(healthPercent > 92)
  623.         m_informationColor = Color(0x00, 0xBC, 0x00);
  624.     else if(healthPercent > 60)
  625.         m_informationColor = Color(0x50, 0xA1, 0x50);
  626.     else if(healthPercent > 30)
  627.         m_informationColor = Color(0xA1, 0xA1, 0x00);
  628.     else if(healthPercent > 8)
  629.         m_informationColor = Color(0xBF, 0x0A, 0x0A);
  630.     else if(healthPercent > 3)
  631.         m_informationColor = Color(0x91, 0x0F, 0x0F);
  632.     else
  633.         m_informationColor = Color(0x85, 0x0C, 0x0C);
  634.  
  635.     m_healthPercent = healthPercent;
  636.     callLuaField("onHealthPercentChange", healthPercent);
  637.  
  638.     if(healthPercent <= 0)
  639.         onDeath();
  640. }
  641.  
  642. void Creature::setDirection(Otc::Direction direction)
  643. {
  644.     assert(direction != Otc::InvalidDirection);
  645.     m_direction = direction;
  646. }
  647.  
  648. void Creature::setOutfit(const Outfit& outfit)
  649. {
  650.     Outfit oldOutfit = m_outfit;
  651.     if(outfit.getCategory() != ThingCategoryCreature) {
  652.         if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
  653.             return;
  654.         m_outfit.setAuxId(outfit.getAuxId());
  655.         m_outfit.setCategory(outfit.getCategory());
  656.     } else {
  657.         if(outfit.getId() > 0 && !g_things.isValidDatId(outfit.getId(), ThingCategoryCreature))
  658.             return;
  659.         m_outfit = outfit;
  660.     }
  661.     m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
  662.  
  663.     callLuaField("onOutfitChange", m_outfit, oldOutfit);
  664. }
  665.  
  666. void Creature::setOutfitColor(const Color& color, int duration)
  667. {
  668.     if(m_outfitColorUpdateEvent) {
  669.         m_outfitColorUpdateEvent->cancel();
  670.         m_outfitColorUpdateEvent = nullptr;
  671.     }
  672.  
  673.     if(duration > 0) {
  674.         Color delta = (color - m_outfitColor) / (float)duration;
  675.         m_outfitColorTimer.restart();
  676.         updateOutfitColor(m_outfitColor, color, delta, duration);
  677.     }
  678.     else
  679.         m_outfitColor = color;
  680. }
  681.  
  682. void Creature::updateOutfitColor(Color color, Color finalColor, Color delta, int duration)
  683. {
  684.     if(m_outfitColorTimer.ticksElapsed() < duration) {
  685.         m_outfitColor = color + delta * m_outfitColorTimer.ticksElapsed();
  686.  
  687.         auto self = static_self_cast<Creature>();
  688.         m_outfitColorUpdateEvent = g_dispatcher.scheduleEvent([=] {
  689.             self->updateOutfitColor(color, finalColor, delta, duration);
  690.         }, 100);
  691.     }
  692.     else {
  693.         m_outfitColor = finalColor;
  694.     }
  695. }
  696.  
  697. void Creature::setSpeed(uint16 speed)
  698. {
  699.     uint16 oldSpeed = m_speed;
  700.     m_speed = speed;
  701.  
  702.     // speed can change while walking (utani hur, paralyze, etc..)
  703.     if(m_walking)
  704.         nextWalkUpdate();
  705.  
  706.     callLuaField("onSpeedChange", m_speed, oldSpeed);
  707. }
  708.  
  709. void Creature::setBaseSpeed(double baseSpeed)
  710. {
  711.     if(m_baseSpeed != baseSpeed) {
  712.         double oldBaseSpeed = m_baseSpeed;
  713.         m_baseSpeed = baseSpeed;
  714.  
  715.         callLuaField("onBaseSpeedChange", baseSpeed, oldBaseSpeed);
  716.     }
  717. }
  718.  
  719. void Creature::setSkull(uint8 skull)
  720. {
  721.     m_skull = skull;
  722.     callLuaField("onSkullChange", m_skull);
  723. }
  724.  
  725. void Creature::setShield(uint8 shield)
  726. {
  727.     m_shield = shield;
  728.     callLuaField("onShieldChange", m_shield);
  729. }
  730.  
  731. void Creature::setEmblem(uint8 emblem)
  732. {
  733.     m_emblem = emblem;
  734.     callLuaField("onEmblemChange", m_emblem);
  735. }
  736.  
  737. void Creature::setType(uint8 type)
  738. {
  739.     m_type = type;
  740.     callLuaField("onTypeChange", m_type);
  741. }
  742.  
  743. void Creature::setIcon(uint8 icon)
  744. {
  745.     m_icon = icon;
  746.     callLuaField("onIconChange", m_icon);
  747. }
  748.  
  749. void Creature::setSkullTexture(const std::string& filename)
  750. {
  751.     m_skullTexture = g_textures.getTexture(filename);
  752. }
  753.  
  754. void Creature::setShieldTexture(const std::string& filename, bool blink)
  755. {
  756.     m_shieldTexture = g_textures.getTexture(filename);
  757.     m_showShieldTexture = true;
  758.  
  759.     if(blink && !m_shieldBlink) {
  760.         auto self = static_self_cast<Creature>();
  761.         g_dispatcher.scheduleEvent([self]() {
  762.             self->updateShield();
  763.         }, SHIELD_BLINK_TICKS);
  764.     }
  765.  
  766.     m_shieldBlink = blink;
  767. }
  768.  
  769. void Creature::setEmblemTexture(const std::string& filename)
  770. {
  771.     m_emblemTexture = g_textures.getTexture(filename);
  772. }
  773.  
  774. void Creature::setTypeTexture(const std::string& filename)
  775. {
  776.     m_typeTexture = g_textures.getTexture(filename);
  777. }
  778.  
  779. void Creature::setIconTexture(const std::string& filename)
  780. {
  781.     m_iconTexture = g_textures.getTexture(filename);
  782. }
  783.  
  784. void Creature::setSpeedFormula(double speedA, double speedB, double speedC)
  785. {
  786.     m_speedFormula[Otc::SpeedFormulaA] = speedA;
  787.     m_speedFormula[Otc::SpeedFormulaB] = speedB;
  788.     m_speedFormula[Otc::SpeedFormulaC] = speedC;
  789. }
  790.  
  791. bool Creature::hasSpeedFormula()
  792. {
  793.     return m_speedFormula[Otc::SpeedFormulaA] != -1 && m_speedFormula[Otc::SpeedFormulaB] != -1
  794.             && m_speedFormula[Otc::SpeedFormulaC] != -1;
  795. }
  796.  
  797. void Creature::addTimedSquare(uint8 color)
  798. {
  799.     m_showTimedSquare = true;
  800.     m_timedSquareColor = Color::from8bit(color);
  801.  
  802.     // schedule removal
  803.     auto self = static_self_cast<Creature>();
  804.     g_dispatcher.scheduleEvent([self]() {
  805.         self->removeTimedSquare();
  806.     }, VOLATILE_SQUARE_DURATION);
  807. }
  808.  
  809. void Creature::updateShield()
  810. {
  811.     m_showShieldTexture = !m_showShieldTexture;
  812.  
  813.     if(m_shield != Otc::ShieldNone && m_shieldBlink) {
  814.         auto self = static_self_cast<Creature>();
  815.         g_dispatcher.scheduleEvent([self]() {
  816.             self->updateShield();
  817.         }, SHIELD_BLINK_TICKS);
  818.     }
  819.     else if(!m_shieldBlink)
  820.         m_showShieldTexture = true;
  821. }
  822.  
  823. Point Creature::getDrawOffset()
  824. {
  825.     Point drawOffset;
  826.     if(m_walking) {
  827.         if(m_walkingTile)
  828.             drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
  829.         drawOffset += m_walkOffset;
  830.     } else {
  831.         const TilePtr& tile = getTile();
  832.         if(tile)
  833.             drawOffset -= Point(1,1) * tile->getDrawElevation();
  834.     }
  835.     return drawOffset;
  836. }
  837.  
  838. int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
  839. {
  840.     int speed = m_speed;
  841.     if(speed < 1)
  842.         return 0;
  843.  
  844.     if(g_game.getFeature(Otc::GameNewSpeedLaw))
  845.         speed *= 2;
  846.  
  847.     int groundSpeed = 0;
  848.     Position tilePos;
  849.  
  850.     if(dir == Otc::InvalidDirection)
  851.         tilePos = m_lastStepToPosition;
  852.     else
  853.         tilePos = m_position.translatedToDirection(dir);
  854.  
  855.     if(!tilePos.isValid())
  856.         tilePos = m_position;
  857.     const TilePtr& tile = g_map.getTile(tilePos);
  858.     if(tile) {
  859.         groundSpeed = tile->getGroundSpeed();
  860.         if(groundSpeed == 0)
  861.             groundSpeed = 150;
  862.     }
  863.  
  864.     int interval = 1000;
  865.     if(groundSpeed > 0 && speed > 0)
  866.         interval = 1000 * groundSpeed;
  867.  
  868.     if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
  869.         int formulatedSpeed = 1;
  870.         if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
  871.             formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
  872.                  + m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
  873.         }
  874.         interval = std::floor(interval / (double)formulatedSpeed);
  875.     }
  876.     else
  877.         interval /= speed;
  878.  
  879.     if(g_game.getClientVersion() >= 900)
  880.         interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();
  881.  
  882.     float factor = 3;
  883.     if(g_game.getClientVersion() <= 810)
  884.         factor = 2;
  885.  
  886.     interval = std::max<int>(interval, g_game.getServerBeat());
  887.  
  888.     if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
  889.        m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
  890.         interval *= factor;
  891.  
  892.     return interval;
  893. }
  894.  
  895. Point Creature::getDisplacement()
  896. {
  897.     if(m_outfit.getCategory() == ThingCategoryEffect)
  898.         return Point(8, 8);
  899.     else if(m_outfit.getCategory() == ThingCategoryItem)
  900.         return Point(0, 0);
  901.     return Thing::getDisplacement();
  902. }
  903.  
  904. int Creature::getDisplacementX()
  905. {
  906.     if(m_outfit.getCategory() == ThingCategoryEffect)
  907.         return 8;
  908.     else if(m_outfit.getCategory() == ThingCategoryItem)
  909.         return 0;
  910.  
  911.     if(m_outfit.getMount() != 0) {
  912.         auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
  913.         return datType->getDisplacementX();
  914.     }
  915.  
  916.     return Thing::getDisplacementX();
  917. }
  918.  
  919. int Creature::getDisplacementY()
  920. {
  921.     if(m_outfit.getCategory() == ThingCategoryEffect)
  922.         return 8;
  923.     else if(m_outfit.getCategory() == ThingCategoryItem)
  924.         return 0;
  925.  
  926.     if(m_outfit.getMount() != 0) {
  927.         auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
  928.         return datType->getDisplacementY();
  929.     }
  930.  
  931.     return Thing::getDisplacementY();
  932. }
  933.  
  934. int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
  935. {
  936.     int exactSize = 0;
  937.  
  938.     animationPhase = 0;
  939.     xPattern = Otc::South;
  940.  
  941.     zPattern = 0;
  942.     if(m_outfit.getMount() != 0)
  943.         zPattern = 1;
  944.  
  945.     for(yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
  946.         if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
  947.             continue;
  948.  
  949.         for(layer = 0; layer < getLayers(); ++layer)
  950.             exactSize = std::max<int>(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
  951.     }
  952.  
  953.     return exactSize;
  954. }
  955.  
  956. const ThingTypePtr& Creature::getThingType()
  957. {
  958.     return g_things.getThingType(m_outfit.getId(), ThingCategoryCreature);
  959. }
  960.  
  961. ThingType* Creature::rawGetThingType()
  962. {
  963.     return g_things.rawGetThingType(m_outfit.getId(), ThingCategoryCreature);
  964. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top