diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index f6b088bbe2c..b56e973631e 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -310,3 +310,11 @@ var/list/bloody_footprints_cache = list() #define FIRE_PROOF -1 #define FLAMMABLE 0 #define ON_FIRE 1 + + +//Ghost orbit types: +#define GHOST_ORBIT_CIRCLE "circle" +#define GHOST_ORBIT_TRIANGLE "triangle" +#define GHOST_ORBIT_HEXAGON "hexagon" +#define GHOST_ORBIT_SQUARE "square" +#define GHOST_ORBIT_PENTAGON "pentagon" diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm index ead70a299a6..17228a32fe4 100644 --- a/code/__HELPERS/matrices.dm +++ b/code/__HELPERS/matrices.dm @@ -3,15 +3,24 @@ Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT -/atom/proc/SpinAnimation(speed = 10, loops = -1) - var/matrix/m120 = matrix(transform) - m120.Turn(120) - var/matrix/m240 = matrix(transform) - m240.Turn(240) - var/matrix/m360 = matrix(transform) - speed /= 3 //Gives us 3 equal time segments for our three turns. - //Why not one turn? Because byond will see that the start and finish are the same place and do nothing - //Why not two turns? Because byond will do a flip instead of a turn - animate(src, transform = m120, time = speed, loops) - animate(transform = m240, time = speed) - animate(transform = m360, time = speed) \ No newline at end of file +/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3) + if(!segments) + return + var/segment = 360/segments + if(!clockwise) + segment = -segment + var/list/matrices = list() + for(var/i in 1 to segments-1) + var/matrix/M = matrix(transform) + M.Turn(segment*i) + matrices += M + var/matrix/last = matrix(transform) + matrices += last + + speed /= segments + + animate(src, transform = matrices[1], time = speed, loops) + for(var/i in 2 to segments) //2 because 1 is covered above + animate(transform = matrices[i], time = speed) + //doesn't have an object argument because this is "Stacking" with the animate call above + //3 billion% intentional diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index bbdab1815e0..8e6afc688e3 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -377,7 +377,7 @@ Turf and target are seperate in case you want to teleport some distance from a t for(var/mob/M in mobs) if(skip_mindless && (!M.mind && !M.ckey)) - if(!isbot(M)) + if(!isbot(M) && !istype(M, /mob/camera/)) continue var/name = M.name if (name in names) @@ -1192,51 +1192,56 @@ B --><-- A //orbit() can run without it (swap orbiting for A) //but then you can never stop it and that's just silly. /atom/movable/var/atom/orbiting = null -//we raise this each time orbit is called to prevent mutiple calls in a short time frame from breaking things -/atom/movable/var/orbitid = 0 -/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = 1, angle_increment = 15, lockinorbit = 0) +//A: atom to orbit +//radius: range to orbit at, radius of the circle formed by orbiting +//clockwise: whether you orbit clockwise or anti clockwise +//rotation_speed: how fast to rotate +//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default. +//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts +//lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts) + +/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE) if(!istype(A)) return - orbitid++ - var/myid = orbitid - if (orbiting) - stop_orbit() - //sadly this is the only way to ensure the original orbit proc stops - //and resets the atom's transform before we continue. - //time is based on the sleep in the loop and the time for the final animation of initial_transform. - sleep(2.6+world.tick_lag) - if (orbiting || !istype(A) || orbitid != myid) //post sleep re-check - return - orbiting = A - var/lastloc = loc - var/angle = 0 - var/matrix/initial_transform = matrix(transform) - while(orbiting && orbiting.loc && orbitid == myid) + if(orbiting) + stop_orbit() + sleep(2.6+world.tick_lag) //the 2 second delay at the end of the existing orbit() call, plus some lag slack. + + orbiting = A + var/matrix/initial_transform = matrix(transform) + var/lastloc = loc + + //Head first! + if(pre_rotation) + var/matrix/M = matrix(transform) + var/pre_rot = 90 + if(!clockwise) + pre_rot = -90 + M.Turn(pre_rot) + transform = M + + var/matrix/shift = matrix(transform) + shift.Translate(0,radius) + transform = shift + + SpinAnimation(rotation_speed, -1, clockwise, rotation_segments) + while(orbiting && orbiting.loc) var/targetloc = get_turf(orbiting) - if (!lockinorbit && loc != lastloc && loc != targetloc) + if(!lockinorbit && loc != lastloc && loc != targetloc) break loc = targetloc lastloc = loc - angle += angle_increment + sleep(0.6) + + animate(src,transform = initial_transform, time = 2) //2 second delay + SpinAnimation(0,0) - var/matrix/shift = matrix(initial_transform) - shift.Translate(radius,0) - if(clockwise) - shift.Turn(angle) - else - shift.Turn(-angle) - animate(src, transform = shift, 2) - sleep(0.6) //the effect breaks above 0.6 delay - animate(src, transform = initial_transform, 2) - orbiting = null /atom/movable/proc/stop_orbit() - if(orbiting) - loc = get_turf(orbiting) - orbiting = null + orbiting = null //Center's an image. diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 590fed5d8a4..90ba95687b4 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -73,4 +73,10 @@ //usually called via datum/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash) //should attempt to salvage what it can from the old instance of subsystem -/datum/subsystem/proc/Recover() \ No newline at end of file +/datum/subsystem/proc/Recover() + +//this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag +/datum/subsystem/on_varedit(edited_var) + if (edited_var == "can_fire" && can_fire) + next_fire = world.time + wait + diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 7f3f58d85bf..848dd8cf5b5 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -247,7 +247,8 @@ datum/proc/on_varedit(modified_var) //called whenever a var is edited body += "" else var/atom/A = D - body += "" + if(istype(A)) + body += "" body += "" diff --git a/code/datums/spells/ethereal_jaunt.dm b/code/datums/spells/ethereal_jaunt.dm index bb0a0d7b8c6..f31bcff297a 100644 --- a/code/datums/spells/ethereal_jaunt.dm +++ b/code/datums/spells/ethereal_jaunt.dm @@ -88,6 +88,7 @@ density = 0 anchored = 1 invisibility = 60 + burn_state = LAVA_PROOF /obj/effect/dummy/spell_jaunt/Destroy() // Eject contents if deleted somehow diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index e663ccaa9cb..a8cb643e6cd 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -409,7 +409,11 @@ var/list/uplink_items = list() desc = "A 5-round magazine of haemorrhage ammo designed for use in the syndicate sniper rifle, causes heavy bleeding in the target." item = /obj/item/ammo_box/magazine/sniper_rounds/haemorrhage - +/datum/uplink_item/ammo/sniper/penetrator + name = "Sniper Magazine - Penetrator Rounds" + desc = "A 5-round magazine of penetrator ammo designed for use in the syndicate sniper rifle. Can pierce walls and multiple enemies." + item = /obj/item/ammo_box/magazine/sniper_rounds/penetrator + cost = 5 // STEALTHY WEAPONS diff --git a/code/game/dna.dm b/code/game/dna.dm index b15fc10715a..00c4a7b403a 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -7,6 +7,7 @@ var/blood_type var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man) var/list/features = list("FFF") //first value is mutant color + var/list/features_buffer = list() // A copy of features, used for cloning -- var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, var/list/mutations = list() //All mutations are from now on here var/list/temporary_mutations = list() //Timers for temporary mutations diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 054dcf76376..f0c2cde3211 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -411,3 +411,26 @@ if(src == user.get_active_hand()) //update inhands user.update_inv_l_hand() user.update_inv_r_hand() + + +//GREY TIDE +/obj/item/weapon/twohanded/spear/grey_tide + icon_state = "spearglass0" + name = "\improper Grey Tide" + desc = "Recovered from the aftermath of a revolt aboard Defense Outpost Theta Aegis, in which a seemingly endless tide of Assistants caused heavy casualities among Nanotrasen military forces." + force_unwielded = 15 + force_wielded = 25 + throwforce = 20 + throw_speed = 4 + attack_verb = list("gored") + +/obj/item/weapon/twohanded/spear/grey_tide/afterattack(atom/movable/AM, mob/living/user, proximity) + ..() + user.faction |= "greytide(\ref[user])" + if(istype(AM, /mob/living)) + var/mob/living/L = AM + if(!L.stat && prob(50)) + var/mob/living/simple_animal/hostile/illusion/M = new(user.loc) + M.faction = user.faction.Copy() + M.Copy_Parent(user, 100, user.health/2.5, 12, 30) + M.GiveTarget(L) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 2552bad79c8..5afbc365da9 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -287,3 +287,20 @@ sharpness = IS_SHARP attack_verb = list("sawed", "torn", "cut", "chopped", "diced") hitsound = "sound/weapons/chainsawhit.ogg" + +/obj/item/weapon/tailclub + name = "tail club" + desc = "For the beating to death of lizards with their own tails." + icon_state = "tailclub" + force = 14 + throwforce = 1 // why are you throwing a club do you even weapon + throw_speed = 1 + throw_range = 1 + attack_verb = list("clubbed", "bludgeoned") + +/obj/item/weapon/melee/chainofcommand/tailwhip + name = "liz o' nine tails" + desc = "A whip fashioned from the severed tails of lizards." + icon_state = "tailwhip" + origin_tech = "combat=1" + needs_permit = 0 diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index b1bb09d9fe1..57677bdfec9 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -218,20 +218,35 @@ /obj/structure/flora/rock name = "rock" desc = "a rock" - icon_state = "rock1" + icon_state = "rock" icon = 'icons/obj/flora/rocks.dmi' anchored = 1 burn_state = FIRE_PROOF + density = 1 /obj/structure/flora/rock/New() ..() - icon_state = "rock[rand(1,5)]" + icon_state = "[icon_state][rand(1,5)]" /obj/structure/flora/rock/pile name = "rocks" desc = "some rocks" - icon_state = "rockpile1" + icon_state = "rockpile" + density = 0 -/obj/structure/flora/rock/pile/New() + +/obj/structure/flora/rock/volcanic + icon_state = "basalt" + desc = "A volcanic rock" + + +/obj/structure/flora/rock/volcanic/New() ..() - icon_state = "rockpile[rand(1,5)]" \ No newline at end of file + icon_state = "[icon_state][rand(1,3)]" + +/obj/structure/flora/rock/pile/volcanic + icon_state = "lavarocks" + +/obj/structure/flora/rock/pile/volcanic/New() + ..() + icon_state = "[icon_state][rand(1,3)]" \ No newline at end of file diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index af2f1680f6c..6aac637a485 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -132,9 +132,12 @@ var/obj/machinery/gateway/centerstation/the_gateway = null //okay, here's the good teleporting stuff /obj/machinery/gateway/centerstation/Bumped(atom/movable/M as mob|obj) - if(!ready) return - if(!active) return - if(!awaygate) return + if(!ready) + return + if(!active) + return + if(!awaygate || qdeleted(awaygate)) + return if(awaygate.calibrated) M.loc = get_step(awaygate.loc, SOUTH) @@ -154,6 +157,7 @@ var/obj/machinery/gateway/centerstation/the_gateway = null user << "\black The gate is already calibrated, there is no work for you to do here." return + /////////////////////////////////////Away//////////////////////// @@ -232,8 +236,12 @@ var/obj/machinery/gateway/centerstation/the_gateway = null /obj/machinery/gateway/centeraway/Bumped(atom/movable/M as mob|obj) - if(!ready) return - if(!active) return + if(!ready) + return + if(!active) + return + if(!stationgate || qdeleted(stationgate)) + return if(istype(M, /mob/living/carbon)) for(var/obj/item/weapon/implant/exile/E in M)//Checking that there is an exile implant in the contents if(E.imp_in == M)//Checking that it's actually implanted vs just in their pocket @@ -251,4 +259,4 @@ var/obj/machinery/gateway/centerstation/the_gateway = null else user << "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target." calibrated = 1 - return \ No newline at end of file + return diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 24e42225941..29dbb61db30 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1,1127 +1,1137 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 - -var/list/preferences_datums = list() - - - -/datum/preferences - //doohickeys for savefiles - var/path - var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used - var/max_save_slots = 3 - - //non-preference stuff - var/muted = 0 - var/last_ip - var/last_id - - //game-preferences - var/lastchangelog = "" //Saved changlog filesize to detect if there was a change - var/ooccolor = null - - //Antag preferences - var/list/be_special = list() //Special role selection - var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more - //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were, - //autocorrected this round, not that you'd need to check that. - - - var/UI_style = "Midnight" - var/nanoui_fancy = TRUE - var/toggles = TOGGLES_DEFAULT - var/chat_toggles = TOGGLES_DEFAULT_CHAT - var/ghost_form = "ghost" - var/allow_midround_antag = 1 - var/preferred_map = null - - //character preferences - var/real_name //our character's name - var/be_random_name = 0 //whether we'll have a random name every round - var/be_random_body = 0 //whether we'll have a random body every round - var/gender = MALE //gender of character (well duh) - var/age = 30 //age of character - var/blood_type = "A+" //blood type (not-chooseable) - var/underwear = "Nude" //underwear type - var/undershirt = "Nude" //undershirt type - var/socks = "Nude" //socks type - var/backbag = 1 //backpack type - var/hair_style = "Bald" //Hair type - var/hair_color = "000" //Hair color - var/facial_hair_style = "Shaved" //Face hair type - var/facial_hair_color = "000" //Facial hair color - var/skin_tone = "caucasian1" //Skin color - var/eye_color = "000" //Eye color - var/datum/species/pref_species = new /datum/species/human() //Mutant race - var/list/features = list("mcolor" = "FFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None") - - var/list/custom_names = list("clown", "mime", "ai", "cyborg", "religion", "deity") - - //Mob preview - var/icon/preview_icon = null - - //Jobs, uses bitflags - var/job_civilian_high = 0 - var/job_civilian_med = 0 - var/job_civilian_low = 0 - - var/job_medsci_high = 0 - var/job_medsci_med = 0 - var/job_medsci_low = 0 - - var/job_engsec_high = 0 - var/job_engsec_med = 0 - var/job_engsec_low = 0 - - // Want randomjob if preferences already filled - Donkie - var/userandomjob = 1 //defaults to 1 for fewer assistants - - // 0 = character settings, 1 = game preferences - var/current_tab = 0 - - // OOC Metadata: - var/metadata = "" - - var/unlock_content = 0 - - var/list/ignoring = list() - -/datum/preferences/New(client/C) - blood_type = random_blood_type() - custom_names["ai"] = pick(ai_names) - custom_names["cyborg"] = pick(ai_names) - custom_names["clown"] = pick(clown_names) - custom_names["mime"] = pick(mime_names) - if(istype(C)) - if(!IsGuestKey(C.key)) - load_path(C.ckey) - unlock_content = C.IsByondMember() - if(unlock_content) - max_save_slots = 8 - var/loaded_preferences_successfully = load_preferences() - if(loaded_preferences_successfully) - if(load_character()) - return - //we couldn't load character data so just randomize the character appearance + name - random_character() //let's create a random character then - rather than a fat, bald and naked man. - real_name = pref_species.random_name(gender,1) - if(!loaded_preferences_successfully) - save_preferences() - save_character() //let's save this new random character so it doesn't keep generating new ones. - return - - -/datum/preferences/proc/ShowChoices(mob/user) - if(!user || !user.client) return - update_preview_icon() - user << browse_rsc(preview_icon, "previewicon.png") - var/dat = "
" - - dat += "Character Settings " - dat += "Game Preferences" - - if(!path) - dat += "
Please create an account to save your preferences
" - - dat += "
" - - dat += "
" - - switch(current_tab) - if (0) // Character Settings# - if(path) - var/savefile/S = new /savefile(path) - if(S) - dat += "
" - var/name - for(var/i=1, i<=max_save_slots, i++) - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) name = "Character[i]" - //if(i!=1) dat += " | " - dat += "[name] " - dat += "
" - - dat += "

