Skip to content

Commit

Permalink
Merge branch 'main' into dudantas/feat-soul-war-quest
Browse files Browse the repository at this point in the history
  • Loading branch information
s2leandro155 committed Jul 5, 2024
2 parents 4e2e537 + 3aeb3e7 commit a2f735a
Show file tree
Hide file tree
Showing 25 changed files with 604 additions and 226 deletions.
4 changes: 2 additions & 2 deletions data/modules/scripts/blessings/blessings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Blessings.Credits = {

Blessings.Config = {
AdventurerBlessingLevel = configManager.getNumber(configKeys.ADVENTURERSBLESSING_LEVEL), -- Free full bless until level
HasToF = false, -- Enables/disables twist of fate
HasToF = not configManager.getBoolean(configKeys.TOGGLE_SERVER_IS_RETRO), -- Enables/disables twist of fate
InquisitonBlessPriceMultiplier = 1.1, -- Bless price multiplied by henricus
SkulledDeathLoseStoreItem = configManager.getBoolean(configKeys.SKULLED_DEATH_LOSE_STORE_ITEM), -- Destroy all items on store when dying with red/blackskull
InventoryGlowOnFiveBless = configManager.getBoolean(configKeys.INVENTORY_GLOW), -- Glow in yellow inventory items when the player has 5 or more bless,
Expand Down Expand Up @@ -142,7 +142,7 @@ Blessings.sendBlessDialog = function(player)
msg:addU16(Blessings.BitWiseTable[v.id])
msg:addByte(player:getBlessingCount(v.id))
if player:getClient().version > 1200 then
msg:addByte(0) -- Store Blessings Count
msg:addByte(player:getBlessingCount(v.id, true)) -- Store Blessings Count
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions data/modules/scripts/gamestore/gamestore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ GameStore.Categories = {
icons = { "Blood_of_the_Mountain.png" },
name = "Blood of the Mountain",
price = 25,
blessid = 8,
blessid = 7,
count = 1,
id = GameStore.SubActions.BLESSING_BLOOD,
description = "<i>Reduces your character's chance to lose any items as well as the amount of your character's experience and skill loss upon death:</i>\n\n&#8226; 1 blessing = 8.00% less Skill / XP loss, 30% equipment protection\n&#8226; 2 blessing = 16.00% less Skill / XP loss, 55% equipment protection\n&#8226; 3 blessing = 24.00% less Skill / XP loss, 75% equipment protection\n&#8226; 4 blessing = 32.00% less Skill / XP loss, 90% equipment protection\n&#8226; 5 blessing = 40.00% less Skill / XP loss, 100% equipment protection\n&#8226; 6 blessing = 48.00% less Skill / XP loss, 100% equipment protection\n&#8226; 7 blessing = 56.00% less Skill / XP loss, 100% equipment protection\n\n{character} \n{limit|5} \n{info} added directly to the Record of Blessings \n{info} characters with a red or black skull will always lose all equipment upon death",
Expand All @@ -154,7 +154,7 @@ GameStore.Categories = {
icons = { "Heart_of_the_Mountain.png" },
name = "Heart of the Mountain",
price = 25,
blessid = 7,
blessid = 8,
count = 1,
id = GameStore.SubActions.BLESSING_HEART,
description = "<i>Reduces your character's chance to lose any items as well as the amount of your character's experience and skill loss upon death:</i>\n\n&#8226; 1 blessing = 8.00% less Skill / XP loss, 30% equipment protection\n&#8226; 2 blessing = 16.00% less Skill / XP loss, 55% equipment protection\n&#8226; 3 blessing = 24.00% less Skill / XP loss, 75% equipment protection\n&#8226; 4 blessing = 32.00% less Skill / XP loss, 90% equipment protection\n&#8226; 5 blessing = 40.00% less Skill / XP loss, 100% equipment protection\n&#8226; 6 blessing = 48.00% less Skill / XP loss, 100% equipment protection\n&#8226; 7 blessing = 56.00% less Skill / XP loss, 100% equipment protection\n\n{character} \n{limit|5} \n{info} added directly to the Record of Blessings \n{info} characters with a red or black skull will always lose all equipment upon death",
Expand Down
31 changes: 20 additions & 11 deletions data/modules/scripts/gamestore/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ GameStore.SubActions = {
BLESSING_SUNS = 6,
BLESSING_SPIRITUAL = 7,
BLESSING_EMBRACE = 8,
BLESSING_HEART = 9,
BLESSING_BLOOD = 10,
BLESSING_BLOOD = 9,
BLESSING_HEART = 10,
BLESSING_ALL_PVE = 11,
BLESSING_ALL_PVP = 12,
CHARM_EXPANSION = 13,
Expand Down Expand Up @@ -399,6 +399,17 @@ function parseRequestStoreOffers(playerId, msg)
player:updateUIExhausted()
end

-- Used on cyclopedia store summary
local function insertPlayerTransactionSummary(player, offer)
local id = offer.id
if offer.type == GameStore.OfferTypes.OFFER_TYPE_HOUSE then
id = offer.itemtype
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_BLESSINGS then
id = offer.blessid
end
player:createTransactionSummary(offer.type, math.max(1, offer.count or 1), id)
end

function parseBuyStoreOffer(playerId, msg)
local player = Player(playerId)
local id = msg:getU32()
Expand Down Expand Up @@ -450,9 +461,7 @@ function parseBuyStoreOffer(playerId, msg)
-- Handled errors are thrown to indicate that the purchase has failed;
-- Handled errors have a code index and unhandled errors do not
local pcallOk, pcallError = pcall(function()
if offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM then
GameStore.processItemPurchase(player, offer.itemtype, offer.count or 1, offer.movable, offer.setOwner)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_UNIQUE then
if offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM or offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_UNIQUE then
GameStore.processItemPurchase(player, offer.itemtype, offer.count or 1, offer.movable, offer.setOwner)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_INSTANT_REWARD_ACCESS then
GameStore.processInstantRewardAccess(player, offer.count)
Expand All @@ -466,11 +475,9 @@ function parseBuyStoreOffer(playerId, msg)
GameStore.processPremiumPurchase(player, offer.id)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_STACKABLE then
GameStore.processStackablePurchase(player, offer.itemtype, offer.count, offer.name, offer.movable, offer.setOwner)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_HOUSE then
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_HOUSE or offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_BED then
GameStore.processHouseRelatedPurchase(player, offer)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT then
GameStore.processOutfitPurchase(player, offer.sexId, offer.addon)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT_ADDON then
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT or offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT_ADDON then
GameStore.processOutfitPurchase(player, offer.sexId, offer.addon)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_MOUNT then
GameStore.processMountPurchase(player, offer.id)
Expand Down Expand Up @@ -504,8 +511,6 @@ function parseBuyStoreOffer(playerId, msg)
GameStore.processHirelingSkillPurchase(player, offer)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_HIRELING_OUTFIT then
GameStore.processHirelingOutfitPurchase(player, offer)
elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_BED then
GameStore.processHouseRelatedPurchase(player, offer)
else
-- This should never happen by our convention, but just in case the guarding condition is messed up...
error({ code = 0, message = "This offer is unavailable [2]" })
Expand All @@ -523,6 +528,9 @@ function parseBuyStoreOffer(playerId, msg)
return queueSendStoreAlertToUser(alertMessage, 500, playerId)
end

if table.contains({ GameStore.OfferTypes.OFFER_TYPE_HOUSE, GameStore.OfferTypes.OFFER_TYPE_EXPBOOST, GameStore.OfferTypes.OFFER_TYPE_PREYBONUS, GameStore.OfferTypes.OFFER_TYPE_BLESSINGS, GameStore.OfferTypes.OFFER_TYPE_ALLBLESSINGS, GameStore.OfferTypes.OFFER_TYPE_INSTANT_REWARD_ACCESS }, offer.type) then
insertPlayerTransactionSummary(player, offer)
end
local configure = useOfferConfigure(offer.type)
if configure ~= GameStore.ConfigureOffers.SHOW_CONFIGURE then
if not player:makeCoinTransaction(offer) then
Expand Down Expand Up @@ -1827,6 +1835,7 @@ function GameStore.processHirelingPurchase(player, offer, productType, hirelingN

player:makeCoinTransaction(offer, hirelingName)
local message = "You have successfully bought " .. hirelingName
player:createTransactionSummary(offer.type, 1)
return addPlayerEvent(sendStorePurchaseSuccessful, 650, player:getId(), message)
-- If not, we ask him to do!
else
Expand Down
7 changes: 4 additions & 3 deletions data/scripts/eventcallbacks/player/on_look.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,12 @@ function callback.playerOnLook(player, thing, position, distance)
description = string.format("%s\nDecays to: %d", description, decayId)
end
elseif thing:isCreature() then
local str = "%s\nHealth: %d / %d"
local str, pId = "%s\n%s\nHealth: %d / %d"
if thing:isPlayer() and thing:getMaxMana() > 0 then
pId = string.format("Player ID: %i", thing:getGuid())
str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
end
description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
description = string.format(str, description, pId, thing:getHealth(), thing:getMaxHealth())
end

description = string.format("%s\nPosition: (%d, %d, %d)", description, position.x, position.y, position.z)
Expand All @@ -76,7 +77,7 @@ function callback.playerOnLook(player, thing, position, distance)
description = string.format("%s\nSpeed: %d", description, speed)

if thing:isPlayer() then
description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp()))
description = string.format("%s\nIP: %s", description, Game.convertIpToString(thing:getIp()))
end
end
end
Expand Down
38 changes: 37 additions & 1 deletion data/scripts/talkactions/god/create_npc.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
-- To summon a temporary npc use /n npcname
-- To summon a permanent npc use /n npcname,true

local createNpc = TalkAction("/n")

function createNpc.onSay(player, words, param)
Expand All @@ -9,11 +12,44 @@ function createNpc.onSay(player, words, param)
return true
end

local split = param:split(",")
local name = split[1]
local permanentStr = split[2]

local position = player:getPosition()
local npc = Game.createNpc(param, position)
local npc = Game.createNpc(name, position)
if npc then
npc:setMasterPos(position)
position:sendMagicEffect(CONST_ME_MAGIC_RED)

if permanentStr and permanentStr == "true" then
local mapName = configManager.getString(configKeys.MAP_NAME)
local mapNpcsPath = mapName .. "-npc.xml"
local filePath = string.format("%s/world/%s", DATA_DIRECTORY, mapNpcsPath)
local npcsFile = io.open(filePath, "r")
if not npcsFile then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when trying to add permanent NPC. NPC File not found.")
return true
end
local fileContent = npcsFile:read("*all")
npcsFile:close()
local endTag = "</npcs>"
if not fileContent:find(endTag, 1, true) then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when trying to add permanent NPC. The NPC file format is incorrect. Missing end tag " .. endTag .. ".")
return true
end
local textToAdd = string.format('\t<npc centerx="%i" centery="%i" centerz="%i" radius="1">\n\t\t<npc name="%s" x="0" y="0" z="%i" spawntime="60" />\n\t</npc>', position.x, position.y, position.z, name, position.z)
local newFileContent = fileContent:gsub(endTag, textToAdd .. "\n" .. endTag)
npcsFile = io.open(filePath, "w")
if not npcsFile then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when trying to write to the NPC file.")
return true
end
npcsFile:write(newFileContent)
npcsFile:close()

player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Permanent NPC added successfully.")
end
else
player:sendCancelMessage("There is not enough room.")
position:sendMagicEffect(CONST_ME_POFF)
Expand Down
1 change: 1 addition & 0 deletions src/creatures/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ target_sources(${PROJECT_NAME}_lib PRIVATE
players/player.cpp
players/achievement/player_achievement.cpp
players/cyclopedia/player_badge.cpp
players/cyclopedia/player_cyclopedia.cpp
players/cyclopedia/player_title.cpp
players/wheel/player_wheel.cpp
players/wheel/wheel_gems.cpp
Expand Down
13 changes: 7 additions & 6 deletions src/creatures/players/achievement/player_achievement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ bool PlayerAchievement::add(uint16_t id, bool message /* = true*/, uint32_t time
addPoints(achievement.points);
int toSaveTimeStamp = timestamp != 0 ? timestamp : (OTSYS_TIME() / 1000);
getUnlockedKV()->set(achievement.name, toSaveTimeStamp);
m_achievementsUnlocked.push_back({ achievement.id, toSaveTimeStamp });
m_achievementsUnlocked.emplace_back(achievement.id, toSaveTimeStamp);
m_achievementsUnlocked.shrink_to_fit();
return true;
}
Expand Down Expand Up @@ -80,7 +80,8 @@ bool PlayerAchievement::isUnlocked(uint16_t id) const {
}

uint16_t PlayerAchievement::getPoints() const {
return m_player.kv()->scoped("achievements")->get("points")->getNumber();
auto kvScoped = m_player.kv()->scoped("achievements")->get("points");
return kvScoped ? static_cast<uint16_t>(kvScoped->getNumber()) : 0;
}

void PlayerAchievement::addPoints(uint16_t toAddPoints) {
Expand Down Expand Up @@ -109,12 +110,12 @@ void PlayerAchievement::loadUnlockedAchievements() {

g_logger().debug("[{}] - Achievement {} found for player {}.", __FUNCTION__, achievementName, m_player.getName());

m_achievementsUnlocked.push_back({ achievement.id, getUnlockedKV()->get(achievementName)->getNumber() });
m_achievementsUnlocked.emplace_back(achievement.id, getUnlockedKV()->get(achievementName)->getNumber());
}
}

void PlayerAchievement::sendUnlockedSecretAchievements() {
std::vector<std::pair<Achievement, uint32_t>> m_achievementsUnlocked;
std::vector<std::pair<Achievement, uint32_t>> achievementsUnlocked;
uint16_t unlockedSecret = 0;
for (const auto &[achievId, achievCreatedTime] : getUnlockedAchievements()) {
Achievement achievement = g_game().getAchievementById(achievId);
Expand All @@ -126,10 +127,10 @@ void PlayerAchievement::sendUnlockedSecretAchievements() {
unlockedSecret++;
}

m_achievementsUnlocked.push_back({ achievement, achievCreatedTime });
achievementsUnlocked.emplace_back(achievement, achievCreatedTime);
}

m_player.sendCyclopediaCharacterAchievements(unlockedSecret, m_achievementsUnlocked);
m_player.sendCyclopediaCharacterAchievements(unlockedSecret, achievementsUnlocked);
}

const std::shared_ptr<KV> &PlayerAchievement::getUnlockedKV() {
Expand Down
6 changes: 3 additions & 3 deletions src/creatures/players/achievement/player_achievement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ class PlayerAchievement {
explicit PlayerAchievement(Player &player);
bool add(uint16_t id, bool message = true, uint32_t timestamp = 0);
bool remove(uint16_t id);
bool isUnlocked(uint16_t id) const;
uint16_t getPoints() const;
[[nodiscard]] bool isUnlocked(uint16_t id) const;
[[nodiscard]] uint16_t getPoints() const;
void addPoints(uint16_t toAddPoints);
void removePoints(uint16_t toRemovePoints);
std::vector<std::pair<uint16_t, uint32_t>> getUnlockedAchievements() const;
[[nodiscard]] std::vector<std::pair<uint16_t, uint32_t>> getUnlockedAchievements() const;
void loadUnlockedAchievements();
void sendUnlockedSecretAchievements();
const std::shared_ptr<KV> &getUnlockedKV();
Expand Down
Loading

0 comments on commit a2f735a

Please sign in to comment.