diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm
index f68657c3e93..b7cc2077352 100644
--- a/code/__DEFINES/lighting.dm
+++ b/code/__DEFINES/lighting.dm
@@ -52,7 +52,7 @@
#define LIGHT_RANGE_FIRE 3 //How many tiles standard fires glow.
#define LIGHTING_PLANE_ALPHA_VISIBLE 255
-#define LIGHTING_PLANE_ALPHA_NV_TRAIT 250
+#define LIGHTING_PLANE_ALPHA_NV_TRAIT 245
#define LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE 192
#define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 128 //For lighting alpha, small amounts lead to big changes. even at 128 its hard to figure out what is dark and what is light, at 64 you almost can't even tell.
#define LIGHTING_PLANE_ALPHA_INVISIBLE 0
diff --git a/code/controllers/subsystem/processing/traits.dm b/code/controllers/subsystem/processing/traits.dm
index 9d536c81310..17eae4bda21 100644
--- a/code/controllers/subsystem/processing/traits.dm
+++ b/code/controllers/subsystem/processing/traits.dm
@@ -9,7 +9,7 @@ PROCESSING_SUBSYSTEM_DEF(traits)
wait = 10
runlevels = RUNLEVEL_GAME
- var/list/traits = list() //Assoc. list of all roundstart trait datums; "name" = /path/
+ var/list/traits = list() //Assoc. list of all roundstart trait datum types; "name" = /path/
var/list/trait_points = list() //Assoc. list of trait names and their "point cost"; positive numbers are good traits, and negative ones are bad
var/list/trait_objects = list() //A list of all trait objects in the game, since some may process
@@ -24,11 +24,10 @@ PROCESSING_SUBSYSTEM_DEF(traits)
traits[initial(T.name)] = T
trait_points[initial(T.name)] = initial(T.value)
-/datum/controller/subsystem/processing/traits/proc/AssignTraits(mob/living/user, client/cli)
- if(!isnewplayer(user))
- GenerateTraits(cli)
+/datum/controller/subsystem/processing/traits/proc/AssignTraits(mob/living/user, client/cli, spawn_effects)
+ GenerateTraits(cli)
for(var/V in cli.prefs.character_traits)
- user.add_trait_datum(V)
+ user.add_trait_datum(V, spawn_effects)
/datum/controller/subsystem/processing/traits/proc/GenerateTraits(client/user)
if(user.prefs.character_traits.len)
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 1daa1e573fc..0b783c64e98 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -361,6 +361,8 @@ SUBSYSTEM_DEF(ticker)
captainless=0
if(player.mind.assigned_role != player.mind.special_role)
SSjob.EquipRank(N, player.mind.assigned_role, 0)
+ if(CONFIG_GET(flag/roundstart_traits))
+ SStraits.AssignTraits(player, N.client, TRUE)
CHECK_TICK
if(captainless)
for(var/mob/dead/new_player/N in GLOB.player_list)
diff --git a/code/datums/traits/_trait.dm b/code/datums/traits/_trait.dm
index a6073b5008e..b7cf589ef53 100644
--- a/code/datums/traits/_trait.dm
+++ b/code/datums/traits/_trait.dm
@@ -11,7 +11,7 @@
var/mob_trait //if applicable, apply and remove this mob trait
var/mob/living/trait_holder
-/datum/trait/New(mob/living/trait_mob)
+/datum/trait/New(mob/living/trait_mob, spawn_effects)
..()
if(!trait_mob || (human_only && !ishuman(trait_mob)) || trait_mob.has_trait_datum(type))
qdel(src)
@@ -23,9 +23,9 @@
trait_holder.add_trait(mob_trait, ROUNDSTART_TRAIT)
START_PROCESSING(SStraits, src)
add()
- if(!SSticker.HasRoundStarted()) //on roundstart or on latejoin; latejoin code is in new_player.dm
+ if(spawn_effects)
on_spawn()
- addtimer(CALLBACK(src, .proc/post_add), 30)
+ addtimer(CALLBACK(src, .proc/post_add), 30)
/datum/trait/Destroy()
STOP_PROCESSING(SStraits, src)
@@ -38,16 +38,25 @@
SStraits.trait_objects -= src
return ..()
+/datum/trait/proc/transfer_mob(mob/living/to_mob)
+ trait_holder.roundstart_traits -= src
+ to_mob.roundstart_traits += src
+ trait_holder = to_mob
+ on_transfer()
+
/datum/trait/proc/add() //special "on add" effects
/datum/trait/proc/on_spawn() //these should only trigger when the character is being created for the first time, i.e. roundstart/latejoin
/datum/trait/proc/remove() //special "on remove" effects
/datum/trait/proc/on_process() //process() has some special checks, so this is the actual process
/datum/trait/proc/post_add() //for text, disclaimers etc. given after you spawn in with the trait
+/datum/trait/proc/on_transfer() //code called when the trait is transferred to a new mob
/datum/trait/process()
if(QDELETED(trait_holder))
qdel(src)
return
+ if(trait_holder.stat == DEAD)
+ return
on_process()
/mob/living/proc/get_trait_string(medical) //helper string. gets a string of all the traits the mob has
@@ -67,6 +76,16 @@
return "None"
return dat.Join("
")
+/mob/living/proc/cleanse_trait_datums() //removes all trait datums
+ for(var/V in roundstart_traits)
+ var/datum/trait/T = V
+ qdel(T)
+
+/mob/living/proc/transfer_trait_datums(mob/living/to_mob)
+ for(var/V in roundstart_traits)
+ var/datum/trait/T = V
+ T.transfer_mob(to_mob)
+
/*
Commented version of Nearsighted to help you add your own traits
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index 9fd966eeadb..c98db62e8b9 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -114,7 +114,7 @@
if(trait_holder.reagents.has_reagent("mindbreaker"))
trait_holder.hallucination = 0
return
- if(prob(1)) //we'll all be mad soon enough
+ if(prob(2)) //we'll all be mad soon enough
madness()
/datum/trait/insanity/proc/madness(mad_fools)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 166ef75f44a..c1dad1ce1a4 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -126,7 +126,7 @@
return examine(user)
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, se, mindref, datum/species/mrace, list/features, factions)
+/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, se, mindref, datum/species/mrace, list/features, factions, list/traits)
if(panel_open)
return FALSE
if(mess || attempting)
@@ -198,6 +198,9 @@
if(H)
H.faction |= factions
+ for(var/V in traits)
+ new V(H)
+
H.set_cloned_appearance()
H.suiciding = FALSE
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index d6cf1846229..40f003ea340 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -71,7 +71,7 @@
if(pod.occupant)
continue //how though?
- if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"]))
+ if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["traits"]))
temp = "[R.fields["name"]] => Cloning cycle in progress..."
records -= R
@@ -409,7 +409,7 @@
else if(pod.occupant)
temp = "Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
- else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"]))
+ else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["traits"]))
temp = "[C.fields["name"]] => Cloning cycle in progress..."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
@@ -482,6 +482,10 @@
R.fields["blood_type"] = dna.blood_type
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
+ R.fields["traits"] = list()
+ for(var/V in mob_occupant.roundstart_traits)
+ var/datum/trait/T = V
+ R.fields["traits"] += T.type
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "[REF(mob_occupant.mind)]"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 3e9e4cd27c6..03571c835b2 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -879,15 +879,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return 1
else if(href_list["preference"] == "trait")
- if(SSticker.HasRoundStarted() && !isnewplayer(user))
- to_chat(user, "The round has already started. Please wait until next round to set up your traits!")
- return
switch(href_list["task"])
if("close")
user << browse(null, "window=mob_occupation")
ShowChoices(user)
if("update")
var/trait = href_list["trait"]
+ if(!SStraits.traits[trait])
+ return
var/value = SStraits.trait_points[trait]
if(value == 0)
if(trait in neutral_traits)
@@ -1459,6 +1458,3 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.update_body()
character.update_hair()
character.update_body_parts()
-
- if(CONFIG_GET(flag/roundstart_traits))
- SStraits.AssignTraits(character, parent)
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index bb928c6fa50..3c49b113e97 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -20,6 +20,7 @@
var/blood_type = null
var/list/features = null
var/factions = null
+ var/list/traits = null
var/contains_sample = 0
/obj/item/seeds/replicapod/attackby(obj/item/W, mob/user, params)
@@ -34,6 +35,7 @@
blood_type = bloodSample.data["blood_type"]
features = bloodSample.data["features"]
factions = bloodSample.data["factions"]
+ traits = bloodSample.data["traits"]
W.reagents.clear_reagents()
to_chat(user, "You inject the contents of the syringe into the seeds.")
contains_sample = 1
@@ -99,6 +101,8 @@
podman.faction |= factions
if(!features["mcolor"])
features["mcolor"] = "#59CE00"
+ for(var/V in traits)
+ new V(podman)
podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
podman.set_cloned_appearance()
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 7b2d8d15db4..5227e9e5241 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -373,9 +373,8 @@
if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5)
SSticker.mode.make_antag_chance(humanc)
- for(var/V in character.roundstart_traits)
- var/datum/trait/T = V
- T.on_spawn() //so latejoins still get their correct traits
+ if(CONFIG_GET(flag/roundstart_traits))
+ SStraits.AssignTraits(humanc, humanc.client, TRUE)
log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index f7b3d15155b..41715d650d3 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -191,6 +191,10 @@
blood_data["real_name"] = real_name
blood_data["features"] = dna.features
blood_data["factions"] = faction
+ blood_data["traits"] = list()
+ for(var/V in roundstart_traits)
+ var/datum/trait/T = V
+ blood_data["traits"] += T.type
return blood_data
//get the id of the substance this mob use as blood.
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 3979bb9b842..106381bade2 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -146,13 +146,13 @@
else
status_traits[trait] |= list(source)
-/mob/living/proc/add_trait_datum(trait) //separate proc due to the way these ones are handled
+/mob/living/proc/add_trait_datum(trait, spawn_effects) //separate proc due to the way these ones are handled
if(has_trait(trait))
return
if(!SStraits || !SStraits.traits[trait])
return
var/datum/trait/T = SStraits.traits[trait]
- new T (src)
+ new T (src, spawn_effects)
return TRUE
/mob/living/proc/remove_trait(trait, list/sources, force)