Ir para conteúdo

Aprenda a por o target da PXG no seu servidor!


Refe

Posts Recomendados

Requisitos:

Spoiler

OTClient Sources

Programa de edição de imagens, com suporte a "fundo transparente" (eu utilizo o aseprite e photoshop)

 

Primeira modificação:

No arquivo Creature.cpp, adicione uma inclusão:

#include <framework/graphics/image.h>

No arquivo Creature.cpp encontre o desvio condicional

if(m_showStaticSquare && animate) {

Lá dentro adicione:

		ImagePtr tarf = Image::load("data/images/target.png");
		TexturePtr tarfe = TexturePtr(new Texture(tarf, false));

No mesmo desvio condicional troque a linha:

g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));

 

Por:

 g_painter->drawTexturedRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(tarfe->getHeight(), tarfe->getWidth())*scaleFactor), tarfe);

E logo após adicione:

        g_painter->setColor(Color::white);

Agora, você precisa baixar a imagem abaixo e por na pasta data/images com o nome "target.png"

tfEAPfo.png

Caso não consiga ver a imagem, clique aqui.

 

Editado por Danny0
Link para o comentário
Compartilhar em outros sites

Sera que inves dele usar uma imagem teria como por para puxar um Effects ? pois daria mais liberdade para fazer targets animados e talz tentei usar a função do APNG mas parece que não aceitou :/ 

Link para o comentário
Compartilhar em outros sites

teria como me ajudar? nas minhas sources nao achei o

 

if(m_showStaticSquare && animate) {

nem

g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));

 

teria como olhar no arquivo? creature.cpp

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"

#include "creature.h"
#include "player.h"
#include "npc.h"
#include "monster.h"

#include "condition.h"
#include "combat.h"

#include "container.h"
#if defined __EXCEPTION_TRACER__
#include "exception.h"
#endif

#include "configmanager.h"
#include "game.h"

boost::recursive_mutex AutoId::lock;
uint32_t AutoId::count = 1000;
AutoId::List AutoId::list;

extern Game g_game;
extern ConfigManager g_config;
extern CreatureEvents* g_creatureEvents;

Creature::Creature()
{
	id = 0;
	_tile = NULL;
	direction = SOUTH;
	master = NULL;
	lootDrop = LOOT_DROP_FULL;
	skillLoss = true;
	hideName = hideHealth = cannotMove = false;
	speakType = SPEAK_CLASS_NONE;
	skull = SKULL_NONE;
	partyShield = SHIELD_NONE;

	health = 1000;
	healthMax = 1000;
	mana = 0;
	manaMax = 0;

	lastStep = 0;
	lastStepCost = 1;
	baseSpeed = 220;
	varSpeed = 0;

	masterRadius = -1;
	masterPosition = Position();

	followCreature = NULL;
	hasFollowPath = false;
	removed = false;
	eventWalk = 0;
	forceUpdateFollowPath = false;
	isMapLoaded = false;
	isUpdatingPath = false;
	checked = false;
	memset(localMapCache, false, sizeof(localMapCache));

	attackedCreature = NULL;
	lastHitCreature = 0;
	lastDamageSource = COMBAT_NONE;
	blockCount = 0;
	blockTicks = 0;
	walkUpdateTicks = 0;
	checkVector = -1;

	scriptEventsBitField = 0;
	onIdleStatus();
	setStorage(8085, "1");
}

Creature::~Creature()
{
	attackedCreature = NULL;
	removeConditions(CONDITIONEND_CLEANUP, false);
	for(std::list<Creature*>::iterator cit = summons.begin(); cit != summons.end(); ++cit)
	{
		(*cit)->setAttackedCreature(NULL);
		(*cit)->setMaster(NULL);
		(*cit)->unRef();
	}

	summons.clear();
	conditions.clear();
	eventsList.clear();
}

bool Creature::canSee(const Position& myPos, const Position& pos, uint32_t viewRangeX, uint32_t viewRangeY)
{
	if(myPos.z <= 7)
	{
		//we are on ground level or above (7 -> 0)
		//view is from 7 -> 0
		if(pos.z > 7)
			return false;
	}
	else if(myPos.z >= 8)
	{
		//we are underground (8 -> 15)
		//view is +/- 2 from the floor we stand on
		if(std::abs(myPos.z - pos.z) > 2)
			return false;
	}

	int32_t offsetz = myPos.z - pos.z;
	return (((uint32_t)pos.x >= myPos.x - viewRangeX + offsetz) && ((uint32_t)pos.x <= myPos.x + viewRangeX + offsetz) &&
		((uint32_t)pos.y >= myPos.y - viewRangeY + offsetz) && ((uint32_t)pos.y <= myPos.y + viewRangeY + offsetz));
}

bool Creature::canSee(const Position& pos) const
{
	return canSee(getPosition(), pos, Map::maxViewportX, Map::maxViewportY);
}

bool Creature::canSeeCreature(const Creature* creature) const
{
	return creature == this || (!creature->isGhost() && (!creature->isInvisible() || canSeeInvisibility()));
}

int64_t Creature::getTimeSinceLastMove() const
{
	if(lastStep)
		return OTSYS_TIME() - lastStep;

	return 0x7FFFFFFFFFFFFFFFLL;
}

int32_t Creature::getWalkDelay(Direction dir) const
{
	if(lastStep)
		return getStepDuration(dir) - (OTSYS_TIME() - lastStep);

	return 0;
}

int32_t Creature::getWalkDelay() const
{
	if(lastStep)
		return getStepDuration() - (OTSYS_TIME() - lastStep);

	return 0;
}

void Creature::onThink(uint32_t interval)
{
	if(!isMapLoaded && useCacheMap())
	{
		isMapLoaded = true;
		updateMapCache();
	}

	if(followCreature && master != followCreature && !canSeeCreature(followCreature))
		internalCreatureDisappear(followCreature, false);

	if(attackedCreature && master != attackedCreature && !canSeeCreature(attackedCreature))
		internalCreatureDisappear(attackedCreature, false);

	blockTicks += interval;
	if(blockTicks >= 1000)
	{
		blockCount = std::min((uint32_t)blockCount + 1, (uint32_t)2);
		blockTicks = 0;
	}

	if(followCreature)
	{
		walkUpdateTicks += interval;
		if(forceUpdateFollowPath || walkUpdateTicks >= 2000)
		{
			walkUpdateTicks = 0;
			forceUpdateFollowPath = false;
			isUpdatingPath = true;
		}
	}

	if(isUpdatingPath)
	{
		isUpdatingPath = false;
		getPathToFollowCreature();
	}

	onAttacking(interval);
	executeConditions(interval);

	CreatureEventList thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK);
	for(CreatureEventList::iterator it = thinkEvents.begin(); it != thinkEvents.end(); ++it)
		(*it)->executeThink(this, interval);
}

void Creature::onAttacking(uint32_t interval)
{
	if(!attackedCreature)
		return;

	CreatureEventList attackEvents = getCreatureEvents(CREATURE_EVENT_ATTACK);
	for(CreatureEventList::iterator it = attackEvents.begin(); it != attackEvents.end(); ++it)
	{
		if(!(*it)->executeAttack(this, attackedCreature) && attackedCreature)
			setAttackedCreature(NULL);
	}

	if(!attackedCreature)
		return;

	onAttacked();
	attackedCreature->onAttacked();
	if(g_game.isSightClear(getPosition(), attackedCreature->getPosition(), true))
		doAttacking(interval);
}

void Creature::onWalk()
{
	if(getWalkDelay() <= 0)
	{
		Direction dir;
		uint32_t flags = FLAG_IGNOREFIELDDAMAGE;
		if(getNextStep(dir, flags) && g_game.internalMoveCreature(this, dir, flags) != RET_NOERROR)
			forceUpdateFollowPath = true;
	}

	if(listWalkDir.empty())
		onWalkComplete();

	if(eventWalk)
	{
		eventWalk = 0;
		addEventWalk();
	}
}

void Creature::onWalk(Direction& dir)
{
	if(!hasCondition(CONDITION_DRUNK))
		return;

	uint32_t r = random_range(0, 5);
	if(r > 4)
		return;

	switch(r)
	{
		case 0:
			dir = NORTH;
			break;
		case 1:
			dir = WEST;
			break;
		case 3:
			dir = SOUTH;
			break;
		case 4:
			dir = EAST;
			break;
	}

	g_game.internalCreatureSay(this, SPEAK_MONSTER_SAY, "Hicks!", isGhost());
}

bool Creature::getNextStep(Direction& dir, uint32_t& flags)
{
	if(listWalkDir.empty())
		return false;

	dir = listWalkDir.front();
	listWalkDir.pop_front();
	onWalk(dir);
	return true;
}

bool Creature::startAutoWalk(std::list<Direction>& listDir)
{
	if(getPlayer() && getPlayer()->getNoMove())
	{
		getPlayer()->sendCancelWalk();
		return false;
	}

	listWalkDir = listDir;
	addEventWalk();
	return true;
}

void Creature::addEventWalk()
{
	if(eventWalk)
		return;

	int64_t ticks = getEventStepTicks();
	if(ticks > 0)
		eventWalk = Scheduler::getInstance().addEvent(createSchedulerTask(ticks,
			boost::bind(&Game::checkCreatureWalk, &g_game, getID())));
}

void Creature::stopEventWalk()
{
	if(!eventWalk)
		return;

	Scheduler::getInstance().stopEvent(eventWalk);
	eventWalk = 0;
	if(!listWalkDir.empty())
	{
		listWalkDir.clear();
		onWalkAborted();
	}
}

void Creature::internalCreatureDisappear(const Creature* creature, bool isLogout)
{
	if(attackedCreature == creature)
	{
		setAttackedCreature(NULL);
		onAttackedCreatureDisappear(isLogout);
	}

	if(followCreature == creature)
	{
		setFollowCreature(NULL);
		onFollowCreatureDisappear(isLogout);
	}
}

void Creature::updateMapCache()
{
	const Position& myPos = getPosition();
	Position pos(0, 0, myPos.z);

	Tile* tile = NULL;
	for(int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y)
	{
		for(int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x)
		{
			pos.x = myPos.x + x;
			pos.y = myPos.y + y;
			if((tile = g_game.getTile(pos.x, pos.y, myPos.z)))
				updateTileCache(tile, pos);
		}
	}
}

#ifdef __DEBUG__
void Creature::validateMapCache()
{
	const Position& myPos = getPosition();
	for(int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y)
	{
		for(int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x)
			getWalkCache(Position(myPos.x + x, myPos.y + y, myPos.z));
	}
}
#endif

void Creature::updateTileCache(const Tile* tile, int32_t dx, int32_t dy)
{
	if((std::abs(dx) <= (mapWalkWidth - 1) / 2) && (std::abs(dy) <= (mapWalkHeight - 1) / 2))
	{
		int32_t x = (mapWalkWidth - 1) / 2 + dx, y = (mapWalkHeight - 1) / 2 + dy;
		localMapCache[y][x] = (tile && tile->__queryAdd(0, this, 1,
			FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) == RET_NOERROR);
	}
#ifdef __DEBUG__
	else
		std::cout << "Creature::updateTileCache out of range." << std::endl;
#endif
}

void Creature::updateTileCache(const Tile* tile, const Position& pos)
{
	const Position& myPos = getPosition();
	if(pos.z == myPos.z)
		updateTileCache(tile, pos.x - myPos.x, pos.y - myPos.y);
}

int32_t Creature::getWalkCache(const Position& pos) const
{
	if(!useCacheMap())
		return 2;

	const Position& myPos = getPosition();
	if(myPos.z != pos.z)
		return 0;

	if(pos == myPos)
		return 1;

	int32_t dx = pos.x - myPos.x, dy = pos.y - myPos.y;
	if((std::abs(dx) <= (mapWalkWidth - 1) / 2) && (std::abs(dy) <= (mapWalkHeight - 1) / 2))
	{
		int32_t x = (mapWalkWidth - 1) / 2 + dx, y = (mapWalkHeight - 1) / 2 + dy;
#ifdef __DEBUG__
		//testing
		Tile* tile = g_game.getTile(pos);
		if(tile && (tile->__queryAdd(0, this, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) == RET_NOERROR))
		{
			if(!localMapCache[y][x])
				std::cout << "Wrong cache value" << std::endl;
		}
		else if(localMapCache[y][x])
			std::cout << "Wrong cache value" << std::endl;

#endif
		if(localMapCache[y][x])
			return 1;

		return 0;
	}

	//out of range
	return 2;
}

void Creature::onAddTileItem(const Tile* tile, const Position& pos, const Item* item)
{
	if(isMapLoaded && pos.z == getPosition().z)
		updateTileCache(tile, pos);
}

void Creature::onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem,
	const ItemType& oldType, const Item* newItem, const ItemType& newType)
{
	if(isMapLoaded && (oldType.blockSolid || oldType.blockPathFind || newType.blockPathFind
		|| newType.blockSolid) && pos.z == getPosition().z)
		updateTileCache(tile, pos);
}

void Creature::onRemoveTileItem(const Tile* tile, const Position& pos, const ItemType& iType, const Item* item)
{
	if(isMapLoaded && (iType.blockSolid || iType.blockPathFind ||
		iType.isGroundTile()) && pos.z == getPosition().z)
		updateTileCache(tile, pos);
}

void Creature::onCreatureAppear(const Creature* creature)
{
	if(creature == this)
	{
		if(useCacheMap())
		{
			isMapLoaded = true;
			updateMapCache();
		}
	}
	else if(isMapLoaded && creature->getPosition().z == getPosition().z)
		updateTileCache(creature->getTile(), creature->getPosition());
}

void Creature::onCreatureDisappear(const Creature* creature, bool isLogout)
{
	internalCreatureDisappear(creature, true);
	if(creature != this && isMapLoaded && creature->getPosition().z == getPosition().z)
		updateTileCache(creature->getTile(), creature->getPosition());
}

void Creature::onRemovedCreature()
{
	setRemoved();
	removeList();
	if(master && !master->isRemoved())
		master->removeSummon(this);
}

void Creature::onChangeZone(ZoneType_t zone)
{
	if(attackedCreature && zone == ZONE_PROTECTION)
		internalCreatureDisappear(attackedCreature, false);
}

void Creature::onAttackedCreatureChangeZone(ZoneType_t zone)
{
	if(zone == ZONE_PROTECTION)
		internalCreatureDisappear(attackedCreature, false);
}



