added ethereals

This commit is contained in:
Putnam
2020-08-08 00:08:43 -07:00
parent 9974c90d8e
commit 9bb3ba5c5a
37 changed files with 524 additions and 24 deletions

View File

@@ -209,6 +209,8 @@
#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands" //from base of mob/swap_hand(): (obj/item)
#define COMPONENT_BLOCK_SWAP 1
#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge"
// /client signals
#define COMSIG_MOB_CLIENT_LOGIN "mob_client_login" //sent when a mob/login() finishes: (client)
#define COMSIG_MOB_CLIENT_LOGOUT "mob_client_logout" //sent when a mob/logout() starts: (client)

View File

@@ -74,6 +74,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define ismush(A) (is_species(A, /datum/species/mush))
#define isshadow(A) (is_species(A, /datum/species/shadow))
#define isskeleton(A) (is_species(A, /datum/species/skeleton))
#define isethereal(A) (is_species(A, /datum/species/ethereal))
// Citadel specific species
#define isipcperson(A) (is_species(A, /datum/species/ipc))

View File

@@ -176,6 +176,15 @@
#define DISGUST_LEVEL_VERYGROSS 50
#define DISGUST_LEVEL_GROSS 25
//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
#define ETHEREAL_CHARGE_OVERLOAD 125
#define ETHEREAL_CHARGE_DANGEROUS 150
//Slime evolution threshold. Controls how fast slimes can split/grow
#define SLIME_EVOLUTION_THRESHOLD 10
@@ -284,6 +293,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.08 //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

@@ -264,6 +264,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

@@ -776,6 +776,10 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
else
return "[number]\th"
/proc/random_capital_letter()
return uppertext(pick(GLOB.alphabet))
/proc/unintelligize(message)
var/regex/word_boundaries = regex(@"\b[\S]+\b", "g")
var/prefix = message[1]

View File

@@ -17,6 +17,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

@@ -493,6 +493,16 @@ 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"
/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"
/obj/screen/alert/ethereal_overcharge
name = "Blood Overcharge"
desc = "Your blood's electric charge is becoming dangerously high, find an outlet for your energy. Use Grab Intent on an APC to channel your energy into it."
icon_state = "ethereal_overcharge"
//Need to cover all use cases - emag, illegal upgrade module, malf AI hack, traitor cyborg
/obj/screen/alert/hacked
name = "Hacked"

View File

@@ -307,6 +307,10 @@
/datum/component/mood/proc/HandleNutrition(mob/living/L)
if(isethereal(L))
HandleCharge(L)
if(HAS_TRAIT(L, TRAIT_NOHUNGER))
return FALSE //no mood events for nutrition
switch(L.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
add_event(null, "nutrition", /datum/mood_event/fat)
@@ -321,6 +325,22 @@
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.get_charge(H))
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)
if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD)
add_event(null, "charge", /datum/mood_event/overcharged)
if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
add_event(null, "charge", /datum/mood_event/supercharged)
/datum/component/mood/proc/update_beauty(area/A)
if(A.outdoors) //if we're outside, we don't care.
clear_event(null, "area_beauty")

View File

@@ -19,6 +19,27 @@
description = "<span class='boldwarning'>I'm starving!</span>\n"
mood_change = -15
//charge
/datum/mood_event/supercharged
description = "<span class='boldwarning'>I can't possibly keep all this power inside, I need to release some quick!</span>\n"
mood_change = -10
/datum/mood_event/overcharged
description = "<span class='warning'>I feel dangerously overcharged, perhaps I should release some power.</span>\n"
mood_change = -4
/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 = -6
/datum/mood_event/decharged
description = "<span class='boldwarning'>I'm in desperate need of some electricity!</span>\n"
mood_change = -10
//Disgust
/datum/mood_event/gross
description = "<span class='warning'>I saw something gross.</span>\n"

View File

@@ -126,17 +126,6 @@
update_icon()
/obj/machinery/recharge_station/proc/process_occupant()
if(occupant && 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)
/obj/machinery/recharge_station/proc/restock_modules()
if(occupant)
var/mob/living/silicon/robot/R = occupant
if(R && R.module)
var/coeff = recharge_speed * 0.005
R.module.respawn_consumable(R, coeff)
if(!occupant)
return
SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, recharge_speed, repairs)

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

