rename item count to countOrSubType, rework and improve things animation/drawing

This commit is contained in:
Eduardo Bart 2012-02-02 14:37:52 -02:00
parent edeee80631
commit ef96215421
24 changed files with 315 additions and 337 deletions

View File

@ -30,14 +30,14 @@ function UIItem:onDrop(widget, mousePos)
if not widget or not widget.currentDragThing then return true end
local pos = self.position
local data = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and data > 1 then
local count = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and count > 1 then
widget.parsed = true
local moveWindow = displayUI('/game/movewindow.otui')
local spinbox = moveWindow:getChildById('spinbox')
spinbox:setMaximum(data)
spinbox:setMaximum(count)
spinbox:setMinimum(1)
spinbox:setCurrentIndex(data)
spinbox:setCurrentIndex(count)
local okButton = moveWindow:getChildById('buttonOk')
okButton.onClick = function() Game.move(widget.currentDragThing, pos, spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end

View File

@ -26,14 +26,14 @@ function UIMap:onDrop(widget, mousePos)
local tile = self:getTile(mousePos)
if not tile then return false end
local data = widget.currentDragThing:getCount()
local count = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and data > 1 then
widget.parsed = true
local moveWindow = displayUI('/game/movewindow.otui')
local spinbox = moveWindow:getChildById('spinbox')
spinbox:setMaximum(data)
spinbox:setMaximum(count)
spinbox:setMinimum(1)
spinbox:setCurrentIndex(data)
spinbox:setCurrentIndex(count)
local okButton = moveWindow:getChildById('buttonOk')
okButton.onClick = function() Game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end

View File

@ -6,6 +6,5 @@ varying vec2 textureCoords; // map texture coords
void main()
{
vec4 outColor = texture2D(texture, textureCoords) * opacity;
gl_FragColor = outColor;
gl_FragColor = texture2D(texture, textureCoords) * opacity;
}

View File

@ -49,6 +49,7 @@ namespace Otc
AWARE_Y_BOTTOM_TILES = AWARE_Y_TILES/2,
EFFECT_TICKS_PER_FRAME = 75,
INVISIBLE_TICKS_PER_FRAME = 500,
ITEM_TICKS_PER_FRAME = 500,
ANIMATED_TEXT_DURATION = 1000,
STATIC_DURATION_PER_CHARACTER = 75,
@ -66,9 +67,11 @@ namespace Otc
DrawCreaturesInformation = 64,
DrawStaticTexts = 128,
DrawAnimatedTexts = 256,
DrawEverything = DrawGround | DrawWalls | DrawCommonItems |
DrawAnimations = 512,
DrawGroundBorders = 1024,
DrawEverything = DrawGround | DrawGroundBorders | DrawWalls | DrawCommonItems |
DrawCreatures | DrawEffects | DrawMissiles |
DrawCreaturesInformation | DrawStaticTexts | DrawAnimatedTexts
DrawCreaturesInformation | DrawStaticTexts | DrawAnimatedTexts | DrawAnimations
};
enum DatOpts {

View File

@ -44,6 +44,7 @@ Creature::Creature() : Thing()
m_showVolatileSquare = false;
m_showStaticSquare = false;
m_direction = Otc::South;
m_walkAnimationPhase = 0;
m_walking = false;
m_walkInterval = 0;
m_walkAnimationInterval = 0;
@ -63,18 +64,20 @@ int LEGS_COLOR_UNIFORM = 12;
int FEET_COLOR_UNIFORM = 13;
int MASK_TEXTURE_UNIFORM = 14;
void Creature::draw(const Point& dest, float scaleFactor)
void Creature::draw(const Point& dest, float scaleFactor, bool animate)
{
int scaledTileSize = Otc::TILE_PIXELS * scaleFactor;
if(m_showVolatileSquare) {
Point animationOffset = animate ? m_walkOffset : Point(0,0);
if(m_showVolatileSquare && animate) {
g_painter.setColor(m_volatileSquareColor);
g_painter.drawBoundingRect(Rect(dest + (m_walkOffset - getDisplacement() + 3)*scaleFactor, Size(28*scaleFactor, 28*scaleFactor)), std::max((int)(2*scaleFactor), 1));
g_painter.drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 3)*scaleFactor, Size(28*scaleFactor, 28*scaleFactor)), std::max((int)(2*scaleFactor), 1));
}
if(m_showStaticSquare) {
if(m_showStaticSquare && animate) {
g_painter.setColor(m_staticSquareColor);
g_painter.drawBoundingRect(Rect(dest + (m_walkOffset - getDisplacement() + 1)*scaleFactor, Size(scaledTileSize, scaledTileSize)), std::max((int)(2*scaleFactor), 1));
g_painter.drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 1)*scaleFactor, Size(scaledTileSize, scaledTileSize)), std::max((int)(2*scaleFactor), 1));
}
g_painter.setColor(Fw::white);
@ -90,12 +93,25 @@ void Creature::draw(const Point& dest, float scaleFactor)
outfitProgram->bindUniformLocation(MASK_TEXTURE_UNIFORM, "maskTexture");
}
// Render creature
int xPattern = 0, yPattern = 0, zPattern = 0;
// outfit is a real creature
if(m_outfit.getCategory() == ThingsType::Creature) {
for(m_yPattern = 0; m_yPattern < getNumPatternsY(); m_yPattern++) {
int animationPhase = animate ? m_walkAnimationPhase : 0;
// xPattern => creature direction
if(m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
xPattern = Otc::East;
else if(m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
xPattern = Otc::West;
else
xPattern = m_direction;
// yPattern => creature addon
for(yPattern = 0; yPattern < getNumPatternsY(); yPattern++) {
// continue if we dont have this addon.
if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1))))
if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
continue;
g_painter.setCustomProgram(outfitProgram);
@ -108,22 +124,23 @@ void Creature::draw(const Point& dest, float scaleFactor)
for(int h = 0; h < getDimensionHeight(); h++) {
for(int w = 0; w < getDimensionWidth(); w++) {
int spriteId = getSpriteId(w, h, 0, m_xPattern, m_yPattern, m_zPattern, m_animation);
int spriteId = getSpriteId(w, h, 0, xPattern, yPattern, zPattern, m_walkAnimationPhase);
if(!spriteId)
continue;
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
if(!spriteTex)
continue;
// setup texture outfit mask
TexturePtr maskTex;
if(getLayers() > 1) {
int maskId = getSpriteId(w, h, 1, m_xPattern, m_yPattern, m_zPattern, m_animation);
int maskId = getSpriteId(w, h, 1, xPattern, yPattern, zPattern, m_walkAnimationPhase);
maskTex = g_sprites.getSpriteTexture(maskId);
}
outfitProgram->setUniformTexture(MASK_TEXTURE_UNIFORM, maskTex, 1);
Rect drawRect(dest.x + (m_walkOffset.x - w*Otc::TILE_PIXELS - getDisplacementX())*scaleFactor,
dest.y + (m_walkOffset.y - h*Otc::TILE_PIXELS - getDisplacementY())*scaleFactor,
Rect drawRect(dest.x + (animationOffset.x - w*Otc::TILE_PIXELS - getDisplacementX())*scaleFactor,
dest.y + (animationOffset.y - h*Otc::TILE_PIXELS - getDisplacementY())*scaleFactor,
scaledTileSize, scaledTileSize);
g_painter.drawTexturedRect(drawRect, spriteTex);
}
@ -131,13 +148,32 @@ void Creature::draw(const Point& dest, float scaleFactor)
g_painter.releaseCustomProgram();
}
// outfit is a creature imitating an item or the invisible effect
} else {
int animationPhase = 0;
int animationPhases = getAnimationPhases();
int animateTicks = Otc::ITEM_TICKS_PER_FRAME;
// when creature is an effect we cant render the first and last animation phase,
// instead we should loop in the phases between
if(m_outfit.getCategory() == ThingsType::Effect) {
animationPhases = std::max(1, animationPhases-2);
animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
}
else if(m_outfit.getCategory() == ThingsType::Item) {
for(int l = 0; l < getLayers(); l++)
internalDraw(dest + m_walkOffset, scaleFactor, l);
if(animationPhases > 1) {
if(animate)
animationPhase = (g_clock.ticks() % (animateTicks * animationPhases)) / animateTicks;
else
animationPhase = animationPhases-1;
}
if(m_outfit.getCategory() == ThingsType::Effect)
animationPhase = std::min(animationPhase+1, getAnimationPhases());
for(int layer = 0; layer < getLayers(); layer++)
internalDraw(dest + animationOffset*scaleFactor, scaleFactor, 0, 0, 0, layer, animationPhase);
}
else if(m_outfit.getCategory() == ThingsType::Effect)
internalDraw(dest + m_walkOffset, scaleFactor, 0);
}
void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect)
@ -244,7 +280,7 @@ void Creature::stopWalk()
// reset walk animation states
m_walkOffset = Point(0,0);
m_animation = 0;
m_walkAnimationPhase = 0;
// stops the walk right away
terminateWalk();
@ -257,9 +293,9 @@ void Creature::updateWalkAnimation(int totalPixelsWalked)
return;
if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || getAnimationPhases() <= 1)
m_animation = 0;
m_walkAnimationPhase = 0;
else if(getAnimationPhases() > 1)
m_animation = 1 + ((totalPixelsWalked * 4) / Otc::TILE_PIXELS) % (getAnimationPhases() - 1);
m_walkAnimationPhase = 1 + ((totalPixelsWalked * 4) / Otc::TILE_PIXELS) % (getAnimationPhases() - 1);
}
void Creature::updateWalkOffset(int totalPixelsWalked)
@ -402,40 +438,13 @@ void Creature::setHealthPercent(uint8 healthPercent)
void Creature::setDirection(Otc::Direction direction)
{
if(m_outfit.getCategory() == ThingsType::Creature) {
if(direction == Otc::NorthEast || direction == Otc::SouthEast)
m_xPattern = Otc::East;
else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
m_xPattern = Otc::West;
else
m_xPattern = direction;
} else {
m_xPattern = 0;
}
m_direction = direction;
}
void Creature::setOutfit(const Outfit& outfit)
{
m_outfit = outfit;
updateType();
m_animation = 0;
if(m_outfit.getCategory() == ThingsType::Effect) {
updateInvisibleAnimation();
m_xPattern = 0;
m_yPattern = 0;
}
if(m_outfit.getCategory() == ThingsType::Item) {
m_xPattern = 0;
m_yPattern = 0;
}
if(m_outfit.getCategory() == ThingsType::Creature && getLayers() == 1) {
m_outfit.resetClothes();
}
m_type = g_thingsType.getThingType(outfit.getId(), outfit.getCategory());
}
void Creature::setSkull(uint8 skull)
@ -493,26 +502,6 @@ void Creature::addVolatileSquare(uint8 color)
}, VOLATILE_SQUARE_DURATION);
}
void Creature::updateInvisibleAnimation()
{
if(!g_game.isOnline() || m_outfit.getCategory() != ThingsType::Effect)
return;
if(m_animation == 1)
m_animation = 2;
else if(m_animation == 2)
m_animation = 3;
else if(m_animation == 3)
m_animation = 1;
else
m_animation = 1;
auto self = asCreature();
g_dispatcher.scheduleEvent([self]() {
self->updateInvisibleAnimation();
}, INVISIBLE_TICKS);
}
void Creature::updateShield()
{
m_showShieldTexture = !m_showShieldTexture;

View File

@ -34,16 +34,16 @@ class Creature : public Thing
public:
enum {
SHIELD_BLINK_TICKS = 500,
INVISIBLE_TICKS = 500,
VOLATILE_SQUARE_DURATION = 1000
};
Creature();
virtual ~Creature() { }
virtual void draw(const Point& dest, float scaleFactor);
virtual void draw(const Point& dest, float scaleFactor, bool animate);
void drawInformation(const Point& point, bool useGray, const Rect& parentRect);
void setId(uint32 id) { m_id = id; }
void setName(const std::string& name);
void setHealthPercent(uint8 healthPercent);
void setDirection(Otc::Direction direction);
@ -64,6 +64,7 @@ public:
void showStaticSquare(const Color& color) { m_showStaticSquare = true; m_staticSquareColor = color; }
void hideStaticSquare() { m_showStaticSquare = false; }
uint32 getId() { return m_id; }
std::string getName() { return m_name; }
uint8 getHealthPercent() { return m_healthPercent; }
Otc::Direction getDirection() { return m_direction; }
@ -96,6 +97,7 @@ protected:
virtual void updateWalk();
virtual void terminateWalk();
uint32 m_id;
std::string m_name;
Size m_nameSize;
uint8 m_healthPercent;
@ -114,6 +116,7 @@ protected:
Color m_informationColor;
// walk related
int m_walkAnimationPhase;
Timer m_walkTimer;
TilePtr m_walkingTile;
int m_walkInterval;

View File

@ -27,35 +27,27 @@
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
void Effect::draw(const Point& dest, float scaleFactor)
void Effect::draw(const Point& dest, float scaleFactor, bool animate)
{
internalDraw(dest, scaleFactor, 0);
if(m_id == 0)
return;
int animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME), getAnimationPhases() - 1);
for(int layer = 0; layer < getLayers(); layer++)
internalDraw(dest, scaleFactor, 0, 0, 0, layer, animate ? animationPhase : 0);
}
void Effect::startAnimation()
{
m_animationTimer.restart();
auto self = asEffect();
// schedule next animation update
if(getAnimationPhases() > 1)
g_dispatcher.scheduleEvent([self]() { self->updateAnimation(); }, Otc::EFFECT_TICKS_PER_FRAME);
// schedule removal
auto self = asEffect();
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, Otc::EFFECT_TICKS_PER_FRAME * getAnimationPhases());
}
void Effect::updateAnimation()
void Effect::setId(uint32 id)
{
int animationPhase = m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME;
if(animationPhase < getAnimationPhases())
m_animation = animationPhase;
if(animationPhase < getAnimationPhases() - 1) {
//schedule next animation update
auto self = asEffect();
g_dispatcher.scheduleEvent([self]() { self->updateAnimation(); }, Otc::EFFECT_TICKS_PER_FRAME);
}
m_id = id;
m_type = g_thingsType.getThingType(m_id, ThingsType::Effect);
}

