mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-12 01:34:53 +01:00
76b5ee3966
I've always found grating that xenobiology had access to species they had no business working with, and slime magic can only explain so much. My idea is to separate those species into their respective departments/antags, instead of having them all into a centralized, cheap source.
Androids should be made by robotics through augmentation
Podpeople are a botany feature
Skeletons should be limited to liches or other magic antags
Zombies should stay limited to romerol
Golems are still available in adamantine slimes (and luminescents can morph into golems with them)
Shadowpeople still lack an official place, but luminescents can become shadowpeople with black cores
The basic races are mostly human and lizard, and there are mutation toxins for those in case someone wants their species back after bodyswapping/ling mutation sting/etc.
511 lines
15 KiB
Plaintext
511 lines
15 KiB
Plaintext
/proc/random_blood_type()
|
|
return pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
|
|
|
|
/proc/random_eye_color()
|
|
switch(pick(20;"brown",20;"hazel",20;"grey",15;"blue",15;"green",1;"amber",1;"albino"))
|
|
if("brown")
|
|
return "630"
|
|
if("hazel")
|
|
return "542"
|
|
if("grey")
|
|
return pick("666","777","888","999","aaa","bbb","ccc")
|
|
if("blue")
|
|
return "36c"
|
|
if("green")
|
|
return "060"
|
|
if("amber")
|
|
return "fc0"
|
|
if("albino")
|
|
return pick("c","d","e","f") + pick("0","1","2","3","4","5","6","7","8","9") + pick("0","1","2","3","4","5","6","7","8","9")
|
|
else
|
|
return "000"
|
|
|
|
/proc/random_underwear(gender)
|
|
if(!GLOB.underwear_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
|
|
switch(gender)
|
|
if(MALE)
|
|
return pick(GLOB.underwear_m)
|
|
if(FEMALE)
|
|
return pick(GLOB.underwear_f)
|
|
else
|
|
return pick(GLOB.underwear_list)
|
|
|
|
/proc/random_undershirt(gender)
|
|
if(!GLOB.undershirt_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
|
|
switch(gender)
|
|
if(MALE)
|
|
return pick(GLOB.undershirt_m)
|
|
if(FEMALE)
|
|
return pick(GLOB.undershirt_f)
|
|
else
|
|
return pick(GLOB.undershirt_list)
|
|
|
|
/proc/random_socks()
|
|
if(!GLOB.socks_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
|
|
return pick(GLOB.socks_list)
|
|
|
|
/proc/random_features()
|
|
if(!GLOB.tails_list_human.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human)
|
|
if(!GLOB.tails_list_lizard.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard)
|
|
if(!GLOB.snouts_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list)
|
|
if(!GLOB.horns_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/horns, GLOB.horns_list)
|
|
if(!GLOB.ears_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.horns_list)
|
|
if(!GLOB.frills_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
|
|
if(!GLOB.spines_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list)
|
|
if(!GLOB.legs_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
|
|
if(!GLOB.body_markings_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
|
|
if(!GLOB.wings_list.len)
|
|
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
|
|
|
|
//For now we will always return none for tail_human and ears.
|
|
return(list("mcolor" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), "tail_lizard" = pick(GLOB.tails_list_lizard), "tail_human" = "None", "wings" = "None", "snout" = pick(GLOB.snouts_list), "horns" = pick(GLOB.horns_list), "ears" = "None", "frills" = pick(GLOB.frills_list), "spines" = pick(GLOB.spines_list), "body_markings" = pick(GLOB.body_markings_list), "legs" = "Normal Legs"))
|
|
|
|
/proc/random_hair_style(gender)
|
|
switch(gender)
|
|
if(MALE)
|
|
return pick(GLOB.hair_styles_male_list)
|
|
if(FEMALE)
|
|
return pick(GLOB.hair_styles_female_list)
|
|
else
|
|
return pick(GLOB.hair_styles_list)
|
|
|
|
/proc/random_facial_hair_style(gender)
|
|
switch(gender)
|
|
if(MALE)
|
|
return pick(GLOB.facial_hair_styles_male_list)
|
|
if(FEMALE)
|
|
return pick(GLOB.facial_hair_styles_female_list)
|
|
else
|
|
return pick(GLOB.facial_hair_styles_list)
|
|
|
|
/proc/random_unique_name(gender, attempts_to_find_unique_name=10)
|
|
for(var/i=1, i<=attempts_to_find_unique_name, i++)
|
|
if(gender==FEMALE)
|
|
. = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
|
|
else
|
|
. = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
|
|
|
|
if(i != attempts_to_find_unique_name && !findname(.))
|
|
break
|
|
|
|
/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10)
|
|
for(var/i=1, i<=attempts_to_find_unique_name, i++)
|
|
. = capitalize(lizard_name(gender))
|
|
|
|
if(i != attempts_to_find_unique_name && !findname(.))
|
|
break
|
|
|
|
/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10)
|
|
for(var/i=1, i<=attempts_to_find_unique_name, i++)
|
|
. = capitalize(plasmaman_name())
|
|
|
|
if(i != attempts_to_find_unique_name && !findname(.))
|
|
break
|
|
|
|
/proc/random_skin_tone()
|
|
return pick(GLOB.skin_tones)
|
|
|
|
GLOBAL_LIST_INIT(skin_tones, list(
|
|
"albino",
|
|
"caucasian1",
|
|
"caucasian2",
|
|
"caucasian3",
|
|
"latino",
|
|
"mediterranean",
|
|
"asian1",
|
|
"asian2",
|
|
"arab",
|
|
"indian",
|
|
"african1",
|
|
"african2"
|
|
))
|
|
|
|
GLOBAL_LIST_EMPTY(species_list)
|
|
|
|
/proc/age2agedescription(age)
|
|
switch(age)
|
|
if(0 to 1)
|
|
return "infant"
|
|
if(1 to 3)
|
|
return "toddler"
|
|
if(3 to 13)
|
|
return "child"
|
|
if(13 to 19)
|
|
return "teenager"
|
|
if(19 to 30)
|
|
return "young adult"
|
|
if(30 to 45)
|
|
return "adult"
|
|
if(45 to 60)
|
|
return "middle-aged"
|
|
if(60 to 70)
|
|
return "aging"
|
|
if(70 to INFINITY)
|
|
return "elderly"
|
|
else
|
|
return "unknown"
|
|
|
|
/*
|
|
Proc for attack log creation, because really why not
|
|
1 argument is the actor
|
|
2 argument is the target of action
|
|
3 is the description of action(like punched, throwed, or any other verb)
|
|
4 is the tool with which the action was made(usually item) 4 and 5 are very similar(5 have "by " before it, that it) and are separated just to keep things in a bit more in order
|
|
5 is additional information, anything that needs to be added
|
|
*/
|
|
|
|
/proc/add_logs(mob/user, mob/target, what_done, object=null, addition=null)
|
|
var/turf/attack_location = get_turf(target)
|
|
|
|
var/is_mob_user = user && GLOB.typecache_mob[user.type]
|
|
var/is_mob_target = target && GLOB.typecache_mob[target.type]
|
|
|
|
var/mob/living/living_target
|
|
|
|
if(target && isliving(target))
|
|
living_target = target
|
|
|
|
var/hp =" "
|
|
if(living_target)
|
|
hp = "(NEWHP: [living_target.health])"
|
|
|
|
var/starget = "NON-EXISTENT SUBJECT"
|
|
if(target)
|
|
if(is_mob_target && target.ckey)
|
|
starget = "[target.name]([target.ckey])"
|
|
else
|
|
starget = "[target.name]"
|
|
|
|
var/ssource = "NON-EXISTENT USER" //How!?
|
|
if(user)
|
|
if(is_mob_user && user.ckey)
|
|
ssource = "[user.name]([user.ckey])"
|
|
else
|
|
ssource = "[user.name]"
|
|
|
|
var/sobject = ""
|
|
if(object)
|
|
sobject = "[object]"
|
|
|
|
var/sattackloc = ""
|
|
if(attack_location)
|
|
sattackloc = "([attack_location.x],[attack_location.y],[attack_location.z])"
|
|
|
|
if(is_mob_user)
|
|
var/message = "<font color='red'>has [what_done] [starget] with [sobject][addition] [hp] [sattackloc]</font>"
|
|
user.log_message(message, INDIVIDUAL_ATTACK_LOG)
|
|
|
|
if(is_mob_target)
|
|
var/message = "<font color='orange'>has been [what_done] by [ssource] with [sobject][addition] [hp] [sattackloc]</font>"
|
|
target.log_message(message, INDIVIDUAL_ATTACK_LOG)
|
|
|
|
log_attack("[ssource] [what_done] [starget] with [sobject][addition] [hp] [sattackloc]")
|
|
|
|
|
|
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null)
|
|
if(!user || !target)
|
|
return 0
|
|
var/user_loc = user.loc
|
|
|
|
var/drifting = 0
|
|
if(!user.Process_Spacemove(0) && user.inertia_dir)
|
|
drifting = 1
|
|
|
|
var/target_loc = target.loc
|
|
|
|
var/holding = user.get_active_held_item()
|
|
var/datum/progressbar/progbar
|
|
if (progress)
|
|
progbar = new(user, time, target)
|
|
|
|
var/endtime = world.time+time
|
|
var/starttime = world.time
|
|
. = 1
|
|
while (world.time < endtime)
|
|
stoplag(1)
|
|
if (progress)
|
|
progbar.update(world.time - starttime)
|
|
if(QDELETED(user) || QDELETED(target))
|
|
. = 0
|
|
break
|
|
if(uninterruptible)
|
|
continue
|
|
|
|
if(drifting && !user.inertia_dir)
|
|
drifting = 0
|
|
user_loc = user.loc
|
|
|
|
if((!drifting && user.loc != user_loc) || target.loc != target_loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke()))
|
|
. = 0
|
|
break
|
|
if (progress)
|
|
qdel(progbar)
|
|
|
|
|
|
//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
|
|
/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
|
|
if(check_clicks && next_move > world.time)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
//pass a list in the format list("health" = mob's health var) to check health during this
|
|
/mob/living/break_do_after_checks(list/checked_health, check_clicks)
|
|
if(islist(checked_health))
|
|
if(health < checked_health["health"])
|
|
return FALSE
|
|
checked_health["health"] = health
|
|
return ..()
|
|
|
|
/proc/do_after(mob/user, delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null)
|
|
if(!user)
|
|
return 0
|
|
var/atom/Tloc = null
|
|
if(target && !isturf(target))
|
|
Tloc = target.loc
|
|
|
|
var/atom/Uloc = user.loc
|
|
|
|
var/drifting = 0
|
|
if(!user.Process_Spacemove(0) && user.inertia_dir)
|
|
drifting = 1
|
|
|
|
var/holding = user.get_active_held_item()
|
|
|
|
var/holdingnull = 1 //User's hand started out empty, check for an empty hand
|
|
if(holding)
|
|
holdingnull = 0 //Users hand started holding something, check to see if it's still holding that
|
|
|
|
var/datum/progressbar/progbar
|
|
if (progress)
|
|
progbar = new(user, delay, target)
|
|
|
|
var/endtime = world.time + delay
|
|
var/starttime = world.time
|
|
. = 1
|
|
while (world.time < endtime)
|
|
stoplag(1)
|
|
if (progress)
|
|
progbar.update(world.time - starttime)
|
|
|
|
if(drifting && !user.inertia_dir)
|
|
drifting = 0
|
|
Uloc = user.loc
|
|
|
|
if(QDELETED(user) || user.stat || user.IsKnockdown() || user.IsStun() || (!drifting && user.loc != Uloc) || (extra_checks && !extra_checks.Invoke()))
|
|
. = 0
|
|
break
|
|
|
|
if(!QDELETED(Tloc) && (QDELETED(target) || Tloc != target.loc))
|
|
if((Uloc != Tloc || Tloc != user) && !drifting)
|
|
. = 0
|
|
break
|
|
|
|
if(needhand)
|
|
//This might seem like an odd check, but you can still need a hand even when it's empty
|
|
//i.e the hand is used to pull some item/tool out of the construction
|
|
if(!holdingnull)
|
|
if(!holding)
|
|
. = 0
|
|
break
|
|
if(user.get_active_held_item() != holding)
|
|
. = 0
|
|
break
|
|
if (progress)
|
|
qdel(progbar)
|
|
|
|
/proc/do_after_mob(mob/user, var/list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks)
|
|
if(!user || !targets)
|
|
return 0
|
|
if(!islist(targets))
|
|
targets = list(targets)
|
|
var/user_loc = user.loc
|
|
|
|
var/drifting = 0
|
|
if(!user.Process_Spacemove(0) && user.inertia_dir)
|
|
drifting = 1
|
|
|
|
var/list/originalloc = list()
|
|
for(var/atom/target in targets)
|
|
originalloc[target] = target.loc
|
|
|
|
var/holding = user.get_active_held_item()
|
|
var/datum/progressbar/progbar
|
|
if(progress)
|
|
progbar = new(user, time, targets[1])
|
|
|
|
var/endtime = world.time + time
|
|
var/starttime = world.time
|
|
. = 1
|
|
mainloop:
|
|
while(world.time < endtime)
|
|
stoplag(1)
|
|
if(progress)
|
|
progbar.update(world.time - starttime)
|
|
if(QDELETED(user) || !targets)
|
|
. = 0
|
|
break
|
|
if(uninterruptible)
|
|
continue
|
|
|
|
if(drifting && !user.inertia_dir)
|
|
drifting = 0
|
|
user_loc = user.loc
|
|
|
|
for(var/atom/target in targets)
|
|
if((!drifting && user_loc != user.loc) || QDELETED(target) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke()))
|
|
. = 0
|
|
break mainloop
|
|
if(progbar)
|
|
qdel(progbar)
|
|
|
|
/proc/is_species(A, species_datum)
|
|
. = FALSE
|
|
if(ishuman(A))
|
|
var/mob/living/carbon/human/H = A
|
|
if(H.dna && istype(H.dna.species, species_datum))
|
|
. = TRUE
|
|
|
|
/proc/spawn_atom_to_turf(spawn_type, target, amount, admin_spawn=FALSE, list/extra_args)
|
|
var/turf/T = get_turf(target)
|
|
if(!T)
|
|
CRASH("attempt to spawn atom type: [spawn_type] in nullspace")
|
|
|
|
var/list/new_args = list(T)
|
|
if(extra_args)
|
|
new_args += extra_args
|
|
|
|
for(var/j in 1 to amount)
|
|
var/atom/X = new spawn_type(arglist(new_args))
|
|
X.admin_spawned = admin_spawn
|
|
|
|
/proc/spawn_and_random_walk(spawn_type, target, amount, walk_chance=100, max_walk=3, always_max_walk=FALSE, admin_spawn=FALSE)
|
|
var/turf/T = get_turf(target)
|
|
var/step_count = 0
|
|
if(!T)
|
|
CRASH("attempt to spawn atom type: [spawn_type] in nullspace")
|
|
|
|
for(var/j in 1 to amount)
|
|
var/atom/movable/X = new spawn_type(T)
|
|
X.admin_spawned = admin_spawn
|
|
|
|
if(always_max_walk || prob(walk_chance))
|
|
if(always_max_walk)
|
|
step_count = max_walk
|
|
else
|
|
step_count = rand(1, max_walk)
|
|
|
|
for(var/i in 1 to step_count)
|
|
step(X, pick(NORTH, SOUTH, EAST, WEST))
|
|
|
|
/proc/deadchat_broadcast(message, mob/follow_target=null, turf/turf_target=null, speaker_key=null, message_type=DEADCHAT_REGULAR)
|
|
for(var/mob/M in GLOB.player_list)
|
|
var/datum/preferences/prefs
|
|
if(M.client && M.client.prefs)
|
|
prefs = M.client.prefs
|
|
else
|
|
prefs = new
|
|
|
|
var/adminoverride = 0
|
|
if(M.client && M.client.holder && (prefs.chat_toggles & CHAT_DEAD))
|
|
adminoverride = 1
|
|
if(isnewplayer(M) && !adminoverride)
|
|
continue
|
|
if(M.stat != DEAD && !adminoverride)
|
|
continue
|
|
if(speaker_key && speaker_key in prefs.ignoring)
|
|
continue
|
|
|
|
switch(message_type)
|
|
if(DEADCHAT_DEATHRATTLE)
|
|
if(prefs.toggles & DISABLE_DEATHRATTLE)
|
|
continue
|
|
if(DEADCHAT_ARRIVALRATTLE)
|
|
if(prefs.toggles & DISABLE_ARRIVALRATTLE)
|
|
continue
|
|
|
|
if(isobserver(M))
|
|
var/rendered_message = message
|
|
|
|
if(follow_target)
|
|
var/F
|
|
if(turf_target)
|
|
F = FOLLOW_OR_TURF_LINK(M, follow_target, turf_target)
|
|
else
|
|
F = FOLLOW_LINK(M, follow_target)
|
|
rendered_message = "[F] [message]"
|
|
else if(turf_target)
|
|
var/turf_link = TURF_LINK(M, turf_target)
|
|
rendered_message = "[turf_link] [message]"
|
|
|
|
to_chat(M, rendered_message)
|
|
else
|
|
to_chat(M, message)
|
|
|
|
|
|
/proc/log_talk(mob/user,message,logtype)
|
|
var/turf/say_turf = get_turf(user)
|
|
|
|
var/sayloc = ""
|
|
if(say_turf)
|
|
sayloc = "([say_turf.x],[say_turf.y],[say_turf.z])"
|
|
|
|
|
|
var/logmessage = "[message] [sayloc]"
|
|
|
|
switch(logtype)
|
|
|
|
if(LOGDSAY)
|
|
log_dsay(logmessage)
|
|
if(LOGSAY)
|
|
log_say(logmessage)
|
|
if(LOGWHISPER)
|
|
log_whisper(logmessage)
|
|
if(LOGEMOTE)
|
|
log_emote(logmessage)
|
|
if(LOGPDA)
|
|
log_pda(logmessage)
|
|
if(LOGCHAT)
|
|
log_chat(logmessage)
|
|
if(LOGCOMMENT)
|
|
log_comment(logmessage)
|
|
if(LOGASAY)
|
|
log_adminsay(logmessage)
|
|
if(LOGOOC)
|
|
log_ooc(logmessage)
|
|
else
|
|
warning("Invalid speech logging type detected. [logtype]. Defaulting to say")
|
|
log_say(logmessage)
|
|
|
|
//Used in chemical_mob_spawn. Generates a random mob based on a given gold_core_spawnable value.
|
|
/proc/create_random_mob(spawn_location, mob_class = HOSTILE_SPAWN)
|
|
var/static/list/mob_spawn_meancritters = list() // list of possible hostile mobs
|
|
var/static/list/mob_spawn_nicecritters = list() // and possible friendly mobs
|
|
|
|
if(mob_spawn_meancritters.len <= 0 || mob_spawn_nicecritters.len <= 0)
|
|
for(var/T in typesof(/mob/living/simple_animal))
|
|
var/mob/living/simple_animal/SA = T
|
|
switch(initial(SA.gold_core_spawnable))
|
|
if(HOSTILE_SPAWN)
|
|
mob_spawn_meancritters += T
|
|
if(FRIENDLY_SPAWN)
|
|
mob_spawn_nicecritters += T
|
|
|
|
var/chosen
|
|
if(mob_class == FRIENDLY_SPAWN)
|
|
chosen = pick(mob_spawn_nicecritters)
|
|
else
|
|
chosen = pick(mob_spawn_meancritters)
|
|
var/mob/living/simple_animal/C = new chosen(spawn_location)
|
|
return C |