@@ -2184,8 +2184,18 @@
if(!ishuman(H))
to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.")
return
var/obj/item/reagent_containers/food/snacks/cookie/cookie = new(H)
//let's keep it simple
//milk to plasmemes and skeletons, meat to lizards, electricity bars to ethereals, cookies to everyone else
var/cookiealt = /obj/item/reagent_containers/food/snacks/cookie
if(isskeleton(H))
cookiealt = /obj/item/reagent_containers/food/condiment/milk
else if(isplasmaman(H))
cookiealt = /obj/item/reagent_containers/food/condiment/milk
else if(isethereal(H))
cookiealt = /obj/item/reagent_containers/food/snacks/energybar
else if(islizard(H))
cookiealt = /obj/item/reagent_containers/food/snacks/meat/slab
var/obj/item/cookie = new cookiealt(H)
if(H.put_in_hands(cookie))
H.update_inv_hands()
else

View File

@@ -162,6 +162,14 @@
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(/datum/reagent/consumable/liquidelectricity = 3)
tastes = list("pure electricity" = 2, "meat" = 1)
foodtype = RAW | MEAT | TOXIC
/obj/item/reagent_containers/food/snacks/carpmeat/aquatic
name = "fillet"
desc = "A fillet of one of the local water dwelling species."

View File

@@ -91,3 +91,13 @@
tastes = list("sweetness" = 3, "cake" = 1)
foodtype = GRAIN | FRUIT | VEGETABLES
custom_price = PRICE_CHEAP
/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(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/liquidelectricity = 3)
filling_color = "#97ee63"
tastes = list("pure electricity" = 3, "fitness" = 2)
foodtype = TOXIC

View File

@@ -324,6 +324,12 @@ Key procs
/datum/language/sylvan = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/sylvan = list(LANGUAGE_ATOM))
/datum/language_holder/ethereal
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/voltaic = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/voltaic = list(LANGUAGE_ATOM))
/datum/language_holder/empty
understood_languages = list()
spoken_languages = list()

View File

@@ -0,0 +1,14 @@
// One of these languages will actually work, I'm certain of it.
/datum/language/voltaic
name = "Voltaic"
desc = "A sparky language made by manipulating electrical discharge."
key = "v"
space_chance = 20
syllables = list(
"bzzt", "skrrt", "zzp", "mmm", "hzz", "tk", "shz", "k", "z",
"bzt", "zzt", "skzt", "skzz", "hmmt", "zrrt", "hzzt", "hz",
"vzt", "zt", "vz", "zip", "tzp", "lzzt", "dzzt", "zdt", "kzt",
"zzzz", "mzz"
)
icon_state = "volt"
default_priority = 90

View File

@@ -1042,7 +1042,7 @@
/mob/living/carbon/human/updatehealth()
. = ..()
dna?.species.spec_updatehealth(src)
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN)) //if we want to ignore slowdown from damage and equipment
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
@@ -1199,6 +1199,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

@@ -56,6 +56,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/list/mutant_organs = list() //Internal organs that are unique to this race.
var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster
var/armor = 0 // overall defense for the race... or less defense, if it's negative.
var/attack_type = BRUTE // the type of damage unarmed attacks from this species do
var/brutemod = 1 // multiplier for brute damage
var/burnmod = 1 // multiplier for burn damage
var/coldmod = 1 // multiplier for cold damage
@@ -1364,6 +1365,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if(hungry >= 70)
H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (hungry / 50))
else if(isethereal(H))
var/datum/species/ethereal/E = H.dna.species
if(E.get_charge(H) <= ETHEREAL_CHARGE_NORMAL)
H.add_movespeed_modifier(MOVESPEED_ID_HUNGRY, override = TRUE, multiplicative_slowdown = (1.5 * (1 - E.get_charge(H) / 100)))
else
H.remove_movespeed_modifier(/datum/movespeed_modifier/hunger)
@@ -1420,6 +1425,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// 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/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH))
target.help_shake_act(user)
@@ -1538,11 +1549,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.dismembering_strike(user, affecting.body_zone)
if(atk_verb == ATTACK_EFFECT_KICK)//kicks deal 1.5x raw damage + 0.5x stamina damage
target.apply_damage(damage*1.5, BRUTE, affecting, armor_block)
target.apply_damage(damage*1.5, attack_type, affecting, armor_block)
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
log_combat(user, target, "kicked")
else//other attacks deal full raw damage + 2x in stamina damage
target.apply_damage(damage, BRUTE, affecting, armor_block)
target.apply_damage(damage, attack_type, affecting, armor_block)
target.apply_damage(damage*2, STAMINA, affecting, armor_block)
log_combat(user, target, "punched")

View File

