diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index da01956e64..edd9149fa3 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -521,7 +521,8 @@ GLOBAL_LIST_INIT(pda_reskins, list( #define VARSET_TO_LIST(L, V) if(L) L[#V] = V #define VARSET_TO_LIST_IF(L, V, C...) if(L && (C)) L[#V] = V -#define PREF_SAVELOAD_COOLDOWN 5 +#define PREF_LOAD_COOLDOWN 5 +#define PREF_SAVE_COOLDOWN 2 SECONDS #define VOMIT_TOXIC 1 #define VOMIT_PURPLE 2 diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 469f27926a..0b28f4fb2b 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -668,7 +668,7 @@ SSticker.show_roundend_report(owner.client) /datum/action/report/IsAvailable() - return 1 + return TRUE /datum/action/report/Topic(href,href_list) if(usr != owner) diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm index 6b70d8cd45..af49128d25 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/action_button.dm @@ -125,6 +125,7 @@ position_info = SCRN_OBJ_IN_PALETTE user.client.prefs.action_buttons_screen_locs["[name]_[id]"] = position_info + user.client.prefs.queue_save_pref(1 SECONDS, TRUE) /atom/movable/screen/movable/action_button/proc/load_position() var/mob/user = our_hud.mymob @@ -138,6 +139,7 @@ if(!user?.client) return user.client.prefs.action_buttons_screen_locs -= "[name]_[id]" + user.client.prefs.queue_save_pref(1 SECONDS, TRUE) /datum/hud/proc/get_action_buttons_icons() . = list() diff --git a/code/datums/action.dm b/code/datums/action.dm index 29c4fa90da..56697d9b3e 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -16,9 +16,6 @@ /// Where any buttons we create should be by default. Accepts screen_loc and location defines var/default_button_position = SCRN_OBJ_IN_LIST - var/use_target_appearance = FALSE - var/list/target_appearance_matrix //if set, will be used to transform the target button appearance as an arglist. - var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon @@ -134,7 +131,7 @@ ApplyIcon(button, force) - if(!IsAvailable()) + if(!IsAvailable(TRUE)) button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0) else button.color = rgb(255,255,255,255) @@ -225,14 +222,11 @@ /datum/action/item_action check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_LYING|AB_CHECK_CONSCIOUS button_icon_state = null - use_target_appearance = TRUE // If you want to override the normal icon being the item // then change this to an icon state /datum/action/item_action/New(Target) ..() - if(button_icon_state) - use_target_appearance = FALSE var/obj/item/I = target LAZYINITLIST(I.actions) I.actions += src @@ -243,17 +237,43 @@ UNSETEMPTY(I.actions) return ..() -/datum/action/item_action/Trigger() - if(!..()) - return 0 +/datum/action/item_action/Trigger(trigger_flags) + . = ..() + if(!.) + return FALSE if(target) var/obj/item/I = target I.ui_action_click(owner, src) - return 1 + return TRUE + +/datum/action/item_action/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force) + var/obj/item/item_target = target + if(button_icon && button_icon_state) + // If set, use the custom icon that we set instead + // of the item appearence + ..() + else if((target && current_button.appearance_cache != item_target.appearance) || force) //replace with /ref comparison if this is not valid. + var/old_layer = item_target.layer + var/old_plane = item_target.plane + item_target.layer = FLOAT_LAYER //AAAH + item_target.plane = FLOAT_PLANE //^ what that guy said + current_button.filters = null + current_button.cut_overlays() + current_button.add_overlay(item_target) + item_target.layer = old_layer + item_target.plane = old_plane + current_button.appearance_cache = item_target.appearance /datum/action/item_action/toggle_light name = "Toggle Light" +/datum/action/item_action/toggle_light/Trigger(trigger_flags) + if(istype(target, /obj/item/pda)) + var/obj/item/pda/P = target + P.toggle_light(owner) + return + ..() + /datum/action/item_action/toggle_hood name = "Toggle Hood" @@ -403,7 +423,6 @@ /datum/action/item_action/clock/quickbind name = "Quickbind" desc = "If you're seeing this, file a bug report." - use_target_appearance = FALSE var/scripture_index = 0 //the index of the scripture we're associated with /datum/action/item_action/toggle_helmet_flashlight @@ -942,7 +961,7 @@ target.plane = old_plane current_button.appearance_cache = target.appearance -/proc/get_action_of_type(mob/M, var/action_type) +/proc/get_action_of_type(mob/M, action_type) if(!M.actions || !ispath(action_type, /datum/action)) return for(var/datum/action/A in M.actions) diff --git a/code/datums/elements/polychromic.dm b/code/datums/elements/polychromic.dm index 2649a8ee6f..5b60bed6fe 100644 --- a/code/datums/elements/polychromic.dm +++ b/code/datums/elements/polychromic.dm @@ -63,7 +63,7 @@ if(suits_with_helmet_typecache[A.type]) RegisterSignal(A, COMSIG_SUIT_MADE_HELMET, .proc/register_helmet) //you better work now you slut else if(_flags & POLYCHROMIC_ACTION && ismob(A)) //in the event mob update icon procs are ever standarized. - var/datum/action/polychromic/P = new(A) + var/datum/action/item_action/polychromic/P = new(A) RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action) actions_by_atom[A] = P P.Grant(A) @@ -73,7 +73,7 @@ /datum/element/polychromic/Detach(atom/A) . = ..() colors_by_atom -= A - var/datum/action/polychromic/P = actions_by_atom[A] + var/datum/action/item_action/polychromic/P = actions_by_atom[A] if(P) actions_by_atom -= A qdel(P) @@ -146,7 +146,7 @@ /datum/element/polychromic/proc/grant_user_action(atom/source, mob/user, slot) if(slot == ITEM_SLOT_BACKPACK || slot == ITEM_SLOT_LEGCUFFED || slot == ITEM_SLOT_HANDCUFFED || slot == ITEM_SLOT_DEX_STORAGE) return - var/datum/action/polychromic/P = actions_by_atom[source] + var/datum/action/item_action/polychromic/P = actions_by_atom[source] if(!P) P = new (source) P.name = "Modify [source]'\s Colors" @@ -156,7 +156,7 @@ P.Grant(user) /datum/element/polychromic/proc/remove_user_action(atom/source, mob/user) - var/datum/action/polychromic/P = actions_by_atom[source] + var/datum/action/item_action/polychromic/P = actions_by_atom[source] P?.Remove(user) /datum/element/polychromic/proc/activate_action(datum/action/source, atom/target) @@ -197,9 +197,14 @@ helmet_by_suit -= S colors_by_atom -= source -/datum/action/polychromic +/datum/action/item_action/polychromic name = "Modify Polychromic Colors" background_icon_state = "bg_polychromic" - use_target_appearance = TRUE button_icon_state = null - target_appearance_matrix = list(0.8,0,0,0,0.8,0) + check_flags = NONE + +/datum/action/item_action/polychromic/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force) + var/matrix/save_matrix = target.transform + target.transform = matrix(0.8, 0, 0, 0, 0.8, 0) + . = ..() + target.transform = save_matrix diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index bd8a57c850..8e04f591f2 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -29,6 +29,7 @@ GLOBAL_LIST_EMPTY(PDAs) item_flags = NOBLUDGEON w_class = WEIGHT_CLASS_TINY slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT + actions_types = list(/datum/action/item_action/toggle_light) armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) resistance_flags = FIRE_PROOF | ACID_PROOF diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index d6d50c9dbc..14d1183d25 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -41,10 +41,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/last_custom_holoform = 0 //Cooldowns for saving/loading. These are four are all separate due to loading code calling these one after another - var/saveprefcooldown - var/loadprefcooldown - var/savecharcooldown - var/loadcharcooldown + COOLDOWN_DECLARE(saveprefcooldown) + COOLDOWN_DECLARE(loadprefcooldown) + COOLDOWN_DECLARE(savecharcooldown) + COOLDOWN_DECLARE(loadcharcooldown) //game-preferences var/lastchangelog = "" //Saved changlog filesize to detect if there was a change @@ -267,6 +267,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/loadout_errors = 0 + var/pref_queue + var/char_queue + /datum/preferences/New(client/C) parent = C @@ -3212,6 +3215,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) load_character() if("changeslot") + if(char_queue != -1) + deltimer(char_queue) // Do not dare. if(!load_character(text2num(href_list["num"]))) random_character() real_name = random_unique_name(gender) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index afbaba72cd..c01921a46a 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -401,7 +401,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(istype(parent)) to_chat(parent, "You're attempting to load your preferences a little too fast. Wait half a second, then try again.") return FALSE - loadprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN + COOLDOWN_START(src, loadprefcooldown, PREF_LOAD_COOLDOWN) if(!fexists(path)) return FALSE @@ -593,15 +593,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(!GLOB.keybindings_by_name[bindname]) modless_key_bindings -= key -/datum/preferences/proc/save_preferences(bypass_cooldown = FALSE) +/datum/preferences/proc/save_preferences(bypass_cooldown = FALSE, silent = FALSE) if(!path) return 0 if(!bypass_cooldown) if(world.time < saveprefcooldown) if(istype(parent)) - to_chat(parent, "You're attempting to save your preferences a little too fast. Wait half a second, then try again.") + queue_save_pref(PREF_SAVE_COOLDOWN, silent) return 0 - saveprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN + COOLDOWN_START(src, saveprefcooldown, PREF_SAVE_COOLDOWN) + if(pref_queue != -1) + deltimer(pref_queue) var/savefile/S = new /savefile(path) if(!S) return 0 @@ -673,7 +675,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car else WRITE_FILE(S["unlockable_loadout"], safe_json_encode(list())) - return 1 + if(parent && !silent) + to_chat(parent, span_notice("Saved preferences!")) + + return TRUE + +/datum/preferences/proc/queue_save_pref(save_in, silent) + if(parent && !silent) + to_chat(parent, span_notice("Saving preferences in [save_in * 0.1] second\s.")) + if(pref_queue != -1) + deltimer(pref_queue) + pref_queue = addtimer(CALLBACK(src, PROC_REF(save_preferences), TRUE, silent), save_in) /datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE) if(!path) @@ -683,7 +695,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(istype(parent)) to_chat(parent, "You're attempting to load your character a little too fast. Wait half a second, then try again.") return "SLOW THE FUCK DOWN" //the reason this isn't null is to make sure that people don't have their character slots overridden by random chars if they accidentally double-click a slot - loadcharcooldown = world.time + PREF_SAVELOAD_COOLDOWN + COOLDOWN_START(src, loadcharcooldown, PREF_LOAD_COOLDOWN) if(!fexists(path)) return FALSE var/savefile/S = new /savefile(path) @@ -1083,15 +1095,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car return 1 -/datum/preferences/proc/save_character(bypass_cooldown = FALSE) +/datum/preferences/proc/save_character(bypass_cooldown = FALSE, silent = FALSE) if(!path) return 0 if(!bypass_cooldown) if(world.time < savecharcooldown) if(istype(parent)) - to_chat(parent, "You're attempting to save your character a little too fast. Wait half a second, then try again.") + queue_save_char(PREF_SAVE_COOLDOWN, silent) return 0 - savecharcooldown = world.time + PREF_SAVELOAD_COOLDOWN + COOLDOWN_START(src, savecharcooldown, PREF_SAVE_COOLDOWN) + if(char_queue != -1) + deltimer(char_queue) var/savefile/S = new /savefile(path) if(!S) return 0 @@ -1278,8 +1292,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car cit_character_pref_save(S) + if(parent && !silent) + to_chat(parent, span_notice("Saved character slot!")) + return 1 +/datum/preferences/proc/queue_save_char(save_in, silent) + if(parent && !silent) + to_chat(parent, span_notice("Saving character in [save_in * 0.1] second\s.")) + if(char_queue != -1) + deltimer(char_queue) + char_queue = addtimer(CALLBACK(src, PROC_REF(save_character), TRUE, silent), save_in) #undef SAVEFILE_VERSION_MAX #undef SAVEFILE_VERSION_MIN diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm index 0d8aa60ba5..e5ad047931 100644 --- a/code/modules/clothing/suits/wiz_robe.dm +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -315,7 +315,7 @@ /obj/item/clothing/suit/space/hardsuit/shielded/wizard/ComponentInitialize() . = ..() - AddElement(/datum/element/spellcasting, SPELL_WIZARD_HAT, ITEM_SLOT_HEAD) + AddElement(/datum/element/spellcasting, SPELL_WIZARD_ROBE, ITEM_SLOT_OCLOTHING) /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard name = "battlemage helmet" @@ -330,7 +330,7 @@ /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/ComponentInitialize() . = ..() - AddElement(/datum/element/spellcasting, SPELL_WIZARD_ROBE, ITEM_SLOT_OCLOTHING) + AddElement(/datum/element/spellcasting, SPELL_WIZARD_HAT, ITEM_SLOT_HEAD) /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/attack_self(mob/user) return