Untitled diff

Created Diff never expires
107 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
885 lines
104 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
884 lines


package.path = package.path .. ";data/scripts/lib/?.lua"
package.path = package.path .. ";data/scripts/lib/?.lua"
require ("galaxy")
require ("galaxy")
require ("utility")
require ("utility")
require ("goods")
require ("goods")
require ("stringutility")
require ("stringutility")
require ("player")
require ("player")
require ("faction")
require ("faction")
require ("merchantutility")


local PublicNamespace = {}


local TradingManager = {}
local TradingManager = {}
TradingManager.__index = TradingManager
TradingManager.__index = TradingManager


local function new()
local function new()
local instance = {}
local instance = {}


instance.buyPriceFactor = 1
instance.buyPriceFactor = 1
instance.sellPriceFactor = 1
instance.sellPriceFactor = 1
instance.tax = 0.0 -- tax is the amount of money the owner of the entity gets from transactions
instance.factionPaymentFactor = 1.0 -- the amount of money the owner of the entity pays or receives directly through transactions


instance.boughtGoods = {}
instance.boughtGoods = {}
instance.soldGoods = {}
instance.soldGoods = {}


instance.numSold = 0
instance.numSold = 0
instance.numBought = 0
instance.numBought = 0


instance.buyFromOthers = true
instance.sellToOthers = true

instance.activelyRequest = false
instance.activelySell = false

instance.deliveredStations = {}
instance.deliveringStations = {}

instance.policies =
instance.policies =
{
{
sellsIllegal = false,
sellsIllegal = false,
buysIllegal = false,
buysIllegal = false,


sellsStolen = false,
sellsStolen = false,
buysStolen = false,
buysStolen = false,


sellsSuspicious = false,
sellsSuspicious = false,
buysSuspicious = false,
buysSuspicious = false,
}
}


-- UI
-- UI
instance.boughtLines = {}
instance.boughtLines = {}
instance.soldLines = {}
instance.soldLines = {}


instance.guiInitialized = false
instance.guiInitialized = false
instance.useTimeCounter = 0 -- time counter for using up bought products
instance.useTimeCounter = 0 -- time counter for using up bought products
instance.useUpGoodsEnabled = true
instance.useUpGoodsEnabled = true


return setmetatable(instance, TradingManager)
return setmetatable(instance, TradingManager)
end

function TradingManager:getBuysFromOthers()
return self.buyFromOthers
end

function TradingManager:getSellsToOthers()
return self.sellToOthers
end

function TradingManager:setBuysFromOthers(value)
self.buyFromOthers = value
end

function TradingManager:setSellsToOthers(value)
self.sellToOthers = value
end
end


-- help functions
-- help functions
function TradingManager:isSoldBySelf(good)
function TradingManager:isSoldBySelf(good)
if good.illegal and not self.policies.sellsIllegal then
if good.illegal and not self.policies.sellsIllegal then
local msg = "This station doesn't sell illegal goods."%_t
local msg = "This station doesn't sell illegal goods."%_t
return false, msg
return false, msg
end
end


if good.stolen and not self.policies.sellsStolen then
if good.stolen and not self.policies.sellsStolen then
local msg = "This station doesn't sell stolen goods."%_t
local msg = "This station doesn't sell stolen goods."%_t
return false, msg
return false, msg
end
end


if good.suspicious and not self.policies.sellsSuspicious then
if good.suspicious and not self.policies.sellsSuspicious then
local msg = "This station doesn't sell suspicious goods."%_t
local msg = "This station doesn't sell suspicious goods."%_t
return false, msg
return false, msg
end
end


return true
return true
end
end


function TradingManager:isBoughtBySelf(good)
function TradingManager:isBoughtBySelf(good)
if good.illegal and not self.policies.buysIllegal then
if good.illegal and not self.policies.buysIllegal then
local msg = "This station doesn't buy illegal goods."%_t
local msg = "This station doesn't buy illegal goods."%_t
return false, msg
return false, msg
end
end


if good.stolen and not self.policies.buysStolen then
if good.stolen and not self.policies.buysStolen then
local msg = "This station doesn't buy stolen goods."%_t
local msg = "This station doesn't buy stolen goods."%_t
return false, msg
return false, msg
end
end


if good.suspicious and not self.policies.buysSuspicious then
if good.suspicious and not self.policies.buysSuspicious then
local msg = "This station doesn't buy suspicious goods."%_t
local msg = "This station doesn't buy suspicious goods."%_t
return false, msg
return false, msg
end
end


return true
return true
end
end


function TradingManager:generateGoods(min, max)
function TradingManager:generateGoods(min, max)
min = min or 10
min = min or 10
max = max or 15
max = max or 15


local numGoods = math.random(min, max)
local numGoods = math.random(min, max)


local bought = {}
local bought = {}
local sold = {}
local sold = {}
local existingGoods = {}
local existingGoods = {}


local maxNumGoods = tablelength(goodsArray)
local maxNumGoods = tablelength(goodsArray)


for i = 1, numGoods do
for i = 1, numGoods do
local index = math.random(1, maxNumGoods)
local index = math.random(1, maxNumGoods)
local g = goodsArray[index]
local g = goodsArray[index]
local good = g:good()
local good = g:good()


-- don't trade potentially illegal goods
-- don't trade potentially illegal goods
if self:isBoughtBySelf(good) then
if self:isBoughtBySelf(good) then


if existingGoods[good.name] == nil then
if existingGoods[good.name] == nil then


