Merge pull request #8387 from PsiOmegaDelta/ChangeAppearance

Mirror and ERT appearance improvement.
This commit is contained in:
Chinsky
2015-03-09 13:42:19 +03:00
11 changed files with 749 additions and 383 deletions

View File

@@ -1096,6 +1096,7 @@
#include "code\modules\mob\living\carbon\brain\posibrain.dm" #include "code\modules\mob\living\carbon\brain\posibrain.dm"
#include "code\modules\mob\living\carbon\brain\robot.dm" #include "code\modules\mob\living\carbon\brain\robot.dm"
#include "code\modules\mob\living\carbon\brain\say.dm" #include "code\modules\mob\living\carbon\brain\say.dm"
#include "code\modules\mob\living\carbon\human\appearance.dm"
#include "code\modules\mob\living\carbon\human\death.dm" #include "code\modules\mob\living\carbon\human\death.dm"
#include "code\modules\mob\living\carbon\human\emote.dm" #include "code\modules\mob\living\carbon\human\emote.dm"
#include "code\modules\mob\living\carbon\human\examine.dm" #include "code\modules\mob\living\carbon\human\examine.dm"
@@ -1257,6 +1258,7 @@
#include "code\modules\nano\nanoui.dm" #include "code\modules\nano\nanoui.dm"
#include "code\modules\nano\modules\alarm_monitor.dm" #include "code\modules\nano\modules\alarm_monitor.dm"
#include "code\modules\nano\modules\crew_monitor.dm" #include "code\modules\nano\modules\crew_monitor.dm"
#include "code\modules\nano\modules\human_appearance.dm"
#include "code\modules\nano\modules\power_monitor.dm" #include "code\modules\nano\modules\power_monitor.dm"
#include "code\modules\nano\modules\rcon.dm" #include "code\modules\nano\modules\rcon.dm"
#include "code\modules\organs\blood.dm" #include "code\modules\organs\blood.dm"

View File

@@ -184,6 +184,8 @@
var/starlight = 0 // Whether space turfs have ambient light or not var/starlight = 0 // Whether space turfs have ambient light or not
var/list/ert_species = list("Human")
/datum/configuration/New() /datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L) for (var/T in L)
@@ -609,6 +611,10 @@
value = text2num(value) value = text2num(value)
config.starlight = value >= 0 ? value : 0 config.starlight = value >= 0 ? value : 0
if("ert_species")
config.ert_species = text2list(value, ";")
if(!config.ert_species.len)
config.ert_species += "Human"
else else
log_misc("Unknown setting in configuration: '[name]'") log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -7,59 +7,19 @@
density = 0 density = 0
anchored = 1 anchored = 1
var/shattered = 0 var/shattered = 0
var/list/ui_users = list()
/obj/structure/mirror/attack_hand(mob/user as mob) /obj/structure/mirror/attack_hand(mob/user as mob)
if(shattered) return if(shattered) return
if(ishuman(user)) if(ishuman(user))
var/mob/living/carbon/human/H = user var/obj/nano_module/appearance_changer/AC = ui_users[user]
if(!AC)
if(H.a_intent == "hurt") AC = new(src, user)
if(prob(30) || H.species.can_shred(H)) AC.name = "SalonPro Nano-Mirror(TM)"
attack_generic(user,1) ui_users[user] = AC
else AC.ui_interact(user)
attack_generic(user)
return
var/userloc = H.loc
//see code/modules/mob/new_player/preferences.dm at approx line 545 for comments!
//this is largely copypasted from there.
//handle facial hair (if necessary)
if(H.gender == MALE)
var/list/species_facial_hair = list()
if(H.species)
for(var/i in facial_hair_styles_list)
var/datum/sprite_accessory/facial_hair/tmp_facial = facial_hair_styles_list[i]
if(H.species.name in tmp_facial.species_allowed)
species_facial_hair += i
else
species_facial_hair = facial_hair_styles_list
var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in species_facial_hair
if(userloc != H.loc) return //no tele-grooming
if(new_style)
H.f_style = new_style
//handle normal hair
var/list/species_hair = list()
if(H.species)
for(var/i in hair_styles_list)
var/datum/sprite_accessory/hair/tmp_hair = hair_styles_list[i]
if(H.species.name in tmp_hair.species_allowed)
species_hair += i
else
species_hair = hair_styles_list
var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in species_hair
if(userloc != H.loc) return //no tele-grooming
if(new_style)
H.h_style = new_style
H.update_hair()
/obj/structure/mirror/proc/shatter() /obj/structure/mirror/proc/shatter()
if(shattered) return if(shattered) return

View File