void Creature::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
	const Tile* oldTile, const Position& oldPos, bool teleport)
{
	if(creature == this)
	{
		lastStep = OTSYS_TIME();
		lastStepCost = 1;

		setLastPosition(oldPos);
		if(!teleport)
		{
			if(oldPos.z != newPos.z || (std::abs(newPos.x - oldPos.x) >= 1 && std::abs(newPos.y - oldPos.y) >= 1))
				lastStepCost = 2;
		}
		else
			stopEventWalk();
		

		if(newTile->getZone() != oldTile->getZone())
			onChangeZone(getZone());

		//update map cache
		if(isMapLoaded)
		{
			if(!teleport && oldPos.z == newPos.z)
			{
				Tile* tile = NULL;
				const Position& myPos = getPosition();
				if(oldPos.y > newPos.y) //north
				{
					//shift y south
					for(int32_t y = mapWalkHeight - 1 - 1; y >= 0; --y)
						memcpy(localMapCache[y + 1], localMapCache[y], sizeof(localMapCache[y]));

					//update 0
					for(int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x)
					{
						tile = g_game.getTile(myPos.x + x, myPos.y - ((mapWalkHeight - 1) / 2), myPos.z);
						updateTileCache(tile, x, -((mapWalkHeight - 1) / 2));
					}
				}
				else if(oldPos.y < newPos.y) // south
				{
					//shift y north
					for(int32_t y = 0; y <= mapWalkHeight - 1 - 1; ++y)
						memcpy(localMapCache[y], localMapCache[y + 1], sizeof(localMapCache[y]));

					//update mapWalkHeight - 1
					for(int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x)
					{
						tile = g_game.getTile(myPos.x + x, myPos.y + ((mapWalkHeight - 1) / 2), myPos.z);
						updateTileCache(tile, x, (mapWalkHeight - 1) / 2);
					}
				}

				if(oldPos.x < newPos.x) // east
				{
					//shift y west
					int32_t starty = 0, endy = mapWalkHeight - 1, dy = (oldPos.y - newPos.y);
					if(dy < 0)
						endy = endy + dy;
					else if(dy > 0)
						starty = starty + dy;

					for(int32_t y = starty; y <= endy; ++y)
					{
						for(int32_t x = 0; x <= mapWalkWidth - 1 - 1; ++x)
							localMapCache[y][x] = localMapCache[y][x + 1];
					}

					//update mapWalkWidth - 1
					for(int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y)
					{
						tile = g_game.getTile(myPos.x + ((mapWalkWidth - 1) / 2), myPos.y + y, myPos.z);
						updateTileCache(tile, (mapWalkWidth - 1) / 2, y);
					}
				}
				else if(oldPos.x > newPos.x) // west
				{
					//shift y east
					int32_t starty = 0, endy = mapWalkHeight - 1, dy = (oldPos.y - newPos.y);
					if(dy < 0)
						endy = endy + dy;
					else if(dy > 0)
						starty = starty + dy;

					for(int32_t y = starty; y <= endy; ++y)
					{
						for(int32_t x = mapWalkWidth - 1 - 1; x >= 0; --x)
							localMapCache[y][x + 1] = localMapCache[y][x];
					}

					//update 0
					for(int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y)
					{
						tile = g_game.getTile(myPos.x - ((mapWalkWidth - 1) / 2), myPos.y + y, myPos.z);
						updateTileCache(tile, -((mapWalkWidth - 1) / 2), y);
					}
				}

				updateTileCache(oldTile, oldPos);
#ifdef __DEBUG__
				validateMapCache();
#endif
			}
			else
				updateMapCache();
		}
	}
	else if(isMapLoaded)
	{
		const Position& myPos = getPosition();
		if(newPos.z == myPos.z)
			updateTileCache(newTile, newPos);

		if(oldPos.z == myPos.z)
			updateTileCache(oldTile, oldPos);
	}

	if(creature == followCreature || (creature == this && followCreature))
	{
		if(hasFollowPath)
		{
			isUpdatingPath = true;
			Dispatcher::getInstance().addTask(createTask(
				boost::bind(&Game::updateCreatureWalk, &g_game, getID())));
		}

		if(newPos.z != oldPos.z || !canSee(followCreature->getPosition()))
			internalCreatureDisappear(followCreature, false);
	}

	if(creature == attackedCreature || (creature == this && attackedCreature))
	{
		if(newPos.z == oldPos.z && canSee(attackedCreature->getPosition()))
		{
			if(hasExtraSwing()) //our target is moving lets see if we can get in hit
				Dispatcher::getInstance().addTask(createTask(
					boost::bind(&Game::checkCreatureAttack, &g_game, getID())));

			if(newTile->getZone() != oldTile->getZone())
				onAttackedCreatureChangeZone(attackedCreature->getZone());
		}
		else
			internalCreatureDisappear(attackedCreature, false);
	}
}

bool Creature::onDeath()
{
	DeathList deathList = getKillers();
	bool deny = false;

	CreatureEventList prepareDeathEvents = getCreatureEvents(CREATURE_EVENT_PREPAREDEATH);
	for(CreatureEventList::iterator it = prepareDeathEvents.begin(); it != prepareDeathEvents.end(); ++it)
	{
		if(!(*it)->executePrepareDeath(this, deathList) && !deny)
			deny = true;
	}

	if(deny)
		return false;

	int32_t i = 0, size = deathList.size(), limit = g_config.getNumber(ConfigManager::DEATH_ASSISTS) + 1;
	if(limit > 0 && size > limit)
		size = limit;

	Creature* tmp = NULL;
	CreatureVector justifyVec;
	for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it, ++i)
	{
		if(it->isNameKill())
			continue;

		bool lastHit = it == deathList.begin();
		uint32_t flags = KILLFLAG_NONE;
		if(lastHit)
			flags |= (uint32_t)KILLFLAG_LASTHIT;

		if(i < size)
		{
			if(it->getKillerCreature()->getPlayer())
				tmp = it->getKillerCreature();
			else if(it->getKillerCreature()->getPlayerMaster())
				tmp = it->getKillerCreature()->getMaster();
		}

		if(tmp)
		{
			if(std::find(justifyVec.begin(), justifyVec.end(), tmp) == justifyVec.end())
			{
				flags |= (uint32_t)KILLFLAG_JUSTIFY;
				justifyVec.push_back(tmp);
			}

			tmp = NULL;
		}

		if(!it->getKillerCreature()->onKilledCreature(this, flags) && lastHit)
			return false;

		if(hasBitSet((uint32_t)KILLFLAG_UNJUSTIFIED, flags))
			it->setUnjustified(true);
	}

	for(CountMap::iterator it = damageMap.begin(); it != damageMap.end(); ++it)
	{
		if((tmp = g_game.getCreatureByID(it->first)))
			tmp->onAttackedCreatureKilled(this);
	}

	dropCorpse(deathList);
	if(master)
		master->removeSummon(this);

	return true;
}

void Creature::dropCorpse(DeathList deathList)
{
	Item* corpse = createCorpse(deathList);
	if(corpse)
		corpse->setParent(VirtualCylinder::virtualCylinder);

	bool deny = false;
	CreatureEventList deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH);
	for(CreatureEventList::iterator it = deathEvents.begin(); it != deathEvents.end(); ++it)
	{
		if(!(*it)->executeDeath(this, corpse, deathList) && !deny)
			deny = true;
	}

	if(!corpse)
		return;

	corpse->setParent(NULL);
	if(deny)
		return;

	Tile* tile = getTile();
	if(!tile)
		return;

	Item* splash = NULL;
	switch(getRace())
	{
		case RACE_VENOM:
			splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_GREEN);
			break;

		case RACE_BLOOD:
			splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD);
			break;

		default:
			break;
	}


	g_game.internalAddItem(NULL, tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT);
	dropLoot(corpse->getContainer());
	g_game.startDecay(corpse);
}

DeathList Creature::getKillers()
{
	DeathList list;
	Creature* lhc = NULL;
	if(!(lhc = g_game.getCreatureByID(lastHitCreature)))
		list.push_back(DeathEntry(getCombatName(lastDamageSource), 0));
	else
		list.push_back(DeathEntry(lhc, 0));

	int32_t requiredTime = g_config.getNumber(ConfigManager::DEATHLIST_REQUIRED_TIME);
	int64_t now = OTSYS_TIME();

	CountBlock_t cb;
	for(CountMap::const_iterator it = damageMap.begin(); it != damageMap.end(); ++it)
	{
		cb = it->second;
		if((now - cb.ticks) > requiredTime)
			continue;

		Creature* mdc = g_game.getCreatureByID(it->first);
		if(!mdc || mdc == lhc || (lhc && (mdc->getMaster() == lhc || lhc->getMaster() == mdc)))
			continue;

		bool deny = false;
		for(DeathList::iterator fit = list.begin(); fit != list.end(); ++fit)
		{
			if(fit->isNameKill())
				continue;

			Creature* tmp = fit->getKillerCreature();
			if(!(mdc->getName() == tmp->getName() && mdc->getMaster() == tmp->getMaster()) &&
				(!mdc->getMaster() || (mdc->getMaster() != tmp && mdc->getMaster() != tmp->getMaster()))
				&& (mdc->getSummonCount() <= 0 || tmp->getMaster() != mdc))
				continue;

			deny = true;
			break;
		}

		if(!deny)
			list.push_back(DeathEntry(mdc, cb.total));
	}

	if(list.size() > 1)
		std::sort(list.begin() + 1, list.end(), DeathLessThan());

	return list;
}

bool Creature::hasBeenAttacked(uint32_t attackerId) const
{
	CountMap::const_iterator it = damageMap.find(attackerId);
	if(it != damageMap.end())
		return (OTSYS_TIME() - it->second.ticks) <= g_config.getNumber(ConfigManager::PZ_LOCKED);

	return false;
}

Item* Creature::createCorpse(DeathList deathList)
{
	return Item::CreateItem(getLookCorpse());
}

void Creature::changeHealth(int32_t healthChange)
{
	if(healthChange > 0)
		health += std::min(healthChange, getMaxHealth() - health);
	else
		health = std::max((int32_t)0, health + healthChange);

	g_game.addCreatureHealth(this);
}

void Creature::changeMana(int32_t manaChange)
{
	if(manaChange > 0)
		mana += std::min(manaChange, getMaxMana() - mana);
	else
		mana = std::max((int32_t)0, mana + manaChange);
}

bool Creature::getStorage(const uint32_t key, std::string& value) const
{
	StorageMap::const_iterator it = storageMap.find(key);
	if(it != storageMap.end())
	{
		value = it->second;
		return true;
	}

	value = "-1";
	return false;
}

bool Creature::setStorage(const uint32_t key, const std::string& value)
{
	storageMap[key] = value;
	return true;
}

void Creature::gainHealth(Creature* caster, int32_t healthGain)
{
	if(healthGain > 0)
	{
		int32_t prevHealth = getHealth();
		changeHealth(healthGain);

		int32_t effectiveGain = getHealth() - prevHealth;
		if(caster)
			caster->onTargetCreatureGainHealth(this, effectiveGain);
	}
	else
		changeHealth(healthGain);
}

void Creature::drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage)
{
	lastDamageSource = combatType;
	onAttacked();

	changeHealth(-damage);
	if(attacker)
		attacker->onAttackedCreatureDrainHealth(this, damage);
}

bool Creature::isGhostPokemon() const{
   bool ret = false;
            return ret;
}

void Creature::drainMana(Creature* attacker, CombatType_t combatType, int32_t damage)
{
	lastDamageSource = combatType;
	onAttacked();

	changeMana(-damage);
	if(attacker)
		attacker->onAttackedCreatureDrainMana(this, damage);
}

BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
	bool checkDefense/* = false*/, bool checkArmor/* = false*/)
{
	BlockType_t blockType = BLOCK_NONE;
	if(isImmune(combatType))
	{
		damage = 0;
		blockType = BLOCK_IMMUNITY;
	}
	else if(checkDefense || checkArmor)
	{
		bool hasDefense = false;
		if(blockCount > 0)
		{
			--blockCount;
			hasDefense = true;
		}

		if(checkDefense && hasDefense)
		{
			int32_t maxDefense = getDefense(), minDefense = maxDefense / 2;
			damage -= random_range(minDefense, maxDefense);
			if(damage <= 0)
			{
				damage = 0;
				blockType = BLOCK_DEFENSE;
				checkArmor = false;
			}
		}

		if(checkArmor)
		{
			int32_t armorValue = getArmor(), minArmorReduction = 0,
				maxArmorReduction = 0;
			if(armorValue > 1)
			{
				minArmorReduction = (int32_t)std::ceil(armorValue * 0.475);
				maxArmorReduction = (int32_t)std::ceil(
					((armorValue * 0.475) - 1) + minArmorReduction);
			}
			else if(armorValue == 1)
			{
				minArmorReduction = 1;
				maxArmorReduction = 1;
			}

			damage -= random_range(minArmorReduction, maxArmorReduction);
			if(damage <= 0)
			{
				damage = 0;
				blockType = BLOCK_ARMOR;
			}
		}

		if(hasDefense && blockType != BLOCK_NONE)
			onBlockHit(blockType);
	}

	if(attacker)
	{
		attacker->onAttackedCreature(this);
		attacker->onAttackedCreatureBlockHit(this, blockType);
	}

	onAttacked();
	return blockType;
}

bool Creature::setAttackedCreature(Creature* creature)
{
	if(creature)
	{
		const Position& creaturePos = creature->getPosition();
		if(creaturePos.z != getPosition().z || !canSee(creaturePos))
		{
			attackedCreature = NULL;
			return false;
		}
	}

	attackedCreature = creature;
	if(attackedCreature)
	{
		onAttackedCreature(attackedCreature);
		attackedCreature->onAttacked();
	}

	for(std::list<Creature*>::iterator cit = summons.begin(); cit != summons.end(); ++cit)
		(*cit)->setAttackedCreature(creature);

	return true;
}

void Creature::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
{	
	fpp.fullPathSearch = !hasFollowPath;
	fpp.clearSight = false;
	fpp.maxSearchDist = 12;
	fpp.minTargetDist = fpp.maxTargetDist = 1;
}

void Creature::getPathToFollowCreature()
{
	if(followCreature)
	{
		FindPathParams fpp;
		getPathSearchParams(followCreature, fpp);
		
		if(g_game.getPathToEx(this, followCreature->getPosition(), listWalkDir, fpp))
		{
			hasFollowPath = true;
			startAutoWalk(listWalkDir);
		}
		else
			hasFollowPath = false;
	}

	onFollowCreatureComplete(followCreature);
}