good.size = round(good.size, 2)
good.size = round(good.size, 2)
good.price = round(good.price)
good.price = round(good.price)
table.insert(bought, good)
table.insert(bought, good)
existingGoods[good.name] = 1
existingGoods[good.name] = 1
end
end


end
end
end
end


for i = 1, numGoods do
for i = 1, numGoods do
local index = math.random(1, maxNumGoods)
local index = math.random(1, maxNumGoods)
local g = goodsArray[index]
local g = goodsArray[index]
local good = g:good()
local good = g:good()


-- don't trade potentially illegal goods
-- don't trade potentially illegal goods
if self:isSoldBySelf(good.name) then
if self:isSoldBySelf(good.name) then


if existingGoods[good.name] == nil then
if existingGoods[good.name] == nil then
good.size = round(good.size, 2)
good.size = round(good.size, 2)
good.price = round(good.price)
good.price = round(good.price)


table.insert(sold, good)
table.insert(sold, good)
existingGoods[good.name] = 1
existingGoods[good.name] = 1
end
end
end
end
end
end


return bought, sold
return bought, sold
end
end


function TradingManager:restoreTradingGoods(data)
function TradingManager:restoreTradingGoods(data)
self.buyPriceFactor = data.buyPriceFactor
self.buyPriceFactor = data.buyPriceFactor
self.sellPriceFactor = data.sellPriceFactor
self.sellPriceFactor = data.sellPriceFactor
self.policies = data.policies
self.policies = data.policies


self.boughtGoods = {}
self.boughtGoods = {}
for _, g in pairs(data.boughtGoods) do
for _, g in pairs(data.boughtGoods) do
table.insert(self.boughtGoods, tableToGood(g))
table.insert(self.boughtGoods, tableToGood(g))
end
end


self.soldGoods = {}
self.soldGoods = {}
for _, g in pairs(data.soldGoods) do
for _, g in pairs(data.soldGoods) do
table.insert(self.soldGoods, tableToGood(g))
table.insert(self.soldGoods, tableToGood(g))
end
end


self.numBought = #self.boughtGoods
self.numBought = #self.boughtGoods
self.numSold = #self.soldGoods
self.numSold = #self.soldGoods

if data.buyFromOthers == nil then
self.buyFromOthers = true
else
self.buyFromOthers = data.buyFromOthers
end

if data.sellToOthers == nil then
self.sellToOthers = true
else
self.sellToOthers = data.sellToOthers
end

self.activelyRequest = data.activelyRequest or false
self.activelySell = data.activelySell or false

self.deliveredStations = data.deliveredStations or {}
self.deliveringStations = data.deliveringStations or {}
end
end


function TradingManager:secureTradingGoods()
function TradingManager:secureTradingGoods()
local data = {}
local data = {}
data.buyPriceFactor = self.buyPriceFactor
data.buyPriceFactor = self.buyPriceFactor
data.sellPriceFactor = self.sellPriceFactor
data.sellPriceFactor = self.sellPriceFactor
data.policies = self.policies
data.policies = self.policies


data.buyFromOthers = self.buyFromOthers
data.sellToOthers = self.sellToOthers
data.activelyRequest = self.activelyRequest
data.activelySell = self.activelySell

data.deliveredStations = self.deliveredStations
data.deliveringStations = self.deliveringStations


data.boughtGoods = {}
data.boughtGoods = {}
for _, g in pairs(self.boughtGoods) do
for _, g in pairs(self.boughtGoods) do
table.insert(data.boughtGoods, goodToTable(g))
table.insert(data.boughtGoods, goodToTable(g))
end
end


data.soldGoods = {}
data.soldGoods = {}
for _, g in pairs(self.soldGoods) do
for _, g in pairs(self.soldGoods) do
table.insert(data.soldGoods, goodToTable(g))
table.insert(data.soldGoods, goodToTable(g))
end
end


return data
return data
end
end


function TradingManager:initializeTrading(boughtGoodsIn, soldGoodsIn, policiesIn)
function TradingManager:initializeTrading(boughtGoodsIn, soldGoodsIn, policiesIn)


local entity = Entity()
local entity = Entity()
entity:waitUntilAsyncWorkFinished()


self.policies = policiesIn or self.policies
self.policies = policiesIn or self.policies


-- generate goods only once, this adds physical goods to the entity
-- generate goods only once, this adds physical goods to the entity
local generated = entity:getValue("goods_generated")
local generated = entity:getValue("goods_generated")
if not generated or generated ~= 1 then
if not generated or generated ~= 1 then
entity:setValue("goods_generated", 1)
entity:setValue("goods_generated", 1)
generated = false
generated = false
else
else
generated = true
generated = true
end
end


boughtGoodsIn = boughtGoodsIn or {}
boughtGoodsIn = boughtGoodsIn or {}
soldGoodsIn = soldGoodsIn or {}
soldGoodsIn = soldGoodsIn or {}


self.numBought = #boughtGoodsIn
self.numBought = #boughtGoodsIn
self.numSold = #soldGoodsIn
self.numSold = #soldGoodsIn


self.boughtGoods = {}
self.boughtGoods = {}


for i, v in ipairs(boughtGoodsIn) do
for i, v in ipairs(boughtGoodsIn) do
if not generated then
if not generated then
local maxStock = self:getMaxStock(v.size)
local maxStock = self:getMaxStock(v.size)
if maxStock > 0 then
if maxStock > 0 then


-- generate a random amount of things
-- generate a random amount of things
local amount
local amount
if math.random() < 0.65 then -- what they buy is most likely not available
if math.random() < 0.65 then -- what they buy is most likely not available
amount = 0
amount = 0
else
else
amount = math.random(1, maxStock)
amount = math.random(1, maxStock)