Occupation Choices

" - dat += "Set Occupation Preferences
" - dat += "

Identity

" - dat += "" - - - dat += "
" - if(appearance_isbanned(user)) - dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game.
" - dat += "Random Name " - dat += "Always Random Name: [be_random_name ? "Yes" : "No"]
" - - dat += "Name: " - dat += "[real_name]
" - - dat += "Gender: [gender == MALE ? "Male" : "Female"]
" - dat += "Age: [age]
" - - dat += "Special Names:
" - dat += "Clown: [custom_names["clown"]] " - dat += "Mime:[custom_names["mime"]]
" - dat += "AI: [custom_names["ai"]] " - dat += "Cyborg: [custom_names["cyborg"]]
" - dat += "Chaplain religion: [custom_names["religion"]] " - dat += "Chaplain deity: [custom_names["deity"]]
" - - dat += "
" - - dat += "
" - - dat += "

Body

" - dat += "Random Body " - dat += "Always Random Body: [be_random_body ? "Yes" : "No"]
" - - dat += "" - - if(pref_species.use_skintones) - - dat += "" - - if(HAIR in pref_species.specflags) - - dat += "" - - if(EYECOLOR in pref_species.specflags) - - dat += "" - - if(config.mutant_races) //We don't allow mutant bodyparts for humans either unless this is true. - - if((MUTCOLORS in pref_species.specflags) || (MUTCOLORS_PARTSONLY in pref_species.specflags)) - - dat += "" - - if("tail_lizard" in pref_species.mutant_bodyparts) - dat += "" - - if("snout" in pref_species.mutant_bodyparts) - dat += "" - - if("horns" in pref_species.mutant_bodyparts) - dat += "" - - if("frills" in pref_species.mutant_bodyparts) - dat += "" - - if("spines" in pref_species.mutant_bodyparts) - dat += "" - - if("body_markings" in pref_species.mutant_bodyparts) - dat += "" - - if(config.mutant_humans) - - if("tail_human" in pref_species.mutant_bodyparts) - dat += "" - - if("ears" in pref_species.mutant_bodyparts) - dat += "" - - dat += "
" - - if(config.mutant_races) - dat += "Species:
[pref_species.name]
" - else - dat += "Species: Human
" - - dat += "Blood Type: [blood_type]
" - dat += "Underwear:
[underwear]
" - dat += "Undershirt:
[undershirt]
" - dat += "Socks:
[socks]
" - dat += "Backpack:
[backbaglist[backbag]]
" - - dat += "

Skin Tone

" - - dat += "[skin_tone]
" - - dat += "
" - - dat += "

Hair Style

" - - dat += "[hair_style]
" - dat += "< >
" - dat += "    Change
" - - - dat += "
" - - dat += "

Facial Hair Style

" - - dat += "[facial_hair_style]
" - dat += "< >
" - dat += "    Change
" - - dat += "
" - - dat += "

Eye Color

" - - dat += "    Change
" - - dat += "
" - - dat += "

Alien/Mutant Color

" - - dat += "    Change
" - - dat += "
" - - dat += "

Tail

" - - dat += "[features["tail_lizard"]]
" - - dat += "
" - - dat += "

Snout

" - - dat += "[features["snout"]]
" - - dat += "
" - - dat += "

Horns

" - - dat += "[features["horns"]]
" - - dat += "
" - - dat += "

Frills

" - - dat += "[features["frills"]]
" - - dat += "
" - - dat += "

Spines

" - - dat += "[features["spines"]]
" - - dat += "
" - - dat += "

Body Markings

" - - dat += "[features["body_markings"]]
" - - dat += "
" - - dat += "

Tail

" - - dat += "[features["tail_human"]]
" - - dat += "
" - - dat += "

Ears

" - - dat += "[features["ears"]]
" - - dat += "
" - - - if (1) // Game Preferences - dat += "
" - dat += "

General Settings

" - dat += "UI Style: [UI_style]
" - dat += "Fancy NanoUI: [(nanoui_fancy) ? "Yes" : "No"]
" - dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"]
" - dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"]
" - dat += "Ghost ears: [(chat_toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
" - dat += "Ghost sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
" - dat += "Ghost whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "Nearest Creatures" : "All Speech"]
" - dat += "Ghost radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "Yes" : "No"]
" - dat += "Ghost pda: [(chat_toggles & CHAT_GHOSTPDA) ? "Nearest Creatures" : "All Messages"]
" - dat += "Pull requests: [(chat_toggles & CHAT_PULLR) ? "Yes" : "No"]
" - dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Yes" : "No"]
" - if(config.allow_Metadata) - dat += "OOC Notes: Edit
" - - if(user.client) - if(user.client.holder) - dat += "Adminhelp Sound: [(toggles & SOUND_ADMINHELP)?"On":"Off"]
" - dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"On":"Off"]
" - - if(unlock_content || check_rights_for(user.client, R_ADMIN)) - dat += "OOC:     Change
" - - if(unlock_content) - dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" - dat += "Ghost Form: [ghost_form]
" - - if (SERVERTOOLS && config.maprotation) - var/p_map = preferred_map - if (!p_map) - p_map = "Default" - if (config.defaultmap) - p_map += " ([config.defaultmap.friendlyname])" - else - if (p_map in config.maplist) - var/datum/votablemap/VM = config.maplist[p_map] - if (!VM) - p_map += " (No longer exists)" - else - p_map = VM.friendlyname - else - p_map += " (No longer exists)" - dat += "Preferred Map: [p_map]" - - dat += "
" - - dat += "

Special Role Settings

" - - if(jobban_isbanned(user, "Syndicate")) - dat += "You are banned from antagonist roles." - src.be_special = list() - - - for (var/i in special_roles) - if(jobban_isbanned(user, i)) - dat += "Be [capitalize(i)]: BANNED
" - else - var/days_remaining = null - if(config.use_age_restriction_for_jobs && ispath(special_roles[i])) //If it's a game mode antag, check if the player meets the minimum age - var/mode_path = special_roles[i] - var/datum/game_mode/temp_mode = new mode_path - days_remaining = temp_mode.get_remaining_days(user.client) - - if(days_remaining) - dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS]
" - else - dat += "Be [capitalize(i)]: [(i in be_special) ? "Yes" : "No"]
" - - dat += "
" - - dat += "
" - - if(!IsGuestKey(user.key)) - dat += "Undo " - dat += "Save Setup " - - dat += "Reset Setup" - dat += "
" - - //user << browse(dat, "window=preferences;size=560x560") - var/datum/browser/popup = new(user, "preferences", "
Character Setup
", 640, 750) - popup.set_content(dat) - popup.open(0) - -/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620) - if(!SSjob) return - - //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. - //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. - //widthPerColumn - Screen's width for every column. - //height - Screen's height. - - var/width = widthPerColumn - - var/HTML = "
" - HTML += "Choose occupation chances
" - HTML += "
Left-click to raise an occupation preference, right-click to lower it.
" - HTML += "
Done