@@ -1,331 +1,245 @@
//STRIKE TEAMS //STRIKE TEAMS
//Thanks to Kilakk for the admin-button portion of this code. //Thanks to Kilakk for the admin-button portion of this code.
var/list/response_team_members = list() var/list/response_team_members = list()
var/global/send_emergency_team = 0 // Used for automagic response teams var/global/send_emergency_team = 0 // Used for automagic response teams
// 'admin_emergency_team' for admin-spawned response teams // 'admin_emergency_team' for admin-spawned response teams
var/ert_base_chance = 10 // Default base chance. Will be incremented by increment ERT chance. var/ert_base_chance = 10 // Default base chance. Will be incremented by increment ERT chance.
var/can_call_ert var/can_call_ert
/client/proc/response_team() /client/proc/response_team()
set name = "Dispatch Emergency Response Team" set name = "Dispatch Emergency Response Team"
set category = "Special Verbs" set category = "Special Verbs"
set desc = "Send an emergency response team to the station" set desc = "Send an emergency response team to the station"
if(!holder) if(!holder)
usr << "\red Only administrators may use this command." usr << "\red Only administrators may use this command."
return return
if(!ticker) if(!ticker)
usr << "\red The game hasn't started yet!" usr << "\red The game hasn't started yet!"
return return
if(ticker.current_state == 1) if(ticker.current_state == 1)
usr << "\red The round hasn't started yet!" usr << "\red The round hasn't started yet!"
return return
if(send_emergency_team) if(send_emergency_team)
usr << "\red Central Command has already dispatched an emergency response team!" usr << "\red Central Command has already dispatched an emergency response team!"
return return
if(alert("Do you want to dispatch an Emergency Response Team?",,"Yes","No") != "Yes") if(alert("Do you want to dispatch an Emergency Response Team?",,"Yes","No") != "Yes")
return return
if(get_security_level() != "red") // Allow admins to reconsider if the alert level isn't Red if(get_security_level() != "red") // Allow admins to reconsider if the alert level isn't Red
switch(alert("The station is not in red alert. Do you still want to dispatch a response team?",,"Yes","No")) switch(alert("The station is not in red alert. Do you still want to dispatch a response team?",,"Yes","No"))
if("No") if("No")
return return
if(send_emergency_team) if(send_emergency_team)
usr << "\red Looks like somebody beat you to it!" usr << "\red Looks like somebody beat you to it!"
return return
message_admins("[key_name_admin(usr)] is dispatching an Emergency Response Team.", 1) message_admins("[key_name_admin(usr)] is dispatching an Emergency Response Team.", 1)
log_admin("[key_name(usr)] used Dispatch Response Team.") log_admin("[key_name(usr)] used Dispatch Response Team.")
trigger_armed_response_team(1) trigger_armed_response_team(1)
client/verb/JoinResponseTeam() client/verb/JoinResponseTeam()
set category = "IC" set category = "IC"
if(istype(usr,/mob/dead/observer) || istype(usr,/mob/new_player)) if(istype(usr,/mob/dead/observer) || istype(usr,/mob/new_player))
if(!send_emergency_team) if(!send_emergency_team)
usr << "No emergency response team is currently being sent." usr << "No emergency response team is currently being sent."
return return
/* if(admin_emergency_team) /* if(admin_emergency_team)
usr << "An emergency response team has already been sent." usr << "An emergency response team has already been sent."
return */ return */
if(jobban_isbanned(usr, "Syndicate") || jobban_isbanned(usr, "Emergency Response Team") || jobban_isbanned(usr, "Security Officer")) if(jobban_isbanned(usr, "Syndicate") || jobban_isbanned(usr, "Emergency Response Team") || jobban_isbanned(usr, "Security Officer"))
usr << "<font color=red><b>You are jobbanned from the emergency reponse team!" usr << "<font color=red><b>You are jobbanned from the emergency reponse team!"
return return
if(response_team_members.len > 5) usr << "The emergency response team is already full!" if(response_team_members.len > 5) usr << "The emergency response team is already full!"
for (var/obj/effect/landmark/L in landmarks_list) if (L.name == "Commando") for (var/obj/effect/landmark/L in landmarks_list) if (L.name == "Commando")
L.name = null//Reserving the place. L.name = null//Reserving the place.
var/new_name = input(usr, "Pick a name","Name") as null|text var/new_name = input(usr, "Pick a name","Name") as null|text
if(!new_name)//Somebody changed his mind, place is available again. if(!new_name)//Somebody changed his mind, place is available again.
L.name = "Commando" L.name = "Commando"
return return
var/leader_selected = isemptylist(response_team_members) var/leader_selected = isemptylist(response_team_members)
var/mob/living/carbon/human/new_commando = create_response_team(L.loc, leader_selected, new_name) var/mob/living/carbon/human/new_commando = create_response_team(L.loc, leader_selected, new_name)
del(L) del(L)
new_commando.mind.key = usr.key //Creates mind stuff.
new_commando.key = usr.key new_commando.mind.key = usr.key
new_commando.key = usr.key
new_commando << "\blue You are [!leader_selected?"a member":"the <B>LEADER</B>"] of an Emergency Response Team, a type of military division, under CentComm's service. There is a code red alert on [station_name()], you are tasked to go and fix the problem."
new_commando << "<b>You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready." new_commando << "\blue You are [!leader_selected?"a member":"the <B>LEADER</B>"] of an Emergency Response Team, a type of military division, under CentComm's service. There is a code red alert on [station_name()], you are tasked to go and fix the problem."
if(!leader_selected) new_commando << "<b>You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready."
new_commando << "<b>As member of the Emergency Response Team, you answer only to your leader and CentComm officials.</b>" if(!leader_selected)
else new_commando << "<b>As member of the Emergency Response Team, you answer only to your leader and CentComm officials.</b>"
new_commando << "<b>As leader of the Emergency Response Team, you answer only to CentComm, and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however." else
return new_commando << "<b>As leader of the Emergency Response Team, you answer only to CentComm, and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however."
else // By setting an explicit location the mob cannot wander off and decide change appearance elsewhere
usr << "You need to be an observer or new player to use this." new_commando.change_appearance(APPEARANCE_ALL, new_commando.loc, new_commando, species_whitelist = config.ert_species)
// returns a number of dead players in % return
proc/percentage_dead()
var/total = 0 else
var/deadcount = 0 usr << "You need to be an observer or new player to use this."
for(var/mob/living/carbon/human/H in mob_list)
if(H.client) // Monkeys and mice don't have a client, amirite? // returns a number of dead players in %
if(H.stat == 2) deadcount++ proc/percentage_dead()
total++ var/total = 0
var/deadcount = 0
if(total == 0) return 0 for(var/mob/living/carbon/human/H in mob_list)
else return round(100 * deadcount / total) if(H.client) // Monkeys and mice don't have a client, amirite?
if(H.stat == 2) deadcount++
// counts the number of antagonists in % total++
proc/percentage_antagonists()
var/total = 0 if(total == 0) return 0
var/antagonists = 0 else return round(100 * deadcount / total)
for(var/mob/living/carbon/human/H in mob_list)
if(is_special_character(H) >= 1) // counts the number of antagonists in %
antagonists++ proc/percentage_antagonists()
total++ var/total = 0
var/antagonists = 0
if(total == 0) return 0 for(var/mob/living/carbon/human/H in mob_list)
else return round(100 * antagonists / total) if(is_special_character(H) >= 1)
antagonists++
// Increments the ERT chance automatically, so that the later it is in the round, total++
// the more likely an ERT is to be able to be called.
proc/increment_ert_chance() if(total == 0) return 0
while(send_emergency_team == 0) // There is no ERT at the time. else return round(100 * antagonists / total)
if(get_security_level() == "green")
ert_base_chance += 1 // Increments the ERT chance automatically, so that the later it is in the round,
if(get_security_level() == "blue") // the more likely an ERT is to be able to be called.
ert_base_chance += 2 proc/increment_ert_chance()
if(get_security_level() == "red") while(send_emergency_team == 0) // There is no ERT at the time.
ert_base_chance += 3 if(get_security_level() == "green")
if(get_security_level() == "delta") ert_base_chance += 1
ert_base_chance += 10 // Need those big guns if(get_security_level() == "blue")
sleep(600 * 3) // Minute * Number of Minutes ert_base_chance += 2
if(get_security_level() == "red")
ert_base_chance += 3
proc/trigger_armed_response_team(var/force = 0) if(get_security_level() == "delta")
if(!can_call_ert && !force) ert_base_chance += 10 // Need those big guns
return sleep(600 * 3) // Minute * Number of Minutes
if(send_emergency_team)
return
proc/trigger_armed_response_team(var/force = 0)
var/send_team_chance = ert_base_chance // Is incremented by increment_ert_chance. if(!can_call_ert && !force)
send_team_chance += 2*percentage_dead() // the more people are dead, the higher the chance return
send_team_chance += percentage_antagonists() // the more antagonists, the higher the chance if(send_emergency_team)
send_team_chance = min(send_team_chance, 100) return
if(force) send_team_chance = 100 var/send_team_chance = ert_base_chance // Is incremented by increment_ert_chance.
send_team_chance += 2*percentage_dead() // the more people are dead, the higher the chance
// there's only a certain chance a team will be sent send_team_chance += percentage_antagonists() // the more antagonists, the higher the chance
if(!prob(send_team_chance)) send_team_chance = min(send_team_chance, 100)
command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "Central Command")
can_call_ert = 0 // Only one call per round, ladies. if(force) send_team_chance = 100
return
// there's only a certain chance a team will be sent
command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "Central Command") if(!prob(send_team_chance))
command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "Central Command")
can_call_ert = 0 // Only one call per round, gentleman. can_call_ert = 0 // Only one call per round, ladies.
send_emergency_team = 1 return
sleep(600 * 5) command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "Central Command")
send_emergency_team = 0 // Can no longer join the ERT.
can_call_ert = 0 // Only one call per round, gentleman.
/* var/area/security/nuke_storage/nukeloc = locate()//To find the nuke in the vault send_emergency_team = 1
var/obj/machinery/nuclearbomb/nuke = locate() in nukeloc
if(!nuke) sleep(600 * 5)
nuke = locate() in world send_emergency_team = 0 // Can no longer join the ERT.
var/obj/item/weapon/paper/P = new
P.info = "Your orders, Commander, are to use all means necessary to return the station to a survivable condition.<br>To this end, you have been provided with the best tools we can give in the three areas of Medicine, Engineering, and Security. The nuclear authorization code is: <b>[ nuke ? nuke.r_code : "AHH, THE NUKE IS GONE!"]</b>. Be warned, if you detonate this without good reason, we will hold you to account for damages. Memorise this code, and then burn this message." /* var/area/security/nuke_storage/nukeloc = locate()//To find the nuke in the vault
P.name = "Emergency Nuclear Code, and ERT Orders" var/obj/machinery/nuclearbomb/nuke = locate() in nukeloc
for (var/obj/effect/landmark/A in world) if(!nuke)
if (A.name == "nukecode") nuke = locate() in world
P.loc = A.loc var/obj/item/weapon/paper/P = new
del(A) P.info = "Your orders, Commander, are to use all means necessary to return the station to a survivable condition.<br>To this end, you have been provided with the best tools we can give in the three areas of Medicine, Engineering, and Security. The nuclear authorization code is: <b>[ nuke ? nuke.r_code : "AHH, THE NUKE IS GONE!"]</b>. Be warned, if you detonate this without good reason, we will hold you to account for damages. Memorise this code, and then burn this message."
continue P.name = "Emergency Nuclear Code, and ERT Orders"
*/ for (var/obj/effect/landmark/A in world)
if (A.name == "nukecode")
/client/proc/create_response_team(obj/spawn_location, leader_selected = 0, commando_name) P.loc = A.loc
del(A)
//usr << "\red ERT has been temporarily disabled. Talk to a coder." continue
//return */
var/mob/living/carbon/human/M = new(null) /client/proc/create_response_team(obj/spawn_location, leader_selected = 0, commando_name)
response_team_members |= M
//usr << "\red ERT has been temporarily disabled. Talk to a coder."
//todo: god damn this. //return
//make it a panel, like in character creation
var/new_facial = input("Please select facial hair color.", "Character Generation") as color var/mob/living/carbon/human/M = new(null)
if(new_facial) response_team_members |= M
M.r_facial = hex2num(copytext(new_facial, 2, 4))
M.g_facial = hex2num(copytext(new_facial, 4, 6)) M.real_name = commando_name
M.b_facial = hex2num(copytext(new_facial, 6, 8)) M.name = commando_name
M.age = !leader_selected ? rand(23,35) : rand(35,45)
var/new_hair = input("Please select hair color.", "Character Generation") as color
if(new_facial) M.check_dna(M)
M.r_hair = hex2num(copytext(new_hair, 2, 4)) M.dna.ready_dna(M)//Creates DNA.
M.g_hair = hex2num(copytext(new_hair, 4, 6))
M.b_hair = hex2num(copytext(new_hair, 6, 8)) M.mind = new
M.mind.current = M
var/new_eyes = input("Please select eye color.", "Character Generation") as color M.mind.original = M
if(new_eyes) M.mind.assigned_role = "MODE"
M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) M.mind.special_role = "Response Team"
M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) if(!(M.mind in ticker.minds))
M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) ticker.minds += M.mind//Adds them to regular mind list.
M.loc = spawn_location
var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation") as text M.equip_strike_team(leader_selected)
if (!new_tone) return M
new_tone = 35
M.s_tone = max(min(round(text2num(new_tone)), 220), 1) /mob/living/carbon/human/proc/equip_strike_team(leader_selected = 0)
M.s_tone = -M.s_tone + 35
//Special radio setup
// hair equip_to_slot_or_del(new /obj/item/device/radio/headset/ert(src), slot_l_ear)
var/list/all_hairs = typesof(/datum/sprite_accessory/hair) - /datum/sprite_accessory/hair
var/list/hairs = list() //Replaced with new ERT uniform
equip_to_slot_or_del(new /obj/item/clothing/under/ert(src), slot_w_uniform)
// loop through potential hairs equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(src), slot_shoes)
for(var/x in all_hairs) equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(src), slot_gloves)
var/datum/sprite_accessory/hair/H = new x // create new hair datum based on type x equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses)
hairs.Add(H.name) // add hair name to hairs /*
del(H) // delete the hair after it's all done
//Old ERT Uniform
// var/new_style = input("Please select hair style", "Character Generation") as null|anything in hairs //Basic Uniform
//hair equip_to_slot_or_del(new /obj/item/clothing/under/syndicate/tacticool(src), slot_w_uniform)
var/new_hstyle = input(usr, "Select a hair style", "Grooming") as null|anything in hair_styles_list equip_to_slot_or_del(new /obj/item/device/flashlight(src), slot_l_store)
if(new_hstyle) equip_to_slot_or_del(new /obj/item/weapon/clipboard(src), slot_r_store)
M.h_style = new_hstyle equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(src), slot_belt)
equip_to_slot_or_del(new /obj/item/clothing/mask/gas/swat(src), slot_wear_mask)
// facial hair
var/new_fstyle = input(usr, "Select a facial hair style", "Grooming") as null|anything in facial_hair_styles_list //Glasses
if(new_fstyle) equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud(src), slot_glasses)
M.f_style = new_fstyle
//Shoes & gloves
// if new style selected (not cancel) equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(src), slot_shoes)
/* if (new_style) equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(src), slot_gloves)
M.h_style = new_style
//Removed
for(var/x in all_hairs) // loop through all_hairs again. Might be slightly CPU expensive, but not significantly. // equip_to_slot_or_del(new /obj/item/clothing/suit/armor/swat(src), slot_wear_suit)
var/datum/sprite_accessory/hair/H = new x // create new hair datum // equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/deathsquad(src), slot_head)
if(H.name == new_style)
M.h_style = H // assign the hair_style variable a new hair datum //Backpack
break equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(src), slot_back)
else equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(src), slot_in_backpack)
del(H) // if hair H not used, delete. BYOND can garbage collect, but better safe than sorry equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/regular(src), slot_in_backpack)
*/
// facial hair var/obj/item/weapon/card/id/W = new(src)
var/list/all_fhairs = typesof(/datum/sprite_accessory/facial_hair) - /datum/sprite_accessory/facial_hair W.assignment = "Emergency Response Team[leader_selected ? " Leader" : ""]"
var/list/fhairs = list() W.registered_name = real_name
W.name = "[real_name]'s ID Card ([W.assignment])"
for(var/x in all_fhairs) W.icon_state = "centcom"
var/datum/sprite_accessory/facial_hair/H = new x W.access = get_all_accesses()
fhairs.Add(H.name) W.access += get_all_centcom_access()
del(H) equip_to_slot_or_del(W, slot_wear_id)
new_style = input("Please select facial style", "Character Generation") as null|anything in fhairs return 1
if(new_style) //debug verb (That is horribly coded, LEAVE THIS OFF UNLESS PRIVATELY TESTING. Seriously.
M.f_style = new_style /*client/verb/ResponseTeam()
for(var/x in all_fhairs) set category = "Admin"
var/datum/sprite_accessory/facial_hair/H = new x if(!send_emergency_team)
if(H.name == new_style) send_emergency_team = 1*/
M.f_style = H
break
else
del(H)
*/
var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female")
if (new_gender)
if(new_gender == "Male")
M.gender = MALE
else
M.gender = FEMALE
//M.rebuild_appearance()
M.update_hair()
M.update_body()
M.check_dna(M)
M.real_name = commando_name
M.name = commando_name
M.age = !leader_selected ? rand(23,35) : rand(35,45)
M.dna.ready_dna(M)//Creates DNA.
//Creates mind stuff.
M.mind = new
M.mind.current = M
M.mind.original = M
M.mind.assigned_role = "MODE"
M.mind.special_role = "Response Team"
if(!(M.mind in ticker.minds))
ticker.minds += M.mind//Adds them to regular mind list.
M.loc = spawn_location
M.equip_strike_team(leader_selected)
return M
/mob/living/carbon/human/proc/equip_strike_team(leader_selected = 0)
//Special radio setup
equip_to_slot_or_del(new /obj/item/device/radio/headset/ert(src), slot_l_ear)
//Replaced with new ERT uniform
equip_to_slot_or_del(new /obj/item/clothing/under/ert(src), slot_w_uniform)
equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(src), slot_shoes)
equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(src), slot_gloves)
equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(src), slot_glasses)
/*
//Old ERT Uniform
//Basic Uniform
equip_to_slot_or_del(new /obj/item/clothing/under/syndicate/tacticool(src), slot_w_uniform)
equip_to_slot_or_del(new /obj/item/device/flashlight(src), slot_l_store)
equip_to_slot_or_del(new /obj/item/weapon/clipboard(src), slot_r_store)
equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(src), slot_belt)
equip_to_slot_or_del(new /obj/item/clothing/mask/gas/swat(src), slot_wear_mask)
//Glasses
equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud(src), slot_glasses)
//Shoes & gloves
equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(src), slot_shoes)
equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(src), slot_gloves)
//Removed
// equip_to_slot_or_del(new /obj/item/clothing/suit/armor/swat(src), slot_wear_suit)
// equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/deathsquad(src), slot_head)
//Backpack
equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(src), slot_back)
equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(src), slot_in_backpack)
equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/regular(src), slot_in_backpack)
*/
var/obj/item/weapon/card/id/W = new(src)
W.assignment = "Emergency Response Team[leader_selected ? " Leader" : ""]"
W.registered_name = real_name
W.name = "[real_name]'s ID Card ([W.assignment])"
W.icon_state = "centcom"
W.access = get_all_accesses()
W.access += get_all_centcom_access()
equip_to_slot_or_del(W, slot_wear_id)
return 1
//debug verb (That is horribly coded, LEAVE THIS OFF UNLESS PRIVATELY TESTING. Seriously.
/*client/verb/ResponseTeam()
set category = "Admin"
if(!send_emergency_team)
send_emergency_team = 1*/