View File

@ -30,15 +30,17 @@
class Effect : public Thing
{
public:
void draw(const Point& dest, float scaleFactor);
void draw(const Point& dest, float scaleFactor, bool animate);
void setId(uint32 id);
void startAnimation();
void updateAnimation();
uint32 getId() { return m_id; }
EffectPtr asEffect() { return std::static_pointer_cast<Effect>(shared_from_this()); }
private:
Timer m_animationTimer;
uint16 m_id;
};
#endif

View File

@ -32,7 +32,8 @@
Item::Item() : Thing()
{
m_count = 1;
m_id = 0;
m_countOrSubType = 1;
}
ItemPtr Item::create(int id)
@ -48,72 +49,51 @@ ItemPtr Item::create(int id)
PainterShaderProgramPtr itemProgram;
void Item::draw(const Point& dest, float scaleFactor)
void Item::draw(const Point& dest, float scaleFactor, bool animate)
{
if(getAnimationPhases() > 1)
m_animation = (g_clock.ticks() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
if(m_id == 0)
return;
if(!itemProgram) {
itemProgram = PainterShaderProgramPtr(new PainterShaderProgram);
itemProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
itemProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/item.frag");
assert(itemProgram->link());
// determine animation phase
int animationPhase = 0;
if(getAnimationPhases() > 1) {
if(animate)
animationPhase = (g_clock.ticks() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
else
animationPhase = getAnimationPhases()-1;
}
g_painter.setCustomProgram(itemProgram);
for(int layer = 0; layer < getLayers(); layer++)
internalDraw(dest, scaleFactor, layer);
g_painter.releaseCustomProgram();
}
void Item::setPosition(const Position& position)
{
// determine x,y,z patterns
int xPattern = 0, yPattern = 0, zPattern = 0;
if(isGround()) {
m_xPattern = position.x % getNumPatternsX();
m_yPattern = position.y % getNumPatternsY();
m_zPattern = position.z % getNumPatternsZ();
xPattern = m_position.x % getNumPatternsX();
yPattern = m_position.y % getNumPatternsY();
zPattern = m_position.z % getNumPatternsZ();
} else if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
if(m_countOrSubType < 5) {
xPattern = m_countOrSubType-1;
yPattern = 0;
} else if(m_countOrSubType < 10) {
xPattern = 0;
yPattern = 1;
} else if(m_countOrSubType < 25) {
xPattern = 1;
yPattern = 1;
} else if(m_countOrSubType < 50) {
xPattern = 2;
yPattern = 1;
} else if(m_countOrSubType <= 100) {
xPattern = 3;
yPattern = 1;
}
Thing::setPosition(position);
}
void Item::setCount(int count)
{
count = std::max(std::min(count, 255), 0);
if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
if(count < 5) {
m_xPattern = count-1;
m_yPattern = 0;
}
else if(count < 10) {
m_xPattern = 0;
m_yPattern = 1;
}
else if(count < 25) {
m_xPattern = 1;
m_yPattern = 1;
}
else if(count < 50) {
m_xPattern = 2;
m_yPattern = 1;
}
else if(count <= 100) {
m_xPattern = 3;
m_yPattern = 1;
}
}
else if(isHangable()) {
if(isHookSouth()) {
m_xPattern = getNumPatternsX() >= 2 ? 1 : 0;
}
else if(isHookEast()) {
m_xPattern = getNumPatternsX() >= 3 ? 2 : 0;
}
}
else if(isFluid() || isFluidContainer()) {
} else if(isHangable()) {
if(isHookSouth())
xPattern = getNumPatternsX() >= 2 ? 1 : 0;
else if(isHookEast())
xPattern = getNumPatternsX() >= 3 ? 2 : 0;
} else if(isFluid() || isFluidContainer()) {
int color = Otc::FluidTransparent;
switch(count) {
switch(m_countOrSubType) {
case Otc::FluidNone:
color = Otc::FluidTransparent;
break;
@ -173,9 +153,49 @@ void Item::setCount(int count)
break;
}
m_xPattern = (color % 4) % getNumPatternsX();
m_yPattern = (color / 4) % getNumPatternsY();
xPattern = (color % 4) % getNumPatternsX();
yPattern = (color / 4) % getNumPatternsY();
}
m_count = count;
// setup item drawing shader
if(!itemProgram) {
itemProgram = PainterShaderProgramPtr(new PainterShaderProgram);
itemProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
itemProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/item.frag");
assert(itemProgram->link());
}
g_painter.setCustomProgram(itemProgram);
// draw all item layers
for(int layer = 0; layer < getLayers(); layer++)
internalDraw(dest, scaleFactor, xPattern, yPattern, zPattern, layer, animationPhase);
// release draw shader
g_painter.releaseCustomProgram();
}
void Item::setId(uint32 id)
{
if(id < g_thingsType.getFirstItemId() || id > g_thingsType.getMaxItemid()) {
logTraceError("invalid item id ", id);
return;
}
m_id = id;
m_type = g_thingsType.getThingType(m_id, ThingsType::Item);
}
int Item::getCount()
{
if(isStackable())
return m_countOrSubType;
else
return 1;
}
int Item::getSubType()
{
if(isFluid() || isFluidContainer())
return m_countOrSubType;
else
return 0;
}

View File

@ -33,17 +33,23 @@ public:
static ItemPtr create(int id);
void draw(const Point& dest, float scaleFactor);
void draw(const Point& dest, float scaleFactor, bool animate);
void setPosition(const Position &position);
void setCount(int count);
void setId(uint32 id);
void setCountOrSubType(uint8 value) { m_countOrSubType = value; }
void setCount(int count) { setCountOrSubType(count); }
void setSubType(int subType) { setCountOrSubType(subType); }
int getCount() { return m_count; }
uint8 getCountOrSubType() { return m_countOrSubType; }
int getSubType();
int getCount();
uint32 getId() { return m_id; }
ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
private:
uint8 m_count;
uint16 m_id;
uint8 m_countOrSubType;
};
#endif

View File

@ -69,9 +69,9 @@ void Map::load()
while(id != 0xFFFF) {
ItemPtr item = Item::create(id);
if(item->isStackable() || item->isFluidContainer() || item->isFluid()) {
uint8 data;
in.read((char*)&data, sizeof(data));
item->setCount(data);
uint8 countOrSubType;
in.read((char*)&countOrSubType, sizeof(countOrSubType));
item->setCountOrSubType(countOrSubType);
}
addThing(item, pos, 255);
in.read((char*)&id, sizeof(id));
@ -95,8 +95,8 @@ void Map::save()
id = item->getId();
out.write((char*)&id, sizeof(id));
if(item->isStackable() || item->isFluidContainer() || item->isFluid()) {
uint8 data = item->getCount();
out.write((char*)&data, sizeof(data));
uint8 countOrSubType = item->getCountOrSubType();
out.write((char*)&countOrSubType, sizeof(countOrSubType));
}
}
}
@ -264,7 +264,7 @@ void Map::setCentralPosition(const Position& centralPosition)
if(teleported) {
for(const auto& pair : m_knownCreatures) {
const CreaturePtr& creature = pair.second;
const TilePtr& tile = creature->getCurrentTile();
const TilePtr& tile = creature->getTile();
if(tile) {
tile->removeThing(creature);
creature->setPosition(Position());
@ -275,7 +275,7 @@ void Map::setCentralPosition(const Position& centralPosition)
for(const auto& pair : m_knownCreatures) {
const CreaturePtr& creature = pair.second;
if(!isAwareOfPosition(creature->getPosition())) {
const TilePtr& tile = creature->getCurrentTile();
const TilePtr& tile = creature->getTile();
if(tile) {
tile->removeThing(creature);
creature->setPosition(Position());

View File

@ -60,12 +60,14 @@ void MapView::draw(const Rect& rect)
int tileDrawFlags = 0;
if(m_viewRange == NEAR_VIEW)
tileDrawFlags = Otc::DrawGround | Otc::DrawWalls | Otc::DrawCommonItems | Otc::DrawCreatures | Otc::DrawEffects;
tileDrawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawCommonItems | Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawAnimations;
else if(m_viewRange == MID_VIEW)
tileDrawFlags = Otc::DrawGround | Otc::DrawWalls | Otc::DrawCommonItems;
tileDrawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawCommonItems;
else if(m_viewRange == FAR_VIEW)
tileDrawFlags = Otc::DrawGround | Otc::DrawWalls;
else // HUGE_VIEW
tileDrawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls;
else if(m_tileSize >= 4) // HUGE_VIEW 1
tileDrawFlags = Otc::DrawGround | Otc::DrawGroundBorders;
else // HUGE_VIEW 2
tileDrawFlags = Otc::DrawGround;
bool animate = m_animated;
@ -109,11 +111,11 @@ void MapView::draw(const Rect& rect)
// avoid drawing texts on map in far zoom outs
if(m_viewRange == NEAR_VIEW) {
for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
const TilePtr& tile = creature->getCurrentTile();
const TilePtr& tile = creature->getTile();
Position pos = tile->getPosition();
Point p = transformPositionTo2D(pos) - drawOffset;
p += (creature->getWalkOffset()-tile->getDrawElevation() + Point(8, -8)) * scaleFactor;
p += (creature->getWalkOffset()-tile->getDrawElevation() + Point(8, -10)) * scaleFactor;
p.x = p.x * horizontalStretchFactor;
p.y = p.y * verticalStretchFactor;
p += rect.topLeft();

View File

@ -27,24 +27,18 @@
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
Missile::Missile() : Thing()
{
m_startTicks = 0;
}
void Missile::draw(const Point& p, const Rect&)
{
if(m_id == 0)
return;
/*
float time = (g_clock.ticks() - m_startTicks) / m_duration;
//internalDraw(p + Point(m_deltax * time, m_deltay * time), 0);
}
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
{
Otc::Direction direction = fromPosition.getDirectionFromPosition(toPosition);
int xPattern = 0, yPattern = 0;
if(direction == Otc::NorthWest) {
m_xPattern = 0;
m_yPattern = 0;
xPattern = 0;
yPattern = 0;
}
else if(direction == Otc::North) {
m_xPattern = 1;
@ -79,20 +73,29 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition)
m_yPattern = 1;
}
//internalDraw(p + Point(m_deltax * time, m_deltay * time), 0, 0);
*/
}
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
{
m_direction = fromPosition.getDirectionFromPosition(toPosition);
m_position = fromPosition;
m_deltax = toPosition.x - fromPosition.x;
m_deltay = toPosition.y - fromPosition.y;
m_startTicks = g_clock.ticks();
m_duration = 150 * std::sqrt(Point(m_deltax, m_deltay).length());
m_deltax *= Otc::TILE_PIXELS;
m_deltay *= Otc::TILE_PIXELS;
m_animationTimer.restart();
// schedule removal
auto self = asMissile();
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, m_duration);
}
ThingType *Missile::getType()
void Missile::setId(uint32 id)
{
return g_thingsType.getThingType(m_id, ThingsType::Missile);
m_id = id;
m_type = g_thingsType.getThingType(m_id, ThingsType::Missile);
}

View File

@ -24,6 +24,7 @@
#define SHOT_H
#include <framework/global.h>
#include <framework/core/timer.h>
#include "thing.h"
class Missile : public Thing
@ -33,23 +34,24 @@ class Missile : public Thing
};
public:
Missile();
void draw(const Point& p, const Rect&);
void updateAnimation();
void setId(uint32 id);
void setPath(const Position& fromPosition, const Position& toPosition);
ThingType *getType();
uint32 getId() { return m_id; }
MissilePtr asMissile() { return std::static_pointer_cast<Missile>(shared_from_this()); }
private:
ticks_t m_startTicks;
Timer m_animationTimer;
int m_deltax;
int m_deltay;
float m_duration;
uint16 m_id;
Otc::Direction m_direction;
};
#endif

View File

@ -28,20 +28,9 @@
Thing::Thing()
{
m_id = 0;
m_xPattern = 0;
m_yPattern = 0;
m_zPattern = 0;
m_animation = 0;
m_type = g_thingsType.getEmptyThingType();
}
void Thing::setId(uint32 id)
{
m_id = id;
updateType();
}
int Thing::getStackPriority()
{
if(isGround())
@ -58,42 +47,28 @@ int Thing::getStackPriority()
return 5;
}
const TilePtr& Thing::getCurrentTile()
const TilePtr& Thing::getTile()
{
return g_map.getTile(m_position);
}
void Thing::internalDraw(const Point& dest, float scaleFactor, int layer)
void Thing::internalDraw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int layer, int animationPhase)
{
int scaledSize = Otc::TILE_PIXELS * scaleFactor;
for(int h = 0; h < getDimensionHeight(); h++) {
for(int w = 0; w < getDimensionWidth(); w++) {
int spriteId = getSpriteId(w, h, layer, m_xPattern, m_yPattern, m_zPattern, m_animation);
int spriteId = getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animationPhase);
if(!spriteId)
continue;
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
Rect drawRect((dest.x - w*scaledSize) - getDisplacementX()*scaleFactor,
(dest.y - h*scaledSize) - getDisplacementY()*scaleFactor,
Rect drawRect(dest.x - (w*Otc::TILE_PIXELS - getDisplacementX())*scaleFactor,
dest.y - (h*Otc::TILE_PIXELS - getDisplacementY())*scaleFactor,
scaledSize, scaledSize);
g_painter.setColor(Fw::white);
g_painter.drawTexturedRect(drawRect, spriteTex);
}
}
}
void Thing::updateType()
{
if(CreaturePtr creature = asCreature())
m_type = g_thingsType.getThingType(creature->getOutfit().getId(), creature->getOutfit().getCategory());
else if(asItem())
m_type = g_thingsType.getThingType(m_id, ThingsType::Item);
else if(asMissile())
m_type = g_thingsType.getThingType(m_id, ThingsType::Missile);
else if(asEffect())
m_type = g_thingsType.getThingType(m_id, ThingsType::Effect);
else
m_type = g_thingsType.getEmptyThingType();
}

View File

@ -40,19 +40,15 @@ public:
virtual ~Thing() { }
virtual void startAnimation() { }
virtual void draw(const Point& dest, float scaleFactor) { }
virtual void draw(const Point& dest, float scaleFactor, bool animate) { }
virtual void setId(uint32 id);
virtual void setPosition(const Position& position) { m_position = position; }
virtual void setId(uint32 id) { }
void setPosition(const Position& position) { m_position = position; }
uint32 getId() { return m_id; }
virtual uint32 getId() { return 0; }
Position getPosition() { return m_position; }
int getStackPriority();
const TilePtr& getCurrentTile();
void setXPattern(int xPattern) { m_xPattern = xPattern; }
void setYPattern(int yPattern) { m_yPattern = yPattern; }
void setZPattern(int zPattern) { m_zPattern = zPattern; }
const TilePtr& getTile();
ThingPtr asThing() { return std::static_pointer_cast<Thing>(shared_from_this()); }
virtual ItemPtr asItem() { return nullptr; }
@ -105,14 +101,9 @@ public:
int getSpriteId(int w = 0, int h = 0, int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animation = 0) { return m_type->getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animation); }
protected:
void internalDraw(const Point& dest, float scaleFactor, int layer);
void updateType();
void internalDraw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int layer, int animationPhase);
uint32 m_id; //TODO: move to derived class to use less memory
Position m_position;
uint8 m_xPattern, m_yPattern, m_zPattern, m_animation; //TODO: remove this variables to use less memory
private:
ThingType *m_type;
};

View File

@ -115,11 +115,12 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType)
ThingType *ThingsType::getThingType(uint16 id, Categories category)
{
assert(id != 0);
if(category == Item)
id -= 100;
else if(category == Creature || category == Effect || category == Missile)
id -= 1;
assert(id < m_things[category].size());
if(id == 0 || id >= m_things[category].size())
return &m_emptyThingType;
return &m_things[category][id];
}