@@ -0,0 +1,182 @@
#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
mutantstomach = /obj/item/organ/stomach/ethereal
mutanttongue = /obj/item/organ/tongue/ethereal
exotic_blood = /datum/reagent/consumable/liquidelectricity //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(MUTCOLORS, NO_UNDERWEAR, HAIR, HAS_FLESH, HAS_BONE) // i mean i guess they have blood so they can have wounds too
species_language_holder = /datum/language_holder/ethereal
inherent_traits = list(TRAIT_NOHUNGER)
sexes = FALSE
toxic_food = NONE
/*
citadel doesn't have per-species temperatures, yet
// Body temperature for ethereals is much higher then humans as they like hotter environments
bodytemp_normal = (BODYTEMP_NORMAL + 50)
bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // about 150C
// Cold temperatures hurt faster as it is harder to move with out the heat energy
bodytemp_cold_damage_limit = (T20C - 10) // about 10c
*/
hair_color = "fixedmutcolor"
hair_alpha = 140
var/current_color
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.
var/drain_time = 0 //used to keep ethereals from spam draining power sources
/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["mcolor"]
r1 = GETREDPART(default_color)
g1 = GETGREENPART(default_color)
b1 = GETBLUEPART(default_color)
spec_updatehealth(H)
RegisterSignal(C, COMSIG_ATOM_EMAG_ACT, .proc/on_emag_act)
RegisterSignal(C, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act)
/datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
.=..()
C.set_light(0)
UnregisterSignal(C, COMSIG_ATOM_EMAG_ACT)
UnregisterSignal(C, COMSIG_ATOM_EMP_ACT)
/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_char(current_color, 2)
else
H.set_light(0)
fixed_mut_color = rgb(128,128,128)
H.update_body()
/datum/species/ethereal/proc/on_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), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds
if(EMP_HEAVY)
addtimer(CALLBACK(src, .proc/stop_emp, H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds
/datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user)
if(emageffect)
return
emageffect = TRUE
if(user)
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), 30 SECONDS) //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/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)
brutemod = 1.25
switch(get_charge(H))
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)
if(H.health > 10.5)
apply_damage(0.65, TOX, null, null, H)
brutemod = 1.75
if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
H.throw_alert("ethereal_charge", /obj/screen/alert/etherealcharge, 1)
brutemod = 1.5
if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD)
H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 1)
apply_damage(0.2, TOX, null, null, H)
brutemod = 1.5
if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
H.throw_alert("ethereal_overcharge", /obj/screen/alert/ethereal_overcharge, 2)
apply_damage(0.65, TOX, null, null, H)
brutemod = 1.75
if(prob(10)) //10% each tick for ethereals to explosively release excess energy if it reaches dangerous levels
discharge_process(H)
else
H.clear_alert("ethereal_charge")
H.clear_alert("ethereal_overcharge")
/datum/species/ethereal/proc/discharge_process(mob/living/carbon/human/H)
to_chat(H, "<span class='warning'>You begin to lose control over your charge!</span>")
H.visible_message("<span class='danger'>[H] begins to spark violently!</span>")
var/static/mutable_appearance/overcharge //shameless copycode from lightning spell
overcharge = overcharge || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER)
H.add_overlay(overcharge)
if(do_mob(H, H, 50, 1))
H.flash_lighting_fx(5, 7, current_color)
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
playsound(H, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
H.cut_overlay(overcharge)
tesla_zap(H, 2, stomach.crystal_charge*50, ZAP_OBJ_DAMAGE | ZAP_ALLOW_DUPLICATES)
if(istype(stomach))
stomach.adjust_charge(100 - stomach.crystal_charge)
to_chat(H, "<span class='warning'>You violently discharge energy!</span>")
H.visible_message("<span class='danger'>[H] violently discharges energy!</span>")
if(prob(10)) //chance of developing heart disease to dissuade overcharging oneself
var/datum/disease/D = new /datum/disease/heart_failure
H.ForceContractDisease(D)
to_chat(H, "<span class='userdanger'>You're pretty sure you just felt your heart stop for a second there..</span>")
H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, 0)
H.Paralyze(100)
return
/datum/species/ethereal/proc/get_charge(mob/living/carbon/H) //this feels like it should be somewhere else. Eh?
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
return stomach.crystal_charge
return ETHEREAL_CHARGE_NONE

View File

@@ -185,6 +185,8 @@
T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
else 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_intensity)

View File

