diff --git a/SQL/migrate/V009__Cargo.sql b/SQL/migrate/V009__Cargo.sql
new file mode 100644
index 00000000000..ed3f6cddd68
--- /dev/null
+++ b/SQL/migrate/V009__Cargo.sql
@@ -0,0 +1,63 @@
+--
+-- Create the Cargo Database
+--
+
+CREATE TABLE `ss13_cargo_categories` (
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(100) NOT NULL COLLATE 'utf8_bin',
+ `display_name` VARCHAR(100) NOT NULL COLLATE 'utf8_bin',
+ `description` VARCHAR(300) NOT NULL COLLATE 'utf8_bin',
+ `icon` VARCHAR(50) NOT NULL COLLATE 'utf8_bin',
+ `price_modifier` FLOAT UNSIGNED NOT NULL DEFAULT '1',
+ `order_by` VARCHAR(5) NULL DEFAULT NULL COLLATE 'utf8_bin',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted_at` DATETIME NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE INDEX `name` (`name`)
+)
+COLLATE='utf8_bin'
+ENGINE=InnoDB
+;
+
+CREATE TABLE `ss13_cargo_items` (
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `path` VARCHAR(150) NOT NULL COLLATE 'utf8_bin',
+ `name` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8_bin',
+ `description` VARCHAR(300) NULL DEFAULT NULL COLLATE 'utf8_bin',
+ `categories` VARCHAR(300) NOT NULL COMMENT 'JSON list of categories' COLLATE 'utf8_bin',
+ `suppliers` TEXT NULL COMMENT 'JSTON list of suppliers' COLLATE 'utf8_bin',
+ `amount` INT(10) UNSIGNED NOT NULL DEFAULT '1',
+ `access` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `container_type` VARCHAR(50) NOT NULL DEFAULT 'crate' COLLATE 'utf8_bin',
+ `groupable` TINYINT(3) UNSIGNED NOT NULL DEFAULT '1',
+ `order_by` VARCHAR(5) NULL DEFAULT NULL COLLATE 'utf8_bin',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted_at` DATETIME NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE INDEX `path` (`path`)
+)
+COLLATE='utf8_bin'
+ENGINE=InnoDB
+;
+
+CREATE TABLE `ss13_cargo_suppliers` (
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `short_name` VARCHAR(50) NOT NULL COLLATE 'utf8_bin',
+ `name` VARCHAR(100) NOT NULL COLLATE 'utf8_bin',
+ `description` VARCHAR(300) NOT NULL COLLATE 'utf8_bin',
+ `tag_line` VARCHAR(300) NOT NULL COLLATE 'utf8_bin',
+ `shuttle_time` INT(11) UNSIGNED NOT NULL,
+ `shuttle_price` INT(11) UNSIGNED NOT NULL,
+ `available` TINYINT(4) UNSIGNED NOT NULL DEFAULT '1',
+ `price_modifier` FLOAT UNSIGNED NOT NULL DEFAULT '1',
+ `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted_at` DATETIME NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE INDEX `Schlüssel 2` (`short_name`)
+)
+COLLATE='utf8_bin'
+ENGINE=InnoDB
+;
diff --git a/aurorastation.dme b/aurorastation.dme
index 2c62b4eef86..5ff0cd574dc 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -203,6 +203,7 @@
#include "code\datums\beam.dm"
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
+#include "code\datums\cargo.dm"
#include "code\datums\category.dm"
#include "code\datums\computerfiles.dm"
#include "code\datums\datacore.dm"
@@ -215,7 +216,6 @@
#include "code\datums\progressbar.dm"
#include "code\datums\server_greeting.dm"
#include "code\datums\statistic.dm"
-#include "code\datums\supplypacks.dm"
#include "code\datums\weakref.dm"
#include "code\datums\diseases\appendicitis.dm"
#include "code\datums\diseases\beesease.dm"
@@ -575,7 +575,6 @@
#include "code\game\machinery\computer\skills.dm"
#include "code\game\machinery\computer\specops_shuttle.dm"
#include "code\game\machinery\computer\station_alert.dm"
-#include "code\game\machinery\computer\supply.dm"
#include "code\game\machinery\computer\syndicate_specops_shuttle.dm"
#include "code\game\machinery\doors\airlock.dm"
#include "code\game\machinery\doors\airlock_control.dm"
@@ -803,7 +802,6 @@
#include "code\game\objects\items\weapons\circuitboards\computer\holodeckcontrol.dm"
#include "code\game\objects\items\weapons\circuitboards\computer\research.dm"
#include "code\game\objects\items\weapons\circuitboards\computer\station_alert.dm"
-#include "code\game\objects\items\weapons\circuitboards\computer\supply.dm"
#include "code\game\objects\items\weapons\circuitboards\computer\telecomms.dm"
#include "code\game\objects\items\weapons\circuitboards\machinery\biogenerator.dm"
#include "code\game\objects\items\weapons\circuitboards\machinery\cloning.dm"
@@ -1284,7 +1282,6 @@
#include "code\modules\events\radiation_storm.dm"
#include "code\modules\events\random_antagonist.dm"
#include "code\modules\events\rogue_drones.dm"
-#include "code\modules\events\shipping_error.dm"
#include "code\modules\events\space_ninja.dm"
#include "code\modules\events\spacevine.dm"
#include "code\modules\events\spider_infestation.dm"
@@ -1744,6 +1741,8 @@
#include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\hacked_camera.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
+#include "code\modules\modular_computers\file_system\programs\civilian\cargo_control.dm"
+#include "code\modules\modular_computers\file_system\programs\civilian\cargo_order.dm"
#include "code\modules\modular_computers\file_system\programs\civilian\crusher_control.dm"
#include "code\modules\modular_computers\file_system\programs\command\card.dm"
#include "code\modules\modular_computers\file_system\programs\command\comm.dm"
@@ -1985,7 +1984,6 @@
#include "code\modules\reagents\dispenser\coffeebeans.dm"
#include "code\modules\reagents\dispenser\dispenser2.dm"
#include "code\modules\reagents\dispenser\dispenser_presets.dm"
-#include "code\modules\reagents\dispenser\supply.dm"
#include "code\modules\reagents\reagent_containers\blood_pack.dm"
#include "code\modules\reagents\reagent_containers\borghydro.dm"
#include "code\modules\reagents\reagent_containers\dropper.dm"
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 778918efd3d..1806473e89c 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -383,6 +383,11 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
//Of course, this will affect code that checks for blocked < 100, as blocked will be less likely to actually be 100.
#define ARMOR_BLOCK_CHANCE_MULT 1.0
+//Cargo Container Types
+#define CARGO_CONTAINER_CRATE "crate"
+#define CARGO_CONTAINER_FREEZER "freezer"
+#define CARGO_CONTAINER_BOX "box"
+
// We should start using these.
#define ITEMSIZE_TINY 1
#define ITEMSIZE_SMALL 2
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 2936dce4196..4112756f3cc 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -271,6 +271,7 @@ var/list/gamemode_cache = list()
var/sun_accuracy = 8
var/sun_target_z = 7
+ var/cargo_load_items_from = "json"
var/merchant_chance = 20 //Chance, in percentage, of the merchant job slot being open at round start
var/show_game_type_odd = 1 // If the check gamemode probability verb is enabled or not
@@ -841,6 +842,9 @@ var/list/gamemode_cache = list()
access_deny_vms = text2num(value)
if("access_warn_vms")
access_warn_vms = text2num(value)
+
+ if("cargo_load_items_from")
+ cargo_load_items_from = value
if("fastboot")
fastboot = TRUE
diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm
index 4096e36a8af..f55c90d363c 100644
--- a/code/controllers/subsystems/supply.dm
+++ b/code/controllers/subsystems/supply.dm
@@ -4,43 +4,70 @@
#define SUPPLY_STATION_AREATYPE /area/supply/station //Type of the supply shuttle area for station
#define SUPPLY_DOCK_AREATYPE /area/supply/dock //Type of the supply shuttle area for dock
+/proc/fetch_supply_account()
+ SScargo.supply_account = department_accounts["Cargo"]
+
var/datum/controller/subsystem/cargo/SScargo
/datum/controller/subsystem/cargo
name = "Cargo"
wait = 30 SECONDS
- flags = SS_NO_TICK_CHECK
+ flags = SS_NO_TICK_CHECK | SS_NO_FIRE
init_order = SS_INIT_CARGO
- //supply points
- var/points = 50
- var/points_per_process = 1
- var/points_per_slip = 2
- var/points_per_crate = 5
- var/points_per_platinum = 5 // 5 points per sheet
- var/points_per_phoron = 5
- //control
+ //Shipment stuff
+ var/shipmentnum
+ var/list/cargo_shipments = list() //List of the shipments to the station
+ var/datum/cargo_shipment/current_shipment = null // The current cargo shipment
+
+ //order stuff
var/ordernum
- var/list/shoppinglist = list()
- var/list/requestlist = list()
- var/list/supply_packs = list()
+ var/list/cargo_items = list() //The list of items
+ var/list/cargo_categories = list() //The list of categories
+ var/list/cargo_suppliers = list() //The list of suppliers
+ var/list/all_orders = list() //All orders
+
+ //Fee Stuff
+ var/credits_per_crate = 100 //Cost / Payment per crate shipped from / to centcom
+ var/credits_per_platinum = 140 //Per sheet
+ var/credits_per_phoron = 100 //Per sheet
+ var/cargo_handlingfee = 50 //The handling fee cargo takes per crate
+ var/cargo_handlingfee_min = 0 // The minimum handling fee
+ var/cargo_handlingfee_max = 500 // The maximum handling fee
+ var/cargo_handlingfee_change = 1 // If the handlingfee can be changed -> For a random event
+ var/datum/money_account/supply_account
+
//shuttle movement
var/movetime = 1200
var/datum/shuttle/ferry/supply/shuttle
/datum/controller/subsystem/cargo/Recover()
- src.points = SScargo.points
- src.shoppinglist = SScargo.shoppinglist
- src.requestlist = SScargo.requestlist
- src.supply_packs = SScargo.supply_packs
src.shuttle = SScargo.shuttle
+ src.cargo_items = SScargo.cargo_items
+ src.cargo_categories = SScargo.cargo_categories
+ src.cargo_shipments = SScargo.cargo_shipments
+ src.all_orders = SScargo.all_orders
+ src.cargo_handlingfee = SScargo.cargo_handlingfee
+ src.cargo_handlingfee_change = SScargo.cargo_handlingfee_change
+ src.supply_account = SScargo.supply_account
/datum/controller/subsystem/cargo/Initialize(timeofday)
- ordernum = rand(1,9000)
+ //Generate the ordernumber and shipmentnumber to start with
+ ordernum = rand(1,8000)
+ shipmentnum = rand(500,700)
- for (var/typepath in subtypesof(/datum/supply_packs))
- var/datum/supply_packs/P = new typepath()
- supply_packs[P.name] = P
+ //Fetch the cargo account once the round is started - TODO: Repalce that once economy gets its own subsystem
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/fetch_supply_account))
+
+ //Load in the cargo items config
+ if(config.cargo_load_items_from == "sql")
+ log_debug("SSCargo: Attempting to Load from SQL")
+ load_from_sql()
+ else if(config.cargo_load_items_from == "json")
+ log_debug("SSCargo: Attempting to Load from JSON")
+ load_from_json()
+ else
+ log_game("SSCargo: invalid load option specified in config")
var/datum/cargospawner/spawner = new
spawner.start()
@@ -50,8 +77,491 @@ var/datum/controller/subsystem/cargo/SScargo
/datum/controller/subsystem/cargo/New()
NEW_SS_GLOBAL(SScargo)
-/datum/controller/subsystem/cargo/fire()
- points += points_per_process
+
+/*
+ Loading Data
+*/
+//Reset cargo to prep for loading in new items
+/datum/controller/subsystem/cargo/proc/reset_cargo()
+ cargo_shipments = list() //List of the shipments to the station
+ current_shipment = null // The current cargo shipment
+ cargo_items = list() //The list of items
+ cargo_categories = list() //The list of categories
+ cargo_suppliers = list() //The list of suppliers
+ all_orders = list() //All orders
+
+//Load the cargo data from SQL
+/datum/controller/subsystem/cargo/proc/load_from_sql()
+ if(!establish_db_connection(dbcon))
+ log_debug("SSCargo: SQL ERROR - Failed to connect. - Falling back to JSON")
+ return load_from_json()
+ else
+ //Reset the currently loaded data
+ reset_cargo()
+
+ //Populate the items missing a name or a description with the missing name / description
+ var/DBQuery/item_null_query = dbcon.NewQuery("SELECT path, name, description, suppliers, id FROM ss13_cargo_items WHERE (name IS NULL OR description IS NULL OR suppliers IS NULL) AND deleted_at IS NULL" )
+ item_null_query.Execute()
+ while(item_null_query.NextRow())
+ //Spawn the item with the path
+ var/oldpath = item_null_query.item[1]
+ var/oldname = item_null_query.item[2]
+ var/olddsec = item_null_query.item[3]
+ var/oldsuppliers = item_null_query.item[4]
+ var/item_id = item_null_query.item[5]
+ var/path = text2path(oldpath)
+
+ log_debug("SSCargo: Got path without name or description - updating: [oldpath]")
+ if(path)
+ var/obj/cargoitem = new path
+ //The following sql queries arnt overly optimized. Its just not worht it, because they are only run once if a item is added without the complete data
+ if(cargoitem)
+ //Update the name of the item if its null
+ if(!oldname)
+ log_debug("SSCargo: Updating name to [cargoitem.name]")
+ var/DBQuery/item_update_name_query = dbcon.NewQuery("UPDATE ss13_cargo_items SET name = :name: WHERE id = :item_id:")
+ item_update_name_query.Execute(list("name" = cargoitem.name, "item_id" = item_id ))
+ //Update the name of the item if its null
+ if(!olddsec)
+ log_debug("SSCargo: Updating desc to [cargoitem.desc]")
+ var/DBQuery/item_update_desc_query = dbcon.NewQuery("UPDATE ss13_cargo_items SET description = :desc: WHERE id = :item_id:")
+ item_update_desc_query.Execute(list("desc" = cargoitem.desc, "item_id" = item_id ))
+ //Set NT as default supplier with a price 1.5 times of the item value
+ if(!oldsuppliers)
+ var/price = get_value(cargoitem) * 1.5
+ var/list/sups = list()
+ sups["nt"] = list()
+ sups["nt"]["base_purchase_price"] = price
+ sups["nt"]["vars"] = list()
+ log_debug("SSCargo: Updating suppliers string to [json_encode(sups)]")
+ var/DBQuery/item_update_supl_query = dbcon.NewQuery("UPDATE ss13_cargo_items SET suppliers = '[json_encode(sups)]' WHERE id = [item_id]")
+ item_update_supl_query.Execute()
+ qdel(cargoitem)
+
+ //Load the categories
+ var/DBQuery/category_query = dbcon.NewQuery("SELECT name, display_name, description, icon, price_modifier FROM ss13_cargo_categories WHERE deleted_at IS NULL ORDER BY order_by ASC")
+ category_query.Execute()
+ while(category_query.NextRow())
+ log_debug("SSCargo: Loading Category: [category_query.item[1]]")
+ var/datum/cargo_category/cc = new()
+ cc.name = category_query.item[1]
+ cc.display_name = category_query.item[2]
+ cc.description = category_query.item[3]
+ cc.icon = category_query.item[4]
+ cc.price_modifier = text2num(category_query.item[5])
+
+ //Add the category to the cargo_categories list
+ cargo_categories[cc.name] = cc
+
+ //Load the suppliers
+ var/DBQuery/supplier_query = dbcon.NewQuery("SELECT short_name, name, description, tag_line, shuttle_time, shuttle_price, available, price_modifier FROM ss13_cargo_suppliers WHERE deleted_at is NULL")
+ supplier_query.Execute()
+ while(supplier_query.NextRow())
+ log_debug("SSCargo: Loading Supplier: [supplier_query.item[1]]")
+ var/datum/cargo_supplier/cs = new()
+ cs.short_name = supplier_query.item[1]
+ cs.name = supplier_query.item[2]
+ cs.description = supplier_query.item[3]
+ cs.tag_line = supplier_query.item[4]
+ cs.shuttle_time = text2num(supplier_query.item[5])
+ cs.shuttle_price = text2num(supplier_query.item[6])
+ cs.available = text2num(supplier_query.item[7])
+ cs.price_modifier = text2num(supplier_query.item[8])
+
+ cargo_suppliers[cs.short_name] = cs
+
+ //Load the items
+ var/DBQuery/item_query = dbcon.NewQuery("SELECT path, name, description, categories, suppliers, amount, access, container_type, groupable FROM ss13_cargo_items WHERE deleted_at is NULL ORDER BY order_by")
+ item_query.Execute()
+ while(item_query.NextRow())
+ log_debug("SSCargo: Loading Item: [item_query.item[2]]")
+ var/itempath = text2path(item_query.item[1])
+ if(!ispath(itempath))
+ log_debug("SSCargo: Warning - Attempted to add item with invalid path: [item_query.item[2]] - [item_query.item[1]]")
+ continue
+ var/datum/cargo_item/ci = new()
+ try
+ ci.path = item_query.item[1]
+ ci.name = item_query.item[2]
+ ci.description = item_query.item[3]
+ ci.categories = json_decode(item_query.item[4])
+ ci.suppliers = json_decode(item_query.item[5])
+ ci.amount = text2num(item_query.item[6])
+ ci.access = text2num(item_query.item[7]) //TODO: Maybe add the option to specify access as string instead of number
+ ci.container_type = item_query.item[8]
+ ci.groupable = text2num(item_query.item[9])
+ catch(var/exception/e)
+ log_debug("SSCargo: Error when loading item: [e]")
+ qdel(ci)
+ continue
+
+ //Check if a valid container is specified
+ if(!(ci.container_type == CARGO_CONTAINER_CRATE || ci.container_type == CARGO_CONTAINER_FREEZER || ci.container_type == CARGO_CONTAINER_BOX))
+ log_debug("SScargo: Invalid container type specified for item - Aborting")
+ qdel(ci)
+ continue
+
+ //Verify the suppliers exist
+ for(var/sup in ci.suppliers)
+ log_debug("SSCargo: Checking [sup]")
+ var/datum/cargo_supplier/cs = get_supplier_by_name(sup)
+ if(!cs)
+ log_debug("SSCargo: [sup] is not a valid supplier")
+
+ //Setting the supplier
+ ci.suppliers[sup]["supplier_datum"] = cs
+
+ //Add the item to the cargo_items list
+ cargo_items[ci.path] = ci
+
+ //Log a message if no categories are specified
+ if(ci.categories.len == 0)
+ log_debug("SSCargo: No categories speicfied for item")
+
+ //Add the item to the categories
+ for(var/category in ci.categories)
+ var/datum/cargo_category/cc = cargo_categories[category]
+ if(cc) //Check if the category exists
+ cc.items.Add(ci)
+ else
+ log_debug("SSCargo: Warning - Attempted to add item to category [category] that does not exist")
+
+ log_debug("SSCargo: Loaded Item: [ci.name]")
+ return 1
+
+//Loads the cargo data from JSON
+/datum/controller/subsystem/cargo/proc/load_from_json()
+ var/list/cargoconfig = list()
+ try
+ cargoconfig = json_decode(return_file_text("config/cargo.json"))
+ catch(var/exception/e)
+ log_debug("SSCargo: Warning: Could not load config, as cargo.json is missing - [e]")
+ return
+
+ //Reset the currently loaded data
+ reset_cargo()
+
+ //Load the cargo categories
+ for (var/category in cargoconfig["categories"])
+ log_debug("SSCargo: Loading Category: [category]")
+ var/datum/cargo_category/cc = new()
+ cc.name = cargoconfig["categories"][category]["name"]
+ cc.display_name = cargoconfig["categories"][category]["display_name"]
+ cc.description = cargoconfig["categories"][category]["description"]
+ cc.icon = cargoconfig["categories"][category]["icon"]
+ cc.price_modifier = cargoconfig["categories"][category]["price_modifier"]
+
+ //Add the category to the cargo_categories list
+ cargo_categories[cc.name] = cc
+
+ //Load the suppliers
+ for (var/supplier in cargoconfig["suppliers"])
+ log_debug("SSCargo: Loading Supplier: [supplier]")
+ var/datum/cargo_supplier/cs = new()
+ cs.short_name = supplier
+ cs.name = cargoconfig["suppliers"][supplier]["name"]
+ cs.description = cargoconfig["suppliers"][supplier]["description"]
+ cs.tag_line = cargoconfig["suppliers"][supplier]["tag_line"]
+ cs.shuttle_time = cargoconfig["suppliers"][supplier]["shuttle_time"]
+ cs.shuttle_price = cargoconfig["suppliers"][supplier]["shuttle_price"]
+ cs.available = cargoconfig["suppliers"][supplier]["available"]
+ cs.price_modifier = cargoconfig["suppliers"][supplier]["price_modifier"]
+
+ cargo_suppliers[cs.short_name] = cs
+
+ //Load the cargoitems
+ for (var/item in cargoconfig["items"])
+ log_debug("SSCargo: Loading Item: [item]")
+ var/itempath = text2path(item)
+ if(!ispath(itempath))
+ log_debug("SSCargo: Warning - Attempted to add item with invalid path: [item]")
+ continue
+ var/datum/cargo_item/ci = new()
+ ci.path = item
+ ci.name = cargoconfig["items"][item]["name"]
+ ci.description = cargoconfig["items"][item]["description"]
+ ci.categories = cargoconfig["items"][item]["categories"]
+ ci.suppliers = cargoconfig["items"][item]["suppliers"]
+ ci.amount = cargoconfig["items"][item]["amount"]
+ ci.access = cargoconfig["items"][item]["access"]
+ ci.container_type = cargoconfig["items"][item]["container_type"]
+ ci.groupable = cargoconfig["items"][item]["groupable"]
+ log_debug("SSCargo: Loaded Item: [ci.name]")
+
+ //Verify the suppliers exist
+ for(var/sup in ci.suppliers)
+ log_debug("SSCargo: Checking [sup]")
+ var/datum/cargo_supplier/cs = get_supplier_by_name(sup)
+ if(!cs)
+ log_debug("SSCargo: [sup] is not a valid supplier")
+
+ //Setting the supplier
+ ci.suppliers[sup]["supplier_datum"] = cs
+
+ //Add the item to the cargo_items list
+ cargo_items[ci.path] = ci
+
+ //Add the item to the categories
+ for(var/category in ci.categories)
+ var/datum/cargo_category/cc = cargo_categories[category]
+ if(cc) //Check if the category exists
+ cc.items.Add(ci)
+ else
+ log_debug("SSCargo: Warning - Attempted to add item to category that does not exist")
+ return 1
+
+
+/*
+ Getting items, categories, suppliers and shipments
+*/
+//Increments the orderid and returns it
+/datum/controller/subsystem/cargo/proc/get_next_order_id()
+ . = ordernum
+ ordernum++
+ return .
+
+//Gets the items from a category
+/datum/controller/subsystem/cargo/proc/get_items_for_category(var/category)
+ var/datum/cargo_category/cc = cargo_categories[category]
+ if(cc)
+ return cc.get_item_list()
+ else
+ return list()
+
+//Gets the categories
+/datum/controller/subsystem/cargo/proc/get_category_list()
+ var/list/category_list = list()
+ for (var/cat_name in cargo_categories)
+ var/datum/cargo_category/cc = cargo_categories[cat_name]
+ category_list.Add(list(cc.get_list()))
+ return category_list
+//Get a category by name
+/datum/controller/subsystem/cargo/proc/get_category_by_name(var/name)
+ return cargo_categories[name]
+
+//Gets a order by order id
+/datum/controller/subsystem/cargo/proc/get_order_by_id(var/id)
+ for (var/datum/cargo_order/co in all_orders)
+ if(co.order_id == id)
+ return co
+ return null
+
+//Gets a supplier by name
+/datum/controller/subsystem/cargo/proc/get_supplier_by_name(var/name)
+ return cargo_suppliers[name]
+
+//Gets all the shipments sent to / from the station
+/datum/controller/subsystem/cargo/proc/get_shipment_list()
+ var/list/shipment_list = list()
+ for(var/datum/cargo_shipment/cs in cargo_shipments)
+ if(cs.get_list() != null)
+ shipment_list.Add(list(cs.get_list()))
+ return shipment_list
+
+//Get a shipment by shipment id
+/datum/controller/subsystem/cargo/proc/get_shipment_by_id(var/id)
+ for(var/datum/cargo_shipment/cs in cargo_shipments)
+ if(cs.shipment_num == id)
+ return cs
+ return null
+
+/*
+ Submitting, Approving, Rejecting and Shipping Orders
+*/
+//Gets the orders based on their status (submitted, approved, shipped)
+/datum/controller/subsystem/cargo/proc/get_orders_by_status(var/status, var/data_list=0)
+ if(!status)
+ log_debug("SSCargo - get_orders_by_status has been called with a invalud status")
+ return list()
+ var/list/orders = list()
+ for (var/datum/cargo_order/co in all_orders)
+ if(co.status == status)
+ if(data_list)
+ orders.Add(list(co.get_list()))
+ else
+ orders.Add(co)
+ return orders
+//Gets the value of orders based on their status, type is passed on to co.get_value
+/datum/controller/subsystem/cargo/proc/get_orders_value_by_status(var/status, var/type=0)
+ if(!status)
+ log_debug("SSCargo - get_orders_value_by_status has been called with a invalud status")
+ return 0
+ var/value = 0
+ for (var/datum/cargo_order/co in all_orders)
+ if(co.status == status)
+ value += co.get_value(type)
+ return value
+//Gets the suppliers of the orders of a specific type
+/datum/controller/subsystem/cargo/proc/get_order_suppliers_by_status(var/status, var/pretty_names=0)
+ if(!status)
+ log_debug("SSCargo - get_order_suppliers_by_status has been called with a invalud status")
+ return list()
+ var/list/suppliers = list()
+ for(var/datum/cargo_order/co in all_orders)
+ if(co.status == status)
+ //Get the list of supplirs and add it to the suppliers list
+ for(var/supplier in co.get_supplier_list())
+ if(pretty_names)
+ var/datum/cargo_supplier/cs = SScargo.cargo_suppliers[supplier]
+ suppliers[cs.short_name] = cs.name
+ else
+ suppliers[supplier] = supplier
+ return suppliers
+
+//Submits an order to cargo
+/datum/controller/subsystem/cargo/proc/submit_order(var/datum/cargo_order/co)
+ co.status = "submitted"
+ co.time_submitted = worldtime2text()
+ co.order_id = get_next_order_id()
+ all_orders.Add(co)
+ return 1
+
+//Approve a order - Returns a status message
+/datum/controller/subsystem/cargo/proc/approve_order(var/datum/cargo_order/co, var/approved_by)
+ if(co.status == "submitted")
+ co.status = "approved"
+ co.time_approved = worldtime2text()
+ co.authorized_by = approved_by
+ return "The order has been approved"
+ else
+ return "The order could not be approved - Invalid Status"
+
+//Reject a order - Returns a status message
+/datum/controller/subsystem/cargo/proc/reject_order(var/datum/cargo_order/co)
+ if(co.status == "submitted")
+ co.status = "rejected"
+ co.time_approved = worldtime2text()
+ return "The order has been rejected"
+ else
+ return "The order could not be rejected - Invalid Status"
+
+
+
+
+//Checks if theorder can be shipped and marks it as shipped if possible
+/datum/controller/subsystem/cargo/proc/ship_order(var/datum/cargo_order/co)
+ //Get the price cargo has to pay for the order
+ var/item_price = co.get_value(1)
+
+ //Get the maximum shipment costs for the order
+ var/max_shipment_cost = co.get_max_shipment_cost()
+
+ //Check if cargo has enough money to pay for the shipment of the item and the maximum shipment cost
+ if(item_price + max_shipment_cost > get_cargo_money())
+ log_debug("SSCargo - Order could not be shipped. Insufficient money. [item_price] + [max_shipment_cost] > [get_cargo_money()]")
+ return 0
+
+ co.status = "shipped"
+ co.time_shipped = worldtime2text()
+ current_shipment.shipment_cost_purchase += item_price //Increase the price of the shipment
+ current_shipment.orders.Add(co) //Add the order to the order list
+ return 1
+//Generate a new cargo shipment
+/datum/controller/subsystem/cargo/proc/new_shipment()
+ current_shipment = new()
+ shipmentnum ++
+ cargo_shipments.Add(current_shipment)
+ current_shipment.shipment_num = shipmentnum
+/*
+ Changing Settings
+*/
+//Gets the current handlingfee
+/datum/controller/subsystem/cargo/proc/get_handlingfee()
+ return cargo_handlingfee
+// Sets the handling fee - Returns a status message
+/datum/controller/subsystem/cargo/proc/set_handlingfee(var/fee)
+ if(!fee)
+ return "Unable to set handlingfee - Can not be NULL"
+ if(fee < cargo_handlingfee_min)
+ return "Unable to set handlingfee - Smaller than minimum: [cargo_handlingfee_min]"
+ if(fee > cargo_handlingfee_max)
+ return "Unable to set handlingfee - Higher than maximum: [cargo_handlingfee_max]"
+ if(cargo_handlingfee_change != 1)
+ return "Unable to set handlingfee - Changing the handlingfee is currently not possible"
+ cargo_handlingfee = fee
+ return
+
+//Gets the current crate fee
+/datum/controller/subsystem/cargo/proc/get_cratefee()
+ return credits_per_crate
+/*
+ Money Stuff
+*/
+//Gets the current money on the cargo account
+/datum/controller/subsystem/cargo/proc/get_cargo_money()
+ return supply_account.money
+//Charges cargo. Accepts a text that should appear as charge and the numer of credits to charge
+/datum/controller/subsystem/cargo/proc/charge_cargo(var/charge_text, var/charge_credits)
+ if(!supply_account)
+ log_debug("SSCargo - Warning Tried to charge supply account but supply acount doesnt exist")
+ return 0
+ return charge_to_account(supply_account.account_number, "[commstation_name()] - Supply", "[charge_text]", "[commstation_name()] - Banking System", -charge_credits)
+//Gets the pending shipment costs for the items that are about to be shipped to the station
+/datum/controller/subsystem/cargo/proc/get_pending_shipment_cost(var/status="approved")
+ //Loop through all the orders marked as shipped and get the suppliers into a list of involved suppliers
+ var/list/suppliers = get_order_suppliers_by_status(status)
+ var/price = 0
+ for(var/supplier in suppliers)
+ var/datum/cargo_supplier/cs = SScargo.cargo_suppliers[supplier]
+ if(cs)
+ price += cs.shuttle_price
+ return price
+//Gets the pending shipment time for the items that are about to be shipped to the station
+/datum/controller/subsystem/cargo/proc/get_pending_shipment_time(var/status="approved")
+ //Loop through all the orders marked as shipped and get the suppliers into a list of involved suppliers
+ var/list/suppliers = get_order_suppliers_by_status(status)
+ var/time = 0
+ for(var/supplier in suppliers)
+ var/datum/cargo_supplier/cs = SScargo.cargo_suppliers[supplier]
+ if(cs)
+ time += cs.shuttle_time
+ return time
+
+/*
+ Shuttle Operations - Calling, Forcing, Canceling, Buying / Selling
+*/
+//Calls the shuttle. Returns a status message
+/datum/controller/subsystem/cargo/proc/shuttle_call(var/caller_name)
+ if(shuttle.at_station())
+ if (shuttle.forbidden_atoms_check())
+ . = "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons."
+ else
+ movetime = 1200 //It always takes two minutes to get to centcom
+ shuttle.launch(src)
+ . = "Initiating launch sequence"
+ current_shipment.shuttle_recalled_by = caller_name
+ else
+ //Check if there is enough money in the cargo account for the current shipment
+ var/shipment_cost = get_pending_shipment_cost()
+ if( shipment_cost > get_cargo_money())
+ . = "The supply shuttle could not be called. Insufficient Funds. [shipment_cost] Credits required"
+ else
+ //Create a new shipment if one does not exist already
+ if(!current_shipment)
+ new_shipment()
+
+ //Set the shuttle movement time
+ current_shipment.shuttle_time = get_pending_shipment_time()
+ current_shipment.shuttle_fee = shipment_cost
+
+ if(current_shipment.shuttle_time < 1200)
+ log_debug("SSCargo: Shuttle Time less than 1200: [current_shipment.shuttle_time] - Setting to 1200")
+ current_shipment.shuttle_time = 1200
+
+ movetime = current_shipment.shuttle_time
+ //Launch it
+ shuttle.launch(src)
+ . = "The supply shuttle has been called and will arrive in approximately [round(SScargo.movetime/600,1)] minutes."
+ current_shipment.shuttle_called_by = caller_name
+ return .
+
+//Cancels the shuttle. Can return a status message
+/datum/controller/subsystem/cargo/proc/shuttle_cancel()
+ shuttle.cancel_launch(src)
+
+//Forces the shuttle. Can return a status message
+/datum/controller/subsystem/cargo/proc/shuttle_force()
+ shuttle.force_launch(src)
//To stop things being sent to centcomm which should not be sent to centcomm. Recursively checks for these types.
/datum/controller/subsystem/cargo/proc/forbidden_atoms_check(atom/A)
@@ -69,8 +579,9 @@ var/datum/controller/subsystem/cargo/SScargo
if(.(B))
return 1
- //Sellin
+//Sells stuff on the shuttle to centcom
/datum/controller/subsystem/cargo/proc/sell()
+ //TODO: Only pay for specific stuff on the shuttle and not for everything else - Charge a cleanup fee for the rest
var/area/area_shuttle = shuttle.get_location_area()
if(!area_shuttle) return
@@ -84,19 +595,10 @@ var/datum/controller/subsystem/cargo/SScargo
if(istype(MA,/obj/structure/closet/crate))
callHook("sell_crate", list(MA, area_shuttle))
- points += points_per_crate
- var/find_slip = 1
+ current_shipment.shipment_cost_sell += credits_per_crate
for(var/atom in MA)
- // Sell manifests
var/atom/A = atom
- if(find_slip && istype(A,/obj/item/weapon/paper/manifest))
- var/obj/item/weapon/paper/manifest/slip = A
- if(!slip.is_copy && slip.stamped && slip.stamped.len) //yes, the clown stamp will work. clown is the highest authority on the station, it makes sense
- points += points_per_slip
- find_slip = 0
- continue
-
// Sell phoron and platinum
if(istype(A, /obj/item/stack))
var/obj/item/stack/P = A
@@ -106,17 +608,26 @@ var/datum/controller/subsystem/cargo/SScargo
qdel(MA)
if(phoron_count)
- points += phoron_count * points_per_phoron
+ current_shipment.shipment_cost_sell += phoron_count * credits_per_phoron
if(plat_count)
- points += plat_count * points_per_platinum
+ current_shipment.shipment_cost_sell += plat_count * credits_per_platinum
-//Buyin
+ charge_cargo("Shipment #[current_shipment.shipment_num] - Income", -current_shipment.shipment_cost_sell)
+ current_shipment.generate_invoice()
+ current_shipment = null //Null the current shipment because its completed
+
+//Buys the item and places them on the shuttle
+//Returns 0 if unsuccessful returns 1 if the shuttle can be sent
/datum/controller/subsystem/cargo/proc/buy()
- if(!shoppinglist.len) return
+ if(!current_shipment)
+ new_shipment()
+
+ var/list/approved_orders = get_orders_by_status("approved",0)
var/area/area_shuttle = shuttle.get_location_area()
- if(!area_shuttle) return
+ if(!area_shuttle)
+ return 0
var/list/clear_turfs = list()
@@ -131,60 +642,68 @@ var/datum/controller/subsystem/cargo/SScargo
continue
clear_turfs += T
- for(var/S in shoppinglist)
- if(!clear_turfs.len) break
+ for(var/datum/cargo_order/co in approved_orders)
+ if(!co)
+ break
+
+ //Check if theres space to place the order
+ if(!clear_turfs.len)
+ log_debug("SSCargo - Order [co.order_id] could not be placed on the shuttle because the shuttle is full")
+ break
+
+ //Check if the supplier is still active
+ for(var/datum/cargo_order_item/coi in co.items)
+ var/datum/cargo_supplier/csu = get_supplier_by_name(coi.supplier)
+ if(!csu)
+ log_debug("SSCargo - Order [co.order_id] could not be placed on the shuttle because supplier [coi.supplier] for item [coi.ci.name] is invalid")
+ break
+ if(!csu.available)
+ log_debug("SSCargo - Order [co.order_id] could not be placed on the shuttle because supplier [coi.supplier] for item [coi.ci.name] is unavailable")
+ break
+
+ //Check if there is enough money to ship the order
+ if(!ship_order(co))
+ break
+
var/i = rand(1,clear_turfs.len)
var/turf/pickedloc = clear_turfs[i]
clear_turfs.Cut(i,i+1)
- var/datum/supply_order/SO = S
- var/datum/supply_packs/SP = SO.object
+ //Spawn the crate
+ var/containertype = co.get_container_type()
+ var/obj/A = new containertype(pickedloc)
- var/obj/A = new SP.containertype(pickedloc)
- A.name = "[SP.containername] [SO.comment ? "([SO.comment])":"" ]"
+ //Label the crate
+ //TODO: Look into wrapping it in a NT paper
+ A.name = "[co.order_id] - [co.customer]"
- //supply manifest generation begin
+ //Set the access requirement
+ if(co.required_access.len > 0)
+ A.req_access = co.required_access.Copy()
- var/obj/item/weapon/paper/manifest/slip
- if(!SP.contraband)
- slip = new /obj/item/weapon/paper/manifest(A)
- slip.is_copy = 0
- slip.info = "
[command_name()] Shipping Manifest
"
- slip.info +="Order #[SO.ordernum]
"
- slip.info +="Destination: [station_name]
"
- slip.info +="[shoppinglist.len] PACKAGES IN THIS SHIPMENT
"
- slip.info +="CONTENTS:
"
+ //Loop through the items and spawn them
+ for(var/datum/cargo_order_item/coi in co.items)
+ if(!coi)
+ continue
- //spawn the stuff, finish generating the manifest while you're at it
- if(SP.access)
- if(isnum(SP.access))
- A.req_access = list(SP.access)
- else if(islist(SP.access))
- var/list/L = SP.access // access var is a plain var, we need a list
- A.req_access = L.Copy()
- else
- world << "Supply pack with invalid access restriction [SP.access] encountered!"
+ //Spawn the specified amount
+ for(i=0, i < coi.ci.amount, i++)
+ var/atom/item = new coi.ci.path(A)
- var/list/contains
- if(istype(SP,/datum/supply_packs/randomised))
- var/datum/supply_packs/randomised/SPR = SP
- contains = list()
- if(SPR.contains.len)
- for(var/j=1,j<=SPR.num_contained,j++)
- contains += pick(SPR.contains)
- else
- contains = SP.contains
+ //Customize items with supplier data
+ var/list/suppliers = coi.ci.suppliers
+ for(var/var_name in suppliers[coi.supplier]["vars"])
+ try
+ item.vars[var_name] = suppliers[coi.supplier]["vars"][var_name]
+ catch(var/exception/e)
+ log_debug("SSCargo: Bad variable name [var_name] for item [coi.ci.path] - [e]")
- for(var/typepath in contains)
- if(!typepath) continue
- var/atom/B2 = new typepath(A)
- if(SP.amount && B2:amount) B2:amount = SP.amount
- if(slip) slip.info += "- [B2.name]
" //add the item to the manifest
+ //Shuttle is loaded now - Charge cargo for it
+ charge_cargo("Shipment #[current_shipment.shipment_num] - Expense",current_shipment.shipment_cost_purchase)
- //manifest finalisation
- if(slip)
- slip.info += "
"
- slip.info += "CHECK CONTENTS AND STAMP BELOW THE LINE TO CONFIRM RECEIPT OF GOODS
"
+ //Now calculate the aliquot shipment cost for the orders and add it to each order
+ var/aliquot_shipment_cost = current_shipment.shuttle_fee / current_shipment.orders.len
+ for(var/datum/cargo_order/co in current_shipment.orders)
+ co.partial_shipment_fee = aliquot_shipment_cost
- shoppinglist.Cut()
- return
+ return 1
diff --git a/code/datums/cargo.dm b/code/datums/cargo.dm
new file mode 100644
index 00000000000..f133b3df893
--- /dev/null
+++ b/code/datums/cargo.dm
@@ -0,0 +1,446 @@
+/*
+ A item orderable via cargo
+*/
+/datum/cargo_item
+ var/path = null //Path of the item
+ var/name = "Cargo Item" //Name of the item
+ var/description = "You should not see this" //Description of the item
+ var/list/categories = list() //List of categories this item appears in
+ var/list/suppliers = list() //List of supliers and their prices
+ var/amount = 1 //Amount of items in the crate
+ var/access = null //What access requirement should be added to the container
+ var/container_type = "crate" //crate or box
+ var/groupable = 1 //If the item can be thrown into the same container as other items
+
+//Gets a list of the cargo item - To be json encoded
+/datum/cargo_item/proc/get_list()
+ var/list/data = list()
+ data["name"] = name
+ data["path"] = path
+ data["description"] = description
+ data["categories"] = categories
+ data["amount"] = amount
+ var/suppliers_list = list()
+ for(var/supplier in suppliers)
+ var/list/sd = list()
+ var/datum/cargo_supplier/cs = suppliers[supplier]["supplier_datum"]
+ if(!cs)
+ log_debug("Cargo - Invalid supplier [supplier] encountered when loading item [name] with path [path]")
+ continue
+ sd["short_name"] = cs.short_name
+ sd["name"] = cs.name
+ sd["available"] = cs.available
+ sd["price_modifier"] = cs.price_modifier
+ sd["base_purchase_price"] = suppliers[supplier]["base_purchase_price"]
+ sd["vars"] = suppliers[supplier]["vars"]
+ sd["adjusted_price"] = sd["base_purchase_price"] * sd["price_modifier"]
+ //Add category adjustments
+ for(var/category in categories)
+ var/datum/cargo_category/cc = SScargo.get_category_by_name(category)
+ if(cc)
+ sd["adjusted_price"] *= cc.price_modifier
+ suppliers_list[supplier] = sd
+ data["suppliers"] = suppliers_list
+ return data
+
+
+/*
+ A supplier of items
+*/
+/datum/cargo_supplier
+ var/short_name = "" //Short name of the cargo supplier
+ var/name = "" //Long name of the cargo supplier
+ var/description = "" //Description of the supplier
+ var/tag_line = "" //Tag line of the supplier
+ var/shuttle_time = 0 //Time the shuttle takes to get to the supplier
+ var/shuttle_price = 0 //Price to call the shuttle
+ var/available = 1 //If the supplier is available
+ var/price_modifier = 1 //Price modifier for the supplier
+//Gets a list of supplier - to be json encoded
+/datum/cargo_supplier/proc/get_list()
+ var/list/data = list()
+ data["short_name"] = short_name
+ data["name"] = name
+ data["description"] = description
+ data["tag_line"] = tag_line
+ data["shuttle_time"] = shuttle_time
+ data["shuttle_price"] = shuttle_price
+ data["available"] = available
+ data["price_modifier"] = price_modifier
+ return data
+
+
+/*
+ A category displayed in the cargo order app
+*/
+/datum/cargo_category
+ var/name = "cargo_category" //Name of the category
+ var/display_name = "Cargo Category"
+ var/description = "You should not see this" //Description of the Category
+ var/icon = "gear" //NanoUI Icon for the category
+ var/price_modifier = 1 //Price Modifier for the category
+ var/list/items = list() //List of items in the category
+
+// Gets a list of the cargo category - to be json encoded
+/datum/cargo_category/proc/get_list()
+ var/list/data = list()
+ data["name"] = name
+ data["display_name"] = display_name
+ data["description"] = description
+ data["icon"] = icon
+ data["price_modifier"] = price_modifier
+ return data
+
+// Gets a list of the items in the cargo category - to be json encoded
+/datum/cargo_category/proc/get_item_list()
+ var/list/item_list = list()
+ for(var/datum/cargo_item/ci in items)
+ item_list.Add(list(ci.get_list()))
+ return item_list
+
+/*
+ A order placed in the cargo order app.
+ Contains multiple order items
+*/
+/datum/cargo_order
+ var/list/items = list() //List of cargo_order_items in the order
+ var/order_id = 0 //ID of the order
+ var/price = 0 //Total price of the order
+ var/item_id = 1 //Current id of the item in the order
+ var/item_num = 0 //Numer of items in the container - Used to limit the items in the crate
+ var/status = "basket" //Status of the order: basket - Adding items, submitted - Submitted to cargo, approved - Order sent to suppliers, rejected - Order has been denied, shipped - Has been shipped to the station, delivered - Order has been delivered
+ var/container_type = "" //Type of the container for the order - cate, box
+ var/list/required_access = list() //Access required to unlock the crate
+ var/can_add_items = 1 //If new items can be added to the order
+ var/customer = null //Person that ordered the items
+ var/authorized_by = null //Person that authorized the order
+ var/received_by = null //Person the order has been delivered to by cargo
+ var/time_submitted = null //Time the order has been sent to cargo
+ var/time_approved = null //Time the order has been approved by cargo
+ var/time_shipped = null //Time the order has been shipped to the station
+ var/time_delivered = null //Time the order has been delivered
+ var/tracking_code = null //Use this code with the order ID to get details about the order
+ var/partial_shipment_fee = 0 //Partial Shipment Fee for the order
+ var/reason = null //Reason for the order
+
+//Gets the tracking code for the order. Generates one if it does not exist already
+/datum/cargo_order/proc/get_tracking_code()
+ if(!tracking_code)
+ tracking_code = rand(1000,9999)
+ return tracking_code
+
+// Returns a list of the items in the order - Formated as list to be json_encoded
+/datum/cargo_order/proc/get_item_list()
+ var/list/item_list = list()
+ for (var/datum/cargo_order_item/coi in items)
+ item_list.Add(list(coi.get_list()))
+ return item_list
+
+// Gets a list of the order data - Formated as list to be json_encoded
+/datum/cargo_order/proc/get_list()
+ var/list/data = list()
+ data["order_id"] = order_id
+ data["tracking_code"] = get_tracking_code()
+ data["price"] = get_value(2)
+ data["price_customer"] = get_value(0)
+ data["price_cargo"] = get_value(1)
+ data["status"] = get_order_status(0)
+ data["status_pretty"] = get_order_status(1)
+ data["customer"] = customer
+ data["authorized_by"] = authorized_by
+ data["received_by"] = received_by
+ data["time_submitted"] = time_submitted
+ data["time_approved"] = time_approved
+ data["time_shipped"] = time_shipped
+ data["time_delivered"] = time_delivered
+ data["items"] = get_item_list()
+ data["shipment_cost"] = partial_shipment_fee
+ data["shipment_cost_max"] = get_max_shipment_cost()
+ return data
+
+//Adds a item to a order. Returns a status message
+/datum/cargo_order/proc/add_item(var/datum/cargo_order_item/coi)
+ if(!coi)
+ return "Unable to add item - Internal Error"
+
+ //Check if the container type of the added item matches the one of the current order
+ if(container_type == "")
+ container_type = coi.ci.container_type
+ else if (container_type != coi.ci.container_type)
+ return "Unable to add item - Different container required" //You can only add items with the same container type to the order
+
+ //Check if more items can be added to the order
+ if(!can_add_items)
+ return "Unable to add item - Order can not contain more items"
+
+ if(!coi.ci.groupable) //The item is not groupable with other items and needs to be ordered on its own
+ if(get_item_count() > 0) // There are already other items in the order. -> Reject it
+ return "Unable to add item - Item can not be grouped and must be ordered separately"
+ else //No item in the order. Add it and set can_add_items to 0
+ can_add_items = 0
+
+ //Check if there is space in the container
+ if(item_num + coi.ci.amount > get_container_storage())
+ return "Unable to add item - Container full"
+
+ //Set item id of coi and increment item_id of co
+ coi.item_id = item_id
+ item_id += 1
+
+ //Increment the item number
+ item_num += coi.ci.amount
+
+ //Add coi to ordered item
+ items.Add(coi)
+ price += coi.price
+
+ //Update the access requirement of the order
+ if(coi.ci.access)
+ required_access.Add(coi.ci.access)
+
+ return "Item successfully added"
+
+//Removes a item from a order - Returns a status message
+/datum/cargo_order/proc/remove_item(var/remove_item_id)
+ //Find the item with the specified id in the items list
+ for (var/datum/cargo_order_item/coi in items)
+ if(coi)
+ if(coi.item_id == remove_item_id)
+ items.Remove(coi)
+ price -= coi.price
+ item_num -= coi.ci.amount
+ qdel(coi)
+ return "Item removed successfully"
+ return "Unable to remove item - Internal Error 608"
+
+// Returns the value of the order
+/datum/cargo_order/proc/get_value(var/type=0)
+ //Type specifies if the price cargo has to pay or the price the customer has to be should be returned
+ // 0 - Price the customer has to pay
+ // 1 - Price cargo has to pay
+ // 2 - Just the value of the items in the crate
+ switch(type)
+ if(0)
+ //The price of the contents of the crate + the price for the crate + the handling fee + the partial shipment fee
+ return price + SScargo.get_cratefee() + SScargo.get_handlingfee() + partial_shipment_fee
+ if(1)
+ //The price of the contents of the crate + the price of the crate
+ return price + SScargo.get_cratefee()
+ if(2)
+ //Just the value of the items in the crate
+ return price
+ else
+ //As a fallback, return the value of the items
+ return price
+
+// Returns the number of items in the order
+/datum/cargo_order/proc/get_item_count()
+ return items.len
+
+// Returns the type of the required container for the order
+/datum/cargo_order/proc/get_container_type()
+ switch(container_type)
+ if(CARGO_CONTAINER_CRATE)
+ if(required_access.len > 0)
+ return /obj/structure/closet/crate/secure
+ else
+ return /obj/structure/closet/crate
+ if(CARGO_CONTAINER_BOX)
+ if(required_access.len > 0)
+ return /obj/structure/closet/crate/secure/large
+ else
+ return /obj/structure/largecrate
+ if(CARGO_CONTAINER_FREEZER)
+ return /obj/structure/closet/crate/freezer
+ else
+ log_debug("Cargo: Tried to get container type for invalid container [container_type]")
+ return /obj/structure/largecrate
+// Returns the numer of items that can be stored in the container
+/datum/cargo_order/proc/get_container_storage()
+ switch(container_type)
+ if(CARGO_CONTAINER_CRATE)
+ return 40 //Thats the default storage capacity of a crate
+ if(CARGO_CONTAINER_FREEZER)
+ return 40
+ if(CARGO_CONTAINER_BOX)
+ return 5 //You can fit 5 larger items into a box
+ else
+ log_debug("Cargo: Tried to get storage size for invalid container [container_type]")
+ return 0 //Something went wrong
+
+// Gets the list of the suppliers involved in the order
+/datum/cargo_order/proc/get_supplier_list()
+ var/list/supplier_list = list()
+ for(var/datum/cargo_order_item/coi in items)
+ supplier_list[coi.supplier] = coi.supplier
+ return supplier_list
+
+// Gets the maximal shipment cost for the item
+/datum/cargo_order/proc/get_max_shipment_cost()
+ var/list/supplier_list = get_supplier_list()
+ var/cost = 0
+ for(var/supplier in supplier_list)
+ var/datum/cargo_supplier/cs = SScargo.cargo_suppliers[supplier]
+ if(cs)
+ cost += cs.shuttle_price
+ return cost
+
+// Gets the order status
+/datum/cargo_order/proc/get_order_status(var/pretty=1)
+ if(pretty)
+ switch(status)
+ if("submitted")
+ return "Submitted to Cargo"
+ if("approved")
+ return "Approved"
+ if("rejected")
+ return "Rejected"
+ if("shipped")
+ return "Shipped to the Station"
+ if("delivered")
+ return "Delivered"
+ else
+ return "Unknown Status"
+
+ else
+ return status
+
+// Returns a HTML to be printed for the order
+/datum/cargo_order/proc/get_report()
+ var/list/order_data = list()
+ order_data += "Order [order_id]
"
+ order_data += "
"
+ //List the personell involved in the order
+ order_data += "Ordered by: [customer]
"
+ order_data += "Submitted at: [time_submitted]
"
+ if(authorized_by)
+ order_data += "Authorized by: [authorized_by]
"
+ order_data += "Approved at: [time_approved]
"
+ if(time_shipped)
+ order_data += "Shipped at: [time_shipped]
"
+ if(received_by)
+ order_data += "Received by:
"
+ order_data += "Delivered at: [time_delivered]
"
+ order_data += "
"
+ order_data += "Order ID: [order_id]
"
+ order_data += "Tracking Code: [get_tracking_code()]
"
+ order_data += "Order Status: [get_order_status(1)]
"
+ order_data += "
"
+ if(required_access.len)
+ order_data += "Required Access:
"
+ order_data += ""
+ for(var/A in required_access)
+ order_data += "- [get_access_desc(A)]
"
+ order_data += "
"
+ order_data += "
"
+ order_data += "Order Fees:
"
+ order_data += ""
+ for(var/item in get_item_list())
+ order_data += "- [item["name"]]: [item["price"]]
"
+ order_data += "- Crate Fee: [SScargo.get_cratefee()]
"
+ order_data += "- Handling Fee: [SScargo.get_handlingfee()]
"
+ if(partial_shipment_fee == 0) //If the partial shipment fee has been calculated, then display it. Otherwise just display a placeholder
+ order_data += "- Additional Shuttle Fees may apply
"
+ else
+ order_data += "- Shuttle Fee: [partial_shipment_fee]
"
+ order_data += "
"
+
+ return order_data.Join("")
+
+
+/*
+ A cargo order item. Part of a category.
+ specifies the item, the supplier and the price of the item
+*/
+/datum/cargo_order_item
+ var/datum/cargo_item/ci //Item that has been ordered
+ var/datum/cargo_supplier/cs //Supplier the item has been ordered from
+ var/supplier //Supplier the item has been ordered from
+ var/price //Price of the item with the given supplier
+ var/item_id //Item id in the order
+ //TODO: Maybe add the option to set a fake item for traitors here -> So that cargo cant see what they are really ordering
+
+//Calculate Price
+/datum/cargo_order_item/proc/calculate_price()
+ price = ci.suppliers[supplier]["base_purchase_price"]
+ //Add suppler modifier
+ price *= cs.price_modifier
+ for(var/category in ci.categories)
+ var/datum/cargo_category/cc = SScargo.get_category_by_name(category)
+ if(cc)
+ price *= cc.price_modifier
+ return price
+
+// Gets a list of the cargo order item - to be json encoded
+/datum/cargo_order_item/proc/get_list()
+ var/list/data = list()
+ data["name"] = ci.name
+ data["supplier"] = supplier
+ data["supplier_name"] = cs.name
+ data["price"] = price
+ data["item_id"] = item_id
+ return data
+
+/datum/cargo_order_item/Destroy()
+ ci = null
+ cs = null
+ return ..()
+
+
+/*
+ A shipment sent to the station. Contains multiple orders
+*/
+/datum/cargo_shipment
+ var/list/orders = list() //List of orders in that shipment
+ var/shipment_num //Number of the shipment
+ var/shipment_cost_sell = 0//The amount of money cargo got for the shipment
+ var/shipment_cost_purchase = 0//The amount of money cargo paid for the shipment
+ var/shipment_invoice = null//The invoice for the shipment (detailing the expenses ,credits received and charges)
+ var/shuttle_fee//The shuttle fee at the time of calling it
+ var/shuttle_time //The time the shuttle took to get to the station
+ var/shuttle_called_by //The person that called the shuttle
+ var/shuttle_recalled_by //The person that recalled the shuttle
+ var/completed = 0
+
+/datum/cargo_shipment/proc/get_list(var/shipment_completion = 1)
+ if(shipment_completion != completed)
+ return null
+ else
+ var/list/data = list()
+ data["shipment_num"] = shipment_num
+ data["shipment_cost_sell"] = shipment_cost_sell
+ data["shipment_cost_purchase"] = shipment_cost_purchase
+ data["shipment_invoice"] = shipment_invoice
+ data["shuttle_fee"] = shuttle_fee
+ data["shuttle_time"] = shuttle_time
+ data["shuttle_called_by"] = shuttle_called_by
+ data["shuttle_recalled_by"] = shuttle_recalled_by
+ data["invoice"] = get_invoice()
+ return data
+
+// Generates the invoice at the time of shipping
+/datum/cargo_shipment/proc/generate_invoice()
+ var/list/invoice_data = list()
+ invoice_data += "One day
"
+ invoice_data += "This will contain the invoice
"
+ invoice_data += "Right now its just a placeholder
"
+ invoice_data += "Shipment num: [shipment_num]
"
+ invoice_data += "shipment cost sell: [shipment_cost_sell]
"
+ invoice_data += "shipment cost purchse: [shipment_cost_purchase]
"
+ invoice_data += "shuttle fee: [shuttle_fee]
"
+ invoice_data += "shuttle time: [shuttle_time]
"
+ invoice_data += "shuttle called by: [shuttle_called_by]
"
+ invoice_data += "shuttle recalled by: [shuttle_recalled_by]
"
+
+ shipment_invoice = invoice_data.Join("")
+ completed = 1
+ return shipment_invoice
+
+// Returns the invoice. Generates it if it does not exist
+/datum/cargo_shipment/proc/get_invoice()
+ if(!shipment_invoice)
+ if(completed == 1)
+ generate_invoice()
+ else
+ return "Invoice Unavailable. Shipment not completed."
+ return shipment_invoice
\ No newline at end of file
diff --git a/code/game/machinery/computer/supply.dm b/code/game/machinery/computer/supply.dm
deleted file mode 100644
index f73aea65a5c..00000000000
--- a/code/game/machinery/computer/supply.dm
+++ /dev/null
@@ -1,416 +0,0 @@
-/obj/machinery/computer/supplycomp
- name = "supply control console"
- icon = 'icons/obj/computer.dmi'
-
- icon_screen = "supply"
- light_color = LIGHT_COLOR_ORANGE
- req_access = list(access_cargo)
- circuit = /obj/item/weapon/circuitboard/supplycomp
- var/temp = null
- var/reqtime = 0 //Cooldown for requisitions - Quarxink
- var/hacked = 0
- var/can_order_contraband = 0
- var/last_viewed_group = "categories"
-
-/obj/machinery/computer/ordercomp
- name = "supply ordering console"
- icon = 'icons/obj/computer.dmi'
- icon_screen = "request"
- light_color = LIGHT_COLOR_ORANGE
- circuit = /obj/item/weapon/circuitboard/ordercomp
- var/temp = null
- var/reqtime = 0 //Cooldown for requisitions - Quarxink
- var/last_viewed_group = "categories"
-
-/obj/machinery/computer/ordercomp/attack_ai(var/mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/supplycomp/attack_ai(var/mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/ordercomp/attack_hand(var/mob/user as mob)
- if(..())
- return
- user.set_machine(src)
- var/dat
- if(temp)
- dat = temp
- else
- var/datum/shuttle/ferry/supply/shuttle = SScargo.shuttle
- if (shuttle)
- dat += {"
Supply shuttle
- Location: [shuttle.has_arrive_time() ? "Moving to station ([shuttle.eta_minutes()] Mins.)":shuttle.at_station() ? "Docked":"Away"]
-
Supply points: [SScargo.points]
-
\nRequest items
- View approved orders
- View requests
- Close"}
-
- user << browse(dat, "window=computer;size=575x450")
- onclose(user, "computer")
- return
-
-/obj/machinery/computer/ordercomp/Topic(href, href_list)
- if(..())
- return 1
-
- if( isturf(loc) && (in_range(src, usr) || istype(usr, /mob/living/silicon)) )
- usr.set_machine(src)
-
- if(href_list["order"])
- if(href_list["order"] == "categories")
- //all_supply_groups
- //Request what?
- last_viewed_group = "categories"
- temp = "Supply points: [SScargo.points]
"
- temp += "Main Menu
"
- temp += "Select a category
"
- for(var/supply_group_name in all_supply_groups )
- temp += "[supply_group_name]
"
- else
- last_viewed_group = href_list["order"]
- temp = "Supply points: [SScargo.points]
"
- temp += "Back to all categories
"
- temp += "Request from: [last_viewed_group]
"
- for(var/supply_name in SScargo.supply_packs )
- var/datum/supply_packs/N = SScargo.supply_packs[supply_name]
- if(N.hidden || N.contraband || N.group != last_viewed_group) continue //Have to send the type instead of a reference to
- temp += "[supply_name] Cost: [N.cost]
" //the obj because it would get caught by the garbage
-
- else if (href_list["doorder"])
- if(world.time < reqtime)
- for(var/mob/V in hearers(src))
- V.show_message("[src]'s monitor flashes, \"[world.time - reqtime] seconds remaining until another requisition form may be printed.\"")
- return
-
- //Find the correct supply_pack datum
- var/datum/supply_packs/P = SScargo.supply_packs[href_list["doorder"]]
- if(!istype(P)) return
-
- var/timeout = world.time + 600
- var/reason = sanitize(input(usr,"Reason:","Why do you require this item?","") as null|text)
- if(world.time > timeout) return
- if(!reason) return
-
- var/idname = "*None Provided*"
- var/idrank = "*None Provided*"
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- idname = H.get_authentification_name()
- idrank = H.get_assignment()
- else if(issilicon(usr))
- idname = usr.real_name
-
- SScargo.ordernum++
- var/obj/item/weapon/paper/reqform = new /obj/item/weapon/paper(loc)
- reqform.name = "Requisition Form - [P.name]"
- reqform.info += "[station_name] Supply Requisition Form
"
- reqform.info += "INDEX: #[SScargo.ordernum]
"
- reqform.info += "REQUESTED BY: [idname]
"
- reqform.info += "RANK: [idrank]
"
- reqform.info += "REASON: [reason]
"
- reqform.info += "SUPPLY CRATE TYPE: [P.name]
"
- reqform.info += "ACCESS RESTRICTION: [get_access_desc(P.access)]
"
- reqform.info += "CONTENTS:
"
- reqform.info += P.manifest
- reqform.info += "
"
- reqform.info += "STAMP BELOW TO APPROVE THIS REQUISITION:
"
-
- reqform.update_icon() //Fix for appearing blank when printed.
- reqtime = (world.time + 5) % 1e5
-
- //make our supply_order datum
- var/datum/supply_order/O = new /datum/supply_order()
- O.ordernum = SScargo.ordernum
- O.object = P
- O.orderedby = idname
- SScargo.requestlist += O
-
- temp = "Thanks for your request. The cargo team will process it as soon as possible.
"
- temp += "
Back Main Menu"
-
- else if (href_list["vieworders"])
- temp = "Current approved orders:
"
- for(var/S in SScargo.shoppinglist)
- var/datum/supply_order/SO = S
- temp += "[SO.object.name] approved by [SO.orderedby] [SO.comment ? "([SO.comment])":""]
"
- temp += "
OK"
-
- else if (href_list["viewrequests"])
- temp = "Current requests:
"
- for(var/S in SScargo.requestlist)
- var/datum/supply_order/SO = S
- temp += "#[SO.ordernum] - [SO.object.name] requested by [SO.orderedby]
"
- temp += "
OK"
-
- else if (href_list["mainmenu"])
- temp = null
-
- add_fingerprint(usr)
- updateUsrDialog()
- return
-
-/obj/machinery/computer/supplycomp/attack_hand(var/mob/user as mob)
- if(!allowed(user))
- user << "Access Denied."
- return
-
- if(..())
- return
- user.set_machine(src)
- post_signal("supply")
- var/dat
- if (temp)
- dat = temp
- else
- var/datum/shuttle/ferry/supply/shuttle = SScargo.shuttle
- if (shuttle)
- dat += "
Supply shuttle
"
- dat += "\nLocation: "
- if (shuttle.has_arrive_time())
- dat += "In transit ([shuttle.eta_minutes()] Mins.)
"
- else
- if (shuttle.at_station())
- if (shuttle.docking_controller)
- switch(shuttle.docking_controller.get_docking_status())
- if ("docked") dat += "Docked at station
"
- if ("undocked") dat += "Undocked from station
"
- if ("docking") dat += "Docking with station [shuttle.can_force()? "Force Launch" : ""]
"
- if ("undocking") dat += "Undocking from station [shuttle.can_force()? "Force Launch" : ""]
"
- else
- dat += "Station
"
-
- if (shuttle.can_launch())
- dat += "Send away"
- else if (shuttle.can_cancel())
- dat += "Cancel launch"
- else
- dat += "*Shuttle is busy*"
- dat += "
\n
"
- else
- dat += "Away
"
- if (shuttle.can_launch())
- dat += "Request supply shuttle"
- else if (shuttle.can_cancel())
- dat += "Cancel request"
- else
- dat += "*Shuttle is busy*"
- dat += "
\n
"
-
-
- dat += {"
\nSupply points: [SScargo.points]
\n
- \nOrder items
\n
- \nView requests
\n
- \nView orders
\n
- \nClose"}
-
-
- user << browse(dat, "window=computer;size=575x450")
- onclose(user, "computer")
- return
-
-/obj/machinery/computer/supplycomp/emag_act(var/remaining_charges, var/mob/user)
- if(!hacked)
- user << "Special supplies unlocked."
- hacked = 1
- return 1
-
-/obj/machinery/computer/supplycomp/Topic(href, href_list)
- if(!SScargo)
- world.log << "## ERROR: Eek. The SScargo controller datum is missing somehow."
- return
- var/datum/shuttle/ferry/supply/shuttle = SScargo.shuttle
- if (!shuttle)
- world.log << "## ERROR: Eek. The supply/shuttle datum is missing somehow."
- return
- if(..())
- return 1
-
- if(isturf(loc) && ( in_range(src, usr) || istype(usr, /mob/living/silicon) ) )
- usr.set_machine(src)
-
- //Calling the shuttle
- if(href_list["send"])
- if(shuttle.at_station())
- if (shuttle.forbidden_atoms_check())
- temp = "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.
OK"
- else
- shuttle.launch(src)
- temp = "Initiating launch sequence. \[Force Launch\]
OK"
- else
- shuttle.launch(src)
- temp = "The supply shuttle has been called and will arrive in approximately [round(SScargo.movetime/600,1)] minutes.
OK"
- post_signal("supply")
-
- if (href_list["force_send"])
- shuttle.force_launch(src)
-
- if (href_list["cancel_send"])
- shuttle.cancel_launch(src)
-
- else if (href_list["order"])
- //if(!shuttle.idle()) return //this shouldn't be necessary it seems
- if(href_list["order"] == "categories")
- //all_supply_groups
- //Request what?
- last_viewed_group = "categories"
- temp = "Supply points: [SScargo.points]
"
- temp += "Main Menu
"
- temp += "Select a category
"
- for(var/supply_group_name in all_supply_groups )
- temp += "[supply_group_name]
"
- else
- last_viewed_group = href_list["order"]
- temp = "Supply points: [SScargo.points]
"
- temp += "Back to all categories
"
- temp += "Request from: [last_viewed_group]
"
- for(var/supply_name in SScargo.supply_packs )
- var/datum/supply_packs/N = SScargo.supply_packs[supply_name]
- if((N.hidden && !hacked) || (N.contraband && !can_order_contraband) || N.group != last_viewed_group) continue //Have to send the type instead of a reference to
- temp += "[supply_name] Cost: [N.cost]
" //the obj because it would get caught by the garbage
-
- /*temp = "Supply points: [SScargo.points]
Request what?
"
-
- for(var/supply_name in SScargo.supply_packs )
- var/datum/supply_packs/N = SScargo.supply_packs[supply_name]
- if(N.hidden && !hacked) continue
- if(N.contraband && !can_order_contraband) continue
- temp += "[supply_name] Cost: [N.cost]
" //the obj because it would get caught by the garbage
- temp += "
OK"*/
-
- else if (href_list["doorder"])
- if(world.time < reqtime)
- for(var/mob/V in hearers(src))
- V.show_message("[src]'s monitor flashes, \"[world.time - reqtime] seconds remaining until another requisition form may be printed.\"")
- return
-
- //Find the correct supply_pack datum
- var/datum/supply_packs/P = SScargo.supply_packs[href_list["doorder"]]
- if(!istype(P)) return
-
- var/timeout = world.time + 600
- var/reason = sanitize(input(usr,"Reason:","Why do you require this item?","") as null|text)
- if(world.time > timeout) return
- if(!reason) return
-
- var/idname = "*None Provided*"
- var/idrank = "*None Provided*"
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- idname = H.get_authentification_name()
- idrank = H.get_assignment()
- else if(issilicon(usr))
- idname = usr.real_name
-
- SScargo.ordernum++
- var/obj/item/weapon/paper/reqform = new /obj/item/weapon/paper(loc)
- reqform.name = "Requisition Form - [P.name]"
- reqform.info += "[station_name] Supply Requisition Form
"
- reqform.info += "INDEX: #[SScargo.ordernum]
"
- reqform.info += "REQUESTED BY: [idname]
"
- reqform.info += "RANK: [idrank]
"
- reqform.info += "REASON: [reason]
"
- reqform.info += "SUPPLY CRATE TYPE: [P.name]
"
- reqform.info += "ACCESS RESTRICTION: [get_access_desc(P.access)]
"
- reqform.info += "CONTENTS:
"
- reqform.info += P.manifest
- reqform.info += "
"
- reqform.info += "STAMP BELOW TO APPROVE THIS REQUISITION:
"
-
- reqform.update_icon() //Fix for appearing blank when printed.
- reqtime = (world.time + 5) % 1e5
-
- //make our supply_order datum
- var/datum/supply_order/O = new /datum/supply_order()
- O.ordernum = SScargo.ordernum
- O.object = P
- O.orderedby = idname
- SScargo.requestlist += O
-
- temp = "Order request placed.
"
- temp += "
Back | Main Menu | Authorize Order"
-
- else if(href_list["confirmorder"])
- //Find the correct supply_order datum
- var/ordernum = text2num(href_list["confirmorder"])
- var/datum/supply_order/O
- var/datum/supply_packs/P
- temp = "Invalid Request"
- for(var/i=1, i<=SScargo.requestlist.len, i++)
- var/datum/supply_order/SO = SScargo.requestlist[i]
- if(SO.ordernum == ordernum)
- O = SO
- P = O.object
- if(SScargo.points >= P.cost)
- SScargo.requestlist.Cut(i,i+1)
- SScargo.points -= P.cost
- SScargo.shoppinglist += O
- temp = "Thanks for your order.
"
- temp += "
Back Main Menu"
- else
- temp = "Not enough supply points.
"
- temp += "
Back Main Menu"
- break
-
- else if (href_list["vieworders"])
- temp = "Current approved orders:
"
- for(var/S in SScargo.shoppinglist)
- var/datum/supply_order/SO = S
- temp += "#[SO.ordernum] - [SO.object.name] approved by [SO.orderedby][SO.comment ? " ([SO.comment])":""]
"// (Cancel)
"
- temp += "
OK"
-/*
- else if (href_list["cancelorder"])
- var/datum/supply_order/remove_supply = href_list["cancelorder"]
- supply_shuttle_shoppinglist -= remove_supply
- supply_shuttle_points += remove_supply.object.cost
- temp += "Canceled: [remove_supply.object.name]
"
-
- for(var/S in supply_shuttle_shoppinglist)
- var/datum/supply_order/SO = S
- temp += "[SO.object.name] approved by [SO.orderedby][SO.comment ? " ([SO.comment])":""] (Cancel)
"
- temp += "
OK"
-*/
- else if (href_list["viewrequests"])
- temp = "Current requests:
"
- for(var/S in SScargo.requestlist)
- var/datum/supply_order/SO = S
- temp += "#[SO.ordernum] - [SO.object.name] requested by [SO.orderedby] Approve Remove
"
-
- temp += "
Clear list"
- temp += "
OK"
-
- else if (href_list["rreq"])
- var/ordernum = text2num(href_list["rreq"])
- temp = "Invalid Request.
"
- for(var/i=1, i<=SScargo.requestlist.len, i++)
- var/datum/supply_order/SO = SScargo.requestlist[i]
- if(SO.ordernum == ordernum)
- SScargo.requestlist.Cut(i,i+1)
- temp = "Request removed.
"
- break
- temp += "
Back Main Menu"
-
- else if (href_list["clearreq"])
- SScargo.requestlist.Cut()
- temp = "List cleared.
"
- temp += "
OK"
-
- else if (href_list["mainmenu"])
- temp = null
-
- add_fingerprint(usr)
- updateUsrDialog()
- return
-
-/obj/machinery/computer/supplycomp/proc/post_signal(var/command)
-
- var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
-
- if(!frequency) return
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = 1
- status_signal.data["command"] = command
-
- frequency.post_signal(src, status_signal)
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 32595ebf2bc..34c98d766ac 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -397,30 +397,13 @@
supplyData["shuttle_moving"] = shuttle.has_arrive_time()
supplyData["shuttle_eta"] = shuttle.eta_minutes()
supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock"
- var/supplyOrderCount = 0
- var/supplyOrderData[0]
- for(var/S in SScargo.shoppinglist)
- var/datum/supply_order/SO = S
-
- supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment))
- if(!supplyOrderData.len)
- supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null)
-
- supplyData["approved"] = supplyOrderData
- supplyData["approved_count"] = supplyOrderCount
-
- var/requestCount = 0
- var/requestData[0]
- for(var/S in SScargo.requestlist)
- var/datum/supply_order/SO = S
- requestCount++
- requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment))
- if(!requestData.len)
- requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null)
-
- supplyData["requests"] = requestData
- supplyData["requests_count"] = requestCount
+ var/list/approved_orders = SScargo.get_orders_by_status("approved",1)
+ supplyData["approved"] = approved_orders
+ supplyData["approved_count"] = approved_orders.len
+ var/list/requested_orders = SScargo.get_orders_by_status("submitted",1)
+ supplyData["requests"] = requested_orders
+ supplyData["requests_count"] = requested_orders.len
values["supply"] = supplyData
diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm
index 39ec0ee0dff..6b123490756 100644
--- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm
+++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm
@@ -142,11 +142,6 @@
name = T_BOARD("disease splicer")
build_path = /obj/machinery/computer/diseasesplicer
-/obj/item/weapon/circuitboard/ordercomp
- name = T_BOARD("supply ordering console")
- build_path = /obj/machinery/computer/ordercomp
- origin_tech = list(TECH_DATA = 2)
-
/obj/item/weapon/circuitboard/mining_shuttle
name = T_BOARD("mining shuttle console")
build_path = /obj/machinery/computer/shuttle_control/mining
diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm
index 22cf2e50ac3..3c709c21988 100644
--- a/code/modules/events/event_container.dm
+++ b/code/modules/events/event_container.dm
@@ -137,7 +137,6 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Money Lotto", /datum/event/money_lotto, 0, list(ASSIGNMENT_ANY = 1), 1, 5, 15),
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mundane News", /datum/event/mundane_news, 300),
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "PDA Spam", /datum/event/pda_spam, 0, list(ASSIGNMENT_ANY = 4), 0, 25, 50),
- new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Shipping Error", /datum/event/shipping_error , 30, list(ASSIGNMENT_ANY = 2), 0),
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Trivial News", /datum/event/trivial_news, 400),
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation", /datum/event/infestation, 60, list(ASSIGNMENT_JANITOR = 20, ASSIGNMENT_SECURITY = 10)),
new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 75, list(ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_GARDENER = 20)),
diff --git a/code/modules/events/shipping_error.dm b/code/modules/events/shipping_error.dm
deleted file mode 100644
index 45d6bdcfeaa..00000000000
--- a/code/modules/events/shipping_error.dm
+++ /dev/null
@@ -1,6 +0,0 @@
-/datum/event/shipping_error/start()
- var/datum/supply_order/O = new /datum/supply_order()
- O.ordernum = SScargo.ordernum
- O.object = SScargo.supply_packs[pick(SScargo.supply_packs)]
- O.orderedby = random_name(pick(MALE,FEMALE), species = "Human")
- SScargo.shoppinglist += O
diff --git a/code/modules/modular_computers/computers/subtypes/preset_console.dm b/code/modules/modular_computers/computers/subtypes/preset_console.dm
index 3808716880e..36bf54a6d17 100644
--- a/code/modules/modular_computers/computers/subtypes/preset_console.dm
+++ b/code/modules/modular_computers/computers/subtypes/preset_console.dm
@@ -59,7 +59,12 @@
_app_preset_name = "civilian"
enrolled = 1
-ERT
+// Supply
+/obj/item/modular_computer/console/preset/supply/
+ _app_preset_name = "supply"
+ enrolled = 1
+
+// ERT
/obj/item/modular_computer/console/preset/ert/install_default_hardware()
..()
ai_slot = new/obj/item/weapon/computer_hardware/ai_slot(src)
diff --git a/code/modules/modular_computers/file_system/programs/app_presets.dm b/code/modules/modular_computers/file_system/programs/app_presets.dm
index e2c4d3544ae..9347e80c0eb 100644
--- a/code/modules/modular_computers/file_system/programs/app_presets.dm
+++ b/code/modules/modular_computers/file_system/programs/app_presets.dm
@@ -1,7 +1,7 @@
/datum/modular_computer_app_presets
var/name = "default_preset"
var/display_name = "default preset"
- var/description = "Description of the preset"
+ var/description = "Description of the preset."
var/available = 0
/datum/modular_computer_app_presets/proc/return_install_programs()
return list()
@@ -9,7 +9,7 @@
/datum/modular_computer_app_presets/all
name = "all"
display_name = "All Programs"
- description = "Contains all Progams"
+ description = "Contains all programs."
available = 0
/datum/modular_computer_app_presets/all/return_install_programs()
var/list/_prg_list = list()
@@ -21,7 +21,7 @@
/datum/modular_computer_app_presets/engineering
name = "engineering"
display_name = "Engineering"
- description = "Contains the most common engineering Programs"
+ description = "Contains the most common engineering programs."
available = 1
/datum/modular_computer_app_presets/engineering/return_install_programs()
var/list/_prg_list = list(
@@ -39,7 +39,7 @@
/datum/modular_computer_app_presets/medical
name = "medical"
display_name = "Medical"
- description = "Contains the most common medical Programs"
+ description = "Contains the most common medical programs."
available = 1
/datum/modular_computer_app_presets/medical/return_install_programs()
var/list/_prg_list = list(
@@ -52,7 +52,7 @@
/datum/modular_computer_app_presets/research
name = "research"
display_name = "Research"
- description = "Contains the most common research Programs"
+ description = "Contains the most common research programs."
available = 1
/datum/modular_computer_app_presets/research/return_install_programs()
var/list/_prg_list = list(
@@ -67,7 +67,7 @@
/datum/modular_computer_app_presets/command
name = "command"
display_name = "Command"
- description = "Contains the most common command Programs"
+ description = "Contains the most common command programs."
available = 1
/datum/modular_computer_app_presets/command/return_install_programs()
var/list/_prg_list = list(
@@ -81,7 +81,7 @@
/datum/modular_computer_app_presets/security
name = "security"
display_name = "Security"
- description = "Contains the most common security Programs"
+ description = "Contains the most common security programs."
available = 1
/datum/modular_computer_app_presets/security/return_install_programs()
var/list/_prg_list = list(
@@ -96,21 +96,36 @@
/datum/modular_computer_app_presets/civilian
name = "civilian"
display_name = "Civilian"
- description = "Contains the most common civilian Programs"
+ description = "Contains the most common civilian programs."
available = 1
/datum/modular_computer_app_presets/civilian/return_install_programs()
var/list/_prg_list = list(
new/datum/computer_file/program/filemanager(),
new/datum/computer_file/program/chatclient(),
new/datum/computer_file/program/game/arcade(),
- new/datum/computer_file/program/game/sudoku()
+ new/datum/computer_file/program/game/sudoku(),
+ new/datum/computer_file/program/civilian/cargoorder()
+ )
+ return _prg_list
+
+/datum/modular_computer_app_presets/supply
+ name = "supply"
+ display_name = "Supply"
+ description = "Contains the most common cargo programs."
+ available = 1
+/datum/modular_computer_app_presets/supply/return_install_programs()
+ var/list/_prg_list = list(
+ new/datum/computer_file/program/filemanager(),
+ new/datum/computer_file/program/chatclient(),
+ new/datum/computer_file/program/civilian/cargocontrol(),
+ new/datum/computer_file/program/civilian/cargoorder()
)
return _prg_list
/datum/modular_computer_app_presets/wall_generic
name = "wallgeneric"
display_name = "Wall - Generic"
- description = "A generic preset for the wall console"
+ description = "A generic preset for the wall console."
available = 0
/datum/modular_computer_app_presets/wall_generic/return_install_programs()
var/list/_prg_list = list(
@@ -124,7 +139,7 @@
/datum/modular_computer_app_presets/merc
name = "merc"
display_name = "Mercenary"
- description = "Preset for the Merc Console"
+ description = "Preset for the Merc Console."
available = 0
/datum/modular_computer_app_presets/merc/return_install_programs()
var/list/_prg_list = list(
@@ -137,7 +152,7 @@
/datum/modular_computer_app_presets/ert
name = "ert"
display_name = "EmergencyResposeTeam"
- description = "Preset for the ERT Console"
+ description = "Preset for the ERT Console."
available = 0
/datum/modular_computer_app_presets/ert/return_install_programs()
var/list/_prg_list = list(
@@ -155,7 +170,7 @@
/datum/modular_computer_app_presets/trashcompactor
name = "trashcompactor"
display_name = "Trash Compactor"
- description = "A preset for the Trash Compactor Wall Console"
+ description = "A preset for the Trash Compactor Wall Console."
available = 0
/datum/modular_computer_app_presets/trashcompactor/return_install_programs()
var/list/_prg_list = list(
@@ -167,7 +182,7 @@
/datum/modular_computer_app_presets/merchant
name = "merchant"
display_name = "Merchant"
- description = "A preset for the merchant console"
+ description = "A preset for the merchant console."
available = 0
/datum/modular_computer_app_presets/merchant/return_install_programs()
var/list/_prg_list = list(
diff --git a/code/modules/modular_computers/file_system/programs/civilian/cargo_control.dm b/code/modules/modular_computers/file_system/programs/civilian/cargo_control.dm
new file mode 100644
index 00000000000..8972e08674f
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/civilian/cargo_control.dm
@@ -0,0 +1,192 @@
+/datum/computer_file/program/civilian/cargocontrol
+ filename = "cargocontrol"
+ filedesc = "Cargo Control"
+ extended_desc = "Application to Control Cargo Orders"
+ size = 12
+ requires_ntnet = 1
+ available_on_ntnet = 1
+ required_access_download = access_hop
+ required_access_run = access_cargo
+ nanomodule_path = /datum/nano_module/program/civilian/cargocontrol/
+
+/datum/nano_module/program/civilian/cargocontrol/
+ name = "Cargo Control"
+ var/page = "overview_main" //overview_main - Main Menu, overview_submitted - Submitted Order Overview, overview_approved - Approved Order Overview, settings - Settings, details - order details
+ var/last_user_name = "" //Name of the User that last used the computer
+ var/status_message = null //A status message that can be displayed
+ var/list/order_details = list() //Order Details for the order
+ var/list/shipment_details = list() //Shipment Details for a selected shipment
+
+/datum/nano_module/program/civilian/cargocontrol/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
+ var/list/data = host.initial_data()
+
+ post_signal("supply")
+
+ //Send the page to display
+ data["page"] = page
+ //Send teh status message
+ data["status_message"] = status_message
+
+ //Pass the ID Data
+ var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
+ last_user_name = GetNameAndAssignmentFromId(user_id_card)
+ data["username"] = last_user_name
+
+ var/list/submitted_orders = SScargo.get_orders_by_status("submitted",1)
+ data["order_submitted_number"] = submitted_orders.len
+ data["order_submitted_value"] = SScargo.get_orders_value_by_status("submitted",1)
+ data["order_submitted_suppliers"] = SScargo.get_order_suppliers_by_status("submitted",1)
+ data["order_submitted_shuttle_time"] = SScargo.get_pending_shipment_time("submitted")
+ data["order_submitted_shuttle_price"] = SScargo.get_pending_shipment_cost("submitted")
+ if(page == "overview_submitted")
+ data["order_list"] = submitted_orders
+
+ var/list/approved_orders = SScargo.get_orders_by_status("approved",1)
+ data["order_approved_number"] = approved_orders.len
+ data["order_approved_value"] = SScargo.get_orders_value_by_status("approved",1)
+ data["order_approved_suppliers"] = SScargo.get_order_suppliers_by_status("approved",1)
+ data["order_approved_shuttle_time"] = SScargo.get_pending_shipment_time("approved")
+ data["order_approved_shuttle_price"] = SScargo.get_pending_shipment_cost("approved")
+ if(page == "overview_approved")
+ data["order_list"] = approved_orders
+
+ var/list/shipped_orders = SScargo.get_orders_by_status("shipped",1)
+ data["order_shipped_number"] = shipped_orders.len
+ data["order_shipped_value"] = SScargo.get_orders_value_by_status("shipped",1)
+ if(page == "overview_shipped")
+ data["order_list"] = shipped_orders
+
+ if(page == "order_details")
+ data["order_details"] = order_details
+
+ if(page == "overview_shipments")
+ data["shipment_list"] = SScargo.get_shipment_list()
+
+ if(page == "shipment_details")
+ data["shipment_details"] = shipment_details
+
+ data["cargo_money"] = SScargo.get_cargo_money()
+ data["handling_fee"] = SScargo.get_handlingfee()
+
+ //Shuttle Stuff
+ var/datum/shuttle/ferry/supply/shuttle = SScargo.shuttle
+ if(shuttle)
+ data["shuttle_available"] = 1
+ data["shuttle_has_arrive_time"] = shuttle.has_arrive_time()
+ data["shuttle_eta_minutes"] = shuttle.eta_minutes()
+ data["shuttle_can_launch"] = shuttle.can_launch()
+ data["shuttle_can_cancel"] = shuttle.can_cancel()
+ data["shuttle_can_force"] = shuttle.can_force()
+ data["shuttle_at_station"] = shuttle.at_station()
+ if(shuttle.docking_controller)
+ data["shuttle_docking_status"] = shuttle.docking_controller.get_docking_status()
+ else
+ data["shuttle_docking_status"] = "error"
+ else
+ data["shuttle_available"] = 0
+
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ ui = new(user, src, ui_key, "cargo_control.tmpl", name, 850, 600, state = state)
+ ui.auto_update_layout = 1
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+
+/datum/nano_module/program/civilian/cargocontrol/Topic(href, href_list)
+ var/datum/shuttle/ferry/supply/shuttle = SScargo.shuttle
+ if (!shuttle)
+ world.log << "## ERROR: Eek. The supply/shuttle datum is missing somehow."
+ return
+ if(..())
+ return 1
+
+ //Page switch between main, submitted, approved and settings
+ if(href_list["page"])
+ switch(href_list["page"])
+ if("overview_main")
+ page = "overview_main" //Main overview page with links to the different sub overview pages - submitted, approved, shipped
+ if("overview_submitted")
+ page = "overview_submitted" //Overview page listing the orders that have been submitted with options to view them, approve them and reject them
+ if("overview_approved")
+ page = "overview_approved" //Overview page listing the current shuttle price and time as well as orders that have been approved, with options to view the details
+ if("overview_shipped")
+ page = "overview_shipped" //Overview page listing the orders that have been shipped to the station but not delivered, with the option to mark them as delivered as well as to specify a person it has been delivered to
+ if("order_details")
+ page = "order_details" //Details page for a specific order - Lists the contents of the orde with the suppliers, prices and required access levels
+ //Fetch the order details and store it for the order. No need to fetch it again every 2 seconds
+ var/datum/cargo_order/co = SScargo.get_order_by_id(text2num(href_list["order_details"]))
+ order_details = co.get_list()
+ if("overview_shipments") //Overview of the shipments to / from the station
+ page = "overview_shipments"
+ if("shipment_details") //Details of a Shipment to / from the station
+ page = "shipment_details"
+ if("settings")
+ page = "settings" //Settings page that allows to tweak various settings such as the cargo handling fee
+ else
+ page = "overview_main" //fall back to overview_main if a unknown page has been supplied
+ return 1
+
+ //Approve a order
+ if(href_list["order_approve"])
+ var/datum/cargo_order/co = SScargo.get_order_by_id(text2num(href_list["order_approve"]))
+ if(co)
+ var/message = SScargo.approve_order(co,last_user_name)
+ if(message)
+ status_message = message
+ return 1
+
+ //Reject a order
+ if(href_list["order_reject"])
+ var/datum/cargo_order/co = SScargo.get_order_by_id(text2num(href_list["order_reject"]))
+ if(co)
+ var/message = SScargo.reject_order(co)
+ if(message)
+ status_message = message
+ return 1
+
+ //Send shuttle
+ if(href_list["shuttle_send"])
+ var/message = SScargo.shuttle_call(last_user_name)
+ if(message)
+ status_message = message
+ return 1
+
+ //Cancel shuttle
+ if(href_list["shuttle_cancel"])
+ var/message = SScargo.shuttle_cancel()
+ if(message)
+ status_message = message
+ return 1
+
+ //Force shuttle
+ if(href_list["shuttle_force"])
+ var/message = SScargo.shuttle_force()
+ if(message)
+ status_message = message
+ return 1
+
+ //Clear Status Message
+ if(href_list["clear_message"])
+ status_message = null
+ return 1
+
+ if(href_list["handling_fee"])
+ var/handling_fee = sanitize(input(usr,"Handling Fee:","Set the new handling fee?",SScargo.get_handlingfee()) as null|text)
+ status_message = SScargo.set_handlingfee(text2num(handling_fee))
+ return 1
+
+ //Change Settings
+
+/datum/nano_module/program/civilian/cargocontrol/proc/post_signal(var/command) //Old code right here - Used to send a refresh command to the status screens incargo
+
+ var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
+
+ if(!frequency) return
+
+ var/datum/signal/status_signal = new
+ status_signal.source = src
+ status_signal.transmission_method = 1
+ status_signal.data["command"] = command
+
+ frequency.post_signal(src, status_signal)
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/civilian/cargo_order.dm b/code/modules/modular_computers/file_system/programs/civilian/cargo_order.dm
new file mode 100644
index 00000000000..3e8d213581d
--- /dev/null
+++ b/code/modules/modular_computers/file_system/programs/civilian/cargo_order.dm
@@ -0,0 +1,187 @@
+/datum/computer_file/program/civilian/cargoorder
+ filename = "cargoorder"
+ filedesc = "Cargo Order"
+ extended_desc = "Application to Order Items from Cargo"
+ size = 10
+ requires_ntnet = 1
+ available_on_ntnet = 1
+ nanomodule_path = /datum/nano_module/program/civilian/cargoorder/
+
+/datum/nano_module/program/civilian/cargoorder/
+ name = "Cargo Order"
+ var/page = "main" //main - Main Menu, order - Order Page, item_details - Item Details Page, tracking - Tracking Page
+ var/selected_category = "" // Category that is currently selected
+ var/selected_item = "" // Path of the currently selected item
+ var/datum/cargo_order/co
+ var/last_user_name = "" //Name of the user that used the program
+ var/status_message = null //Status Message to be displayed to the user
+ var/user_tracking_id = 0 //Tracking id of the user
+ var/user_tracking_code = 0 //Tracking Code of the user
+
+/datum/nano_module/program/civilian/cargoorder/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
+ //Check if a cargo order exists. If not create a new one
+ if(!co)
+ var/datum/cargo_order/crord = new
+ co = crord
+
+ var/list/data = host.initial_data()
+
+ //Pass the ID Data
+ var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
+ if(!user_id_card)
+ last_user_name = "Unknown"
+ else
+ last_user_name = user_id_card.registered_name
+
+
+ data["username"] = last_user_name
+
+ //Pass the list of all ordered items and the order value
+ data["order_items"] = co.get_item_list()
+ data["order_value"] = co.get_value(0)
+ data["order_item_count"] = co.get_item_count()
+ data["order_shuttle_fee"] = co.get_max_shipment_cost()
+
+ //Pass Data for Main page
+ if(page == "main")
+ //Pass all available categories and the selected category
+ data["cargo_categories"] = SScargo.get_category_list()
+ data["selected_category"] = selected_category
+
+ //Pass a list of items in the selected category
+ data["category_items"] = SScargo.get_items_for_category(selected_category)
+
+ //Pass Data for Item Details Page
+ else if(page == "item_details")
+ var/datum/cargo_item/ci = SScargo.cargo_items[selected_item]
+ if(ci)
+ data["item_details"] = ci.get_list()
+
+ else if (page == "tracking")
+ data["tracking_id"] = user_tracking_id
+ data["tracking_code"] = user_tracking_code
+ //If no tracking id / code is entered the page the enter them should be displayed
+ if(!user_tracking_id || !user_tracking_code)
+ data["tracking_status"] = "Incomplete Input"
+ //If we have a tracking id / code, then try to find a order with mathing details
+ else if(user_tracking_id && user_tracking_code)
+ //Now, lets try to find a order with a matching id
+ var/datum/cargo_order/co = SScargo.get_order_by_id(user_tracking_id)
+ if(co)
+ if(co.tracking_code == user_tracking_code)
+ data["tracking_status"] = "Success"
+ data["tracked_order"] = co.get_list()
+ data["tracked_order_report"] = co.get_report()
+ else
+ data["tracking_status"] = "Invalid Tracking Code"
+ else
+ data["tracking_status"] = "Invalid Order"
+
+ //Pass the current page
+ data["page"] = page
+
+ //Pass the status message along
+ data["status_message"] = status_message
+
+ data["handling_fee"] = SScargo.get_handlingfee()
+ data["crate_fee"] = SScargo.get_cratefee()
+
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ ui = new(user, src, ui_key, "cargo_order.tmpl", name, 500, 600, state = state)
+ ui.auto_update_layout = 1
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+
+/datum/nano_module/program/civilian/cargoorder/Topic(href, href_list)
+ if(..())
+ return 1
+
+ //Send the order to cargo
+ if(href_list["submit_order"])
+ if(co.items.len == 0)
+ return 1 //Only submit the order if there are items in it
+
+ if(last_user_name == "Unknown")
+ status_message = "Unable to submit order. ID could not be located"
+ return 1
+
+ var/reason = sanitize(input(usr,"Reason:","Why do you require this item?","") as null|text)
+ if(!reason)
+ status_message = "Unable to submit order. No reason supplied."
+ return 1
+
+ co.customer = last_user_name
+ co.reason = reason
+ SScargo.submit_order(co)
+ status_message = "Order submitted successfully. Order ID: [co.order_id] Tracking code: [co.get_tracking_code()]"
+ //TODO: Print a list with the order data
+ co = null
+ return 1
+
+ //Add item to the order list
+ if(href_list["add_item"])
+ var/datum/cargo_order_item/coi = new
+ coi.ci = SScargo.cargo_items[href_list["add_item"]]
+ coi.supplier = href_list["supplier"]
+ //Check if the selected supplier exists for the item and get the price for the supplier
+ var/supplier_details = coi.ci.suppliers[coi.supplier]
+ if(supplier_details)
+ coi.cs = SScargo.get_supplier_by_name(coi.supplier)
+ coi.calculate_price()
+ if(coi.price > 0)
+ status_message = co.add_item(coi)
+ else
+ status_message = "Unable to add item [coi.ci.name] - Internal Error 602."
+ log_debug("Cargo Order: Warning - Attempted to order item [coi.ci.name] from supplier [href_list["supplier"]] with invalid purchase price")
+ qdel(coi)
+ else
+ status_message = "Unable to add item [coi.ci.name] - Internal Error 605."
+ log_debug("Cargo Order: Warning - Attempted to order item [coi.ci.name] from non existant supplier [href_list["supplier"]]")
+ qdel(coi)
+
+ //Reset page to main page - TODO: Maybe add a way to disable jumping back to the main page
+ page = "main"
+ selected_item = ""
+ return 1
+
+ //Remove item from the order list
+ if(href_list["remove_item"])
+ status_message = co.remove_item(text2num(href_list["remove_item"]))
+ return 1
+
+ //Clear the items in the order list
+ if(href_list["clear_order"])
+ status_message = "Order Cleared"
+ qdel(co)
+ co = new
+ return 1
+
+ //Change the selected page
+ if(href_list["item_details"])
+ page = "item_details"
+ selected_item = href_list["item_details"]
+ return 1
+ if(href_list["page"])
+ page = href_list["page"]
+ return 1
+ //Tracking Stuff
+ if(href_list["trackingid"])
+ var/trackingid = text2num(sanitize(input(usr,"Order ID:","ID of the Order that you want to track","") as null|text))
+ if(trackingid)
+ user_tracking_id = trackingid
+ return 1
+ if(href_list["trackingcode"])
+ var/trackingcode = text2num(sanitize(input(usr,"Tracking Code:","Tracking Code of the Order that you want to track","") as null|text))
+ if(trackingcode)
+ user_tracking_code = trackingcode
+ return 1
+ //Change the displayed item category
+ if(href_list["select_category"])
+ selected_category = href_list["select_category"]
+ return 1
+
+ if(href_list["clear_message"])
+ status_message = null
+ return 1
\ No newline at end of file
diff --git a/code/modules/research/designs/circuit_designs.dm b/code/modules/research/designs/circuit_designs.dm
index 54f08b4c752..22a1fdcc9ed 100644
--- a/code/modules/research/designs/circuit_designs.dm
+++ b/code/modules/research/designs/circuit_designs.dm
@@ -335,19 +335,6 @@
build_path = /obj/item/weapon/airlock_electronics/secure
sort_string = "JDAAA"
-/datum/design/circuit/ordercomp
- name = "supply ordering console"
- id = "ordercomp"
- build_path = /obj/item/weapon/circuitboard/ordercomp
- sort_string = "KAAAA"
-
-/datum/design/circuit/supplycomp
- name = "supply control console"
- id = "supplycomp"
- req_tech = list(TECH_DATA = 3)
- build_path = /obj/item/weapon/circuitboard/supplycomp
- sort_string = "KAAAB"
-
/datum/design/circuit/biogenerator
name = "biogenerator"
id = "biogenerator"
diff --git a/code/modules/shuttles/shuttle_supply.dm b/code/modules/shuttles/shuttle_supply.dm
index cfcd6c4e6c2..84efb4b4934 100644
--- a/code/modules/shuttles/shuttle_supply.dm
+++ b/code/modules/shuttles/shuttle_supply.dm
@@ -27,7 +27,8 @@
return
if (!at_station()) //at centcom
- SScargo.buy()
+ if(!SScargo.buy()) //Check if the shuttle can be sent
+ moving_status = SHUTTLE_IDLE //Dont move the shuttle
//We pretend it's a long_jump by making the shuttle stay at centcom for the "in-transit" period.
var/area/away_area = get_location_area(away_location)
diff --git a/config/example/config.txt b/config/example/config.txt
index 32da00df2d9..9399d6b1635 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -497,3 +497,6 @@ LOG_GELF_PORT 12201
# Enables fastboot - some features not essential to testing (like sunlight) will be disabled to speed up server boot. Should not be used on production servers.
FASTBOOT
+
+# Where to load the cargo items from. json or sql
+CARGO_LOAD_ITEMS_FROM json
\ No newline at end of file
diff --git a/html/changelogs/arrow768-PR-3221.yml b/html/changelogs/arrow768-PR-3221.yml
new file mode 100644
index 00000000000..e9db885e23c
--- /dev/null
+++ b/html/changelogs/arrow768-PR-3221.yml
@@ -0,0 +1,37 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+# balance
+#################################
+
+# Your name.
+author: Arrow768
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Cargo is now based on credits instead of points."
\ No newline at end of file
diff --git a/maps/aurora/aurora-1_centcomm.dmm b/maps/aurora/aurora-1_centcomm.dmm
index 6ff3bd67362..720367c46f1 100644
--- a/maps/aurora/aurora-1_centcomm.dmm
+++ b/maps/aurora/aurora-1_centcomm.dmm
@@ -10007,7 +10007,7 @@
},
/area/centcom/control)
"wZ" = (
-/obj/machinery/computer/ordercomp,
+/obj/item/modular_computer/console/preset/supply,
/turf/unsimulated/floor{
icon_state = "floor"
},
diff --git a/maps/aurora/aurora-4_mainlevel.dmm b/maps/aurora/aurora-4_mainlevel.dmm
index 909b855be4a..0b0c02b9529 100644
--- a/maps/aurora/aurora-4_mainlevel.dmm
+++ b/maps/aurora/aurora-4_mainlevel.dmm
@@ -29637,7 +29637,7 @@
/obj/machinery/light_switch{
pixel_x = 32
},
-/obj/machinery/computer/supplycomp,
+/obj/item/modular_computer/console/preset/supply,
/turf/simulated/floor/wood,
/area/crew_quarters/heads/hop)
"bao" = (
@@ -55983,7 +55983,7 @@
/turf/simulated/floor/tiled,
/area/quartermaster/office)
"bTB" = (
-/obj/machinery/computer/ordercomp,
+/obj/item/modular_computer/console/preset/civilian,
/obj/effect/floor_decal/corner/brown{
icon_state = "corner_white";
dir = 9
@@ -56401,7 +56401,7 @@
/turf/simulated/floor/tiled,
/area/quartermaster/office)
"bUq" = (
-/obj/machinery/computer/supplycomp,
+/obj/item/modular_computer/console/preset/supply/,
/turf/simulated/floor/tiled,
/area/quartermaster/office)
"bUr" = (
diff --git a/maps/aurora/aurora-6_surface.dmm b/maps/aurora/aurora-6_surface.dmm
index 3221580a80e..56d662ddb88 100644
--- a/maps/aurora/aurora-6_surface.dmm
+++ b/maps/aurora/aurora-6_surface.dmm
@@ -16995,7 +16995,7 @@
/turf/simulated/floor/tiled,
/area/quartermaster/qm)
"Fs" = (
-/obj/machinery/computer/supplycomp,
+/obj/item/modular_computer/console/preset/supply,
/turf/simulated/floor/tiled,
/area/quartermaster/qm)
"Ft" = (
diff --git a/nano/templates/cargo_control.tmpl b/nano/templates/cargo_control.tmpl
new file mode 100644
index 00000000000..7bd1b9a8c6b
--- /dev/null
+++ b/nano/templates/cargo_control.tmpl
@@ -0,0 +1,311 @@
+
+{{:helper.link('Main', 'cart', {'page' : 'overview_main'}, null)}}
+{{:helper.link('Submitted', 'cart', {'page' : 'overview_submitted'}, null)}}
+{{:helper.link('Approved', 'cart', {'page' : 'overview_approved'}, null)}}
+{{:helper.link('Shipped', 'cart', {'page' : 'overview_shipped'}, null)}}
+{{:helper.link('Shipments', 'cart', {'page' : 'overview_shipments'}, null)}}
+{{:helper.link('Settings', 'cart', {'page' : 'settings'}, null)}}
+
+
+
+{{if data.page == "overview_main"}}
+
+
+
+
+
+ | Welcome: |
+ {{:data.username}} |
+
+
+ | Cargo Account Value |
+ {{:data.cargo_money}} |
+
+
+ Shuttle Operations |
+
+ {{if data.shuttle_has_arrive_time}}
+
+ | ETA: |
+ {{:data.shuttle_eta_minutes}} Minutes |
+
+ {{/if}}
+
+ |
+ {{if data.shuttle_can_launch}}
+ {{:helper.link('Send', 'play', {'shuttle_send' : '1'}, null )}}
+ {{else}}
+ {{:helper.link('Send', 'play', null, "disabled" )}}
+ {{/if}}
+ {{if data.shuttle_can_cancel}}
+ {{:helper.link('Cancel', 'stop', {'shuttle_cancel' : '1'}, null )}}
+ {{else}}
+ {{:helper.link('Cancel', 'stop', null, "disabled" )}}
+ {{/if}}
+ {{if data.shuttle_can_force}}
+ {{:helper.link('Force', 'seek-end', {'shuttle_force' : '1'}, null )}}
+ {{else}}
+ {{:helper.link('Force', 'seek-end', null, "disabled" )}}
+ {{/if}}
+ |
+
+
+
+
+
+{{else data.page == "overview_submitted"}}
+
+
+
+
+
+ Submitted Orders |
+
+
+ | Submitted Order Number: |
+ {{:data.order_submitted_number}} |
+
+
+ | Submitted Order Value: |
+ {{:data.order_submitted_value}} Credits |
+
+
+ | Estimated Shuttle Time: |
+ {{:data.order_submitted_shuttle_time / 10}}s |
+
+
+ | Estimated Shuttle Cost: |
+ {{:data.order_submitted_shuttle_price}} Credits |
+
+
+
+
+
+
+
+ | Order ID |
+ Customer |
+ Price |
+ Actions |
+
+ {{props data.order_list}}
+
+ | {{:value.order_id}} |
+ {{:value.customer}} |
+ {{:value.price}} |
+
+ {{:helper.link('Approve', 'close', {'order_approve' : value.order_id}, null)}}
+ {{:helper.link('Reject', 'close', {'order_reject' : value.order_id}, null)}}
+ {{:helper.link('Details', 'close', {'order_details' : value.order_id, 'page': 'order_details'}, null)}}
+ |
+
+ {{/props}}
+
+{{else data.page == "overview_approved"}}
+
+
+
+
+
+ Approved Orders |
+
+
+ | Approved Order Number: |
+ {{:data.order_approved_number}} |
+
+
+ | Approved Order Value: |
+ {{:data.order_approved_value}} Credits |
+
+
+ | Estimated Shuttle Time: |
+ {{:data.order_approved_shuttle_time / 10}}s |
+
+
+ | Estimated Shuttle Cost: |
+ {{:data.order_approved_shuttle_price}} Credits |
+
+
+
+
+
+
+
+ | Order ID |
+ Customer |
+ Price |
+ Actions |
+
+ {{props data.order_list}}
+
+ | {{:value.order_id}} |
+ {{:value.customer}} |
+ {{:value.price}} |
+
+ {{:helper.link('Details', 'close', {'order_details' : value.order_id, 'page': 'order_details'}, null)}}
+ |
+
+ {{/props}}
+
+
+{{else data.page == "overview_shipped"}}
+
+
+
+
+
+ Shipped Orders |
+
+
+ | Shipped Order Number: |
+ {{:data.order_shipped_number}} |
+
+
+ | Shipped Order Value: |
+ {{:data.order_shipped_value}} Credits |
+
+
+
+
+
+
+
+ | Order ID |
+ Customer |
+ Price |
+ Actions |
+
+ {{props data.order_list}}
+
+ | {{:value.order_id}} |
+ {{:value.customer}} |
+ {{:value.price}} |
+
+ {{:helper.link('Details', 'close', {'order_details' : value.order_id, 'page': 'order_details'}, null)}}
+ |
+
+ {{/props}}
+
+
+{{else data.page == "overview_shipments"}}
+ Shipment Overview
+
+
+ | Shipment # |
+ Expense |
+ Income |
+
+ {{props data.shipment_list}}
+
+ | {{:value.shipment_num}} |
+ {{:value.shipment_cost_purchase}} |
+ {{:value.shipment_cost_sell}} |
+
+ {{/props}}
+
+
+{{else data.page == "settings"}}
+
+
+
+
+
+ Settings |
+
+
+ | Cargo Handling Fee: |
+ {{:helper.link(data.handling_fee, 'pencil', {'handling_fee' : '1'}, null)}} |
+
+
+
+
+
+{{else data.page == "order_details"}}
+
+
+
+
+
+ Order No: {{:data.order_details.order_id}} |
+
+
+ | Tracking Code: |
+ {{:data.order_details.tracking_code}} |
+
+
+ | Price (Customer): |
+ {{:data.order_details.price_customer}} |
+
+
+ | Price (Cargo): |
+ {{:data.order_details.price_cargo}} |
+
+
+ | Item Value: |
+ {{:data.order_details.price}} |
+
+ {{if data.order_details.shipment_cost != 0}}
+
+ | Shipment Cost: (aliquot) |
+ {{:data.order_details.shipment_cost}} |
+
+ {{else}}
+
+ | Shipment Cost: (max) |
+ {{:data.order_details.shipment_cost_max}} |
+
+ {{/if}}
+
+ | Status: |
+ {{:data.order_details.status_pretty}} |
+
+
+ | Customer: |
+ {{:data.order_details.customer}} |
+
+ {{if data.order_details.authorized_by}}
+
+ | Authorized By: |
+ {{:data.order_details.authorized_by}} |
+
+ {{/if}}
+ {{if data.order_details.time_submitted}}
+
+ | Submitted at: |
+ {{:data.order_details.time_submitted}} |
+
+ {{/if}}
+ {{if data.order_details.time_approved}}
+
+ | Approved at: |
+ {{:data.order_details.time_approved}} |
+
+ {{/if}}
+ {{if data.order_details.time_shipped}}
+
+ | Shipped at: |
+ {{:data.order_details.time_shipped}} |
+
+ {{/if}}
+
+
+
+
+
+
+
+ | Item Name |
+ Supplier |
+ Price |
+
+ {{props data.order_details.items}}
+
+ | {{:value.name}} |
+ {{:value.supplier_name}} |
+ {{:value.price}} |
+
+ {{/props}}
+
+{{else}}
+ else
+{{/if}}
\ No newline at end of file
diff --git a/nano/templates/cargo_order.tmpl b/nano/templates/cargo_order.tmpl
new file mode 100644
index 00000000000..209a55e7101
--- /dev/null
+++ b/nano/templates/cargo_order.tmpl
@@ -0,0 +1,175 @@
+
+{{:helper.link('Order', 'gear', {'page' : 'main'}, null)}}
+{{:helper.link('Tracking', 'gear', {'page' : 'tracking'}, null)}}
+
+
+{{if data.page == "main" || data.page == "item_details"}}
+
+
+
+
+
+ | Welcome: |
+ {{:data.username}} |
+
+ {{if data.status_message}}
+
+ | Status: |
+ {{:data.status_message}} |
+
+ {{/if}}
+
+ Order |
+
+
+ | Items: |
+ {{:data.order_item_count}} |
+
+
+ | Price: |
+ {{:data.order_value}} Credits |
+
+
+ | Shuttle Fee: |
+ {{:data.order_shuttle_fee}} |
+
+
+ | {{:helper.link('Details', 'cart', {'page' : 'order'}, null)}} |
+ {{:helper.link('Clear', 'cancel', {'clear_order' : 'clear_order'}, null)}} {{:helper.link("Submit Order", 'play', {'submit_order' : 'submit_order'}, null)}} |
+
+
+
+
+
+{{/if}}
+{{if data.page == "main"}}
+
+
+ {{props data.cargo_categories}}
+ {{:helper.link(value.display_name, value.icon, {'select_category' : value.name}, (data.selected_category == value.name) ? 'selected' : null)}}
+ {{/props}}
+
+
+
+
+
+ {{for data.category_items}}
+
+ | {{:value.name}} |
+
+
+ | {{:value.description}} |
+
+
+ | {{:helper.link('Item Details', 'gear', {'item_details' : value.path}, null)}} |
+
+
|
+ {{/for}}
+
+
+{{else data.page == "item_details"}}
+
+
+
+ | {{:helper.link('Return', 'gear', {'page' : 'main'}, null)}} |
+
+
+ | Name: |
+ {{:data.item_details.name}} |
+
+
+ | Description: |
+ {{:data.item_details.description}} |
+
+
+ | Items per Order: |
+ {{:data.item_details.amount}} |
+
+
+
+
Suppliers:
+
+ {{props data.item_details.suppliers}}
+ {{if value.available && value.adjusted_price > 0}}
+ {{:helper.link(value.name + " " + value.adjusted_price, 'gear', {'add_item' : data.item_details.path, 'supplier': key}, null)}}
+ {{else}}
+ {{:helper.link(value.name + " /Unavailable/", 'gear', null, "disabled")}}
+ {{/if}}
+ {{/for}}
+
+{{else data.page == "order"}}
+
+
+
+ | Name |
+ Supplier |
+ Price |
+ |
+
+ {{props data.order_items}}
+
+ | {{:value.name}} |
+ {{:value.supplier_name}} |
+ {{:value.price}} |
+ {{:helper.link('Delete', 'close', {'remove_item' : value.item_id}, null)}} |
+
+ {{/props}}
+
+ | Crate Fee |
+ NT Supply Department |
+ {{:data.crate_fee}} |
+ |
+
+
+ | Handling Fee |
+ Cargo |
+ {{:data.handling_fee}} |
+ |
+
+
+ | Additional Shuttle Fees may apply |
+
+
+ {{:helper.link("Submit Order", 'play', {'submit_order' : 'submit_order'}, null)}} |
+
+ {{:helper.link('Return', 'gear', {'page' : 'main'}, null)}} |
+{{else data.page == "tracking"}}
+
+
Tracking Data
+
+
+
+ Order ID:
+
+
+ {{:helper.link(data.tracking_id, 'pencil', {'trackingid' : '1'})}}
+
+
+
+
+ Tracking Code:
+
+
+ {{:helper.link(data.tracking_code, 'pencil', {'trackingcode' : '1'})}}
+
+
+
+
Order Data
+
+ {{if data.tracking_status == "Success"}}
+
+
+
+ {{:data.tracked_order_report}}
+
+
+
+ {{else}}
+
+ Tracking Status:
+
+
+ {{:data.tracking_status}}
+
+ {{/if}}
+{{/if}}
\ No newline at end of file
diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl
index 2befc5b0779..3a5ffeb258e 100644
--- a/nano/templates/pda.tmpl
+++ b/nano/templates/pda.tmpl
@@ -806,18 +806,18 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm
{{if data.records.supply.approved_count == 0}}
No current approved orders
{{else}}
- {{for data.records.supply.approved}}
- #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}}
+ {{props data.records.supply.approved}}
+ #{{:value.order_id}} - {{:value.customer}} - {{:value.price_cargo}} Credits
+ {{/props}}
{{/if}}
Current Requested Orders
{{if data.records.supply.requests_count == 0}}
No current requested orders
{{else}}
- {{for data.records.supply.requests}}
- #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}}
+ {{props data.records.supply.requests}}
+ #{{:value.order_id}} - {{:value.customer}} - {{:value.price_cargo}} Credits
+ {{/props}}
{{/if}}