Make your living in pioneer as a trader

Post Reply
akuballa
Posts: 2
Joined: Mon Apr 14, 2014 8:23 pm

Make your living in pioneer as a trader

Post by akuballa »

I found pioneer, when looking for games to play on linux. Interesting, even more after reading about the lua scripts. I like spacesims, so I a gave it a try. After some looks around, I found out that it would take a while to make enough money to buy a bigger ship to make more money. Thanks to a the lua scripts I took a shortcut to fortune and made my first billion. Mission bigger ship accomplished - back to the path of virtue. But to make your living in pioneer as a trader is harder than I thought, especially when you own a big ship. One click per item - in my case 960 per load and 1920 clicks per cargo run. I am a programmer, I have weak wrists, can't click that often :). So better typing than clicking I managed to replace the row click by buttons allowing me to by/sell 1/5/10 or 50 items at once. Filling my cargo bay with 20 clicks saves some livetime :).

1. Added 5 buy and 5 sell cells to stationColumnHeading and shipColumnHeading.
2. Moved onSell an onBuy from EquipmentTableWidgets.Pair to defaultFuncs so I can use them from CommodityMarket.lua.
3. Added config.noBuyOnRowClick and config.noSellOnRowClick params to disable onBuy and onSell triggered by shipTable.onRowClicked and stationTable.onRowClicked event (nicer counting).

data/ui/StationView/EquipmentTableWidgets.lua

Code: Select all

local Engine = import("Engine")
local Lang = import("Lang")
local Game = import("Game")
local EquipDef = import("EquipDef")
local utils = import("utils")
local Format = import("Format")

local MessageBox = import("ui/MessageBox")

local l = Lang.GetResource("ui-core")

-- XXX equipment strings are in core. this sucks
local lcore = Lang.GetResource("core")

local ui = Engine.ui

local equipIcon = {
	HYDROGEN =              "Hydrogen",
	LIQUID_OXYGEN =         "Liquid_Oxygen",
	METAL_ORE =             "Metal_ore",
	CARBON_ORE =            "Carbon_ore",
	METAL_ALLOYS =          "Metal_alloys",
	PLASTICS =              "Plastics",
	FRUIT_AND_VEG =         "Fruit_and_Veg",
	ANIMAL_MEAT =           "Animal_Meat",
	LIVE_ANIMALS =          "Live_Animals",
	LIQUOR =                "Liquor",
	GRAIN =                 "Grain",
	TEXTILES =              "Textiles",
	FERTILIZER =            "Fertilizer",
	WATER =                 "Water",
	MEDICINES =             "Medicines",
	CONSUMER_GOODS =        "Consumer_goods",
	COMPUTERS =             "Computers",
	ROBOTS =                "Robots",
	PRECIOUS_METALS =       "Precious_metals",
	INDUSTRIAL_MACHINERY =  "Industrial_machinery",
	FARM_MACHINERY =        "Farm_machinery",
	MINING_MACHINERY =      "Mining_machinery",
	AIR_PROCESSORS =        "Air_processors",
	SLAVES =                "Slaves",
	HAND_WEAPONS =          "Hand_weapons",
	BATTLE_WEAPONS =        "Battle_weapons",
	NERVE_GAS =             "Nerve_Gas",
	NARCOTICS =             "Narcotics",
	MILITARY_FUEL =         "Military_fuel",
	RUBBISH =               "Rubbish",
	RADIOACTIVES =          "Radioactive_waste",
}