View File

@ -49,8 +49,8 @@ public:
uint32 getSignature() { return m_signature; }
bool isLoaded() { return m_loaded; }
int getFirstItemId() { return 100; }
int getMaxItemid() { return m_things[Item].size() + 100 - 1; }
uint16 getFirstItemId() { return 100; }
uint16 getMaxItemid() { return m_things[Item].size() + 99; }
private:
uint32 m_signature;

View File

@ -39,23 +39,18 @@ Tile::Tile(const Position& position)
void Tile::draw(const Point& dest, float scaleFactor, int drawFlags)
{
int drawElevation = 0;
// optimization far far views
if(drawFlags == Otc::DrawGround) {
const ThingPtr& thing = m_things.front();
if(thing)
thing->draw(dest, scaleFactor);
return;
}
bool animate = drawFlags & Otc::DrawAnimations;
// first bottom items
if(drawFlags & Otc::DrawGround || drawFlags & Otc::DrawWalls) {
if(drawFlags & Otc::DrawGround || drawFlags & Otc::DrawWalls || drawFlags & Otc::DrawGroundBorders) {
for(const ThingPtr& thing : m_things) {
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
break;
if((drawFlags & Otc::DrawGround && thing->isGround()) || (drawFlags & Otc::DrawWalls))
thing->draw(dest - drawElevation*scaleFactor, scaleFactor);
if((thing->isGround() && drawFlags & Otc::DrawGround) ||
(thing->isGroundBorder() && drawFlags & Otc::DrawGroundBorders) ||
(thing->isOnBottom() && drawFlags & Otc::DrawWalls))
thing->draw(dest - drawElevation*scaleFactor, scaleFactor, animate);
drawElevation += thing->getElevation();
if(drawElevation > Otc::MAX_ELEVATION)
@ -69,7 +64,7 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags)
const ThingPtr& thing = *it;
if(thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround() || thing->asCreature())
break;
thing->draw(dest - drawElevation*scaleFactor, scaleFactor);
thing->draw(dest - drawElevation*scaleFactor, scaleFactor, animate);
drawElevation += thing->getElevation();
if(drawElevation > Otc::MAX_ELEVATION)
@ -79,30 +74,32 @@ void Tile::draw(const Point& dest, float scaleFactor, int drawFlags)
// creatures
if(drawFlags & Otc::DrawCreatures) {
if(animate) {
for(const CreaturePtr& creature : m_walkingCreatures) {
creature->draw(Point(dest.x + ((creature->getPosition().x - m_position.x)*Otc::TILE_PIXELS - drawElevation)*scaleFactor,
dest.y + ((creature->getPosition().y - m_position.y)*Otc::TILE_PIXELS - drawElevation)*scaleFactor), scaleFactor);
dest.y + ((creature->getPosition().y - m_position.y)*Otc::TILE_PIXELS - drawElevation)*scaleFactor), scaleFactor, animate);
}
}
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
CreaturePtr creature = (*it)->asCreature();
if(creature && !creature->isWalking())
creature->draw(dest - drawElevation, scaleFactor);
if(creature && (!creature->isWalking() || !animate))
creature->draw(dest - drawElevation, scaleFactor, animate);
}
}
// effects
if(drawFlags & Otc::DrawEffects) {
for(const EffectPtr& effect : m_effects)
effect->draw(dest, scaleFactor);
effect->draw(dest, scaleFactor, animate);
}
// top items
if(drawFlags & Otc::DrawWalls) {
for(const ThingPtr& thing : m_things) {
if(thing->isOnTop())
thing->draw(dest - drawElevation, scaleFactor);
thing->draw(dest - drawElevation, scaleFactor, animate);
}
}
}

