User:Umiven/UmivenBank.xml

From Discworld MUD Wiki
Jump to: navigation, search

Check for new versions at: Bank Tracker

To use, copy the text in the box below inside a file named UmivenBank.xml in your MUSHclient/quow_plugins/ directory. You need to save the file using a simple text editor like Notepad++, nano, kate, gedit, etc., but not a words processor like word, write or libreoffice.

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<!-- Bank Helper created by Umiven -->
<muclient>
<plugin
   name="UmivenBanker"
   author="Umiven"
   id="556d6976656e000000000001"
   language="Lua"
   purpose="Bank Tracker"
   date_written="2022-05-22"
   date_modified="2023-01-24"
   save_state="y"
   requires="5.06"
   version="1.04"
   >
</plugin>

<script>
<![CDATA[
-- ********************************************************************
-- *****                       Bank Tracker                       *****
-- *****                      For Discworld                       *****
-- *****                                                          *****
-- *****  Keeps track of the amount of money in every bank.       *****
-- *****  To use this plugin, go to each bank and get the         *****
-- *****  'balance', which will then be stored.                   *****
-- *****  You can recall the every stored bank and the amount     *****
-- *****  typing 'bank' or 'banks'. This will give you an         *****
-- *****  overview of every bank, the amount in it and a total    *****
-- *****  across all bank accounts.                               *****
-- *****  As a small aside, you can easily deposit half of your   *****
-- *****  currently held money. To do so, take out all the money  *****
-- *****  you want to deposit in the bank and look at your        *****
-- *****  inventory. Then type 'deposithalf' to deposit half of   *****
-- *****  all the money you are currently holding (rounded down). *****
-- ********************************************************************

--#region global variables
local errorColour = "red"
local bankNameColour = "orange"
local moneyColour = "yellow"
local totalColour = "#80FF80"
--#endregion

local json = require("json")

--#region database
local banksInfo = {
	["Bing's First"] = {locations = "Bing's First Bank|branch of Bing's Bank|neat branch of Bing's bank", city = "Ankh-Morpork", streets = "Upper Broadway"},
	["Lancrastian Farmers' Cooperative"] = {locations = "Lancrastian Farmers' Cooperative Bank", city = "Ankh-Morpork, Lancre, Ohulan Cutash", streets = "The Ridings, Lancre Town square, market"},
	["First Imperial Bank of the Empire"] = {locations = "branch of the First Imperial Bank of the Empire|First Imperial Bank of the Empire", city = "Bes Pelargic", streets = "Market Street"},
	["Klatchian Continental"] = {locations = "Klatchian Continental Bank", city = "Djelibeybi, Ephebe", streets = "Market Street, Logical Lane"},
	["Genua National"] = {locations = "Genua National Bank", city = "Genua", streets = "Royal Avenue"},
}

local regionInformation = {
	["AM"] = {
		wichitBeads = 4,
		regexFind = {"A%$", "%dp"},
		denominations = {
			{name = "A$", value = 100}
		}
	},
	["BP"] = {
		wichitBeads = 4,
		regexFind = {"Rh", "%ds"},
		denominations = {
			{name = "Rh", value = 120},
			{name = "s", value = 1}
		}
	},
	["LAN"] = {
		wichitBeads = 3,
		regexFind = {"Lp", "Ls", "LC", "LSov", "LH"},
		denominations = {
			{name = "LH", value = 82944},
			{name = "LSov", value = 6912},
			{name = "LC", value = 576},
			{name = "Ls", value = 48},
			{name = "Lp", value = 4}
		}
	},
	["GEN"] = {
		wichitBeads = 3,
		regexFind = {"Gc", "Gl", "Gf", "Gd"},
		denominations = {
			{name = "Gd", value = 10000},
			{name = "Gf", value = 1000},
			{name = "Gl", value = 100},
			{name = "Gc", value = 1}
		}
	},
	["DJB"] = {
		wichitBeads = 2,
		regexFind = {"DjToon"},
		denominations = {
			{name = "DjToon ", value = 100}
		}
	},
	["EPH"] = {
		wichitBeads = 2,
		regexFind = {"%dM", "%dde"},
		denominations = {
			{name = "M", value = 4800},
			{name = "S", value = 96},
			{name = "de", value = 1}
		}
	},
	["KLA"] = {
		wichitBeads = 5,
		regexFind = {"dr"},
		denominations = {
			{name = " dr", value = 100}
		}
	}
}
--#endregion

--#region General functions
function string.addLeadingTrailing(str, max, fill, trailing)
	if type(str) ~= "string" or type(max) ~= "number" or type(fill) ~= "string" then
		Note("One of the entered variables is of the incorrect type")
	else
		-- set trailing or leading boolean optional parameter
		local trail = trailing or false

		local amountToAdd = max - #str
		local returnString = str

		returnString = trail and returnString .. string.rep(fill, amountToAdd) or string.rep(fill, amountToAdd) .. returnString

		return returnString
	end
end

function string.isEmpty(s)
    local success, msg = pcall(function() assert(type(s) == "string") end)
    if not success then
        Note(msg)
    end
    return s == nil or #s == 0
end

function string.toTable(s, delimiter)
	local result = {}
	for match in (s..delimiter):gmatch("(.-)"..delimiter) do
		table.insert(result, match)
	end
	return result
end

function string.trim(s)
	return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end

function table.print(t)
	for k,v in pairs(t) do
		local vType = type(v)
		if vType == "table" then
			Note(k)
			table.print(v)
		else
			Note(k .. ": " .. tostring(v))
		end
	end
end

function table.reverse(t)
	for i = #t - 1, 1, -1 do
		t[#t] = table.remove(t, i)
	end
end

function table.valueMaxStringLength(t)
	local maxStringLength =  0
	for key, value in pairs(t) do
		if string.len(value) > maxStringLength then
			maxStringLength = string.len(value)
		end
	end
	return maxStringLength
end
--#endregion

--#region Bank functions
function BankDepositHalfMoney()
	local moneyString = GetVariable("bankPurseContentsHalf")
	Send("deposit " .. moneyString)
end

function BankPrintAllInfo()
	BankPrintAllBanks()
	ColourNote(totalColour, "", "Total: " .. BankGetTotalMoney())
end

function BankPrintBank(bankName, amount, currency)
	if type(bankName) ~= "string" then
		ColourNote(errorColour, "", "BankPrintBank error: bankName is not of type string")
	end
	if type(amount) ~= "number" then
		ColourNote(errorColour, "", "BankPrintBank error: amount is not of type number")
	end
	if type(currency) ~= "string" then
		error("BankPrintBank error: currency is not of type string")	
	end

	if type(bankName) == "string" and type(amount) == "number" and type(currency) == "string" then
		local bankArray = BankGetBankArray()

		-- Get max length of bank names
		local bankNameTable = {}
		for key, value in pairs(bankArray) do
			table.insert(bankNameTable, key)
		end
		local bankNameStringMaxLength = table.valueMaxStringLength(bankNameTable)

		-- Get max length of local currency amounts
		local localTable = {}
		for key, value in pairs(bankArray) do
			local localAmount = value.amount
			local localCurrency = value.currency
			local localMoney = WichitBeadsToCurrency(localAmount, localCurrency)

			table.insert(localTable, localMoney)
		end
		local localStringMaxLength = table.valueMaxStringLength(localTable)

		-- Get max length of AM currency amount
		local amTable = {}
		for key, value in pairs(bankArray) do
			local amAmount = value.amount
			local amMoney = WichitBeadsToCurrency(amAmount, "AM")
			table.insert(amTable, amMoney)
		end
		local amStringMaxLength = table.valueMaxStringLength(amTable)

		local localAmount = WichitBeadsToCurrency(amount, currency)
		local amAmount = WichitBeadsToCurrency(amount, "AM")
		amAmount = string.gsub(amAmount, "A%$", "")
		ColourTell(bankNameColour, "", string.addLeadingTrailing(bankName, bankNameStringMaxLength, " ", true))
		Tell(" ")

		if currency ~= "" then
			ColourTell(moneyColour, "", string.addLeadingTrailing(localAmount, localStringMaxLength, " ", true))
			Tell(" (")
			ColourTell(moneyColour, "", "A$")
			ColourTell(moneyColour, "", string.addLeadingTrailing(amAmount, amStringMaxLength - 2, " ", false))
			Tell(")")
		end
		Note("")
	end
end

function BankPrintAllBanks()
	local bankArray = BankGetBankArray()
	if type(bankArray) == "table" then
		local bankTable = {}
		for key, value in pairs(bankArray) do
			table.insert(bankTable, {name = key, amount = value.amount, currency = value.currency})
		end
		table.sort(bankTable, function (k1,k2) return string.lower(k1.name) < string.lower(k2.name) end)
		for _, value in ipairs(bankTable) do
			BankPrintBank(value.name, value.amount, value.currency)
		end
	else
		error("BankPrintAllBanks error: bankArray is not of type table")
	end
end
--#endregion

--#region Variable functions

--#region Get
function BankGetBankArray()
    local bankArray
    local bankBalancesString = GetVariable("bankBalances")

    local success, res = pcall(json.decode, bankBalancesString);
    if success then
        bankArray = res
    else
        bankArray = {}
        for bankInfoKey, bankInfoValue in pairs(banksInfo) do
            bankArray[bankInfoKey] = {
                amount = 0,
                currency = "",
            }
        end
    end
    return bankArray
end
-- end

function BankGetCurrent()
	local result = GetVariable("bankCurrent") or ""
	return result
end

function BankGetTotalMoney()
	local bankArray = BankGetBankArray()
	local totalWichitBeads = 0

	for _, value in pairs(bankArray) do
		totalWichitBeads = totalWichitBeads + value.amount
	end
	return WichitBeadsToCurrency(totalWichitBeads, "AM")
end
--#endregion

--#region Set
function BankSetAmount(name, output, wildcards)
	local bankArray = BankGetBankArray()
	local bankName = BankGetCurrent()
	local localMoney = wildcards[2]
	local currencyType = CurrencyGetType(localMoney)
	local lowestDenomination = CurrencyToLowestDenomination(localMoney, currencyType)
	local wichitBeads = CurrencyToWichitBeads(lowestDenomination, currencyType)

	if bankArray[bankName] then
		bankArray[bankName].amount = wichitBeads
		bankArray[bankName].currency = currencyType
	else
		bankArray[bankName] = { amount = wichitBeads, currency = currencyType }
	end

	BankSetBankBalances(bankArray)
end

function BankSetBankBalances(bankArray)
	if type(bankArray) == "table" then
		SetVariable("bankBalances", json.encode(bankArray))
	else
		Note("BankSetBankBalances error: bankArray is not of type table.")
	end
end

function BankSetCurrent(name, output, wildcards)
	local currentBank = wildcards[1]
	if type(currentBank) == "string" then
		for key, value in pairs(banksInfo) do
			if string.match(value.locations, currentBank) then
				SetVariable("bankCurrent", key)
				break
			end
		end
	else
		Note("BankSetCurrent error: wildcard match is not of type string.")
	end
end

function BankSetPurse(name, output, wildcards)
	local moneyString = wildcards[1]
	if type(moneyString) == "string" then
		SetVariable("bankPurseContents", "")
		SetVariable("bankPurseContentsHalf", "")

		if moneyString ~= "only moths" then
			moneyString = string.gsub(moneyString, " and ", ", ")
			while string.find(moneyString, "one") do
				moneyString = string.gsub(moneyString, "one", "1")
			end
			SetVariable("bankPurseContents", moneyString)
			local moneyTable = string.toTable(moneyString, ", ")
			for i = 1, #moneyTable, 1 do
				local newAmount = string.match(moneyTable[i], "%d+")
				if (newAmount*1 > 1) then
					moneyTable[i] = string.gsub(moneyTable[i], "%d+", math.floor(newAmount/2))
				end
			end
			SetVariable("bankPurseContentsHalf", table.concat(moneyTable,", "))
		end
	else
		ColourNote("red", "", "BankSetPurse error: Matched is not of type string")
	end
end
--#endregion

--#region reset
function BankResetBalances()
	DeleteVariable("bankBalances")
	local bankArray = BankGetBankArray()
	BankSetBankBalances(bankArray)
end
--#endregion

--#endregion

--#region Currency functions
function CurrencyGetType(fullMoneyString)
    for currencyType, regexes in pairs(currencyTypes) do
        for _, regex in pairs(regexes) do
            if string.find(fullMoneyString, regex) then
                return currencyType
            end
        end
    end
end

function CurrencyGetType(fullMoneyString)
	for type, info in pairs(regionInformation) do
		for _, regex in pairs(info.regexFind) do
			if string.find(fullMoneyString, regex) then
				return type
			end
		end
	end
end

function CurrencyToLowestDenomination(money, type)
	local amount = 0

	if type == "AM" then
		local dollar = tonumber(string.match(money, "A%$([%d.]+)")) or 0
		local penny = tonumber(string.match(money, "(%d+)p")) or 0
		amount = dollar*100 + penny
	elseif type == "BP" then
		local rhinu = string.match(money, "(%d+)Rh") or 0
		local saveloy = string.match(money, "(%d+)s") or 0
		amount = (tonumber(rhinu)*120) + tonumber(saveloy)
	elseif type == "LAN" then
		local multiplicationTable = {82944,6912,576,48,4}
		if (string.match(money, "(%d+)/[24]")) then
			amount = tonumber(string.match(money, "(%d+)/4")) or tonumber(string.match(money, "(%d+)/2") or 0) * 2
		end
		money = string.gsub(money, "-", "0")
		money = string.gsub(money, "(%d+)/[24]", "0")
		money = string.match(money, "([%d+|-]+)")
		local moneyTable = string.toTable(money,"|")
		for i = 1, #moneyTable do
			amount = amount + ((moneyTable[i] or 0) * multiplicationTable[i])
		end
	elseif type == "GEN" then
		local multiplicationTable = {1,100,1000,10000}
		money = string.gsub(money, "G%a", "")
		money = string.match(money, "[%d,?]+")
		local amountTable = string.toTable(money, ",")
		table.reverse(amountTable)
		for i = 1, #amountTable, 1 do
			amount = amount + (amountTable[i] * multiplicationTable[i])
		end
	elseif type == "DJB" then
		local toons = string.match(money, "DjToon ([%d.]+)") or 0
		amount = tonumber(toons)*100
	elseif type == "EPH" then
		local mina = tonumber(string.match(money, "(%d+)M")) or 0
		local stater = tonumber(string.match(money, "S(%d+)")) or 0
		local derechmus = tonumber(string.match(money, "(%d+)de")) or 0
		amount = mina * 4800 + stater * 96 + derechmus
	elseif type == "KLA" then
		money = string.gsub(money, " dr", "")
		if string.find(money, ",") then
			amount = tonumber(string.gsub(money, ",", ""))
		else
			amount = tonumber(money) * 100
		end
	end
	return amount
end

function CurrencyToWichitBeads(baseDenominationMoney, coinType)
    if type(baseDenominationMoney) ~= "number" then
        error("baseDenominationMoney must be a number")
    end
    if type(coinType) ~= "string" then
        error("type must be a string")
    end
    local info = regionInformation[coinType]
    if info then
        return baseDenominationMoney * info.wichitBeads
    else
        error("Unsupported type: "..coinType)
    end
end

function WichitBeadsToCurrency(wichitBeads, type)
	local region = regionInformation[type]
	if region then
		local returnString = ""
		local lowestDenomination = wichitBeads/region.wichitBeads

		for _, denomination in ipairs(region.denominations) do
			denomination.amount = math.floor(lowestDenomination/denomination.value)
			lowestDenomination = math.floor(lowestDenomination % denomination.value)
		end


		if type == "AM" or type == "DJB" then
			for _, value in ipairs(region.denominations) do
				returnString = returnString .. value.name .. value.amount .. "." .. lowestDenomination
			end
		elseif type == "BP" then
			for _, value in ipairs(region.denominations) do
				if value.amount > 0 then
					returnString = returnString .. value.amount .. value.name .. " "
				end
			end
		elseif type == "EPH" then
			local result = {}
			if region.denominations[1].amount > 0 then
				table.insert(result, region.denominations[1].amount .. "M ")
			end
			if region.denominations[2].amount > 0 then
				table.insert(result, "S" .. region.denominations[2].amount .. "|")
			end
			table.insert(result, region.denominations[3].amount .. "de")

			returnString = table.concat(result, "")
		elseif type == "GEN" then
			local resultString = ""
			for index, denomination in ipairs(region.denominations) do
				if denomination.amount > 0 then
					resultString = denomination.amount
					for i = index+1, #region.denominations, 1 do
						resultString = resultString .. "," .. region.denominations[i].amount
					end
					resultString = resultString .. denomination.name
					break
				end
			end
			returnString = resultString
		elseif type == "LAN" then
			local resultString = ""
			for index, denomination in ipairs(region.denominations) do
				if denomination.amount > 0 then
					resultString = denomination.name .. " " .. denomination.amount
					for i = index+1, #region.denominations, 1 do
						resultString = resultString .. "|" .. region.denominations[i].amount
					end
					break
				end
			end

			if lowestDenomination == 3 then
				resultString = resultString .. " 3/4"
			elseif lowestDenomination == 2 then
				resultString = resultString .. " 1/2"
			elseif lowestDenomination == 1 then
				resultString = resultString .. " 1/4"
			end

			returnString = resultString:gsub("|0","|-")
		elseif type == "KLA" then
			returnString = region.denominations[1].amount .. "." .. lowestDenomination .. region.denominations[1].name
		end
		return returnString
	end
end
--#endregion
]]>
</script> 

<!--  Triggers  -->
<triggers>
	<!-- Bank Triggers -->
		<trigger
			enabled="y"
			regexp="y"
			match="(You have|This gives a total of) (.*) in your account( after the withdrawal)?\."
			name="lblBankSetAmount"
			group="BankTrigger"
			script="BankSetAmount"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(Bing\'s First Bank)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(branch of Bing\'s Bank)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(neat branch of Bing\'s bank)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(Lancrastian Farmers\' Cooperative Bank)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(branch of the First Imperial Bank of the Empire)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(First Imperial Bank of the Empire)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			match="\[(Klatchian Continental Bank)\]"
			group="BankTrigger"
			script="BankSetCurrent"
			sequence="100"
		>
		</trigger>
		<trigger
			enabled="y"
			regexp="y"
			script="BankSetCurrent"
			group="BankTrigger"
			match="\[(Genua National Bank)\]"
			sequence="100"
		>
		</trigger>
	<!-- Purse Triggers -->
		<trigger
			enabled="y"
			regexp="y"
			match="^Your purse contains (.*)\.$"
			group="BankTrigger"
			script="BankSetPurse"
			sequence="100"
		>
		</trigger>
</triggers>

<!--  Aliases  -->
<aliases>
	<alias
		enabled="y"
		regexp="y"
		ignore_case="y"
		match="^banks?$"
		group="BankAlias"
		script="BankPrintAllInfo"
		sequence="100"
	>
	</alias>
	<alias
		enabled="y"
		regexp="y"
		ignore_case="y"
		match="banks?reset"
		group="BankAlias"
		script="BankResetBalances"
		sequence="100"
	>
	</alias>
	<alias
		enabled="y"
		regexp="y"
		ignore_case="y"
		match="^deposithalf$"
		group="BankAlias"
		script="BankDepositHalfMoney"
		sequence="100"
	>
	</alias>
</aliases>

<!--  Timers  -->
<timers>
</timers>

</muclient>