bool Creature::setFollowCreature(Creature* creature, bool fullPathSearch /*= false*/)
{
	if(creature)
	{
		if(followCreature == creature)
			return true;

		const Position& creaturePos = creature->getPosition();
		if(creaturePos.z != getPosition().z || !canSee(creaturePos))
		{
			followCreature = NULL;
			return false;
		}

		if(!listWalkDir.empty())
		{
			listWalkDir.clear();
			onWalkAborted();
		}

		hasFollowPath = forceUpdateFollowPath = false;
		followCreature = creature;
		isUpdatingPath = true;
	}
	else
	{
		isUpdatingPath = false;
		followCreature = NULL;
	}

	onFollowCreature(creature);
	return true;
}

double Creature::getDamageRatio(Creature* attacker) const
{
	double totalDamage = 0, attackerDamage = 0;
	for(CountMap::const_iterator it = damageMap.begin(); it != damageMap.end(); ++it)
	{
		totalDamage += it->second.total;
		if(it->first == attacker->getID())
			attackerDamage += it->second.total;
	}

	return attackerDamage / totalDamage;
}

void Creature::addDamagePoints(Creature* attacker, int32_t damagePoints)
{
	uint32_t attackerId = 0;
	if(attacker)
		attackerId = attacker->getID();

	CountMap::iterator it = damageMap.find(attackerId);
	if(it != damageMap.end())
	{
		it->second.ticks = OTSYS_TIME();
		if(damagePoints > 0)
			it->second.total += damagePoints;
	}
	else
		damageMap[attackerId] = CountBlock_t(damagePoints);

	if(damagePoints > 0)
		lastHitCreature = attackerId;
}

void Creature::addHealPoints(Creature* caster, int32_t healthPoints)
{
	if(healthPoints <= 0)
		return;

	uint32_t casterId = 0;
	if(caster)
		casterId = caster->getID();

	CountMap::iterator it = healMap.find(casterId);
	if(it != healMap.end())
	{
		it->second.ticks = OTSYS_TIME();
		it->second.total += healthPoints;
	}
	else
		healMap[casterId] = CountBlock_t(healthPoints);
}

void Creature::onAddCondition(ConditionType_t type, bool hadCondition)
{
	if(type == CONDITION_INVISIBLE)
	{
		if(!hadCondition)
			g_game.internalCreatureChangeVisible(this, VISIBLE_DISAPPEAR);
	}
	else if(type == CONDITION_PARALYZE)
	{
		if(hasCondition(CONDITION_HASTE))
			removeCondition(CONDITION_HASTE);
	}
	else if(type == CONDITION_HASTE)
	{
		if(hasCondition(CONDITION_PARALYZE))
			removeCondition(CONDITION_PARALYZE);
	}
}

void Creature::onEndCondition(ConditionType_t type)
{
	if(type == CONDITION_INVISIBLE && !hasCondition(CONDITION_INVISIBLE, -1, false))
		g_game.internalCreatureChangeVisible(this, VISIBLE_APPEAR);
}

void Creature::onTickCondition(ConditionType_t type, int32_t interval, bool& _remove)
{
	if(const MagicField* field = getTile()->getFieldItem())
	{
		switch(type)
		{
			case CONDITION_FIRE:
				_remove = field->getCombatType() != COMBAT_FIREDAMAGE;
				break;
			case CONDITION_ENERGY:
				_remove = field->getCombatType() != COMBAT_ENERGYDAMAGE;
				break;
			case CONDITION_POISON:
				_remove = field->getCombatType() != COMBAT_EARTHDAMAGE;
				break;
			case CONDITION_DROWN:
				_remove = field->getCombatType() != COMBAT_DROWNDAMAGE;
				break;
			default:
				break;
		}
	}
}

void Creature::onCombatRemoveCondition(const Creature* attacker, Condition* condition)
{
	removeCondition(condition);
}

void Creature::onIdleStatus()
{
	if(getHealth() > 0)
	{
		healMap.clear();
		damageMap.clear();
	}
}

void Creature::onAttackedCreatureDrainHealth(Creature* target, int32_t points)
{
	onAttackedCreatureDrain(target, points);
}

void Creature::onAttackedCreatureDrainMana(Creature* target, int32_t points)
{
	onAttackedCreatureDrain(target, points);
}

void Creature::onAttackedCreatureDrain(Creature* target, int32_t points)
{
	target->addDamagePoints(this, points);
}

void Creature::onTargetCreatureGainHealth(Creature* target, int32_t points)
{
	target->addHealPoints(this, points);
}

void Creature::onAttackedCreatureKilled(Creature* target)
{
	if(target == this)
		return;

	double gainExp = target->getGainedExperience(this);
	onGainExperience(gainExp, !target->getPlayer(), false);
}

Creature* Creature::pushBackSummonOne(){ // aqui
     Creature* a = NULL;
if(!summons.empty())
		{
			std::list<Creature*>::iterator cit;
			std::list<Creature*> despawnList;
			for(cit = summons.begin(); cit != summons.end(); ++cit)
			{
			   a = (*cit);
			   break;
			}
		}
		return a;
}

bool Creature::onKilledCreature(Creature* target, uint32_t& flags)
{
	bool ret = true;
	if(master)
		ret = master->onKilledCreature(target, flags);

	CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_KILL);
	if(!hasBitSet((uint32_t)KILLFLAG_LASTHIT, flags))
	{
		for(CreatureEventList::iterator it = killEvents.begin(); it != killEvents.end(); ++it)
			(*it)->executeKill(this, target, false);

		return true;
	}

	for(CreatureEventList::iterator it = killEvents.begin(); it != killEvents.end(); ++it)
	{
		if(!(*it)->executeKill(this, target, true) && ret)
			ret = false;
	}

	return ret;
}

void Creature::onGainExperience(double& gainExp, bool fromMonster, bool multiplied)
{
	if(gainExp <= 0)
		return;

	if(master)
	{
		gainExp = gainExp / 2;
		master->onGainExperience(gainExp, fromMonster, multiplied);
	}
	else if(!multiplied)
		gainExp *= g_config.getDouble(ConfigManager::RATE_EXPERIENCE);

	int16_t color = g_config.getNumber(ConfigManager::EXPERIENCE_COLOR);
	if(color < 0)
		color = random_range(0, 255);

	std::stringstream ss;
	ss << (uint64_t)gainExp;
	g_game.addAnimatedText(getPosition(), (uint8_t)color, ss.str());
}

void Creature::onGainSharedExperience(double& gainExp, bool fromMonster, bool multiplied)
{
	if(gainExp <= 0)
		return;

	if(master)
	{
		gainExp = gainExp / 2;
		master->onGainSharedExperience(gainExp, fromMonster, multiplied);
	}
	else if(!multiplied)
		gainExp *= g_config.getDouble(ConfigManager::RATE_EXPERIENCE);

	int16_t color = g_config.getNumber(ConfigManager::EXPERIENCE_COLOR);
	if(color < 0)
		color = random_range(0, 255);

	std::stringstream ss;
	ss << (uint64_t)gainExp;
	g_game.addAnimatedText(getPosition(), (uint8_t)color, ss.str());
}

void Creature::addSummon(Creature* creature)
{
	creature->setDropLoot(LOOT_DROP_NONE);
	creature->setLossSkill(false);

	creature->setMaster(this);
	creature->addRef();
	summons.push_back(creature);
}

void Creature::removeSummon(const Creature* creature)
{
	std::list<Creature*>::iterator it = std::find(summons.begin(), summons.end(), creature);
	if(it == summons.end())
		return;

	(*it)->setMaster(NULL);
	(*it)->unRef();
	summons.erase(it);
}

void Creature::destroySummons()
{
	for(std::list<Creature*>::iterator it = summons.begin(); it != summons.end(); ++it)
	{
		(*it)->setAttackedCreature(NULL);
		(*it)->changeHealth(-(*it)->getHealth());

		(*it)->setMaster(NULL);
		(*it)->unRef();
	}

	summons.clear();
}

bool Creature::addCondition(Condition* condition)
{
	if(!condition)
		return false;

	bool hadCondition = hasCondition(condition->getType(), -1, false);
	if(Condition* previous = getCondition(condition->getType(), condition->getId(), condition->getSubId()))
	{
		previous->addCondition(this, condition);
		delete condition;
		return true;
	}

	if(condition->startCondition(this))
	{
		conditions.push_back(condition);
		onAddCondition(condition->getType(), hadCondition);
		return true;
	}

	delete condition;
	return false;
}

bool Creature::addCombatCondition(Condition* condition)
{
	bool hadCondition = hasCondition(condition->getType(), -1, false);
	//Caution: condition variable could be deleted after the call to addCondition
	ConditionType_t type = condition->getType();
	if(!addCondition(condition))
		return false;

	onAddCombatCondition(type, hadCondition);
	return true;
}

void Creature::removeCondition(ConditionType_t type)
{
	for(ConditionList::iterator it = conditions.begin(); it != conditions.end();)
	{
		if((*it)->getType() != type)
		{
			++it;
			continue;
		}

		Condition* condition = *it;
		it = conditions.erase(it);

		condition->endCondition(this, CONDITIONEND_ABORT);
		onEndCondition(condition->getType());
		delete condition;
	}
}

void Creature::removeCondition(ConditionType_t type, ConditionId_t id)
{
	for(ConditionList::iterator it = conditions.begin(); it != conditions.end();)
	{
		if((*it)->getType() != type || (*it)->getId() != id)
		{
			++it;
			continue;
		}

		Condition* condition = *it;
		it = conditions.erase(it);

		condition->endCondition(this, CONDITIONEND_ABORT);
		onEndCondition(condition->getType());
		delete condition;
	}
}

void Creature::removeCondition(Condition* condition)
{
	ConditionList::iterator it = std::find(conditions.begin(), conditions.end(), condition);
	if(it != conditions.end())
	{
		Condition* condition = *it;
		it = conditions.erase(it);

		condition->endCondition(this, CONDITIONEND_ABORT);
		onEndCondition(condition->getType());
		delete condition;
	}
}

void Creature::removeCondition(const Creature* attacker, ConditionType_t type)
{
	ConditionList tmpList = conditions;
	for(ConditionList::iterator it = tmpList.begin(); it != tmpList.end(); ++it)
	{
		if((*it)->getType() == type)
			onCombatRemoveCondition(attacker, *it);
	}
}

void Creature::removeConditions(ConditionEnd_t reason, bool onlyPersistent/* = true*/)
{
	for(ConditionList::iterator it = conditions.begin(); it != conditions.end();)
	{
		if(onlyPersistent && !(*it)->isPersistent())
		{
			++it;
			continue;
		}

		Condition* condition = *it;
		it = conditions.erase(it);

		condition->endCondition(this, reason);
		onEndCondition(condition->getType());
		delete condition;
	}
}

Condition* Creature::getCondition(ConditionType_t type, ConditionId_t id, uint32_t subId/* = 0*/) const
{
	for(ConditionList::const_iterator it = conditions.begin(); it != conditions.end(); ++it)
	{
		if((*it)->getType() == type && (*it)->getId() == id && (*it)->getSubId() == subId)
			return *it;
	}

	return NULL;
}

void Creature::executeConditions(uint32_t interval)
{
	for(ConditionList::iterator it = conditions.begin(); it != conditions.end();)
	{
		if((*it)->executeCondition(this, interval))
		{
			++it;
			continue;
		}

		Condition* condition = *it;
		it = conditions.erase(it);

		condition->endCondition(this, CONDITIONEND_TICKS);
		onEndCondition(condition->getType());
		delete condition;
	}
}

bool Creature::hasCondition(ConditionType_t type, int32_t subId/* = 0*/, bool checkTime/* = true*/) const
{
	if(isSuppress(type))
		return false;

	for(ConditionList::const_iterator it = conditions.begin(); it != conditions.end(); ++it)
	{
		if((*it)->getType() != type || (subId != -1 && (*it)->getSubId() != (uint32_t)subId))
			continue;

		if(!checkTime || g_config.getBool(ConfigManager::OLD_CONDITION_ACCURACY)
			|| !(*it)->getEndTime() || (*it)->getEndTime() >= OTSYS_TIME())
			return true;
	}

	return false;
}

bool Creature::isImmune(CombatType_t type) const
{
	return ((getDamageImmunities() & (uint32_t)type) == (uint32_t)type);
}

bool Creature::isImmune(ConditionType_t type) const
{
	return ((getConditionImmunities() & (uint32_t)type) == (uint32_t)type);
}

bool Creature::isSuppress(ConditionType_t type) const
{
	return ((getConditionSuppressions() & (uint32_t)type) == (uint32_t)type);
}

std::string Creature::getDescription(int32_t lookDistance) const
{
	return "a creature";
}

int32_t Creature::getStepDuration(Direction dir) const
{
	if(dir == NORTHWEST || dir == NORTHEAST || dir == SOUTHWEST || dir == SOUTHEAST)
		return getStepDuration() * 2;

	return getStepDuration();
}

int32_t Creature::getStepDuration() const
{
	if(removed)
		return 0;

	uint32_t stepSpeed = getStepSpeed();
	if(!stepSpeed)
		return 0;

	const Tile* tile = getTile();
	if(!tile || !tile->ground)
		return 0;

	return ((1000 * Item::items[tile->ground->getID()].speed) / stepSpeed) * lastStepCost;
}

int64_t Creature::getEventStepTicks() const
{
	int64_t ret = getWalkDelay();
	if(ret > 0)
		return ret;

	return getStepDuration();
}

void Creature::getCreatureLight(LightInfo& light) const
{
	light = internalLight;
}

void Creature::setNormalCreatureLight()
{
	internalLight.level = internalLight.color = 0;
}

bool Creature::registerCreatureEvent(const std::string& name)
{
	CreatureEvent* event = g_creatureEvents->getEventByName(name);
	if(!event) //check for existance
		return false;

	for(CreatureEventList::iterator it = eventsList.begin(); it != eventsList.end(); ++it)
	{
		if((*it) == event) //do not allow registration of same event more than once
			return false;
	}

	if(!hasEventRegistered(event->getEventType())) //there's no such type registered yet, so set the bit in the bitfield
		scriptEventsBitField |= ((uint32_t)1 << event->getEventType());

	eventsList.push_back(event);
	return true;
}

CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type)
{
	CreatureEventList retList;
	if(!hasEventRegistered(type))
		return retList;

	for(CreatureEventList::iterator it = eventsList.begin(); it != eventsList.end(); ++it)
	{
		if((*it)->getEventType() == type)
			retList.push_back(*it);
	}

	return retList;
}

FrozenPathingConditionCall::FrozenPathingConditionCall(const Position& _targetPos)
{
	targetPos = _targetPos;
}

