409 lines
19 KiB
Lua
409 lines
19 KiB
Lua
--[[
|
||
Illarion Server
|
||
|
||
This program is free software: you can redistribute it and/or modify it under
|
||
the terms of the GNU Affero General Public License as published by the Free
|
||
Software Foundation, either version 3 of the License, or (at your option) any
|
||
later version.
|
||
|
||
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||
PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||
details.
|
||
|
||
You should have received a copy of the GNU Affero General Public License along
|
||
with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
]]
|
||
|
||
local common = require("base.common")
|
||
local lookat = require("base.lookat")
|
||
local tutorial = require("content.tutorial")
|
||
|
||
local M = {}
|
||
|
||
local DEFAULT_WEAR = 60 -- default duration of 3 hours, 177-180 minutes based on when in the current cycle it was lit.
|
||
|
||
local LightsOff = {}
|
||
local LightsOn = {}
|
||
-- torch
|
||
LightsOff[Item.torch] = { on = 392 }
|
||
LightsOn[392] = { off = Item.torch, portable = true }
|
||
-- torch holder
|
||
LightsOff[401] = { on = 402, req = { id = 392, alternative = Item.torch, num = 1 } } -- facing south
|
||
LightsOn[402] = { off = 401}
|
||
LightsOff[403] = { on = 404, req = { id = 392, alternative = Item.torch, num = 1 } } -- facing west
|
||
LightsOn[404] = { off = 403}
|
||
-- candles
|
||
LightsOff[2853] = { on = 2851, req = { id = Item.candles, num = 3 } } -- facing south
|
||
LightsOn[2851] = { off = 2853 }
|
||
LightsOff[2854] = { on = 2852, req = { id = Item.candles, num = 3 } } -- facing west
|
||
LightsOn[2852] = { off = 2854 }
|
||
LightsOff[5232] = { on = 5233, req = { id = Item.candles, num = 3 } }
|
||
LightsOn[5233] = { off = 5232 }
|
||
-- candle
|
||
LightsOff[399] = { on = 400, req = { id = Item.candles, num = 1 } }
|
||
LightsOn[400] = { off = 399, portable = true }
|
||
-- oil lamp
|
||
LightsOff[92] = { on = 397, req = { id = Item.lampOil, num = 1, remnant = 390} }
|
||
LightsOn[397] = { off = 92, portable = true }
|
||
-- oil lamp holder
|
||
LightsOff[395] = { on = 396, req = { id = Item.lampOil, num = 1, remnant = 390 } }
|
||
LightsOn[396] = { off = 395 }
|
||
-- lantern
|
||
LightsOff[393] = { on = 394, req = { id = Item.candles, num = 1 } } -- black, portable
|
||
LightsOn[394] = { off = 393, portable = true }
|
||
LightsOff[2856] = { on = 2855, req = { id = Item.candles, num = 1 } } -- grey, static
|
||
LightsOn[2855] = { off = 2856 }
|
||
LightsOff[1127] = { on = 1123, req = {id = Item.candles, num = 1} } -- wall lantern
|
||
LightsOff[1123] = { off = 1127 }
|
||
LightsOff[1129] = { on = 1124, req = {id = Item.candles, num = 1} } -- wall lantern
|
||
LightsOff[1124] = { off = 1129 }
|
||
LightsOff[1128] = { on = 1125, req = {id = Item.candles, num = 1} } -- wall lantern
|
||
LightsOff[1125] = { off = 1128 }
|
||
LightsOff[1130] = { on = 1126, req = {id = Item.candles, num = 1} } -- wall lantern
|
||
LightsOff[1126] = { off = 1130 }
|
||
-- chandelier
|
||
LightsOff[Item.chandelierUnlit] = { on = Item.chandelier, req = {id = Item.candles, num = 10}}
|
||
LightsOn[Item.chandelier] = {off = Item.chandelierUnlit}
|
||
|
||
local ReqTexts = {}
|
||
ReqTexts.german = { [392] = "Fackeln", [Item.candles] = "Kerzen", [Item.lampOil] = "Lampen<EFBFBD>l" }
|
||
ReqTexts.english = { [392] = "torches", [Item.candles] = "candles", [Item.lampOil] = "lamp oil" }
|
||
|
||
|
||
local function lightTheItem(theItem, newWear)
|
||
|
||
theItem.id = LightsOff[theItem.id].on
|
||
theItem.wear = newWear
|
||
world:changeItem(theItem)
|
||
end
|
||
|
||
local function passesCheckForStackSizeAndPosition(user, sourceItem)
|
||
|
||
if sourceItem.id == Item.torch and sourceItem:getType() ~= scriptItem.inventory then
|
||
common.InformNLS(user,
|
||
"Nimm die Lichtquelle in die Hand.",
|
||
"Take the light source into your hand.")
|
||
return false
|
||
end
|
||
if sourceItem:getType() == scriptItem.container then
|
||
common.InformNLS(user,
|
||
"Nimm die Lichtquelle in die Hand oder lege sie am G<>rtel ab.",
|
||
"Take the light source into your hand or put it on your belt.")
|
||
return false
|
||
end
|
||
|
||
if sourceItem.number > 1 then
|
||
user:inform("Du kannst immer nur eine Lichtquelle auf einmal anz<6E>nden. Um einen Stapel aufzuteilen, halte die Umschalttaste, w<>hrend du den Stapel auf ein freies Inventarfeld ziehst.",
|
||
"You can only light up one light source at once. To split a stack, hold shift while dragging the item stack to a free inventory slot.")
|
||
return false
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
local function checkIfRequirementsAreMetAndConsumeUnlitItem(user, unlitItem, sourceItem)
|
||
|
||
local litTorch = false
|
||
local rareness
|
||
|
||
if unlitItem.req then
|
||
-- there's a requirement, check on body and belt
|
||
|
||
local alternative = unlitItem.req.alternative
|
||
|
||
local hasEnoughAlternativeItem = false
|
||
|
||
if alternative then
|
||
hasEnoughAlternativeItem = user:countItemAt("body", alternative) + user:countItemAt("belt", alternative) >= unlitItem.req.num
|
||
end
|
||
|
||
local hasEnoughOfRequiredItem = user:countItemAt("body", unlitItem.req.id) + user:countItemAt("belt", unlitItem.req.id) >= unlitItem.req.num
|
||
|
||
for i = 1, 3 do
|
||
local alternateCheck
|
||
if alternative then
|
||
alternateCheck = user:countItemAt("body", alternative, {["rareness"] = i+1}) + user:countItemAt("belt", alternative, {["rareness"] = i+1}) >= unlitItem.req.num
|
||
end
|
||
local requiredCheck = user:countItemAt("body", unlitItem.req.id, {["rareness"] = i+1}) + user:countItemAt("belt", unlitItem.req.id, {["rareness"] = i+1}) >= unlitItem.req.num
|
||
if alternateCheck then
|
||
rareness = i+1
|
||
hasEnoughAlternativeItem = true
|
||
end
|
||
|
||
if requiredCheck then
|
||
hasEnoughOfRequiredItem = true
|
||
rareness = i+1
|
||
end
|
||
end
|
||
|
||
local itemToTake = unlitItem.req.id
|
||
|
||
if not hasEnoughOfRequiredItem and hasEnoughAlternativeItem then
|
||
itemToTake = alternative
|
||
end
|
||
|
||
if hasEnoughOfRequiredItem or hasEnoughAlternativeItem then
|
||
local myItem
|
||
local itemRest = unlitItem.req.num
|
||
for i=1,17 do
|
||
myItem = user:getItemAt( i )
|
||
if ( myItem.id == itemToTake ) and ((rareness and myItem:getData("rareness") == tostring(rareness)) or not rareness) then
|
||
|
||
world:erase( myItem, math.min( itemRest, myItem.number ) )
|
||
|
||
if itemToTake == 392 then
|
||
litTorch = myItem.wear
|
||
end
|
||
itemRest = itemRest - math.min( itemRest, myItem.number )
|
||
if itemRest == 0 then
|
||
break
|
||
end
|
||
end
|
||
end
|
||
if unlitItem.req.remnant then
|
||
common.CreateItem(user, unlitItem.req.remnant, unlitItem.req.num, 333, nil)
|
||
end
|
||
else
|
||
return false, litTorch, rareness
|
||
end
|
||
elseif not common.IsNilOrEmpty(sourceItem:getData("rareness")) then
|
||
rareness = tonumber(sourceItem:getData("rareness"))
|
||
end
|
||
|
||
return true, litTorch, rareness
|
||
end
|
||
|
||
local function handleUsageQuests(user, sourceItem) -- returns true if the quest handles the lighting process
|
||
--Tutorial Quest 330: Lighting a torch with NPC Henry Cunnigan
|
||
if user:getQuestProgress(330) == 2 and sourceItem.id == Item.torch and user:isInRangeToPosition((position (703,290,0)),20) then -- Only invoked if the user has the quest, has a torch and is in range of the NPC
|
||
user:setQuestProgress(330,3) -- Quest advanced when torch lit
|
||
common.InformNLS(user, tutorial.getTutorialInformDE("lights"), tutorial.getTutorialInformEN("lights"))
|
||
local Henry = common.getNpc(position(703,290,0),1,"Henry Cunnigan")
|
||
common.TalkNLS(Henry, Character.say, tutorial.getTutorialTalkDE("lights"), tutorial.getTutorialTalkEN("lights"))
|
||
return false
|
||
end
|
||
|
||
--Quest 105: NPC Gregor Remethar "A light at the end of the tunnel"
|
||
if sourceItem.id == 395 and (sourceItem.pos == position (873, 796, -3) or sourceItem.pos == position (873, 798, -3) ) and user:getQuestProgress(105) == 1 then
|
||
common.InformNLS(user, "[Queststatus] Du entfachst die Ehrenfeuer von Runewick. Kehre zu Gregor Remethar zur<75>ck, um deine Belohnung einzufordern.", "[Quest status] You lit the lights of honour of Runewick. Return to Gregor Remethar to claim your reward.")
|
||
user:setQuestProgress(105,2)
|
||
lightTheItem(sourceItem, math.random(20,60)) --these lights burn quite long
|
||
return true
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
local function deleteParchmentsInHands(user, german, english, portable, sourceItem)
|
||
|
||
local leftHand = user:getItemAt(Character.left_tool)
|
||
local rightHand = user:getItemAt(Character.right_tool)
|
||
|
||
local burnt = false
|
||
|
||
local plural = false
|
||
|
||
if portable and not common.hasItemIdInHand(user, sourceItem.id) then
|
||
user:inform("Die "..german.." muss sich in deiner Hand befinden, damit du ein Pergament verbrennen kannst.", "The "..english.." must remain in your hands if you want to burn a parchment.")
|
||
return
|
||
end
|
||
|
||
|
||
if rightHand.id == Item.parchment then
|
||
world:erase(rightHand, rightHand.number)
|
||
burnt = true
|
||
if rightHand.number > 1 then
|
||
plural = true
|
||
end
|
||
end
|
||
|
||
if leftHand.id == Item.parchment then
|
||
world:erase(leftHand, leftHand.number)
|
||
|
||
if burnt or leftHand.number > 1 then
|
||
plural = true
|
||
end
|
||
|
||
burnt = true
|
||
end
|
||
|
||
local parchmentsEn = plural and "parchments" or "parchment"
|
||
local parchmentsDe = plural and "die Pergamente" or "das Pergament"
|
||
local pluralWasWhere = plural and "were" or "was"
|
||
local pluralWelcheWelchesDe = plural and "welche" or "welches"
|
||
local pluralBefandenBefandDe = plural and "befanden" or "befand"
|
||
|
||
if burnt then
|
||
user:inform("Du hast die "..german.." verwendet, um "..parchmentsDe.." zu verbrennen, "..pluralWelcheWelchesDe.." sich in deiner Hand "..pluralBefandenBefandDe..".", "You used the "..english.." to burn the "..parchmentsEn.." that "..pluralWasWhere.." in your hands.")
|
||
else
|
||
user:inform("In deinen H<>nden sind keine Pergamente. Hast du sie etwa verloren?", "No parchments were found in your hands. Did you lose them somewhere?")
|
||
end
|
||
|
||
end
|
||
|
||
local function burnParchmentConfirmation(user, german, english, portable, sourceItem)
|
||
local callback = function(dialog)
|
||
|
||
if not dialog:getSuccess() then
|
||
return
|
||
end
|
||
|
||
local selected = dialog:getSelectedIndex()+1
|
||
|
||
if selected == 1 then
|
||
deleteParchmentsInHands(user, german, english, portable, sourceItem)
|
||
else
|
||
return
|
||
end
|
||
end
|
||
|
||
local dialog = SelectionDialog(common.GetNLS(user,"Best<EFBFBD>tigung","Confirmation Check"), common.GetNLS(user,"Bist du sicher, dass du die Pergamente in deinen H<>nden verbrennen willst? Dies kann nicht r<>ckg<6B>ngig gemacht werden und wird alle Pergamente in deinen Handpl<70>tzen dauerhaft zerst<73>ren.", "Are you sure you want to burn the parchment(s) in your hands? This can not be undone and will permanently delete any parchments in your hand slots."), callback)
|
||
dialog:addOption(0,common.GetNLS(user,"Ja","Yes"))
|
||
dialog:addOption(0,common.GetNLS(user,"Nein, das ist Kunst.","No, I changed my mind."))
|
||
dialog:setCloseOnMove()
|
||
user:requestSelectionDialog(dialog)
|
||
end
|
||
|
||
function M.UseItem(user, sourceItem)
|
||
|
||
if sourceItem.id == Item.candles then
|
||
return
|
||
end
|
||
|
||
if not passesCheckForStackSizeAndPosition(user, sourceItem) then
|
||
return
|
||
end
|
||
|
||
local unlitItem = LightsOff[sourceItem.id]
|
||
local litItem = LightsOn[sourceItem.id]
|
||
|
||
if unlitItem then
|
||
local requirementsMet, litTorch, rareness = checkIfRequirementsAreMetAndConsumeUnlitItem(user, unlitItem, sourceItem)
|
||
if requirementsMet then
|
||
if not handleUsageQuests(user, sourceItem) then
|
||
-- no quests that already lit the item, proceeding with default
|
||
local wear = DEFAULT_WEAR
|
||
|
||
if rareness then
|
||
wear = wear + (rareness-1)*20 -- an hour extra wear per rarity
|
||
end
|
||
|
||
if litTorch then -- A lit torch will already have accounted for rareness and may have less wear remaining
|
||
wear = litTorch
|
||
end
|
||
|
||
lightTheItem(sourceItem, wear)
|
||
end
|
||
elseif unlitItem.req then
|
||
local number = ""
|
||
if unlitItem.req.num > 1 then
|
||
number = tostring(unlitItem.req.num).." "
|
||
end
|
||
|
||
common.InformNLS(user,
|
||
"Daf<EFBFBD>r brauchst du "..number.. ReqTexts.german[unlitItem.req.id] .. " in der Hand oder im G<>rtel.",
|
||
"You need "..number.. ReqTexts.english[unlitItem.req.id] .. " in your belt or hands to do that.")
|
||
end
|
||
elseif litItem then
|
||
if common.hasItemIdInHand(user, Item.parchment) then
|
||
local commonItem = world:getItemStatsFromId(sourceItem.id)
|
||
if litItem.portable and not common.IsItemInHands(sourceItem) then
|
||
user:inform("Um diese "..commonItem.German.." zum Verbrennen von Pergamenten zu verwenden, musst du sie in der Hand halten.", "To use this "..commonItem.English.." to burn a parchment, you must hold both in your hands.")
|
||
else
|
||
burnParchmentConfirmation(user, commonItem.German, commonItem.English, litItem.portable, sourceItem)
|
||
end
|
||
else
|
||
common.InformNLS(user,"Du verbrennst dir die Finger beim Versuch, das Feuer zu ersticken.","You burn your fingers while trying to extinguish the flames.")
|
||
end
|
||
end
|
||
end
|
||
|
||
function M.MoveItemAfterMove(user, itemBefore, itemAfter)
|
||
|
||
-- Quest 305: we burn a tobacco plantation
|
||
if user:getQuestProgress(305) == 2 then
|
||
if (itemAfter.pos.x >= 3) and (itemAfter.pos.x <= 6) and (itemAfter.pos.y >= 565) and (itemAfter.pos.y <= 571) and (itemAfter.pos.z <= 0) then
|
||
if LightsOn[itemBefore.id] then
|
||
local spawnFire = function(posi)
|
||
world:createItemFromId(359,1,posi,true,333,nil)
|
||
end
|
||
world:makeSound(7,position(5,568,0))
|
||
world:createItemFromId(359,1,position(5,568,0),true,333,nil)
|
||
common.CreateCircle(position(5,568,0), 1, spawnFire)
|
||
common.CreateCircle(position(5,568,0), 2, spawnFire)
|
||
user:setQuestProgress(305,3)
|
||
user:inform("Du hast das Tabakfeld zerst<73>rt. Gut gemacht. Spreche nun mit Tobis Vunu.","You destroyed the tobacco field. Well done. Talk to Tobis Vunu now.")
|
||
else
|
||
user:inform("Du kannst das Feld vermutlich mit brennenden Dingen besser abfackeln.","It's much easier to burn down a field if you are using fire.")
|
||
end
|
||
end
|
||
end
|
||
|
||
--Tutorial Quest 330: Equipping a torch with NPC Henry Cunnigan
|
||
if user:getQuestProgress(330)==1 and itemAfter.id==Item.torch and user:isInRangeToPosition((position (703,290,0)),20) and itemAfter:getType() == 4 then -- Only invoked if the user has the quest, has a torch and is in range of the NPC
|
||
user:setQuestProgress(330,2) --Quest advancement when torch equipped
|
||
local NPCList=world:getNPCSInRangeOf(position(703,290,0),1) --Let's be tolerant, the NPC might move a tile.
|
||
common.InformNLS(user, tutorial.getTutorialInformDE("lightsStart"), tutorial.getTutorialInformEN("lightsStart"))
|
||
for i, Henry in pairs(NPCList) do
|
||
common.TalkNLS(Henry, Character.say, tutorial.getTutorialTalkDE("lightsStart"), tutorial.getTutorialTalkEN("lightsStart"))
|
||
end
|
||
end
|
||
|
||
return true --leave safely
|
||
end
|
||
|
||
function M.LookAtItem(user, sourceItem)
|
||
|
||
local rareTexts = {
|
||
{value = 2, text = {english = "So uncommonly pristine, it is sure to burn longer than normal.", german = "So ungew<65>hnlich makellos, dass es sicher l<>nger als gew<65>hnlich brennt."}},
|
||
{value = 3, text = {english = "Of such rarely seen pristinity, it is sure to burn longer than normal.", german = "Von einer derart selten gesehenen Makellosigkeit, dass es sicher l<>nger als gew<65>hnlich brennt."}},
|
||
{value = 4, text = {english = "So uniquely pristine, it is sure to burn longer than normal, as if blessed by Br<42>gon himself.", german = "So einzigartig makellos, dass es sicher l<>nger als gew<65>hnlich brennt, als w<>re es von Br<42>gon selbst gesegnet."}}
|
||
}
|
||
|
||
|
||
local rareness, craftedRare = tonumber(sourceItem:getData("rareness")), sourceItem:getData("craftedRare")
|
||
|
||
local preText = {english = "", german = ""}
|
||
|
||
if craftedRare == "true" and rareness then
|
||
for _, rareText in pairs(rareTexts) do
|
||
if rareText.value == rareness then
|
||
preText.english = rareText.text.english
|
||
preText.german = rareText.text.german
|
||
if not sourceItem.id == Item.candles and not sourceItem.id == Item.lampOil then
|
||
preText.english = preText.english.."\n\n"
|
||
preText.german = preText.german.."\n\n"
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
|
||
if(LightsOn[sourceItem.id]) then
|
||
local TimeLeftI = sourceItem.wear
|
||
if(TimeLeftI == 255) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird nie ausbrennen.", preText.english.."It will never burn down.")
|
||
elseif (TimeLeftI == 0) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird sofort ausbrennen.", preText.english.."It will burn down immediately.")
|
||
elseif (TimeLeftI == 1) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird demn<6D>chst ausbrennen.", preText.english.."It will burn down anytime soon.")
|
||
elseif (TimeLeftI == 2) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird bald ausbrennen.", preText.english.."It will burn down soon.")
|
||
elseif (TimeLeftI <= 4) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird nach einer Weile ausbrennen.", preText.english.."It will burn down in a while.")
|
||
elseif (TimeLeftI <= DEFAULT_WEAR) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird nicht allzu bald ausbrennen.", preText.english.."It will not burn down anytime soon.")
|
||
elseif (TimeLeftI > DEFAULT_WEAR) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie wird nach langer Zeit ausbrennen.", preText.english.."It will burn down in a long time.")
|
||
end
|
||
elseif (LightsOff[sourceItem.id]) then
|
||
lookat.SetSpecialDescription(sourceItem, preText.german.."Sie ist nicht angez<65>ndet.", preText.english.."It is not lit, yet.")
|
||
else
|
||
lookat.SetSpecialDescription(sourceItem, preText.german, preText.english)
|
||
end
|
||
|
||
return lookat.GenerateLookAt(user, sourceItem, lookat.NONE, nil, nil, nil, true)
|
||
end
|
||
|
||
return M
|