mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +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)
|
||||
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)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
@@ -208,6 +214,7 @@
|
||||
"no_retreat" = no_retreat,
|
||||
"nutrition_energy_conversion" = nutrition_energy_conversion,
|
||||
"extended_kin" = extended_kin,
|
||||
"savefile_selected" = correct_savefile_selected()
|
||||
)
|
||||
|
||||
return data
|
||||
@@ -227,14 +234,14 @@
|
||||
if(!isnum(new_time))
|
||||
return FALSE
|
||||
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
|
||||
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)
|
||||
if(!set_new_color)
|
||||
return FALSE
|
||||
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
|
||||
if("adjust_break")
|
||||
var/new_break_chance = text2num(params["val"])
|
||||
@@ -242,7 +249,7 @@
|
||||
if(!isnum(new_break_chance))
|
||||
return FALSE
|
||||
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
|
||||
if("adjust_distance")
|
||||
var/new_distance = text2num(params["val"])
|
||||
@@ -250,16 +257,16 @@
|
||||
if(!isnum(new_distance))
|
||||
return FALSE
|
||||
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
|
||||
if("toggle_retreat")
|
||||
var/new_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")
|
||||
var/new_retreat = !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()
|
||||
set name = "Shadekin Control Panel"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The way datum/mind stuff works has been changed a lot.
|
||||
Minds now represent IC characters rather than following a client around constantly.
|
||||
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
|
||||
- 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:
|
||||
@@ -23,7 +23,7 @@
|
||||
var/key
|
||||
var/name //replaces mob/var/original_name
|
||||
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/memory
|
||||
@@ -508,7 +508,7 @@
|
||||
mind.key = key
|
||||
else
|
||||
mind = new /datum/mind(key)
|
||||
mind.original = src
|
||||
mind.original_character = WEAKREF(src)
|
||||
if(SSticker)
|
||||
SSticker.minds += mind
|
||||
else
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
player.current = new mob_path(get_turf(player.current))
|
||||
player.transfer_to(player.current)
|
||||
if(holder) qdel(holder)
|
||||
player.original = player.current
|
||||
player.original_character = WEAKREF(player.current)
|
||||
if(!preserve_appearance && (flags & ANTAG_SET_APPEARANCE))
|
||||
spawn(3)
|
||||
var/mob/living/carbon/human/H = player.current
|
||||
|
||||
@@ -93,8 +93,9 @@ var/datum/antagonist/technomancer/technomancers
|
||||
var/text = print_player_lite(player)
|
||||
|
||||
var/obj/item/technomancer_core/core
|
||||
if(player.original)
|
||||
core = locate() in player.original
|
||||
var/mob/living/original = player.original_character?.resolve()
|
||||
if(original)
|
||||
core = locate() in original
|
||||
if(core)
|
||||
text += "<br>Bought [english_list(core.spells)], and used \a [core]."
|
||||
else
|
||||
|
||||
@@ -89,7 +89,7 @@ var/datum/antagonist/rogue_ai/malf
|
||||
player.current = new mob_path(get_turf(player.current), null, null, 1)
|
||||
player.transfer_to(player.current)
|
||||
if(holder) qdel(holder)
|
||||
player.original = player.current
|
||||
player.original_character = WEAKREF(player.current)
|
||||
return player.current
|
||||
|
||||
/datum/antagonist/rogue_ai/set_antag_name(var/mob/living/silicon/player)
|
||||
|
||||
@@ -530,7 +530,9 @@ GLOBAL_LIST_EMPTY(additional_antag_types)
|
||||
|
||||
continue //Happy connected client
|
||||
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)
|
||||
var/mob/living/original = D.mind.original_character?.resolve()
|
||||
if((original && original == L) || D.mind.current == L)
|
||||
if(L.stat == DEAD)
|
||||
if(L.suiciding) //Suicider
|
||||
msg += "[span_bold(L.name)] ([ckey(D.mind.key)]), the [L.job] ([span_red(span_bold("Suicide"))])<br>"
|
||||
|
||||
@@ -325,7 +325,8 @@ GLOBAL_LIST_EMPTY(all_objectives)
|
||||
/datum/objective/survive/check_completion()
|
||||
if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
|
||||
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 1
|
||||
|
||||
|
||||
@@ -144,8 +144,8 @@
|
||||
continue
|
||||
sendPDAs["[P.name]"] = "\ref[P]"
|
||||
data["possibleRecipients"] = sendPDAs
|
||||
|
||||
data["isMalfAI"] = ((isAI(user) || isrobot(user)) && (user.mind.special_role && user.mind.original == user))
|
||||
var/mob/living/original = user.mind.original_character?.resolve()
|
||||
data["isMalfAI"] = ((isAI(user) || isrobot(user)) && (user.mind.special_role && (original && original == user)))
|
||||
|
||||
return data
|
||||
|
||||
@@ -210,7 +210,8 @@
|
||||
temp = noserver
|
||||
//Hack the Console to get the password
|
||||
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
|
||||
update_icon()
|
||||
//Time it takes to bruteforce is dependant on the password length.
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
return TRUE
|
||||
if(!isAI(user))
|
||||
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
|
||||
|
||||
@@ -319,6 +319,7 @@ var/const/preview_icons = 'icons/mob/human_races/preview.dmi'
|
||||
|
||||
data["b_type"] = pref.b_type
|
||||
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"] = 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
|
||||
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")
|
||||
pref.synth_color = !pref.synth_color
|
||||
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.
|
||||
/// 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)
|
||||
if(success)
|
||||
client?.prefs?.value_cache[preference_type] = preference_value
|
||||
if(remembered_default)
|
||||
client?.prefs?.return_to_character_slot(src, remembered_default)
|
||||
return success
|
||||
|
||||
/// Set a /datum/preference entry.
|
||||
|
||||
@@ -136,9 +136,6 @@
|
||||
switch(action)
|
||||
// Basic actions
|
||||
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))
|
||||
open_load_dialog(ui.user)
|
||||
. = TRUE
|
||||
|
||||
@@ -76,6 +76,14 @@ var/global/client_record_update_lock = FALSE
|
||||
playsound(COM, 'sound/machines/deniedbeep.ogg', 50, 0)
|
||||
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"))
|
||||
if(!choice || choice == "DENY")
|
||||
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)
|
||||
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)
|
||||
if(!new_data)
|
||||
message_admins("[active.fields["name"]] refused [record_string] record update from [user] with review.")
|
||||
|
||||
@@ -76,8 +76,6 @@
|
||||
if(!tail_option)
|
||||
return
|
||||
tail_layering = tail_option
|
||||
write_preference_directly(/datum/preference/choiced/human/tail_layering, input)
|
||||
|
||||
update_tail_showing()
|
||||
|
||||
/mob/living/carbon/human/verb/hide_wings_vr()
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
/mob/living/silicon/robot/show_laws(var/everyone = 0)
|
||||
laws_sanity_check()
|
||||
var/who
|
||||
var/mob/living/original
|
||||
if(mind)
|
||||
original = mind.original_character?.resolve()
|
||||
|
||||
if (everyone)
|
||||
who = world
|
||||
@@ -21,7 +24,7 @@
|
||||
photosync()
|
||||
to_chat(src, span_infoplain(span_bold("Laws synced with AI, be sure to note any changes.")))
|
||||
// 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.")))
|
||||
else
|
||||
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
|
||||
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.
|
||||
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.")))
|
||||
else if(connected_ai)
|
||||
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.current == src)
|
||||
mind.current = null
|
||||
if(mind.original == src)
|
||||
mind.original = null
|
||||
var/mob/living/original = mind.original_character?.resolve()
|
||||
if(original && original == src)
|
||||
mind.original_character = 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
|
||||
if(C.mob.mind)
|
||||
mindname = C.mob.mind.name
|
||||
if(C.mob.mind.original && C.mob.mind.original.real_name)
|
||||
realname = C.mob.mind.original.real_name
|
||||
var/mob/living/original = C.mob.mind.original_character?.resolve()
|
||||
if(original && original.real_name)
|
||||
realname = original.real_name
|
||||
if(mindname && mindname != realname)
|
||||
name = "[realname] died as [mindname]"
|
||||
else
|
||||
@@ -529,10 +530,11 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
|
||||
C = O
|
||||
else if(istype(O, /datum/mind))
|
||||
var/datum/mind/M = O
|
||||
var/mob/living/original = M.original_character?.resolve()
|
||||
if(M.current && M.current.client)
|
||||
C = M.current.client
|
||||
else if(M.original && M.original.client)
|
||||
C = M.original.client
|
||||
else if(original && original.client)
|
||||
C = original.client
|
||||
|
||||
if(C)
|
||||
var/name
|
||||
|
||||
@@ -423,7 +423,7 @@
|
||||
|
||||
if(mind)
|
||||
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_slot = client.prefs.default_slot
|
||||
mind.transfer_to(new_character) //won't transfer key since the mind is not active
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
if(mind)
|
||||
mind.transfer_to(O)
|
||||
O.mind.original = O
|
||||
O.mind.original_character = WEAKREF(O)
|
||||
else
|
||||
O.key = key
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
if(mind) //TODO
|
||||
mind.transfer_to(O)
|
||||
if(O.mind.assigned_role == JOB_CYBORG)
|
||||
O.mind.original = O
|
||||
O.mind.original_character = WEAKREF(O)
|
||||
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")
|
||||
else
|
||||
|
||||
@@ -43,6 +43,7 @@ export const SubtabBody = (props: {
|
||||
s_tone,
|
||||
b_type,
|
||||
digitigrade,
|
||||
tail_layering,
|
||||
synth_color,
|
||||
synth_color_toggle,
|
||||
synth_markings,
|
||||
@@ -130,6 +131,11 @@ export const SubtabBody = (props: {
|
||||
{digitigrade ? 'Yes' : 'No'}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Tail Layering">
|
||||
<Button inline onClick={() => act('set_tail_layering')}>
|
||||
{tail_layering}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Blood Type">
|
||||
<Button inline onClick={() => act('blood_type')}>
|
||||
{b_type}
|
||||
|
||||
@@ -181,6 +181,7 @@ export type BodyData = {
|
||||
body_markings: Record<string, BodyMarking>;
|
||||
|
||||
tail_style: string;
|
||||
tail_layering: string;
|
||||
tail_color1: string;
|
||||
tail_color2: string;
|
||||
tail_color3: string;
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Stack,
|
||||
Tooltip,
|
||||
} from 'tgui-core/components';
|
||||
import { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
type Data = {
|
||||
stun_time: number;
|
||||
@@ -18,8 +19,9 @@ type Data = {
|
||||
flicker_color: string | null;
|
||||
flicker_break_chance: number;
|
||||
flicker_distance: number;
|
||||
no_retreat: number;
|
||||
extended_kin: number;
|
||||
no_retreat: BooleanLike;
|
||||
extended_kin: BooleanLike;
|
||||
savefile_selected: BooleanLike;
|
||||
nutrition_energy_conversion: number;
|
||||
};
|
||||
|
||||
@@ -33,6 +35,7 @@ export const ShadekinConfig = (props) => {
|
||||
flicker_break_chance,
|
||||
flicker_distance,
|
||||
no_retreat,
|
||||
savefile_selected,
|
||||
extended_kin,
|
||||
nutrition_energy_conversion,
|
||||
} = data;
|
||||
@@ -40,7 +43,7 @@ export const ShadekinConfig = (props) => {
|
||||
const isSubtle =
|
||||
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 (
|
||||
<Window width={300} height={windowHeight} theme="abductor">
|
||||
@@ -51,6 +54,11 @@ export const ShadekinConfig = (props) => {
|
||||
<NoticeBox>Subtle Phasing, causes {stun_time} s stun.</NoticeBox>
|
||||
</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>
|
||||
<Section fill title="Light Settings">
|
||||
<LabeledList>
|
||||
|
||||
Reference in New Issue
Block a user