-- limit to a max value
-- limit to 500k value at max
local maxValue = 300 * 1000 * Balancing_GetSectorRichnessFactor(Sector():getCoordinates())
local maxValue = 200 * 10000 * Balancing_GetSectorRichnessFactor(Sector():getCoordinates())
amount = math.min(maxStock, math.floor(maxValue / v.price))
amount = math.min(maxStock, math.floor(maxValue / v.price))


-- but have at least 7 - 10
-- but have at least 7 - 10
amount = math.max(amount, math.random(7, 10))
amount = math.max(amount, math.random(7, 10))


-- ... if max stock allows it
-- ... if max stock allows it
amount = math.min(amount, maxStock)
amount = math.min(amount, maxStock)
end
end


entity:addCargo(v, amount)
entity:addCargo(v, amount)
end
end
end
end


table.insert(self.boughtGoods, v)
table.insert(self.boughtGoods, v)
end
end


self.soldGoods = {}
self.soldGoods = {}


for i, v in ipairs(soldGoodsIn) do
for i, v in ipairs(soldGoodsIn) do
if not generated then
if not generated then
local maxStock = self:getMaxStock(v.size)
local maxStock = self:getMaxStock(v.size)
if maxStock > 0 then
if maxStock > 0 then


-- generate a random amount of things
-- generate a random amount of things
local amount = 0
local amount = 0
if math.random() < 0.35 then -- what they sell is most likely available
if math.random() < 0.35 then -- what they sell is most likely available
amount = 0
amount = 0
else
else
amount = math.random(1, maxStock)
amount = math.random(1, maxStock)


-- limit to 500k value at max
-- limit to 500k value at max
local maxValue = 500 * 1000
local maxValue = 5000000
amount = math.min(maxStock, math.floor(maxValue / v.price))
amount = math.min(maxStock, math.floor(maxValue / v.price))


-- but have at least a few
-- but have at least a few
amount = math.max(amount, math.random(2, 5))
amount = math.max(amount, math.random(2, 5))


-- ... if max stock allows it
-- ... if max stock allows it
amount = math.min(amount, maxStock)
amount = math.min(amount, maxStock)
end
end


entity:addCargo(v, amount)
entity:addCargo(v, amount)
end
end
end
end


table.insert(self.soldGoods, v)
table.insert(self.soldGoods, v)
end
end


self.numBought = #self.boughtGoods
self.numBought = #self.boughtGoods
self.numSold = #self.soldGoods
self.numSold = #self.soldGoods


end
end


function TradingManager:requestGoods()
function TradingManager:requestGoods()
self.boughtGoods = {}
self.boughtGoods = {}
self.soldGoods = {}
self.soldGoods = {}


self.numBought = 0
self.numBought = 0
self.numSold = 0
self.numSold = 0


invokeServerFunction("sendGoods", Player().index)
invokeServerFunction("sendGoods", Player().index)
end
end


function TradingManager:sendGoods(playerIndex)
function TradingManager:sendGoods(playerIndex)


local player = Player(playerIndex)
local player = Player(playerIndex)


invokeClientFunction(player, "receiveGoods", self.buyPriceFactor, self.sellPriceFactor, self.boughtGoods, self.soldGoods, self.policies)
invokeClientFunction(player, "receiveGoods", self.buyPriceFactor, self.sellPriceFactor, self.boughtGoods, self.soldGoods, self.policies)
end
end


function TradingManager:receiveGoods(buyFactor, sellFactor, boughtGoods_in, soldGoods_in, policies_in)
function TradingManager:receiveGoods(buyFactor, sellFactor, boughtGoods_in, soldGoods_in, policies_in)


self.buyPriceFactor = buyFactor
self.buyPriceFactor = buyFactor
self.sellPriceFactor = sellFactor
self.sellPriceFactor = sellFactor


self.policies = policies_in
self.policies = policies_in


self.boughtGoods = boughtGoods_in
self.boughtGoods = boughtGoods_in
self.soldGoods = soldGoods_in
self.soldGoods = soldGoods_in


self.numBought = #self.boughtGoods
self.numBought = #self.boughtGoods
self.numSold = #self.soldGoods
self.numSold = #self.soldGoods


local player = Player()
local playerCraft = player.craft
if playerCraft.factionIndex == player.allianceIndex then
player = player.alliance
end

for i, good in ipairs(self.boughtGoods) do
for i, good in ipairs(self.boughtGoods) do
self:updateBoughtGoodGui(i, good, self:getBuyPrice(good.name, player.index))
self:updateBoughtGoodGui(i, good, self:getBuyPrice(good.name, Player().index))
end
end


for i, good in ipairs(self.soldGoods) do
for i, good in ipairs(self.soldGoods) do
self:updateSoldGoodGui(i, good, self:getSellPrice(good.name, player.index))
self:updateSoldGoodGui(i, good, self:getSellPrice(good.name, Player().index))
end
end


end
end


function TradingManager:updateBoughtGoodGui(index, good, price)
function TradingManager:updateBoughtGoodGui(index, good, price)


if not self.guiInitialized then return end
if not self.guiInitialized then return end


local maxAmount = self:getMaxStock(good.size)
local maxAmount = self:getMaxStock(good.size)
local amount = self:getNumGoods(good.name)
local amount = self:getNumGoods(good.name)


local line = self.boughtLines[index]
local line = self.boughtLines[index]


