Adds a new race: Ethereal (also adds wrappers for nutrition adjustment) (#40995)

cl Qustinnus / Floyd / Ethereal sprites by Space, is that it? / Alerts and food sprites by MrDroppodBringer
add: Adds Ethereal; a race which lives off of electricity and shines bright. If they are healthy they shine a bright green light, and the more damaged they are, the less they shine and the greyer they become. Their punches do burn damage and they are weak to blunt attacks!
They dont need to eat normal food and dont have nutrition, Instead they gain charge by going into borg rechargers, eating ethereal food or doign specific interactions.
refactor: all nutrition changes now go through a proc so we can override behavior
/cl

Adds Ethereal. A race which is essentialy inspired by Zoltan but then with different mechanics to make it fit with SS13 more. I'm trying to stay away from making them actually provide power but the change from nutrition to electricity seemed kind of fun.

They have the following specifications:

    They are walking lights; and shine bright and green if healthy, and get greyer and darker the more damaged they are. When dead they are just a grey unlit corpse.
    They do burn punch damage instead of blunt.
    They are weaker to blunt; especially when low on charge
    They have charge instead of nutrition. Charge is gained by some interactions or by going into a borg charger. or eating new ethereal food.
    They are slightly stronger to shock damage, and gain charge from it a bit; however, it is still deadly to them and thus they aren't free insulated gloves.
This commit is contained in:
Qustinnus
2018-11-28 22:09:56 +01:00
committed by yogstation13-bot
parent 0866db32cc
commit c00a94b80e
83 changed files with 516 additions and 102 deletions

View File

@@ -90,6 +90,8 @@
#define NO_DNA_COPY 14
#define DRINKSBLOOD 15
#define NOEYES 16
#define DYNCOLORS 17 //Use this if you want to change the race's color without the player being able to pick their own color. AKA special color shifting
#define AGENDER 18
#define ORGAN_SLOT_BRAIN "brain"
#define ORGAN_SLOT_APPENDIX "appendix"

View File

@@ -68,6 +68,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define ismoth(A) (is_species(A, /datum/species/moth))
#define ishumanbasic(A) (is_species(A, /datum/species/human))
#define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) )
#define isethereal(A) (is_species(A, /datum/species/ethereal))
//more carbon mobs
#define ismonkey(A) (istype(A, /mob/living/carbon/monkey))

View File

@@ -162,6 +162,13 @@
//Used as an upper limit for species that continuously gain nutriment
#define NUTRITION_LEVEL_ALMOST_FULL 535
//Charge levels for Ethereals
#define ETHEREAL_CHARGE_NONE 0
#define ETHEREAL_CHARGE_LOWPOWER 20
#define ETHEREAL_CHARGE_NORMAL 50
#define ETHEREAL_CHARGE_ALMOSTFULL 75
#define ETHEREAL_CHARGE_FULL 100
//Slime evolution threshold. Controls how fast slimes can split/grow
#define SLIME_EVOLUTION_THRESHOLD 10
@@ -252,6 +259,7 @@
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases
#define ETHEREAL_CHARGE_FACTOR 0.12 //factor at which ethereal's charge decreases
#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
#define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism

View File

@@ -72,7 +72,7 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
//For now we will always return none for tail_human and ears.
return(list("mcolor" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), "tail_lizard" = pick(GLOB.tails_list_lizard), "tail_human" = "None", "wings" = "None", "snout" = pick(GLOB.snouts_list), "horns" = pick(GLOB.horns_list), "ears" = "None", "frills" = pick(GLOB.frills_list), "spines" = pick(GLOB.spines_list), "body_markings" = pick(GLOB.body_markings_list), "legs" = "Normal Legs", "caps" = pick(GLOB.caps_list), "moth_wings" = pick(GLOB.moth_wings_list)))
return(list("mcolor" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),"ethcolor" = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)], "tail_lizard" = pick(GLOB.tails_list_lizard), "tail_human" = "None", "wings" = "None", "snout" = pick(GLOB.snouts_list), "horns" = pick(GLOB.horns_list), "ears" = "None", "frills" = pick(GLOB.frills_list), "spines" = pick(GLOB.spines_list), "body_markings" = pick(GLOB.body_markings_list), "legs" = "Normal Legs", "caps" = pick(GLOB.caps_list), "moth_wings" = pick(GLOB.moth_wings_list)))
/proc/random_hair_style(gender)
switch(gender)
@@ -116,6 +116,13 @@
if(!findname(.))
break
/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10)
for(var/i in 1 to attempts_to_find_unique_name)
. = capitalize(ethereal_name())
if(!findname(.))
break
/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
for(var/i in 1 to attempts_to_find_unique_name)
. = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last))

View File

@@ -4,6 +4,12 @@
else
return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
/proc/ethereal_name()
var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
if(prob(65))
tempname += random_capital_letter()
return tempname
/proc/plasmaman_name()
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"

View File

@@ -765,3 +765,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
return "twelfth"
else
return "[number]\th"
/proc/random_capital_letter()
return uppertext(pick(GLOB.alphabet))

View File

@@ -36,6 +36,8 @@ GLOBAL_LIST_EMPTY(wings_open_list)
GLOBAL_LIST_EMPTY(r_wings_list)
GLOBAL_LIST_EMPTY(moth_wings_list)
GLOBAL_LIST_EMPTY(caps_list)
GLOBAL_LIST_INIT(color_list_ethereal, list("F Class(Green)" = "97ee63", "F2 Class (Light Green)" = "00fa9a", "F3 Class (Dark Green)" = "37835b", "M Class (Red)" = "9c3030", "M1 Class (Purple)" = "ee82ee", "G Class (Yellow)" = "fbdf56", "O Class (Blue)" = "3399ff", "A Class (Cyan)" = "00ffff"))
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things

View File

@@ -16,6 +16,7 @@ GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt"))
GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt"))
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt"))
GLOBAL_LIST_INIT(ethereal_names, world.file2list("strings/names/ethereal.txt"))
GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt"))
GLOBAL_LIST_INIT(nightmare_names, world.file2list("strings/names/nightmare.txt"))
GLOBAL_LIST_INIT(megacarp_first_names, world.file2list("strings/names/megacarp1.txt"))

View File

@@ -479,6 +479,13 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the
desc = "Unit's power cell is running low. Recharging stations are available in robotics, the dormitory bathrooms, and the AI satellite."
icon_state = "lowcell"
//Ethereal
/obj/screen/alert/etherealcharge
name = "Low Blood Charge"
desc = "Your blood's electric charge is running low, find a source of charge for your blood. Use a recharging station found in robotics or the dormitory bathrooms, or eat some Ethereal-friendly food."
icon_state = "etherealcharge"
//Need to cover all use cases - emag, illegal upgrade module, malf AI hack, traitor cyborg
/obj/screen/alert/hacked
name = "Hacked"

View File