@@ -16,6 +16,8 @@
wires = new /datum/wires/robot(src)
AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES)
RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge)
robot_modules_background = new()
robot_modules_background.icon_state = "block"
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it.
@@ -1097,6 +1099,15 @@
for(var/i in connected_ai.aicamera.stored)
aicamera.stored[i] = TRUE
/mob/living/silicon/robot/proc/charge(datum/source, amount, repairs)
if(module)
var/coeff = amount * 0.005
module.respawn_consumable(src, coeff)
if(repairs)
heal_bodypart_damage(repairs, repairs - 1)
if(cell)
cell.charge = min(cell.charge + amount, cell.maxcharge)
/mob/living/silicon/robot/proc/rest_style()
set name = "Switch Rest Style"
set category = "Robot Commands"

View File

@@ -838,6 +838,46 @@
// attack with hand - remove cell (if cover open) or interact with the APC
/obj/machinery/power/apc/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(isethereal(user))
var/mob/living/carbon/human/H = user
if(H.a_intent == INTENT_HARM)
if(cell.charge <= (cell.maxcharge / 2)) // if charge is under 50% you shouldnt drain it
to_chat(H, "<span class='warning'>The APC doesn't have much power, you probably shouldn't drain any.</span>")
return
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
if(stomach.crystal_charge > 145)
to_chat(H, "<span class='warning'>Your charge is full!</span>")
return
to_chat(H, "<span class='notice'>You start channeling some power through the APC into your body.</span>")
if(do_after(user, 75, target = src))
if(cell.charge <= (cell.maxcharge / 2) || (stomach.crystal_charge > 145))
return
if(istype(stomach))
to_chat(H, "<span class='notice'>You receive some charge from the APC.</span>")
stomach.adjust_charge(10)
cell.charge -= 10
else
to_chat(H, "<span class='warning'>You can't receive charge from the APC!</span>")
return
if(H.a_intent == INTENT_GRAB)
if(cell.charge == cell.maxcharge)
to_chat(H, "<span class='warning'>The APC is full!</span>")
return
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
if(stomach.crystal_charge < 10)
to_chat(H, "<span class='warning'>Your charge is too low!</span>")
return
to_chat(H, "<span class='notice'>You start channeling power through your body into the APC.</span>")
if(do_after(user, 75, target = src))
if(cell.charge == cell.maxcharge || (stomach.crystal_charge < 10))
return
if(istype(stomach))
to_chat(H, "<span class='notice'>You transfer some power to the APC.</span>")
stomach.adjust_charge(-10)
cell.charge += 10
else
to_chat(H, "<span class='warning'>You can't transfer power to the APC!</span>")
return
if(opened && (!issilicon(user)))
if(cell)
user.visible_message("[user] removes \the [cell] from [src]!","<span class='notice'>You remove \the [cell].</span>")

View File

@@ -151,6 +151,27 @@
if(prob(25))
corrupt()
/obj/item/stock_parts/cell/attack_self(mob/user)
if(isethereal(user))
var/mob/living/carbon/human/H = user
if(charge < 100)
to_chat(H, "<span class='warning'>The [src] doesn't have enough power!</span>")
return
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
if(stomach.crystal_charge > 146)
to_chat(H, "<span class='warning'>Your charge is full!</span>")
return
to_chat(H, "<span class='notice'>You clumsily channel power through the [src] and into your body, wasting some in the process.</span>")
if(do_after(user, 5, target = src))
if((charge < 100) || (stomach.crystal_charge > 146))
return
if(istype(stomach))
to_chat(H, "<span class='notice'>You receive some charge from the [src].</span>")
stomach.adjust_charge(3)
charge -= 100 //you waste way more than you receive, so that ethereals cant just steal one cell and forget about hunger
else
to_chat(H, "<span class='warning'>You can't receive charge from the [src]!</span>")
return
/obj/item/stock_parts/cell/blob_act(obj/structure/blob/B)
ex_act(EXPLODE_DEVASTATE)

View File

@@ -610,7 +610,18 @@
var/mob/living/carbon/human/H = user
if(istype(H))
var/datum/species/ethereal/eth_species = H.dna?.species
if(istype(eth_species))
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))
var/obj/item/organ/stomach/ethereal/stomach = H.getorganslot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
to_chat(H, "<span class='notice'>You receive some charge from the [fitting].</span>")
stomach.adjust_charge(2)
else
to_chat(H, "<span class='warning'>You can't receive charge from the [fitting]!</span>")
return
if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
if(G.max_heat_protection_temperature)

View File