" // Easier to press up here. - HTML += "" - HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. - HTML += "" - var/index = -1 - - //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. - var/datum/job/lastJob - - for(var/datum/job/job in SSjob.occupations) - - index += 1 - if((index >= limit) || (job.title in splitJobs)) - width += widthPerColumn - if((index < limit) && (lastJob != null)) - //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with - //the last job's selection color. Creating a rather nice effect. - for(var/i = 0, i < (limit - index), i += 1) - HTML += "" - HTML += "
  
" - index = 0 - - HTML += "" - continue - if(!job.player_old_enough(user.client)) - var/available_in_days = job.available_in_days(user.client) - HTML += "[rank]" - continue - if((job_civilian_low & ASSISTANT) && (rank != "Assistant") && !jobban_isbanned(user, "Assistant")) - HTML += "[rank]" - continue - if(config.enforce_human_authority && !user.client.prefs.pref_species.qualifies_for_rank(rank, user.client.prefs.features)) - if(user.client.prefs.pref_species.id == "human") - HTML += "[rank]" - else - HTML += "[rank]" - continue - if((rank in command_positions) || (rank == "AI"))//Bold head jobs - HTML += "[rank]" - else - HTML += "[rank]" - - HTML += "" - continue - - HTML += "[prefLevelLabel]" - HTML += "" - - for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even - HTML += "" - - HTML += "
" - var/rank = job.title - lastJob = job - if(jobban_isbanned(user, rank)) - HTML += "[rank] BANNED
\[IN [(available_in_days)] DAYS\]
\[MUTANT\]
\[NON-HUMAN\]
" - - var/prefLevelLabel = "ERROR" - var/prefLevelColor = "pink" - var/prefUpperLevel = -1 // level to assign on left click - var/prefLowerLevel = -1 // level to assign on right click - - if(GetJobDepartment(job, 1) & job.flag) - prefLevelLabel = "High" - prefLevelColor = "slateblue" - prefUpperLevel = 4 - prefLowerLevel = 2 - else if(GetJobDepartment(job, 2) & job.flag) - prefLevelLabel = "Medium" - prefLevelColor = "green" - prefUpperLevel = 1 - prefLowerLevel = 3 - else if(GetJobDepartment(job, 3) & job.flag) - prefLevelLabel = "Low" - prefLevelColor = "orange" - prefUpperLevel = 2 - prefLowerLevel = 4 - else - prefLevelLabel = "NEVER" - prefLevelColor = "red" - prefUpperLevel = 3 - prefLowerLevel = 1 - - - HTML += "" - - if(rank == "Assistant")//Assistant is special - if(job_civilian_low & ASSISTANT) - HTML += "Yes" - else - HTML += "No" - HTML += "
  
" - - HTML += "
" - - HTML += "