@@ -266,6 +266,12 @@
print_mood(user)
/datum/component/mood/proc/HandleNutrition(mob/living/L)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(isethereal(H))
HandleCharge(H)
if(H.has_trait(TRAIT_NOHUNGER))
return FALSE //no mood events for nutrition
switch(L.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
if (!L.has_trait(TRAIT_VORACIOUS))
@@ -283,5 +289,17 @@
if(0 to NUTRITION_LEVEL_STARVING)
add_event(null, "nutrition", /datum/mood_event/starving)
/datum/component/mood/proc/HandleCharge(mob/living/carbon/human/H)
var/datum/species/ethereal/E = H.dna?.species
switch(E.ethereal_charge)
if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER)
add_event(null, "charge", /datum/mood_event/decharged)
if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
add_event(null, "charge", /datum/mood_event/lowpower)
if(ETHEREAL_CHARGE_NORMAL to ETHEREAL_CHARGE_ALMOSTFULL)
clear_event(null, "charge")
if(ETHEREAL_CHARGE_ALMOSTFULL to ETHEREAL_CHARGE_FULL)
add_event(null, "charge", /datum/mood_event/charged)
#undef MINOR_INSANITY_PEN
#undef MAJOR_INSANITY_PEN

View File

@@ -120,7 +120,7 @@
for(var/datum/reagent/R in M.reagents.reagent_list) //Not just toxins!
M.reagents.remove_reagent(R.id, actual_power)
if(food_conversion)
M.nutrition += 0.3
M.adjust_nutrition(0.3)
if(prob(2))
to_chat(M, "<span class='notice'>You feel a mild warmth as your blood purifies itself.</span>")
return 1
@@ -157,7 +157,7 @@
C.reagents.metabolize(C, can_overdose=TRUE)
C.overeatduration = max(C.overeatduration - 2, 0)
var/lost_nutrition = 9 - (reduced_hunger * 5)
C.nutrition = max(C.nutrition - (lost_nutrition * HUNGER_FACTOR), 0) //Hunger depletes at 10x the normal speed
C.adjust_nutrition(-lost_nutrition * HUNGER_FACTOR) //Hunger depletes at 10x the normal speed
if(prob(2))
to_chat(C, "<span class='notice'>You feel an odd gurgle in your stomach, as if it was working much faster than normal.</span>")
return 1

View File

@@ -48,4 +48,4 @@ Bonus
else
to_chat(M, "<span class='warning'><i>[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]</i></span>")
M.overeatduration = max(M.overeatduration - 100, 0)
M.nutrition = max(M.nutrition - 100, 0)
M.adjust_nutrition(-100)

View File

@@ -52,7 +52,7 @@
if(prob(3))
to_chat(affected_mob, "<span class='warning'><i>[pick("Your stomach silently rumbles...", "Your stomach seizes up and falls limp, muscles dead and lifeless.", "You could eat a crayon")]</i></span>")
affected_mob.overeatduration = max(affected_mob.overeatduration - 100, 0)
affected_mob.nutrition = max(affected_mob.nutrition - 100, 0)
affected_mob.adjust_nutrition(-100)
if(prob(15))
to_chat(affected_mob, "<span class='danger'>[pick("You feel uncomfortably hot...", "You feel like unzipping your jumpsuit", "You feel like taking off some clothes...")]</span>")
affected_mob.adjust_bodytemperature(40)

View File

@@ -65,7 +65,7 @@
D.visible_message("<span class='danger'>[A] has [atk_verb]ed [D]!</span>", \
"<span class='userdanger'>[A] has [atk_verb]ed [D]!</span>", null, COMBAT_MESSAGE_RANGE)
D.apply_damage(damage, BRUTE, affecting, armor_block)
D.apply_damage(damage, A.dna.species.attack_type, affecting, armor_block)
log_combat(A, D, "punched")

View File

@@ -68,7 +68,7 @@
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
var/atom/throw_target = get_edge_target_turf(D, A.dir)
D.throw_at(throw_target, 1, 14, A)
D.apply_damage(10, BRUTE)
D.apply_damage(10, A.dna.species.attack_type)
log_combat(A, D, "kicked (CQC)")
if(D.IsParalyzed() && !D.stat)
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking [D.p_them()] out!</span>", \
@@ -111,7 +111,7 @@
if(I && D.temporarilyRemoveItemFromInventory(I))
A.put_in_hands(I)
D.adjustStaminaLoss(50)
D.apply_damage(25, BRUTE)
D.apply_damage(25, A.dna.species.attack_type)
return TRUE
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
@@ -177,7 +177,7 @@
if(I && D.temporarilyRemoveItemFromInventory(I))
A.put_in_hands(I)
D.Jitter(2)
D.apply_damage(5, BRUTE)
D.apply_damage(5, A.dna.species.attack_type)
else
D.visible_message("<span class='danger'>[A] attempted to disarm [D]!</span>", \
"<span class='userdanger'>[A] attempted to disarm [D]!</span>")

View File

@@ -110,7 +110,7 @@
D.visible_message("<span class='warning'>[A] karate chops [D]'s neck!</span>", \
"<span class='userdanger'>[A] karate chops your neck, rendering you unable to speak!</span>")
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
D.apply_damage(5, A.dna.species.attack_type)
if(D.silent <= 10)
D.silent = CLAMP(D.silent + 10, 0, 10)
log_combat(A, D, "neck chopped")
@@ -131,7 +131,7 @@
if(!(D.mobility_flags & MOBILITY_STAND))
bonus_damage += 5
picked_hit_type = "stomps on"
D.apply_damage(bonus_damage, BRUTE)
D.apply_damage(bonus_damage, A.dna.species.attack_type)
if(picked_hit_type == "kicks" || picked_hit_type == "stomps on")
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
playsound(get_turf(D), 'sound/effects/hit_kick.ogg', 50, 1, -1)

View File

@@ -11,7 +11,7 @@
atk_verb = pick("punches", "smashes", "ruptures", "cracks")
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
D.apply_damage(rand(15,30), BRUTE)
D.apply_damage(rand(15,30), A.dna.species.attack_type)
playsound(D, 'sound/effects/meteorimpact.ogg', 25, 1, -1)
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.

View File

@@ -42,8 +42,8 @@
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
"<span class='userdanger'>[A] [atk_verb] you!</span>")
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1)
D.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD)
A.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD)
D.apply_damage(rand(5,10), A.dna.species.attack_type, BODY_ZONE_HEAD)
A.apply_damage(rand(5,10), A.dna.species.attack_type, BODY_ZONE_HEAD)
if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat))
D.adjustBrainLoss(5)
A.Stun(rand(10,45))
@@ -53,7 +53,7 @@
atk_verb = pick("punches", "kicks", "hits", "slams into")
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
D.apply_damage(rand(15,30), BRUTE)
D.apply_damage(rand(15,30), A.dna.species.attack_type)
playsound(get_turf(D), 'sound/effects/meteorimpact.ogg', 25, 1, -1)
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.

View File

@@ -78,7 +78,7 @@
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
"<span class='userdanger'>[A] kicks you in the jaw!</span>")
D.apply_damage(20, BRUTE, BODY_ZONE_HEAD)
D.apply_damage(20, A.dna.species.attack_type, BODY_ZONE_HEAD)
D.drop_all_held_items()
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
D.Stun(80)
@@ -93,7 +93,7 @@
"<span class='userdanger'>[A] piledrives you with their elbow!</span>")
if(D.stat)
D.death() //FINISH HIM!
D.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
D.apply_damage(50, A.dna.species.attack_type, BODY_ZONE_CHEST)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 75, 1, -1)
return 1
log_combat(A, D, "elbow dropped (Sleeping Carp)")

View File

