-
Total de itens
116 -
Registro em
-
Última visita
-
Dias Ganhos
2
Tipo de Conteúdo
Perfis
Fóruns
Calendário
Publique
Posts postados por GaspaR1
-
-
35 minutos atrás, kasemaru1 disse:
E vaga remunerada ou é só pra ajudar a fazer o negocio?
Vaga remunerada, quando o projeto estiver online.
-
Bom primeiramente, quero agradecer a todos que estão lendo essa publicação... e desde já informar que esse é um projeto sério, onde iremos seguir o GTA história por história, em um mundo aberto... para todos os fãs de um Dayz, Samp, então vocês irão gostar do que irei mostrar a vocês.
Primeiro de tudo, qual a finalidade do projeto ?
Fácil, hoje em dia é muito comum ver um Poketibia, um NTO, DBZ E ETC, mas cadê a inovação? pra mim já deu, poketibia existe vários outros grandes, NTO, DBZ, então hoje em dia não compensa mais, a não ser é claro que você faça algo inovador e diferente senão, não irá para frente.
então eu já vi alguns OTS, de GTA... mas nenhum que se mantém seguindo a risca o próprio jogo, e então vamos mudar isso, transformando o Tibia em um GTA, uma versão leve para quem não tem um PC totalmente bom, porque sim existe pessoas que ainda não tem condição para um PC Gamer extra luxuoso, então a minha primeira meta é deixar o GTA TIBIA jogável para todos.
Quais sistemas já temos? ( Alguns irão precisar de modificações claro, para uma melhor jogabilidade )
--> Sistema de armas.
--> Sistema de avião.
--> Sistema de carros, roubos e etc.
--> Sistema de Jetski.
--> Sistema de gasolina.
--> Sistema de compra do seu terreno, onde você mesmo pode construir sua casa in-game.
--> Não irei citar todos, apenas alguns que acho importante.
Faltando fazer?
--> Estou criando o mapa do zero, irei criar o mapa todo de San Andreas. ( já comecei a criação, prints no final do post)
--> Criar o sistema quests.
--> Criar o sistema de estrelas.
--> Criar o sistema de profissão ( Trabalho ).
--> e outras coisinhas.
!! Lembrando !!
Já temos launcher, criptografia, layout para o client ( Próprio ), vps linux ( Dedicado ), e site.
VAGAS
2 Vaga para Programador.
2 Vagas para Spriter.
RESSALTANDO NOVAMENTE
Isso não é para crianças, então se seu intuito não está voltado para essas duas vagas ou ajudar, por favor não venham pedir vaga.
Discord
AlaOGaspar
#7077
Não sou muito fã de escrever e ainda mais de organizar kkk, então irei deixar meu discord aqui para caso vocês queiram saber + do servidor.
Citar -
Salve galera, bom estou tento um problema...
recentemente adicionei o campo de visão extendido no OTC do mehah,
mas estou com um problema.
Sempre que deslogo e logo dnv, o nome do jogador fica no lugar, alguém poderia me ajudar ?
-
9 minutos atrás, Yan Liima disse:
64bits só com VS.
Possa ser que o diretório das lib do seu dev não estejam corretas. Tenta desinstar todos dev cpp do seu PC e instala esse AQUUUI
Pra garantir que funcione 100%, instala o openssl também.
eu instalei o seu, mas vou verificar e com o visual ? vs2019 n funfa
9 minutos atrás, GaspaR1 disse:eu instalei o seu, mas vou verificar e com o visual ? vs2019 n funfa
e como eu faço pra zerar tudo do dev ?
2 horas atrás, GaspaR1 disse:eu instalei o seu, mas vou verificar e com o visual ? vs2019 n funfa
e como eu faço pra zerar tudo do dev ?
EDIT: consegui compilar, mas agora não loga wtf
-
Em 17/07/2019 em 14:22, Yan Liima disse:
Salve salve pessoal, no inicio desse ano estava dando uma estudada e mexendo com a TFS 0.4 rev3884, e vi que havia alguns bugs e que não tinha Cast incluso. Com base nisso decidi atualizar e otimizar a source, já que ainda ela é uma das mais utilizadas no mundo de Otserv. Decidi compartilhar esse meu trabalho com vocês! Acredito que possa ser uma das melhores REV atualmente.
Conto com o seu feedback, caso haja algum bug, algo que tenha que mudar/optimizar, não exite em avisar aqui no tópico. Toda ajuda será bem vinda xD
The Forgotten Server, Tibia Versão: 8.60
O que contém nela?
• War System • Cast System (Cast do Summ, implementado na Source por mim e corrigido do mesmo. Com uma nova função que adicionei de Kick.) • Anti-Divulgação (Configuravel no config.lua) • Bug de Anti-push corrigido! • Bugs de ElfBot corrigido(De party e alguns outros). • Problema de não aceitar outro items corrigido(skipItemsVersionCheck); • Opcode incluso; • Retirado erro de Malformed File; • creatureevent onMoveItem() & onMoveItem2() incluso; • getOtsysTime(), getPlayerPing(cid), doPlayerSendPing(cid) incluso; • função doPlayerOpenChannel incluso; • função getCreaturePathTo() incluso; • função doSetCreatureLight() incluso; • Adicionado Max Packet Por Segundo(É algo que não havia na 0.4 e decidi por. ta 100%) • Adicionado exhaust ao comprar/vender items(retirei da src do Fir3...) • Bug de clonar usando o comando !disband corrigido! • Comandos de house corrigido(como o Aleta Som por exemplo..) • Ao entrar em PZ remove battle • Salt removido • Log do chat, salva tudo que os jogadores falam (Ative no config.lua: "logsPlayers", necessário criar a pasta "players" no logs.) • O comando /addskill que causava um congelamento foi corrigido! • Podendo atacar & usar runa ao mesmo tempo. • É possivel fazer os monstros nascerem mesmo com o jogador perto(no config.lua deixe o allowBlockSpawn como false) • Com healthHealingColor e manaHealingColor (para alterar as cores do heal, configuravel no config.lua) • Mailbox Block adicionado (itens de clone mais difíceis com sistema de parcel) + Configurações extras no sistema de mail system. • timeBetweenCustomActions adicionado (exhausted em talkactions e VIP LIST, para evitar travamentos de elfbot). • classicEquipmentSlots adicionado (slot correto para cada equipamento, basta por como false no config). ••• E muito mais!!! •••
Dentro da pasta contém o config.lua com todas as tag já adicionadas.
Não esquecam de executar a Query do Cast na sua DB:
ALTER TABLE `players` ADD `cast` TINYINT NOT NULL DEFAULT '0', ADD `castViewers` INT( 11 ) NOT NULL DEFAULT '0', ADD `castDescription` VARCHAR( 255 ) NOT NULL
Downloads uint8(Effects até 255)
Distro: TheForgottenServer.exe
Src + datapack: Source & Data
-------------------------------------------------------
Downloads uint16(Effects até 65534)
Distro: TheForgottenServer.exe
Src + datapack: Source & Data
É necessário fazer a modificação do Hexadecimal no cliente. Aqui tem um já pronto: Cliente.exe(com mc) ou Cliente.exe(sem mc) (só será necessario se utilizar a src com o uint 16.)
Lembrado também que precisa utilizar a lib 000-constant.lua deste datapack.
-------------------------------------------------------
Scans:
Distro(uint8) & Distro(uint16)
Obs: Os virus detectado é um falso positivo, então não se preocupem!
A distro foi testada em Windows e em Linux Ubuntu 14.04, em ambos funcionaram muito bem!
E para quem se interessa em saber onde se localiza os code do Cast, aqui está uma imagem. Você pode achar procurando por "//CAST"
Façam um ótimo aproveito
mano, estou tento problema na hora de compilar no dev
da o seguinte erro , tem alguma ideia do que seja ? ou poderia me mandar o seu dev ? tbm tentei compilar com o visual 19, mas tbm da erro falta o otpch.cpp.
-
Salve galera beleza ? antes de tudo não sei se é a área correta, se não estiver na área correta peço que alguém mova porfavor...
bom recentemente segui um tutorial para aumentar o campo de visão do personagem no meu OT, e funcionou só que fica com umas bordinhas ainda, alguém saberia arrumar ? ou me ajudar...
map.cpp otclient
/* * 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 "map.h" #include "game.h" #include "localplayer.h" #include "tile.h" #include "item.h" #include "missile.h" #include "statictext.h" #include "mapview.h" #include "minimap.h" #include <framework/core/eventdispatcher.h> #include <framework/core/application.h> Map g_map; TilePtr Map::m_nulltile; void Map::init() { resetAwareRange(); m_animationFlags |= Animation_Show; } void Map::terminate() { clean(); } void Map::addMapView(const MapViewPtr& mapView) { m_mapViews.push_back(mapView); } void Map::removeMapView(const MapViewPtr& mapView) { auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView); if(it != m_mapViews.end()) m_mapViews.erase(it); } void Map::notificateTileUpdate(const Position& pos) { if(!pos.isMapPosition()) return; for(const MapViewPtr& mapView : m_mapViews) mapView->onTileUpdate(pos); g_minimap.updateTile(pos, getTile(pos)); } void Map::clean() { cleanDynamicThings(); for(int i=0;i<=Otc::MAX_Z;++i) m_tileBlocks[i].clear(); m_waypoints.clear(); g_towns.clear(); g_houses.clear(); g_creatures.clearSpawns(); m_tilesRect = Rect(65534, 65534, 0, 0); } void Map::cleanDynamicThings() { for(const auto& pair : m_knownCreatures) { const CreaturePtr& creature = pair.second; removeThing(creature); } m_knownCreatures.clear(); for(int i=0;i<=Otc::MAX_Z;++i) m_floorMissiles[i].clear(); cleanTexts(); } void Map::cleanTexts() { m_animatedTexts.clear(); m_staticTexts.clear(); } void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) { if(!thing) return; if(thing->isItem() || thing->isCreature() || thing->isEffect()) { const TilePtr& tile = getOrCreateTile(pos); if(tile) tile->addThing(thing, stackPos); } else { if(thing->isMissile()) { m_floorMissiles[pos.z].push_back(thing->static_self_cast<Missile>()); } else if(thing->isAnimatedText()) { // this code will stack animated texts of the same color AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>(); AnimatedTextPtr prevAnimatedText; bool merged = false; for(auto other : m_animatedTexts) { if(other->getPosition() == pos) { prevAnimatedText = other; if(other->merge(animatedText)) { merged = true; break; } } } if(!merged) { if(prevAnimatedText) { Point offset = prevAnimatedText->getOffset(); float t = prevAnimatedText->getTimer().ticksElapsed(); if(t < Otc::ANIMATED_TEXT_DURATION / 4.0) { // didnt move 12 pixels int y = 12 - 48 * t / (float)Otc::ANIMATED_TEXT_DURATION; offset += Point(0, y); } offset.y = std::min<int>(offset.y, 12); animatedText->setOffset(offset); } m_animatedTexts.push_back(animatedText); } } else if(thing->isStaticText()) { StaticTextPtr staticText = thing->static_self_cast<StaticText>(); bool mustAdd = true; for(auto other : m_staticTexts) { // try to combine messages if(other->getPosition() == pos && other->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) { mustAdd = false; break; } } if(mustAdd) m_staticTexts.push_back(staticText); else return; } thing->setPosition(pos); thing->onAppear(); } notificateTileUpdate(pos); } ThingPtr Map::getThing(const Position& pos, int stackPos) { if(TilePtr tile = getTile(pos)) return tile->getThing(stackPos); return nullptr; } bool Map::removeThing(const ThingPtr& thing) { if(!thing) return false; bool ret = false; if(thing->isMissile()) { MissilePtr missile = thing->static_self_cast<Missile>(); int z = missile->getPosition().z; auto it = std::find(m_floorMissiles[z].begin(), m_floorMissiles[z].end(), missile); if(it != m_floorMissiles[z].end()) { m_floorMissiles[z].erase(it); ret = true; } } else if(thing->isAnimatedText()) { AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>(); auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText); if(it != m_animatedTexts.end()) { m_animatedTexts.erase(it); ret = true; } } else if(thing->isStaticText()) { StaticTextPtr staticText = thing->static_self_cast<StaticText>(); auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText); if(it != m_staticTexts.end()) { m_staticTexts.erase(it); ret = true; } } else if(const TilePtr& tile = thing->getTile()) ret = tile->removeThing(thing); notificateTileUpdate(thing->getPosition()); return ret; } bool Map::removeThingByPos(const Position& pos, int stackPos) { if(TilePtr tile = getTile(pos)) return removeThing(tile->getThing(stackPos)); return false; } void Map::colorizeThing(const ThingPtr& thing, const Color& color) { if(!thing) return; if(thing->isItem()) thing->static_self_cast<Item>()->setColor(color); else if(thing->isCreature()) { const TilePtr& tile = thing->getTile(); assert(tile); const ThingPtr& topThing = tile->getTopThing(); assert(topThing); topThing->static_self_cast<Item>()->setColor(color); } } void Map::removeThingColor(const ThingPtr& thing) { if(!thing) return; if(thing->isItem()) thing->static_self_cast<Item>()->setColor(Color::alpha); else if(thing->isCreature()) { const TilePtr& tile = thing->getTile(); assert(tile); const ThingPtr& topThing = tile->getTopThing(); assert(topThing); topThing->static_self_cast<Item>()->setColor(Color::alpha); } } StaticTextPtr Map::getStaticText(const Position& pos) { for(auto staticText : m_staticTexts) { // try to combine messages if(staticText->getPosition() == pos) return staticText; } return nullptr; } const TilePtr& Map::createTile(const Position& pos) { if(!pos.isMapPosition()) return m_nulltile; if(pos.x < m_tilesRect.left()) m_tilesRect.setLeft(pos.x); if(pos.y < m_tilesRect.top()) m_tilesRect.setTop(pos.y); if(pos.x > m_tilesRect.right()) m_tilesRect.setRight(pos.x); if(pos.y > m_tilesRect.bottom()) m_tilesRect.setBottom(pos.y); TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)]; return block.create(pos); } template <typename... Items> const TilePtr& Map::createTileEx(const Position& pos, const Items&... items) { if(!pos.isValid()) return m_nulltile; const TilePtr& tile = getOrCreateTile(pos); auto vec = {items...}; for(auto it : vec) addThing(it, pos); return tile; } const TilePtr& Map::getOrCreateTile(const Position& pos) { if(!pos.isMapPosition()) return m_nulltile; if(pos.x < m_tilesRect.left()) m_tilesRect.setLeft(pos.x); if(pos.y < m_tilesRect.top()) m_tilesRect.setTop(pos.y); if(pos.x > m_tilesRect.right()) m_tilesRect.setRight(pos.x); if(pos.y > m_tilesRect.bottom()) m_tilesRect.setBottom(pos.y); TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)]; return block.getOrCreate(pos); } const TilePtr& Map::getTile(const Position& pos) { if(!pos.isMapPosition()) return m_nulltile; auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos)); if(it != m_tileBlocks[pos.z].end()) return it->second.get(pos); return m_nulltile; } const TileList Map::getTiles(int floor/* = -1*/) { TileList tiles; if(floor > Otc::MAX_Z) { return tiles; } else if(floor < 0) { // Search all floors for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) { for(const auto& pair : m_tileBlocks[z]) { const TileBlock& block = pair.second; for(const TilePtr& tile : block.getTiles()) { if(tile != nullptr) tiles.push_back(tile); } } } } else { for(const auto& pair : m_tileBlocks[floor]) { const TileBlock& block = pair.second; for(const TilePtr& tile : block.getTiles()) { if(tile != nullptr) tiles.push_back(tile); } } } return tiles; } void Map::cleanTile(const Position& pos) { if(!pos.isMapPosition()) return; auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos)); if(it != m_tileBlocks[pos.z].end()) { TileBlock& block = it->second; if(const TilePtr& tile = block.get(pos)) { tile->clean(); if(tile->canErase()) block.remove(pos); notificateTileUpdate(pos); } } for(auto it = m_staticTexts.begin();it != m_staticTexts.end();) { const StaticTextPtr& staticText = *it; if(staticText->getPosition() == pos && staticText->getMessageMode() == Otc::MessageNone) it = m_staticTexts.erase(it); else ++it; } } void Map::setShowZone(tileflags_t zone, bool show) { if(show) m_zoneFlags |= (uint32)zone; else m_zoneFlags &= ~(uint32)zone; } void Map::setShowZones(bool show) { if(!show) m_zoneFlags = 0; else if(m_zoneFlags == 0) m_zoneFlags = TILESTATE_HOUSE | TILESTATE_PROTECTIONZONE; } void Map::setZoneColor(tileflags_t zone, const Color& color) { if((m_zoneFlags & zone) == zone) m_zoneColors[zone] = color; } Color Map::getZoneColor(tileflags_t flag) { auto it = m_zoneColors.find(flag); if(it == m_zoneColors.end()) return Color::alpha; return it->second; } void Map::setForceShowAnimations(bool force) { if(force) { if(!(m_animationFlags & Animation_Force)) m_animationFlags |= Animation_Force; } else m_animationFlags &= ~Animation_Force; } bool Map::isForcingAnimations() { return (m_animationFlags & Animation_Force) == Animation_Force; } bool Map::isShowingAnimations() { return (m_animationFlags & Animation_Show) == Animation_Show; } void Map::setShowAnimations(bool show) { if(show) { if(!(m_animationFlags & Animation_Show)) m_animationFlags |= Animation_Show; } else m_animationFlags &= ~Animation_Show; } void Map::beginGhostMode(float opacity) { g_painter->setOpacity(opacity); } void Map::endGhostMode() { g_painter->resetOpacity(); } std::map<Position, ItemPtr> Map::findItemsById(uint16 clientId, uint32 max) { std::map<Position, ItemPtr> ret; uint32 count = 0; for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) { for(const auto& pair : m_tileBlocks[z]) { const TileBlock& block = pair.second; for(const TilePtr& tile : block.getTiles()) { if(unlikely(!tile || tile->isEmpty())) continue; for(const ItemPtr& item : tile->getItems()) { if(item->getId() == clientId) { ret.insert(std::make_pair(tile->getPosition(), item)); if(++count >= max) break; } } } } } return ret; } void Map::addCreature(const CreaturePtr& creature) { m_knownCreatures[creature->getId()] = creature; } CreaturePtr Map::getCreatureById(uint32 id) { auto it = m_knownCreatures.find(id); if(it == m_knownCreatures.end()) return nullptr; return it->second; } void Map::removeCreatureById(uint32 id) { if(id == 0) return; auto it = m_knownCreatures.find(id); if(it != m_knownCreatures.end()) m_knownCreatures.erase(it); } void Map::removeUnawareThings() { // remove creatures from tiles that we are not aware of anymore for(const auto& pair : m_knownCreatures) { const CreaturePtr& creature = pair.second; if(!isAwareOfPosition(creature->getPosition())) removeThing(creature); } // remove static texts from tiles that we are not aware anymore for(auto it = m_staticTexts.begin(); it != m_staticTexts.end();) { const StaticTextPtr& staticText = *it; if(staticText->getMessageMode() == Otc::MessageNone && !isAwareOfPosition(staticText->getPosition())) it = m_staticTexts.erase(it); else ++it; } if(!g_game.getFeature(Otc::GameKeepUnawareTiles)) { // remove tiles that we are not aware anymore for(int z = 0; z <= Otc::MAX_Z; ++z) { std::unordered_map<uint, TileBlock>& tileBlocks = m_tileBlocks[z]; for(auto it = tileBlocks.begin(); it != tileBlocks.end();) { TileBlock& block = (*it).second; bool blockEmpty = true; for(const TilePtr& tile : block.getTiles()) { if(!tile) continue; const Position& pos = tile->getPosition(); if(!isAwareOfPosition(pos)) block.remove(pos); else blockEmpty = false; } if(blockEmpty) it = tileBlocks.erase(it); else ++it; } } } } void Map::setCentralPosition(const Position& centralPosition) { if(m_centralPosition == centralPosition) return; m_centralPosition = centralPosition; removeUnawareThings(); // this fixes local player position when the local player is removed from the map, // the local player is removed from the map when there are too many creatures on his tile, // so there is no enough stackpos to the server send him g_dispatcher.addEvent([this] { LocalPlayerPtr localPlayer = g_game.getLocalPlayer(); if(!localPlayer || localPlayer->getPosition() == m_centralPosition) return; TilePtr tile = localPlayer->getTile(); if(tile && tile->hasThing(localPlayer)) return; Position oldPos = localPlayer->getPosition(); Position pos = m_centralPosition; if(oldPos != pos) { if(!localPlayer->isRemoved()) localPlayer->onDisappear(); localPlayer->setPosition(pos); localPlayer->onAppear(); g_logger.debug("forced player position update"); } }); for(const MapViewPtr& mapView : m_mapViews) mapView->onMapCenterChange(centralPosition); } std::vector<CreaturePtr> Map::getSightSpectators(const Position& centerPos, bool multiFloor) { return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left - 1, m_awareRange.right - 2, m_awareRange.top - 1, m_awareRange.bottom - 2); } std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor) { return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left, m_awareRange.right, m_awareRange.top, m_awareRange.bottom); } std::vector<CreaturePtr> Map::getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange) { return getSpectatorsInRangeEx(centerPos, multiFloor, xRange, xRange, yRange, yRange); } std::vector<CreaturePtr> Map::getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange) { int minZRange = 0; int maxZRange = 0; std::vector<CreaturePtr> creatures; if(multiFloor) { minZRange = 0; maxZRange = Otc::MAX_Z; } //TODO: optimize //TODO: get creatures from other floors corretly //TODO: delivery creatures in distance order for(int iz=-minZRange; iz<=maxZRange; ++iz) { for(int iy=-minYRange; iy<=maxYRange; ++iy) { for(int ix=-minXRange; ix<=maxXRange; ++ix) { TilePtr tile = getTile(centerPos.translated(ix,iy,iz)); if(!tile) continue; auto tileCreatures = tile->getCreatures(); creatures.insert(creatures.end(), tileCreatures.rbegin(), tileCreatures.rend()); } } } return creatures; } bool Map::isLookPossible(const Position& pos) { TilePtr tile = getTile(pos); return tile && tile->isLookPossible(); } bool Map::isCovered(const Position& pos, int firstFloor) { // check for tiles on top of the postion Position tilePos = pos; while(tilePos.coveredUp() && tilePos.z >= firstFloor) { TilePtr tile = getTile(tilePos); // the below tile is covered when the above tile has a full ground if(tile && tile->isFullGround()) return true; } return false; } bool Map::isCompletelyCovered(const Position& pos, int firstFloor) { const TilePtr& checkTile = getTile(pos); Position tilePos = pos; while(tilePos.coveredUp() && tilePos.z >= firstFloor) { bool covered = true; bool done = false; // check in 2x2 range tiles that has no transparent pixels for(int x=0;x<2 && !done;++x) { for(int y=0;y<2 && !done;++y) { const TilePtr& tile = getTile(tilePos.translated(-x, -y)); if(!tile || !tile->isFullyOpaque()) { covered = false; done = true; } else if(x==0 && y==0 && (!checkTile || checkTile->isSingleDimension())) { done = true; } } } if(covered) return true; } return false; } bool Map::isAwareOfPosition(const Position& pos) { if(pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor()) return false; Position groundedPos = pos; while(groundedPos.z != m_centralPosition.z) { if(groundedPos.z > m_centralPosition.z) { if(groundedPos.x == 65535 || groundedPos.y == 65535) // When pos == 65535,65535,15 we cant go up to 65536,65536,14 break; groundedPos.coveredUp(); } else { if(groundedPos.x == 0 || groundedPos.y == 0) // When pos == 0,0,0 we cant go down to -1,-1,1 break; groundedPos.coveredDown(); } } return m_centralPosition.isInRange(groundedPos, m_awareRange.left, m_awareRange.right, m_awareRange.top, m_awareRange.bottom); } void Map::setAwareRange(const AwareRange& range) { m_awareRange = range; removeUnawareThings(); } void Map::resetAwareRange() { AwareRange range; range.left = 19; //Change this to = maxClientViewportX range.top = 19; //Change this to = maxClientViewportY range.bottom = range.top+1; range.right = range.left+1; setAwareRange(range); } int Map::getFirstAwareFloor() { if(m_centralPosition.z > Otc::SEA_FLOOR) return m_centralPosition.z-Otc::AWARE_UNDEGROUND_FLOOR_RANGE; else return 0; } int Map::getLastAwareFloor() { if(m_centralPosition.z > Otc::SEA_FLOOR) return std::min<int>(m_centralPosition.z+Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z); else return Otc::SEA_FLOOR; } std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxComplexity, int flags) { // pathfinding using A* search algorithm // as described in http://en.wikipedia.org/wiki/A*_search_algorithm struct Node { Node(const Position& pos) : cost(0), totalCost(0), pos(pos), prev(nullptr), dir(Otc::InvalidDirection) { } float cost; float totalCost; Position pos; Node *prev; Otc::Direction dir; }; struct LessNode : std::binary_function<std::pair<Node*, float>, std::pair<Node*, float>, bool> { bool operator()(std::pair<Node*, float> a, std::pair<Node*, float> b) const { return b.second < a.second; } }; std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> ret; std::vector<Otc::Direction>& dirs = std::get<0>(ret); Otc::PathFindResult& result = std::get<1>(ret); result = Otc::PathFindResultNoWay; if(startPos == goalPos) { result = Otc::PathFindResultSamePosition; return ret; } if(startPos.z != goalPos.z) { result = Otc::PathFindResultImpossible; return ret; } // check the goal pos is walkable if(g_map.isAwareOfPosition(goalPos)) { const TilePtr goalTile = getTile(goalPos); if(!goalTile || !goalTile->isWalkable()) { return ret; } } else { const MinimapTile& goalTile = g_minimap.getTile(goalPos); if(goalTile.hasFlag(MinimapTileNotWalkable)) { return ret; } } std::unordered_map<Position, Node*, PositionHasher> nodes; std::priority_queue<std::pair<Node*, float>, std::vector<std::pair<Node*, float>>, LessNode> searchList; Node *currentNode = new Node(startPos); currentNode->pos = startPos; nodes[startPos] = currentNode; Node *foundNode = nullptr; while(currentNode) { if((int)nodes.size() > maxComplexity) { result = Otc::PathFindResultTooFar; break; } // path found if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost)) foundNode = currentNode; // cost too high if(foundNode && currentNode->totalCost >= foundNode->cost) break; for(int i=-1;i<=1;++i) { for(int j=-1;j<=1;++j) { if(i == 0 && j == 0) continue; bool wasSeen = false; bool hasCreature = false; bool isNotWalkable = true; bool isNotPathable = true; int speed = 100; Position neighborPos = currentNode->pos.translated(i, j); if(g_map.isAwareOfPosition(neighborPos)) { wasSeen = true; if(const TilePtr& tile = getTile(neighborPos)) { hasCreature = tile->hasCreature(); isNotWalkable = !tile->isWalkable(); isNotPathable = !tile->isPathable(); speed = tile->getGroundSpeed(); } } else { const MinimapTile& mtile = g_minimap.getTile(neighborPos); wasSeen = mtile.hasFlag(MinimapTileWasSeen); isNotWalkable = mtile.hasFlag(MinimapTileNotWalkable); isNotPathable = mtile.hasFlag(MinimapTileNotPathable); if(isNotWalkable || isNotPathable) wasSeen = true; speed = mtile.getSpeed(); } float walkFactor = 0; if(neighborPos != goalPos) { if(!(flags & Otc::PathFindAllowNotSeenTiles) && !wasSeen) continue; if(wasSeen) { if(!(flags & Otc::PathFindAllowCreatures) && hasCreature) continue; if(!(flags & Otc::PathFindAllowNonPathable) && isNotPathable) continue; if(!(flags & Otc::PathFindAllowNonWalkable) && isNotWalkable) continue; } } else { if(!(flags & Otc::PathFindAllowNotSeenTiles) && !wasSeen) continue; if(wasSeen) { if(!(flags & Otc::PathFindAllowNonWalkable) && isNotWalkable) continue; } } Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos); if(walkDir >= Otc::NorthEast) walkFactor += 3.0f; else walkFactor += 1.0f; float cost = currentNode->cost + (speed * walkFactor) / 100.0f; Node *neighborNode; if(nodes.find(neighborPos) == nodes.end()) { neighborNode = new Node(neighborPos); nodes[neighborPos] = neighborNode; } else { neighborNode = nodes[neighborPos]; if(neighborNode->cost <= cost) continue; } neighborNode->prev = currentNode; neighborNode->cost = cost; neighborNode->totalCost = neighborNode->cost + neighborPos.distance(goalPos); neighborNode->dir = walkDir; searchList.push(std::make_pair(neighborNode, neighborNode->totalCost)); } } if(!searchList.empty()) { currentNode = searchList.top().first; searchList.pop(); } else currentNode = nullptr; } if(foundNode) { currentNode = foundNode; while(currentNode) { dirs.push_back(currentNode->dir); currentNode = currentNode->prev; } dirs.pop_back(); std::reverse(dirs.begin(), dirs.end()); result = Otc::PathFindResultOk; } for(auto it : nodes) delete it.second; return ret; }
protocol.cpp
/** * The Forgotten Server - a free and open-source MMORPG server emulator * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com> * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "otpch.h" #include <boost/range/adaptor/reversed.hpp> #include "protocolgame.h" #include "outputmessage.h" #include "player.h" #include "configmanager.h" #include "actions.h" #include "game.h" #include "iologindata.h" #include "iomarket.h" #include "waitlist.h" #include "ban.h" #include "scheduler.h" extern ConfigManager g_config; extern Actions actions; extern CreatureEvents* g_creatureEvents; extern Chat* g_chat; void ProtocolGame::release() { //dispatcher thread if (player && player->client == shared_from_this()) { player->client.reset(); player->decrementReferenceCounter(); player = nullptr; } OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this()); Protocol::release(); } void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) { //dispatcher thread Player* foundPlayer = g_game.getPlayerByName(name); if (!foundPlayer || g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { player = new Player(getThis()); player->setName(name); player->incrementReferenceCounter(); player->setID(); if (!IOLoginData::preloadPlayer(player, name)) { disconnectClient("Your character could not be loaded."); return; } if (IOBan::isPlayerNamelocked(player->getGUID())) { disconnectClient("Your character has been namelocked."); return; } if (g_game.getGameState() == GAME_STATE_CLOSING && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("The game is just going down.\nPlease try again later."); return; } if (g_game.getGameState() == GAME_STATE_CLOSED && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("Server is currently closed.\nPlease try again later."); return; } if (g_config.getBoolean(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER && g_game.getPlayerByAccount(player->getAccount())) { disconnectClient("You may only login with one character\nof your account at the same time."); return; } if (!player->hasFlag(PlayerFlag_CannotBeBanned)) { BanInfo banInfo; if (IOBan::isAccountBanned(accountId, banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; if (banInfo.expiresAt > 0) { ss << "Your account has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; } else { ss << "Your account has been permanently banned by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; } disconnectClient(ss.str()); return; } } WaitingList& waitingList = WaitingList::getInstance(); if (!waitingList.clientLogin(player)) { uint32_t currentSlot = waitingList.getClientSlot(player); uint32_t retryTime = WaitingList::getTime(currentSlot); std::ostringstream ss; ss << "Too many players online.\nYou are at place " << currentSlot << " on the waiting list."; auto output = OutputMessagePool::getOutputMessage(); output->addByte(0x16); output->addString(ss.str()); output->addByte(retryTime); send(output); disconnect(); return; } if (!IOLoginData::loadPlayerById(player, player->getGUID())) { disconnectClient("Your character could not be loaded."); return; } player->setOperatingSystem(operatingSystem); if (!g_game.placeCreature(player, player->getLoginPosition())) { if (!g_game.placeCreature(player, player->getTemplePosition(), false, true)) { disconnectClient("Temple position is wrong. Contact the administrator."); return; } } if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { player->registerCreatureEvent("ExtendedOpcode"); } player->lastIP = player->getIP(); player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1); acceptPackets = true; } else { if (eventConnect != 0 || !g_config.getBoolean(ConfigManager::REPLACE_KICK_ON_LOGIN)) { //Already trying to connect disconnectClient("You are already logged in."); return; } if (foundPlayer->client) { foundPlayer->disconnect(); foundPlayer->isConnecting = true; eventConnect = g_scheduler.addEvent(createSchedulerTask(1000, std::bind(&ProtocolGame::connect, getThis(), foundPlayer->getID(), operatingSystem))); } else { connect(foundPlayer->getID(), operatingSystem); } } OutputMessagePool::getInstance().addProtocolToAutosend(shared_from_this()); } void ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem) { eventConnect = 0; Player* foundPlayer = g_game.getPlayerByID(playerId); if (!foundPlayer || foundPlayer->client) { disconnectClient("You are already logged in."); return; } if (isConnectionExpired()) { //ProtocolGame::release() has been called at this point and the Connection object //no longer exists, so we return to prevent leakage of the Player. return; } player = foundPlayer; player->incrementReferenceCounter(); g_chat->removeUserFromAllChannels(*player); player->clearModalWindows(); player->setOperatingSystem(operatingSystem); player->isConnecting = false; player->client = getThis(); sendAddCreature(player, player->getPosition(), 0, false); player->lastIP = player->getIP(); player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1); acceptPackets = true; } void ProtocolGame::logout(bool displayEffect, bool forced) { //dispatcher thread if (!player) { return; } if (!player->isRemoved()) { if (!forced) { if (!player->isAccessPlayer()) { if (player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) { player->sendCancelMessage(RETURNVALUE_YOUCANNOTLOGOUTHERE); return; } if (!player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) { player->sendCancelMessage(RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT); return; } } //scripting event - onLogout if (!g_creatureEvents->playerLogout(player)) { //Let the script handle the error message return; } } if (displayEffect && player->getHealth() > 0) { g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF); } } disconnect(); g_game.removeCreature(player); } void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { disconnect(); return; } OperatingSystem_t operatingSystem = static_cast<OperatingSystem_t>(msg.get<uint16_t>()); version = msg.get<uint16_t>(); msg.skipBytes(7); // U32 client version, U8 client type, U16 dat revision if (!Protocol::RSA_decrypt(msg)) { disconnect(); return; } xtea::key key; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(std::move(key)); if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { NetworkMessage opcodeMessage; opcodeMessage.addByte(0x32); opcodeMessage.addByte(0x00); opcodeMessage.add<uint16_t>(0x00); writeToOutputBuffer(opcodeMessage); } msg.skipBytes(1); // gamemaster flag std::string sessionKey = msg.getString(); auto sessionArgs = explodeString(sessionKey, "\n", 4); if (sessionArgs.size() != 4) { disconnect(); return; } std::string& accountName = sessionArgs[0]; std::string& password = sessionArgs[1]; std::string& token = sessionArgs[2]; uint32_t tokenTime = 0; try { tokenTime = std::stoul(sessionArgs[3]); } catch (const std::invalid_argument&) { disconnectClient("Malformed token packet."); return; } catch (const std::out_of_range&) { disconnectClient("Token time is too long."); return; } if (accountName.empty()) { disconnectClient("You must enter your account name."); return; } std::string characterName = msg.getString(); uint32_t timeStamp = msg.get<uint32_t>(); uint8_t randNumber = msg.getByte(); if (challengeTimestamp != timeStamp || challengeRandom != randNumber) { disconnect(); return; } if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { std::ostringstream ss; ss << "Only clients with protocol " << CLIENT_VERSION_STR << " allowed!"; disconnectClient(ss.str()); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient("Gameworld is under maintenance. Please re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(ss.str()); return; } uint32_t accountId = IOLoginData::gameworldAuthentication(accountName, password, characterName, token, tokenTime); if (accountId == 0) { disconnectClient("Account name or password is not correct."); return; } g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); } void ProtocolGame::onConnect() { auto output = OutputMessagePool::getOutputMessage(); static std::random_device rd; static std::ranlux24 generator(rd()); static std::uniform_int_distribution<uint16_t> randNumber(0x00, 0xFF); // Skip checksum output->skipBytes(sizeof(uint32_t)); // Packet length & type output->add<uint16_t>(0x0006); output->addByte(0x1F); // Add timestamp & random number challengeTimestamp = static_cast<uint32_t>(time(nullptr)); output->add<uint32_t>(challengeTimestamp); challengeRandom = randNumber(generator); output->addByte(challengeRandom); // Go back and write checksum output->skipBytes(-12); output->add<uint32_t>(adlerChecksum(output->getOutputBuffer() + sizeof(uint32_t), 8)); send(output); } void ProtocolGame::disconnectClient(const std::string& message) const { auto output = OutputMessagePool::getOutputMessage(); output->addByte(0x14); output->addString(message); send(output); disconnect(); } void ProtocolGame::writeToOutputBuffer(const NetworkMessage& msg) { auto out = getOutputBuffer(msg.getLength()); out->append(msg); } void ProtocolGame::parsePacket(NetworkMessage& msg) { if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) { return; } uint8_t recvbyte = msg.getByte(); if (!player) { if (recvbyte == 0x0F) { disconnect(); } return; } //a dead player can not performs actions if (player->isRemoved() || player->getHealth() <= 0) { if (recvbyte == 0x0F) { disconnect(); return; } if (recvbyte != 0x14) { return; } } switch (recvbyte) { case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break; case 0x1D: addGameTask(&Game::playerReceivePingBack, player->getID()); break; case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break; case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode case 0x64: parseAutoWalk(msg); break; case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break; case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break; case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break; case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break; case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break; case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break; case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break; case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break; case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break; case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break; case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break; case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break; case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break; case 0x77: parseEquipObject(msg); break; case 0x78: parseThrow(msg); break; case 0x79: parseLookInShop(msg); break; case 0x7A: parsePlayerPurchase(msg); break; case 0x7B: parsePlayerSale(msg); break; case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break; case 0x7D: parseRequestTrade(msg); break; case 0x7E: parseLookInTrade(msg); break; case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break; case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break; case 0x82: parseUseItem(msg); break; case 0x83: parseUseItemEx(msg); break; case 0x84: parseUseWithCreature(msg); break; case 0x85: parseRotateItem(msg); break; case 0x87: parseCloseContainer(msg); break; case 0x88: parseUpArrowContainer(msg); break; case 0x89: parseTextWindow(msg); break; case 0x8A: parseHouseWindow(msg); break; case 0x8C: parseLookAt(msg); break; case 0x8D: parseLookInBattleList(msg); break; case 0x8E: /* join aggression */ break; case 0x96: parseSay(msg); break; case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break; case 0x98: parseOpenChannel(msg); break; case 0x99: parseCloseChannel(msg); break; case 0x9A: parseOpenPrivateChannel(msg); break; case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break; case 0xA0: parseFightModes(msg); break; case 0xA1: parseAttack(msg); break; case 0xA2: parseFollow(msg); break; case 0xA3: parseInviteToParty(msg); break; case 0xA4: parseJoinParty(msg); break; case 0xA5: parseRevokePartyInvite(msg); break; case 0xA6: parsePassPartyLeadership(msg); break; case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break; case 0xA8: parseEnableSharedPartyExperience(msg); break; case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break; case 0xAB: parseChannelInvite(msg); break; case 0xAC: parseChannelExclude(msg); break; case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break; case 0xC9: /* update tile */ break; case 0xCA: parseUpdateContainer(msg); break; case 0xCB: parseBrowseField(msg); break; case 0xCC: parseSeekInContainer(msg); break; case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break; case 0xD3: parseSetOutfit(msg); break; case 0xD4: parseToggleMount(msg); break; case 0xDC: parseAddVip(msg); break; case 0xDD: parseRemoveVip(msg); break; case 0xDE: parseEditVip(msg); break; case 0xE6: parseBugReport(msg); break; case 0xE7: /* thank you */ break; case 0xE8: parseDebugAssert(msg); break; case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break; case 0xF1: parseQuestLine(msg); break; case 0xF2: parseRuleViolationReport(msg); break; case 0xF3: /* get object info */ break; case 0xF4: parseMarketLeave(); break; case 0xF5: parseMarketBrowse(msg); break; case 0xF6: parseMarketCreateOffer(msg); break; case 0xF7: parseMarketCancelOffer(msg); break; case 0xF8: parseMarketAcceptOffer(msg); break; case 0xF9: parseModalWindowAnswer(msg); break; default: // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl; break; } if (msg.isOverrun()) { disconnect(); } } void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg) { msg.add<uint16_t>(0x00); //environmental effects int32_t count; Item* ground = tile->getGround(); if (ground) { msg.addItem(ground); count = 1; } else { count = 0; } const TileItemVector* items = tile->getItemList(); if (items) { for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) { msg.addItem(*it); count++; if (count == 9 && tile->getPosition() == player->getPosition()) { break; } else if (count == 10) { return; } } } const CreatureVector* creatures = tile->getCreatures(); if (creatures) { bool playerAdded = false; for (const Creature* creature : boost::adaptors::reverse(*creatures)) { if (!player->canSeeCreature(creature)) { continue; } if (tile->getPosition() == player->getPosition() && count == 9 && !playerAdded) { creature = player; } if (creature->getID() == player->getID()) { playerAdded = true; } bool known; uint32_t removedKnown; checkCreatureAsKnown(creature->getID(), known, removedKnown); AddCreature(msg, creature, known, removedKnown); if (++count == 10) { return; } } } if (items) { for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) { msg.addItem(*it); if (++count == 10) { return; } } } } void ProtocolGame::GetMapDescription(int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, NetworkMessage& msg) { int32_t skip = -1; int32_t startz, endz, zstep; if (z > 7) { startz = z - 2; endz = std::min<int32_t>(MAP_MAX_LAYERS - 1, z + 2); zstep = 1; } else { startz = 7; endz = 0; zstep = -1; } for (int32_t nz = startz; nz != endz + zstep; nz += zstep) { GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip); } if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } } void ProtocolGame::GetFloorDescription(NetworkMessage& msg, int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, int32_t offset, int32_t& skip) { for (int32_t nx = 0; nx < width; nx++) { for (int32_t ny = 0; ny < height; ny++) { Tile* tile = g_game.map.getTile(x + nx + offset, y + ny + offset, z); if (tile) { if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } skip = 0; GetTileDescription(tile, msg); } else if (skip == 0xFE) { msg.addByte(0xFF); msg.addByte(0xFF); skip = -1; } else { ++skip; } } } } void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown) { auto result = knownCreatureSet.insert(id); if (!result.second) { known = true; return; } known = false; if (knownCreatureSet.size() > 1300) { // Look for a creature to remove for (auto it = knownCreatureSet.begin(), end = knownCreatureSet.end(); it != end; ++it) { Creature* creature = g_game.getCreatureByID(*it); if (!canSee(creature)) { removedKnown = *it; knownCreatureSet.erase(it); return; } } // Bad situation. Let's just remove anyone. auto it = knownCreatureSet.begin(); if (*it == id) { ++it; } removedKnown = *it; knownCreatureSet.erase(it); } else { removedKnown = 0; } } bool ProtocolGame::canSee(const Creature* c) const { if (!c || !player || c->isRemoved()) { return false; } if (!player->canSeeCreature(c)) { return false; } return canSee(c->getPosition()); } bool ProtocolGame::canSee(const Position& pos) const { return canSee(pos.x, pos.y, pos.z); } bool ProtocolGame::canSee(int32_t x, int32_t y, int32_t z) const { if (!player) { return false; } const Position& myPos = player->getPosition(); if (myPos.z <= 7) { //we are on ground level or above (7 -> 0) //view is from 7 -> 0 if (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.getZ() - z) > 2) { return false; } } //negative offset means that the action taken place is on a lower floor than ourself int32_t offsetz = myPos.getZ() - z; if ((x >= myPos.getX() - Map::maxClientViewportX + offsetz) && (x <= myPos.getX() + (Map::maxClientViewportX+1) + offsetz) && (y >= myPos.getY() - Map::maxClientViewportY + offsetz) && (y <= myPos.getY() + (Map::maxClientViewportY+1) + offsetz)) { return true; } return false; } // Parse methods void ProtocolGame::parseChannelInvite(NetworkMessage& msg) { const std::string name = msg.getString(); addGameTask(&Game::playerChannelInvite, player->getID(), name); } void ProtocolGame::parseChannelExclude(NetworkMessage& msg) { const std::string name = msg.getString(); addGameTask(&Game::playerChannelExclude, player->getID(), name); } void ProtocolGame::parseOpenChannel(NetworkMessage& msg) { uint16_t channelId = msg.get<uint16_t>(); addGameTask(&Game::playerOpenChannel, player->getID(), channelId); } void ProtocolGame::parseCloseChannel(NetworkMessage& msg) { uint16_t channelId = msg.get<uint16_t>(); addGameTask(&Game::playerCloseChannel, player->getID(), channelId); } void ProtocolGame::parseOpenPrivateChannel(NetworkMessage& msg) { const std::string receiver = msg.getString(); addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver); } void ProtocolGame::parseAutoWalk(NetworkMessage& msg) { uint8_t numdirs = msg.getByte(); if (numdirs == 0 || (msg.getBufferPosition() + numdirs) != (msg.getLength() + 8)) { return; } msg.skipBytes(numdirs); std::forward_list<Direction> path; for (uint8_t i = 0; i < numdirs; ++i) { uint8_t rawdir = msg.getPreviousByte(); switch (rawdir) { case 1: path.push_front(DIRECTION_EAST); break; case 2: path.push_front(DIRECTION_NORTHEAST); break; case 3: path.push_front(DIRECTION_NORTH); break; case 4: path.push_front(DIRECTION_NORTHWEST); break; case 5: path.push_front(DIRECTION_WEST); break; case 6: path.push_front(DIRECTION_SOUTHWEST); break; case 7: path.push_front(DIRECTION_SOUTH); break; case 8: path.push_front(DIRECTION_SOUTHEAST); break; default: break; } } if (path.empty()) { return; } addGameTask(&Game::playerAutoWalk, player->getID(), path); } void ProtocolGame::parseSetOutfit(NetworkMessage& msg) { Outfit_t newOutfit; newOutfit.lookType = msg.get<uint16_t>(); newOutfit.lookHead = msg.getByte(); newOutfit.lookBody = msg.getByte(); newOutfit.lookLegs = msg.getByte(); newOutfit.lookFeet = msg.getByte(); newOutfit.lookAddons = msg.getByte(); newOutfit.lookMount = msg.get<uint16_t>(); addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit); } void ProtocolGame::parseToggleMount(NetworkMessage& msg) { bool mount = msg.getByte() != 0; addGameTask(&Game::playerToggleMount, player->getID(), mount); } void ProtocolGame::parseUseItem(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); uint8_t index = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId); } void ProtocolGame::parseUseItemEx(NetworkMessage& msg) { Position fromPos = msg.getPosition(); uint16_t fromSpriteId = msg.get<uint16_t>(); uint8_t fromStackPos = msg.getByte(); Position toPos = msg.getPosition(); uint16_t toSpriteId = msg.get<uint16_t>(); uint8_t toStackPos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(), fromPos, fromStackPos, fromSpriteId, toPos, toStackPos, toSpriteId); } void ProtocolGame::parseUseWithCreature(NetworkMessage& msg) { Position fromPos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t fromStackPos = msg.getByte(); uint32_t creatureId = msg.get<uint32_t>(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseWithCreature, player->getID(), fromPos, fromStackPos, creatureId, spriteId); } void ProtocolGame::parseCloseContainer(NetworkMessage& msg) { uint8_t cid = msg.getByte(); addGameTask(&Game::playerCloseContainer, player->getID(), cid); } void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg) { uint8_t cid = msg.getByte(); addGameTask(&Game::playerMoveUpContainer, player->getID(), cid); } void ProtocolGame::parseUpdateContainer(NetworkMessage& msg) { uint8_t cid = msg.getByte(); addGameTask(&Game::playerUpdateContainer, player->getID(), cid); } void ProtocolGame::parseThrow(NetworkMessage& msg) { Position fromPos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t fromStackpos = msg.getByte(); Position toPos = msg.getPosition(); uint8_t count = msg.getByte(); if (toPos != fromPos) { addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerMoveThing, player->getID(), fromPos, spriteId, fromStackpos, toPos, count); } } void ProtocolGame::parseLookAt(NetworkMessage& msg) { Position pos = msg.getPosition(); msg.skipBytes(2); // spriteId uint8_t stackpos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, stackpos); } void ProtocolGame::parseLookInBattleList(NetworkMessage& msg) { uint32_t creatureId = msg.get<uint32_t>(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInBattleList, player->getID(), creatureId); } void ProtocolGame::parseSay(NetworkMessage& msg) { std::string receiver; uint16_t channelId; SpeakClasses type = static_cast<SpeakClasses>(msg.getByte()); switch (type) { case TALKTYPE_PRIVATE_TO: case TALKTYPE_PRIVATE_RED_TO: receiver = msg.getString(); channelId = 0; break; case TALKTYPE_CHANNEL_Y: case TALKTYPE_CHANNEL_R1: channelId = msg.get<uint16_t>(); break; default: channelId = 0; break; } const std::string text = msg.getString(); if (text.length() > 255) { return; } addGameTask(&Game::playerSay, player->getID(), channelId, type, receiver, text); } void ProtocolGame::parseFightModes(NetworkMessage& msg) { uint8_t rawFightMode = msg.getByte(); // 1 - offensive, 2 - balanced, 3 - defensive uint8_t rawChaseMode = msg.getByte(); // 0 - stand while fightning, 1 - chase opponent uint8_t rawSecureMode = msg.getByte(); // 0 - can't attack unmarked, 1 - can attack unmarked // uint8_t rawPvpMode = msg.getByte(); // pvp mode introduced in 10.0 fightMode_t fightMode; if (rawFightMode == 1) { fightMode = FIGHTMODE_ATTACK; } else if (rawFightMode == 2) { fightMode = FIGHTMODE_BALANCED; } else { fightMode = FIGHTMODE_DEFENSE; } addGameTask(&Game::playerSetFightModes, player->getID(), fightMode, rawChaseMode != 0, rawSecureMode != 0); } void ProtocolGame::parseAttack(NetworkMessage& msg) { uint32_t creatureId = msg.get<uint32_t>(); // msg.get<uint32_t>(); creatureId (same as above) addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId); } void ProtocolGame::parseFollow(NetworkMessage& msg) { uint32_t creatureId = msg.get<uint32_t>(); // msg.get<uint32_t>(); creatureId (same as above) addGameTask(&Game::playerFollowCreature, player->getID(), creatureId); } void ProtocolGame::parseEquipObject(NetworkMessage& msg) { uint16_t spriteId = msg.get<uint16_t>(); // msg.get<uint8_t>(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerEquipItem, player->getID(), spriteId); } void ProtocolGame::parseTextWindow(NetworkMessage& msg) { uint32_t windowTextId = msg.get<uint32_t>(); const std::string newText = msg.getString(); addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText); } void ProtocolGame::parseHouseWindow(NetworkMessage& msg) { uint8_t doorId = msg.getByte(); uint32_t id = msg.get<uint32_t>(); const std::string text = msg.getString(); addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text); } void ProtocolGame::parseLookInShop(NetworkMessage& msg) { uint16_t id = msg.get<uint16_t>(); uint8_t count = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count); } void ProtocolGame::parsePlayerPurchase(NetworkMessage& msg) { uint16_t id = msg.get<uint16_t>(); uint8_t count = msg.getByte(); uint8_t amount = msg.getByte(); bool ignoreCap = msg.getByte() != 0; bool inBackpacks = msg.getByte() != 0; addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks); } void ProtocolGame::parsePlayerSale(NetworkMessage& msg) { uint16_t id = msg.get<uint16_t>(); uint8_t count = msg.getByte(); uint8_t amount = msg.getByte(); bool ignoreEquipped = msg.getByte() != 0; addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount, ignoreEquipped); } void ProtocolGame::parseRequestTrade(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); uint32_t playerId = msg.get<uint32_t>(); addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId); } void ProtocolGame::parseLookInTrade(NetworkMessage& msg) { bool counterOffer = (msg.getByte() == 0x01); uint8_t index = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counterOffer, index); } void ProtocolGame::parseAddVip(NetworkMessage& msg) { const std::string name = msg.getString(); addGameTask(&Game::playerRequestAddVip, player->getID(), name); } void ProtocolGame::parseRemoveVip(NetworkMessage& msg) { uint32_t guid = msg.get<uint32_t>(); addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid); } void ProtocolGame::parseEditVip(NetworkMessage& msg) { uint32_t guid = msg.get<uint32_t>(); const std::string description = msg.getString(); uint32_t icon = std::min<uint32_t>(10, msg.get<uint32_t>()); // 10 is max icon in 9.63 bool notify = msg.getByte() != 0; addGameTask(&Game::playerRequestEditVip, player->getID(), guid, description, icon, notify); } void ProtocolGame::parseRotateItem(NetworkMessage& msg) { Position pos = msg.getPosition(); uint16_t spriteId = msg.get<uint16_t>(); uint8_t stackpos = msg.getByte(); addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId); } void ProtocolGame::parseRuleViolationReport(NetworkMessage& msg) { uint8_t reportType = msg.getByte(); uint8_t reportReason = msg.getByte(); const std::string& targetName = msg.getString(); const std::string& comment = msg.getString(); std::string translation; if (reportType == REPORT_TYPE_NAME) { translation = msg.getString(); } else if (reportType == REPORT_TYPE_STATEMENT) { translation = msg.getString(); msg.get<uint32_t>(); // statement id, used to get whatever player have said, we don't log that. } addGameTask(&Game::playerReportRuleViolation, player->getID(), targetName, reportType, reportReason, comment, translation); } void ProtocolGame::parseBugReport(NetworkMessage& msg) { uint8_t category = msg.getByte(); std::string message = msg.getString(); Position position; if (category == BUG_CATEGORY_MAP) { position = msg.getPosition(); } addGameTask(&Game::playerReportBug, player->getID(), message, position, category); } void ProtocolGame::parseDebugAssert(NetworkMessage& msg) { if (debugAssertSent) { return; } debugAssertSent = true; std::string assertLine = msg.getString(); std::string date = msg.getString(); std::string description = msg.getString(); std::string comment = msg.getString(); addGameTask(&Game::playerDebugAssert, player->getID(), assertLine, date, description, comment); } void ProtocolGame::parseInviteToParty(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerInviteToParty, player->getID(), targetId); } void ProtocolGame::parseJoinParty(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerJoinParty, player->getID(), targetId); } void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId); } void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg) { uint32_t targetId = msg.get<uint32_t>(); addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId); } void ProtocolGame::parseEnableSharedPartyExperience(NetworkMessage& msg) { bool sharedExpActive = msg.getByte() == 1; addGameTask(&Game::playerEnableSharedPartyExperience, player->getID(), sharedExpActive); } void ProtocolGame::parseQuestLine(NetworkMessage& msg) { uint16_t questId = msg.get<uint16_t>(); addGameTask(&Game::playerShowQuestLine, player->getID(), questId); } void ProtocolGame::parseMarketLeave() { addGameTask(&Game::playerLeaveMarket, player->getID()); } void ProtocolGame::parseMarketBrowse(NetworkMessage& msg) { uint16_t browseId = msg.get<uint16_t>(); if (browseId == MARKETREQUEST_OWN_OFFERS) { addGameTask(&Game::playerBrowseMarketOwnOffers, player->getID()); } else if (browseId == MARKETREQUEST_OWN_HISTORY) { addGameTask(&Game::playerBrowseMarketOwnHistory, player->getID()); } else { addGameTask(&Game::playerBrowseMarket, player->getID(), browseId); } } void ProtocolGame::parseMarketCreateOffer(NetworkMessage& msg) { uint8_t type = msg.getByte(); uint16_t spriteId = msg.get<uint16_t>(); uint16_t amount = msg.get<uint16_t>(); uint32_t price = msg.get<uint32_t>(); bool anonymous = (msg.getByte() != 0); addGameTask(&Game::playerCreateMarketOffer, player->getID(), type, spriteId, amount, price, anonymous); } void ProtocolGame::parseMarketCancelOffer(NetworkMessage& msg) { uint32_t timestamp = msg.get<uint32_t>(); uint16_t counter = msg.get<uint16_t>(); addGameTask(&Game::playerCancelMarketOffer, player->getID(), timestamp, counter); } void ProtocolGame::parseMarketAcceptOffer(NetworkMessage& msg) { uint32_t timestamp = msg.get<uint32_t>(); uint16_t counter = msg.get<uint16_t>(); uint16_t amount = msg.get<uint16_t>(); addGameTask(&Game::playerAcceptMarketOffer, player->getID(), timestamp, counter, amount); } void ProtocolGame::parseModalWindowAnswer(NetworkMessage& msg) { uint32_t id = msg.get<uint32_t>(); uint8_t button = msg.getByte(); uint8_t choice = msg.getByte(); addGameTask(&Game::playerAnswerModalWindow, player->getID(), id, button, choice); } void ProtocolGame::parseBrowseField(NetworkMessage& msg) { const Position& pos = msg.getPosition(); addGameTask(&Game::playerBrowseField, player->getID(), pos); } void ProtocolGame::parseSeekInContainer(NetworkMessage& msg) { uint8_t containerId = msg.getByte(); uint16_t index = msg.get<uint16_t>(); addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index); } // Send methods void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver) { NetworkMessage msg; msg.addByte(0xAD); msg.addString(receiver); writeToOutputBuffer(msg); } void ProtocolGame::sendChannelEvent(uint16_t channelId, const std::string& playerName, ChannelEvent_t channelEvent) { NetworkMessage msg; msg.addByte(0xF3); msg.add<uint16_t>(channelId); msg.addString(playerName); msg.addByte(channelEvent); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x8E); msg.add<uint32_t>(creature->getID()); AddOutfit(msg, outfit); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureLight(const Creature* creature) { if (!canSee(creature)) { return; } NetworkMessage msg; AddCreatureLight(msg, creature); writeToOutputBuffer(msg); } void ProtocolGame::sendWorldLight(LightInfo lightInfo) { NetworkMessage msg; AddWorldLight(msg, lightInfo); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureWalkthrough(const Creature* creature, bool walkthrough) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x92); msg.add<uint32_t>(creature->getID()); msg.addByte(walkthrough ? 0x00 : 0x01); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureShield(const Creature* creature) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x91); msg.add<uint32_t>(creature->getID()); msg.addByte(player->getPartyShield(creature->getPlayer())); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureSkull(const Creature* creature) { if (g_game.getWorldType() != WORLD_TYPE_PVP) { return; } if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x90); msg.add<uint32_t>(creature->getID()); msg.addByte(player->getSkullClient(creature)); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureType(uint32_t creatureId, uint8_t creatureType) { NetworkMessage msg; msg.addByte(0x95); msg.add<uint32_t>(creatureId); msg.addByte(creatureType); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureHelpers(uint32_t creatureId, uint16_t helpers) { NetworkMessage msg; msg.addByte(0x94); msg.add<uint32_t>(creatureId); msg.add<uint16_t>(helpers); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x93); msg.add<uint32_t>(creature->getID()); msg.addByte(0x01); msg.addByte(color); writeToOutputBuffer(msg); } void ProtocolGame::sendTutorial(uint8_t tutorialId) { NetworkMessage msg; msg.addByte(0xDC); msg.addByte(tutorialId); writeToOutputBuffer(msg); } void ProtocolGame::sendAddMarker(const Position& pos, uint8_t markType, const std::string& desc) { NetworkMessage msg; msg.addByte(0xDD); msg.addPosition(pos); msg.addByte(markType); msg.addString(desc); writeToOutputBuffer(msg); } void ProtocolGame::sendReLoginWindow(uint8_t unfairFightReduction) { NetworkMessage msg; msg.addByte(0x28); msg.addByte(0x00); msg.addByte(unfairFightReduction); writeToOutputBuffer(msg); } void ProtocolGame::sendStats() { NetworkMessage msg; AddPlayerStats(msg); writeToOutputBuffer(msg); } void ProtocolGame::sendBasicData() { NetworkMessage msg; msg.addByte(0x9F); if (player->isPremium()) { msg.addByte(1); msg.add<uint32_t>(time(nullptr) + (player->premiumDays * 86400)); } else { msg.addByte(0); msg.add<uint32_t>(0); } msg.addByte(player->getVocation()->getClientId()); msg.add<uint16_t>(0xFF); // number of known spells for (uint8_t spellId = 0x00; spellId < 0xFF; spellId++) { msg.addByte(spellId); } writeToOutputBuffer(msg); } void ProtocolGame::sendTextMessage(const TextMessage& message) { NetworkMessage msg; msg.addByte(0xB4); msg.addByte(message.type); switch (message.type) { case MESSAGE_DAMAGE_DEALT: case MESSAGE_DAMAGE_RECEIVED: case MESSAGE_DAMAGE_OTHERS: { msg.addPosition(message.position); msg.add<uint32_t>(message.primary.value); msg.addByte(message.primary.color); msg.add<uint32_t>(message.secondary.value); msg.addByte(message.secondary.color); break; } case MESSAGE_HEALED: case MESSAGE_HEALED_OTHERS: case MESSAGE_EXPERIENCE: case MESSAGE_EXPERIENCE_OTHERS: { msg.addPosition(message.position); msg.add<uint32_t>(message.primary.value); msg.addByte(message.primary.color); break; } case MESSAGE_GUILD: case MESSAGE_PARTY_MANAGEMENT: case MESSAGE_PARTY: msg.add<uint16_t>(message.channelId); break; default: { break; } } msg.addString(message.text); writeToOutputBuffer(msg); } void ProtocolGame::sendClosePrivate(uint16_t channelId) { NetworkMessage msg; msg.addByte(0xB3); msg.add<uint16_t>(channelId); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName) { NetworkMessage msg; msg.addByte(0xB2); msg.add<uint16_t>(channelId); msg.addString(channelName); msg.add<uint16_t>(0x01); msg.addString(player->getName()); msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); } void ProtocolGame::sendChannelsDialog() { NetworkMessage msg; msg.addByte(0xAB); const ChannelList& list = g_chat->getChannelList(*player); msg.addByte(list.size()); for (ChatChannel* channel : list) { msg.add<uint16_t>(channel->getId()); msg.addString(channel->getName()); } writeToOutputBuffer(msg); } void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName, const UsersMap* channelUsers, const InvitedMap* invitedUsers) { NetworkMessage msg; msg.addByte(0xAC); msg.add<uint16_t>(channelId); msg.addString(channelName); if (channelUsers) { msg.add<uint16_t>(channelUsers->size()); for (const auto& it : *channelUsers) { msg.addString(it.second->getName()); } } else { msg.add<uint16_t>(0x00); } if (invitedUsers) { msg.add<uint16_t>(invitedUsers->size()); for (const auto& it : *invitedUsers) { msg.addString(it.second->getName()); } } else { msg.add<uint16_t>(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendChannelMessage(const std::string& author, const std::string& text, SpeakClasses type, uint16_t channel) { NetworkMessage msg; msg.addByte(0xAA); msg.add<uint32_t>(0x00); msg.addString(author); msg.add<uint16_t>(0x00); msg.addByte(type); msg.add<uint16_t>(channel); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendIcons(uint16_t icons) { NetworkMessage msg; msg.addByte(0xA2); msg.add<uint16_t>(icons); writeToOutputBuffer(msg); } void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool hasParent, uint16_t firstIndex) { NetworkMessage msg; msg.addByte(0x6E); msg.addByte(cid); if (container->getID() == ITEM_BROWSEFIELD) { msg.addItem(1987, 1); msg.addString("Browse Field"); } else { msg.addItem(container); msg.addString(container->getName()); } msg.addByte(container->capacity()); msg.addByte(hasParent ? 0x01 : 0x00); msg.addByte(container->isUnlocked() ? 0x01 : 0x00); // Drag and drop msg.addByte(container->hasPagination() ? 0x01 : 0x00); // Pagination uint32_t containerSize = container->size(); msg.add<uint16_t>(containerSize); msg.add<uint16_t>(firstIndex); if (firstIndex < containerSize) { uint8_t itemsToSend = std::min<uint32_t>(std::min<uint32_t>(container->capacity(), containerSize - firstIndex), std::numeric_limits<uint8_t>::max()); msg.addByte(itemsToSend); for (auto it = container->getItemList().begin() + firstIndex, end = it + itemsToSend; it != end; ++it) { msg.addItem(*it); } } else { msg.addByte(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendShop(Npc* npc, const ShopInfoList& itemList) { NetworkMessage msg; msg.addByte(0x7A); msg.addString(npc->getName()); uint16_t itemsToSend = std::min<size_t>(itemList.size(), std::numeric_limits<uint16_t>::max()); msg.add<uint16_t>(itemsToSend); uint16_t i = 0; for (auto it = itemList.begin(); i < itemsToSend; ++it, ++i) { AddShopItem(msg, *it); } writeToOutputBuffer(msg); } void ProtocolGame::sendCloseShop() { NetworkMessage msg; msg.addByte(0x7C); writeToOutputBuffer(msg); } void ProtocolGame::sendSaleItemList(const std::list<ShopInfo>& shop) { NetworkMessage msg; msg.addByte(0x7B); msg.add<uint64_t>(player->getMoney() + player->getBankBalance()); std::map<uint16_t, uint32_t> saleMap; if (shop.size() <= 5) { // For very small shops it's not worth it to create the complete map for (const ShopInfo& shopInfo : shop) { if (shopInfo.sellPrice == 0) { continue; } int8_t subtype = -1; const ItemType& itemType = Item::items[shopInfo.itemId]; if (itemType.hasSubType() && !itemType.stackable) { subtype = (shopInfo.subType == 0 ? -1 : shopInfo.subType); } uint32_t count = player->getItemTypeCount(shopInfo.itemId, subtype); if (count > 0) { saleMap[shopInfo.itemId] = count; } } } else { // Large shop, it's better to get a cached map of all item counts and use it // We need a temporary map since the finished map should only contain items // available in the shop std::map<uint32_t, uint32_t> tempSaleMap; player->getAllItemTypeCount(tempSaleMap); // We must still check manually for the special items that require subtype matches // (That is, fluids such as potions etc., actually these items are very few since // health potions now use their own ID) for (const ShopInfo& shopInfo : shop) { if (shopInfo.sellPrice == 0) { continue; } int8_t subtype = -1; const ItemType& itemType = Item::items[shopInfo.itemId]; if (itemType.hasSubType() && !itemType.stackable) { subtype = (shopInfo.subType == 0 ? -1 : shopInfo.subType); } if (subtype != -1) { uint32_t count; if (!itemType.isFluidContainer() && !itemType.isSplash()) { count = player->getItemTypeCount(shopInfo.itemId, subtype); // This shop item requires extra checks } else { count = subtype; } if (count > 0) { saleMap[shopInfo.itemId] = count; } } else { std::map<uint32_t, uint32_t>::const_iterator findIt = tempSaleMap.find(shopInfo.itemId); if (findIt != tempSaleMap.end() && findIt->second > 0) { saleMap[shopInfo.itemId] = findIt->second; } } } } uint8_t itemsToSend = std::min<size_t>(saleMap.size(), std::numeric_limits<uint8_t>::max()); msg.addByte(itemsToSend); uint8_t i = 0; for (std::map<uint16_t, uint32_t>::const_iterator it = saleMap.begin(); i < itemsToSend; ++it, ++i) { msg.addItemId(it->first); msg.addByte(std::min<uint32_t>(it->second, std::numeric_limits<uint8_t>::max())); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketEnter(uint32_t depotId) { NetworkMessage msg; msg.addByte(0xF6); msg.add<uint64_t>(player->getBankBalance()); msg.addByte(std::min<uint32_t>(IOMarket::getPlayerOfferCount(player->getGUID()), std::numeric_limits<uint8_t>::max())); DepotChest* depotChest = player->getDepotChest(depotId, false); if (!depotChest) { msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); return; } player->setInMarket(true); std::map<uint16_t, uint32_t> depotItems; std::forward_list<Container*> containerList { depotChest, player->getInbox() }; do { Container* container = containerList.front(); containerList.pop_front(); for (Item* item : container->getItemList()) { Container* c = item->getContainer(); if (c && !c->empty()) { containerList.push_front(c); continue; } const ItemType& itemType = Item::items[item->getID()]; if (itemType.wareId == 0) { continue; } if (c && (!itemType.isContainer() || c->capacity() != itemType.maxItems)) { continue; } if (!item->hasMarketAttributes()) { continue; } depotItems[itemType.wareId] += Item::countByType(item, -1); } } while (!containerList.empty()); uint16_t itemsToSend = std::min<size_t>(depotItems.size(), std::numeric_limits<uint16_t>::max()); msg.add<uint16_t>(itemsToSend); uint16_t i = 0; for (std::map<uint16_t, uint32_t>::const_iterator it = depotItems.begin(); i < itemsToSend; ++it, ++i) { msg.add<uint16_t>(it->first); msg.add<uint16_t>(std::min<uint32_t>(0xFFFF, it->second)); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketLeave() { NetworkMessage msg; msg.addByte(0xF7); writeToOutputBuffer(msg); } void ProtocolGame::sendMarketBrowseItem(uint16_t itemId, const MarketOfferList& buyOffers, const MarketOfferList& sellOffers) { NetworkMessage msg; msg.addByte(0xF9); msg.addItemId(itemId); msg.add<uint32_t>(buyOffers.size()); for (const MarketOffer& offer : buyOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); } msg.add<uint32_t>(sellOffers.size()); for (const MarketOffer& offer : sellOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketAcceptOffer(const MarketOfferEx& offer) { NetworkMessage msg; msg.addByte(0xF9); msg.addItemId(offer.itemId); if (offer.type == MARKETACTION_BUY) { msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); msg.add<uint32_t>(0x00); } else { msg.add<uint32_t>(0x00); msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.addString(offer.playerName); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketBrowseOwnOffers(const MarketOfferList& buyOffers, const MarketOfferList& sellOffers) { NetworkMessage msg; msg.addByte(0xF9); msg.add<uint16_t>(MARKETREQUEST_OWN_OFFERS); msg.add<uint32_t>(buyOffers.size()); for (const MarketOffer& offer : buyOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); } msg.add<uint32_t>(sellOffers.size()); for (const MarketOffer& offer : sellOffers) { msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketCancelOffer(const MarketOfferEx& offer) { NetworkMessage msg; msg.addByte(0xF9); msg.add<uint16_t>(MARKETREQUEST_OWN_OFFERS); if (offer.type == MARKETACTION_BUY) { msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); msg.add<uint32_t>(0x00); } else { msg.add<uint32_t>(0x00); msg.add<uint32_t>(0x01); msg.add<uint32_t>(offer.timestamp); msg.add<uint16_t>(offer.counter); msg.addItemId(offer.itemId); msg.add<uint16_t>(offer.amount); msg.add<uint32_t>(offer.price); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketBrowseOwnHistory(const HistoryMarketOfferList& buyOffers, const HistoryMarketOfferList& sellOffers) { uint32_t i = 0; std::map<uint32_t, uint16_t> counterMap; uint32_t buyOffersToSend = std::min<uint32_t>(buyOffers.size(), 810 + std::max<int32_t>(0, 810 - sellOffers.size())); uint32_t sellOffersToSend = std::min<uint32_t>(sellOffers.size(), 810 + std::max<int32_t>(0, 810 - buyOffers.size())); NetworkMessage msg; msg.addByte(0xF9); msg.add<uint16_t>(MARKETREQUEST_OWN_HISTORY); msg.add<uint32_t>(buyOffersToSend); for (auto it = buyOffers.begin(); i < buyOffersToSend; ++it, ++i) { msg.add<uint32_t>(it->timestamp); msg.add<uint16_t>(counterMap[it->timestamp]++); msg.addItemId(it->itemId); msg.add<uint16_t>(it->amount); msg.add<uint32_t>(it->price); msg.addByte(it->state); } counterMap.clear(); i = 0; msg.add<uint32_t>(sellOffersToSend); for (auto it = sellOffers.begin(); i < sellOffersToSend; ++it, ++i) { msg.add<uint32_t>(it->timestamp); msg.add<uint16_t>(counterMap[it->timestamp]++); msg.addItemId(it->itemId); msg.add<uint16_t>(it->amount); msg.add<uint32_t>(it->price); msg.addByte(it->state); } writeToOutputBuffer(msg); } void ProtocolGame::sendMarketDetail(uint16_t itemId) { NetworkMessage msg; msg.addByte(0xF8); msg.addItemId(itemId); const ItemType& it = Item::items[itemId]; if (it.armor != 0) { msg.addString(std::to_string(it.armor)); } else { msg.add<uint16_t>(0x00); } if (it.attack != 0) { // TODO: chance to hit, range // example: // "attack +x, chance to hit +y%, z fields" if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) { std::ostringstream ss; ss << it.attack << " physical +" << it.abilities->elementDamage << ' ' << getCombatName(it.abilities->elementType); msg.addString(ss.str()); } else { msg.addString(std::to_string(it.attack)); } } else { msg.add<uint16_t>(0x00); } if (it.isContainer()) { msg.addString(std::to_string(it.maxItems)); } else { msg.add<uint16_t>(0x00); } if (it.defense != 0) { if (it.extraDefense != 0) { std::ostringstream ss; ss << it.defense << ' ' << std::showpos << it.extraDefense << std::noshowpos; msg.addString(ss.str()); } else { msg.addString(std::to_string(it.defense)); } } else { msg.add<uint16_t>(0x00); } if (!it.description.empty()) { const std::string& descr = it.description; if (descr.back() == '.') { msg.addString(std::string(descr, 0, descr.length() - 1)); } else { msg.addString(descr); } } else { msg.add<uint16_t>(0x00); } if (it.decayTime != 0) { std::ostringstream ss; ss << it.decayTime << " seconds"; msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (it.abilities) { std::ostringstream ss; bool separator = false; for (size_t i = 0; i < COMBAT_COUNT; ++i) { if (it.abilities->absorbPercent[i] == 0) { continue; } if (separator) { ss << ", "; } else { separator = true; } ss << getCombatName(indexToCombatType(i)) << ' ' << std::showpos << it.abilities->absorbPercent[i] << std::noshowpos << '%'; } msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (it.minReqLevel != 0) { msg.addString(std::to_string(it.minReqLevel)); } else { msg.add<uint16_t>(0x00); } if (it.minReqMagicLevel != 0) { msg.addString(std::to_string(it.minReqMagicLevel)); } else { msg.add<uint16_t>(0x00); } msg.addString(it.vocationString); msg.addString(it.runeSpellName); if (it.abilities) { std::ostringstream ss; bool separator = false; for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; i++) { if (!it.abilities->skills[i]) { continue; } if (separator) { ss << ", "; } else { separator = true; } ss << getSkillName(i) << ' ' << std::showpos << it.abilities->skills[i] << std::noshowpos; } if (it.abilities->stats[STAT_MAGICPOINTS] != 0) { if (separator) { ss << ", "; } else { separator = true; } ss << "magic level " << std::showpos << it.abilities->stats[STAT_MAGICPOINTS] << std::noshowpos; } if (it.abilities->speed != 0) { if (separator) { ss << ", "; } ss << "speed " << std::showpos << (it.abilities->speed >> 1) << std::noshowpos; } msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } if (it.charges != 0) { msg.addString(std::to_string(it.charges)); } else { msg.add<uint16_t>(0x00); } std::string weaponName = getWeaponName(it.weaponType); if (it.slotPosition & SLOTP_TWO_HAND) { if (!weaponName.empty()) { weaponName += ", two-handed"; } else { weaponName = "two-handed"; } } msg.addString(weaponName); if (it.weight != 0) { std::ostringstream ss; if (it.weight < 10) { ss << "0.0" << it.weight; } else if (it.weight < 100) { ss << "0." << it.weight; } else { std::string weightString = std::to_string(it.weight); weightString.insert(weightString.end() - 2, '.'); ss << weightString; } ss << " oz"; msg.addString(ss.str()); } else { msg.add<uint16_t>(0x00); } MarketStatistics* statistics = IOMarket::getInstance().getPurchaseStatistics(itemId); if (statistics) { msg.addByte(0x01); msg.add<uint32_t>(statistics->numTransactions); msg.add<uint32_t>(std::min<uint64_t>(std::numeric_limits<uint32_t>::max(), statistics->totalPrice)); msg.add<uint32_t>(statistics->highestPrice); msg.add<uint32_t>(statistics->lowestPrice); } else { msg.addByte(0x00); } statistics = IOMarket::getInstance().getSaleStatistics(itemId); if (statistics) { msg.addByte(0x01); msg.add<uint32_t>(statistics->numTransactions); msg.add<uint32_t>(std::min<uint64_t>(std::numeric_limits<uint32_t>::max(), statistics->totalPrice)); msg.add<uint32_t>(statistics->highestPrice); msg.add<uint32_t>(statistics->lowestPrice); } else { msg.addByte(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendQuestLog() { NetworkMessage msg; msg.addByte(0xF0); msg.add<uint16_t>(g_game.quests.getQuestsCount(player)); for (const Quest& quest : g_game.quests.getQuests()) { if (quest.isStarted(player)) { msg.add<uint16_t>(quest.getID()); msg.addString(quest.getName()); msg.addByte(quest.isCompleted(player)); } } writeToOutputBuffer(msg); } void ProtocolGame::sendQuestLine(const Quest* quest) { NetworkMessage msg; msg.addByte(0xF1); msg.add<uint16_t>(quest->getID()); msg.addByte(quest->getMissionsCount(player)); for (const Mission& mission : quest->getMissions()) { if (mission.isStarted(player)) { msg.addString(mission.getName(player)); msg.addString(mission.getDescription(player)); } } writeToOutputBuffer(msg); } void ProtocolGame::sendTradeItemRequest(const std::string& traderName, const Item* item, bool ack) { NetworkMessage msg; if (ack) { msg.addByte(0x7D); } else { msg.addByte(0x7E); } msg.addString(traderName); if (const Container* tradeContainer = item->getContainer()) { std::list<const Container*> listContainer {tradeContainer}; std::list<const Item*> itemList {tradeContainer}; while (!listContainer.empty()) { const Container* container = listContainer.front(); listContainer.pop_front(); for (Item* containerItem : container->getItemList()) { Container* tmpContainer = containerItem->getContainer(); if (tmpContainer) { listContainer.push_back(tmpContainer); } itemList.push_back(containerItem); } } msg.addByte(itemList.size()); for (const Item* listItem : itemList) { msg.addItem(listItem); } } else { msg.addByte(0x01); msg.addItem(item); } writeToOutputBuffer(msg); } void ProtocolGame::sendCloseTrade() { NetworkMessage msg; msg.addByte(0x7F); writeToOutputBuffer(msg); } void ProtocolGame::sendCloseContainer(uint8_t cid) { NetworkMessage msg; msg.addByte(0x6F); msg.addByte(cid); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureTurn(const Creature* creature, uint32_t stackPos) { if (!canSee(creature)) { return; } NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(creature->getPosition()); msg.addByte(stackPos); msg.add<uint16_t>(0x63); msg.add<uint32_t>(creature->getID()); msg.addByte(creature->getDirection()); msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, const Position* pos/* = nullptr*/) { NetworkMessage msg; msg.addByte(0xAA); static uint32_t statementId = 0; msg.add<uint32_t>(++statementId); msg.addString(creature->getName()); //Add level only for players if (const Player* speaker = creature->getPlayer()) { msg.add<uint16_t>(speaker->getLevel()); } else { msg.add<uint16_t>(0x00); } msg.addByte(type); if (pos) { msg.addPosition(*pos); } else { msg.addPosition(creature->getPosition()); } msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId) { NetworkMessage msg; msg.addByte(0xAA); static uint32_t statementId = 0; msg.add<uint32_t>(++statementId); if (!creature) { msg.add<uint32_t>(0x00); } else if (type == TALKTYPE_CHANNEL_R2) { msg.add<uint32_t>(0x00); type = TALKTYPE_CHANNEL_R1; } else { msg.addString(creature->getName()); //Add level only for players if (const Player* speaker = creature->getPlayer()) { msg.add<uint16_t>(speaker->getLevel()); } else { msg.add<uint16_t>(0x00); } } msg.addByte(type); msg.add<uint16_t>(channelId); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendPrivateMessage(const Player* speaker, SpeakClasses type, const std::string& text) { NetworkMessage msg; msg.addByte(0xAA); static uint32_t statementId = 0; msg.add<uint32_t>(++statementId); if (speaker) { msg.addString(speaker->getName()); msg.add<uint16_t>(speaker->getLevel()); } else { msg.add<uint32_t>(0x00); } msg.addByte(type); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendCancelTarget() { NetworkMessage msg; msg.addByte(0xA3); msg.add<uint32_t>(0x00); writeToOutputBuffer(msg); } void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed) { NetworkMessage msg; msg.addByte(0x8F); msg.add<uint32_t>(creature->getID()); msg.add<uint16_t>(creature->getBaseSpeed() / 2); msg.add<uint16_t>(speed / 2); writeToOutputBuffer(msg); } void ProtocolGame::sendCancelWalk() { NetworkMessage msg; msg.addByte(0xB5); msg.addByte(player->getDirection()); writeToOutputBuffer(msg); } void ProtocolGame::sendSkills() { NetworkMessage msg; AddPlayerSkills(msg); writeToOutputBuffer(msg); } void ProtocolGame::sendPing() { NetworkMessage msg; msg.addByte(0x1D); writeToOutputBuffer(msg); } void ProtocolGame::sendPingBack() { NetworkMessage msg; msg.addByte(0x1E); writeToOutputBuffer(msg); } void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type) { NetworkMessage msg; msg.addByte(0x85); msg.addPosition(from); msg.addPosition(to); msg.addByte(type); writeToOutputBuffer(msg); } void ProtocolGame::sendMagicEffect(const Position& pos, uint8_t type) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x83); msg.addPosition(pos); msg.addByte(type); writeToOutputBuffer(msg); } void ProtocolGame::sendCreatureHealth(const Creature* creature) { NetworkMessage msg; msg.addByte(0x8C); msg.add<uint32_t>(creature->getID()); if (creature->isHealthHidden()) { msg.addByte(0x00); } else { msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100)); } writeToOutputBuffer(msg); } void ProtocolGame::sendFYIBox(const std::string& message) { NetworkMessage msg; msg.addByte(0x15); msg.addString(message); writeToOutputBuffer(msg); } //tile void ProtocolGame::sendMapDescription(const Position& pos) { NetworkMessage msg; msg.addByte(0x64); msg.addPosition(player->getPosition()); GetMapDescription(pos.x - Map::maxClientViewportX, pos.y - Map::maxClientViewportY, pos.z, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, msg); writeToOutputBuffer(msg); } void ProtocolGame::sendAddTileItem(const Position& pos, uint32_t stackpos, const Item* item) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); msg.addByte(stackpos); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendUpdateTileItem(const Position& pos, uint32_t stackpos, const Item* item) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(pos); msg.addByte(stackpos); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendRemoveTileThing(const Position& pos, uint32_t stackpos) { if (!canSee(pos)) { return; } NetworkMessage msg; RemoveTileThing(msg, pos, stackpos); writeToOutputBuffer(msg); } void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos) { if (!canSee(pos)) { return; } NetworkMessage msg; msg.addByte(0x69); msg.addPosition(pos); if (tile) { GetTileDescription(tile, msg); msg.addByte(0x00); msg.addByte(0xFF); } else { msg.addByte(0x01); msg.addByte(0xFF); } writeToOutputBuffer(msg); } void ProtocolGame::sendPendingStateEntered() { NetworkMessage msg; msg.addByte(0x0A); writeToOutputBuffer(msg); } void ProtocolGame::sendEnterWorld() { NetworkMessage msg; msg.addByte(0x0F); writeToOutputBuffer(msg); } void ProtocolGame::sendFightModes() { NetworkMessage msg; msg.addByte(0xA7); msg.addByte(player->fightMode); msg.addByte(player->chaseMode); msg.addByte(player->secureMode); msg.addByte(PVP_MODE_DOVE); writeToOutputBuffer(msg); } void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos, int32_t stackpos, bool isLogin) { if (!canSee(pos)) { return; } if (creature != player) { if (stackpos != -1) { NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); msg.addByte(stackpos); bool known; uint32_t removedKnown; checkCreatureAsKnown(creature->getID(), known, removedKnown); AddCreature(msg, creature, known, removedKnown); writeToOutputBuffer(msg); } if (isLogin) { sendMagicEffect(pos, CONST_ME_TELEPORT); } return; } NetworkMessage msg; msg.addByte(0x17); msg.add<uint32_t>(player->getID()); msg.add<uint16_t>(0x32); // beat duration (50) msg.addDouble(Creature::speedA, 3); msg.addDouble(Creature::speedB, 3); msg.addDouble(Creature::speedC, 3); // can report bugs? if (player->getAccountType() >= ACCOUNT_TYPE_TUTOR) { msg.addByte(0x01); } else { msg.addByte(0x00); } msg.addByte(0x00); // can change pvp framing option msg.addByte(0x00); // expert mode button enabled msg.add<uint16_t>(0x00); // URL (string) to ingame store images msg.add<uint16_t>(25); // premium coin package size writeToOutputBuffer(msg); sendPendingStateEntered(); sendEnterWorld(); sendMapDescription(pos); if (isLogin) { sendMagicEffect(pos, CONST_ME_TELEPORT); } for (int i = CONST_SLOT_FIRST; i <= CONST_SLOT_LAST; ++i) { sendInventoryItem(static_cast<slots_t>(i), player->getInventoryItem(static_cast<slots_t>(i))); } sendStats(); sendSkills(); //gameworld light-settings sendWorldLight(g_game.getWorldLightInfo()); //player light level sendCreatureLight(creature); sendVIPEntries(); sendBasicData(); player->sendIcons(); } void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& newPos, int32_t newStackPos, const Position& oldPos, int32_t oldStackPos, bool teleport) { if (creature == player) { if (oldStackPos >= 10) { sendMapDescription(newPos); } else if (teleport) { NetworkMessage msg; RemoveTileThing(msg, oldPos, oldStackPos); writeToOutputBuffer(msg); sendMapDescription(newPos); } else { NetworkMessage msg; if (oldPos.z == 7 && newPos.z >= 8) { RemoveTileThing(msg, oldPos, oldStackPos); } else { msg.addByte(0x6D); msg.addPosition(oldPos); msg.addByte(oldStackPos); msg.addPosition(newPos); } if (newPos.z > oldPos.z) { MoveDownCreature(msg, creature, newPos, oldPos); } else if (newPos.z < oldPos.z) { MoveUpCreature(msg, creature, newPos, oldPos); } if (oldPos.y > newPos.y) { // north, for old x msg.addByte(0x65); GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, 1, msg); } else if (oldPos.y < newPos.y) { // south, for old x msg.addByte(0x67); GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y + (Map::maxClientViewportY+1), newPos.z, (Map::maxClientViewportX+1)*2, 1, msg); } if (oldPos.x < newPos.x) { // east, [with new y] msg.addByte(0x66); GetMapDescription(newPos.x + (Map::maxClientViewportX+1), newPos.y - Map::maxClientViewportY, newPos.z, 1, (Map::maxClientViewportY+1)*2, msg); } else if (oldPos.x > newPos.x) { // west, [with new y] msg.addByte(0x68); GetMapDescription(newPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, 1, (Map::maxClientViewportY+1)*2, msg); } writeToOutputBuffer(msg); } } else if (canSee(oldPos) && canSee(creature->getPosition())) { if (teleport || (oldPos.z == 7 && newPos.z >= 8) || oldStackPos >= 10) { sendRemoveTileThing(oldPos, oldStackPos); sendAddCreature(creature, newPos, newStackPos, false); } else { NetworkMessage msg; msg.addByte(0x6D); msg.addPosition(oldPos); msg.addByte(oldStackPos); msg.addPosition(creature->getPosition()); writeToOutputBuffer(msg); } } else if (canSee(oldPos)) { sendRemoveTileThing(oldPos, oldStackPos); } else if (canSee(creature->getPosition())) { sendAddCreature(creature, newPos, newStackPos, false); } } void ProtocolGame::sendInventoryItem(slots_t slot, const Item* item) { NetworkMessage msg; if (item) { msg.addByte(0x78); msg.addByte(slot); msg.addItem(item); } else { msg.addByte(0x79); msg.addByte(slot); } writeToOutputBuffer(msg); } void ProtocolGame::sendItems() { NetworkMessage msg; msg.addByte(0xF5); const std::vector<uint16_t>& inventory = Item::items.getInventory(); msg.add<uint16_t>(inventory.size() + 11); for (uint16_t i = 1; i <= 11; i++) { msg.add<uint16_t>(i); msg.addByte(0); //always 0 msg.add<uint16_t>(1); // always 1 } for (auto clientId : inventory) { msg.add<uint16_t>(clientId); msg.addByte(0); //always 0 msg.add<uint16_t>(1); } writeToOutputBuffer(msg); } void ProtocolGame::sendAddContainerItem(uint8_t cid, uint16_t slot, const Item* item) { NetworkMessage msg; msg.addByte(0x70); msg.addByte(cid); msg.add<uint16_t>(slot); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint16_t slot, const Item* item) { NetworkMessage msg; msg.addByte(0x71); msg.addByte(cid); msg.add<uint16_t>(slot); msg.addItem(item); writeToOutputBuffer(msg); } void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint16_t slot, const Item* lastItem) { NetworkMessage msg; msg.addByte(0x72); msg.addByte(cid); msg.add<uint16_t>(slot); if (lastItem) { msg.addItem(lastItem); } else { msg.add<uint16_t>(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxlen, bool canWrite) { NetworkMessage msg; msg.addByte(0x96); msg.add<uint32_t>(windowTextId); msg.addItem(item); if (canWrite) { msg.add<uint16_t>(maxlen); msg.addString(item->getText()); } else { const std::string& text = item->getText(); msg.add<uint16_t>(text.size()); msg.addString(text); } const std::string& writer = item->getWriter(); if (!writer.empty()) { msg.addString(writer); } else { msg.add<uint16_t>(0x00); } time_t writtenDate = item->getDate(); if (writtenDate != 0) { msg.addString(formatDateShort(writtenDate)); } else { msg.add<uint16_t>(0x00); } writeToOutputBuffer(msg); } void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text) { NetworkMessage msg; msg.addByte(0x96); msg.add<uint32_t>(windowTextId); msg.addItem(itemId, 1); msg.add<uint16_t>(text.size()); msg.addString(text); msg.add<uint16_t>(0x00); msg.add<uint16_t>(0x00); writeToOutputBuffer(msg); } void ProtocolGame::sendHouseWindow(uint32_t windowTextId, const std::string& text) { NetworkMessage msg; msg.addByte(0x97); msg.addByte(0x00); msg.add<uint32_t>(windowTextId); msg.addString(text); writeToOutputBuffer(msg); } void ProtocolGame::sendOutfitWindow() { NetworkMessage msg; msg.addByte(0xC8); Outfit_t currentOutfit = player->getDefaultOutfit(); Mount* currentMount = g_game.mounts.getMountByID(player->getCurrentMount()); if (currentMount) { currentOutfit.lookMount = currentMount->clientId; } AddOutfit(msg, currentOutfit); std::vector<ProtocolOutfit> protocolOutfits; if (player->isAccessPlayer()) { static const std::string gamemasterOutfitName = "Gamemaster"; protocolOutfits.emplace_back(gamemasterOutfitName, 75, 0); } const auto& outfits = Outfits::getInstance().getOutfits(player->getSex()); protocolOutfits.reserve(outfits.size()); for (const Outfit& outfit : outfits) { uint8_t addons; if (!player->getOutfitAddons(outfit, addons)) { continue; } protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons); if (protocolOutfits.size() == 100) { // Game client doesn't allow more than 100 outfits break; } } msg.addByte(protocolOutfits.size()); for (const ProtocolOutfit& outfit : protocolOutfits) { msg.add<uint16_t>(outfit.lookType); msg.addString(outfit.name); msg.addByte(outfit.addons); } std::vector<const Mount*> mounts; for (const Mount& mount : g_game.mounts.getMounts()) { if (player->hasMount(&mount)) { mounts.push_back(&mount); } } msg.addByte(mounts.size()); for (const Mount* mount : mounts) { msg.add<uint16_t>(mount->clientId); msg.addString(mount->name); } writeToOutputBuffer(msg); } void ProtocolGame::sendUpdatedVIPStatus(uint32_t guid, VipStatus_t newStatus) { NetworkMessage msg; msg.addByte(0xD3); msg.add<uint32_t>(guid); msg.addByte(newStatus); writeToOutputBuffer(msg); } void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, const std::string& description, uint32_t icon, bool notify, VipStatus_t status) { NetworkMessage msg; msg.addByte(0xD2); msg.add<uint32_t>(guid); msg.addString(name); msg.addString(description); msg.add<uint32_t>(std::min<uint32_t>(10, icon)); msg.addByte(notify ? 0x01 : 0x00); msg.addByte(status); writeToOutputBuffer(msg); } void ProtocolGame::sendVIPEntries() { const std::forward_list<VIPEntry>& vipEntries = IOLoginData::getVIPEntries(player->getAccount()); for (const VIPEntry& entry : vipEntries) { VipStatus_t vipStatus = VIPSTATUS_ONLINE; Player* vipPlayer = g_game.getPlayerByGUID(entry.guid); if (!vipPlayer || vipPlayer->isInGhostMode() || player->isAccessPlayer()) { vipStatus = VIPSTATUS_OFFLINE; } sendVIP(entry.guid, entry.name, entry.description, entry.icon, entry.notify, vipStatus); } } void ProtocolGame::sendSpellCooldown(uint8_t spellId, uint32_t time) { NetworkMessage msg; msg.addByte(0xA4); msg.addByte(spellId); msg.add<uint32_t>(time); writeToOutputBuffer(msg); } void ProtocolGame::sendSpellGroupCooldown(SpellGroup_t groupId, uint32_t time) { NetworkMessage msg; msg.addByte(0xA5); msg.addByte(groupId); msg.add<uint32_t>(time); writeToOutputBuffer(msg); } void ProtocolGame::sendModalWindow(const ModalWindow& modalWindow) { NetworkMessage msg; msg.addByte(0xFA); msg.add<uint32_t>(modalWindow.id); msg.addString(modalWindow.title); msg.addString(modalWindow.message); msg.addByte(modalWindow.buttons.size()); for (const auto& it : modalWindow.buttons) { msg.addString(it.first); msg.addByte(it.second); } msg.addByte(modalWindow.choices.size()); for (const auto& it : modalWindow.choices) { msg.addString(it.first); msg.addByte(it.second); } msg.addByte(modalWindow.defaultEscapeButton); msg.addByte(modalWindow.defaultEnterButton); msg.addByte(modalWindow.priority ? 0x01 : 0x00); writeToOutputBuffer(msg); } ////////////// Add common messages void ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove) { CreatureType_t creatureType = creature->getType(); const Player* otherPlayer = creature->getPlayer(); if (known) { msg.add<uint16_t>(0x62); msg.add<uint32_t>(creature->getID()); } else { msg.add<uint16_t>(0x61); msg.add<uint32_t>(remove); msg.add<uint32_t>(creature->getID()); msg.addByte(creatureType); msg.addString(creature->getName()); } if (creature->isHealthHidden()) { msg.addByte(0x00); } else { msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100)); } msg.addByte(creature->getDirection()); if (!creature->isInGhostMode() && !creature->isInvisible()) { AddOutfit(msg, creature->getCurrentOutfit()); } else { static Outfit_t outfit; AddOutfit(msg, outfit); } LightInfo lightInfo = creature->getCreatureLight(); msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level); msg.addByte(lightInfo.color); msg.add<uint16_t>(creature->getStepSpeed() / 2); msg.addByte(player->getSkullClient(creature)); msg.addByte(player->getPartyShield(otherPlayer)); if (!known) { msg.addByte(player->getGuildEmblem(otherPlayer)); } if (creatureType == CREATURETYPE_MONSTER) { const Creature* master = creature->getMaster(); if (master) { const Player* masterPlayer = master->getPlayer(); if (masterPlayer) { if (masterPlayer == player) { creatureType = CREATURETYPE_SUMMON_OWN; } else { creatureType = CREATURETYPE_SUMMON_OTHERS; } } } } msg.addByte(creatureType); // Type (for summons) msg.addByte(creature->getSpeechBubble()); msg.addByte(0xFF); // MARK_UNMARKED if (otherPlayer) { msg.add<uint16_t>(otherPlayer->getHelpers()); } else { msg.add<uint16_t>(0x00); } msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01); } void ProtocolGame::AddPlayerStats(NetworkMessage& msg) { msg.addByte(0xA0); msg.add<uint16_t>(std::min<int32_t>(player->getHealth(), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(std::min<int32_t>(player->getMaxHealth(), std::numeric_limits<uint16_t>::max())); msg.add<uint32_t>(player->getFreeCapacity()); msg.add<uint32_t>(player->getCapacity()); msg.add<uint64_t>(player->getExperience()); msg.add<uint16_t>(player->getLevel()); msg.addByte(player->getLevelPercent()); msg.add<uint16_t>(100); // base xp gain rate msg.add<uint16_t>(0); // xp voucher msg.add<uint16_t>(0); // low level bonus msg.add<uint16_t>(0); // xp boost msg.add<uint16_t>(100); // stamina multiplier (100 = x1.0) msg.add<uint16_t>(std::min<int32_t>(player->getMana(), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(std::min<int32_t>(player->getMaxMana(), std::numeric_limits<uint16_t>::max())); msg.addByte(std::min<uint32_t>(player->getMagicLevel(), std::numeric_limits<uint8_t>::max())); msg.addByte(std::min<uint32_t>(player->getBaseMagicLevel(), std::numeric_limits<uint8_t>::max())); msg.addByte(player->getMagicLevelPercent()); msg.addByte(player->getSoul()); msg.add<uint16_t>(player->getStaminaMinutes()); msg.add<uint16_t>(player->getBaseSpeed() / 2); Condition* condition = player->getCondition(CONDITION_REGENERATION); msg.add<uint16_t>(condition ? condition->getTicks() / 1000 : 0x00); msg.add<uint16_t>(player->getOfflineTrainingTime() / 60 / 1000); msg.add<uint16_t>(0); // xp boost time (seconds) msg.addByte(0); // enables exp boost in the store } void ProtocolGame::AddPlayerSkills(NetworkMessage& msg) { msg.addByte(0xA1); for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(player->getBaseSkill(i)); msg.addByte(player->getSkillPercent(i)); } for (uint8_t i = SPECIALSKILL_FIRST; i <= SPECIALSKILL_LAST; ++i) { msg.add<uint16_t>(std::min<int32_t>(100, player->varSpecialSkills[i])); msg.add<uint16_t>(0); } } void ProtocolGame::AddOutfit(NetworkMessage& msg, const Outfit_t& outfit) { msg.add<uint16_t>(outfit.lookType); if (outfit.lookType != 0) { msg.addByte(outfit.lookHead); msg.addByte(outfit.lookBody); msg.addByte(outfit.lookLegs); msg.addByte(outfit.lookFeet); msg.addByte(outfit.lookAddons); } else { msg.addItemId(outfit.lookTypeEx); } msg.add<uint16_t>(outfit.lookMount); } void ProtocolGame::AddWorldLight(NetworkMessage& msg, LightInfo lightInfo) { msg.addByte(0x82); msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level)); msg.addByte(lightInfo.color); } void ProtocolGame::AddCreatureLight(NetworkMessage& msg, const Creature* creature) { LightInfo lightInfo = creature->getCreatureLight(); msg.addByte(0x8D); msg.add<uint32_t>(creature->getID()); msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level)); msg.addByte(lightInfo.color); } //tile void ProtocolGame::RemoveTileThing(NetworkMessage& msg, const Position& pos, uint32_t stackpos) { if (stackpos >= 10) { return; } msg.addByte(0x6C); msg.addPosition(pos); msg.addByte(stackpos); } void ProtocolGame::MoveUpCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos) { if (creature != player) { return; } //floor change up msg.addByte(0xBE); //going to surface if (newPos.z == 7) { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 5, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 3, skip); //(floor 7 and 6 already set) GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 4, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 4, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 3, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 5, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 6, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 1, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 7, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 0, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 8, skip); if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } } //underground, going one floor up (still underground) else if (newPos.z > 7) { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, oldPos.getZ() - 3, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 3, skip); if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } } //moving up a floor up makes us out of sync //west msg.addByte(0x68); GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - (Map::maxClientViewportY-1), newPos.z, 1, (Map::maxClientViewportY+1)*2, msg); //north msg.addByte(0x65); GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, 1, msg); } void ProtocolGame::MoveDownCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos) { if (creature != player) { return; } //floor change down msg.addByte(0xBF); //going from surface to underground if (newPos.z == 8) { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -1, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 1, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -2, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -3, skip); if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } } //going further down else if (newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) { int32_t skip = -1; GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -3, skip); if (skip >= 0) { msg.addByte(skip); msg.addByte(0xFF); } } //moving down a floor makes us out of sync //east msg.addByte(0x66); GetMapDescription(oldPos.x + Map::maxClientViewportX+1, oldPos.y - (Map::maxClientViewportY+1), newPos.z, 1, ((Map::maxClientViewportY+1)*2), msg); //south msg.addByte(0x67); GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y + (Map::maxClientViewportY+1), newPos.z, ((Map::maxClientViewportX+1)*2), 1, msg); } void ProtocolGame::AddShopItem(NetworkMessage& msg, const ShopInfo& item) { const ItemType& it = Item::items[item.itemId]; msg.add<uint16_t>(it.clientId); if (it.isSplash() || it.isFluidContainer()) { msg.addByte(serverFluidToClient(item.subType)); } else { msg.addByte(0x00); } msg.addString(item.realName); msg.add<uint32_t>(it.weight); msg.add<uint32_t>(item.buyPrice); msg.add<uint32_t>(item.sellPrice); } void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg) { uint8_t opcode = msg.getByte(); const std::string& buffer = msg.getString(); // process additional opcodes via lua script event addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer); }
-
já foi resolvido, pode fechar...
-
Galera estou enfrentando um problema no meu site na hora de criação de conta
Já procurei em tudo que é lugar, acontece qnd eu desativo os inicias do site com os iniciais ativos a conta cria 100%, mas qnd eu desativo da isso ai + a conta cria..
quem poder me ajudar urgente eu pago
wpp : 85991761786
Discord : AlaOGaspar
#7077
Error: Incorrect integer value: '' for column 'key' at row 1
-
então galera, eu quero remover o sistema de icone do meu servidor, e deixar apenas as balls normais e estou disposto a pagar, me chamem no wpp 85994142350
que passo os arquivos para vocês, segue o vídeo abaixo tmj sz
-
Em 23/04/2020 em 21:57, Everaldo Woopz disse:
eu to com esse mesmo problema :x mas, nao consigo conectar no bit, eu consigo colocar o user e a senha
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
mas não da em nada no bit, ele pede minha senha eu coloco e fala pra colocar denovo e fica nessa
-
.Salve galera, bem rapidinho qual a melhor base atualmente para por online? não vou dizer sem bugs... mas uma base estável que eu possa por on e ir melhorando e claro open source tmj e rep++
-
qual a versão do php ?
-
Galera alguém sabe onde encontro esse remake de grama? rep+ pra quem me ajudar
Spoiler -
tempo de registro please
-
1 minuto atrás, Carlos Dukka disse:
tem 3 mil arquivos dps vo passa o de 7 agora o movimento e so preocurar que axa estavtudo cortado e separado tem q ir juntando
não teria só a spr e dat? mais pratico.
-
deveria disponibilizar a spr e dat, completa seria mais útil, mas mesmo assim bom trabalho, ( muita das sprites estão sem sua movimentação por isso seria uma boa, o pack completo do .spr e .dat )
-
Fala ae galera beleza?! Bom antes de tudo eu quero me apresentar para vocês, eu me chamo Mikael ( conhecido como alaogaspar no youtube ), tenho 22 anos e sou do ceará, jogo poketibia desde 2013, 1014, por aí nem lembro mais, sou mapper a um bom tempo, e também busco sempre aprender sobre mais coisas, trabalho, e recentemente estou a iniciar uma loja virtual, mas meu sonho sempre foi ter um projeto de poketibia, onde não tenha isso de P2W o famoso pay to win, pois todo servidor hoje em dia é assim... e eu tenho um projeto a um bom tempo, criei o mapa do zero, e ainda estou a editar esse mapa... e estou contratando algumas pessoas que querem ser da staff e me ajudar a abrir esse servidor o mais rápido possível, pois tenho uma vps dedicada e um domínio já e quero muito abrir esse servidor, então do que eu preciso ?
Antes de tudo fiquem com algumas imagens do servidor, lembrando que ainda estou editando algumas partes.
Necessito de:
Programador Lua/C++,
Web Designer
OTC Maker
Requisitos:
Ser maior de 17 anos, ter no minimo 2 horas disponível por dia, ter uma boa comunicação, educação e ser de confiança.
Benefícios:
A mais eu vou trabalhar de graça ? vou ganhar o que ?
Bom, além de ter um canto na minha staff, você será recompensado por trabalhos, claro que não muito... mas o bastante para conseguimos manter o servidor.
está interessado? mande-me mensagem no wpp ( 85994142350)
não está conseguindo? preencha isso aqui.
- Nome Completo:
- Idade:
- Escolaridade:
- Whatsapp para Contato:
- Experiencia:
- Conhecimentos no Otserv:
Aguardando by : AlaOGaspar
-
Galera, alguém poderia me ajudar ? recentemente adicionei um sistema de surf no meu servidor, agora ele tá funfando de boa, mas algumas vezes que entro na água ele dá esse erro "[Error - MoveEvent::executeStep] Call stack overflow. " aí o char trava e desloga, rep+ pra quem me ajudar, meus sistemas.
movements.xml
<?xml version="1.0" encoding="UTF-8"?> <movements> <movevent type="StepIn" actionid="54545" event="script" value="portacp.lua"/> <movevent type="StepIn" actionid="54333" event="script" value="tpfishing.lua"/> <movevent type="StepOut" actionid="54545" event="script" value="portacp.lua"/> <movevent type="StepIn" actionid="54555" event="script" value="portapredioverde.lua"/> <movevent type="StepOut" actionid="54555" event="script" value="portapredioverde.lua"/> <movevent type="StepIn" actionid="54546" event="script" value="portacp2.lua"/> <movevent type="StepOut" actionid="54546" event="script" value="portacp2.lua"/> <movevent type="StepIn" actionid="54547" event="script" value="portashop.lua"/> <movevent type="StepOut" actionid="54547" event="script" value="portashop.lua"/> <movevent type="StepIn" actionid="54548" event="script" value="portatrade.lua"/> <movevent type="StepOut" actionid="54548" event="script" value="portatrade.lua"/> <movevent type="StepIn" actionid="54549" event="script" value="portalavender.lua"/> <movevent type="StepOut" actionid="54549" event="script" value="portalavender.lua"/> <movevent type="StepIn" actionid="54550" event="script" value="portashoplavender.lua"/> <movevent type="StepOut" actionid="54550" event="script" value="portashoplavender.lua"/> <movevent type="StepIn" actionid="54551" event="script" value="portatradelavender.lua"/> <movevent type="StepOut" actionid="54551" event="script" value="portatradelavender.lua"/> <movevent type="StepIn" actionid="54552" event="script" value="portatradesaffron1.lua"/> <movevent type="StepOut" actionid="54552" event="script" value="portatradesaffron1.lua"/> <movevent type="StepIn" actionid="54553" event="script" value="portatradesaffron2.lua"/> <movevent type="StepOut" actionid="54553" event="script" value="portatradesaffron2.lua"/> -- Icone System <movevent type="Equip" itemid="11826-11837;11737-11748;12826-12831;10975-10977;12621-12623;12861-13781;13797-13823;13836-13861;13902-13904;13919-13930;13933-13935;13937-13939;14020-14022;14015-14017;14033-14035;14038-14040;14043-14045;14141-14143;14157-14159;14163-14165;14173-14175;14081-14083;14190-14192;14178-14180;14193-14195;14199-14201;14202-14204;14205-14207;14208-14210;14211-14213;14216-14218;14219-14221;14222-14224;14227-14229;14232-14234;14237-14239;14242-14244;14247-14249;14254-14256;14258-14260;14261-14263;14264-14266;14267-14269;14270-14272;14273-14275;14276-14278;14280-14282;14285-14287;14290-14292;14294-14296;14300-14302;14305-14307;14310-14312;14315-14317;14320-14322;14325-14327;14330-14332;14335-14337;14340-14342;14345-14347;14355-14357;14360-14362;14365-14367;14370-14372;14375-14377;14381-14383;14386-14388;14391-14393;14396-14398;14086-14088;14091-14093;14106-14108;14111-14113;14121-14123;14126-14128;14101-14103;14401-14403;14406-14408;14411-14413;14416-14418;14421-14423;14426-14428;14431-14433;14436-14438;14442-14444;14447-14449;14451-14453;14455-14457;20561-20563;20564-20566;20567-20569;20570-20572;20573-20575;20576-20578;20580-20582;20584-20586;20589-20591;20595-20597;20600-20601;20605-20607;20610-20612;20680-20682;20685-20687;20695-20697;20700-20702;20705-20707;20710-20712;20714-20716;20725-20727;20730-20732;20740-20742;20751-20753;20754-20756;20758-20760;20763-20765;20766-20768;20770-20772;20773-20775;20777-20779;20782-20784;20787-20789;20791-20793;" slot="feet" event="script" value="portrait.lua"/> <movevent type="DeEquip" itemid="11826-11837;11737-11748;12826-12831;10975-10977;12621-12623;12861-13781;13797-13823;13836-13861;13902-13904;13919-13930;13933-13935;13937-13939;14020-14022;14015-14017;14141-14143;14157-14159;14163-14165;14173-14175;14081-14083;14190-14192;14178-14180;14193-14195;14199-14201;14202-14204;14205-14207;14208-14210;14211-14213;14216-14218;14219-14221;14222-14224;14227-14229;14232-14234;14237-14239;14242-14244;14247-14249;14254-14256;14258-14260;14261-14263;14264-14266;14267-14269;14270-14272;14273-14275;14276-14278;14280-14282;14285-14287;14290-14292;14294-14296;14300-14302;14305-14307;14310-14312;14315-14317;14320-14322;14325-14327;14330-14332;14335-14337;14340-14342;14345-14347;14355-14357;14360-14362;14365-14367;14370-14372;14375-14377;14381-14383;14386-14388;14391-14393;14396-14398;14086-14088;14091-14093;14106-14108;14111-14113;14121-14123;14126-14128;14101-14103;14401-14403;14406-14408;14411-14413;14416-14418;14421-14423;14426-14428;14431-14433;14436-14438;14442-14444;14447-14449;14451-14453;14455-14457;20561-20563;20564-20566;20567-20569;20570-20572;20573-20575;20576-20578;20580-20582;20584-20586;20589-20591;20595-20597;20600-20601;20605-20607;20610-20612;20680-20682;20685-20687;20695-20697;20700-20702;20705-20707;20710-20712;20714-20716;20725-20727;20730-20732;20740-20742;20795-20797;" slot="feet" event="script" value="portrait.lua"/> -- Outland <movevent type="StepIn" actionid="25007" event="script" value="outlandtile.lua"/> <movevent type="StepIn" actionid="25000" event="script" value="outlandtile1.lua"/> <movevent type="StepIn" actionid="23021" event="script" value="tiletpback.lua"/> <movevent type="StepIn" actionid="23020" event="script" value="tiletp.lua"/> <movevent type="StepIn" actionid="23022" event="script" value="tiletpelec.lua"/> <movevent type="StepIn" actionid="23037" event="script" value="tiletpelecback.lua"/> <movevent type="StepIn" actionid="23023" event="script" value="tiletpgengar.lua"/> <movevent type="StepIn" actionid="23024" event="script" value="tiletpgengarback.lua"/> <movevent type="StepIn" actionid="23025" event="script" value="tiletpprimeape.lua"/> <movevent type="StepIn" actionid="23026" event="script" value="tiletpprimeapeback.lua"/> <movevent type="StepIn" actionid="23027" event="script" value="tiletpgya.lua"/> <movevent type="StepIn" actionid="23028" event="script" value="tiletpgyaback.lua"/> <movevent type="StepIn" actionid="23029" event="script" value="tiletpvenusaur.lua"/> <movevent type="StepIn" actionid="23030" event="script" value="tiletpvenusaurback.lua"/> <movevent type="StepIn" actionid="23031" event="script" value="tiletppassaro.lua"/> <movevent type="StepIn" actionid="23032" event="script" value="tiletppassaroback.lua"/> <movevent type="StepIn" actionid="23033" event="script" value="tiletpsteelix.lua"/> <movevent type="StepIn" actionid="23034" event="script" value="tiletpsteelixback.lua"/> <movevent type="StepIn" actionid="23035" event="script" value="tiletphypno.lua"/> <movevent type="StepIn" actionid="23036" event="script" value="tiletphypnoback.lua"/> <movevent type="StepIn" actionid="33691;33692;33693;33694;33695;33696;33697;3368;33699;33711;33712;33713;33714;33715;33716;33717;33718;33719;33720;33721;33722;33723;33724;33725" event="script" value="PVP/Trade_Go.lua"/> <movevent type="StepIn" actionid="33799;33800-33808" event="script" value="PVP/Trade_Back.lua"/> <movevent type="StepIn" actionid="12572-12575" event="script" value="PVP/PVP_tile.lua"/> <movevent type="StepIn" actionid="54322" event="script" value="tppvp.lua"/> <movevent type="StepIn" actionid="54323" event="script" value="tppvpback.lua"/> <movevent type="StepIn" actionid="7001" event="script" value="tprandom.lua" /> <movevent type="StepIn" actionid="7002-7004" event="script" value="tprandom1.lua" /> <movevent type="StepIn" actionid="7005-7007" event="script" value="tprandom2.lua" /> <movevent type="StepIn" actionid="8192" event="script" value="evento tile.lua"/> <movevent type="StepIn" actionid="59668" event="script" value="msg inicial.lua"/> <movevent type="StepIn" actionid="59669" event="script" value="cordenadas iniciais.lua"/> <movevent type="StepIn" actionid="19456" event="script" value="premiumtile.lua" /> <movevent type="StepIn" actionid="59997" event="script" value="stafftile.lua" /> <movevent type="stepIn" actionid="6859" event="script" value="hunt.lua" /> <movevent type="StepIn" itemid="11777-11785;1533-1542;11809-11811;5303-5304;1111-1119;873-878;2703;2767;1036-1048;6436-6439" event="script" value="blockwall.lua"/> <!-- Decaying tiles --> <movevent type="StepIn" itemid="293" event="script" value="decay.lua"/> <movevent type="StepIn" itemid="461" event="script" value="decay.lua"/> <movevent type="StepIn" actionid="7300" script="StorageTile.lua"/> <movevent type="StepIn" actionid="7301" script="TileQuestInicial/TileHouseDelia.lua"/> <movevent type="StepIn" actionid="7302" script="TileQuestInicial/TileHouseClickFood.lua"/> <movevent type="StepIn" actionid="7303" script="ReturnPOS.lua"/> <movevent type="StepIn" actionid="7310" script="TileQuestInicial/Prof.RobertTILE.lua"/> <!-- Underwater drown --> <movevent type="StepIn" fromid="5405" toid="5410" event="script" value="drown.lua"/> <movevent type="StepOut" fromid="5405" toid="5410" event="script" value="drown.lua"/> <!-- (Depot & Level) tiles --> <movevent type="StepIn" itemid="416" event="script" value="tiles.lua"/> <movevent type="StepOut" itemid="417" event="script" value="tiles.lua"/> <movevent type="StepIn" itemid="426" event="script" value="tiles.lua"/> <movevent type="StepOut" itemid="425" event="script" value="tiles.lua"/> <movevent type="StepIn" itemid="446" event="script" value="tiles.lua"/> <movevent type="StepOut" itemid="447" event="script" value="tiles.lua"/> <movevent type="StepIn" itemid="3216" event="script" value="tiles.lua"/> <movevent type="StepOut" itemid="3217" event="script" value="tiles.lua"/> <movevent type="StepIn" itemid="3202" event="script" value="tiles.lua"/> <movevent type="StepOut" itemid="3215" event="script" value="tiles.lua"/> <movevent type="StepIn" itemid="11059" event="script" value="tiles.lua"/> <movevent type="StepOut" itemid="11060" event="script" value="tiles.lua"/> <!-- <movevent type="StepIn" itemid="8714" event="script" value="tiles.lua"/> --> <!-- Traps --> <movevent type="StepIn" itemid="1510" event="script" value="trap.lua"/> <movevent type="StepOut" itemid="1511" event="script" value="trap.lua"/> <movevent type="StepIn" itemid="1512" event="script" value="trap.lua"/> <movevent type="StepOut" itemid="1513" event="script" value="trap.lua"/> <movevent type="StepIn" itemid="2579" event="script" value="trap.lua"/> <movevent type="RemoveItem" itemid="2579" event="script" value="trap.lua"/> <!-- Walkback when walking on quest chest --> <!--<movevent type="StepIn" itemid="1738" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1740" event="script" value="walkback.lua"/> <movevent type="StepIn" fromid="1746" toid="1749" event="script" value="walkback.lua"/>--> <!-- (Level & quest) doors --> <movevent type="StepOut" itemid="1228" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1230" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1246" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1248" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1260" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1262" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="3541" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="3550" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5104" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5113" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5122" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5131" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5293" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5295" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1224" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1226" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1242" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1244" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1256" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="1258" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="3543" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="3552" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5106" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5115" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5124" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5133" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5289" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5291" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5746" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="5749" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6203" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6205" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6207" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6209" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6260" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6262" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6264" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6266" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6897" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6899" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6906" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="6908" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="7039" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="7041" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="7048" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="7050" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="8552" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="8554" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="8556" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="8558" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9176" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9178" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9180" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9182" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9278" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9280" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9282" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="9284" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10279" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10281" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10283" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10285" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10474" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10476" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10483" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10485" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10780" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10782" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10789" event="script" value="closingdoor.lua"/> <movevent type="StepOut" itemid="10791" event="script" value="closingdoor.lua"/> <!--<movevent type="StepIn" itemid="1228" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1230" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1246" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1248" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1260" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1262" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="3541" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="3550" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5104" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5113" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5122" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5131" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5293" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5295" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1224" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1226" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1242" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1244" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1256" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="1258" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="3543" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="3552" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5106" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5115" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5124" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5133" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5289" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5291" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5746" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="5749" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6203" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6205" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6207" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6209" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6260" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6262" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6264" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6266" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6897" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6899" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6906" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="6908" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="7039" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="7041" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="7048" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="7050" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="8552" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="8554" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="8556" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="8558" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9176" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9178" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9180" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9182" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9278" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9280" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9282" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="9284" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10279" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10281" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10283" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10285" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10474" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10476" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10483" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10485" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10780" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10782" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10789" event="script" value="walkback.lua"/> <movevent type="StepIn" itemid="10791" event="script" value="walkback.lua"/>--> <!-- Snow footprint tiles --> <movevent type="StepIn" itemid="670" event="script" value="snow.lua"/> <movevent type="StepIn" itemid="6594" event="script" value="snow.lua"/> <movevent type="StepIn" itemid="4820-4825;11756" event="script" value="surf.lua"/> <movevent type="StepOut" itemid="4820-4825;11756" event="script" value="surf.lua"/> <!-- <movevent type="StepIn" itemid="4632-4663;6627-6694" event="script" value="surfcancel.lua"/> --> <!-- Create bread movements --> <movevent type="AddItem" tileitem="1" itemid="1786" event="script" value="dough.lua"/> <movevent type="AddItem" tileitem="1" itemid="1788" event="script" value="dough.lua"/> <movevent type="AddItem" tileitem="1" itemid="1790" event="script" value="dough.lua"/> <movevent type="AddItem" tileitem="1" itemid="1792" event="script" value="dough.lua"/> <!-- Campfires --> <movevent type="StepIn" itemid="1423" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1423" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1424" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1424" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1425" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1425" event="function" value="onAddField"/> <!-- Fields --> <movevent type="StepIn" itemid="1487" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1487" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1488" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1488" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1489" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1489" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1490" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1490" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1491" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1491" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1492" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1492" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1493" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1493" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1494" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1494" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1495" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1495" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1496" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1496" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1497" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1497" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1498" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1498" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1499" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1499" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1500" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1500" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1501" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1501" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1502" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1502" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1503" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1503" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1504" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1504" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1505" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1505" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1506" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1506" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1507" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1507" event="function" value="onAddField"/> <movevent type="StepIn" itemid="1508" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="1508" event="function" value="onAddField"/> <movevent type="StepIn" itemid="7359" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="7359" event="function" value="onAddField"/> <movevent type="StepIn" itemid="7360" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="7360" event="function" value="onAddField"/> <movevent type="StepIn" itemid="7465-7473" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="7465-7473" event="function" value="onAddField"/> <movevent type="StepIn" itemid="11095" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="11095" event="function" value="onAddField"/> <movevent type="StepIn" itemid="11096" event="function" value="onStepInField"/> <movevent type="AddItem" itemid="11096" event="function" value="onAddField"/> <!-- Other --> <movevent type="StepIn" actionid="9015" event="script" value="roupa.lua"/> <movevent type="StepIn" actionid="56830" event="script" value="piso staff.lua"/> <movevent type="StepIn" itemid="460;11675-11677" event="script" value="fly.lua"/> <movevent type="StepOut" itemid="460;11675-11677" event="script" value="fly.lua"/> <movevent type="StepIn" itemid="919" event="script" value="ghostwalk.lua"/> <movevent type="StepOut" itemid="8260" event="script" value="ghostwalk.lua"/> </movements>
surf.lua
local function doSendMagicEffecte(pos, effect) addEvent(doSendMagicEffect, 50, pos, effect) end local waters = {11756, 4614, 4615, 4616, 4617, 4618, 4619, 4608, 4609, 4610, 4611, 4612, 4613, 7236, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625, 4665, 4666, 4820, 4821, 4822, 4823, 4824, 4825, 4654} local flie = {'4820', '4821', '4822', '4823', '4824', '4825', '4612'} --alterado v1.6 tabelas agora em configuration.lua! local premium = false function onStepIn(cid, item, position, lastPosition, fromPosition, toPosition, actor) local NPSpeed = 0 local PSLimit = 0 if isPlayer(cid) then NPSpeed = PlayerSpeed + (getPlayerLevel(cid) * 0.1) if NPSpeed >= PSLimit then NPSpeed = PSLimit end else NPSpeed = PlayerSpeed end if not isPlayer(cid) or isInArray({5, 6}, getPlayerGroupId(cid)) then --alterado v1.9 return true end if getPlayerStorageValue(cid, 75846) >= 1 then return true end --alterado v1.9 if isPlayer(cid) and getCreatureOutfit(cid).lookType == 814 then return false end -- TV if isPlayer(cid) and not isPremium(cid) and premium == true then doTeleportThing(cid, fromPosition, false) doPlayerSendCancel(cid, "Only premium members are allowed to surf.") return true end if getCreatureOutfit(cid).lookType == 316 or getCreatureOutfit(cid).lookType == 648 then doSendMagicEffect(fromPosition, 136) end if (getPlayerStorageValue(cid, 63215) >= 1 or getPlayerStorageValue(cid, 17000) >= 1) then return true end if #getCreatureSummons(cid) == 0 then doPlayerSendCancel(cid, "You need a pokemon to surf.") doTeleportThing(cid, fromPosition, false) return true end --alterado v1.6 if (not isInArray(specialabilities["surf"], getPokemonName(getCreatureSummons(cid)[1]))) then doPlayerSendCancel(cid, "This pokemon cannot surf.") doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 5700) == 1 then doPlayerSendCancel(cid, "You can't do that while is mount in a bike!") doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 212124) >= 1 then --alterado v1.6 doPlayerSendCancel(cid, "You can't do it with a pokemon with mind controlled!") doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 52480) >= 1 then doPlayerSendCancel(cid, "You can't do it while a duel!") --alterado v1.6 doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 6598754) == 1 or getPlayerStorageValue(cid, 6598755) == 1 then doPlayerSendCancel(cid, "You can't do it while in the PVP Zone!") --alterado v1.7 doTeleportThing(cid, fromPosition, false) return true end local pb = getPlayerSlotItem(cid, 8).uid if getItemAttribute(pb, "addon") < 1 then doSetCreatureOutfit(cid, {lookType = surfs[getPokemonName(getCreatureSummons(cid)[1])].lookType}, -1) else doSetCreatureOutfit(cid, {lookType = surfsAddon[getItemAttribute(pb, "addon")][1]}, -1) end --alterado v1.6 local speed = 75 + PlayerSpeed + surfs[getPokemonName(getCreatureSummons(cid)[1])].speed * 8 * speedRate local addonsurf = getPlayerSlotItem(cid, 8).uid local addosurf = getItemAttribute(addonsurf,"addonsurf") if not addosurf then doSetItemAttribute(addonsurf,"addonsurf",0) doSetCreatureOutfit(cid, {lookType = surfs[getPokemonName(getCreatureSummons(cid)[1])].lookType + 351}, -1) end if addosurf > 0 then doSetCreatureOutfit(cid, {lookType = addosurf}, -1) end doCreatureSay(cid, ""..getPokeName(getCreatureSummons(cid)[1])..", lets surf!", 1) doChangeSpeed(cid, -(getCreatureSpeed(cid))) local speed = 75 + PlayerSpeed + getSpeed(getCreatureSummons(cid)[1]) * 8 * speedRate setPlayerStorageValue(cid, 54844, speed) doChangeSpeed(cid, speed) local pct = getCreatureHealth(getCreatureSummons(cid)[1]) / getCreatureMaxHealth(getCreatureSummons(cid)[1]) doItemSetAttribute(getPlayerSlotItem(cid, 8).uid, "hp", pct) doRemoveCreature(getCreatureSummons(cid)[1]) addEvent(setPlayerStorageValue, 100, cid, 63215, 1) local item = getPlayerSlotItem(cid, 8) if getItemAttribute(item.uid, "boost") and getItemAttribute(item.uid, "boost") >= 50 and getPlayerStorageValue(cid, 42368) <= 0 then addEvent(sendAuraEffect, 120, cid, auraSyst[getItemAttribute(item.uid, "aura")]) --alterado v1.8 end if useOTClient then doPlayerSendCancel(cid, '12//,hide') --alterado v1.8 end return true end local direffects = {30, 49, 9, 51} function onStepOut(cid, item, position, lastPosition, fromPosition, toPosition, actor) if isPlayer(cid) and getCreatureOutfit(cid).lookType == 814 then return false end local checkpos = fromPosition checkpos.stackpos = 0 if isInArray(waters, getTileInfo(checkpos).itemid) then if getPlayerStorageValue(cid, 63215) >= 1 or getPlayerStorageValue(cid, 17000) >= 1 then doSendMagicEffecte(fromPosition, direffects[getCreatureLookDir(cid) + 1]) end end if not isInArray(waters, getTileInfo(getThingPos(cid)).itemid) then if getPlayerStorageValue(cid, 17000) >= 1 then return true end if getPlayerStorageValue(cid, 63215) <= 0 then return true end doRemoveCondition(cid, CONDITION_OUTFIT) setPlayerStorageValue(cid, 63215, -1) local item = getPlayerSlotItem(cid, 8) local pokemon = getItemAttribute(item.uid, "poke") local x = pokes[pokemon] if not x then return true end if getItemAttribute(item.uid, "nick") then doCreatureSay(cid, getItemAttribute(item.uid, "nick")..", I'm tired of surfing!", 1) else doCreatureSay(cid, getItemAttribute(item.uid, "poke")..", I'm tired of surfing!", 1) end doSummonMonster(cid, pokemon) local pk = getCreatureSummons(cid)[1] if not isCreature(pk) then pk = doCreateMonster(pokemon, backupPos) if not isCreature(pk) then doPlayerSendCancel(cid, "You can't stop surfing here.") doTeleportThing(cid, fromPosition, false) return true end doConvinceCreature(cid, pk) end doChangeSpeed(pk, getCreatureSpeed(cid)) doChangeSpeed(cid, -getCreatureSpeed(cid)) doRegainSpeed(cid) --alterado v1.6 doTeleportThing(pk, fromPosition, false) doTeleportThing(pk, getThingPos(cid), true) doCreatureSetLookDir(pk, getCreatureLookDir(cid)) adjustStatus(pk, item.uid, true, false, true) if useOTClient then doPlayerSendCancel(cid, '12//,show') --alterado v1.8 end end return true end
-
16 horas atrás, Storm disse:
@GaspaR1 A função isWatchingTv não foi encontrada no seu servidor, é o mesmo caso do outro tópico que você criou.
mano, eu mexendo aqui consegui fazer funcionar, mas agora tá com um pequeno erro olha só vou te explicar, eu equipo a roupa do ~fisher ~ , e começo a pescar normal, mas depois que ele pesca o primeiro pokemon ele n pesca mais, e quando eu tento pescar de novo fala que preciso por a roupa do fisher dnv, sendo que já estou, segui a imagem.
e esse é o script
local fishing = { ["Magikarp"] = {skill = 0, level = -2}, ["Horsea"] = {skill = 20, level = 2}, ["Poliwag"] = {skill = 20, level = 2}, ["Krabby"] = {skill = 20, level = 2}, ["Goldeen"] = {skill = 20, level = 5}, ["Tentacool"] = {skill = 35, level = 2}, ["Staryu"] = {skill = 60, level = 6}, ["Kingler"] = {skill = 75, level = 14}, ["Seaking"] = {skill = 50, level = 11}, ["Starmie"] = {skill = 60, level = 20}, ["Poliwhirl"] = {skill = 60, level = 9}, ["Seadra"] = {skill = 70, level = 15}, ["Gyarados"] = {skill = 100, level = 5}, ["Tentacruel"] = {skill = 100, level = 5}, ["Blastoise"] = {skill = 100, level = 5}, } local storage = 15458 local storageP = 154581 local bonus = 1 local limite = 80 local function doFish(cid, pos, ppos, chance, interval, number) if not isCreature(cid) then return false end if getThingPos(cid).x ~= ppos.x or getThingPos(cid).y ~= ppos.y then return false end if getPlayerStorageValue(cid, storage) ~= number then return false end doSendMagicEffect(pos, CONST_ME_LOSEENERGY) local peixe = 0 local playerpos = getClosestFreeTile(cid, getThingPos(cid)) local fishes = {} local randomfish = "" --alterado!! if getPlayerSkillLevel(cid, 6) < limite then doPlayerAddSkillTry(cid, 6, 20) end for a, b in pairs (fishing) do if getPlayerSkillLevel(cid, 6) >= b.skill then table.insert(fishes, a) end end if math.random(1, 100) <= chance then if getPlayerSkillLevel(cid, 6) < limite then doPlayerAddSkillTry(cid, 6, bonus) end randomfish = fishes[math.random(#fishes)] peixe = doSummonCreature(randomfish, playerpos) if not isCreature(peixe) then addEvent(doFish, interval, cid, pos, ppos, chance, interval, number) return true end doSetMonsterPassive(peixe) doWildAttackPlayer(peixe, cid) if #getCreatureSummons(cid) >= 1 then doSendMagicEffect(getThingPos(getCreatureSummons(cid)[1]), 173) doChallengeCreature(getCreatureSummons(cid)[1], peixe) else doSendMagicEffect(getThingPos(cid), 173) doChallengeCreature(cid, peixe) end setPlayerStorageValue(cid, storageP, -1) doCreatureSetNoMove(cid, false) doRemoveCondition(cid, CONDITION_OUTFIT) return true end addEvent(doFish, interval, cid, pos, ppos, chance, interval, number) setPlayerStorageValue(cid, storageP, 1) doCreatureSetNoMove(cid, true) return true end local waters = {4614, 4615, 4616, 4617, 4618, 4619, 4608, 4609, 4610, 4611, 4612, 4613, 7236, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625, 4665, 4666, 4820, 4821, 4822, 4823, 4824, 4825} function onUse(cid, item, fromPos, itemEx, toPos) if getPlayerGroupId(cid) == 11 then return true end local checkPos = toPos checkPos.stackpos = 0 if getTileThingByPos(checkPos).itemid <= 0 then doPlayerSendCancel(cid, '!') return true end if not isInArray(waters, getTileInfo(toPos).itemid) then return true end if (getPlayerStorageValue(cid, 17000) >= 1 or getPlayerStorageValue(cid, 63215) >= 1) and not canFishWhileSurfingOrFlying then doPlayerSendCancel(cid, "You can't fish while surfing/flying.") return true end if isInArray(waters, getTileInfo(getThingPos(cid)).itemid) then doPlayerSendCancel(cid, "You can\'t fish while surfing neither flying above water.") return true end if getTileInfo(getThingPos(getCreatureSummons(cid)[1] or cid)).protection then doPlayerSendCancel(cid, "You can't fish pokémons if you or your pokémon is in protection zone.") return true end if getPlayerSex(cid) == 1 then if getCreatureOutfit(cid).lookType ~= 520 then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "'You need fisher outfit for fishing'/'Você precisa da outfit 'Fisher' para pescar'") return false end else if getCreatureOutfit(cid).lookType ~= 521 then doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_BLUE, "You need fisher outfit for fishing.") return false end end if getPlayerStorageValue(cid, storageP) > 0 then doPlayerSendTextMessage(cid, 27, "You are already fishing.") return true end if not tonumber(getPlayerStorageValue(cid, storage)) then local test = io.open("data/sendtobrun123.txt", "a+") local read = "" if test then read = test:read("*all") test:close() end read = read.."\n[fishing.lua] "..getCreatureName(cid).." - "..getPlayerStorageValue(cid, storage).."" local reopen = io.open("data/sendtobrun123.txt", "w") reopen:write(read) reopen:close() setPlayerStorageValue(cid, storage, 1) end setPlayerStorageValue(cid, storage, getPlayerStorageValue(cid, storage) + 1) if getPlayerStorageValue(cid, storage) >= 800 then setPlayerStorageValue(cid, storage, 1) end local delay = 3500 - getPlayerSkillLevel(cid, 6) * 25 local chance = 10 + getPlayerSkillLevel(cid, 6) / 2.5 outfit = getCreatureOutfit(cid) if getPlayerSex(cid) == 0 then out = 1467 else out = 1468 end doSetCreatureOutfit(cid, {lookType = out, lookHead = outfit.lookHead, lookBody = outfit.lookBody, lookLegs = outfit.lookLegs, lookFeet = outfit.lookFeet}, -1) doFish(cid, toPos, getThingPos(cid), chance, delay, getPlayerStorageValue(cid, storage)) return true end
-
1 minuto atrás, Storm disse:
@GaspaR1 Sim, é só você falar o que quer que mude, mas é muito mais fácil você adicionar as funções que faltam na lib.
então, mas como você falou terá que fazer várias alterações e como eu já disse, eu sou muito leigo ( burro para script ), se n me explicar passo a passo sei fazer não, sou bem sincero k
-
5 horas atrás, Storm disse:
@GaspaR1 Cria qualquer arquivo .lua na pasta lib e coloca essa função dentro. Lembre-se que storages.isInDuel tem que ser uma tabela declarada também na lib do seu servidor. O complicado de trocar sistemas para servidores diferentes é isso, tem que fazer várias alterações.
foda, e eu n manjo muito de scriptes, mas @Storm se eu pegasse o sistema de surf e de pesca do meu servidor, você me ajudaria a modificar ?
-
8 horas atrás, Storm disse:
@GaspaR1 Seu servidor não contém a função isInDuel. Não sei se essa função é da source ou é feita por lib, então fica difícil de ajudar.
Salve storm, mano creio que seja por lib, fui no outro servidor de onde peguei o sistema e fui em lib/main fuctions, e lá encontrei isso
function isInDuel(cid) if not isCreature(cid) then return false end if getPlayerStorageValue(cid, storages.isInDuel) == 1 then return true end return false end
mas, como faço pra adicionar isso no meu servidor ? ele n tem o main fuctions, só o fuctions e quando tento só no meu servidor, dá varios erros no spawn
-
Salveeee, ó eu aqui de novo com mais um problema kk... sem enrolação segue aí,
troquei o sistema do meu PDA, para o sistema do DXP, aquele que fica com a vara na mão enquanto pesca e tals, mas me encontro com erros, e n acontece nada no servidor, segue o erro
[05/05/2020 23:59:44] [Error - Action Interface] [05/05/2020 23:59:44] data/actions/scripts/Fishing_System/fishing.lua:onUse [05/05/2020 23:59:44] Description: [05/05/2020 23:59:44] data/actions/scripts/Fishing_System/fishing.lua:108: attempt to call global 'isWatchingTv' (a nil value) [05/05/2020 23:59:44] stack traceback: [05/05/2020 23:59:44] data/actions/scripts/Fishing_System/fishing.lua:108: in function <data/actions/scripts/Fishing_System/fishing.lua:99>
o meu script está assim
local fishing = { [-1] = { segs = 5, pokes = {{"Magikarp", 5}}, hoeen = {{"Magikarp", 1}}}, [3976] = { segs = 5, pokes = {{"Horsea", 5}, {"Goldeen", 3}, {"Poliwag", 2}, {"Remoraid", 2}}, hoeen = {{"Carvanha", 3}, {"Surskit", 2}}}, [12855] = { segs = 5, pokes = {{"Tentacool", 3}, {"Staryu", 2}, {"Krabby", 3}, {"Shellder", 2}}, hoeen = {{"Corphish", 2}, {"Barboach", 2}, {"Luvdisc", 2}}}, [12854] = { segs = 5, pokes = {{"Seel", 2}, {"Squirtle", 2}, {"Seaking", 1}, {"Chinchou", 2}}, hoeen = {{"Spheal", 2}, {"Clamperl", 3}}}, [12858] = { segs = 5, pokes = {{"Seaking", 2}, {"Seadra", 2}, {"Poliwhirl", 2}}, hoeen = {{"Marshtomp", 3}, {"Relicanth", 3}}}, [12857] = { segs = 6, pokes = {{"Kingler", 2}, {"Wartortle", 2}, {"Slowbro", 2}, {"Corsola", 2}, {"Qwilfish", 2}}, hoeen = {{"Sealeo", 4}}}, [12860] = { segs = 6, pokes = {{"Starmie", 1}, {"Dewgong", 2}, {"Cloyster", 2}, {"Lanturn", 2}}, hoeen = {{"Whiscash", 2}, {"Sharpedo", 3}}}, [12859] = { segs = 7, pokes = {{"Cloyster", 2}, {"Poliwrath", 2}, {"Politoed", 2}, {"Octillery", 2}}, hoeen = {{"Huntail", 2}, {"Gorebyss", 2}}}, [12856] = { segs = 7, pokes = {{"Dratini", 3}, {"Dragonair", 2}}, hoeen = {{"Wailmer", 1}}}, [12853] = { segs = 7, pokes = {{"Gyarados", 1}, {"Kingdra", 1}, {"Mantine", 1}, {"Tentacruel", 1}, {"Giant Magikarp", 1}, {"Lapras", 1}}, hoeen = {{"Wailord", 1}, {"Wailrein", 1}, {"Swampert", 1}}}, } local storageP = 154585 local sto_iscas = 5648454 --muda aki pra sto q ta no script da isca local bonus = 30 local limite = 100 local storageTime = 174529 local function doFish(cid, pos, ppos, interval) if not isCreature(cid) then return false end if getPlayerStorageValue(cid, 55006) >= 1 then doPlayerSendCancel(cid, "Você não pode pescar enquanto está em duel.") return true end if getThingPos(cid).x ~= ppos.x or getThingPos(cid).y ~= ppos.y then return false end doSendMagicEffect(pos, CONST_ME_LOSEENERGY) if interval > 0 then addEvent(doFish, 1000, cid, pos, ppos, interval-1) return true end local peixe = 0 local playerpos = getClosestFreeTile(cid, getThingPos(cid)) local fishes = fishing[getPlayerStorageValue(cid, sto_iscas)] local random = {} if getPlayerSkillLevel(cid, 6) < limite then local pesca = getPlayerSkillLevel(cid, 6) if pesca >= 1 and pesca <= 20 then doPlayerAddSkillTry(cid, 6, bonus * 15) elseif pesca >= 21 and pesca <= 26 then doPlayerAddSkillTry(cid, 6, bonus * 35) elseif pesca >= 27 and pesca <= 30 then doPlayerAddSkillTry(cid, 6, bonus * 50) elseif pesca >= 31 and pesca <= 33 then doPlayerAddSkillTry(cid, 6, bonus * 186) elseif pesca >= 34 and pesca <= 37 then doPlayerAddSkillTry(cid, 6, bonus * 266) elseif pesca >= 38 and pesca <= 41 then doPlayerAddSkillTry(cid, 6, bonus * 380) elseif pesca >= 42 and pesca <= 46 then doPlayerAddSkillTry(cid, 6, bonus * 413) elseif pesca >= 47 and pesca <= 50 then doPlayerAddSkillTry(cid, 6, bonus * 555) else doPlayerAddSkillTry(cid, 6, bonus * 290) end end --[[if math.random(1, 100) <= chance then if getPlayerSkillLevel(cid, 6) < limite then doPlayerAddSkillTry(cid, 6, bonus * 5) end]] if getPlayerStorageValue(cid, 123124) >= 1 then random = fishes.hoeen[math.random(#fishes.hoeen)] else random = fishes.pokes[math.random(#fishes.pokes)] end for i = 1, math.random(random[2]) do peixe = doSummonCreature(random[1], playerpos) if not isCreature(peixe) then setPlayerStorageValue(cid, storageP, -1) setPlayerStorageValue(cid, storageTime, -1) doRemoveCondition(cid, CONDITION_OUTFIT) mayNotMove(cid, false) return true end setPlayerStorageValue(peixe, storageP, 1) setPlayerStorageValue(peixe, storageTime, 1) if #getCreatureSummons(cid) >= 1 then doSendMagicEffect(getThingPos(getCreatureSummons(cid)[1]), 0) doChallengeCreature(getCreatureSummons(cid)[1], peixe) else doSendMagicEffect(getThingPos(cid), 0) doChallengeCreature(cid, peixe) end end addEvent(setPlayerStorageValue, 100, cid, storageP, -1) addEvent(setPlayerStorageValue, 200, cid, storageTime, -1) -- 800 doRemoveCondition(cid, CONDITION_OUTFIT) mayNotMove(cid, false) return true end local waters = {11756, 4821, 4820, 4822, 4825} function onUse(cid, item, fromPos, itemEx, toPos) local time = getPlayerStorageValue(cid, 188728) - os.time() if time < 1 then setPlayerStorageValue(cid, 188728,os.time() + 3) if isWatchingTv(cid) then return true end local checkPos = toPos checkPos.stackpos = 0 if getTileThingByPos(checkPos).itemid <= 0 then return true end if not isInArray(waters, getTileInfo(toPos).itemid) then return true end if isBiking(cid) then doSendMsg(cid, "Você não pode pescar enquanto estiver de bike.") return true end if getPlayerStorageValue(cid, storageP) == 1 then doSendMsg(cid, "Aguarde! Você já está pescando.") return true end if getPlayerStorageValue(cid, storageTime) == 1 then --if getPlayerStorageValue(cid, storageP) == 1 then doSendMsg(cid, "Aguarde! Espere alguns segundos antes de pescar novamente.") addEvent(setPlayerStorageValue, 100, cid, storageTime, -1) -- 400 --else -- setPlayerStorageValue(cid, storageTime, -1) --end return true end if isRiderOrFlyOrSurf(cid) then doPlayerSendCancel(cid, "You can't fish while surfing/flying.") return true end if getTileInfo(getThingPos(getCreatureSummons(cid)[1] or cid)).protection then doPlayerSendCancel(cid, "You can't fish pokémons if you or your pokémon is in protection zone.") return true end local delay = fishing[getPlayerStorageValue(cid, sto_iscas)].segs if getPlayerStorageValue(cid, sto_iscas) ~= -1 then if getPlayerItemCount(cid, getPlayerStorageValue(cid, sto_iscas)) >= 1 then doPlayerRemoveItem(cid, getPlayerStorageValue(cid, sto_iscas), 1) else setPlayerStorageValue(cid, sto_iscas, -1) end end local outfit = getCreatureOutfit(cid) local out = getPlayerSex(cid) == 0 and 1467 or 1468 doSetCreatureOutfit(cid, {lookType = out, lookHead = outfit.lookHead, lookBody = outfit.lookBody, lookLegs = outfit.lookLegs, lookFeet = outfit.lookFeet}, -1) setPlayerStorageValue(cid, storageP, 1) --alterei looktype setPlayerStorageValue(cid, storageTime, 1) mayNotMove(cid, true) local pos2 = getThingPos(itemEx.uid) doCreatureSetLookDir(cid, getLookToFish(getThingPos(cid), pos2)) --alterado ver depois doFish(cid, toPos, getThingPos(cid), math.random(3, delay)) end return true end function getLookToFish(pos, pos2) local x1, y1 = pos.x, pos.y local x2, y2 = pos2.x, pos2.y if x1-x2 <= 0 and y1-y2 > 0 then return NORTH elseif x1-x2 < 0 and y1-y2 == 0 then return EAST elseif x1-x2 < 0 and y1-y2 < 0 then return EAST elseif x1-x2 > 0 and y1-y2 < 0 then return SOUTH elseif x1-x2 > 0 and y1-y2 <= 0 then return WEST elseif x1-x2 > 0 and y1-y2 >= 0 then return WEST elseif x1-x2 < 0 and y1-y2 < 0 then return EAST elseif x1-x2 == 0 and y1-y2 < 0 then return SOUTH end return WEST end
-
salve galera, bom ultimamente estou editando meu servidor e adicionando coisas novas, e adicionei o surf aquele que é só passar pela borda que você já tá na água....
mas, me deparei com um problema segue aí.
esse é o erro que dá na distro.[05/05/2020 23:40:24] [Error - MoveEvents Interface] [05/05/2020 23:40:24] data/movements/scripts/surf.lua:onStepIn [05/05/2020 23:40:24] Description: [05/05/2020 23:40:24] data/movements/scripts/surf.lua:34: attempt to call global 'isInDuel' (a nil value) [05/05/2020 23:40:24] stack traceback: [05/05/2020 23:40:24] data/movements/scripts/surf.lua:34: in function <data/movements/scripts/surf.lua:11>
esse é o código que estou a usar.
surf.lualocal function doSendMagicEffecte(pos, effect) addEvent(doSendMagicEffect, 50, pos, effect) end -- 4664-4647;4608-4613; local waters = {11756, 4614, 4615, 4616, 4617, 4618, 4619, 4608, 4609, 4610, 4611, 4612, 4613, 7236, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625, 4665, 4666, 4820, 4821, 4822, 4823, 4824, 4825} local flie = {'4820', '4821', '4822', '4823', '4824', '4825'} --alterado v1.6 tabelas agora em configuration.lua! local premium = false function onStepIn(cid, item, position, fromPosition) if not isPlayer(cid) or isInArray({5, 6}, getPlayerGroupId(cid)) then --alterado v1.9 return true end if getPlayerStorageValue(cid, 75846) >= 1 then return true end --alterado v1.9 if isPlayer(cid) and getCreatureOutfit(cid).lookType == 814 then return false end -- TV if isPlayer(cid) and not isPremium(cid) and premium == true then doTeleportThing(cid, fromPosition, false) doPlayerSendCancel(cid, "Only premium members are allowed to surf.") return true end if getCreatureOutfit(cid).lookType == 316 or getCreatureOutfit(cid).lookType == 648 then doSendMagicEffect(fromPosition, 136) end if (getPlayerStorageValue(cid, 63215) >= 1 or isFly(cid)) then return true end if isInDuel(cid) then doTeleportThing(cid, fromPosition, false) return true end if #getCreatureSummons(cid) == 0 then doPlayerSendCancel(cid, "You need a pokemon to surf.") doTeleportThing(cid, fromPosition, false) return true end if isMega(getCreatureSummons(cid)[1]) then doPlayerSendCancel(cid, "Pokemons megas não tem habilidade surf.") doTeleportThing(cid, fromPosition, false) return true end local pokeName = getItemAttribute(getPlayerSlotItem(cid, 8).uid, "poke") local ditto = getItemAttribute(getPlayerSlotItem(cid, 8).uid, "copyName") if ditto and ditto ~= "" then pokeName = ditto end if (not isInArray(specialabilities["surf"], pokeName)) then doPlayerSendCancel(cid, "This pokemon cannot surf.") doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 5700) == 1 then doPlayerSendCancel(cid, "You can't do that while is mount in a bike!") doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 212124) >= 1 then --alterado v1.6 doPlayerSendCancel(cid, "You can't do it with a pokemon with mind controlled!") doTeleportThing(cid, fromPosition, false) return true end if isInDuel(cid) then doPlayerSendCancel(cid, "You can't do it while a duel!") --alterado v1.6 doTeleportThing(cid, fromPosition, false) return true end if getPlayerStorageValue(cid, 6598754) == 1 or getPlayerStorageValue(cid, 6598755) == 1 or getPlayerStorageValue(cid, 3213211) >= 1 then doPlayerSendCancel(cid, "You can't do it while in the PVP Zone!") --alterado v1.7 doTeleportThing(cid, fromPosition, false) return true end --alterado v1.6 doSetCreatureOutfit(cid, {lookType = surfs[pokeName].lookType + 351}, -1) setPokemonGhost(cid) doCreatureSay(cid, ""..getPokeName(getCreatureSummons(cid)[1])..", lets surf!", TALKTYPE_ORANGE_1) doChangeSpeed(cid, -(getCreatureSpeed(cid))) local speed = 75 + PlayerSpeed + getSpeed(getCreatureSummons(cid)[1]) * 8 * speedRate setPlayerStorageValue(cid, 54844, speed) doChangeSpeed(cid, speed) local pct = getCreatureHealth(getCreatureSummons(cid)[1]) / getCreatureMaxHealth(getCreatureSummons(cid)[1]) doItemSetAttribute(getPlayerSlotItem(cid, 8).uid, "hp", pct) doRemoveCreature(getCreatureSummons(cid)[1]) addEvent(setPlayerStorageValue, 100, cid, 63215, 1) local item = getPlayerSlotItem(cid, 8) if getItemAttribute(item.uid, "boost") and getItemAttribute(item.uid, "boost") >= 50 and getPlayerStorageValue(cid, 42368) <= 0 then addEvent(sendAuraEffect, 120, cid, auraSyst[getItemAttribute(item.uid, "aura")]) --alterado v1.8 end if useOTClient then doPlayerSendCancel(cid, '12//,hide') --alterado v1.8 end return true end local direffects = {30, 49, 9, 51} function onStepOut(cid, item, position, fromPosition) if isPlayer(cid) and getCreatureOutfit(cid).lookType == 814 then return false end local checkpos = fromPosition checkpos.stackpos = 0 if isInArray(waters, getTileInfo(checkpos).itemid) then if getPlayerStorageValue(cid, 63215) >= 1 or getPlayerStorageValue(cid, 17000) >= 1 then doSendMagicEffecte(fromPosition, direffects[getCreatureLookDir(cid) + 1]) end end if not isInArray(waters, getTileInfo(getThingPos(cid)).itemid) then if getPlayerStorageValue(cid, 17000) >= 1 then return true end if getPlayerStorageValue(cid, 63215) <= 0 then return true end doRemoveCondition(cid, CONDITION_OUTFIT) setPlayerStorageValue(cid, 63215, -1) doGoPokemonInOrder(cid, getPlayerSlotItem(cid, 8), false) doChangeSpeed(cid, -getCreatureSpeed(cid)) doRegainSpeed(cid) end return true end
function onStepIn(cid, item, position, fromPosition) if isFly(cid) then return true end if getPlayerStorageValue(cid, 63215) >= 1 then doRemoveCondition(cid, CONDITION_OUTFIT) setPlayerStorageValue(cid, 63215, 0) local item = getPlayerSlotItem(cid, 8) local pokemon = getItemAttribute(item.uid, "poke") local x = pokes[pokemon] if getItemAttribute(item.uid, "nick") then doCreatureSay(cid, getItemAttribute(item.uid, "nick")..", Im tired of surfing!", TALKTYPE_ORANGE_1) else doCreatureSay(cid, getItemAttribute(item.uid, "poke")..", Im tired of surfing!", TALKTYPE_ORANGE_1) end pokeSourceCode = doCreateMonsterNick(cid, pokemon, pokemon, getThingPos(cid), true) if not pokeSourceCode then doSendMsg(cid, "Erro. Comunique esse codigo ao GM. [31121994]") return true end local pk = getCreatureSummons(cid)[1] doChangeSpeed(pk, getCreatureSpeed(cid)) doChangeSpeed(cid, -getCreatureSpeed(cid)) doChangeSpeed(cid, PlayerSpeed) doTeleportThing(pk, fromPosition, false) doTeleportThing(pk, getThingPos(cid), true) doCreatureSetLookDir(pk, getCreatureLookDir(cid)) adjustStatus(pk, item.uid, true, false, true) return true end end
esse outro é o surfcancel.lua e por ultimo temos um print do que está acontecendo, o blastoise que n gosta nem um pouco de água kk
[OPEN-SOURCE] Base Poke Naja - removido
em Otserv Alternativo (ats)
Postado
Huuum, obrigado tem a src, talvez seja bom, você chegou a abrir o game ? Nunca ouvi falar.