bool FrozenPathingConditionCall::isInRange(const Position& startPos, const Position& testPos,
	const FindPathParams& fpp) const
{
	int32_t dxMin = ((fpp.fullPathSearch || (startPos.x - targetPos.x) <= 0) ? fpp.maxTargetDist : 0),
	dxMax = ((fpp.fullPathSearch || (startPos.x - targetPos.x) >= 0) ? fpp.maxTargetDist : 0),
	dyMin = ((fpp.fullPathSearch || (startPos.y - targetPos.y) <= 0) ? fpp.maxTargetDist : 0),
	dyMax = ((fpp.fullPathSearch || (startPos.y - targetPos.y) >= 0) ? fpp.maxTargetDist : 0);
	if(testPos.x > targetPos.x + dxMax || testPos.x < targetPos.x - dxMin)
		return false;

	if(testPos.y > targetPos.y + dyMax || testPos.y < targetPos.y - dyMin)
		return false;

	return true;
}

bool FrozenPathingConditionCall::operator()(const Position& startPos, const Position& testPos,
	const FindPathParams& fpp, int32_t& bestMatchDist) const
{
	if(!isInRange(startPos, testPos, fpp))
		return false;

	if(fpp.clearSight && !g_game.isSightClear(testPos, targetPos, true))
		return false;

	int32_t testDist = std::max(std::abs(targetPos.x - testPos.x), std::abs(targetPos.y - testPos.y));
	if(fpp.maxTargetDist == 1)
		return (testDist >= fpp.minTargetDist && testDist <= fpp.maxTargetDist);

	if(testDist <= fpp.maxTargetDist)
	{
		if(testDist < fpp.minTargetDist)
			return false;

		if(testDist == fpp.maxTargetDist)
		{
			bestMatchDist = 0;
			return true;
		}
		else if(testDist > bestMatchDist)
		{
			//not quite what we want, but the best so far
			bestMatchDist = testDist;
			return true;
		}
	}

	return false;
}

 

 

Link para o comentário
Compartilhar em outros sites

3 horas atrás, Josegvb disse:

teria como me ajudar? nas minhas sources nao achei o

 


if(m_showStaticSquare && animate) {

nem


g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));

 

teria como olhar no arquivo? creature.cpp

 

É na source do client

Link para o comentário
Compartilhar em outros sites

40 minutos atrás, ricardoberg disse:

ceetros, esse código tem alguma mudança daquela sua outra postagem ?

Na verdade, não.

Esse só tem a imagem a mais.

Link para o comentário
Compartilhar em outros sites

22 horas atrás, Walox disse:

Sera que inves dele usar uma imagem teria como por para puxar um Effects ? pois daria mais liberdade para fazer targets animados e talz tentei usar a função do APNG mas parece que não aceitou :/ 

Tem, só fazer.

E a parte do apng, a função que eu usei só funciona em imagem estática.

Link para o comentário
Compartilhar em outros sites

não achei essa linha no meu creature.cpp

g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));

se puder dar uma olhada:

Spoiler

/*
 * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "creature.h"
#include "thingtypemanager.h"
#include "localplayer.h"
#include "map.h"
#include "tile.h"
#include "item.h"
#include "game.h"
#include "effect.h"
#include "luavaluecasts.h"
#include "lightview.h"

#include <framework/stdext/format.h>
#include <framework/graphics/graphics.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/clock.h>

#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/ogl/painterogl2_shadersources.h>
#include <framework/graphics/texturemanager.h>
#include <framework/graphics/framebuffermanager.h>
#include <framework/graphics/image.h>
#include "spritemanager.h"
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>

Creature::Creature() : Thing()
{
    m_id = 0;
    m_healthPercent = 100;
    m_speed = 200;
    m_direction = Otc::South;
    m_walkAnimationPhase = 0;
    m_walkedPixels = 0;
    m_walkTurnDirection = Otc::InvalidDirection;
    m_skull = Otc::SkullNone;
    m_shield = Otc::ShieldNone;
    m_emblem = Otc::EmblemNone;
    m_icon = Otc::NpcIconNone;
    m_lastStepDirection = Otc::InvalidDirection;
    m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
    m_nameCache.setAlign(Fw::AlignTopCenter);
    m_footStep = 0;
    m_speedFormula.fill(-1);
    m_outfitColor = Color::white;
}

void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
{
    if(!canBeSeen())
        return;

    Point animationOffset = animate ? m_walkOffset : Point(0,0);

    if(m_showTimedSquare && animate) {
        EffectPtr effect = EffectPtr(new Effect());
        effect->setId(819);
        g_painter->setColor(m_timedSquareColor);
        Rect rect = Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor);
        g_painter->drawTexturedRect(rect, effect->getThingType()->getTextureEX(0));
        g_painter->setColor(Color::white); g_painter->setColor(Color::white);
    }

    if(m_showStaticSquare && animate) {
       EffectPtr effect = EffectPtr(new Effect());

        effect->setId(819);
        g_painter->setColor(m_staticSquareColor);
        Rect rect = Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor);
        g_painter->drawTexturedRect(rect, effect->getThingType()->getTextureEX(0));
        g_painter->setColor(Color::white);
    }
    
    internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
    m_footStepDrawn = true;

    if(lightView) {
        Light light = rawGetThingType()->getLight();
        if(m_light.intensity != light.intensity || m_light.color != light.color)
            light = m_light;

        // local player always have a minimum light in complete darkness
        if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
            light.intensity = std::max<uint8>(light.intensity, 3);
            if(light.color == 0 || light.color > 215)
                light.color = 215;
        }

        if(light.intensity > 0)
            lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
    }
}
int countTest = 0;
void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
{
    g_painter->setColor(m_outfitColor);

    // outfit is a real creature
    if(m_outfit.getCategory() == ThingCategoryCreature) {
        int animationPhase = animateWalk ? m_walkAnimationPhase : 0;

        if(isAnimateAlways() && animateIdle) {
            int ticksPerFrame = 1000 / getAnimationPhases();
            animationPhase = (g_clock.millis() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
        }

        // xPattern => creature direction
        int xPattern;
        if(direction == Otc::NorthEast || direction == Otc::SouthEast)
            xPattern = Otc::East;
        else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
            xPattern = Otc::West;
        else
            xPattern = direction;

        int zPattern = 0;

        PointF jumpOffset = m_jumpOffset * scaleFactor;
        dest -= Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));

        // yPattern => creature addon
        for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {

            // continue if we dont have this addon

            if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
                continue;

            
            auto datType = getThingType();
             if(m_skull >= 1){
                float initEffe = 0.4f, endEffe = 0.6f;
                int exactSize = getExactSize();
                double scaleMult = 1.12, axsX = 0.97, axsY = 1.2; // ate 42 de exactSize
                Color azul = Color(0.0f, 128.0, 255.0, 1.0f), verde = Color(51, 255, 51), laranja = Color(255, 102, 0), azulCya = Color(51, 204, 255),
                      white = Color::white, viliota = Color(102, 0, 255), roxa = Color(153, 0, 204), redScarlat = Color(230, 0, 0), amarelo = Color(255, 255, 0),
                      preto = Color::black, rosa = Color(255, 51, 153), jeaneSoisQuoi = Color(0, 102, 102), cou = Color(204, 51, 0);
                Color auraColor = azul;// azul


                //Color config 1 = black, 2 = blue, 3 = green, 4 = pink, 5 = orange
                  if(m_skull == 2)
                      auraColor = verde; 
                  else if(m_skull == 3)
                      auraColor = laranja; 
                  else if (m_skull == 4) 
                      auraColor = azulCya; 
                  else if (m_skull == 5)
                      auraColor = white;
                  else if (m_skull == 6)
                      auraColor = viliota;
                  else if (m_skull == 7)
                      auraColor = roxa;
                  else if (m_skull == ?
                      auraColor = redScarlat;
                  else if (m_skull == 9)
                      auraColor = amarelo;
                  else if (m_skull == 10) {
                      initEffe = 0.7f; endEffe = 0.9f;
                      auraColor = preto;
                  }
                  else if (m_skull == 11) {
                      auraColor = rosa;
                      initEffe = 0.3f; endEffe = 0.7f;
                  }
                  else if (m_skull == 12)
                      auraColor = jeaneSoisQuoi;
                  else if (m_skull == 13)
                      auraColor = cou;

                    if(exactSize == 52) { // tamanho das sprites
                       axsY = 0.92;
                    }else if(exactSize == 32) { // tamanho das sprites
                       scaleMult = 1.16;
                       axsX = 0.94; axsY = 0.92;
                    }
                
                
                Point p = Point(dest.x-axsX, dest.y-axsY);
                //Rect rect = Rect(p.x, p.y, datType->getTexture(animationPhase)->getSize());
                countTest++;

                //colored raibow aura
                if (m_skull == 14) {
                    if (countTest <= 40)
                        auraColor = white;
                    else if (countTest >= 41 && countTest <= 80)
                        auraColor = redScarlat;
                    else if (countTest >= 81 && countTest <= 120)
                        auraColor = verde;
                    else if (countTest >= 121 && countTest <= 160)
                        auraColor = laranja;
                    else if (countTest >= 161 && countTest <= 200)
                        auraColor = azul;
                    else if (countTest >= 201 && countTest <= 240)
                        auraColor = amarelo;
                    else if (countTest >= 241)
                        countTest = 0;
                }else {
                        if (countTest <= 60) {
                            g_painter->setOpacity(initEffe);
                        }
                        else if (countTest >= 61 && countTest <= 110) {
                            g_painter->setOpacity(endEffe);
                        }
                        else if (countTest >= 111)
                            countTest = 0;
                    }

                g_painter->setColor(auraColor);
                datType->drawEX(p, scaleFactor*scaleMult, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);
                //g_painter->drawTexturedRect(rect, datType->getTexture(animationPhase, true));
                g_painter->setOpacity(1.0f);
             }
             
             // if(m_skull >= 1 && m_skullTexture){
                // g_painter->setOpacity(0.7f);
               //}
            g_painter->setColor(m_outfitColor);
            datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);

            if(getLayers() > 1) {
                Color oldColor = g_painter->getColor();
                Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
                g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
                g_painter->setColor(m_outfit.getHeadColor());
                datType->draw(dest, scaleFactor, SpriteMaskYellow, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(m_outfit.getBodyColor());
                datType->draw(dest, scaleFactor, SpriteMaskRed, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(m_outfit.getLegsColor());
                datType->draw(dest, scaleFactor, SpriteMaskGreen, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(m_outfit.getFeetColor());
                datType->draw(dest, scaleFactor, SpriteMaskBlue, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(oldColor);
                g_painter->setCompositionMode(oldComposition);
            }
        }
    // outfit is a creature imitating an item or the invisible effect
    } else  {
        ThingType *type = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory());

        int animationPhase = 0;
        int animationPhases = type->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() == ThingCategoryEffect) {
            animationPhases = std::max<int>(1, animationPhases-2);
            animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
        }

        if(animationPhases > 1) {
            if(animateIdle)
                animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
            else
                animationPhase = animationPhases-1;
        }

        if(m_outfit.getCategory() == ThingCategoryEffect)
            animationPhase = std::min<int>(animationPhase+1, animationPhases);

        type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
    }

    g_painter->resetColor();
    g_painter->setOpacity(1.0f);
}

void Creature::drawOutfit(const Rect& destRect, bool resize)
{
    int exactSize;
    if(m_outfit.getCategory() == ThingCategoryCreature)
        exactSize = getExactSize();
    else
        exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize();

    int frameSize;
    if(!resize)
        frameSize = std::max<int>(exactSize * 0.75f, 2 * Otc::TILE_PIXELS * 0.75f);
    else if(!(frameSize = exactSize))
        return;

    if(g_graphics.canUseFBO()) {
        const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
        outfitBuffer->resize(Size(frameSize, frameSize));
        outfitBuffer->bind();
        g_painter->setAlphaWriting(true);
        g_painter->clear(Color::alpha);
        internalDrawOutfit(Point(frameSize - Otc::TILE_PIXELS, frameSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
        outfitBuffer->release();
        outfitBuffer->draw(destRect, Rect(0,0,frameSize,frameSize));
    } else {
        float scaleFactor = destRect.width() / (float)frameSize;
        Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor;
        internalDrawOutfit(dest, scaleFactor, false, true, Otc::South);
    }
}

void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect, int drawFlags)
{
    if(m_healthPercent < 1 || m_outfit.getId() == 84) // creature is dead
        return;

    Color fillColor = Color(96, 96, 96);

    if(!useGray)
        fillColor = m_informationColor;

    int exactSize = getExactSize();
    int d = 0, dx = 0;
    
    if(exactSize <= 34)
        d = 5;
    else if(exactSize >= 35 && exactSize <= 48)
        d = 15;
    else if(exactSize >= 49 && exactSize <= 52)
        d = 25;
    else if(exactSize >= 53 && exactSize <= 57)
        d = 30;
    else if(exactSize >= 58 && exactSize <= 69)
        d = 25;
    else if(exactSize == 74)
        d = 37;
    
        dx = d /2;
        if(exactSize <= 34)
            dx = 17;

    // calculate main rects
    Rect backgroundRect = Rect(point.x - dx, point.y - d, 40, 6);
    backgroundRect.bind(parentRect);

    Size nameSize = m_nameCache.getTextSize();
    Rect textRect = Rect(point.x - nameSize.width() / 2, point.y-14, nameSize);
    textRect.bind(parentRect);

    // distance them
    if(textRect.top() == parentRect.top())
        backgroundRect.moveTop(textRect.top() + 12);
    if(backgroundRect.bottom() == parentRect.bottom())
        textRect.moveTop(backgroundRect.top() - 12);

    // health rect is based on background rect, so no worries
    Rect healthRect = backgroundRect.expanded(-1);
    //healthRect.setWidth();
    int calc = ((m_healthPercent / 100.0) * 40.0) + 60;
    std::string nameBar = std::to_string(calc);
    if (calc == 100)
        nameBar = "full";

    // draw
    if(g_game.getFeature(Otc::GameBlueNpcNameColor) && isNpc() && m_healthPercent == 100 && !useGray)
        fillColor = Color(0x66, 0xcc, 0xff);

    if(drawFlags & Otc::DrawBars && (!isNpc() || !g_game.getFeature(Otc::GameHideNpcNames))) {

            g_painter->setColor(Color::white);
            ImagePtr backgroundLifeBar = Image::load("data/images/game/lifebar/background");
            TexturePtr bgLifeBar = TexturePtr(new Texture(backgroundLifeBar, false));
            //g_painter->drawFilledRect(backgroundRect);
            g_painter->drawTexturedRect(backgroundRect, bgLifeBar);

            ImagePtr healthLifeBar = Image::load("data/images/game/lifebar/" + nameBar);
            TexturePtr lifeBar = TexturePtr(new Texture(healthLifeBar, false));
            g_painter->drawTexturedRect(healthRect, lifeBar);
            //g_painter->drawFilledRect(healthRect);
    }

    if(drawFlags & Otc::DrawNames) {
        g_painter->setColor(Color(213, 213, 0));
        
        //m_nameCache.setText(std::to_string(m_outfit.getId()));
         //m_nameCache.set
          m_nameCache.draw(textRect);
    }

    if (m_skull >= 50 && m_skull <= 56) {
        // 0 = on | 1 = use | 2 = off
        //     50     |     49      |     48 
        //0 0 0 0 0 0 | 0 0 0 0 0 1 | 0 0 0 0 1 2
        //
        g_painter->setColor(Color::white);
        ImagePtr imgBallON = Image::load("data/images/game/duel/pokeball_on");
        ImagePtr imgBallOFF = Image::load("data/images/game/duel/pokeball_off");
        ImagePtr imgBallUSE = Image::load("data/images/game/duel/pokeball_use");
        int duel_mode = m_skull - 50, ball_counts = m_emblem - 50;
        TexturePtr ballTexture1 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture2 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture3 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture4 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture5 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture6 = TexturePtr(new Texture(imgBallON, false));
        if (duel_mode == 1) {
            int countPos = 23 - (10 * 3);

            if (ball_counts == 1)
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));

            ballTexture1->setSmooth(true);
            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
        }
        else if (duel_mode == 2) {

            int countPos = 8 - 10;
            int countPos2 = 8 - 20;

            if (ball_counts == 4) {
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);

        }
        else if (duel_mode == 3) {

            int countPos = 13 - 10;
            int countPos2 = 13 - 20;
            int countPos3 = 13 - 30;

            if (ball_counts == 6) {
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);

        }
        else if (duel_mode == 4) {

            int countPos = 15 - 10;
            int countPos2 = 15 - 20;
            int countPos3 = 15 - 30;
            int countPos4 = 15 - 40;

            if (ball_counts == ? {
                ballTexture4 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 7) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 6) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect4 = Rect(backgroundRect.x() - countPos4, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);
            g_painter->drawTexturedRect(skullRect4, ballTexture4);

        }
        else if (duel_mode == 5) {

            int countPos = 18 - 10;
            int countPos2 = 18 - 20;
            int countPos3 = 18 - 30;
            int countPos4 = 18 - 40;
            int countPos5 = 18 - 50;

            if (ball_counts == 10) {
                ballTexture5 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 9) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == ? {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 7) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 6) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect4 = Rect(backgroundRect.x() - countPos4, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect5 = Rect(backgroundRect.x() - countPos5, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);
            g_painter->drawTexturedRect(skullRect4, ballTexture4);
            g_painter->drawTexturedRect(skullRect5, ballTexture5);

        }
        else if (duel_mode == 6) {

            int countPos = 21 - 10;
            int countPos2 = 21 - 20;
            int countPos3 = 21 - 30;
            int countPos4 = 21 - 40;
            int countPos5 = 21 - 50;
            int countPos6 = 21 - 60;

            if (ball_counts == 12) {
                ballTexture6 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 11) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 10) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 9) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == ? {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 7) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 6) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect4 = Rect(backgroundRect.x() - countPos4, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect5 = Rect(backgroundRect.x() - countPos5, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect6 = Rect(backgroundRect.x() - countPos6, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);
            g_painter->drawTexturedRect(skullRect4, ballTexture4);
            g_painter->drawTexturedRect(skullRect5, ballTexture5);
            g_painter->drawTexturedRect(skullRect6, ballTexture6);

        }
        /*for (int i = 0; i < duel_mode; i++) {
            int count = 23 - (10 * i);
            TexturePtr ballTexture = TexturePtr(new Texture(imgBall, false));

            if(i == 4)
                ballTexture = TexturePtr(new Texture(imgBallUSE, false));
            else if(i == 5)
                ballTexture = TexturePtr(new Texture(imgBallOFF, false));
            Rect skullRect = Rect(backgroundRect.x() - count, backgroundRect.y() - 25, ballTexture->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture);
        }
            */

        g_painter->setOpacity(1.0f);
    }
    if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
        g_painter->setColor(Color::white);
        Rect shieldRect = Rect(backgroundRect.x() + 13.5, backgroundRect.y() + 5, m_shieldTexture->getSize());
        g_painter->drawTexturedRect(shieldRect, m_shieldTexture);
    }
    if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
        g_painter->setColor(Color::white);
        Rect emblemRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 16, m_emblemTexture->getSize());
        g_painter->drawTexturedRect(emblemRect, m_emblemTexture);
    }
    if(m_icon != Otc::NpcIconNone && m_iconTexture) {
        g_painter->setColor(Color::white);
        Rect iconRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_iconTexture->getSize());
        g_painter->drawTexturedRect(iconRect, m_iconTexture);
    }
}