View File

@@ -79,7 +79,9 @@ var/list/admin_verbs_admin = list(
/client/proc/toggle_antagHUD_restrictions, /client/proc/toggle_antagHUD_restrictions,
/client/proc/allow_character_respawn, /* Allows a ghost to respawn */ /client/proc/allow_character_respawn, /* Allows a ghost to respawn */
/client/proc/event_manager_panel, /client/proc/event_manager_panel,
/client/proc/empty_ai_core_toggle_latejoin /client/proc/empty_ai_core_toggle_latejoin,
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
/client/proc/change_human_appearance_self /* Allows the human-based mob itself change its basic appearance */
) )
var/list/admin_verbs_ban = list( var/list/admin_verbs_ban = list(
/client/proc/unban_panel, /client/proc/unban_panel,
@@ -715,6 +717,9 @@ var/list/admin_verbs_mentor = list(
set name = "Rename Silicon" set name = "Rename Silicon"
set category = "Admin" set category = "Admin"
if(!istype(S))
return
if(holder) if(holder)
var/new_name = trim_strip_input(src, "Enter new name. Leave blank or as is to cancel.", "Enter new silicon name", S.real_name) var/new_name = trim_strip_input(src, "Enter new name. Leave blank or as is to cancel.", "Enter new silicon name", S.real_name)
if(new_name && new_name != S.real_name) if(new_name && new_name != S.real_name)
@@ -722,6 +727,41 @@ var/list/admin_verbs_mentor = list(
S.SetName(new_name) S.SetName(new_name)
feedback_add_details("admin_verb","RAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! feedback_add_details("admin_verb","RAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/change_human_appearance_admin(mob/living/carbon/human/H in world)
set name = "Change Mob Appearance - Admin"
set desc = "Allows you to change the mob appearance"
set category = "Admin"
if(!istype(H))
return
if(holder)
admin_log_and_message_admins("is altering the appearance of [H].")
H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0)
feedback_add_details("admin_verb","CHAA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/change_human_appearance_self(mob/living/carbon/human/H in world)
set name = "Change Mob Appearance - Self"
set desc = "Allows the mob to change its appearance"
set category = "Admin"
if(!istype(H))
return
if(!H.client)
usr << "Only mobs with clients can alter their own appearance."
return
if(holder)
switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel"))
if("Yes")
admin_log_and_message_admins("has allowed [H] to change \his appearance, without whitelisting of races.")
H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0)
if("No")
admin_log_and_message_admins("has allowed [H] to change \his appearance, with whitelisting of races.")
H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1)
feedback_add_details("admin_verb","CMAS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//---- bs12 verbs ---- //---- bs12 verbs ----

View File

@@ -0,0 +1,187 @@
/mob/living/carbon/human/proc/change_appearance(var/flags = APPEARANCE_ALL_HAIR, var/location = src, var/mob/user = src, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list())
var/obj/nano_module/appearance_changer/AC = new(location, src, check_species_whitelist, species_whitelist, species_blacklist)
AC.flags = flags
AC.ui_interact(user)
/mob/living/carbon/human/proc/change_species(var/new_species)
if(!new_species)
return
if(species == new_species)
return
if(!(new_species in all_species))
return
set_species(new_species)
reset_hair()
return 1
/mob/living/carbon/human/proc/change_gender(var/gender)
if(src.gender == gender)
return
src.gender = gender
reset_hair()
update_body()
update_dna()
return 1
/mob/living/carbon/human/proc/change_hair(var/hair_style)
if(!hair_style)
return
if(h_style == hair_style)
return
if(!(hair_style in hair_styles_list))
return
h_style = hair_style
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style)
if(!facial_hair_style)
return
if(f_style == facial_hair_style)
return
if(!(facial_hair_style in facial_hair_styles_list))
return
f_style = facial_hair_style
update_hair()
return 1
/mob/living/carbon/human/proc/reset_hair()
var/list/valid_hairstyles = generate_valid_hairstyles()
var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles()
if(valid_hairstyles.len)
h_style = pick(valid_hairstyles)
else
//this shouldn't happen
h_style = "Bald"
if(valid_facial_hairstyles.len)
f_style = pick(valid_facial_hairstyles)
else
//this shouldn't happen
f_style = "Shaved"
update_hair()
/mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue)
if(red == r_eyes && green == g_eyes && blue == b_eyes)
return
r_eyes = red
g_eyes = green
b_eyes = blue
update_body()
return 1
/mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue)
if(red == r_eyes && green == g_eyes && blue == b_eyes)
return
r_hair = red
g_hair = green
b_hair = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue)
if(red == r_facial && green == g_facial && blue == b_facial)
return
r_facial = red
g_facial = green
b_facial = blue
update_hair()
return 1
/mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue)
if(red == r_skin && green == g_skin && blue == b_skin || !(species.flags & HAS_SKIN_COLOR))
return
r_skin = red
g_skin = green
b_skin = blue
update_body()
return 1
/mob/living/carbon/human/proc/change_skin_tone(var/tone)
if(s_tone == tone || !(species.flags & HAS_SKIN_TONE))
return
s_tone = tone
update_body()
return 1
/mob/living/carbon/human/proc/update_dna()
check_dna()
dna.ready_dna(src)
/mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list())
var/list/valid_species = new()
for(var/current_species_name in all_species)
var/datum/species/current_species = all_species[current_species_name]
if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it!
if(!(current_species.flags & CAN_JOIN))
continue
if(whitelist.len && !(current_species_name in whitelist))
continue
if(blacklist.len && (current_species_name in blacklist))
continue
if((current_species.flags & IS_WHITELISTED) && !is_alien_whitelisted(src, current_species_name))
continue
valid_species += current_species_name
return valid_species
/mob/living/carbon/human/proc/generate_valid_hairstyles()
var/list/valid_hairstyles = new()
for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(!(species.name in S.species_allowed))
continue
valid_hairstyles += hairstyle
return valid_hairstyles
/mob/living/carbon/human/proc/generate_valid_facial_hairstyles()
var/list/valid_facial_hairstyles = new()
for(var/facialhairstyle in facial_hair_styles_list)
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(!(species.name in S.species_allowed))
continue
valid_facial_hairstyles += facialhairstyle
return valid_facial_hairstyles
/proc/q()
var/mob/living/carbon/human/H = usr
H.change_appearance(APPEARANCE_ALL)

