862 lines
37 KiB
Lua
862 lines
37 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 globalvar = require("base.globalvar")
|
||
local character = require("base.character")
|
||
local money = require("base.money")
|
||
local mob = require("base.mob")
|
||
local scheduledFunction = require("scheduled.scheduledFunction")
|
||
local monsterHooks = require("monster.base.hooks")
|
||
|
||
local M = {}
|
||
|
||
local destinationIds = {}
|
||
|
||
local harborList = {}
|
||
harborList[1] = {nameDe="Cadomyr Hafen", nameEn="Cadomyr Harbour", targetDe="zum Hafen Cadomyr" ,pos=position(101,790,0),pict=2701,start=true}
|
||
harborList[2] = {nameDe="Galmair Hafen", nameEn="Galmair Harbour", targetDe="zum Hafen Galmair", pos=position(451,95,0),pict=61,start=true}
|
||
harborList[3] = {nameDe="Runewick Hafen", nameEn="Runewick Harbour", targetDe="zum Hafen Runewick", pos=position(727,809,0),pict=105,start=true}
|
||
harborList[4] = {nameDe="Trollshaven", nameEn="Troll's Haven", targetDe="zum Trollshaven", pos=position(683,284,0),pict=155,start=true}
|
||
harborList[5] = {nameDe="Cadomyr - Verlorener Hafen", nameEn="Cadomyr - Lost Harbour", targetDe="zum verlorenen Hafen Cadomyr", pos=position(105,833,0),pict=272,start=true}
|
||
harborList[6] = {nameDe="Leuchtturm", nameEn="Lighthouse", targetDe="zum Leuchtturm", pos=position(554,658,0),pict=509,start=true}
|
||
harborList[7] = {nameDe="Ostland Hafen", nameEn="Eastland Harbour", targetDe="zum Ostlandg Hafen", pos=position(888,485,0),pict=2760,start=true}
|
||
harborList[8] = {nameDe="N<EFBFBD>rdlicher Hafen", nameEn="Northern Harbour", targetDe="zum N<>rdlichen Hafen", pos=position(870,285,0),pict=308,start=true}
|
||
harborList[9] = {nameDe="Un<EFBFBD>berwindbarer Limes", nameEn="Insurmountable Limes", targetDe="zum Un<55>berwindbaren Limes", pos=position(678,46,0),pict=474,start=true}
|
||
harborList[10] = {nameDe="N<EFBFBD>rdliche Inseln - Ra", nameEn="Northern Islands - Ra", targetDe="zu der n<>rdlichen Insel Ra", pos=position(364,49,0),pict=359,start=false}
|
||
harborList[11] = {nameDe="N<EFBFBD>rdliche Inseln - Hept", nameEn="Northern Islands - Hept", targetDe="zu der n<>rdlichen Insel Hept", pos=position(415,85,0),pict=360,start=false}
|
||
harborList[12] = {nameDe="N<EFBFBD>rdliche Inseln - Yeg", nameEn="Northern Islands - Yeg", targetDe="zu der n<>rdlichen Insel Yeg", pos=position(478,34,0),pict=372,start=false}
|
||
harborList[13] = {nameDe="N<EFBFBD>rdliche Inseln - Sohl", nameEn="Northern Islands - Sohl", targetDe="zu der n<>rdlichen Insel Sohl", pos=position(424,24,0),pict=1272,start=false}
|
||
harborList[14] = {nameDe="N<EFBFBD>rdliche Inseln - Pen", nameEn="Northern Islands - Pen", targetDe="zu der n<>rdlichen Insel Pen", pos=position(389,39,0),pict=467,start=false}
|
||
|
||
M.harborList = harborList
|
||
|
||
local PRICE_FERRY = 1000 --costs of one trip
|
||
local PRICE_PIRATES = 10000 -- pay the pirates
|
||
local CHANCE_ATTACK = 5
|
||
local chanceToFlee = 25
|
||
local attackDuration = 300 -- s until pitates must be killed
|
||
local attackLastWarning = 70 -- s before timeout Warning Backstab is sent
|
||
|
||
M.personalTarget = {}
|
||
M.attackEndTime = 0
|
||
local LAST_TARGET = 1
|
||
local LAST_SHIP = 2
|
||
local LAST_OVERBOARD = 3
|
||
M.lastTarget = LAST_TARGET
|
||
|
||
local piratesSpawnPos = {position(349,869,1),
|
||
position(349,873,1),
|
||
position(350,881,1),
|
||
position(352,884,1),
|
||
position(356,885,1),
|
||
position(359,882,1),
|
||
position(359,879,1),
|
||
position(359,871,1),
|
||
position(351,863,2),
|
||
position(355,862,2),
|
||
position(357,863,2)}
|
||
local pirateMobsHigh = {1,5,6,10}
|
||
local pirateMobsMedium = {2,3,4}
|
||
local pirateMobsLow = {7,8,9}
|
||
local fighterCapabilityLow = 30
|
||
local fighterCapabilityMedium = 70
|
||
|
||
local shipCenterPos = position(352,870,1)
|
||
local someShores = {{position(193,839,0),position(191,821,0)},--south Letma
|
||
{position(352,778,0),position(371,785,0)},--north Kantabi desert
|
||
{position(667,696,0),position(648,709,0)},--Oldras Altar
|
||
{position(733,601,0),position(722,588,0)},--3 sisters
|
||
{position(877,453,0),position(878,437,0)},--Elstree Forest
|
||
{position(878,399,0),position(877,380,0)},--Pauldron
|
||
{position(715,261,0),position(725,263,0)},--Hempty opposite
|
||
{position(664, 89,0),position(650, 97,0)},--Northern forest west
|
||
{position(851,177,0),position(847,199,0)}}--Northern forest east
|
||
|
||
local pirateDoors = {position(354,873,0),position(355,873,0)}
|
||
|
||
local function getSettingsForHarbor(harborId)
|
||
local blockedOut = false
|
||
local blockedIn = false
|
||
local foundValue, blockedHarbors = ScriptVars:find("seafaringBlockOutgoing")
|
||
if not foundValue then
|
||
blockedHarbors = 0
|
||
end
|
||
if common.isBitSet(blockedHarbors, harborId) then
|
||
blockedOut = true
|
||
end
|
||
foundValue, blockedHarbors = ScriptVars:find("seafaringBlockIncoming")
|
||
if not foundValue then
|
||
blockedHarbors = 0
|
||
end
|
||
if common.isBitSet(blockedHarbors, harborId) then
|
||
blockedIn = true
|
||
end
|
||
return blockedOut, blockedIn
|
||
end
|
||
|
||
local function blockText(user,blockedOut, blockedIn)
|
||
local text
|
||
if blockedOut and blockedIn then
|
||
text = common.GetNLS(user,"gesperrt","blocked")
|
||
elseif blockedOut then
|
||
text = common.GetNLS(user,"nur ankommende Schiffe","incoming ferry only")
|
||
elseif blockedIn then
|
||
text = common.GetNLS(user,"nur auslaufende Schiffe","outgoing ferry only")
|
||
else
|
||
text = common.GetNLS(user,"in Betrieb","operational")
|
||
end
|
||
return text
|
||
end
|
||
|
||
local function setInOut(harborId, state, variable)
|
||
local foundValue, blockedHarbors = ScriptVars:find(variable)
|
||
if not foundValue then
|
||
blockedHarbors = 0
|
||
end
|
||
if state then
|
||
blockedHarbors = common.addBit(blockedHarbors,harborId)
|
||
else
|
||
blockedHarbors = common.removeBit(blockedHarbors,harborId)
|
||
end
|
||
ScriptVars:set(variable, blockedHarbors)
|
||
end
|
||
|
||
local function setOutgoing(harborId, state)
|
||
setInOut(harborId, state, "seafaringBlockOutgoing")
|
||
end
|
||
|
||
local function setIncoming(harborId, state)
|
||
setInOut(harborId, state, "seafaringBlockIncoming")
|
||
end
|
||
|
||
local function getFerryPrice()
|
||
local foundValue, price = ScriptVars:find("seafaringPrice")
|
||
if foundValue then
|
||
return math.max(1, tonumber(price))
|
||
end
|
||
return PRICE_FERRY
|
||
end
|
||
|
||
local function setFerryPrice(price)
|
||
ScriptVars:set("seafaringPrice", price)
|
||
end
|
||
|
||
local function getPiratePrice()
|
||
local foundValue, price = ScriptVars:find("seafaringRansom")
|
||
if foundValue then
|
||
return math.max(1, tonumber(price))
|
||
end
|
||
return PRICE_PIRATES
|
||
end
|
||
|
||
local function setPiratePrice(price)
|
||
ScriptVars:set("seafaringRansom", price)
|
||
end
|
||
|
||
local function getChancePirateAttack()
|
||
local foundValue, chance = ScriptVars:find("seafaringChanceAttack")
|
||
if foundValue then
|
||
return math.max(0, tonumber(chance))
|
||
end
|
||
return CHANCE_ATTACK
|
||
end
|
||
|
||
local function setChancePirateAttack(chance)
|
||
ScriptVars:set("seafaringChanceAttack", chance)
|
||
end
|
||
|
||
local function personsOnShip()
|
||
return common.countPlayersInRangeOf(shipCenterPos, 30)
|
||
end
|
||
|
||
local function isPersonOnShip(user)
|
||
if user:isInRangeToPosition(position(352,870,0), 30) or
|
||
user:isInRangeToPosition(position(352,870,1), 30) or
|
||
user:isInRangeToPosition(position(352,870,2), 30) then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
local function isPirateOnShip()
|
||
local monsters = world:getMonstersInRangeOf(shipCenterPos, 30)
|
||
return next(monsters) ~= nil
|
||
end
|
||
|
||
local function portalForLeftOverRemove()
|
||
while world:isItemOnField(position(355,864,2)) do
|
||
local item = world:getItemOnField(position(355,864,2))
|
||
world:erase(item, item.number)
|
||
end
|
||
end
|
||
|
||
local function portalForLeftOverCreate()
|
||
portalForLeftOverRemove()
|
||
world:createItemFromId( 10, 1, position(355,864,2), true, 999, nil)
|
||
local portal = world:getItemOnField(position(355,864,2))
|
||
portal.id = 10
|
||
portal.quality = 999
|
||
portal.wear = 255
|
||
local targetPos = common.getOneOutOfList(someShores)[1]
|
||
portal:setData("destinationCoordsX",targetPos.x)
|
||
portal:setData("destinationCoordsY",targetPos.y)
|
||
portal:setData("destinationCoordsZ",targetPos.z)
|
||
world:changeItem(portal)
|
||
end
|
||
|
||
local function informAllOnShip(msgDe,msgEn)
|
||
for i, targetStruct in pairs (M.personalTarget) do
|
||
local user = targetStruct[1]
|
||
if isPersonOnShip(user) then
|
||
common.InformNLS(user,msgDe,msgEn)
|
||
end
|
||
end
|
||
end
|
||
|
||
local function sendAllToTarget(msgDe,msgEn)
|
||
for i, targetStruct in pairs (M.personalTarget) do
|
||
local user = targetStruct[1]
|
||
if isPersonOnShip(user) then
|
||
user:warp(targetStruct[2])
|
||
world:gfx(globalvar.gfxPLATSCH,user.pos)
|
||
world:makeSound(9,user.pos)
|
||
common.InformNLS(user,msgDe,msgEn)
|
||
M.personalTarget[i]=nil
|
||
end
|
||
end
|
||
end
|
||
|
||
local function fellOverBoard(user)
|
||
common.InformNLS(user,"Wo bist du? Du warst auf einem Schiff, bist <20>ber Bord gegangen und hier gelandet.",
|
||
"Where are you? You were on a ship, went over board and landed here.")
|
||
local targetPos = common.getOneOutOfList(someShores)[1]
|
||
user:warp(targetPos)
|
||
end
|
||
|
||
local function killAllPirates()
|
||
local monsters = world:getMonstersInRangeOf(shipCenterPos, 30)
|
||
for _, monster in ipairs(monsters) do
|
||
monsterHooks.setForcedDeath(monster)
|
||
monsterHooks.setNoDrop(monster)
|
||
character.ChangeHP(monster, -10000)
|
||
monsterHooks.cleanHooks(monster)
|
||
end
|
||
end
|
||
|
||
local function isBackstabDoorOpen()
|
||
for d=1,2 do
|
||
local checkDoor = world:getItemOnField(pirateDoors[d])
|
||
if checkDoor.id == 3318 then
|
||
return true
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
local function closeBackstabDoors()
|
||
for d=1,2 do
|
||
local checkDoor = world:getItemOnField(pirateDoors[d])
|
||
if checkDoor.id == 3318 then
|
||
world:swap(checkDoor,3314,233)
|
||
end
|
||
end
|
||
end
|
||
|
||
local function piratesRule()
|
||
informAllOnShip("Malach<EFBFBD>n war wohl mit den Piraten. Sie sind in der Lage das Schiff zu <20>berrennen und setzen alle Anwesenden ihrem Gl<47>ck mit Cherga aus. Wird Cherga Gnade haben?",
|
||
"Malach<EFBFBD>n was obviously with the pirates. They overrun the ship and all passenger have to face Cherga. Will Cherga have mercy on you?")
|
||
for i, targetStruct in pairs (M.personalTarget) do
|
||
local user = targetStruct[1]
|
||
if isPersonOnShip(user) then
|
||
character.DeathAfterTime(user,math.random(10,30),0,27,true)
|
||
end
|
||
end
|
||
portalForLeftOverCreate()
|
||
closeBackstabDoors()
|
||
killAllPirates()
|
||
M.lastTarget = LAST_OVERBOARD
|
||
end
|
||
|
||
local function georgeBackstabRocks()
|
||
informAllOnShip("George Backstab st<73>rmt die Stufen hinauf und schmei<65>t alle, Piraten und Reisende <20>ber Bord. Du erreichst eine K<>ste. Sei vorsichtig, auch die Piraten haben die K<>ste erreicht.",
|
||
"George Backstab storms up the stairs and throws all the pirates and passengers over the ship's rail. You reach a shore. Be careful, the pirates might be nearby.")
|
||
local targetShore = common.getOneOutOfList(someShores)
|
||
local players = world:getPlayersInRangeOf(shipCenterPos, 30); --get all player on ship
|
||
for i, player in pairs (players) do
|
||
player:warp(targetShore[1])
|
||
world:gfx(globalvar.gfxPLATSCH,player.pos)
|
||
end
|
||
local monsters = world:getMonstersInRangeOf(shipCenterPos, 30); --get all pirates on ship
|
||
for i, monster in pairs (monsters) do
|
||
monster:warp(targetShore[2])
|
||
world:gfx(globalvar.gfxPLATSCH,monster.pos)
|
||
end
|
||
portalForLeftOverCreate()
|
||
closeBackstabDoors()
|
||
M.lastTarget = LAST_OVERBOARD
|
||
end
|
||
local function underAttack()
|
||
world:gfx(11,shipCenterPos)
|
||
local currentTime = common.GetCurrentTimestamp()
|
||
if isPirateOnShip() then
|
||
if isBackstabDoorOpen() then
|
||
georgeBackstabRocks()
|
||
return
|
||
elseif currentTime > M.attackEndTime then
|
||
piratesRule()
|
||
return
|
||
elseif (currentTime > M.attackEndTime - attackLastWarning) and not M.attackWarningSaid then
|
||
informAllOnShip("[Hinweis] Es ist nur noch eine Minute <20>brig, das Schiff von den Piraten zu s<>ubern. Vielleicht sollte doch die Hilfe des rabiaten George Backstab in Anspruch genommen werden. Hierzu einfach die Verliest<73>r unten im Schiffsbauch <20>ffnen.",
|
||
"[Hint] There is only one minute left to clear the boat of pirates. You should probably consider using the brutally help of George Backstab. Just open the door down in the ship's hold.")
|
||
M.attackWarningSaid = true
|
||
end
|
||
scheduledFunction.registerFunction(5, function() underAttack() end)
|
||
else
|
||
sendAllToTarget("Nachdem die Piratenmeute zur<75>ckgeschlagen werden konnte, wird das gew<65>nschte Ziel sicher erreicht.",
|
||
"After all the pirates were pushed back, you reach your final destination safely.")
|
||
portalForLeftOverCreate()
|
||
M.lastTarget = LAST_TARGET
|
||
end
|
||
end
|
||
|
||
local function piratesFight(user)
|
||
informAllOnShip("Die Piraten erreichen das Schiff und ziehen ihre Waffen. Auf welcher Seite wird wohl Malach<63>n stehen?",
|
||
"The pirates reach the ship and draw their weapons. Which side will be supported by Malach<63>n?")
|
||
informAllOnShip("[Hinweis] Von nun an bleiben nur noch f<>nf Minuten <20>ber, um ein Scheitern und somit die Begegnung mit Cherga zu vermeiden. Unten im Schiffsbauch befindet sich Hilfe. <20>ffne die T<>r f<>r den Str<74>fling George Backstab und er wird das Schiff von den Piraten s<>ubern. Aber bedenke, er ist nicht zimperlich.",
|
||
"[Hint] You have just five minutes left to avoid failure and thus a meeting with Cherga. There is help waiting for you downstairs in the ship's hold. Open the door to free the prisoner George Backstab and he will help you clear the ship of pirates. However, he was never demure.")
|
||
|
||
local spawnPos = common.Shuffle(piratesSpawnPos)
|
||
local partyMember = {}
|
||
for _, member in pairs (M.personalTarget) do
|
||
table.insert(partyMember, member[1])
|
||
end
|
||
local countParty, bestFighter = mob.getPartyFightCapability(partyMember)
|
||
local monsterMob
|
||
if not bestFighter or bestFighter < fighterCapabilityLow then
|
||
monsterMob = pirateMobsLow[math.random(1,#pirateMobsLow)]
|
||
elseif bestFighter < fighterCapabilityMedium then
|
||
monsterMob = pirateMobsMedium[math.random(1,#pirateMobsMedium)]
|
||
else
|
||
monsterMob = pirateMobsHigh[math.random(1,#pirateMobsHigh)]
|
||
end
|
||
local monsterAmount = math.max(4, math.min(11,countParty*2+math.random(-2,2)))
|
||
local monsterList = mob.getMonsters(monsterMob, monsterAmount)
|
||
|
||
for p=1,monsterAmount do
|
||
local enemy = monsterList[p]
|
||
world:gfx(41,spawnPos[p])
|
||
world:createMonster(enemy,spawnPos[p],0)
|
||
world:makeSound(1,user.pos)
|
||
end
|
||
|
||
M.attackEndTime = common.GetCurrentTimestamp() + attackDuration
|
||
M.attackWarningSaid = false
|
||
scheduledFunction.registerFunction(5, function() underAttack() end)
|
||
end
|
||
|
||
local function piratesFlee(user)
|
||
if math.random(1,100) <= chanceToFlee then
|
||
sendAllToTarget("Die Bem<65>hungen zahlen sich aus und die Flucht gelingt. Sicher wird das gew<65>nschte Ziel erreicht.",
|
||
"Your effort is rewarded. You are able to flee successfully and reach your final destination safely.")
|
||
portalForLeftOverCreate()
|
||
M.lastTarget = LAST_TARGET
|
||
else
|
||
informAllOnShip("Oh nein, zu langsam f<>r eine erfolgreiche Flucht!", "Oh no, too slow for a successful escape!")
|
||
piratesFight(user)
|
||
M.lastTarget = LAST_SHIP
|
||
end
|
||
end
|
||
|
||
local function piratesPay(user)
|
||
local pricePirates = getPiratePrice()
|
||
local germanMoney, englishMoney = money.MoneyToString(pricePirates)
|
||
if money.CharHasMoney(user,pricePirates) then
|
||
money.TakeMoneyFromChar(user,pricePirates)
|
||
common.TalkNLS(user,Character.say,"#me bezahlt" .. germanMoney .. " an die Piraten. Die Freibeuter verlassen daraufhin gr<67>lend das Schiff.",
|
||
"#me pay" .. englishMoney .. " to the pirates. The wild gang left the ship chanting.")
|
||
sendAllToTarget("Das Gold ist weg, aber daf<61>r wird das gew<65>nschte Ziel ohne Blessuren erreicht.",
|
||
"The gold is gone but in return you reach your final destination safely.")
|
||
portalForLeftOverCreate()
|
||
M.lastTarget = LAST_TARGET
|
||
else
|
||
informAllOnShip("Nein, das ist zu wenig Geld! Damit lassen sich die Piraten nicht bestechen.",
|
||
"No, that's not enough for bribing the pirates!")
|
||
piratesFight(user)
|
||
M.lastTarget = LAST_SHIP
|
||
end
|
||
end
|
||
|
||
local function piratesAttack(user)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local pricePirates = getPiratePrice()
|
||
local germanMoney, englishMoney = money.MoneyToString(pricePirates)
|
||
|
||
closeBackstabDoors()
|
||
|
||
local callback = function(dialog)
|
||
local success = dialog:getSuccess()
|
||
if success then
|
||
local selected = dialog:getSelectedIndex()
|
||
if (selected == 0) then
|
||
M.lastTarget = LAST_SHIP
|
||
piratesFight(user)
|
||
elseif (selected == 1) then
|
||
piratesFlee(user)
|
||
elseif (selected == 2) then
|
||
piratesPay(user)
|
||
end
|
||
elseif isPersonOnShip(user) then
|
||
piratesAttack(user)
|
||
end
|
||
end
|
||
|
||
dialogTitle = common.GetNLS(user,"Piratenangriff","Pirates attack")
|
||
dialogAddText = common.GetNLS(user,"Piraten n<>hern sich dem Schiff. Folgende M<>glichkeiten stehen zur Wahl:",
|
||
"Pirates are coming closer to your ship. You can choose between the following options:")
|
||
local dialog = SelectionDialog(dialogTitle, dialogAddText, callback)
|
||
|
||
dialog:addOption(1,common.GetNLS(user,"K<EFBFBD>mpfe gegen die Piraten","Fight against the pirates"))
|
||
dialog:addOption(53,common.GetNLS(user,"Fliehe vor den Piraten (25% Erfolgschance, ansonsten wartet der Kampf)",
|
||
"Flee from the pirates (25% chance of success, otherwise you have to fight)"))
|
||
dialog:addOption(61,common.GetNLS(user,"Zahle" .. germanMoney .. ", um verschont zu bleiben.",
|
||
"Pay" .. englishMoney .. " in order to be spared"))
|
||
user:requestSelectionDialog(dialog)
|
||
|
||
end
|
||
|
||
local function directTravel(user,harborId)
|
||
common.InformNLS(user,"Du hast dich dazu entschlossen, " .. harborList[harborId].targetDe .. " zu reisen.",
|
||
"You have chosen to travel to " ..harborList[harborId].nameEn ..".")
|
||
world:gfx(1,user.pos)
|
||
world:makeSound(9,user.pos)
|
||
user:warp(harborList[harborId].pos)
|
||
world:gfx(globalvar.gfxPLATSCH,user.pos)
|
||
world:makeSound(9,user.pos)
|
||
end
|
||
|
||
local function travelToShip(user)
|
||
local pricePirates = getPiratePrice()
|
||
local germanMoney, englishMoney = money.MoneyToString(pricePirates)
|
||
|
||
common.InformNLS(user,"[Hinweis 1] Piraten n<>hern sich dem Schiff. Folgende M<>glichkeiten stehen zur Wahl: K<>mpfen, fliehen oder" .. germanMoney .. " zahlen.",
|
||
"[Information 1] Pirates are coming closer to your ship. You can choose between the following options: fight, flee or pay" .. englishMoney .. ".")
|
||
common.InformNLS(user,"[Hinweis 2] Die Entscheidung liegt bei der Person, die f<>r die F<>hre bezahlt hat.", "[Information 2] The person who paid for the ferry trip decides.")
|
||
world:gfx(1,user.pos)
|
||
world:makeSound(9,user.pos)
|
||
user:warp(shipCenterPos)
|
||
world:gfx(globalvar.gfxPLATSCH,user.pos)
|
||
world:makeSound(9,user.pos)
|
||
end
|
||
|
||
local function takePartInTravel(user, harborId)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
|
||
local callback = function(extDialog)
|
||
|
||
local success = extDialog:getSuccess()
|
||
if success then
|
||
local selected = extDialog:getSelectedIndex()
|
||
if selected == 0 then
|
||
if M.lastTarget == LAST_SHIP then
|
||
travelToShip(user)
|
||
elseif M.lastTarget == LAST_TARGET then
|
||
directTravel(user,harborId)
|
||
else -- overboard
|
||
fellOverBoard(user)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre","Ferry")
|
||
dialogAddText = common.GetNLS(user,"M<EFBFBD>chtest du in die F<>hre " .. harborList[harborId].targetDe .. " einsteigen?",
|
||
"Do you want to enter the ferry to " .. harborList[harborId].nameEn .. "?")
|
||
local extDialog = SelectionDialog(dialogTitle, dialogAddText, callback)
|
||
extDialog:setCloseOnMove()
|
||
|
||
extDialog:addOption(harborList[harborId].pict, common.GetNLS(user,"Ja, ich m<>chte reisen!","Yes, I want to travel!"))
|
||
extDialog:addOption(228, common.GetNLS(user,"Nein, ich will hier bleiben!","No, I want to stay here!"))
|
||
user:requestSelectionDialog(extDialog)
|
||
end
|
||
|
||
local function travelToTarget(user, harborId, startPos)
|
||
local limitChancePirateAttack = getChancePirateAttack()
|
||
local facePirates = false
|
||
if math.random(1,100) < limitChancePirateAttack and personsOnShip() == 0 then --Pirates!
|
||
facePirates = true
|
||
end
|
||
|
||
local travelers = world:getPlayersInRangeOf(startPos, 5)
|
||
for _, player in pairs(travelers) do
|
||
if facePirates then
|
||
M.personalTarget[player.id] = {player, harborList[harborId].pos}
|
||
else
|
||
M.personalTarget[player.id]=nil
|
||
end
|
||
if user.id ~= player.id then
|
||
takePartInTravel(player, harborId)
|
||
elseif facePirates then
|
||
M.lastTarget = LAST_SHIP
|
||
piratesAttack(user)
|
||
travelToShip(user)
|
||
portalForLeftOverRemove()
|
||
else
|
||
M.lastTarget = LAST_TARGET
|
||
directTravel(user,harborId)
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
local function setDestinationId(user, destinationId)
|
||
|
||
destinationIds[user.id] = destinationId
|
||
|
||
end
|
||
|
||
local function getDestinationId(user)
|
||
|
||
return destinationIds[user.id]
|
||
|
||
end
|
||
|
||
local function setSail(user, sourceItem)
|
||
|
||
local priceFerry = getFerryPrice()
|
||
local destinationId = getDestinationId(user)
|
||
|
||
money.TakeMoneyFromChar(user, priceFerry)
|
||
travelToTarget(user, destinationId, sourceItem.pos)
|
||
|
||
end
|
||
|
||
local function abortFerry(user)
|
||
|
||
user:inform("Da das Auslaufen unterbrochen wurde, geben die Matrosen dein Geld zur<75>ck, bevor sie sich wieder ihrem Tagesgesch<63>ft widmen.", "As the process of setting sail is interrupted, the sailors return your money before returning to their usual work.")
|
||
|
||
end
|
||
|
||
local function startFerry(user, sourceItem)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local dialogOption
|
||
|
||
local foundValue, blockedHarbors = ScriptVars:find("seafaringBlockIncoming")
|
||
if not foundValue then
|
||
blockedHarbors = 0
|
||
end
|
||
local priceFerry = getFerryPrice()
|
||
local germanMoney, englishMoney = money.MoneyToString(priceFerry)
|
||
|
||
common.TurnTo(user,sourceItem.pos)
|
||
|
||
local callback = function(dialog)
|
||
|
||
local success = dialog:getSuccess()
|
||
if success then
|
||
local selected = dialog:getSelectedIndex()
|
||
if dialogOption[selected+1][2] then
|
||
if money.CharHasMoney(user,priceFerry) then
|
||
|
||
user:inform("Als du das Fahrgeld <20>bergibst, beginnen die nahegelegenen Seeleute, sich auf die bevorstehende Reise vorzubereiten.", "As you hand over the fare, the nearby sailors begin to prepare for the journey ahead.") -- Verification of chatGPT GERMAN TRANSLATION needed
|
||
|
||
local potentialTravelers = world:getPlayersInRangeOf(sourceItem.pos, 10)
|
||
|
||
for _, potentialTraveler in pairs(potentialTravelers) do
|
||
potentialTraveler:inform("Nach dem Abkassieren deutet der F<>hrmann der Mannschaft, alles bereit zum Ablegen zu machen.", "As the sailor is handed the coins, he calls for his fellow crewmates and they start getting ready to set sail.")
|
||
end
|
||
|
||
setDestinationId(user, dialogOption[selected+1][1])
|
||
|
||
user:startAction(200, 21, 10, 0, 0)
|
||
else
|
||
common.InformNLS(user,"Du hast nicht genug Geld f<>r diese Reise. Die Reise kostet" .. germanMoney .." f<>r eine <20>berfahrt.",
|
||
"You don't have enough money for this journey. The journey costs" .. englishMoney .." for one passage.")
|
||
end
|
||
else
|
||
common.InformNLS(user,"Kein Schiffsf<73>hrer ist bereit, diesen Hafen anzusteuern. Du wirst wohl den Landweg nehmen m<>ssen.",
|
||
"No sailor is willing to head for this port. You will probably have to walk.")
|
||
end
|
||
end
|
||
end
|
||
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre","Ferry")
|
||
dialogAddText = common.GetNLS(user,"Eine Reise kostet" .. germanMoney .." f<>r die ganze Gruppe. W<>hle eine Ziel aus.",
|
||
"A journey costs" .. englishMoney .." for the group. Choose a destination.")
|
||
local dialog = SelectionDialog(dialogTitle, dialogAddText, callback)
|
||
dialog:setCloseOnMove()
|
||
|
||
dialogOption = {}
|
||
for i, harbor in pairs(harborList) do
|
||
if not common.isBitSet(blockedHarbors, i) and sourceItem.pos ~= harbor.pos then
|
||
dialog:addOption(harbor.pict, common.GetNLS(user,harbor.nameDe,harbor.nameEn))
|
||
table.insert(dialogOption,{i,true})
|
||
elseif sourceItem.pos ~= harbor.pos then
|
||
dialog:addOption(harbor.pict, common.GetNLS(user,harbor.nameDe .. " (keine Verbindung)",
|
||
harbor.nameEn .. " (no boats)"))
|
||
table.insert(dialogOption,{i,false})
|
||
end
|
||
end
|
||
user:requestSelectionDialog(dialog)
|
||
end
|
||
|
||
function M.ferryLookAt(user, sourceItem, lookAt)
|
||
for i, harbor in pairs(harborList) do
|
||
if sourceItem.pos == harbor.pos then
|
||
local foundValue, blockedHarbors = ScriptVars:find("seafaringBlockOutgoing")
|
||
if not foundValue then
|
||
blockedHarbors = 0
|
||
end
|
||
lookAt.name = common.GetNLS(user,"F<EFBFBD>hre","Ferry")
|
||
if common.isBitSet(blockedHarbors, i) then
|
||
lookAt.description = common.GetNLS(user,"Der Hafen ist verwaist. Hier wird so schnell keine F<>hre vorbeikommen.",
|
||
"The port is deserted. Don't waste your time waiting for a ferry.")
|
||
else
|
||
local germanMoney, englishMoney = money.MoneyToString(getFerryPrice())
|
||
lookAt.description = common.GetNLS(user,"Wer bei der n<>chsten Fahrt mit m<>chte, sollte sich schnellstens hier innerhalb von f<>nf Schritten sammeln. Die Fahrt kostet"..germanMoney.." f<>r die ganze Gruppe.",
|
||
"Anyone who would like to join for the next trip should gather here within five steps. A trip costs"..englishMoney.." for the whole group.")
|
||
end
|
||
return true, lookAt
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
local function gmManageCostFerry(user)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local priceFerry = getFerryPrice()
|
||
local _, englishMoney = money.MoneyToString(priceFerry)
|
||
local thisInputDialog = function (dialog)
|
||
|
||
if (not dialog:getSuccess()) then
|
||
return
|
||
end
|
||
|
||
local input = dialog:getInput()
|
||
|
||
if not common.IsNilOrEmpty(input) then
|
||
local newPrice = tonumber(input)
|
||
if newPrice ~= nil then
|
||
if newPrice > 0 and newPrice <= 1000000 then --100 gold
|
||
setFerryPrice(newPrice)
|
||
_, englishMoney = money.MoneyToString(newPrice)
|
||
user:inform("The new ferry price is"..englishMoney.." .")
|
||
user:logAdmin("[Ferry] Ferry price changed to"..englishMoney.." .")
|
||
return
|
||
end
|
||
user:inform("The price for the ferry must be in between 1 Copper and 100 Gold")
|
||
end
|
||
end
|
||
|
||
end
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre - Einstellungen","Ferry - Settings")
|
||
dialogAddText = common.GetNLS(user,"Preis einer F<>hrfahrt:"..englishMoney.." ("..tostring(priceFerry).." Kupfer)\nBitte neuen Preis in Kupferst<73>cken angeben.",
|
||
"Price of one trip:"..englishMoney.." ("..tostring(priceFerry).." copper)\nPlease enter new price in amount of copper.")
|
||
|
||
user:requestInputDialog(InputDialog(dialogTitle, dialogAddText ,false, 255, thisInputDialog))
|
||
end
|
||
|
||
local function gmManageCostPirate(user)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local pricePirates = getPiratePrice()
|
||
local _, englishMoney = money.MoneyToString(pricePirates)
|
||
local thisInputDialog = function (dialog)
|
||
|
||
if (not dialog:getSuccess()) then
|
||
return
|
||
end
|
||
|
||
local input = dialog:getInput()
|
||
|
||
if not common.IsNilOrEmpty(input) then
|
||
local newPrice = tonumber(input)
|
||
if newPrice ~= nil then
|
||
if newPrice > 0 and newPrice <= 10000000 then --1000 gold
|
||
setPiratePrice(newPrice)
|
||
_, englishMoney = money.MoneyToString(newPrice)
|
||
user:inform("The ransom to the pirates is"..englishMoney.." .")
|
||
user:logAdmin("[Ferry] Ransom to pirates changed to"..englishMoney.." .")
|
||
return
|
||
end
|
||
user:inform("The price for the pirates must be in between 1 Copper and 1000 Gold")
|
||
end
|
||
end
|
||
|
||
end
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre - Einstellungen","Ferry - Settings")
|
||
dialogAddText = common.GetNLS(user,"L<EFBFBD>segeld an die Piraten:"..englishMoney.." ("..tostring(pricePirates).." Kupfer)\nBitte neuen Preis in Kupferst<73>cken angeben.",
|
||
"Ransom to pay to the pirates:"..englishMoney.." ("..tostring(pricePirates).." copper)\nPlease enter new price in amount of copper.")
|
||
|
||
user:requestInputDialog(InputDialog(dialogTitle, dialogAddText ,false, 255, thisInputDialog))
|
||
end
|
||
|
||
local function gmManageProbabilityPirates(user)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local chancePirateAttack = getChancePirateAttack()
|
||
local thisInputDialog = function (dialog)
|
||
|
||
if (not dialog:getSuccess()) then
|
||
return
|
||
end
|
||
|
||
local input = dialog:getInput()
|
||
|
||
if not common.IsNilOrEmpty(input) then
|
||
local newChance = tonumber(input)
|
||
if newChance ~= nil then
|
||
if newChance >= 0 and newChance <= 101 then
|
||
setChancePirateAttack(newChance)
|
||
user:inform("The chance the pirates attack is"..tostring(newChance).."%.")
|
||
user:logAdmin("[Ferry] Chance the pirates attack changed to"..tostring(newChance).."%.")
|
||
return
|
||
end
|
||
user:inform("The chance the pirates attack must be in between 0 and 101 %")
|
||
end
|
||
end
|
||
|
||
end
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre - Einstellungen","Ferry - Settings")
|
||
dialogAddText = common.GetNLS(user,"Wahrscheinlichkeit eines Piraten<65>berfalls: "..tostring(chancePirateAttack).." %)\nBitte neuen Wert in Prozent (0-101) angeben.",
|
||
"Chance the pirates attack: "..tostring(chancePirateAttack).." %)\nPlease enter the new value in percent (0-101).")
|
||
|
||
user:requestInputDialog(InputDialog(dialogTitle, dialogAddText ,false, 255, thisInputDialog))
|
||
end
|
||
|
||
local function gmManageBlockPort(user,harborId)
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local blockedOut
|
||
local blockedIn
|
||
|
||
local callback = function(dialog)
|
||
if (not dialog:getSuccess()) then
|
||
return
|
||
end
|
||
local selected = dialog:getSelectedIndex()
|
||
if (selected == 0 or selected == 2) and blockedOut then
|
||
setOutgoing(harborId, false)
|
||
elseif (selected == 1 or selected == 3) and not blockedOut then
|
||
setOutgoing(harborId, true)
|
||
end
|
||
if (selected == 0 or selected == 1) and blockedIn then
|
||
setIncoming(harborId, false)
|
||
elseif (selected == 2 or selected == 3) and not blockedIn then
|
||
setIncoming(harborId, true)
|
||
end
|
||
end
|
||
blockedOut, blockedIn = getSettingsForHarbor(harborId)
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre - Einstellungen","Ferry - Settings")
|
||
dialogAddText = common.GetNLS(user,harborList[harborId].nameDe,harborList[harborId].nameEn) .. "\n" ..blockText(user,blockedOut, blockedIn)
|
||
|
||
local dialog = SelectionDialog(dialogTitle, dialogAddText, callback)
|
||
dialog:addOption(0, common.GetNLS(user,"Voll in Betrieb","Fully operational"))
|
||
dialog:addOption(0, common.GetNLS(user,"Nur ankommender Verkehr","Incoming ferry only"))
|
||
dialog:addOption(0, common.GetNLS(user,"Nur auslaufender Verkehr","Outgoing ferry only"))
|
||
dialog:addOption(0, common.GetNLS(user,"Au<EFBFBD>er Betrieb","Out of operation"))
|
||
user:requestSelectionDialog(dialog)
|
||
end
|
||
|
||
function M.gmManagePorts(user)
|
||
local optionList = {}
|
||
local dialogTitle
|
||
local dialogAddText
|
||
local blockedOut
|
||
local blockedIn
|
||
local germanMoney
|
||
local englishMoney
|
||
local SELECT_COST_FERRY = 10001
|
||
local SELECT_COST_PIRATE = 10002
|
||
local SELECT_PROPERTY_PIRATE = 10003
|
||
|
||
local callback = function(dialog)
|
||
if (not dialog:getSuccess()) then
|
||
return
|
||
end
|
||
local selected = dialog:getSelectedIndex()
|
||
local selectedOption = optionList[selected+1]
|
||
if selectedOption == SELECT_COST_FERRY then
|
||
gmManageCostFerry(user)
|
||
elseif selectedOption == SELECT_COST_PIRATE then
|
||
gmManageCostPirate(user)
|
||
elseif selectedOption == SELECT_PROPERTY_PIRATE then
|
||
gmManageProbabilityPirates(user)
|
||
else
|
||
gmManageBlockPort(user,selectedOption)
|
||
end
|
||
end
|
||
dialogTitle = common.GetNLS(user,"F<EFBFBD>hre - Einstellungen","Ferry - Settings")
|
||
dialogAddText = common.GetNLS(user,"W<EFBFBD>hle die gew<65>nsche Einstellung aus oder F<>hre aua",
|
||
"Select the property or the ferry.")
|
||
local dialog = SelectionDialog(dialogTitle, dialogAddText, callback)
|
||
germanMoney, englishMoney = money.MoneyToString(getFerryPrice())
|
||
dialog:addOption(3077, common.GetNLS(user,"Kosten eine F<>hrfahrt ("..germanMoney..")","Costs one ferry trip("..englishMoney..")"))
|
||
table.insert(optionList, SELECT_COST_FERRY)
|
||
germanMoney, englishMoney = money.MoneyToString(getPiratePrice())
|
||
dialog:addOption(61, common.GetNLS(user,"L<EFBFBD>segeld ("..germanMoney..")","Ramson ("..englishMoney..")"))
|
||
table.insert(optionList, SELECT_COST_PIRATE)
|
||
local chancePirateAttack = getChancePirateAttack()
|
||
dialog:addOption(1, common.GetNLS(user,"Wahrscheilichkeit Piraten<65>berfall ("..tostring(chancePirateAttack).."%)","Probability pirate attack ("..tostring(chancePirateAttack).."%)"))
|
||
table.insert(optionList, SELECT_PROPERTY_PIRATE)
|
||
for i, harbor in pairs (harborList) do
|
||
if not common.IsNilOrEmpty(harbor.nameDe) and not common.IsNilOrEmpty(harbor.nameEn) then
|
||
blockedOut, blockedIn = getSettingsForHarbor(i)
|
||
dialog:addOption(harbor.pict, common.GetNLS(user,harbor.nameDe,harbor.nameEn).." ("..blockText(user,blockedOut, blockedIn)..")")
|
||
table.insert(optionList, i)
|
||
end
|
||
end
|
||
user:requestSelectionDialog(dialog)
|
||
end
|
||
|
||
function M.login(user)
|
||
if isPersonOnShip(user) then
|
||
if isPirateOnShip() then
|
||
common.InformNLS(user,"Piraten sind gerade dabei, das Schiff zu <20>berrennen. Mitgefangen, mitgehangen! Deine Hilfe w<>re nicht schlecht.",
|
||
"Pirates are about to attack the ship. Cling together, swing together! Your help might be very appreciated.")
|
||
else
|
||
fellOverBoard(user)
|
||
end
|
||
end
|
||
end
|
||
|
||
function M.useFerry(user, sourceItem, actionState)
|
||
for i, harbor in pairs(harborList) do
|
||
if sourceItem.pos == harbor.pos then
|
||
local foundValue, blockedHarbors = ScriptVars:find("seafaringBlockOutgoing")
|
||
if not foundValue then
|
||
blockedHarbors = 0
|
||
end
|
||
if not common.isBitSet(blockedHarbors, i) then
|
||
if actionState == Action.none then
|
||
startFerry(user, sourceItem)
|
||
elseif actionState == Action.abort then
|
||
abortFerry(user)
|
||
elseif actionState == Action.success then
|
||
setSail(user, sourceItem)
|
||
end
|
||
end
|
||
return true
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
return M
|