line.name.caption = good.displayName
line.name.caption = good.displayName
line.stock.caption = amount .. "/" .. maxAmount
line.stock.caption = amount .. "/" .. maxAmount
line.price.caption = createMonetaryString(price)
line.price.caption = createMonetaryString(price)
line.size.caption = round(good.size, 2)
line.size.caption = round(good.size, 2)
line.icon.picture = good.icon
line.icon.picture = good.icon


local ownCargo = 0
local ownCargo = 0
local ship = Entity(Player().craftIndex)
local ship = Entity(Player().craftIndex)
if ship then
if ship then
ownCargo = ship:getCargoAmount(good) or 0
ownCargo = ship:getCargoAmount(good) or 0
end
end
if ownCargo == 0 then ownCargo = "-" end
if ownCargo == 0 then ownCargo = "-" end
line.you.caption = tostring(ownCargo)
line.you.caption = tostring(ownCargo)


line:show()
line:show()
end
end


function TradingManager:updateSoldGoodGui(index, good, price)
function TradingManager:updateSoldGoodGui(index, good, price)


if not self.guiInitialized then return end
if not self.guiInitialized then return end


local maxAmount = self:getMaxStock(good.size)
local maxAmount = self:getMaxStock(good.size)
local amount = self:getNumGoods(good.name)
local amount = self:getNumGoods(good.name)


local line = self.soldLines[index]
local line = self.soldLines[index]


line.icon.picture = good.icon
line.icon.picture = good.icon
line.name.caption = good.displayName
line.name.caption = good.displayName
line.stock.caption = amount .. "/" .. maxAmount
line.stock.caption = amount .. "/" .. maxAmount
line.price.caption = createMonetaryString(price)
line.price.caption = createMonetaryString(price)
line.size.caption = round(good.size, 2)
line.size.caption = round(good.size, 2)


for i, good in pairs(self.soldGoods) do
for i, good in pairs(self.soldGoods) do
local line = self.soldLines[i]
local line = self.soldLines[i]


local ownCargo = 0
local ownCargo = 0
local ship = Entity(Player().craftIndex)
local ship = Entity(Player().craftIndex)
if ship then
if ship then
ownCargo = math.floor((ship.freeCargoSpace or 0) / good.size)
ownCargo = math.floor((ship.freeCargoSpace or 0) / good.size)
end
end


if ownCargo == 0 then ownCargo = "-" end
if ownCargo == 0 then ownCargo = "-" end
line.you.caption = tostring(ownCargo)
line.you.caption = tostring(ownCargo)
end
end


line:show()
line:show()


end
end


function TradingManager:updateBoughtGoodAmount(index)
function TradingManager:updateBoughtGoodAmount(index)


local good = self.boughtGoods[index];
local good = self.boughtGoods[index];


if good ~= nil then -- it's possible that the production may start before the initialization of the client version of the factory
if good ~= nil then -- it's possible that the production may start before the initialization of the client version of the factory
local player = Player()
self:updateBoughtGoodGui(index, good, self:getBuyPrice(good.name, Player().index))
local playerCraft = player.craft
if playerCraft.factionIndex == player.allianceIndex then
player = player.alliance
end

self:updateBoughtGoodGui(index, good, self:getBuyPrice(good.name, player.index))
end
end


end
end


function TradingManager:updateSoldGoodAmount(index)
function TradingManager:updateSoldGoodAmount(index)


local good = self.soldGoods[index];
local good = self.soldGoods[index];


if good ~= nil then -- it's possible that the production may start before the initialization of the client version of the factory
if good ~= nil then -- it's possible that the production may start before the initialization of the client version of the factory
local player = Player()
self:updateSoldGoodGui(index, good, self:getSellPrice(good.name, Player().index))
local playerCraft = player.craft
if playerCraft.factionIndex == player.allianceIndex then
player = player.alliance
end

self:updateSoldGoodGui(index, good, self:getSellPrice(good.name, player.index))
end
end
end
end


function TradingManager:buildBuyGui(window)
function TradingManager:buildBuyGui(window)
self:buildGui(window, 1)
self:buildGui(window, 1)
end
end


function TradingManager:buildSellGui(window)
function TradingManager:buildSellGui(window)
self:buildGui(window, 0)
self:buildGui(window, 0)
end
end


function TradingManager:buildGui(window, guiType)
function TradingManager:buildGui(window, guiType)


local buttonCaption = ""
local buttonCaption = ""
local buttonCallback = ""
local buttonCallback = ""
local textCallback = ""
local textCallback = ""


if guiType == 1 then
if guiType == 1 then
buttonCaption = "Buy"%_t
buttonCaption = "Buy"%_t
buttonCallback = "onBuyButtonPressed"
buttonCallback = "onBuyButtonPressed"
textCallback = "onBuyTextEntered"
textCallback = "onBuyTextEntered"
else
else
buttonCaption = "Sell"%_t
buttonCaption = "Sell"%_t
buttonCallback = "onSellButtonPressed"
buttonCallback = "onSellButtonPressed"
textCallback = "onSellTextEntered"
textCallback = "onSellTextEntered"
end
end


local size = window.size
local size = window.size


-- window:createFrame(Rect(size))
-- window:createFrame(Rect(size))


local pictureX = 270
local pictureX = 270
local nameX = 10
local nameX = 10
local stockX = 310
local stockX = 310
local volX = 460
local volX = 460
local priceX = 530
local priceX = 530
local youX = 630
local youX = 630
local textBoxX = 720
local textBoxX = 720
local buttonX = 790
local buttonX = 790


local buttonSize = 70
local buttonSize = 70