View File

@ -92,9 +92,6 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<Thing>("getPosition", &Thing::getPosition);
g_lua.bindClassMemberFunction<Thing>("getStackPriority", &Thing::getStackPriority);
g_lua.bindClassMemberFunction<Thing>("getAnimationPhases", &Thing::getAnimationPhases);
g_lua.bindClassMemberFunction<Thing>("setXPattern", &Thing::setXPattern);
g_lua.bindClassMemberFunction<Thing>("setYPattern", &Thing::setYPattern);
g_lua.bindClassMemberFunction<Thing>("setZPattern", &Thing::setZPattern);
g_lua.bindClassMemberFunction<Thing>("asThing", &Thing::asThing);
g_lua.bindClassMemberFunction<Thing>("asItem", &Thing::asItem);
g_lua.bindClassMemberFunction<Thing>("asCreature", &Thing::asCreature);

View File

@ -1125,7 +1125,7 @@ ItemPtr ProtocolGame::internalGetItem(InputMessage& msg, int id)
ItemPtr item = Item::create(id);
if(item->isStackable() || item->isFluidContainer() || item->isFluid())
item->setCount(msg.getU8());
item->setCountOrSubType(msg.getU8());
return item;
}

View File

@ -30,7 +30,7 @@ void UICreature::draw()
if(m_creature) {
g_painter.setColor(Fw::white);
m_creature->draw(m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top), 1);
m_creature->draw(m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top), 1, false);
}
drawChildren();

