From 4c6f1b622baf63f9e8cc7d70cdb48b38256274b6 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Fri, 17 Apr 2020 07:48:11 +0200
Subject: [PATCH 01/34] Porting Goofconomy & co.
---
code/__DEFINES/economy.dm | 35 ++
code/__DEFINES/maps.dm | 2 +
code/__DEFINES/preferences.dm | 3 +-
code/__DEFINES/subsystems.dm | 1 +
code/__HELPERS/game.dm | 13 +
code/__HELPERS/level_traits.dm | 2 +
code/__HELPERS/unsorted.dm | 23 +-
code/_globalvars/lists/flavor_misc.dm | 2 +
.../configuration/entries/game_options.dm | 2 +
code/controllers/subsystem/economy.dm | 139 +++++++
code/controllers/subsystem/job.dm | 4 +
code/controllers/subsystem/mapping.dm | 5 +-
code/controllers/subsystem/shuttle.dm | 6 -
code/game/atoms.dm | 3 +
code/game/machinery/Sleeper.dm | 13 +-
code/game/machinery/_machinery.dm | 34 ++
code/game/machinery/autolathe.dm | 2 +
code/game/machinery/bank_machine.dm | 38 +-
code/game/machinery/cloning.dm | 31 +-
code/game/machinery/computer/card.dm | 3 +-
code/game/machinery/computer/cloning.dm | 14 +-
.../game/machinery/computer/communications.dm | 11 +-
.../machinery/doors/airlock_electronics.dm | 1 +
code/game/machinery/doors/firedoor.dm | 1 +
code/game/machinery/doppler_array.dm | 6 +-
code/game/machinery/firealarm.dm | 1 +
code/game/objects/items/RCD.dm | 1 +
code/game/objects/items/RSF.dm | 27 +-
code/game/objects/items/cards_ids.dm | 220 ++++++++++-
code/game/objects/items/cigs_lighters.dm | 3 +-
.../circuitboards/machine_circuitboards.dm | 15 +-
code/game/objects/items/crab17.dm | 229 ++++++++++++
code/game/objects/items/credit_holochip.dm | 107 ++++++
code/game/objects/items/devices/flashlight.dm | 2 +
code/game/objects/items/devices/scanners.dm | 2 +
.../objects/items/devices/sensor_device.dm | 1 +
code/game/objects/items/kitchen.dm | 3 +
code/game/objects/items/pinpointer.dm | 1 +
code/game/objects/items/stacks/cash.dm | 2 +-
code/game/objects/items/stacks/medical.dm | 1 +
code/game/objects/items/storage/belt.dm | 2 +
code/game/objects/items/storage/boxes.dm | 1 +
code/game/objects/items/storage/fancy.dm | 2 +
code/game/objects/items/storage/wallets.dm | 17 +-
code/game/objects/items/tanks/watertank.dm | 1 +
code/game/objects/items/weaponry.dm | 2 +
.../crates_lockers/crates/secure.dm | 41 ++-
.../objects/structures/ghost_role_spawners.dm | 2 +-
code/modules/admin/secrets.dm | 12 +
.../antagonists/blob/blob/blob_report.dm | 11 +
.../antagonists/traitor/syndicate_contract.dm | 24 +-
.../atmospherics/machinery/airalarm.dm | 1 +
.../components/unary_devices/cryo.dm | 9 +-
code/modules/awaymissions/zlevel.dm | 7 +-
code/modules/cargo/bounties/science.dm | 2 +-
code/modules/cargo/bounty.dm | 24 +-
code/modules/cargo/bounty_console.dm | 4 +-
code/modules/cargo/console.dm | 27 +-
code/modules/cargo/exports.dm | 1 +
code/modules/cargo/expressconsole.dm | 35 +-
code/modules/cargo/order.dm | 11 +-
code/modules/cargo/packs.dm | 12 +-
code/modules/client/preferences.dm | 5 +
code/modules/client/preferences_toggles.dm | 10 +
code/modules/clothing/ears/_ears.dm | 2 +
code/modules/clothing/gloves/color.dm | 2 +
code/modules/clothing/gloves/miscellaneous.dm | 1 +
code/modules/clothing/head/beanie.dm | 1 +
code/modules/clothing/head/helmet.dm | 1 +
code/modules/clothing/head/misc.dm | 1 +
code/modules/clothing/neck/_neck.dm | 36 ++
code/modules/clothing/outfits/vr.dm | 15 +-
code/modules/clothing/shoes/colour.dm | 1 +
code/modules/clothing/shoes/miscellaneous.dm | 2 +
code/modules/clothing/suits/armor.dm | 1 +
code/modules/clothing/under/miscellaneous.dm | 1 +
code/modules/clothing/under/pants.dm | 2 +
code/modules/clothing/under/skirt_dress.dm | 4 +
code/modules/economy/_economy.dm | 2 +
code/modules/economy/account.dm | 118 ++++++
code/modules/economy/paystand.dm | 138 +++++++
code/modules/events/pirates.dm | 42 ++-
code/modules/events/shuttle_loan.dm | 4 +-
code/modules/food_and_drinks/drinks/drinks.dm | 10 +-
.../food_and_drinks/drinks/drinks/bottle.dm | 13 +-
.../drinks/drinks/drinkingglass.dm | 2 +
.../food_and_drinks/food/snacks_vend.dm | 3 +
code/modules/jobs/job_types/_job.dm | 19 +-
code/modules/jobs/job_types/assistant.dm | 2 +
.../jobs/job_types/atmospheric_technician.dm | 2 +
code/modules/jobs/job_types/bartender.dm | 2 +
code/modules/jobs/job_types/botanist.dm | 2 +
code/modules/jobs/job_types/captain.dm | 4 +
.../jobs/job_types/cargo_technician.dm | 2 +
code/modules/jobs/job_types/chaplain.dm | 2 +
code/modules/jobs/job_types/chemist.dm | 2 +
code/modules/jobs/job_types/chief_engineer.dm | 2 +
.../jobs/job_types/chief_medical_officer.dm | 2 +
code/modules/jobs/job_types/clown.dm | 2 +
code/modules/jobs/job_types/cook.dm | 2 +
code/modules/jobs/job_types/curator.dm | 2 +
code/modules/jobs/job_types/detective.dm | 2 +
code/modules/jobs/job_types/geneticist.dm | 2 +
.../jobs/job_types/head_of_personnel.dm | 2 +
.../jobs/job_types/head_of_security.dm | 2 +
code/modules/jobs/job_types/janitor.dm | 2 +
code/modules/jobs/job_types/lawyer.dm | 2 +
code/modules/jobs/job_types/medical_doctor.dm | 2 +
code/modules/jobs/job_types/mime.dm | 2 +
code/modules/jobs/job_types/paramedic.dm | 2 +
code/modules/jobs/job_types/quartermaster.dm | 2 +
.../jobs/job_types/research_director.dm | 2 +
code/modules/jobs/job_types/roboticist.dm | 2 +
code/modules/jobs/job_types/scientist.dm | 2 +
.../jobs/job_types/security_officer.dm | 2 +
code/modules/jobs/job_types/shaft_miner.dm | 2 +
.../jobs/job_types/station_engineer.dm | 2 +
code/modules/jobs/job_types/virologist.dm | 2 +
code/modules/jobs/job_types/warden.dm | 3 +
code/modules/mapping/map_template.dm | 8 +-
code/modules/mining/money_bag.dm | 2 +-
.../mob/living/carbon/human/human_defines.dm | 3 +-
.../mob/living/carbon/human/human_helpers.dm | 11 +
.../mob/living/silicon/robot/robot_modules.dm | 2 +-
.../modular_computers/hardware/hard_drive.dm | 1 +
.../modular_computers/laptop_vendor.dm | 10 +-
code/modules/photography/camera/camera.dm | 1 +
code/modules/power/apc.dm | 3 +-
code/modules/power/cable.dm | 5 +-
code/modules/power/singularity/collector.dm | 6 +-
code/modules/power/tesla/coil.dm | 6 +
.../reagents/reagent_containers/dropper.dm | 1 +
.../reagents/reagent_containers/glass.dm | 1 +
.../reagents/reagent_containers/hypospray.dm | 2 +
.../reagents/reagent_containers/syringes.dm | 1 +
.../autolathe_designs_tcomms_and_misc.dm | 16 +
.../machine_designs_all_misc.dm | 8 +
code/modules/research/techweb/_techweb.dm | 8 +
code/modules/research/techweb/all_nodes.dm | 2 +-
.../ruins/spaceruin_code/listeningstation.dm | 2 +-
code/modules/shuttle/supply.dm | 37 +-
.../modules/spells/spell_types/devil_boons.dm | 16 +-
.../uplink/uplink_items/uplink_badass.dm | 1 +
.../uplink/uplink_items/uplink_bundles.dm | 1 +
.../uplink/uplink_items/uplink_devices.dm | 10 +
code/modules/vending/_vending.dm | 344 ++++++++++++++----
code/modules/vending/assist.dm | 3 +
code/modules/vending/autodrobe.dm | 7 +
code/modules/vending/boozeomat.dm | 5 +-
code/modules/vending/cartridge.dm | 3 +
code/modules/vending/cigarette.dm | 3 +
code/modules/vending/clothesmate.dm | 6 +
code/modules/vending/coffee.dm | 3 +
code/modules/vending/cola.dm | 3 +
code/modules/vending/drinnerware.dm | 3 +
code/modules/vending/engineering.dm | 3 +
code/modules/vending/engivend.dm | 3 +
code/modules/vending/games.dm | 3 +
code/modules/vending/kinkmate.dm | 3 +
code/modules/vending/liberation.dm | 3 +
code/modules/vending/liberation_toy.dm | 3 +
code/modules/vending/magivend.dm | 3 +
code/modules/vending/medical.dm | 3 +
code/modules/vending/medical_wall.dm | 3 +
code/modules/vending/megaseed.dm | 3 +
code/modules/vending/nutrimax.dm | 3 +
code/modules/vending/plasmaresearch.dm | 3 +
code/modules/vending/robotics.dm | 2 +
code/modules/vending/security.dm | 3 +
code/modules/vending/snack.dm | 72 +---
code/modules/vending/sovietsoda.dm | 3 +
code/modules/vending/sovietvend.dm | 3 +
code/modules/vending/sustenance.dm | 3 +
code/modules/vending/toys.dm | 3 +
code/modules/vending/wardrobes.dm | 26 ++
code/modules/vending/youtool.dm | 3 +
config/game_options.txt | 3 +
config/vr_config.txt | 13 +
icons/obj/crates.dmi | Bin 22621 -> 23582 bytes
icons/obj/device.dmi | Bin 53345 -> 53137 bytes
icons/obj/economy.dmi | Bin 13420 -> 16128 bytes
icons/obj/items_and_weapons.dmi | Bin 134455 -> 135077 bytes
icons/obj/money_machine.dmi | Bin 0 -> 4676 bytes
icons/obj/money_machine_64.dmi | Bin 0 -> 2307 bytes
icons/obj/vending_restock.dmi | Bin 2380 -> 2460 bytes
sound/items/dump_it.ogg | Bin 0 -> 190123 bytes
tgstation.dme | 7 +
tgui-next/packages/tgui/interfaces/Cargo.js | 19 +-
tgui-next/packages/tgui/interfaces/Vending.js | 64 +++-
tgui-next/packages/tgui/public/tgui.bundle.js | 4 +-
190 files changed, 2213 insertions(+), 353 deletions(-)
create mode 100644 code/__DEFINES/economy.dm
create mode 100644 code/controllers/subsystem/economy.dm
create mode 100644 code/game/objects/items/crab17.dm
create mode 100644 code/game/objects/items/credit_holochip.dm
create mode 100644 code/modules/economy/_economy.dm
create mode 100644 code/modules/economy/account.dm
create mode 100644 code/modules/economy/paystand.dm
create mode 100644 config/vr_config.txt
create mode 100644 icons/obj/money_machine.dmi
create mode 100644 icons/obj/money_machine_64.dmi
create mode 100644 sound/items/dump_it.ogg
diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm
new file mode 100644
index 0000000000..bc9534f527
--- /dev/null
+++ b/code/__DEFINES/economy.dm
@@ -0,0 +1,35 @@
+#define STARTING_PAYCHECKS 5
+
+#define PAYCHECK_ASSISTANT 25
+#define PAYCHECK_MINIMAL 75
+#define PAYCHECK_EASY 125
+#define PAYCHECK_MEDIUM 175
+#define PAYCHECK_HARD 200
+#define PAYCHECK_COMMAND 250
+
+#define MAX_GRANT_CIV 2500
+#define MAX_GRANT_ENG 3000
+#define MAX_GRANT_SCI 5000
+#define MAX_GRANT_SECMEDSRV 3000
+
+#define ACCOUNT_CIV "CIV"
+#define ACCOUNT_CIV_NAME "Civil Budget"
+#define ACCOUNT_ENG "ENG"
+#define ACCOUNT_ENG_NAME "Engineering Budget"
+#define ACCOUNT_SCI "SCI"
+#define ACCOUNT_SCI_NAME "Scientific Budget"
+#define ACCOUNT_MED "MED"
+#define ACCOUNT_MED_NAME "Medical Budget"
+#define ACCOUNT_SRV "SRV"
+#define ACCOUNT_SRV_NAME "Service Budget"
+#define ACCOUNT_CAR "CAR"
+#define ACCOUNT_CAR_NAME "Cargo Budget"
+#define ACCOUNT_SEC "SEC"
+#define ACCOUNT_SEC_NAME "Defense Budget"
+
+#define NO_FREEBIES "commies go home"
+
+//ID bank account support defines.
+#define ID_NO_BANK_ACCOUNT 0
+#define ID_FREE_BANK_ACCOUNT 1
+#define ID_LOCKED_BANK_ACCOUNT 2
diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm
index 73e900226e..8b529859ac 100644
--- a/code/__DEFINES/maps.dm
+++ b/code/__DEFINES/maps.dm
@@ -38,6 +38,7 @@ require only minor tweaks.
#define ZTRAIT_SPACE_RUINS "Space Ruins"
#define ZTRAIT_LAVA_RUINS "Lava Ruins"
#define ZTRAIT_ISOLATED_RUINS "Isolated Ruins" //Placing ruins on z levels with this trait will use turf reservation instead of usual placement.
+#define ZTRAIT_VIRTUAL_REALITY "Virtual Reality"
// number - bombcap is multiplied by this before being applied to bombs
#define ZTRAIT_BOMBCAP_MULTIPLIER "Bombcap Multiplier"
@@ -71,6 +72,7 @@ require only minor tweaks.
ZTRAIT_BOMBCAP_MULTIPLIER = 5, \
ZTRAIT_BASETURF = /turf/open/lava/smooth/lava_land_surface)
#define ZTRAITS_REEBE list(ZTRAIT_REEBE = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 0.5)
+#define ZTRAITS_VR list(ZTRAIT_VIRTUAL_REALITY = TRUE, ZTRAIT_AWAY = TRUE)
#define DL_NAME "name"
#define DL_TRAITS "traits"
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index 06926317ee..84eed5483a 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -30,8 +30,9 @@
#define CHAT_GHOSTPDA (1<<8)
#define CHAT_GHOSTRADIO (1<<9)
#define CHAT_LOOC (1<<10)
+#define CHAT_BANKCARD (1<<11)
-#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_LOOC)
+#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_LOOC|CHAT_BANKCARD)
#define PARALLAX_INSANE -1 //for show offs
#define PARALLAX_HIGH 0 //default.
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 5aa0301bf6..104e69706c 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -65,6 +65,7 @@
#define INIT_ORDER_INSTRUMENTS 53
#define INIT_ORDER_MAPPING 50
#define INIT_ORDER_NETWORKS 45
+#define INIT_ORDER_ECONOMY 40
#define INIT_ORDER_ATOMS 30
#define INIT_ORDER_LANGUAGE 25
#define INIT_ORDER_MACHINES 20
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 170d93c31f..679f89f4d2 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -506,6 +506,19 @@
return
winset(C, "mainwindow", "flash=5")
+//Recursively checks if an item is inside a given type, even through layers of storage. Returns the atom if it finds it.
+/proc/recursive_loc_check(atom/movable/target, type)
+ var/atom/A = target
+ if(istype(A, type))
+ return A
+
+ while(!istype(A.loc, type))
+ if(!A.loc)
+ return
+ A = A.loc
+
+ return A.loc
+
/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank)
if(!SSticker.IsRoundInProgress() || QDELETED(character))
return
diff --git a/code/__HELPERS/level_traits.dm b/code/__HELPERS/level_traits.dm
index 3e6e88c8fa..c903314da0 100644
--- a/code/__HELPERS/level_traits.dm
+++ b/code/__HELPERS/level_traits.dm
@@ -12,3 +12,5 @@
#define is_reserved_level(z) SSmapping.level_trait(z, ZTRAIT_RESERVED)
#define is_away_level(z) SSmapping.level_trait(z, ZTRAIT_AWAY)
+
+#define is_vr_level(z) SSmapping.level_trait(z, ZTRAIT_VIRTUAL_REALITY)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index afa858afb7..5b91afca4c 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1025,6 +1025,27 @@ B --><-- A
/proc/get_random_station_turf()
return safepick(get_area_turfs(pick(GLOB.the_station_areas)))
+/proc/get_safe_random_station_turf() //excludes dense turfs (like walls) and areas that have valid_territory set to FALSE
+ for (var/i in 1 to 5)
+ var/list/L = get_area_turfs(pick(GLOB.the_station_areas))
+ var/turf/target
+ while (L.len && !target)
+ var/I = rand(1, L.len)
+ var/turf/T = L[I]
+ var/area/X = get_area(T)
+ if(!T.density && X.valid_territory)
+ var/clear = TRUE
+ for(var/obj/O in T)
+ if(O.density)
+ clear = FALSE
+ break
+ if(clear)
+ target = T
+ if (!target)
+ L.Cut(I,I+1)
+ if (target)
+ return target
+
/proc/get_closest_atom(type, list, source)
var/closest_atom
var/closest_distance
@@ -1568,7 +1589,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/proc/blood_sucking_checks(var/mob/living/carbon/target, check_neck, check_blood)
//Bypass this if the target isnt carbon.
if(!iscarbon(target))
- return TRUE
+ return TRUE
if(check_neck)
if(istype(target.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
return FALSE
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index 968995e81d..8430e690cc 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -221,3 +221,5 @@ GLOBAL_LIST_INIT(numbers_as_words, world.file2list("strings/numbers_as_words.txt
GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_as_words + generate_number_strings())
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "null","Error: No comment given.", "It's a good day to die!"))
+
+GLOBAL_LIST_INIT(redacted_strings, list("\[REDACTED\]", "\[CLASSIFIED\]", "\[ARCHIVED\]", "\[EXPLETIVE DELETED\]", "\[EXPUNGED\]", "\[INFORMATION ABOVE YOUR SECURITY CLEARANCE\]", "\[MOVE ALONG CITIZEN\]", "\[NOTHING TO SEE HERE\]", "\[ACCESS DENIED\]"))
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index f11093cba7..63e3f489bd 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -74,6 +74,8 @@
/datum/config_entry/flag/disable_peaceborg
+/datum/config_entry/flag/economy //money money money money money money money money money money money money
+
/datum/config_entry/number/minimum_secborg_alert //Minimum alert level for secborgs to be chosen.
config_entry_value = 3
diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm
new file mode 100644
index 0000000000..078d122aa6
--- /dev/null
+++ b/code/controllers/subsystem/economy.dm
@@ -0,0 +1,139 @@
+SUBSYSTEM_DEF(economy)
+ name = "Economy"
+ wait = 5 MINUTES
+ init_order = INIT_ORDER_ECONOMY
+ runlevels = RUNLEVEL_GAME
+ var/roundstart_paychecks = 5
+ var/budget_pool = 35000
+ var/list/department_accounts = list(ACCOUNT_CIV = ACCOUNT_CIV_NAME,
+ ACCOUNT_ENG = ACCOUNT_ENG_NAME,
+ ACCOUNT_SCI = ACCOUNT_SCI_NAME,
+ ACCOUNT_MED = ACCOUNT_MED_NAME,
+ ACCOUNT_SRV = ACCOUNT_SRV_NAME,
+ ACCOUNT_CAR = ACCOUNT_CAR_NAME,
+ ACCOUNT_SEC = ACCOUNT_SEC_NAME)
+ var/list/generated_accounts = list()
+ var/full_ancap = FALSE // Enables extra money charges for things that normally would be free, such as sleepers/cryo/cloning.
+ //Take care when enabling, as players will NOT respond well if the economy is set up for low cash flows.
+ var/alive_humans_bounty = 100
+ var/crew_safety_bounty = 1500
+ var/monster_bounty = 150
+ var/mood_bounty = 100
+ var/techweb_bounty = 250
+ var/slime_bounty = list("grey" = 10,
+ // tier 1
+ "orange" = 100,
+ "metal" = 100,
+ "blue" = 100,
+ "purple" = 100,
+ // tier 2
+ "dark purple" = 500,
+ "dark blue" = 500,
+ "green" = 500,
+ "silver" = 500,
+ "gold" = 500,
+ "yellow" = 500,
+ "red" = 500,
+ "pink" = 500,
+ // tier 3
+ "cerulean" = 750,
+ "sepia" = 750,
+ "bluespace" = 750,
+ "pyrite" = 750,
+ "light pink" = 750,
+ "oil" = 750,
+ "adamantine" = 750,
+ // tier 4
+ "rainbow" = 1000)
+ var/list/bank_accounts = list() //List of normal accounts (not department accounts)
+ var/list/dep_cards = list()
+
+/datum/controller/subsystem/economy/Initialize(timeofday)
+ var/budget_to_hand_out = round(budget_pool / department_accounts.len)
+ for(var/A in department_accounts)
+ new /datum/bank_account/department(A, budget_to_hand_out)
+ return ..()
+
+/datum/controller/subsystem/economy/fire(resumed = 0)
+ eng_payout() // Payout based on nothing. What will replace it? Surplus power, powered APC's, air alarms? Who knows.
+ sci_payout() // Payout based on slimes.
+ secmedsrv_payout() // Payout based on crew safety, health, and mood.
+ civ_payout() // Payout based on ??? Profit
+ car_payout() // Cargo's natural gain in the cash moneys.
+ for(var/A in bank_accounts)
+ var/datum/bank_account/B = A
+ B.payday(1)
+
+
+/datum/controller/subsystem/economy/proc/get_dep_account(dep_id)
+ for(var/datum/bank_account/department/D in generated_accounts)
+ if(D.department_id == dep_id)
+ return D
+
+/datum/controller/subsystem/economy/proc/eng_payout()
+ var/engineering_cash = 3000
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_ENG)
+ if(D)
+ D.adjust_money(engineering_cash)
+
+
+/datum/controller/subsystem/economy/proc/car_payout()
+ var/cargo_cash = 500
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_CAR)
+ if(D)
+ D.adjust_money(cargo_cash)
+
+/datum/controller/subsystem/economy/proc/secmedsrv_payout()
+ var/crew
+ var/alive_crew
+ var/dead_monsters
+ var/cash_to_grant
+ for(var/mob/m in GLOB.mob_list)
+ if(isnewplayer(m))
+ continue
+ if(m.mind)
+ if(isbrain(m) || iscameramob(m))
+ continue
+ if(ishuman(m))
+ var/mob/living/carbon/human/H = m
+ crew++
+ if(H.stat != DEAD)
+ alive_crew++
+ var/datum/component/mood/mood = H.GetComponent(/datum/component/mood)
+ var/medical_cash = (H.health / H.maxHealth) * alive_humans_bounty
+ if(mood)
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_SRV)
+ if(D)
+ var/mood_dosh = (mood.mood_level / 9) * mood_bounty
+ D.adjust_money(mood_dosh)
+ medical_cash *= (mood.sanity / 100)
+
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_MED)
+ if(D)
+ D.adjust_money(medical_cash)
+ if(ishostile(m))
+ var/mob/living/simple_animal/hostile/H = m
+ if(H.stat == DEAD && (H.z in SSmapping.levels_by_trait(ZTRAIT_STATION)))
+ dead_monsters++
+ CHECK_TICK
+ var/living_ratio = alive_crew / crew
+ cash_to_grant = (crew_safety_bounty * living_ratio) + (monster_bounty * dead_monsters)
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_SEC)
+ if(D)
+ D.adjust_money(min(cash_to_grant, MAX_GRANT_SECMEDSRV))
+
+/datum/controller/subsystem/economy/proc/sci_payout()
+ var/science_bounty = 0
+ for(var/mob/living/simple_animal/slime/S in GLOB.mob_list)
+ if(S.stat == DEAD)
+ continue
+ science_bounty += slime_bounty[S.colour]
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_SCI)
+ if(D)
+ D.adjust_money(min(science_bounty, MAX_GRANT_SCI))
+
+/datum/controller/subsystem/economy/proc/civ_payout()
+ var/civ_cash = (rand(1,5) * 500)
+ var/datum/bank_account/D = get_dep_account(ACCOUNT_CIV)
+ if(D)
+ D.adjust_money(min(civ_cash, MAX_GRANT_CIV))
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 91d0db85d1..7fc3f576de 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -477,6 +477,10 @@ SUBSYSTEM_DEF(job)
to_chat(M, "[job.custom_spawn_text]")
if(CONFIG_GET(number/minimal_access_threshold))
to_chat(M, "As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.")
+ if(ishuman(H))
+ var/mob/living/carbon/human/wageslave = H
+ to_chat(M, "Your account ID is [wageslave.account_id].")
+ H.add_memory("Your account ID is [wageslave.account_id].")
if(job && H)
if(job.dresscodecompliant)// CIT CHANGE - dress code compliance
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index f13d5a2779..5a1f17e8fb 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -438,9 +438,12 @@ GLOBAL_LIST_EMPTY(the_station_areas)
else
if(answer in GLOB.potentialRandomZlevels)
away_name = answer
+ var/list/traits = list(ZTRAIT_AWAY = TRUE)
+ if(answer in GLOB.potentialRandomVRlevels)
+ traits[ZTRAIT_VIRTUAL_REALITY] = TRUE
to_chat(usr,"Loading [away_name]...")
var/datum/map_template/template = new(away_name, "Away Mission")
- away_level = template.load_new_z()
+ away_level = template.load_new_z(traits)
else
return
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index e4a3ff1f9a..b9ec1d647f 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -35,10 +35,8 @@ SUBSYSTEM_DEF(shuttle)
//supply shuttle stuff
var/obj/docking_port/mobile/supply/supply
var/ordernum = 1 //order number given to next order
- var/points = 5000 //number of trade-points we have
var/centcom_message = "" //Remarks from CentCom on how well you checked the last order.
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentCom, associated with their potencies
- var/passive_supply_points_per_minute = 125
var/list/supply_packs = list()
var/list/shoppinglist = list()
@@ -113,9 +111,6 @@ SUBSYSTEM_DEF(shuttle)
qdel(T, force=TRUE)
CheckAutoEvac()
- if(!(times_fired % CEILING(600/wait, 1)))
- points += passive_supply_points_per_minute
-
var/esETA = emergency?.getModeStr()
emergency_shuttle_stat_text = "[esETA? "[esETA] [emergency.getTimerStr()]" : ""]"
@@ -559,7 +554,6 @@ SUBSYSTEM_DEF(shuttle)
centcom_message = SSshuttle.centcom_message
ordernum = SSshuttle.ordernum
- points = SSshuttle.points
emergencyNoEscape = SSshuttle.emergencyNoEscape
emergencyCallAmount = SSshuttle.emergencyCallAmount
shuttle_purchased = SSshuttle.shuttle_purchased
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 44a891e24a..48518f69c8 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -32,6 +32,9 @@
var/list/filter_data //For handling persistent filters
+ var/custom_price
+ var/custom_premium_price
+
var/datum/component/orbiter/orbiters
var/rad_flags = NONE // Will move to flags_1 when i can be arsed to
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 42904383bb..3f2edd7174 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -26,6 +26,8 @@
var/list/chem_buttons //Used when emagged to scramble which chem is used, eg: antitoxin -> morphine
var/scrambled_chems = FALSE //Are chem buttons scrambled? used as a warning
var/enter_message = "You feel cool air surround you. You go numb as your senses turn inward."
+ payment_department = ACCOUNT_MED
+ fair_market_price = 5
/obj/machinery/sleeper/Initialize()
. = ..()
@@ -205,6 +207,13 @@
ui = new(user, src, ui_key, "sleeper", name, 550, 700, master_ui, state)
ui.open()
+/obj/machinery/sleeper/process()
+ ..()
+ check_nap_violations()
+
+/obj/machinery/sleeper/nap_violation(mob/violator)
+ open_machine()
+
/obj/machinery/sleeper/ui_data()
var/list/data = list()
var/chemical_list = list()
@@ -250,7 +259,7 @@
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN)
-
+
if(mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
chemical_list += list(list("name" = R.name, "volume" = R.volume))
@@ -290,7 +299,7 @@
if(..())
return
var/mob/living/mob_occupant = occupant
-
+ check_nap_violations()
switch(action)
if("door")
if(state_open)
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 995d11acb7..93121a0753 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -121,6 +121,10 @@ Class Procs:
var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE
+ var/fair_market_price = 69
+ var/market_verb = "Customer"
+ var/payment_department = ACCOUNT_ENG
+
/obj/machinery/Initialize()
if(!armor)
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 70)
@@ -248,6 +252,36 @@ Class Procs:
return FALSE
return TRUE
+/obj/machinery/proc/check_nap_violations()
+ if(!SSeconomy.full_ancap)
+ return TRUE
+ if(occupant && !state_open)
+ if(ishuman(occupant))
+ var/mob/living/carbon/human/H = occupant
+ var/obj/item/card/id/I = H.get_idcard()
+ if(I)
+ var/datum/bank_account/insurance = I.registered_account
+ if(!insurance)
+ say("[market_verb] NAP Violation: No bank account found.")
+ nap_violation()
+ return FALSE
+ else
+ if(!insurance.adjust_money(-fair_market_price))
+ say("[market_verb] NAP Violation: Unable to pay.")
+ nap_violation()
+ return FALSE
+ var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
+ if(D)
+ D.adjust_money(fair_market_price)
+ else
+ say("[market_verb] NAP Violation: No ID card found.")
+ nap_violation()
+ return FALSE
+ return TRUE
+
+/obj/machinery/proc/nap_violation(mob/violator)
+ return
+
////////////////////////////////////////////////////////////////////////////////////////////
//Return a non FALSE value to interrupt attack_hand propagation to subtypes.
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 6fa7fa30c0..e12e4c6cf5 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -32,6 +32,8 @@
var/list/datum/design/matching_designs
var/selected_category
var/screen = 1
+ var/base_price = 25
+ var/hacked_price = 50
var/list/categories = list(
"Tools",
diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm
index 41867a8520..2b683f16a3 100644
--- a/code/game/machinery/bank_machine.dm
+++ b/code/game/machinery/bank_machine.dm
@@ -8,6 +8,7 @@
var/obj/item/radio/radio
var/radio_channel = RADIO_CHANNEL_COMMON
var/minimum_time_between_warnings = 400
+ var/syphoning_credits = 0
/obj/machinery/computer/bank_machine/Initialize()
. = ..()
@@ -25,9 +26,14 @@
if(istype(I, /obj/item/stack/spacecash))
var/obj/item/stack/spacecash/C = I
value = C.value * C.amount
+ else if(istype(I, /obj/item/holochip))
+ var/obj/item/holochip/H = I
+ value = H.credits
if(value)
- SSshuttle.points += value
- to_chat(user, "You deposit [I]. The station now has [SSshuttle.points] credits.")
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ D.adjust_money(value)
+ to_chat(user, "You deposit [I]. The Cargo Budget is now [D.account_balance] cr.")
qdel(I)
return
return ..()
@@ -38,14 +44,16 @@
if(siphoning)
if (stat & (BROKEN|NOPOWER))
say("Insufficient power. Halting siphon.")
- siphoning = FALSE
- if(SSshuttle.points < 200)
- say("Station funds depleted. Halting siphon.")
- siphoning = FALSE
- else
- new /obj/item/stack/spacecash/c200(drop_location()) // will autostack
- playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1)
- SSshuttle.points -= 200
+ end_syphon()
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(!D.has_money(200))
+ say("Cargo budget depleted. Halting siphon.")
+ end_syphon()
+ return
+
+ playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1)
+ syphoning_credits += 200
+ D.adjust_money(-200)
if(next_warning < world.time && prob(15))
var/area/A = get_area(loc)
var/message = "Unauthorized credit withdrawal underway in [A.map_name]!!"
@@ -61,7 +69,8 @@
/obj/machinery/computer/bank_machine/ui_data(mob/user)
var/list/data = list()
- data["current_balance"] = SSshuttle.points
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ data["current_balance"] = D.account_balance
data["siphoning"] = siphoning
data["station_name"] = station_name()
@@ -78,5 +87,10 @@
. = TRUE
if("halt")
say("Station credit withdrawal halted.")
- siphoning = FALSE
+ end_syphon()
. = TRUE
+
+/obj/machinery/computer/bank_machine/proc/end_syphon()
+ siphoning = FALSE
+ new /obj/item/holochip(drop_location(), syphoning_credits) //get the loot
+ syphoning_credits = 0
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index bc0fec68ba..ecea8c74c3 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -37,6 +37,9 @@
var/list/unattached_flesh
var/flesh_number = 0
+ var/datum/bank_account/current_insurance
+ fair_market_price = 5 // He nodded, because he knew I was right. Then he swiped his credit card to pay me for arresting him.
+ payment_department = ACCOUNT_MED
/obj/machinery/clonepod/Initialize()
. = ..()
@@ -131,7 +134,7 @@
return examine(user)
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, datum/species/mrace, list/features, factions, list/quirks)
+/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance)
if(panel_open)
return FALSE
if(mess || attempting)
@@ -161,7 +164,7 @@
mess = TRUE
update_icon()
return FALSE
-
+ current_insurance = insurance
attempting = TRUE //One at a time!!
countdown.start()
@@ -224,15 +227,29 @@
connected_message("Clone Ejected: Loss of power.")
else if(mob_occupant && (mob_occupant.loc == src))
- if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
- connected_message("Clone Rejected: Deceased.")
+ if(SSeconomy.full_ancap)
+ if(!current_insurance)
+ go_out()
+ connected_message("Clone Ejected: No bank account.")
+ if(internal_radio)
+ SPEAK("The cloning of [mob_occupant.real_name] has been terminated due to no bank account to draw payment from.")
+ else if(!current_insurance.adjust_money(-fair_market_price))
+ go_out()
+ connected_message("Clone Ejected: Out of Money.")
+ if(internal_radio)
+ SPEAK("The cloning of [mob_occupant.real_name] has been ended prematurely due to being unable to pay.")
+ else
+ var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
+ if(D)
+ D.adjust_money(fair_market_price)
+ if(mob_occupant && (mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes. connected_message("Clone Rejected: Deceased.")
if(internal_radio)
SPEAK("The cloning has been \
aborted due to unrecoverable tissue failure.")
go_out()
mob_occupant.copy_from_prefs_vr()
- else if(mob_occupant.cloneloss > (100 - heal_level))
+ else if(mob_occupant && mob_occupant.cloneloss > (100 - heal_level))
mob_occupant.Unconscious(80)
var/dmg_mult = CONFIG_GET(number/damage_multiplier)
//Slowly get that clone healed and finished.
@@ -259,7 +276,7 @@
use_power(7500) //This might need tweaking.
- else if((mob_occupant.cloneloss <= (100 - heal_level)))
+ else if((mob_occupant && mob_occupant.cloneloss <= (100 - heal_level)))
connected_message("Cloning Process Complete.")
if(internal_radio)
SPEAK("The cloning cycle is complete.")
@@ -368,7 +385,7 @@
if(!mob_occupant)
return
-
+ current_insurance = null
REMOVE_TRAIT(mob_occupant, TRAIT_STABLEHEART, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_MUTATION_STASIS, CLONING_POD_TRAIT)
REMOVE_TRAIT(mob_occupant, TRAIT_STABLELIVER, CLONING_POD_TRAIT)
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index b0e80b63d2..74cceacd12 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -467,7 +467,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
to_chat(usr, "No log exists for this job.")
updateUsrDialog()
return
-
+ if(inserted_modify_id.registered_account)
+ inserted_modify_id.registered_account.account_job = jobdatum // this is a terrible idea and people will grief but sure whatever
inserted_modify_id.access = ( istype(src, /obj/machinery/computer/card/centcom) ? get_centcom_access(t1) : jobdatum.get_access() )
if (inserted_modify_id)
inserted_modify_id.assignment = t1
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 07cc252b87..981a5643a8 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -73,7 +73,7 @@
if(pod.occupant)
continue //how though?
- if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"]))
+ if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"]))
temp = "[R.fields["name"]] => Cloning cycle in progress..."
records -= R
@@ -415,7 +415,7 @@
else if(pod.occupant)
temp = "Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
- else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"]))
+ else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"]))
temp = "[C.fields["name"]] => Cloning cycle in progress..."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
@@ -441,9 +441,13 @@
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
+ var/datum/bank_account/has_bank_account
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
+ var/obj/item/card/id/I = C.get_idcard()
+ if(I)
+ has_bank_account = I.registered_account
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
@@ -468,7 +472,10 @@
scantemp = "Subject already in database."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
-
+ if(SSeconomy.full_ancap && !has_bank_account)
+ scantemp = "Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan."
+ playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
+ return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
@@ -490,6 +497,7 @@
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
R.fields["quirks"] = list()
+ R.fields["bank_account"] = has_bank_account
for(var/V in mob_occupant.roundstart_quirks)
var/datum/quirk/T = V
R.fields["quirks"][T.type] = T.clone_data()
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 4c3d85a162..4cef487baf 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -163,11 +163,15 @@
else if(!S.prerequisites_met())
to_chat(usr, "You have not met the requirements for purchasing this shuttle.")
else
- if(SSshuttle.points >= S.credit_cost)
+ var/points_to_check
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ points_to_check = D.account_balance
+ if(points_to_check >= S.credit_cost)
var/obj/machinery/shuttle_manipulator/M = locate() in GLOB.machines
if(M)
SSshuttle.shuttle_purchased = TRUE
- SSshuttle.points -= S.credit_cost
+ D.adjust_money(-S.credit_cost)
minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase")
message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].")
SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]")
@@ -576,7 +580,8 @@
dat += "
Lift access restrictions on maintenance and external airlocks?
\[ OK | Cancel \]"
if(STATE_PURCHASE)
- dat += "Budget: [SSshuttle.points] Credits.
"
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ dat += "Budget: [D.account_balance] Credits.
"
dat += "
"
dat += "Caution: Purchasing dangerous shuttles may lead to mutiny and/or death.
"
dat += "
"
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm
index 7b90715f2b..fed54f55f8 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock_electronics.dm
@@ -1,6 +1,7 @@
/obj/item/electronics/airlock
name = "airlock electronics"
req_access = list(ACCESS_MAINT_TUNNELS)
+ custom_price = 50
var/list/accesses = list()
var/one_access = 0
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 1b83bb4b96..4533d18ae4 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -260,6 +260,7 @@
/obj/item/electronics/firelock
name = "firelock circuitry"
+ custom_price = 50
desc = "A circuit board used in construction of firelocks."
icon_state = "mainboard"
diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm
index db806ef3ac..a9c411c634 100644
--- a/code/game/machinery/doppler_array.dm
+++ b/code/game/machinery/doppler_array.dm
@@ -174,9 +174,11 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
else
linked_techweb.largest_bomb_value = TECHWEB_BOMB_POINTCAP
point_gain = 1000
-
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SCI)
+ if(D)
+ D.adjust_money(point_gain)
linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, point_gain)
- say("Gained [point_gain] points from explosion dataset.")
+ say("Explosion details and mixture analyzed and sold to the highest bidder for [point_gain] cr, with a reward of [point_gain] points.")
else //you've made smaller bombs
say("Data already captured. Aborting.")
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index f4f308c490..16ad36d0e1 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -2,6 +2,7 @@
/obj/item/electronics/firealarm
name = "fire alarm electronics"
+ custom_price = 50
desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
/obj/item/wallframe/firealarm
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index d248556a9c..565030b13a 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -154,6 +154,7 @@ RLD
icon_state = "rcd"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
+ custom_price = 1700
max_matter = 160
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
has_ammobar = TRUE
diff --git a/code/game/objects/items/RSF.dm b/code/game/objects/items/RSF.dm
index ba0766de00..35843c1030 100644
--- a/code/game/objects/items/RSF.dm
+++ b/code/game/objects/items/RSF.dm
@@ -41,24 +41,21 @@ RSF
/obj/item/rsf/attack_self(mob/user)
playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
switch(mode)
+ if(5)
+ mode = 1
+ to_chat(user, "Changed dispensing mode to 'Drinking Glass'")
if(1)
mode = 2
- to_chat(user, "Changed dispensing mode to 'Drinking Glass'")
+ to_chat(user, "Changed dispensing mode to 'Paper'")
if(2)
mode = 3
- to_chat(user, "Changed dispensing mode to 'Paper'")
+ to_chat(user, "Changed dispensing mode to 'Pen'")
if(3)
mode = 4
- to_chat(user, "Changed dispensing mode to 'Pen'")
+ to_chat(user, "Changed dispensing mode to 'Dice Pack'")
if(4)
mode = 5
- to_chat(user, "Changed dispensing mode to 'Dice Pack'")
- if(5)
- mode = 6
to_chat(user, "Changed dispensing mode to 'Cigarette'")
- if(6)
- mode = 1
- to_chat(user, "Changed dispensing mode to 'Dosh'")
// Change mode
/obj/item/rsf/afterattack(atom/A, mob/user, proximity)
@@ -81,26 +78,22 @@ RSF
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
switch(mode)
if(1)
- to_chat(user, "Dispensing Dosh...")
- new /obj/item/stack/spacecash/c10(T)
- use_matter(200, user)
- if(2)
to_chat(user, "Dispensing Drinking Glass...")
new /obj/item/reagent_containers/food/drinks/drinkingglass(T)
use_matter(20, user)
- if(3)
+ if(2)
to_chat(user, "Dispensing Paper Sheet...")
new /obj/item/paper(T)
use_matter(10, user)
- if(4)
+ if(3)
to_chat(user, "Dispensing Pen...")
new /obj/item/pen(T)
use_matter(50, user)
- if(5)
+ if(4)
to_chat(user, "Dispensing Dice Pack...")
new /obj/item/storage/pill_bottle/dice(T)
use_matter(200, user)
- if(6)
+ if(5)
to_chat(user, "Dispensing Cigarette...")
new /obj/item/clothing/mask/cigarette(T)
use_matter(10, user)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 20e0b09d26..bcc4697d0b 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -6,8 +6,6 @@
* FINGERPRINT CARD
*/
-
-
/*
* DATA CARDS - Used for the IC data card reader
*/
@@ -173,13 +171,19 @@
var/registered_name = null // The name registered_name on the card
var/assignment = null
var/access_txt // mapping aid
-
-
+ var/bank_support = ID_FREE_BANK_ACCOUNT
+ var/datum/bank_account/registered_account
+ var/obj/machinery/paystand/my_store
/obj/item/card/id/Initialize(mapload)
. = ..()
if(mapload && access_txt)
access = text2access(access_txt)
+ var/turf/T = get_turf(src)
+ if(bank_support == ID_FREE_BANK_ACCOUNT && is_vr_level(T.z)) //economy is quite exploitable on VR in so many ways.
+ bank_support = ID_NO_BANK_ACCOUNT
+ else if(bank_support == ID_LOCKED_BANK_ACCOUNT)
+ registered_account = new /datum/bank_account/remote/non_transferable(pick(GLOB.redacted_strings))
/obj/item/card/id/vv_edit_var(var_name, var_value)
. = ..()
@@ -193,12 +197,150 @@
user.visible_message("[user] shows you: [icon2html(src, viewers(user))] [src.name].", \
"You show \the [src.name].")
add_fingerprint(user)
+
+/obj/item/card/id/attackby(obj/item/W, mob/user, params)
+ if(!bank_support)
+ return ..()
+ if(istype(W, /obj/item/holochip))
+ insert_money(W, user)
+ else if(istype(W, /obj/item/stack/spacecash) || istype(W, /obj/item/coin))
+ insert_money(W, user, TRUE)
+ else if(istype(W, /obj/item/storage/bag/money))
+ var/obj/item/storage/bag/money/money_bag = W
+ var/list/money_contained = money_bag.contents
+ var/money_added = mass_insert_money(money_contained, user)
+ if (money_added)
+ to_chat(user, "You stuff the contents into the card! They disappear in a puff of bluespace smoke, adding [money_added] worth of credits to the linked account.")
+ else
+ return ..()
+
+/obj/item/card/id/proc/insert_money(obj/item/I, mob/user, physical_currency)
+ var/cash_money = I.get_item_credit_value()
+ if(!cash_money)
+ to_chat(user, "[I] doesn't seem to be worth anything!")
return
+ if(!registered_account)
+ to_chat(user, "[src] doesn't have a linked account to deposit [I] into!")
+ return
+
+ registered_account.adjust_money(cash_money)
+ if(physical_currency)
+ to_chat(user, "You stuff [I] into [src]. It disappears in a small puff of bluespace smoke, adding [cash_money] credits to the linked account.")
+ else
+ to_chat(user, "You insert [I] into [src], adding [cash_money] credits to the linked account.")
+
+ to_chat(user, "The linked account now reports a balance of [registered_account.account_balance] cr.")
+ qdel(I)
+
+/obj/item/card/id/proc/mass_insert_money(list/money, mob/user)
+ if (!money || !money.len)
+ return FALSE
+
+ var/total = 0
+
+ for (var/obj/item/physical_money in money)
+ var/cash_money = physical_money.get_item_credit_value()
+
+ total += cash_money
+
+ registered_account.adjust_money(cash_money)
+
+ QDEL_LIST(money)
+
+ return total
+
+/obj/item/card/id/proc/alt_click_can_use_id(mob/living/user)
+ if(!isliving(user))
+ return
+ if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ return
+
+ return TRUE
+
+// Returns true if new account was set.
+/obj/item/card/id/proc/set_new_account(mob/living/user)
+ if(bank_support != ID_FREE_BANK_ACCOUNT)
+ to_chat(user, "This ID has no modular banking support whatsover, must be an older model...")
+ return
+ . = FALSE
+ var/datum/bank_account/old_account = registered_account
+
+ var/new_bank_id = input(user, "Enter your account ID number.", "Account Reclamation", 111111) as num | null
+
+ if (isnull(new_bank_id))
+ return
+
+ if(!alt_click_can_use_id(user))
+ return
+ if(!new_bank_id || new_bank_id < 111111 || new_bank_id > 999999)
+ to_chat(user, "The account ID number needs to be between 111111 and 999999.")
+ return
+ if (registered_account && registered_account.account_id == new_bank_id)
+ to_chat(user, "The account ID was already assigned to this card.")
+ return
+
+ for(var/A in SSeconomy.bank_accounts)
+ var/datum/bank_account/B = A
+ if(B.account_id == new_bank_id)
+ if (old_account)
+ old_account.bank_cards -= src
+
+ B.bank_cards += src
+ registered_account = B
+ to_chat(user, "The provided account has been linked to this ID card.")
+
+ return TRUE
+
+ to_chat(user, "The account ID number provided is invalid.")
+ return
+
+/obj/item/card/id/AltClick(mob/living/user)
+ . = ..()
+ if(!bank_support || !alt_click_can_use_id(user))
+ return
+
+ if(!registered_account)
+ set_new_account(user)
+ return
+
+ if (world.time < registered_account.withdrawDelay)
+ registered_account.bank_card_talk("ERROR: UNABLE TO LOGIN DUE TO SCHEDULED MAINTENANCE. MAINTENANCE IS SCHEDULED TO COMPLETE IN [(registered_account.withdrawDelay - world.time)/10] SECONDS.", TRUE)
+ return
+
+ var/amount_to_remove = FLOOR(input(user, "How much do you want to withdraw? Current Balance: [registered_account.account_balance]", "Withdraw Funds", 5) as num|null, 1)
+
+ if(!amount_to_remove || amount_to_remove < 0)
+ return
+ if(!alt_click_can_use_id(user))
+ return
+ if(registered_account.adjust_money(-amount_to_remove))
+ var/obj/item/holochip/holochip = new (user.drop_location(), amount_to_remove)
+ user.put_in_hands(holochip)
+ to_chat(user, "You withdraw [amount_to_remove] credits into a holochip.")
+ return
+ else
+ var/difference = amount_to_remove - registered_account.account_balance
+ registered_account.bank_card_talk("ERROR: The linked account requires [difference] more credit\s to perform that withdrawal.", TRUE)
+
/obj/item/card/id/examine(mob/user)
. = ..()
if(mining_points)
. += "There's [mining_points] mining equipment redemption point\s loaded onto this card."
+ if(!bank_support || (bank_support == ID_LOCKED_BANK_ACCOUNT && !registered_account))
+ . += "This ID has no banking support whatsover, must be an older model..."
+ else if(registered_account)
+ . += "The account linked to the ID belongs to '[registered_account.account_holder]' and reports a balance of [registered_account.account_balance] cr."
+ if(registered_account.account_job)
+ var/datum/bank_account/D = SSeconomy.get_dep_account(registered_account.account_job.paycheck_department)
+ if(D)
+ . += "The [D.account_holder] reports a balance of [D.account_balance] cr."
+ . += "Alt-Click the ID to pull money from the linked account in the form of holochips."
+ . += "You can insert credits into the linked account by pressing holochips, cash, or coins against the ID."
+ if(registered_account.account_holder == user.real_name)
+ . += "If you lose this ID card, you can reclaim your account by Alt-Clicking a blank ID card while holding it and entering your account ID number."
+ else
+ . += "There is no registered account linked to this card. Alt-Click to add one."
/obj/item/card/id/GetAccess()
return access
@@ -278,7 +420,11 @@ update_label("John Doe", "Clowny")
else
return ..()
- var/popup_input = alert(user, "Choose Action", "Agent ID", "Show", "Forge/Reset")
+ var/popup_input
+ if(bank_support == ID_FREE_BANK_ACCOUNT)
+ popup_input = alert(user, "Choose Action", "Agent ID", "Show", "Forge/Reset", "Change Account ID")
+ else
+ popup_input = alert(user, "Choose Action", "Agent ID", "Show", "Forge/Reset")
if(user.incapacitated())
return
if(popup_input == "Forge/Reset" && !forged)
@@ -302,6 +448,18 @@ update_label("John Doe", "Clowny")
forged = TRUE
to_chat(user, "You successfully forge the ID card.")
log_game("[key_name(user)] has forged \the [initial(name)] with name \"[registered_name]\" and occupation \"[assignment]\".")
+
+ // First time use automatically sets the account id to the user.
+ if (first_use && !registered_account)
+ if(ishuman(user))
+ var/mob/living/carbon/human/accountowner = user
+
+ for(var/bank_account in SSeconomy.bank_accounts)
+ var/datum/bank_account/account = bank_account
+ if(account.account_id == accountowner.account_id)
+ account.bank_cards += src
+ registered_account = account
+ to_chat(user, "Your account number has been automatically assigned.")
return
else if (popup_input == "Forge/Reset" && forged)
registered_name = initial(registered_name)
@@ -311,6 +469,9 @@ update_label("John Doe", "Clowny")
forged = FALSE
to_chat(user, "You successfully reset the ID card.")
return
+ else if (popup_input == "Change Account ID")
+ set_new_account(user)
+ return
return ..()
/obj/item/card/id/syndicate/anyone
@@ -327,6 +488,15 @@ update_label("John Doe", "Clowny")
assignment = "Syndicate Overlord"
access = list(ACCESS_SYNDICATE)
+/obj/item/card/id/no_banking
+ bank_support = ID_NO_BANK_ACCOUNT
+
+/obj/item/card/id/locked_banking
+ bank_support = ID_LOCKED_BANK_ACCOUNT
+
+/obj/item/card/id/syndicate/locked_banking
+ bank_support = ID_LOCKED_BANK_ACCOUNT
+
/obj/item/card/id/captains_spare
name = "captain's spare ID"
desc = "The spare ID of the High Lord himself."
@@ -396,6 +566,17 @@ update_label("John Doe", "Clowny")
access = get_all_accesses()+get_ert_access("sec")-ACCESS_CHANGE_IDS
. = ..()
+/obj/item/card/id/debug
+ name = "\improper Debug ID"
+ desc = "A debug ID card. Has ALL the all access, you really shouldn't have this."
+ icon_state = "centcom"
+ assignment = "Jannie"
+
+/obj/item/card/id/debug/Initialize()
+ access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
+ registered_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ . = ..()
+
/obj/item/card/id/prisoner
name = "prisoner ID card"
desc = "You are a number, you are not a free man."
@@ -514,6 +695,34 @@ update_label("John Doe", "Clowny")
desc = "A special ID card that allows access to APC terminals."
access = list(ACCESS_ENGINE_EQUIP)
+/obj/item/card/id/departmental_budget
+ name = "departmental card (FUCK)"
+ desc = "Provides access to the departmental budget."
+ var/department_ID = ACCOUNT_CIV
+ var/department_name = ACCOUNT_CIV_NAME
+
+/obj/item/card/id/departmental_budget/Initialize()
+ . = ..()
+ var/datum/bank_account/B = SSeconomy.get_dep_account(department_ID)
+ if(B)
+ registered_account = B
+ if(!B.bank_cards.Find(src))
+ B.bank_cards += src
+ name = "departmental card ([department_name])"
+ desc = "Provides access to the [department_name]."
+ SSeconomy.dep_cards += src
+
+/obj/item/card/id/departmental_budget/Destroy()
+ SSeconomy.dep_cards -= src
+ return ..()
+
+/obj/item/card/id/departmental_budget/update_label()
+ return
+
+/obj/item/card/id/departmental_budget/car
+ department_ID = ACCOUNT_CAR
+ department_name = ACCOUNT_CAR_NAME
+
//Polychromatic Knight Badge
/obj/item/card/id/knight
@@ -577,4 +786,3 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/debug/Initialize()
access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
. = ..()
-
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 2303278f5c..6ebeffe90f 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -506,6 +506,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/oil = 5)
+ custom_price = 55
/obj/item/lighter/Initialize()
. = ..()
@@ -710,7 +711,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
item_state = "black_vape"
w_class = WEIGHT_CLASS_TINY
var/chem_volume = 100
- var/vapetime = FALSE //this so it won't puff out clouds every tick
+ var/vapetime = FALSE //this so it won't puff out clouds every tick
var/screw = FALSE // kinky
var/super = FALSE //for the fattest vapes dude.
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index b13cfd9f64..890a17e52c 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -229,10 +229,11 @@
def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)
/obj/item/circuitboard/machine/vendor
- name = "Booze-O-Mat Vendor (Machine Board)"
+ name = "Custom Vendor (Machine Board)"
desc = "You can turn the \"brand selection\" dial using a screwdriver."
- build_path = /obj/machinery/vending/boozeomat
- req_components = list(/obj/item/vending_refill/boozeomat = 1)
+ custom_premium_price = 100
+ build_path = /obj/machinery/vending/custom
+ req_components = list(/obj/item/vending_refill/custom = 1)
var/static/list/vending_names_paths = list(
/obj/machinery/vending/boozeomat = "Booze-O-Mat",
@@ -269,7 +270,8 @@
/obj/machinery/vending/wardrobe/viro_wardrobe = "ViroDrobe",
/obj/machinery/vending/clothing = "ClothesMate",
/obj/machinery/vending/medical = "NanoMed Plus",
- /obj/machinery/vending/wallmed = "NanoMed")
+ /obj/machinery/vending/wallmed = "NanoMed",
+ /obj/machinery/vending/custom = "Custom Vendor")
/obj/item/circuitboard/machine/vendor/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/screwdriver))
@@ -1019,6 +1021,11 @@
build_path = /obj/machinery/ore_silo
req_components = list()
+/obj/item/circuitboard/machine/paystand
+ name = "Pay Stand (Machine Board)"
+ build_path = /obj/machinery/paystand
+ req_components = list()
+
/obj/item/circuitboard/machine/autobottler
name = "Auto-Bottler (Machine Board)"
build_path = /obj/machinery/rnd/production/protolathe/department/autobottler //Manips make you print things cheaper, even chems
diff --git a/code/game/objects/items/crab17.dm b/code/game/objects/items/crab17.dm
new file mode 100644
index 0000000000..8d55d3d5a2
--- /dev/null
+++ b/code/game/objects/items/crab17.dm
@@ -0,0 +1,229 @@
+/obj/item/suspiciousphone
+ name = "suspicious phone"
+ desc = "This device raises pink levels to unknown highs."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "suspiciousphone"
+ w_class = WEIGHT_CLASS_SMALL
+ attack_verb = list("dumped")
+ var/dumped = FALSE
+
+/obj/item/suspiciousphone/attack_self(mob/user)
+ if(!ishuman(user))
+ to_chat(user, "This device is too advanced for you!")
+ return
+ if(dumped)
+ to_chat(user, "You already activated Protocol CRAB-17.")
+ return FALSE
+ if(alert(user, "Are you sure you want to crash this market with no survivors?", "Protocol CRAB-17", "Yes", "No") == "Yes")
+ if(dumped || QDELETED(src)) //Prevents fuckers from cheesing alert
+ return FALSE
+ var/turf/targetturf = get_safe_random_station_turf()
+ if (!targetturf)
+ return FALSE
+ new /obj/effect/dumpeetTarget(targetturf, user)
+ dumped = TRUE
+
+/obj/structure/checkoutmachine
+ name = "\improper Nanotrasen Space-Coin Market"
+ desc = "This is good for spacecoin because"
+ icon = 'icons/obj/money_machine.dmi'
+ icon_state = "bogdanoff"
+ layer = LARGE_MOB_LAYER
+ armor = list("melee" = 80, "bullet" = 30, "laser" = 30, "energy" = 60, "bomb" = 90, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80)
+ density = TRUE
+ pixel_z = -8
+ max_integrity = 5000
+ var/list/accounts_to_rob
+ var/mob/living/carbon/human/bogdanoff
+ var/canwalk = FALSE
+
+/obj/structure/checkoutmachine/examine(mob/living/user)
+ . = ..()
+ . += "It's integrated integrity meter reads: HEALTH: [obj_integrity]."
+
+/obj/structure/checkoutmachine/proc/check_if_finished()
+ for(var/i in accounts_to_rob)
+ var/datum/bank_account/B = i
+ if (B.being_dumped)
+ return FALSE
+ return TRUE
+
+/obj/structure/checkoutmachine/attackby(obj/item/W, mob/user, params)
+ if(check_if_finished())
+ qdel(src)
+ return
+ if(istype(W, /obj/item/card/id))
+ var/obj/item/card/id/card = W
+ if(!card.registered_account)
+ to_chat(user, "This card does not have a registered account!")
+ return
+ if(!card.registered_account.being_dumped)
+ to_chat(user, "It appears that your funds are safe from draining!")
+ return
+ if(do_after(user, 40, target = src))
+ if(!card.registered_account.being_dumped)
+ return
+ to_chat(user, "You quickly cash out your funds to a more secure banking location. Funds are safu.") // This is a reference and not a typo
+ card.registered_account.being_dumped = FALSE
+ card.registered_account.withdrawDelay = 0
+ if(check_if_finished())
+ qdel(src)
+ return
+ else
+ return ..()
+
+/obj/structure/checkoutmachine/Initialize(mapload, mob/living/user)
+ . = ..()
+ bogdanoff = user
+ add_overlay("flaps")
+ add_overlay("hatch")
+ add_overlay("legs_retracted")
+ addtimer(CALLBACK(src, .proc/startUp), 50)
+ QDEL_IN(src, 8 MINUTES) //Self destruct after 8 min
+
+
+/obj/structure/checkoutmachine/proc/startUp() //very VERY snowflake code that adds a neat animation when the pod lands.
+ start_dumping() //The machine doesnt move during this time, giving people close by a small window to grab their funds before it starts running around
+ sleep(10)
+ if(QDELETED(src))
+ return
+ playsound(src, 'sound/machines/click.ogg', 15, TRUE, -3)
+ cut_overlay("flaps")
+ sleep(10)
+ if(QDELETED(src))
+ return
+ playsound(src, 'sound/machines/click.ogg', 15, TRUE, -3)
+ cut_overlay("hatch")
+ sleep(30)
+ if(QDELETED(src))
+ return
+ playsound(src,'sound/machines/twobeep.ogg',50,FALSE)
+ var/mutable_appearance/hologram = mutable_appearance(icon, "hologram")
+ hologram.pixel_y = 16
+ add_overlay(hologram)
+ var/mutable_appearance/holosign = mutable_appearance(icon, "holosign")
+ holosign.pixel_y = 16
+ add_overlay(holosign)
+ add_overlay("legs_extending")
+ cut_overlay("legs_retracted")
+ pixel_z += 4
+ sleep(5)
+ if(QDELETED(src))
+ return
+ add_overlay("legs_extended")
+ cut_overlay("legs_extending")
+ pixel_z += 4
+ sleep(20)
+ if(QDELETED(src))
+ return
+ add_overlay("screen_lines")
+ sleep(5)
+ if(QDELETED(src))
+ return
+ cut_overlay("screen_lines")
+ sleep(5)
+ if(QDELETED(src))
+ return
+ add_overlay("screen_lines")
+ add_overlay("screen")
+ sleep(5)
+ if(QDELETED(src))
+ return
+ playsound(src,'sound/machines/triple_beep.ogg',50,FALSE)
+ add_overlay("text")
+ sleep(10)
+ if(QDELETED(src))
+ return
+ add_overlay("legs")
+ cut_overlay("legs_extended")
+ cut_overlay("screen")
+ add_overlay("screen")
+ cut_overlay("screen_lines")
+ add_overlay("screen_lines")
+ cut_overlay("text")
+ add_overlay("text")
+ canwalk = TRUE
+ START_PROCESSING(SSfastprocess, src)
+
+/obj/structure/checkoutmachine/Destroy()
+ stop_dumping()
+ STOP_PROCESSING(SSfastprocess, src)
+ priority_announce("The credit deposit machine at [get_area(src)] has been destroyed. Station funds have stopped draining!", sender_override = "CRAB-17 Protocol")
+ explosion(src, 0,0,1, flame_range = 2)
+ return ..()
+
+/obj/structure/checkoutmachine/proc/start_dumping()
+ accounts_to_rob = SSeconomy.bank_accounts.Copy()
+ accounts_to_rob -= bogdanoff.get_bank_account()
+ for(var/i in accounts_to_rob)
+ var/datum/bank_account/B = i
+ B.dumpeet()
+ dump()
+
+/obj/structure/checkoutmachine/proc/dump()
+ var/percentage_lost = (rand(5, 15) / 100)
+ for(var/i in accounts_to_rob)
+ var/datum/bank_account/B = i
+ if(!B.being_dumped)
+ continue
+ var/amount = B.account_balance * percentage_lost
+ var/datum/bank_account/account = bogdanoff.get_bank_account()
+ if (account) // get_bank_account() may return FALSE
+ account.transfer_money(B, amount)
+ B.bank_card_talk("You have lost [percentage_lost * 100]% of your funds! A spacecoin credit deposit machine is located at: [get_area(src)].")
+ addtimer(CALLBACK(src, .proc/dump), 150) //Drain every 15 seconds
+
+/obj/structure/checkoutmachine/process()
+ var/anydir = pick(GLOB.cardinals)
+ if(Process_Spacemove(anydir))
+ Move(get_step(src, anydir), anydir)
+
+/obj/structure/checkoutmachine/proc/stop_dumping()
+ for(var/i in accounts_to_rob)
+ var/datum/bank_account/B = i
+ B.being_dumped = FALSE
+
+/obj/effect/dumpeetFall //Falling pod
+ name = ""
+ icon = 'icons/obj/money_machine_64.dmi'
+ pixel_z = 300
+ desc = "Get out of the way!"
+ layer = FLY_LAYER//that wasnt flying, that was falling with style!
+ icon_state = "missile_blur"
+
+/obj/effect/dumpeetTarget
+ name = "Landing Zone Indicator"
+ desc = "A holographic projection designating the landing zone of something. It's probably best to stand back."
+ icon = 'icons/mob/actions/actions_items.dmi'
+ icon_state = "sniper_zoom"
+ layer = PROJECTILE_HIT_THRESHHOLD_LAYER
+ light_range = 2
+ var/obj/effect/dumpeetFall/DF
+ var/obj/structure/checkoutmachine/dump
+ var/mob/living/carbon/human/bogdanoff
+
+/obj/effect/ex_act()
+ return
+
+/obj/effect/dumpeetTarget/Initialize(mapload, user)
+ . = ..()
+ bogdanoff = user
+ addtimer(CALLBACK(src, .proc/startLaunch), 100)
+ sound_to_playing_players('sound/items/dump_it.ogg', 20)
+ deadchat_broadcast("Protocol CRAB-17 has been activated. A space-coin market has been launched at the station!", turf_target = get_turf(src))
+
+/obj/effect/dumpeetTarget/proc/startLaunch()
+ DF = new /obj/effect/dumpeetFall(drop_location())
+ dump = new /obj/structure/checkoutmachine(null, bogdanoff)
+ priority_announce("The spacecoin bubble has popped! Get to the credit deposit machine at [get_area(src)] and cash out before you lose all of your funds!", sender_override = "CRAB-17 Protocol")
+ animate(DF, pixel_z = -8, time = 5, , easing = LINEAR_EASING)
+ playsound(src, 'sound/weapons/mortar_whistle.ogg', 70, TRUE, 6)
+ addtimer(CALLBACK(src, .proc/endLaunch), 5, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
+
+
+
+/obj/effect/dumpeetTarget/proc/endLaunch()
+ QDEL_NULL(DF) //Delete the falling machine effect, because at this point its animation is over. We dont use temp_visual because we want to manually delete it as soon as the pod appears
+ playsound(src, "explosion", 80, TRUE)
+ dump.forceMove(get_turf(src))
+ qdel(src) //The target's purpose is complete. It can rest easy now
diff --git a/code/game/objects/items/credit_holochip.dm b/code/game/objects/items/credit_holochip.dm
new file mode 100644
index 0000000000..0acb225772
--- /dev/null
+++ b/code/game/objects/items/credit_holochip.dm
@@ -0,0 +1,107 @@
+/obj/item/holochip
+ name = "credit holochip"
+ desc = "A hard-light chip encoded with an amount of credits. It is a modern replacement for physical money that can be directly converted to virtual currency and viceversa. Keep away from magnets."
+ icon = 'icons/obj/economy.dmi'
+ icon_state = "holochip"
+ throwforce = 0
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ var/credits = 0
+
+/obj/item/holochip/Initialize(mapload, amount)
+ . = ..()
+ credits = amount
+ update_icon()
+
+/obj/item/holochip/examine(mob/user)
+ . = ..()
+ . += "It's loaded with [credits] credit[( credits > 1 ) ? "s" : ""]\n"+\
+ "Alt-Click to split."
+
+/obj/item/holochip/get_item_credit_value()
+ return credits
+
+/obj/item/holochip/update_icon()
+ name = "\improper [credits] credit holochip"
+ var/rounded_credits = credits
+ switch(credits)
+ if(1 to 999)
+ icon_state = "holochip"
+ if(1000 to 999999)
+ icon_state = "holochip_kilo"
+ rounded_credits = round(rounded_credits * 0.001)
+ if(1000000 to 999999999)
+ icon_state = "holochip_mega"
+ rounded_credits = round(rounded_credits * 0.000001)
+ if(1000000000 to INFINITY)
+ icon_state = "holochip_giga"
+ rounded_credits = round(rounded_credits * 0.000000001)
+ var/overlay_color = "#914792"
+ switch(rounded_credits)
+ if(0 to 4)
+ overlay_color = "#8E2E38"
+ if(5 to 9)
+ overlay_color = "#914792"
+ if(10 to 19)
+ overlay_color = "#BF5E0A"
+ if(20 to 49)
+ overlay_color = "#358F34"
+ if(50 to 99)
+ overlay_color = "#676767"
+ if(100 to 199)
+ overlay_color = "#009D9B"
+ if(200 to 499)
+ overlay_color = "#0153C1"
+ if(500 to INFINITY)
+ overlay_color = "#2C2C2C"
+ cut_overlays()
+ var/mutable_appearance/holochip_overlay = mutable_appearance('icons/obj/economy.dmi', "[icon_state]-color")
+ holochip_overlay.color = overlay_color
+ add_overlay(holochip_overlay)
+
+/obj/item/holochip/proc/spend(amount, pay_anyway = FALSE)
+ if(credits >= amount)
+ credits -= amount
+ if(credits == 0)
+ qdel(src)
+ update_icon()
+ return amount
+ else if(pay_anyway)
+ qdel(src)
+ return credits
+ else
+ return 0
+
+/obj/item/holochip/attackby(obj/item/I, mob/user, params)
+ ..()
+ if(istype(I, /obj/item/holochip))
+ var/obj/item/holochip/H = I
+ credits += H.credits
+ to_chat(user, "You insert the credits into [src].")
+ update_icon()
+ qdel(H)
+
+/obj/item/holochip/AltClick(mob/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+ var/split_amount = round(input(user,"How many credits do you want to extract from the holochip?") as null|num)
+ if(split_amount == null || split_amount <= 0 || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+ else
+ var/new_credits = spend(split_amount, TRUE)
+ var/obj/item/holochip/H = new(user ? user : drop_location(), new_credits)
+ if(user)
+ if(!user.put_in_hands(H))
+ H.forceMove(user.drop_location())
+ add_fingerprint(user)
+ H.add_fingerprint(user)
+ to_chat(user, "You extract [split_amount] credits into a new holochip.")
+
+/obj/item/holochip/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ var/wipe_chance = 60 / severity
+ if(prob(wipe_chance))
+ visible_message("[src] fizzles and disappears!")
+ qdel(src) //rip cash
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 29a31122bf..1c50717bd5 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -1,6 +1,7 @@
/obj/item/flashlight
name = "flashlight"
desc = "A hand-held emergency light."
+ custom_price = 100
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight"
item_state = "flashlight"
@@ -422,6 +423,7 @@
/obj/item/flashlight/glowstick
name = "glowstick"
desc = "A military-grade glowstick."
+ custom_price = 50
w_class = WEIGHT_CLASS_SMALL
brightness_on = 4
color = LIGHT_COLOR_GREEN
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index b6cab8b438..1bc0f81695 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -11,6 +11,7 @@ SLIME SCANNER
/obj/item/t_scanner
name = "\improper T-ray scanner"
desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
+ custom_price = 150
icon = 'icons/obj/device.dmi'
icon_state = "t-ray0"
var/on = FALSE
@@ -79,6 +80,7 @@ SLIME SCANNER
var/mode = 1
var/scanmode = 0
var/advanced = FALSE
+ custom_price = 300
/obj/item/healthanalyzer/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")
diff --git a/code/game/objects/items/devices/sensor_device.dm b/code/game/objects/items/devices/sensor_device.dm
index 79d26776a9..07b975f133 100644
--- a/code/game/objects/items/devices/sensor_device.dm
+++ b/code/game/objects/items/devices/sensor_device.dm
@@ -5,6 +5,7 @@
icon_state = "scanner"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
+ custom_price = 1750
/obj/item/sensor_device/attack_self(mob/user)
GLOB.crewmonitor.show(user,src) //Proc already exists, just had to call it
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index 502930bf65..df5c840a1c 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -70,6 +70,7 @@
sharpness = IS_SHARP_ACCURATE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/bayonet = FALSE //Can this be attached to a gun?
+ custom_price = 250
/obj/item/kitchen/knife/Initialize()
. = ..()
@@ -107,6 +108,7 @@
custom_materials = list(/datum/material/iron=18000)
attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
w_class = WEIGHT_CLASS_NORMAL
+ custom_price = 600
/obj/item/kitchen/knife/combat
name = "combat knife"
@@ -174,6 +176,7 @@
throw_range = 7
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked")
+ custom_price = 200
/obj/item/kitchen/rollingpin/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins flattening [user.p_their()] head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
index 090c2f6d57..5a47b2eecc 100644
--- a/code/game/objects/items/pinpointer.dm
+++ b/code/game/objects/items/pinpointer.dm
@@ -78,6 +78,7 @@
name = "crew pinpointer"
desc = "A handheld tracking device that points to crew suit sensors."
icon_state = "pinpointer_crew"
+ custom_price = 1000
var/has_owner = FALSE
var/pinpointer_owner = null
diff --git a/code/game/objects/items/stacks/cash.dm b/code/game/objects/items/stacks/cash.dm
index 94f6fca28c..430018929d 100644
--- a/code/game/objects/items/stacks/cash.dm
+++ b/code/game/objects/items/stacks/cash.dm
@@ -3,7 +3,7 @@
singular_name = "bill"
icon = 'icons/obj/economy.dmi'
icon_state = "spacecash"
- amount = 1
+ amount = INFINITY
max_amount = 20
throwforce = 0
throw_speed = 2
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 50e9b94e97..588b231bda 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -93,6 +93,7 @@
var/stop_bleeding = 1800
var/heal_brute = 5
self_delay = 10
+ custom_price = 100
/obj/item/stack/medical/gauze/heal(mob/living/M, mob/user)
if(ishuman(M))
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index dc6f5f701e..0cc108c1b9 100755
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -43,6 +43,7 @@
icon_state = "utilitybelt"
item_state = "utility"
content_overlays = TRUE
+ custom_premium_price = 300
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //because this is easier than trying to have showers wash all contents.
/obj/item/storage/belt/utility/ComponentInitialize()
@@ -709,6 +710,7 @@
icon_state = "fannypack_leather"
item_state = "fannypack_leather"
dying_key = DYE_REGISTRY_FANNYPACK
+ custom_price = 100
/obj/item/storage/belt/fannypack/ComponentInitialize()
. = ..()
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 515c39ffcb..91206df4c2 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -622,6 +622,7 @@
item_state = "zippo"
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT
+ custom_price = 20
/obj/item/storage/box/matches/ComponentInitialize()
. = ..()
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index 3bc90d3615..18499d66be 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -136,6 +136,7 @@
slot_flags = ITEM_SLOT_BELT
icon_type = "cigarette"
spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette
+ custom_price = 75
/obj/item/storage/fancy/cigarettes/ComponentInitialize()
. = ..()
@@ -276,6 +277,7 @@
icon_state = "cig_paper_pack"
icon_type = "rolling paper"
spawn_type = /obj/item/rollingpaper
+ custom_price = 25
/obj/item/storage/fancy/rollingpapers/ComponentInitialize()
. = ..()
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index 27cd9c8908..0b4b6f54f3 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -16,6 +16,7 @@
STR.cant_hold = typecacheof(list(/obj/item/screwdriver/power))
STR.can_hold = typecacheof(list(
/obj/item/stack/spacecash,
+ /obj/item/holochip,
/obj/item/card,
/obj/item/clothing/mask/cigarette,
/obj/item/flashlight/pen,
@@ -101,17 +102,5 @@
icon_state = "random_wallet"
/obj/item/storage/wallet/random/PopulateContents()
- var/item1_type = pick( /obj/item/stack/spacecash/c10, /obj/item/stack/spacecash/c100, /obj/item/stack/spacecash/c1000, /obj/item/stack/spacecash/c20, /obj/item/stack/spacecash/c200, /obj/item/stack/spacecash/c50, /obj/item/stack/spacecash/c500)
- var/item2_type
- if(prob(50))
- item2_type = pick( /obj/item/stack/spacecash/c10, /obj/item/stack/spacecash/c100, /obj/item/stack/spacecash/c1000, /obj/item/stack/spacecash/c20, /obj/item/stack/spacecash/c200, /obj/item/stack/spacecash/c50, /obj/item/stack/spacecash/c500)
- var/item3_type = pick( /obj/item/coin/silver, /obj/item/coin/silver, /obj/item/coin/gold, /obj/item/coin/iron, /obj/item/coin/iron, /obj/item/coin/iron )
-
- spawn(2)
- if(item1_type)
- new item1_type(src)
- if(item2_type)
- new item2_type(src)
- if(item3_type)
- new item3_type(src)
- update_icon()
+ new /obj/item/holochip(src, rand(5,30))
+ icon_state = "wallet"
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 6ff5dfc8ad..67dbc19289 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -145,6 +145,7 @@
desc = "A janitorial watertank backpack with nozzle to clean dirt and graffiti."
icon_state = "waterbackpackjani"
item_state = "waterbackpackjani"
+ custom_price = 1200
/obj/item/watertank/janitor/Initialize()
. = ..()
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 8496a8a216..01131a3e85 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -525,6 +525,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
icon_state = "skateboard2"
item_state = "skateboard2"
board_item_type = /obj/vehicle/ridden/scooter/skateboard/pro
+ custom_premium_price = 500
/obj/item/melee/skateboard/hoverboard
name = "hoverboard"
@@ -532,6 +533,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
icon_state = "hoverboard_red"
item_state = "hoverboard_red"
board_item_type = /obj/vehicle/ridden/scooter/skateboard/hoverboard
+ custom_premium_price = 2015
/obj/item/melee/skateboard/hoverboard/admin
name = "\improper Board Of Directors"
diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm
index 4ac69253d3..2c923c1905 100644
--- a/code/game/objects/structures/crates_lockers/crates/secure.dm
+++ b/code/game/objects/structures/crates_lockers/crates/secure.dm
@@ -74,4 +74,43 @@
/obj/structure/closet/crate/secure/medical
desc = "A secure medical crate."
name = "medical crate"
- icon_state = "medical_secure_crate"
\ No newline at end of file
+ icon_state = "medical_secure_crate"
+
+/obj/structure/closet/crate/secure/owned
+ name = "private crate"
+ desc = "A crate cover designed to only open for who purchased its contents."
+ icon_state = "privatecrate"
+ var/datum/bank_account/buyer_account
+ var/privacy_lock = TRUE
+
+/obj/structure/closet/crate/secure/owned/examine(mob/user)
+ . = ..()
+ to_chat(user, "It's locked with a privacy lock, and can only be unlocked by the buyer's ID.")
+
+/obj/structure/closet/crate/secure/owned/Initialize(mapload, datum/bank_account/_buyer_account)
+ . = ..()
+ buyer_account = _buyer_account
+
+/obj/structure/closet/crate/secure/owned/togglelock(mob/living/user, silent)
+ if(privacy_lock)
+ if(!broken)
+ var/obj/item/card/id/id_card = user.get_idcard(TRUE)
+ if(id_card)
+ if(id_card.registered_account)
+ if(id_card.registered_account == buyer_account)
+ if(iscarbon(user))
+ add_fingerprint(user)
+ locked = !locked
+ user.visible_message("[user] unlocks [src]'s privacy lock.",
+ "You unlock [src]'s privacy lock.")
+ privacy_lock = FALSE
+ update_icon()
+ else if(!silent)
+ to_chat(user, "Bank account does not match with buyer!")
+ else if(!silent)
+ to_chat(user, "No linked bank account detected!")
+ else if(!silent)
+ to_chat(user, "No ID detected!")
+ else if(!silent)
+ to_chat(user, "[src] is broken!")
+ else ..()
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index c918e7b867..d0be6c8469 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -689,7 +689,7 @@
name = "ID, jumpsuit and shoes"
uniform = /obj/item/clothing/under/color/random
shoes = /obj/item/clothing/shoes/sneakers/black
- id = /obj/item/card/id
+ id = /obj/item/card/id/no_banking
r_hand = /obj/item/storage/box/syndie_kit/chameleon/ghostcafe
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index c70db70ee8..a06b674e42 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -63,6 +63,7 @@
There can only be one! (40-second delay)
Make all players stupid
Egalitarian Station Mode
+ Anarcho-Capitalist Station Mode
Break all lights
Fix all lights
The floor is lava! (DANGEROUS: extremely lame)
@@ -478,6 +479,17 @@
usr.client.ak47s()
sound_to_playing_players('sound/misc/ak47s.ogg')
+ if("ancap")
+ if(!check_rights(R_FUN))
+ return
+ SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Anarcho-capitalist Station"))
+ SSeconomy.full_ancap = !SSeconomy.full_ancap
+ message_admins("[key_name_admin(usr)] toggled Anarcho-capitalist mode")
+ if(SSeconomy.full_ancap)
+ priority_announce("The NAP is now in full effect.", null, "commandreport")
+ else
+ priority_announce("The NAP has been revoked.", null, "commandreport")
+
if("guns")
if(!check_rights(R_FUN))
return
diff --git a/code/modules/antagonists/blob/blob/blob_report.dm b/code/modules/antagonists/blob/blob/blob_report.dm
index 4385b732c3..d532121e12 100644
--- a/code/modules/antagonists/blob/blob/blob_report.dm
+++ b/code/modules/antagonists/blob/blob/blob_report.dm
@@ -8,6 +8,13 @@
var/mach = 0
/datum/station_state/proc/count()
+ floor = 0
+ wall = 0
+ r_wall = 0
+ window = 0
+ door = 0
+ grille = 0
+ mach = 0
for(var/Z in SSmapping.levels_by_trait(ZTRAIT_STATION))
for(var/turf/T in block(locate(1,1,Z), locate(world.maxx,world.maxy,Z)))
// don't count shuttles since they may have just left
@@ -48,6 +55,10 @@
else if(ismachinery(O))
mach += 1
+ CHECK_TICK
+ CHECK_TICK
+ CHECK_TICK
+
/datum/station_state/proc/score(datum/station_state/result)
if(!result)
return 0
diff --git a/code/modules/antagonists/traitor/syndicate_contract.dm b/code/modules/antagonists/traitor/syndicate_contract.dm
index daa9127591..70ff59eee0 100644
--- a/code/modules/antagonists/traitor/syndicate_contract.dm
+++ b/code/modules/antagonists/traitor/syndicate_contract.dm
@@ -78,14 +78,28 @@
var/mob/living/carbon/human/target = M // After we remove items, at least give them what they need to live.
target.dna.species.give_important_for_life(target)
handleVictimExperience(M) // After pod is sent we start the victim narrative/heal.
- var/points_to_check = SSshuttle.points // This is slightly delayed because of the sleep calls above to handle the narrative. We don't want to tell the station instantly.
- if(points_to_check >= ransom)
- SSshuttle.points -= ransom
- else
- SSshuttle.points -= points_to_check
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ var/points_to_check = min(D.account_balance, ransom)
+ D.adjust_money(min(points_to_check, ransom))
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. \
As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection")
+ sleep(30)
+
+ // Pay contractor their portion of ransom
+ if (status == CONTRACT_STATUS_COMPLETE)
+ var/mob/living/carbon/human/H
+ var/obj/item/card/id/C
+ if(ishuman(contract.owner.current))
+ H = contract.owner.current
+ C = H.get_idcard(TRUE)
+
+ if(C && C.registered_account)
+ C.registered_account.adjust_money(points_to_check * 0.35)
+
+ C.registered_account.bank_card_talk("We've processed the ransom, agent. Here's your cut - your balance is now \
+ [C.registered_account.account_balance] cr.", TRUE)
+
/datum/syndicate_contract/proc/handleVictimExperience(var/mob/living/M) // They're off to holding - handle the return timer and give some text about what's going on.
addtimer(CALLBACK(src, .proc/returnVictim, M), 4 MINUTES) // Ship 'em back - dead or alive... 4 minutes wait.
if(M.stat != DEAD) //Even if they weren't the target, we're still treating them the same.
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index a4617462fe..aa1e5c7401 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -36,6 +36,7 @@
/obj/item/electronics/airalarm
name = "air alarm electronics"
icon_state = "airalarm_electronics"
+ custom_price = 50
/obj/item/wallframe/airalarm
name = "air alarm frame"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index e013a86fd2..b859c536cc 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -33,6 +33,9 @@
var/message_cooldown
var/breakout_time = 300
+ fair_market_price = 10
+ payment_department = ACCOUNT_MED
+
/obj/machinery/atmospherics/components/unary/cryo_cell/Initialize()
. = ..()
initialize_directions = dir
@@ -149,6 +152,9 @@
add_overlay("cover-on")
addtimer(CALLBACK(src, .proc/run_anim, anim_up, occupant_overlay), 7, TIMER_UNIQUE)
+/obj/machinery/atmospherics/components/unary/cryo_cell/nap_violation(mob/violator)
+ open_machine()
+
/obj/machinery/atmospherics/components/unary/cryo_cell/process()
..()
@@ -162,7 +168,8 @@
return
var/mob/living/mob_occupant = occupant
-
+ if(!check_nap_violations())
+ return
if(mob_occupant.stat == DEAD) // We don't bother with dead people.
return
diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm
index d4c9fdbee7..00460e8a85 100644
--- a/code/modules/awaymissions/zlevel.dm
+++ b/code/modules/awaymissions/zlevel.dm
@@ -1,5 +1,7 @@
// How much "space" we give the edge of the map
GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "[global.config.directory]/awaymissionconfig.txt"))
+// So far only adds an additional trait to vr levels. But I'll probably use make VR separate from away missions in a near future.
+GLOBAL_LIST_INIT(potentialRandomVRlevels, generateMapList(filename = "[global.config.directory]/vr_config.txt"))
/proc/createRandomZlevel()
if(GLOB.awaydestinations.len) //crude, but it saves another var!
@@ -8,7 +10,10 @@ GLOBAL_LIST_INIT(potentialRandomZlevels, generateMapList(filename = "[global.con
if(GLOB.potentialRandomZlevels && GLOB.potentialRandomZlevels.len)
to_chat(world, "Loading away mission...")
var/map = pick(GLOB.potentialRandomZlevels)
- load_new_z_level(map, "Away Mission")
+ var/list/traits = list(ZTRAIT_AWAY = TRUE)
+ if(map in GLOB.potentialRandomVRlevels)
+ traits[ZTRAIT_VIRTUAL_REALITY] = TRUE
+ load_new_z_level(map, "Away Mission", traits)
to_chat(world, "Away mission loaded.")
/proc/reset_gateway_spawns(reset = FALSE)
diff --git a/code/modules/cargo/bounties/science.dm b/code/modules/cargo/bounties/science.dm
index ad03b2f393..a4632f7ed0 100644
--- a/code/modules/cargo/bounties/science.dm
+++ b/code/modules/cargo/bounties/science.dm
@@ -55,7 +55,7 @@
/datum/bounty/item/science/advanced_mop
name = "Advanced Mop"
- description = "Excuse me. I'd like to request 17 credits for a push broom rebristling. Either that, or an advanced mop."
+ description = "Excuse me. I'd like to request 17 cr for a push broom rebristling. Either that, or an advanced mop."
reward = 3000
wanted_types = list(/obj/item/mop/advanced)
diff --git a/code/modules/cargo/bounty.dm b/code/modules/cargo/bounty.dm
index bfd97e4d1f..b888dc1a28 100644
--- a/code/modules/cargo/bounty.dm
+++ b/code/modules/cargo/bounty.dm
@@ -21,7 +21,9 @@ GLOBAL_LIST_EMPTY(bounties_list)
// Called when the claim button is clicked. Override to provide fancy rewards.
/datum/bounty/proc/claim()
if(can_claim())
- SSshuttle.points += reward
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ D.adjust_money(reward)
claimed = TRUE
// If an item sent in the cargo shuttle can satisfy the bounty.
@@ -126,11 +128,11 @@ GLOBAL_LIST_EMPTY(bounties_list)
/proc/setup_bounties()
var/pick // instead of creating it a bunch let's go ahead and toss it here, we know we're going to use it for dynamics and subtypes!
-
+
/********************************Subtype Gens********************************/
var/list/easy_add_list_subtypes = list(/datum/bounty/item/assistant = 2,
- /datum/bounty/item/mech = 1,
- /datum/bounty/item/chef = 2,
+ /datum/bounty/item/mech = 1,
+ /datum/bounty/item/chef = 2,
/datum/bounty/item/security = 1,
/datum/bounty/virus = 1,
/datum/bounty/item/engineering = 1,
@@ -139,30 +141,30 @@ GLOBAL_LIST_EMPTY(bounties_list)
/datum/bounty/item/botany = 2,
/datum/bounty/item/silly = 1,
/datum/bounty/item/gardencook = 1)
-
+
for(var/the_type in easy_add_list_subtypes)
for(var/i in 1 to easy_add_list_subtypes[the_type])
pick = pick(subtypesof(the_type))
try_add_bounty(new pick)
-
+
/********************************Strict Type Gens********************************/
var/list/easy_add_list_strict_types = list(/datum/bounty/reagent/simple_drink = 1,
/datum/bounty/reagent/complex_drink = 1,
/datum/bounty/reagent/chemical = 1)
-
+
for(var/the_strict_type in easy_add_list_strict_types)
for(var/i in 1 to easy_add_list_strict_types[the_strict_type])
try_add_bounty(new the_strict_type)
-
+
/********************************Dynamic Gens********************************/
-
+
for(var/i in 0 to 1)
if(prob(50))
pick = pick(subtypesof(/datum/bounty/item/slime))
else
pick = pick(subtypesof(/datum/bounty/item/science))
try_add_bounty(new pick)
-
+
/********************************Cutoff for Non-Low Priority Bounties********************************/
var/datum/bounty/B = pick(GLOB.bounties_list)
B.mark_high_priority()
@@ -172,7 +174,7 @@ GLOBAL_LIST_EMPTY(bounties_list)
/datum/bounty/item/syndicate_documents,
/datum/bounty/item/adamantine,
/datum/bounty/more_bounties)
-
+
for(var/low_priority_bounty in low_priority_strict_type_list)
try_add_bounty(new low_priority_bounty)
diff --git a/code/modules/cargo/bounty_console.dm b/code/modules/cargo/bounty_console.dm
index 45260f4926..f499c38090 100644
--- a/code/modules/cargo/bounty_console.dm
+++ b/code/modules/cargo/bounty_console.dm
@@ -35,10 +35,10 @@
if(!GLOB.bounties_list.len)
setup_bounties()
-
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/list/dat = list({"Refresh
Print Paper
-
Credits: [SSshuttle.points]
+ Credits: [D.account_balance]
| Name | Description | Reward | Completion | Status |
"})
for(var/datum/bounty/B in GLOB.bounties_list)
diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm
index 64b208a90b..1883a5f615 100644
--- a/code/modules/cargo/console.dm
+++ b/code/modules/cargo/console.dm
@@ -74,9 +74,12 @@
/obj/machinery/computer/cargo/ui_data()
var/list/data = list()
data["location"] = SSshuttle.supply.getStatusText()
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ data["points"] = D.account_balance
data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
+ data["self_paid"] = self_paid
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
- data["points"] = SSshuttle.points
data["loan"] = !!SSshuttle.shuttle_loan
data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
var/message = "Remember to stamp and send back the supply manifests."
@@ -92,6 +95,7 @@
"cost" = SO.pack.cost,
"id" = SO.id,
"orderer" = SO.orderer,
+ "paid" = !isnull(SO.paying_account) //paid by requester
))
data["requests"] = list()
@@ -165,6 +169,7 @@
. = TRUE
if("add")
var/id = text2path(params["id"])
+ var/self_paid = text2num(params["self_paid"])
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
if(!istype(pack))
return
@@ -182,19 +187,33 @@
name = usr.real_name
rank = "Silicon"
+ var/datum/bank_account/account
+ if(self_paid && ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/card/id/id_card = H.get_idcard(TRUE)
+ if(!istype(id_card))
+ say("No ID card detected.")
+ return
+ account = id_card.registered_account
+ if(!istype(account))
+ say("Invalid bank account.")
+ return
+
var/reason = ""
- if(requestonly)
+ if(requestonly && !self_paid)
reason = stripped_input("Reason:", name, "")
if(isnull(reason) || ..())
return
var/turf/T = get_turf(src)
- var/datum/supply_order/SO = new(pack, name, rank, ckey, reason)
+ var/datum/supply_order/SO = new(pack, name, rank, ckey, reason, account)
SO.generateRequisition(T)
- if(requestonly)
+ if(requestonly && !self_paid)
SSshuttle.requestlist += SO
else
SSshuttle.shoppinglist += SO
+ if(self_paid)
+ say("Order processed. The price will be charged to [account.account_holder]'s bank account on delivery.")
. = TRUE
if("remove")
var/id = text2num(params["id"])
diff --git a/code/modules/cargo/exports.dm b/code/modules/cargo/exports.dm
index bb90fa717a..0a1346ba01 100644
--- a/code/modules/cargo/exports.dm
+++ b/code/modules/cargo/exports.dm
@@ -26,6 +26,7 @@ Credit dupes that require a lot of manual work shouldn't be removed, unless they
var/list/total_value = list() //export instance => total value of sold objects
var/list/reagents_volume = list()//export reagents => into the total volume of the object sold
var/list/reagents_value = list()//export reagents => into the reagent type total value.
+ var/list/exported_atoms_ref = list() //if they're not deleted they go in here for use.
// external_report works as "transaction" object, pass same one in if you're doing more than one export in single go
/proc/export_item_and_contents(atom/movable/AM, allowed_categories = EXPORT_CARGO, apply_elastic = TRUE, delete_unsold = TRUE, dry_run=FALSE, datum/export_report/external_report)
diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm
index a65d8cad40..678f5c851f 100644
--- a/code/modules/cargo/expressconsole.dm
+++ b/code/modules/cargo/expressconsole.dm
@@ -96,17 +96,19 @@
/obj/machinery/computer/cargo/express/ui_data(mob/user)
var/canBeacon = beacon && (isturf(beacon.loc) || ismob(beacon.loc))//is the beacon in a valid location?
var/list/data = list()
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ data["points"] = D.account_balance
data["locked"] = locked//swipe an ID to unlock
data["siliconUser"] = hasSiliconAccessInArea(user)
data["beaconzone"] = beacon ? get_area(beacon) : ""//where is the beacon located? outputs in the tgui
data["usingBeacon"] = usingBeacon //is the mode set to deliver to the beacon or the cargobay?
data["canBeacon"] = !usingBeacon || canBeacon //is the mode set to beacon delivery, and is the beacon in a valid location?
- data["canBuyBeacon"] = cooldown <= 0 && SSshuttle.points >= BEACON_COST
+ data["canBuyBeacon"] = cooldown <= 0 && D.account_balance >= BEACON_COST
data["beaconError"] = usingBeacon && !canBeacon ? "(BEACON ERROR)" : ""//changes button text to include an error alert if necessary
data["hasBeacon"] = beacon != null//is there a linked beacon?
data["beaconName"] = beacon ? beacon.name : "No Beacon Found"
data["printMsg"] = cooldown > 0 ? "Print Beacon for [BEACON_COST] credits ([cooldown])" : "Print Beacon for [BEACON_COST] credits"//buttontext for printing beacons
- data["points"] = SSshuttle.points
data["supplies"] = list()
message = "Sales are near-instantaneous - please choose carefully."
if(SSshuttle.supplyBlocked)
@@ -137,13 +139,14 @@
if (beacon)
beacon.update_status(SP_READY) //turns on the beacon's ready light
if("printBeacon")
- if (SSshuttle.points >= BEACON_COST)
- cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam
- var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location())
- C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc)
- printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1
- beacon.name = "Supply Pod Beacon #[printed_beacons]"
- SSshuttle.points -= BEACON_COST
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ if(D.adjust_money(-BEACON_COST))
+ cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam
+ var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location())
+ C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc)
+ printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1
+ beacon.name = "Supply Pod Beacon #[printed_beacons]"
if("add")//Generate Supply Order first
var/id = text2path(params["id"])
@@ -163,8 +166,12 @@
var/reason = ""
var/list/empty_turfs
var/datum/supply_order/SO = new(pack, name, rank, ckey, reason)
+ var/points_to_check
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ points_to_check = D.account_balance
if(!(obj_flags & EMAGGED))
- if(SO.pack.cost <= SSshuttle.points)
+ if(SO.pack.cost <= points_to_check)
var/LZ
if (istype(beacon) && usingBeacon)//prioritize beacons over landing in cargobay
LZ = get_turf(beacon)
@@ -181,14 +188,14 @@
CHECK_TICK
if(empty_turfs && empty_turfs.len)
LZ = pick(empty_turfs)
- if (SO.pack.cost <= SSshuttle.points && LZ)//we need to call the cost check again because of the CHECK_TICK call
- SSshuttle.points -= SO.pack.cost
+ if (SO.pack.cost <= points_to_check && LZ)//we need to call the cost check again because of the CHECK_TICK call
+ D.adjust_money(-SO.pack.cost)
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
new /obj/effect/abstract/DPtarget(LZ, podType, SO)
. = TRUE
update_icon()
else
- if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^)
+ if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= points_to_check) // bulk discount :^)
landingzone = GLOB.areas_by_type[pick(GLOB.the_station_areas)] //override default landing zone
for(var/turf/open/floor/T in landingzone.contents)
if(is_blocked_turf(T))
@@ -196,7 +203,7 @@
LAZYADD(empty_turfs, T)
CHECK_TICK
if(empty_turfs && empty_turfs.len)
- SSshuttle.points -= SO.pack.cost * (0.72*MAX_EMAG_ROCKETS)
+ D.adjust_money(-(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS)))
SSblackbox.record_feedback("nested tally", "cargo_imports", MAX_EMAG_ROCKETS, list("[SO.pack.cost * 0.72]", "[SO.pack.name]"))
SO.generateRequisition(get_turf(src))
for(var/i in 1 to MAX_EMAG_ROCKETS)
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index b78f218348..5e6f7c677d 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -28,14 +28,16 @@
var/orderer_ckey
var/reason
var/datum/supply_pack/pack
+ var/datum/bank_account/paying_account
-/datum/supply_order/New(datum/supply_pack/pack, orderer, orderer_rank, orderer_ckey, reason)
+/datum/supply_order/New(datum/supply_pack/pack, orderer, orderer_rank, orderer_ckey, reason, paying_account)
id = SSshuttle.ordernum++
src.pack = pack
src.orderer = orderer
src.orderer_rank = orderer_rank
src.orderer_ckey = orderer_ckey
src.reason = reason
+ src.paying_account = paying_account
/datum/supply_order/proc/generateRequisition(turf/T)
var/obj/item/paper/P = new(T)
@@ -47,6 +49,8 @@
P.info += "Item: [pack.name]
"
P.info += "Access Restrictions: [get_access_desc(pack.access)]
"
P.info += "Requested by: [orderer]
"
+ if(paying_account)
+ P.info += "Paid by: [paying_account.account_holder]
"
P.info += "Rank: [orderer_rank]
"
P.info += "Comment: [reason]
"
@@ -61,6 +65,9 @@
P.name = "shipping manifest - #[id] ([pack.name])"
P.info += "[command_name()] Shipping Manifest
"
P.info += "
"
+ if(paying_account)
+ P.info += "Direct purchase from [paying_account.account_holder]
"
+ P.name += " - Purchased by [paying_account.account_holder]"
P.info += "Order #[id]
"
P.info += "Destination: [station_name]
"
P.info += "Item: [pack.name]
"
@@ -84,7 +91,7 @@
return P
/datum/supply_order/proc/generate(atom/A)
- var/obj/structure/closet/crate/C = pack.generate(A)
+ var/obj/structure/closet/crate/C = pack.generate(A, paying_account)
var/obj/item/paper/fluff/jobs/cargo/manifest/M = generateManifest(C)
if(M.errors & MANIFEST_ERROR_ITEM)
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 07a75bbfaf..96557d58ef 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -16,16 +16,20 @@
var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console
var/admin_spawned = FALSE //Can only an admin spawn this crate?
-/datum/supply_pack/proc/generate(atom/A)
- var/obj/structure/closet/crate/C = new crate_type(A)
- C.name = crate_name
+/datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account)
+ var/obj/structure/closet/crate/C
+ if(paying_account)
+ C = new /obj/structure/closet/crate/secure/owned(A, paying_account)
+ C.name = "[crate_name] - Purchased by [paying_account.account_holder]"
+ else
+ C = new crate_type(A)
+ C.name = crate_name
if(access)
C.req_access = list(access)
if(access_any)
C.req_one_access = access_any
fill(C)
-
return C
/datum/supply_pack/proc/fill(obj/structure/closet/crate/C)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index f7d251f32d..1fbf93a914 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -900,7 +900,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Ghosts of Others: [button_name]
"
dat += "
"
+
dat += "FPS: [clientfps]
"
+
+ dat += "Income Updates: [(chat_toggles & CHAT_BANKCARD) ? "Allowed" : "Muted"]
"
+ dat += "
"
+
dat += "Parallax (Fancy Space): "
switch (parallax)
if (PARALLAX_LOW)
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index 8f7156863d..2670e1bcf4 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -250,6 +250,16 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings, listen_ooc)()
/datum/verbs/menu/Settings/listen_ooc/Get_checked(client/C)
return C.prefs.chat_toggles & CHAT_OOC
+TOGGLE_CHECKBOX(/datum/verbs/menu/Settings, listen_bank_card)()
+ set name = "Show/Hide Income Updates"
+ set category = "Preferences"
+ set desc = "Show or hide updates to your income"
+ usr.client.prefs.chat_toggles ^= CHAT_BANKCARD
+ usr.client.prefs.save_preferences()
+ to_chat(usr, "You will [(usr.client.prefs.chat_toggles & CHAT_BANKCARD) ? "now" : "no longer"] be notified when you get paid.")
+ SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle Income Notifications", "[(usr.client.prefs.chat_toggles & CHAT_BANKCARD) ? "Enabled" : "Disabled"]"))
+/datum/verbs/menu/Settings/listen_bank_card/Get_checked(client/C)
+ return C.prefs.chat_toggles & CHAT_BANKCARD
GLOBAL_LIST_INIT(ghost_forms, list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \
"ghost_blue","ghost_yellow","ghost_green","ghost_pink", \
diff --git a/code/modules/clothing/ears/_ears.dm b/code/modules/clothing/ears/_ears.dm
index 1c31e19202..39d23c0107 100644
--- a/code/modules/clothing/ears/_ears.dm
+++ b/code/modules/clothing/ears/_ears.dm
@@ -6,6 +6,7 @@
throwforce = 0
slot_flags = ITEM_SLOT_EARS
resistance_flags = NONE
+ custom_price = 250
/obj/item/clothing/ears/earmuffs
name = "earmuffs"
@@ -30,6 +31,7 @@
slot_flags = ITEM_SLOT_EARS | ITEM_SLOT_HEAD | ITEM_SLOT_NECK //Fluff item, put it whereever you want!
actions_types = list(/datum/action/item_action/toggle_headphones)
var/headphones_on = FALSE
+ custom_price = 125
/obj/item/clothing/ears/headphones/Initialize()
. = ..()
diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm
index 77f06a8a74..63521c9b75 100644
--- a/code/modules/clothing/gloves/color.dm
+++ b/code/modules/clothing/gloves/color.dm
@@ -10,6 +10,8 @@
permeability_coefficient = 0.05
resistance_flags = NONE
var/can_be_cut = 1
+ custom_price = 1200
+ custom_premium_price = 1200
/obj/item/clothing/gloves/color/fyellow //Cheap Chinese Crap
desc = "These gloves are cheap knockoffs of the coveted ones - no way this can end badly."
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index a37dc8b638..948f14a960 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -10,6 +10,7 @@
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
strip_mod = 0.9
+ custom_price = 75
/obj/item/clothing/gloves/fingerless/pugilist
name = "armwraps"
diff --git a/code/modules/clothing/head/beanie.dm b/code/modules/clothing/head/beanie.dm
index 4117e88811..79f8931889 100644
--- a/code/modules/clothing/head/beanie.dm
+++ b/code/modules/clothing/head/beanie.dm
@@ -5,6 +5,7 @@
name = "white beanie"
desc = "A stylish beanie. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their heads."
icon_state = "beanie" //Default white
+ custom_price = 60
/obj/item/clothing/head/beanie/black
name = "black beanie"
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 9ad05efb7a..987faf8fbb 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -58,6 +58,7 @@
desc = "A reliable, blue tinted helmet reminding you that you still owe that engineer a beer."
icon_state = "blueshift"
item_state = "blueshift"
+ custom_premium_price = 750
/obj/item/clothing/head/helmet/riot
name = "riot helmet"
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 2cb043ba88..8627887492 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -129,6 +129,7 @@
dog_fashion = /datum/dog_fashion/head/pirate
/obj/item/clothing/head/pirate/captain
+ name = "pirate captain hat"
icon_state = "hgpiratecap"
item_state = "hgpiratecap"
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index 402ea37f21..3052d7af8e 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -22,6 +22,7 @@
icon_state = "bluetie"
item_state = "" //no inhands
w_class = WEIGHT_CLASS_SMALL
+ custom_price = 60
/obj/item/clothing/neck/tie/blue
name = "blue tie"
@@ -87,6 +88,7 @@
/obj/item/clothing/neck/scarf //Default white color, same functionality as beanies.
name = "white scarf"
icon_state = "scarf"
+ custom_price = 60
desc = "A stylish scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks."
dog_fashion = /datum/dog_fashion/head
@@ -251,6 +253,40 @@
icon = 'icons/obj/clothing/neck.dmi'
icon_state = "bling"
+/obj/item/clothing/neck/necklace/dope/merchant
+ desc = "Don't ask how it works, the proof is in the holochips!"
+ /// scales the amount received in case an admin wants to emulate taxes/fees.
+ var/profit_scaling = 1
+ /// toggles between sell (TRUE) and get price post-fees (FALSE)
+ var/selling = FALSE
+
+/obj/item/clothing/neck/necklace/dope/merchant/attack_self(mob/user)
+ . = ..()
+ selling = !selling
+ to_chat(user, "[src] has been set to [selling ? "'Sell'" : "'Get Price'"] mode.")
+
+/obj/item/clothing/neck/necklace/dope/merchant/afterattack(obj/item/I, mob/user, proximity)
+ . = ..()
+ if(!proximity)
+ return
+ var/datum/export_report/ex = export_item_and_contents(I, allowed_categories = (ALL), dry_run=TRUE)
+ var/price = 0
+ for(var/x in ex.total_amount)
+ price += ex.total_value[x]
+
+ if(price)
+ var/true_price = round(price*profit_scaling)
+ to_chat(user, "[selling ? "Sold" : "Getting the price of"] [I], value: [true_price] credits[I.contents.len ? " (exportable contents included)" : ""].[profit_scaling < 1 && selling ? "[round(price-true_price)] credit\s taken as processing fee\s." : ""]")
+ if(selling)
+ new /obj/item/holochip(get_turf(user),true_price)
+ for(var/i in ex.exported_atoms_ref)
+ var/atom/movable/AM = i
+ if(QDELETED(AM))
+ continue
+ qdel(AM)
+ else
+ to_chat(user, "There is no export value for [I] or any items within it.")
+
//////////////////////////////////
//VERY SUPER BADASS NECKERCHIEFS//
//////////////////////////////////
diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm
index ee350e3891..669c03be2c 100644
--- a/code/modules/clothing/outfits/vr.dm
+++ b/code/modules/clothing/outfits/vr.dm
@@ -3,15 +3,21 @@
uniform = /obj/item/clothing/under/color/random
shoes = /obj/item/clothing/shoes/sneakers/black
ears = /obj/item/radio/headset
- id = /obj/item/card/id
+ id = /obj/item/card/id/locked_banking
+ var/starting_funds = 350
/datum/outfit/vr/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
H.dna.species.before_equip_job(null, H)
/datum/outfit/vr/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
var/obj/item/card/id/id = H.wear_id
- if (istype(id))
- id.access |= get_all_accesses()
+ if(!istype(id))
+ return
+ id.access |= get_all_accesses()
+ if(id.registered_account)
+ id.registered_account.account_holder = "[H.real_name] (VR)"
+ if(starting_funds && id.bank_support == ID_LOCKED_BANK_ACCOUNT) //No payroll or ability to virtually transfer funds to an external account.
+ id.registered_account.adjust_money(starting_funds)
/datum/outfit/vr/syndicate
name = "Syndicate VR Operative - Basic"
@@ -19,11 +25,12 @@
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/syndicate/locked_banking
belt = /obj/item/gun/ballistic/automatic/pistol
l_pocket = /obj/item/paper/fluff/vr/fluke_ops
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/kitchen/knife/combat/survival)
+ starting_funds = 0 //Should be operating, not shopping.
/datum/outfit/vr/syndicate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
. = ..()
diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm
index df0f03f614..8cadb84cef 100644
--- a/code/modules/clothing/shoes/colour.dm
+++ b/code/modules/clothing/shoes/colour.dm
@@ -1,5 +1,6 @@
/obj/item/clothing/shoes/sneakers
dying_key = DYE_REGISTRY_SNEAKERS
+ custom_price = 50
/obj/item/clothing/shoes/sneakers/black
name = "black shoes"
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 7a3ed902ea..d6d4b1af1e 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -71,6 +71,7 @@
equip_delay_other = 50
resistance_flags = NONE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 40, "acid" = 75)
+ custom_price = 600
/obj/item/clothing/shoes/galoshes/dry
name = "absorbent galoshes"
@@ -371,6 +372,7 @@
/obj/item/clothing/shoes/cowboyboots
name = "cowboy boots"
desc = "A standard pair of brown cowboy boots."
+ custom_price = 60 //remember to replace these lame cosmetics with tg's YEEEEHAW counterparts.
icon_state = "cowboyboots"
/obj/item/clothing/shoes/cowboyboots/black
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index a19dfaa889..0df1b1e18c 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -47,6 +47,7 @@
desc = "A large, yet comfortable piece of armor, protecting you from some threats."
icon_state = "blueshift"
item_state = "blueshift"
+ custom_premium_price = 750
/obj/item/clothing/suit/armor/hos
name = "armored greatcoat"
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index d475ca8100..4ff3a3f9de 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -86,6 +86,7 @@
icon_state = "overalls"
item_state = "lb_suit"
can_adjust = FALSE
+ custom_price = 60
/obj/item/clothing/under/misc/assistantformal
name = "assistant's formal uniform"
diff --git a/code/modules/clothing/under/pants.dm b/code/modules/clothing/under/pants.dm
index d0048326ff..11543ac675 100644
--- a/code/modules/clothing/under/pants.dm
+++ b/code/modules/clothing/under/pants.dm
@@ -3,6 +3,7 @@
body_parts_covered = GROIN|LEGS
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
+ custom_price = 60
/obj/item/clothing/under/pants/classicjeans
name = "classic jeans"
@@ -13,6 +14,7 @@
name = "Must Hang jeans"
desc = "Made in the finest space jeans factory this side of Alpha Centauri."
icon_state = "jeansmustang"
+ custom_price = 180
/obj/item/clothing/under/pants/blackjeans
name = "black jeans"
diff --git a/code/modules/clothing/under/skirt_dress.dm b/code/modules/clothing/under/skirt_dress.dm
index fa2c9eed71..94483f5804 100644
--- a/code/modules/clothing/under/skirt_dress.dm
+++ b/code/modules/clothing/under/skirt_dress.dm
@@ -15,6 +15,7 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
+ custom_price = 60
/obj/item/clothing/under/dress/skirt/red
name = "red skirt"
@@ -24,6 +25,7 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
+ custom_price = 60
/obj/item/clothing/under/dress/skirt/purple
name = "purple skirt"
@@ -33,6 +35,7 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
+ custom_price = 60
/obj/item/clothing/under/dress/sundress
name = "sundress"
@@ -146,6 +149,7 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = TRUE
alt_covers_chest = TRUE
+ custom_price = 60
/obj/item/clothing/under/dress/skirt/plaid/blue
name = "blue plaid skirt"
diff --git a/code/modules/economy/_economy.dm b/code/modules/economy/_economy.dm
new file mode 100644
index 0000000000..9bafb62eae
--- /dev/null
+++ b/code/modules/economy/_economy.dm
@@ -0,0 +1,2 @@
+/obj/item/proc/get_item_credit_value()
+ return
\ No newline at end of file
diff --git a/code/modules/economy/account.dm b/code/modules/economy/account.dm
new file mode 100644
index 0000000000..f9addc1f14
--- /dev/null
+++ b/code/modules/economy/account.dm
@@ -0,0 +1,118 @@
+#define DUMPTIME 3000
+
+/datum/bank_account
+ var/account_holder = "Rusty Venture"
+ var/account_balance = 0
+ var/datum/job/account_job
+ var/list/bank_cards = list()
+ var/add_to_accounts = TRUE
+ var/transferable = TRUE
+ var/account_id
+ var/being_dumped = FALSE //pink levels are rising
+ var/withdrawDelay = 0
+
+/datum/bank_account/New(newname, job)
+ if(add_to_accounts)
+ SSeconomy.bank_accounts += src
+ account_holder = newname
+ account_job = job
+ account_id = rand(111111,999999)
+
+/datum/bank_account/Destroy()
+ if(add_to_accounts)
+ SSeconomy.bank_accounts -= src
+ return ..()
+
+/datum/bank_account/proc/dumpeet()
+ being_dumped = TRUE
+ withdrawDelay = world.time + DUMPTIME
+
+/datum/bank_account/proc/_adjust_money(amt)
+ account_balance += amt
+ if(account_balance < 0)
+ account_balance = 0
+
+/datum/bank_account/proc/has_money(amt)
+ return account_balance >= amt
+
+/datum/bank_account/proc/adjust_money(amt)
+ if((amt < 0 && has_money(-amt)) || amt > 0)
+ _adjust_money(amt)
+ return TRUE
+ return FALSE
+
+/datum/bank_account/proc/transfer_money(datum/bank_account/from, amount)
+ if(!transferable || !from.has_money(amount))
+ return FALSE
+ adjust_money(amount)
+ from.adjust_money(-amount)
+ return TRUE
+
+/datum/bank_account/proc/payday(amt_of_paychecks, free = FALSE)
+ var/money_to_transfer = account_job.paycheck * amt_of_paychecks
+ if(free)
+ adjust_money(money_to_transfer)
+ else
+ var/datum/bank_account/D = SSeconomy.get_dep_account(account_job.paycheck_department)
+ if(D)
+ if(!transfer_money(D, money_to_transfer))
+ bank_card_talk("ERROR: Payday aborted, departmental funds insufficient.")
+ return FALSE
+ else
+ bank_card_talk("Payday processed, account now holds [account_balance] cr.")
+ return TRUE
+ bank_card_talk("ERROR: Payday aborted, unable to contact departmental account.")
+ return FALSE
+
+/datum/bank_account/proc/bank_card_talk(message, force)
+ if(!message || !bank_cards.len)
+ return
+ for(var/obj/A in bank_cards)
+ var/icon_source = A
+ /*
+ if(istype(A, /obj/item/card/id))
+ var/obj/item/card/id/id_card = A
+ if(id_card.uses_overlays)
+ icon_source = id_card.get_cached_flat_icon()
+ */
+ var/mob/card_holder = recursive_loc_check(A, /mob)
+ if(ismob(card_holder)) //If on a mob
+ if(card_holder.client && !(card_holder.client.prefs.chat_toggles & CHAT_BANKCARD) && !force)
+ return
+
+ card_holder.playsound_local(get_turf(card_holder), 'sound/machines/twobeep.ogg', 50, TRUE)
+ if(card_holder.can_hear())
+ to_chat(card_holder, "[icon2html(icon_source, card_holder)] [message]")
+ else if(isturf(A.loc)) //If on the ground
+ for(var/mob/M in hearers(1,get_turf(A)))
+ if(M.client && !(M.client.prefs.chat_toggles & CHAT_BANKCARD) && !force)
+ return
+ playsound(A, 'sound/machines/twobeep.ogg', 50, TRUE)
+ A.audible_message("[icon2html(icon_source, hearers(A))] [message]", null, 1)
+ break
+ else
+ for(var/mob/M in A.loc) //If inside a container with other mobs (e.g. locker)
+ if(M.client && !(M.client.prefs.chat_toggles & CHAT_BANKCARD) && !force)
+ return
+ M.playsound_local(get_turf(M), 'sound/machines/twobeep.ogg', 50, TRUE)
+ if(M.can_hear())
+ to_chat(M, "[icon2html(icon_source, M)] [message]")
+
+/datum/bank_account/department
+ account_holder = "Guild Credit Agency"
+ var/department_id = "REPLACE_ME"
+ add_to_accounts = FALSE
+
+/datum/bank_account/department/New(dep_id, budget)
+ department_id = dep_id
+ account_balance = budget
+ account_holder = SSeconomy.department_accounts[dep_id]
+ SSeconomy.generated_accounts += src
+
+/datum/bank_account/remote // Bank account not belonging to the local station
+ add_to_accounts = FALSE
+
+/datum/bank_account/remote/non_transferable
+ transferable = FALSE
+
+#undef DUMPTIME
diff --git a/code/modules/economy/paystand.dm b/code/modules/economy/paystand.dm
new file mode 100644
index 0000000000..f674bc230d
--- /dev/null
+++ b/code/modules/economy/paystand.dm
@@ -0,0 +1,138 @@
+/obj/machinery/paystand
+ name = "unregistered pay stand"
+ desc = "See title."
+ icon = 'icons/obj/economy.dmi'
+ icon_state = "card_scanner"
+ density = TRUE
+ anchored = TRUE
+ var/locked = FALSE
+ var/obj/item/card/id/my_card
+ var/obj/item/assembly/signaler/signaler //attached signaler, let people attach signalers that get activated if the user's transaction limit is achieved.
+ var/signaler_threshold = 0 //signaler threshold amount
+ var/amount_deposited = 0 //keep track of the amount deposited over time so you can pay multiple times to reach the signaler threshold
+ var/force_fee = 0 //replaces the "pay whatever" functionality with a set amount when non-zero.
+
+/obj/machinery/paystand/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/card/id))
+ if(W == my_card)
+ if(user.a_intent == INTENT_DISARM)
+ var/rename_msg = stripped_input(user, "Rename the Paystand:", "Paystand Naming", name)
+ if(!rename_msg || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ return
+ name = rename_msg
+ return
+ else if(user.a_intent == INTENT_GRAB)
+ var/force_fee_input = input(user,"Set the fee!","Set a fee!",0) as num|null
+ if(isnull(force_fee_input) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ return
+ force_fee = force_fee_input
+ return
+ locked = !locked
+ to_chat(user, "You [src.locked ? "lock" : "unlock"] the paystand, protecting the bolts from [anchored ? "loosening" : "tightening"].")
+ return
+ if(!my_card)
+ var/obj/item/card/id/assistant_mains_need_to_die = W
+ if(!assistant_mains_need_to_die.registered_account)
+ return
+ var/msg = stripped_input(user, "Name of pay stand:", "Paystand Naming", "[user]'s Awesome Paystand")
+ if(!msg)
+ return
+ name = msg
+ desc = "Owned by [assistant_mains_need_to_die.registered_account.account_holder], pays directly into [user.p_their()] account."
+ my_card = assistant_mains_need_to_die
+ to_chat(user, "You link the stand to your account.")
+ return
+ var/obj/item/card/id/vbucks = W
+ if(vbucks.registered_account)
+ var/momsdebitcard = 0
+ if(!force_fee)
+ momsdebitcard = input(user, "How much would you like to deposit?", "Money Deposit") as null|num
+ else
+ momsdebitcard = force_fee
+ if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ return
+ if(momsdebitcard < 1)
+ to_chat(user, "ERROR: Invalid amount designated.")
+ return
+ if(vbucks.registered_account.adjust_money(-momsdebitcard))
+ purchase(vbucks.registered_account.account_holder, momsdebitcard)
+ to_chat(user, "Thanks for purchasing! The vendor has been informed.")
+ return
+ else
+ to_chat(user, "ERROR: Account has insufficient funds to make transaction.")
+ return
+ else
+ to_chat(user, "ERROR: No bank account assigned to identification card.")
+ return
+ if(istype(W, /obj/item/holochip))
+ var/obj/item/holochip/H = W
+ var/cashmoney = input(user, "How much would you like to deposit?", "Money Deposit") as null|num
+ if(H.spend(cashmoney, FALSE))
+ purchase(user, cashmoney)
+ to_chat(user, "Thanks for purchasing! The vendor has been informed.")
+ return
+ else
+ to_chat(user, "ERROR: Insufficient funds to make transaction.")
+ return
+ if(istype(W, /obj/item/stack/spacecash))
+ to_chat(user, "What is this, the 2000s? We only take card here.")
+ return
+ if(istype(W, /obj/item/coin))
+ to_chat(user, "What is this, the 1800s? We only take card here.")
+ return
+ if(istype(W, /obj/item/assembly/signaler))
+ var/obj/item/assembly/signaler/S = W
+ if(S.secured)
+ to_chat(user, "The signaler needs to be in attachable mode to add it to the paystand!")
+ return
+ if(!my_card)
+ to_chat(user, "ERROR: No identification card has been assigned to this paystand yet!")
+ return
+ if(!signaler)
+ var/cash_limit = input(user, "Enter the minimum amount of cash needed to deposit before the signaler is activated.", "Signaler Activation Threshold") as null|num
+ if(cash_limit < 1)
+ to_chat(user, "ERROR: Invalid amount designated.")
+ return
+ if(cash_limit)
+ S.forceMove(src)
+ signaler = S
+ signaler_threshold = cash_limit
+ to_chat(user, "You attach the signaler to the paystand.")
+ desc += " A signaler appears to be attached to the scanner."
+ else
+ to_chat(user, "A signaler is already attached to this unit!")
+
+ if(default_deconstruction_screwdriver(user, "card_scanner", "card_scanner", W))
+ return
+
+ else if(default_pry_open(W))
+ return
+
+ else if(default_unfasten_wrench(user, W))
+ return
+
+ else if(default_deconstruction_crowbar(W))
+ return
+ else
+ return ..()
+
+/obj/machinery/paystand/proc/purchase(buyer, price)
+ my_card.registered_account.adjust_money(price)
+ my_card.registered_account.bank_card_talk("Purchase made at your vendor by [buyer] for [price] credits.")
+ amount_deposited = amount_deposited + price
+ if(signaler && amount_deposited >= signaler_threshold)
+ signaler.activate()
+ amount_deposited = 0
+
+/obj/machinery/paystand/default_unfasten_wrench(mob/user, obj/item/I, time = 20)
+ if(locked)
+ to_chat(user, "The bolts on this paystand are currently covered!")
+ return FALSE
+ . = ..()
+
+/obj/machinery/paystand/examine(mob/user)
+ . = ..()
+ if(force_fee)
+ . += "This paystand forces a payment of [force_fee] credit\s per swipe instead of a variable amount."
+ if(user.get_active_held_item() == my_card)
+ . += "Paystands can be edited through swiping your card with different intents. Disarm allows editing the name while Grab changes payment functionality."
diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm
index 86ff1ed0da..0198dd445e 100644
--- a/code/modules/events/pirates.dm
+++ b/code/modules/events/pirates.dm
@@ -29,7 +29,9 @@
if(fake)
return
threat_message = new
- payoff = round(SSshuttle.points * 0.80)
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ payoff = round(D.account_balance * 0.80)
threat_message.title = "Business proposition"
threat_message.content = "This is [ship_name]. Pay up [payoff] credits or you'll walk the plank."
threat_message.possible_answers = list("We'll pay.","No way.")
@@ -38,13 +40,14 @@
/datum/round_event/pirates/proc/answered()
if(threat_message && threat_message.answered == 1)
- if(SSshuttle.points >= payoff)
- SSshuttle.points -= payoff
- priority_announce("Thanks for the credits, landlubbers.",sender_override = ship_name)
- paid_off = TRUE
- return
- else
- priority_announce("Trying to cheat us? You'll regret this!",sender_override = ship_name)
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ if(D.adjust_money(-payoff))
+ priority_announce("Thanks for the credits, landlubbers.",sender_override = ship_name)
+ paid_off = TRUE
+ return
+ else
+ priority_announce("Trying to cheat us? You'll regret this!",sender_override = ship_name)
if(!shuttle_spawned)
spawn_shuttle()
@@ -101,9 +104,10 @@
/obj/machinery/shuttle_scrambler/process()
if(active)
if(is_station_level(z))
- var/siphoned = min(SSshuttle.points,siphon_per_tick)
- SSshuttle.points -= siphoned
- credits_stored += siphoned
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ var/siphoned = min(D.account_balance,siphon_per_tick)
+ D.adjust_money(-siphoned)
interrupt_research()
else
return
@@ -139,12 +143,7 @@
new /obj/effect/temp_visual/emp(get_turf(S))
/obj/machinery/shuttle_scrambler/proc/dump_loot(mob/user)
- if(credits_stored < 200)
- to_chat(user,"Not enough credits to retrieve.")
- return
- while(credits_stored >= 200)
- new /obj/item/stack/spacecash/c200(drop_location())
- credits_stored -= 200
+ new /obj/item/holochip(drop_location(), credits_stored)
to_chat(user,"You retrieve the siphoned credits!")
credits_stored = 0
@@ -456,3 +455,12 @@
/datum/export/pirate/cash/get_amount(obj/O)
var/obj/item/stack/spacecash/C = O
return ..() * C.amount * C.value
+
+/datum/export/pirate/holochip
+ cost = 1
+ unit_name = "holochip"
+ export_types = list(/obj/item/holochip)
+
+/datum/export/pirate/holochip/get_cost(atom/movable/AM)
+ var/obj/item/holochip/H = AM
+ return H.credits
diff --git a/code/modules/events/shuttle_loan.dm b/code/modules/events/shuttle_loan.dm
index c585961604..bf9f25cb04 100644
--- a/code/modules/events/shuttle_loan.dm
+++ b/code/modules/events/shuttle_loan.dm
@@ -69,7 +69,9 @@
priority_announce(thanks_msg, "Cargo shuttle commandeered by CentCom.")
dispatched = 1
- SSshuttle.points += bonus_points
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ if(D)
+ D.adjust_money(bonus_points)
endWhen = activeFor + 1
SSshuttle.supply.mode = SHUTTLE_CALL
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 1592efb032..46600e9fee 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -147,7 +147,7 @@
return
if (!(locate(/obj/structure/table) in src_location) || !(locate(/obj/structure/table) in over_location))
return
-
+
//Are we an expert slider?
var/datum/action/innate/D = get_action_of_type(user, /datum/action/innate/drink_fling)
if(!D?.active)
@@ -268,6 +268,7 @@
/obj/item/reagent_containers/food/drinks/ice
name = "ice cup"
desc = "Careful, cold ice, do not chew."
+ custom_price = 15
icon_state = "coffee"
list_reagents = list(/datum/reagent/consumable/ice = 30)
spillable = TRUE
@@ -281,7 +282,7 @@
spillable = TRUE
/obj/item/reagent_containers/food/drinks/mug/on_reagent_change(changetype)
- cut_overlays()
+ cut_overlays()
if(reagents.total_volume)
var/mutable_appearance/MA = mutable_appearance(icon,"mugoverlay")
MA.color = mix_color_from_reagents(reagents.reagent_list)
@@ -302,6 +303,7 @@
list_reagents = list(/datum/reagent/consumable/hot_coco = 30, /datum/reagent/consumable/sugar = 5)
foodtype = SUGAR
resistance_flags = FREEZE_PROOF
+ custom_price = 120
/obj/item/reagent_containers/food/drinks/dry_ramen
name = "cup ramen"
@@ -310,6 +312,7 @@
list_reagents = list(/datum/reagent/consumable/dry_ramen = 30)
foodtype = GRAIN
isGlass = FALSE
+ custom_price = 95
/obj/item/reagent_containers/food/drinks/beer
name = "space beer"
@@ -317,6 +320,7 @@
icon_state = "beer"
list_reagents = list(/datum/reagent/consumable/ethanol/beer = 30)
foodtype = GRAIN | ALCOHOL
+ custom_price = 60
/obj/item/reagent_containers/food/drinks/beer/light
name = "Carp Lite"
@@ -417,6 +421,7 @@
custom_materials = list(/datum/material/iron=250)
volume = 60
isGlass = FALSE
+ custom_price = 200
/obj/item/reagent_containers/food/drinks/flask/gold
name = "captain's flask"
@@ -447,6 +452,7 @@
reagent_flags = NONE
spillable = FALSE
isGlass = FALSE
+ custom_price = 45
/obj/item/reagent_containers/food/drinks/soda_cans/suicide_act(mob/living/carbon/user)
user.visible_message("[user] is trying to eat \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 95b9f92873..21c3af442e 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -254,6 +254,7 @@
var/shortname = pickweight(
list("T&T" = 1, "A&A" = 1, "Generic" = 1))
var/fullname
+ var/removals = GLOB.redacted_strings.Copy()
switch(shortname)
if("T&T")
fullname = "Teal and Tealer"
@@ -261,9 +262,6 @@
fullname = "Ash and Asher"
if("Generic")
fullname = "Nanotrasen Cheap Imitations"
- var/removals = list("\[REDACTED\]", "\[EXPLETIVE DELETED\]",
- "\[EXPUNGED\]", "\[INFORMATION ABOVE YOUR SECURITY CLEARANCE\]",
- "\[MOVE ALONG CITIZEN\]", "\[NOTHING TO SEE HERE\]")
var/chance = 50
if(prob(chance))
@@ -348,6 +346,7 @@
/obj/item/reagent_containers/food/drinks/bottle/applejack
name = "Buckin' Bronco's Applejack"
desc = "Kicks like a horse, tastes like an apple!"
+ custom_price = 100
icon_state = "applejack_bottle"
list_reagents = list(/datum/reagent/consumable/ethanol/applejack = 100)
foodtype = FRUIT
@@ -358,6 +357,7 @@
/obj/item/reagent_containers/food/drinks/bottle/champagne
name = "Eau d' Dandy Brut Champagne"
desc = "Finely sourced from only the most pretentious French vineyards."
+ custom_premium_price = 250
icon_state = "champagne_bottle"
list_reagents = list(/datum/reagent/consumable/ethanol/champagne = 100)
@@ -376,6 +376,7 @@
/obj/item/reagent_containers/food/drinks/bottle/trappist
name = "Mont de Requin Trappistes Bleu"
desc = "Brewed in space-Belgium. Fancy!"
+ custom_premium_price = 170
icon_state = "trappistbottle"
volume = 50
list_reagents = list(/datum/reagent/consumable/ethanol/trappist = 50)
@@ -388,6 +389,7 @@
/obj/item/reagent_containers/food/drinks/bottle/orangejuice
name = "orange juice"
desc = "Full of vitamins and deliciousness!"
+ custom_price = 100
icon_state = "orangejuice"
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
@@ -399,6 +401,7 @@
/obj/item/reagent_containers/food/drinks/bottle/cream
name = "milk cream"
desc = "It's cream. Made from milk. What else did you think you'd find in there?"
+ custom_price = 100
icon_state = "cream"
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
@@ -410,6 +413,7 @@
/obj/item/reagent_containers/food/drinks/bottle/tomatojuice
name = "tomato juice"
desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness."
+ custom_price = 100
icon_state = "tomatojuice"
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
@@ -421,6 +425,7 @@
/obj/item/reagent_containers/food/drinks/bottle/limejuice
name = "lime juice"
desc = "Sweet-sour goodness."
+ custom_price = 100
icon_state = "limejuice"
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
@@ -454,6 +459,7 @@
/obj/item/reagent_containers/food/drinks/bottle/menthol
name = "menthol"
desc = "Tastes naturally minty, and imparts a very mild numbing sensation."
+ custom_price = 100
icon_state = "mentholbox"
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
@@ -464,6 +470,7 @@
/obj/item/reagent_containers/food/drinks/bottle/grenadine
name = "Jester Grenadine"
desc = "Contains 0% real cherries!"
+ custom_price = 100
icon_state = "grenadine"
isGlass = TRUE
list_reagents = list(/datum/reagent/consumable/grenadine = 100)
diff --git a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
index defc44ed51..5ebcec91b9 100644
--- a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
@@ -11,6 +11,7 @@
spillable = TRUE
resistance_flags = ACID_PROOF
obj_flags = UNIQUE_RENAME
+ custom_price = 25
/obj/item/reagent_containers/food/drinks/drinkingglass/on_reagent_change(changetype)
cut_overlays()
@@ -46,6 +47,7 @@
possible_transfer_amounts = list()
volume = 15
custom_materials = list(/datum/material/glass=100)
+ custom_price = 20
/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(changetype)
cut_overlays()
diff --git a/code/modules/food_and_drinks/food/snacks_vend.dm b/code/modules/food_and_drinks/food/snacks_vend.dm
index 239dd433b0..a4d924bae4 100644
--- a/code/modules/food_and_drinks/food/snacks_vend.dm
+++ b/code/modules/food_and_drinks/food/snacks_vend.dm
@@ -41,6 +41,7 @@
filling_color = "#FFD700"
tastes = list("salt" = 1, "crisps" = 1)
foodtype = JUNKFOOD | FRIED
+ custom_price = 90
/obj/item/reagent_containers/food/snacks/no_raisin
name = "4no raisins"
@@ -68,6 +69,7 @@
junkiness = 25
filling_color = "#FFD700"
foodtype = JUNKFOOD | GRAIN | SUGAR
+ custom_price = 30
/obj/item/reagent_containers/food/snacks/cheesiehonkers
name = "cheesie honkers"
@@ -79,6 +81,7 @@
filling_color = "#FFD700"
tastes = list("cheese" = 5, "crisps" = 2)
foodtype = JUNKFOOD | DAIRY | SUGAR
+ custom_price = 45
/obj/item/reagent_containers/food/snacks/syndicake
name = "syndi-cakes"
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index ee441c21f7..88a953e310 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -56,6 +56,9 @@
//can be overridden by antag_rep.txt config
var/antag_rep = 10
+ var/paycheck = PAYCHECK_MINIMAL
+ var/paycheck_department = ACCOUNT_CIV
+
var/list/mind_traits // Traits added to the mind of the mob assigned this job
var/list/blacklisted_quirks //list of quirk typepaths blacklisted.
@@ -99,7 +102,13 @@
/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source)
if(!H)
return FALSE
-
+ if(!visualsOnly)
+ var/datum/bank_account/bank_account = new(H.real_name, src)
+ bank_account.account_holder = H.real_name
+ bank_account.account_job = src
+ bank_account.account_id = rand(111111,999999)
+ bank_account.payday(STARTING_PAYCHECKS, TRUE)
+ H.account_id = bank_account.account_id
if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions))
if(H.dna.species.id != "human")
H.set_species(/datum/species/human)
@@ -227,12 +236,18 @@
H.real_name = "[J.title] #[rand(10000, 99999)]"
var/obj/item/card/id/C = H.wear_id
- if(istype(C))
+ if(istype(C) && C.bank_support)
C.access = J.get_access()
shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable
C.registered_name = H.real_name
C.assignment = J.title
C.update_label()
+ for(var/A in SSeconomy.bank_accounts)
+ var/datum/bank_account/B = A
+ if(B.account_id == H.account_id)
+ C.registered_account = B
+ B.bank_cards += C
+ break
H.sec_hud_set_ID()
var/obj/item/pda/PDA = H.get_item_by_slot(pda_slot)
diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm
index c4fa213b61..91b3a3f581 100644
--- a/code/modules/jobs/job_types/assistant.dm
+++ b/code/modules/jobs/job_types/assistant.dm
@@ -14,6 +14,8 @@ Assistant
minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
antag_rep = 7
+ paycheck = PAYCHECK_ASSISTANT // Get a job. Job reassignment changes your paycheck now. Get over it.
+ paycheck_department = ACCOUNT_CIV
display_order = JOB_DISPLAY_ORDER_ASSISTANT
dresscodecompliant = FALSE
threat = 0.2
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index 019e50799e..0934507721 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -17,6 +17,8 @@
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ENGINE,
ACCESS_ENGINE_EQUIP, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_ENG
display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN
threat = 0.5
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index 709c53d51d..e5cd015460 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -14,6 +14,8 @@
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_BARTENDER
threat = 0.5
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
index 4cf106ea99..65f3e7ca48 100644
--- a/code/modules/jobs/job_types/botanist.dm
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_BOTANIST
threat = 1.5 // lol powergame
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index d38a2a3ddf..3733658c33 100644
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -15,11 +15,15 @@
exp_type = EXP_TYPE_COMMAND
exp_type_department = EXP_TYPE_COMMAND
+
outfit = /datum/outfit/job/captain
access = list() //See get_access()
minimal_access = list() //See get_access()
+ paycheck = PAYCHECK_COMMAND
+ paycheck_department = ACCOUNT_SEC
+
mind_traits = list(TRAIT_CAPTAIN_METABOLISM, TRAIT_DISK_VERIFIER)
display_order = JOB_DISPLAY_ORDER_CAPTAIN
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
index d574482444..840af56a0e 100644
--- a/code/modules/jobs/job_types/cargo_technician.dm
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -14,6 +14,8 @@
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MINING,
ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_CAR
display_order = JOB_DISPLAY_ORDER_CARGO_TECHNICIAN
threat = 0.2
diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm
index cf9c5a6a3c..5f66519365 100644
--- a/code/modules/jobs/job_types/chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_CIV
display_order = JOB_DISPLAY_ORDER_CHAPLAIN
threat = 0.5
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index 44b0e90ec8..9ffabd6a06 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -15,6 +15,8 @@
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_MED
display_order = JOB_DISPLAY_ORDER_CHEMIST
threat = 1.5
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index 0d70e872ac..b16b6ffa44 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -26,6 +26,8 @@
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA,
ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_COMMAND
+ paycheck_department = ACCOUNT_ENG
display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index 8dd7fafab3..ce072d4641 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -24,6 +24,8 @@
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS)
+ paycheck = PAYCHECK_COMMAND
+ paycheck_department = ACCOUNT_MED
display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index c65c062bce..7ad7148614 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_THEATRE)
minimal_access = list(ACCESS_THEATRE)
+ paycheck = PAYCHECK_MINIMAL
+ paycheck_department = ACCOUNT_SRV
mind_traits = list(TRAIT_CLOWN_MENTALITY)
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index 20969bf1d9..5a5916cb7e 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -14,6 +14,8 @@
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_COOK
threat = 0.2
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index d73d909f4f..4c588901c4 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_LIBRARY)
minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_CIV
display_order = JOB_DISPLAY_ORDER_CURATOR
threat = 0.3
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index 55c13df7a2..e5afe7e1b3 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -17,6 +17,8 @@
access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_SEC
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index 2e8b18d772..6ab0f46c63 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -15,6 +15,8 @@
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_MED
display_order = JOB_DISPLAY_ORDER_GENETICIST
threat = 1.5
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index b1fe3471f1..8015c19c36 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -30,6 +30,8 @@
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_HYDROPONICS, ACCESS_LAWYER,
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_COMMAND
+ paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index 3cf4fbb102..69ed63a514 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -27,6 +27,8 @@
ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_COMMAND
+ paycheck_department = ACCOUNT_SEC
display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/insanity)
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
index 73028255be..2f6d6f0e32 100644
--- a/code/modules/jobs/job_types/janitor.dm
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_JANITOR
threat = 0.2
diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm
index 3f80e44492..1a7499800b 100644
--- a/code/modules/jobs/job_types/lawyer.dm
+++ b/code/modules/jobs/job_types/lawyer.dm
@@ -14,6 +14,8 @@
access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
+ paycheck = PAYCHECK_EASY
+ paycheck_department = ACCOUNT_CIV
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index 3eaa2ae10a..89a766762c 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_MED
display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR
threat = 0.5
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index 72a6ac8e13..4ba2489ab2 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -13,6 +13,8 @@
access = list(ACCESS_THEATRE)
minimal_access = list(ACCESS_THEATRE)
+ paycheck = PAYCHECK_MINIMAL
+ paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_MIME
diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm
index df6e1431ae..a9703e3f9e 100644
--- a/code/modules/jobs/job_types/paramedic.dm
+++ b/code/modules/jobs/job_types/paramedic.dm
@@ -14,6 +14,8 @@
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM, ACCESS_MAINT_TUNNELS)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM, ACCESS_MAINT_TUNNELS)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_MED
display_order = JOB_DISPLAY_ORDER_PARAMEDIC
diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm
index 897defb0ea..4c6b8e064f 100644
--- a/code/modules/jobs/job_types/quartermaster.dm
+++ b/code/modules/jobs/job_types/quartermaster.dm
@@ -24,6 +24,8 @@
minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING,
ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_KEYCARD_AUTH, ACCESS_RC_ANNOUNCE,
ACCESS_SEC_DOORS, ACCESS_HEADS)
+ paycheck = PAYCHECK_HARD //They can already buy stuff using cargo budget, don't give em a command-level paycheck.
+ paycheck_department = ACCOUNT_CAR
display_order = JOB_DISPLAY_ORDER_QUARTERMASTER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index 15e5c64654..7128fbe2c7 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -28,6 +28,8 @@
ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK)
+ paycheck = PAYCHECK_COMMAND
+ paycheck_department = ACCOUNT_SCI
display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index f9f1d20d3b..d77b2120a2 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -15,6 +15,8 @@
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS)
minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_SCI
display_order = JOB_DISPLAY_ORDER_ROBOTICIST
threat = 1
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index 9809e7b4dc..476f740b9d 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -15,6 +15,8 @@
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS)
minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_SCI
display_order = JOB_DISPLAY_ORDER_SCIENTIST
threat = 1.2
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index decb334423..bc6f6a94c7 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -17,6 +17,8 @@
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access()
+ paycheck = PAYCHECK_HARD
+ paycheck_department = ACCOUNT_SEC
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index 9eb268895e..a09c4376fb 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -16,6 +16,8 @@
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MINING,
ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_HARD
+ paycheck_department = ACCOUNT_CAR
display_order = JOB_DISPLAY_ORDER_SHAFT_MINER
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index 66ddc90e9b..83a175f240 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -17,6 +17,8 @@
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_ENG
display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 4ba65dff59..c965341054 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -15,6 +15,8 @@
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
+ paycheck = PAYCHECK_MEDIUM
+ paycheck_department = ACCOUNT_MED
display_order = JOB_DISPLAY_ORDER_VIROLOGIST
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index 15d839ac48..5762731f62 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -18,6 +18,9 @@
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access()
+ paycheck = PAYCHECK_HARD
+ paycheck_department = ACCOUNT_SEC
+
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
display_order = JOB_DISPLAY_ORDER_WARDEN
diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm
index 3e361179de..30bb74a927 100644
--- a/code/modules/mapping/map_template.dm
+++ b/code/modules/mapping/map_template.dm
@@ -55,11 +55,11 @@
SSmachines.setup_template_powernets(cables)
SSair.setup_template_machinery(atmos_machines)
-/datum/map_template/proc/load_new_z()
+/datum/map_template/proc/load_new_z(list/traits = list(ZTRAIT_AWAY = TRUE))
var/x = round((world.maxx - width)/2)
var/y = round((world.maxy - height)/2)
- var/datum/space_level/level = SSmapping.add_new_zlevel(name, list(ZTRAIT_AWAY = TRUE))
+ var/datum/space_level/level = SSmapping.add_new_zlevel(name, traits)
var/datum/parsed_map/parsed = load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=TRUE)
var/list/bounds = parsed.bounds
if(!bounds)
@@ -121,6 +121,6 @@
//for your ever biggening badminnery kevinz000
//❤ - Cyberboss
-/proc/load_new_z_level(var/file, var/name)
+/proc/load_new_z_level(file, name, list/traits = list(ZTRAIT_AWAY = TRUE))
var/datum/map_template/template = new(file, name)
- template.load_new_z()
+ template.load_new_z(traits)
diff --git a/code/modules/mining/money_bag.dm b/code/modules/mining/money_bag.dm
index fd5997d3c4..66f99ec40c 100644
--- a/code/modules/mining/money_bag.dm
+++ b/code/modules/mining/money_bag.dm
@@ -15,7 +15,7 @@
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_items = 40
STR.max_combined_w_class = 40
- STR.can_hold = typecacheof(list(/obj/item/coin, /obj/item/stack/spacecash))
+ STR.can_hold = typecacheof(list(/obj/item/coin, /obj/item/stack/spacecash, /obj/item/holochip))
/obj/item/storage/bag/money/vault/PopulateContents()
new /obj/item/coin/silver(src)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 68c312b19c..b9e787b7d5 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -11,7 +11,7 @@
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
-
+
//Hair colour and style
var/hair_color = "000"
var/hair_style = "Bald"
@@ -72,4 +72,5 @@
var/creamed = FALSE //to use with creampie overlays
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot))
var/lastpuke = 0
+ var/account_id
var/last_fire_update
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 7b3953e40e..7c256f5367 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -127,6 +127,17 @@
to_chat(src, "Your fingers don't fit in the trigger guard!")
return FALSE
+/mob/living/carbon/human/proc/get_bank_account()
+ RETURN_TYPE(/datum/bank_account)
+ var/datum/bank_account/account
+ var/obj/item/card/id/I = get_idcard()
+
+ if(I && I.registered_account)
+ account = I.registered_account
+ return account
+
+ return FALSE
+
/mob/living/carbon/human/can_see_reagents()
. = ..()
if(.) //No need to run through all of this if it's already true.
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index d3e7d7c395..473a7d4c98 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -698,9 +698,9 @@
/obj/item/toy/crayon/spraycan/borg,
/obj/item/hand_labeler/borg,
/obj/item/razor,
+ /obj/item/rsf,
/obj/item/instrument/violin,
/obj/item/instrument/guitar,
- /obj/item/rsf/cyborg,
/obj/item/reagent_containers/dropper,
/obj/item/lighter,
/obj/item/storage/bag/tray,
diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm
index 285463bc0f..76463c6867 100644
--- a/code/modules/modular_computers/hardware/hard_drive.dm
+++ b/code/modules/modular_computers/hardware/hard_drive.dm
@@ -157,6 +157,7 @@
max_capacity = 64
icon_state = "ssd_mini"
w_class = WEIGHT_CLASS_TINY
+ custom_price = 150
/obj/item/computer_hardware/hard_drive/small/syndicate // Syndicate variant - very slight better
desc = "An efficient SSD for portable devices developed by a rival organisation."
diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm
index 2bed456c41..9e0e1c8014 100644
--- a/code/modules/modular_computers/laptop_vendor.dm
+++ b/code/modules/modular_computers/laptop_vendor.dm
@@ -244,12 +244,12 @@
visible_message("[user] inserts [c.value] credits into [src].")
qdel(c)
return
- /*else if(istype(I, /obj/item/holochip))
+ else if(istype(I, /obj/item/holochip))
var/obj/item/holochip/HC = I
credits += HC.credits
- visible_message("[user] inserts a $[HC.credits] holocredit chip into [src].")
+ visible_message("[user] inserts a [HC.credits] cr holocredit chip into [src].")
qdel(HC)
- return
+ return
else if(istype(I, /obj/item/card/id))
if(state != 2)
return
@@ -260,8 +260,8 @@
say("Insufficient money on card to purchase!")
return
credits += target_credits
- say("$[target_credits] has been desposited from your account.")
- return */ //Goonconomy when
+ say("[target_credits] cr has been desposited from your account.")
+ return
return ..()
// Simplified payment processing, returns 1 on success.
diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm
index b7b7bc36b7..0090856d83 100644
--- a/code/modules/photography/camera/camera.dm
+++ b/code/modules/photography/camera/camera.dm
@@ -15,6 +15,7 @@
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_NECK
custom_materials = list(/datum/material/iron = 50, /datum/material/glass = 150)
+ custom_price = 120
var/flash_enabled = TRUE
var/state_on = "camera"
var/state_off = "camera_off"
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 1b23b1bb5d..d29b0b62fd 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -1350,7 +1350,7 @@
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
area.poweralert(0, src)
-
+
else if(cell_percent < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 2)
@@ -1579,4 +1579,5 @@
/obj/item/electronics/apc
name = "power control module"
icon_state = "power_mod"
+ custom_price = 50
desc = "Heavy-duty switching circuits for power control."
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 49848824e4..4eac585999 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -472,6 +472,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/item/stack/cable_coil
name = "cable coil"
+ custom_price = 75
gender = NEUTER //That's a cable coil sounds better than that's some cable coils
icon = 'icons/obj/power.dmi'
icon_state = "coil"
@@ -566,7 +567,7 @@ By design, d1 is the smallest direction and d2 is the highest
return
var/obj/item/restraints/handcuffs/cable/result = new(get_turf(user))
user.put_in_hands(result)
- result.color = color
+ result.color = color
to_chat(user, "You make some restraints out of cable")
//add cables to the stack
@@ -849,4 +850,4 @@ By design, d1 is the smallest direction and d2 is the highest
. = ..()
var/list/cable_colors = GLOB.cable_colors
color = pick(cable_colors)
-
+
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index 2e6ec57f77..f5a841ab42 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -62,7 +62,11 @@
loaded_tank.air_contents.gases[/datum/gas/oxygen] -= gasdrained
loaded_tank.air_contents.gases[/datum/gas/carbon_dioxide] += gasdrained*2
GAS_GARBAGE_COLLECT(loaded_tank.air_contents.gases)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, stored_power*RAD_COLLECTOR_MINING_CONVERSION_RATE)
+ var/bitcoins_mined = stored_power*RAD_COLLECTOR_MINING_CONVERSION_RATE
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG)
+ if(D)
+ D.adjust_money(bitcoins_mined)
+ SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, bitcoins_mined)
last_push = stored_power
stored_power = 0
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index e29ffa865e..64d317b385 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -83,6 +83,9 @@
flick("coilhit", src)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 5, power_produced, tesla_flags, shocked_targets)
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG)
+ if(D)
+ D.adjust_money(min(power_produced, 1))
if(istype(linked_techweb))
linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min(power_produced, 1)) // x4 coils = ~240/m point bonus for R&D
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
@@ -118,6 +121,9 @@
flick("rpcoilhit", src)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 5, power_produced, tesla_flags, shocked_things)
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG)
+ if(D)
+ D.adjust_money(min(power_produced, 3))
if(istype(linked_techweb))
linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min(power_produced, 3)) // x4 coils with a pulse per second or so = ~720/m point bonus for R&D
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 846637850b..b4c570dfc6 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -7,6 +7,7 @@
possible_transfer_amounts = list(1, 2, 3, 4, 5)
volume = 5
reagent_flags = TRANSPARENT
+ custom_price = 75
/obj/item/reagent_containers/dropper/afterattack(obj/target, mob/user , proximity)
. = ..()
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 800d66969d..ab58510482 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -362,6 +362,7 @@
icon = 'icons/obj/drinks.dmi'
icon_state = "smallbottle"
item_state = "bottle"
+ custom_price = 30
list_reagents = list(/datum/reagent/water = 49.5, /datum/reagent/fluorine = 0.5)//see desc, don't think about it too hard
custom_materials = list(/datum/material/glass=0)
volume = 50
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index 9555f5b64b..06db1d46ab 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -96,6 +96,8 @@
reagent_flags = DRAWABLE
flags_1 = null
list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/preservahyde = 3)
+ custom_price = 150
+ custom_premium_price = 300
/obj/item/reagent_containers/hypospray/medipen/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins to choke on \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index b8957775b1..fc4a95e58d 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -15,6 +15,7 @@
var/show_filling = TRUE
custom_materials = list(/datum/material/iron=10, /datum/material/glass=20)
reagent_flags = TRANSPARENT
+ custom_price = 150
/obj/item/reagent_containers/syringe/Initialize()
. = ..()
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm
index 30cd56c66a..eebeec2c78 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_tcomms_and_misc.dm
@@ -256,3 +256,19 @@
materials = list(/datum/material/iron = 300, /datum/material/glass = 150)
build_path = /obj/item/key/collar
category = list("initial", "Misc")
+
+/datum/design/price_tagger
+ name = "Price Tagger"
+ id = "price_tagger"
+ build_type = AUTOLATHE
+ materials = list(/datum/material/iron = 1500, /datum/material/glass = 500)
+ build_path = /obj/item/price_tagger
+ category = list("initial", "Misc")
+
+/datum/design/custom_vendor_refill
+ name = "Custom Vendor Refill"
+ id = "custom_vendor_refill"
+ build_type = AUTOLATHE
+ materials = list(/datum/material/iron = 5000, /datum/material/glass = 2000)
+ build_path = /obj/item/vending_refill/custom
+ category = list("initial", "Misc")
\ No newline at end of file
diff --git a/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm b/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm
index 6d63df7d4b..21c39ff0e0 100644
--- a/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm
+++ b/code/modules/research/designs/machine_desings/machine_designs_all_misc.dm
@@ -107,6 +107,14 @@
departmental_flags = DEPARTMENTAL_FLAG_ALL
category = list ("Medical Machinery")
+/datum/design/board/paystand
+ name = "Machine Design (Pay Stand)"
+ desc = "The circuit board for a paystand."
+ id = "paystand"
+ build_path = /obj/item/circuitboard/machine/paystand
+ category = list ("Misc. Machinery")
+ departmental_flags = DEPARTMENTAL_FLAG_ALL
+
/datum/design/board/autoylathe
name = "Machine Design (Autoylathe)"
desc = "The circuit board for an autoylathe."
diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm
index 388fa3785c..a505fefb91 100644
--- a/code/modules/research/techweb/_techweb.dm
+++ b/code/modules/research/techweb/_techweb.dm
@@ -199,6 +199,10 @@
researched_designs -= design.id
return TRUE
+/datum/techweb/proc/get_point_total(list/pointlist)
+ for(var/i in pointlist)
+ . += pointlist[i]
+
/datum/techweb/proc/can_afford(list/pointlist)
for(var/i in pointlist)
if(research_points[i] < pointlist[i])
@@ -227,6 +231,10 @@
for(var/id in node.design_ids)
add_design_by_id(id)
update_node_status(node)
+ if(!istype(src, /datum/techweb/admin))
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SCI)
+ if(D)
+ D.adjust_money(SSeconomy.techweb_bounty)
return TRUE
/datum/techweb/proc/unresearch_node_id(id)
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index dafa119873..fd58dbd308 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -9,7 +9,7 @@
description = "NT default research technologies."
// Default research tech, prevents bricking
design_ids = list("basic_matter_bin", "basic_cell", "basic_scanning", "basic_capacitor", "basic_micro_laser", "micro_mani", "desttagger", "handlabel", "packagewrap",
- "destructive_analyzer", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab",
+ "destructive_analyzer", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab", "paystand",
"space_heater", "beaker", "large_beaker", "bucket", "xlarge_beaker", "sec_beanbag", "sec_rshot", "sec_bshot", "sec_slug", "sec_Islug", "sec_dart", "sec_38", "sec_38lethal",
"rglass","plasteel","plastitanium","plasmaglass","plasmareinforcedglass","titaniumglass","plastitaniumglass")
diff --git a/code/modules/ruins/spaceruin_code/listeningstation.dm b/code/modules/ruins/spaceruin_code/listeningstation.dm
index 8efeaaabff..e48a1c45d5 100644
--- a/code/modules/ruins/spaceruin_code/listeningstation.dm
+++ b/code/modules/ruins/spaceruin_code/listeningstation.dm
@@ -32,7 +32,7 @@
/obj/item/paper/fluff/ruins/listeningstation/receipt
name = "receipt"
- info = "1 x Stechkin pistol - $600
1 x silencer - $200
shipping charge - $4360
total - $5160"
+ info = "1 x Stechkin pistol - 600 cr
1 x silencer - 200 cr
shipping charge - 4360 cr
total - 5160 cr"
/obj/item/paper/fluff/ruins/listeningstation/odd_report
name = "odd report"
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index bdf6e8cc87..a4ef2dfde9 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -109,30 +109,46 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
continue
empty_turfs += T
+ var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/value = 0
var/purchases = 0
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
if(!empty_turfs.len)
break
- if(SO.pack.cost > SSshuttle.points)
- continue
- SSshuttle.points -= SO.pack.cost
+ var/price = SO.pack.cost
+ var/datum/bank_account/D
+ if(SO.paying_account) //Someone paid out of pocket
+ D = SO.paying_account
+ price *= 1.1 //TODO make this customizable by the quartermaster
+ else
+ D = cargo_budget
+ if(D)
+ if(!D.adjust_money(-SO.pack.cost))
+ if(SO.paying_account)
+ D.bank_card_talk("Cargo order #[SO.id] rejected due to lack of funds. Credits required: [price]")
+ continue
+
+ if(SO.paying_account)
+ D.bank_card_talk("Cargo order #[SO.id] has shipped. [price] credits have been charged to your bank account.")
+ var/datum/bank_account/department/cargo = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ cargo.adjust_money(price - SO.pack.cost) //Cargo gets the handling fee
value += SO.pack.cost
SSshuttle.shoppinglist -= SO
SSshuttle.orderhistory += SO
SO.generate(pick_n_take(empty_turfs))
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
- investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]) has shipped.", INVESTIGATE_CARGO)
+ investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]), paid by [D.account_holder] has shipped.", INVESTIGATE_CARGO)
if(SO.pack.dangerous)
- message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)] has shipped.")
+ message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)], paid by [D.account_holder] has shipped.")
purchases++
- investigate_log("[purchases] orders in this shipment, worth [value] credits. [SSshuttle.points] credits left.", INVESTIGATE_CARGO)
+ investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO)
/obj/docking_port/mobile/supply/proc/sell()
- var/presale_points = SSshuttle.points
+ var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
+ var/gain = 0
if(!GLOB.exports_list.len) // No exports list? Generate it!
setupExports()
@@ -164,14 +180,15 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
continue
msg += export_text + "\n"
- SSshuttle.points += ex.total_value[E]
+ gain += ex.total_value[E]
for(var/chem in ex.reagents_value)
var/value = ex.reagents_value[chem]
msg += "[value > 0 ? "+" : ""][value] credits: received [ex.reagents_volume[chem]]u of [chem].\n"
- SSshuttle.points += value
+ gain += value
+ D.adjust_money(gain)
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
SSshuttle.centcom_message = msg
- investigate_log("Shuttle contents sold for [SSshuttle.points - presale_points] credits. Contents: [ex.exported_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
+ investigate_log("Shuttle contents sold for [gain] credits. Contents: [ex.exported_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
diff --git a/code/modules/spells/spell_types/devil_boons.dm b/code/modules/spells/spell_types/devil_boons.dm
index ab3e3cc27e..8ba106d77b 100644
--- a/code/modules/spells/spell_types/devil_boons.dm
+++ b/code/modules/spells/spell_types/devil_boons.dm
@@ -16,14 +16,14 @@
for(var/mob/living/carbon/C in targets)
if(user.dropItemToGround(user.get_active_held_item()))
var/obj/item = pick(
- new /obj/item/coin/gold(user.loc),
- new /obj/item/coin/diamond(user.loc),
- new /obj/item/coin/silver(user.loc),
- new /obj/item/clothing/accessory/medal/gold(user.loc),
- new /obj/item/stack/sheet/mineral/gold(user.loc),
- new /obj/item/stack/sheet/mineral/silver(user.loc),
- new /obj/item/stack/sheet/mineral/diamond(user.loc),
- new /obj/item/stack/spacecash/c1000(user.loc))
+ new /obj/item/coin/gold(user.drop_location()),
+ new /obj/item/coin/diamond(user.drop_location()),
+ new /obj/item/coin/silver(user.drop_location()),
+ new /obj/item/clothing/accessory/medal/gold(user.drop_location()),
+ new /obj/item/stack/sheet/mineral/gold(user.drop_location()),
+ new /obj/item/stack/sheet/mineral/silver(user.drop_location()),
+ new /obj/item/stack/sheet/mineral/diamond(user.drop_location()),
+ new /obj/item/holochip(user.drop_location(), 1000))
C.put_in_hands(item)
/obj/effect/proc_holder/spell/targeted/view_range
diff --git a/code/modules/uplink/uplink_items/uplink_badass.dm b/code/modules/uplink/uplink_items/uplink_badass.dm
index 681efea5b3..0be2071ba5 100644
--- a/code/modules/uplink/uplink_items/uplink_badass.dm
+++ b/code/modules/uplink/uplink_items/uplink_badass.dm
@@ -58,6 +58,7 @@
manufactured to pack a little bit more of a punch if your client needs some convincing."
item = /obj/item/storage/secure/briefcase/syndie
cost = 1
+ restricted = TRUE
/datum/uplink_item/badass/syndiecards
name = "Syndicate Playing Cards"
diff --git a/code/modules/uplink/uplink_items/uplink_bundles.dm b/code/modules/uplink/uplink_items/uplink_bundles.dm
index 7d0e52947a..1a9dcbd0a6 100644
--- a/code/modules/uplink/uplink_items/uplink_bundles.dm
+++ b/code/modules/uplink/uplink_items/uplink_bundles.dm
@@ -40,6 +40,7 @@
cost = 20
player_minimum = 30
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+ restricted = TRUE
/datum/uplink_item/suits/infiltrator_bundle
name = "Insidious Infiltration Gear Case"
diff --git a/code/modules/uplink/uplink_items/uplink_devices.dm b/code/modules/uplink/uplink_items/uplink_devices.dm
index 194281ded6..15437020a6 100644
--- a/code/modules/uplink/uplink_items/uplink_devices.dm
+++ b/code/modules/uplink/uplink_items/uplink_devices.dm
@@ -262,3 +262,13 @@
cost = 2
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
restricted = TRUE
+
+/* for now
+/datum/uplink_item/device_tools/suspiciousphone
+ name = "Protocol CRAB-17 Phone"
+ desc = "The Protocol CRAB-17 Phone, a phone borrowed from an unknown third party, it can be used to crash the space market, funneling the losses of the crew to your bank account.\
+ The crew can move their funds to a new banking site though, unless they HODL, in which case they deserve it."
+ item = /obj/item/suspiciousphone
+ cost = 7
+ restricted = TRUE
+*/
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 4f7502bb02..abbfa94f11 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -30,6 +30,10 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/amount = 0
///How many we can store at maximum
var/max_amount = 0
+ ///Does the item have a custom price override
+ var/custom_price
+ ///Does the item have a custom premium price override
+ var/custom_premium_price
/**
* # vending machines
@@ -50,6 +54,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
integrity_failure = 0.33
armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 70)
circuit = /obj/item/circuitboard/machine/vendor
+ payment_department = ACCOUNT_SRV
light_power = 0.5
light_range = MINIMUM_USEFUL_LIGHT_RANGE
/// Is the machine active (No sales pitches if off)!
@@ -120,7 +125,12 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/scan_id = TRUE
///Coins that we accept?
var/obj/item/coin/coin
+ ///Bills we accept?
+ var/obj/item/stack/spacecash/bill
///Default price of items if not overridden
+ var/default_price = 25
+ ///Default price of premium items if not overridden
+ var/extra_price = 50
/**
* Is this item on station or not
*
@@ -142,7 +152,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/obj/item/vending_refill/refill_canister = null
/// how many items have been inserted in a vendor
- var/loaded_items
+ var/loaded_items = 0
///Name of lighting mask for the vending machine
var/light_mask
@@ -178,6 +188,15 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
// so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated.
last_slogan = world.time + rand(0, slogan_delay)
power_change()
+ if(onstation_override) //overrides the checks if true.
+ onstation = TRUE
+ return
+ if(mapload && !is_station_level(z)) //check if it was initially created off station during mapload.
+ onstation = FALSE
+ if(circuit)
+ circuit.onstation = onstation //sync up the circuit so the pricing schema is carried over if it's reconstructed.
+ else if(circuit && (circuit.onstation != onstation)) //check if they're not the same to minimize the amount of edited values.
+ onstation = circuit.onstation //if it was constructed outside mapload, sync the vendor up with the circuit's var so you can't bypass price requirements by moving / reconstructing it off station.
/obj/machinery/vending/Destroy()
QDEL_NULL(wires)
@@ -281,6 +300,7 @@ GLOBAL_LIST_EMPTY(vending_products)
if(!start_empty)
R.amount = amount
R.max_amount = amount
+ R.custom_price = initial(temp.custom_price)
recordlist += R
/**
* Refill a vending machine from a refill canister
@@ -372,19 +392,7 @@ GLOBAL_LIST_EMPTY(vending_products)
if(panel_open && is_wire_tool(I))
wires.interact(user)
return
- else if(istype(I, /obj/item/coin))
- if(coin)
- to_chat(user, "[src] already has [coin] inserted")
- return
- if(!premium.len)
- to_chat(user, "[src] doesn't have a coin slot.")
- return
- if(!user.transferItemToLoc(I, src))
- return
- coin = I
- to_chat(user, "You insert [I] into [src].")
- return
- else if(refill_canister && istype(I, refill_canister))
+ if(refill_canister && istype(I, refill_canister))
if (!panel_open)
to_chat(user, "You should probably unscrew the service panel first!")
else if (stat & (BROKEN|NOPOWER))
@@ -439,7 +447,7 @@ GLOBAL_LIST_EMPTY(vending_products)
vending_machine_input[format_text(I.name)] = 1
to_chat(user, "You insert [I] into [src]'s input compartment.")
loaded_items++
-
+
/**
* Is the passed in user allowed to load this vending machines compartments
*
@@ -520,11 +528,14 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/machinery/vending/ui_static_data(mob/user)
. = list()
+ .["onstation"] = onstation
+ .["department"] = payment_department
.["product_records"] = list()
for (var/datum/data/vending_product/R in product_records)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
+ price = R.custom_price || default_price,
max_amount = R.max_amount,
ref = REF(R)
)
@@ -534,6 +545,7 @@ GLOBAL_LIST_EMPTY(vending_products)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
+ price = R.custom_premium_price || extra_price,
max_amount = R.max_amount,
ref = REF(R),
premium = TRUE
@@ -544,6 +556,7 @@ GLOBAL_LIST_EMPTY(vending_products)
var/list/data = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
+ price = R.custom_price || default_price,
max_amount = R.max_amount,
ref = REF(R),
premium = TRUE
@@ -552,11 +565,25 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/machinery/vending/ui_data(mob/user)
. = list()
+ var/mob/living/carbon/human/H
+ var/obj/item/card/id/C
+ if(ishuman(user))
+ H = user
+ C = H.get_idcard(TRUE)
+ if(C?.registered_account)
+ .["user"] = list()
+ .["user"]["name"] = C.registered_account.account_holder
+ .["user"]["cash"] = C.registered_account.account_balance
+ if(C.registered_account.account_job)
+ .["user"]["job"] = C.registered_account.account_job.title
+ .["user"]["department"] = C.registered_account.account_job.paycheck_department
+ else
+ .["user"]["job"] = "No Job"
+ .["user"]["department"] = "No Department"
.["stock"] = list()
- for(var/datum/data/vending_product/R in product_records + coin_records + hidden_records)
+ for (var/datum/data/vending_product/R in product_records + coin_records + hidden_records)
.["stock"][R.name] = R.amount
.["extended_inventory"] = extended_inventory
- .["coin"] = coin
/obj/machinery/vending/ui_act(action, params)
. = ..()
@@ -570,74 +597,74 @@ GLOBAL_LIST_EMPTY(vending_products)
if(panel_open)
to_chat(usr, "The vending machine cannot dispense products while its service panel is open!")
return
- if((!allowed(usr)) && !(obj_flags & EMAGGED) && scan_id) //For SECURE VENDING MACHINES YEAH
- to_chat(usr, "Access denied." )
- flick(icon_deny,src)
- return
vend_ready = FALSE //One thing at a time!!
var/datum/data/vending_product/R = locate(params["ref"])
+ var/list/record_to_check = product_records + coin_records
+ if(extended_inventory)
+ record_to_check = product_records + coin_records + hidden_records
if(!R || !istype(R) || !R.product_path)
vend_ready = TRUE
return
+ var/price_to_use = default_price
+ if(R.custom_price)
+ price_to_use = R.custom_price
if(R in hidden_records)
if(!extended_inventory)
vend_ready = TRUE
return
- else if(R in coin_records)
- if(!(coin))
- to_chat(usr, "You need to a coin to get this item!")
- vend_ready = TRUE
- return
- if(coin && coin.string_attached)
- if(!prob(50))
- to_chat(usr, "You weren't able to pull [coin] out fast enough, the machine ate it, string and all!")
- QDEL_NULL(coin)
- return
- if(!usr.CanReach(src))
- to_chat(usr, "You successfully pull [coin] out of [src] to the floor.")
- coin = null
- if(!usr.put_in_hands(coin))
- to_chat(usr, "You couldn't pull [coin] out because your hands are full!")
- QDEL_NULL(coin)
- to_chat(usr, "You successfully pull [coin] out before [src] could swallow it.")
- coin = null
- QDEL_NULL(coin)
- else if(!(R in product_records))
+ else if (!(R in record_to_check))
vend_ready = TRUE
message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(usr)]!")
return
- if(R.amount <= 0)
- to_chat(usr, "Sold out.")
+ if (R.amount <= 0)
+ say("Sold out of [R.name].")
+ flick(icon_deny,src)
vend_ready = TRUE
return
- else
- R.amount--
- if(((last_reply + 200) <= world.time) && vend_reply)
- speak(vend_reply)
- last_reply = world.time
+ if(onstation && ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/card/id/C = H.get_idcard(TRUE)
+
+ if(!C)
+ say("No card found.")
+ flick(icon_deny,src)
+ vend_ready = TRUE
+ return
+ else if (!C.registered_account)
+ say("No account found.")
+ flick(icon_deny,src)
+ vend_ready = TRUE
+ return
+ var/datum/bank_account/account = C.registered_account
+ if(account.account_job && account.account_job.paycheck_department == payment_department)
+ price_to_use = 0
+ if(coin_records.Find(R) || hidden_records.Find(R))
+ price_to_use = R.custom_premium_price ? R.custom_premium_price : extra_price
+ if(price_to_use && !account.adjust_money(-price_to_use))
+ say("You do not possess the funds to purchase [R.name].")
+ flick(icon_deny,src)
+ vend_ready = TRUE
+ return
+ var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
+ if(D)
+ D.adjust_money(price_to_use)
+ if(last_shopper != usr || purchase_message_cooldown < world.time)
+ say("Thank you for shopping with [src]!")
+ purchase_message_cooldown = world.time + 5 SECONDS
+ last_shopper = usr
use_power(5)
if(icon_vend) //Show the vending animation if needed
flick(icon_vend,src)
- var/vended = new R.product_path(get_turf(src))
+ playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3)
+ var/obj/item/vended = new R.product_path(get_turf(src))
+ R.amount--
if(usr.CanReach(src) && usr.put_in_hands(vended))
to_chat(usr, "You take [R.name] out of the slot.")
else
to_chat(usr, "[capitalize(R.name)] falls onto the floor!")
-
-
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
vend_ready = TRUE
- return
- if("takeoutcoin")
- usr.put_in_hands(coin)
- to_chat(usr, "You remove [coin] from [src].")
- coin = null
- return
-
- if("togglevoice")
- if(panel_open)
- shut_up = !shut_up
-
+
/obj/machinery/vending/process()
if(stat & (BROKEN|NOPOWER))
return PROCESS_KILL
@@ -748,3 +775,196 @@ GLOBAL_LIST_EMPTY(vending_products)
/obj/machinery/vending/onTransitZ()
return
+
+/obj/machinery/vending/custom
+ name = "Custom Vendor"
+ icon_state = "robotics"
+ icon_deny = "robotics-deny"
+ max_integrity = 400
+ payment_department = NO_FREEBIES
+ refill_canister = /obj/item/vending_refill/custom
+ /// where the money is sent
+ var/datum/bank_account/private_a
+ /// max number of items that the custom vendor can hold
+ var/max_loaded_items = 20
+ /// Base64 cache of custom icons.
+ var/list/base64_cache = list()
+
+/obj/machinery/vending/custom/compartmentLoadAccessCheck(mob/user)
+ . = FALSE
+ var/mob/living/carbon/human/H
+ var/obj/item/card/id/C
+ if(ishuman(user))
+ H = user
+ C = H.get_idcard(FALSE)
+ if(C?.registered_account && C.registered_account == private_a)
+ return TRUE
+
+/obj/machinery/vending/custom/canLoadItem(obj/item/I, mob/user)
+ . = FALSE
+ if(loaded_items >= max_loaded_items)
+ say("There are too many items in stock.")
+ return
+ if(istype(I, /obj/item/stack))
+ say("Loose items may cause problems, try use it inside wrapping paper.")
+ return
+ if(I.custom_price)
+ return TRUE
+
+/obj/machinery/vending/custom/ui_data(mob/user)
+ . = ..()
+ .["access"] = compartmentLoadAccessCheck(user)
+ .["vending_machine_input"] = list()
+ for (var/O in vending_machine_input)
+ if(vending_machine_input[O] > 0)
+ var/base64
+ var/price = 0
+ for(var/obj/T in contents)
+ if(T.name == O)
+ price = T.custom_price
+ if(!base64)
+ if(base64_cache[T.type])
+ base64 = base64_cache[T.type]
+ else
+ base64 = icon2base64(icon(T.icon, T.icon_state))
+ base64_cache[T.type] = base64
+ break
+ var/list/data = list(
+ name = O,
+ price = price,
+ img = base64
+ )
+ .["vending_machine_input"] += list(data)
+
+/obj/machinery/vending/custom/ui_act(action, params)
+ . = ..()
+ if(.)
+ return
+ switch(action)
+ if("dispense")
+ . = TRUE
+ if(!vend_ready)
+ return
+ var/N = params["item"]
+ var/obj/S
+ vend_ready = FALSE
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/card/id/C = H.get_idcard(TRUE)
+
+ if(!C)
+ say("No card found.")
+ flick(icon_deny,src)
+ vend_ready = TRUE
+ return
+ else if (!C.registered_account)
+ say("No account found.")
+ flick(icon_deny,src)
+ vend_ready = TRUE
+ return
+ var/datum/bank_account/account = C.registered_account
+ for(var/obj/O in contents)
+ if(O.name == N)
+ S = O
+ break
+ if(S)
+ if(compartmentLoadAccessCheck(usr))
+ vending_machine_input[N] = max(vending_machine_input[N] - 1, 0)
+ S.forceMove(drop_location())
+ loaded_items--
+ use_power(5)
+ vend_ready = TRUE
+ updateUsrDialog()
+ return
+ if(account.has_money(S.custom_price))
+ account.adjust_money(-S.custom_price)
+ var/datum/bank_account/owner = private_a
+ if(owner)
+ owner.adjust_money(S.custom_price)
+ vending_machine_input[N] = max(vending_machine_input[N] - 1, 0)
+ S.forceMove(drop_location())
+ loaded_items--
+ use_power(5)
+ if(last_shopper != usr || purchase_message_cooldown < world.time)
+ say("Thank you for buying local and purchasing [S]!")
+ purchase_message_cooldown = world.time + 5 SECONDS
+ last_shopper = usr
+ vend_ready = TRUE
+ updateUsrDialog()
+ return
+ else
+ say("You do not possess the funds to purchase this.")
+ vend_ready = TRUE
+
+/obj/machinery/vending/custom/attackby(obj/item/I, mob/user, params)
+ if(!private_a)
+ var/mob/living/carbon/human/H
+ var/obj/item/card/id/C
+ if(ishuman(user))
+ H = user
+ C = H.get_idcard(TRUE)
+ if(C?.registered_account)
+ private_a = C.registered_account
+ say("\The [src] has been linked to [C].")
+
+ if(compartmentLoadAccessCheck(user))
+ if(istype(I, /obj/item/pen))
+ name = stripped_input(user,"Set name","Name", name, 20)
+ desc = stripped_input(user,"Set description","Description", desc, 60)
+ slogan_list += stripped_input(user,"Set slogan","Slogan","Epic", 60)
+ last_slogan = world.time + rand(0, slogan_delay)
+ return
+
+ if(canLoadItem(I))
+ loadingAttempt(I,user)
+ updateUsrDialog()
+ return
+
+ if(panel_open && is_wire_tool(I))
+ wires.interact(user)
+ return
+
+ return ..()
+
+/obj/machinery/vending/custom/crowbar_act(mob/living/user, obj/item/I)
+ return FALSE
+
+/obj/machinery/vending/custom/Destroy()
+ unbuckle_all_mobs(TRUE)
+ var/turf/T = get_turf(src)
+ if(T)
+ for(var/obj/item/I in contents)
+ I.forceMove(T)
+ explosion(T, -1, 0, 3)
+ return ..()
+
+/obj/machinery/vending/custom/unbreakable
+ name = "Indestructible Vendor"
+ resistance_flags = INDESTRUCTIBLE
+
+/obj/item/vending_refill/custom
+ machine_name = "Custom Vendor"
+ icon_state = "refill_custom"
+ custom_premium_price = 100
+
+/obj/item/price_tagger
+ name = "price tagger"
+ desc = "This tool is used to set a price for items used in custom vendors."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pricetagger"
+ custom_premium_price = 25
+ ///the price of the item
+ var/price = 1
+
+/obj/item/price_tagger/attack_self(mob/user)
+ price = max(1, round(input(user,"set price","price") as num|null, 1))
+ to_chat(user, " The [src] will now give things a [price] cr tag.")
+
+/obj/item/price_tagger/afterattack(atom/target, mob/user, proximity)
+ . = ..()
+ if(!proximity)
+ return
+ if(isitem(target))
+ var/obj/item/I = target
+ I.custom_price = price
+ to_chat(user, "You set the price of [I] to [price] cr.")
diff --git a/code/modules/vending/assist.dm b/code/modules/vending/assist.dm
index 5dafd3935c..b1b8519803 100644
--- a/code/modules/vending/assist.dm
+++ b/code/modules/vending/assist.dm
@@ -19,6 +19,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/assist
resistance_flags = FIRE_PROOF
+ default_price = 125
+ extra_price = 100
+ payment_department = NO_FREEBIES
/obj/item/vending_refill/assist
icon_state = "refill_engi"
\ No newline at end of file
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 2eaf24c493..d791ceedf1 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -138,12 +138,19 @@
/obj/item/clothing/head/christmashat = 3,
/obj/item/clothing/head/christmashatg = 3,
/obj/item/clothing/under/costume/drfreeze = 1) //End of Cit Changes
+
refill_canister = /obj/item/vending_refill/autodrobe
+ default_price = 180
+ extra_price = 360
+ payment_department = ACCOUNT_SRV
/obj/machinery/vending/autodrobe/all_access
desc = "A vending machine for costumes. This model appears to have no access restrictions."
req_access = null
+/obj/machinery/vending/autodrobe/canLoadItem(obj/item/I,mob/user)
+ return (I.type in products)
+
/obj/item/vending_refill/autodrobe
machine_name = "AutoDrobe"
icon_state = "refill_costume"
diff --git a/code/modules/vending/boozeomat.dm b/code/modules/vending/boozeomat.dm
index 5a6380c322..4b73344c22 100644
--- a/code/modules/vending/boozeomat.dm
+++ b/code/modules/vending/boozeomat.dm
@@ -4,7 +4,7 @@
icon_state = "boozeomat"
icon_deny = "boozeomat-deny"
products = list(/obj/item/reagent_containers/food/drinks/drinkingglass = 30,
- /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass = 12,
+ /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass = 12,
/obj/item/reagent_containers/food/drinks/bottle/gin = 5,
/obj/item/reagent_containers/food/drinks/bottle/whiskey = 5,
/obj/item/reagent_containers/food/drinks/bottle/tequila = 5,
@@ -41,6 +41,9 @@
product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!"
req_access = list(ACCESS_BAR)
refill_canister = /obj/item/vending_refill/boozeomat
+ default_price = 120
+ extra_price = 100
+ payment_department = ACCOUNT_SRV
/obj/machinery/vending/boozeomat/all_access
desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one. This model appears to have no access restrictions."
diff --git a/code/modules/vending/cartridge.dm b/code/modules/vending/cartridge.dm
index 35b1a1da7a..93fb3a0af8 100644
--- a/code/modules/vending/cartridge.dm
+++ b/code/modules/vending/cartridge.dm
@@ -16,6 +16,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/cart
resistance_flags = FIRE_PROOF
+ default_price = 250
+ extra_price = 500
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/cart
icon_state = "refill_pda"
diff --git a/code/modules/vending/cigarette.dm b/code/modules/vending/cigarette.dm
index f567c9765e..5895568158 100644
--- a/code/modules/vending/cigarette.dm
+++ b/code/modules/vending/cigarette.dm
@@ -20,6 +20,9 @@
/obj/item/storage/fancy/cigarettes/cigars/havana = 1,
/obj/item/storage/fancy/cigarettes/cigars/cohiba = 1)
refill_canister = /obj/item/vending_refill/cigarette
+ default_price = 75
+ extra_price = 250
+ payment_department = ACCOUNT_SRV
/obj/machinery/vending/cigarette/syndicate
products = list(/obj/item/storage/fancy/cigarettes/cigpack_syndicate = 7,
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index 521c1e0999..2155d0fe8b 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -173,6 +173,12 @@
/obj/item/clothing/suit/jacket/letterman_nanotrasen = 5,
/obj/item/clothing/suit/hooded/wintercoat/polychromic = 5)
refill_canister = /obj/item/vending_refill/clothing
+ default_price = 60
+ extra_price = 120
+ payment_department = NO_FREEBIES
+
+/obj/machinery/vending/clothing/canLoadItem(obj/item/I,mob/user)
+ return (I.type in products)
/obj/item/vending_refill/clothing
machine_name = "ClothesMate"
diff --git a/code/modules/vending/coffee.dm b/code/modules/vending/coffee.dm
index 355d037f99..f4a8b2503e 100644
--- a/code/modules/vending/coffee.dm
+++ b/code/modules/vending/coffee.dm
@@ -14,6 +14,9 @@
/obj/item/reagent_containers/food/condiment/sugar = 1)
refill_canister = /obj/item/vending_refill/coffee
+ default_price = 45
+ extra_price = 150
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/coffee
machine_name = "Solar's Best Hot Drinks"
diff --git a/code/modules/vending/cola.dm b/code/modules/vending/cola.dm
index 57cf315209..5bbd0c3d02 100644
--- a/code/modules/vending/cola.dm
+++ b/code/modules/vending/cola.dm
@@ -21,6 +21,9 @@
/obj/item/reagent_containers/food/drinks/soda_cans/grey_bull = 1,
/obj/item/reagent_containers/food/drinks/soda_cans/monkey_energy = 1)
refill_canister = /obj/item/vending_refill/cola
+ default_price = 45
+ extra_price = 200
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/cola
machine_name = "Robust Softdrinks"
diff --git a/code/modules/vending/drinnerware.dm b/code/modules/vending/drinnerware.dm
index 8f257d07ec..2e574a50a1 100644
--- a/code/modules/vending/drinnerware.dm
+++ b/code/modules/vending/drinnerware.dm
@@ -29,6 +29,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/dinnerware
resistance_flags = FIRE_PROOF
+ default_price = 50
+ extra_price = 250
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/dinnerware
icon_state = "refill_cook"
\ No newline at end of file
diff --git a/code/modules/vending/engineering.dm b/code/modules/vending/engineering.dm
index e067c094f6..20ca364277 100644
--- a/code/modules/vending/engineering.dm
+++ b/code/modules/vending/engineering.dm
@@ -29,3 +29,6 @@
/obj/item/stock_parts/manipulator = 5)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
+ default_price = 450
+ extra_price = 500
+ payment_department = ACCOUNT_ENG
diff --git a/code/modules/vending/engivend.dm b/code/modules/vending/engivend.dm
index 15da7cab15..e5571d1d6a 100644
--- a/code/modules/vending/engivend.dm
+++ b/code/modules/vending/engivend.dm
@@ -30,6 +30,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/engivend
resistance_flags = FIRE_PROOF
+ default_price = 450
+ extra_price = 500
+ payment_department = ACCOUNT_ENG
/obj/item/vending_refill/engivend
icon_state = "refill_engi"
\ No newline at end of file
diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm
index e663dca7ce..81c49eeb31 100644
--- a/code/modules/vending/games.dm
+++ b/code/modules/vending/games.dm
@@ -11,6 +11,9 @@
premium = list(/obj/item/melee/skateboard/pro = 3,
/obj/item/melee/skateboard/hoverboard = 1)
refill_canister = /obj/item/vending_refill/games
+ default_price = 50
+ extra_price = 250
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/games
machine_name = "\improper Good Clean Fun"
diff --git a/code/modules/vending/kinkmate.dm b/code/modules/vending/kinkmate.dm
index acfeeddaa9..37f4e380ce 100644
--- a/code/modules/vending/kinkmate.dm
+++ b/code/modules/vending/kinkmate.dm
@@ -40,6 +40,9 @@
/obj/item/clothing/under/pants/chaps = 5
)
refill_canister = /obj/item/vending_refill/kink
+ default_price = 80
+ extra_price = 250
+ payment_department = NO_FREEBIES
/obj/item/vending_refill/kink
machine_name = "KinkMate"
diff --git a/code/modules/vending/liberation.dm b/code/modules/vending/liberation.dm
index affc1dfed7..c75d313c52 100644
--- a/code/modules/vending/liberation.dm
+++ b/code/modules/vending/liberation.dm
@@ -28,3 +28,6 @@
/obj/item/reagent_containers/food/snacks/burger/superbite = 3) //U S A
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
+ default_price = 150
+ extra_price = 500
+ payment_department = ACCOUNT_SEC
diff --git a/code/modules/vending/liberation_toy.dm b/code/modules/vending/liberation_toy.dm
index e2c97b32db..09cbd006d0 100644
--- a/code/modules/vending/liberation_toy.dm
+++ b/code/modules/vending/liberation_toy.dm
@@ -25,3 +25,6 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/donksoft
+ default_price = 150
+ extra_price = 300
+ payment_department = ACCOUNT_SRV
diff --git a/code/modules/vending/magivend.dm b/code/modules/vending/magivend.dm
index ab7670c453..525b9f1af2 100644
--- a/code/modules/vending/magivend.dm
+++ b/code/modules/vending/magivend.dm
@@ -16,3 +16,6 @@
contraband = list(/obj/item/reagent_containers/glass/bottle/wizarditis = 1) //No one can get to the machine to hack it anyways; for the lulz - Microwave
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50, "magic" = 100)
resistance_flags = FIRE_PROOF
+ default_price = 250
+ extra_price = 500
+ payment_department = ACCOUNT_SRV
diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm
index d32af7de03..af8df11cc6 100644
--- a/code/modules/vending/medical.dm
+++ b/code/modules/vending/medical.dm
@@ -47,6 +47,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/medical
+ default_price = 250
+ extra_price = 500
+ payment_department = ACCOUNT_MED
/obj/item/vending_refill/medical
machine_name = "NanoMed Plus"
diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm
index a048d253c5..9d1885c769 100644
--- a/code/modules/vending/medical_wall.dm
+++ b/code/modules/vending/medical_wall.dm
@@ -18,6 +18,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/wallmed
+ default_price = 250
+ extra_price = 500
+ payment_department = ACCOUNT_MED
/obj/item/vending_refill/wallmed
machine_name = "NanoMed"
diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm
index 37ce00069c..4cc19d4df5 100644
--- a/code/modules/vending/megaseed.dm
+++ b/code/modules/vending/megaseed.dm
@@ -57,6 +57,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/hydroseeds
resistance_flags = FIRE_PROOF
+ default_price = 100
+ extra_price = 350
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/hydroseeds
icon_state = "refill_hydro"
diff --git a/code/modules/vending/nutrimax.dm b/code/modules/vending/nutrimax.dm
index 42b7848ac1..b55a39ff1e 100644
--- a/code/modules/vending/nutrimax.dm
+++ b/code/modules/vending/nutrimax.dm
@@ -19,6 +19,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/hydronutrients
resistance_flags = FIRE_PROOF
+ default_price = 100
+ extra_price = 250
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/hydronutrients
icon_state = "refill_hydro"
diff --git a/code/modules/vending/plasmaresearch.dm b/code/modules/vending/plasmaresearch.dm
index 40b709f5b5..412a9fb33c 100644
--- a/code/modules/vending/plasmaresearch.dm
+++ b/code/modules/vending/plasmaresearch.dm
@@ -11,3 +11,6 @@
/obj/item/assembly/prox_sensor = 6,
/obj/item/assembly/igniter = 6)
contraband = list(/obj/item/assembly/health = 3)
+ default_price = 400
+ extra_price = 600
+ payment_department = ACCOUNT_SCI
diff --git a/code/modules/vending/robotics.dm b/code/modules/vending/robotics.dm
index 852b7d65f0..ca07724460 100644
--- a/code/modules/vending/robotics.dm
+++ b/code/modules/vending/robotics.dm
@@ -21,3 +21,5 @@
/obj/item/crowbar = 5)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
+ default_price = 600
+ payment_department = ACCOUNT_SCI
diff --git a/code/modules/vending/security.dm b/code/modules/vending/security.dm
index 09681def64..2fc1afa375 100644
--- a/code/modules/vending/security.dm
+++ b/code/modules/vending/security.dm
@@ -25,6 +25,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/security
+ default_price = 650
+ extra_price = 700
+ payment_department = ACCOUNT_SEC
/obj/machinery/vending/security/pre_throw(obj/item/I)
if(istype(I, /obj/item/grenade))
diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm
index 9dda649b24..aff02b019a 100644
--- a/code/modules/vending/snack.dm
+++ b/code/modules/vending/snack.dm
@@ -26,77 +26,15 @@
/obj/item/storage/box/donkpockets = 2)
refill_canister = /obj/item/vending_refill/snack
- var/chef_compartment_access = "28" //ACCESS_KITCHEN
+ canload_access_list = list(ACCESS_KITCHEN)
+ default_price = 60
+ extra_price = 160
+ payment_department = ACCOUNT_SRV
+ input_display_header = "Chef's Food Selection"
/obj/item/vending_refill/snack
machine_name = "Getmore Chocolate Corp"
-/obj/machinery/vending/snack/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/reagent_containers/food/snacks))
- if(!compartment_access_check(user))
- return
- var/obj/item/reagent_containers/food/snacks/S = W
- if(!S.junkiness)
- if(!iscompartmentfull(user))
- if(!user.transferItemToLoc(W, src))
- return
- food_load(W)
- to_chat(user, "You insert [W] into [src]'s chef compartment.")
- else
- to_chat(user, "[src]'s chef compartment does not accept junk food.")
-
- else if(istype(W, /obj/item/storage/bag/tray))
- if(!compartment_access_check(user))
- return
- var/obj/item/storage/T = W
- var/loaded = 0
- var/denied_items = 0
- for(var/obj/item/reagent_containers/food/snacks/S in T.contents)
- if(iscompartmentfull(user))
- break
- if(!S.junkiness)
- SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, S, src, TRUE)
- food_load(S)
- loaded++
- else
- denied_items++
- if(denied_items)
- to_chat(user, "[src] refuses some items.")
- if(loaded)
- to_chat(user, "You insert [loaded] dishes into [src]'s chef compartment.")
- updateUsrDialog()
- return
-
- else
- return ..()
-
-/obj/machinery/vending/snack/Destroy()
- for(var/obj/item/reagent_containers/food/snacks/S in contents)
- S.forceMove(get_turf(src))
- return ..()
-
-/obj/machinery/vending/snack/proc/compartment_access_check(user)
- req_access_txt = chef_compartment_access
- if(!allowed(user) && !(obj_flags & EMAGGED) && scan_id)
- to_chat(user, "[src]'s chef compartment blinks red: Access denied.")
- req_access_txt = "0"
- return 0
- req_access_txt = "0"
- return 1
-
-/obj/machinery/vending/snack/proc/iscompartmentfull(mob/user)
- if(contents.len >= 30) // no more than 30 dishes can fit inside
- to_chat(user, "[src]'s chef compartment is full.")
- return 1
- return 0
-
-/obj/machinery/vending/snack/proc/food_load(obj/item/reagent_containers/food/snacks/S)
- if(dish_quants[S.name])
- dish_quants[S.name]++
- else
- dish_quants[S.name] = 1
- sortList(dish_quants)
-
/obj/machinery/vending/snack/random
name = "\improper Random Snackies"
icon_state = "random_snack"
diff --git a/code/modules/vending/sovietsoda.dm b/code/modules/vending/sovietsoda.dm
index 39364d78da..d820794660 100644
--- a/code/modules/vending/sovietsoda.dm
+++ b/code/modules/vending/sovietsoda.dm
@@ -7,3 +7,6 @@
contraband = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/cola = 20)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
+ default_price = 1
+ extra_price = 1
+ payment_department = NO_FREEBIES
diff --git a/code/modules/vending/sovietvend.dm b/code/modules/vending/sovietvend.dm
index c555362fb6..daf64d5f3e 100644
--- a/code/modules/vending/sovietvend.dm
+++ b/code/modules/vending/sovietvend.dm
@@ -23,6 +23,9 @@
premium = list()
refill_canister = /obj/item/vending_refill/soviet
+ default_price = 1
+ extra_price = 1
+ payment_department = NO_FREEBIES
/obj/item/vending_refill/soviet
machine_name = "sovietvend"
diff --git a/code/modules/vending/sustenance.dm b/code/modules/vending/sustenance.dm
index 9783607a21..55e6b02e8e 100644
--- a/code/modules/vending/sustenance.dm
+++ b/code/modules/vending/sustenance.dm
@@ -14,6 +14,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/sustenance
resistance_flags = FIRE_PROOF
+ default_price = 0
+ extra_price = 0
+ payment_department = NO_FREEBIES
/obj/item/vending_refill/sustenance
icon_state = "refill_cook"
diff --git a/code/modules/vending/toys.dm b/code/modules/vending/toys.dm
index 08bb4615bb..a00dd17a9c 100644
--- a/code/modules/vending/toys.dm
+++ b/code/modules/vending/toys.dm
@@ -25,6 +25,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/donksoft
+ default_price = 150
+ extra_price = 300
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/donksoft
machine_name = "Donksoft Toy Vendor"
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index acd58959f1..0da6a68583 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -1,6 +1,15 @@
/obj/item/vending_refill/wardrobe
icon_state = "refill_clothes"
+/obj/machinery/vending/wardrobe
+ default_price = 350
+ extra_price = 400
+ payment_department = NO_FREEBIES
+ input_display_header = "Returned Clothing"
+
+/obj/machinery/vending/wardrobe/canLoadItem(obj/item/I,mob/user)
+ return (I.type in products)
+
/obj/machinery/vending/wardrobe/sec_wardrobe
name = "\improper SecDrobe"
desc = "A vending machine for security and security-related clothing!"
@@ -22,6 +31,7 @@
premium = list(/obj/item/clothing/under/rank/security/officer/formal = 5,
/obj/item/clothing/head/beret/sec/navyofficer = 5)
refill_canister = /obj/item/vending_refill/wardrobe/sec_wardrobe
+ payment_department = ACCOUNT_SEC
/obj/item/vending_refill/wardrobe/sec_wardrobe
machine_name = "SecDrobe"
@@ -57,6 +67,7 @@
/obj/item/clothing/suit/apron/surgical = 5,
/obj/item/clothing/mask/surgical = 5)
refill_canister = /obj/item/vending_refill/wardrobe/medi_wardrobe
+ payment_department = ACCOUNT_MED
/obj/item/vending_refill/wardrobe/medi_wardrobe
machine_name = "MediDrobe"
@@ -80,6 +91,7 @@
/obj/item/clothing/head/hardhat = 5,
/obj/item/clothing/head/hardhat/weldhat = 3)
refill_canister = /obj/item/vending_refill/wardrobe/engi_wardrobe
+ payment_department = ACCOUNT_ENG
/obj/item/vending_refill/wardrobe/engi_wardrobe
machine_name = "EngiDrobe"
@@ -101,6 +113,7 @@
/obj/item/clothing/under/rank/engineering/atmospheric_technician/skirt = 5,
/obj/item/clothing/shoes/sneakers/black = 5)
refill_canister = /obj/item/vending_refill/wardrobe/atmos_wardrobe
+ payment_department = ACCOUNT_ENG
/obj/item/vending_refill/wardrobe/atmos_wardrobe
machine_name = "AtmosDrobe"
@@ -119,6 +132,7 @@
/obj/item/clothing/head/soft = 5,
/obj/item/radio/headset/headset_cargo = 3)
refill_canister = /obj/item/vending_refill/wardrobe/cargo_wardrobe
+ payment_department = ACCOUNT_CAR
/obj/item/vending_refill/wardrobe/cargo_wardrobe
machine_name = "CargoDrobe"
@@ -141,6 +155,7 @@
/obj/item/clothing/mask/bandana/skull = 2)
contraband = list(/obj/item/clothing/suit/hooded/techpriest = 2)
refill_canister = /obj/item/vending_refill/wardrobe/robo_wardrobe
+ payment_department = ACCOUNT_SCI
/obj/item/vending_refill/wardrobe/robo_wardrobe
machine_name = "RoboDrobe"
@@ -163,6 +178,7 @@
/obj/item/radio/headset/headset_sci = 4,
/obj/item/clothing/mask/gas = 5)
refill_canister = /obj/item/vending_refill/wardrobe/science_wardrobe
+ payment_department = ACCOUNT_SCI
/obj/item/vending_refill/wardrobe/science_wardrobe
machine_name = "SciDrobe"
@@ -182,6 +198,7 @@
/obj/item/clothing/under/rank/civilian/hydroponics/skirt = 5,
/obj/item/clothing/mask/bandana = 4)
refill_canister = /obj/item/vending_refill/wardrobe/hydro_wardrobe
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/wardrobe/hydro_wardrobe
machine_name = "HyDrobe"
@@ -206,6 +223,7 @@
/obj/item/clothing/glasses/regular/jamjar = 1,
/obj/item/storage/bag/books = 1)
refill_canister = /obj/item/vending_refill/wardrobe/curator_wardrobe
+ payment_department = ACCOUNT_CIV
/obj/item/vending_refill/wardrobe/curator_wardrobe
machine_name = "CuraDrobe"
@@ -234,6 +252,7 @@
/obj/item/clothing/neck/petcollar = 3,
/obj/item/storage/belt/bandolier = 1)
refill_canister = /obj/item/vending_refill/wardrobe/bar_wardrobe
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/wardrobe/bar_wardrobe
machine_name = "BarDrobe"
@@ -259,6 +278,7 @@
/obj/item/book/granter/crafting_recipe/cooking_sweets_101 = 2,
/obj/item/book/granter/crafting_recipe/coldcooking = 2)
refill_canister = /obj/item/vending_refill/wardrobe/chef_wardrobe
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/wardrobe/chef_wardrobe
machine_name = "ChefDrobe"
@@ -290,6 +310,7 @@
/obj/item/screwdriver = 2,
/obj/item/stack/cable_coil/random = 4)
refill_canister = /obj/item/vending_refill/wardrobe/jani_wardrobe
+ payment_department = ACCOUNT_SRV
/obj/item/vending_refill/wardrobe/jani_wardrobe
machine_name = "JaniDrobe"
@@ -321,6 +342,7 @@
/obj/item/clothing/shoes/laceup = 3,
/obj/item/clothing/accessory/lawyers_badge = 3)
refill_canister = /obj/item/vending_refill/wardrobe/law_wardrobe
+ payment_department = ACCOUNT_CIV
/obj/item/vending_refill/wardrobe/law_wardrobe
machine_name = "LawDrobe"
@@ -368,6 +390,7 @@
/obj/item/storage/bag/chemistry = 3,
/obj/item/fermichem/pHbooklet = 3)//pH indicator)
refill_canister = /obj/item/vending_refill/wardrobe/chem_wardrobe
+ payment_department = ACCOUNT_MED
/obj/item/vending_refill/wardrobe/chem_wardrobe
machine_name = "ChemDrobe"
@@ -386,6 +409,7 @@
/obj/item/storage/backpack/genetics = 3,
/obj/item/storage/backpack/satchel/gen = 3)
refill_canister = /obj/item/vending_refill/wardrobe/gene_wardrobe
+ payment_department = ACCOUNT_MED
/obj/item/vending_refill/wardrobe/gene_wardrobe
machine_name = "GeneDrobe"
@@ -406,6 +430,7 @@
/obj/item/storage/backpack/virology = 3,
/obj/item/storage/backpack/satchel/vir = 3)
refill_canister = /obj/item/vending_refill/wardrobe/viro_wardrobe
+ payment_department = ACCOUNT_MED
/obj/item/vending_refill/wardrobe/viro_wardrobe
machine_name = "ViroDrobe"
@@ -436,6 +461,7 @@
/obj/item/clothing/glasses/sunglasses/gar/supergar = 1,
/obj/item/clothing/gloves/color/captain = 1)
refill_canister = /obj/item/vending_refill/wardrobe/cap_wardrobe
+ payment_department = ACCOUNT_CIV
/obj/item/vending_refill/wardrobe/cap_wardrobe
machine_name = "Captain's Wardrobe"
diff --git a/code/modules/vending/youtool.dm b/code/modules/vending/youtool.dm
index c027cea6e5..009621b85a 100644
--- a/code/modules/vending/youtool.dm
+++ b/code/modules/vending/youtool.dm
@@ -21,6 +21,9 @@
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
refill_canister = /obj/item/vending_refill/tool
resistance_flags = FIRE_PROOF
+ default_price = 125
+ extra_price = 350
+ payment_department = ACCOUNT_ENG
/obj/item/vending_refill/tool
icon_state = "refill_engi"
\ No newline at end of file
diff --git a/config/game_options.txt b/config/game_options.txt
index 8c48ac6ede..51e68ac273 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -583,6 +583,9 @@ NIGHTSHIFT_TOGGLE_PUBLIC_REQUIRES_AUTH
## A cap on how many monkeys may be created via monkey cubes
MONKEYCAP 64
+## Enable the capitalist agenda on your server.
+ECONOMY
+
## Uncomment to use TG-style combat
#DISABLE_STAMBUFFER
diff --git a/config/vr_config.txt b/config/vr_config.txt
new file mode 100644
index 0000000000..8ca2334d5f
--- /dev/null
+++ b/config/vr_config.txt
@@ -0,0 +1,13 @@
+#List the potential virtual reality Z-levels here. awaymissionconfig copypasta follows.
+
+#Maps must be the full path to them
+#Maps should be 255x255 or smaller and be bounded. Falling off the edge of the map will result in undefined behavior.
+#SPECIFYING AN INVALID MAP WILL RESULT IN RUNTIMES ON GAME START
+
+#!!IMPORTANT NOTES FOR HOSTING VR MAPS!!:
+#Do NOT tick the maps during compile -- the game uses this list to decide which map to load. Ticking the maps will result in them ALL being loaded at once.
+#DO tick the associated code file for the virtual reality levels you are enabling. Otherwise, the map will be trying to reference objects which do not exist, which will cause runtime errors!
+
+#_maps/RandomZLevels/VR/murderdome.dmm
+#_maps/RandomZLevels/VR/snowdin_VR.dm
+#_maps/RandomZLevels/VR/syndicate_trainer.dm
\ No newline at end of file
diff --git a/icons/obj/crates.dmi b/icons/obj/crates.dmi
index ecb66d0119b504f18f5309f07896199483565a1d..532324fcf44b6d70825d63746d2382a84c312c29 100644
GIT binary patch
literal 23582
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∾L3`w(YM0%hRtZ`sFTbPx$a97mjOJK
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 E(K`M0jll@Sq32#J
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 |