View File

@@ -0,0 +1,163 @@
/obj/nano_module/appearance_changer
name = "Appearance Editor"
flags = APPEARANCE_ALL_HAIR
var/mob/living/carbon/human/owner = null
var/list/valid_species = list()
var/list/valid_hairstyles = list()
var/list/valid_facial_hairstyles = list()
var/check_whitelist
var/list/whitelist
var/list/blacklist
/obj/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list())
..()
loc = location
owner = H
src.check_whitelist = check_species_whitelist
src.whitelist = species_whitelist
src.blacklist = species_blacklist
/obj/nano_module/appearance_changer/Topic(ref, href_list)
if(..())
return 1
if(href_list["race"])
if(can_change(APPEARANCE_RACE) && (href_list["race"] in valid_species))
if(owner.change_species(href_list["race"]))
cut_and_generate_data()
return 1
if(href_list["gender"])
if(can_change(APPEARANCE_GENDER))
if(owner.change_gender(href_list["gender"]))
cut_and_generate_data()
return 1
if(href_list["skin_tone"])
if(can_change_skin_tone())
var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", owner.s_tone) as num|null
if(isnum(new_s_tone) && CanUseTopic(usr) == STATUS_INTERACTIVE)
new_s_tone = 35 - max(min( round(new_s_tone), 220),1)
return owner.change_skin_tone(new_s_tone)
if(href_list["skin_color"])
if(can_change_skin_color())
var/new_skin = input(usr, "Choose your character's skin colour: ", "Skin Color", rgb(owner.r_skin, owner.g_skin, owner.b_skin)) as color|null
if(new_skin && can_still_topic())
var/r_skin = hex2num(copytext(new_skin, 2, 4))
var/g_skin = hex2num(copytext(new_skin, 4, 6))
var/b_skin = hex2num(copytext(new_skin, 6, 8))
if(owner.change_skin_color(r_skin, g_skin, b_skin))
update_dna()
return 1
if(href_list["hair"])
if(can_change(APPEARANCE_HAIR) && (href_list["hair"] in valid_hairstyles))
if(owner.change_hair(href_list["hair"]))
update_dna()
return 1
if(href_list["hair_color"])
if(can_change(APPEARANCE_HAIR_COLOR))
var/new_hair = input("Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null
if(new_hair && can_still_topic())
var/r_hair = hex2num(copytext(new_hair, 2, 4))
var/g_hair = hex2num(copytext(new_hair, 4, 6))
var/b_hair = hex2num(copytext(new_hair, 6, 8))
if(owner.change_hair_color(r_hair, g_hair, b_hair))
update_dna()
return 1
if(href_list["facial_hair"])
if(can_change(APPEARANCE_FACIAL_HAIR) && (href_list["facial_hair"] in valid_facial_hairstyles))
if(owner.change_facial_hair(href_list["facial_hair"]))
update_dna()
return 1
if(href_list["facial_hair_color"])
if(can_change(APPEARANCE_FACIAL_HAIR_COLOR))
var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null
if(new_facial && can_still_topic())
var/r_facial = hex2num(copytext(new_facial, 2, 4))
var/g_facial = hex2num(copytext(new_facial, 4, 6))
var/b_facial = hex2num(copytext(new_facial, 6, 8))
if(owner.change_facial_hair_color(r_facial, g_facial, b_facial))
update_dna()
return 1
if(href_list["eye_color"])
if(can_change(APPEARANCE_EYE_COLOR))
var/new_eyes = input("Please select eye color.", "Eye Color", rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) as color|null
if(new_eyes && can_still_topic())
var/r_eyes = hex2num(copytext(new_eyes, 2, 4))
var/g_eyes = hex2num(copytext(new_eyes, 4, 6))
var/b_eyes = hex2num(copytext(new_eyes, 6, 8))
if(owner.change_eye_color(r_eyes, g_eyes, b_eyes))
update_dna()
return 1
return 0
/obj/nano_module/appearance_changer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
generate_data(check_whitelist, whitelist, blacklist)
var/data[0]
data["specimen"] = owner.species.name
data["gender"] = owner.gender
data["change_race"] = can_change(APPEARANCE_RACE)
if(data["change_race"])
var/species[0]
for(var/specimen in valid_species)
species[++species.len] = list("specimen" = specimen)
data["species"] = species
data["change_gender"] = can_change(APPEARANCE_GENDER)
data["change_skin_tone"] = can_change_skin_tone()
data["change_skin_color"] = can_change_skin_color()
data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR)
data["change_hair"] = can_change(APPEARANCE_HAIR)
if(data["change_hair"])
var/hair_styles[0]
for(var/hair_style in valid_hairstyles)
hair_styles[++hair_styles.len] = list("hairstyle" = hair_style)
data["hair_styles"] = hair_styles
data["hair_style"] = owner.h_style
data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR)
if(data["change_facial_hair"])
var/facial_hair_styles[0]
for(var/facial_hair_style in valid_facial_hairstyles)
facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style)
data["facial_hair_styles"] = facial_hair_styles
data["facial_hair_style"] = owner.f_style
data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR)
data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "appearance_changer.tmpl", "[src.name]", 800, 450)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/nano_module/appearance_changer/proc/update_dna()
if(owner && (flags & APPEARANCE_UPDATE_DNA))
owner.update_dna()
/obj/nano_module/appearance_changer/proc/can_change(var/flag)
return owner && (flags & flag)
/obj/nano_module/appearance_changer/proc/can_change_skin_tone()
return owner && (flags & APPEARANCE_SKIN) && owner.species.flags & HAS_SKIN_TONE
/obj/nano_module/appearance_changer/proc/can_change_skin_color()
return owner && (flags & APPEARANCE_SKIN) && owner.species.flags & HAS_SKIN_COLOR
/obj/nano_module/appearance_changer/proc/can_still_topic()
return CanUseTopic(usr, list(), default_state) == STATUS_INTERACTIVE
/obj/nano_module/appearance_changer/proc/cut_and_generate_data()
// Making the assumption that the available species remain constant
valid_facial_hairstyles.Cut()
valid_facial_hairstyles.Cut()
generate_data()
/obj/nano_module/appearance_changer/proc/generate_data()
if(!valid_species.len)
valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist)
if(!valid_hairstyles.len || !valid_facial_hairstyles.len)
valid_hairstyles = owner.generate_valid_hairstyles()
valid_facial_hairstyles = owner.generate_valid_facial_hairstyles()