void Creature::turn(Otc::Direction direction)
{
    // if is not walking change the direction right away
    if(!m_walking)
        setDirection(direction);
    // schedules to set the new direction when walk ends
    else
        m_walkTurnDirection = direction;
}

void Creature::walk(const Position& oldPos, const Position& newPos)
{
    if(oldPos == newPos)
        return;

    // get walk direction
    m_lastStepDirection = oldPos.getDirectionFromPosition(newPos);
    m_lastStepFromPosition = oldPos;
    m_lastStepToPosition = newPos;

    // set current walking direction
    setDirection(m_lastStepDirection);

    // starts counting walk
    m_walking = true;
    m_walkTimer.restart();
    m_walkedPixels = 0;

    if(m_walkFinishAnimEvent) {
        m_walkFinishAnimEvent->cancel();
        m_walkFinishAnimEvent = nullptr;
    }

    // no direction need to be changed when the walk ends
    m_walkTurnDirection = Otc::InvalidDirection;

    // starts updating walk
    nextWalkUpdate();
}

void Creature::stopWalk()
{
    if(!m_walking)
        return;

    // stops the walk right away
    terminateWalk();
}

void Creature::jump(int height, int duration)
{
    if(!m_jumpOffset.isNull())
        return;

    m_jumpTimer.restart();
    m_jumpHeight = height;
    m_jumpDuration = duration;

    updateJump();
}

void Creature::updateJump()
{
    int t = m_jumpTimer.ticksElapsed();
    double a = -4 * m_jumpHeight / (m_jumpDuration * m_jumpDuration);
    double b = +4 * m_jumpHeight / (m_jumpDuration);

    double height = a*t*t + b*t;
    int roundHeight = stdext::round(height);
    int halfJumpDuration = m_jumpDuration / 2;

    // schedules next update
    if(m_jumpTimer.ticksElapsed() < m_jumpDuration) {
        m_jumpOffset = PointF(height, height);

        int diff = 0;
        if(m_jumpTimer.ticksElapsed() < halfJumpDuration)
            diff = 1;
        else if(m_jumpTimer.ticksElapsed() > halfJumpDuration)
            diff = -1;

        int nextT, i = 1;
        do {
            nextT = stdext::round((-b + std::sqrt(std::max<int>(b*b + 4*a*(roundHeight+diff*i), 0.0)) * diff) / (2*a));
            ++i;

            if(nextT < halfJumpDuration)
                diff = 1;
            else if(nextT > halfJumpDuration)
                diff = -1;
        } while(nextT - m_jumpTimer.ticksElapsed() == 0 && i < 3);

        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self] {
            self->updateJump();
        }, nextT - m_jumpTimer.ticksElapsed());
    }
    else
        m_jumpOffset = PointF(0, 0);
}

void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
{
    callLuaField("onPositionChange", newPos, oldPos);
}

void Creature::onAppear()
{
    // cancel any disappear event
    if(m_disappearEvent) {
        m_disappearEvent->cancel();
        m_disappearEvent = nullptr;
    }

    // creature appeared the first time or wasn't seen for a long time
    if(m_removed) {
        stopWalk();
        m_removed = false;
        callLuaField("onAppear");
    // walk
    } else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1) && m_allowAppearWalk) {
        m_allowAppearWalk = false;
        walk(m_oldPosition, m_position);
        callLuaField("onWalk", m_oldPosition, m_position);
    // teleport
    } else if(m_oldPosition != m_position) {
        stopWalk();
        callLuaField("onDisappear");
        callLuaField("onAppear");
    } // else turn
}

void Creature::onDisappear()
{
    if(m_disappearEvent)
        m_disappearEvent->cancel();

    m_oldPosition = m_position;

    // a pair onDisappear and onAppear events are fired even when creatures walks or turns,
    // so we must filter
    auto self = static_self_cast<Creature>();
    m_disappearEvent = g_dispatcher.addEvent([self] {
        self->m_removed = true;
        self->stopWalk();

        self->callLuaField("onDisappear");

        // invalidate this creature position
        if(!self->isLocalPlayer())
            self->setPosition(Position());
        self->m_oldPosition = Position();
        self->m_disappearEvent = nullptr;
    });
}

void Creature::onDeath()
{
    callLuaField("onDeath");
}

void Creature::updateWalkAnimation(int totalPixelsWalked)
{
    // update outfit animation
    if(m_outfit.getCategory() != ThingCategoryCreature)
        return;

    int footAnimPhases = getAnimationPhases() - 1;
    int footDelay = getStepDuration(true) / 3;
    // Since mount is a different outfit we need to get the mount animation phases
    if(m_outfit.getMount() != 0) {
        ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
        footAnimPhases = type->getAnimationPhases() - 1;
    }
    if(footAnimPhases == 0)
        m_walkAnimationPhase = 0;
    else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
        m_footStep++;
        m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
        m_footStepDrawn = false;
        m_footTimer.restart();
    } else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
        m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
    }

    if(totalPixelsWalked == 32 && !m_walkFinishAnimEvent) {
        auto self = static_self_cast<Creature>();
        m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
            if(!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true))
                self->m_walkAnimationPhase = 0;
            self->m_walkFinishAnimEvent = nullptr;
        }, std::min<int>(footDelay, 200));
    }

}

void Creature::updateWalkOffset(int totalPixelsWalked)
{
    m_walkOffset = Point(0,0);
    if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
        m_walkOffset.y = 32 - totalPixelsWalked;
    else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
        m_walkOffset.y = totalPixelsWalked - 32;

    if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
        m_walkOffset.x = totalPixelsWalked - 32;
    else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
        m_walkOffset.x = 32 - totalPixelsWalked;
}

void Creature::updateWalkingTile()
{
    // determine new walking tile
    TilePtr newWalkingTile;
    Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
                             Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
                             Otc::TILE_PIXELS, Otc::TILE_PIXELS);
    for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
        for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
            Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);

            // only render creatures where bottom right is inside tile rect
            if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
                newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
            }
        }
    }

    if(newWalkingTile != m_walkingTile) {
        if(m_walkingTile)
            m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
        if(newWalkingTile) {
            newWalkingTile->addWalkingCreature(static_self_cast<Creature>());

            // recache visible tiles in map views
            if(newWalkingTile->isEmpty())
                g_map.notificateTileUpdate(newWalkingTile->getPosition());
        }
        m_walkingTile = newWalkingTile;
    }
}

void Creature::nextWalkUpdate()
{
    // remove any previous scheduled walk updates
    if(m_walkUpdateEvent)
        m_walkUpdateEvent->cancel();

    // do the update
    updateWalk();

    // schedules next update
    if(m_walking) {
        auto self = static_self_cast<Creature>();
        m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
            self->m_walkUpdateEvent = nullptr;
            self->nextWalkUpdate();
        }, getStepDuration() / 32);
    }
}

void Creature::updateWalk()
{
    float walkTicksPerPixel = getStepDuration(true) / 32;
    int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);

    // needed for paralyze effect
    m_walkedPixels = std::max<int>(m_walkedPixels, totalPixelsWalked);

    // update walk animation and offsets
    updateWalkAnimation(totalPixelsWalked);
    updateWalkOffset(m_walkedPixels);
    updateWalkingTile();

    // terminate walk
    if(m_walking && m_walkTimer.ticksElapsed() >= getStepDuration())
        terminateWalk();
}

void Creature::terminateWalk()
{
    // remove any scheduled walk update
    if(m_walkUpdateEvent) {
        m_walkUpdateEvent->cancel();
        m_walkUpdateEvent = nullptr;
    }

    // now the walk has ended, do any scheduled turn
    if(m_walkTurnDirection != Otc::InvalidDirection)  {
        setDirection(m_walkTurnDirection);
        m_walkTurnDirection = Otc::InvalidDirection;
    }

    if(m_walkingTile) {
        m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
        m_walkingTile = nullptr;
    }

    m_walking = false;
    m_walkedPixels = 0;

    // reset walk animation states
    m_walkOffset = Point(0,0);
    m_walkAnimationPhase = 0;
}

void Creature::setName(const std::string& name)
{
    m_nameCache.setText(name);
    m_name = name;
}