[userandomjob ? "Get random job if preferences unavailable" : "Be an Assistant if preference unavailable"]
" - HTML += "
Reset Preferences
" - - user << browse(null, "window=preferences") - //user << browse(HTML, "window=mob_occupation;size=[width]x[height]") - var/datum/browser/popup = new(user, "mob_occupation", "
Occupation Preferences
", width, height) - popup.set_window_options("can_close=0") - popup.set_content(HTML) - popup.open(0) - return - -/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level) - if (!job) - return 0 - - if (level == 1) // to high - // remove any other job(s) set to high - job_civilian_med |= job_civilian_high - job_engsec_med |= job_engsec_high - job_medsci_med |= job_medsci_high - job_civilian_high = 0 - job_engsec_high = 0 - job_medsci_high = 0 - - if (job.department_flag == CIVILIAN) - job_civilian_low &= ~job.flag - job_civilian_med &= ~job.flag - job_civilian_high &= ~job.flag - - switch(level) - if (1) - job_civilian_high |= job.flag - if (2) - job_civilian_med |= job.flag - if (3) - job_civilian_low |= job.flag - - return 1 - else if (job.department_flag == ENGSEC) - job_engsec_low &= ~job.flag - job_engsec_med &= ~job.flag - job_engsec_high &= ~job.flag - - switch(level) - if (1) - job_engsec_high |= job.flag - if (2) - job_engsec_med |= job.flag - if (3) - job_engsec_low |= job.flag - - return 1 - else if (job.department_flag == MEDSCI) - job_medsci_low &= ~job.flag - job_medsci_med &= ~job.flag - job_medsci_high &= ~job.flag - - switch(level) - if (1) - job_medsci_high |= job.flag - if (2) - job_medsci_med |= job.flag - if (3) - job_medsci_low |= job.flag - - return 1 - - return 0 - -/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) - if(!SSjob) - return - var/datum/job/job = SSjob.GetJob(role) - - if(!job) - user << browse(null, "window=mob_occupation") - ShowChoices(user) - return - - if (!isnum(desiredLvl)) - user << "UpdateJobPreference - desired level was not a number. Please notify coders!" - ShowChoices(user) - return - - if(role == "Assistant") - if(job_civilian_low & job.flag) - job_civilian_low &= ~job.flag - else - job_civilian_low |= job.flag - SetChoices(user) - return 1 - - SetJobPreferenceLevel(job, desiredLvl) - SetChoices(user) - - return 1 - - -/datum/preferences/proc/ResetJobs() - - job_civilian_high = 0 - job_civilian_med = 0 - job_civilian_low = 0 - - job_medsci_high = 0 - job_medsci_med = 0 - job_medsci_low = 0 - - job_engsec_high = 0 - job_engsec_med = 0 - job_engsec_low = 0 - - -/datum/preferences/proc/GetJobDepartment(datum/job/job, level) - if(!job || !level) return 0 - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(1) - return job_civilian_high - if(2) - return job_civilian_med - if(3) - return job_civilian_low - if(MEDSCI) - switch(level) - if(1) - return job_medsci_high - if(2) - return job_medsci_med - if(3) - return job_medsci_low - if(ENGSEC) - switch(level) - if(1) - return job_engsec_high - if(2) - return job_engsec_med - if(3) - return job_engsec_low - return 0 - -/datum/preferences/proc/process_link(mob/user, list/href_list) - if(href_list["jobbancheck"]) - var/job = sanitizeSQL(href_list["jobbancheck"]) - var/sql_ckey = sanitizeSQL(user.ckey) - var/DBQuery/query_get_jobban = dbcon.NewQuery("SELECT reason, bantime, duration, expiration_time, a_ckey FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND job = '[job]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") - if(!query_get_jobban.Execute()) - var/err = query_get_jobban.ErrorMsg() - log_game("SQL ERROR obtaining reason from ban table. Error : \[[err]\]\n") - return - if(query_get_jobban.NextRow()) - var/reason = query_get_jobban.item[1] - var/bantime = query_get_jobban.item[2] - var/duration = query_get_jobban.item[3] - var/expiration_time = query_get_jobban.item[4] - var/a_ckey = query_get_jobban.item[5] - var/text - text = "You, or another user of this computer, ([user.ckey]) is banned from playing [job]. The ban reason is:
[reason]
This ban was applied by [a_ckey] on [bantime]" - if(text2num(duration) > 0) - text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)" - text += ".
" - user << text - return - - if(href_list["preference"] == "job") - switch(href_list["task"]) - if("close") - user << browse(null, "window=mob_occupation") - ShowChoices(user) - if("reset") - ResetJobs() - SetChoices(user) - if("random") - if(jobban_isbanned(user, "Assistant")) - userandomjob = 1 - else - userandomjob = !userandomjob - SetChoices(user) - if("setJobLevel") - UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) - else - SetChoices(user) - return 1 - - switch(href_list["task"]) - if("random") - switch(href_list["preference"]) - if("name") - real_name = pref_species.random_name(gender,1) - if("age") - age = rand(AGE_MIN, AGE_MAX) - if("hair") - hair_color = random_short_color() - if("hair_style") - hair_style = random_hair_style(gender) - if("facial") - facial_hair_color = random_short_color() - if("facial_hair_style") - facial_hair_style = random_facial_hair_style(gender) - if("underwear") - underwear = random_underwear(gender) - if("undershirt") - undershirt = random_undershirt(gender) - if("socks") - socks = random_socks(gender) - if("eyes") - eye_color = random_eye_color() - if("s_tone") - skin_tone = random_skin_tone() - if("bag") - backbag = rand(1,2) - if("all") - random_character() - - if("input") - switch(href_list["preference"]) - if("ghostform") - if(unlock_content) - var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in ghost_forms - if(new_form) - ghost_form = new_form - if("name") - var/new_name = reject_bad_name( input(user, "Choose your character's name:", "Character Preference") as text|null ) - if(new_name) - real_name = new_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - - if("age") - var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null - if(new_age) - age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) - - if("metadata") - var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null - if(new_metadata) - metadata = sanitize(copytext(new_metadata,1,MAX_MESSAGE_LEN)) - - if("hair") - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference") as null|color - if(new_hair) - hair_color = sanitize_hexcolor(new_hair) - - - if("hair_style") - var/new_hair_style - if(gender == MALE) - new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in hair_styles_male_list - else - new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in hair_styles_female_list - if(new_hair_style) - hair_style = new_hair_style - - if("next_hair_style") - if (gender == MALE) - hair_style = next_list_item(hair_style, hair_styles_male_list) - else - hair_style = next_list_item(hair_style, hair_styles_female_list) - - if("previous_hair_style") - if (gender == MALE) - hair_style = previous_list_item(hair_style, hair_styles_male_list) - else - hair_style = previous_list_item(hair_style, hair_styles_female_list) - - if("facial") - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference") as null|color - if(new_facial) - facial_hair_color = sanitize_hexcolor(new_facial) - - if("facial_hair_style") - var/new_facial_hair_style - if(gender == MALE) - new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in facial_hair_styles_male_list - else - new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in facial_hair_styles_female_list - if(new_facial_hair_style) - facial_hair_style = new_facial_hair_style - - if("next_facehair_style") - if (gender == MALE) - facial_hair_style = next_list_item(facial_hair_style, facial_hair_styles_male_list) - else - facial_hair_style = next_list_item(facial_hair_style, facial_hair_styles_female_list) - - if("previous_facehair_style") - if (gender == MALE) - facial_hair_style = previous_list_item(facial_hair_style, facial_hair_styles_male_list) - else - facial_hair_style = previous_list_item(facial_hair_style, facial_hair_styles_female_list) - - if("underwear") - var/new_underwear - if(gender == MALE) - new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_m - else - new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_f - if(new_underwear) - underwear = new_underwear - - if("undershirt") - var/new_undershirt - if(gender == MALE) - new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_m - else - new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_f - if(new_undershirt) - undershirt = new_undershirt - - if("socks") - var/new_socks - if(gender == MALE) - new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in socks_m - else - new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in socks_f - if(new_socks) - socks = new_socks - - if("eyes") - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference") as color|null - if(new_eyes) - eye_color = sanitize_hexcolor(new_eyes) - - if("species") - - var/result = input(user, "Select a species", "Species Selection") as null|anything in roundstart_species - - if(result) - var/newtype = roundstart_species[result] - pref_species = new newtype() - //Now that we changed our species, we must verify that the mutant colour is still allowed. - var/temp_hsv = RGBtoHSV(features["mcolor"]) - if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.specflags) && ReadHSV(temp_hsv)[3] < ReadHSV("#7F7F7F")[3])) - features["mcolor"] = pref_species.default_color - if("mutant_color") - var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference") as color|null - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - if(new_mutantcolor == "#000000") - features["mcolor"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.specflags) || ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor"] = sanitize_hexcolor(new_mutantcolor) - else - user << "Invalid color. Your color is not bright enough." - - if("tail_lizard") - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in tails_list_lizard - if(new_tail) - features["tail_lizard"] = new_tail - - if("tail_human") - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in tails_list_human - if(new_tail) - features["tail_human"] = new_tail - - if("snout") - var/new_snout - new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in snouts_list - if(new_snout) - features["snout"] = new_snout - - if("horns") - var/new_horns - new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in horns_list - if(new_horns) - features["horns"] = new_horns - - if("ears") - var/new_ears - new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in ears_list - if(new_ears) - features["ears"] = new_ears - - if("frills") - var/new_frills - new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in frills_list - if(new_frills) - features["frills"] = new_frills - - if("spines") - var/new_spines - new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in spines_list - if(new_spines) - features["spines"] = new_spines - - if("body_markings") - var/new_body_markings - new_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in body_markings_list - if(new_body_markings) - features["body_markings"] = new_body_markings - - if("s_tone") - var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in skin_tones - if(new_s_tone) - skin_tone = new_s_tone - - if("ooccolor") - var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference") as color|null - if(new_ooccolor) - ooccolor = sanitize_ooccolor(new_ooccolor) - - if("bag") - var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist - if(new_backbag) - backbag = backbaglist.Find(new_backbag) - - if("clown_name") - var/new_clown_name = reject_bad_name( input(user, "Choose your character's clown name:", "Character Preference") as text|null ) - if(new_clown_name) - custom_names["clown"] = new_clown_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - - if("mime_name") - var/new_mime_name = reject_bad_name( input(user, "Choose your character's mime name:", "Character Preference") as text|null ) - if(new_mime_name) - custom_names["mime"] = new_mime_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - - if("ai_name") - var/new_ai_name = reject_bad_name( input(user, "Choose your character's AI name:", "Character Preference") as text|null, 1 ) - if(new_ai_name) - custom_names["ai"] = new_ai_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, 0-9, -, ' and ." - - if("cyborg_name") - var/new_cyborg_name = reject_bad_name( input(user, "Choose your character's cyborg name:", "Character Preference") as text|null, 1 ) - if(new_cyborg_name) - custom_names["cyborg"] = new_cyborg_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, 0-9, -, ' and ." - - if("religion_name") - var/new_religion_name = reject_bad_name( input(user, "Choose your character's religion:", "Character Preference") as text|null ) - if(new_religion_name) - custom_names["religion"] = new_religion_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - - if("deity_name") - var/new_deity_name = reject_bad_name( input(user, "Choose your character's deity:", "Character Preference") as text|null ) - if(new_deity_name) - custom_names["deity"] = new_deity_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - if ("preferred_map") - var/maplist = list() - var/default = "Default" - if (config.defaultmap) - default += " ([config.defaultmap.friendlyname])" - for (var/M in config.maplist) - var/datum/votablemap/VM = config.maplist[M] - var/friendlyname = "[VM.friendlyname] " - if (VM.voteweight <= 0) - friendlyname += " (disabled)" - maplist[friendlyname] = VM.name - maplist[default] = null - var/pickedmap = input(user, "Choose your preferred map. This will be used to help weight random map selection.", "Character Preference") as null|anything in maplist - if (pickedmap) - preferred_map = maplist[pickedmap] - - - else - switch(href_list["preference"]) - if("publicity") - if(unlock_content) - toggles ^= MEMBER_PUBLIC - if("gender") - if(gender == MALE) - gender = FEMALE - else - gender = MALE - underwear = random_underwear(gender) - undershirt = random_undershirt(gender) - socks = random_socks(gender) - facial_hair_style = random_facial_hair_style(gender) - hair_style = random_hair_style(gender) - - if("ui") - switch(UI_style) - if("Midnight") - UI_style = "Plasmafire" - if("Plasmafire") - UI_style = "Retro" - else - UI_style = "Midnight" - - if("nanoui") - nanoui_fancy = !nanoui_fancy - - if("hear_adminhelps") - toggles ^= SOUND_ADMINHELP - if("announce_login") - toggles ^= ANNOUNCE_LOGIN - - if("be_special") - var/be_special_type = href_list["be_special_type"] - if(be_special_type in be_special) - be_special -= be_special_type - else - be_special += be_special_type - - if("name") - be_random_name = !be_random_name - - if("all") - be_random_body = !be_random_body - - if("hear_midis") - toggles ^= SOUND_MIDI - - if("lobby_music") - toggles ^= SOUND_LOBBY - if(toggles & SOUND_LOBBY) - user << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) - else - user.stopLobbySound() - - if("ghost_ears") - chat_toggles ^= CHAT_GHOSTEARS - - if("ghost_sight") - chat_toggles ^= CHAT_GHOSTSIGHT - - if("ghost_whispers") - chat_toggles ^= CHAT_GHOSTWHISPER - - if("ghost_radio") - chat_toggles ^= CHAT_GHOSTRADIO - - if("ghost_pda") - chat_toggles ^= CHAT_GHOSTPDA - - if("pull_requests") - chat_toggles ^= CHAT_PULLR - - if("allow_midround_antag") - toggles ^= MIDROUND_ANTAG - - if("save") - save_preferences() - save_character() - - if("load") - load_preferences() - load_character() - - if("changeslot") - if(!load_character(text2num(href_list["num"]))) - random_character() - real_name = random_unique_name(gender) - save_character() - - if("tab") - if (href_list["tab"]) - current_tab = text2num(href_list["tab"]) - - ShowChoices(user) - return 1 - -/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1) - if(be_random_name) - real_name = pref_species.random_name(gender) - - if(be_random_body) - random_character(gender) - - if(config.humans_need_surnames) - var/firstspace = findtext(real_name, " ") - var/name_length = length(real_name) - if(!firstspace) //we need a surname - real_name += " [pick(last_names)]" - else if(firstspace == name_length) - real_name += "[pick(last_names)]" - - character.real_name = real_name - character.name = character.real_name - - character.gender = gender - character.age = age - - character.eye_color = eye_color - character.hair_color = hair_color - character.facial_hair_color = facial_hair_color - - character.skin_tone = skin_tone - character.hair_style = hair_style - character.facial_hair_style = facial_hair_style - character.underwear = underwear - character.undershirt = undershirt - character.socks = socks - - character.backbag = backbag - - character.dna.blood_type = blood_type - character.dna.features = features - character.dna.real_name = character.real_name - var/datum/species/chosen_species - if(pref_species != /datum/species/human && config.mutant_races) - chosen_species = pref_species.type - else - chosen_species = /datum/species/human - character.set_species(chosen_species, icon_update=0) - - if(icon_updates) - character.update_body() - character.update_hair() - character.update_mutcolor() \ No newline at end of file +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +var/list/preferences_datums = list() + + + +/datum/preferences + //doohickeys for savefiles + var/path + var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used + var/max_save_slots = 3 + + //non-preference stuff + var/muted = 0 + var/last_ip + var/last_id + + //game-preferences + var/lastchangelog = "" //Saved changlog filesize to detect if there was a change + var/ooccolor = null + + //Antag preferences + var/list/be_special = list() //Special role selection + var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more + //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were, + //autocorrected this round, not that you'd need to check that. + + + var/UI_style = "Midnight" + var/nanoui_fancy = TRUE + var/toggles = TOGGLES_DEFAULT + var/chat_toggles = TOGGLES_DEFAULT_CHAT + var/ghost_form = "ghost" + var/ghost_orbit = GHOST_ORBIT_CIRCLE + var/allow_midround_antag = 1 + var/preferred_map = null + + //character preferences + var/real_name //our character's name + var/be_random_name = 0 //whether we'll have a random name every round + var/be_random_body = 0 //whether we'll have a random body every round + var/gender = MALE //gender of character (well duh) + var/age = 30 //age of character + var/blood_type = "A+" //blood type (not-chooseable) + var/underwear = "Nude" //underwear type + var/undershirt = "Nude" //undershirt type + var/socks = "Nude" //socks type + var/backbag = 1 //backpack type + var/hair_style = "Bald" //Hair type + var/hair_color = "000" //Hair color + var/facial_hair_style = "Shaved" //Face hair type + var/facial_hair_color = "000" //Facial hair color + var/skin_tone = "caucasian1" //Skin color + var/eye_color = "000" //Eye color + var/datum/species/pref_species = new /datum/species/human() //Mutant race + var/list/features = list("mcolor" = "FFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None") + + var/list/custom_names = list("clown", "mime", "ai", "cyborg", "religion", "deity") + + //Mob preview + var/icon/preview_icon = null + + //Jobs, uses bitflags + var/job_civilian_high = 0 + var/job_civilian_med = 0 + var/job_civilian_low = 0 + + var/job_medsci_high = 0 + var/job_medsci_med = 0 + var/job_medsci_low = 0 + + var/job_engsec_high = 0 + var/job_engsec_med = 0 + var/job_engsec_low = 0 + + // Want randomjob if preferences already filled - Donkie + var/userandomjob = 1 //defaults to 1 for fewer assistants + + // 0 = character settings, 1 = game preferences + var/current_tab = 0 + + // OOC Metadata: + var/metadata = "" + + var/unlock_content = 0 + + var/list/ignoring = list() + +/datum/preferences/New(client/C) + blood_type = random_blood_type() + custom_names["ai"] = pick(ai_names) + custom_names["cyborg"] = pick(ai_names) + custom_names["clown"] = pick(clown_names) + custom_names["mime"] = pick(mime_names) + if(istype(C)) + if(!IsGuestKey(C.key)) + load_path(C.ckey) + unlock_content = C.IsByondMember() + if(unlock_content) + max_save_slots = 8 + var/loaded_preferences_successfully = load_preferences() + if(loaded_preferences_successfully) + if(load_character()) + return + //we couldn't load character data so just randomize the character appearance + name + random_character() //let's create a random character then - rather than a fat, bald and naked man. + real_name = pref_species.random_name(gender,1) + if(!loaded_preferences_successfully) + save_preferences() + save_character() //let's save this new random character so it doesn't keep generating new ones. + return + + +/datum/preferences/proc/ShowChoices(mob/user) + if(!user || !user.client) return + update_preview_icon() + user << browse_rsc(preview_icon, "previewicon.png") + var/dat = "
" + + dat += "Character Settings " + dat += "Game Preferences" + + if(!path) + dat += "
Please create an account to save your preferences
" + + dat += "
" + + dat += "
" + + switch(current_tab) + if (0) // Character Settings# + if(path) + var/savefile/S = new /savefile(path) + if(S) + dat += "
" + var/name + for(var/i=1, i<=max_save_slots, i++) + S.cd = "/character[i]" + S["real_name"] >> name + if(!name) name = "Character[i]" + //if(i!=1) dat += " | " + dat += "[name] " + dat += "
" + + dat += "