-- header
-- header
window:createLabel(vec2(nameX, 0), "Name"%_t, 15)
window:createLabel(vec2(nameX, 0), "Name"%_t, 15)
window:createLabel(vec2(stockX, 0), "Stock"%_t, 15)
window:createLabel(vec2(stockX, 0), "Stock"%_t, 15)
window:createLabel(vec2(priceX, 0), "Cr"%_t, 15)
window:createLabel(vec2(priceX, 0), "Cr"%_t, 15)
window:createLabel(vec2(volX, 0), "Vol"%_t, 15)
window:createLabel(vec2(volX, 0), "Vol"%_t, 15)


if guiType == 1 then
if guiType == 1 then
window:createLabel(vec2(youX, 0), "Max"%_t, 15)
window:createLabel(vec2(youX, 0), "Max"%_t, 15)
else
else
window:createLabel(vec2(youX, 0), "You"%_t, 15)
window:createLabel(vec2(youX, 0), "You"%_t, 15)
end
end


local y = 25
local y = 25
for i = 1, 15 do
for i = 1, 15 do


local yText = y + 6
local yText = y + 6


local frame = window:createFrame(Rect(0, y, textBoxX - 10, 30 + y))
local frame = window:createFrame(Rect(0, y, textBoxX - 10, 30 + y))


local icon = window:createPicture(Rect(pictureX, yText - 5, 29 + pictureX, 29 + yText - 5), "")
local icon = window:createPicture(Rect(pictureX, yText - 5, 29 + pictureX, 29 + yText - 5), "")
local nameLabel = window:createLabel(vec2(nameX, yText), "", 15)
local nameLabel = window:createLabel(vec2(nameX, yText), "", 15)
local stockLabel = window:createLabel(vec2(stockX, yText), "", 15)
local stockLabel = window:createLabel(vec2(stockX, yText), "", 15)
local priceLabel = window:createLabel(vec2(priceX, yText), "", 15)
local priceLabel = window:createLabel(vec2(priceX, yText), "", 15)
local sizeLabel = window:createLabel(vec2(volX, yText), "", 15)
local sizeLabel = window:createLabel(vec2(volX, yText), "", 15)
local youLabel = window:createLabel(vec2(youX, yText), "", 15)
local youLabel = window:createLabel(vec2(youX, yText), "", 15)
local numberTextBox = window:createTextBox(Rect(textBoxX, yText - 6, 60 + textBoxX, 30 + yText - 6), textCallback)
local numberTextBox = window:createTextBox(Rect(textBoxX, yText - 6, 60 + textBoxX, 30 + yText - 6), textCallback)
local button = window:createButton(Rect(buttonX, yText - 6, window.size.x, 30 + yText - 6), buttonCaption, buttonCallback)
local button = window:createButton(Rect(buttonX, yText - 6, window.size.x, 30 + yText - 6), buttonCaption, buttonCallback)


button.maxTextSize = 16
button.maxTextSize = 16


numberTextBox.text = "0"
numberTextBox.text = "0"
numberTextBox.allowedCharacters = "0123456789"
numberTextBox.allowedCharacters = "0123456789"
numberTextBox.clearOnClick = 1
numberTextBox.clearOnClick = 1


icon.isIcon = 1
icon.isIcon = 1


local show = function (self)
local show = function (self)
self.icon:show()
self.icon:show()
self.frame:show()
self.frame:show()
self.name:show()
self.name:show()
self.stock:show()
self.stock:show()
self.price:show()
self.price:show()
self.size:show()
self.size:show()
self.number:show()
self.number:show()
self.button:show()
self.button:show()
self.you:show()
self.you:show()
end
end
local hide = function (self)
local hide = function (self)
self.icon:hide()
self.icon:hide()
self.frame:hide()
self.frame:hide()
self.name:hide()
self.name:hide()
self.stock:hide()
self.stock:hide()
self.price:hide()
self.price:hide()
self.size:hide()
self.size:hide()
self.number:hide()
self.number:hide()
self.button:hide()
self.button:hide()
self.you:hide()
self.you:hide()
end
end


local line = {icon = icon, frame = frame, name = nameLabel, stock = stockLabel, price = priceLabel, you = youLabel, size = sizeLabel, number = numberTextBox, button = button, show = show, hide = hide}
local line = {icon = icon, frame = frame, name = nameLabel, stock = stockLabel, price = priceLabel, you = youLabel, size = sizeLabel, number = numberTextBox, button = button, show = show, hide = hide}
line:hide()
line:hide()


if guiType == 1 then
if guiType == 1 then
table.insert(self.soldLines, line)
table.insert(self.soldLines, line)
else
else
table.insert(self.boughtLines, line)
table.insert(self.boughtLines, line)
end
end


y = y + 35
y = y + 35
end
end


end
end


function TradingManager:onBuyTextEntered(textBox)
function TradingManager:onBuyTextEntered(textBox)


local enteredNumber = tonumber(textBox.text)
local enteredNumber = tonumber(textBox.text)
if enteredNumber == nil then
if enteredNumber == nil then
enteredNumber = 0
enteredNumber = 0
end
end


local newNumber = enteredNumber
local newNumber = enteredNumber


local goodIndex = nil
local goodIndex = nil
for i, line in pairs(self.soldLines) do
for i, line in pairs(self.soldLines) do
if line.number.index == textBox.index then
if line.number.index == textBox.index then
goodIndex = i
goodIndex = i
break
break
end
end
end
end


if goodIndex == nil then return end
if goodIndex == nil then return end


