diff --git a/New Text Document.txt b/New Text Document.txt index 1dc6e3b..9ea74f3 100644 --- a/New Text Document.txt +++ b/New Text Document.txt @@ -1 +1 @@ -next: 17723 \ No newline at end of file +next: 17739 \ No newline at end of file diff --git a/config.lua b/config.lua index 5a68061..42dfdcc 100644 --- a/config.lua +++ b/config.lua @@ -1,6 +1,10 @@ -- Custom -knightCloseAttackDamageIncreasePercent = 50 -paladinRangeAttackDamageIncreasePercent = 40 +clientVersion = 792 +knightCloseAttackDamageIncreasePercent = 20 +paladinRangeAttackDamageIncreasePercent = 15 +-- Min/Max rate spawn is a multiplication of the map spawntime in spawns.xml Regular monster spawn time is 600. The formula would be randomValue = random(600*100, 600*200) which varies between 60s and 120s +minRateSpawn = 100 +maxRateSpawn = 200 -- Combat settings -- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced" @@ -15,15 +19,15 @@ expFromPlayersLevelRange = 75 distanceWeaponsDropOnGround = false -- Skull System -banLength = 30 * 24 * 60 * 60 +banLength = 2 * 24 * 60 * 60 whiteSkullTime = 15 * 60 -redSkullTime = 30 * 24 * 60 * 60 +redSkullTime = 7 * 24 * 60 * 60 killsDayRedSkull = 3 -killsWeekRedSkull = 5 -killsMonthRedSkull = 10 -killsDayBanishment = 6 -killsWeekBanishment = 10 -killsMonthBanishment = 20 +killsWeekRedSkull = 6 +killsMonthRedSkull = 99999 +killsDayBanishment = 1 +killsWeekBanishment = 12 +killsMonthBanishment = 99999 -- Connection Config -- NOTE: maxPlayers set to 0 means no limit @@ -32,7 +36,7 @@ bindOnlyGlobalAddress = false loginProtocolPort = 7171 gameProtocolPort = 7172 statusProtocolPort = 7171 -maxPlayers = 1000 +maxPlayers = 0 motd = "Welcome to Sabrehaven!" onePlayerOnlinePerAccount = true allowClones = false @@ -42,7 +46,6 @@ replaceKickOnLogin = true maxPacketsPerSecond = -1 autoStackCumulatives = false moneyRate = 1 -clientVersion = 792 -- Deaths -- NOTE: Leave deathLosePercent as -1 if you want to use the default @@ -89,7 +92,7 @@ newbieLevelThreshold = 5 -- Rates -- NOTE: rateExp is not used if you have enabled stages in data/XML/stages.xml rateExp = 1 -rateSkill = 5 +rateSkill = 3 rateLoot = 2 rateMagic = 2 rateSpawn = 0 @@ -109,7 +112,7 @@ defaultPriority = "high" startupDatabaseOptimization = true -- Status server information -ownerName = "" +ownerName = "Erikas" ownerEmail = "" -url = "https://otland.net/" -location = "Sweden" +url = "https://sabrehaven.com/" +location = "Poland" diff --git a/data/XML/quests.xml b/data/XML/quests.xml index 0c904a4..840be0d 100644 --- a/data/XML/quests.xml +++ b/data/XML/quests.xml @@ -446,6 +446,26 @@ <mission name="Paw and Fur: Dwarfs" storageid="17703" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Low Undeads" storageid="17704" startvalue="0" endvalue="100" description="You already hunted |STATE|/100 undeads." /> <mission name="Paw and Fur: Low Undeads" storageid="17704" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Elves" storageid="17729" startvalue="0" endvalue="200" description="You already hunted |STATE|/200 elves." /> + <mission name="Paw and Fur: Elves" storageid="17729" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Bugs" storageid="17730" startvalue="0" endvalue="40" description="You already hunted |STATE|/40 bugs." /> + <mission name="Paw and Fur: Bugs" storageid="17730" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Outlaws" storageid="17731" startvalue="0" endvalue="250" description="You already hunted |STATE|/250 outlaws." /> + <mission name="Paw and Fur: Outlaws" storageid="17731" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Hyaenas" storageid="17732" startvalue="0" endvalue="30" description="You already hunted |STATE|/30 hyaenas." /> + <mission name="Paw and Fur: Hyaenas" storageid="17732" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Lions" storageid="17733" startvalue="0" endvalue="20" description="You already hunted |STATE|/20 lions." /> + <mission name="Paw and Fur: Lions" storageid="17733" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Bears" storageid="17734" startvalue="0" endvalue="35" description="You already hunted |STATE|/35 bears." /> + <mission name="Paw and Fur: Bears" storageid="17734" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Slimes" storageid="17735" startvalue="0" endvalue="100" description="You already hunted |STATE|/100 slimes." /> + <mission name="Paw and Fur: Slimes" storageid="17735" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Beholders" storageid="17736" startvalue="0" endvalue="250" description="You already hunted |STATE|/250 beholders." /> + <mission name="Paw and Fur: Beholders" storageid="17736" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Djinns" storageid="17737" startvalue="0" endvalue="500" description="You already hunted |STATE|/500 djinns." /> + <mission name="Paw and Fur: Djinns" storageid="17737" startvalue="99999" endvalue="99999" description="You have finished the task." /> + <mission name="Paw and Fur: Pirates" storageid="17738" startvalue="0" endvalue="600" description="You already hunted |STATE|/600 pirates." /> + <mission name="Paw and Fur: Pirates" storageid="17738" startvalue="99999" endvalue="99999" description="You have finished the task." /> <!--Grizzly Adams: level 50 to 79 --> <mission name="Paw and Fur: Quara Scouts" storageid="17616" startvalue="0" endvalue="200" description="You already hunted |STATE|/200 quara scouts." /> @@ -459,17 +479,27 @@ <mission name="Paw and Fur: Dragons" storageid="17620" startvalue="0" endvalue="200" description="You already hunted |STATE|/200 dragons." /> <mission name="Paw and Fur: Dragons" storageid="17620" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Medium Class Orcs" storageid="17712" startvalue="0" endvalue="300" description="You already hunted |STATE|/300 orcs." /> + <mission name="Paw and Fur: Medium Class Orcs" storageid="17712" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: High Class Minotaurs" storageid="17713" startvalue="0" endvalue="300" description="You already hunted |STATE|/300 minotaurs." /> + <mission name="Paw and Fur: High Class Minotaurs" storageid="17713" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Lizards" storageid="17714" startvalue="0" endvalue="300" description="You already hunted |STATE|/300 lizards." /> + <mission name="Paw and Fur: Lizards" storageid="17714" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: High Class Dwarfs" storageid="17715" startvalue="0" endvalue="300" description="You already hunted |STATE|/300 dwarfs." /> + <mission name="Paw and Fur: High Class Dwarfs" storageid="17715" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Medium Undeads" storageid="17716" startvalue="0" endvalue="200" description="You already hunted |STATE|/200 undeads." /> + <mission name="Paw and Fur: Medium Undeads" storageid="17716" startvalue="99999" endvalue="99999" description="You have finished the task." /> <!--Grizzly Adams: level 80 to 129 --> <mission name="Paw and Fur: Quara" storageid="17621" startvalue="0" endvalue="600" description="You already hunted |STATE|/600 quara." /> + <mission name="Paw and Fur: Quara" storageid="17621" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Giant Spiders" storageid="17622" startvalue="0" endvalue="500" description="You already hunted |STATE|/500 giant spiders." /> + <mission name="Paw and Fur: Giant Spiders" storageid="17622" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Banshees" storageid="17623" startvalue="0" endvalue="300" description="You already hunted |STATE|/300 banshees." /> + <mission name="Paw and Fur: Banshees" storageid="17623" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Lichs" storageid="17624" startvalue="0" endvalue="500" description="You already hunted |STATE|/500 lichs." /> + <mission name="Paw and Fur: Lichs" storageid="17624" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Cults" storageid="17625" startvalue="0" endvalue="500" description="You already hunted |STATE|/500 cults." /> + <mission name="Paw and Fur: Cults" storageid="17625" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: High Class Orcs" storageid="17717" startvalue="0" endvalue="125" description="You already hunted |STATE|/125 orcs." /> <mission name="Paw and Fur: High Class Orcs" storageid="17717" startvalue="99999" endvalue="99999" description="You have finished the task." /> <mission name="Paw and Fur: Heros" storageid="17718" startvalue="0" endvalue="150" description="You already hunted |STATE|/150 heros." /> diff --git a/data/XML/stages.xml b/data/XML/stages.xml index 575c4dd..7bbf9e2 100644 --- a/data/XML/stages.xml +++ b/data/XML/stages.xml @@ -1,10 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <stages> <config enabled="1"/> - <stage minlevel="1" maxlevel="20" multiplier="15" /> - <stage minlevel="21" maxlevel="40" multiplier="12" /> - <stage minlevel="41" maxlevel="60" multiplier="10" /> - <stage minlevel="61" maxlevel="80" multiplier="6" /> - <stage minlevel="81" maxlevel="100" multiplier="3" /> - <stage minlevel="101" multiplier="2" /> + <stage minlevel="1" maxlevel="10" multiplier="10" /> + <stage minlevel="11" maxlevel="20" multiplier="9" /> + <stage minlevel="21" maxlevel="30" multiplier="8" /> + <stage minlevel="31" maxlevel="40" multiplier="7" /> + <stage minlevel="41" maxlevel="50" multiplier="6" /> + <stage minlevel="51" maxlevel="60" multiplier="5" /> + <stage minlevel="61" maxlevel="70" multiplier="4" /> + <stage minlevel="71" maxlevel="80" multiplier="3" /> + <stage minlevel="81" multiplier="2" /> </stages> \ No newline at end of file diff --git a/data/actions/actions.xml b/data/actions/actions.xml index c2ee247..72566eb 100644 --- a/data/actions/actions.xml +++ b/data/actions/actions.xml @@ -239,6 +239,8 @@ <action itemid="3031" script="misc/changegold.lua" /> <action itemid="3035" script="misc/changegold.lua" /> <action itemid="3043" script="misc/changegold.lua" /> + <action fromaid="17724" toaid="17728" script="misc/skill_trainer.lua" /> + <action fromid="6506" toid="6508" script="misc/christmas_bundle.lua" /> <!-- Chests --> <action itemid="2479" script="misc/chests.lua" /> diff --git a/data/actions/scripts/misc/christmas_bundle.lua b/data/actions/scripts/misc/christmas_bundle.lua new file mode 100644 index 0000000..fa1368d --- /dev/null +++ b/data/actions/scripts/misc/christmas_bundle.lua @@ -0,0 +1,50 @@ +function onUse(player, item, fromPosition, target, toPosition, isHotkey) + + local bundleTypes = { + [6506] = { -- red christmas bundle + 6503 + }, + [6507] = { -- blue christmas bundle + 6504 + }, + [6508] = { -- green christmas bundle + 6502 + } + } + + local common = { + {6569, 15}, {3598, 20}, {3599, 10}, {3586, 10}, {3585, 5}, 6500, 6501, 6489, 6387 + } + + local targetItem = bundleTypes[item.itemid] + if not targetItem then + return true + end + + targetItem = common + + -- In case there's going to be more than one unique item per bundle + for i = 1, #bundleTypes[item.itemid] do + table.insert(targetItem, bundleTypes[item.itemid][i]) + end + + local rewards = {} + repeat + local count = 1 + local rand = math.random(#targetItem) + local gift = targetItem[rand] + if type(gift) == "table" then + count = gift[2] + gift = gift[1] + end + rewards[#rewards + 1] = {gift, count} + table.remove(targetItem, rand) + until #rewards == 7 + + for i = 1, #rewards do + player:addItem(rewards[i][1], rewards[i][2]) + end + item:remove(1) + fromPosition:sendMagicEffect(CONST_ME_GIFT_WRAPS) + return true +end \ No newline at end of file diff --git a/data/actions/scripts/misc/skill_trainer.lua b/data/actions/scripts/misc/skill_trainer.lua new file mode 100644 index 0000000..a41a360 --- /dev/null +++ b/data/actions/scripts/misc/skill_trainer.lua @@ -0,0 +1,30 @@ +local statues = { + [17725] = SKILL_SWORD, + [17724] = SKILL_AXE, + [17726] = SKILL_CLUB, + [17727] = SKILL_DISTANCE, + [17728] = SKILL_MAGLEVEL +} + +function onUse(player, item, fromPosition, target, toPosition, isHotkey) + local skill = statues[item:getActionId()] + if not player:isPremium() then + player:sendCancelMessage(RETURNVALUE_YOUNEEDPREMIUMACCOUNT) + return true + end + + if player:isPzLocked() then + return false + end + + local entreePrice = 1000 + if player:getBankBalance() < entreePrice then + player:sendCancelMessage("You do not have 1000 gold coins in your bank account balance to participate in offline training.") + return true + end + + player:setOfflineTrainingSkill(skill) + player:setBankBalance(player:getBankBalance() - entreePrice) + player:remove() + return true +end diff --git a/data/creaturescripts/creaturescripts.xml b/data/creaturescripts/creaturescripts.xml index bf0570a..fa369a3 100644 --- a/data/creaturescripts/creaturescripts.xml +++ b/data/creaturescripts/creaturescripts.xml @@ -6,7 +6,8 @@ <event type="login" name="FirstItems" script="firstitems.lua"/> <event type="login" name="RegenerateStamina" script="regeneratestamina.lua" /> <event type="death" name="PlayerDeath" script="playerdeath.lua"/> - + <event type="login" name="OfflineTraining" script="offlinetraining.lua" /> + <!-- Killing In The Name Of Quest --> - <event type="kill" name="KillingInTheNameOfKills" script="killing_in_the_name_of.lua" /> + <event type="death" name="KillingInTheNameOf" script="killing_in_the_name_of.lua" /> </creaturescripts> diff --git a/data/creaturescripts/scripts/killing_in_the_name_of.lua b/data/creaturescripts/scripts/killing_in_the_name_of.lua index aa79f25..a3b2f92 100644 --- a/data/creaturescripts/scripts/killing_in_the_name_of.lua +++ b/data/creaturescripts/scripts/killing_in_the_name_of.lua @@ -40,11 +40,35 @@ local tasks = { ['rat'] = {taskerStorage = 17608, progressStorage = 17699, killsRequired = 25}, ['cave rat'] = {taskerStorage = 17608, progressStorage = 17699, killsRequired = 25}, ['wolf'] = {taskerStorage = 17608, progressStorage = 17700, killsRequired = 100}, + ['winter wolf'] = {taskerStorage = 17608, progressStorage = 17700, killsRequired = 100}, ['wasp'] = {taskerStorage = 17608, progressStorage = 17701, killsRequired = 100}, ['larva'] = {taskerStorage = 17608, progressStorage = 17702, killsRequired = 100}, ['dwarf'] = {taskerStorage = 17608, progressStorage = 17703, killsRequired = 100}, ['skeleton'] = {taskerStorage = 17608, progressStorage = 17704, killsRequired = 100}, ['ghoul'] = {taskerStorage = 17608, progressStorage = 17704, killsRequired = 100}, + ['elf'] = {taskerStorage = 17608, progressStorage = 17729, killsRequired = 200}, + ['elf scout'] = {taskerStorage = 17608, progressStorage = 17729, killsRequired = 200}, + ['elf arcanist'] = {taskerStorage = 17608, progressStorage = 17729, killsRequired = 200}, + ['bug'] = {taskerStorage = 17608, progressStorage = 17730, killsRequired = 40}, + ['smuggler'] = {taskerStorage = 17608, progressStorage = 17731, killsRequired = 250}, + ['wild warrior'] = {taskerStorage = 17608, progressStorage = 17731, killsRequired = 250}, + ['bandit'] = {taskerStorage = 17608, progressStorage = 17731, killsRequired = 250}, + ['hyaena'] = {taskerStorage = 17608, progressStorage = 17732, killsRequired = 30}, + ['lion'] = {taskerStorage = 17608, progressStorage = 17733, killsRequired = 20}, + ['bear'] = {taskerStorage = 17608, progressStorage = 17734, killsRequired = 35}, + ['slime'] = {taskerStorage = 17608, progressStorage = 17735, killsRequired = 100}, + ['beholder'] = {taskerStorage = 17608, progressStorage = 17736, killsRequired = 250}, + ['elder beholder'] = {taskerStorage = 17608, progressStorage = 17736, killsRequired = 250}, + ['green djinn'] = {taskerStorage = 17608, progressStorage = 17737, killsRequired = 500}, + ['blue djinn'] = {taskerStorage = 17608, progressStorage = 17737, killsRequired = 500}, + ['marid'] = {taskerStorage = 17608, progressStorage = 17737, killsRequired = 500}, + ['efreet'] = {taskerStorage = 17608, progressStorage = 17737, killsRequired = 500}, + ['pirate skeleton'] = {taskerStorage = 17608, progressStorage = 17738, killsRequired = 600}, + ['pirate marauder'] = {taskerStorage = 17608, progressStorage = 17738, killsRequired = 600}, + ['pirate cutthroat'] = {taskerStorage = 17608, progressStorage = 17738, killsRequired = 600}, + ['pirate ghost'] = {taskerStorage = 17608, progressStorage = 17738, killsRequired = 600}, + ['pirate buccaneer'] = {taskerStorage = 17608, progressStorage = 17738, killsRequired = 600}, + ['pirate corsair'] = {taskerStorage = 17608, progressStorage = 17738, killsRequired = 600}, ['orc spearman'] = {taskerStorage = 17608, progressStorage = 17712, killsRequired = 300}, ['orc shaman'] = {taskerStorage = 17608, progressStorage = 17712, killsRequired = 300}, ['orc rider'] = {taskerStorage = 17608, progressStorage = 17712, killsRequired = 300}, @@ -84,56 +108,37 @@ local tasks = { ['orc'] = {taskerStorage = 17652, progressStorage = 17651, killsRequired = 50}, } -local function randomSort(arr) - local sorted = {} - local rand2 - local rand - local mem - for i=1,#arr do - sorted[i] = arr[i] - end - if (#arr <= 1) then - return sorted; - end - for i=1,(#arr)^2 do - repeat - rand = math.random(1,#sorted) - rand2 = math.random(1,#sorted) - until rand ~= rand2 - mem = sorted[rand] - sorted[rand] = pgtss[rand2] - sorted[rand2] = mem - end - return sorted -end - local maxPlayersInPartyShare = 2 --- not tested probably nothing is working -function onKill(player, target) - if target:isPlayer() or target:getMaster() then + +function onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) + if not creature:isMonster() or creature:getMaster() then return true end - local targetName = target:getName():lower() + local player = mostdamagekiller + if not mostdamagekiller:isPlayer() then + local master = mostdamagekiller:getMaster() + if master and master:isPlayer() then + player = master + else + return true + end + end + + local targetName = creature:getName():lower() local task = tasks[targetName] if task ~= nil then - local players local party = player:getParty() - if party ~= nil and party:isSharedExperienceEnabled() then + if party ~= nil and party:isSharedExperienceActive() then players = party:getMembers() -- all members of the party players[#players + 1] = party:getLeader() -- don't forget the leader - - if #players > maxPlayersInPartyShare then -- if more than 4 players are in party than shuffle the table and give task bonus only for the first 4 players - players = randomSort(players) - end else players = { player } -- no party? then just the player end for i, member in ipairs(players) do - print(i) - if i < maxPlayersInPartyShare then + if i <= maxPlayersInPartyShare then local inProgressQuest = member:getStorageValue(task.taskerStorage) if inProgressQuest == task.progressStorage then local playerQuestKills = member:getStorageValue(task.progressStorage) @@ -145,5 +150,5 @@ function onKill(player, target) end end end - return true + return true end \ No newline at end of file diff --git a/data/creaturescripts/scripts/login.lua b/data/creaturescripts/scripts/login.lua index 5d971b6..480455d 100644 --- a/data/creaturescripts/scripts/login.lua +++ b/data/creaturescripts/scripts/login.lua @@ -58,7 +58,6 @@ function onLogin(player) player:registerEvent("PlayerLogout") player:registerEvent("FirstItems") player:registerEvent("RegenerateStamina") - player:registerEvent("KillingInTheNameOfKills") return true end diff --git a/data/creaturescripts/scripts/offlinetraining.lua b/data/creaturescripts/scripts/offlinetraining.lua new file mode 100644 index 0000000..9767a9a --- /dev/null +++ b/data/creaturescripts/scripts/offlinetraining.lua @@ -0,0 +1,76 @@ +function onLogin(player) + local lastLogout = player:getLastLogout() + local offlineTime = lastLogout ~= 0 and math.min(os.time() - lastLogout, 86400 * 21) or 0 + local offlineTrainingSkill = player:getOfflineTrainingSkill() + if offlineTrainingSkill == -1 then + player:addOfflineTrainingTime(offlineTime * 1000) + return true + end + + player:setOfflineTrainingSkill(-1) + + if offlineTime < 600 then + player:setBankBalance(player:getBankBalance() + 1000) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must be logged out for more than 10 minutes to start offline training. Your 1000 gold coins entree fee were returned to your bank account.") + return true + end + + local trainingTime = math.max(0, math.min(offlineTime, math.min(43200 / 2, player:getOfflineTrainingTime() / 1000))) + player:removeOfflineTrainingTime(trainingTime * 1000) + + local remainder = offlineTime - trainingTime + if remainder > 0 then + player:addOfflineTrainingTime(remainder * 1000) + end + + if trainingTime < 60 then + return true + end + + local text = "During your absence you trained for" + local hours = math.floor(trainingTime / 3600) + if hours > 1 then + text = string.format("%s %d hours", text, hours) + elseif hours == 1 then + text = string.format("%s 1 hour", text) + end + + local minutes = math.floor((trainingTime % 3600) / 60) + if minutes ~= 0 then + if hours ~= 0 then + text = string.format("%s and", text) + end + + if minutes > 1 then + text = string.format("%s %d minutes", text, minutes) + else + text = string.format("%s 1 minute", text) + end + end + + text = string.format("%s.", text) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, text) + + local vocation = player:getVocation() + local promotion = vocation:getPromotion() + local topVocation = not promotion and vocation or promotion + + local updateSkills = false + if table.contains({SKILL_CLUB, SKILL_SWORD, SKILL_AXE, SKILL_DISTANCE}, offlineTrainingSkill) then + local modifier = topVocation:getAttackSpeed() / 1000 + updateSkills = player:addOfflineTrainingTries(offlineTrainingSkill, (trainingTime / modifier) / (offlineTrainingSkill == SKILL_DISTANCE and 8 or 4)) + elseif offlineTrainingSkill == SKILL_MAGLEVEL then + local gainTicks = topVocation:getManaGainTicks() * 4 + if gainTicks == 0 then + gainTicks = 1 + end + + updateSkills = player:addOfflineTrainingTries(SKILL_MAGLEVEL, trainingTime * (vocation:getManaGainAmount() / gainTicks)) + end + + if updateSkills then + player:addOfflineTrainingTries(SKILL_SHIELD, trainingTime / 8) + end + + return true +end diff --git a/data/creaturescripts/scripts/playerdeath.lua b/data/creaturescripts/scripts/playerdeath.lua index 99f4afd..73fdc56 100644 --- a/data/creaturescripts/scripts/playerdeath.lua +++ b/data/creaturescripts/scripts/playerdeath.lua @@ -2,96 +2,85 @@ local deathListEnabled = true local maxDeathRecords = 50 function onDeath(player, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified) - local playerId = player:getId() + local playerId = player:getId() if nextUseStaminaTime[playerId] then nextUseStaminaTime[playerId] = nil end - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.") - - -- restart blessings values - player:setStorageValue(101,0) - player:setStorageValue(102,0) - player:setStorageValue(103,0) - player:setStorageValue(104,0) - player:setStorageValue(105,0) - - if not deathListEnabled then - return - end + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.") + + -- restart blessings values + player:setStorageValue(101,0) + player:setStorageValue(102,0) + player:setStorageValue(103,0) + player:setStorageValue(104,0) + player:setStorageValue(105,0) + + if not deathListEnabled then + return + end - local byPlayer = 0 - local killerName - if killer ~= nil then - if killer:isPlayer() then - byPlayer = 1 - else - local master = killer:getMaster() - if master and master ~= killer and master:isPlayer() then - killer = master - byPlayer = 1 - end - end - killerName = killer:getName() - else - killerName = "field item" - end + local byPlayer = false + local killerName + if killer ~= nil then + if killer:isPlayer() then + byPlayer = true + else + local master = killer:getMaster() + if master and master ~= killer and master:isPlayer() then + killer = master + byPlayer = true + end + end + killerName = killer:getName() + else + killerName = "field item" + end - local byPlayerMostDamage = 0 - local mostDamageKillerName - if mostDamageKiller ~= nil then - if mostDamageKiller:isPlayer() then - byPlayerMostDamage = 1 - else - local master = mostDamageKiller:getMaster() - if master and master ~= mostDamageKiller and master:isPlayer() then - mostDamageKiller = master - byPlayerMostDamage = 1 - end - end - mostDamageName = mostDamageKiller:getName() - else - mostDamageName = "field item" - end + local byPlayerMostDamage = 0 + local mostDamageKillerName + if mostDamageKiller ~= nil then + if mostDamageKiller:isPlayer() then + byPlayerMostDamage = 1 + else + local master = mostDamageKiller:getMaster() + if master and master ~= mostDamageKiller and master:isPlayer() then + mostDamageKiller = master + byPlayerMostDamage = 1 + end + end + mostDamageName = mostDamageKiller:getName() + else + mostDamageName = "field item" + end - local playerGuid = player:getGuid() - db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. byPlayer .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (unjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")") - local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid) + local playerGuid = player:getGuid() + db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. (byPlayer and 1 or 0) .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (unjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")") + local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid) - local deathRecords = 0 - local tmpResultId = resultId - while tmpResultId ~= false do - tmpResultId = result.next(resultId) - deathRecords = deathRecords + 1 - end + local deathRecords = 0 + local tmpResultId = resultId + while tmpResultId ~= false do + tmpResultId = result.next(resultId) + deathRecords = deathRecords + 1 + end - if resultId ~= false then - result.free(resultId) - end + if resultId ~= false then + result.free(resultId) + end - local limit = deathRecords - maxDeathRecords - if limit > 0 then - db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit) - end + local limit = deathRecords - maxDeathRecords + if limit > 0 then + db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit) + end - if byPlayer == 1 then - local targetGuild = player:getGuild() - targetGuild = targetGuild and targetGuild:getId() or 0 - if targetGuild ~= 0 then - local killerGuild = killer:getGuild() - killerGuild = killerGuild and killerGuild:getId() or 0 - if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then - local warId = false - resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))") - if resultId ~= false then - warId = result.getDataInt(resultId, "id") - result.free(resultId) - end + if not byPlayer then + return + end - if warId ~= false then - db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(player:getName()) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")") - end - end - end - end -end + local warId = guildwars:isInWar(killer, player) + if warId ~= 0 then + guildwars:processKill(warId, killer, player) + end + +end \ No newline at end of file diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua index 5f51c2d..fadfdab 100644 --- a/data/events/scripts/player.lua +++ b/data/events/scripts/player.lua @@ -1,5 +1,38 @@ +local trainingStatues = {17724, 17725, 17726, 17727, 17728} + function Player:onLook(thing, position, distance) local description = "You see " .. thing:getDescription(distance) + + if thing:isItem() and thing:getId() == 2028 then + if isInArray(trainingStatues, thing:getActionId()) then + local trainingTime = math.min(43200 / 2, self:getOfflineTrainingTime() / 1000) + local text = "You have" + local hours = math.floor(trainingTime / 3600) + if hours > 1 then + text = string.format("%s %d hours", text, hours) + elseif hours == 1 then + text = string.format("%s 1 hour", text) + end + + local minutes = math.floor((trainingTime % 3600) / 60) + if minutes ~= 0 then + if hours ~= 0 then + text = string.format("%s and", text) + end + + if minutes > 1 then + text = string.format("%s %d minutes", text, minutes) + else + text = string.format("%s 1 minute", text) + end + end + + text = string.format(" %s offline training time remaining.", text) + + description = string.format(description .. "%s", text) + end + end + if self:getGroup():getAccess() then if thing:isItem() then description = string.format("%s\nItem ID: %d", description, thing:getId()) diff --git a/data/global.lua b/data/global.lua index 6c2ede8..dfb8606 100644 --- a/data/global.lua +++ b/data/global.lua @@ -48,4 +48,35 @@ end if not nextUseStaminaTime then nextUseStaminaTime = {} +end + +function isInArray(array, value, isCaseSensitive) + local compareLowerCase = false + if value ~= nil and type(value) == "string" and not isCaseSensitive then + value = string.lower(value) + compareLowerCase = true + end + if array == nil or value == nil then + return (array == value), nil + end + local t = type(array) + if t ~= "table" then + if compareLowerCase and t == "string" then + return (string.lower(array) == string.lower(value)), nil + else + return (array == value), nil + end + end + for k,v in pairs(array) do + local newV + if compareLowerCase and type(v) == "string" then + newV = string.lower(v) + else + newV = v + end + if newV == value then + return true, k + end + end + return false end \ No newline at end of file diff --git a/data/items792/items.srv b/data/items792/items.srv index 398f8df..40a666c 100644 --- a/data/items792/items.srv +++ b/data/items792/items.srv @@ -11218,17 +11218,17 @@ Attributes = {ChangeTarget=2541,Brightness=0,LightColor=215} TypeID = 2543 Name = "a box" Flags = {Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=2469} +Attributes = {DisguiseTarget=2469} TypeID = 2544 Name = "a wooden coffin" Flags = {Bottom,Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=2476} +Attributes = {DisguiseTarget=2476} TypeID = 2545 Name = "a wooden coffin" Flags = {Bottom,Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=2474} +Attributes = {DisguiseTarget=2474} TypeID = 2546 Name = "a chest" @@ -11268,12 +11268,12 @@ Attributes = {DisguiseTarget=3634} TypeID = 2553 Name = "drawers" Flags = {Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=2433} +Attributes = {DisguiseTarget=2433} TypeID = 2554 Name = "drawers" Flags = {Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=2434} +Attributes = {DisguiseTarget=2434} TypeID = 2555 Name = "a small hole" @@ -11293,27 +11293,27 @@ Attributes = {DisguiseTarget=4285} TypeID = 2558 Name = "a bookcase" Flags = {Chest,Unpass,Unmove,Unlay,Height,Disguise} -Attributes = {,DisguiseTarget=2435} +Attributes = {DisguiseTarget=2435} TypeID = 2559 Name = "a bookcase" Flags = {Chest,Unpass,Unmove,Unlay,Height,Disguise} -Attributes = {,DisguiseTarget=2438} +Attributes = {DisguiseTarget=2438} TypeID = 2560 Name = "a stone coffin" Flags = {Bottom,Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=1983} +Attributes = {DisguiseTarget=1983} TypeID = 2561 Name = "a barrel" Flags = {Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=2523} +Attributes = {DisguiseTarget=2523} TypeID = 2562 Name = "a hollow stone" Flags = {Bottom,Chest,Unpass,Unmove,Unlay,Height,Disguise} -Attributes = {,DisguiseTarget=1777} +Attributes = {DisguiseTarget=1777} TypeID = 2563 Name = "a pile of bones" @@ -11323,12 +11323,12 @@ Attributes = {DisguiseTarget=4305} TypeID = 2564 Name = "a sarcophagus" Flags = {Bottom,Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=1994} +Attributes = {DisguiseTarget=1994} TypeID = 2565 Name = "a sarcophagus" Flags = {Bottom,Chest,Unpass,Unmove,Height,Disguise} -Attributes = {,DisguiseTarget=1992} +Attributes = {DisguiseTarget=1992} TypeID = 2566 Name = "a lever" diff --git a/data/lib/compat/compat.lua b/data/lib/compat/compat.lua index aed2428..789451e 100644 --- a/data/lib/compat/compat.lua +++ b/data/lib/compat/compat.lua @@ -372,6 +372,7 @@ function setPlayerGroupId(cid, groupId) local p = Player(cid) return p ~= nil an function doPlayerSetSex(cid, sex) local p = Player(cid) return p ~= nil and p:setSex(sex) or false end function doPlayerSetGuildLevel(cid, level) local p = Player(cid) return p ~= nil and p:setGuildLevel(level) or false end function doPlayerSetGuildNick(cid, nick) local p = Player(cid) return p ~= nil and p:setGuildNick(nick) or false end +function doPlayerSetOfflineTrainingSkill(cid, skillId) local p = Player(cid) return p and p:setOfflineTrainingSkill(skillId) or false end function doShowTextDialog(cid, itemId, text) local p = Player(cid) return p ~= nil and p:showTextDialog(itemId, text) or false end function doPlayerAddItemEx(cid, uid, ...) local p = Player(cid) return p ~= nil and p:addItemEx(Item(uid), ...) or false end function doPlayerRemoveItem(cid, itemid, count, ...) local p = Player(cid) return p ~= nil and p:removeItem(itemid, count, ...) or false end diff --git a/data/lib/core/core.lua b/data/lib/core/core.lua index 8bc8ac0..457e61e 100644 --- a/data/lib/core/core.lua +++ b/data/lib/core/core.lua @@ -9,4 +9,5 @@ dofile('data/lib/core/player.lua') dofile('data/lib/core/position.lua') dofile('data/lib/core/teleport.lua') dofile('data/lib/core/tile.lua') -dofile('data/lib/core/vocation.lua') \ No newline at end of file +dofile('data/lib/core/vocation.lua') +dofile('data/lib/core/guildwars.lua') \ No newline at end of file diff --git a/data/lib/core/guildwars.lua b/data/lib/core/guildwars.lua new file mode 100644 index 0000000..0deb969 --- /dev/null +++ b/data/lib/core/guildwars.lua @@ -0,0 +1,199 @@ +guildwars = {} + +guildwars.__index = guildwars + +function guildwars:isInWar(player1, player2) + if not player1:getGuild() or not player2:getGuild() then + return 0 + end + + if player1:getGuild():getId() == 0 or player2:getGuild():getId() == 0 then + return 0 + end + + if player1:getGuild():getId() == player2:getGuild():getId() then + return 0 + end + + return isInWar(player1:getId(), player2:getId()) +end + +function guildwars:processKill(warId, killer, player) + local fragLimit = self:getFragLimit(warId) + + local killerFrags = self:getKills(warId, killer:getGuild():getId()) + 1 + local deadFrags = self:getKills(warId, player:getGuild():getId()) + + local killerMsg = "Opponent " .. player:getName() .. " of the " .. player:getGuild():getName() .. " was killed by " .. killer:getName() .. ". The new score is " .. killerFrags .. ":" .. deadFrags .. " frags (limit " .. fragLimit .. ")." + sendGuildChannelMessage(killer:getGuild():getId(), TALKTYPE_CHANNEL_O, killerMsg) + + local deadMsg = "Guild member " .. player:getName() .. " was killed by " .. killer:getName() .. " of the " .. killer:getGuild():getName() .. ". The new score is " .. deadFrags .. ":" .. killerFrags .. " frags (limit " .. fragLimit .. ")." + sendGuildChannelMessage(player:getGuild():getId(), TALKTYPE_CHANNEL_O, deadMsg) + + self:insertKill(warId, killer, player) + + if killerFrags >= fragLimit then + self:endWar(warId, killer, player, killerFrags) + end +end + +function guildwars:getFragLimit(warId) + local resultId = db.storeQuery("SELECT `frag_limit` FROM `guild_wars` WHERE `id` = " .. warId) + if resultId ~= false then + local frag_limit = result.getDataInt(resultId, "frag_limit") + result.free(resultId) + return frag_limit + end + return 0 +end + +function guildwars:getBounty(warId) + local resultId = db.storeQuery("SELECT `bounty` FROM `guild_wars` WHERE `id` = " .. warId) + if resultId ~= false then + local bounty = result.getDataInt(resultId, "bounty") + result.free(resultId) + return bounty + end + return 0 +end + +function guildwars:getKills(warId, guildId) + local resultId = db.storeQuery("SELECT COUNT(*) as frags FROM `guildwar_kills` WHERE `warid` = " .. warId .. " and `killerguild` = " .. guildId) + if resultId ~= false then + local frags = result.getDataInt(resultId, "frags") + result.free(resultId) + return frags + end + return 0 +end + +function guildwars:insertKill(warId, killer, target) + db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `warid`, `time`) VALUES (" .. db.escapeString(killer:getName()) .. ", " .. db.escapeString(target:getName()) .. ", " .. killer:getGuild():getId() .. ", " .. target:getGuild():getId() .. ", " .. warId .. ", " .. os.time() .. ")") +end + +function guildwars:endWar(warId, killer, player, frags) + local winGuildInternalMessage = "Congratulations! You have won the war against " .. player:getGuild():getName() .. " with " .. frags .. " frags." + sendGuildChannelMessage(killer:getGuild():getId(), TALKTYPE_CHANNEL_O, winGuildInternalMessage) + + local loseGuildInternalMessage = "You have lost the war against " .. killer:getGuild():getName() .. ". They have reached the limit of " .. frags .. " frags." + sendGuildChannelMessage(player:getGuild():getId(), TALKTYPE_CHANNEL_O, loseGuildInternalMessage) + + broadcastMessage(killer:getGuild():getName() .. " have won the war against " .. player:getGuild():getName() .. " with " .. frags .. " frags.", MESSAGE_EVENT_ADVANCE) + + self:updateState(warId, 5) + + self:setWarEmblem(killer:getGuild(), player:getGuild()) + + local bounty = self:getBounty(warId) + if bounty > 0 then + killer:getGuild():increaseBankBalance(bounty * 2) + end +end + +function guildwars:setWarEmblem(guild1, guild2) + guild1:setGuildWarEmblem(guild2) +end + +function guildwars:updateState(warId, status) + db.query("UPDATE `guild_wars` SET `status` = " .. status .. " WHERE `id` = " .. warId) +end + +function guildwars:getPendingInvitation(guild1, guild2) + local resultId = db.storeQuery("SELECT `id`, `bounty` FROM `guild_wars` WHERE `guild1` = " .. guild1 .. " AND `guild2` = " .. guild2 .. " AND `status` = 0") + + if resultId then + local id = result.getDataInt(resultId, "id") + local bounty = result.getDataInt(resultId, "bounty") + result.free(resultId) + + return id, bounty + end + + return 0 +end + +function guildwars:startWar(player, warId, guild1, guild2, bounty) + if bounty > 0 then + local guildBalance = guild1:getBankBalance() + if guildBalance < bounty then + player:sendCancelMessage("Your guild does not have that much money in the bank account balance to accept this war with the bounty of " .. bounty .. " gold.") + return true + end + + if not guild1:decreaseBankBalance(bounty) then + player:sendCancelMessage("Your guild does not have that much money in the bank account balance to accept this war with the bounty of " .. bounty .. " gold.") + return true + end + end + + self:updateState(warId, 1) + + self:setWarEmblem(guild1, guild2) + + broadcastMessage(guild1:getName() .. " has accepted " .. guild2:getName() .. " invitation to war.", MESSAGE_EVENT_ADVANCE) +end + +function guildwars:rejectWar(warId, guild1, guild2, bounty) + self:updateState(warId, 2) + broadcastMessage(guild1:getName() .. " has rejected " .. guild2:getName() .. " invitation to war.", MESSAGE_EVENT_ADVANCE) + + if bounty > 0 then + guild2:increaseBankBalance(bounty) + end +end + +function guildwars:cancelWar(warId, guild1, guild2, bounty) + self:updateState(warId, 3) + broadcastMessage(guild1:getName() .. " has canceled invitation to a war with " .. guild2:getName() .. ".", MESSAGE_EVENT_ADVANCE) + + if bounty > 0 then + guild1:increaseBankBalance(bounty) + end +end + +function guildwars:invite(player, guild1, guild2, frags, bounty) + local str = "" + local tmpQuery = db.storeQuery("SELECT `guild1`, `status` FROM `guild_wars` WHERE `guild1` IN (" .. guild1:getId() .. "," .. guild2:getId() .. ") AND `guild2` IN (" .. guild2:getId() .. "," .. guild1:getId() .. ") AND `status` IN (0, 1)") + if tmpQuery then + if result.getDataInt(tmpQuery, "status") == 0 then + if result.getDataInt(tmpQuery, "guild1") == guild1:getId() then + str = "You have already invited " .. guild2:getName() .. " to war." + else + str = guild2:getName() .. " have already invited you to war." + end + else + str = "You are already on a war with " .. guild2:getName() .. "." + end + + result.free(tmpQuery) + end + + if str ~= "" then + player:sendCancelMessage(str) + return true + end + + frags = math.max(10, math.min(500, frags)) + bounty = math.max(0, math.min(10000000, bounty)) + + if bounty > 0 then + local guildBalance = guild1:getBankBalance() + if guildBalance < bounty then + player:sendCancelMessage("Your guild does not have that much money in the bank account balance to set this bounty.") + return true + end + + if not guild1:decreaseBankBalance(bounty) then + player:sendCancelMessage("Your guild does not have that much money in the bank account balance to set this bounty.") + return true + end + end + + db.asyncQuery("INSERT INTO `guild_wars` (`guild1`, `guild2`, `frag_limit`, `bounty`) VALUES (" .. guild1:getId() .. ", " .. guild2:getId() .. ", " .. frags .. ", " .. bounty .. ");") + + local message = guild1:getName() .. " has invited " .. guild2:getName() .. " to war for " .. frags .. " frags." + if bounty > 0 then + message = message .. " The bounty reward is set to " .. bounty .. " gold." + end + broadcastMessage(message, MESSAGE_EVENT_ADVANCE) +end \ No newline at end of file diff --git a/data/monster/781/acolyte of the cult.xml b/data/monster/781/acolyte of the cult.xml index f446281..65e7387 100644 --- a/data/monster/781/acolyte of the cult.xml +++ b/data/monster/781/acolyte of the cult.xml @@ -39,14 +39,17 @@ <voice sentence="Praise voodoo!" /> </voices> <loot> - <item id="3085" chance="14" /><!-- dragon necklace --> - <item id="2843" chance="13" /><!-- book --> - <item id="5810" chance="14" /><!-- pirate voodoo doll --> - <item id="6088" chance="10" /><!-- music sheet --> - <item id="3282" chance="56" /><!-- morning star --> - <item id="3052" chance="9" /><!-- life ring --> - <item id="3031" countmax="40" chance="240" /><!-- gold coin --> - <item id="3032" chance="10" /><!-- small emerald --> - <item id="3065" chance="7" /><!-- terra rod --> -</loot> + <item id="3085" chance="14" /><!-- dragon necklace --> + <item id="2843" chance="13" /><!-- book --> + <item id="5810" chance="14" /><!-- pirate voodoo doll --> + <item id="6088" chance="10" /><!-- music sheet --> + <item id="3282" chance="56" /><!-- morning star --> + <item id="3052" chance="9" /><!-- life ring --> + <item id="3031" countmax="40" chance="240" /><!-- gold coin --> + <item id="3032" chance="10" /><!-- small emerald --> + <item id="3065" chance="7" /><!-- terra rod --> + </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/adept of the cult.xml b/data/monster/781/adept of the cult.xml index 4cc880b..f7bd43f 100644 --- a/data/monster/781/adept of the cult.xml +++ b/data/monster/781/adept of the cult.xml @@ -39,15 +39,18 @@ <summon name="Ghoul" chance="10" max="2" /> </summons> <loot> - <item id="3053" chance="9" /><!-- time ring --> - <item id="5810" chance="19" /><!-- pirate voodoo doll --> - <item id="2843" chance="13" /><!-- book --> - <item id="3054" chance="15" /><!-- silver amulet --> - <item id="3031" countmax="60" chance="227" /><!-- gold coin --> - <item id="3311" chance="14" /><!-- clerical mace --> - <item id="6089" chance="10" /><!-- music sheet --> - <item id="3067" chance="7" /><!-- hailstorm rod --> - <item id="3566" chance="6" /><!-- red robe --> - <item id="3030" chance="7" /><!-- small ruby --> -</loot> + <item id="3053" chance="9" /><!-- time ring --> + <item id="5810" chance="19" /><!-- pirate voodoo doll --> + <item id="2843" chance="13" /><!-- book --> + <item id="3054" chance="15" /><!-- silver amulet --> + <item id="3031" countmax="60" chance="227" /><!-- gold coin --> + <item id="3311" chance="14" /><!-- clerical mace --> + <item id="6089" chance="10" /><!-- music sheet --> + <item id="3067" chance="7" /><!-- hailstorm rod --> + <item id="3566" chance="6" /><!-- red robe --> + <item id="3030" chance="7" /><!-- small ruby --> + </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/azure frog.xml b/data/monster/781/azure frog.xml index dc482fc..12fbe88 100644 --- a/data/monster/781/azure frog.xml +++ b/data/monster/781/azure frog.xml @@ -1,4 +1,4 @@ -<monster name="Azure Frog" namedescription="a azure frog" race="blood" experience="20" speed="95" manacost="305"> +<monster name="Azure Frog" nameDescription="a azure frog" race="blood" experience="20" speed="95" manacost="305"> <health now="60" max="60" /> <look type="226" head="69" body="66" legs="69" feet="66" corpse="6079" /> <targetchange interval="1000" chance="50" /> diff --git a/data/monster/781/carrion worm.xml b/data/monster/781/carrion worm.xml index 72b53ad..faecb29 100644 --- a/data/monster/781/carrion worm.xml +++ b/data/monster/781/carrion worm.xml @@ -26,8 +26,11 @@ <immunity invisible="0" /> </immunities> <loot> - <item id="3031" countmax="45" chance="187" /><!-- gold coin --> - <item id="3492" countmax="2" chance="22" /><!-- worm --> - <item id="3577" chance="100" /><!-- meat --> -</loot> + <item id="3031" countmax="45" chance="187" /><!-- gold coin --> + <item id="3492" countmax="2" chance="22" /><!-- worm --> + <item id="3577" chance="100" /><!-- meat --> + </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/coral frog.xml b/data/monster/781/coral frog.xml index dbca01d..13680eb 100644 --- a/data/monster/781/coral frog.xml +++ b/data/monster/781/coral frog.xml @@ -1,4 +1,4 @@ -<monster name="Coral Frog" namedescription="a coral frog" race="blood" experience="20" speed="95" manacost="305"> +<monster name="Coral Frog" nameDescription="a coral frog" race="blood" experience="20" speed="95" manacost="305"> <health now="60" max="60" /> <look type="226" head="114" body="98" legs="97" feet="114" corpse="6079" /> <targetchange interval="1000" chance="50" /> diff --git a/data/monster/781/enlightened of the cult.xml b/data/monster/781/enlightened of the cult.xml index 6e0e328..d0a343d 100644 --- a/data/monster/781/enlightened of the cult.xml +++ b/data/monster/781/enlightened of the cult.xml @@ -60,4 +60,7 @@ <item id="3055" chance="6" /><!-- platinum amulet --> <item id="2995" chance="5" /><!-- piggy bank --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/novice of the cult.xml b/data/monster/781/novice of the cult.xml index 7bdd721..a7a8172 100644 --- a/data/monster/781/novice of the cult.xml +++ b/data/monster/781/novice of the cult.xml @@ -45,4 +45,7 @@ <item id="3074" chance="11" /><!-- wand of vortex --> <item id="5810" chance="10" /><!-- pirate voodoo doll --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/pirate buccaneer.xml b/data/monster/781/pirate buccaneer.xml index d8d4697..c1123fe 100644 --- a/data/monster/781/pirate buccaneer.xml +++ b/data/monster/781/pirate buccaneer.xml @@ -30,20 +30,23 @@ <voice sentence="Plundeeeeer!" /> </voices> <loot> - <item id="3031" countmax="59" chance="275" /><!-- gold coin --> - <item id="6095" chance="15" /><!-- pirate shirt --> - <item id="3273" chance="108" /><!-- sabre --> - <item id="2920" chance="103" /><!-- torch --> - <item id="3298" countmax="5" chance="60" /><!-- throwing knife --> - <item id="5090" chance="18" /><!-- treasure map --> - <item id="3123" chance="104" /><!-- worn leather boots --> - <item id="5926" chance="8" /><!-- pirate backpack --> - <item id="6097" chance="10" /><!-- hook --> - <item id="6098" chance="9" /><!-- eye patch --> - <item id="3413" chance="44" /><!-- battle shield --> - <item id="3357" chance="11" /><!-- plate armor --> - <item id="6126" chance="8" /><!-- peg leg --> - <item id="5792" chance="5" /><!-- dice --> - <item id="5552" chance="5" /><!-- rum flask --> -</loot> + <item id="3031" countmax="59" chance="275" /><!-- gold coin --> + <item id="6095" chance="15" /><!-- pirate shirt --> + <item id="3273" chance="108" /><!-- sabre --> + <item id="2920" chance="103" /><!-- torch --> + <item id="3298" countmax="5" chance="60" /><!-- throwing knife --> + <item id="5090" chance="18" /><!-- treasure map --> + <item id="3123" chance="104" /><!-- worn leather boots --> + <item id="5926" chance="8" /><!-- pirate backpack --> + <item id="6097" chance="10" /><!-- hook --> + <item id="6098" chance="9" /><!-- eye patch --> + <item id="3413" chance="44" /><!-- battle shield --> + <item id="3357" chance="11" /><!-- plate armor --> + <item id="6126" chance="8" /><!-- peg leg --> + <item id="5792" chance="5" /><!-- dice --> + <item id="5552" chance="5" /><!-- rum flask --> + </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/pirate corsair.xml b/data/monster/781/pirate corsair.xml index e2a0e5d..c1ea8d8 100644 --- a/data/monster/781/pirate corsair.xml +++ b/data/monster/781/pirate corsair.xml @@ -47,4 +47,7 @@ <item id="6096" chance="12" /><!-- pirate hat --> <item id="5813" chance="6" /><!-- skull candle --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/pirate cutthroat.xml b/data/monster/781/pirate cutthroat.xml index c89a9e6..54df4c3 100644 --- a/data/monster/781/pirate cutthroat.xml +++ b/data/monster/781/pirate cutthroat.xml @@ -43,4 +43,7 @@ <item id="5552" chance="6" /><!-- rum flask --> <item id="5792" chance="5" /><!-- dice --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/pirate ghost.xml b/data/monster/781/pirate ghost.xml index 0886ace..609cdea 100644 --- a/data/monster/781/pirate ghost.xml +++ b/data/monster/781/pirate ghost.xml @@ -48,4 +48,7 @@ <item id="3271" chance="7" /><!-- spike sword --> <item id="3566" chance="7" /><!-- red robe --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/pirate marauder.xml b/data/monster/781/pirate marauder.xml index 3051600..f4453c1 100644 --- a/data/monster/781/pirate marauder.xml +++ b/data/monster/781/pirate marauder.xml @@ -45,4 +45,7 @@ <item id="5928" chance="6" /><!-- goldfish bowl --> <item id="5792" chance="6" /><!-- dice --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/pirate skeleton.xml b/data/monster/781/pirate skeleton.xml index 489b2b2..cdbac7f 100644 --- a/data/monster/781/pirate skeleton.xml +++ b/data/monster/781/pirate skeleton.xml @@ -27,4 +27,7 @@ <item id="3337" chance="18" /><!-- bone club --> <item id="3264" chance="12" /><!-- sword --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara constrictor scout.xml b/data/monster/781/quara constrictor scout.xml index 6fa015c..e6cf6d7 100644 --- a/data/monster/781/quara constrictor scout.xml +++ b/data/monster/781/quara constrictor scout.xml @@ -36,4 +36,7 @@ <item id="5895" chance="10" /><!-- fish fin --> <item id="3033" chance="9" /><!-- small amethyst --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara constrictor.xml b/data/monster/781/quara constrictor.xml index 3838bd5..97ccb44 100644 --- a/data/monster/781/quara constrictor.xml +++ b/data/monster/781/quara constrictor.xml @@ -49,4 +49,7 @@ <item id="5895" chance="10" /><!-- fish fin --> <item id="3294" chance="70" /><!-- short sword --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara hydromancer scout.xml b/data/monster/781/quara hydromancer scout.xml index 3ce57ed..c7ceefb 100644 --- a/data/monster/781/quara hydromancer scout.xml +++ b/data/monster/781/quara hydromancer scout.xml @@ -58,4 +58,7 @@ <item id="3098" chance="8" /><!-- ring of healing --> <item id="3370" chance="8" /><!-- knight armor --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara hydromancer.xml b/data/monster/781/quara hydromancer.xml index 7b39a2d..19fa6db 100644 --- a/data/monster/781/quara hydromancer.xml +++ b/data/monster/781/quara hydromancer.xml @@ -64,4 +64,7 @@ <item id="3370" chance="8" /><!-- knight armor --> <item id="5895" chance="15" /><!-- fish fin --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara mantassin scout.xml b/data/monster/781/quara mantassin scout.xml index 6b8b723..4234ad5 100644 --- a/data/monster/781/quara mantassin scout.xml +++ b/data/monster/781/quara mantassin scout.xml @@ -38,4 +38,7 @@ <item id="3265" chance="16" /><!-- two handed sword --> <item id="3029" chance="5" /><!-- small sapphire --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara mantassin.xml b/data/monster/781/quara mantassin.xml index 6e46754..9937329 100644 --- a/data/monster/781/quara mantassin.xml +++ b/data/monster/781/quara mantassin.xml @@ -48,4 +48,7 @@ <item id="3373" chance="6" /><!-- strange helmet --> <item id="3567" chance="6" /><!-- blue robe --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara pincher scout.xml b/data/monster/781/quara pincher scout.xml index 57b2d21..e2653c6 100644 --- a/data/monster/781/quara pincher scout.xml +++ b/data/monster/781/quara pincher scout.xml @@ -45,4 +45,7 @@ <item id="3061" chance="10" /><!-- life crystal --> <item id="5895" chance="10" /><!-- fish fin --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara pincher.xml b/data/monster/781/quara pincher.xml index 7450e8c..62e3782 100644 --- a/data/monster/781/quara pincher.xml +++ b/data/monster/781/quara pincher.xml @@ -44,4 +44,7 @@ <item id="5895" chance="20" /><!-- fish fin --> <item id="3381" chance="8" /><!-- crown armor --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara predator scout.xml b/data/monster/781/quara predator scout.xml index e50b854..7be5c1e 100644 --- a/data/monster/781/quara predator scout.xml +++ b/data/monster/781/quara predator scout.xml @@ -36,4 +36,7 @@ <item id="3028" chance="9" /><!-- small diamond --> <item id="5895" chance="9" /><!-- fish fin --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/quara predator.xml b/data/monster/781/quara predator.xml index f544212..c2afb14 100644 --- a/data/monster/781/quara predator.xml +++ b/data/monster/781/quara predator.xml @@ -45,4 +45,7 @@ <item id="3581" chance="54" /><!-- shrimp --> <item id="5895" chance="24" /><!-- fish fin --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/781/thornback tortoise.xml b/data/monster/781/thornback tortoise.xml index 51d578e..253c02d 100644 --- a/data/monster/781/thornback tortoise.xml +++ b/data/monster/781/thornback tortoise.xml @@ -28,4 +28,7 @@ <item id="5678" countmax="3" chance="10" /><!-- tortoise egg --> <item id="3279" chance="10" /><!-- war hammer --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/790/hand of cursed fate.xml b/data/monster/790/hand of cursed fate.xml index 9305ea7..db6bbe3 100644 --- a/data/monster/790/hand of cursed fate.xml +++ b/data/monster/790/hand of cursed fate.xml @@ -67,4 +67,7 @@ <item id="5668" chance="2" /><!-- mysterious voodoo skull --> <item id="3155" countmax="8" chance="42" /><!-- sudden death rune --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/790/juggernaut.xml b/data/monster/790/juggernaut.xml index 71b8929..34bac7e 100644 --- a/data/monster/790/juggernaut.xml +++ b/data/monster/790/juggernaut.xml @@ -62,4 +62,7 @@ <item id="3340" chance="4" /><!-- heavy mace --> <item id="3342" chance="4" /><!-- war axe --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/790/nightmare.xml b/data/monster/790/nightmare.xml index 5b621e1..0156afc 100644 --- a/data/monster/790/nightmare.xml +++ b/data/monster/790/nightmare.xml @@ -62,4 +62,7 @@ <item id="5668" chance="1" /><!-- mysterious voodoo skull --> <item id="3342" chance="95" /><!-- war axe --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/790/wyvern.xml b/data/monster/790/wyvern.xml index e2c10af..dd45c95 100644 --- a/data/monster/790/wyvern.xml +++ b/data/monster/790/wyvern.xml @@ -47,4 +47,7 @@ <item id="3071" chance="8" /><!-- wand of inferno --> <item id="3010" chance="5" /><!-- emerald bangle --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/amazon.xml b/data/monster/amazon.xml index 6438a14..37dfc4e 100644 --- a/data/monster/amazon.xml +++ b/data/monster/amazon.xml @@ -39,4 +39,7 @@ <item id="3426" countmax="1" chance="50" /> <!-- a studded shield --> <item id="2920" countmax="1" chance="50" /> <!-- a torch --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/ancientscarab.xml b/data/monster/ancientscarab.xml index 72c41c0..4fe9f61 100644 --- a/data/monster/ancientscarab.xml +++ b/data/monster/ancientscarab.xml @@ -65,4 +65,7 @@ <item id="3033" countmax="4" chance="12" /> <!-- a small amethyst --> <item id="3032" countmax="3" chance="6" /> <!-- a small emerald --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/bandit.xml b/data/monster/bandit.xml index 0c862f0..63e4058 100644 --- a/data/monster/bandit.xml +++ b/data/monster/bandit.xml @@ -37,4 +37,7 @@ <item id="3577" countmax="1" chance="100" /> <!-- meat --> <item id="3279" countmax="1" chance="1" /> <!-- a war hammer --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/banshee.xml b/data/monster/banshee.xml index 6a002ef..8864d60 100644 --- a/data/monster/banshee.xml +++ b/data/monster/banshee.xml @@ -68,4 +68,7 @@ <item id="3004" countmax="1" chance="5" /> <!-- a wedding ring --> <item id="3026" countmax="1" chance="10" /> <!-- a white pearl --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/bear.xml b/data/monster/bear.xml index a7e6a38..77daf88 100644 --- a/data/monster/bear.xml +++ b/data/monster/bear.xml @@ -31,4 +31,7 @@ <item id="5896" countmax="1" chance="25" /> <!-- bear paw --> <item id="5902" countmax="1" chance="10" /> <!-- honeycomb --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/behemoth.xml b/data/monster/behemoth.xml index 20a427c..782b73d 100644 --- a/data/monster/behemoth.xml +++ b/data/monster/behemoth.xml @@ -59,4 +59,7 @@ <item id="5893" countmax="1" chance="9" /> <!-- perfect behemoth fang --> <item id="5930" countmax="1" chance="9" /> <!-- behemoth claw --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/beholder.xml b/data/monster/beholder.xml index 3beafa4..9ddbbce 100644 --- a/data/monster/beholder.xml +++ b/data/monster/beholder.xml @@ -67,4 +67,7 @@ <item id="3412" countmax="1" chance="30" /> <!-- a wooden shield --> <item id="5898" countmax="1" chance="8" /> <!-- beholder eye --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/bluedjinn.xml b/data/monster/bluedjinn.xml index f5c16a7..42b4c65 100644 --- a/data/monster/bluedjinn.xml +++ b/data/monster/bluedjinn.xml @@ -61,4 +61,7 @@ <item id="3029" countmax="4" chance="25" /> <!-- a small sapphire --> <item id="5912" countmax="1" chance="10" /> <!-- a blue piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/bonebeast.xml b/data/monster/bonebeast.xml index 6eab7c4..d0d7e8c 100644 --- a/data/monster/bonebeast.xml +++ b/data/monster/bonebeast.xml @@ -55,4 +55,7 @@ <item id="3114" countmax="1" chance="200" /> <!-- a skull --> <item id="5925" countmax="1" chance="10" /> <!-- a hardened bone --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/bug.xml b/data/monster/bug.xml index 81dfd68..94c361e 100644 --- a/data/monster/bug.xml +++ b/data/monster/bug.xml @@ -24,4 +24,7 @@ <item id="3590" countmax="3" chance="30" /> <!-- a cherry --> <item id="3031" countmax="6" chance="350" /> <!-- a gold coin --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/carniphila.xml b/data/monster/carniphila.xml index 6796187..0752f93 100644 --- a/data/monster/carniphila.xml +++ b/data/monster/carniphila.xml @@ -48,4 +48,7 @@ <item id="3738" countmax="1" chance="5" /> <!-- a sling herb --> <item id="3738" countmax="1" chance="5" /> <!-- a sling herb --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/caverat.xml b/data/monster/caverat.xml index 4c32d81..1f406b3 100644 --- a/data/monster/caverat.xml +++ b/data/monster/caverat.xml @@ -30,4 +30,7 @@ <item id="3031" countmax="2" chance="850" /> <!-- a gold coin --> <item id="3492" countmax="3" chance="500" /> <!-- a worm --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/crocodile.xml b/data/monster/crocodile.xml index 8839412..a58ea18 100644 --- a/data/monster/crocodile.xml +++ b/data/monster/crocodile.xml @@ -28,4 +28,7 @@ <item id="3559" countmax="1" chance="80" /> <!-- leather legs --> <item id="3577" countmax="4" chance="700" /> <!-- meat --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/cyclops.xml b/data/monster/cyclops.xml index cdc6f93..d6ee2f3 100644 --- a/data/monster/cyclops.xml +++ b/data/monster/cyclops.xml @@ -40,4 +40,7 @@ <item id="3294" countmax="1" chance="80" /> <!-- a short sword --> <item id="3012" countmax="1" chance="2" /> <!-- a wolf tooth chain --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/demon.xml b/data/monster/demon.xml index 719792f..b04caec 100644 --- a/data/monster/demon.xml +++ b/data/monster/demon.xml @@ -81,4 +81,7 @@ <item id="5954" countmax="1" chance="100" /> <!-- a demon horn --> <item id="5776" countmax="1" chance="1" /> <!-- a Sabrehaven talon --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/demonskeleton.xml b/data/monster/demonskeleton.xml index 4a46cda..c05cf0f 100644 --- a/data/monster/demonskeleton.xml +++ b/data/monster/demonskeleton.xml @@ -39,4 +39,7 @@ <item id="3287" countmax="3" chance="100" /> <!-- a throwing star --> <item id="2920" countmax="1" chance="500" /> <!-- a torch --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/dragon.xml b/data/monster/dragon.xml index 9d3ea28..2c57489 100644 --- a/data/monster/dragon.xml +++ b/data/monster/dragon.xml @@ -63,4 +63,7 @@ <item id="5877" countmax="1" chance="10" /> <!-- green dragon leather --> <item id="5920" countmax="1" chance="10" /> <!-- green dragon scale --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/dragonlord.xml b/data/monster/dragonlord.xml index 73b2126..e0fcc4d 100644 --- a/data/monster/dragonlord.xml +++ b/data/monster/dragonlord.xml @@ -64,4 +64,7 @@ <item id="5882" countmax="1" chance="18" /> <!-- red dragon scale --> <item id="5948" countmax="1" chance="10" /> <!-- red dragon leather --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/dwarf.xml b/data/monster/dwarf.xml index bf04a40..cc187a2 100644 --- a/data/monster/dwarf.xml +++ b/data/monster/dwarf.xml @@ -39,4 +39,7 @@ <item id="3723" countmax="1" chance="500" /> <!-- a white mushroom --> <item id="5880" countmax="1" chance="7" /> <!-- iron ore --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/dwarfgeomancer.xml b/data/monster/dwarfgeomancer.xml index 9d2fc7a..4dbb92b 100644 --- a/data/monster/dwarfgeomancer.xml +++ b/data/monster/dwarfgeomancer.xml @@ -53,4 +53,7 @@ <item id="3723" countmax="2" chance="600" /> <!-- a white mushroom --> <item id="5880" countmax="1" chance="1" /> <!-- Iron Ore --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/dwarfguard.xml b/data/monster/dwarfguard.xml index fb294f2..5a25481 100644 --- a/data/monster/dwarfguard.xml +++ b/data/monster/dwarfguard.xml @@ -40,4 +40,7 @@ <item id="3723" countmax="2" chance="550" /> <!-- a white mushroom --> <item id="5880" countmax="1" chance="8" /> <!-- iron ore --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/dwarfsoldier.xml b/data/monster/dwarfsoldier.xml index 94171a5..dc6ada3 100644 --- a/data/monster/dwarfsoldier.xml +++ b/data/monster/dwarfsoldier.xml @@ -42,4 +42,7 @@ <item id="3723" countmax="2" chance="400" /> <!-- a white mushroom --> <item id="5880" countmax="1" chance="6" /> <!-- iron ore --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/efreet.xml b/data/monster/efreet.xml index 792fbf3..65c1448 100644 --- a/data/monster/efreet.xml +++ b/data/monster/efreet.xml @@ -77,4 +77,7 @@ <item id="3071" countmax="1" chance="5" /> <!-- a wand of inferno --> <item id="5910" countmax="1" chance="25" /> <!-- green piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/elderbeholder.xml b/data/monster/elderbeholder.xml index 992f66a..2774cc5 100644 --- a/data/monster/elderbeholder.xml +++ b/data/monster/elderbeholder.xml @@ -73,4 +73,7 @@ <item id="3265" countmax="1" chance="60" /> <!-- a two handed sword --> <item id="5898" countmax="1" chance="8" /> <!-- beholder eye --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/elf.xml b/data/monster/elf.xml index 2c66ef0..811094a 100644 --- a/data/monster/elf.xml +++ b/data/monster/elf.xml @@ -43,4 +43,7 @@ <item id="3376" countmax="1" chance="150" /> <!-- a studded helmet --> <item id="5921" countmax="1" chance="10" /> <!-- a heaven blossom --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/elfarcanist.xml b/data/monster/elfarcanist.xml index f13c928..824e502 100644 --- a/data/monster/elfarcanist.xml +++ b/data/monster/elfarcanist.xml @@ -67,4 +67,7 @@ <item id="3037" countmax="1" chance="2" /> <!-- a yellow gem --> <item id="5922" countmax="1" chance="25" /> <!-- a holy orchid --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/elfscout.xml b/data/monster/elfscout.xml index 6ca1c18..fff5943 100644 --- a/data/monster/elfscout.xml +++ b/data/monster/elfscout.xml @@ -46,4 +46,7 @@ <item id="2901" countmax="1" chance="140" /> <!-- a waterskin --> <item id="5921" countmax="1" chance="10" /> <!-- a heaven blossom --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/frosttroll.xml b/data/monster/frosttroll.xml index 730e9b7..42adb76 100644 --- a/data/monster/frosttroll.xml +++ b/data/monster/frosttroll.xml @@ -34,4 +34,7 @@ <item id="3130" countmax="1" chance="80" /> <!-- twigs --> <item id="3412" countmax="1" chance="150" /> <!-- a wooden shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/gargoyle.xml b/data/monster/gargoyle.xml index 9720ff8..f05e1d4 100644 --- a/data/monster/gargoyle.xml +++ b/data/monster/gargoyle.xml @@ -49,4 +49,7 @@ <item id="3336" countmax="1" chance="80" /> <!-- a studded club --> <item id="3012" countmax="1" chance="2" /> <!-- a wolf tooth chain --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/ghost.xml b/data/monster/ghost.xml index 4573e1f..b6f475e 100644 --- a/data/monster/ghost.xml +++ b/data/monster/ghost.xml @@ -43,4 +43,7 @@ <item id="3049" countmax="1" chance="2" /> <!-- a stealth ring --> <item id="5909" countmax="1" chance="8" /> <!-- white piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/ghoul.xml b/data/monster/ghoul.xml index f365d50..8e6fbf4 100644 --- a/data/monster/ghoul.xml +++ b/data/monster/ghoul.xml @@ -42,4 +42,7 @@ <item id="3492" countmax="6" chance="800" /> <!-- a worm --> <item id="5913" countmax="1" chance="10" /> <!-- a brown piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/giantspider.xml b/data/monster/giantspider.xml index 8f598f7..fd4b7d0 100644 --- a/data/monster/giantspider.xml +++ b/data/monster/giantspider.xml @@ -49,4 +49,7 @@ <item id="3053" countmax="1" chance="7" /> <!-- a time ring --> <item id="5879" countmax="1" chance="21" /> <!-- spider silk --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/goblin.xml b/data/monster/goblin.xml index 5c98564..6ca253c 100644 --- a/data/monster/goblin.xml +++ b/data/monster/goblin.xml @@ -43,4 +43,7 @@ <item id="3462" countmax="1" chance="100" /> <!-- a small axe --> <item id="1781" countmax="3" chance="300" /> <!-- a small stone --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/greendjinn.xml b/data/monster/greendjinn.xml index ac33dd8..61573ec 100644 --- a/data/monster/greendjinn.xml +++ b/data/monster/greendjinn.xml @@ -62,4 +62,7 @@ <item id="2933" countmax="1" chance="75" /> <!-- a small oil lamp --> <item id="5910" countmax="1" chance="25" /> <!-- green piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/hero.xml b/data/monster/hero.xml index e5fd612..c76a9ec 100644 --- a/data/monster/hero.xml +++ b/data/monster/hero.xml @@ -63,4 +63,7 @@ <item id="3004" countmax="1" chance="50" /> <!-- a wedding ring --> <item id="5911" countmax="1" chance="25" /> <!-- a red piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/hyaena.xml b/data/monster/hyaena.xml index 55eae6f..3eda2b4 100644 --- a/data/monster/hyaena.xml +++ b/data/monster/hyaena.xml @@ -28,4 +28,7 @@ <item id="3577" countmax="2" chance="500" /> <!-- meat --> <item id="3492" countmax="3" chance="500" /> <!-- a worm --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/hydra.xml b/data/monster/hydra.xml index 432f11d..41af5c3 100644 --- a/data/monster/hydra.xml +++ b/data/monster/hydra.xml @@ -60,4 +60,7 @@ <item id="3081" countmax="1" chance="8" /> <!-- a stone skin amulet --> <item id="3369" countmax="1" chance="10" /> <!-- a warrior helmet --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/kongra.xml b/data/monster/kongra.xml index 37c13c0..2898bec 100644 --- a/data/monster/kongra.xml +++ b/data/monster/kongra.xml @@ -39,4 +39,7 @@ <item id="3084" countmax="1" chance="10" /> <!-- a protection amulet --> <item id="5883" countmax="1" chance="8" /> <!-- ape fur --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/larva.xml b/data/monster/larva.xml index 3ab193e..9369268 100644 --- a/data/monster/larva.xml +++ b/data/monster/larva.xml @@ -28,4 +28,7 @@ <item id="3031" countmax="10" chance="350" /> <!-- a gold coin --> <item id="3577" countmax="1" chance="300" /> <!-- meat --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/lich.xml b/data/monster/lich.xml index 8bcc06f..02ae1db 100644 --- a/data/monster/lich.xml +++ b/data/monster/lich.xml @@ -73,4 +73,7 @@ <item id="3373" countmax="1" chance="5" /> <!-- a strange helmet --> <item id="3026" countmax="1" chance="25" /> <!-- a white pearl --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/lion.xml b/data/monster/lion.xml index 382c6f6..e7623bc 100644 --- a/data/monster/lion.xml +++ b/data/monster/lion.xml @@ -27,4 +27,7 @@ <item id="3582" countmax="2" chance="200" /> <!-- ham --> <item id="3577" countmax="3" chance="450" /> <!-- meat --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/lizardsentinel.xml b/data/monster/lizardsentinel.xml index 61f0163..ead8e00 100644 --- a/data/monster/lizardsentinel.xml +++ b/data/monster/lizardsentinel.xml @@ -42,4 +42,7 @@ <item id="5876" countmax="1" chance="9" /> <!-- lizard leather --> <item id="5881" countmax="1" chance="9" /><!-- lizard scale --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/lizardsnakecharmer.xml b/data/monster/lizardsnakecharmer.xml index c33f84d..9fcd1f9 100644 --- a/data/monster/lizardsnakecharmer.xml +++ b/data/monster/lizardsnakecharmer.xml @@ -57,4 +57,7 @@ <item id="5876" countmax="1" chance="9" /> <!-- lizard leather --> <item id="5881" countmax="1" chance="9" /><!-- lizard scale --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/lizardtemplar.xml b/data/monster/lizardtemplar.xml index b54fed4..5652d7c 100644 --- a/data/monster/lizardtemplar.xml +++ b/data/monster/lizardtemplar.xml @@ -39,4 +39,7 @@ <item id="5876" countmax="1" chance="10" /> <!-- lizard leather --> <item id="5881" countmax="1" chance="10" /><!-- lizard scale --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/marid.xml b/data/monster/marid.xml index 4bc26c9..a5b58dc 100644 --- a/data/monster/marid.xml +++ b/data/monster/marid.xml @@ -77,4 +77,7 @@ <item id="2948" countmax="1" chance="3" /> <!-- a wooden flute --> <item id="5912" countmax="1" chance="25" /> <!-- a blue piece of cloth --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/merlkin.xml b/data/monster/merlkin.xml index 13389f7..39f6312 100644 --- a/data/monster/merlkin.xml +++ b/data/monster/merlkin.xml @@ -54,4 +54,7 @@ <item id="3072" countmax="1" chance="10" /> <!-- a wand of plague --> <item id="5883" countmax="1" chance="8" /> <!-- ape fur --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/minotaur.xml b/data/monster/minotaur.xml index 3d69955..ef8b1c5 100644 --- a/data/monster/minotaur.xml +++ b/data/monster/minotaur.xml @@ -39,4 +39,7 @@ <item id="3264" countmax="1" chance="100" /> <!-- a sword --> <item id="5878" countmax="1" chance="8" /> <!-- minotaur leather --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/minotaurarcher.xml b/data/monster/minotaurarcher.xml index 523948d..d2d35ad 100644 --- a/data/monster/minotaurarcher.xml +++ b/data/monster/minotaurarcher.xml @@ -41,4 +41,7 @@ <item id="3375" countmax="1" chance="20" /> <!-- a soldier helmet --> <item id="5878" countmax="1" chance="10" /> <!-- minotaur leather --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/minotaurguard.xml b/data/monster/minotaurguard.xml index 52ea09d..37f6d85 100644 --- a/data/monster/minotaurguard.xml +++ b/data/monster/minotaurguard.xml @@ -37,4 +37,7 @@ <item id="3577" countmax="1" chance="100" /> <!-- meat --> <item id="5878" countmax="1" chance="10" /> <!-- minotaur leather --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/minotaurmage.xml b/data/monster/minotaurmage.xml index 208e2b8..f03f855 100644 --- a/data/monster/minotaurmage.xml +++ b/data/monster/minotaurmage.xml @@ -53,4 +53,7 @@ <item id="3073" countmax="1" chance="5" /> <!-- a wand of cosmic energy --> <item id="5878" countmax="1" chance="10" /> <!-- minotaur leather --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/necromancer.xml b/data/monster/necromancer.xml index 9946431..e0bd2d1 100644 --- a/data/monster/necromancer.xml +++ b/data/monster/necromancer.xml @@ -55,4 +55,7 @@ <item id="3294" countmax="1" chance="150" /> <!-- a short sword --> <item id="3324" countmax="1" chance="1" /> <!-- a skull staff --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orc.xml b/data/monster/orc.xml index eb8d3ed..f1e5556 100644 --- a/data/monster/orc.xml +++ b/data/monster/orc.xml @@ -34,4 +34,7 @@ <item id="3376" countmax="1" chance="90" /> <!-- a studded helmet --> <item id="3426" countmax="1" chance="100" /> <!-- a studded shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcberserker.xml b/data/monster/orcberserker.xml index 362cbc1..3e4af67 100644 --- a/data/monster/orcberserker.xml +++ b/data/monster/orcberserker.xml @@ -38,4 +38,7 @@ <item id="3582" countmax="1" chance="170" /> <!-- ham --> <item id="2914" countmax="1" chance="80" /> <!-- a lamp --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcleader.xml b/data/monster/orcleader.xml index ecfff7e..84846c4 100644 --- a/data/monster/orcleader.xml +++ b/data/monster/orcleader.xml @@ -47,4 +47,7 @@ <item id="3298" countmax="4" chance="100" /> <!-- a throwing knife --> <item id="3369" countmax="1" chance="1" /> <!-- a warrior helmet --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcrider.xml b/data/monster/orcrider.xml index 7baca5f..ff15207 100644 --- a/data/monster/orcrider.xml +++ b/data/monster/orcrider.xml @@ -43,4 +43,7 @@ <item id="2920" countmax="1" chance="80" /> <!-- a torch --> <item id="3012" countmax="1" chance="100" /> <!-- a wolf tooth chain --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcshaman.xml b/data/monster/orcshaman.xml index 7fad036..52bdffb 100644 --- a/data/monster/orcshaman.xml +++ b/data/monster/orcshaman.xml @@ -54,4 +54,7 @@ <item id="3289" countmax="1" chance="70" /> <!-- a staff --> <item id="3072" countmax="1" chance="10" /> <!-- a wand of plague --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcspearman.xml b/data/monster/orcspearman.xml index 50b1793..3831011 100644 --- a/data/monster/orcspearman.xml +++ b/data/monster/orcspearman.xml @@ -35,4 +35,7 @@ <item id="3376" countmax="1" chance="90" /> <!-- a studded helmet --> <item id="3362" countmax="1" chance="100" /> <!-- studded legs --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcwarlord.xml b/data/monster/orcwarlord.xml index f3b255f..c2c8e2c 100644 --- a/data/monster/orcwarlord.xml +++ b/data/monster/orcwarlord.xml @@ -55,4 +55,7 @@ <item id="3287" countmax="40" chance="300" /> <!-- a throwing star --> <item id="3265" countmax="1" chance="20" /> <!-- a two handed sword --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/orcwarrior.xml b/data/monster/orcwarrior.xml index fe8bfec..64a6e22 100644 --- a/data/monster/orcwarrior.xml +++ b/data/monster/orcwarrior.xml @@ -35,4 +35,7 @@ <item id="3273" countmax="1" chance="500" /> <!-- a sabre --> <item id="3412" countmax="1" chance="180" /> <!-- a wooden shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/priestess.xml b/data/monster/priestess.xml index edc7591..2eba86d 100644 --- a/data/monster/priestess.xml +++ b/data/monster/priestess.xml @@ -58,4 +58,7 @@ <item id="3727" countmax="1" chance="35" /> <!-- a wood mushroom --> <item id="2948" countmax="1" chance="14" /> <!-- a wooden flute --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/raids/orc.xml b/data/monster/raids/orc.xml index f826b6c..2af5ccc 100644 --- a/data/monster/raids/orc.xml +++ b/data/monster/raids/orc.xml @@ -35,4 +35,7 @@ <item id="3426" countmax="1" chance="100" /> <!-- a studded shield --> <item id="3244" countmax="1" chance="1000" /> <!-- an old backpack --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/raids/orcwarlord.xml b/data/monster/raids/orcwarlord.xml index d18ac94..3d38cef 100644 --- a/data/monster/raids/orcwarlord.xml +++ b/data/monster/raids/orcwarlord.xml @@ -58,4 +58,7 @@ <item id="3394" countmax="1" chance="6" /> <!-- an amazon armor --> <item id="3437" countmax="1" chance="4" /> <!-- an amazon shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/rat.xml b/data/monster/rat.xml index b851408..c6f5a5b 100644 --- a/data/monster/rat.xml +++ b/data/monster/rat.xml @@ -25,4 +25,7 @@ <item id="3031" countmax="4" chance="700" /> <!-- a gold coin --> <item id="3492" countmax="3" chance="500" /> <!-- a worm --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/rotworm.xml b/data/monster/rotworm.xml index 10b8e06..514df79 100644 --- a/data/monster/rotworm.xml +++ b/data/monster/rotworm.xml @@ -35,4 +35,7 @@ <item id="3264" countmax="1" chance="30" /> <!-- a sword --> <item id="3492" countmax="5" chance="500" /> <!-- a worm --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/serpentspawn.xml b/data/monster/serpentspawn.xml index 002f77e..3c301de 100644 --- a/data/monster/serpentspawn.xml +++ b/data/monster/serpentspawn.xml @@ -77,4 +77,7 @@ <item id="3373" countmax="1" chance="6" /> <!-- a strange helmet --> <item id="3428" countmax="1" chance="4" /> <!-- a tower shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/sibang.xml b/data/monster/sibang.xml index 1398723..a810785 100644 --- a/data/monster/sibang.xml +++ b/data/monster/sibang.xml @@ -45,4 +45,7 @@ <item id="1781" countmax="3" chance="300" /> <!-- a small stone --> <item id="5883" countmax="1" chance="8" /> <!-- ape fur --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/skeleton.xml b/data/monster/skeleton.xml index b28eda2..d6f22c1 100644 --- a/data/monster/skeleton.xml +++ b/data/monster/skeleton.xml @@ -35,4 +35,7 @@ <item id="2920" countmax="1" chance="500" /> <!-- a torch --> <item id="3367" countmax="1" chance="80" /> <!-- a viking helmet --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/slime.xml b/data/monster/slime.xml index ca7e4a5..3f6a843 100644 --- a/data/monster/slime.xml +++ b/data/monster/slime.xml @@ -30,4 +30,7 @@ <voices> <voice sentence="Blubb" /> </voices> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/smuggler.xml b/data/monster/smuggler.xml index 3fa96e0..29a1d55 100644 --- a/data/monster/smuggler.xml +++ b/data/monster/smuggler.xml @@ -36,4 +36,7 @@ <item id="3264" countmax="1" chance="50" /> <!-- a sword --> <item id="2920" countmax="2" chance="300" /> <!-- a torch --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/swamptroll.xml b/data/monster/swamptroll.xml index 269aa21..0b1ca4e 100644 --- a/data/monster/swamptroll.xml +++ b/data/monster/swamptroll.xml @@ -33,4 +33,7 @@ <item id="3552" countmax="1" chance="100" /> <!-- leather boots --> <item id="2920" countmax="1" chance="150" /> <!-- a torch --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/tarantula.xml b/data/monster/tarantula.xml index 360fd6c..116a556 100644 --- a/data/monster/tarantula.xml +++ b/data/monster/tarantula.xml @@ -38,4 +38,7 @@ <item id="3351" countmax="1" chance="10" /> <!-- a steel helmet --> <item id="3053" countmax="1" chance="1" /> <!-- a time ring --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/troll.xml b/data/monster/troll.xml index 78c722d..6e188b9 100644 --- a/data/monster/troll.xml +++ b/data/monster/troll.xml @@ -39,4 +39,7 @@ <item id="3336" countmax="1" chance="50" /> <!-- a studded club --> <item id="3412" countmax="1" chance="150" /> <!-- a wooden shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/vampire.xml b/data/monster/vampire.xml index c2ada84..df8fe61 100644 --- a/data/monster/vampire.xml +++ b/data/monster/vampire.xml @@ -54,4 +54,7 @@ <item id="3373" countmax="1" chance="4" /> <!-- a strange helmet --> <item id="3434" countmax="1" chance="1" /> <!-- a vampire shield --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/warlock.xml b/data/monster/warlock.xml index 47ce6aa..7fc16d4 100644 --- a/data/monster/warlock.xml +++ b/data/monster/warlock.xml @@ -82,4 +82,7 @@ <item id="3081" countmax="1" chance="5" /> <!-- a stone skin amulet --> <item id="3034" countmax="1" chance="11" /> <!-- a talon --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/wasp.xml b/data/monster/wasp.xml index ed404ad..c117099 100644 --- a/data/monster/wasp.xml +++ b/data/monster/wasp.xml @@ -29,4 +29,7 @@ <loot> <item id="5902" countmax="1" chance="30" /> <!-- honeycomb --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/wildwarrior.xml b/data/monster/wildwarrior.xml index 1b2d20c..cb86fc1 100644 --- a/data/monster/wildwarrior.xml +++ b/data/monster/wildwarrior.xml @@ -42,4 +42,7 @@ <item id="3409" countmax="1" chance="10" /> <!-- a steel shield --> <item id="3279" countmax="1" chance="1" /> <!-- a war hammer --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/winterwolf.xml b/data/monster/winterwolf.xml index 3be92bf..9434727 100644 --- a/data/monster/winterwolf.xml +++ b/data/monster/winterwolf.xml @@ -23,4 +23,7 @@ <loot> <item id="3577" countmax="2" chance="300" /> <!-- meat --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/monster/wolf.xml b/data/monster/wolf.xml index 42101bf..44147ba 100644 --- a/data/monster/wolf.xml +++ b/data/monster/wolf.xml @@ -25,4 +25,7 @@ <item id="3492" countmax="1" chance="100" /> <!-- a worm --> <item id="5897" countmax="1" chance="8" /> <!-- wolf paw --> </loot> + <script> + <event name="KillingInTheNameOf" /> + </script> </monster> \ No newline at end of file diff --git a/data/movements/movements.xml b/data/movements/movements.xml index 6f254bc..d3b494b 100644 --- a/data/movements/movements.xml +++ b/data/movements/movements.xml @@ -676,11 +676,6 @@ <movevent event="RemoveItem" itemid="3482" script="misc/open_trap.lua" /> <movevent event="StepIn" frommovementid="51191" tomovementid="51198" script="misc/turtles.lua" /> <movevent event="AddItem" itemid="6278" tileitem="1" script="misc/lit_candlestick.lua" /> - <movevent event="StepIn" movementid="17705" script="misc/thais_trainers.lua" /> - <movevent event="AddItem" movementid="17705" tileitem="1" script="misc/thais_trainers.lua" /> - <movevent event="StepIn" movementid="17706" script="misc/thais_trainers_back.lua" /> - <movevent event="AddItem" movementid="17706" tileitem="1" script="misc/thais_trainers_back.lua" /> - <movevent event="StepIn" movementid="17708" script="misc/step_trainers.lua" /> <!--Doors --> <movevent event="StepOut" itemid="1643" script="misc/doors.lua" /> diff --git a/data/movements/scripts/misc/step_trainers.lua b/data/movements/scripts/misc/step_trainers.lua deleted file mode 100644 index ec6c0ca..0000000 --- a/data/movements/scripts/misc/step_trainers.lua +++ /dev/null @@ -1,70 +0,0 @@ -local trainingRoomExit = {x = 32231, y = 32200, z = 7} - -function checkTrainingTile(playerId, pos, movementId) - local player = Player(playerId) - if not player then - return true - end - - if getTopCreature(pos).uid ~= playerId then - return true - end - - if player:getStorageValue(17709) >= 10800000 then - player:teleportTo(trainingRoomExit) - Position(pos):sendMagicEffect(CONST_ME_TELEPORT) - player:sendTextMessage(MESSAGE_INFO_DESCR, "Your training time have expired. Come back tomorrow.") - Position(player:getPosition()):sendMagicEffect(CONST_ME_TELEPORT) - return true - end - - local trainingTime = player:getStorageValue(17709) - player:setStorageValue(17709, trainingTime + 60000) - player:sendTextMessage(MESSAGE_STATUS_SMALL, "You have " .. math.modf((10800000 - trainingTime) / 1000 / 60) .. " minutes of remaining training time in the Thais training chamber.") - addEvent(checkTrainingTile, 60000, playerId, pos, movementId) - return true -end - -function onStepIn(creature, item, position, fromPosition) - local player = creature:getPlayer() - if not player then - return true - end - - local dayOfYear = tonumber(os.date("%j")) - - -- Reset counting storage value if it does not match the last time saved day - if player:getStorageValue(17711) ~= dayOfYear then - player:setStorageValue(17709, 0) - end - - if player:getStorageValue(17711) == dayOfYear and player:getStorageValue(17709) >= 10800000 then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are not allowed to train today anymore. Come back tomorrow.") - if position == fromPosition then - player:teleportTo(trainingRoomExit) - else - player:teleportTo(fromPosition) - end - return true - end - - if player:getStorageValue(17710) > os.time() then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have 1 minute training monk chamber step in timeout.") - if position == fromPosition then - player:teleportTo(trainingRoomExit) - else - player:teleportTo(fromPosition) - end - return true - end - - local playerId = player:getId() - local pos = player:getPosition() - - local trainingTime = player:getStorageValue(17709) - player:setStorageValue(17709, trainingTime + 60000) - player:sendTextMessage(MESSAGE_STATUS_SMALL, "You have " .. math.modf((10800000 - trainingTime) / 1000 / 60) .. " minutes of remaining training time in the Thais training chamber.") - player:setStorageValue(17710, os.time() + 1 * 60) - player:setStorageValue(17711, dayOfYear) - addEvent(checkTrainingTile, 60000, playerId, pos, item:getMovementId()) -end \ No newline at end of file diff --git a/data/movements/scripts/misc/thais_trainers.lua b/data/movements/scripts/misc/thais_trainers.lua deleted file mode 100644 index 830a919..0000000 --- a/data/movements/scripts/misc/thais_trainers.lua +++ /dev/null @@ -1,15 +0,0 @@ -function onStepIn(creature, item, position, fromPosition) - local player = creature:getPlayer() - if not player then - return true - end - - doRelocate(item:getPosition(),{x = 32231, y = 32200, z = 7}) - Game.sendMagicEffect({x = 32231, y = 32200, z = 7}, 11) -end - -function onAddItem(item, tileitem, position) - doRelocate(item:getPosition(),{x = 32231, y = 32200, z = 7}) - item:getPosition():sendMagicEffect(11) - Game.sendMagicEffect({x = 32231, y = 32200, z = 7}, 11) -end diff --git a/data/movements/scripts/misc/thais_trainers_back.lua b/data/movements/scripts/misc/thais_trainers_back.lua deleted file mode 100644 index 57d49ba..0000000 --- a/data/movements/scripts/misc/thais_trainers_back.lua +++ /dev/null @@ -1,15 +0,0 @@ -function onStepIn(creature, item, position, fromPosition) - local player = creature:getPlayer() - if not player then - return true - end - - doRelocate(item:getPosition(),{x = 32350, y = 32222, z = 7}) - Game.sendMagicEffect({x = 32350, y = 32222, z = 7}, 11) -end - -function onAddItem(item, tileitem, position) - doRelocate(item:getPosition(),{x = 32350, y = 32222, z = 7}) - item:getPosition():sendMagicEffect(11) - Game.sendMagicEffect({x = 32350, y = 32222, z = 7}, 11) -end diff --git a/data/npc/daniel.npc b/data/npc/daniel.npc index 2eb2f7f..ebcf915 100644 --- a/data/npc/daniel.npc +++ b/data/npc/daniel.npc @@ -98,10 +98,10 @@ Topic=3,"rotworm" -> Amount=17635, "Maybe you have noticed the numerous rotworms Topic=3,"cyclop" -> Amount=17636, "We've successfully driven the minotaurs off this island, but the underground city of the cyclopes - Cyclopolis - is still standing. ...", "We're always looking for adventurers who'd help us decimate the number of cyclopes. Will you assist the city of Edron by killing 150 of them?", Topic=4 -"task",QuestValue(17633)=100 -> Amount=20*QuestValue(17633)*ExperienceStage(49)*40/100, Price=2000, "Very nice, %N. That will push the trolls' forces back a little. Here is your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney -"task",QuestValue(17634)=150 -> Amount=25*QuestValue(17634)*ExperienceStage(49)*40/100, Price=2500, "Congratulations, you've fought well against the goblin plague. Thank you! Here is your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney -"task",QuestValue(17635)=150 -> Amount=55*QuestValue(17635)*ExperienceStage(49)*40/100, Price=3000, "Well done! Thanks to you the city is a bit safer. Here's your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney -"task",QuestValue(17636)=150 -> Amount=150*QuestValue(17636)*ExperienceStage(49)*40/100, Price=8000, "Very good job, %N. You've been a great help. Here's your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney +"task",QuestValue(17633)=100 -> Amount=20*QuestValue(17633)*ExperienceStage(49)*40/100, Price=800, "Very nice, %N. That will push the trolls' forces back a little. Here is your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney +"task",QuestValue(17634)=150 -> Amount=25*QuestValue(17634)*ExperienceStage(49)*40/100, Price=1000, "Congratulations, you've fought well against the goblin plague. Thank you! Here is your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney +"task",QuestValue(17635)=150 -> Amount=55*QuestValue(17635)*ExperienceStage(49)*40/100, Price=1200, "Well done! Thanks to you the city is a bit safer. Here's your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney +"task",QuestValue(17636)=150 -> Amount=150*QuestValue(17636)*ExperienceStage(49)*40/100, Price=4000, "Very good job, %N. You've been a great help. Here's your reward!", SetQuestValue(QuestValue(17632),99999), SetQuestValue(17632,0), Experience(Amount), CreateMoney # Speaks "task",QuestValue(17632)>0 -> "Your current task is in progress. Follow the status of your task in the quest log. If you wish to cancel your in-progress task then don't be afraid and feel free to cancel." diff --git a/data/npc/gen-bank.ndb b/data/npc/gen-bank.ndb index 3514778..62690f3 100644 --- a/data/npc/gen-bank.ndb +++ b/data/npc/gen-bank.ndb @@ -14,6 +14,9 @@ "money" -> * "change" -> * "exchange" -> * +"guild" -> "If you are a member of a guild, you can deposit money on its account via guild deposit or check the guild money via guild balance. ...", + "If you are leader or vice leader of a guild, you can also withdraw gold from your guild account via guild withdraw. ...", + "Please keep in mind that we may need some time to process such requests." "change","gold",! -> "How many platinum coins do you want to get?", Topic=91 "exchange","gold",! -> * @@ -90,6 +93,9 @@ Topic=99 -> "Well, can I help you with something else "balance",balance>9999999 -> Amount=Balance, "You have made ten millions and it still grows! Your account balance is %A gold." "balance",balance>99999999 -> Amount=Balance, "I think you must be one of the richest inhabitants in the world! Your account balance is %A gold." +"guild","balance" -> "You are not a member of a guild." +"guild","balance",GuildLevel>0 -> Amount=GuildBalance, "Your guild account balance is %A gold." + "deposit" -> "You don't have any gold with you." "deposit",CountMoney>0 -> "Please tell me how much gold it is you would like to deposit.", Topic=81 "deposit","all",CountMoney>0 -> Price=CountMoney, "Would you really like to deposit %P gold?", Topic=82 @@ -104,6 +110,22 @@ Topic=82,"yes",CountMoney>=Price -> "Alright, we have added the amount of %P gol Topic=82,"yes" -> "I am inconsolable, but it seems you have lost your gold. I hope you get it back." Topic=82 -> "As you wish. Is there something else I can do for you?" +"guild","deposit",GuildLevel<=0 -> "You are not a member of a guild." +"guild","deposit" -> "You don't have any gold in your bank account." +"guild","deposit",Balance>0 -> "Please tell me how much gold it is you would like to deposit for your guild.", Topic=71 +"guild","deposit","all",GuildLevel<=0 -> "You are not a member of a guild." +"guild","deposit","all",Balance>0 -> Price=Balance, "Would you really like to deposit %P gold in to your guild bank account?", Topic=72 +"guild","deposit",$1,0<$1,GuildLevel<=0 -> "You are not a member of a guild." +"guild","deposit",$1,0<$1,Balance>=$1 -> Price=$1, "Would you really like to deposit %P gold in to your guild bank account?", Topic=72 +"guild","deposit",$1,0<$1,Balance<$1 -> "You do not have enough gold in your bank account." +Topic=71,$1,0<$1,Balance>=$1 -> Price=$1, "Would you really like to deposit %P gold in to your guild bank account?", Topic=72 +Topic=71,"0" -> "You are joking, aren't you?" +Topic=71,$1,0<$1,Balance<$1 -> "You do not have enough gold in your bank account." +Topic=71 -> "Please tell me how much gold it is you would like to deposit for your guild.", Topic=71 +Topic=72,"yes",Balance>=Price,GuildLevel>0 -> "Alright, we have added the amount of %P gold to your guild balance. Keep in mind that only authorized person can withdraw from the guild account.", GuildDeposit(Price) +Topic=72,"yes" -> "I am inconsolable, but it seems you do not have enough gold in your bank account anymore." +Topic=72 -> "As you wish. Is there something else I can do for you?" + "withdraw" -> "Please tell me how much gold you would like to withdraw.", Topic=83 "withdraw",$1,0<$1,Balance>=$1 -> Price=$1, "Are you sure you wish to withdraw %P gold from your bank account?", Topic=84 "withdraw","0" -> "Sure, you want nothing you get nothing!" @@ -116,6 +138,21 @@ Topic=84,"yes",Balance>=Price -> "Here you are, %P gold. Please let me know if t Topic=84,"yes" -> "I am inconsolable, but it seems you don't have that many gold in your bank account." Topic=84 -> "The customer is king! Come back anytime you want to if you wish to withdraw your money." +"guild","withdraw",GuildLevel<=0 -> "I am sorry but it seems you are currently not in any guild." +"guild","withdraw",GuildLevel=1 -> "I am sorry but you are not eligible to withdraw from the guild account." +"guild","withdraw" -> "Please tell me how much gold you would like to withdraw from your guild account.", Topic=73 +"guild","withdraw",$1,0<$1,GuildLevel<=0 -> "I am sorry but it seems you are currently not in any guild." +"guild","withdraw",$1,0<$1,GuildLevel=1 -> "I am sorry but you are not eligible to withdraw from the guild account." +"guild","withdraw",$1,0<$1,GuildBalance>=$1 -> Price=$1, "Are you sure you wish to withdraw %P gold from your guild bank account?", Topic=74 +"guild","withdraw",$1,0<$1,GuildBalance<$1 -> "There is not enough gold on your guild account." +Topic=73,$1,0<$1,GuildBalance>=$1 -> Price=$1, "Are you sure you wish to withdraw %P gold from your guild bank account?", Topic=74 +Topic=73,"0" -> "Sure, you want nothing you get nothing!" +Topic=73,$1,0<$1,GuildBalance<$1 -> "There is not enough gold on your guild account." +Topic=73 -> "Please tell me how much gold you would like to withdraw from your guild account..", Topic=73 +Topic=74,"yes",GuildBalance>=Price,GuildLevel>1 -> "Here you are, we withdraw %P gold from your guild account to your personal account. Please let me know if there is something else I can do for you.", GuildWithdraw(Price) +Topic=74,"yes" -> "I am inconsolable, but it seems you don't have that many gold in your guild bank account." +Topic=74 -> "The customer is king! Come back anytime you want to if you wish to withdraw your money." + "transfer" -> "Please tell me the amount of gold you would like to transfer.", Topic=85 "transfer","0","to" -> "Please think about it. Okay?" "transfer",$1,0<$1,"to",Balance<$1 -> "There is not enough gold on your account." diff --git a/data/npc/gen-t-runes-free-s.ndb b/data/npc/gen-t-runes-free-s.ndb index d4ac5cf..14bcb27 100644 --- a/data/npc/gen-t-runes-free-s.ndb +++ b/data/npc/gen-t-runes-free-s.ndb @@ -64,6 +64,8 @@ "bp","explosion","rune" -> * "backpack","fire","wall","rune" -> Type=3190, Data=4, Amount=1, Price=246*20, "Do you want to buy a backpack of fire wall rune for %P gold?", Topic=100 "bp","fire","wall","rune" -> * +"backpack","sudden","death","rune" -> Type=3155, Data=1, Amount=1, Price=325*20, "Do you want to buy a backpack of sudden death rune for %P gold?", Topic=100 +"bp","sudden","death","rune" -> * "backpack","energy","wall","rune" -> Type=3166, Data=4, Amount=1, Price=341*20, "Do you want to buy a backpack of energy wall rune for %P gold?", Topic=100 "bp","energy","wall","rune" -> * diff --git a/data/npc/gen-xmas.ndb b/data/npc/gen-xmas.ndb index 885ee48..ac923ca 100644 --- a/data/npc/gen-xmas.ndb +++ b/data/npc/gen-xmas.ndb @@ -13,21 +13,34 @@ VANISH,! -> "Good bye, little %N!" "farewell" -> * "job" -> "Ho ho ho! You don't know Santa Claus? Never mind. You may ask me for a present." "name" -> "Sorry, I don't have time to chat. Please ask for your present." +"thank" -> "You had a few hard times last year, I know. Considering all that you did well and I'm proud of you." +"thank",amount>9000 -> "You're one of my favourite children, little %N. But pssht, don't tell the others! I love all of you, of course." -#verteilt orange -"present",QuestValue(217)<3,amount<1000,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3586, Amount=10,Create(Type),Idle -#verteilt candy canes -"present",QuestValue(217)<3,amount<3500,amount>999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3599, Amount=8,Create(Type),Idle -#verteilt apfel -"present",QuestValue(217)<3,amount<5000,amount>3499,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3585, Amount=15,Create(Type),Idle -#verteilt kekse -"present",QuestValue(217)<3,amount<6000,amount>4999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3598, Amount=8,Create(Type),Idle -#verteilt schneeball -"present",QuestValue(217)<3,amount<9950,amount>5999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=2992, Amount=5,Create(Type),Idle -#verteilt doll -"present",QuestValue(217)<3,amount<9999,amount>9949,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=2991, Amount=1,Create(Type),Idle -#verteilt teddy -"present",QuestValue(217)<3,amount=10000,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=2993, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,amount<2000,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3599, Amount=10,Create(Type),Type=6506, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,amount<4000,amount>1999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3599, Amount=10,Create(Type),Type=6507, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,amount<6000,amount>3999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3599, Amount=10,Create(Type),Type=6508, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,amount<8000,amount>5999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3599, Amount=10,Create(Type),Type=2992, Amount=10,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount<9000,amount>7999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3039, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount<9500,amount>8999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3036, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,amount<9982,amount>9499,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=2991, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9983,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3382, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9984,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3419, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9985,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3381, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9986,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3420, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9987,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3279, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9988,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3079, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9989,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3386, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9990,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3567, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9991,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3364, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9992,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3366, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9993,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3389, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9994,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3001, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9995,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3570, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9996,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=5919, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9997,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3553, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9998,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=3057, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=9999,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=5080, Amount=1,Create(Type),Idle +"present",QuestValue(217)<3,Level>20,amount=10000,! -> "Here is your present! Enjoy!",SetQuestValue(217,3),Type=2993, Amount=1,Create(Type),Idle "present",QuestValue(217)=3 -> "You already got your present! Next please!", Idle diff --git a/data/npc/killing-tasks.ndb b/data/npc/killing-tasks.ndb index 3bd5606..d9203bb 100644 --- a/data/npc/killing-tasks.ndb +++ b/data/npc/killing-tasks.ndb @@ -34,42 +34,59 @@ VANISH,! -> "Happy hunting, old chap!" "trade" -> * "sabrehaven","talon" -> "We as a hunting society know very interesting purposes of those magical talons. But only the loyal hunters of the 'Paw and Fur - Hunting Elite' are allowed to know." -# Level 6-49 -"task",QuestValue(17607)=1,QuestValue(17608)=0,level>5,level<50 -> "Alright, what would you like to hunt? Frost trolls, swamp trolls, rats, wolves, wasps, larvas, dwarfs, low undeads, crocodiles, tarantulas, carniphilas, apes, thornback tortoises or gargoyles.", Topic=1 -Topic=1,"crocodile" -> Amount=17609, "They are a nuisance! You'll find them here in the jungle near the river. Hunt 100 crocodiles and you'll get a nice reward. Interested?", Topic=2 -Topic=1,"tarantula" -> Amount=17610, "There is a veritable plague of tarantulas living in the caves north of the river to the east. Can you squish 100 tarantulas for the Hunting Elite. What do you say?", Topic=2 -Topic=1,"carniphila" -> Amount=17611, "Damn walking weed-thingies! You'll find them deeper in the jungle. Weed out 50 carniphilas for our society. Alright?", Topic=2 -Topic=1,"ape" -> Amount=17612, "You'll find the apes deeper in the jungle. Hunt 100 merlkins, kongras or sibangs to complete this task. Alright?", Topic=2 -Topic=1,"tortoise" -> Amount=17613, "You'll find them on the Laguna Islands. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"gargoyle" -> Amount=17614, "They can be found all over Tibia. Hunt 65 of them. Interested?", Topic=2 -Topic=1,"frost","troll" -> Amount=17697, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"swamp","troll" -> Amount=17698, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"rat" -> Amount=17699, "They can be found all over Tibia. Hunt 25 of them. Interested?", Topic=2 -Topic=1,"wolves" -> Amount=17700, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"wasp" -> Amount=17701, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"larva" -> Amount=17702, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"dwarf" -> Amount=17703, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1,"undead" -> Amount=17704, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 -Topic=1 -> "Maybe next time." +"low","task",QuestValue(17607)=1,QuestValue(17608)=0 -> "You can hunt: Frost trolls, swamp trolls, lions, rats, hyaenas, bears, bugs, wolves, wasps, larvas, dwarfs, low undeads, crocodiles, tarantulas, carniphilas, apes, thornback tortoises, gargoyles, elves, outlaws or slimes.", Topic=5 +"medium","task",QuestValue(17607)=1,QuestValue(17608)=0 -> "You can hunt: Medium class orcs, high class minotaurs, lizards, high class dwarfs, medium undeads, quara scouts, ancient scarabs, wyverns, bonebeasts, beholders, djinns, pirates or dragons.", Topic=5 +"high","task",QuestValue(17607)=1,QuestValue(17608)=0 -> "You can hunt: High class orcs, hero, necromancers, underwater quara, giant spiders, banshees, lichs or cults.", Topic=5 +"very","high","task",QuestValue(17607)=1,QuestValue(17608)=0 -> "You can hunt: Nightmare, hydras, serpent spawns, behemoths, dragon lords, warlocks, hand of cursed fates, juggernauts, demons.", Topic=5 +"task",QuestValue(17607)=1,QuestValue(17608)=0 -> "Alright, what would you like to hunt? I have low level tasks, medium level tasks, high level tasks and very high level tasks.", Topic=5 -"task",QuestValue(17609)=100 -> Data=1, Amount=40*QuestValue(17609)*ExperienceStage(49)*40/100, Price=6000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17610)=100 -> Data=2, Amount=120*QuestValue(17610)*ExperienceStage(49)*40/100, Price=10000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17611)=50 -> Data=2, Amount=150*QuestValue(17611)*ExperienceStage(49)*40/100, Price=8000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17612)=100 -> Data=1, Amount=115*QuestValue(17612)*ExperienceStage(49)*40/100, Price=10000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17613)=100 -> Data=2, Amount=150*QuestValue(17613)*ExperienceStage(49)*40/100, Price=10000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17614)=65 -> Data=3, Amount=150*QuestValue(17614)*ExperienceStage(49)*40/100, Price=10000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17697)=100 -> Data=2, Amount=23*QuestValue(17697)*ExperienceStage(49)*40/100, Price=5000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17698)=100 -> Data=2, Amount=25*QuestValue(17698)*ExperienceStage(49)*40/100, Price=5500, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17699)=25 -> Data=1, Amount=7*QuestValue(17699)*ExperienceStage(49)*40/100, Price=2000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17700)=100 -> Data=2, Amount=18*QuestValue(17700)*ExperienceStage(49)*40/100, Price=7000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17701)=100 -> Data=2, Amount=24*QuestValue(17701)*ExperienceStage(49)*40/100, Price=7000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17702)=100 -> Data=2, Amount=44*QuestValue(17702)*ExperienceStage(49)*40/100, Price=8000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17703)=100 -> Data=2, Amount=45*QuestValue(17703)*ExperienceStage(49)*40/100, Price=6000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17704)=100 -> Data=2, Amount=60*QuestValue(17704)*ExperienceStage(49)*40/100, Price=7000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +# Recommended tasks for low level +Topic=5,"crocodile" -> Amount=17609, "They are a nuisance! You'll find them here in the jungle near the river. Hunt 100 crocodiles and you'll get a nice reward. Interested?", Topic=2 +Topic=5,"tarantula" -> Amount=17610, "There is a veritable plague of tarantulas living in the caves north of the river to the east. Can you squish 100 tarantulas for the Hunting Elite. What do you say?", Topic=2 +Topic=5,"carniphila" -> Amount=17611, "Damn walking weed-thingies! You'll find them deeper in the jungle. Weed out 50 carniphilas for our society. Alright?", Topic=2 +Topic=5,"ape" -> Amount=17612, "You'll find the apes deeper in the jungle. Hunt 100 merlkins, kongras or sibangs to complete this task. Alright?", Topic=2 +Topic=5,"tortoise" -> Amount=17613, "You'll find them on the Laguna Islands. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"gargoyle" -> Amount=17614, "They can be found all over Tibia. Hunt 65 of them. Interested?", Topic=2 +Topic=5,"frost","troll" -> Amount=17697, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"swamp","troll" -> Amount=17698, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"rat" -> Amount=17699, "They can be found all over Tibia. Hunt 25 of them. Interested?", Topic=2 +Topic=5,"wolves" -> Amount=17700, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"wasp" -> Amount=17701, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"larva" -> Amount=17702, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"dwarf" -> Amount=17703, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"undead" -> Amount=17704, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5,"elves" -> Amount=17729, "They can be found all over Tibia. Hunt 200 of them. Interested?", Topic=2 +Topic=5,"bug" -> Amount=17730, "They can be found all over Tibia. Hunt 40 of them. Interested?", Topic=2 +Topic=5,"outlaw" -> Amount=17731, "They can be found all over Tibia. Hunt 250 of them. Interested?", Topic=2 +Topic=5,"hyaena" -> Amount=17732, "They can be found all over Tibia. Hunt 30 of them. Interested?", Topic=2 +Topic=5,"lion" -> Amount=17733, "They can be found all over Tibia. Hunt 20 of them. Interested?", Topic=2 +Topic=5,"bear" -> Amount=17734, "They can be found all over Tibia. Hunt 35 of them. Interested?", Topic=2 +Topic=5,"slime" -> Amount=17735, "They can be found all over Tibia. Hunt 100 of them. Interested?", Topic=2 +Topic=5 -> "Maybe next time." -# Level 50-79 -"available","task",QuestValue(17607)=1,QuestValue(17608)=0,level>49 -> "You can hunt: Medium class orcs, high class minotaurs, lizards, high class dwarfs, medium undeads, quara scouts, ancient scarabs, wyverns, bonebeasts or dragons. ...", "High class orcs, hero, necromancers, underwater quara, giant spiders, banshees, lichs or cults. ...", "Nightmare, hydras, serpent spawns, behemoths, dragon lords, warlocks, hand of cursed fates, juggernauts, demons." -"task",QuestValue(17607)=1,QuestValue(17608)=0,level>49 -> "Alright, what would you like to hunt? If you have no idea yet I can tell you which available tasks are for you.", Topic=5 +"task",QuestValue(17609)=100 -> Data=1, Amount=40*QuestValue(17609)*ExperienceStage(29)*40/100, Price=2000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17610)=100 -> Data=2, Amount=120*QuestValue(17610)*ExperienceStage(29)*40/100, Price=6000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17611)=50 -> Data=2, Amount=150*QuestValue(17611)*ExperienceStage(29)*40/100, Price=5000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17612)=100 -> Data=1, Amount=115*QuestValue(17612)*ExperienceStage(29)*40/100, Price=6000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17613)=100 -> Data=2, Amount=150*QuestValue(17613)*ExperienceStage(29)*40/100, Price=6000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17614)=65 -> Data=3, Amount=150*QuestValue(17614)*ExperienceStage(29)*40/100, Price=5000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17697)=100 -> Data=2, Amount=23*QuestValue(17697)*ExperienceStage(29)*40/100, Price=1000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17698)=100 -> Data=2, Amount=25*QuestValue(17698)*ExperienceStage(29)*40/100, Price=1100, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17699)=25 -> Data=1, Amount=7*QuestValue(17699)*ExperienceStage(29)*40/100, Price=200, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17700)=100 -> Data=2, Amount=19*QuestValue(17700)*ExperienceStage(29)*40/100, Price=900, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17701)=100 -> Data=2, Amount=24*QuestValue(17701)*ExperienceStage(29)*40/100, Price=1000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17702)=100 -> Data=2, Amount=44*QuestValue(17702)*ExperienceStage(29)*40/100, Price=1200, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17703)=100 -> Data=2, Amount=45*QuestValue(17703)*ExperienceStage(29)*40/100, Price=2000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17704)=100 -> Data=2, Amount=60*QuestValue(17704)*ExperienceStage(29)*40/100, Price=2500, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17729)=200 -> Data=3, Amount=97*QuestValue(17729)*ExperienceStage(29)*40/100, Price=3800, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17730)=40 -> Data=1, Amount=18*QuestValue(17730)*ExperienceStage(29)*40/100, Price=400, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17731)=250 -> Data=1, Amount=57*QuestValue(17731)*ExperienceStage(29)*40/100, Price=4000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17732)=30 -> Data=1, Amount=20*QuestValue(17732)*ExperienceStage(29)*40/100, Price=350, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17733)=20 -> Data=1, Amount=30*QuestValue(17733)*ExperienceStage(29)*40/100, Price=600, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17734)=35 -> Data=1, Amount=23*QuestValue(17734)*ExperienceStage(29)*40/100, Price=400, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17735)=100 -> Data=1, Amount=160*QuestValue(17735)*ExperienceStage(29)*40/100, Price=7000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 + +# Recommended tasks for medium level Topic=5,"quara","scout" -> Amount=17616, "The scouts can be found on Malada, one of the Shattered Isles. Your task is to kill 200 quara scouts. I accept quara constrictor scouts, quara hydromancer scouts, quara mantassin scouts, quara pincher scouts and quara predator scouts, are you in?", Topic=2 Topic=5,"scarab" -> Amount=17617, "They can be found in tombs beneath the desert around Ankrahmun. Hunt 125 of them. Interested?", Topic=2 Topic=5,"wyvern" -> Amount=17618, "They can be found all over Tibia. Hunt 100 wyverns. Interested?", Topic=2 @@ -78,20 +95,27 @@ Topic=5,"dragon" -> Amount=17620, "They can be found all over Tibia. Hunt 200 dr Topic=5,"medium","orc" -> Amount=17712, "They can be found all over Tibia. Hunt 300 of them. Interested?", Topic=2 Topic=5,"minotaur" -> Amount=17713, "They can be found all over Tibia. Hunt 300 of them. Interested?", Topic=2 Topic=5,"lizard" -> Amount=17714, "They can be found all over Tibia. Hunt 300 of them. Interested?", Topic=2 -Topic=5,"dwarf" -> Amount=17715, "They can be found all over Tibia. Hunt 300 of them. Interested?", Topic=2 -Topic=5,"undead" -> Amount=17716, "They can be found all over Tibia. Hunt 200 of them. Interested?", Topic=2 +Topic=5,"high","dwarf" -> Amount=17715, "They can be found all over Tibia. Hunt 300 of them. Interested?", Topic=2 +Topic=5,"medium","undead" -> Amount=17716, "They can be found all over Tibia. Hunt 200 of them. Interested?", Topic=2 +Topic=5,"beholder" -> Amount=17736, "They can be found all over Tibia. Hunt 250 of them. Interested?", Topic=2 +Topic=5,"djinn" -> Amount=17737, "They can be found all over Tibia. Hunt 500 of them. Interested?", Topic=2 +Topic=5,"pirate" -> Amount=17738, "They can be found all over Tibia. Hunt 600 of them. Interested?", Topic=2 -"task",QuestValue(17616)=200 -> Data=2, Amount=430*QuestValue(17616)*ExperienceStage(79)*35/100, Price=20000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17617)=125 -> Data=2, Amount=720*QuestValue(17617)*ExperienceStage(79)*35/100, Price=25000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17618)=100 -> Data=3, Amount=515*QuestValue(17618)*ExperienceStage(79)*35/100, Price=30000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17619)=100 -> Data=3, Amount=580*QuestValue(17619)*ExperienceStage(79)*35/100, Price=30000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17620)=200 -> Data=2, Amount=700*QuestValue(17620)*ExperienceStage(79)*35/100, Price=25000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17712)=300 -> Data=2, Amount=100*QuestValue(17712)*ExperienceStage(79)*35/100, Price=20000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17713)=300 -> Data=2, Amount=125*QuestValue(17713)*ExperienceStage(79)*35/100, Price=21000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17714)=300 -> Data=2, Amount=158*QuestValue(17714)*ExperienceStage(79)*35/100, Price=21000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17715)=300 -> Data=2, Amount=166*QuestValue(17715)*ExperienceStage(79)*35/100, Price=21000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17716)=200 -> Data=2, Amount=221*QuestValue(17716)*ExperienceStage(79)*35/100, Price=20000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17616)=200 -> Data=2, Amount=430*QuestValue(17616)*ExperienceStage(49)*35/100, Price=13000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17617)=125 -> Data=2, Amount=720*QuestValue(17617)*ExperienceStage(49)*35/100, Price=13000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17618)=100 -> Data=3, Amount=515*QuestValue(17618)*ExperienceStage(49)*35/100, Price=11000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17619)=100 -> Data=3, Amount=580*QuestValue(17619)*ExperienceStage(49)*35/100, Price=12000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17620)=200 -> Data=2, Amount=700*QuestValue(17620)*ExperienceStage(49)*35/100, Price=15000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17712)=300 -> Data=2, Amount=100*QuestValue(17712)*ExperienceStage(49)*35/100, Price=10000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17713)=300 -> Data=2, Amount=125*QuestValue(17713)*ExperienceStage(49)*35/100, Price=11000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17714)=300 -> Data=2, Amount=158*QuestValue(17714)*ExperienceStage(49)*35/100, Price=11500, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17715)=300 -> Data=2, Amount=166*QuestValue(17715)*ExperienceStage(49)*35/100, Price=11500, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17716)=200 -> Data=2, Amount=221*QuestValue(17716)*ExperienceStage(49)*35/100, Price=11000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17736)=250 -> Data=3, Amount=450*QuestValue(17736)*ExperienceStage(49)*35/100, Price=15000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17737)=500 -> Data=4, Amount=245*QuestValue(17737)*ExperienceStage(49)*35/100, Price=30000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17738)=600 -> Data=4, Amount=205*QuestValue(17738)*ExperienceStage(49)*35/100, Price=30000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +# Recommended tasks for high level Topic=5,"quara" -> Amount=17621, "As you wish. Seek out a quara settlement and hunt 600 quara, it doesn't matter which type you hunt except scouts. Alright?", Topic=2 Topic=5,"spider" -> Amount=17622, "Never liked spiders. Simply too many legs. And I always find them in my bath! Those nasty creepy-crawlies are a threat to the hygiene of every living being in Tibia. Hunt 500 of them. Okay?", Topic=2 Topic=5,"banshee" -> Amount=17623, "The Banshee is an undead creature of sheer terror. There is several places where you can hunt them. Hunt 300 of them. Okay?", Topic=2 @@ -101,15 +125,16 @@ Topic=5,"high","orc" -> Amount=17717, "They can be found all over Tibia. Hunt 12 Topic=5,"hero" -> Amount=17718, "They can be found all over Tibia. Hunt 150 of them. Interested?", Topic=2 Topic=5,"necromancer" -> Amount=17719, "They can be found all over Tibia. Hunt 300 of them. Interested?", Topic=2 -"task",QuestValue(17621)=600 -> Data=4, Amount=850*QuestValue(17621)*ExperienceStage(129)*30/100, Price=50000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17622)=500 -> Data=3, Amount=900*QuestValue(17622)*ExperienceStage(129)*30/100, Price=60000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17623)=300 -> Data=5, Amount=900*QuestValue(17623)*ExperienceStage(129)*30/100, Price=45000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17624)=500 -> Data=4, Amount=900*QuestValue(17624)*ExperienceStage(129)*30/100, Price=65000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17625)=500 -> Data=2, Amount=325*QuestValue(17625)*ExperienceStage(129)*30/100, Price=50000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17717)=125 -> Data=2, Amount=475*QuestValue(17717)*ExperienceStage(129)*30/100, Price=30000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17718)=150 -> Data=2, Amount=1200*QuestValue(17718)*ExperienceStage(129)*30/100, Price=35000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17719)=300 -> Data=2, Amount=500*QuestValue(17719)*ExperienceStage(129)*30/100, Price=35000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17621)=600 -> Data=4, Amount=850*QuestValue(17621)*ExperienceStage(69)*30/100, Price=50000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17622)=500 -> Data=3, Amount=900*QuestValue(17622)*ExperienceStage(69)*30/100, Price=60000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17623)=300 -> Data=5, Amount=900*QuestValue(17623)*ExperienceStage(69)*30/100, Price=45000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17624)=500 -> Data=4, Amount=900*QuestValue(17624)*ExperienceStage(69)*30/100, Price=65000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17625)=500 -> Data=2, Amount=325*QuestValue(17625)*ExperienceStage(69)*30/100, Price=50000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17717)=125 -> Data=2, Amount=475*QuestValue(17717)*ExperienceStage(69)*30/100, Price=30000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17718)=150 -> Data=2, Amount=1200*QuestValue(17718)*ExperienceStage(69)*30/100, Price=35000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17719)=300 -> Data=2, Amount=500*QuestValue(17719)*ExperienceStage(69)*30/100, Price=35000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +# Recommended tasks for very high level Topic=5,"hydra" -> Amount=17626, "The hydras are located in the eastern jungle of Tiquanda and there are several mountain caves that are inhabited by them. Your task is to hunt a mere 650 hydras. Are you willing to do that?", Topic=2 Topic=5,"serpent" -> Amount=17627, "Very dangerous, nasty and slimy creatures. They live deep in the old ruins of Banuta. I think a mere 800 serpent spawns should do the trick. What do you say?", Topic=2 Topic=5,"behemoth" -> Amount=17628, "Behemoths must be kept away from the settlements at all costs. You'll find them east of here in the taboo-area or under Cyclopolis in Edron. Go there and hunt a few of them - shall we say... 700? Are you up for that?", Topic=2 @@ -120,14 +145,14 @@ Topic=5,"nightmare" -> Amount=17720, "They can be found all over Tibia. Hunt 150 Topic=5,"warlock" -> Amount=17721, "They can be found all over Tibia. Hunt 300 warlocks. Interested?", Topic=2 Topic=5,"demon" -> Amount=17722, "Oh, this one is crazy task. Hunt 6666 demons. Interested?", Topic=2 -"task",QuestValue(17626)=650 -> Data=4, Amount=2100*QuestValue(17626)*ExperienceStage(130)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17627)=800 -> Data=5, Amount=2000*QuestValue(17627)*ExperienceStage(130)*25/100, Price=120000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17628)=700 -> Data=5, Amount=2500*QuestValue(17628)*ExperienceStage(130)*25/100, Price=110000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17629)=600 -> Data=5, Amount=2100*QuestValue(17629)*ExperienceStage(130)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17630)=200 -> Data=5, Amount=5000*QuestValue(17630)*ExperienceStage(130)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17631)=200 -> Data=6, Amount=6500*QuestValue(17631)*ExperienceStage(130)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17720)=150 -> Data=6, Amount=2150*QuestValue(17720)*ExperienceStage(130)*25/100, Price=45000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 -"task",QuestValue(17721)=300 -> Data=6, Amount=4000*QuestValue(17721)*ExperienceStage(130)*25/100, Price=60000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17626)=650 -> Data=4, Amount=2100*QuestValue(17626)*ExperienceStage(79)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17627)=800 -> Data=5, Amount=2000*QuestValue(17627)*ExperienceStage(79)*25/100, Price=120000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17628)=700 -> Data=5, Amount=2500*QuestValue(17628)*ExperienceStage(79)*25/100, Price=110000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17629)=600 -> Data=5, Amount=2100*QuestValue(17629)*ExperienceStage(79)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17630)=200 -> Data=5, Amount=5000*QuestValue(17630)*ExperienceStage(79)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17631)=200 -> Data=6, Amount=6500*QuestValue(17631)*ExperienceStage(79)*25/100, Price=100000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17720)=150 -> Data=6, Amount=2150*QuestValue(17720)*ExperienceStage(79)*25/100, Price=45000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 +"task",QuestValue(17721)=300 -> Data=6, Amount=4000*QuestValue(17721)*ExperienceStage(79)*25/100, Price=60000, "Spiffing work, old chap. What would you like to get for reward: %A EXP or %P gold?", Topic=4 "task",QuestValue(17722)=6666 -> "You really did that? It is not implemented yet bro." # Speaks diff --git a/data/npc/santaclaus.npc b/data/npc/santaclaus.npc new file mode 100644 index 0000000..200eac8 --- /dev/null +++ b/data/npc/santaclaus.npc @@ -0,0 +1,11 @@ +# GIMUD - Graphical Interface Multi User Dungeon +# 17608 - any task in progress + +Name = "Santa Claus" +Outfit = (160,0-112-93-95-0) +Home = [32362,32207,7] +Radius = 3 + +Behaviour = { +@"gen-xmas.ndb" +} diff --git a/data/spells/scripts/spells/poison strike.lua b/data/spells/scripts/spells/poison strike.lua new file mode 100644 index 0000000..906dc58 --- /dev/null +++ b/data/spells/scripts/spells/poison strike.lua @@ -0,0 +1,20 @@ +local combat = Combat() +combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_EARTHDAMAGE) +combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_GREEN_RINGS) + +function onGetFormulaValues(player, level, maglevel) + local base = 45 + local variation = 10 + + local formula = 3 * maglevel + (2 * level) + + local min = (formula * (base - variation)) / 100 + local max = (formula * (base + variation)) / 100 + return -min, -max +end + +combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues") + +function onCastSpell(creature, variant) + return combat:execute(creature, variant) +end \ No newline at end of file diff --git a/data/spells/scripts/spells/poison wave.lua b/data/spells/scripts/spells/poison wave.lua new file mode 100644 index 0000000..b2893d5 --- /dev/null +++ b/data/spells/scripts/spells/poison wave.lua @@ -0,0 +1,21 @@ +local combat = Combat() +combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_EARTHDAMAGE) +combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_GREEN_RINGS) +combat:setArea(createCombatArea(AREA_SQUAREWAVE5)) + +function onGetFormulaValues(player, level, maglevel) + local base = 150 + local variation = 50 + + local formula = 3 * maglevel + (2 * level) + + local min = (formula * (base - variation)) / 100 + local max = (formula * (base + variation)) / 100 + return -min, -max +end + +combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues") + +function onCastSpell(creature, variant) + return combat:execute(creature, variant) +end \ No newline at end of file diff --git a/data/spells/scripts/runes/wild growth.lua b/data/spells/scripts/spells/wild growth.lua similarity index 100% rename from data/spells/scripts/runes/wild growth.lua rename to data/spells/scripts/spells/wild growth.lua diff --git a/data/spells/spells.xml b/data/spells/spells.xml index 94f0d4b..8d5529b 100644 --- a/data/spells/spells.xml +++ b/data/spells/spells.xml @@ -45,7 +45,16 @@ <vocation name="Druid" /> <vocation name="Elder Druid" /> </instant> - + <instant name="Poison Wave" words="exevo pox hur" lvl="38" mana="250" direction="1" needlearn="0" script="spells/poison wave.lua"> + <vocation name="Druid" /> + <vocation name="Elder Druid" /> + </instant> + <instant name="Wild Growth" words="exevo grav vita" lvl="27" mana="220" prem="1" cooldown="1000" range="3" direction="1" blocktype="all" needlearn="0" script="spells/wild growth.lua"> + <vocation name="Druid" /> + <vocation name="Elder Druid" /> + </instant> + + <!-- Knight Spells --> <instant name="Challenge" words="exeta res" lvl="20" mana="30" prem="1" aggressive="0" needlearn="0" script="spells/challenge.lua"> <vocation name="Elite Knight" /> @@ -136,6 +145,12 @@ <vocation name="Master Sorcerer" /> <vocation name="Elder Druid" /> </instant> + <instant name="Poison Strike" words="exori pox" lvl="12" mana="20" prem="1" cooldown="1000" range="3" direction="1" blockwalls="1" needlearn="0" script="spells/poison strike.lua"> + <vocation name="Sorcerer" /> + <vocation name="Druid" /> + <vocation name="Master Sorcerer" /> + <vocation name="Elder Druid" /> + </instant> <instant name="Great Light" words="utevo gran lux" lvl="13" mana="60" aggressive="0" selftarget="1" needlearn="0" script="spells/great light.lua"> <vocation name="Sorcerer" /> <vocation name="Druid" /> @@ -248,10 +263,6 @@ <rune name="Destroy Field" id="3148" allowfaruse="1" charges="3" maglv="3" aggressive="0" range="5" script="runes/destroy field.lua" /> <rune name="Chameleon" id="3178" allowfaruse="1" charges="1" maglv="4" aggressive="0" selftarget="1" blocktype="solid" function="chameleon" /> <rune name="Magic Wall" id="3180" allowfaruse="1" charges="3" maglv="9" blocktype="all" script="runes/magic wall.lua" /> - <rune name="Wild Growth" id="3156" allowfaruse="1" charges="2" maglv="8" blocktype="all" script="runes/wild growth.lua"> - <vocation name="Druid" /> - <vocation name="Elder Druid" showInDescription="0" /> - </rune> <rune name="Paralyze" id="3165" allowfaruse="1" charges="1" maglv="18" mana="1400" needtarget="1" blocktype="solid" script="runes/paralyze.lua"> <vocation name="Druid" /> <vocation name="Elder Druid" showInDescription="0" /> @@ -426,10 +437,6 @@ <vocation name="Sorcerer" /> <vocation name="Master Sorcerer" /> </conjure> - <conjure name="Wild Growth" words="exevo grav vita" lvl="27" mana="220" soul="5" prem="1" reagentId="3147" conjureId="3156" conjureCount="2" needlearn="0" function="conjureRune"> - <vocation name="Druid" /> - <vocation name="Elder Druid" /> - </conjure> <conjure name="Paralyze" words="adana ani" lvl="54" mana="1400" soul="3" prem="1" reagentId="3147" conjureId="3165" conjureCount="1" needlearn="0" function="conjureRune"> <vocation name="Druid" /> <vocation name="Elder Druid" /> diff --git a/data/talkactions/scripts/ban.lua b/data/talkactions/scripts/ban.lua index fc46763..21bd0b0 100644 --- a/data/talkactions/scripts/ban.lua +++ b/data/talkactions/scripts/ban.lua @@ -1,39 +1,57 @@ local banDays = 7 -function onSay(player, words, param) - if not player:getGroup():getAccess() then - return true - end +function onSay(cid, words, param) + local player = Player(cid) + if not player:getGroup():getAccess() then + return true + end - local name = param - local reason = '' + local name = param + local reason = '' + local banInfo = '' + local banTime = 0 + local banMultiplier = 0 + local params = param:split(',') + if params ~= nil then + name = params[1] + reason = string.trim(params[2]) + banInfo = string.trim(params[3]) + print(banInfo) + end + if banInfo then + if banInfo:find('h') then + banTime = banInfo:sub(0, banInfo:find('h') - 1) + banMultiplier = 3600 + elseif banInfo:find('d') then + banTime = banInfo:sub(0, banInfo:find('d') - 1) + banMultiplier = 86400 + else + banTime = banDays + banMultiplier = 86400 + end + banTime = banTime * banMultiplier + end + + local accountId = getAccountNumberByPlayerName(name) + if accountId == 0 then + return false + end - local separatorPos = param:find(',') - if separatorPos ~= nil then - name = param:sub(0, separatorPos - 1) - reason = string.trim(param:sub(separatorPos + 1)) - end + local resultId = db.storeQuery("SELECT 1 FROM `account_bans` WHERE `account_id` = " .. accountId) + if resultId ~= false then + result.free(resultId) + return false + end - local accountId = getAccountNumberByPlayerName(name) - if accountId == 0 then - return false - end + local timeNow = os.time() + db:query("INSERT INTO `account_bans` (`account_id`, `reason`, `banned_at`, `expires_at`, `banned_by`) VALUES (" .. + accountId .. ", " .. db.escapeString(reason) .. ", " .. timeNow .. ", " .. timeNow + banTime .. ", " .. player:getGuid() .. ")") - local resultId = db.storeQuery("SELECT 1 FROM `account_bans` WHERE `account_id` = " .. accountId) - if resultId ~= false then - result.free(resultId) - return false - end - - local timeNow = os.time() - db.query("INSERT INTO `account_bans` (`account_id`, `reason`, `banned_at`, `expires_at`, `banned_by`) VALUES (" .. - accountId .. ", " .. db.escapeString(reason) .. ", " .. timeNow .. ", " .. timeNow + (banDays * 86400) .. ", " .. player:getGuid() .. ")") - - local target = Player(name) - if target ~= nil then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, target:getName() .. " has been banned.") - target:remove() - else - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, name .. " has been banned.") - end -end + local target = Player(name) + if target ~= nil then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, target:getName() .. " has been banned.") + target:remove() + else + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, name .. " has been banned.") + end +end \ No newline at end of file diff --git a/data/talkactions/scripts/kills.lua b/data/talkactions/scripts/kills.lua index abdec2d..8dcee05 100644 --- a/data/talkactions/scripts/kills.lua +++ b/data/talkactions/scripts/kills.lua @@ -44,11 +44,11 @@ function onSay(player, words, param) message = message .. "Default murders\n" message = message .. "- Daily kills for red skull " .. killsDayRedSkull .. "\n" message = message .. "- Weekly kills for red skull " .. killsWeekRedSkull .. "\n" - message = message .. "- Monthly kills for red skull " .. killsMonthRedSkull .. "\n" + message = message .. "- Monthly kills for red skull " .. (killsMonthRedSkull >= 99999 and "unlimited" or tostring(killsMonthRedSkull)) .. "\n" message = message .. "- Daily kills for banishment " .. killsDayBanishment .. "\n" message = message .. "- Weekly kills for banishment " .. killsWeekBanishment .. "\n" - message = message .. "- Monthly kills for banishment " .. killsMonthBanishment .. "\n" + message = message .. "- Monthly kills for banishment " .. (killsMonthBanishment >= 99999 and "unlimited" or tostring(killsMonthBanishment)) .. "\n" message = message .. "\n" diff --git a/data/talkactions/scripts/physical_damage.lua b/data/talkactions/scripts/physical_damage.lua new file mode 100644 index 0000000..5fe8ba9 --- /dev/null +++ b/data/talkactions/scripts/physical_damage.lua @@ -0,0 +1,302 @@ +local weaponSkillsConfig = { + [WEAPON_SWORD] = SKILL_SWORD, + [WEAPON_CLUB] = SKILL_CLUB, + [WEAPON_AXE] = SKILL_AXE, + [WEAPON_DISTANCE] = SKILL_DISTANCE +} + +local skillNameConfig = { + [SKILL_SWORD] = "Sword Fighting", + [SKILL_CLUB] = "Club Fighting", + [SKILL_AXE] = "Axe Fighting", + [SKILL_DISTANCE] = "Distance Fighting", + [SKILL_FIST] = "Fist Fighting" +} + +local function ltrim(s) + if s == nil then + return s + end + + return s:match'^%s*(.*)' +end + +local function getWeapon(player) + local itemLeft = player:getSlotItem(CONST_SLOT_LEFT) + if itemLeft and itemLeft:getType():getWeaponType() ~= WEAPON_NONE and itemLeft:getType():getWeaponType() ~= WEAPON_SHIELD and itemLeft:getType():getWeaponType() ~= WEAPON_AMMO and itemLeft:getType():getWeaponType() ~= WEAPON_WAND then + return itemLeft:getType() + end + + local itemRight = player:getSlotItem(CONST_SLOT_RIGHT) + if itemRight and itemRight:getType():getWeaponType() ~= WEAPON_NONE and itemRight:getType():getWeaponType() ~= WEAPON_SHIELD and itemRight:getType():getWeaponType() ~= WEAPON_AMMO and itemRight:getType():getWeaponType() ~= WEAPON_WAND then + return itemRight:getType() + end +end + +local function getAmmunition(player) + local item = player:getSlotItem(CONST_SLOT_AMMO) + if item and item:getType():getWeaponType() == WEAPON_AMMO then + return item:getType() + end +end + +local function getAttack(weapon, ammunition) + local attack = 7 + if weapon ~= nil then + attack = weapon:getAttack() + if weapon:getWeaponType() == WEAPON_DISTANCE and weapon:getAmmoType() ~= 0 then + if ammunition ~= nil and ammunition:getAmmoType() == weapon:getAmmoType() then + attack = attack + ammunition:getAttack() + end + end + end + + return attack +end + +local function getDamageFormula(attack, attackSkill, fightMode) + local damage = attack + if fightMode == FIGHTMODE_ATTACK then + damage = math.floor(damage + 2 * damage / 10) + elseif fightMode == FIGHTMODE_DEFENSE then + damage = math.floor(damage - 4 * damage / 10) + end + + local formula = math.floor((5 * (attackSkill) + 50) * damage) + return formula +end + +local function getDamage(attack, attackSkill, fightMode, random1, random2) + local formula = getDamageFormula(attack, attackSkill, fightMode) + local randResult = math.floor(random1 % 100); + local damage = -math.floor((math.ceil(formula * ((random2 % 100 + randResult) / 2) / 10000.))); + return damage +end + +local function setVocationDamageIncrease(vocationId, damage) + if vocationId == 4 or vocationId == 8 then + local knightCloseAttackDamageIncreasePercent = configManager.getNumber(configKeys.KNIGHT_CLOSE_ATTACK_DAMAGE_INCREASE_PERCENT) + if knightCloseAttackDamageIncreasePercent ~= -1 then + damage = math.floor(damage + damage * knightCloseAttackDamageIncreasePercent / 100); + end + elseif vocationId == 3 or vocationId == 7 then + local paladinRangeAttackDamageIncreasePercent = configManager.getNumber(configKeys.PALADIN_RANGE_ATTACK_DAMAGE_INCREASE_PERCENT) + if paladinRangeAttackDamageIncreasePercent ~= -1 then + damage = math.floor(damage + damage * paladinRangeAttackDamageIncreasePercent / 100); + end + end + + return damage +end + +local function getDefense(creature, random1, random2) + local totalDefense = creature:getType():getDefense() + 1 + local defenseSkill = creature:getType():getSkill() + + local formula = math.floor((5 * (defenseSkill) + 50) * totalDefense) + local randresult = math.floor(random1 % 100) + + return math.floor(formula * ((random2 % 100 + randresult) / 2) / 10000.) +end + +local function rshift(x, by) + return math.floor(x / 2 ^ by) +end + +local function getArmor(creature, rand) + local armor = creature:getType():getArmor() + if armor > 1 then + return rand % rshift(armor, 1) + rshift(armor, 1); + end + + return armor +end + +local function setPhysicalDamageBlock(creature, damage, random1, random2, randomArmor) + if bit.band(creature:getType():getCombatImmunities(), COMBAT_PHYSICALDAMAGE) == COMBAT_PHYSICALDAMAGE then + return 0 + end + + damage = damage + getDefense(creature, random1, random2) + + if damage >= 0 then + return 0 + end + + if damage < 0 then + damage = damage + getArmor(creature, randomArmor) + if damage >= 0 then + return 0 + end + end + + return damage +end + +local function isThrowableHit(weapon, ammunition, skillValue, rand) + local distance = 15 -- we consider distance is always the best + local hitChance = 75 -- throwables and such + + if weapon:getAmmoType() ~= 0 then + hitChance = 90 -- bows and crossbows + if ammunition == nil or ammunition:getAmmoType() ~= weapon:getAmmoType() then + hitChance = -1 -- no ammo or invalid ammo + end + end + + if rand % distance <= skillValue then + return rand % 100 <= hitChance + end + + return false +end + +local function getTotalDamage(creature, weapon, ammunition, vocation, attack, skillValue, fightMode) + local damage = setVocationDamageIncrease(vocation:getId(), getDamage(attack, skillValue, fightMode, os.rand(), os.rand())) + local minDamage = setVocationDamageIncrease(vocation:getId(), getDamage(attack, skillValue, fightMode, 0, 0)) + local maxDamage = setVocationDamageIncrease(vocation:getId(), getDamage(attack, skillValue, fightMode, 99, 99)) + + if weapon ~= nil and weapon:getWeaponType() == WEAPON_DISTANCE then + if isThrowableHit(weapon, ammunition, skillValue, os.rand()) then + damage = setPhysicalDamageBlock(creature, damage, os.rand(), os.rand(), os.rand()) + else + damage = 0 + end + minDamage = 0 + if isThrowableHit(weapon, ammunition, skillValue, 0) then + maxDamage = setPhysicalDamageBlock(creature, maxDamage, 0, 0, 0) + else + maxDamage = 0 + end + else + damage = setPhysicalDamageBlock(creature, damage, os.rand(), os.rand(), os.rand()) + minDamage = setPhysicalDamageBlock(creature, minDamage, 99, 99, rshift(creature:getType():getArmor(), 1) + 1) + maxDamage = setPhysicalDamageBlock(creature, maxDamage, 0, 0, 0) + end + + local container = {} + container[0] = damage + container[1] = minDamage + container[2] = maxDamage + return container +end + +function onSay(player, words, param) + local split = param:split(",") + local creatureName = ltrim(split[1]) + local skillValueNumber = ltrim(split[2]) + local vocationName = ltrim(split[3]) + local weaponName = ltrim(split[4]) + local ammunitionName = ltrim(split[5]) + + local creature = Creature("Troll") + if creatureName ~= nil then + creature = Creature(creatureName) + if creature == nil then + player:sendCancelMessage("The monster does not exist.") + return false + end + else + creatureName = creature:getName() + end + + local weapon = getWeapon(player) + if weaponName ~= nil then + weapon = ItemType(weaponName) + if weapon == nil or weapon:getWeaponType() == WEAPON_NONE or weapon:getWeaponType() == WEAPON_SHIELD or weapon:getWeaponType() == WEAPON_AMMO or weapon:getWeaponType() == WEAPON_WAND then + player:sendCancelMessage("The weapon does not exist.") + return false + end + else + if weapon ~= nil then + weaponName = weapon:getName() + end + end + + local ammunition = getAmmunition(player) + if ammunitionName ~= nil then + ammunition = ItemType(ammunitionName) + if ammunition == nil or ammunition:getWeaponType() ~= WEAPON_AMMO then + player:sendCancelMessage("The ammunition does not exist.") + return false + end + else + if ammunition ~= nil then + ammunitionName = ammunition:getName() + end + end + + local skillType = SKILL_FIST + local attack = getAttack(weapon, ammunition) + if weapon ~= nil then + skillType = weaponSkillsConfig[weapon:getWeaponType()] + end + + local skillValue = player:getSkillLevel(skillType) + if skillValueNumber ~= nil then + if tonumber(skillValueNumber) > 0 then + skillValue = tonumber(skillValueNumber) + else + player:sendCancelMessage("The skill value has to be a number and greater than zero.") + return false + end + end + + local vocation = player:getVocation() + if vocationName ~= nil then + vocation = Vocation(vocationName) + if vocation == nil then + player:sendCancelMessage("The vocation does not exist.") + return false + end + else + vocationName = vocation:getName() + end + + local commandStr = "Executing command: !physicaldamage " .. creatureName .. ", " .. skillValue .. ", " .. vocationName .. "" + + if weapon ~= nil then + commandStr = commandStr .. ", " .. weaponName + end + + if ammunition ~= nil and weapon ~= nil and weapon:getWeaponType() == WEAPON_DISTANCE then + commandStr = commandStr .. ", " .. ammunitionName + end + player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, commandStr) + + local offensiveDamageContainer = getTotalDamage(creature, weapon, ammunition, vocation, attack, skillValue, FIGHTMODE_ATTACK) + local balancedDamageContainer = getTotalDamage(creature, weapon, ammunition, vocation, attack, skillValue, FIGHTMODE_BALANCED) + local defensiveDamageContainer = getTotalDamage(creature, weapon, ammunition, vocation, attack, skillValue, FIGHTMODE_DEFENSE) + + local message = "" + message = message .. "Vocation: " .. vocation:getName() .. "\n" + message = message .. "Skill Name: " .. skillNameConfig[skillType] .. ", Skill Value: " .. skillValue .. "\n" + message = message .. "Weapon: " .. (weaponName or 'none') .. " (atk: " .. attack .. ")\n" + message = message .. "Creature: " .. creatureName .. " (arm: " .. creature:getType():getArmor() .. ", def: " .. creature:getType():getDefense() .. ", skill: " .. creature:getType():getSkill() .. ")\n" + message = message .. "\nOffensive Fighting Damage\n" + message = message .. "Min: " .. offensiveDamageContainer[1] .. ", Max: " .. offensiveDamageContainer[2] .. "\n" + message = message .. "\nBalanced Fighting Damage\n" + message = message .. "Min: " .. balancedDamageContainer[1] .. ", Max: " .. balancedDamageContainer[2] .. "\n" + message = message .. "\nDefensive Fighting Damage\n" + message = message .. "Min: " .. defensiveDamageContainer[1] .. ", Max: " .. defensiveDamageContainer[2] .. "\n" + + message = message .. "\nFirst 100 Hits Damage Simulator in Offensive Fighting\n" + local creatureHealth = creature:getType():getMaxHealth() + local creatureHitsTillDeath = 1 + for i=1,100 do + local damageContainer = getTotalDamage(creature, weapon, ammunition, vocation, attack, skillValue, FIGHTMODE_ATTACK) + message = message .. "Hit: " .. i .. ", Damage: " .. damageContainer[0] .. "\n" + creatureHealth = creatureHealth + damageContainer[0] + if creatureHealth > 0 then + creatureHitsTillDeath = creatureHitsTillDeath + 1 + end + end + + if creatureHealth <= 0 then + message = message .. "\nIt would take you approximately " .. creatureHitsTillDeath .. " hits to slain " .. creature:getName() .. ".\n" + else + message = message .. "\nIt would take you more than 100 hits to slain " .. creature:getName() .. ".\n" + end + player:showTextDialog(weapon and weapon:getId() or 2950, message, false) + return false +end \ No newline at end of file diff --git a/data/talkactions/scripts/war.lua b/data/talkactions/scripts/war.lua new file mode 100644 index 0000000..146dfdd --- /dev/null +++ b/data/talkactions/scripts/war.lua @@ -0,0 +1,60 @@ +function onSay(player, words, param) + if not player:getGuild() or player:getGuildLevel() < 3 then + player:sendCancelMessage("You cannot execute this talkaction.") + return true + end + + local t = param:split(",") + + if not t[2] then + player:sendCancelMessage("Not enough param(s).") + return true + end + + local enemyGuildName = string.trim(t[2]) + + local enemyGuild = Guild(getGuildId(enemyGuildName)) + if not enemyGuild then + player:sendCancelMessage("Guild \"" .. enemyGuildName .. "\" does not exists or nobody is online from the guild.") + return true + end + + if enemyGuild:getId() == player:getGuild():getId() then + player:sendCancelMessage("You cannot perform war action on your own guild.") + return true + end + + local warCommand = string.trim(t[1]) + + if isInArray({"accept", "reject", "cancel"}, warCommand) then + local pendingWarId, bounty = 0 + + if warCommand == "cancel" then + pendingWarId, bounty = guildwars:getPendingInvitation(player:getGuild():getId(), enemyGuild:getId()) + else + pendingWarId, bounty = guildwars:getPendingInvitation(enemyGuild:getId(), player:getGuild():getId()) + end + + if pendingWarId == 0 then + player:sendCancelMessage("Currently there's no pending invitation for a war with " .. enemyGuild:getName() .. ".") + return true + end + + if warCommand == "reject" then + guildwars:rejectWar(pendingWarId, player:getGuild(), enemyGuild, bounty) + elseif warCommand == "cancel" then + guildwars:cancelWar(pendingWarId, player:getGuild(), enemyGuild, bounty) + else + guildwars:startWar(player, pendingWarId, player:getGuild(), enemyGuild, bounty) + end + + return true + end + + if warCommand == "invite" then + guildwars:invite(player, player:getGuild(), enemyGuild, tonumber(t[3] and string.trim(t[3]) or 100), tonumber(t[4] and string.trim(t[4]) or 0)) + return true + end + + return true +end \ No newline at end of file diff --git a/data/talkactions/talkactions.xml b/data/talkactions/talkactions.xml index 4dd0bd1..fcc3cca 100644 --- a/data/talkactions/talkactions.xml +++ b/data/talkactions/talkactions.xml @@ -52,10 +52,13 @@ <talkaction words="!uptime" script="uptime.lua"/> <talkaction words="!deathlist" script="deathlist.lua"/> <talkaction words="!kills" script="kills.lua"/> + <talkaction words="!frags" script="kills.lua"/> <talkaction words="!online" script="online.lua"/> <talkaction words="!serverinfo" script="serverinfo.lua"/> <talkaction words="!share" script="experienceshare.lua"/> <talkaction words="!shop" script="znoteshop.lua"/> + <talkaction words="!physicaldamage" separator=" " script="physical_damage.lua"/> + <talkaction words="!war" separator=" " script="war.lua"/> <talkaction words="469" script="469.lua"/> <!-- test talkactions --> diff --git a/data/world792/map.otbm b/data/world792/map.otbm index ee85a5a..8bc5c54 100644 Binary files a/data/world792/map.otbm and b/data/world792/map.otbm differ diff --git a/data/world792/spawns.xml b/data/world792/spawns.xml index 624c973..193920b 100644 --- a/data/world792/spawns.xml +++ b/data/world792/spawns.xml @@ -1208,7 +1208,7 @@ <monster name="Wyvern" x="0" y="1" z="5" spawntime="600" /> </spawn> <spawn centerx="33213" centery="31763" centerz="5" radius="1"> - <monster name="Wyvern" x="0" y="0" z="5" spawntime="120" /> + <monster name="Wyvern" x="0" y="0" z="5" spawntime="600" /> </spawn> <spawn centerx="33233" centery="31764" centerz="5" radius="1"> <monster name="Wyvern" x="0" y="1" z="5" spawntime="600" /> @@ -6973,48 +6973,11 @@ <monster name="wolf" x="-2" y="-1" z="7" spawntime="600" /> <monster name="wolf" x="0" y="0" z="7" spawntime="600" /> </spawn> - <spawn centerx="32236" centery="32186" centerz="7" radius="5"> - <monster name="Training Monk" x="3" y="-3" z="7" spawntime="71" /> - <monster name="Training Monk" x="-1" y="-2" z="7" spawntime="71" /> - <monster name="Training Monk" x="3" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="-1" y="0" z="7" spawntime="71" /> - <monster name="Training Monk" x="3" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="-1" y="2" z="7" spawntime="71" /> - <monster name="Training Monk" x="3" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-1" y="4" z="7" spawntime="71" /> - <monster name="Training Monk" x="3" y="5" z="7" spawntime="768" /> - </spawn> <spawn centerx="32677" centery="32186" centerz="7" radius="4"> <monster name="wild warrior" x="2" y="-3" z="7" spawntime="650" /> <monster name="wild warrior" x="0" y="0" z="7" spawntime="650" /> <monster name="wild warrior" x="0" y="2" z="7" spawntime="650" /> </spawn> - <spawn centerx="32219" centery="32187" centerz="7" radius="5"> - <monster name="Training Monk" x="-3" y="-4" z="7" spawntime="71" /> - <monster name="Training Monk" x="4" y="-4" z="7" spawntime="71" /> - <monster name="Training Monk" x="-3" y="-2" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="-2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-3" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="-3" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-3" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="4" z="7" spawntime="768" /> - </spawn> - <spawn centerx="32225" centery="32187" centerz="7" radius="5"> - <monster name="Training Monk" x="2" y="-3" z="7" spawntime="71" /> - <monster name="Training Monk" x="2" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="5" z="7" spawntime="768" /> - </spawn> - <spawn centerx="32242" centery="32187" centerz="7" radius="5"> - <monster name="Training Monk" x="5" y="-4" z="7" spawntime="71" /> - <monster name="Training Monk" x="5" y="-2" z="7" spawntime="768" /> - <monster name="Training Monk" x="5" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="5" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="5" y="4" z="7" spawntime="768" /> - </spawn> <spawn centerx="32004" centery="32188" centerz="7" radius="3"> <monster name="snake" x="0" y="-1" z="7" spawntime="600" /> <monster name="snake" x="0" y="0" z="7" spawntime="600" /> @@ -7055,28 +7018,6 @@ <spawn centerx="33053" centery="32191" centerz="7" radius="1"> <monster name="elf" x="0" y="0" z="7" spawntime="600" /> </spawn> - <spawn centerx="32225" centery="32193" centerz="7" radius="5"> - <monster name="Training Monk" x="-2" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="5" z="7" spawntime="768" /> - </spawn> - <spawn centerx="32236" centery="32193" centerz="7" radius="5"> - <monster name="Training Monk" x="-1" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="-1" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-1" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="-1" y="5" z="7" spawntime="768" /> - </spawn> - <spawn centerx="32243" centery="32193" centerz="7" radius="5"> - <monster name="Training Monk" x="4" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="4" z="7" spawntime="768" /> - </spawn> <spawn centerx="32438" centery="32193" centerz="7" radius="11"> <monster name="snake" x="-2" y="-7" z="7" spawntime="400" /> <monster name="snake" x="-2" y="-3" z="7" spawntime="400" /> @@ -7097,12 +7038,6 @@ <monster name="deer" x="1" y="-2" z="7" spawntime="600" /> <monster name="deer" x="0" y="0" z="7" spawntime="600" /> </spawn> - <spawn centerx="32219" centery="32195" centerz="7" radius="5"> - <monster name="Training Monk" x="-3" y="-2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-3" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="-3" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-3" y="4" z="7" spawntime="71" /> - </spawn> <spawn centerx="32850" centery="32195" centerz="7" radius="4" /> <spawn centerx="31981" centery="32196" centerz="7" radius="3"> <monster name="wolf" x="0" y="0" z="7" spawntime="600" /> @@ -7147,40 +7082,10 @@ <monster name="deer" x="2" y="-2" z="7" spawntime="600" /> <monster name="deer" x="0" y="0" z="7" spawntime="600" /> </spawn> - <spawn centerx="32220" centery="32204" centerz="7" radius="5"> - <monster name="Training Monk" x="-4" y="-3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="0" z="7" spawntime="71" /> - <monster name="Training Monk" x="-4" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="5" z="7" spawntime="768" /> - </spawn> - <spawn centerx="32243" centery="32204" centerz="7" radius="5"> - <monster name="Training Monk" x="4" y="-5" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="-3" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="-1" z="7" spawntime="71" /> - <monster name="Training Monk" x="-4" y="0" z="7" spawntime="71" /> - <monster name="Training Monk" x="4" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="5" z="7" spawntime="768" /> - </spawn> <spawn centerx="32948" centery="32204" centerz="7" radius="3"> <monster name="rabbit" x="-1" y="-1" z="7" spawntime="600" /> <monster name="rabbit" x="0" y="0" z="7" spawntime="600" /> </spawn> - <spawn centerx="32237" centery="32207" centerz="7" radius="5"> - <monster name="Training Monk" x="-2" y="-4" z="7" spawntime="71" /> - <monster name="Training Monk" x="-2" y="-2" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="5" z="7" spawntime="768" /> - </spawn> <spawn centerx="32874" centery="32207" centerz="7" radius="4"> <monster name="snake" x="-1" y="-3" z="7" spawntime="600" /> <monster name="snake" x="-3" y="0" z="7" spawntime="600" /> @@ -7190,16 +7095,6 @@ <monster name="spider" x="0" y="0" z="7" spawntime="600" /> <monster name="spider" x="1" y="1" z="7" spawntime="600" /> </spawn> - <spawn centerx="32225" centery="32208" centerz="7" radius="5"> - <monster name="Training Monk" x="2" y="-5" z="7" spawntime="71" /> - <monster name="Training Monk" x="2" y="-3" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-2" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="5" z="7" spawntime="768" /> - </spawn> <spawn centerx="31985" centery="32209" centerz="7" radius="4"> <monster name="snake" x="1" y="-2" z="7" spawntime="600" /> <monster name="snake" x="0" y="0" z="7" spawntime="600" /> @@ -7217,14 +7112,6 @@ <monster name="sheep" x="3" y="2" z="7" spawntime="100" /> <monster name="sheep" x="2" y="4" z="7" spawntime="100" /> </spawn> - <spawn centerx="32243" centery="32212" centerz="7" radius="5"> - <monster name="Training Monk" x="4" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="2" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="4" z="7" spawntime="768" /> - <monster name="Training Monk" x="4" y="5" z="7" spawntime="768" /> - </spawn> <spawn centerx="32716" centery="32212" centerz="7" radius="4"> <monster name="wolf" x="0" y="-3" z="7" spawntime="600" /> <monster name="wolf" x="1" y="-3" z="7" spawntime="600" /> @@ -7239,29 +7126,15 @@ <monster name="snake" x="0" y="1" z="7" spawntime="600" /> <monster name="snake" x="3" y="3" z="7" spawntime="600" /> </spawn> - <spawn centerx="32237" centery="32213" centerz="7" radius="5"> - <monster name="Training Monk" x="-2" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="2" y="5" z="7" spawntime="768" /> - </spawn> <spawn centerx="32156" centery="32214" centerz="7" radius="5"> <monster name="wolf" x="2" y="-2" z="7" spawntime="600" /> <monster name="wolf" x="-1" y="0" z="7" spawntime="600" /> <monster name="wolf" x="0" y="0" z="7" spawntime="600" /> <monster name="wolf" x="3" y="0" z="7" spawntime="600" /> </spawn> - <spawn centerx="32220" centery="32214" centerz="7" radius="5"> - <monster name="Training Monk" x="-4" y="-3" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="-1" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="0" z="7" spawntime="768" /> - <monster name="Training Monk" x="-4" y="1" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="2" z="7" spawntime="71" /> - <monster name="Training Monk" x="-4" y="3" z="7" spawntime="768" /> - <monster name="Training Monk" x="3" y="4" z="7" spawntime="71" /> - </spawn> <spawn centerx="32368" centery="32214" centerz="7" radius="1"> <monster name="dog" x="0" y="0" z="7" spawntime="400" /> </spawn> - <spawn centerx="32225" centery="32215" centerz="7" radius="5" /> <spawn centerx="32853" centery="32215" centerz="7" radius="3"> <monster name="snake" x="0" y="-1" z="7" spawntime="600" /> <monster name="snake" x="0" y="0" z="7" spawntime="600" /> diff --git a/sabrehaven.sql b/sabrehaven.sql index 6dd3015..9a7a706 100644 --- a/sabrehaven.sql +++ b/sabrehaven.sql @@ -93,7 +93,8 @@ CREATE TABLE `guilds` ( `name` varchar(255) NOT NULL, `ownerid` int(11) NOT NULL, `creationdata` int(11) NOT NULL, - `motd` varchar(255) NOT NULL DEFAULT '' + `motd` varchar(255) NOT NULL DEFAULT '', + `balance` bigint(20) UNSIGNED NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- @@ -171,11 +172,10 @@ CREATE TABLE `guild_wars` ( `id` int(11) NOT NULL, `guild1` int(11) NOT NULL DEFAULT '0', `guild2` int(11) NOT NULL DEFAULT '0', - `name1` varchar(255) NOT NULL, - `name2` varchar(255) NOT NULL, `status` tinyint(2) NOT NULL DEFAULT '0', - `started` bigint(15) NOT NULL DEFAULT '0', - `ended` bigint(15) NOT NULL DEFAULT '0' + `frag_limit` int(11) NOT NULL DEFAULT '0', + `declaration_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `bounty` bigint(20) UNSIGNED NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- @@ -1138,6 +1138,8 @@ CREATE TABLE `players` ( `onlinetime` int(11) NOT NULL DEFAULT '0', `deletion` bigint(15) NOT NULL DEFAULT '0', `balance` bigint(20) UNSIGNED NOT NULL DEFAULT '0', + `offlinetraining_time` smallint(5) unsigned NOT NULL DEFAULT '43200', + `offlinetraining_skill` int(11) NOT NULL DEFAULT '-1', `stamina` smallint(5) NOT NULL DEFAULT '3360', `skill_fist` int(10) UNSIGNED NOT NULL DEFAULT '10', `skill_fist_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0', @@ -1583,6 +1585,14 @@ ALTER TABLE `account_viplist` ALTER TABLE `guilds` ADD CONSTRAINT `guilds_ibfk_1` FOREIGN KEY (`ownerid`) REFERENCES `players` (`id`) ON DELETE CASCADE; +-- +-- Constraints for table `guild_wars` +-- +ALTER TABLE `guild_wars` + ADD CONSTRAINT `guild1_ibfk_1` FOREIGN KEY (`guild1`) REFERENCES `guilds` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `guild2_ibfk_1` FOREIGN KEY (`guild2`) REFERENCES `guilds` (`id`) ON DELETE CASCADE; +COMMIT; + -- -- Constraints for table `guildwar_kills` -- diff --git a/src/behaviourdatabase.cpp b/src/behaviourdatabase.cpp index 0351fa4..d5a788e 100644 --- a/src/behaviourdatabase.cpp +++ b/src/behaviourdatabase.cpp @@ -292,9 +292,15 @@ bool BehaviourDatabase::loadActions(ScriptReader& script, NpcBehaviour* behaviou } else if (identifier == "withdraw") { action->type = BEHAVIOUR_TYPE_WITHDRAW; searchType = BEHAVIOUR_PARAMETER_ONE; + } else if (identifier == "guildwithdraw") { + action->type = BEHAVIOUR_TYPE_GUILDWITHDRAW; + searchType = BEHAVIOUR_PARAMETER_ONE; } else if (identifier == "deposit") { action->type = BEHAVIOUR_TYPE_DEPOSIT; searchType = BEHAVIOUR_PARAMETER_ONE; + } else if (identifier == "guilddeposit") { + action->type = BEHAVIOUR_TYPE_GUILDDEPOSIT; + searchType = BEHAVIOUR_PARAMETER_ONE; } else if (identifier == "transfer") { action->type = BEHAVIOUR_TYPE_TRANSFER; searchType = BEHAVIOUR_PARAMETER_ONE; @@ -535,12 +541,18 @@ NpcBehaviourNode* BehaviourDatabase::readValue(ScriptReader& script) } else if (identifier == "level") { node = new NpcBehaviourNode(); node->type = BEHAVIOUR_TYPE_LEVEL; + } else if (identifier == "guildlevel") { + node = new NpcBehaviourNode(); + node->type = BEHAVIOUR_TYPE_GUILDLEVEL; } else if (identifier == "poison") { node = new NpcBehaviourNode(); node->type = BEHAVIOUR_TYPE_POISON; } else if (identifier == "balance") { node = new NpcBehaviourNode(); node->type = BEHAVIOUR_TYPE_BALANCE; + } else if (identifier == "guildbalance") { + node = new NpcBehaviourNode(); + node->type = BEHAVIOUR_TYPE_GUILDBALANCE; } else if (identifier == "transfertoplayernamestate") { node = new NpcBehaviourNode(); node->type = BEHAVIOUR_TYPE_MESSAGE_TRANSFERTOPLAYERNAME_STATE; @@ -1060,11 +1072,58 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl player->setBankBalance(player->getBankBalance() - money); break; } + case BEHAVIOUR_TYPE_GUILDWITHDRAW: { + int32_t money = evaluate(action->expression, player, message); + const Guild* playerGuild = player->getGuild(); + if (!playerGuild) { + break; + } + + if (player->getGuildRank()->level <= 1) { + break; + } + + if (money <= 0) { + break; + } + + + if (IOGuild::getGuildBalance(playerGuild->getId()) < static_cast<uint64_t>(money)) { + break; + } + + if (IOGuild::decreaseGuildBankBalance(playerGuild->getId(), money)) { + player->setBankBalance(player->getBankBalance() + money); + } + + break; + } case BEHAVIOUR_TYPE_DEPOSIT: { int32_t money = evaluate(action->expression, player, message); player->setBankBalance(player->getBankBalance() + money); break; } + case BEHAVIOUR_TYPE_GUILDDEPOSIT: { + int32_t money = evaluate(action->expression, player, message); + const Guild* playerGuild = player->getGuild(); + if (!playerGuild) { + break; + } + + if (money <= 0) { + break; + } + + if (player->getBankBalance() < static_cast<uint64_t>(money)) { + break; + } + + if (IOGuild::increaseGuildBankBalance(playerGuild->getId(), money)) { + player->setBankBalance(player->getBankBalance() - money); + } + + break; + } case BEHAVIOUR_TYPE_TRANSFER: { int32_t money = evaluate(action->expression, player, message); uint16_t state = 0; @@ -1204,6 +1263,14 @@ int32_t BehaviourDatabase::evaluate(NpcBehaviourNode* node, Player* player, cons } case BEHAVIOUR_TYPE_LEVEL: return player->getLevel(); + case BEHAVIOUR_TYPE_GUILDLEVEL: { + const Guild* playerGuild = player->getGuild(); + if (!playerGuild) { + return -1; + } + + return player->getGuildRank()->level; + } case BEHAVIOUR_TYPE_RANDOM: { int32_t min = evaluate(node->left, player, message); int32_t max = evaluate(node->right, player, message); @@ -1254,6 +1321,14 @@ int32_t BehaviourDatabase::evaluate(NpcBehaviourNode* node, Player* player, cons return checkOperation(player, node, message); case BEHAVIOUR_TYPE_BALANCE: return player->getBankBalance(); + case BEHAVIOUR_TYPE_GUILDBALANCE: { + const Guild* playerGuild = player->getGuild(); + if (!playerGuild) { + return false; + } + + return IOGuild::getGuildBalance(playerGuild->getId()); + } case BEHAVIOUR_TYPE_CLIENTVERSION: return g_game.getClientVersion(); case BEHAVIOUR_TYPE_MESSAGE_TRANSFERTOPLAYERNAME_STATE: { diff --git a/src/behaviourdatabase.h b/src/behaviourdatabase.h index 3309694..4630d10 100644 --- a/src/behaviourdatabase.h +++ b/src/behaviourdatabase.h @@ -63,6 +63,7 @@ enum NpcBehaviourType_t BEHAVIOUR_TYPE_SPELLLEVEL, // get spell level BEHAVIOUR_TYPE_TEACHSPELL, // player learn spell BEHAVIOUR_TYPE_LEVEL, // get player level + BEHAVIOUR_TYPE_GUILDLEVEL, // get player guild level BEHAVIOUR_TYPE_RANDOM, // random value BEHAVIOUR_TYPE_QUESTVALUE, // get/set quest value BEHAVIOUR_TYPE_TELEPORT, // teleport player to position @@ -81,8 +82,11 @@ enum NpcBehaviourType_t BEHAVIOUR_TYPE_SUMMON, // summons a monster BEHAVIOUR_TYPE_EXPERIENCE, // grant experience to a player BEHAVIOUR_TYPE_BALANCE, // return player balance + BEHAVIOUR_TYPE_GUILDBALANCE, // return guild balance BEHAVIOUR_TYPE_WITHDRAW, // withdraw from player bank balance + BEHAVIOUR_TYPE_GUILDWITHDRAW, // withdraw from guild bank balance BEHAVIOUR_TYPE_DEPOSIT, // deposit x amount of gold + BEHAVIOUR_TYPE_GUILDDEPOSIT, // deposit x amount of gold to guild BEHAVIOUR_TYPE_TRANSFER, // transfer x amount of gold BEHAVIOUR_TYPE_EXPERIENCESTAGE, // get experience staged based on player level BEHAVIOUR_TYPE_BLESS, // add blessing to player diff --git a/src/chat.cpp b/src/chat.cpp index 59973c8..a046aa9 100644 --- a/src/chat.cpp +++ b/src/chat.cpp @@ -105,6 +105,17 @@ bool ChatChannel::removeUser(const Player& player) return true; } +bool ChatChannel::hasUser(const Player& player) { + return users.find(player.getID()) != users.end(); +} + +void ChatChannel::sendToAll(const std::string& message, SpeakClasses type) const +{ + for (const auto& it : users) { + it.second->sendChannelMessage("", message, type, id); + } +} + bool ChatChannel::talk(const Player& fromPlayer, SpeakClasses type, const std::string& text) { if (users.find(fromPlayer.getID()) == users.end()) { diff --git a/src/chat.h b/src/chat.h index e181142..5a07cfc 100644 --- a/src/chat.h +++ b/src/chat.h @@ -41,8 +41,10 @@ class ChatChannel bool addUser(Player& player); bool removeUser(const Player& player); + bool hasUser(const Player& player); bool talk(const Player& fromPlayer, SpeakClasses type, const std::string& text); + void sendToAll(const std::string& message, SpeakClasses type) const; const std::string& getName() const { return name; diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 088a283..0d16691 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -101,6 +101,8 @@ bool ConfigManager::load() integer[RATE_LOOT] = getGlobalNumber(L, "rateLoot", 2); integer[RATE_MAGIC] = getGlobalNumber(L, "rateMagic", 3); integer[RATE_SPAWN] = getGlobalNumber(L, "rateSpawn", 1); + integer[MIN_RATE_SPAWN] = getGlobalNumber(L, "minRateSpawn", 100); + integer[MAX_RATE_SPAWN] = getGlobalNumber(L, "maxRateSpawn", 200); integer[BAN_LENGTH] = getGlobalNumber(L, "banLength", 30 * 24 * 60 * 60); integer[ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenActions", 200); integer[EX_ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenExActions", 1000); diff --git a/src/configmanager.h b/src/configmanager.h index 1b571ae..3caa4fa 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -87,6 +87,8 @@ class ConfigManager RATE_LOOT, RATE_MAGIC, RATE_SPAWN, + MIN_RATE_SPAWN, + MAX_RATE_SPAWN, BAN_LENGTH, MAX_MESSAGEBUFFER, ACTIONS_DELAY_INTERVAL, diff --git a/src/game.cpp b/src/game.cpp index b75b6a1..90f77f6 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3925,7 +3925,6 @@ LightInfo Game::getWorldLightInfo() const void Game::shutdown() { - saveGameState(); std::cout << "Shutting down..." << std::flush; g_scheduler.shutdown(); diff --git a/src/ioguild.cpp b/src/ioguild.cpp index b4ef9b5..67b91af 100644 --- a/src/ioguild.cpp +++ b/src/ioguild.cpp @@ -39,7 +39,7 @@ uint32_t IOGuild::getGuildIdByName(const std::string& name) void IOGuild::getWarList(uint32_t guildId, GuildWarList& guildWarList) { std::ostringstream query; - query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `ended` = 0 AND `status` = 1"; + query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `status` IN (1, 4)"; DBResult_ptr result = Database::getInstance()->storeQuery(query.str()); if (!result) { @@ -55,3 +55,29 @@ void IOGuild::getWarList(uint32_t guildId, GuildWarList& guildWarList) } } while (result->next()); } + +uint64_t IOGuild::getGuildBalance(uint32_t id) +{ + std::ostringstream query; + query << "SELECT `balance` FROM `guilds` WHERE `id` = " << id; + DBResult_ptr result = Database::getInstance()->storeQuery(query.str()); + if (!result) { + return 0; + } + + return result->getNumber<uint64_t>("balance"); +} + +bool IOGuild::increaseGuildBankBalance(uint32_t guid, uint64_t bankBalance) +{ + std::ostringstream query; + query << "UPDATE `guilds` SET `balance` = `balance` + " << bankBalance << " WHERE `id` = " << guid; + return Database::getInstance()->executeQuery(query.str()); +} + +bool IOGuild::decreaseGuildBankBalance(uint32_t guid, uint64_t bankBalance) +{ + std::ostringstream query; + query << "UPDATE `guilds` SET `balance` = `balance` - " << bankBalance << " WHERE `id` = " << guid; + return Database::getInstance()->executeQuery(query.str()); +} \ No newline at end of file diff --git a/src/ioguild.h b/src/ioguild.h index e5f058c..6414ae5 100644 --- a/src/ioguild.h +++ b/src/ioguild.h @@ -27,6 +27,10 @@ class IOGuild public: static uint32_t getGuildIdByName(const std::string& name); static void getWarList(uint32_t guildId, GuildWarList& guildWarList); + + static uint64_t getGuildBalance(uint32_t id); + static bool increaseGuildBankBalance(uint32_t guid, uint64_t bankBalance); + static bool decreaseGuildBankBalance(uint32_t guid, uint64_t bankBalance); }; #endif diff --git a/src/iologindata.cpp b/src/iologindata.cpp index 8501bd8..ebe3a04 100644 --- a/src/iologindata.cpp +++ b/src/iologindata.cpp @@ -190,7 +190,7 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name) bool IOLoginData::loadPlayerById(Player* player, uint32_t id) { std::ostringstream query; - query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id; + query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id; return loadPlayer(player, Database::getInstance()->storeQuery(query.str())); } @@ -198,7 +198,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; - query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name); + query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name); return loadPlayer(player, db->storeQuery(query.str())); } @@ -321,6 +321,9 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result) player->lastLoginSaved = result->getNumber<time_t>("lastlogin"); player->lastLogout = result->getNumber<time_t>("lastlogout"); + player->offlineTrainingTime = result->getNumber<int32_t>("offlinetraining_time") * 1000; + player->offlineTrainingSkill = result->getNumber<int32_t>("offlinetraining_skill"); + Town* town = g_game.map.towns.getTown(result->getNumber<uint32_t>("town_id")); if (!town) { std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber<uint32_t>("town_id") << " which doesn't exist" << std::endl; @@ -660,6 +663,8 @@ bool IOLoginData::savePlayer(Player* player) query << "`lastlogout` = " << player->getLastLogout() << ','; query << "`balance` = " << player->bankBalance << ','; + query << "`offlinetraining_time` = " << player->getOfflineTrainingTime() / 1000 << ','; + query << "`offlinetraining_skill` = " << player->getOfflineTrainingSkill() << ','; query << "`stamina` = " << player->getStaminaMinutes() << ','; query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ','; diff --git a/src/iomapserialize.cpp b/src/iomapserialize.cpp index a6a5b9d..ef6183f 100644 --- a/src/iomapserialize.cpp +++ b/src/iomapserialize.cpp @@ -99,6 +99,27 @@ bool IOMapSerialize::saveHouseItems() } stream.clear(); } + + static const Direction directions[] = { DIRECTION_EAST, DIRECTION_WEST, DIRECTION_NORTH, DIRECTION_SOUTH }; + for (Direction direction : directions) { + Position position = getNextPosition(direction, tile->getPosition()); + Tile* nextTile = g_game.map.getTile(position); + if (nextTile && nextTile->hasFlag(TILESTATE_BLOCKSOLID) && !nextTile->hasFlag(TILESTATE_PROTECTIONZONE)) { + saveTile(stream, nextTile); + + size_t attributesSize; + const char* attributes = stream.getStream(attributesSize); + if (attributesSize > 0) { + query << house->getId() << ',' << db->escapeBlob(attributes, attributesSize); + if (!stmt.addRow(query)) { + return false; + } + stream.clear(); + } + + nextTile->setFlag(TILESTATE_PROTECTIONZONE); + } + } } } @@ -177,6 +198,9 @@ bool IOMapSerialize::loadItem(PropStream& propStream, Cylinder* parent) } else if (iType.isBed() && findItem->getBed()) { item = findItem; break; + } else if (!iType.moveable && iType.changeUse && findItem->getID() == iType.transformToOnUse) { + item = findItem; + break; } } } @@ -247,7 +271,7 @@ void IOMapSerialize::saveTile(PropWriteStream& stream, const Tile* tile) const ItemType& it = Item::items[item->getID()]; // Note that these are NEGATED, ie. these are the items that will be saved. - if (!(it.moveable || item->getDoor() || (item->getContainer() && !item->getContainer()->empty()) || it.canWriteText || item->getBed())) { + if (!(it.moveable || item->getDoor() || (item->getContainer() && !item->getContainer()->empty()) || it.canWriteText || it.isHangable || item->getBed())) { continue; } diff --git a/src/luascript.cpp b/src/luascript.cpp index 0028383..3927d1d 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -1012,6 +1012,12 @@ void LuaScriptInterface::registerFunctions() //getWaypointPosition(name) lua_register(luaState, "getWaypointPositionByName", LuaScriptInterface::luaGetWaypointPositionByName); + //sendChannelMessage(channelId, type, message) + lua_register(luaState, "sendChannelMessage", LuaScriptInterface::luaSendChannelMessage); + + //sendGuildChannelMessage(guildId, type, message) + lua_register(luaState, "sendGuildChannelMessage", LuaScriptInterface::luaSendGuildChannelMessage); + #ifndef LUAJIT_VERSION //bit operations for Lua, based on bitlib project release 24 //bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshift, bit.rshift @@ -1656,6 +1662,8 @@ void LuaScriptInterface::registerFunctions() registerEnumIn("configKeys", ConfigManager::RATE_LOOT) registerEnumIn("configKeys", ConfigManager::RATE_MAGIC) registerEnumIn("configKeys", ConfigManager::RATE_SPAWN) + registerEnumIn("configKeys", ConfigManager::MIN_RATE_SPAWN) + registerEnumIn("configKeys", ConfigManager::MAX_RATE_SPAWN) registerEnumIn("configKeys", ConfigManager::MAX_MESSAGEBUFFER) registerEnumIn("configKeys", ConfigManager::ACTIONS_DELAY_INTERVAL) registerEnumIn("configKeys", ConfigManager::EX_ACTIONS_DELAY_INTERVAL) @@ -1684,6 +1692,9 @@ void LuaScriptInterface::registerFunctions() registerEnumIn("configKeys", ConfigManager::BLOCK_HEIGHT) registerEnumIn("configKeys", ConfigManager::DROP_ITEMS) registerEnumIn("configKeys", ConfigManager::CLIENT_VERSION) + + // random + registerMethod("os", "rand", LuaScriptInterface::luaRandomRand); // os registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime); @@ -2005,6 +2016,15 @@ void LuaScriptInterface::registerFunctions() registerMethod("Player", "getSkillTries", LuaScriptInterface::luaPlayerGetSkillTries); registerMethod("Player", "addSkillTries", LuaScriptInterface::luaPlayerAddSkillTries); + registerMethod("Player", "addOfflineTrainingTime", LuaScriptInterface::luaPlayerAddOfflineTrainingTime); + registerMethod("Player", "getOfflineTrainingTime", LuaScriptInterface::luaPlayerGetOfflineTrainingTime); + registerMethod("Player", "removeOfflineTrainingTime", LuaScriptInterface::luaPlayerRemoveOfflineTrainingTime); + + registerMethod("Player", "addOfflineTrainingTries", LuaScriptInterface::luaPlayerAddOfflineTrainingTries); + + registerMethod("Player", "getOfflineTrainingSkill", LuaScriptInterface::luaPlayerGetOfflineTrainingSkill); + registerMethod("Player", "setOfflineTrainingSkill", LuaScriptInterface::luaPlayerSetOfflineTrainingSkill); + registerMethod("Player", "getItemCount", LuaScriptInterface::luaPlayerGetItemCount); registerMethod("Player", "getItemById", LuaScriptInterface::luaPlayerGetItemById); @@ -2142,10 +2162,15 @@ void LuaScriptInterface::registerFunctions() registerMethod("Guild", "getId", LuaScriptInterface::luaGuildGetId); registerMethod("Guild", "getName", LuaScriptInterface::luaGuildGetName); registerMethod("Guild", "getMembersOnline", LuaScriptInterface::luaGuildGetMembersOnline); + registerMethod("Guild", "setGuildWarEmblem", LuaScriptInterface::luaGuildSetGuildWarEmblem); registerMethod("Guild", "addRank", LuaScriptInterface::luaGuildAddRank); registerMethod("Guild", "getRankById", LuaScriptInterface::luaGuildGetRankById); registerMethod("Guild", "getRankByLevel", LuaScriptInterface::luaGuildGetRankByLevel); + + registerMethod("Guild", "getBankBalance", LuaScriptInterface::luaGuildGetBankBalance); + registerMethod("Guild", "increaseBankBalance", LuaScriptInterface::luaGuildIncreaseBankBalance); + registerMethod("Guild", "decreaseBankBalance", LuaScriptInterface::luaGuildDecreaseBankBalance); // Group registerClass("Group", "", LuaScriptInterface::luaGroupCreate); @@ -2264,6 +2289,7 @@ void LuaScriptInterface::registerFunctions() registerMethod("ItemType", "getDefense", LuaScriptInterface::luaItemTypeGetDefense); registerMethod("ItemType", "getArmor", LuaScriptInterface::luaItemTypeGetArmor); registerMethod("ItemType", "getWeaponType", LuaScriptInterface::luaItemTypeGetWeaponType); + registerMethod("ItemType", "getAmmoType", LuaScriptInterface::luaItemTypeGetAmmoType); registerMethod("ItemType", "getTransformEquipId", LuaScriptInterface::luaItemTypeGetTransformEquipId); registerMethod("ItemType", "getTransformDeEquipId", LuaScriptInterface::luaItemTypeGetTransformDeEquipId); @@ -2348,6 +2374,7 @@ void LuaScriptInterface::registerFunctions() registerMethod("MonsterType", "getMaxSummons", LuaScriptInterface::luaMonsterTypeGetMaxSummons); registerMethod("MonsterType", "getArmor", LuaScriptInterface::luaMonsterTypeGetArmor); + registerMethod("MonsterType", "getSkill", LuaScriptInterface::luaMonsterTypeGetSkill); registerMethod("MonsterType", "getDefense", LuaScriptInterface::luaMonsterTypeGetDefense); registerMethod("MonsterType", "getOutfit", LuaScriptInterface::luaMonsterTypeGetOutfit); registerMethod("MonsterType", "getRace", LuaScriptInterface::luaMonsterTypeGetRace); @@ -3558,7 +3585,7 @@ int LuaScriptInterface::luaIsInWar(lua_State* L) return 1; } - pushBoolean(L, player->isInWar(targetPlayer)); + lua_pushnumber(L, player->getWarId(targetPlayer)); return 1; } @@ -3576,6 +3603,40 @@ int LuaScriptInterface::luaGetWaypointPositionByName(lua_State* L) return 1; } +int LuaScriptInterface::luaSendChannelMessage(lua_State* L) +{ + //sendChannelMessage(channelId, type, message) + uint32_t channelId = getNumber<uint32_t>(L, 1); + ChatChannel* channel = g_chat->getChannelById(channelId); + if (!channel) { + pushBoolean(L, false); + return 1; + } + + SpeakClasses type = getNumber<SpeakClasses>(L, 2); + std::string message = getString(L, 3); + channel->sendToAll(message, type); + pushBoolean(L, true); + return 1; +} + +int LuaScriptInterface::luaSendGuildChannelMessage(lua_State* L) +{ + //sendGuildChannelMessage(guildId, type, message) + uint32_t guildId = getNumber<uint32_t>(L, 1); + ChatChannel* channel = g_chat->getGuildChannelById(guildId); + if (!channel) { + pushBoolean(L, false); + return 1; + } + + SpeakClasses type = getNumber<SpeakClasses>(L, 2); + std::string message = getString(L, 3); + channel->sendToAll(message, type); + pushBoolean(L, true); + return 1; +} + std::string LuaScriptInterface::escapeString(const std::string& string) { std::string s = string; @@ -3888,6 +3949,14 @@ int LuaScriptInterface::luaRawGetMetatable(lua_State* L) return 1; } +// random +int LuaScriptInterface::luaRandomRand(lua_State* L) +{ + // random.rand() + lua_pushnumber(L, rand()); + return 1; +} + // os int LuaScriptInterface::luaSystemTime(lua_State* L) { @@ -7517,6 +7586,95 @@ int LuaScriptInterface::luaPlayerAddSkillTries(lua_State* L) return 1; } +int LuaScriptInterface::luaPlayerAddOfflineTrainingTime(lua_State* L) +{ + // player:addOfflineTrainingTime(time) + Player* player = getUserdata<Player>(L, 1); + if (player) { + int32_t time = getNumber<int32_t>(L, 2); + player->addOfflineTrainingTime(time); + player->sendStats(); + pushBoolean(L, true); + } + else { + lua_pushnil(L); + } + return 1; +} + + +int LuaScriptInterface::luaPlayerGetOfflineTrainingTime(lua_State* L) +{ + // player:getOfflineTrainingTime() + Player* player = getUserdata<Player>(L, 1); + if (player) { + lua_pushnumber(L, player->getOfflineTrainingTime()); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaPlayerRemoveOfflineTrainingTime(lua_State* L) +{ + // player:removeOfflineTrainingTime(time) + Player* player = getUserdata<Player>(L, 1); + if (player) { + int32_t time = getNumber<int32_t>(L, 2); + player->removeOfflineTrainingTime(time); + player->sendStats(); + pushBoolean(L, true); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaPlayerAddOfflineTrainingTries(lua_State* L) +{ + // player:addOfflineTrainingTries(skillType, tries) + Player* player = getUserdata<Player>(L, 1); + if (player) { + skills_t skillType = getNumber<skills_t>(L, 2); + uint64_t tries = getNumber<uint64_t>(L, 3); + pushBoolean(L, player->addOfflineTrainingTries(skillType, tries)); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaPlayerGetOfflineTrainingSkill(lua_State* L) +{ + // player:getOfflineTrainingSkill() + Player* player = getUserdata<Player>(L, 1); + if (player) { + lua_pushnumber(L, player->getOfflineTrainingSkill()); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaPlayerSetOfflineTrainingSkill(lua_State* L) +{ + // player:setOfflineTrainingSkill(skillId) + Player* player = getUserdata<Player>(L, 1); + if (player) { + uint32_t skillId = getNumber<uint32_t>(L, 2); + player->setOfflineTrainingSkill(skillId); + pushBoolean(L, true); + } + else { + lua_pushnil(L); + } + return 1; +} + int LuaScriptInterface::luaPlayerGetItemCount(lua_State* L) { // player:getItemCount(itemId[, subType = -1]) @@ -9114,6 +9272,44 @@ int LuaScriptInterface::luaGuildGetName(lua_State* L) return 1; } +int LuaScriptInterface::luaGuildSetGuildWarEmblem(lua_State* L) +{ + // guild:setGuildWarEmblem(guild2) + const Guild* guild = getUserdata<const Guild>(L, 1); + if (!guild) { + lua_pushnil(L); + return 1; + } + + const Guild* guild2 = getUserdata<const Guild>(L, 2); + if (!guild2) { + lua_pushnil(L); + return 1; + } + + auto& members = guild->getMembersOnline(); + for (Player* player : members) { + GuildWarList guildWarList; + IOGuild::getWarList(player->getGuild()->getId(), guildWarList); + player->guildWarList = guildWarList; + } + + auto& members2 = guild2->getMembersOnline(); + for (Player* player : members2) { + GuildWarList guildWarList; + IOGuild::getWarList(player->getGuild()->getId(), guildWarList); + player->guildWarList = guildWarList; + g_game.updateCreatureSkull(player); + } + + for (Player* player : members) { + g_game.updateCreatureSkull(player); + } + + pushBoolean(L, true); + return 1; +} + int LuaScriptInterface::luaGuildGetMembersOnline(lua_State* L) { // guild:getMembersOnline() @@ -9195,6 +9391,49 @@ int LuaScriptInterface::luaGuildGetRankByLevel(lua_State* L) return 1; } +int LuaScriptInterface::luaGuildGetBankBalance(lua_State* L) +{ + // guild:getBankBalance() + Guild* guild = getUserdata<Guild>(L, 1); + if (guild) { + lua_pushnumber(L, IOGuild::getGuildBalance(guild->getId())); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaGuildIncreaseBankBalance(lua_State* L) +{ + // guild:increaseBankBalance(amount) + Guild* guild = getUserdata<Guild>(L, 1); + if (guild) { + uint32_t amount = getNumber<uint32_t>(L, 2); + bool isSuccess = IOGuild::increaseGuildBankBalance(guild->getId(), amount); + pushBoolean(L, isSuccess); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaGuildDecreaseBankBalance(lua_State* L) +{ + // guild:decreaseBankBalance(amount) + Guild* guild = getUserdata<Guild>(L, 1); + if (guild) { + uint32_t amount = getNumber<uint32_t>(L, 2); + bool isSuccess = IOGuild::decreaseGuildBankBalance(guild->getId(), amount); + pushBoolean(L, isSuccess); + } + else { + lua_pushnil(L); + } + return 1; +} + // Group int LuaScriptInterface::luaGroupCreate(lua_State* L) { @@ -10327,6 +10566,19 @@ int LuaScriptInterface::luaItemTypeGetWeaponType(lua_State* L) return 1; } +int LuaScriptInterface::luaItemTypeGetAmmoType(lua_State* L) +{ + // itemType:getAmmoType() + const ItemType* itemType = getUserdata<const ItemType>(L, 1); + if (itemType) { + lua_pushnumber(L, itemType->ammoType); + } + else { + lua_pushnil(L); + } + return 1; +} + int LuaScriptInterface::luaItemTypeGetTransformEquipId(lua_State* L) { // itemType:getTransformEquipId() @@ -11225,6 +11477,19 @@ int LuaScriptInterface::luaMonsterTypeGetArmor(lua_State* L) return 1; } +int LuaScriptInterface::luaMonsterTypeGetSkill(lua_State* L) +{ + // monsterType:getSkill() + MonsterType* monsterType = getUserdata<MonsterType>(L, 1); + if (monsterType) { + lua_pushnumber(L, monsterType->info.skill); + } + else { + lua_pushnil(L); + } + return 1; +} + int LuaScriptInterface::luaMonsterTypeGetDefense(lua_State* L) { // monsterType:getDefense() diff --git a/src/luascript.h b/src/luascript.h index 22157a1..7fad48b 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -485,6 +485,9 @@ class LuaScriptInterface static int luaGetWaypointPositionByName(lua_State* L); + static int luaSendChannelMessage(lua_State* L); + static int luaSendGuildChannelMessage(lua_State* L); + #ifndef LUAJIT_VERSION static int luaBitNot(lua_State* L); static int luaBitAnd(lua_State* L); @@ -520,6 +523,9 @@ class LuaScriptInterface static int luaIsType(lua_State* L); static int luaRawGetMetatable(lua_State* L); + // random + static int luaRandomRand(lua_State* L); + // os static int luaSystemTime(lua_State* L); @@ -830,6 +836,15 @@ class LuaScriptInterface static int luaPlayerGetSkillTries(lua_State* L); static int luaPlayerAddSkillTries(lua_State* L); + static int luaPlayerAddOfflineTrainingTime(lua_State* L); + static int luaPlayerGetOfflineTrainingTime(lua_State* L); + static int luaPlayerRemoveOfflineTrainingTime(lua_State* L); + + static int luaPlayerAddOfflineTrainingTries(lua_State* L); + + static int luaPlayerGetOfflineTrainingSkill(lua_State* L); + static int luaPlayerSetOfflineTrainingSkill(lua_State* L); + static int luaPlayerGetItemCount(lua_State* L); static int luaPlayerGetItemById(lua_State* L); @@ -965,11 +980,16 @@ class LuaScriptInterface static int luaGuildGetId(lua_State* L); static int luaGuildGetName(lua_State* L); static int luaGuildGetMembersOnline(lua_State* L); + static int luaGuildSetGuildWarEmblem(lua_State* L); static int luaGuildAddRank(lua_State* L); static int luaGuildGetRankById(lua_State* L); static int luaGuildGetRankByLevel(lua_State* L); + static int luaGuildGetBankBalance(lua_State* L); + static int luaGuildIncreaseBankBalance(lua_State* L); + static int luaGuildDecreaseBankBalance(lua_State* L); + // Group static int luaGroupCreate(lua_State* L); @@ -1081,6 +1101,7 @@ class LuaScriptInterface static int luaItemTypeGetDefense(lua_State* L); static int luaItemTypeGetArmor(lua_State* L); static int luaItemTypeGetWeaponType(lua_State* L); + static int luaItemTypeGetAmmoType(lua_State* L); static int luaItemTypeGetTransformEquipId(lua_State* L); static int luaItemTypeGetTransformDeEquipId(lua_State* L); @@ -1161,6 +1182,7 @@ class LuaScriptInterface static int luaMonsterTypeGetMaxSummons(lua_State* L); static int luaMonsterTypeGetArmor(lua_State* L); + static int luaMonsterTypeGetSkill(lua_State* L); static int luaMonsterTypeGetDefense(lua_State* L); static int luaMonsterTypeGetOutfit(lua_State* L); static int luaMonsterTypeGetRace(lua_State* L); diff --git a/src/networkmessage.cpp b/src/networkmessage.cpp index 6ad238f..e503be0 100644 --- a/src/networkmessage.cpp +++ b/src/networkmessage.cpp @@ -95,7 +95,7 @@ void NetworkMessage::addPosition(const Position& pos) addByte(pos.z); } -void NetworkMessage::addItem(uint16_t id, uint8_t count) +void NetworkMessage::addItem(uint16_t id, uint8_t count, bool textWindow /* = false*/) { const ItemType& it = Item::items[id]; @@ -105,14 +105,17 @@ void NetworkMessage::addItem(uint16_t id, uint8_t count) add<uint16_t>(it.id); } - if (it.stackable || it.isRune()) { - addByte(count); - } else if (it.isSplash() || it.isFluidContainer()) { - addByte(getLiquidColor(count)); + if (!textWindow) { + if (it.stackable || it.isRune()) { + addByte(count); + } + else if (it.isSplash() || it.isFluidContainer()) { + addByte(getLiquidColor(count)); + } } } -void NetworkMessage::addItem(const Item* item) +void NetworkMessage::addItem(const Item* item, bool textWindow /* = false*/) { const ItemType& it = Item::items[item->getID()]; @@ -122,12 +125,16 @@ void NetworkMessage::addItem(const Item* item) add<uint16_t>(it.id); } - if (it.stackable) { - addByte(std::min<uint16_t>(0xFF, item->getItemCount())); - } else if (it.isRune()) { - addByte(std::min<uint16_t>(0xFF, item->getCharges())); - } else if (it.isSplash() || it.isFluidContainer()) { - addByte(getLiquidColor(item->getFluidType())); + if (!textWindow) { + if (it.stackable) { + addByte(std::min<uint16_t>(0xFF, item->getItemCount())); + } + else if (it.isRune()) { + addByte(std::min<uint16_t>(0xFF, item->getCharges())); + } + else if (it.isSplash() || it.isFluidContainer()) { + addByte(getLiquidColor(item->getFluidType())); + } } } diff --git a/src/networkmessage.h b/src/networkmessage.h index 7d11153..9ced1bb 100644 --- a/src/networkmessage.h +++ b/src/networkmessage.h @@ -110,8 +110,8 @@ class NetworkMessage // write functions for complex types void addPosition(const Position& pos); - void addItem(uint16_t id, uint8_t count); - void addItem(const Item* item); + void addItem(uint16_t id, uint8_t count, bool textWindow = false); + void addItem(const Item* item, bool textWindow = false); void addItemId(uint16_t itemId); MsgSize_t getLength() const { diff --git a/src/player.cpp b/src/player.cpp index 96ac98b..6e6afcd 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1194,6 +1194,8 @@ void Player::onThink(uint32_t interval) if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) { checkSkullTicks(); } + + addOfflineTrainingTime(interval); } uint32_t Player::isMuted() const @@ -3445,10 +3447,6 @@ Skulls_t Player::getSkullClient(const Creature* creature) const return SKULL_GREEN; } - if (!player->getGuildWarList().empty() && guild == player->getGuild()) { - return SKULL_GREEN; - } - if (player->hasAttacked(this)) { return SKULL_YELLOW; } @@ -3612,6 +3610,33 @@ bool Player::hasLearnedInstantSpell(const std::string& spellName) const return false; } +uint32_t Player::getWarId(const Player* targetPlayer) const +{ + if (!targetPlayer || !guild) { + return false; + } + + const Guild* targetPlayerGuild = targetPlayer->getGuild(); + if (!targetPlayerGuild) { + return false; + } + + const auto targetGuild = guild->getId(); + const auto killerGuild = targetPlayerGuild->getId(); + + Database* db = Database::getInstance(); + + std::ostringstream query; + query << "SELECT `id` FROM `guild_wars` WHERE `status` IN (1, 4) AND ((`guild1` = " << killerGuild << " AND `guild2` = " << targetGuild << ") OR (`guild1` = " << targetGuild << " AND `guild2` = " << killerGuild << "))"; + DBResult_ptr result = db->storeQuery(query.str()); + + if (!result) { + return 0; + } + + return result->getNumber<uint32_t>("id"); +} + bool Player::isInWar(const Player* player) const { if (!player || !guild) { @@ -3737,6 +3762,141 @@ void Player::sendClosePrivate(uint16_t channelId) } } +bool Player::addOfflineTrainingTries(skills_t skill, uint64_t tries) +{ + if (tries == 0 || skill == SKILL_LEVEL) { + return false; + } + + bool sendUpdate = false; + uint32_t oldSkillValue, newSkillValue; + long double oldPercentToNextLevel, newPercentToNextLevel; + + if (skill == SKILL_MAGLEVEL) { + uint64_t currReqMana = vocation->getReqMana(magLevel); + uint64_t nextReqMana = vocation->getReqMana(magLevel + 1); + + if (currReqMana >= nextReqMana) { + return false; + } + + oldSkillValue = magLevel; + oldPercentToNextLevel = static_cast<long double>(manaSpent * 100) / nextReqMana; + + g_events->eventPlayerOnGainSkillTries(this, SKILL_MAGLEVEL, tries); + uint32_t currMagLevel = magLevel; + + while ((manaSpent + tries) >= nextReqMana) { + tries -= nextReqMana - manaSpent; + + magLevel++; + manaSpent = 0; + + g_creatureEvents->playerAdvance(this, SKILL_MAGLEVEL, magLevel - 1, magLevel); + + sendUpdate = true; + currReqMana = nextReqMana; + nextReqMana = vocation->getReqMana(magLevel + 1); + + if (currReqMana >= nextReqMana) { + tries = 0; + break; + } + } + + manaSpent += tries; + + if (magLevel != currMagLevel) { + std::ostringstream ss; + ss << "You advanced to magic level " << magLevel << '.'; + sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str()); + } + + uint8_t newPercent; + if (nextReqMana > currReqMana) { + newPercent = Player::getPercentLevel(manaSpent, nextReqMana); + newPercentToNextLevel = static_cast<long double>(manaSpent * 100) / nextReqMana; + } + else { + newPercent = 0; + newPercentToNextLevel = 0; + } + + if (newPercent != magLevelPercent) { + magLevelPercent = newPercent; + sendUpdate = true; + } + + newSkillValue = magLevel; + } + else { + uint64_t currReqTries = vocation->getReqSkillTries(skill, skills[skill].level); + uint64_t nextReqTries = vocation->getReqSkillTries(skill, skills[skill].level + 1); + if (currReqTries >= nextReqTries) { + return false; + } + + oldSkillValue = skills[skill].level; + oldPercentToNextLevel = static_cast<long double>(skills[skill].tries * 100) / nextReqTries; + + g_events->eventPlayerOnGainSkillTries(this, skill, tries); + uint32_t currSkillLevel = skills[skill].level; + + while ((skills[skill].tries + tries) >= nextReqTries) { + tries -= nextReqTries - skills[skill].tries; + + skills[skill].level++; + skills[skill].tries = 0; + skills[skill].percent = 0; + + g_creatureEvents->playerAdvance(this, skill, (skills[skill].level - 1), skills[skill].level); + + sendUpdate = true; + currReqTries = nextReqTries; + nextReqTries = vocation->getReqSkillTries(skill, skills[skill].level + 1); + + if (currReqTries >= nextReqTries) { + tries = 0; + break; + } + } + + skills[skill].tries += tries; + + if (currSkillLevel != skills[skill].level) { + std::ostringstream ss; + ss << "You advanced to " << getSkillName(skill) << " level " << skills[skill].level << '.'; + sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str()); + } + + uint8_t newPercent; + if (nextReqTries > currReqTries) { + newPercent = Player::getPercentLevel(skills[skill].tries, nextReqTries); + newPercentToNextLevel = static_cast<long double>(skills[skill].tries * 100) / nextReqTries; + } + else { + newPercent = 0; + newPercentToNextLevel = 0; + } + + if (skills[skill].percent != newPercent) { + skills[skill].percent = newPercent; + sendUpdate = true; + } + + newSkillValue = skills[skill].level; + } + + if (sendUpdate) { + sendSkills(); + } + + std::ostringstream ss; + ss << std::fixed << std::setprecision(2) << "Your " << ucwords(getSkillName(skill)) << " skill changed from level " << oldSkillValue << " (with " << oldPercentToNextLevel << "% progress towards level " << (oldSkillValue + 1) << ") to level " << newSkillValue << " (with " << newPercentToNextLevel << "% progress towards level " << (newSkillValue + 1) << ')'; + sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str()); + return sendUpdate; +} + uint64_t Player::getMoney() const { std::vector<const Container*> containers; diff --git a/src/player.h b/src/player.h index 15703a4..10a40bb 100644 --- a/src/player.h +++ b/src/player.h @@ -154,6 +154,25 @@ class Player final : public Creature, public Cylinder return staminaMinutes; } + bool addOfflineTrainingTries(skills_t skill, uint64_t tries); + + void addOfflineTrainingTime(int32_t addTime) { + offlineTrainingTime = std::min<int32_t>(12 * 3600 * 1000, offlineTrainingTime + addTime); + } + void removeOfflineTrainingTime(int32_t removeTime) { + offlineTrainingTime = std::max<int32_t>(0, offlineTrainingTime - removeTime); + } + int32_t getOfflineTrainingTime() const { + return offlineTrainingTime; + } + + int32_t getOfflineTrainingSkill() const { + return offlineTrainingSkill; + } + void setOfflineTrainingSkill(int32_t skill) { + offlineTrainingSkill = skill; + } + uint64_t getBankBalance() const { return bankBalance; } @@ -182,6 +201,7 @@ class Player final : public Creature, public Cylinder guildNick = nick; } + uint32_t getWarId(const Player* player) const; bool isInWar(const Player* player) const; bool isInWarList(uint32_t guild_id) const; @@ -619,6 +639,11 @@ class Player final : public Creature, public Cylinder } } + void sendChannelMessage(const std::string& author, const std::string& text, SpeakClasses type, uint16_t channel) { + if (client) { + client->sendChannelMessage(author, text, type, channel); + } + } void sendCreatureAppear(const Creature* creature, const Position& pos, bool isLogin) { if (client) { client->sendAddCreature(creature, pos, creature->getTile()->getStackposOfCreature(this, creature), isLogin); @@ -1069,6 +1094,8 @@ class Player final : public Creature, public Cylinder int32_t premiumDays = 0; int32_t bloodHitCount = 0; int32_t shieldBlockCount = 0; + int32_t offlineTrainingSkill = -1; + int32_t offlineTrainingTime = 0; int32_t idleTime = 0; int32_t lastWalkingTime = 0; diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index 42c71f8..d0a4a23 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -1176,6 +1176,18 @@ void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelNam 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) { @@ -1755,7 +1767,7 @@ void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t ma NetworkMessage msg; msg.addByte(0x96); msg.add<uint32_t>(windowTextId); - msg.addItem(item); + msg.addItem(item, true); if (canWrite) { msg.add<uint16_t>(maxlen); @@ -1791,7 +1803,7 @@ void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const NetworkMessage msg; msg.addByte(0x96); msg.add<uint32_t>(windowTextId); - msg.addItem(itemId, 1); + msg.addItem(itemId, 1, true); msg.add<uint16_t>(text.size()); msg.addString(text); msg.add<uint16_t>(0x00); diff --git a/src/protocolgame.h b/src/protocolgame.h index c581a5e..1d5f637 100644 --- a/src/protocolgame.h +++ b/src/protocolgame.h @@ -140,6 +140,7 @@ class ProtocolGame final : public Protocol void parseCloseChannel(NetworkMessage& msg); //Send functions + void sendChannelMessage(const std::string& author, const std::string& text, SpeakClasses type, uint16_t channel); void sendClosePrivate(uint16_t channelId); void sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName); void sendChannelsDialog(); diff --git a/src/spawn.cpp b/src/spawn.cpp index 0de9026..26350aa 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -89,7 +89,7 @@ bool Spawns::loadFromXml(const std::string& filename) spawnList.emplace_front(pos, radius); Spawn& spawn = spawnList.front(); - uint32_t interval = uniform_random(pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 250, pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 500); + uint32_t interval = uniform_random(pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * g_config.getNumber(ConfigManager::MIN_RATE_SPAWN), pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * g_config.getNumber(ConfigManager::MAX_RATE_SPAWN)); if (interval > MINSPAWN_INTERVAL) { uint32_t exInterval = g_config.getNumber(ConfigManager::RATE_SPAWN); if (exInterval) { diff --git a/src/tile.cpp b/src/tile.cpp index 6240678..2c16f6a 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -521,6 +521,20 @@ ReturnValue Tile::queryAdd(int32_t, const Thing& thing, uint32_t, uint32_t flags } } + if (monster->hasCondition(CONDITION_AGGRESSIVE) && !monster->canPushItems()) { + if (hasFlag(TILESTATE_FIREDAMAGE) && !monster->isImmune(COMBAT_FIREDAMAGE)) { + return RETURNVALUE_NOTPOSSIBLE; + } + + if (hasFlag(TILESTATE_POISONDAMAGE) && !monster->isImmune(COMBAT_EARTHDAMAGE)) { + return RETURNVALUE_NOTPOSSIBLE; + } + + if (hasFlag(TILESTATE_ENERGYDAMAGE) && !monster->isImmune(COMBAT_ENERGYDAMAGE)) { + return RETURNVALUE_NOTPOSSIBLE; + } + } + if (!monster->hasCondition(CONDITION_AGGRESSIVE) && !hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags)) { if (hasFlag(TILESTATE_FIREDAMAGE) && !monster->isImmune(COMBAT_FIREDAMAGE)) { diff --git a/src/vocation.cpp b/src/vocation.cpp index 98a9973..1732fc5 100644 --- a/src/vocation.cpp +++ b/src/vocation.cpp @@ -187,7 +187,7 @@ uint64_t Vocation::getReqMana(uint32_t magLevel) return it->second; } - uint64_t reqMana = static_cast<uint64_t>(400 * std::pow<double>(manaMultiplier, static_cast<int32_t>(magLevel) - 1)); + uint64_t reqMana = static_cast<uint64_t>(1600 * std::pow<double>(manaMultiplier, static_cast<int32_t>(magLevel) - 1)); uint32_t modResult = reqMana % 20; if (modResult < 10) { reqMana -= modResult;