This commit is contained in:
Ghommie
2020-06-30 00:49:06 +02:00
303 changed files with 6981 additions and 73525 deletions
+55
View File
@@ -5,6 +5,61 @@
/datum/brain_trauma/magic
resilience = TRAUMA_RESILIENCE_LOBOTOMY
/datum/brain_trauma/magic/lumiphobia
name = "Lumiphobia"
desc = "Patient has an inexplicable adverse reaction to light."
scan_desc = "light hypersensitivity"
gain_text = "<span class='warning'>You feel a craving for darkness.</span>"
lose_text = "<span class='notice'>Light no longer bothers you.</span>"
var/next_damage_warning = 0
/datum/brain_trauma/magic/lumiphobia/on_life()
..()
var/turf/T = owner.loc
if(istype(T))
var/light_amount = T.get_lumcount()
if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying
if(world.time > next_damage_warning)
to_chat(owner, "<span class='warning'><b>The light burns you!</b></span>")
next_damage_warning = world.time + 100 //Avoid spamming
owner.take_overall_damage(0,3)
/datum/brain_trauma/magic/poltergeist
name = "Poltergeist"
desc = "Patient appears to be targeted by a violent invisible entity."
scan_desc = "paranormal activity"
gain_text = "<span class='warning'>You feel a hateful presence close to you.</span>"
lose_text = "<span class='notice'>You feel the hateful presence fade away.</span>"
/datum/brain_trauma/magic/poltergeist/on_life()
..()
if(prob(4))
var/most_violent = -1 //So it can pick up items with 0 throwforce if there's nothing else
var/obj/item/throwing
for(var/obj/item/I in view(5, get_turf(owner)))
if(I.anchored)
continue
if(I.throwforce > most_violent)
most_violent = I.throwforce
throwing = I
if(throwing)
throwing.throw_at(owner, 8, 2)
/datum/brain_trauma/magic/antimagic
name = "Athaumasia"
desc = "Patient is completely inert to magical forces."
scan_desc = "thaumic blank"
gain_text = "<span class='notice'>You realize that magic cannot be real.</span>"
lose_text = "<span class='notice'>You realize that magic might be real.</span>"
/datum/brain_trauma/magic/antimagic/on_gain()
ADD_TRAIT(owner, TRAIT_ANTIMAGIC, TRAUMA_TRAIT)
..()
/datum/brain_trauma/magic/antimagic/on_lose()
REMOVE_TRAIT(owner, TRAIT_ANTIMAGIC, TRAUMA_TRAIT)
..()
/datum/brain_trauma/magic/stalker
name = "Stalking Phantom"
desc = "Patient is stalked by a phantom only they can see."
+2 -1
View File
@@ -119,8 +119,9 @@
/datum/brain_trauma/severe/paralysis/spinesnapped
random_gain = FALSE
clonable = FALSE
paralysis_type = "legs"
resilience = TRAUMA_RESILIENCE_LOBOTOMY
resilience = TRAUMA_RESILIENCE_LOBOTOMY // It shouldn't fix severed spinal cords really, but there is no specific surgery for that yet.
/datum/brain_trauma/severe/narcolepsy
name = "Narcolepsy"
@@ -92,7 +92,7 @@
qdel(src)
/obj/item/glasswork/glasses
name = "Hand Made Glasses"
desc = "Hande made glasses that have not been polished at all making them useless. Selling them could still be worth a bit of credits."
name = "Handmade Glasses"
desc = "Handmade glasses that have not been polished at all making them useless. Selling them could still be worth a few credits."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "frames_2"
@@ -92,7 +92,7 @@
time = 150
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
always_availible = FALSE // Disabled til learned
always_availible = FALSE // Disabled until learned
/datum/crafting_recipe/bloodsucker/candelabrum
+244
View File
@@ -0,0 +1,244 @@
/*!
This component makes it possible to make things edible. What this means is that you can take a bite or force someone to take a bite (in the case of items).
These items take a specific time to eat, and can do most of the things our original food items could.
Behavior that's still missing from this component that original food items had that should either be put into seperate components or somewhere else:
Components:
Drying component (jerky etc)
Customizable component (custom pizzas etc)
Processable component (Slicing and cooking behavior essentialy, making it go from item A to B when conditions are met.)
Dunkable component (Dunking things into reagent containers to absorb a specific amount of reagents)
Misc:
Something for cakes (You can store things inside)
*/
/datum/component/edible
///Amount of reagents taken per bite
var/bite_consumption = 2
///Amount of bites taken so far
var/bitecount = 0
///Flags for food
var/food_flags = NONE
///Bitfield of the types of this food
var/foodtypes = NONE
///Amount of seconds it takes to eat this food
var/eat_time = 30
///Defines how much it lowers someones satiety (Need to eat, essentialy)
var/junkiness = 0
///Message to send when eating
var/list/eatverbs
///Callback to be ran for when you take a bite of something
var/datum/callback/after_eat
///Last time we checked for food likes
var/last_check_time
/datum/component/edible/Initialize(list/initial_reagents, food_flags = NONE, foodtypes = NONE, volume = 50, eat_time = 30, list/tastes, list/eatverbs = list("bite","chew","nibble","gnaw","gobble","chomp"), bite_consumption = 2, datum/callback/after_eat)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, .proc/UseByAnimal)
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/UseFromHand)
else if(isturf(parent))
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/TryToEatTurf)
src.bite_consumption = bite_consumption
src.food_flags = food_flags
src.foodtypes = foodtypes
src.eat_time = eat_time
src.eatverbs = eatverbs
src.junkiness = junkiness
src.after_eat = after_eat
var/atom/owner = parent
owner.create_reagents(volume, INJECTABLE)
if(initial_reagents)
for(var/rid in initial_reagents)
var/amount = initial_reagents[rid]
if(tastes && tastes.len && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin))
owner.reagents.add_reagent(rid, amount, tastes.Copy())
else
owner.reagents.add_reagent(rid, amount)
/datum/component/edible/proc/examine(datum/source, mob/user, list/examine_list)
if(!(food_flags & FOOD_IN_CONTAINER))
switch (bitecount)
if (0)
return
if(1)
examine_list += "[parent] was bitten by someone!"
if(2,3)
examine_list += "[parent] was bitten [bitecount] times!"
else
examine_list += "[parent] was bitten multiple times!"
/datum/component/edible/proc/UseFromHand(obj/item/source, mob/living/M, mob/living/user)
return TryToEat(M, user)
/datum/component/edible/proc/TryToEatTurf(datum/source, mob/user)
return TryToEat(user, user)
///All the checks for the act of eating itself and
/datum/component/edible/proc/TryToEat(mob/living/eater, mob/living/feeder)
set waitfor = FALSE
var/atom/owner = parent
if(feeder.a_intent == INTENT_HARM)
return
if(!owner.reagents.total_volume)//Shouldn't be needed but it checks to see if it has anything left in it.
to_chat(feeder, "<span class='warning'>None of [owner] left, oh no!</span>")
if(isturf(parent))
var/turf/T = parent
T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
else
qdel(parent)
return
if(!CanConsume(eater, feeder))
return
var/fullness = eater.nutrition + 10 //The theoretical fullness of the person eating if they were to eat this
for(var/datum/reagent/consumable/C in eater.reagents.reagent_list) //we add the nutrition value of what we're currently digesting
fullness += C.nutriment_factor * C.volume / C.metabolization_rate
. = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose
if(eater == feeder)//If you're eating it yourself.
if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time
return
var/eatverb = pick(eatverbs)
if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS))
to_chat(eater, "<span class='warning'>You don't feel like eating any more junk food at the moment!</span>")
return
else if(fullness <= 50)
eater.visible_message("<span class='notice'>[eater] hungrily [eatverb]s \the [parent], gobbling it down!</span>", "<span class='notice'>You hungrily [eatverb] \the [parent], gobbling it down!</span>")
else if(fullness > 50 && fullness < 150)
eater.visible_message("<span class='notice'>[eater] hungrily [eatverb]s \the [parent].</span>", "<span class='notice'>You hungrily [eatverb] \the [parent].</span>")
else if(fullness > 150 && fullness < 500)
eater.visible_message("<span class='notice'>[eater] [eatverb]s \the [parent].</span>", "<span class='notice'>You [eatverb] \the [parent].</span>")
else if(fullness > 500 && fullness < 600)
eater.visible_message("<span class='notice'>[eater] unwillingly [eatverb]s a bit of \the [parent].</span>", "<span class='notice'>You unwillingly [eatverb] a bit of \the [parent].</span>")
else if(fullness > (600 * (1 + eater.overeatduration / 2000))) // The more you eat - the more you can eat
eater.visible_message("<span class='warning'>[eater] cannot force any more of \the [parent] to go down [eater.p_their()] throat!</span>", "<span class='warning'>You cannot force any more of \the [parent] to go down your throat!</span>")
return
else //If you're feeding it to someone else.
if(isbrain(eater))
to_chat(feeder, "<span class='warning'>[eater] doesn't seem to have a mouth!</span>")
return
if(fullness <= (600 * (1 + eater.overeatduration / 1000)))
eater.visible_message("<span class='danger'>[feeder] attempts to feed [eater] [parent].</span>", \
"<span class='userdanger'>[feeder] attempts to feed you [parent].</span>")
else
eater.visible_message("<span class='warning'>[feeder] cannot force any more of [parent] down [eater]'s throat!</span>", \
"<span class='warning'>[feeder] cannot force any more of [parent] down your throat!</span>")
return
if(!do_mob(feeder, eater)) //Wait 3 seconds before you can feed
return
log_combat(feeder, eater, "fed", owner.reagents.log_list())
eater.visible_message("<span class='danger'>[feeder] forces [eater] to eat [parent]!</span>", \
"<span class='userdanger'>[feeder] forces you to eat [parent]!</span>")
TakeBite(eater, feeder)
///This function lets the eater take a bite and transfers the reagents to the eater.
/datum/component/edible/proc/TakeBite(mob/living/eater, mob/living/feeder)
var/atom/owner = parent
if(!owner?.reagents)
return FALSE
if(eater.satiety > -200)
eater.satiety -= junkiness
playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE)
if(owner.reagents.total_volume)
SEND_SIGNAL(parent, COMSIG_FOOD_EATEN, eater, feeder)
var/fraction = min(bite_consumption / owner.reagents.total_volume, 1)
owner.reagents.reaction(eater, INGEST, fraction)
owner.reagents.trans_to(eater, bite_consumption)
bitecount++
On_Consume(eater)
checkLiked(fraction, eater)
//Invoke our after eat callback if it is valid
if(after_eat)
after_eat.Invoke(eater, feeder)
return TRUE
///Checks whether or not the eater can actually consume the food
/datum/component/edible/proc/CanConsume(mob/living/eater, mob/living/feeder)
if(!iscarbon(eater))
return FALSE
var/mob/living/carbon/C = eater
var/covered = ""
if(C.is_mouth_covered(head_only = 1))
covered = "headgear"
else if(C.is_mouth_covered(mask_only = 1))
covered = "mask"
if(covered)
var/who = (isnull(feeder) || eater == feeder) ? "your" : "[eater.p_their()]"
to_chat(feeder, "<span class='warning'>You have to remove [who] [covered] first!</span>")
return FALSE
return TRUE
///Check foodtypes to see if we should send a moodlet
/datum/component/edible/proc/checkLiked(var/fraction, mob/M)
if(last_check_time + 50 > world.time)
return FALSE
if(!ishuman(M))
return FALSE
var/mob/living/carbon/human/H = M
if(HAS_TRAIT(H, TRAIT_AGEUSIA) && foodtypes & H.dna.species.toxic_food)
to_chat(H, "<span class='warning'>You don't feel so good...</span>")
H.adjust_disgust(25 + 30 * fraction)
else
if(foodtypes & H.dna.species.toxic_food)
to_chat(H,"<span class='warning'>What the hell was that thing?!</span>")
H.adjust_disgust(25 + 30 * fraction)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "toxic_food", /datum/mood_event/disgusting_food)
else if(foodtypes & H.dna.species.disliked_food)
to_chat(H,"<span class='notice'>That didn't taste very good...</span>")
H.adjust_disgust(11 + 15 * fraction)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "gross_food", /datum/mood_event/gross_food)
else if(foodtypes & H.dna.species.liked_food)
to_chat(H,"<span class='notice'>I love this taste!</span>")
H.adjust_disgust(-5 + -2.5 * fraction)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "fav_food", /datum/mood_event/favorite_food)
if((foodtypes & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
last_check_time = world.time
///Delete the item when it is fully eaten
/datum/component/edible/proc/On_Consume(mob/living/eater)
var/atom/owner = parent
if(!eater)
return
if(!owner.reagents.total_volume)
if(isturf(parent))
var/turf/T = parent
T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
else
qdel(parent)
///Ability to feed food to puppers
/datum/component/edible/proc/UseByAnimal(datum/source, mob/user)
var/atom/owner = parent
if(!isdog(user))
return
var/mob/living/L = user
if(bitecount == 0 || prob(50))
L.emote("me", 1, "nibbles away at \the [parent]")
bitecount++
. = COMPONENT_ITEM_NO_ATTACK
L.taste(owner.reagents) // why should carbons get all the fun?
if(bitecount >= 5)
var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where \the [parent] was")
if(sattisfaction_text)
L.emote("me", 1, "[sattisfaction_text]")
qdel(parent)
+3 -2
View File
@@ -69,8 +69,9 @@
out += "[out ? " and it " : "[master] "]seems to be glowing a bit."
if(RAD_AMOUNT_HIGH to INFINITY) //At this level the object can contaminate other objects
out += "[out ? " and it " : "[master] "]hurts to look at."
else
out += "."
if(!LAZYLEN(out))
return
out += "."
examine_list += out.Join()
/datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user)
+10 -3
View File
@@ -8,6 +8,8 @@
var/list/faction = list("mining")
/datum/component/spawner/Initialize(_mob_types, _spawn_time, _faction, _spawn_text, _max_mobs)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
if(_spawn_time)
spawn_time=_spawn_time
if(_mob_types)
@@ -19,20 +21,25 @@
if(_max_mobs)
max_mobs=_max_mobs
RegisterSignal(parent, list(COMSIG_PARENT_QDELETING), .proc/stop_spawning)
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/stop_spawning)
RegisterSignal(parent, COMSIG_OBJ_ATTACK_GENERIC, .proc/on_attack_generic)
START_PROCESSING(SSprocessing, src)
/datum/component/spawner/process()
try_spawn_mob()
/datum/component/spawner/proc/stop_spawning(force, hint)
/datum/component/spawner/proc/stop_spawning(datum/source, force, hint)
STOP_PROCESSING(SSprocessing, src)
for(var/mob/living/simple_animal/L in spawned_mobs)
if(L.nest == src)
L.nest = null
spawned_mobs = null
// Stopping clientless simple mobs' from indiscriminately bashing their own spawners due DestroySurroundings() et similars.
/datum/component/spawner/proc/on_attack_generic(datum/source, mob/user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
if(!user.client && ((user.faction & faction) || (user in spawned_mobs)))
return COMPONENT_STOP_GENERIC_ATTACK
/datum/component/spawner/proc/try_spawn_mob()
var/atom/P = parent
if(spawned_mobs.len >= max_mobs)
+5 -5
View File
@@ -20,11 +20,11 @@
/datum/disease/transformation/Copy()
var/datum/disease/transformation/D = ..()
D.stage1 = stage1.Copy()
D.stage2 = stage2.Copy()
D.stage3 = stage3.Copy()
D.stage4 = stage4.Copy()
D.stage5 = stage5.Copy()
D.stage1 = stage1?.Copy()
D.stage2 = stage2?.Copy()
D.stage3 = stage3?.Copy()
D.stage4 = stage4?.Copy()
D.stage5 = stage5?.Copy()
D.new_form = D.new_form
return D
+5 -2
View File
@@ -8,8 +8,11 @@
if(. == ELEMENT_INCOMPATIBLE || !isatom(target) || isarea(target))
return ELEMENT_INCOMPATIBLE
beauty = beautyamount
RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
if(ismovable(target))
RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
var/area/A = get_area(target)
if(A)
enter_area(null, A)
+9 -3
View File
@@ -23,10 +23,14 @@
var/end_sound
var/chance
var/volume = 100
var/vary = FALSE
var/max_loops
var/direct
var/extra_range = 0
var/falloff
var/timerid
var/init_timerid
/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE)
if(!mid_sounds)
@@ -47,13 +51,15 @@
/datum/looping_sound/proc/start(atom/add_thing)
if(add_thing)
output_atoms |= add_thing
if(timerid)
if(timerid || init_timerid)
return
on_start()
/datum/looping_sound/proc/stop(atom/remove_thing)
if(remove_thing)
output_atoms -= remove_thing
if(init_timerid)
deltimer(init_timerid)
if(!timerid)
return
on_stop()
@@ -80,7 +86,7 @@
if(direct)
SEND_SOUND(thing, S)
else
playsound(thing, S, volume)
playsound(thing, S, volume, vary, extra_range, falloff)
/datum/looping_sound/proc/get_sound(starttime, _mid_sounds)
. = _mid_sounds || mid_sounds
@@ -92,7 +98,7 @@
if(start_sound)
play(start_sound)
start_wait = start_length
addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME)
init_timerid = addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_STOPPABLE)
/datum/looping_sound/proc/on_stop()
if(end_sound)
+56 -6
View File
@@ -6,8 +6,6 @@ Simple datum which is instanced once per type and is used for every object of sa
/datum/material
var/name = "material"
var/desc = "its..stuff."
///Var that's mostly used by science machines to identify specific materials, should most likely be phased out at some point
var/id = "mat"
///Base color of the material, is used for greyscale. Item isn't changed in color if this is null.
var/color
///Base alpha of the material, is used for greyscale icons.
@@ -26,6 +24,20 @@ Simple datum which is instanced once per type and is used for every object of sa
var/armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 1, "acid" = 1)
///How beautiful is this material per unit?
var/beauty_modifier = 0
///Can be used to override the sound items make, lets add some SLOSHing.
var/item_sound_override
///Can be used to override the stepsound a turf makes. MORE SLOOOSH
var/turf_sound_override
///what texture icon state to overlay
var/texture_layer_icon_state
///a cached filter for the texture icon
var/cached_texture_filter
/datum/material/New()
. = ..()
if(texture_layer_icon_state)
var/texture_icon = icon('icons/materials/composite.dmi', texture_layer_icon_state)
cached_texture_filter = filter(type="layer", icon=texture_icon, blend_mode = BLEND_INSET_OVERLAY)
///This proc is called when the material is added to an object.
/datum/material/proc/on_applied(atom/source, amount, material_flags)
@@ -34,16 +46,27 @@ Simple datum which is instanced once per type and is used for every object of sa
source.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
if(alpha)
source.alpha = alpha
if(texture_layer_icon_state)
ADD_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
source.filters += cached_texture_filter
if(material_flags & MATERIAL_ADD_PREFIX)
source.name = "[name] [source.name]"
if(istype(source, /obj)) //objs
on_applied_obj(source, amount, material_flags)
if(beauty_modifier)
addtimer(CALLBACK(source, /datum.proc/_AddElement, list(/datum/element/beauty, beauty_modifier * amount)), 0)
if(istype(source, /obj)) //objs
on_applied_obj(source, amount, material_flags)
else if(isturf(source, /turf)) //turfs
on_applied_turf(source, amount, material_flags)
source.mat_update_desc(src)
///This proc is called when a material updates an object's description
/atom/proc/mat_update_desc(/datum/material/mat)
return
///This proc is called when the material is added to an object specifically.
/datum/material/proc/on_applied_obj(var/obj/o, amount, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
@@ -61,6 +84,24 @@ Simple datum which is instanced once per type and is used for every object of sa
for(var/i in current_armor)
temp_armor_list[i] = current_armor[i] * armor_modifiers[i]
o.armor = getArmor(arglist(temp_armor_list))
if(!isitem(o))
return
var/obj/item/I = o
if(!item_sound_override)
return
I.hitsound = item_sound_override
I.usesound = item_sound_override
I.throwhitsound = item_sound_override
/datum/material/proc/on_applied_turf(var/turf/T, amount, material_flags)
if(isopenturf(T))
if(!turf_sound_override)
return
var/turf/open/O = T
O.footstep = turf_sound_override
O.barefootstep = turf_sound_override
O.clawfootstep = turf_sound_override
O.heavyfootstep = turf_sound_override
///This proc is called when the material is removed from an object.
/datum/material/proc/on_removed(atom/source, material_flags)
@@ -68,6 +109,9 @@ Simple datum which is instanced once per type and is used for every object of sa
if(color)
source.remove_atom_colour(FIXED_COLOUR_PRIORITY, color)
source.alpha = initial(source.alpha)
if(texture_layer_icon_state)
source.filters -= cached_texture_filter
REMOVE_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
if(material_flags & MATERIAL_ADD_PREFIX)
source.name = initial(source.name)
@@ -75,10 +119,16 @@ Simple datum which is instanced once per type and is used for every object of sa
if(istype(source, /obj)) //objs
on_removed_obj(source, material_flags)
else if(istype(source, /turf)) //turfs
on_removed_turf(source, material_flags)
///This proc is called when the material is removed from an object specifically.
/datum/material/proc/on_removed_obj(var/obj/o, amount, material_flags)
/datum/material/proc/on_removed_obj(obj/o, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/new_max_integrity = initial(o.max_integrity)
o.modify_max_integrity(new_max_integrity)
o.force = initial(o.force)
o.throwforce = initial(o.throwforce)
/datum/material/proc/on_removed_turf(turf/T, material_flags)
return
+144 -29
View File
@@ -1,21 +1,19 @@
///Has no special properties.
/datum/material/iron
name = "iron"
id = "iron"
desc = "Common iron ore often found in sedimentary and igneous layers of the crust."
color = "#878687"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/metal
value_per_unit = 0.0025
///Breaks extremely easily but is transparent.
/datum/material/glass
name = "glass"
id = "glass"
desc = "Glass forged by melting sand."
color = "#88cdf1"
alpha = 150
categories = list(MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
integrity_modifier = 0.1
sheet_type = /obj/item/stack/sheet/glass
value_per_unit = 0.0025
@@ -30,10 +28,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Has no special properties. Could be good against vampires in the future perhaps.
/datum/material/silver
name = "silver"
id = "silver"
desc = "Silver"
color = list(255/255, 284/255, 302/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/silver
value_per_unit = 0.025
beauty_modifier = 0.075
@@ -41,11 +38,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Slight force increase
/datum/material/gold
name = "gold"
id = "gold"
desc = "Gold"
color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium
strength_modifier = 1.2
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/gold
value_per_unit = 0.0625
beauty_modifier = 0.15
@@ -54,11 +50,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Has no special properties
/datum/material/diamond
name = "diamond"
id = "diamond"
desc = "Highly pressurized carbon"
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
alpha = 132
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
value_per_unit = 0.25
beauty_modifier = 0.3
@@ -67,10 +62,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Is slightly radioactive
/datum/material/uranium
name = "uranium"
id = "uranium"
desc = "Uranium"
color = rgb(48, 237, 26)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/uranium
value_per_unit = 0.05
beauty_modifier = 0.3 //It shines so beautiful
@@ -88,10 +82,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Adds firestacks on hit (Still needs support to turn into gas on destruction)
/datum/material/plasma
name = "plasma"
id = "plasma"
desc = "Isn't plasma a state of matter? Oh whatever."
color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/plasma
value_per_unit = 0.1
beauty_modifier = 0.15
@@ -111,7 +104,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Can cause bluespace effects on use. (Teleportation) (Not yet implemented)
/datum/material/bluespace
name = "bluespace crystal"
id = "bluespace_crystal"
desc = "Crystals with bluespace properties"
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
alpha = 200
@@ -123,10 +115,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Honks and slips
/datum/material/bananium
name = "bananium"
id = "bananium"
desc = "Material with hilarious properties"
color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/bananium
value_per_unit = 0.5
beauty_modifier = 0.5
@@ -146,11 +137,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Mediocre force increase
/datum/material/titanium
name = "titanium"
id = "titanium"
desc = "Titanium"
color = "#b3c0c7"
strength_modifier = 1.3
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/titanium
value_per_unit = 0.0625
beauty_modifier = 0.05
@@ -158,11 +148,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
/datum/material/runite
name = "runite"
id = "runite"
desc = "Runite"
color = "#3F9995"
strength_modifier = 1.3
categories = list(MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/runite
beauty_modifier = 0.5
armor_modifiers = list("melee" = 1.35, "bullet" = 2, "laser" = 0.5, "energy" = 1.25, "bomb" = 1.25, "bio" = 1, "rad" = 1, "fire" = 1.4, "acid" = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle.
@@ -170,7 +159,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Force decrease
/datum/material/plastic
name = "plastic"
id = "plastic"
desc = "Plastic"
color = "#caccd9"
strength_modifier = 0.85
@@ -182,7 +170,6 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Force decrease and mushy sound effect. (Not yet implemented)
/datum/material/biomass
name = "biomass"
id = "biomass"
desc = "Organic matter"
color = "#735b4d"
strength_modifier = 0.8
@@ -190,12 +177,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
/datum/material/wood
name = "wood"
id = "wood"
desc = "Flexible, durable, but flamable. Hard to come across in space."
color = "#bb8e53"
strength_modifier = 0.5
sheet_type = /obj/item/stack/sheet/mineral/wood
categories = list(MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
value_per_unit = 0.06
beauty_modifier = 0.1
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 0.4, "energy" = 0.4, "bomb" = 1, "bio" = 0.2, "rad" = 0, "fire" = 0, "acid" = 0.3)
@@ -215,11 +201,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
///Stronk force increase
/datum/material/adamantine
name = "adamantine"
id = "adamantine"
desc = "A powerful material made out of magic, I mean science!"
color = "#6d7e8e"
strength_modifier = 1.5
categories = list(MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/adamantine
value_per_unit = 0.25
beauty_modifier = 0.4
@@ -228,10 +213,9 @@ Unless you know what you're doing, only use the first three numbers. They're in
///RPG Magic. (Admin only)
/datum/material/mythril
name = "mythril"
id = "mythril"
desc = "How this even exists is byond me"
color = "#f2d5d7"
categories = list(MAT_CATEGORY_RIGID = TRUE)
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/mythril
value_per_unit = 0.75
beauty_modifier = 0.5
@@ -246,3 +230,134 @@ Unless you know what you're doing, only use the first three numbers. They're in
. = ..()
if(istype(source, /obj/item))
qdel(source.GetComponent(/datum/component/fantasy))
//I don't like sand. It's coarse, and rough, and irritating, and it gets everywhere.
/datum/material/sand
name = "sand"
desc = "You know, it's amazing just how structurally sound sand can be."
color = "#EDC9AF"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/sandblock
value_per_unit = 0.001
strength_modifier = 0.5
integrity_modifier = 0.1
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 1.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
beauty_modifier = 0.25
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "sand"
//And now for our lavaland dwelling friends, sand, but in stone form! Truly revolutionary.
/datum/material/sandstone
name = "sandstone"
desc = "Bialtaakid 'ant taerif ma hdha."
color = "#B77D31"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/sandstone
value_per_unit = 0.0025
armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 1.25, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
beauty_modifier = 0.3
turf_sound_override = FOOTSTEP_WOOD
texture_layer_icon_state = "brick"
/datum/material/snow
name = "snow"
desc = "There's no business like snow business."
color = "#FFFFFF"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/snow
value_per_unit = 0.0025
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0.25, "acid" = 1.5)
beauty_modifier = 0.3
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "sand"
/datum/material/runedmetal
name = "runed metal"
desc = "Mir'ntrath barhah Nar'sie."
color = "#3C3434"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/runed_metal
value_per_unit = 0.75
armor_modifiers = list("melee" = 1.2, "bullet" = 1.2, "laser" = 1, "energy" = 1, "bomb" = 1.2, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
beauty_modifier = -0.15
texture_layer_icon_state = "runed"
/datum/material/bronze
name = "bronze"
desc = "Clock Cult? Never heard of it."
color = "#92661A"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/tile/bronze
value_per_unit = 0.025
armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
beauty_modifier = 0.2
/datum/material/paper
name = "paper"
desc = "Ten thousand folds of pure starchy power."
color = "#E5DCD5"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/paperframes
value_per_unit = 0.0025
armor_modifiers = list("melee" = 0.1, "bullet" = 0.1, "laser" = 0.1, "energy" = 0.1, "bomb" = 0.1, "bio" = 0.1, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
beauty_modifier = 0.3
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "paper"
/datum/material/paper/on_applied_obj(obj/source, amount, material_flags)
. = ..()
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/obj/paper = source
paper.resistance_flags |= FLAMMABLE
paper.obj_flags |= UNIQUE_RENAME
/datum/material/paper/on_removed_obj(obj/source, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/obj/paper = source
paper.resistance_flags &= ~FLAMMABLE
return ..()
/datum/material/cardboard
name = "cardboard"
desc = "They say cardboard is used by hobos to make incredible things."
color = "#5F625C"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/cardboard
value_per_unit = 0.003
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
beauty_modifier = -0.1
/datum/material/cardboard/on_applied_obj(obj/source, amount, material_flags)
. = ..()
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/obj/cardboard = source
cardboard.resistance_flags |= FLAMMABLE
cardboard.obj_flags |= UNIQUE_RENAME
/datum/material/cardboard/on_removed_obj(obj/source, material_flags)
if(material_flags & MATERIAL_AFFECT_STATISTICS)
var/obj/cardboard = source
cardboard.resistance_flags &= ~FLAMMABLE
return ..()
/datum/material/bone
name = "bone"
desc = "Man, building with this will make you the coolest caveman on the block."
color = "#e3dac9"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/bone
value_per_unit = 0.05
armor_modifiers = list("melee" = 1.2, "bullet" = 0.75, "laser" = 0.75, "energy" = 1.2, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
beauty_modifier = -0.2
/datum/material/bamboo
name = "bamboo"
desc = "If it's good enough for pandas, it's good enough for you."
color = "#339933"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/bamboo
value_per_unit = 0.0025
armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 0.5, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.51, "rad" = 1.5, "fire" = 0.5, "acid" = 1.5)
beauty_modifier = 0.2
turf_sound_override = FOOTSTEP_WOOD
texture_layer_icon_state = "bamboo"
+32
View File
@@ -0,0 +1,32 @@
///It's gross, gets the name of it's owner, and is all kinds of fucked up
/datum/material/meat
name = "meat"
desc = "Meat"
color = rgb(214, 67, 67)
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/meat
value_per_unit = 0.05
beauty_modifier = -0.3
strength_modifier = 0.7
armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
item_sound_override = 'sound/effects/meatslap.ogg'
turf_sound_override = FOOTSTEP_MEAT
texture_layer_icon_state = "meat"
/datum/material/meat/on_removed(atom/source, material_flags)
. = ..()
qdel(source.GetComponent(/datum/component/edible))
/datum/material/meat/on_applied_obj(obj/O, amount, material_flags)
. = ..()
O.obj_flags |= UNIQUE_RENAME //So you can name it after the person its made from, a depressing comprimise.
make_edible(O, amount, material_flags)
/datum/material/meat/on_applied_turf(turf/T, amount, material_flags)
. = ..()
make_edible(T, amount, material_flags)
/datum/material/meat/proc/make_edible(atom/source, amount, material_flags)
var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT)
source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, RAW | MEAT | GROSS, null, 30, list("Fleshy"))
+30
View File
@@ -0,0 +1,30 @@
/datum/material/pizza
name = "pizza"
desc = "~Jamme, jamme, n'coppa, jamme ja! Jamme, jamme, n'coppa jamme ja, funi-culi funi-cala funi-culi funi-cala!! Jamme jamme ja funiculi funicula!~"
color = "#FF9F23"
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/pizza
value_per_unit = 0.05
beauty_modifier = 0.1
strength_modifier = 0.7
armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
item_sound_override = 'sound/effects/meatslap.ogg'
turf_sound_override = FOOTSTEP_MEAT
texture_layer_icon_state = "pizza"
/datum/material/pizza/on_removed(atom/source, material_flags)
. = ..()
qdel(source.GetComponent(/datum/component/edible))
/datum/material/pizza/on_applied_obj(obj/O, amount, material_flags)
. = ..()
make_edible(O, amount, material_flags)
/datum/material/pizza/on_applied_turf(turf/T, amount, material_flags)
. = ..()
make_edible(T, amount, material_flags)
/datum/material/pizza/proc/make_edible(atom/source, amount, material_flags)
var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT)
source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, GRAIN | MEAT | DAIRY | VEGETABLES, null, 30, list("crust", "tomato", "cheese", "meat"))
+1 -1
View File
@@ -67,7 +67,7 @@
var/datum/skill_holder/skill_holder
/datum/mind/New(var/key)
skill_holder = new()
skill_holder = new(src)
src.key = key
soulOwner = src
martial_art = default_martial_art
+7
View File
@@ -42,6 +42,7 @@
school = "evocation"
charge_max = 600
clothes_req = NONE
antimagic_allowed = TRUE
range = 20
base_icon_state = "fireball"
action_icon_state = "fireball0"
@@ -122,6 +123,7 @@
desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly."
school = "evocation"
clothes_req = NONE
antimagic_allowed = TRUE
charge_max = 600
invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!"
invocation_type = "shout"
@@ -155,6 +157,7 @@
dropmessage = "You let the electricity from your hand dissipate."
hand_path = /obj/item/melee/touch_attack/shock
charge_max = 400
antimagic_allowed = TRUE
clothes_req = NONE
action_icon_state = "zap"
@@ -212,6 +215,7 @@
desc = "Get a scent off of the item you're currently holding to track it. With an empty hand, you'll track the scent you've remembered."
charge_max = 100
clothes_req = NONE
antimagic_allowed = TRUE
range = -1
include_user = TRUE
action_icon_state = "nose"
@@ -290,6 +294,7 @@
name = "Drop a limb"
desc = "Concentrate to make a random limb pop right off your body."
clothes_req = NONE
antimagic_allowed = TRUE
charge_max = 100
action_icon_state = "autotomy"
@@ -327,6 +332,7 @@
name = "Lay Web"
desc = "Drops a web. Only you will be able to traverse your web easily, making it pretty good for keeping you safe."
clothes_req = NONE
antimagic_allowed = TRUE
charge_max = 4 SECONDS //the same time to lay a web
action_icon = 'icons/mob/actions/actions_genetic.dmi'
action_icon_state = "lay_web"
@@ -368,6 +374,7 @@
name = "Launch spike"
desc = "Shoot your tongue out in the direction you're facing, embedding it and dealing damage until they remove it."
clothes_req = NONE
antimagic_allowed = TRUE
charge_max = 100
action_icon = 'icons/mob/actions/actions_genetic.dmi'
action_icon_state = "spike"
+5 -1
View File
@@ -462,6 +462,10 @@
suffix = "whiteship_pod"
name = "Salvage Pod"
/datum/map_template/shuttle/whiteship/cog
suffix = "cog"
name = "NT Prisoner Transport"
/datum/map_template/shuttle/cargo/box
suffix = "box"
name = "supply shuttle (Box)"
@@ -628,4 +632,4 @@
/datum/map_template/shuttle/hunter/bounty
suffix = "bounty"
name = "Bounty Hunter Ship"
name = "Bounty Hunter Ship"
+63 -3
View File
@@ -11,6 +11,66 @@
if(!mind.skill_holder)
to_chat(usr, "<span class='warning'>How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without the capability for skills? (PROBABLY A BUG, PRESS F1.)</span>")
return
var/datum/browser/B = new(usr, "skilldisplay_[REF(src)]", "Skills of [src]")
B.set_content(mind.skill_html_readout())
B.open()
mind.skill_holder.ui_interact(src)
/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "skillpanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
ui.open()
else if(need_static_data_update)
update_static_data(user)
need_static_data_update = FALSE
/datum/skill_holder/ui_static_data(mob/user)
. = list()
.["skills"] = list()
for(var/path in GLOB.skill_datums)
var/datum/skill/S = GLOB.skill_datums[path]
var/list/dat = S.get_skill_data(src)
if(islist(dat["modifiers"]))
dat["modifiers"] = jointext(dat["modifiers"], ", ")
dat["percent_base"] = (dat["value_base"] / dat["max_value"])
dat["percent_mod"] = (dat["value_mod"] / dat["max_value"])
.["skills"] += list(dat)
/datum/skill_holder/ui_data(mob/user)
. = list()
.["playername"] = owner.name
.["see_skill_mods"] = see_skill_mods
.["admin"] = check_rights(R_DEBUG)
/datum/skill_holder/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("toggle_mods")
see_skill_mods = !see_skill_mods
return TRUE
if ("adj_exp")
if(!check_rights(R_DEBUG))
return
var/skill = text2path(params["skill"])
var/number = input("Please insert the amount of experience/progress you'd like to add/subtract:") as num|null
if (number)
owner.set_skill_value(skill, owner.get_skill_value(skill, FALSE) + number)
return TRUE
if ("set_exp")
if(!check_rights(R_DEBUG))
return
var/skill = text2path(params["skill"])
var/number = input("Please insert the number you want to set the player's exp/progress to:") as num|null
if (!isnull(number))
owner.set_skill_value(skill, number)
return TRUE
if ("set_lvl")
if(!check_rights(R_DEBUG))
return
var/datum/skill/level/S = GLOB.skill_datums[text2path(params["skill"])]
var/number = input("Please insert a whole number between 0[S.associative ? " ([S.unskilled_tier])" : ""] and [S.max_levels][S.associative ? " ([S.levels[S.max_levels]])" : ""] corresponding to the level you'd like to set the player to.") as num|null
if (number >= 0 && number <= S.max_levels)
owner.set_skill_value(S.type, S.get_skill_level_value(number))
return TRUE
+85 -20
View File
@@ -8,6 +8,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
continue
S = new path
.[S.type] = S
. = sortTim(., /proc/cmp_skill_categories, TRUE)
/**
* Skill datums
@@ -34,6 +35,8 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/competency_multiplier = 1
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
/// Index of this skill in the UI
var/ui_category = SKILL_UI_CAT_MISC
/**
* Ensures what someone's setting as a value for this skill is valid.
@@ -57,10 +60,28 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
return new_value > existing
/**
* Standard value "render"
* Get a list of data used in the skill panel menu.
*/
/datum/skill/proc/standard_render_value(value, level)
return value
/datum/skill/proc/get_skill_data(datum/skill_holder/H)
var/skill_value = H.owner.get_skill_value(type, FALSE)
. = list(
"name" = name,
"desc" = desc,
"path" = type,
"value_base" = skill_value,
"value_mod" = skill_value,
"modifiers" = "None",
"max_value" = 1 //To avoid division by zero later on.
)
var/list/mods = LAZYACCESS(H.skill_value_mods, type)
if(mods)
var/list/mod_names = list()
for(var/k in mods)
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
mod_names |= M.name
skill_value = M.apply_modifier(skill_value, type, H, MODIFIER_TARGET_VALUE)
.["value_mod"] = skill_value
.["modifiers"] = mod_names //Will be jointext()'d later.
// Just saying, the choice to use different sub-parent-types is to force coders to resolve issues as I won't be implementing custom procs to grab skill levels in a certain context.
// Aka: So people don't forget to change checks if they change a skill's progression type.
@@ -71,10 +92,12 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
/datum/skill/binary/sanitize_value(new_value)
return new_value? TRUE : FALSE
return new_value >= 1 ? TRUE : FALSE
/datum/skill/binary/standard_render_value(value, level)
return value? "Yes" : "No"
/datum/skill/binary/get_skill_data(datum/skill_holder/H)
. = ..()
.["base_readout"] = .["value_base"] ? "Learned: Yes" : "Learned: No"
.["mod_readout"] = .["value_mod"] ? "Learned: Yes" : "Learned: No"
/datum/skill/numerical
abstract_type = /datum/skill/numerical
@@ -84,14 +107,15 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/max_value = 100
/// Min value of this skill
var/min_value = 0
/// Display as a percent in standard_render_value?
var/display_as_percent = FALSE
/datum/skill/numerical/sanitize_value(new_value)
return clamp(new_value, min_value, max_value)
/datum/skill/numerical/standard_render_value(value, level)
return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]"
/datum/skill/numerical/get_skill_data(datum/skill_holder/H)
. = ..()
.["base_readout"] = "Skill Progress: \[[.["value_base"]] / [max_value]\]"
.["mod_readout"] = "Skill Progress: \[[.["value_mod"]] / [max_value]\]"
.["max_value"] = max_value
/datum/skill/enum
abstract_type = /datum/skill/enum
@@ -123,13 +147,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/max_assoc = ""
var/max_assoc_start = 1
for(var/lvl in 1 to max_levels)
var/value
switch(level_up_method)
if(STANDARD_LEVEL_UP)
value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
if(DWARFY_LEVEL_UP)
value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
value = round(value, 1)
var/value = round(get_skill_level_value(lvl), 1)
if(!associative)
levels += value
continue
@@ -167,8 +185,13 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
else if(. < 0)
to_chat(M.current, "<span class='warning'>I feel like I've become worse at [name]!</span>")
/datum/skill/level/standard_render_value(value, level)
var/current_lvl = associative ? (!level ? unskilled_tier : levels[level]) : level
/datum/skill/level/get_skill_data(datum/skill_holder/H)
. = ..()
var/skill_value_base = .["value_base"]
var/skill_value_mod = .["value_mod"]
.["level_based"] = TRUE
var/level = LAZYACCESS(H.skill_levels, type) || 0
var/current_lvl_xp_sum = 0
if(level)
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
@@ -176,8 +199,50 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
if(next_lvl_xp > current_lvl_xp_sum)
next_lvl_xp -= current_lvl_xp_sum
.["lvl_base_num"] = .["lvl_mod_num"] = level
.["lvl_base"] = .["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
.["base_style"] = .["mod_style"] = "font-weight:bold; color:hsl([(level+1)*(350/max_levels+1)], 50%, 50%)"
.["xp_next_lvl_base"] = .["xp_next_lvl_mod"] = "\[[skill_value_base - current_lvl_xp_sum]/[next_lvl_xp]\]"
return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]"
.["max_lvl"] = max_levels
var/max_value = associative ? levels[levels[max_levels]] : levels[max_levels]
.["max_value"] = max_value
.["base_readout"] = "Overall Skill Progress: \[[skill_value_base]/[max_value]\]"
.["mod_readout"] = "Overall Skill Progress: \[[skill_value_mod]/[max_value]\]"
var/list/mods = LAZYACCESS(H.skill_level_mods, type)
if(mods) //I'm not proud of doing the same-ish process twice a row but here we go.
var/list/mod_names = .["modifiers"]
if(!mod_names)
.["modifiers"] = mod_names = list()
for(var/k in mods)
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
mod_names |= M.name
level = M.apply_modifier(level, type, H, MODIFIER_TARGET_LEVEL)
if(level)
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
else
current_lvl_xp_sum = 0
next_index = min(max_levels, level+1)
next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
if(next_lvl_xp > current_lvl_xp_sum)
next_lvl_xp -= current_lvl_xp_sum
.["lvl_mod_num"] = level
.["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
.["mod_style"] = "font-weight:bold; color:hsl([(level+1)*(300/(max_levels+1))], 50%, 50%)"
.["xp_next_lvl_mod"] = "\[[skill_value_mod - current_lvl_xp_sum]/[next_lvl_xp]\]"
/**
* Gets the base value required to reach a level specified by the 'num' arg.
*/
/datum/skill/level/proc/get_skill_level_value(num)
switch(level_up_method)
if(STANDARD_LEVEL_UP)
. = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, num)
if(DWARFY_LEVEL_UP)
. = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, num)
/datum/skill/level/job
abstract_type = /datum/skill/level/job
+13 -15
View File
@@ -20,6 +20,18 @@
var/list/original_values
var/list/original_affinities
var/list/original_levels
/// The mind datum this skill is associated with, only used for the check_skills UI
var/datum/mind/owner
/// For UI updates.
var/need_static_data_update = TRUE
/// Whether modifiers and final skill values or only base values are displayed.
var/see_skill_mods = TRUE
/// The current selected skill category.
var/selected_category
/datum/skill_holder/New(owner)
..()
src.owner = owner
/**
* Grabs the value of a skill.
@@ -79,6 +91,7 @@
CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
var/datum/skill/S = GLOB.skill_datums[skill]
value = S.sanitize_value(value)
skill_holder.need_static_data_update = TRUE
if(!isnull(value))
LAZYINITLIST(skill_holder.skills)
S.set_skill_value(skill_holder, value, src, silent)
@@ -183,18 +196,3 @@
divisor++
if(divisor)
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
/**
* Generates a HTML readout of our skills.
* Port to tgui-next when?
*/
/datum/mind/proc/skill_html_readout()
var/list/out = list("<center><h1>Skills</h1></center><hr>")
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
for(var/path in GLOB.skill_datums)
var/datum/skill/S = GLOB.skill_datums[path]
var/skill_value = get_skill_value(path)
var/skill_level = get_skill_level(path, round = TRUE)
out += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skill_value, skill_level)]</td></tr>"
out += "</table>"
return out.Join("")
+5 -5
View File
@@ -7,6 +7,8 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
* and cause lots of edge cases. These are fairly simple overall... make a subtype though, don't use this one.
*/
/datum/skill_modifier
/// Name and description of the skill modifier, used in the UI
var/name = "???"
/// flags for this skill modifier.
var/modifier_flags = NONE
/// target skills, can be a specific skill typepath or a list of skill traits.
@@ -110,6 +112,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
ADD_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels, get_skill_level(path, FALSE))
LAZYSET(skill_holder.all_current_skill_modifiers, id, TRUE)
skill_holder.need_static_data_update = TRUE
if(M.modifier_flags & MODIFIER_SKILL_BODYBOUND)
M.RegisterSignal(src, COMSIG_MIND_TRANSFER, /datum/skill_modifier.proc/on_mind_transfer)
@@ -141,6 +144,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL && skill_holder.skill_level_mods)
REMOVE_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels)
LAZYREMOVE(skill_holder.all_current_skill_modifiers, id)
skill_holder.need_static_data_update = TRUE
if(!mind_transfer && M.modifier_flags & MODIFIER_SKILL_BODYBOUND)
M.UnregisterSignal(src, COMSIG_MIND_TRANSFER)
@@ -165,11 +169,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
var/datum/skill/S = GLOB.skill_datums[skillpath]
if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
var/datum/skill/level/L = S
switch(L.level_up_method)
if(STANDARD_LEVEL_UP)
mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
if(DWARFY_LEVEL_UP)
mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
mod = L.get_skill_level_value(L.competency_thresholds[mod])
else
mod = S.competency_thresholds[mod]
+2 -1
View File
@@ -1,5 +1,6 @@
/datum/skill/level/job/wiring
name = "Wiring"
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
desc = "How proficient and knowledged you are at wiring beyond making post-futuristic wire art."
name_color = COLOR_PALE_ORANGE
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
ui_category = SKILL_UI_CAT_ENG
+2 -1
View File
@@ -1,5 +1,6 @@
/datum/skill/numerical/surgery
name = "Surgery"
desc = "How proficient you are at doing surgery."
desc = "How proficient you are at performing surgical procedures."
name_color = COLOR_PALE_BLUE_GRAY
competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
ui_category = SKILL_UI_CAT_MED
+2 -1
View File
@@ -1,6 +1,7 @@
/// Jobbie skill modifiers.
/datum/skill_modifier/job
name = "Job Training"
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF
priority = MODIFIER_SKILL_PRIORITY_MAX
@@ -23,7 +24,7 @@
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF
level_mod = JOB_SKILL_TRAINED
/datum/skill_modifier/job/level/New(id)
/datum/skill_modifier/job/level/New(id, register = FALSE)
if(level_mod)
value_mod = GET_STANDARD_LVL(level_mod)
..()
+2
View File
@@ -1,8 +1,10 @@
/datum/skill_modifier/bad_mood
name = "Mood (Dejected)"
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = list(SKILL_SANITY)
/datum/skill_modifier/great_mood
name = "Mood (Elated)"
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = list(SKILL_SANITY)
affinity_mod = 1.2
+2
View File
@@ -1,4 +1,5 @@
/datum/skill_modifier/brain_damage
name = "Brain Damage"
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
value_mod = 0.85
@@ -6,6 +7,7 @@
affinity_mod = 0.85
/datum/skill_modifier/heavy_brain_damage
name = "Brain Damage (Severe)"
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
priority = MODIFIER_SKILL_PRIORITY_LOW
+7 -6
View File
@@ -81,11 +81,11 @@
owner.adjustStaminaLoss(-0.5) //reduce stamina loss by 0.5 per tick, 10 per 2 seconds
if(human_owner && human_owner.drunkenness)
human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds
if(prob(20))
if(carbon_owner)
carbon_owner.handle_dreams()
if(prob(10) && owner.health > owner.crit_threshold)
owner.emote("snore")
if(carbon_owner && !carbon_owner.dreaming && prob(2))
carbon_owner.dream()
// 2% per second, tick interval is in deciseconds
if(prob((tick_interval+1) * 0.2) && owner.health > owner.crit_threshold)
owner.emote("snore")
/datum/status_effect/staggered
id = "staggered"
@@ -711,8 +711,9 @@ datum/status_effect/pacify
if(hearing_args[HEARING_SPEAKER] == owner)
return
var/mob/living/carbon/C = owner
var/hypnomsg = uncostumize_say(hearing_args[HEARING_RAW_MESSAGE], hearing_args[HEARING_MESSAGE_MODE])
C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10)
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hypnomsg), 10)
addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it
qdel(src)
+5 -4
View File
@@ -6,6 +6,7 @@
var/id = "effect" //Used for screen alerts.
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
var/next_tick //The scheduled time for the next tick.
var/mob/living/owner //The mob affected by the status effect.
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
@@ -31,7 +32,7 @@
return
if(duration != -1)
duration = world.time + duration
tick_interval = world.time + tick_interval
next_tick = world.time + tick_interval
if(alert_type)
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
A.attached_effect = src //so the alert can reference us, if it needs to
@@ -52,9 +53,9 @@
if(!owner)
qdel(src)
return
if(tick_interval < world.time)
if(next_tick < world.time)
tick()
tick_interval = world.time + initial(tick_interval)
next_tick = world.time + tick_interval
if(duration != -1 && duration < world.time)
qdel(src)
@@ -221,7 +222,7 @@
threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
on_threshold_drop()
if(stacks_added > 0)
tick_interval += delay_before_decay //refreshes time until decay
next_tick += delay_before_decay //refreshes time until decay
stacks = min(stacks, max_stacks)
status_overlay.icon_state = "[overlay_state][stacks]"
status_underlay.icon_state = "[underlay_state][stacks]"