local good = self.soldGoods[goodIndex]
local good = self.soldGoods[goodIndex]


if not good then
if not good then
print ("good with index " .. goodIndex .. " isn't sold.")
print ("good with index " .. goodIndex .. " isn't sold.")
printEntityDebugInfo()
printEntityDebugInfo()
return
return
end
end


-- make sure the player can't buy more than the station has in stock
-- make sure the player can't buy more than the station has in stock
local stock = self:getNumGoods(good.name)
local stock = self:getNumGoods(good.name)


if stock < newNumber then
if stock < newNumber then
newNumber = stock
newNumber = stock
end
end


local player = Player()
local player = Player()
local ship = player.craft
local ship = player.craft
local shipFaction
local shipFaction
if ship.factionIndex == player.allianceIndex then
if ship.factionIndex == player.allianceIndex then
shipFaction = player.alliance
shipFaction = player.alliance
end
end
if shipFaction == nil then
if shipFaction == nil then
shipFaction = player
shipFaction = player
end
end
if ship.freeCargoSpace == nil then return end --> no cargo bay
if ship.freeCargoSpace == nil then return end --> no cargo bay


-- make sure the player does not buy more than he can have in his cargo bay
-- make sure the player does not buy more than he can have in his cargo bay
local maxShipHold = math.floor(ship.freeCargoSpace / good.size)
local maxShipHold = math.floor(ship.freeCargoSpace / good.size)
local msg
local msg


if maxShipHold < newNumber then
if maxShipHold < newNumber then
newNumber = maxShipHold
newNumber = maxShipHold
if newNumber == 0 then
if newNumber == 0 then
msg = "Not enough space in your cargo bay!"%_t
msg = "Not enough space in your cargo bay!"%_t
else
else
msg = "You can only store ${amount} of this good!"%_t % {amount = newNumber}
msg = "You can only store ${amount} of this good!"%_t % {amount = newNumber}
end
end
end
end


