diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm
index 7fe5fa4876..ecd043a66a 100644
--- a/code/__DEFINES/loadout.dm
+++ b/code/__DEFINES/loadout.dm
@@ -55,6 +55,9 @@
//donator items
#define LOADOUT_CATEGORY_DONATOR "Donator"
+//unlockable items
+#define LOADOUT_CATEGORY_UNLOCKABLE "Unlockable"
+
//how many prosthetics can we have
#define MAXIMUM_LOADOUT_PROSTHETICS 2
diff --git a/code/_globalvars/lists/loadout_categories.dm b/code/_globalvars/lists/loadout_categories.dm
index 0f0ac52214..4a61a94dc7 100644
--- a/code/_globalvars/lists/loadout_categories.dm
+++ b/code/_globalvars/lists/loadout_categories.dm
@@ -9,5 +9,6 @@ GLOBAL_LIST_INIT(loadout_categories, list(
LOADOUT_CATEGORY_SHOES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_GLOVES = LOADOUT_SUBCATEGORIES_NONE,
LOADOUT_CATEGORY_GLASSES = LOADOUT_SUBCATEGORIES_NONE,
- LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE
+ LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE,
+ LOADOUT_CATEGORY_UNLOCKABLE = LOADOUT_SUBCATEGORIES_NONE
))
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 01ef96b7e8..62a3530afe 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -24,13 +24,17 @@
create_reagents(mopcap, NONE, NO_REAGENTS_VALUE)
-/obj/item/mop/proc/clean(turf/A)
+/obj/item/mop/proc/clean(turf/A, mob/user)
if(reagents.has_reagent(/datum/reagent/water, 1) || reagents.has_reagent(/datum/reagent/water/holywater, 1) || reagents.has_reagent(/datum/reagent/consumable/ethanol/vodka, 1) || reagents.has_reagent(/datum/reagent/space_cleaner, 1))
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
A.clean_blood()
+ var/cleaned_something = FALSE
for(var/obj/effect/O in A)
if(is_cleanable(O))
+ cleaned_something = TRUE
qdel(O)
+ if(cleaned_something && user && user.client)
+ user.client.increment_progress("janitor", 1)
reagents.reaction(A, TOUCH, 10) //Needed for proper floor wetting.
reagents.remove_any(1) //reaction() doesn't use up the reagents
@@ -59,7 +63,7 @@
if(!L.UseStaminaBuffer(stamusage, warn = TRUE))
return
user.visible_message("[user] cleans \the [T] with [src].", "You clean \the [T] with [src].")
- clean(T)
+ clean(T, user)
user.DelayNextAction(CLICK_CD_MELEE)
user.do_attack_animation(T, used_item = src)
playsound(T, "slosh", 50, 1)
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index c36fba96cb..e718bce620 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -243,7 +243,7 @@ LINEN BINS
/obj/item/bedsheet/random/Initialize()
..()
- var/type = pick(typesof(/obj/item/bedsheet) - list(/obj/item/bedsheet/random, /obj/item/bedsheet/chameleon))
+ var/type = pick(typesof(/obj/item/bedsheet) - (list(/obj/item/bedsheet/random, /obj/item/bedsheet/chameleon) + typesof(/obj/item/bedsheet/unlockable)))
new type(loc)
return INITIALIZE_HINT_QDEL
@@ -257,9 +257,32 @@ LINEN BINS
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/bedsheet
chameleon_action.chameleon_name = "Bedsheet"
- chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/bedsheet/chameleon, /obj/item/bedsheet/random), only_root_path = TRUE)
+ chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/bedsheet/chameleon, /obj/item/bedsheet/random, /obj/item/bedsheet/unlockable), only_root_path = FALSE)
chameleon_action.initialize_disguises()
+//unlockable bedsheets
+/obj/item/bedsheet/unlockable
+ name = "unlockable bedsheet"
+ desc = "this shouldn't be here!"
+
+//janitor: clean 100 messes with mop as janitor
+/obj/item/bedsheet/unlockable/janitor
+ name = "janitor bedsheet"
+ desc = "A white bedsheet, with a warning sign on the front."
+ icon_state = "sheetjanitor"
+
+//cook: use microwave 100 times properly (contents must make one good item) as cook
+/obj/item/bedsheet/unlockable/cook
+ name = "cook bedsheet"
+ desc = "A grey bedsheet, with a microwave on the front."
+ icon_state = "sheetcook"
+
+//miner: redeem 100,000 mining points
+/obj/item/bedsheet/unlockable/miner
+ name = "miner bedsheet"
+ desc = "A red and black bedsheet. It seems to be made with goliath hide."
+ icon_state = "sheetminer"
+
//bedsheet bin
/obj/structure/bedsheetbin
name = "linen bin"
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 617d4a1d72..c298d150f8 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -1024,3 +1024,25 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
verb_tabs |= verb_to_init.category
verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name)
src << output("[url_encode(json_encode(verb_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs")
+
+//increment progress for an unlockable loadout item
+/client/proc/increment_progress(key, amount)
+ if(prefs)
+ var/savefile/S = new /savefile(prefs.path)
+ var/list/unlockable_loadout_data = prefs.unlockable_loadout_data
+ if(!length(unlockable_loadout_data))
+ unlockable_loadout_data = list()
+ unlockable_loadout_data[key] = amount
+ WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data))
+ prefs.unlockable_loadout_data = unlockable_loadout_data
+ return TRUE
+ else
+ if(unlockable_loadout_data[key])
+ unlockable_loadout_data[key] += amount
+ else
+ unlockable_loadout_data[key] = amount
+ WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data))
+ prefs.unlockable_loadout_data = unlockable_loadout_data
+ return TRUE
+ return FALSE
+
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index e97f6dc3f4..7c6ba30b80 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -198,6 +198,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/gear_points = 10
var/list/gear_categories
var/list/loadout_data = list()
+ var/list/unlockable_loadout_data = list()
var/loadout_slot = 1 //goes from 1 to MAXIMUM_LOADOUT_SAVES
var/gear_category
var/gear_subcategory
@@ -907,12 +908,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
loadout_color_non_poly = loadout_item[LOADOUT_COLOR][1]
extra_color_data += "
Color"
extra_color_data += " "
- else if(gear_points <= 0)
+ else if((gear_points - gear.cost) < 0)
class_link = "style='white-space:normal;' class='linkOff'"
else if(donoritem)
class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'"
- else
+ else if(!istype(gear, /datum/gear/unlockable) || can_use_unlockable(gear))
class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'"
+ else
+ class_link = "style='white-space:normal;background:#eb2e2e;' class='linkOff'"
dat += "
| " @@ -2675,6 +2687,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(G.donoritem && !G.donator_ckey_check(user.ckey)) to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.") return + if(istype(G, /datum/gear/unlockable) && !can_use_unlockable(G)) + to_chat(user, "To use this item, you need to meet the defined requirements!") + return if(gear_points >= initial(G.cost)) var/list/new_loadout_data = list(LOADOUT_ITEM = "[G.type]") if(length(G.loadout_initial_colors)) @@ -2960,6 +2975,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(find_gear) loadout_data["SAVE_[save_slot]"] -= list(find_gear) +/datum/preferences/proc/can_use_unlockable(datum/gear/unlockable/unlockable_gear) + if(unlockable_loadout_data[unlockable_gear.progress_key] >= unlockable_gear.progress_required) + return TRUE + return FALSE + #undef DEFAULT_SLOT_AMT #undef HANDS_SLOT_AMT #undef BACKPACK_SLOT_AMT diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 86f7622a93..0db9fbb66c 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 47 +#define SAVEFILE_VERSION_MAX 48 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -285,6 +285,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["loadout"] = safe_json_encode(loadout_data) + if(current_version < 48) //unlockable loadout items but we need to clear bad data from a mistake + S["unlockable_loadout"] = list() + /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) return @@ -427,6 +430,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped + if(S["unlockable_loadout"]) + unlockable_loadout_data = safe_json_decode(S["unlockable_loadout"]) + else + unlockable_loadout_data = list() + if(needs_update >= 0) //save the updated version var/old_default_slot = default_slot var/old_max_save_slots = max_save_slots @@ -532,6 +540,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["auto_ooc"], auto_ooc) WRITE_FILE(S["no_tetris_storage"], no_tetris_storage) + if(length(unlockable_loadout_data)) + WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data)) + else + WRITE_FILE(S["unlockable_loadout"], safe_json_encode(list())) + return 1 /datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE) @@ -736,7 +749,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car belly_prefs = json_from_file["belly_prefs"] //gear loadout - loadout_data = safe_json_decode(S["loadout"]) + if(S["loadout"]) + loadout_data = safe_json_decode(S["loadout"]) + else + loadout_data = list() //try to fix any outdated data if necessary //preference updating will handle saving the updated data for us. diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm index d9e3bc6165..6bdf3cff8e 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm @@ -195,7 +195,7 @@ /obj/machinery/microwave/AltClick(mob/user) . = ..() if(user.canUseTopic(src, !hasSiliconAccessInArea(user))) - cook() + cook(user) return TRUE /obj/machinery/microwave/ui_interact(mob/user) @@ -226,7 +226,7 @@ if("eject") eject() if("use") - cook() + cook(user) if("examine") examine(user) @@ -236,7 +236,7 @@ AM.forceMove(drop_location()) ingredients.Cut() -/obj/machinery/microwave/proc/cook() +/obj/machinery/microwave/proc/cook(mob/user) if(stat & (NOPOWER|BROKEN)) return if(operating || broken > 0 || panel_open || !anchored || dirty == 100) @@ -257,7 +257,7 @@ start_can_fail() return break - start() + start(user) /obj/machinery/microwave/proc/turn_on() visible_message("\The [src] turns on.", "You hear a microwave humming.") @@ -277,9 +277,9 @@ #define MICROWAVE_MUCK 1 #define MICROWAVE_PRE 2 -/obj/machinery/microwave/proc/start() +/obj/machinery/microwave/proc/start(mob/user) turn_on() - loop(MICROWAVE_NORMAL, 10) + loop(MICROWAVE_NORMAL, 10, user = user) /obj/machinery/microwave/proc/start_can_fail() turn_on() @@ -292,7 +292,7 @@ update_icon() loop(MICROWAVE_MUCK, 4) -/obj/machinery/microwave/proc/loop(type, time, wait = max(12 - 2 * productivity, 2)) // standard wait is 10 +/obj/machinery/microwave/proc/loop(type, time, wait = max(12 - 2 * productivity, 2), mob/user) // standard wait is 10 if(stat & (NOPOWER|BROKEN)) if(type == MICROWAVE_PRE) pre_fail() @@ -300,7 +300,7 @@ if(!time) switch(type) if(MICROWAVE_NORMAL) - loop_finish() + loop_finish(user) if(MICROWAVE_MUCK) muck_finish() if(MICROWAVE_PRE) @@ -308,16 +308,21 @@ return time-- use_power(500) - addtimer(CALLBACK(src, .proc/loop, type, time, wait), wait) + addtimer(CALLBACK(src, .proc/loop, type, time, wait, user), wait) -/obj/machinery/microwave/proc/loop_finish() +/obj/machinery/microwave/proc/loop_finish(mob/user) operating = FALSE var/metal = 0 + var/cooked_food = 0 for(var/obj/item/O in ingredients) - O.microwave_act(src) + var/cooked_result = O.microwave_act(src) + if(!istype(cooked_result, /obj/item/reagent_containers/food/snacks/badrecipe)) + cooked_food += 1 if(O.custom_materials?.len) metal += O.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] + if(cooked_food && user.client) + user.client.increment_progress("cook", cooked_food) if(metal) spark() @@ -336,8 +341,8 @@ spark() after_finish_loop() -/obj/machinery/microwave/proc/pre_success() - loop(MICROWAVE_NORMAL, 10) +/obj/machinery/microwave/proc/pre_success(mob/user) + loop(MICROWAVE_NORMAL, 10, user) /obj/machinery/microwave/proc/muck_finish() visible_message("\The [src] gets covered in muck!") diff --git a/code/modules/mining/point_bank.dm b/code/modules/mining/point_bank.dm index 11f23a5d7c..f18b62635f 100644 --- a/code/modules/mining/point_bank.dm +++ b/code/modules/mining/point_bank.dm @@ -30,6 +30,8 @@ if(points) if(I) I.mining_points += points + if(usr.client) + usr.client.increment_progress("miner", points) points = 0 else to_chat(usr, "No ID detected.") diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index 276b5c9458..084a2c3649 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/obj/bedsheets.dmi b/icons/obj/bedsheets.dmi index 05535334cf..f62dd34c66 100644 Binary files a/icons/obj/bedsheets.dmi and b/icons/obj/bedsheets.dmi differ diff --git a/modular_citadel/code/modules/client/loadout/unlockable.dm b/modular_citadel/code/modules/client/loadout/unlockable.dm new file mode 100644 index 0000000000..6e522812b8 --- /dev/null +++ b/modular_citadel/code/modules/client/loadout/unlockable.dm @@ -0,0 +1,30 @@ +/datum/gear/unlockable + category = LOADOUT_CATEGORY_UNLOCKABLE + slot = SLOT_NECK + + var/progress_required //what does our progress need to be to unlock it + var/progress_key //what is the key used to retrieve existing progress for this unlockable + +/datum/gear/unlockable/janitor + name = "Janitor Bedsheet" + description = "Clean 100 messes with a mop to unlock this. It has a warning sign on!" + path = /obj/item/bedsheet/unlockable/janitor + + progress_required = 100 + progress_key = "janitor" + +/datum/gear/unlockable/cook + name = "Cook Bedsheet" + description = "Cook 250 items using the microwave to unlock this. It has a microwave on!" + path = /obj/item/bedsheet/unlockable/cook + + progress_required = 250 + progress_key = "cook" + +/datum/gear/unlockable/miner + name = "Miner Bedsheet" + description = "Redeem a total of 100,000 miner points to unlock this. It's made out of goliath hide!" + path = /obj/item/bedsheet/unlockable/miner + + progress_required = 100000 + progress_key = "miner" \ No newline at end of file diff --git a/tgstation.dme b/tgstation.dme index 2b00eb6b98..ed6b50a573 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3609,6 +3609,7 @@ #include "modular_citadel\code\modules\client\loadout\shoes.dm" #include "modular_citadel\code\modules\client\loadout\suit.dm" #include "modular_citadel\code\modules\client\loadout\uniform.dm" +#include "modular_citadel\code\modules\client\loadout\unlockable.dm" #include "modular_citadel\code\modules\client\verbs\who.dm" #include "modular_citadel\code\modules\clothing\neck.dm" #include "modular_citadel\code\modules\clothing\trek.dm" |