@@ -19,6 +19,19 @@
description = "<span class='boldwarning'>I'm starving!</span>\n"
mood_change = -15
//charge
/datum/mood_event/charged
description = "<span class='nicegreen'>I feel the power in my veins!</span>\n"
mood_change = 6
/datum/mood_event/lowpower
description = "<span class='warning'>My power is running low, I should go charge up somewhere.</span>\n"
mood_change = -7
/datum/mood_event/decharged
description = "<span class='boldwarning'>I'm in desperate need of some electricity!</span>\n"
mood_change = -12
//Disgust
/datum/mood_event/gross
description = "<span class='warning'>I saw something gross.</span>\n"

View File

@@ -439,7 +439,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
if(food <= 0)
dat += "<br>You ran out of food and starved."
if(obj_flags & EMAGGED)
user.nutrition = 0 //yeah you pretty hongry
user.set_nutrition(0) //yeah you pretty hongry
to_chat(user, "<span class='userdanger'>Your body instantly contracts to that of one who has not eaten in months. Agonizing cramps seize you as you fall to the floor.</span>")
if(fuel <= 0)
dat += "<br>You ran out of fuel, and drift, slowly, into a star."

View File

@@ -10,7 +10,7 @@
req_access = list(ACCESS_ROBOTICS)
state_open = TRUE
circuit = /obj/item/circuitboard/machine/cyborgrecharger
occupant_typecache = list(/mob/living/silicon/robot)
occupant_typecache = list(/mob/living/silicon/robot, /mob/living/carbon/human)
var/recharge_speed
var/repairs
@@ -80,13 +80,13 @@
/obj/machinery/recharge_station/open_machine()
. = ..()
if(iscyborg(occupant))
if(iscyborg(occupant) || isethereal(occupant))
use_power = IDLE_POWER_USE
/obj/machinery/recharge_station/close_machine()
. = ..()
if(occupant)
if(iscyborg(occupant))
if(iscyborg(occupant) || isethereal(occupant))
use_power = ACTIVE_POWER_USE
add_fingerprint(occupant)
@@ -104,13 +104,20 @@
update_icon()
/obj/machinery/recharge_station/proc/process_occupant()
if(occupant && iscyborg(occupant))
if(!occupant)
return
if(iscyborg(occupant))
var/mob/living/silicon/robot/R = occupant
restock_modules()
if(repairs)
R.heal_bodypart_damage(repairs, repairs - 1)
if(R.cell)
R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge)
if(isethereal(occupant))
var/mob/living/carbon/human/H = occupant
var/datum/species/ethereal/E = H.dna?.species
if(E)
E.adjust_charge(recharge_speed / 70) //Around 3 per process if unupgraded
/obj/machinery/recharge_station/proc/restock_modules()
if(occupant)

View File

@@ -130,7 +130,7 @@
if (istype(R, /datum/reagent/consumable))
var/datum/reagent/consumable/nutri_check = R
if(nutri_check.nutriment_factor >0)
H.nutrition += nutri_check.nutriment_factor * nutri_check.volume
H.adjust_nutrition(nutri_check.nutriment_factor * nutri_check.volume)
reagents.remove_reagent(nutri_check.id,nutri_check.volume)
reagents.trans_to(H, reagents.total_volume, transfered_by = user)
qdel(src)

View File

@@ -197,9 +197,9 @@
..()
to_chat(user,"<span class='caution'>Your stomach rumbles...</span>")
if(user.nutrition)
user.nutrition = 200
user.set_nutrition(200)
if(user.nutrition <= 0)
user.nutrition = 0
user.set_nutrition(0)
/obj/item/book/granter/spell/blind
spell = /obj/effect/proc_holder/spell/targeted/trigger/blind

View File

@@ -35,6 +35,10 @@
name = "syndi-cakes"
icon_state = "syndi_cakes"
/obj/item/trash/energybar
name = "energybar wrapper"
icon_state = "energybar"
/obj/item/trash/waffles
name = "waffles tray"
icon_state = "waffles"

View File

@@ -25,6 +25,7 @@
// Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant.
H.dna.features["mcolor"] = random_short_color()
H.dna.features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)]
H.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard)
H.dna.features["snout"] = pick(GLOB.snouts_list)
H.dna.features["horns"] = pick(GLOB.horns_list)

View File

@@ -56,7 +56,7 @@
changeling.trueabsorbs++
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
user.set_nutrition(min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED))
if(target.mind)//if the victim has got a mind
// Absorb a lizard, speak Draconic.

View File

@@ -180,7 +180,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(soulsOwned.Find(soul))
return
soulsOwned += soul
owner.current.nutrition = NUTRITION_LEVEL_FULL
owner.current.set_nutrition(NUTRITION_LEVEL_FULL)
to_chat(owner.current, "<span class='warning'>You feel satiated as you received a new soul.</span>")
update_hud()
switch(SOULVALUE)

View File

@@ -69,7 +69,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/skin_tone = "caucasian1" //Skin color
var/eye_color = "000" //Eye color
var/datum/species/pref_species = new /datum/species/human() //Mutant race
var/list/features = list("mcolor" = "FFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "wings" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain")
var/list/features = list("mcolor" = "FFF", "ethcolor" = "9c3030", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "wings" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain")
var/list/custom_names = list()
var/preferred_ai_core_display = "Blue"
@@ -211,7 +211,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Name:</b> "
dat += "<a href='?_src_=prefs;preference=name;task=input'>[real_name]</a><BR>"
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender'>[gender == MALE ? "Male" : "Female"]</a><BR>"
if(!(AGENDER in pref_species.species_traits))
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender'>[gender == MALE ? "Male" : "Female"]</a><BR>"
dat += "<b>Age:</b> <a href='?_src_=prefs;preference=age;task=input'>[age]</a><BR>"
dat += "<b>Special Names:</b><BR>"
@@ -271,6 +272,16 @@ GLOBAL_LIST_EMPTY(preferences_datums)
mutant_colors = TRUE
if(istype(pref_species, /datum/species/ethereal)) //not the best thing to do tbf but I dont know whats better.
if(!use_skintones)
dat += APPEARANCE_CATEGORY_COLUMN
dat += "<h3>Ethereal Color</h3>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["ethcolor"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=color_ethereal;task=input'>Change</a><BR>"
if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
if(!use_skintones && !mutant_colors)
@@ -1374,6 +1385,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
else
to_chat(user, "<span class='danger'>Invalid color. Your color is not bright enough.</span>")
if("color_ethereal")
var/new_etherealcolor = input(user, "Choose your ethereal color", "Character Preference") as null|anything in GLOB.color_list_ethereal
if(new_etherealcolor)
features["ethcolor"] = GLOB.color_list_ethereal[new_etherealcolor]
if("tail_lizard")
var/new_tail
@@ -1703,8 +1720,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
pref_species = new /datum/species/human
save_character()
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
character.dna.features = features.Copy()
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
character.dna.real_name = character.real_name
if("tail_lizard" in pref_species.default_features)

View File

@@ -237,6 +237,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!S["features["mcolor"]"] || S["features["mcolor"]"] == "#000")
WRITE_FILE(S["features["mcolor"]"] , "#FFF")
if(!S["feature_ethcolor"] || S["feature_ethcolor"] == "#000")
WRITE_FILE(S["feature_ethcolor"] , "#9c3030")
//Character
S["real_name"] >> real_name
@@ -256,6 +259,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["backbag"] >> backbag
S["uplink_loc"] >> uplink_spawn_loc
S["feature_mcolor"] >> features["mcolor"]
S["feature_ethcolor"] >> features["ethcolor"]
S["feature_lizard_tail"] >> features["tail_lizard"]
S["feature_lizard_snout"] >> features["snout"]
S["feature_lizard_horns"] >> features["horns"]
@@ -316,6 +320,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!features["mcolor"] || features["mcolor"] == "#000")
features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
if(!features["ethcolor"] || features["ethcolor"] == "#000")
features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)]
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
@@ -339,6 +346,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0)
features["ethcolor"] = copytext(features["ethcolor"],1,7)
features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard)
features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human, "None")
features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list)
@@ -397,6 +405,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
WRITE_FILE(S["species"] , pref_species.id)
WRITE_FILE(S["feature_mcolor"] , features["mcolor"])
WRITE_FILE(S["feature_ethcolor"] , features["ethcolor"])
WRITE_FILE(S["feature_lizard_tail"] , features["tail_lizard"])
WRITE_FILE(S["feature_human_tail"] , features["tail_human"])
WRITE_FILE(S["feature_lizard_snout"] , features["snout"])