View File

@@ -1,11 +1,11 @@
/atom/movable/proc/nano_host() /atom/proc/nano_host()
return src return src
/obj/nano_module/nano_host() /obj/nano_module/nano_host()
return loc return loc
/atom/movable/proc/CanUseTopic(var/mob/user, href_list, var/datum/topic_state/custom_state) /atom/proc/CanUseTopic(var/mob/user, href_list, var/datum/topic_state/custom_state)
return user.can_use_topic(nano_host(), custom_state) return user.can_use_topic(nano_host(), custom_state)

View File

@@ -772,8 +772,23 @@ var/list/be_special_flags = list(
#define STATUS_UPDATE 1 // ORANGE Visability #define STATUS_UPDATE 1 // ORANGE Visability
#define STATUS_DISABLED 0 // RED Visability #define STATUS_DISABLED 0 // RED Visability
#define STATUS_CLOSE -1 // Close the interface #define STATUS_CLOSE -1 // Close the interface
//General-purpose life speed define for plants. //General-purpose life speed define for plants.
#define HYDRO_SPEED_MULTIPLIER 1 #define HYDRO_SPEED_MULTIPLIER 1
#define NANO_IGNORE_DISTANCE 1 #define NANO_IGNORE_DISTANCE 1
#define DEFAULT_JOB_TYPE /datum/job/assistant #define DEFAULT_JOB_TYPE /datum/job/assistant
// Appearance change flags
#define APPEARANCE_UPDATE_DNA 1
#define APPEARANCE_RACE 2|APPEARANCE_UPDATE_DNA
#define APPEARANCE_GENDER 4|APPEARANCE_UPDATE_DNA
#define APPEARANCE_SKIN 8
#define APPEARANCE_HAIR 16
#define APPEARANCE_HAIR_COLOR 32
#define APPEARANCE_FACIAL_HAIR 64
#define APPEARANCE_FACIAL_HAIR_COLOR 128
#define APPEARANCE_EYE_COLOR 256
#define APPEARANCE_ALL_HAIR APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR
#define APPEARANCE_ALL 511

View File

@@ -322,5 +322,9 @@ EVENT_CUSTOM_START_MAJOR 80;100
## Uncomment to disable respawning by default. ## Uncomment to disable respawning by default.
#DISABLE_RESPAWN #DISABLE_RESPAWN
## Strength of ambient star light. Set to 0 or less to turn off. ## Strength of ambient star light. Set to 0 or less to turn off. A value of 1 is unlikely to have a noticeable effect in most lightning systems.
STARLIGHT 0 STARLIGHT 0
## Defines which races are allowed to join as ERT, in singular form. If unset, defaults to only human. Casing matters, separate using ;
## Example races include: Human, Tajara, Skrell, Unathi
# ERT_SPECIES Human;Skrell;Unathi

View File

@@ -0,0 +1,75 @@
{{if data.change_race}}
<div class="item">
<div class="itemLabelNarrow">
Species:
</div>
<div class="itemContentWide">
{{for data.species}}
{{:helper.link(value.specimen, null, { 'race' : value.specimen}, null, data.specimen == value.specimen ? 'selected' : null)}}
{{/for}}
</div>
</div>
{{/if}}
{{if data.change_gender}}
<div class="item">
<div class="itemLabelNarrow">
Gender:
</div>
<div class="itemContentWide">
{{:helper.link('Male', null, { 'gender' : 'male'}, null, data.gender == 'male' ? 'selected' : null)}}
{{:helper.link('Female', null, { 'gender' : 'female'}, null, data.gender == 'female' ? 'selected' : null)}}
</div>
</div>
{{/if}}
{{if data.change_eye_color || data.change_skin_tone || data.change_skin_color || data.change_hair_color || data.change_facial_hair_color}}
<div class="item">
<div class="itemLabelNarrow">
Colors:
</div>
<div class="itemContentWide">
{{if data.change_eye_color}}
{{:helper.link('Change eye color', null, { 'eye_color' : 1})}}
{{/if}}
{{if data.change_skin_tone}}
{{:helper.link('Change skin tone', null, { 'skin_tone' : 1})}}
{{/if}}
{{if data.change_skin_color}}
{{:helper.link('Change skin color', null, { 'skin_color' : 1})}}
{{/if}}
{{if data.change_hair_color}}
{{:helper.link('Change hair color', null, { 'hair_color' : 1})}}
{{/if}}
{{if data.change_facial_hair_color}}
{{:helper.link('Change facial hair color', null, { 'facial_hair_color' : 1})}}
{{/if}}
</div>
</div>
{{/if}}
{{if data.change_hair}}
<div class="item">
<div class="itemLabelNarrow">
Hair styles:
</div>
<div class="itemContentWide">
{{for data.hair_styles}}
{{:helper.link(value.hairstyle, null, { 'hair' : value.hairstyle}, null, data.hair_style == value.hairstyle ? 'selected' : null)}}
{{/for}}
</div>
</div>
{{/if}}
{{if data.change_facial_hair}}
<div class="item">
<div class="itemLabelNarrow">
Facial hair styles:
</div>
<div class="itemContentWide">
{{for data.facial_hair_styles}}
{{:helper.link(value.facialhairstyle, null, { 'facial_hair' : value.facialhairstyle}, null, data.facial_hair_style == value.facialhairstyle ? 'selected' : null)}}
{{/for}}
</div>
</div>
{{/if}}