mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
[MIRROR] Fixes savefile corruption bug and allows character swapping (#11406)
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c58ead6223
commit
4d3de029e3
@@ -192,6 +192,12 @@
|
|||||||
stun_time -= min(flicker_break_chance / 5, 1)
|
stun_time -= min(flicker_break_chance / 5, 1)
|
||||||
return stun_time
|
return stun_time
|
||||||
|
|
||||||
|
///Sees if the savefile we have selected in CHARACTER SETUP is the same as our ACTIVE CHARACTER savefile.
|
||||||
|
/datum/component/shadekin/proc/correct_savefile_selected()
|
||||||
|
if(owner.client.prefs.default_slot == owner.mind.loaded_from_slot)
|
||||||
|
return TRUE
|
||||||
|
return FALSE
|
||||||
|
|
||||||
/datum/component/shadekin/tgui_interact(mob/user, datum/tgui/ui)
|
/datum/component/shadekin/tgui_interact(mob/user, datum/tgui/ui)
|
||||||
ui = SStgui.try_update_ui(user, src, ui)
|
ui = SStgui.try_update_ui(user, src, ui)
|
||||||
if(!ui)
|
if(!ui)
|
||||||
@@ -208,6 +214,7 @@
|
|||||||
"no_retreat" = no_retreat,
|
"no_retreat" = no_retreat,
|
||||||
"nutrition_energy_conversion" = nutrition_energy_conversion,
|
"nutrition_energy_conversion" = nutrition_energy_conversion,
|
||||||
"extended_kin" = extended_kin,
|
"extended_kin" = extended_kin,
|
||||||
|
"savefile_selected" = correct_savefile_selected()
|
||||||
)
|
)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@@ -227,14 +234,14 @@
|
|||||||
if(!isnum(new_time))
|
if(!isnum(new_time))
|
||||||
return FALSE
|
return FALSE
|
||||||
flicker_time = new_time
|
flicker_time = new_time
|
||||||
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_time, new_time, WRITE_PREF_MANUAL)
|
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_time, new_time, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
|
||||||
return TRUE
|
return TRUE
|
||||||
if("adjust_color")
|
if("adjust_color")
|
||||||
var/set_new_color = tgui_color_picker(ui.user, "Select a color you wish the lights to flicker as (Default is #E0EFF0)", "Color Selector", flicker_color)
|
var/set_new_color = tgui_color_picker(ui.user, "Select a color you wish the lights to flicker as (Default is #E0EFF0)", "Color Selector", flicker_color)
|
||||||
if(!set_new_color)
|
if(!set_new_color)
|
||||||
return FALSE
|
return FALSE
|
||||||
flicker_color = set_new_color
|
flicker_color = set_new_color
|
||||||
ui.user.write_preference_directly(/datum/preference/color/living/flicker_color, set_new_color, WRITE_PREF_MANUAL)
|
ui.user.write_preference_directly(/datum/preference/color/living/flicker_color, set_new_color, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
|
||||||
return TRUE
|
return TRUE
|
||||||
if("adjust_break")
|
if("adjust_break")
|
||||||
var/new_break_chance = text2num(params["val"])
|
var/new_break_chance = text2num(params["val"])
|
||||||
@@ -242,7 +249,7 @@
|
|||||||
if(!isnum(new_break_chance))
|
if(!isnum(new_break_chance))
|
||||||
return FALSE
|
return FALSE
|
||||||
flicker_break_chance = new_break_chance
|
flicker_break_chance = new_break_chance
|
||||||
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_break_chance, new_break_chance, WRITE_PREF_MANUAL)
|
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_break_chance, new_break_chance, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
|
||||||
return TRUE
|
return TRUE
|
||||||
if("adjust_distance")
|
if("adjust_distance")
|
||||||
var/new_distance = text2num(params["val"])
|
var/new_distance = text2num(params["val"])
|
||||||
@@ -250,16 +257,16 @@
|
|||||||
if(!isnum(new_distance))
|
if(!isnum(new_distance))
|
||||||
return FALSE
|
return FALSE
|
||||||
flicker_distance = new_distance
|
flicker_distance = new_distance
|
||||||
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_distance, new_distance, WRITE_PREF_MANUAL)
|
ui.user.write_preference_directly(/datum/preference/numeric/living/flicker_distance, new_distance, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
|
||||||
return TRUE
|
return TRUE
|
||||||
if("toggle_retreat")
|
if("toggle_retreat")
|
||||||
var/new_retreat = !no_retreat
|
var/new_retreat = !no_retreat
|
||||||
no_retreat = !no_retreat
|
no_retreat = !no_retreat
|
||||||
ui.user.write_preference_directly(/datum/preference/toggle/living/dark_retreat_toggle, new_retreat, WRITE_PREF_MANUAL)
|
ui.user.write_preference_directly(/datum/preference/toggle/living/dark_retreat_toggle, new_retreat, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
|
||||||
if("toggle_nutrition")
|
if("toggle_nutrition")
|
||||||
var/new_retreat = !nutrition_energy_conversion
|
var/new_retreat = !nutrition_energy_conversion
|
||||||
nutrition_energy_conversion = !nutrition_energy_conversion
|
nutrition_energy_conversion = !nutrition_energy_conversion
|
||||||
ui.user.write_preference_directly(/datum/preference/toggle/living/shadekin_nutrition_conversion, new_retreat, WRITE_PREF_MANUAL)
|
ui.user.write_preference_directly(/datum/preference/toggle/living/shadekin_nutrition_conversion, new_retreat, WRITE_PREF_MANUAL, save_to_played_slot = TRUE)
|
||||||
|
|
||||||
/mob/living/proc/shadekin_control_panel()
|
/mob/living/proc/shadekin_control_panel()
|
||||||
set name = "Shadekin Control Panel"
|
set name = "Shadekin Control Panel"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
The way datum/mind stuff works has been changed a lot.
|
The way datum/mind stuff works has been changed a lot.
|
||||||
Minds now represent IC characters rather than following a client around constantly.
|
Minds now represent IC characters rather than following a client around constantly.
|
||||||
Guidelines for using minds properly:
|
Guidelines for using minds properly:
|
||||||
- Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living!
|
- Never mind.transfer_to(ghost). The var/current and var/original_character of a mind must always be of type mob/living!
|
||||||
ghost.mind is however used as a reference to the ghost's corpse
|
ghost.mind is however used as a reference to the ghost's corpse
|
||||||
- When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human)
|
- When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human)
|
||||||
the existing mind of the old mob should be transfered to the new mob like so:
|
the existing mind of the old mob should be transfered to the new mob like so:
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
var/key
|
var/key
|
||||||
var/name //replaces mob/var/original_name
|
var/name //replaces mob/var/original_name
|
||||||
var/mob/living/current
|
var/mob/living/current
|
||||||
var/mob/living/original //TODO: remove.not used in any meaningful way ~Carn. First I'll need to tweak the way silicon-mobs handle minds.
|
var/datum/weakref/original_character //replaces /mob/living/original
|
||||||
var/active = 0
|
var/active = 0
|
||||||
|
|
||||||
var/memory
|
var/memory
|
||||||
@@ -508,7 +508,7 @@
|
|||||||
mind.key = key
|
mind.key = key
|
||||||
else
|
else
|
||||||
mind = new /datum/mind(key)
|
mind = new /datum/mind(key)
|
||||||
mind.original = src
|
mind.original_character = WEAKREF(src)
|
||||||
if(SSticker)
|
if(SSticker)
|
||||||
SSticker.minds += mind
|
SSticker.minds += mind
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
player.current = new mob_path(get_turf(player.current))
|
player.current = new mob_path(get_turf(player.current))
|
||||||
player.transfer_to(player.current)
|
player.transfer_to(player.current)
|
||||||
if(holder) qdel(holder)
|
if(holder) qdel(holder)
|
||||||
player.original = player.current
|
player.original_character = WEAKREF(player.current)
|
||||||
if(!preserve_appearance && (flags & ANTAG_SET_APPEARANCE))
|
if(!preserve_appearance && (flags & ANTAG_SET_APPEARANCE))
|
||||||
spawn(3)
|
spawn(3)
|
||||||
var/mob/living/carbon/human/H = player.current
|
var/mob/living/carbon/human/H = player.current
|
||||||
|
|||||||
@@ -93,8 +93,9 @@ var/datum/antagonist/technomancer/technomancers
|
|||||||
var/text = print_player_lite(player)
|
var/text = print_player_lite(player)
|
||||||
|
|
||||||
var/obj/item/technomancer_core/core
|
var/obj/item/technomancer_core/core
|
||||||
if(player.original)
|
var/mob/living/original = player.original_character?.resolve()
|
||||||
core = locate() in player.original
|
if(original)
|
||||||
|
core = locate() in original
|
||||||
if(core)
|
if(core)
|
||||||
text += "<br>Bought [english_list(core.spells)], and used \a [core]."
|
text += "<br>Bought [english_list(core.spells)], and used \a [core]."
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ var/datum/antagonist/rogue_ai/malf
|
|||||||
player.current = new mob_path(get_turf(player.current), null, null, 1)
|
player.current = new mob_path(get_turf(player.current), null, null, 1)
|
||||||
player.transfer_to(player.current)
|
player.transfer_to(player.current)
|
||||||
if(holder) qdel(holder)
|
if(holder) qdel(holder)
|
||||||
player.original = player.current
|
player.original_character = WEAKREF(player.current)
|
||||||
return player.current
|
return player.current
|
||||||
|
|
||||||
/datum/antagonist/rogue_ai/set_antag_name(var/mob/living/silicon/player)
|
/datum/antagonist/rogue_ai/set_antag_name(var/mob/living/silicon/player)
|
||||||
|
|||||||
@@ -530,21 +530,23 @@ GLOBAL_LIST_EMPTY(additional_antag_types)
|
|||||||
|
|
||||||
continue //Happy connected client
|
continue //Happy connected client
|
||||||
for(var/mob/observer/dead/D in GLOB.dead_mob_list)
|
for(var/mob/observer/dead/D in GLOB.dead_mob_list)
|
||||||
if(D.mind && (D.mind.original == L || D.mind.current == L))
|
if(D.mind)
|
||||||
if(L.stat == DEAD)
|
var/mob/living/original = D.mind.original_character?.resolve()
|
||||||
if(L.suiciding) //Suicider
|
if((original && original == L) || D.mind.current == L)
|
||||||
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Suicide"))])<br>"
|
if(L.stat == DEAD)
|
||||||
continue //Disconnected client
|
if(L.suiciding) //Suicider
|
||||||
|
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Suicide"))])<br>"
|
||||||
|
continue //Disconnected client
|
||||||
|
else
|
||||||
|
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] (Dead)<br>"
|
||||||
|
continue //Dead mob, ghost abandoned
|
||||||
else
|
else
|
||||||
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] (Dead)<br>"
|
if(D.can_reenter_corpse)
|
||||||
continue //Dead mob, ghost abandoned
|
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Adminghosted"))])<br>"
|
||||||
else
|
continue //Lolwhat
|
||||||
if(D.can_reenter_corpse)
|
else
|
||||||
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Adminghosted"))])<br>"
|
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Ghosted"))])<br>"
|
||||||
continue //Lolwhat
|
continue //Ghosted while alive
|
||||||
else
|
|
||||||
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Ghosted"))])<br>"
|
|
||||||
continue //Ghosted while alive
|
|
||||||
|
|
||||||
continue // CHOMPEdit: Escape infinite loop in case there's nobody connected. Shouldn't happen ever, but.
|
continue // CHOMPEdit: Escape infinite loop in case there's nobody connected. Shouldn't happen ever, but.
|
||||||
|
|
||||||
|
|||||||
@@ -325,7 +325,8 @@ GLOBAL_LIST_EMPTY(all_objectives)
|
|||||||
/datum/objective/survive/check_completion()
|
/datum/objective/survive/check_completion()
|
||||||
if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
|
if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
|
||||||
return 0 //Brains no longer win survive objectives. --NEO
|
return 0 //Brains no longer win survive objectives. --NEO
|
||||||
if(issilicon(owner.current) && owner.current != owner.original)
|
var/mob/living/original = owner.original_character?.resolve()
|
||||||
|
if(issilicon(owner.current) && (original && (owner.current != original)))
|
||||||
return 0
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|||||||
@@ -144,8 +144,8 @@
|
|||||||
continue
|
continue
|
||||||
sendPDAs["[P.name]"] = "\ref[P]"
|
sendPDAs["[P.name]"] = "\ref[P]"
|
||||||
data["possibleRecipients"] = sendPDAs
|
data["possibleRecipients"] = sendPDAs
|
||||||
|
var/mob/living/original = user.mind.original_character?.resolve()
|
||||||
data["isMalfAI"] = ((isAI(user) || isrobot(user)) && (user.mind.special_role && user.mind.original == user))
|
data["isMalfAI"] = ((isAI(user) || isrobot(user)) && (user.mind.special_role && (original && original == user)))
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@@ -210,7 +210,8 @@
|
|||||||
temp = noserver
|
temp = noserver
|
||||||
//Hack the Console to get the password
|
//Hack the Console to get the password
|
||||||
if("hack")
|
if("hack")
|
||||||
if((isAI(ui.user) || isrobot(ui.user)) && (ui.user.mind.special_role && ui.user.mind.original == ui.user))
|
var/mob/living/original = ui.user.mind.original_character?.resolve()
|
||||||
|
if((isAI(ui.user) || isrobot(ui.user)) && (ui.user.mind.special_role && (original && original == ui.user)))
|
||||||
hacking = 1
|
hacking = 1
|
||||||
update_icon()
|
update_icon()
|
||||||
//Time it takes to bruteforce is dependant on the password length.
|
//Time it takes to bruteforce is dependant on the password length.
|
||||||
|
|||||||
@@ -92,7 +92,8 @@
|
|||||||
return TRUE
|
return TRUE
|
||||||
if(!isAI(user))
|
if(!isAI(user))
|
||||||
return FALSE
|
return FALSE
|
||||||
return (user.mind.special_role && user.mind.original == user)
|
var/mob/living/original = user.mind.original_character?.resolve()
|
||||||
|
return (user.mind.special_role && (original && original == user))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the user is allowed to hack a specific borg
|
* Check if the user is allowed to hack a specific borg
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ var/const/preview_icons = 'icons/mob/human_races/preview.dmi'
|
|||||||
|
|
||||||
data["b_type"] = pref.b_type
|
data["b_type"] = pref.b_type
|
||||||
data["digitigrade"] = pref.digitigrade
|
data["digitigrade"] = pref.digitigrade
|
||||||
|
data["tail_layering"] = pref.read_preference(/datum/preference/choiced/human/tail_layering)
|
||||||
|
|
||||||
data["synth_color_toggle"] = pref.synth_color
|
data["synth_color_toggle"] = pref.synth_color
|
||||||
data["synth_color"] = pref.read_preference(/datum/preference/color/human/synth_color)
|
data["synth_color"] = pref.read_preference(/datum/preference/color/human/synth_color)
|
||||||
@@ -996,6 +997,13 @@ var/const/preview_icons = 'icons/mob/human_races/preview.dmi'
|
|||||||
pref.digitigrade = !pref.digitigrade
|
pref.digitigrade = !pref.digitigrade
|
||||||
return TOPIC_REFRESH_UPDATE_PREVIEW
|
return TOPIC_REFRESH_UPDATE_PREVIEW
|
||||||
|
|
||||||
|
if("set_tail_layering")
|
||||||
|
var/new_tail_layering = tgui_input_list(user, "Select a tail layer.", "Set Tail Layer", GLOB.tail_layer_options,
|
||||||
|
pref.read_preference(/datum/preference/choiced/human/tail_layering))
|
||||||
|
if(new_tail_layering)
|
||||||
|
pref.update_preference_by_type(/datum/preference/choiced/human/tail_layering, new_tail_layering)
|
||||||
|
return TOPIC_REFRESH_UPDATE_PREVIEW
|
||||||
|
|
||||||
if("synth_color_toggle")
|
if("synth_color_toggle")
|
||||||
pref.synth_color = !pref.synth_color
|
pref.synth_color = !pref.synth_color
|
||||||
return TOPIC_REFRESH_UPDATE_PREVIEW
|
return TOPIC_REFRESH_UPDATE_PREVIEW
|
||||||
|
|||||||
@@ -318,10 +318,17 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
|
|||||||
|
|
||||||
/// Write a /datum/preference type and return its value directly to the json.
|
/// Write a /datum/preference type and return its value directly to the json.
|
||||||
/// Please use SScharacter_setup.queue_preferences_save(prefs) when you edit multiple at once and set direct_write to WRITE_PREF_MANUAL
|
/// Please use SScharacter_setup.queue_preferences_save(prefs) when you edit multiple at once and set direct_write to WRITE_PREF_MANUAL
|
||||||
/mob/proc/write_preference_directly(preference_type, preference_value, write_mode = WRITE_PREF_INSTANT)
|
/// Additionally, if you want something to be changed IN ROUND and change a pref for THAT CHARACTER'S SAVESLOT, ensure save_to_played_slot = TRUE!
|
||||||
|
/mob/proc/write_preference_directly(preference_type, preference_value, write_mode = WRITE_PREF_INSTANT, save_to_played_slot)
|
||||||
|
var/remembered_default
|
||||||
|
if(save_to_played_slot && (mind.loaded_from_slot != client?.prefs?.default_slot))
|
||||||
|
remembered_default = client?.prefs?.default_slot
|
||||||
|
client?.prefs?.load_character(mind.loaded_from_slot)
|
||||||
var/success = client?.prefs?.write_preference_by_type(preference_type, preference_value, write_mode)
|
var/success = client?.prefs?.write_preference_by_type(preference_type, preference_value, write_mode)
|
||||||
if(success)
|
if(success)
|
||||||
client?.prefs?.value_cache[preference_type] = preference_value
|
client?.prefs?.value_cache[preference_type] = preference_value
|
||||||
|
if(remembered_default)
|
||||||
|
client?.prefs?.return_to_character_slot(src, remembered_default)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
/// Set a /datum/preference entry.
|
/// Set a /datum/preference entry.
|
||||||
|
|||||||
@@ -136,9 +136,6 @@
|
|||||||
switch(action)
|
switch(action)
|
||||||
// Basic actions
|
// Basic actions
|
||||||
if("load")
|
if("load")
|
||||||
if(!isnewplayer(ui.user))
|
|
||||||
to_chat(ui.user, span_userdanger("You can't change your character slot while being in round."))
|
|
||||||
return FALSE
|
|
||||||
if(!IsGuestKey(ui.user.key))
|
if(!IsGuestKey(ui.user.key))
|
||||||
open_load_dialog(ui.user)
|
open_load_dialog(ui.user)
|
||||||
. = TRUE
|
. = TRUE
|
||||||
|
|||||||
@@ -76,6 +76,14 @@ var/global/client_record_update_lock = FALSE
|
|||||||
playsound(COM, 'sound/machines/deniedbeep.ogg', 50, 0)
|
playsound(COM, 'sound/machines/deniedbeep.ogg', 50, 0)
|
||||||
return "Update syncronization failed (OOC: Record's owner is offline)"
|
return "Update syncronization failed (OOC: Record's owner is offline)"
|
||||||
|
|
||||||
|
var/datum/preferences/P = C.prefs
|
||||||
|
if(P.default_slot != M.mind.loaded_from_slot)
|
||||||
|
if(COM && !QDELETED(COM))
|
||||||
|
COM.visible_message(span_notice("\The [COM] buzzes!"))
|
||||||
|
playsound(COM, 'sound/machines/deniedbeep.ogg', 50, 0)
|
||||||
|
to_chat(M, span_warning("[user] attempted to update your [record_string] record, but your current character slot does not match your played slot. Please ensure your currently played character is selected in your Character Setup."))
|
||||||
|
return "Update syncronization failed (OOC: Player's current character slot does not match their played slot. They have been informed.)"
|
||||||
|
|
||||||
var/choice = tgui_alert(M, "Your [record_string] record has been updated from the a records console by [user]. Please review the changes made to your [record_string] record. Accepting these changes will SAVE your CURRENT character slot! If your new [record_string] record has errors, it is recomended to have it corrected IC instead of editing it yourself.", "Record Updated", list("Review Changes","DENY"))
|
var/choice = tgui_alert(M, "Your [record_string] record has been updated from the a records console by [user]. Please review the changes made to your [record_string] record. Accepting these changes will SAVE your CURRENT character slot! If your new [record_string] record has errors, it is recomended to have it corrected IC instead of editing it yourself.", "Record Updated", list("Review Changes","DENY"))
|
||||||
if(!choice || choice == "DENY")
|
if(!choice || choice == "DENY")
|
||||||
message_admins("[active.fields["name"]] refused [record_string] record update from [user] without review.")
|
message_admins("[active.fields["name"]] refused [record_string] record update from [user] without review.")
|
||||||
@@ -84,7 +92,6 @@ var/global/client_record_update_lock = FALSE
|
|||||||
playsound(COM, 'sound/machines/deniedbeep.ogg', 50, 0)
|
playsound(COM, 'sound/machines/deniedbeep.ogg', 50, 0)
|
||||||
return "Update syncronization failed (OOC: Player refused without review)"
|
return "Update syncronization failed (OOC: Player refused without review)"
|
||||||
|
|
||||||
var/datum/preferences/P = C.prefs
|
|
||||||
var/new_data = strip_html_simple(tgui_input_text(M,"Please review [user]'s changes to your [record_string] record before confirming. Confirming will SAVE your CURRENT character slot! If your new [record_string] record major errors, it is recomended to have it corrected IC instead of editing it yourself.","Character Preference", html_decode(active.fields["notes"]), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
|
var/new_data = strip_html_simple(tgui_input_text(M,"Please review [user]'s changes to your [record_string] record before confirming. Confirming will SAVE your CURRENT character slot! If your new [record_string] record major errors, it is recomended to have it corrected IC instead of editing it yourself.","Character Preference", html_decode(active.fields["notes"]), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
|
||||||
if(!new_data)
|
if(!new_data)
|
||||||
message_admins("[active.fields["name"]] refused [record_string] record update from [user] with review.")
|
message_admins("[active.fields["name"]] refused [record_string] record update from [user] with review.")
|
||||||
|
|||||||
@@ -76,8 +76,6 @@
|
|||||||
if(!tail_option)
|
if(!tail_option)
|
||||||
return
|
return
|
||||||
tail_layering = tail_option
|
tail_layering = tail_option
|
||||||
write_preference_directly(/datum/preference/choiced/human/tail_layering, input)
|
|
||||||
|
|
||||||
update_tail_showing()
|
update_tail_showing()
|
||||||
|
|
||||||
/mob/living/carbon/human/verb/hide_wings_vr()
|
/mob/living/carbon/human/verb/hide_wings_vr()
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
/mob/living/silicon/robot/show_laws(var/everyone = 0)
|
/mob/living/silicon/robot/show_laws(var/everyone = 0)
|
||||||
laws_sanity_check()
|
laws_sanity_check()
|
||||||
var/who
|
var/who
|
||||||
|
var/mob/living/original
|
||||||
|
if(mind)
|
||||||
|
original = mind.original_character?.resolve()
|
||||||
|
|
||||||
if (everyone)
|
if (everyone)
|
||||||
who = world
|
who = world
|
||||||
@@ -21,7 +24,7 @@
|
|||||||
photosync()
|
photosync()
|
||||||
to_chat(src, span_infoplain(span_bold("Laws synced with AI, be sure to note any changes.")))
|
to_chat(src, span_infoplain(span_bold("Laws synced with AI, be sure to note any changes.")))
|
||||||
// TODO: Update to new antagonist system.
|
// TODO: Update to new antagonist system.
|
||||||
if(mind && mind.special_role == "traitor" && mind.original == src)
|
if(mind && mind.special_role == "traitor" && (original && original == src))
|
||||||
to_chat(src, span_infoplain(span_bold("Remember, your AI does NOT share or know about your law 0.")))
|
to_chat(src, span_infoplain(span_bold("Remember, your AI does NOT share or know about your law 0.")))
|
||||||
else
|
else
|
||||||
to_chat(src, span_infoplain(span_bold("No AI selected to sync laws with, disabling lawsync protocol.")))
|
to_chat(src, span_infoplain(span_bold("No AI selected to sync laws with, disabling lawsync protocol.")))
|
||||||
@@ -32,7 +35,7 @@
|
|||||||
if(shell) //AI shell
|
if(shell) //AI shell
|
||||||
to_chat(who, span_infoplain(span_bold("Remember, you are an AI remotely controlling your shell, other AIs can be ignored.")))
|
to_chat(who, span_infoplain(span_bold("Remember, you are an AI remotely controlling your shell, other AIs can be ignored.")))
|
||||||
// TODO: Update to new antagonist system.
|
// TODO: Update to new antagonist system.
|
||||||
else if(mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai)
|
else if(mind && (mind.special_role == "traitor" && (original && original == src)) && connected_ai)
|
||||||
to_chat(who, span_infoplain(span_bold("Remember, [connected_ai.name] is technically your master, but your objective comes first.")))
|
to_chat(who, span_infoplain(span_bold("Remember, [connected_ai.name] is technically your master, but your objective comes first.")))
|
||||||
else if(connected_ai)
|
else if(connected_ai)
|
||||||
to_chat(who, span_infoplain(span_bold("Remember, [connected_ai.name] is your master, other AIs can be ignored.")))
|
to_chat(who, span_infoplain(span_bold("Remember, [connected_ai.name] is your master, other AIs can be ignored.")))
|
||||||
|
|||||||
@@ -44,8 +44,9 @@
|
|||||||
if(mind)
|
if(mind)
|
||||||
if(mind.current == src)
|
if(mind.current == src)
|
||||||
mind.current = null
|
mind.current = null
|
||||||
if(mind.original == src)
|
var/mob/living/original = mind.original_character?.resolve()
|
||||||
mind.original = null
|
if(original && original == src)
|
||||||
|
mind.original_character = null
|
||||||
|
|
||||||
. = ..()
|
. = ..()
|
||||||
update_client_z(null)
|
update_client_z(null)
|
||||||
|
|||||||
@@ -464,8 +464,9 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
|||||||
var/realname = C.mob.real_name
|
var/realname = C.mob.real_name
|
||||||
if(C.mob.mind)
|
if(C.mob.mind)
|
||||||
mindname = C.mob.mind.name
|
mindname = C.mob.mind.name
|
||||||
if(C.mob.mind.original && C.mob.mind.original.real_name)
|
var/mob/living/original = C.mob.mind.original_character?.resolve()
|
||||||
realname = C.mob.mind.original.real_name
|
if(original && original.real_name)
|
||||||
|
realname = original.real_name
|
||||||
if(mindname && mindname != realname)
|
if(mindname && mindname != realname)
|
||||||
name = "[realname] died as [mindname]"
|
name = "[realname] died as [mindname]"
|
||||||
else
|
else
|
||||||
@@ -529,10 +530,11 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
|||||||
C = O
|
C = O
|
||||||
else if(istype(O, /datum/mind))
|
else if(istype(O, /datum/mind))
|
||||||
var/datum/mind/M = O
|
var/datum/mind/M = O
|
||||||
|
var/mob/living/original = M.original_character?.resolve()
|
||||||
if(M.current && M.current.client)
|
if(M.current && M.current.client)
|
||||||
C = M.current.client
|
C = M.current.client
|
||||||
else if(M.original && M.original.client)
|
else if(original && original.client)
|
||||||
C = M.original.client
|
C = original.client
|
||||||
|
|
||||||
if(C)
|
if(C)
|
||||||
var/name
|
var/name
|
||||||
|
|||||||
@@ -423,7 +423,7 @@
|
|||||||
|
|
||||||
if(mind)
|
if(mind)
|
||||||
mind.active = 0 //we wish to transfer the key manually
|
mind.active = 0 //we wish to transfer the key manually
|
||||||
mind.original = new_character
|
mind.original_character = WEAKREF(new_character)
|
||||||
mind.loaded_from_ckey = client.ckey
|
mind.loaded_from_ckey = client.ckey
|
||||||
mind.loaded_from_slot = client.prefs.default_slot
|
mind.loaded_from_slot = client.prefs.default_slot
|
||||||
mind.transfer_to(new_character) //won't transfer key since the mind is not active
|
mind.transfer_to(new_character) //won't transfer key since the mind is not active
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
if(mind)
|
if(mind)
|
||||||
mind.transfer_to(O)
|
mind.transfer_to(O)
|
||||||
O.mind.original = O
|
O.mind.original_character = WEAKREF(O)
|
||||||
else
|
else
|
||||||
O.key = key
|
O.key = key
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
if(mind) //TODO
|
if(mind) //TODO
|
||||||
mind.transfer_to(O)
|
mind.transfer_to(O)
|
||||||
if(O.mind.assigned_role == JOB_CYBORG)
|
if(O.mind.assigned_role == JOB_CYBORG)
|
||||||
O.mind.original = O
|
O.mind.original_character = WEAKREF(O)
|
||||||
else if(mind && mind.special_role)
|
else if(mind && mind.special_role)
|
||||||
O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite")
|
O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite")
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export const SubtabBody = (props: {
|
|||||||
s_tone,
|
s_tone,
|
||||||
b_type,
|
b_type,
|
||||||
digitigrade,
|
digitigrade,
|
||||||
|
tail_layering,
|
||||||
synth_color,
|
synth_color,
|
||||||
synth_color_toggle,
|
synth_color_toggle,
|
||||||
synth_markings,
|
synth_markings,
|
||||||
@@ -130,6 +131,11 @@ export const SubtabBody = (props: {
|
|||||||
{digitigrade ? 'Yes' : 'No'}
|
{digitigrade ? 'Yes' : 'No'}
|
||||||
</Button>
|
</Button>
|
||||||
</LabeledList.Item>
|
</LabeledList.Item>
|
||||||
|
<LabeledList.Item label="Tail Layering">
|
||||||
|
<Button inline onClick={() => act('set_tail_layering')}>
|
||||||
|
{tail_layering}
|
||||||
|
</Button>
|
||||||
|
</LabeledList.Item>
|
||||||
<LabeledList.Item label="Blood Type">
|
<LabeledList.Item label="Blood Type">
|
||||||
<Button inline onClick={() => act('blood_type')}>
|
<Button inline onClick={() => act('blood_type')}>
|
||||||
{b_type}
|
{b_type}
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ export type BodyData = {
|
|||||||
body_markings: Record<string, BodyMarking>;
|
body_markings: Record<string, BodyMarking>;
|
||||||
|
|
||||||
tail_style: string;
|
tail_style: string;
|
||||||
|
tail_layering: string;
|
||||||
tail_color1: string;
|
tail_color1: string;
|
||||||
tail_color2: string;
|
tail_color2: string;
|
||||||
tail_color3: string;
|
tail_color3: string;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'tgui-core/components';
|
} from 'tgui-core/components';
|
||||||
|
import { BooleanLike } from 'tgui-core/react';
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
stun_time: number;
|
stun_time: number;
|
||||||
@@ -18,8 +19,9 @@ type Data = {
|
|||||||
flicker_color: string | null;
|
flicker_color: string | null;
|
||||||
flicker_break_chance: number;
|
flicker_break_chance: number;
|
||||||
flicker_distance: number;
|
flicker_distance: number;
|
||||||
no_retreat: number;
|
no_retreat: BooleanLike;
|
||||||
extended_kin: number;
|
extended_kin: BooleanLike;
|
||||||
|
savefile_selected: BooleanLike;
|
||||||
nutrition_energy_conversion: number;
|
nutrition_energy_conversion: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ export const ShadekinConfig = (props) => {
|
|||||||
flicker_break_chance,
|
flicker_break_chance,
|
||||||
flicker_distance,
|
flicker_distance,
|
||||||
no_retreat,
|
no_retreat,
|
||||||
|
savefile_selected,
|
||||||
extended_kin,
|
extended_kin,
|
||||||
nutrition_energy_conversion,
|
nutrition_energy_conversion,
|
||||||
} = data;
|
} = data;
|
||||||
@@ -40,7 +43,7 @@ export const ShadekinConfig = (props) => {
|
|||||||
const isSubtle =
|
const isSubtle =
|
||||||
flicker_time < 5 || flicker_break_chance < 5 || flicker_distance < 5;
|
flicker_time < 5 || flicker_break_chance < 5 || flicker_distance < 5;
|
||||||
|
|
||||||
const windowHeight = (isSubtle ? 220 : 190) + (extended_kin ? 95 : 0);
|
const windowHeight = (isSubtle ? 220 : 190) + (extended_kin ? 95 : 0) + (savefile_selected ? 0 : 90);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Window width={300} height={windowHeight} theme="abductor">
|
<Window width={300} height={windowHeight} theme="abductor">
|
||||||
@@ -51,6 +54,11 @@ export const ShadekinConfig = (props) => {
|
|||||||
<NoticeBox>Subtle Phasing, causes {stun_time} s stun.</NoticeBox>
|
<NoticeBox>Subtle Phasing, causes {stun_time} s stun.</NoticeBox>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
)}
|
)}
|
||||||
|
{!savefile_selected && (
|
||||||
|
<Stack.Item>
|
||||||
|
<NoticeBox>WARNING: Your current selected savefile (in Character Setup) is not the same as your currently loaded savefile. Please select it to prevent savefile corruption.</NoticeBox>
|
||||||
|
</Stack.Item>
|
||||||
|
)}
|
||||||
<Stack.Item>
|
<Stack.Item>
|
||||||
<Section fill title="Light Settings">
|
<Section fill title="Light Settings">
|
||||||
<LabeledList>
|
<LabeledList>
|
||||||
|
|||||||
Reference in New Issue
Block a user