void Creature::setHealthPercent(uint8 healthPercent)
{
    if(healthPercent > 92)
        m_informationColor = Color(0x00, 0xBC, 0x00);
    else if(healthPercent > 60)
        m_informationColor = Color(0x50, 0xA1, 0x50);
    else if(healthPercent > 30)
        m_informationColor = Color(0xA1, 0xA1, 0x00);
    else if(healthPercent > ?
        m_informationColor = Color(0xBF, 0x0A, 0x0A);
    else if(healthPercent > 3)
        m_informationColor = Color(0x91, 0x0F, 0x0F);
    else
        m_informationColor = Color(0x85, 0x0C, 0x0C);

    m_healthPercent = healthPercent;
    callLuaField("onHealthPercentChange", healthPercent);

    if(healthPercent <= 0)
        onDeath();
}

void Creature::setDirection(Otc::Direction direction)
{
    assert(direction != Otc::InvalidDirection);
    m_direction = direction;
}

void Creature::setOutfit(const Outfit& outfit)
{
    Outfit oldOutfit = m_outfit;
    if(outfit.getCategory() != ThingCategoryCreature) {
        if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
            return;
        m_outfit.setAuxId(outfit.getAuxId());
        m_outfit.setCategory(outfit.getCategory());
        m_outfit2.setAuxId(outfit.getAuxId());
        m_outfit2.setCategory(outfit.getCategory());
    } else {
        if(outfit.getId() > 0 && !g_things.isValidDatId(outfit.getId(), ThingCategoryCreature))
            return;
        m_outfit = outfit;
        m_outfit2 = outfit;
    }
    m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
    callLuaField("onOutfitChange", m_outfit, oldOutfit);
}

void Creature::setOutfitColor(const Color& color, int duration)
{
    if(m_outfitColorUpdateEvent) {
        m_outfitColorUpdateEvent->cancel();
        m_outfitColorUpdateEvent = nullptr;
    }

    if(duration > 0) {
        Color delta = (color - m_outfitColor) / (float)duration;
        m_outfitColorTimer.restart();
        updateOutfitColor(m_outfitColor, color, delta, duration);
    }
    else
        m_outfitColor = color;
}

void Creature::updateOutfitColor(Color color, Color finalColor, Color delta, int duration)
{
    if(m_outfitColorTimer.ticksElapsed() < duration) {
        m_outfitColor = color + delta * m_outfitColorTimer.ticksElapsed();

        auto self = static_self_cast<Creature>();
        m_outfitColorUpdateEvent = g_dispatcher.scheduleEvent([=] {
            self->updateOutfitColor(color, finalColor, delta, duration);
        }, 100);
    }
    else {
        m_outfitColor = finalColor;
    }
}

void Creature::setSpeed(uint16 speed)
{
    uint16 oldSpeed = m_speed;
    m_speed = speed;

    // speed can change while walking (utani hur, paralyze, etc..)
    if(m_walking)
        nextWalkUpdate();

    callLuaField("onSpeedChange", m_speed, oldSpeed);
}

void Creature::setBaseSpeed(double baseSpeed)
{
    if(m_baseSpeed != baseSpeed) {
        double oldBaseSpeed = m_baseSpeed;
        m_baseSpeed = baseSpeed;

        callLuaField("onBaseSpeedChange", baseSpeed, oldBaseSpeed);
    }
}

void Creature::setSkull(uint8 skull)
{
    m_skull = skull;
    callLuaField("onSkullChange", m_skull);
}

void Creature::setShield(uint8 shield)
{
    m_shield = shield;
    callLuaField("onShieldChange", m_shield);
}

void Creature::setEmblem(uint8 emblem)
{
    m_emblem = emblem;
    callLuaField("onEmblemChange", m_emblem);
}

void Creature::setIcon(uint8 icon)
{
    m_icon = icon;
    callLuaField("onIconChange", m_icon);
}

void Creature::setSkullTexture(const std::string& filename)
{
    m_skullTexture = g_textures.getTexture(filename);
}

void Creature::setShieldTexture(const std::string& filename, bool blink)
{
    m_shieldTexture = g_textures.getTexture(filename);
    m_showShieldTexture = true;

    if(blink && !m_shieldBlink) {
        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self]() {
            self->updateShield();
        }, SHIELD_BLINK_TICKS);
    }

    m_shieldBlink = blink;
}

void Creature::setEmblemTexture(const std::string& filename)
{
    m_emblemTexture = g_textures.getTexture(filename);
}

void Creature::setIconTexture(const std::string& filename)
{
    m_iconTexture = g_textures.getTexture(filename);
}


void Creature::setSpeedFormula(double speedA, double speedB, double speedC)
{
    m_speedFormula[Otc::SpeedFormulaA] = speedA;
    m_speedFormula[Otc::SpeedFormulaB] = speedB;
    m_speedFormula[Otc::SpeedFormulaC] = speedC;
}

bool Creature::hasSpeedFormula()
{
    return m_speedFormula[Otc::SpeedFormulaA] != -1 && m_speedFormula[Otc::SpeedFormulaB] != -1
            && m_speedFormula[Otc::SpeedFormulaC] != -1;
}

void Creature::addTimedSquare(uint8 color)
{
    m_showTimedSquare = true;
    m_timedSquareColor = Color::from8bit(color);

    // schedule removal
    auto self = static_self_cast<Creature>();
    g_dispatcher.scheduleEvent([self]() {
        self->removeTimedSquare();
    }, VOLATILE_SQUARE_DURATION);
}

void Creature::updateShield()
{
    m_showShieldTexture = !m_showShieldTexture;

    if(m_shield != Otc::ShieldNone && m_shieldBlink) {
        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self]() {
            self->updateShield();
        }, SHIELD_BLINK_TICKS);
    }
    else if(!m_shieldBlink)
        m_showShieldTexture = true;
}

Point Creature::getDrawOffset()
{
    Point drawOffset;
    if(m_walking) {
        if(m_walkingTile)
            drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
        drawOffset += m_walkOffset;
    } else {
        const TilePtr& tile = getTile();
        if(tile)
            drawOffset -= Point(1,1) * tile->getDrawElevation();
    }
    return drawOffset;
}

int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
{
    int speed = m_speed;
    if(speed < 1)
        return 0;

    if(g_game.getFeature(Otc::GameNewSpeedLaw))
        speed *= 2;

    int groundSpeed = 0;
    Position tilePos;

    if(dir == Otc::InvalidDirection)
        tilePos = m_lastStepToPosition;
    else
        tilePos = m_position.translatedToDirection(dir);

    if(!tilePos.isValid())
        tilePos = m_position;
    const TilePtr& tile = g_map.getTile(tilePos);
    if(tile) {
        groundSpeed = tile->getGroundSpeed();
        if(groundSpeed == 0)
            groundSpeed = 150;
    }

    int interval = 1000;
    if(groundSpeed > 0 && speed > 0)
        interval = 1000 * groundSpeed;

    if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
        int formulatedSpeed = 1;
        if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
            formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
                 + m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
        }
        interval = std::floor(interval / (double)formulatedSpeed);
    }
    else
        interval /= speed;

    if(g_game.getClientVersion() >= 900)
        interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();

    float factor = 3;
    if(g_game.getClientVersion() <= 810)
        factor = 2;

    interval = std::max<int>(interval, g_game.getServerBeat());

    if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
       m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
        interval *= factor;

    return interval;
}

Point Creature::getDisplacement()
{
    if(m_outfit.getCategory() == ThingCategoryEffect)
        return Point(8, 8);
    else if(m_outfit.getCategory() == ThingCategoryItem)
        return Point(0, 0);
    return Thing::getDisplacement();
}

int Creature::getDisplacementX()
{
    if(m_outfit.getCategory() == ThingCategoryEffect)
        return 8;
    else if(m_outfit.getCategory() == ThingCategoryItem)
        return 0;

    if(m_outfit.getMount() != 0) {
        auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
        return datType->getDisplacementX();
    }

    return Thing::getDisplacementX();
}

int Creature::getDisplacementY()
{
    if(m_outfit.getCategory() == ThingCategoryEffect)
        return 8;
    else if(m_outfit.getCategory() == ThingCategoryItem)
        return 0;

    if(m_outfit.getMount() != 0) {
        auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
        return datType->getDisplacementY();
    }

    return Thing::getDisplacementY();
}

int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
{
    int exactSize = 0;

    animationPhase = 0;
    xPattern = Otc::South;

    zPattern = 0;
    if(m_outfit.getMount() != 0)
        zPattern = 1;

    for(yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
        if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
            continue;

        for(layer = 0; layer < getLayers(); ++layer)
            exactSize = std::max<int>(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
    }

    return exactSize;
}

const ThingTypePtr& Creature::getThingType()
{
    return g_things.getThingType(m_outfit.getId(), ThingCategoryCreature);
}

const ThingTypePtr& Creature::getThingType2()
{
    return g_things.getThingType2(m_outfit.getId(), ThingCategoryCreature);
}

ThingType* Creature::rawGetThingType()
{
    if (!iniciou) {
        novaOutType = g_things.getThingTypeInSecondList(m_outfit2.getId(), ThingCategoryCreature);
        iniciou = true;
    }
    return g_things.rawGetThingType(m_outfit.getId(), ThingCategoryCreature);
}

ThingType* Creature::rawGetThingType2()
{
    if (!iniciou) {
        novaOutType = g_things.getThingTypeInSecondList(m_outfit2.getId(), ThingCategoryCreature);
        iniciou = true;
    }
    return novaOutType;
}
 

 

Link para o comentário
Compartilhar em outros sites

  • 2 weeks later...
Em 13/07/2018 em 16:09, OrionX disse:

Desculpe reviver o post, mas não estou achando os seguintes comandos na source, poderia me ajudar?

 

quais ?

Em 11/07/2018 em 11:05, boxxer321 disse:

não achei essa linha no meu creature.cpp


g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));

se puder dar uma olhada:

  Mostrar conteúdo oculto

