diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 65ec4589a5..a1cb45ba61 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -357,17 +357,25 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" dat += "
" - var/client_file = user.client.Import() + var/savefile/client_file = user.client.Import() var/savefile_name - if(client_file) - var/savefile/cache_savefile = new(user.client.Import()) - if(!cache_savefile["deleted"] || savefile_needs_update(cache_savefile) != -2) - cache_savefile["real_name"] >> savefile_name + if(istype(client_file, /savefile)) + if(!client_file["deleted"] || savefile_needs_update(client_file) != -2) + client_file["real_name"] >> savefile_name dat += "Local storage: [savefile_name ? savefile_name : "Empty"]" dat += "
" dat += "Export current slot" dat += "Import into current slot" dat += "Delete locally saved character" + dat += "
" + dat += "[offer ? "Cancel offer" : "Offer slot"]" + dat += "Retrieve offered character" + if(offer) + dat += "
" + dat += "The redemption code is [offer.redemption_code]" + dat += "
" + dat += "The offer will automatically be cancelled if there is an error, or if someone takes it" + dat += "
" dat += "
" @@ -3469,6 +3477,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(istype(S, /savefile)) if(istype(load_character(provided = S), /savefile)) tgui_alert_async(user, "Successfully loaded character slot.") + save_character(TRUE) else tgui_alert_async(user, "Failed loading character slot") return @@ -3480,6 +3489,63 @@ GLOBAL_LIST_EMPTY(preferences_datums) user.client.clear_export() tgui_alert_async(user, "Local save data erased.") + if("give_slot") + if(!QDELETED(offer)) + var/datum/character_offer_instance/offer_datum = LAZYACCESS(GLOB.character_offers, offer.redemption_code) + if(!offer_datum) + return + qdel(offer_datum) + else + var/savefile/S = save_character(export = TRUE) + if(istype(S, /savefile)) + var/datum/character_offer_instance/offer_datum = new(usr.ckey, S) + if(QDELETED(offer_datum)) + tgui_alert_async(usr, "Could not set up offer, try again later") + return + offer_datum.RegisterSignal(usr, COMSIG_MOB_CLIENT_LOGOUT, TYPE_PROC_REF(/datum/character_offer_instance, on_quit)) + offer = offer_datum + tgui_alert_async(usr, "The redemption code is [offer_datum.redemption_code], give it to the receiver") + + if("retrieve_slot") + if(!LAZYLEN(GLOB.character_offers)) + tgui_alert_async(usr, "There are no active offers") + return + var/retrieve_code = input(usr, "Input the 5 digit redemption code") as text|null + if(!retrieve_code) + return + if(!text2num(retrieve_code)) + tgui_alert_async(usr, "Only numbers allowed") + return + if(length(retrieve_code) != 5) + tgui_alert_async(usr, "Exactly 5 digits, no less, no more, try again") + return + var/datum/character_offer_instance/offer_datum = LAZYACCESS(GLOB.character_offers, retrieve_code) + if(!offer_datum) + tgui_alert_async(usr, "This is an invalid code!") + return + var/savefile/savefile = offer_datum.character_savefile + var/mob/living/the_owner = get_mob_by_ckey(offer_datum.owner_ckey) + if(savefile_needs_update(savefile) == -2) + tgui_alert_async(usr, "Something's wrong, this savefile is corrupted.") + to_chat(the_owner, span_boldwarning("Something went wrong with the trade, it's been canceled.")) + qdel(offer_datum) + return + var/character_name = savefile["real_name"] + if(tgui_alert(usr, "You are overwriting the currently selected slot with the character [character_name]", "Are you sure?", buttons = list("Yes, load this character deleting the currently selected slot", "No")) == "No") + return + if(QDELETED(offer_datum)) + tgui_alert_async(usr, "This character is no longer available, such a shame!") + return + to_chat(the_owner, span_boldwarning("[usr.key] has retrieved your character, [character_name]!")) + if(!load_character(provided = savefile)) + tgui_alert_async(usr, "Something went wrong loading the savefile, even though it has already been checked, please report this issue!") + to_chat(the_owner, span_boldwarning("Something went wrong at the final step of the trade, report this.")) + qdel(offer_datum) + return + tgui_alert_async(usr, "Successfully received [character_name]!") + save_character(TRUE) + qdel(offer_datum) + if(href_list["preference"] == "gear") if(href_list["clear_loadout"]) loadout_data["SAVE_[loadout_slot]"] = list() diff --git a/modular_sand/code/modules/character_trading/character_trading.dm b/modular_sand/code/modules/character_trading/character_trading.dm new file mode 100644 index 0000000000..62d36d3631 --- /dev/null +++ b/modular_sand/code/modules/character_trading/character_trading.dm @@ -0,0 +1,41 @@ +#define REDEMPTION_CODE_GENERATION_ATTEMPTS 5 + +GLOBAL_LIST_INIT(character_offers, list()) + +/datum/character_offer_instance + var/owner_ckey + var/savefile/character_savefile + var/redemption_code + +/datum/character_offer_instance/New(owner_ckey, character_savefile) + . = ..() + if(!owner_ckey || !character_savefile) + qdel(src) + return + src.owner_ckey = owner_ckey + src.character_savefile = character_savefile + + // 5 digit number, no fucking way some idiot is guessing this + var/attempts = 0 + while(!redemption_code || LAZYFIND(GLOB.character_offers, redemption_code)) + if(attempts >= REDEMPTION_CODE_GENERATION_ATTEMPTS) + qdel(src) + return + redemption_code = "[random_nukecode()]" + attempts++ + + LAZYSET(GLOB.character_offers, redemption_code, src) + +/datum/character_offer_instance/Destroy(force, ...) + var/datum/preferences/to_remove = LAZYACCESS(GLOB.preferences_datums, owner_ckey) + to_remove.offer = null + LAZYREMOVE(GLOB.character_offers, redemption_code) + owner_ckey = null + character_savefile = null + redemption_code = null + return ..() + +/datum/character_offer_instance/proc/on_quit() + qdel(src) + +#undef REDEMPTION_CODE_GENERATION_ATTEMPTS diff --git a/modular_sand/code/modules/client/preferences.dm b/modular_sand/code/modules/client/preferences.dm index 3bc14f3e50..5613c034ba 100644 --- a/modular_sand/code/modules/client/preferences.dm +++ b/modular_sand/code/modules/client/preferences.dm @@ -11,6 +11,8 @@ /// Chance of moaning during an interaction var/moaning_multiplier = 65 + var/datum/character_offer_instance/offer + //SANDSTORM EDIT - extra language /datum/preferences/proc/SetLanguage(mob/user) var/list/dat = list() diff --git a/tgstation.dme b/tgstation.dme index eac4b2b968..821cf07e66 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4188,6 +4188,7 @@ #include "modular_sand\code\modules\cargo\packs\misc.dm" #include "modular_sand\code\modules\cargo\packs\supply_pack.dm" #include "modular_sand\code\modules\cargo\packs\vending.dm" +#include "modular_sand\code\modules\character_trading\character_trading.dm" #include "modular_sand\code\modules\client\asset_cache.dm" #include "modular_sand\code\modules\client\client_procs.dm" #include "modular_sand\code\modules\client\preferences.dm"