Occupation Choices

" + dat += "Set Occupation Preferences
" + dat += "

Identity

" + dat += "" + + + dat += "
" + if(appearance_isbanned(user)) + dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game.
" + dat += "Random Name " + dat += "Always Random Name: [be_random_name ? "Yes" : "No"]
" + + dat += "Name: " + dat += "[real_name]
" + + dat += "Gender: [gender == MALE ? "Male" : "Female"]
" + dat += "Age: [age]
" + + dat += "Special Names:
" + dat += "Clown: [custom_names["clown"]] " + dat += "Mime:[custom_names["mime"]]
" + dat += "AI: [custom_names["ai"]] " + dat += "Cyborg: [custom_names["cyborg"]]
" + dat += "Chaplain religion: [custom_names["religion"]] " + dat += "Chaplain deity: [custom_names["deity"]]
" + + dat += "
" + + dat += "
" + + dat += "

Body

" + dat += "Random Body " + dat += "Always Random Body: [be_random_body ? "Yes" : "No"]
" + + dat += "" + + if(pref_species.use_skintones) + + dat += "" + + if(HAIR in pref_species.specflags) + + dat += "" + + if(EYECOLOR in pref_species.specflags) + + dat += "" + + if(config.mutant_races) //We don't allow mutant bodyparts for humans either unless this is true. + + if((MUTCOLORS in pref_species.specflags) || (MUTCOLORS_PARTSONLY in pref_species.specflags)) + + dat += "" + + if("tail_lizard" in pref_species.mutant_bodyparts) + dat += "" + + if("snout" in pref_species.mutant_bodyparts) + dat += "" + + if("horns" in pref_species.mutant_bodyparts) + dat += "" + + if("frills" in pref_species.mutant_bodyparts) + dat += "" + + if("spines" in pref_species.mutant_bodyparts) + dat += "" + + if("body_markings" in pref_species.mutant_bodyparts) + dat += "" + + if(config.mutant_humans) + + if("tail_human" in pref_species.mutant_bodyparts) + dat += "" + + if("ears" in pref_species.mutant_bodyparts) + dat += "" + + dat += "
" + + if(config.mutant_races) + dat += "Species:
[pref_species.name]
" + else + dat += "Species: Human
" + + dat += "Blood Type: [blood_type]
" + dat += "Underwear:
[underwear]
" + dat += "Undershirt:
[undershirt]
" + dat += "Socks:
[socks]
" + dat += "Backpack:
[backbaglist[backbag]]
" + + dat += "

Skin Tone

" + + dat += "[skin_tone]
" + + dat += "
" + + dat += "

Hair Style

" + + dat += "[hair_style]
" + dat += "< >
" + dat += "    Change
" + + + dat += "
" + + dat += "

Facial Hair Style

" + + dat += "[facial_hair_style]
" + dat += "< >
" + dat += "    Change
" + + dat += "
" + + dat += "

Eye Color

" + + dat += "    Change
" + + dat += "
" + + dat += "

Alien/Mutant Color

" + + dat += "    Change
" + + dat += "
" + + dat += "

Tail

" + + dat += "[features["tail_lizard"]]
" + + dat += "
" + + dat += "

Snout

" + + dat += "[features["snout"]]
" + + dat += "
" + + dat += "

Horns

" + + dat += "[features["horns"]]
" + + dat += "
" + + dat += "

Frills

" + + dat += "[features["frills"]]
" + + dat += "
" + + dat += "

Spines

" + + dat += "[features["spines"]]
" + + dat += "
" + + dat += "

Body Markings

" + + dat += "[features["body_markings"]]
" + + dat += "
" + + dat += "

Tail

" + + dat += "[features["tail_human"]]
" + + dat += "
" + + dat += "

Ears

" + + dat += "[features["ears"]]
" + + dat += "
" + + + if (1) // Game Preferences + dat += "
" + dat += "

General Settings

" + dat += "UI Style: [UI_style]
" + dat += "Fancy NanoUI: [(nanoui_fancy) ? "Yes" : "No"]
" + dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"]
" + dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"]
" + dat += "Ghost ears: [(chat_toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
" + dat += "Ghost sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
" + dat += "Ghost whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "Nearest Creatures" : "All Speech"]
" + dat += "Ghost radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "Yes" : "No"]
" + dat += "Ghost pda: [(chat_toggles & CHAT_GHOSTPDA) ? "Nearest Creatures" : "All Messages"]
" + dat += "Pull requests: [(chat_toggles & CHAT_PULLR) ? "Yes" : "No"]
" + dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Yes" : "No"]
" + if(config.allow_Metadata) + dat += "OOC Notes: Edit
" + + if(user.client) + if(user.client.holder) + dat += "Adminhelp Sound: [(toggles & SOUND_ADMINHELP)?"On":"Off"]
" + dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"On":"Off"]
" + + if(unlock_content || check_rights_for(user.client, R_ADMIN)) + dat += "OOC:     Change
" + + if(unlock_content) + dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" + dat += "Ghost Form: [ghost_form]
" + dat += "Ghost Orbit: [ghost_orbit]
" + + if (SERVERTOOLS && config.maprotation) + var/p_map = preferred_map + if (!p_map) + p_map = "Default" + if (config.defaultmap) + p_map += " ([config.defaultmap.friendlyname])" + else + if (p_map in config.maplist) + var/datum/votablemap/VM = config.maplist[p_map] + if (!VM) + p_map += " (No longer exists)" + else + p_map = VM.friendlyname + else + p_map += " (No longer exists)" + dat += "Preferred Map: [p_map]" + + dat += "
" + + dat += "

Special Role Settings

" + + if(jobban_isbanned(user, "Syndicate")) + dat += "You are banned from antagonist roles." + src.be_special = list() + + + for (var/i in special_roles) + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: BANNED
" + else + var/days_remaining = null + if(config.use_age_restriction_for_jobs && ispath(special_roles[i])) //If it's a game mode antag, check if the player meets the minimum age + var/mode_path = special_roles[i] + var/datum/game_mode/temp_mode = new mode_path + days_remaining = temp_mode.get_remaining_days(user.client) + + if(days_remaining) + dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS]
" + else + dat += "Be [capitalize(i)]: [(i in be_special) ? "Yes" : "No"]
" + + dat += "
" + + dat += "
" + + if(!IsGuestKey(user.key)) + dat += "Undo " + dat += "Save Setup " + + dat += "Reset Setup" + dat += "
" + + //user << browse(dat, "window=preferences;size=560x560") + var/datum/browser/popup = new(user, "preferences", "
Character Setup
", 640, 750) + popup.set_content(dat) + popup.open(0) + +/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620) + if(!SSjob) return + + //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. + //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. + //widthPerColumn - Screen's width for every column. + //height - Screen's height. + + var/width = widthPerColumn + + var/HTML = "
" + HTML += "Choose occupation chances
" + HTML += "
Left-click to raise an occupation preference, right-click to lower it.
" + HTML += "
Done

" // Easier to press up here. + HTML += "" + HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. + HTML += "" + var/index = -1 + + //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. + var/datum/job/lastJob + + for(var/datum/job/job in SSjob.occupations) + + index += 1 + if((index >= limit) || (job.title in splitJobs)) + width += widthPerColumn + if((index < limit) && (lastJob != null)) + //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with + //the last job's selection color. Creating a rather nice effect. + for(var/i = 0, i < (limit - index), i += 1) + HTML += "" + HTML += "
  
" + index = 0 + + HTML += "" + continue + if(!job.player_old_enough(user.client)) + var/available_in_days = job.available_in_days(user.client) + HTML += "[rank]" + continue + if((job_civilian_low & ASSISTANT) && (rank != "Assistant") && !jobban_isbanned(user, "Assistant")) + HTML += "[rank]" + continue + if(config.enforce_human_authority && !user.client.prefs.pref_species.qualifies_for_rank(rank, user.client.prefs.features)) + if(user.client.prefs.pref_species.id == "human") + HTML += "[rank]" + else + HTML += "[rank]" + continue + if((rank in command_positions) || (rank == "AI"))//Bold head jobs + HTML += "[rank]" + else + HTML += "[rank]" + + HTML += "" + continue + + HTML += "[prefLevelLabel]" + HTML += "" + + for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even + HTML += "" + + HTML += "
" + var/rank = job.title + lastJob = job + if(jobban_isbanned(user, rank)) + HTML += "[rank] BANNED
\[IN [(available_in_days)] DAYS\]
\[MUTANT\]
\[NON-HUMAN\]
" + + var/prefLevelLabel = "ERROR" + var/prefLevelColor = "pink" + var/prefUpperLevel = -1 // level to assign on left click + var/prefLowerLevel = -1 // level to assign on right click + + if(GetJobDepartment(job, 1) & job.flag) + prefLevelLabel = "High" + prefLevelColor = "slateblue" + prefUpperLevel = 4 + prefLowerLevel = 2 + else if(GetJobDepartment(job, 2) & job.flag) + prefLevelLabel = "Medium" + prefLevelColor = "green" + prefUpperLevel = 1 + prefLowerLevel = 3 + else if(GetJobDepartment(job, 3) & job.flag) + prefLevelLabel = "Low" + prefLevelColor = "orange" + prefUpperLevel = 2 + prefLowerLevel = 4 + else + prefLevelLabel = "NEVER" + prefLevelColor = "red" + prefUpperLevel = 3 + prefLowerLevel = 1 + + + HTML += "" + + if(rank == "Assistant")//Assistant is special + if(job_civilian_low & ASSISTANT) + HTML += "Yes" + else + HTML += "No" + HTML += "
  
" + + HTML += "
" + + HTML += "