/*
 * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "creature.h"
#include "thingtypemanager.h"
#include "localplayer.h"
#include "map.h"
#include "tile.h"
#include "item.h"
#include "game.h"
#include "effect.h"
#include "luavaluecasts.h"
#include "lightview.h"

#include <framework/stdext/format.h>
#include <framework/graphics/graphics.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/clock.h>

#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/ogl/painterogl2_shadersources.h>
#include <framework/graphics/texturemanager.h>
#include <framework/graphics/framebuffermanager.h>
#include <framework/graphics/image.h>
#include "spritemanager.h"
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>

Creature::Creature() : Thing()
{
    m_id = 0;
    m_healthPercent = 100;
    m_speed = 200;
    m_direction = Otc::South;
    m_walkAnimationPhase = 0;
    m_walkedPixels = 0;
    m_walkTurnDirection = Otc::InvalidDirection;
    m_skull = Otc::SkullNone;
    m_shield = Otc::ShieldNone;
    m_emblem = Otc::EmblemNone;
    m_icon = Otc::NpcIconNone;
    m_lastStepDirection = Otc::InvalidDirection;
    m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
    m_nameCache.setAlign(Fw::AlignTopCenter);
    m_footStep = 0;
    m_speedFormula.fill(-1);
    m_outfitColor = Color::white;
}

void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
{
    if(!canBeSeen())
        return;

    Point animationOffset = animate ? m_walkOffset : Point(0,0);

    if(m_showTimedSquare && animate) {
        EffectPtr effect = EffectPtr(new Effect());
        effect->setId(819);
        g_painter->setColor(m_timedSquareColor);
        Rect rect = Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor);
        g_painter->drawTexturedRect(rect, effect->getThingType()->getTextureEX(0));
        g_painter->setColor(Color::white); g_painter->setColor(Color::white);
    }

    if(m_showStaticSquare && animate) {
       EffectPtr effect = EffectPtr(new Effect());

        effect->setId(819);
        g_painter->setColor(m_staticSquareColor);
        Rect rect = Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor);
        g_painter->drawTexturedRect(rect, effect->getThingType()->getTextureEX(0));
        g_painter->setColor(Color::white);
    }
    
    internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
    m_footStepDrawn = true;

    if(lightView) {
        Light light = rawGetThingType()->getLight();
        if(m_light.intensity != light.intensity || m_light.color != light.color)
            light = m_light;

        // local player always have a minimum light in complete darkness
        if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
            light.intensity = std::max<uint8>(light.intensity, 3);
            if(light.color == 0 || light.color > 215)
                light.color = 215;
        }

        if(light.intensity > 0)
            lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
    }
}
int countTest = 0;
void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
{
    g_painter->setColor(m_outfitColor);

    // outfit is a real creature
    if(m_outfit.getCategory() == ThingCategoryCreature) {
        int animationPhase = animateWalk ? m_walkAnimationPhase : 0;

        if(isAnimateAlways() && animateIdle) {
            int ticksPerFrame = 1000 / getAnimationPhases();
            animationPhase = (g_clock.millis() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
        }

        // xPattern => creature direction
        int xPattern;
        if(direction == Otc::NorthEast || direction == Otc::SouthEast)
            xPattern = Otc::East;
        else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
            xPattern = Otc::West;
        else
            xPattern = direction;

        int zPattern = 0;

        PointF jumpOffset = m_jumpOffset * scaleFactor;
        dest -= Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));

        // yPattern => creature addon
        for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {

            // continue if we dont have this addon

            if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
                continue;

            
            auto datType = getThingType();
             if(m_skull >= 1){
                float initEffe = 0.4f, endEffe = 0.6f;
                int exactSize = getExactSize();
                double scaleMult = 1.12, axsX = 0.97, axsY = 1.2; // ate 42 de exactSize
                Color azul = Color(0.0f, 128.0, 255.0, 1.0f), verde = Color(51, 255, 51), laranja = Color(255, 102, 0), azulCya = Color(51, 204, 255),
                      white = Color::white, viliota = Color(102, 0, 255), roxa = Color(153, 0, 204), redScarlat = Color(230, 0, 0), amarelo = Color(255, 255, 0),
                      preto = Color::black, rosa = Color(255, 51, 153), jeaneSoisQuoi = Color(0, 102, 102), cou = Color(204, 51, 0);
                Color auraColor = azul;// azul


                //Color config 1 = black, 2 = blue, 3 = green, 4 = pink, 5 = orange
                  if(m_skull == 2)
                      auraColor = verde; 
                  else if(m_skull == 3)
                      auraColor = laranja; 
                  else if (m_skull == 4) 
                      auraColor = azulCya; 
                  else if (m_skull == 5)
                      auraColor = white;
                  else if (m_skull == 6)
                      auraColor = viliota;
                  else if (m_skull == 7)
                      auraColor = roxa;
                  else if (m_skull == ?
                      auraColor = redScarlat;
                  else if (m_skull == 9)
                      auraColor = amarelo;
                  else if (m_skull == 10) {
                      initEffe = 0.7f; endEffe = 0.9f;
                      auraColor = preto;
                  }
                  else if (m_skull == 11) {
                      auraColor = rosa;
                      initEffe = 0.3f; endEffe = 0.7f;
                  }
                  else if (m_skull == 12)
                      auraColor = jeaneSoisQuoi;
                  else if (m_skull == 13)
                      auraColor = cou;

                    if(exactSize == 52) { // tamanho das sprites
                       axsY = 0.92;
                    }else if(exactSize == 32) { // tamanho das sprites
                       scaleMult = 1.16;
                       axsX = 0.94; axsY = 0.92;
                    }
                
                
                Point p = Point(dest.x-axsX, dest.y-axsY);
                //Rect rect = Rect(p.x, p.y, datType->getTexture(animationPhase)->getSize());
                countTest++;

                //colored raibow aura
                if (m_skull == 14) {
                    if (countTest <= 40)
                        auraColor = white;
                    else if (countTest >= 41 && countTest <= 80)
                        auraColor = redScarlat;
                    else if (countTest >= 81 && countTest <= 120)
                        auraColor = verde;
                    else if (countTest >= 121 && countTest <= 160)
                        auraColor = laranja;
                    else if (countTest >= 161 && countTest <= 200)
                        auraColor = azul;
                    else if (countTest >= 201 && countTest <= 240)
                        auraColor = amarelo;
                    else if (countTest >= 241)
                        countTest = 0;
                }else {
                        if (countTest <= 60) {
                            g_painter->setOpacity(initEffe);
                        }
                        else if (countTest >= 61 && countTest <= 110) {
                            g_painter->setOpacity(endEffe);
                        }
                        else if (countTest >= 111)
                            countTest = 0;
                    }

                g_painter->setColor(auraColor);
                datType->drawEX(p, scaleFactor*scaleMult, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);
                //g_painter->drawTexturedRect(rect, datType->getTexture(animationPhase, true));
                g_painter->setOpacity(1.0f);
             }
             
             // if(m_skull >= 1 && m_skullTexture){
                // g_painter->setOpacity(0.7f);
               //}
            g_painter->setColor(m_outfitColor);
            datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);

            if(getLayers() > 1) {
                Color oldColor = g_painter->getColor();
                Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
                g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
                g_painter->setColor(m_outfit.getHeadColor());
                datType->draw(dest, scaleFactor, SpriteMaskYellow, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(m_outfit.getBodyColor());
                datType->draw(dest, scaleFactor, SpriteMaskRed, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(m_outfit.getLegsColor());
                datType->draw(dest, scaleFactor, SpriteMaskGreen, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(m_outfit.getFeetColor());
                datType->draw(dest, scaleFactor, SpriteMaskBlue, xPattern, yPattern, zPattern, animationPhase);
                g_painter->setColor(oldColor);
                g_painter->setCompositionMode(oldComposition);
            }
        }
    // outfit is a creature imitating an item or the invisible effect
    } else  {
        ThingType *type = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory());

        int animationPhase = 0;
        int animationPhases = type->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() == ThingCategoryEffect) {
            animationPhases = std::max<int>(1, animationPhases-2);
            animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
        }

        if(animationPhases > 1) {
            if(animateIdle)
                animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
            else
                animationPhase = animationPhases-1;
        }

        if(m_outfit.getCategory() == ThingCategoryEffect)
            animationPhase = std::min<int>(animationPhase+1, animationPhases);

        type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
    }

    g_painter->resetColor();
    g_painter->setOpacity(1.0f);
}

void Creature::drawOutfit(const Rect& destRect, bool resize)
{
    int exactSize;
    if(m_outfit.getCategory() == ThingCategoryCreature)
        exactSize = getExactSize();
    else
        exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize();

    int frameSize;
    if(!resize)
        frameSize = std::max<int>(exactSize * 0.75f, 2 * Otc::TILE_PIXELS * 0.75f);
    else if(!(frameSize = exactSize))
        return;

    if(g_graphics.canUseFBO()) {
        const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
        outfitBuffer->resize(Size(frameSize, frameSize));
        outfitBuffer->bind();
        g_painter->setAlphaWriting(true);
        g_painter->clear(Color::alpha);
        internalDrawOutfit(Point(frameSize - Otc::TILE_PIXELS, frameSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
        outfitBuffer->release();
        outfitBuffer->draw(destRect, Rect(0,0,frameSize,frameSize));
    } else {
        float scaleFactor = destRect.width() / (float)frameSize;
        Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor;
        internalDrawOutfit(dest, scaleFactor, false, true, Otc::South);
    }
}

void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect, int drawFlags)
{
    if(m_healthPercent < 1 || m_outfit.getId() == 84) // creature is dead
        return;

    Color fillColor = Color(96, 96, 96);

    if(!useGray)
        fillColor = m_informationColor;

    int exactSize = getExactSize();
    int d = 0, dx = 0;
    
    if(exactSize <= 34)
        d = 5;
    else if(exactSize >= 35 && exactSize <= 48)
        d = 15;
    else if(exactSize >= 49 && exactSize <= 52)
        d = 25;
    else if(exactSize >= 53 && exactSize <= 57)
        d = 30;
    else if(exactSize >= 58 && exactSize <= 69)
        d = 25;
    else if(exactSize == 74)
        d = 37;
    
        dx = d /2;
        if(exactSize <= 34)
            dx = 17;

    // calculate main rects
    Rect backgroundRect = Rect(point.x - dx, point.y - d, 40, 6);
    backgroundRect.bind(parentRect);

    Size nameSize = m_nameCache.getTextSize();
    Rect textRect = Rect(point.x - nameSize.width() / 2, point.y-14, nameSize);
    textRect.bind(parentRect);

    // distance them
    if(textRect.top() == parentRect.top())
        backgroundRect.moveTop(textRect.top() + 12);
    if(backgroundRect.bottom() == parentRect.bottom())
        textRect.moveTop(backgroundRect.top() - 12);

    // health rect is based on background rect, so no worries
    Rect healthRect = backgroundRect.expanded(-1);
    //healthRect.setWidth();
    int calc = ((m_healthPercent / 100.0) * 40.0) + 60;
    std::string nameBar = std::to_string(calc);
    if (calc == 100)
        nameBar = "full";

    // draw
    if(g_game.getFeature(Otc::GameBlueNpcNameColor) && isNpc() && m_healthPercent == 100 && !useGray)
        fillColor = Color(0x66, 0xcc, 0xff);

    if(drawFlags & Otc::DrawBars && (!isNpc() || !g_game.getFeature(Otc::GameHideNpcNames))) {

            g_painter->setColor(Color::white);
            ImagePtr backgroundLifeBar = Image::load("data/images/game/lifebar/background");
            TexturePtr bgLifeBar = TexturePtr(new Texture(backgroundLifeBar, false));
            //g_painter->drawFilledRect(backgroundRect);
            g_painter->drawTexturedRect(backgroundRect, bgLifeBar);

            ImagePtr healthLifeBar = Image::load("data/images/game/lifebar/" + nameBar);
            TexturePtr lifeBar = TexturePtr(new Texture(healthLifeBar, false));
            g_painter->drawTexturedRect(healthRect, lifeBar);
            //g_painter->drawFilledRect(healthRect);
    }

    if(drawFlags & Otc::DrawNames) {
        g_painter->setColor(Color(213, 213, 0));
        
        //m_nameCache.setText(std::to_string(m_outfit.getId()));
         //m_nameCache.set
          m_nameCache.draw(textRect);
    }

    if (m_skull >= 50 && m_skull <= 56) {
        // 0 = on | 1 = use | 2 = off
        //     50     |     49      |     48 
        //0 0 0 0 0 0 | 0 0 0 0 0 1 | 0 0 0 0 1 2
        //
        g_painter->setColor(Color::white);
        ImagePtr imgBallON = Image::load("data/images/game/duel/pokeball_on");
        ImagePtr imgBallOFF = Image::load("data/images/game/duel/pokeball_off");
        ImagePtr imgBallUSE = Image::load("data/images/game/duel/pokeball_use");
        int duel_mode = m_skull - 50, ball_counts = m_emblem - 50;
        TexturePtr ballTexture1 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture2 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture3 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture4 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture5 = TexturePtr(new Texture(imgBallON, false));
        TexturePtr ballTexture6 = TexturePtr(new Texture(imgBallON, false));
        if (duel_mode == 1) {
            int countPos = 23 - (10 * 3);

            if (ball_counts == 1)
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));

            ballTexture1->setSmooth(true);
            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
        }
        else if (duel_mode == 2) {

            int countPos = 8 - 10;
            int countPos2 = 8 - 20;

            if (ball_counts == 4) {
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);

        }
        else if (duel_mode == 3) {

            int countPos = 13 - 10;
            int countPos2 = 13 - 20;
            int countPos3 = 13 - 30;

            if (ball_counts == 6) {
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);

        }
        else if (duel_mode == 4) {

            int countPos = 15 - 10;
            int countPos2 = 15 - 20;
            int countPos3 = 15 - 30;
            int countPos4 = 15 - 40;

            if (ball_counts == ? {
                ballTexture4 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 7) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 6) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect4 = Rect(backgroundRect.x() - countPos4, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);
            g_painter->drawTexturedRect(skullRect4, ballTexture4);

        }
        else if (duel_mode == 5) {

            int countPos = 18 - 10;
            int countPos2 = 18 - 20;
            int countPos3 = 18 - 30;
            int countPos4 = 18 - 40;
            int countPos5 = 18 - 50;

            if (ball_counts == 10) {
                ballTexture5 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 9) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == ? {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 7) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 6) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect4 = Rect(backgroundRect.x() - countPos4, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect5 = Rect(backgroundRect.x() - countPos5, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);
            g_painter->drawTexturedRect(skullRect4, ballTexture4);
            g_painter->drawTexturedRect(skullRect5, ballTexture5);

        }
        else if (duel_mode == 6) {

            int countPos = 21 - 10;
            int countPos2 = 21 - 20;
            int countPos3 = 21 - 30;
            int countPos4 = 21 - 40;
            int countPos5 = 21 - 50;
            int countPos6 = 21 - 60;

            if (ball_counts == 12) {
                ballTexture6 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 11) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 10) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 9) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == ? {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 7) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 6) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 5) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 4) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 3) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
            }
            else if (ball_counts == 2) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallUSE, false));
            }
            else if (ball_counts == 1) {
                ballTexture6 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture5 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture4 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture3 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture2 = TexturePtr(new Texture(imgBallOFF, false));
                ballTexture1 = TexturePtr(new Texture(imgBallOFF, false));
            }

            Rect skullRect = Rect(backgroundRect.x() - countPos, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect2 = Rect(backgroundRect.x() - countPos2, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect3 = Rect(backgroundRect.x() - countPos3, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect4 = Rect(backgroundRect.x() - countPos4, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect5 = Rect(backgroundRect.x() - countPos5, backgroundRect.y() - 25, ballTexture1->getSize());
            Rect skullRect6 = Rect(backgroundRect.x() - countPos6, backgroundRect.y() - 25, ballTexture1->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture1);
            g_painter->drawTexturedRect(skullRect2, ballTexture2);
            g_painter->drawTexturedRect(skullRect3, ballTexture3);
            g_painter->drawTexturedRect(skullRect4, ballTexture4);
            g_painter->drawTexturedRect(skullRect5, ballTexture5);
            g_painter->drawTexturedRect(skullRect6, ballTexture6);

        }
        /*for (int i = 0; i < duel_mode; i++) {
            int count = 23 - (10 * i);
            TexturePtr ballTexture = TexturePtr(new Texture(imgBall, false));

            if(i == 4)
                ballTexture = TexturePtr(new Texture(imgBallUSE, false));
            else if(i == 5)
                ballTexture = TexturePtr(new Texture(imgBallOFF, false));
            Rect skullRect = Rect(backgroundRect.x() - count, backgroundRect.y() - 25, ballTexture->getSize());
            g_painter->setOpacity(0.8f);
            g_painter->drawTexturedRect(skullRect, ballTexture);
        }
            */

        g_painter->setOpacity(1.0f);
    }
    if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
        g_painter->setColor(Color::white);
        Rect shieldRect = Rect(backgroundRect.x() + 13.5, backgroundRect.y() + 5, m_shieldTexture->getSize());
        g_painter->drawTexturedRect(shieldRect, m_shieldTexture);
    }
    if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
        g_painter->setColor(Color::white);
        Rect emblemRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 16, m_emblemTexture->getSize());
        g_painter->drawTexturedRect(emblemRect, m_emblemTexture);
    }
    if(m_icon != Otc::NpcIconNone && m_iconTexture) {
        g_painter->setColor(Color::white);
        Rect iconRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_iconTexture->getSize());
        g_painter->drawTexturedRect(iconRect, m_iconTexture);
    }
}

void Creature::turn(Otc::Direction direction)
{
    // if is not walking change the direction right away
    if(!m_walking)
        setDirection(direction);
    // schedules to set the new direction when walk ends
    else
        m_walkTurnDirection = direction;
}

void Creature::walk(const Position& oldPos, const Position& newPos)
{
    if(oldPos == newPos)
        return;

    // get walk direction
    m_lastStepDirection = oldPos.getDirectionFromPosition(newPos);
    m_lastStepFromPosition = oldPos;
    m_lastStepToPosition = newPos;

    // set current walking direction
    setDirection(m_lastStepDirection);

    // starts counting walk
    m_walking = true;
    m_walkTimer.restart();
    m_walkedPixels = 0;

    if(m_walkFinishAnimEvent) {
        m_walkFinishAnimEvent->cancel();
        m_walkFinishAnimEvent = nullptr;
    }

    // no direction need to be changed when the walk ends
    m_walkTurnDirection = Otc::InvalidDirection;

    // starts updating walk
    nextWalkUpdate();
}

void Creature::stopWalk()
{
    if(!m_walking)
        return;

    // stops the walk right away
    terminateWalk();
}

void Creature::jump(int height, int duration)
{
    if(!m_jumpOffset.isNull())
        return;

    m_jumpTimer.restart();
    m_jumpHeight = height;
    m_jumpDuration = duration;

    updateJump();
}

void Creature::updateJump()
{
    int t = m_jumpTimer.ticksElapsed();
    double a = -4 * m_jumpHeight / (m_jumpDuration * m_jumpDuration);
    double b = +4 * m_jumpHeight / (m_jumpDuration);

    double height = a*t*t + b*t;
    int roundHeight = stdext::round(height);
    int halfJumpDuration = m_jumpDuration / 2;

    // schedules next update
    if(m_jumpTimer.ticksElapsed() < m_jumpDuration) {
        m_jumpOffset = PointF(height, height);

        int diff = 0;
        if(m_jumpTimer.ticksElapsed() < halfJumpDuration)
            diff = 1;
        else if(m_jumpTimer.ticksElapsed() > halfJumpDuration)
            diff = -1;

        int nextT, i = 1;
        do {
            nextT = stdext::round((-b + std::sqrt(std::max<int>(b*b + 4*a*(roundHeight+diff*i), 0.0)) * diff) / (2*a));
            ++i;

            if(nextT < halfJumpDuration)
                diff = 1;
            else if(nextT > halfJumpDuration)
                diff = -1;
        } while(nextT - m_jumpTimer.ticksElapsed() == 0 && i < 3);

        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self] {
            self->updateJump();
        }, nextT - m_jumpTimer.ticksElapsed());
    }
    else
        m_jumpOffset = PointF(0, 0);
}

void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
{
    callLuaField("onPositionChange", newPos, oldPos);
}

void Creature::onAppear()
{
    // cancel any disappear event
    if(m_disappearEvent) {
        m_disappearEvent->cancel();
        m_disappearEvent = nullptr;
    }

    // creature appeared the first time or wasn't seen for a long time
    if(m_removed) {
        stopWalk();
        m_removed = false;
        callLuaField("onAppear");
    // walk
    } else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1) && m_allowAppearWalk) {
        m_allowAppearWalk = false;
        walk(m_oldPosition, m_position);
        callLuaField("onWalk", m_oldPosition, m_position);
    // teleport
    } else if(m_oldPosition != m_position) {
        stopWalk();
        callLuaField("onDisappear");
        callLuaField("onAppear");
    } // else turn
}