View File

@@ -36,4 +36,4 @@
if(foodtype & H.dna.species.toxic_food)
to_chat(H, "<span class='warning'>You don't feel so good...</span>")
H.adjust_disgust(25 + 30 * fraction)
last_check_time = world.time
last_check_time = world.time

View File

@@ -88,10 +88,10 @@ All foods are distributed among various categories. Use common sense.
if(!reagents.total_volume) //Shouldn't be needed but it checks to see if it has anything left in it.
to_chat(user, "<span class='notice'>None of [src] left, oh no!</span>")
qdel(src)
return 0
return FALSE
if(iscarbon(M))
if(!canconsume(M, user))
return 0
return FALSE
var/fullness = M.nutrition + 10
for(var/datum/reagent/consumable/C in M.reagents.reagent_list) //we add the nutrition value of what we're currently digesting
@@ -100,7 +100,7 @@ All foods are distributed among various categories. Use common sense.
if(M == user) //If you're eating it yourself.
if(junkiness && M.satiety < -150 && M.nutrition > NUTRITION_LEVEL_STARVING + 50 && !user.has_trait(TRAIT_VORACIOUS))
to_chat(M, "<span class='notice'>You don't feel like eating any more junk food at the moment.</span>")
return 0
return FALSE
else if(fullness <= 50)
user.visible_message("<span class='notice'>[user] hungrily [eatverb]s \the [src], gobbling it down!</span>", "<span class='notice'>You hungrily [eatverb] \the [src], gobbling it down!</span>")
else if(fullness > 50 && fullness < 150)
@@ -111,7 +111,7 @@ All foods are distributed among various categories. Use common sense.
user.visible_message("<span class='notice'>[user] unwillingly [eatverb]s a bit of \the [src].</span>", "<span class='notice'>You unwillingly [eatverb] a bit of \the [src].</span>")
else if(fullness > (600 * (1 + M.overeatduration / 2000))) // The more you eat - the more you can eat
user.visible_message("<span class='warning'>[user] cannot force any more of \the [src] to go down [user.p_their()] throat!</span>", "<span class='warning'>You cannot force any more of \the [src] to go down your throat!</span>")
return 0
return FALSE
if(M.has_trait(TRAIT_VORACIOUS))
M.changeNext_move(CLICK_CD_MELEE * 0.5) //nom nom nom
else
@@ -122,7 +122,7 @@ All foods are distributed among various categories. Use common sense.
else
M.visible_message("<span class='warning'>[user] cannot force any more of [src] down [M]'s throat!</span>", \
"<span class='warning'>[user] cannot force any more of [src] down [M]'s throat!</span>")
return 0
return FALSE
if(!do_mob(user, M))
return
@@ -146,7 +146,7 @@ All foods are distributed among various categories. Use common sense.
bitecount++
On_Consume(M)
checkLiked(fraction, M)
return 1
return TRUE
return 0

View File

@@ -132,6 +132,13 @@
tastes = list("brains" = 1, "meat" = 1)
foodtype = RAW | MEAT | TOXIC
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ethereal
icon_state = "etherealmeat"
desc = "So shiny you feel like ingesting it might make you shine too"
filling_color = "#97ee63"
list_reagents = list("liquidelectricity" = 3)
tastes = list("pure electrictiy" = 2, "meat" = 1)
foodtype = RAW | MEAT | TOXIC
////////////////////////////////////// OTHER MEATS ////////////////////////////////////////////////////////

View File

@@ -281,3 +281,11 @@
bonus_reagents = list("nutriment" = 8, "vitamin" = 1)
tastes = list("bun" = 4, "bacon" = 2)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/empoweredburger
name = "empowered burger"
desc = "It's shockingly good, if you live off of electricity that is."
icon_state = "empoweredburger"
list_reagents = list("nutriment" = 8, "liquidelectricity" = 5)
tastes = list("bun" = 2, "pure electricity" = 4)
foodtype = GRAIN | TOXIC

View File

@@ -92,3 +92,13 @@
filling_color = "#F5F5DC"
tastes = list("sweetness" = 3, "cake" = 1)
foodtype = GRAIN | FRUIT | VEGETABLES
/obj/item/reagent_containers/food/snacks/energybar
name = "High-power energy bars"
icon_state = "energybar"
desc = "An energy bar with a lot of punch, you probably shouldn't eat this if you're not an Ethereal."
trash = /obj/item/trash/energybar
list_reagents = list("nutriment" = 3, "liquidelectricity" = 3)
filling_color = "#97ee63"
tastes = list("pure electricity" = 3, "fitness" = 2)
foodtype = TOXIC

View File

@@ -293,3 +293,13 @@
result = /obj/item/reagent_containers/food/snacks/burger/baconburger
subcategory = CAT_BURGER
/datum/crafting_recipe/food/empoweredburger
name = "Empowered Burger"
reqs = list(
/obj/item/stack/sheet/mineral/plasma = 2,
/obj/item/reagent_containers/food/snacks/bun = 1
)
result = /obj/item/reagent_containers/food/snacks/burger/empoweredburger
subcategory = CAT_BURGER

View File

@@ -48,7 +48,7 @@
nutrition_ratio = 1
if(satiety > 80)
nutrition_ratio *= 1.25
nutrition = max(0, nutrition - nutrition_ratio * HUNGER_FACTOR)
adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR)
blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio)
//Effects of bloodloss

View File

@@ -480,7 +480,7 @@
playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
var/turf/T = get_turf(src)
if(!blood)
nutrition -= lost_nutrition
adjust_nutrition(-lost_nutrition)
adjustToxLoss(-3)
for(var/i=0 to distance)
if(blood)

View File

@@ -36,8 +36,8 @@
. = ..()
if(. && (movement_type & FLOATING)) //floating is easy
if(has_trait(TRAIT_NOHUNGER))
nutrition = NUTRITION_LEVEL_FED - 1 //just less than feeling vigorous
set_nutrition(NUTRITION_LEVEL_FED - 1) //just less than feeling vigorous
else if(nutrition && stat != DEAD)
nutrition -= HUNGER_FACTOR/10
adjust_nutrition(-(HUNGER_FACTOR/10))
if(m_intent == MOVE_INTENT_RUN)
nutrition -= HUNGER_FACTOR/10
adjust_nutrition(-(HUNGER_FACTOR/10))

View File