local defaultFuncs = {
	-- can we trade in this item
	canTrade = function (e)
		return EquipDef[e].purchasable and EquipDef[e].slot == "CARGO" and Game.system:IsCommodityLegal(e)
	end,

	-- how much of this item do we have in stock?
	getStock = function (e)
		return Game.player:GetDockedWith():GetEquipmentStock(e)
	end,

	-- what do we charge for this item?
	getPrice = function (e)
		return Game.player:GetDockedWith():GetEquipmentPrice(e)
	end,

	-- do something when a "buy" button is clicked
	-- return true if the buy can proceed
	onClickBuy = function (e)
		return true -- allow buy
	end,

	-- do something when a "sell" button is clicked
	-- return true if the buy can proceed
	onClickSell = function (e)
		return true -- allow sell
	end,

	-- do something when we buy this commodity
	bought = function (e)
		-- add one to our stock
		Game.player:GetDockedWith():AddEquipmentStock(e, 1)
	end,

	-- do something when we sell this items
	sold = function (e)
		Game.player:GetDockedWith():AddEquipmentStock(e, -1)
	end,

	onBuy = function (e, funcs)
		if not funcs.onClickBuy(e) then
			return
		end

		if funcs.getStock(e) <= 0 then
			MessageBox.Message(l.ITEM_IS_OUT_OF_STOCK)
			return false
		end

		local player = Game.player

		-- if this ship model doesn't support fitting of this equip:
		if player:GetEquipSlotCapacity(EquipDef[e].slot) < 1 then
			MessageBox.Message(string.interp(l.NOT_SUPPORTED_ON_THIS_SHIP,
				 {equipment = EquipDef[e].name,}))
			return false
		end

		-- if ship maxed out in this slot
		if player:GetEquipFree(EquipDef[e].slot) < 1 then
			MessageBox.Message(l.SHIP_IS_FULLY_EQUIPPED)
			return false
		end

		-- if ship too heavy to support more
		if player.freeCapacity < EquipDef[e].mass then
			MessageBox.Message(l.SHIP_IS_FULLY_LADEN)
			return false
		end

		local price = funcs.getPrice(e)
		if player:GetMoney() < funcs.getPrice(e) then
			MessageBox.Message(l.YOU_NOT_ENOUGH_MONEY)
			return false
		end

		assert(player:AddEquip(e) == 1)
		player:AddMoney(-price)

		funcs.sold(e)
	end,

	onSell = function (e, funcs)
		if not funcs.onClickSell(e) then
			return
		end
		if Game.player:GetEquipCount(EquipDef[e].slot, e) > 0 then
			Game.player:RemoveEquip(e)
			Game.player:AddMoney(funcs.getPrice(e))
			funcs.bought(e)
		else
			return false
		end
	end
}

local stationColumnHeading = {
	icon   = "",
	name   = l.NAME_OBJECT,
	price  = l.PRICE,
	stock  = l.IN_STOCK,
	mass   = l.MASS,
	buy1   = "",
	buy5   = "",
	buy10  = "",
	buy50  = "",
}
local shipColumnHeading = {
	icon      = "",
	name      = l.NAME_OBJECT,
	amount    = l.AMOUNT,
	mass      = l.MASS,
	massTotal = l.TOTAL_MASS,
	sell1     = "",
	sell5     = "",
	sell10    = "",
	sell50    = "",
}

local defaultStationColumnValue = {
	icon  = function (e, funcs) return equipIcon[e] and ui:Image("icons/goods/"..equipIcon[e]..".png") or "" end,
	name  = function (e, funcs) return lcore[e] end,
	price = function (e, funcs) return Format.Money(funcs.getPrice(e)) end,
	stock = function (e, funcs) return funcs.getStock(e) end,
	mass  = function (e, funcs) return string.format("%dt", EquipDef[e].mass) end,
	buy1  = function (e, funcs) return "" end,
	buy5  = function (e, funcs) return "" end,
	buy10 = function (e, funcs) return "" end,
	buy50 = function (e, funcs) return "" end,
}

local defaultShipColumnValue = {
	icon      = function (e, funcs) return equipIcon[e] and ui:Image("icons/goods/"..equipIcon[e]..".png") or "" end,
	name      = function (e, funcs) return lcore[e] end,
	amount    = function (e, funcs) return Game.player:GetEquipCount(EquipDef[e].slot, e) end,
	mass      = function (e, funcs) return string.format("%dt", EquipDef[e].mass) end,
	massTotal = function (e, funcs) return string.format("%dt", Game.player:GetEquipCount(EquipDef[e].slot,e)*EquipDef[e].mass) end,
	sell1     = function (e, funcs) return "" end,
	sell5     = function (e, funcs) return "" end,
	sell10    = function (e, funcs) return "" end,
	sell50    = function (e, funcs) return "" end,
}


local EquipmentTableWidgets = {}

