Merge pull request #13081 from Putnam3145/ethereals

Ports ethereals from TG
This commit is contained in:
silicons
2020-08-09 05:39:43 -07:00
committed by GitHub
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_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, 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, drop_if_replaced = TRUE)
..()
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,