@@ -768,7 +768,6 @@
color = "#97ee63"
taste_description = "pure electricity"
/* //We don't have ethereals here, so I'll just comment it out.
/datum/reagent/consumable/liquidelectricity/reaction_mob(mob/living/M, method=TOUCH, reac_volume) //can't be on life because of the way blood works.
if((method == INGEST || method == INJECT || method == PATCH) && iscarbon(M))
@@ -776,10 +775,9 @@
var/obj/item/organ/stomach/ethereal/stomach = C.getorganslot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
stomach.adjust_charge(reac_volume * REM)
*/
/datum/reagent/consumable/liquidelectricity/on_mob_life(mob/living/carbon/M)
if(prob(25)) // && !isethereal(M))
if(prob(25) && !isethereal(M))
M.electrocute_act(rand(10,15), "Liquid Electricity in their body", 1) //lmao at the newbs who eat energy bars
playsound(M, "sparks", 50, TRUE)
return ..()

View File

@@ -91,3 +91,36 @@
/obj/item/organ/stomach/ipc
name = "ipc stomach"
icon_state = "stomach-ipc"
/obj/item/organ/stomach/ethereal
name = "biological battery"
icon_state = "stomach-p" //Welp. At least it's more unique in functionaliy.
desc = "A crystal-like organ that stores the electric charge of ethereals."
var/crystal_charge = ETHEREAL_CHARGE_FULL
/obj/item/organ/stomach/ethereal/on_life()
..()
adjust_charge(-ETHEREAL_CHARGE_FACTOR)
/obj/item/organ/stomach/ethereal/Insert(mob/living/carbon/M, special = 0)
..()
RegisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge)
RegisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT, .proc/on_electrocute)
/obj/item/organ/stomach/ethereal/Remove(mob/living/carbon/M, special = 0)
UnregisterSignal(owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT)
UnregisterSignal(owner, COMSIG_LIVING_ELECTROCUTE_ACT)
..()
/obj/item/organ/stomach/ethereal/proc/charge(datum/source, amount, repairs)
adjust_charge(amount / 70)
/obj/item/organ/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
if(flags & SHOCK_ILLUSION)
return
adjust_charge(shock_damage * siemens_coeff * 2)
to_chat(owner, "<span class='notice'>You absorb some of the shock into your body!</span>")
/obj/item/organ/stomach/ethereal/proc/adjust_charge(amount)
crystal_charge = clamp(crystal_charge + amount, ETHEREAL_CHARGE_NONE, ETHEREAL_CHARGE_DANGEROUS)

View File

@@ -312,3 +312,26 @@
desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms."
electronics_magic = FALSE
organ_flags = ORGAN_SYNTHETIC
/obj/item/organ/tongue/ethereal
name = "electric discharger"
desc = "A sophisticated ethereal organ, capable of synthesising speech via electrical discharge."
icon_state = "electrotongue"
say_mod = "crackles"
attack_verb = list("shocked", "jolted", "zapped")
taste_sensitivity = 101 // Not a tongue, they can't taste shit
var/static/list/languages_possible_ethereal = typecacheof(list(
/datum/language/common,
/datum/language/draconic,
/datum/language/codespeak,
/datum/language/monkey,
/datum/language/narsie,
/datum/language/beachbum,
/datum/language/aphasia,
/datum/language/sylvan,
/datum/language/voltaic
))
/obj/item/organ/tongue/ethereal/Initialize(mapload)
. = ..()
languages_possible = languages_possible_ethereal

View File

@@ -12,7 +12,8 @@
/obj/item/reagent_containers/food/snacks/no_raisin = 5,
/obj/item/reagent_containers/food/snacks/spacetwinkie = 5,
/obj/item/reagent_containers/food/snacks/cheesiehonkers = 5,
/obj/item/reagent_containers/food/snacks/cornchips = 5)
/obj/item/reagent_containers/food/snacks/cornchips = 5,
/obj/item/reagent_containers/food/snacks/energybar = 6)
contraband = list(
/obj/item/reagent_containers/food/snacks/cracker = 10,
/obj/item/reagent_containers/food/snacks/honeybar = 5,

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 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

@@ -2271,6 +2271,7 @@
#include "code\modules\language\swarmer.dm"
#include "code\modules\language\sylvan.dm"
#include "code\modules\language\vampiric.dm"
#include "code\modules\language\voltaic.dm"
#include "code\modules\language\xenocommon.dm"
#include "code\modules\library\lib_codex_gigas.dm"
#include "code\modules\library\lib_items.dm"
@@ -2499,6 +2500,7 @@
#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\dwarves.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\furrypeople.dm"