@@ -773,6 +773,7 @@
hud_used.healthdoll.icon_state = "healthdoll_DEAD"
/mob/living/carbon/human/fully_heal(admin_revive = 0)
dna?.species.spec_fully_heal(src)
if(admin_revive)
regenerate_limbs()
regenerate_organs()
@@ -869,6 +870,20 @@
. = ..()
. *= physiology.do_after_speed
/mob/living/carbon/human/updatehealth()
. = ..()
dna?.species.spec_updatehealth(src)
/mob/living/carbon/human/adjust_nutrition(var/change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
if(has_trait(TRAIT_NOHUNGER))
return FALSE
return ..()
/mob/living/carbon/human/set_nutrition(var/change) //Seriously fuck you oldcoders.
if(has_trait(TRAIT_NOHUNGER))
return FALSE
return ..()
/mob/living/carbon/human/species
var/race = null
@@ -978,6 +993,9 @@
/mob/living/carbon/human/species/lizard
race = /datum/species/lizard
/mob/living/carbon/human/species/ethereal
race = /datum/species/ethereal
/mob/living/carbon/human/species/lizard/ashwalker
race = /datum/species/lizard/ashwalker

View File

@@ -477,12 +477,18 @@
if(stat == CONSCIOUS)
to_chat(src, "<span class='notice'>You feel your heart beating again!</span>")
siemens_coeff *= physiology.siemens_coeff
dna.species.spec_electrocute_act(src, shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun)
. = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun)
if(.)
electrocution_animation(40)
/mob/living/carbon/human/emag_act(mob/user)
.=..()
dna?.species.spec_emag_act(src)
/mob/living/carbon/human/emp_act(severity)
dna?.species.spec_emp_act(src, severity)
. = ..()
if(. & EMP_PROTECT_CONTENTS)
return
@@ -734,20 +740,21 @@
to_chat(src, "<span class='danger'>Your thinking is clouded and distant.</span>")
else if(oxyloss > 30)
to_chat(src, "<span class='danger'>You're choking!</span>")
switch(nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
to_chat(src, "<span class='info'>You're completely stuffed!</span>")
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
to_chat(src, "<span class='info'>You're well fed!</span>")
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
to_chat(src, "<span class='info'>You're not hungry.</span>")
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
to_chat(src, "<span class='info'>You could use a bite to eat.</span>")
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
to_chat(src, "<span class='info'>You feel quite hungry.</span>")
if(0 to NUTRITION_LEVEL_STARVING)
to_chat(src, "<span class='danger'>You're starving!</span>")
if(!has_trait(TRAIT_NOHUNGER))
switch(nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
to_chat(src, "<span class='info'>You're completely stuffed!</span>")
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
to_chat(src, "<span class='info'>You're well fed!</span>")
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
to_chat(src, "<span class='info'>You're not hungry.</span>")
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
to_chat(src, "<span class='info'>You could use a bite to eat.</span>")
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
to_chat(src, "<span class='info'>You feel quite hungry.</span>")
if(0 to NUTRITION_LEVEL_STARVING)
to_chat(src, "<span class='danger'>You're starving!</span>")
if(roundstart_quirks.len)
to_chat(src, "<span class='notice'>You have these quirks: [get_trait_string()].</span>")

View File

@@ -39,6 +39,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/heatmod = 1 // multiplier for heat damage
var/acidmod = 1 // multiplier for acid damage // yogs - Old Plant People
var/stunmod = 1 // multiplier for stun duration
var/attack_type = BRUTE //Type of damage attack does
var/punchdamagelow = 0 //lowest possible punch damage
var/punchdamagehigh = 9 //highest possible punch damage
var/punchstunthreshold = 9//damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
@@ -245,6 +246,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
// Drop the items the new species can't wear
if((AGENDER in species_traits))
C.gender = PLURAL
for(var/slot_id in no_equip)
var/obj/item/thing = C.get_item_by_slot(slot_id)
if(thing && (!thing.species_exception || !is_type_in_list(src,thing.species_exception)))
@@ -951,6 +954,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
////////
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
if(has_trait(TRAIT_NOHUNGER))
return //hunger is for BABIES
//The fucking TRAIT_FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
if(H.has_trait(TRAIT_FAT))//I share your pain, past coder.
@@ -982,7 +987,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.Jitter(5)
hunger_rate = 3 * HUNGER_FACTOR
hunger_rate *= H.physiology.hunger_mod
H.nutrition = max(0, H.nutrition - hunger_rate)
H.adjust_nutrition(-hunger_rate)
if (H.nutrition > NUTRITION_LEVEL_FULL)
@@ -1087,9 +1092,14 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
. += (health_deficiency / 25)
if(CONFIG_GET(flag/disable_human_mood))
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if((hungry >= 70) && !flight) //Being hungry will still allow you to use a flightsuit/wings.
. += hungry / 50
if(!H.has_trait(TRAIT_NOHUNGER))
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if((hungry >= 70) && !flight) //Being hungry will still allow you to use a flightsuit/wings.
. += hungry / 50
else if(isethereal(H))
var/datum/species/ethereal/E = H.dna.species
if(E.ethereal_charge <= ETHEREAL_CHARGE_NORMAL)
. += 1.5 * (1 - E.ethereal_charge / 100)
//Moving in high gravity is very slow (Flying too)
if(gravity > STANDARD_GRAVITY)
@@ -1110,6 +1120,21 @@ GLOBAL_LIST_EMPTY(roundstart_races)
// ATTACK PROCS //
//////////////////
/datum/species/proc/spec_updatehealth(mob/living/carbon/human/H)
return
/datum/species/proc/spec_fully_heal(mob/living/carbon/human/H)
return
/datum/species/proc/spec_emp_act(mob/living/carbon/human/H, severity)
return
/datum/species/proc/spec_emag_act(mob/living/carbon/human/H, mob/user)
return
/datum/species/proc/spec_electrocute_act(mob/living/carbon/human/H, shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
return
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(!((target.health < 0 || target.has_trait(TRAIT_FAKEDEATH)) && !(target.mobility_flags & MOBILITY_STAND)))
target.help_shake_act(user)
@@ -1189,7 +1214,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(user.limb_destroyer)
target.dismembering_strike(user, affecting.body_zone)
target.apply_damage(damage, BRUTE, affecting, armor_block)
target.apply_damage(damage, attack_type, affecting, armor_block)
log_combat(user, target, "punched")
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
target.visible_message("<span class='danger'>[user] has knocked [target] down!</span>", \

View File

@@ -0,0 +1,141 @@
#define ETHEREAL_COLORS list("#00ffff", "#ffc0cb", "#9400D3", "#4B0082", "#0000FF", "#00FF00", "#FFFF00", "#FF7F00", "#FF0000")
/datum/species/ethereal
name = "Ethereal"
id = "ethereal"
attack_verb = "burn"
attack_sound = 'sound/weapons/etherealhit.ogg'
miss_sound = 'sound/weapons/etherealmiss.ogg'
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ethereal
exotic_bloodtype = "LE" //Liquid Electricity. fuck you think of something better gamer
siemens_coeff = 0.5 //They thrive on energy
brutemod = 1.25 //They're weak to punches
attack_type = BURN //burn bish
damage_overlay_type = "" //We are too cool for regular damage overlays
species_traits = list(DYNCOLORS, NOSTOMACH, AGENDER, NO_UNDERWEAR)
inherent_traits = list(TRAIT_NOHUNGER)
sexes = FALSE //no fetish content allowed
toxic_food = NONE
var/current_color
var/ethereal_charge = ETHEREAL_CHARGE_FULL
var/EMPeffect = FALSE
var/emageffect = FALSE
var/r1
var/g1
var/b1
var/static/r2 = 237
var/static/g2 = 164
var/static/b2 = 149
//this is shit but how do i fix it? no clue.
/datum/species/ethereal/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
.=..()
if(ishuman(C))
var/mob/living/carbon/human/H = C
default_color = "#" + H.dna.features["ethcolor"]
r1 = GetRedPart(default_color)
g1 = GetGreenPart(default_color)
b1 = GetBluePart(default_color)
spec_updatehealth(H)
/datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
.=..()
C.set_light(0)
/datum/species/ethereal/random_name(gender,unique,lastname)
if(unique)
return random_unique_ethereal_name()
var/randname = ethereal_name()
return randname
/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H)
.=..()
if(H.stat != DEAD && !EMPeffect)
var/healthpercent = max(H.health, 0) / 100
if(!emageffect)
current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent))
H.set_light(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color)
fixed_mut_color = copytext(current_color, 2)
else
H.set_light(0)
fixed_mut_color = rgb(128,128,128)
H.update_body()
/datum/species/ethereal/spec_emp_act(mob/living/carbon/human/H, severity)
.=..()
EMPeffect = TRUE
spec_updatehealth(H)
to_chat(H, "<span class='notice'>You feel the light of your body leave you.</span>")
switch(severity)
if(EMP_LIGHT)
addtimer(CALLBACK(src, .proc/stop_emp, H), 100, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds
if(EMP_HEAVY)
addtimer(CALLBACK(src, .proc/stop_emp, H), 200, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds
/datum/species/ethereal/spec_emag_act(mob/living/carbon/human/H, mob/user)
if(emageffect)
return
emageffect = TRUE
to_chat(user, "<span class='notice'>You tap [H] on the back with your card.</span>")
H.visible_message("<span class='danger'>[H] starts flickering in an array of colors!</span>")
handle_emag(H)
addtimer(CALLBACK(src, .proc/stop_emag, H), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //Disco mode for 30 seconds! This doesn't affect the ethereal at all besides either annoying some players, or making someone look badass.
/datum/species/ethereal/spec_life(mob/living/carbon/human/H)
.=..()
handle_charge(H)
/datum/species/ethereal/spec_fully_heal(mob/living/carbon/human/H)
.=..()
set_charge(ETHEREAL_CHARGE_FULL)
/datum/species/ethereal/spec_electrocute_act(mob/living/carbon/human/H, shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
.=..()
adjust_charge(shock_damage * siemens_coeff * 2)
to_chat(H, "<span class='notice'>You absorb some of the shock into your body!</span>")
/datum/species/ethereal/proc/stop_emp(mob/living/carbon/human/H)
EMPeffect = FALSE
spec_updatehealth(H)
to_chat(H, "<span class='notice'>You feel more energized as your shine comes back.</span>")
/datum/species/ethereal/proc/handle_emag(mob/living/carbon/human/H)
if(!emageffect)
return
current_color = pick(ETHEREAL_COLORS)
spec_updatehealth(H)
addtimer(CALLBACK(src, .proc/handle_emag, H), 5) //Call ourselves every 0.5 seconds to change color
/datum/species/ethereal/proc/stop_emag(mob/living/carbon/human/H)
emageffect = FALSE
spec_updatehealth(H)
H.visible_message("<span class='danger'>[H] stops flickering and goes back to their normal state!</span>")
/datum/species/ethereal/proc/handle_charge(mob/living/carbon/human/H)
var/charge_rate = ETHEREAL_CHARGE_FACTOR
brutemod = 1.25
adjust_charge(-charge_rate)
switch(ethereal_charge)
if(ETHEREAL_CHARGE_NONE)
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 3)
if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER)
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 2)
apply_damage(0.5, BRUTE)
brutemod = 1.75
if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 1)
brutemod = 1.5
else
H.clear_alert("ethereal_charge")
/datum/species/ethereal/proc/adjust_charge(var/change)
ethereal_charge = CLAMP(ethereal_charge + change, ETHEREAL_CHARGE_NONE, ETHEREAL_CHARGE_FULL)
/datum/species/ethereal/proc/set_charge(var/change)
ethereal_charge = CLAMP(change, ETHEREAL_CHARGE_NONE, ETHEREAL_CHARGE_FULL)

View File

@@ -292,9 +292,9 @@
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(1,T.get_lumcount()) - 0.5
H.nutrition += light_amount * 10
H.adjust_nutrition(light_amount * 10)
if(H.nutrition > NUTRITION_LEVEL_ALMOST_FULL)
H.nutrition = NUTRITION_LEVEL_ALMOST_FULL
H.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL)
if(light_amount > 0.2) //if there's enough light, heal
H.heal_overall_damage(1,1)
H.adjustToxLoss(-1)