function EquipmentTableWidgets.Pair (config)
	local funcs = {
		canTrade = config.canTrade or defaultFuncs.canTrade,
		getStock = config.getStock or defaultFuncs.getStock,
		getPrice = config.getPrice or defaultFuncs.getPrice,
		onClickBuy = config.onClickBuy or defaultFuncs.onClickBuy,
		onClickSell = config.onClickSell or defaultFuncs.onClickSell,
		bought = config.bought or defaultFuncs.bought,
		sold = config.sold or defaultFuncs.sold,
		onBuy = defaultFuncs.onBuy,
		onSell = defaultFuncs.onSell,
	}

	local stationColumnValue = {
		icon  = config.icon  or defaultStationColumnValue.icon,
		name  = config.name  or defaultStationColumnValue.name,
		price = config.price or defaultStationColumnValue.price,
		stock = config.stock or defaultStationColumnValue.stock,
		mass  = config.mass  or defaultStationColumnValue.mass,
		buy1  = config.buy1  or defaultStationColumnValue.buy1,
		buy5  = config.buy5  or defaultStationColumnValue.buy5,
		buy10 = config.buy10 or defaultStationColumnValue.buy10,
		buy50 = config.buy50 or defaultStationColumnValue.buy50,
	}

	local shipColumnValue = {
		icon      = config.icon      or defaultShipColumnValue.icon,
		name      = config.name      or defaultShipColumnValue.name,
		amount    = config.amount    or defaultShipColumnValue.amount,
		mass      = config.mass      or defaultShipColumnValue.mass,
		massTotal = config.massTotal or defaultShipColumnValue.massTotal,
		sell1     = config.sell1     or defaultShipColumnValue.sell1,
		sell5     = config.sell5     or defaultShipColumnValue.sell5,
		sell10    = config.sell10    or defaultShipColumnValue.sell10,
		sell50    = config.sell50    or defaultShipColumnValue.sell50,
	}

	local equipTypes = {}
	for k,v in pairs(EquipDef) do
		if funcs.canTrade(v.id) and k ~= "NONE" then
			table.insert(equipTypes, k)
		end
	end
	table.sort(equipTypes)

	local stationTable =
		ui:Table()
			:SetRowSpacing(5)
			:SetColumnSpacing(10)
			:SetHeadingRow(utils.build_table(utils.map(function (k,v) return k,stationColumnHeading[v] end, ipairs(config.stationColumns))))
			:SetHeadingFont("LARGE")
			:SetRowAlignment("CENTER")
			:SetMouseEnabled(true)

	local function fillStationTable ()
		stationTable:ClearRows()

		local rowEquip = {}
		local row = 1
		for i=1,#equipTypes do
			local e = equipTypes[i]
			data = utils.build_table(utils.map(function (k,v) return k,stationColumnValue[v](e,funcs) end, ipairs(config.stationColumns)))
			stationTable:AddRow(data)
			rowEquip[row] = e
			row = row + 1
		end

		return rowEquip
	end
	local stationRowEquip = fillStationTable()

	local shipTable =
		ui:Table()
			:SetRowSpacing(5)
			:SetColumnSpacing(10)
			:SetHeadingRow(utils.build_table(utils.map(function (k,v) return k,shipColumnHeading[v] end, ipairs(config.shipColumns))))
			:SetHeadingFont("LARGE")
			:SetRowAlignment("CENTER")
			:SetMouseEnabled(true)

	local function fillShipTable ()
		shipTable:ClearRows()

		local rowEquip = {}
		local row = 1
		for i=1,#equipTypes do
			local e = equipTypes[i]
			local n = Game.player:GetEquipCount(EquipDef[e].slot, e)
			if n > 0 then
				local icon = equipIcon[e] and ui:Image("icons/goods/"..equipIcon[e]..".png") or ""
				shipTable:AddRow(utils.build_table(utils.map(function (k,v) return k,shipColumnValue[v](e, funcs) end, ipairs(config.shipColumns))))
				rowEquip[row] = e
				row = row + 1
			end
		end

		return rowEquip
	end
	local shipRowEquip = fillShipTable()

	stationTable.onRowClicked:Connect(function(row)
		local e = stationRowEquip[row+1]
		if config.noBuyOnRowClick == nil then
			funcs.onBuy(e, funcs)
		end
		stationRowEquip = fillStationTable()
		shipRowEquip = fillShipTable()
	end)

	shipTable.onRowClicked:Connect(function (row)
		local e = shipRowEquip[row+1]
		if config.noSellOnRowClick == nil then
			funcs.onSell(e, funcs)
		end
		stationRowEquip = fillStationTable()
		shipRowEquip = fillShipTable()
	end)

	return stationTable, shipTable
end