-- make sure the player does not buy more than he can afford (if this isn't his station)
-- make sure the player does not buy more than he can afford (if this isn't his station)
if Faction().index ~= shipFaction.index then
if Faction().index ~= shipFaction.index then
local maxAffordable = math.floor(shipFaction.money / self:getSellPrice(good.name, shipFaction.index))
local maxAffordable = math.floor(shipFaction.money / self:getSellPrice(good.name, shipFaction.index))
if shipFaction.infiniteResources then maxAffordable = math.huge end
if shipFaction.infiniteResources then maxAffordable = math.huge end


if maxAffordable < newNumber then
if maxAffordable < newNumber then
newNumber = maxAffordable
newNumber = maxAffordable


if newNumber == 0 then
if newNumber == 0 then
msg = "You can't afford any of this good!"%_t
msg = "You can't afford any of this good!"%_t
else
else
msg = "You can only afford ${amount} of this good!"%_t % {amount = newNumber}
msg = "You can only afford ${amount} of this good!"%_t % {amount = newNumber}
end
end
end
end
end
end


if msg then
if msg then
self:sendError(nil, msg)
self:sendError(nil, msg)
end
end


if newNumber ~= enteredNumber then
if newNumber ~= enteredNumber then
textBox.text = newNumber
textBox.text = newNumber
end
end
end
end


function TradingManager:onSellTextEntered(textBox)
function TradingManager:onSellTextEntered(textBox)


local enteredNumber = tonumber(textBox.text)
local enteredNumber = tonumber(textBox.text)
if enteredNumber == nil then
if enteredNumber == nil then
enteredNumber = 0
enteredNumber = 0
end
end


local newNumber = enteredNumber
local newNumber = enteredNumber


local goodIndex = nil
local goodIndex = nil
for i, line in pairs(self.boughtLines) do
for i, line in pairs(self.boughtLines) do
if line.number.index == textBox.index then
if line.number.index == textBox.index then
goodIndex = i
goodIndex = i
break
break
end
end
end
end
if goodIndex == nil then return end
if goodIndex == nil then return end


local good = self.boughtGoods[goodIndex]
local good = self.boughtGoods[goodIndex]
if not good then
if not good then
print ("good with index " .. goodIndex .. " isn't bought")
print ("good with index " .. goodIndex .. " isn't bought")
printEntityDebugInfo();
printEntityDebugInfo();
return
return
end
end


local stock = self:getNumGoods(good.name)
local stock = self:getNumGoods(good.name)


local maxAmountPlaceable = self:getMaxStock(good.size) - stock;
local maxAmountPlaceable = self:getMaxStock(good.size) - stock;
if maxAmountPlaceable < newNumber then
if maxAmountPlaceable < newNumber then
newNumber = maxAmountPlaceable
newNumber = maxAmountPlaceable
end
end




local ship = Player().craft
local ship = Player().craft


local msg
local msg


-- make sure the player does not sell more than he has in his cargo bay
-- make sure the player does not sell more than he has in his cargo bay
local amountOnPlayerShip = ship:getCargoAmount(good)
local amountOnPlayerShip = ship:getCargoAmount(good)
if amountOnPlayerShip == nil then return end --> no cargo bay
if amountOnPlayerShip == nil then return end --> no cargo bay


if amountOnPlayerShip < newNumber then
if amountOnPlayerShip < newNumber then
newNumber = amountOnPlayerShip
newNumber = amountOnPlayerShip
if newNumber == 0 then
if newNumber == 0 then
msg = "You don't have any of this!"%_t
msg = "You don't have any of this!"%_t
end
end
end
end


if msg then
if msg then
self:sendError(nil, msg)
self:sendError(nil, msg)
end
end


-- maximum number of sellable things is the amount the player has on his ship
-- maximum number of sellable things is the amount the player has on his ship
if newNumber ~= enteredNumber then
if newNumber ~= enteredNumber then
textBox.text = newNumber
textBox.text = newNumber
end
end
end
end


function TradingManager:onBuyButtonPressed(button)
function TradingManager:onBuyButtonPressed(button)


local shipIndex = Player().craftIndex
local shipIndex = Player().craftIndex
local goodIndex = nil
local goodIndex = nil


for i, line in ipairs(self.soldLines) do
for i, line in ipairs(self.soldLines) do
if line.button.index == button.index then
if line.button.index == button.index then
goodIndex = i
goodIndex = i
end
end
end
end


if goodIndex == nil then
if goodIndex == nil then
print("internal error, good matching 'Buy' button doesn't exist.")
print("internal error, good matching 'Buy' button doesn't exist.")
return
return
end
end


local amount = self.soldLines[goodIndex].number.text
local amount = self.soldLines[goodIndex].number.text
if amount == "" then
if amount == "" then
amount = 0
amount = 0
else
else
amount = tonumber(amount)
amount = tonumber(amount)
end
end


local good = self.soldGoods[goodIndex]
local good = self.soldGoods[goodIndex]
if not good then
if not good then
print ("internal error, good with index " .. goodIndex .. " of buy button not found.")
print ("internal error, good with index " .. goodIndex .. " of buy button not found.")
printEntityDebugInfo()
printEntityDebugInfo()
return
return
end
end


invokeServerFunction("sellToShip", shipIndex, good.name, amount)
invokeServerFunction("sellToShip", shipIndex, good.name, amount)
end
end


function TradingManager:onSellButtonPressed(button)
function TradingManager:onSellButtonPressed(button)


local shipIndex = Player().craftIndex
local shipIndex = Player().craftIndex
local goodIndex = nil
local goodIndex = nil


for i, line in ipairs(self.boughtLines) do
for i, line in ipairs(self.boughtLines) do
if line.button.index == button.index then
if line.button.index == button.index then
goodIndex = i
goodIndex = i
end
end
end
end


if goodIndex == nil then
if goodIndex == nil then
return
return
end
end


local amount = self.boughtLines[goodIndex].number.text
local amount = self.boughtLines[goodIndex].number.text
if amount == "" then
if amount == "" then
amount = 0
amount = 0
else
else
amount = tonumber(amount)
amount = tonumber(amount)
end
end


local good = self.boughtGoods[goodIndex]
local good = self.boughtGoods[goodIndex]
if not good then
if not good then
print ("internal error, good with index " .. goodIndex .. " of sell button not found.")
print ("internal error, good with index " .. goodIndex .. " of sell button not found.")
printEntityDebugInfo()
printEntityDebugInfo()
return
return
end
end


invokeServerFunction("buyFromShip", shipIndex, good.name, amount)
invokeServerFunction("buyFromShip", shipIndex, good.name, amount)


end
end


function TradingManager:sendError(faction, msg, ...)
function TradingManager:sendError(faction, msg, ...)
if onServer() then
if onServer() then
if faction.isPlayer then
if faction.isPlayer then
Player(faction.index):sendChatMessage(Entity().title, 1, msg, ...)
Player(faction.index):sendChatMessage(Entity().title, 1, msg, ...)
end
end
elseif onClient() then
elseif onClient() then
displayChatMessage(msg, Entity().title, 1)
displayChatMessage(msg, Entity().title, 1)
end
end
end
end


function TradingManager:transferMoney(owner, from, to, amount, fromDescription, toDescription)
if from.index == to.index then return end

local ownerMoney = amount * self.factionPaymentFactor

if owner.index == from.index then
from:pay(fromDescription or "", ownerMoney)
to:receive(toDescription or "", amount)
elseif owner.index == to.index then
from:pay(fromDescription or "", amount)
to:receive(toDescription or "", ownerMoney)
else
from:pay(fromDescription or "", amount)
to:receive(toDescription or "", amount)
end

receiveTransactionTax(Entity(), amount * self.tax)
end

function TradingManager:buyFromShip(shipIndex, goodName, amount, noDockCheck)
function TradingManager:buyFromShip(shipIndex, goodName, amount, noDockCheck)


-- check if the good can be bought
-- check if the good can be bought
if not self:getBoughtGoodByName(goodName) == nil then
if not self:getBoughtGoodByName(goodName) == nil then
self:sendError(shipFaction, "%s isn't bought."%_t, goodName)
self:sendError(shipFaction, "%s isn't bought."%_t, goodName)
return
return
end
end


local shipFaction, ship = getInteractingFactionByShip(shipIndex, callingPlayer, AlliancePrivilege.SpendResources)
local shipFaction, ship = getInteractingFactionByShip(shipIndex, callingPlayer, AlliancePrivilege.SpendResources)
if not shipFaction then return end
if not shipFaction then return end


if ship.freeCargoSpace == nil then
if ship.freeCargoSpace == nil then
self:sendError(shipFaction, "Your ship has no cargo bay!"%_t)
self:sendError(shipFaction, "Your ship has no cargo bay!"%_t)
return
return
end
end


-- check if the specific good from the player can be bought (ie. it's not illegal or something like that)
-- check if the specific good from the player can be bought (ie. it's not illegal or something like that)
local cargos = ship:findCargos(goodName)
local cargos = ship:findCargos(goodName)
local good = nil
local good = nil
local msg = "You don't have any %s that the station buys!"%_t
local msg = "You don't have any %s that the station buys!"%_t
local args = {goodName}
local args = {goodName}


for g, amount in pairs(cargos) do
for g, amount in pairs(cargos) do
local ok
local ok
ok, msg = self:isBoughtBySelf(g)
ok, msg = self:isBoughtBySelf(g)
args = {}
args = {}
if ok then
if ok then
good = g
good = g
break
break
end
end
end
end


if not good then
if not good then
self:sendError(shipFaction, msg, unpack(args))
self:sendError(shipFaction, msg, unpack(args))
return
return
end
end


local station = Entity()
local station = Entity()
local stationFaction = Faction()
local stationFaction = Faction()


-- make sure the ship can not sell more than the station can have in stock
-- make sure the ship can not sell more than the station can have in stock
local maxAmountPlaceable = self:getMaxStock(good.size) - self:getNumGoods(good.name);
local maxAmountPlaceable = self:getMaxStock(good.size) - self:getNumGoods(good.name);


if maxAmountPlaceable < amount then
if maxAmountPlaceable < amount then
amount = maxAmountPlaceable
amount = maxAmountPlaceable


if maxAmountPlaceable == 0 then
if maxAmountPlaceable == 0 then
self:sendError(shipFaction, "This station is not able to take any more %s."%_t, good.translatablePlural)
self:sendError(shipFaction, "This station is not able to take any more %s."%_t, good.plural)
end
end
end
end


-- make sure the player does not sell more than he has in his cargo bay
-- make sure the player does not sell more than he has in his cargo bay
local amountOnShip = ship:getCargoAmount(good)
local amountOnShip = ship:getCargoAmount(good)


if amountOnShip < amount then
if amountOnShip < amount then
amount = amountOnShip
amount = amountOnShip


if amountOnShip == 0 then
if amountOnShip == 0 then
self:sendError(shipFaction, "You don't have any %s on your ship"%_t, good.translatablePlural)
self:sendError(shipFaction, "You don't have any %s on your ship"%_t, good.plural)
end
end
end
end


if amount <= 0 then
if amount == 0 then
return
return
end
end


-- begin transaction
-- begin transaction
-- calculate price. if the seller is the owner of the station, the price is 0
-- calculate price. if the seller is the owner of the station, the price is 0
local price = self:getBuyPrice(good.name, shipFaction.index) * amount
local price = self:getBuyPrice(good.name, shipFaction.index) * amount


local canPay, msg, args = stationFaction:canPay(price);
local canPay, msg, args = stationFaction:canPay(price);
if not canPay then
if not canPay then
self:sendError(shipFaction, "This station's faction doesn't have enough money."%_t)
self:sendError(shipFaction, "This station's faction doesn't have enough money."%_t)
return
return
end
end


if not noDockCheck then
if not noDockCheck then
-- test the docking last so the player can know what he can buy from afar already
-- test the docking last so the player can know what he can buy from afar already
local errors = {}
local errors = {}
errors[EntityType.Station] = "You must be docked to the station to trade
errors[EntityType.Station] = "You must be docked to the station to trade."%_T
errors[EntityType.Ship] = "You must be closer to the ship to trade."%_T
if not CheckShipDocked(shipFaction, ship, station, errors) then
return
end
end

-- give money to ship faction
shipFaction:receive(price)
stationFaction:pay(price)

-- remove goods from ship
ship:removeCargo(good, amount)

-- add goods to station
self:increaseGoods(good.name, amount)

-- trading (non-military) ships get higher relation gain
local relationsChange = GetRelationChangeFromMoney(price)
if ship:getNumArmedTurrets() <= 1 then
relationsChange = relationsChange * 1.5
end

Galaxy():changeFactionRelations(shipFaction, stationFaction, relationsChange)
end

function TradingManager:sellToShip(shipIndex, goodName, amount, noDockCheck)

local good = self:getSoldGoodByName(goodName)
if good == nil then return end

local shipFaction, ship = getInteractingFactionByShip(shipIndex, callingPlayer, AlliancePrivilege.SpendResources)
if not shipFaction then return end

if ship.freeCargoSpace == nil then
self:sendError(shipFaction, "Your ship has no cargo bay!"%_t)
return
end

local station = Entity()
local stationFaction = Faction()

-- make sure the player can not buy more than the station has in stock
local amountBuyable = self:getNumGoods(goodName)

if amountBuyable < amount then
amount = amountBuyable

if amountBuyable == 0 then
self:sendError(shipFaction, "This station has no more %s to sell."%_t, good.plural)
end
end

-- make sure the player does not buy more than he can have in his cargo bay
local maxShipHold = math.floor(ship.freeCargoSpace / good.size)

if maxShipHold < amount then
amount = maxShipHold

if maxShipHold == 0 then
self:sendError(shipFaction, "Your ship can not take more %s."%_t, good.plural)
end
end

if amount == 0 then
return
end

-- begin transaction
-- calculate price. if the owner of the station wants to buy, the price is 0
local price = self:getSellPrice(good.name, shipFaction.index) * amount

local canPay, msg, args = shipFaction:canPay(price);
if not canPay then
self:sendError(shipFaction, msg, unpack(args))
return
end

if not noDockCheck then
-- test the docking last so the player can know what he can buy from afar already
local errors = {}
errors[EntityType.Station] = "You must be docked to the station to trade."%_T
errors[EntityType.Ship] = "You must be closer to the ship to trade."%_T
if not CheckShipDocked(shipFaction, ship, station, errors) then
return
end
end

-- make player pay