View File

@@ -42,7 +42,7 @@
if(H.blood_volume < BLOOD_VOLUME_NORMAL)
if(H.nutrition >= NUTRITION_LEVEL_STARVING)
H.blood_volume += 3
H.nutrition -= 2.5
H.adjust_nutrition(-2.5)
if(H.blood_volume < BLOOD_VOLUME_OKAY)
if(prob(5))
to_chat(H, "<span class='danger'>You feel drained!</span>")
@@ -170,7 +170,7 @@
to_chat(H, "<span class='notice'>You feel very bloated!</span>")
else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
H.blood_volume += 3
H.nutrition -= 2.5
H.adjust_nutrition(-2.5)
..()

View File

@@ -20,7 +20,6 @@
. = ..()
if(ishuman(C))
var/mob/living/carbon/human/H = C
H.dna.features["moth_wings"] = "[(H.client && H.client.prefs && LAZYLEN(H.client.prefs.features) && H.client.prefs.features["moth_wings"]) ? H.client.prefs.features["moth_wings"] : "Plain"]"
handle_mutant_bodyparts(H)
/datum/species/moth/random_name(gender,unique,lastname)

View File

@@ -31,9 +31,9 @@
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(1,T.get_lumcount()) - 0.5
H.nutrition += light_amount * 10
H.adjust_nutrition(light_amount * 10)
if(H.nutrition > NUTRITION_LEVEL_ALMOST_FULL)
H.nutrition = NUTRITION_LEVEL_ALMOST_FULL
H.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL)
if(light_amount > 0.2) //if there's enough light, heal
H.heal_overall_damage(1,1)
H.adjustToxLoss(-1)
@@ -64,4 +64,4 @@
H.adjustFireLoss(rand(5,15))
H.show_message("<span class='userdanger'>The radiation beam singes you!</span>")
if(/obj/item/projectile/energy/florayield)
H.nutrition = min(H.nutrition+30, NUTRITION_LEVEL_FULL)
H.set_nutrition(min(H.nutrition+30, NUTRITION_LEVEL_FULL))

View File

@@ -143,6 +143,7 @@
respawn_progress = 0
return
var/turf/T = get_turf(owner)
if(istype(T))
var/light_amount = T.get_lumcount()
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
@@ -187,6 +188,9 @@
return
if(isliving(AM))
var/mob/living/L = AM
if(isethereal(AM))
AM.emp_act(EMP_LIGHT)
if(iscyborg(AM))
var/mob/living/silicon/robot/borg = AM
if(!borg.lamp_cooldown)

