From 093fc81dfd065dcea6f052af90904611b991f6e3 Mon Sep 17 00:00:00 2001 From: Sarah Wesker Date: Sun, 28 Apr 2024 16:30:17 -0400 Subject: [PATCH] fix networkmessage / fix pos distances / otcv8 features --- src/combat.cpp | 8 +-- src/combat.h | 2 +- src/const.h | 142 ++++++++++++++++++++++++++++++++++++++ src/creature.cpp | 18 ++--- src/game.cpp | 2 +- src/itemloader.h | 1 + src/items.cpp | 8 +++ src/items.h | 1 + src/luanetworkmessage.cpp | 41 +++++++++-- src/luascript.cpp | 141 +++++++++++++++++++++++++++++++++++++ src/map.cpp | 6 +- src/monster.cpp | 86 ++++------------------- src/npc.cpp | 6 +- src/protocolgame.cpp | 56 +++++++++++++-- src/protocolgame.h | 2 + src/weapons.cpp | 2 +- 16 files changed, 416 insertions(+), 106 deletions(-) diff --git a/src/combat.cpp b/src/combat.cpp index 09daf1f..7b534af 100644 --- a/src/combat.cpp +++ b/src/combat.cpp @@ -22,7 +22,7 @@ std::vector getList(const MatrixArea& area, const Position& targetPos, co std::vector vec; - auto center = area.getCenter(); + auto& center = area.getCenter(); Position tmpPos(targetPos.x - center.first, targetPos.y - center.second, targetPos.z); for (uint32_t row = 0; row < area.getRows(); ++row, ++tmpPos.y) { @@ -437,7 +437,7 @@ bool Combat::setParam(CombatParam_t param, uint32_t value) return false; } -int32_t Combat::getParam(CombatParam_t param) +int32_t Combat::getParam(CombatParam_t param) const { switch (param) { case COMBAT_PARAM_TYPE: @@ -1222,8 +1222,8 @@ void TargetCallback::onTargetCombat(Creature* creature, Creature* target) const const MatrixArea& AreaCombat::getArea(const Position& centerPos, const Position& targetPos) const { - int32_t dx = centerPos.getOffsetX(targetPos); - int32_t dy = centerPos.getOffsetY(targetPos); + int32_t dx = targetPos.getOffsetX(centerPos); + int32_t dy = targetPos.getOffsetY(centerPos); Direction dir; if (dx < 0) { diff --git a/src/combat.h b/src/combat.h index bef8026..99faa3b 100644 --- a/src/combat.h +++ b/src/combat.h @@ -115,7 +115,7 @@ class Combat bool loadCallBack(CallBackParam key, LuaScriptInterface* scriptInterface); bool setParam(CombatParam_t param, uint32_t value); - int32_t getParam(CombatParam_t param); + int32_t getParam(CombatParam_t param) const; void setArea(AreaCombat* area); bool hasArea() const { return area != nullptr; } diff --git a/src/const.h b/src/const.h index 7d28ff7..594e530 100644 --- a/src/const.h +++ b/src/const.h @@ -487,6 +487,148 @@ enum ReloadTypes_t : uint8_t RELOAD_TYPE_WEAPONS, }; +enum class GameFeature : uint8_t +{ + ProtocolChecksum = 1, + AccountNames = 2, + ChallengeOnLogin = 3, + PenalityOnDeath = 4, + NameOnNpcTrade = 5, + DoubleFreeCapacity = 6, + DoubleExperience = 7, + TotalCapacity = 8, + SkillsBase = 9, + PlayerRegenerationTime = 10, + ChannelPlayerList = 11, + PlayerMounts = 12, + EnvironmentEffect = 13, + CreatureEmblems = 14, + ItemAnimationPhase = 15, + MagicEffectU16 = 16, + PlayerMarket = 17, + SpritesU32 = 18, + TileAddThingWithStackpos = 19, + OfflineTrainingTime = 20, + PurseSlot = 21, + FormatCreatureName = 22, + SpellList = 23, + ClientPing = 24, + ExtendedClientPing = 25, + DoubleHealth = 28, + DoubleSkills = 29, + ChangeMapAwareRange = 30, + MapMovePosition = 31, + AttackSeq = 32, + BlueNpcNameColor = 33, + DiagonalAnimatedText = 34, + LoginPending = 35, + NewSpeedLaw = 36, + ForceFirstAutoWalkStep = 37, + MinimapRemove = 38, + DoubleShopSellAmount = 39, + ContainerPagination = 40, + ThingMarks = 41, + LooktypeU16 = 42, + PlayerStamina = 43, + PlayerAddons = 44, + MessageStatements = 45, + MessageLevel = 46, + NewFluids = 47, + PlayerStateU16 = 48, + NewOutfitProtocol = 49, + PVPMode = 50, + WritableDate = 51, + AdditionalVipInfo = 52, + BaseSkillU16 = 53, + CreatureIcons = 54, + HideNpcNames = 55, + SpritesAlphaChannel = 56, + PremiumExpiration = 57, + BrowseField = 58, + EnhancedAnimations = 59, + OGLInformation = 60, + MessageSizeCheck = 61, + PreviewState = 62, + LoginPacketEncryption = 63, + ClientVersion = 64, + ContentRevision = 65, + ExperienceBonus = 66, + Authenticator = 67, + UnjustifiedPoints = 68, + SessionKey = 69, + DeathType = 70, + IdleAnimations = 71, + KeepUnawareTiles = 72, + IngameStore = 73, + IngameStoreHighlights = 74, + IngameStoreServiceType = 75, + AdditionalSkills = 76, + DistanceEffectU16 = 77, + Prey = 78, + DoubleMagicLevel = 79, + + ExtendedOpcode = 80, + MinimapLimitedToSingleFloor = 81, + SendWorldName = 82, + + DoubleLevel = 83, + DoubleSoul = 84, + DoublePlayerGoodsMoney = 85, + CreatureWalkthrough = 86, + DoubleTradeMoney = 87, + SequencedPackets = 88, + Tibia12Protocol = 89, + + // 90-99 otclientv8 features + NewWalking = 90, + SlowerManualWalking = 91, + + ItemTooltip = 93, + + Bot = 95, + BiggerMapCache = 96, + ForceLight = 97, + NoDebug = 98, + BotProtection = 99, + + // Custom features for customer + CreatureDirectionPassable = 100, + FasterAnimations = 101, + CenteredOutfits = 102, + SendIdentifiers = 103, + WingsAndAura = 104, + PlayerStateU32 = 105, + OutfitShaders = 106, + ForceAllowItemHotkeys = 107, + CountU16 = 108, + DrawAuraOnTop = 109, + + // advanced features + PacketSizeU32 = 110, + PacketCompression = 111, + + // OTCv8-dev features + OldInformationBar = 112, + HealthInfoBackground = 113, + WingOffset = 114, + AuraFrontAndBack = 115, + + MapDrawGroundFirst = 116, + MapIgnoreCorpseCorrection = 117, + DontCacheFiles = 118, + BigAurasCenter = 119, + NewUpdateWalk = 120, + NewCreatureStacking = 121, + CreaturesMana = 122, + QuickLootFlags = 123, + DontMergeAnimatedText = 124, + MissionId = 125, + ItemCustomAttributes = 126, + AnimatedTextCustomFont = 127, + + LastFeature = 130 +}; + inline constexpr int32_t CHANNEL_GUILD = 0x00; inline constexpr int32_t CHANNEL_PARTY = 0x01; inline constexpr int32_t CHANNEL_PRIVATE = 0xFFFF; diff --git a/src/creature.cpp b/src/creature.cpp index ab03f22..2fb2013 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -338,8 +338,8 @@ void Creature::updateTileCache(const Tile* tile, const Position& pos) { const Position& myPos = getPosition(); if (pos.z == myPos.z) { - int32_t dx = myPos.getOffsetX(pos); - int32_t dy = myPos.getOffsetY(pos); + int32_t dx = pos.getOffsetX(myPos); + int32_t dy = pos.getOffsetY(myPos); updateTileCache(tile, dx, dy); } } @@ -359,8 +359,8 @@ int32_t Creature::getWalkCache(const Position& pos) const return 1; } - if (int32_t dx = myPos.getOffsetX(pos); std::abs(dx) <= maxWalkCacheWidth) { - if (int32_t dy = myPos.getOffsetY(pos); std::abs(dy) <= maxWalkCacheHeight) { + if (int32_t dx = pos.getOffsetX(myPos); std::abs(dx) <= maxWalkCacheWidth) { + if (int32_t dy = pos.getOffsetY(myPos); std::abs(dy) <= maxWalkCacheHeight) { if (localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx]) { return 1; } @@ -476,7 +476,7 @@ void Creature::onCreatureMove(Creature* creature, const Tile* newTile, const Pos if (oldPos.z != newPos.z) { // floor change extra cost lastStepCost = 2; - } else if (newPos.getDistanceX(oldPos) >= 1 && oldPos.getDistanceY(newPos) >= 1) { + } else if (newPos.getDistanceX(oldPos) >= 1 && newPos.getDistanceY(oldPos) >= 1) { // diagonal extra cost lastStepCost = 3; if (getPlayer()) { @@ -492,7 +492,7 @@ void Creature::onCreatureMove(Creature* creature, const Tile* newTile, const Pos std::forward_list despawnList; for (Creature* summon : summons) { const Position& pos = summon->getPosition(); - if (newPos.getDistanceZ(pos) > 2 || std::max(newPos.getDistanceX(pos), pos.getDistanceY(newPos)) > 30) { + if (newPos.getDistanceZ(pos) > 2 || std::max(newPos.getDistanceX(pos), newPos.getDistanceY(pos)) > 30) { despawnList.push_front(summon); } } @@ -1565,7 +1565,7 @@ bool FrozenPathingConditionCall::isInRange(const Position& startPos, const Posit return false; } } else { - int32_t dx = targetPos.getOffsetX(startPos); + int32_t dx = startPos.getOffsetX(targetPos); int32_t dxMax = (dx >= 0 ? fpp.maxTargetDist : 0); if (testPos.x > targetPos.x + dxMax) { @@ -1577,7 +1577,7 @@ bool FrozenPathingConditionCall::isInRange(const Position& startPos, const Posit return false; } - int32_t dy = targetPos.getOffsetY(startPos); + int32_t dy = startPos.getOffsetY(targetPos); int32_t dyMax = (dy >= 0 ? fpp.maxTargetDist : 0); if (testPos.y > targetPos.y + dyMax) { @@ -1603,7 +1603,7 @@ bool FrozenPathingConditionCall::operator()(const Position& startPos, const Posi return false; } - int32_t testDist = std::max(targetPos.getDistanceX(testPos), testPos.getDistanceY(targetPos)); + int32_t testDist = std::max(targetPos.getDistanceX(testPos), targetPos.getDistanceY(testPos)); if (fpp.maxTargetDist == 1) { if (testDist < fpp.minTargetDist || testDist > fpp.maxTargetDist) { return false; diff --git a/src/game.cpp b/src/game.cpp index aacf59c..151360f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3195,7 +3195,7 @@ void Game::playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos int32_t lookDistance = -1; if (thing != player) { - lookDistance = std::max(playerPos.getDistanceX(thingPos), thingPos.getDistanceY(playerPos)); + lookDistance = std::max(playerPos.getDistanceX(thingPos), playerPos.getDistanceY(thingPos)); if (playerPos.z != thingPos.z) { lookDistance += 15; } diff --git a/src/itemloader.h b/src/itemloader.h index 5eeece5..87c1dd7 100644 --- a/src/itemloader.h +++ b/src/itemloader.h @@ -95,6 +95,7 @@ enum itemattrib_t ITEM_ATTR_WRITEABLE3, // deprecated ITEM_ATTR_WAREID, + ITEM_ATTR_CLASSIFICATION, ITEM_ATTR_LAST }; diff --git a/src/items.cpp b/src/items.cpp index 4f37141..f6491e7 100644 --- a/src/items.cpp +++ b/src/items.cpp @@ -489,6 +489,13 @@ bool Items::loadFromOtb(const std::string& file) break; } + case ITEM_ATTR_CLASSIFICATION: { + if (!stream.skip(1)) { + return false; + } + break; + } + default: { // skip unknown attributes if (!stream.skip(datalen)) { @@ -552,6 +559,7 @@ bool Items::loadFromOtb(const std::string& file) iType.rotatable = hasBitSet(FLAG_ROTATABLE, flags); iType.canReadText = hasBitSet(FLAG_READABLE, flags); iType.lookThrough = hasBitSet(FLAG_LOOKTHROUGH, flags); + iType.isAnimation = hasBitSet(FLAG_ANIMATION, flags); // iType.walkStack = !hasBitSet(FLAG_FULLTILE, flags); iType.forceUse = hasBitSet(FLAG_FORCEUSE, flags); diff --git a/src/items.h b/src/items.h index c80b6b6..e0a74a1 100644 --- a/src/items.h +++ b/src/items.h @@ -401,6 +401,7 @@ class ItemType bool isHangable = false; bool allowDistRead = false; bool lookThrough = false; + bool isAnimation = false; bool stopTime = false; bool showCount = true; bool supply = false; diff --git a/src/luanetworkmessage.cpp b/src/luanetworkmessage.cpp index bf3c3d6..8b2593e 100644 --- a/src/luanetworkmessage.cpp +++ b/src/luanetworkmessage.cpp @@ -13,9 +13,14 @@ using namespace Lua; // NetworkMessage int luaNetworkMessageCreate(lua_State* L) { - // NetworkMessage() + // NetworkMessage([player]) pushUserdata(L, new NetworkMessage); setMetatable(L, -1, "NetworkMessage"); + + if (const auto player = getPlayer(L, 1)) { + lua_pushinteger(L, player->getID()); + lua_setiuservalue(L, 2, 1); + } return 1; } @@ -211,7 +216,17 @@ int luaNetworkMessageAddItem(lua_State* L) NetworkMessage* message = getUserdata(L, 1); if (message) { - message->addItem(item, false); + if (getAssociatedValue(L, 1, 1)) { + if (const auto player = getPlayer(L, -1)) { + message->addItem(item, player->isOTCv8()); + } else { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::PLAYER_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + } else { + message->addItem(item, false); + } pushBoolean(L, true); } else { lua_pushnil(L); @@ -239,7 +254,17 @@ int luaNetworkMessageAddItemId(lua_State* L) } } - message->addItemId(itemId, false); + if (getAssociatedValue(L, 1, 1)) { + if (const auto player = getPlayer(L, -1)) { + message->addItemId(itemId, player->isOTCv8()); + } else { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::PLAYER_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + } else { + message->addItemId(itemId, false); + } pushBoolean(L, true); return 1; } @@ -309,7 +334,7 @@ int luaNetworkMessageSkipBytes(lua_State* L) int luaNetworkMessageSendToPlayer(lua_State* L) { - // networkMessage:sendToPlayer(player) + // networkMessage:sendToPlayer([player]) NetworkMessage* message = getUserdata(L, 1); if (!message) { lua_pushnil(L); @@ -322,6 +347,14 @@ int luaNetworkMessageSendToPlayer(lua_State* L) return 1; } + if (getAssociatedValue(L, 1, 1)) { + if (const auto p = getPlayer(L, -1)) { + p->sendNetworkMessage(*message); + pushBoolean(L, true); + return 1; + } + } + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::PLAYER_NOT_FOUND)); lua_pushnil(L); return 1; diff --git a/src/luascript.cpp b/src/luascript.cpp index aac0542..ad06562 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -1236,6 +1236,147 @@ void LuaScriptInterface::registerFunctions() registerEnumClass(ExperienceRateType::BONUS); registerEnumClass(ExperienceRateType::STAMINA); + // GameFeature + registerTable("GameFeature"); + + registerEnumClass(GameFeature::ProtocolChecksum); + registerEnumClass(GameFeature::AccountNames); + registerEnumClass(GameFeature::ChallengeOnLogin); + registerEnumClass(GameFeature::PenalityOnDeath); + registerEnumClass(GameFeature::NameOnNpcTrade); + registerEnumClass(GameFeature::DoubleFreeCapacity); + registerEnumClass(GameFeature::DoubleExperience); + registerEnumClass(GameFeature::TotalCapacity); + registerEnumClass(GameFeature::SkillsBase); + registerEnumClass(GameFeature::PlayerRegenerationTime); + registerEnumClass(GameFeature::ChannelPlayerList); + registerEnumClass(GameFeature::PlayerMounts); + registerEnumClass(GameFeature::EnvironmentEffect); + registerEnumClass(GameFeature::CreatureEmblems); + registerEnumClass(GameFeature::ItemAnimationPhase); + registerEnumClass(GameFeature::MagicEffectU16); + registerEnumClass(GameFeature::PlayerMarket); + registerEnumClass(GameFeature::SpritesU32); + registerEnumClass(GameFeature::TileAddThingWithStackpos); + registerEnumClass(GameFeature::OfflineTrainingTime); + registerEnumClass(GameFeature::PurseSlot); + registerEnumClass(GameFeature::FormatCreatureName); + registerEnumClass(GameFeature::SpellList); + registerEnumClass(GameFeature::ClientPing); + registerEnumClass(GameFeature::ExtendedClientPing); + registerEnumClass(GameFeature::DoubleHealth); + registerEnumClass(GameFeature::DoubleSkills); + registerEnumClass(GameFeature::ChangeMapAwareRange); + registerEnumClass(GameFeature::MapMovePosition); + registerEnumClass(GameFeature::AttackSeq); + registerEnumClass(GameFeature::BlueNpcNameColor); + registerEnumClass(GameFeature::DiagonalAnimatedText); + registerEnumClass(GameFeature::LoginPending); + registerEnumClass(GameFeature::NewSpeedLaw); + registerEnumClass(GameFeature::ForceFirstAutoWalkStep); + registerEnumClass(GameFeature::MinimapRemove); + registerEnumClass(GameFeature::DoubleShopSellAmount); + registerEnumClass(GameFeature::ContainerPagination); + registerEnumClass(GameFeature::ThingMarks); + registerEnumClass(GameFeature::LooktypeU16); + registerEnumClass(GameFeature::PlayerStamina); + registerEnumClass(GameFeature::PlayerAddons); + registerEnumClass(GameFeature::MessageStatements); + registerEnumClass(GameFeature::MessageLevel); + registerEnumClass(GameFeature::NewFluids); + registerEnumClass(GameFeature::PlayerStateU16); + registerEnumClass(GameFeature::NewOutfitProtocol); + registerEnumClass(GameFeature::PVPMode); + registerEnumClass(GameFeature::WritableDate); + registerEnumClass(GameFeature::AdditionalVipInfo); + registerEnumClass(GameFeature::BaseSkillU16); + registerEnumClass(GameFeature::CreatureIcons); + registerEnumClass(GameFeature::HideNpcNames); + registerEnumClass(GameFeature::SpritesAlphaChannel); + registerEnumClass(GameFeature::PremiumExpiration); + registerEnumClass(GameFeature::BrowseField); + registerEnumClass(GameFeature::EnhancedAnimations); + registerEnumClass(GameFeature::OGLInformation); + registerEnumClass(GameFeature::MessageSizeCheck); + registerEnumClass(GameFeature::PreviewState); + registerEnumClass(GameFeature::LoginPacketEncryption); + registerEnumClass(GameFeature::ClientVersion); + registerEnumClass(GameFeature::ContentRevision); + registerEnumClass(GameFeature::ExperienceBonus); + registerEnumClass(GameFeature::Authenticator); + registerEnumClass(GameFeature::UnjustifiedPoints); + registerEnumClass(GameFeature::SessionKey); + registerEnumClass(GameFeature::DeathType); + registerEnumClass(GameFeature::IdleAnimations); + registerEnumClass(GameFeature::KeepUnawareTiles); + registerEnumClass(GameFeature::IngameStore); + registerEnumClass(GameFeature::IngameStoreHighlights); + registerEnumClass(GameFeature::IngameStoreServiceType); + registerEnumClass(GameFeature::AdditionalSkills); + registerEnumClass(GameFeature::DistanceEffectU16); + registerEnumClass(GameFeature::Prey); + registerEnumClass(GameFeature::DoubleMagicLevel); + + registerEnumClass(GameFeature::ExtendedOpcode); + registerEnumClass(GameFeature::MinimapLimitedToSingleFloor); + registerEnumClass(GameFeature::SendWorldName); + + registerEnumClass(GameFeature::DoubleLevel); + registerEnumClass(GameFeature::DoubleSoul); + registerEnumClass(GameFeature::DoublePlayerGoodsMoney); + registerEnumClass(GameFeature::CreatureWalkthrough); + registerEnumClass(GameFeature::DoubleTradeMoney); + registerEnumClass(GameFeature::SequencedPackets); + registerEnumClass(GameFeature::Tibia12Protocol); + + // 90 - 99 otclientv8 features registerEnumClass(GameFeature::NewWalking); + registerEnumClass(GameFeature::SlowerManualWalking); + + registerEnumClass(GameFeature::ItemTooltip); + + registerEnumClass(GameFeature::Bot); + registerEnumClass(GameFeature::BiggerMapCache); + registerEnumClass(GameFeature::ForceLight); + registerEnumClass(GameFeature::NoDebug); + registerEnumClass(GameFeature::BotProtection); + + // Custom features for customer + registerEnumClass(GameFeature::CreatureDirectionPassable); + registerEnumClass(GameFeature::FasterAnimations); + registerEnumClass(GameFeature::CenteredOutfits); + registerEnumClass(GameFeature::SendIdentifiers); + registerEnumClass(GameFeature::WingsAndAura); + registerEnumClass(GameFeature::PlayerStateU32); + registerEnumClass(GameFeature::OutfitShaders); + registerEnumClass(GameFeature::ForceAllowItemHotkeys); + registerEnumClass(GameFeature::CountU16); + registerEnumClass(GameFeature::DrawAuraOnTop); + + // advanced features + registerEnumClass(GameFeature::PacketSizeU32); + registerEnumClass(GameFeature::PacketCompression); + + // OTCv8 - dev features + registerEnumClass(GameFeature::OldInformationBar); + registerEnumClass(GameFeature::HealthInfoBackground); + registerEnumClass(GameFeature::WingOffset); + registerEnumClass(GameFeature::AuraFrontAndBack); + + registerEnumClass(GameFeature::MapDrawGroundFirst); + registerEnumClass(GameFeature::MapIgnoreCorpseCorrection); + registerEnumClass(GameFeature::DontCacheFiles); + registerEnumClass(GameFeature::BigAurasCenter); + registerEnumClass(GameFeature::NewUpdateWalk); + registerEnumClass(GameFeature::NewCreatureStacking); + registerEnumClass(GameFeature::CreaturesMana); + registerEnumClass(GameFeature::QuickLootFlags); + registerEnumClass(GameFeature::DontMergeAnimatedText); + registerEnumClass(GameFeature::MissionId); + registerEnumClass(GameFeature::ItemCustomAttributes); + registerEnumClass(GameFeature::AnimatedTextCustomFont); + + registerEnumClass(GameFeature::LastFeature); + // Combat Formula registerEnum(COMBAT_FORMULA_UNDEFINED); registerEnum(COMBAT_FORMULA_LEVELMAGIC); diff --git a/src/map.cpp b/src/map.cpp index 0157603..60c9ca0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -373,7 +373,7 @@ void Map::getSpectatorsInternal(SpectatorVec& spectators, const Position& center continue; } - int16_t offsetZ = cpos.getOffsetZ(centerPos); + int16_t offsetZ = centerPos.getOffsetZ(cpos); if ((min_y + offsetZ) > cpos.y || (max_y + offsetZ) < cpos.y || (min_x + offsetZ) > cpos.x || (max_x + offsetZ) < cpos.x) { continue; @@ -495,7 +495,7 @@ bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool bool sameFloor /*= false*/, int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/) const { - if (fromPos.getDistanceX(toPos) > rangex || toPos.getDistanceY(fromPos) > rangey) { + if (fromPos.getDistanceX(toPos) > rangex || fromPos.getDistanceY(toPos) > rangey) { return false; } @@ -579,7 +579,7 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool same // target is on the same floor if (fromPos.z == toPos.z) { // skip checks if toPos is next to us - if (fromPos.getDistanceX(toPos) < 2 && toPos.getDistanceY(fromPos) < 2) { + if (fromPos.getDistanceX(toPos) < 2 && fromPos.getDistanceY(toPos) < 2) { return true; } diff --git a/src/monster.cpp b/src/monster.cpp index d3b94bf..a5e356d 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -517,11 +517,11 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL if (++it != resultList.end()) { const Position& targetPosition = target->getPosition(); - int32_t minRange = myPos.getDistanceX(targetPosition) + targetPosition.getDistanceY(myPos); + int32_t minRange = myPos.getDistanceX(targetPosition) + myPos.getDistanceY(targetPosition); do { const Position& pos = (*it)->getPosition(); - if (int32_t distance = myPos.getDistanceX(pos) + pos.getDistanceY(myPos); distance < minRange) { + if (int32_t distance = myPos.getDistanceX(pos) + myPos.getDistanceY(pos); distance < minRange) { target = *it; minRange = distance; } @@ -535,7 +535,7 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL } const Position& pos = creature->getPosition(); - if (int32_t distance = myPos.getDistanceX(pos) + pos.getDistanceY(myPos); distance < minRange) { + if (int32_t distance = myPos.getDistanceX(pos) + myPos.getDistanceY(pos); distance < minRange) { target = creature; minRange = distance; } @@ -831,7 +831,7 @@ bool Monster::canUseAttack(const Position& pos, const Creature* target) const { if (isHostile()) { const Position& targetPos = target->getPosition(); - uint32_t distance = std::max(pos.getDistanceX(targetPos), targetPos.getDistanceY(pos)); + uint32_t distance = std::max(pos.getDistanceX(targetPos), pos.getDistanceY(targetPos)); for (const spellBlock_t& spellBlock : mType->info.attackSpells) { if (spellBlock.range != 0 && distance <= spellBlock.range) { return g_game.isSightClear(pos, targetPos, true); @@ -1024,7 +1024,7 @@ bool Monster::walkToSpawn() return false; } - int32_t distance = std::max(position.getDistanceX(masterPos), masterPos.getDistanceY(position)); + int32_t distance = std::max(position.getDistanceX(masterPos), position.getDistanceY(masterPos)); if (distance == 0) { return false; } @@ -1102,10 +1102,7 @@ void Monster::pushItems(Tile* tile) bool Monster::pushCreature(Creature* creature) { - static std::vector dirList{DIRECTION_NORTH, DIRECTION_WEST, DIRECTION_EAST, DIRECTION_SOUTH}; - std::shuffle(dirList.begin(), dirList.end(), getRandomGenerator()); - - for (Direction dir : dirList) { + for (Direction dir : getShuffleDirections()) { const Position& tryPos = Spells::getCasterPosition(creature, dir); Tile* toTile = g_game.map.getTile(tryPos); if (toTile && !toTile->hasFlag(TILESTATE_BLOCKPATH)) { @@ -1220,8 +1217,8 @@ bool Monster::getDanceStep(const Position& creaturePos, Direction& direction, bo assert(attackedCreature != nullptr); const Position& centerPos = attackedCreature->getPosition(); - int32_t offset_x = centerPos.getOffsetX(creaturePos); - int32_t offset_y = centerPos.getOffsetY(creaturePos); + int32_t offset_x = creaturePos.getOffsetX(centerPos); + int32_t offset_y = creaturePos.getOffsetY(centerPos); int32_t distance_x = std::abs(offset_x); int32_t distance_y = std::abs(offset_y); @@ -1319,8 +1316,8 @@ bool Monster::getDistanceStep(const Position& targetPos, Direction& direction, b // in that position) } - int32_t offsetx = targetPos.getOffsetX(creaturePos); - int32_t offsety = targetPos.getOffsetY(creaturePos); + int32_t offsetx = creaturePos.getOffsetX(targetPos); + int32_t offsety = creaturePos.getOffsetY(targetPos); if (dx <= 1 && dy <= 1) { // seems like a target is near, it this case we need to slow down our movements (as a monster) @@ -1889,69 +1886,10 @@ bool Monster::getCombatValues(int32_t& min, int32_t& max) void Monster::updateLookDirection() { - Direction newDir = getDirection(); - if (attackedCreature) { - const Position& pos = getPosition(); - const Position& attackedCreaturePos = attackedCreature->getPosition(); - int32_t offsetx = pos.getOffsetX(attackedCreaturePos); - int32_t offsety = pos.getOffsetY(attackedCreaturePos); - - int32_t dx = std::abs(offsetx); - int32_t dy = std::abs(offsety); - if (dx > dy) { - // look EAST/WEST - if (offsetx < 0) { - newDir = DIRECTION_WEST; - } else { - newDir = DIRECTION_EAST; - } - } else if (dx < dy) { - // look NORTH/SOUTH - if (offsety < 0) { - newDir = DIRECTION_NORTH; - } else { - newDir = DIRECTION_SOUTH; - } - } else { - Direction dir = getDirection(); - if (offsetx < 0 && offsety < 0) { - if (dir == DIRECTION_SOUTH) { - newDir = DIRECTION_WEST; - } else if (dir == DIRECTION_NORTH) { - newDir = DIRECTION_WEST; - } else if (dir == DIRECTION_EAST) { - newDir = DIRECTION_NORTH; - } - } else if (offsetx < 0 && offsety > 0) { - if (dir == DIRECTION_NORTH) { - newDir = DIRECTION_WEST; - } else if (dir == DIRECTION_SOUTH) { - newDir = DIRECTION_WEST; - } else if (dir == DIRECTION_EAST) { - newDir = DIRECTION_SOUTH; - } - } else if (offsetx > 0 && offsety < 0) { - if (dir == DIRECTION_SOUTH) { - newDir = DIRECTION_EAST; - } else if (dir == DIRECTION_NORTH) { - newDir = DIRECTION_EAST; - } else if (dir == DIRECTION_WEST) { - newDir = DIRECTION_NORTH; - } - } else { - if (dir == DIRECTION_NORTH) { - newDir = DIRECTION_EAST; - } else if (dir == DIRECTION_SOUTH) { - newDir = DIRECTION_EAST; - } else if (dir == DIRECTION_WEST) { - newDir = DIRECTION_SOUTH; - } - } - } + Direction newDir = getDirectionTo(getPosition(), attackedCreature->getPosition(), false); + g_game.internalCreatureTurn(this, newDir); } - - g_game.internalCreatureTurn(this, newDir); } void Monster::dropLoot(Container* corpse, Creature*) diff --git a/src/npc.cpp b/src/npc.cpp index 38b6ff5..19687d1 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -458,8 +458,8 @@ void Npc::turnToCreature(Creature* creature) { const Position& creaturePos = creature->getPosition(); const Position& myPos = getPosition(); - const auto dx = creaturePos.getOffsetX(myPos); - const auto dy = creaturePos.getOffsetY(myPos); + const auto dx = myPos.getOffsetX(creaturePos); + const auto dy = myPos.getOffsetY(creaturePos); float tan; if (dx != 0) { @@ -684,7 +684,7 @@ int NpcScriptInterface::luagetDistanceTo(lua_State* L) if (npcPos.z != thingPos.z) { lua_pushinteger(L, -1); } else { - lua_pushinteger(L, std::max(npcPos.getDistanceX(thingPos), thingPos.getDistanceY(npcPos))); + lua_pushinteger(L, std::max(npcPos.getDistanceX(thingPos), npcPos.getDistanceY(thingPos))); } return 1; } diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index bf11c37..8078d17 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -372,6 +372,7 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) } if (isOTCv8) { + sendOTCv8Features(); NetworkMessage opcodeMessage; opcodeMessage.addByte(0x32); opcodeMessage.addByte(0x00); @@ -2331,7 +2332,10 @@ void ProtocolGame::sendOutfitWindow() protocolOutfits.emplace_back("Gamemaster", 75, 0); } - const size_t maxProtocolOutfits = static_cast(g_config[ConfigKeysInteger::MAX_PROTOCOL_OUTFITS]); + size_t maxProtocolOutfits = static_cast(g_config[ConfigKeysInteger::MAX_PROTOCOL_OUTFITS]); + if (isOTCv8) { + maxProtocolOutfits = std::numeric_limits::max(); + } for (const Outfit* outfit : outfits) { uint8_t addons; @@ -2470,12 +2474,20 @@ void ProtocolGame::AddPlayerStats(NetworkMessage& msg) static_cast(std::min(player->getMaxMana(), std::numeric_limits::max()))); msg.addByte(static_cast(std::min(player->getMagicLevel(), std::numeric_limits::max()))); + if (isOTCv8) { + msg.addByte( + static_cast(std::min(player->getBaseMagicLevel(), std::numeric_limits::max()))); + } msg.addByte(static_cast(player->getMagicLevelPercent())); msg.addByte(player->getSoul()); msg.add(player->getStaminaMinutes()); + if (isOTCv8) { + msg.add(player->getBaseSpeed() / 2); + } + /*msg.add(player->getBaseSpeed() / 2); Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT); @@ -2492,17 +2504,30 @@ void ProtocolGame::AddPlayerSkills(NetworkMessage& msg) { msg.addByte(0xA1); - for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { - msg.addByte( - std::min(static_cast(player->getSkillLevel(i)), std::numeric_limits::max())); - msg.addByte(static_cast(player->getSkillPercent(i))); + if (!isOTCv8) { + for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { + msg.addByte( + std::min(static_cast(player->getSkillLevel(i)), std::numeric_limits::max())); + msg.addByte(static_cast(player->getSkillPercent(i))); + } + } else { + for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { + msg.add(std::min(player->getSkillLevel(i), std::numeric_limits::max())); + msg.add(player->getBaseSkill(i)); + msg.addByte(static_cast(player->getSkillPercent(i))); + } + + for (uint8_t i = SPECIALSKILL_FIRST; i <= SPECIALSKILL_LAST; ++i) { + msg.add(static_cast(std::min(100, player->varSpecialSkills[i]))); + msg.add(0); + } } } void ProtocolGame::AddOutfit(NetworkMessage& msg, const Outfit_t& outfit) { uint16_t lookType = outfit.lookType; - if (isOTCv8 && lookType >= 367) { + if (!isOTCv8 && lookType >= 367) { lookType = 128; } @@ -2676,3 +2701,22 @@ void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg) g_game.parsePlayerExtendedOpcode(playerID, opcode, buffer); }); } + +void ProtocolGame::sendOTCv8Features() +{ + std::vector features = {GameFeature::ExtendedOpcode, GameFeature::PlayerMounts, + GameFeature::SpritesU32, GameFeature::SpritesAlphaChannel, + GameFeature::IdleAnimations, GameFeature::EnhancedAnimations, + GameFeature::AdditionalSkills, GameFeature::DoubleSkills, + GameFeature::SkillsBase, GameFeature::BaseSkillU16}; + + auto msg = getOutputBuffer(1024); + msg->addByte(0x43); + msg->add(features.size()); + for (const GameFeature& feature : features) { + msg->addByte(static_cast(feature)); + msg->addByte(0x01); + } + + send(std::move(getCurrentBuffer())); +} diff --git a/src/protocolgame.h b/src/protocolgame.h index 32d765f..0a32452 100644 --- a/src/protocolgame.h +++ b/src/protocolgame.h @@ -254,6 +254,8 @@ class ProtocolGame final : public Protocol // otclient void parseExtendedOpcode(NetworkMessage& msg); + void sendOTCv8Features(); + friend class Player; std::unordered_set knownCreatureSet; diff --git a/src/weapons.cpp b/src/weapons.cpp index d0fe4b7..b6225c6 100644 --- a/src/weapons.cpp +++ b/src/weapons.cpp @@ -256,7 +256,7 @@ int32_t Weapon::playerWeaponCheck(Player* player, Creature* target, uint8_t shoo return 0; } - if (std::max(playerPos.getDistanceX(targetPos), targetPos.getDistanceY(playerPos)) > shootRange) { + if (std::max(playerPos.getDistanceX(targetPos), playerPos.getDistanceY(targetPos)) > shootRange) { return 0; }