return EquipmentTableWidgets
4. Added local commodityButton function to return my buttons
5. Added buy1 etc. as config params to EquipmentTableWidgets.Pair call
6. Refreshing the table content is still triggered by shipTable.onRowClicked and stationTable.onRowClicked in EquipmentTableWidgets.lua

data/ui/StationView/CommodityMarket.lua

Code: Select all

local Engine = import("Engine")
local Lang = import("Lang")
local Game = import("Game")
local ShipDef = import("ShipDef")
local EquipDef = import("EquipDef")
local EquipmentTableWidgets = import("EquipmentTableWidgets")

local ui = Engine.ui
local l = Lang.GetResource("ui-core")
local commodityButton = function (e, num, mode, funcs)
	local button = ui:Button(ui:HBox():PackEnd(ui:Label(num)))
		button.onClick:Connect(function()
			for i = 1, num, 1 do
				if mode == 'sell' then
					bool = funcs.onSell(e, funcs)
				end
				if mode == 'buy' then
					bool = funcs.onBuy(e, funcs)
				end				
				if bool == false then
					break
				end
			end
		end)
	return button
end

local commodityMarket = function (args)

	local stationTable, shipTable = EquipmentTableWidgets.Pair({
		stationColumns = { "icon", "name", "price", "stock", "buy1", "buy5", "buy10", "buy50" },
		buy1   = function(e,funcs) return commodityButton(e, 1, "buy", funcs) end,
		buy5   = function(e,funcs) return commodityButton(e, 5, "buy", funcs) end,
		buy10  = function(e,funcs) return commodityButton(e, 10, "buy", funcs) end,
		buy50  = function(e,funcs) return commodityButton(e, 50, "buy", funcs) end,
		sell1  = function(e,funcs) return commodityButton(e, 1, "sell", funcs) end,
		sell5  = function(e,funcs) return commodityButton(e, 5, "sell", funcs) end,
		sell10 = function(e,funcs) return commodityButton(e, 10, "sell", funcs) end,
		sell50 = function(e,funcs) return commodityButton(e, 50, "sell", funcs) end,
		noBuyOnRowClick = true,
		noSellOnRowClick = true,
		shipColumns = { "icon", "name", "amount", "sell1", "sell5", "sell10", "sell50" },
	})

	return
		ui:Grid({48,4,48},1)
			:SetColumn(0, {
				ui:VBox():PackEnd({
					ui:Label(l.AVAILABLE_FOR_PURCHASE):SetFont("HEADING_LARGE"),
					ui:Expand():SetInnerWidget(stationTable),
				})
			})
			:SetColumn(2, {
				ui:VBox():PackEnd({
					ui:Label(l.IN_CARGO_HOLD):SetFont("HEADING_LARGE"),
					ui:Expand():SetInnerWidget(shipTable),
				})
			})
end

return commodityMarket
I tested it for a while and it does not seem to affect the other scripts using EquipmentTableWidgets.lua. Would need some nicer buttons perhaps, but I was not able to add a nicer one. Maybe I should spent some more time to read code :)
impaktor
Posts: 1008
Joined: Fri Dec 20, 2013 9:54 am
Location: Tellus
Contact:

Re: Make your living in pioneer as a trader

Post by impaktor »

That is one solution, but I think a better one would be either where you hold down the mouse button, or where you have a box/field where you could fill in how much you want to sell/buy when clicking. It would default to 1t for buying and all in cargo for selling. I guess this would take some more Lua hacking.

Also, feel free to create a github account and contribute with code and branches there, as that is the "usual" way to share code.

And welcome to the forum.
akuballa
Posts: 2
Joined: Mon Apr 14, 2014 8:23 pm

Re: Make your living in pioneer as a trader

Post by akuballa »

impaktor wrote:I think a better one would be either where you hold down the mouse button
That was my first thought too, but I think it can not be handled by the lua scripts only. I am a webdeveloper living in a LAMP world and I am not sure that my understanding works for c++ too. At the moment there is only the click event enabled (LuaTable.cpp) on a table row. I think it would need two events. First is mouseDown to trigger a sell/buy loop, second is mouseUp to stop the loop. No idea how to implement it. Neither the way to implement the events nor how to write a lua function that is able to stop a loop triggered by an other function. Any suggestions for documentation? In Javascript it is called event - onmouseup, onmousedown, etc. is ther something similar in lua or c?

Thanks for help
Post Reply