View File

@@ -417,7 +417,7 @@
if(SSmobs.times_fired%3==1)
if(!(M.status_flags & GODMODE))
M.adjustBruteLoss(5)
nutrition += 10
adjust_nutrition(10)
/*

View File

@@ -471,7 +471,7 @@
SetParalyzed(0, FALSE)
SetSleeping(0, FALSE)
radiation = 0
nutrition = NUTRITION_LEVEL_FED + 50
set_nutrition(NUTRITION_LEVEL_FED + 50)
bodytemperature = BODYTEMP_NORMAL
set_blindness(0)
set_blurriness(0)
@@ -1209,4 +1209,4 @@
if("resize")
update_transform()
if("lighting_alpha")
sync_lighting_plane_alpha()
sync_lighting_plane_alpha()

View File

@@ -239,19 +239,19 @@
/mob/living/simple_animal/slime/proc/handle_nutrition()
if(docile) //God as my witness, I will never go hungry again
nutrition = 700
set_nutrition(700) //fuck you for using the base nutrition var
return
if(prob(15))
nutrition -= 1 + is_adult
adjust_nutrition(-(1 + is_adult))
if(nutrition <= 0)
nutrition = 0
set_nutrition(0)
if(prob(75))
adjustBruteLoss(rand(0,5))
else if (nutrition >= get_grow_nutrition() && amount_grown < SLIME_EVOLUTION_THRESHOLD)
nutrition -= 20
adjust_nutrition(-20)
amount_grown++
update_action_buttons_icon()
@@ -262,7 +262,7 @@
Evolve()
/mob/living/simple_animal/slime/proc/add_nutrition(nutrition_to_add = 0)
nutrition = min((nutrition + nutrition_to_add), get_max_nutrition())
set_nutrition(min((nutrition + nutrition_to_add), get_max_nutrition()))
if(nutrition >= get_grow_nutrition())
if(powerlevel<10)
if(prob(30-powerlevel*2))

View File

@@ -160,7 +160,7 @@
var/mob/living/simple_animal/slime/M
M = new(loc, child_colour)
if(ckey)
M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
M.set_nutrition(new_nutrition) //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
M.powerlevel = new_powerlevel
if(i != 1)
step_away(M,src)

View File

@@ -99,7 +99,7 @@
create_reagents(100)
set_colour(new_colour)
. = ..()
nutrition = 700
set_nutrition(700)
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
@@ -261,7 +261,7 @@
return
attacked += 5
if(nutrition >= 100) //steal some nutrition. negval handled in life()
nutrition -= (50 + (40 * M.is_adult))
adjust_nutrition(-(50 + (40 * M.is_adult)))
M.add_nutrition(50 + (40 * M.is_adult))
if(health > 0)
M.adjustBruteLoss(-10 + (-10 * M.is_adult))

View File

@@ -34,7 +34,7 @@
continue
var/datum/atom_hud/alternate_appearance/AA = v
AA.onNewMob(src)
nutrition = rand(NUTRITION_LEVEL_START_MIN, NUTRITION_LEVEL_START_MAX)
set_nutrition(rand(NUTRITION_LEVEL_START_MIN, NUTRITION_LEVEL_START_MAX))
. = ..()
update_config_movespeed()
update_movespeed(TRUE)
@@ -937,6 +937,12 @@
var/datum/language_holder/H = get_language_holder()
H.open_language_menu(usr)
/mob/proc/adjust_nutrition(var/change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
nutrition = max(0, nutrition + change)
/mob/proc/set_nutrition(var/change) //Seriously fuck you oldcoders.
nutrition = max(0, change)
/mob/setMovetype(newval)
. = ..()
update_movespeed(FALSE)

View File

@@ -449,7 +449,7 @@
var/list/babies = list()
for(var/i=1,i<=number,i++)
var/mob/living/simple_animal/slime/M = new/mob/living/simple_animal/slime(loc)
M.nutrition = round(nutrition/number)
M.set_nutrition(round(nutrition/number))
step_away(M,src)
babies += M
new_slime = pick(babies)

View File

@@ -602,7 +602,13 @@
var/mob/living/carbon/human/H = user
if(istype(H))
if(isethereal(H))
to_chat(H, "<span class='notice'>You start channeling some power through the [fitting] into your body.</span>")
if(do_after(user, 50, target = src))
to_chat(H, "<span class='notice'>You receive some charge from the [fitting].</span>")
H.dna?.species.adjust_charge(5)
return
if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
if(G.max_heat_protection_temperature)

View File

@@ -1764,7 +1764,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/fernet/on_mob_life(mob/living/carbon/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(1*REM, 0)
M.nutrition = max(M.nutrition - 5, 0)
M.adjust_nutrition(-5)
M.overeatduration = 0
return ..()
@@ -1783,7 +1783,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/fernet_cola/on_mob_life(mob/living/carbon/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(0.5*REM, 0)
M.nutrition = max(M.nutrition - 3, 0)
M.adjust_nutrition(- 3)
M.overeatduration = 0
return ..()
@@ -1801,7 +1801,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "A glass of Fanciulli. It's just Manhattan with Fernet."
/datum/reagent/consumable/ethanol/fanciulli/on_mob_life(mob/living/carbon/M)
M.nutrition = max(M.nutrition - 5, 0)
M.adjust_nutrition(-5)
M.overeatduration = 0
return ..()

View File

@@ -638,7 +638,7 @@
M.adjustOxyLoss(-0.5, 0)
if(M.nutrition && (M.nutrition - 2 > 0))
if(!(M.mind && M.mind.assigned_role == "Medical Doctor")) //Drains the nutrition of the holder. Not medical doctors though, since it's the Doctor's Delight!
M.nutrition -= 2
M.adjust_nutrition(-2)
..()
. = 1

View File

@@ -17,7 +17,10 @@
/datum/reagent/consumable/on_mob_life(mob/living/carbon/M)
current_cycle++
M.nutrition += nutriment_factor
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(!H.has_trait(TRAIT_NOHUNGER))
H.adjust_nutrition(nutriment_factor)
holder.remove_reagent(src.id, metabolization_rate)
/datum/reagent/consumable/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
@@ -626,7 +629,7 @@
/datum/reagent/consumable/nutriment/stabilized/on_mob_life(mob/living/carbon/M)
if(M.nutrition > NUTRITION_LEVEL_FULL - 25)
M.nutrition -= 3*nutriment_factor
M.adjust_nutrition(-3*nutriment_factor)
..()
////Lavaland Flora Reagents////
@@ -687,3 +690,22 @@
nutriment_factor = 5 * REAGENTS_METABOLISM
color = "#eef442" // rgb: 238, 244, 66
taste_description = "mournful honking"
/datum/reagent/consumable/liquidelectricity
name = "Liquid Electricity"
id = "liquidelectricity"
description = "The blood of Ethereals, and the stuff that keeps them going. Great for them, horrid for anyone else."
nutriment_factor = 5 * REAGENTS_METABOLISM
color = "#97ee63"
taste_description = "pure electrictiy"
/datum/reagent/consumable/liquidelectricity/on_mob_life(mob/living/carbon/M)
if(isethereal(M))
var/mob/living/carbon/human/H = M
var/datum/species/ethereal/E = H.dna?.species
E.adjust_charge(5*REM)
else if(prob(25)) //scp13 optimization
M.electrocute_act(rand(10,15), "Liquid Electricity in their body", 1) //lmao at the newbs who eat energy bars
playsound(M, "sparks", 50, 1)
return ..()

View File

@@ -357,7 +357,7 @@
/datum/reagent/medicine/mine_salve/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
if(method in list(INGEST, VAPOR, INJECT))
M.nutrition -= 5
M.adjust_nutrition(-5)
if(show_message)
to_chat(M, "<span class='warning'>Your stomach feels empty and cramps!</span>")
else

View File

@@ -660,7 +660,7 @@
/datum/reagent/toxin/lipolicide/on_mob_life(mob/living/carbon/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
M.adjustToxLoss(1*REM, 0)
M.nutrition = max(M.nutrition - 3, 0) // making the chef more valuable, one meme trap at a time
M.adjust_nutrition(-3) // making the chef more valuable, one meme trap at a time
M.overeatduration = 0
return ..()

View File

@@ -69,6 +69,9 @@
/obj/item/reagent_containers/blood/lizard
blood_type = "L"
/obj/item/reagent_containers/blood/ethereal
blood_type = "LE"
/obj/item/reagent_containers/blood/universal
blood_type = "U"

View File

@@ -196,7 +196,7 @@
return ..()
/datum/nanite_program/metabolic_synthesis/active_effect()
host_mob.nutrition -= 0.5
host_mob.adjust_nutrition(-0.5)
/datum/nanite_program/triggered/access
name = "Subdermal ID"

View File

@@ -866,7 +866,7 @@ datum/status_effect/stabilized/blue/on_remove()
healing_types += CLONE
owner.apply_damage_type(-heal_amount, damagetype=pick(healing_types))
owner.nutrition += 3
owner.adjust_nutrition(3)
M.adjustCloneLoss(heal_amount * 1.2) //This way, two people can't just convert each other's damage away.
else
messagedelivered = FALSE

View File

@@ -36,7 +36,7 @@ Burning extracts:
S.visible_message("<span class='danger'>A baby slime emerges from [src], and it nuzzles [user] before burbling hungrily!</span>")
S.Friends[user] = 20 //Gas, gas, gas
S.bodytemperature = T0C + 400 //We gonna step on the gas.
S.nutrition = S.get_hunger_nutrition() //Tonight, we fight!
S.set_nutrition(S.get_hunger_nutrition()) //Tonight, we fight!
..()
/obj/item/slimecross/burning/orange

View File

@@ -128,7 +128,7 @@ Regenerative extracts:
colour = "silver"
/obj/item/slimecross/regenerative/silver/core_effect(mob/living/target, mob/user)
target.nutrition = NUTRITION_LEVEL_FULL - 1
target.set_nutrition(NUTRITION_LEVEL_FULL - 1)
to_chat(target, "<span class='notice'>You feel satiated.</span>")
/obj/item/slimecross/regenerative/bluespace

View File

@@ -187,7 +187,7 @@
/obj/item/slime_extract/purple/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
if(SLIME_ACTIVATE_MINOR)
user.nutrition += 50
user.adjust_nutrition(50)
user.blood_volume += 50
to_chat(user, "<span class='notice'>You activate [src], and your body is refilled with fresh slime jelly!</span>")
return 150
@@ -635,7 +635,7 @@
return
M.docile = 1
M.nutrition = 700
M.set_nutrition(700)
to_chat(M, "<span class='warning'>You absorb the potion and feel your intense desire to feed melt away.</span>")
to_chat(user, "<span class='notice'>You feed the slime the potion, removing its hunger and calming it.</span>")
var/newname = copytext(sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text),1,MAX_NAME_LEN)

View File

@@ -320,7 +320,7 @@
body_gender = H.gender
should_draw_gender = S.sexes
if(MUTCOLORS in S.species_traits)
if((MUTCOLORS in S.species_traits) || (DYNCOLORS in S.species_traits))
if(S.fixed_mut_color)
species_color = S.fixed_mut_color
else

View File

@@ -35,7 +35,7 @@
user.visible_message("[user] extracts [target]'s fat!", "<span class='notice'>You extract [target]'s fat.</span>")
target.overeatduration = 0 //patient is unfatted
var/removednutriment = target.nutrition
target.nutrition = NUTRITION_LEVEL_WELL_FED
target.set_nutrition(NUTRITION_LEVEL_WELL_FED)
removednutriment -= 450 //whatever was removed goes into the meat
var/mob/living/carbon/human/H = target
var/typeofmeat = /obj/item/reagent_containers/food/snacks/meat/slab/human

View File

@@ -22,7 +22,7 @@
if(owner.nutrition <= hunger_threshold)
synthesizing = TRUE
to_chat(owner, "<span class='notice'>You feel less hungry...</span>")
owner.nutrition += 50
owner.adjust_nutrition(50)
addtimer(CALLBACK(src, .proc/synth_cool), 50)
/obj/item/organ/cyberimp/chest/nutriment/proc/synth_cool()

View File

@@ -10,7 +10,8 @@
/obj/item/reagent_containers/food/snacks/chips = 6,
/obj/item/reagent_containers/food/snacks/sosjerky = 6,
/obj/item/reagent_containers/food/snacks/no_raisin = 6,
/obj/item/reagent_containers/food/drinks/dry_ramen = 3)
/obj/item/reagent_containers/food/drinks/dry_ramen = 3,
/obj/item/reagent_containers/food/snacks/energybar = 6)
contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6)
refill_canister = /obj/item/vending_refill/snack
var/chef_compartment_access = "28" //ACCESS_KITCHEN

View File

@@ -71,4 +71,4 @@
user.adjustCloneLoss(-hp_gained, 0)
user.updatehealth()
user.adjustBrainLoss(-hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!"
user.nutrition = min(user.nutrition + hp_gained, NUTRITION_LEVEL_FULL)
user.set_nutrition(min(user.nutrition + hp_gained, NUTRITION_LEVEL_FULL))

View File

@@ -438,6 +438,7 @@ ROUNDSTART_RACES plasmaman
#ROUNDSTART_RACES shadow
## Races that are better than humans in some ways, but worse in others
ROUNDSTART_RACES ethereal
#ROUNDSTART_RACES jelly
#ROUNDSTART_RACES golem
#ROUNDSTART_RACES adamantine

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,38 @@
Aten
Apollo
Arche
Atlas
Eos
Halo
Kale
Nysa
Orion
Pallas
Rigel
Themis
Aurora
Andromeda
Lyra
Saggitarius
Crux
Canis
Cygnus
Corvus
Cepheus
Auriga
Corona
Aquilla
Serpens
Cetus
Puppis
Ophiuchus
Carina
Cassiopeia
Canes
Fornax
Berenices
Coma
Vela
Triangulum
Tau
Ceti

View File

@@ -1935,6 +1935,7 @@
#include "code\modules\mob\living\carbon\human\species_types\angel.dm"
#include "code\modules\mob\living\carbon\human\species_types\corporate.dm"
#include "code\modules\mob\living\carbon\human\species_types\dullahan.dm"
#include "code\modules\mob\living\carbon\human\species_types\ethereal.dm"
#include "code\modules\mob\living\carbon\human\species_types\felinid.dm"
#include "code\modules\mob\living\carbon\human\species_types\flypeople.dm"
#include "code\modules\mob\living\carbon\human\species_types\golems.dm"