void Creature::onDisappear()
{
    if(m_disappearEvent)
        m_disappearEvent->cancel();

    m_oldPosition = m_position;

    // a pair onDisappear and onAppear events are fired even when creatures walks or turns,
    // so we must filter
    auto self = static_self_cast<Creature>();
    m_disappearEvent = g_dispatcher.addEvent([self] {
        self->m_removed = true;
        self->stopWalk();

        self->callLuaField("onDisappear");

        // invalidate this creature position
        if(!self->isLocalPlayer())
            self->setPosition(Position());
        self->m_oldPosition = Position();
        self->m_disappearEvent = nullptr;
    });
}

void Creature::onDeath()
{
    callLuaField("onDeath");
}

void Creature::updateWalkAnimation(int totalPixelsWalked)
{
    // update outfit animation
    if(m_outfit.getCategory() != ThingCategoryCreature)
        return;

    int footAnimPhases = getAnimationPhases() - 1;
    int footDelay = getStepDuration(true) / 3;
    // Since mount is a different outfit we need to get the mount animation phases
    if(m_outfit.getMount() != 0) {
        ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
        footAnimPhases = type->getAnimationPhases() - 1;
    }
    if(footAnimPhases == 0)
        m_walkAnimationPhase = 0;
    else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
        m_footStep++;
        m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
        m_footStepDrawn = false;
        m_footTimer.restart();
    } else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
        m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
    }

    if(totalPixelsWalked == 32 && !m_walkFinishAnimEvent) {
        auto self = static_self_cast<Creature>();
        m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
            if(!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true))
                self->m_walkAnimationPhase = 0;
            self->m_walkFinishAnimEvent = nullptr;
        }, std::min<int>(footDelay, 200));
    }

}

void Creature::updateWalkOffset(int totalPixelsWalked)
{
    m_walkOffset = Point(0,0);
    if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
        m_walkOffset.y = 32 - totalPixelsWalked;
    else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
        m_walkOffset.y = totalPixelsWalked - 32;

    if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
        m_walkOffset.x = totalPixelsWalked - 32;
    else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
        m_walkOffset.x = 32 - totalPixelsWalked;
}

void Creature::updateWalkingTile()
{
    // determine new walking tile
    TilePtr newWalkingTile;
    Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
                             Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
                             Otc::TILE_PIXELS, Otc::TILE_PIXELS);
    for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
        for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
            Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);

            // only render creatures where bottom right is inside tile rect
            if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
                newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
            }
        }
    }

    if(newWalkingTile != m_walkingTile) {
        if(m_walkingTile)
            m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
        if(newWalkingTile) {
            newWalkingTile->addWalkingCreature(static_self_cast<Creature>());

            // recache visible tiles in map views
            if(newWalkingTile->isEmpty())
                g_map.notificateTileUpdate(newWalkingTile->getPosition());
        }
        m_walkingTile = newWalkingTile;
    }
}

void Creature::nextWalkUpdate()
{
    // remove any previous scheduled walk updates
    if(m_walkUpdateEvent)
        m_walkUpdateEvent->cancel();

    // do the update
    updateWalk();

    // schedules next update
    if(m_walking) {
        auto self = static_self_cast<Creature>();
        m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
            self->m_walkUpdateEvent = nullptr;
            self->nextWalkUpdate();
        }, getStepDuration() / 32);
    }
}

void Creature::updateWalk()
{
    float walkTicksPerPixel = getStepDuration(true) / 32;
    int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);

    // needed for paralyze effect
    m_walkedPixels = std::max<int>(m_walkedPixels, totalPixelsWalked);

    // update walk animation and offsets
    updateWalkAnimation(totalPixelsWalked);
    updateWalkOffset(m_walkedPixels);
    updateWalkingTile();

    // terminate walk
    if(m_walking && m_walkTimer.ticksElapsed() >= getStepDuration())
        terminateWalk();
}

void Creature::terminateWalk()
{
    // remove any scheduled walk update
    if(m_walkUpdateEvent) {
        m_walkUpdateEvent->cancel();
        m_walkUpdateEvent = nullptr;
    }

    // now the walk has ended, do any scheduled turn
    if(m_walkTurnDirection != Otc::InvalidDirection)  {
        setDirection(m_walkTurnDirection);
        m_walkTurnDirection = Otc::InvalidDirection;
    }

    if(m_walkingTile) {
        m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
        m_walkingTile = nullptr;
    }

    m_walking = false;
    m_walkedPixels = 0;

    // reset walk animation states
    m_walkOffset = Point(0,0);
    m_walkAnimationPhase = 0;
}

void Creature::setName(const std::string& name)
{
    m_nameCache.setText(name);
    m_name = name;
}

void Creature::setHealthPercent(uint8 healthPercent)
{
    if(healthPercent > 92)
        m_informationColor = Color(0x00, 0xBC, 0x00);
    else if(healthPercent > 60)
        m_informationColor = Color(0x50, 0xA1, 0x50);
    else if(healthPercent > 30)
        m_informationColor = Color(0xA1, 0xA1, 0x00);
    else if(healthPercent > ?
        m_informationColor = Color(0xBF, 0x0A, 0x0A);
    else if(healthPercent > 3)
        m_informationColor = Color(0x91, 0x0F, 0x0F);
    else
        m_informationColor = Color(0x85, 0x0C, 0x0C);

    m_healthPercent = healthPercent;
    callLuaField("onHealthPercentChange", healthPercent);

    if(healthPercent <= 0)
        onDeath();
}

void Creature::setDirection(Otc::Direction direction)
{
    assert(direction != Otc::InvalidDirection);
    m_direction = direction;
}

void Creature::setOutfit(const Outfit& outfit)
{
    Outfit oldOutfit = m_outfit;
    if(outfit.getCategory() != ThingCategoryCreature) {
        if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
            return;
        m_outfit.setAuxId(outfit.getAuxId());
        m_outfit.setCategory(outfit.getCategory());
        m_outfit2.setAuxId(outfit.getAuxId());
        m_outfit2.setCategory(outfit.getCategory());
    } else {
        if(outfit.getId() > 0 && !g_things.isValidDatId(outfit.getId(), ThingCategoryCreature))
            return;
        m_outfit = outfit;
        m_outfit2 = outfit;
    }
    m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
    callLuaField("onOutfitChange", m_outfit, oldOutfit);
}

void Creature::setOutfitColor(const Color& color, int duration)
{
    if(m_outfitColorUpdateEvent) {
        m_outfitColorUpdateEvent->cancel();
        m_outfitColorUpdateEvent = nullptr;
    }

    if(duration > 0) {
        Color delta = (color - m_outfitColor) / (float)duration;
        m_outfitColorTimer.restart();
        updateOutfitColor(m_outfitColor, color, delta, duration);
    }
    else
        m_outfitColor = color;
}

void Creature::updateOutfitColor(Color color, Color finalColor, Color delta, int duration)
{
    if(m_outfitColorTimer.ticksElapsed() < duration) {
        m_outfitColor = color + delta * m_outfitColorTimer.ticksElapsed();

        auto self = static_self_cast<Creature>();
        m_outfitColorUpdateEvent = g_dispatcher.scheduleEvent([=] {
            self->updateOutfitColor(color, finalColor, delta, duration);
        }, 100);
    }
    else {
        m_outfitColor = finalColor;
    }
}

void Creature::setSpeed(uint16 speed)
{
    uint16 oldSpeed = m_speed;
    m_speed = speed;

    // speed can change while walking (utani hur, paralyze, etc..)
    if(m_walking)
        nextWalkUpdate();

    callLuaField("onSpeedChange", m_speed, oldSpeed);
}

void Creature::setBaseSpeed(double baseSpeed)
{
    if(m_baseSpeed != baseSpeed) {
        double oldBaseSpeed = m_baseSpeed;
        m_baseSpeed = baseSpeed;

        callLuaField("onBaseSpeedChange", baseSpeed, oldBaseSpeed);
    }
}

void Creature::setSkull(uint8 skull)
{
    m_skull = skull;
    callLuaField("onSkullChange", m_skull);
}

void Creature::setShield(uint8 shield)
{
    m_shield = shield;
    callLuaField("onShieldChange", m_shield);
}

void Creature::setEmblem(uint8 emblem)
{
    m_emblem = emblem;
    callLuaField("onEmblemChange", m_emblem);
}

void Creature::setIcon(uint8 icon)
{
    m_icon = icon;
    callLuaField("onIconChange", m_icon);
}

void Creature::setSkullTexture(const std::string& filename)
{
    m_skullTexture = g_textures.getTexture(filename);
}

void Creature::setShieldTexture(const std::string& filename, bool blink)
{
    m_shieldTexture = g_textures.getTexture(filename);
    m_showShieldTexture = true;

    if(blink && !m_shieldBlink) {
        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self]() {
            self->updateShield();
        }, SHIELD_BLINK_TICKS);
    }

    m_shieldBlink = blink;
}

void Creature::setEmblemTexture(const std::string& filename)
{
    m_emblemTexture = g_textures.getTexture(filename);
}

void Creature::setIconTexture(const std::string& filename)
{
    m_iconTexture = g_textures.getTexture(filename);
}


void Creature::setSpeedFormula(double speedA, double speedB, double speedC)
{
    m_speedFormula[Otc::SpeedFormulaA] = speedA;
    m_speedFormula[Otc::SpeedFormulaB] = speedB;
    m_speedFormula[Otc::SpeedFormulaC] = speedC;
}

bool Creature::hasSpeedFormula()
{
    return m_speedFormula[Otc::SpeedFormulaA] != -1 && m_speedFormula[Otc::SpeedFormulaB] != -1
            && m_speedFormula[Otc::SpeedFormulaC] != -1;
}

void Creature::addTimedSquare(uint8 color)
{
    m_showTimedSquare = true;
    m_timedSquareColor = Color::from8bit(color);

    // schedule removal
    auto self = static_self_cast<Creature>();
    g_dispatcher.scheduleEvent([self]() {
        self->removeTimedSquare();
    }, VOLATILE_SQUARE_DURATION);
}

void Creature::updateShield()
{
    m_showShieldTexture = !m_showShieldTexture;

    if(m_shield != Otc::ShieldNone && m_shieldBlink) {
        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self]() {
            self->updateShield();
        }, SHIELD_BLINK_TICKS);
    }
    else if(!m_shieldBlink)
        m_showShieldTexture = true;
}

Point Creature::getDrawOffset()
{
    Point drawOffset;
    if(m_walking) {
        if(m_walkingTile)
            drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
        drawOffset += m_walkOffset;
    } else {
        const TilePtr& tile = getTile();
        if(tile)
            drawOffset -= Point(1,1) * tile->getDrawElevation();
    }
    return drawOffset;
}

int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
{
    int speed = m_speed;
    if(speed < 1)
        return 0;

    if(g_game.getFeature(Otc::GameNewSpeedLaw))
        speed *= 2;

    int groundSpeed = 0;
    Position tilePos;

    if(dir == Otc::InvalidDirection)
        tilePos = m_lastStepToPosition;
    else
        tilePos = m_position.translatedToDirection(dir);

    if(!tilePos.isValid())
        tilePos = m_position;
    const TilePtr& tile = g_map.getTile(tilePos);
    if(tile) {
        groundSpeed = tile->getGroundSpeed();
        if(groundSpeed == 0)
            groundSpeed = 150;
    }

    int interval = 1000;
    if(groundSpeed > 0 && speed > 0)
        interval = 1000 * groundSpeed;

    if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
        int formulatedSpeed = 1;
        if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
            formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
                 + m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
        }
        interval = std::floor(interval / (double)formulatedSpeed);
    }
    else
        interval /= speed;

    if(g_game.getClientVersion() >= 900)
        interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();

    float factor = 3;
    if(g_game.getClientVersion() <= 810)
        factor = 2;

    interval = std::max<int>(interval, g_game.getServerBeat());

    if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
       m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
        interval *= factor;

    return interval;
}

Point Creature::getDisplacement()
{
    if(m_outfit.getCategory() == ThingCategoryEffect)
        return Point(8, 8);
    else if(m_outfit.getCategory() == ThingCategoryItem)
        return Point(0, 0);
    return Thing::getDisplacement();
}

int Creature::getDisplacementX()
{
    if(m_outfit.getCategory() == ThingCategoryEffect)
        return 8;
    else if(m_outfit.getCategory() == ThingCategoryItem)
        return 0;

    if(m_outfit.getMount() != 0) {
        auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
        return datType->getDisplacementX();
    }

    return Thing::getDisplacementX();
}

int Creature::getDisplacementY()
{
    if(m_outfit.getCategory() == ThingCategoryEffect)
        return 8;
    else if(m_outfit.getCategory() == ThingCategoryItem)
        return 0;

    if(m_outfit.getMount() != 0) {
        auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
        return datType->getDisplacementY();
    }

    return Thing::getDisplacementY();
}

int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
{
    int exactSize = 0;

    animationPhase = 0;
    xPattern = Otc::South;

    zPattern = 0;
    if(m_outfit.getMount() != 0)
        zPattern = 1;

    for(yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
        if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
            continue;

        for(layer = 0; layer < getLayers(); ++layer)
            exactSize = std::max<int>(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
    }

    return exactSize;
}

const ThingTypePtr& Creature::getThingType()
{
    return g_things.getThingType(m_outfit.getId(), ThingCategoryCreature);
}

const ThingTypePtr& Creature::getThingType2()
{
    return g_things.getThingType2(m_outfit.getId(), ThingCategoryCreature);
}

ThingType* Creature::rawGetThingType()
{
    if (!iniciou) {
        novaOutType = g_things.getThingTypeInSecondList(m_outfit2.getId(), ThingCategoryCreature);
        iniciou = true;
    }
    return g_things.rawGetThingType(m_outfit.getId(), ThingCategoryCreature);
}

ThingType* Creature::rawGetThingType2()
{
    if (!iniciou) {
        novaOutType = g_things.getThingTypeInSecondList(m_outfit2.getId(), ThingCategoryCreature);
        iniciou = true;
    }
    return novaOutType;
}
 

 

a linha: 

  g_painter->drawTexturedRect(rect, effect->getThingType()->getTextureEX(0));

 

Link para o comentário
Compartilhar em outros sites

  • 3 weeks later...
Em 26/07/2018 em 22:48, Refe disse:

quais ?

a linha: 


  g_painter->drawTexturedRect(rect, effect->getThingType()->getTextureEX(0));

 

Pode mandar a png dnv ? nao esta carregando a que esta no topico agradeço

Link para o comentário
Compartilhar em outros sites

  • 1 month later...
  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...