diff --git a/data-otservbr-global/monster/reptiles/boar_man.lua b/data-otservbr-global/monster/reptiles/boar_man.lua index b2568e7ce2a..53ec742ca22 100644 --- a/data-otservbr-global/monster/reptiles/boar_man.lua +++ b/data-otservbr-global/monster/reptiles/boar_man.lua @@ -15,7 +15,7 @@ monster.outfit = { monster.raceId = 2339 monster.Bestiary = { - class = "Hybrids", + class = "Humanoid", race = BESTY_RACE_HUMANOID, toKill = 2500, FirstUnlock = 100, diff --git a/data-otservbr-global/monster/reptiles/crape_man.lua b/data-otservbr-global/monster/reptiles/crape_man.lua index 031dbf2ca48..99d2db01f34 100644 --- a/data-otservbr-global/monster/reptiles/crape_man.lua +++ b/data-otservbr-global/monster/reptiles/crape_man.lua @@ -15,7 +15,7 @@ monster.outfit = { monster.raceId = 2337 monster.Bestiary = { - class = "Hybrids", + class = "Humanoid", race = BESTY_RACE_HUMANOID, toKill = 2500, FirstUnlock = 100, diff --git a/data-otservbr-global/monster/reptiles/liodile.lua b/data-otservbr-global/monster/reptiles/liodile.lua index 77676a87a6b..d7f79621679 100644 --- a/data-otservbr-global/monster/reptiles/liodile.lua +++ b/data-otservbr-global/monster/reptiles/liodile.lua @@ -15,7 +15,7 @@ monster.outfit = { monster.raceId = 2338 monster.Bestiary = { - class = "Hybrids", + class = "Humanoid", race = BESTY_RACE_HUMANOID, toKill = 2500, FirstUnlock = 100, diff --git a/data-otservbr-global/monster/reptiles/rhindeer.lua b/data-otservbr-global/monster/reptiles/rhindeer.lua index d9de46b857c..743d9fb492a 100644 --- a/data-otservbr-global/monster/reptiles/rhindeer.lua +++ b/data-otservbr-global/monster/reptiles/rhindeer.lua @@ -15,7 +15,7 @@ monster.outfit = { monster.raceId = 2342 monster.Bestiary = { - class = "Hybrids", + class = "Humanoid", race = BESTY_RACE_HUMANOID, toKill = 2500, FirstUnlock = 100, diff --git a/data-otservbr-global/scripts/spells/house/kick.lua b/data-otservbr-global/scripts/spells/house/kick.lua index be7c7517a35..b4b583c1007 100644 --- a/data-otservbr-global/scripts/spells/house/kick.lua +++ b/data-otservbr-global/scripts/spells/house/kick.lua @@ -4,6 +4,13 @@ function spell.onCastSpell(player, variant) local targetPlayer = Player(variant:getString()) or player local guest = targetPlayer:getTile():getHouse() local owner = player:getTile():getHouse() + -- Owner kick yourself from house + if targetPlayer == player then + player:getPosition():sendMagicEffect(CONST_ME_POFF) + player:teleportTo(owner:getExitPosition()) + player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + return true + end if not owner or not guest or not guest:kickPlayer(player, targetPlayer) then player:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE) player:getPosition():sendMagicEffect(CONST_ME_POFF) diff --git a/data/global.lua b/data/global.lua index 04a8ff78fe9..4caec8c69f9 100644 --- a/data/global.lua +++ b/data/global.lua @@ -100,8 +100,8 @@ if not _G.NextUseXpStamina then _G.NextUseXpStamina = {} end -if not _G._G.NextUseConcoctionTime then - _G._G.NextUseConcoctionTime = {} +if not _G.NextUseConcoctionTime then + _G.NextUseConcoctionTime = {} end -- Delay potion diff --git a/data/scripts/talkactions/gm/position.lua b/data/scripts/talkactions/gm/position.lua index f68b4210996..1869b109c5f 100644 --- a/data/scripts/talkactions/gm/position.lua +++ b/data/scripts/talkactions/gm/position.lua @@ -1,22 +1,46 @@ local position = TalkAction("/pos", "!pos") +local function extractCoordinates(input) + local patterns = { + -- table format + "{%s*x%s*=%s*(%d+)%s*,%s*y%s*=%s*(%d+)%s*,%s*z%s*=%s*(%d+)%s*}", + -- Position format + "Position%s*%((%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)", + -- x, y, z format + "(%d+)%s*,%s*(%d+)%s*,%s*(%d+)", + } + + for _, pattern in ipairs(patterns) do + local x, y, z = string.match(input, pattern) + if x and y and z then + return tonumber(x), tonumber(y), tonumber(z) + end + end +end + function position.onSay(player, words, param) -- create log logCommand(player, words, param) - local param = string.gsub(param, "%s+", "") - local tile = load("return " .. param)() - local split = param:split(",") - if type(tile) == "table" and tile.x and tile.y and tile.z then - player:teleportTo(Position(tile.x, tile.y, tile.z)) - elseif split and param ~= "" then - player:teleportTo(Position(split[1], split[2], split[3])) - elseif param == "" then - local playerPosition = player:getPosition() - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your current position is: \z - " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. ".") + if param == "" then + local pos = player:getPosition() + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your current position is: " .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. ".") + return + end + + local x, y, z = extractCoordinates(param) + if x and y and z then + local teleportPosition = Position(x, y, z) + local tile = Tile(teleportPosition) + if not tile then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Invalid tile or position. Send a valid position.") + return + end + + player:teleportTo(teleportPosition) + else + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Invalid position format. Use one of the following formats: \n/pos {x = ..., y = ..., z = ...}\n/pos Position(..., ..., ...)\n/pos x, y, z.") end - return true end position:separator(" ") diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index f5ec13f3473..151e5458a85 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -2024,13 +2024,12 @@ void Combat::applyExtensions(std::shared_ptr caster, std::shared_ptrgetPlayer(); auto monster = caster->getMonster(); if (player) { chance = player->getSkillLevel(SKILL_CRITICAL_HIT_CHANCE); - multiplier = player->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE); - + bonus = player->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE); if (target) { uint16_t playerCharmRaceid = player->parseRacebyCharm(CHARM_LOW, false, 0); if (playerCharmRaceid != 0) { @@ -2048,8 +2047,8 @@ void Combat::applyExtensions(std::shared_ptr caster, std::shared_ptrcritChance(); } - multiplier += damage.criticalDamage; - multiplier = 1 + multiplier / 100; + bonus += damage.criticalDamage; + double multiplier = 1.0 + static_cast(bonus) / 100; chance += (uint16_t)damage.criticalChance; if (chance != 0 && uniform_random(1, 100) <= chance) { diff --git a/src/game/game.cpp b/src/game/game.cpp index b6733395831..e9cb108942e 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -6625,10 +6625,8 @@ bool Game::combatChangeHealth(std::shared_ptr attacker, std::shared_pt } } + std::string attackMsg = fmt::format("{} attack", damage.critical ? "critical " : " "); std::stringstream ss; - ss << (damage.critical ? "critical " : " ") << "attack"; - std::string attackMsg = ss.str(); - ss.str({}); if (target->hasCondition(CONDITION_MANASHIELD) && damage.primary.type != COMBAT_UNDEFINEDDAMAGE) { int32_t manaDamage = std::min(target->getMana(), healthChange); @@ -6915,17 +6913,19 @@ void Game::buildMessageAsSpectator( ) const { if (spectatorMessage.empty()) { ss.str({}); + auto attackMsg = damage.critical ? "critical " : ""; + auto article = damage.critical ? "a" : "an"; ss << ucfirst(target->getNameDescription()) << " loses " << damageString; if (attacker) { ss << " due to "; if (attacker == target) { if (targetPlayer) { - ss << targetPlayer->getPossessivePronoun() << " own attack"; + ss << targetPlayer->getPossessivePronoun() << " own " << attackMsg << "attack"; } else { - ss << "its own attack"; + ss << "its own " << attackMsg << "attack"; } } else { - ss << "an attack by " << attacker->getNameDescription(); + ss << article << " " << attackMsg << "attack by " << attacker->getNameDescription(); } } ss << '.'; @@ -6945,13 +6945,15 @@ void Game::buildMessageAsTarget( const std::string &damageString ) const { ss.str({}); + auto attackMsg = damage.critical ? "critical " : ""; + auto article = damage.critical ? "a" : "an"; ss << "You lose " << damageString; if (!attacker) { ss << '.'; } else if (targetPlayer == attackerPlayer) { - ss << " due to your own attack."; + ss << " due to your own " << attackMsg << "attack."; } else { - ss << " due to an attack by " << attacker->getNameDescription() << '.'; + ss << " due to " << article << " " << attackMsg << "attack by " << attacker->getNameDescription() << '.'; } if (damage.extension) { ss << " " << damage.exString; @@ -6965,7 +6967,7 @@ void Game::buildMessageAsAttacker( std::stringstream &ss, const std::string &damageString ) const { ss.str({}); - ss << ucfirst(target->getNameDescription()) << " loses " << damageString << " due to your attack."; + ss << ucfirst(target->getNameDescription()) << " loses " << damageString << " due to your " << (damage.critical ? "critical " : " ") << "attack."; if (damage.extension) { ss << " " << damage.exString; }