[userandomjob ? "Get random job if preferences unavailable" : "Be an Assistant if preference unavailable"]
" + HTML += "
Reset Preferences
" + + user << browse(null, "window=preferences") + //user << browse(HTML, "window=mob_occupation;size=[width]x[height]") + var/datum/browser/popup = new(user, "mob_occupation", "
Occupation Preferences
", width, height) + popup.set_window_options("can_close=0") + popup.set_content(HTML) + popup.open(0) + return + +/datum/preferences/proc/SetJobPreferenceLevel(datum/job/job, level) + if (!job) + return 0 + + if (level == 1) // to high + // remove any other job(s) set to high + job_civilian_med |= job_civilian_high + job_engsec_med |= job_engsec_high + job_medsci_med |= job_medsci_high + job_civilian_high = 0 + job_engsec_high = 0 + job_medsci_high = 0 + + if (job.department_flag == CIVILIAN) + job_civilian_low &= ~job.flag + job_civilian_med &= ~job.flag + job_civilian_high &= ~job.flag + + switch(level) + if (1) + job_civilian_high |= job.flag + if (2) + job_civilian_med |= job.flag + if (3) + job_civilian_low |= job.flag + + return 1 + else if (job.department_flag == ENGSEC) + job_engsec_low &= ~job.flag + job_engsec_med &= ~job.flag + job_engsec_high &= ~job.flag + + switch(level) + if (1) + job_engsec_high |= job.flag + if (2) + job_engsec_med |= job.flag + if (3) + job_engsec_low |= job.flag + + return 1 + else if (job.department_flag == MEDSCI) + job_medsci_low &= ~job.flag + job_medsci_med &= ~job.flag + job_medsci_high &= ~job.flag + + switch(level) + if (1) + job_medsci_high |= job.flag + if (2) + job_medsci_med |= job.flag + if (3) + job_medsci_low |= job.flag + + return 1 + + return 0 + +/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) + if(!SSjob) + return + var/datum/job/job = SSjob.GetJob(role) + + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) + return + + if (!isnum(desiredLvl)) + user << "UpdateJobPreference - desired level was not a number. Please notify coders!" + ShowChoices(user) + return + + if(role == "Assistant") + if(job_civilian_low & job.flag) + job_civilian_low &= ~job.flag + else + job_civilian_low |= job.flag + SetChoices(user) + return 1 + + SetJobPreferenceLevel(job, desiredLvl) + SetChoices(user) + + return 1 + + +/datum/preferences/proc/ResetJobs() + + job_civilian_high = 0 + job_civilian_med = 0 + job_civilian_low = 0 + + job_medsci_high = 0 + job_medsci_med = 0 + job_medsci_low = 0 + + job_engsec_high = 0 + job_engsec_med = 0 + job_engsec_low = 0 + + +/datum/preferences/proc/GetJobDepartment(datum/job/job, level) + if(!job || !level) return 0 + switch(job.department_flag) + if(CIVILIAN) + switch(level) + if(1) + return job_civilian_high + if(2) + return job_civilian_med + if(3) + return job_civilian_low + if(MEDSCI) + switch(level) + if(1) + return job_medsci_high + if(2) + return job_medsci_med + if(3) + return job_medsci_low + if(ENGSEC) + switch(level) + if(1) + return job_engsec_high + if(2) + return job_engsec_med + if(3) + return job_engsec_low + return 0 + +/datum/preferences/proc/process_link(mob/user, list/href_list) + if(href_list["jobbancheck"]) + var/job = sanitizeSQL(href_list["jobbancheck"]) + var/sql_ckey = sanitizeSQL(user.ckey) + var/DBQuery/query_get_jobban = dbcon.NewQuery("SELECT reason, bantime, duration, expiration_time, a_ckey FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND job = '[job]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") + if(!query_get_jobban.Execute()) + var/err = query_get_jobban.ErrorMsg() + log_game("SQL ERROR obtaining reason from ban table. Error : \[[err]\]\n") + return + if(query_get_jobban.NextRow()) + var/reason = query_get_jobban.item[1] + var/bantime = query_get_jobban.item[2] + var/duration = query_get_jobban.item[3] + var/expiration_time = query_get_jobban.item[4] + var/a_ckey = query_get_jobban.item[5] + var/text + text = "You, or another user of this computer, ([user.ckey]) is banned from playing [job]. The ban reason is:
[reason]
This ban was applied by [a_ckey] on [bantime]" + if(text2num(duration) > 0) + text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)" + text += ".
" + user << text + return + + if(href_list["preference"] == "job") + switch(href_list["task"]) + if("close") + user << browse(null, "window=mob_occupation") + ShowChoices(user) + if("reset") + ResetJobs() + SetChoices(user) + if("random") + if(jobban_isbanned(user, "Assistant")) + userandomjob = 1 + else + userandomjob = !userandomjob + SetChoices(user) + if("setJobLevel") + UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) + else + SetChoices(user) + return 1 + + switch(href_list["task"]) + if("random") + switch(href_list["preference"]) + if("name") + real_name = pref_species.random_name(gender,1) + if("age") + age = rand(AGE_MIN, AGE_MAX) + if("hair") + hair_color = random_short_color() + if("hair_style") + hair_style = random_hair_style(gender) + if("facial") + facial_hair_color = random_short_color() + if("facial_hair_style") + facial_hair_style = random_facial_hair_style(gender) + if("underwear") + underwear = random_underwear(gender) + if("undershirt") + undershirt = random_undershirt(gender) + if("socks") + socks = random_socks(gender) + if("eyes") + eye_color = random_eye_color() + if("s_tone") + skin_tone = random_skin_tone() + if("bag") + backbag = rand(1,2) + if("all") + random_character() + + if("input") + switch(href_list["preference"]) + if("ghostform") + if(unlock_content) + var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in ghost_forms + if(new_form) + ghost_form = new_form + if("ghostorbit") + if(unlock_content) + var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in ghost_orbits + if(new_orbit) + ghost_orbit = new_orbit + + if("name") + var/new_name = reject_bad_name( input(user, "Choose your character's name:", "Character Preference") as text|null ) + if(new_name) + real_name = new_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + + if("age") + var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null + if(new_age) + age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) + + if("metadata") + var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null + if(new_metadata) + metadata = sanitize(copytext(new_metadata,1,MAX_MESSAGE_LEN)) + + if("hair") + var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference") as null|color + if(new_hair) + hair_color = sanitize_hexcolor(new_hair) + + + if("hair_style") + var/new_hair_style + if(gender == MALE) + new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in hair_styles_male_list + else + new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in hair_styles_female_list + if(new_hair_style) + hair_style = new_hair_style + + if("next_hair_style") + if (gender == MALE) + hair_style = next_list_item(hair_style, hair_styles_male_list) + else + hair_style = next_list_item(hair_style, hair_styles_female_list) + + if("previous_hair_style") + if (gender == MALE) + hair_style = previous_list_item(hair_style, hair_styles_male_list) + else + hair_style = previous_list_item(hair_style, hair_styles_female_list) + + if("facial") + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference") as null|color + if(new_facial) + facial_hair_color = sanitize_hexcolor(new_facial) + + if("facial_hair_style") + var/new_facial_hair_style + if(gender == MALE) + new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in facial_hair_styles_male_list + else + new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in facial_hair_styles_female_list + if(new_facial_hair_style) + facial_hair_style = new_facial_hair_style + + if("next_facehair_style") + if (gender == MALE) + facial_hair_style = next_list_item(facial_hair_style, facial_hair_styles_male_list) + else + facial_hair_style = next_list_item(facial_hair_style, facial_hair_styles_female_list) + + if("previous_facehair_style") + if (gender == MALE) + facial_hair_style = previous_list_item(facial_hair_style, facial_hair_styles_male_list) + else + facial_hair_style = previous_list_item(facial_hair_style, facial_hair_styles_female_list) + + if("underwear") + var/new_underwear + if(gender == MALE) + new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_m + else + new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_f + if(new_underwear) + underwear = new_underwear + + if("undershirt") + var/new_undershirt + if(gender == MALE) + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_m + else + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_f + if(new_undershirt) + undershirt = new_undershirt + + if("socks") + var/new_socks + if(gender == MALE) + new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in socks_m + else + new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in socks_f + if(new_socks) + socks = new_socks + + if("eyes") + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference") as color|null + if(new_eyes) + eye_color = sanitize_hexcolor(new_eyes) + + if("species") + + var/result = input(user, "Select a species", "Species Selection") as null|anything in roundstart_species + + if(result) + var/newtype = roundstart_species[result] + pref_species = new newtype() + //Now that we changed our species, we must verify that the mutant colour is still allowed. + var/temp_hsv = RGBtoHSV(features["mcolor"]) + if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.specflags) && ReadHSV(temp_hsv)[3] < ReadHSV("#7F7F7F")[3])) + features["mcolor"] = pref_species.default_color + if("mutant_color") + var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference") as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + if(new_mutantcolor == "#000000") + features["mcolor"] = pref_species.default_color + else if((MUTCOLORS_PARTSONLY in pref_species.specflags) || ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright, but only if they affect the skin + features["mcolor"] = sanitize_hexcolor(new_mutantcolor) + else + user << "Invalid color. Your color is not bright enough." + + if("tail_lizard") + var/new_tail + new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in tails_list_lizard + if(new_tail) + features["tail_lizard"] = new_tail + + if("tail_human") + var/new_tail + new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in tails_list_human + if(new_tail) + features["tail_human"] = new_tail + + if("snout") + var/new_snout + new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in snouts_list + if(new_snout) + features["snout"] = new_snout + + if("horns") + var/new_horns + new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in horns_list + if(new_horns) + features["horns"] = new_horns + + if("ears") + var/new_ears + new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in ears_list + if(new_ears) + features["ears"] = new_ears + + if("frills") + var/new_frills + new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in frills_list + if(new_frills) + features["frills"] = new_frills + + if("spines") + var/new_spines + new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in spines_list + if(new_spines) + features["spines"] = new_spines + + if("body_markings") + var/new_body_markings + new_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in body_markings_list + if(new_body_markings) + features["body_markings"] = new_body_markings + + if("s_tone") + var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in skin_tones + if(new_s_tone) + skin_tone = new_s_tone + + if("ooccolor") + var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference") as color|null + if(new_ooccolor) + ooccolor = sanitize_ooccolor(new_ooccolor) + + if("bag") + var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist + if(new_backbag) + backbag = backbaglist.Find(new_backbag) + + if("clown_name") + var/new_clown_name = reject_bad_name( input(user, "Choose your character's clown name:", "Character Preference") as text|null ) + if(new_clown_name) + custom_names["clown"] = new_clown_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + + if("mime_name") + var/new_mime_name = reject_bad_name( input(user, "Choose your character's mime name:", "Character Preference") as text|null ) + if(new_mime_name) + custom_names["mime"] = new_mime_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + + if("ai_name") + var/new_ai_name = reject_bad_name( input(user, "Choose your character's AI name:", "Character Preference") as text|null, 1 ) + if(new_ai_name) + custom_names["ai"] = new_ai_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, 0-9, -, ' and ." + + if("cyborg_name") + var/new_cyborg_name = reject_bad_name( input(user, "Choose your character's cyborg name:", "Character Preference") as text|null, 1 ) + if(new_cyborg_name) + custom_names["cyborg"] = new_cyborg_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, 0-9, -, ' and ." + + if("religion_name") + var/new_religion_name = reject_bad_name( input(user, "Choose your character's religion:", "Character Preference") as text|null ) + if(new_religion_name) + custom_names["religion"] = new_religion_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + + if("deity_name") + var/new_deity_name = reject_bad_name( input(user, "Choose your character's deity:", "Character Preference") as text|null ) + if(new_deity_name) + custom_names["deity"] = new_deity_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + if ("preferred_map") + var/maplist = list() + var/default = "Default" + if (config.defaultmap) + default += " ([config.defaultmap.friendlyname])" + for (var/M in config.maplist) + var/datum/votablemap/VM = config.maplist[M] + var/friendlyname = "[VM.friendlyname] " + if (VM.voteweight <= 0) + friendlyname += " (disabled)" + maplist[friendlyname] = VM.name + maplist[default] = null + var/pickedmap = input(user, "Choose your preferred map. This will be used to help weight random map selection.", "Character Preference") as null|anything in maplist + if (pickedmap) + preferred_map = maplist[pickedmap] + + + else + switch(href_list["preference"]) + if("publicity") + if(unlock_content) + toggles ^= MEMBER_PUBLIC + if("gender") + if(gender == MALE) + gender = FEMALE + else + gender = MALE + underwear = random_underwear(gender) + undershirt = random_undershirt(gender) + socks = random_socks(gender) + facial_hair_style = random_facial_hair_style(gender) + hair_style = random_hair_style(gender) + + if("ui") + switch(UI_style) + if("Midnight") + UI_style = "Plasmafire" + if("Plasmafire") + UI_style = "Retro" + else + UI_style = "Midnight" + + if("nanoui") + nanoui_fancy = !nanoui_fancy + + if("hear_adminhelps") + toggles ^= SOUND_ADMINHELP + if("announce_login") + toggles ^= ANNOUNCE_LOGIN + + if("be_special") + var/be_special_type = href_list["be_special_type"] + if(be_special_type in be_special) + be_special -= be_special_type + else + be_special += be_special_type + + if("name") + be_random_name = !be_random_name + + if("all") + be_random_body = !be_random_body + + if("hear_midis") + toggles ^= SOUND_MIDI + + if("lobby_music") + toggles ^= SOUND_LOBBY + if(toggles & SOUND_LOBBY) + user << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) + else + user.stopLobbySound() + + if("ghost_ears") + chat_toggles ^= CHAT_GHOSTEARS + + if("ghost_sight") + chat_toggles ^= CHAT_GHOSTSIGHT + + if("ghost_whispers") + chat_toggles ^= CHAT_GHOSTWHISPER + + if("ghost_radio") + chat_toggles ^= CHAT_GHOSTRADIO + + if("ghost_pda") + chat_toggles ^= CHAT_GHOSTPDA + + if("pull_requests") + chat_toggles ^= CHAT_PULLR + + if("allow_midround_antag") + toggles ^= MIDROUND_ANTAG + + if("save") + save_preferences() + save_character() + + if("load") + load_preferences() + load_character() + + if("changeslot") + if(!load_character(text2num(href_list["num"]))) + random_character() + real_name = random_unique_name(gender) + save_character() + + if("tab") + if (href_list["tab"]) + current_tab = text2num(href_list["tab"]) + + ShowChoices(user) + return 1 + +/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1) + if(be_random_name) + real_name = pref_species.random_name(gender) + + if(be_random_body) + random_character(gender) + + if(config.humans_need_surnames) + var/firstspace = findtext(real_name, " ") + var/name_length = length(real_name) + if(!firstspace) //we need a surname + real_name += " [pick(last_names)]" + else if(firstspace == name_length) + real_name += "[pick(last_names)]" + + character.real_name = real_name + character.name = character.real_name + + character.gender = gender + character.age = age + + character.eye_color = eye_color + character.hair_color = hair_color + character.facial_hair_color = facial_hair_color + + character.skin_tone = skin_tone + character.hair_style = hair_style + character.facial_hair_style = facial_hair_style + character.underwear = underwear + character.undershirt = undershirt + character.socks = socks + + character.backbag = backbag + + character.dna.blood_type = blood_type + character.dna.features = features + character.dna.features_buffer = features.Copy() + character.dna.species.mutant_bodyparts_buffer = character.dna.species.mutant_bodyparts.Copy() + character.dna.real_name = character.real_name + var/datum/species/chosen_species + if(pref_species != /datum/species/human && config.mutant_races) + chosen_species = pref_species.type + else + chosen_species = /datum/species/human + character.set_species(chosen_species, icon_update=0) + + if(icon_updates) + character.update_body() + character.update_hair() + character.update_mutcolor() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 5abcbd7b972..b5d4f5c11f3 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -178,6 +178,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["chat_toggles"] >> chat_toggles S["toggles"] >> toggles S["ghost_form"] >> ghost_form + S["ghost_orbit"] >> ghost_orbit S["preferred_map"] >> preferred_map S["ignoring"] >> ignoring @@ -194,6 +195,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot)) toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) ghost_form = sanitize_inlist(ghost_form, ghost_forms, initial(ghost_form)) + ghost_orbit = sanitize_inlist(ghost_orbit, ghost_orbits, initial(ghost_orbit)) return 1 @@ -215,6 +217,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["toggles"] << toggles S["chat_toggles"] << chat_toggles S["ghost_form"] << ghost_form + S["ghost_orbit"] << ghost_orbit S["preferred_map"] << preferred_map S["ignoring"] << ignoring diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 4f944500504..0b62d0a289d 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -205,7 +205,7 @@ src.ambience_playing = 0 feedback_add_details("admin_verb", "SAmbi") //If you are copy-pasting this, I bet you read this comment expecting to see the same thing :^) -var/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \ +var/global/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \ "ghost_blue","ghost_yellow","ghost_green","ghost_pink", \ "ghost_cyan","ghost_dblue","ghost_dred","ghost_dgreen", \ "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink", "ghost_purpleswirl","ghost_funkypurp","ghost_pinksherbert","ghost_blazeit",\ @@ -222,6 +222,22 @@ var/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_ if(istype(mob,/mob/dead/observer)) mob.icon_state = new_form +var/global/list/ghost_orbits = list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOST_ORBIT_SQUARE,GHOST_ORBIT_HEXAGON,GHOST_ORBIT_PENTAGON) + +/client/verb/pick_ghost_orbit() + set name = "Choose Ghost Orbit" + set category = "Preferences" + set desc = "Choose your preferred ghostly orbit." + if(!is_content_unlocked()) + return + var/new_orbit = input(src, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND",null) as null|anything in ghost_orbits + if(new_orbit) + prefs.ghost_orbit = new_orbit + prefs.save_preferences() + if(istype(mob, /mob/dead/observer)) + var/mob/dead/observer/O = mob + O.ghost_orbit = new_orbit + /client/verb/toggle_intent_style() set name = "Toggle Intent Selection Style" set category = "Preferences" diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 9e228e9befe..8dd3f56aeab 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -105,7 +105,7 @@ /obj/item/clothing/head/rabbitears name = "rabbit ears" - desc = "Wearing these makes you looks useless, and only good for your sex appeal." + desc = "Wearing these makes you look useless, and only good for your sex appeal." icon_state = "bunny" /obj/item/clothing/head/flatcap @@ -240,4 +240,9 @@ /obj/item/clothing/head/rice_hat name = "rice hat" desc = "Welcome to the rice fields, motherfucker." - icon_state = "rice_hat" \ No newline at end of file + icon_state = "rice_hat" + +/obj/item/clothing/head/lizard + name = "lizardskin cloche hat" + desc = "How many lizards died to make this hat? Not enough." + icon_state = "lizard" diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index c7f42350d07..40d77f12752 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -200,10 +200,6 @@ return 0 - - - - /obj/item/clothing/suit/armor/reactive/stealth name = "reactive stealth armor" @@ -221,10 +217,21 @@ owner.alpha = initial(owner.alpha) return 1 +/obj/item/clothing/suit/armor/reactive/tesla + name = "reactive tesla armor" - - - +/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, attack_text) + if(!active) + return 0 + if(prob(hit_reaction_chance)) + owner.visible_message("The [src] blocks the [attack_text], sending out arcs of lightning!") + for(var/mob/living/M in view(6, owner)) + if(M == owner) + continue + owner.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5) + M.adjustFireLoss(25) + playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1) + return 1 //All of the armor below is mostly unused diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 2655699220b..5e03c3db4e4 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -81,6 +81,22 @@ parts = list(/obj/item/weapon/stock_parts/cell = 1) category = CAT_WEAPON +/datum/table_recipe/tailclub + name = "Tail Club" + result = /obj/item/weapon/tailclub + reqs = list(/obj/item/organ/severedtail = 1, + /obj/item/stack/sheet/metal = 1) + time = 80 + category = CAT_WEAPON + +/datum/table_recipe/tailwhip + name = "Liz O' Nine Tails" + result = /obj/item/weapon/melee/chainofcommand/tailwhip + reqs = list(/obj/item/organ/severedtail = 1, + /obj/item/stack/cable_coil = 1) + time = 80 + category = CAT_WEAPON + /datum/table_recipe/ed209 name = "ED209" result = /mob/living/simple_animal/bot/ed209 @@ -261,3 +277,15 @@ /datum/reagent/water/holywater = 10) parts = list(/obj/item/device/camera = 1) category = CAT_MISC + +/datum/table_recipe/lizardhat + name = "Lizard Cloche Hat" + result = /obj/item/clothing/head/lizard + time = 20 + reqs = list(/obj/item/organ/severedtail = 1) + +/datum/table_recipe/lizardhat_alternate + name = "Lizard Cloche Hat" + result = /obj/item/clothing/head/lizard + time = 20 + reqs = list(/obj/item/stack/sheet/animalhide/lizard = 1) diff --git a/code/modules/food&drinks/food/snacks_meat.dm b/code/modules/food&drinks/food/snacks_meat.dm index dc10ed81e25..b007d4c43d4 100644 --- a/code/modules/food&drinks/food/snacks_meat.dm +++ b/code/modules/food&drinks/food/snacks_meat.dm @@ -119,6 +119,11 @@ desc = "Vegan meat, on a stick." bonus_reagents = list("nutriment" = 1) +/obj/item/weapon/reagent_containers/food/snacks/kebab/tail + name = "lizard-tail kebab" + desc = "Severed lizard tail on a stick." + bonus_reagents = list("nutriment" = 1, "vitamin" = 4) + /obj/item/weapon/reagent_containers/food/snacks/monkeycube name = "monkey cube" desc = "Just add water!" diff --git a/code/modules/food&drinks/recipes/tablecraft/recipes_meat.dm b/code/modules/food&drinks/recipes/tablecraft/recipes_meat.dm index fdf6bba6915..d37dff01d5d 100644 --- a/code/modules/food&drinks/recipes/tablecraft/recipes_meat.dm +++ b/code/modules/food&drinks/recipes/tablecraft/recipes_meat.dm @@ -29,6 +29,15 @@ result = /obj/item/weapon/reagent_containers/food/snacks/kebab/tofu category = CAT_FOOD +/datum/table_recipe/tailkebab + name = "Lizard tail kebab" + reqs = list( + /obj/item/stack/rods = 1, + /obj/item/organ/severedtail = 1 + ) + result = /obj/item/weapon/reagent_containers/food/snacks/kebab/tail + category = CAT_FOOD + // see code/module/crafting/table.dm ////////////////////////////////////////////////FISH//////////////////////////////////////////////// diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index 76dac151c11..5a97bdceed7 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -8,6 +8,7 @@ icon_state = client.prefs.ghost_form if (ghostimage) ghostimage.icon_state = src.icon_state + ghost_orbit = client.prefs.ghost_orbit updateghostimages() diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 350ea9720d0..413ea9a4ae7 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -24,6 +24,7 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi var/seedarkness = 1 var/ghost_hud_enabled = 1 //did this ghost disable the on-screen HUD? var/data_hud_seen = 0 //this should one of the defines in __DEFINES/hud.dm + var/ghost_orbit = GHOST_ORBIT_CIRCLE /mob/dead/observer/New(mob/body) sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF @@ -225,7 +226,21 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(orbiting != target) src << "Now orbiting [target]." - orbit(target,orbitsize,0) + var/rot_seg + + switch(ghost_orbit) + if(GHOST_ORBIT_TRIANGLE) + rot_seg = 3 + if(GHOST_ORBIT_SQUARE) + rot_seg = 4 + if(GHOST_ORBIT_PENTAGON) + rot_seg = 5 + if(GHOST_ORBIT_HEXAGON) + rot_seg = 6 + else //Circular + rot_seg = 36 //360/10 bby, smooth enough aproximation of a circle + + orbit(target,orbitsize, FALSE, 20, rot_seg) /mob/dead/observer/orbit() ..() diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm index 0b336378dd4..dcdee906810 100644 --- a/code/modules/mob/living/bloodcrawl.dm +++ b/code/modules/mob/living/bloodcrawl.dm @@ -9,6 +9,8 @@ density = 0 anchored = 1 invisibility = 60 + burn_state = LAVA_PROOF + obj/effect/dummy/slaughter/relaymove(mob/user, direction) if (!src.canmove || !direction) return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 17afa3091b4..916587af53a 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -676,6 +676,8 @@ else facial_hair_style = "Shaved" hair_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") + dna.species.mutant_bodyparts = dna.species.mutant_bodyparts_buffer.Copy() + dna.features = dna.features_buffer.Copy() underwear = "Nude" update_body() update_hair() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index a2df6aee39e..6c3687c15e6 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -42,6 +42,7 @@ var/say_mod = "says" // affects the speech message var/list/default_features = list() // Default mutant bodyparts for this species. Don't forget to set one for every mutant bodypart you allow this species to have. var/list/mutant_bodyparts = list() // Parts of the body that are diferent enough from the standard human model that they cause clipping with some equipment + var/list/mutant_bodyparts_buffer = list() // A copy of mutant_bodyparts() that allows cloned people to keep their snowflake bodyparts upon cloning, should they be changed 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. @@ -380,9 +381,9 @@ var/icon_string if(S.gender_specific) - icon_string = "[id]_[g]_[bodypart]_[S.icon_state]_[layer]" + icon_string = "[g]_[bodypart]_[S.icon_state]_[layer]" else - icon_string = "[id]_m_[bodypart]_[S.icon_state]_[layer]" + icon_string = "m_[bodypart]_[S.icon_state]_[layer]" I = image("icon" = 'icons/mob/mutant_bodyparts.dmi', "icon_state" = icon_string, "layer" =- layer) @@ -406,9 +407,9 @@ if(S.hasinner) if(S.gender_specific) - icon_string = "[id]_[g]_[bodypart]inner_[S.icon_state]_[layer]" + icon_string = "[g]_[bodypart]inner_[S.icon_state]_[layer]" else - icon_string = "[id]_m_[bodypart]inner_[S.icon_state]_[layer]" + icon_string = "m_[bodypart]inner_[S.icon_state]_[layer]" I = image("icon" = 'icons/mob/mutant_bodyparts.dmi', "icon_state" = icon_string, "layer" =- layer) diff --git a/code/modules/mob/living/simple_animal/hostile/illusion.dm b/code/modules/mob/living/simple_animal/hostile/illusion.dm index 7518f55e1da..b16ef6d9207 100644 --- a/code/modules/mob/living/simple_animal/hostile/illusion.dm +++ b/code/modules/mob/living/simple_animal/hostile/illusion.dm @@ -8,12 +8,14 @@ melee_damage_lower = 5 melee_damage_upper = 5 a_intent = "harm" + attacktext = "gores" maxHealth = 100 health = 100 speed = 0 faction = list("illusion") var/life_span = INFINITY //how long until they despawn var/mob/living/parent_mob + var/multiply_chance = 0 //if we multiply on hit /mob/living/simple_animal/hostile/illusion/Life() @@ -22,11 +24,15 @@ death() -/mob/living/simple_animal/hostile/illusion/proc/Copy_Parent(mob/living/original, life = 50) +/mob/living/simple_animal/hostile/illusion/proc/Copy_Parent(mob/living/original, life = 50, health = 100, damage = 0, replicate = 0 ) appearance = original.appearance parent_mob = original dir = original.dir - life_span = world.time+life //5 seconds + life_span = world.time+life + melee_damage_lower = damage + melee_damage_upper = damage + multiply_chance = replicate + faction -= "neutral" /mob/living/simple_animal/hostile/illusion/death() @@ -42,6 +48,17 @@ return ..() +/mob/living/simple_animal/hostile/illusion/AttackingTarget() + ..() + if(istype(target, /mob/living) && prob(multiply_chance)) + var/mob/living/L = target + if(L.stat == DEAD) + return + var/mob/living/simple_animal/hostile/illusion/M = new(loc) + M.faction = faction.Copy() + M.Copy_Parent(parent_mob, life_span, health/2, melee_damage_upper, multiply_chance) + M.GiveTarget(L) + ///////Actual Types///////// /mob/living/simple_animal/hostile/illusion/escape diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 04b17c1e4d7..e9dda2cb13b 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -26,6 +26,7 @@ var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/last_warning var/consumedSupermatter = 0 //If the singularity has eaten a supermatter shard and can go to stage six + burn_state = LAVA_PROOF /obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0) //CARN: admin-alert for chuckle-fuckery. diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index f14886328c1..8c9d07d2a77 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -131,4 +131,26 @@ var/mob/living/carbon/human/H = target H.drip(100) - return ..() \ No newline at end of file + return ..() + + +//penetrator ammo +/obj/item/ammo_box/magazine/sniper_rounds/penetrator + name = "sniper rounds (penetrator)" + desc = "An extremely powerful round capable of passing straight through cover and anyone unfortunate enough to be behind it." + ammo_type = /obj/item/ammo_casing/penetrator + max_ammo = 5 + +/obj/item/ammo_casing/penetrator + desc = "A .50 caliber penetrator round casing." + caliber = ".50" + projectile_type = /obj/item/projectile/bullet/sniper/penetrator + icon_state = ".50" + +/obj/item/projectile/bullet/sniper/penetrator + name = "penetrator round" + damage = 60 + forcedodge = 1 + stun = 0 + weaken = 0 + breakthings = FALSE \ No newline at end of file diff --git a/code/modules/surgery/limb augmentation.dm b/code/modules/surgery/limb augmentation.dm index ee1293db5c5..f84e595c635 100644 --- a/code/modules/surgery/limb augmentation.dm +++ b/code/modules/surgery/limb augmentation.dm @@ -5,7 +5,7 @@ //SURGERY STEPS /datum/surgery_step/replace - name = "sever muscules" + name = "sever muscles" implements = list(/obj/item/weapon/scalpel = 100, /obj/item/weapon/wirecutters = 55) time = 32 diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index 9e231fae5d1..2e931859bd2 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -68,7 +68,12 @@ max_damage = 75 body_part = LEG_RIGHT - +/obj/item/organ/severedtail + name = "tail" + desc = "A severed tail." + icon_state = "severedtail" + color = "#161" + var/markings = "Smooth" //Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all. //Damage will not exceed max_damage using this proc diff --git a/code/modules/surgery/tail_modification.dm b/code/modules/surgery/tail_modification.dm new file mode 100644 index 00000000000..68aa3e4fd47 --- /dev/null +++ b/code/modules/surgery/tail_modification.dm @@ -0,0 +1,73 @@ +// The detachment and attachment of lizard tails +// Dismemberment lite; can/should be generalized aka augs when we get more mutant parts and/or for actual dismemberment + +// TAIL REMOVAL + +/datum/surgery/tail_removal + name = "tail removal" + steps = list(/datum/surgery_step/sever_tail, /datum/surgery_step/close) + species = list(/mob/living/carbon/human) + possible_locs = list("groin") + +/datum/surgery/tail_removal/can_start(mob/user, mob/living/carbon/target) + var/mob/living/carbon/human/L = target + if(("tail_lizard" in L.dna.species.mutant_bodyparts) || ("waggingtail_lizard" in L.dna.species.mutant_bodyparts)) + return 1 + return 0 + +/datum/surgery_step/sever_tail + name = "sever tail" + implements = list(/obj/item/weapon/scalpel = 100, /obj/item/weapon/circular_saw = 100, /obj/item/weapon/melee/energy/sword/cyborg/saw = 100, /obj/item/weapon/melee/arm_blade = 80, /obj/item/weapon/twohanded/required/chainsaw = 80, /obj/item/weapon/mounted_chainsaw = 80, /obj/item/weapon/twohanded/fireaxe = 50, /obj/item/weapon/hatchet = 40, /obj/item/weapon/kitchen/knife/butcher = 25) + time = 64 + +/datum/surgery_step/sever_tail/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] begins to sever [target]'s tail!", "You begin to sever [target]'s tail...") + +/datum/surgery_step/sever_tail/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + var/mob/living/carbon/human/L = target + user.visible_message("[user] severs [L]'s tail!", "You sever [L]'s tail.") + if("tail_lizard" in L.dna.species.mutant_bodyparts) + L.dna.species.mutant_bodyparts -= "tail_lizard" + else if("waggingtail_lizard" in L.dna.species.mutant_bodyparts) + L.dna.species.mutant_bodyparts -= "waggingtail_lizard" + if("spines" in L.dna.features) + L.dna.features -= "spines" + var/obj/item/organ/severedtail/S = new(get_turf(target)) + S.color = "#[L.dna.features["mcolor"]]" + S.markings = "[L.dna.features["tail"]]" + L.update_body() + return 1 + +// TAIL ATTACHMENT + +/datum/surgery/tail_attachment + name = "tail attachment" + steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/replace, /datum/surgery_step/attach_tail, /datum/surgery_step/close) + species = list(/mob/living/carbon/human) + possible_locs = list("groin") + +/datum/surgery/tail_attachment/can_start(mob/user, mob/living/carbon/target) + var/mob/living/carbon/human/L = target + if(!("tail_lizard" in L.dna.species.mutant_bodyparts) && !("waggingtail_lizard" in L.dna.species.mutant_bodyparts)) + return 1 + return 0 + +/datum/surgery_step/attach_tail + name = "attach tail" + implements = list(/obj/item/organ/severedtail = 100) + time = 64 + +/datum/surgery_step/attach_tail/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + user.visible_message("[user] begins to attach a tail to [target]!", "You begin to attach the tail to [target]...") + +/datum/surgery_step/attach_tail/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + var/mob/living/carbon/human/L = target + user.visible_message("[user] gives [L] a tail!", "You give [L] a tail. It adjusts to [L]'s melanin.") // fluff for color + if(!(L.dna.features["mcolor"])) + L.dna.features["mcolor"] = tool.color + var/obj/item/organ/severedtail/T = tool + L.dna.features["tail_lizard"] = T.markings + L.dna.species.mutant_bodyparts += "tail_lizard" + qdel(tool) + L.update_body() + return 1 \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index 8aa95a0808b..bdaf3a102e0 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -83,6 +83,11 @@ +

bgobandit updated:

+

neersighted updated: