mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 18:02:57 +00:00
added ethereals
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)]"
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
14
code/modules/language/voltaic.dm
Normal file
14
code/modules/language/voltaic.dm
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
182
code/modules/mob/living/carbon/human/species_types/ethereal.dm
Normal file
182
code/modules/mob/living/carbon/human/species_types/ethereal.dm
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 |
BIN
sound/weapons/etherealhit.ogg
Normal file
BIN
sound/weapons/etherealhit.ogg
Normal file
Binary file not shown.
BIN
sound/weapons/etherealmiss.ogg
Normal file
BIN
sound/weapons/etherealmiss.ogg
Normal file
Binary file not shown.
38
strings/names/ethereal.txt
Normal file
38
strings/names/ethereal.txt
Normal 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
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user