From f52b7dc286fe410fec025924cc8b858afb6ba434 Mon Sep 17 00:00:00 2001 From: Sarah Wesker Date: Wed, 13 Dec 2023 15:38:47 -0400 Subject: [PATCH] world light to lua / effect & mastereffect --- .lua-format | 2 +- data/lib/core/game.lua | 39 +++++++ data/lib/core/player.lua | 100 ++++++++---------- .../player/world_light_time.lua | 12 +++ data/scripts/globalevents/world_light.lua | 44 ++++++++ data/scripts/globalevents/world_time.lua | 17 +++ data/scripts/lib/register_monster_type.lua | 2 +- src/game.cpp | 42 -------- src/game.h | 32 ------ src/luamonstertype.cpp | 15 ++- src/luaplayer.cpp | 3 +- src/luascript.cpp | 42 -------- src/luascript.h | 3 - src/monster.cpp | 6 +- src/monsters.cpp | 37 ++++++- src/monsters.h | 2 + src/player.h | 6 -- src/protocolgame.cpp | 10 -- src/protocolgame.h | 1 - 19 files changed, 210 insertions(+), 205 deletions(-) create mode 100644 data/scripts/creaturescripts/player/world_light_time.lua create mode 100644 data/scripts/globalevents/world_light.lua create mode 100644 data/scripts/globalevents/world_time.lua diff --git a/.lua-format b/.lua-format index 5c7cb67..df17791 100644 --- a/.lua-format +++ b/.lua-format @@ -3,4 +3,4 @@ continuation_indent_width: 1 use_tab: true tab_width: 4 chop_down_table: true -column_limit: 130 \ No newline at end of file +column_limit: 100 \ No newline at end of file diff --git a/data/lib/core/game.lua b/data/lib/core/game.lua index e8f8381..250ccc3 100644 --- a/data/lib/core/game.lua +++ b/data/lib/core/game.lua @@ -117,3 +117,42 @@ do return table.concat(response, " ") end end + +do + local worldLightLevel = 0 + local worldLightColor = 0 + + function Game.getWorldLight() return worldLightLevel, worldLightColor end + + function Game.setWorldLight(color, level) + if not configManager.getBoolean(configKeys.DEFAULT_WORLD_LIGHT) then return end + + local previousColor = worldLightColor + local previousLevel = worldLightLevel + worldLightColor = color + worldLightLevel = level + + if worldLightColor ~= previousColor or worldLightLevel ~= previousLevel then + for _, player in ipairs(Game.getPlayers()) do + player:sendWorldLight(worldLightColor, worldLightLevel) + end + end + end +end + +do + local worldTime = 0 + + function Game.getWorldTime() return worldTime end + + function Game.setWorldTime(time) + worldTime = time + + -- quarter-hourly update to client clock near the minimap + if worldTime % 15 == 0 then + for _, player in ipairs(Game.getPlayers()) do + player:sendWorldTime(worldTime) + end + end + end +end diff --git a/data/lib/core/player.lua b/data/lib/core/player.lua index f925cd9..007197a 100644 --- a/data/lib/core/player.lua +++ b/data/lib/core/player.lua @@ -1,8 +1,7 @@ local foodCondition = Condition(CONDITION_REGENERATION, CONDITIONID_DEFAULT) function Player.feed(self, food) - local condition = - self:getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT) + local condition = self:getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT) if condition then condition:setTicks(condition:getTicks() + (food * 1000)) else @@ -10,14 +9,10 @@ function Player.feed(self, food) if not vocation then return nil end foodCondition:setTicks(food * 1000) - foodCondition:setParameter(CONDITION_PARAM_HEALTHGAIN, - vocation:getHealthGainAmount()) - foodCondition:setParameter(CONDITION_PARAM_HEALTHTICKS, - vocation:getHealthGainTicks() * 1000) - foodCondition:setParameter(CONDITION_PARAM_MANAGAIN, - vocation:getManaGainAmount()) - foodCondition:setParameter(CONDITION_PARAM_MANATICKS, - vocation:getManaGainTicks() * 1000) + foodCondition:setParameter(CONDITION_PARAM_HEALTHGAIN, vocation:getHealthGainAmount()) + foodCondition:setParameter(CONDITION_PARAM_HEALTHTICKS, vocation:getHealthGainTicks() * 1000) + foodCondition:setParameter(CONDITION_PARAM_MANAGAIN, vocation:getManaGainAmount()) + foodCondition:setParameter(CONDITION_PARAM_MANATICKS, vocation:getManaGainTicks() * 1000) self:addCondition(foodCondition) end @@ -25,9 +20,7 @@ function Player.feed(self, food) end function Player.getClosestFreePosition(self, position, extended) - if self:getGroup():getAccess() and self:getAccountType() >= ACCOUNT_TYPE_GOD then - return position - end + if self:getGroup():getAccess() and self:getAccountType() >= ACCOUNT_TYPE_GOD then return position end return Creature.getClosestFreePosition(self, position, extended) end @@ -39,22 +32,13 @@ function Player.hasFlag(self, flag) return self:getGroup():hasFlag(flag) end function Player.getLossPercent(self) local blessings = 0 - local lossPercent = { - [0] = 100, - [1] = 70, - [2] = 45, - [3] = 25, - [4] = 10, - [5] = 0 - } + local lossPercent = {[0] = 100, [1] = 70, [2] = 45, [3] = 25, [4] = 10, [5] = 0} for i = 1, 5 do if self:hasBlessing(i) then blessings = blessings + 1 end end return lossPercent[blessings] end -function Player.getPremiumTime(self) - return math.max(0, self:getPremiumEndsAt() - os.time()) -end +function Player.getPremiumTime(self) return math.max(0, self:getPremiumEndsAt() - os.time()) end function Player.setPremiumTime(self, seconds) self:setPremiumEndsAt(os.time() + seconds) @@ -74,21 +58,14 @@ function Player.removePremiumTime(self, seconds) return true end -function Player.getPremiumDays(self) - return math.floor(self:getPremiumTime() / 86400) -end +function Player.getPremiumDays(self) return math.floor(self:getPremiumTime() / 86400) end -function Player.addPremiumDays(self, days) - return self:addPremiumTime(days * 86400) -end +function Player.addPremiumDays(self, days) return self:addPremiumTime(days * 86400) end -function Player.removePremiumDays(self, days) - return self:removePremiumTime(days * 86400) -end +function Player.removePremiumDays(self, days) return self:removePremiumTime(days * 86400) end function Player.isPremium(self) - return self:getPremiumTime() > 0 or - configManager.getBoolean(configKeys.FREE_PREMIUM) or + return self:getPremiumTime() > 0 or configManager.getBoolean(configKeys.FREE_PREMIUM) or self:hasFlag(PlayerFlag_IsAlwaysPremium) end @@ -97,14 +74,12 @@ function Player.sendCancelMessage(self, message) return self:sendTextMessage(MESSAGE_STATUS_SMALL, message) end -function Player.isUsingOtClient(self) - return self:getClient().os >= CLIENTOS_OTCLIENT_LINUX -end +function Player.isUsingOtClient(self) return self:getClient().os >= CLIENTOS_OTCLIENT_LINUX end function Player.sendExtendedOpcode(self, opcode, buffer) if not self:isUsingOtClient() then return false end - local networkMessage = NetworkMessage() + local networkMessage = NetworkMessage() networkMessage:addByte(0x32) networkMessage:addByte(opcode) networkMessage:addString(buffer) @@ -125,8 +100,8 @@ function Player.transferMoneyTo(self, target, amount) if targetPlayer then targetPlayer:setBankBalance(targetPlayer:getBankBalance() + amount) else - db.query("UPDATE `players` SET `balance` = `balance` + " .. amount .. - " WHERE `id` = '" .. target.guid .. "'") + db.query("UPDATE `players` SET `balance` = `balance` + " .. amount .. " WHERE `id` = '" .. + target.guid .. "'") end self:setBankBalance(self:getBankBalance() - amount) @@ -163,9 +138,7 @@ function Player.canCarryMoney(self, amount) -- If player don't have enough available inventory slots to carry this money local backpack = self:getSlotItem(CONST_SLOT_BACKPACK) - if not backpack or backpack:getEmptySlots(true) < inventorySlots then - return false - end + if not backpack or backpack:getEmptySlots(true) < inventorySlots then return false end return true end @@ -215,12 +188,11 @@ function Player.addLevel(self, amount, round) local level, amount = self:getLevel(), amount or 1 if amount > 0 then return self:addExperience(Game.getExperienceForLevel(level + amount) - - (round and self:getExperience() or - Game.getExperienceForLevel(level))) + (round and self:getExperience() or Game.getExperienceForLevel(level))) else - return self:removeExperience(((round and self:getExperience() or - Game.getExperienceForLevel(level)) - - Game.getExperienceForLevel(level + amount))) + return self:removeExperience( + ((round and self:getExperience() or Game.getExperienceForLevel(level)) - + Game.getExperienceForLevel(level + amount))) end end @@ -238,8 +210,7 @@ function Player.addMagicLevel(self, value) else value = math.min(currentMagLevel, math.abs(value)) while value > 0 do - sum = sum + - self:getVocation():getRequiredManaSpent(currentMagLevel - value + 1) + sum = sum + self:getVocation():getRequiredManaSpent(currentMagLevel - value + 1) value = value - 1 end @@ -253,9 +224,7 @@ function Player.addSkillLevel(self, skillId, value) if value > 0 then while value > 0 do - sum = sum + - self:getVocation() - :getRequiredSkillTries(skillId, currentSkillLevel + value) + sum = sum + self:getVocation():getRequiredSkillTries(skillId, currentSkillLevel + value) value = value - 1 end @@ -263,9 +232,7 @@ function Player.addSkillLevel(self, skillId, value) else value = math.min(currentSkillLevel, math.abs(value)) while value > 0 do - sum = sum + - self:getVocation() - :getRequiredSkillTries(skillId, currentSkillLevel - value + 1) + sum = sum + self:getVocation():getRequiredSkillTries(skillId, currentSkillLevel - value + 1) value = value - 1 end @@ -297,3 +264,22 @@ function Player.removeTibiaCoins(self, removeCoins) if tibiaCoins < removeCoins then return false end return self:setTibiaCoins(tibiaCoins - removeCoins) end + +function Player.sendWorldLight(self, color, level) + local msg = NetworkMessage() + msg:addByte(0x82) + msg:addByte(self:getGroup():getAccess() and 0xFF or level) + msg:addByte(color) + msg:sendToPlayer(self) + return true +end + +function Player.sendWorldTime(self, time) + if self:getClient().version < 1272 then return false end + local msg = NetworkMessage() + msg:addByte(0xEF) + msg:addByte(time / 60) -- hour + msg:addByte(time % 60) -- min + msg:sendToPlayer(self) + return true +end diff --git a/data/scripts/creaturescripts/player/world_light_time.lua b/data/scripts/creaturescripts/player/world_light_time.lua new file mode 100644 index 0000000..f84b7af --- /dev/null +++ b/data/scripts/creaturescripts/player/world_light_time.lua @@ -0,0 +1,12 @@ +local event = CreatureEvent("WorldTimeAndLight") + +function event.onLogin(player) + local worldTime = Game.getWorldTime() + player:sendWorldTime(worldTime) + + local worldLightColor, worldLightLevel = Game.getWorldLight() + player:sendWorldLight(worldLightColor, worldLightLevel) + return true +end + +event:register() diff --git a/data/scripts/globalevents/world_light.lua b/data/scripts/globalevents/world_light.lua new file mode 100644 index 0000000..e3cc9d0 --- /dev/null +++ b/data/scripts/globalevents/world_light.lua @@ -0,0 +1,44 @@ +local event = GlobalEvent("WorldLight") + +local lightConfig = {day = 250, night = 40} + +local worldConfig = {sunrise = 360, dayTime = 480, sunset = 1080, nightTime = 1200} + +local lightChange = { + sunrise = math.floor(((lightConfig.day - lightConfig.night) / + (worldConfig.dayTime - worldConfig.sunrise) * 100) / 100), + sunset = math.floor(((lightConfig.day - lightConfig.night) / + (worldConfig.nightTime - worldConfig.sunset) * 100) / 100) +} + +do + -- load default values + local defaultColor = 215 + local defaultLevel = lightConfig.day + Game.setWorldLight(defaultColor, defaultLevel) +end + +local function calculateWorldLightLevel() + local worldTime = Game.getWorldTime() + if worldTime >= worldConfig.sunrise and worldTime <= worldConfig.dayTime then + return math.floor(((worldConfig.dayTime - worldConfig.sunrise) - (worldConfig.dayTime - worldTime)) * + lightChange.sunrise + lightConfig.night) + elseif worldTime >= worldConfig.sunset and worldTime <= worldConfig.nightTime then + return lightConfig.day - ((worldTime - worldConfig.sunset) * lightChange.sunset) + elseif worldTime >= worldConfig.nightTime or worldTime < worldConfig.sunrise then + return lightConfig.night + end + return lightConfig.day +end + +function event.onTime(interval) + if not configManager.getBoolean(configKeys.DEFAULT_WORLD_LIGHT) then return true end + + local worldLightColor, worldLightLevel = Game.getWorldLight() + local level = calculateWorldLightLevel() + Game.setWorldLight(worldLightColor, level) + return true +end + +event:interval(10000) -- 10 seconds +event:register() diff --git a/data/scripts/globalevents/world_time.lua b/data/scripts/globalevents/world_time.lua new file mode 100644 index 0000000..60ce6c4 --- /dev/null +++ b/data/scripts/globalevents/world_time.lua @@ -0,0 +1,17 @@ +local event = GlobalEvent("WorldTime") + +-- 1h realtime = 1day worldtime +-- 2.5s realtime = 1min worldtime +-- worldTime is calculated in minutes + +function event.onTime(interval) + local currentTime = os.time() + local sec = os.date("%S", currentTime) + local min = os.date("%M", currentTime) + local worldTime = (sec + (min * 60)) / 2.5 + Game.setWorldTime(worldTime) + return true +end + +event:interval(2500) -- 2.5 seconds +event:register() diff --git a/data/scripts/lib/register_monster_type.lua b/data/scripts/lib/register_monster_type.lua index 1ebed8b..150af77 100644 --- a/data/scripts/lib/register_monster_type.lua +++ b/data/scripts/lib/register_monster_type.lua @@ -132,7 +132,7 @@ end registerMonsterType.summons = function(mtype, mask) if type(mask.summons) == "table" then for k, v in pairs(mask.summons) do - mtype:addSummon(v.name, v.interval, v.chance) + mtype:addSummon(v.name, v.interval, v.chance, v.effect, v.masterEffect) end end end diff --git a/src/game.cpp b/src/game.cpp index 15c6d5d..0418141 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -49,11 +49,6 @@ Game::~Game() void Game::start(ServiceManager* manager) { serviceManager = manager; - updateWorldTime(); - - if (g_config[ConfigKeysBoolean::DEFAULT_WORLD_LIGHT]) { - g_scheduler.addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL, [this]() { checkLight(); })); - } g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, [this]() { checkCreatures(0); })); g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, [this]() { checkDecay(); })); } @@ -4588,43 +4583,6 @@ void Game::checkDecay() cleanup(); } -void Game::checkLight() -{ - g_scheduler.addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL, [this]() { checkLight(); })); - uint8_t previousLightLevel = lightLevel; - updateWorldLightLevel(); - - if (previousLightLevel != lightLevel) { - LightInfo lightInfo = getWorldLightInfo(); - - for (const auto& it : players) { - it.second->sendWorldLight(lightInfo); - } - } -} - -void Game::updateWorldLightLevel() -{ - if (getWorldTime() >= GAME_SUNRISE && getWorldTime() <= GAME_DAYTIME) { - lightLevel = ((GAME_DAYTIME - GAME_SUNRISE) - (GAME_DAYTIME - getWorldTime())) * float(LIGHT_CHANGE_SUNRISE) + - LIGHT_NIGHT; - } else if (getWorldTime() >= GAME_SUNSET && getWorldTime() <= GAME_NIGHTTIME) { - lightLevel = LIGHT_DAY - ((getWorldTime() - GAME_SUNSET) * float(LIGHT_CHANGE_SUNSET)); - } else if (getWorldTime() >= GAME_NIGHTTIME || getWorldTime() < GAME_SUNRISE) { - lightLevel = LIGHT_NIGHT; - } else { - lightLevel = LIGHT_DAY; - } -} - -void Game::updateWorldTime() -{ - g_scheduler.addEvent(createSchedulerTask(EVENT_WORLDTIMEINTERVAL, [this]() { updateWorldTime(); })); - time_t osTime = time(nullptr); - struct tm timeInfo = fmt::localtime(osTime); - worldTime = (timeInfo.tm_sec + (timeInfo.tm_min * 60)) / 2.5f; -} - void Game::shutdown() { std::cout << "Shutting down..." << std::flush; diff --git a/src/game.h b/src/game.h index 7ff9659..2c8f780 100644 --- a/src/game.h +++ b/src/game.h @@ -216,17 +216,6 @@ class Game size_t getNpcsOnline() const { return npcs.size(); } uint32_t getPlayersRecord() const { return playersRecord; } - LightInfo getWorldLightInfo() const { return {lightLevel, lightColor}; } - void setWorldLightInfo(LightInfo lightInfo) - { - lightLevel = lightInfo.level; - lightColor = lightInfo.color; - for (const auto& it : players) { - it.second->sendWorldLight(lightInfo); - } - } - void updateWorldLightLevel(); - ReturnValue internalMoveCreature(Creature* creature, Direction direction, uint32_t flags = 0); ReturnValue internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags = 0); @@ -451,9 +440,6 @@ class Game void startDecay(Item* item); - int16_t getWorldTime() { return worldTime; } - void updateWorldTime(); - void loadMotdNum(); void saveMotdNum() const; std::string_view getMotdHash() const { return motdHash; } @@ -537,24 +523,6 @@ class Game std::unordered_set tilesToClean; - static constexpr uint8_t LIGHT_DAY = 250; - static constexpr uint8_t LIGHT_NIGHT = 40; - // 1h realtime = 1day worldtime - // 2.5s realtime = 1min worldtime - // worldTime is calculated in minutes - static constexpr int16_t GAME_SUNRISE = 360; - static constexpr int16_t GAME_DAYTIME = 480; - static constexpr int16_t GAME_SUNSET = 1080; - static constexpr int16_t GAME_NIGHTTIME = 1200; - static constexpr float LIGHT_CHANGE_SUNRISE = - static_cast(float(float(LIGHT_DAY - LIGHT_NIGHT) / float(GAME_DAYTIME - GAME_SUNRISE)) * 100) / 100.0f; - static constexpr float LIGHT_CHANGE_SUNSET = - static_cast(float(float(LIGHT_DAY - LIGHT_NIGHT) / float(GAME_NIGHTTIME - GAME_SUNSET)) * 100) / 100.0f; - - uint8_t lightLevel = LIGHT_DAY; - uint8_t lightColor = 215; - int16_t worldTime = 0; - GameState_t gameState = GAME_STATE_NORMAL; WorldType_t worldType = WORLD_TYPE_PVP; diff --git a/src/luamonstertype.cpp b/src/luamonstertype.cpp index 4184864..35f099c 100644 --- a/src/luamonstertype.cpp +++ b/src/luamonstertype.cpp @@ -823,10 +823,13 @@ int luaMonsterTypeGetSummonList(lua_State* L) int index = 0; lua_createtable(L, monsterType->info.summons.size(), 0); for (const auto& summonBlock : monsterType->info.summons) { - lua_createtable(L, 0, 3); + lua_createtable(L, 0, 6); setField(L, "name", summonBlock.name); setField(L, "speed", summonBlock.speed); setField(L, "chance", summonBlock.chance); + setField(L, "max", summonBlock.max); + setField(L, "effect", summonBlock.effect); + setField(L, "masterEffect", summonBlock.masterEffect); lua_rawseti(L, -2, ++index); } return 1; @@ -834,13 +837,17 @@ int luaMonsterTypeGetSummonList(lua_State* L) int luaMonsterTypeAddSummon(lua_State* L) { - // monsterType:addSummon(name, speed, chance) + // monsterType:addSummon(name, interval, chance[, max = uint32_t[, effect = CONST_ME_TELEPORT[, masterEffect = + // CONST_ME_NONE]]]) MonsterType* monsterType = getUserdata(L, 1); if (monsterType) { summonBlock_t summon; summon.name = getString(L, 2); - summon.speed = getInteger(L, 3); - summon.chance = getInteger(L, 4); + summon.speed = getInteger(L, 3); + summon.chance = getInteger(L, 4); + summon.max = getInteger(L, 5, std::numeric_limits::max()); + summon.effect = getInteger(L, 6, CONST_ME_TELEPORT); + summon.masterEffect = getInteger(L, 7, CONST_ME_NONE); monsterType->info.summons.push_back(summon); pushBoolean(L, true); } else { diff --git a/src/luaplayer.cpp b/src/luaplayer.cpp index 115ed10..41246ae 100644 --- a/src/luaplayer.cpp +++ b/src/luaplayer.cpp @@ -3,12 +3,11 @@ #include "otpch.h" -#include "player.h" - #include "chat.h" #include "game.h" #include "iologindata.h" #include "luascript.h" +#include "player.h" #include "spells.h" #include "vocation.h" diff --git a/src/luascript.cpp b/src/luascript.cpp index d510b0c..5265905 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -1065,15 +1065,6 @@ void LuaScriptInterface::registerFunctions() // getDepotId(uid) lua_register(luaState, "getDepotId", LuaScriptInterface::luaGetDepotId); - // getWorldTime() - lua_register(luaState, "getWorldTime", LuaScriptInterface::luaGetWorldTime); - - // getWorldLight() - lua_register(luaState, "getWorldLight", LuaScriptInterface::luaGetWorldLight); - - // setWorldLight(level, color) - lua_register(luaState, "setWorldLight", LuaScriptInterface::luaSetWorldLight); - // getWorldUpTime() lua_register(luaState, "getWorldUpTime", LuaScriptInterface::luaGetWorldUpTime); @@ -2314,39 +2305,6 @@ int LuaScriptInterface::luaDebugPrint(lua_State* L) return 0; } -int LuaScriptInterface::luaGetWorldTime(lua_State* L) -{ - // getWorldTime() - int16_t time = g_game.getWorldTime(); - lua_pushinteger(L, time); - return 1; -} - -int LuaScriptInterface::luaGetWorldLight(lua_State* L) -{ - // getWorldLight() - LightInfo lightInfo = g_game.getWorldLightInfo(); - lua_pushinteger(L, lightInfo.level); - lua_pushinteger(L, lightInfo.color); - return 2; -} - -int LuaScriptInterface::luaSetWorldLight(lua_State* L) -{ - // setWorldLight(level, color) - if (g_config[ConfigKeysBoolean::DEFAULT_WORLD_LIGHT]) { - Lua::pushBoolean(L, false); - return 1; - } - - LightInfo lightInfo; - lightInfo.level = Lua::getInteger(L, 1); - lightInfo.color = Lua::getInteger(L, 2); - g_game.setWorldLightInfo(lightInfo); - Lua::pushBoolean(L, true); - return 1; -} - int LuaScriptInterface::luaGetWorldUpTime(lua_State* L) { // getWorldUpTime() diff --git a/src/luascript.h b/src/luascript.h index 45515f0..3f91b2a 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -286,10 +286,7 @@ class LuaScriptInterface static int luaGetDepotId(lua_State* L); // get world info - static int luaGetWorldTime(lua_State* L); static int luaGetWorldUpTime(lua_State* L); - static int luaGetWorldLight(lua_State* L); - static int luaSetWorldLight(lua_State* L); // get subtype name static int luaGetSubTypeName(lua_State* L); diff --git a/src/monster.cpp b/src/monster.cpp index 1081ee4..a9e10b2 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -981,11 +981,13 @@ void Monster::onThinkDefense(uint32_t interval) Monster* summon = Monster::createMonster(summonBlock.name); if (summon) { - if (g_game.placeCreature(summon, getPosition(), false, summonBlock.force)) { + if (g_game.placeCreature(summon, getPosition(), false, summonBlock.force, summonBlock.effect)) { summon->setDropLoot(false); summon->setSkillLoss(false); summon->setMaster(this); - g_game.addMagicEffect(getPosition(), CONST_ME_MAGIC_BLUE); + if (summonBlock.masterEffect != CONST_ME_NONE) { + g_game.addMagicEffect(getPosition(), summonBlock.masterEffect); + } } else { delete summon; } diff --git a/src/monsters.cpp b/src/monsters.cpp index 7063a45..27e8624 100644 --- a/src/monsters.cpp +++ b/src/monsters.cpp @@ -1335,6 +1335,8 @@ MonsterType* Monsters::loadMonster(const std::string& file, const std::string& m int32_t chance = 100; int32_t speed = 1000; int32_t max = mType->info.maxSummons; + MagicEffectClasses effect = CONST_ME_TELEPORT; + MagicEffectClasses masterEffect = CONST_ME_NONE; bool force = false; if ((attr = summonNode.attribute("speed")) || (attr = summonNode.attribute("interval"))) { @@ -1354,6 +1356,35 @@ MonsterType* Monsters::loadMonster(const std::string& file, const std::string& m max = pugi::cast(attr.value()); } + for (const auto& attributeNode : summonNode.children()) { + if ((attr = attributeNode.attribute("key"))) { + const char* value = attr.value(); + if (caseInsensitiveEqual(value, "mastereffect")) { + if ((attr = attributeNode.attribute("value"))) { + masterEffect = + getMagicEffect(boost::algorithm::to_lower_copy(attr.as_string())); + if (masterEffect == CONST_ME_NONE) { + std::cout + << "[Warning - Monsters::loadMonster] Summon master effect - Unknown masterEffect: " + << attr.as_string() << std::endl; + } + } + } else if (caseInsensitiveEqual(value, "effect")) { + if ((attr = attributeNode.attribute("value"))) { + effect = getMagicEffect(boost::algorithm::to_lower_copy(attr.as_string())); + if (effect == CONST_ME_NONE) { + effect = CONST_ME_TELEPORT; + std::cout << "[Warning - Monsters::loadMonster] Summon effect - Unknown effect: " + << attr.as_string() << std::endl; + } + } + } else { + std::cout << "[Warning - Monsters::loadMonster] Summon effect type \"" << attr.as_string() + << "\" does not exist." << std::endl; + } + } + } + if ((attr = summonNode.attribute("force"))) { force = attr.as_bool(); } @@ -1364,6 +1395,8 @@ MonsterType* Monsters::loadMonster(const std::string& file, const std::string& m sb.speed = speed; sb.chance = chance; sb.max = max; + sb.effect = effect; + sb.masterEffect = masterEffect; sb.force = force; mType->info.summons.emplace_back(sb); } else { @@ -1539,8 +1572,8 @@ bool Monsters::registerBestiaryMonster(const MonsterType* mType) { auto [it, success] = bestiaryMonsters.insert_or_assign(mType->raceId, mType->name); if (!success) { - std::cout << "[Warning - Monsters::registerBestiaryMonster] Monster raceId " << mType->raceId - << " already exists but was overwritten for the monster " << mType->name << ". " << std::endl; + /* std::cout << "[Warning - Monsters::registerBestiaryMonster] Monster raceId " << mType->raceId + << " already exists but was overwritten for the monster " << mType->name << ". " << std::endl;*/ } return success; } diff --git a/src/monsters.h b/src/monsters.h index f68c048..63e8c73 100644 --- a/src/monsters.h +++ b/src/monsters.h @@ -49,6 +49,8 @@ struct summonBlock_t uint32_t chance; uint32_t speed; uint32_t max; + MagicEffectClasses effect = CONST_ME_TELEPORT; + MagicEffectClasses masterEffect = CONST_ME_NONE; bool force = false; }; diff --git a/src/player.h b/src/player.h index 9f8e716..6adeaa6 100644 --- a/src/player.h +++ b/src/player.h @@ -813,12 +813,6 @@ class Player final : public Creature, public Cylinder client->sendCloseTrade(); } } - void sendWorldLight(LightInfo lightInfo) - { - if (client) { - client->sendWorldLight(lightInfo); - } - } void sendChannelsDialog() { if (client) { diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index c477add..bccb079 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -1387,13 +1387,6 @@ void ProtocolGame::sendCreatureLight(const Creature* 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)) { @@ -2080,9 +2073,6 @@ void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos sendStats(); sendSkills(); - // gameworld light-settings - sendWorldLight(g_game.getWorldLightInfo()); - // player light level sendCreatureLight(creature); diff --git a/src/protocolgame.h b/src/protocolgame.h index d1b4f9f..8de9551 100644 --- a/src/protocolgame.h +++ b/src/protocolgame.h @@ -187,7 +187,6 @@ class ProtocolGame final : public Protocol void sendAnimatedText(std::string_view message, const Position& pos, TextColor_t color); void sendCreatureLight(const Creature* creature); - void sendWorldLight(LightInfo lightInfo); void sendCreatureSquare(const Creature* creature, SquareColor_t color);