View File

@ -38,7 +38,7 @@ void UIItem::draw()
Point topLeft = m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top);
g_painter.setColor(Fw::white);
m_item->draw(topLeft, 1);
m_item->draw(topLeft, 1, true);
if(m_font && m_item->isStackable() && m_item->getCount() > 1) {
std::string count = Fw::tostring(m_item->getCount());
@ -65,12 +65,6 @@ void UIItem::setItemId(int id)
}
}
void UIItem::setItemCount(int count)
{
if(m_item)
m_item->setCount(count);
}
void UIItem::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);

View File

@ -34,13 +34,15 @@ public:
void draw();
void setItemId(int id);
void setItemCount(int count);
void setItemCount(int count) { if(m_item) m_item->setCount(count); }
void setItemSubType(int subType) { if(m_item) m_item->setSubType(subType); }
void setItem(const ItemPtr& item) { m_item = item; }
void setVirtual(bool virt) { m_virtual = virt; }
void clearItem() { setItemId(0); }
int getItemId() { return m_item ? m_item->getId() : 0; }
int getItemCount() { return m_item ? m_item->getCount() : 0; }
int getItemSubType() { return m_item ? m_item->getSubType() : 0; }
ItemPtr getItem() { return m_item; }
bool isVirtual() { return m_virtual; }