diff --git a/_maps/RandomRuins/SpaceRuins/derelict1.dmm b/_maps/RandomRuins/SpaceRuins/derelict1.dmm index 9c1a0d9783..a7a9a32b73 100644 --- a/_maps/RandomRuins/SpaceRuins/derelict1.dmm +++ b/_maps/RandomRuins/SpaceRuins/derelict1.dmm @@ -26,6 +26,7 @@ "g" = ( /obj/structure/alien/weeds, /obj/structure/table_frame, +/obj/item/organ/alien/plasmavessel/small/tiny, /turf/open/floor/plating/airless, /area/ruin/unpowered) "h" = ( @@ -77,9 +78,15 @@ /obj/structure/alien/weeds, /obj/structure/bed/nest, /obj/effect/decal/remains/xeno, +/obj/item/organ/brain/alien, +/turf/open/floor/plating/airless, +/area/ruin/unpowered) +"s" = ( +/obj/structure/alien/weeds, +/obj/effect/decal/remains/xeno, +/obj/item/organ/alien/plasmavessel/small, /turf/open/floor/plating/airless, /area/ruin/unpowered) - (1,1,1) = {" a a @@ -106,7 +113,7 @@ a a a b -b +s b a a diff --git a/_maps/RandomRuins/SpaceRuins/derelict2.dmm b/_maps/RandomRuins/SpaceRuins/derelict2.dmm index c57ac798ac..a20be471f4 100644 --- a/_maps/RandomRuins/SpaceRuins/derelict2.dmm +++ b/_maps/RandomRuins/SpaceRuins/derelict2.dmm @@ -64,12 +64,17 @@ /obj/structure/chair{ dir = 4 }, +/obj/item/clothing/under/polychromic/shirt, +/obj/item/clothing/neck/tie/black, +/obj/item/clothing/shoes/laceup, +/obj/item/storage/wallet/random, +/obj/item/clothing/gloves/color/white, /obj/effect/decal/remains/human, /turf/open/floor/plasteel, /area/ruin/space/has_grav/powered/dinner_for_two) "n" = ( /obj/structure/table, -/obj/item/candle{ +/obj/item/candle/infinite{ pixel_y = 5 }, /obj/item/trash/plate{ @@ -84,6 +89,11 @@ /obj/structure/chair{ dir = 8 }, +/obj/item/clothing/under/polychromic/skirt, +/obj/item/clothing/shoes/laceup, +/obj/item/clothing/gloves/color/white, +/obj/item/clothing/glasses/regular, +/obj/item/lipstick/random, /obj/effect/decal/remains/human, /turf/open/floor/plasteel, /area/ruin/space/has_grav/powered/dinner_for_two) diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index c4da3f1e32..053136a434 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -11448,12 +11448,6 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) -"aAq" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/fore) "aAr" = ( /obj/structure/closet, /obj/effect/decal/cleanable/cobweb, @@ -11963,13 +11957,6 @@ /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plating, /area/maintenance/starboard/fore) -"aBD" = ( -/obj/machinery/meter, -/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ - dir = 8 - }, -/turf/open/floor/plating, -/area/maintenance/starboard/fore) "aBE" = ( /obj/item/clothing/under/rank/mailman, /obj/item/clothing/head/mailman, @@ -12352,10 +12339,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/crew_quarters/fitness) -"aCx" = ( -/obj/machinery/atmospherics/components/binary/valve, -/turf/open/floor/plating, -/area/maintenance/starboard/fore) "aCy" = ( /obj/effect/decal/cleanable/oil, /turf/open/floor/plating, @@ -12961,10 +12944,8 @@ /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet) "aDV" = ( +/obj/machinery/atmospherics/pipe/manifold/supply/hidden, /obj/machinery/meter, -/obj/machinery/atmospherics/pipe/simple/supply/hidden{ - dir = 5 - }, /turf/open/floor/plating, /area/maintenance/starboard/fore) "aDW" = ( @@ -56758,6 +56739,12 @@ }, /turf/open/floor/wood, /area/maintenance/bar) +"gOZ" = ( +/obj/machinery/door/airlock/maintenance{ + req_access_txt = "12" + }, +/turf/open/floor/plating, +/area/crew_quarters/fitness) "gWd" = ( /obj/structure/cable{ icon_state = "1-4" @@ -56878,6 +56865,12 @@ /obj/machinery/rnd/production/techfab/department/cargo, /turf/open/floor/plasteel, /area/quartermaster/office) +"jnR" = ( +/obj/machinery/atmospherics/components/binary/valve{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/fore) "jqv" = ( /obj/structure/chair/wood/normal{ dir = 1 @@ -57260,6 +57253,12 @@ /obj/item/reagent_containers/food/drinks/beer, /turf/open/floor/plating, /area/maintenance/starboard/aft) +"rsp" = ( +/obj/machinery/atmospherics/components/unary/tank/air{ + dir = 4 + }, +/turf/open/floor/plating, +/area/maintenance/starboard/fore) "rBq" = ( /obj/item/clothing/head/kitty, /obj/item/clothing/under/maid, @@ -57561,6 +57560,13 @@ }, /turf/open/floor/wood, /area/maintenance/bar) +"vpY" = ( +/obj/machinery/atmospherics/pipe/simple/supply/hidden{ + dir = 10 + }, +/obj/machinery/meter, +/turf/open/floor/plating, +/area/maintenance/starboard/fore) "vxh" = ( /obj/structure/table, /obj/effect/spawner/lootdrop/maintenance{ @@ -96101,12 +96107,12 @@ arj auB auB arj -arj +gOZ arj anf anf -anf -awD +rsp +rsp alP aGB aIf @@ -96355,14 +96361,14 @@ aaa aaa aaf aaa -aaa -aaf -aaa -aaa +gXs +aoV alP -ayf -aBD -aCx +anf +anf +anf +anf +aDW aDV alP aGL @@ -96612,15 +96618,15 @@ aaa aaa aaf aaa -aaa -aaf -aaa -aaa +gXs +aoV alP -aAq -aAq +awD +anf +anf +anf aCy -aCG +jnR alP aGL avI @@ -96877,7 +96883,7 @@ alP alP alP alP -aDW +vpY aFn aGP avI diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 14d16fe659..d005f1eb40 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -4696,7 +4696,7 @@ }, /area/abductor_ship) "lI" = ( -/turf/open/space/transit, +/turf/open/space/transit/centcom, /area/space) "lJ" = ( /obj/machinery/door/airlock/centcom{ @@ -20511,7 +20511,7 @@ fX fX fX fX -fY +fX fX fX fX @@ -21282,7 +21282,7 @@ fX fX fX fX -fX +fY fX fX fX diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 9f3e6b4db0..aea7d42be6 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -97,6 +97,7 @@ #define NO_DNA_COPY 14 #define DRINKSBLOOD 15 #define NOEYES 16 +#define MARKINGS 17 #define ORGAN_SLOT_BRAIN "brain" #define ORGAN_SLOT_APPENDIX "appendix" diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 21024e78f7..e04639baf2 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -38,7 +38,7 @@ #define R_DEFAULT R_AUTOLOGIN -#define R_EVERYTHING (1<<15)-1 //the sum of all other rank permissions, used for +EVERYTHING +#define R_EVERYTHING ALL //the sum of all other rank permissions, used for +EVERYTHING #define ADMIN_QUE(user) "(?)" #define ADMIN_FLW(user) "(FLW)" diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index f642791224..c7daff49ed 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -93,6 +93,7 @@ #define MUTCOLORS3 36 #define NOAROUSAL 37 //Stops all arousal effects #define NOGENITALS 38 //Cannot create, use, or otherwise have genitals +#define MATRIXED 39 //if icon is color matrix'd //Citadel istypes #define isborer(A) (istype(A, /mob/living/simple_animal/borer)) diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 9a29829c2b..15e8048926 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -97,6 +97,20 @@ //the define for visible message range in combat #define COMBAT_MESSAGE_RANGE 3 +//Shove knockdown lengths (deciseconds) +#define SHOVE_KNOCKDOWN_SOLID 30 +#define SHOVE_KNOCKDOWN_HUMAN 30 +#define SHOVE_KNOCKDOWN_TABLE 30 +#define SHOVE_KNOCKDOWN_COLLATERAL 10 +//Shove slowdown +#define SHOVE_SLOWDOWN_ID "shove_slowdown" +#define SHOVE_SLOWDOWN_LENGTH 30 +#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier +//Shove disarming item list +GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( + /obj/item/gun))) + + //Combat object defines //Embedded objects @@ -118,6 +132,10 @@ #define TRIGGER_GUARD_ALLOW_ALL -1 #define TRIGGER_GUARD_NONE 0 #define TRIGGER_GUARD_NORMAL 1 +//E-gun self-recharge values +#define EGUN_NO_SELFCHARGE 0 +#define EGUN_SELFCHARGE 1 +#define EGUN_SELFCHARGE_BORG 2 //Object/Item sharpness #define IS_BLUNT 0 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 7301284ee4..709a4daeba 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -51,10 +51,11 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s //Human Overlays Indexes///////// //LOTS OF CIT CHANGES HERE. BE CAREFUL WHEN UPSTREAM ADDS MORE LAYERS -#define MUTATIONS_LAYER 30 //mutations. Tk headglows, cold resistance glow, etc -#define GENITALS_BEHIND_LAYER 29 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer -#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts -#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag +#define MUTATIONS_LAYER 31 //mutations. Tk headglows, cold resistance glow, etc +#define GENITALS_BEHIND_LAYER 30 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer +#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts +#define BODYPARTS_LAYER 28 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag +#define MARKING_LAYER 27 //Matrixed body markings because clashing with snouts? #define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts #define GENITALS_ADJ_LAYER 25 #define BODY_LAYER 24 //underwear, undershirts, socks, eyes, lips(makeup) @@ -82,7 +83,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define HANDS_LAYER 3 #define BODY_FRONT_LAYER 2 #define FIRE_LAYER 1 //If you're on fire -#define TOTAL_LAYERS 30 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 31 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; //Human Overlay Index Shortcuts for alternate_worn_layer, layers //Because I *KNOW* somebody will think layer+1 means "above" diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 76f66521a7..e6d4fd126b 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -25,6 +25,7 @@ #define NOBLUDGEON (1<<7) // when an item has this it produces no "X has been hit by Y with Z" message in the default attackby() #define NODROP (1<<8) // This flag makes it so that an item literally cannot be removed at all, or at least that's how it should be. Only deleted. #define ABSTRACT (1<<9) // for all things that are technically items but used for various different stuff +#define IMMUTABLE_SLOW (1<<10) //When players should not be able to change the slowdown of the item (Speed potions, ect) // Flags for the clothing_flags var on /obj/item/clothing diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index c8a583a55e..36ecebb699 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -35,7 +35,7 @@ #define TRANSIT_REQUEST 1 #define TRANSIT_READY 2 -#define SHUTTLE_TRANSIT_BORDER 8 +#define SHUTTLE_TRANSIT_BORDER 10 #define PARALLAX_LOOP_TIME 25 #define HYPERSPACE_END_TIME 5 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 2455d373ab..a5617e6148 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -57,6 +57,7 @@ #define TRAIT_HEAVY_SLEEPER "heavy_sleeper" #define TRAIT_NIGHT_VISION "night_vision" #define TRAIT_LIGHT_STEP "light_step" +#define TRAIT_SPEEDY_STEP "speedy_step" #define TRAIT_SPIRITUAL "spiritual" #define TRAIT_VORACIOUS "voracious" #define TRAIT_SELF_AWARE "self_aware" @@ -90,4 +91,4 @@ #define STASIS_MUTE "stasis" #define GENETICS_SPELL "genetics_spell" #define EYES_COVERED "eyes_covered" -#define CULT_EYES "cult_eyes" \ No newline at end of file +#define CULT_EYES "cult_eyes" diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index 9e38d9cf1e..b6c968b163 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -37,6 +37,7 @@ GLOBAL_LIST_EMPTY(mam_ears_list) GLOBAL_LIST_EMPTY(mam_tails_list) GLOBAL_LIST_EMPTY(mam_tails_animated_list) GLOBAL_LIST_EMPTY(taur_list) +GLOBAL_LIST_EMPTY(mam_snouts_list) //Exotic Species GLOBAL_LIST_EMPTY(exotic_tails_list) @@ -242,7 +243,7 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) if("Wolf") hdna.features["mam_tail"] = "Wolf" hdna.features["mam_ears"] = "Wolf" - hdna.features["snout"] = "Wolf" + hdna.features["mam_snouts"] = "Wolf" hdna.features["mam_body_markings"] = "Wolf" hdna.features["mcolor"] = "555" hdna.features["mcolor2"] = "999" @@ -250,7 +251,7 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) if("Fox") hdna.features["mam_tail"] = "Fox" hdna.features["mam_ears"] = "Fox" - hdna.features["snout"] = "Fox, Long" + hdna.features["mam_snouts"] = "Fox, Long" hdna.features["mam_body_markings"] = "Fox" hdna.features["mcolor"] = "f60" hdna.features["mcolor2"] = "fff" @@ -258,6 +259,6 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) if("Fennec") hdna.features["mam_tail"] = "Fennec" hdna.features["mam_ears"] = "Fennec" - hdna.features["snout"] = "Fox, Short" + hdna.features["mam_snouts"] = "Fox, Short" hdna.features["mam_body_markings"] = "Fox" H.regenerate_icons() diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index c590c844eb..7d578337bc 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -511,6 +511,13 @@ var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems) announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common +/proc/GetHexColors(const/hexa) + return list( + GetRedPart(hexa)/ 255, + GetGreenPart(hexa)/ 255, + GetBluePart(hexa)/ 255 + ) + /proc/GetRedPart(const/hexa) return hex2num(copytext(hexa, 2, 4)) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 4a7f2fdbc1..f6ef08fe0d 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -37,13 +37,9 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list) - //avian bodyparts (i swear this isn't starbound) -// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list) -// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list) -// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list) -// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list) //xeno parts (hiss?) init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index d2cb3baa6a..5fb64004c0 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -712,7 +712,19 @@ world var/static/icon/flat_template = icon('icons/effects/effects.dmi', "nothing") #define BLANK icon(flat_template) - #define SET_SELF(SETVAR) var/icon/SELF_ICON=icon(icon(curicon, curstate, base_icon_dir),"",SOUTH,no_anim?1:null);if(A.alpha<255)SELF_ICON.Blend(rgb(255,255,255,A.alpha),ICON_MULTIPLY);if(A.color)SELF_ICON.Blend(A.color,ICON_MULTIPLY);;##SETVAR=SELF_ICON; + #define SET_SELF(SETVAR) do { \ + var/icon/SELF_ICON=icon(icon(curicon, curstate, base_icon_dir),"",SOUTH,no_anim?1:null); \ + if(A.alpha<255) { \ + SELF_ICON.Blend(rgb(255,255,255,A.alpha),ICON_MULTIPLY);\ + } \ + if(A.color) { \ + if(islist(A.color)){ \ + SELF_ICON.MapColors(arglist(A.color))} \ + else{ \ + SELF_ICON.Blend(A.color,ICON_MULTIPLY)} \ + } \ + ##SETVAR=SELF_ICON;\ + } while (0) #define INDEX_X_LOW 1 #define INDEX_X_HIGH 2 @@ -860,7 +872,11 @@ world flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1) if(A.color) - flat.Blend(A.color, ICON_MULTIPLY) + if(islist(A.color)) + flat.MapColors(arglist(A.color)) + else + flat.Blend(A.color, ICON_MULTIPLY) + if(A.alpha < 255) flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 92132b092e..eff6f54653 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -91,6 +91,8 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list) if(!GLOB.mam_ears_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list) + if(!GLOB.mam_snouts_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list) // if(ishuman(src)) // var/mob/living/carbon/human/H = src @@ -113,11 +115,11 @@ "mcolor2" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), "mcolor3" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), "tail_lizard" = pick(GLOB.tails_list_lizard), - "tail_human" = "None", + "tail_human" = pick(GLOB.tails_list_human), "wings" = "None", "snout" = pick(GLOB.snouts_list), "horns" = pick(GLOB.horns_list), - "ears" = "None", + "ears" = pick(GLOB.ears_list), "frills" = pick(GLOB.frills_list), "spines" = pick(GLOB.spines_list), "body_markings" = pick(GLOB.body_markings_list), @@ -127,6 +129,7 @@ "taur" = "None", "mam_body_markings" = pick(GLOB.mam_body_markings_list), "mam_ears" = pick(GLOB.mam_ears_list), + "mam_snouts" = pick(GLOB.mam_snouts_list), "mam_tail" = pick(GLOB.mam_tails_list), "mam_tail_animated" = "None", "xenodorsal" = "Standard", diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index c3b7a6bfed..165cea9557 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -192,7 +192,9 @@ //Set news report and mode result mode.set_round_result() - send2irc("Server", "Round just ended.") + var/survival_rate = GLOB.joined_player_list.len ? "[PERCENT(popcount[POPCOUNT_SURVIVORS]/GLOB.joined_player_list.len)]%" : "there's literally no player" + + send2irc("Server", "A round of [mode.name] just ended[mode_result == "undefined" ? "." : " with a [mode_result]."] Survival rate: [survival_rate]") if(length(CONFIG_GET(keyed_list/cross_server))) send_news_report() @@ -583,4 +585,4 @@ qdel(query_update_everything_ranks) return qdel(query_update_everything_ranks) - qdel(query_check_everything_ranks) \ No newline at end of file + qdel(query_check_everything_ranks) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index e569996998..c883254afe 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -6,6 +6,8 @@ GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb. GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys, for stealthmins +GLOBAL_LIST_EMPTY(bunker_passthrough) + //Since it didn't really belong in any other category, I'm putting this here //This is for procs to replace all the goddamn 'in world's that are chilling around the code diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 355b46850b..d23d0905e9 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -125,8 +125,12 @@ if(prob(33)) I.add_mob_blood(src) var/turf/location = get_turf(src) - add_splatter_floor(location) - if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood + if(iscarbon(src)) + var/mob/living/carbon/C = src + C.bleed(totitemdamage) + else + add_splatter_floor(location) + if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood user.add_mob_blood(src) return TRUE //successful attack @@ -163,4 +167,7 @@ attack_message = "[user] has [message_verb] [src][message_hit_area] with [I]!" visible_message("[attack_message]",\ "[attack_message]", null, COMBAT_MESSAGE_RANGE) + if(hit_area == BODY_ZONE_HEAD) + if(prob(2)) + playsound(src, 'sound/weapons/dink.ogg', 30, 1) return 1 diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index f216b025f8..4cd317318f 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -62,6 +62,8 @@ /datum/config_entry/flag/allow_ai // allow ai job +/datum/config_entry/flag/allow_ai_multicam //whether the AI can use their multicam + /datum/config_entry/flag/disable_human_mood /datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen. diff --git a/code/controllers/subsystem/air_turfs.dm b/code/controllers/subsystem/air_turfs.dm index 96e6e05f6f..2902940bf9 100644 --- a/code/controllers/subsystem/air_turfs.dm +++ b/code/controllers/subsystem/air_turfs.dm @@ -4,7 +4,7 @@ SUBSYSTEM_DEF(air_turfs) name = "Atmospherics - Turfs" init_order = INIT_ORDER_AIR_TURFS priority = FIRE_PRIORITY_AIR_TURFS - wait = 1 + wait = 2 flags = SS_BACKGROUND runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/currentrun = list() diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 9b70cb9117..a2c60618ac 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -435,11 +435,13 @@ GLOBAL_LIST_EMPTY(the_station_areas) GLOB.the_gateway.awaygate = new_gate GLOB.the_gateway.wait = world.time -/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) +/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override, border_type_override) UNTIL(initialized && !clearing_reserved_turfs) var/datum/turf_reservation/reserve = new type if(turf_type_override) reserve.turf_type = turf_type_override + if(border_type_override) + reserve.borderturf = border_type_override if(!z) for(var/i in levels_by_trait(ZTRAIT_RESERVED)) if(reserve.Reserve(width, height, i)) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 8402a0150e..e2e7c3d327 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -443,17 +443,22 @@ SUBSYSTEM_DEF(shuttle) */ var/transit_path = /turf/open/space/transit + var/border_path = /turf/open/space/transit/border switch(travel_dir) if(NORTH) transit_path = /turf/open/space/transit/north + border_path = /turf/open/space/transit/border/north if(SOUTH) transit_path = /turf/open/space/transit/south + border_path = /turf/open/space/transit/border/south if(EAST) transit_path = /turf/open/space/transit/east + border_path = /turf/open/space/transit/border/east if(WEST) transit_path = /turf/open/space/transit/west + border_path = /turf/open/space/transit/border/west - var/datum/turf_reservation/proposal = SSmapping.RequestBlockReservation(transit_width, transit_height, null, /datum/turf_reservation/transit, transit_path) + var/datum/turf_reservation/proposal = SSmapping.RequestBlockReservation(transit_width, transit_height, null, /datum/turf_reservation/transit, transit_path, border_path) if(!istype(proposal)) return FALSE diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 4b347b2a39..c92db7cd01 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -269,7 +269,7 @@ SUBSYSTEM_DEF(timer) var/new_bucket_count var/i = 1 for (i in 1 to length(alltimers)) - var/datum/timedevent/timer = alltimers[1] + var/datum/timedevent/timer = alltimers[i] if (!timer) continue diff --git a/code/datums/browser.dm b/code/datums/browser.dm index 358f2bfe29..4c501a3e7f 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -463,4 +463,3 @@ // so just reset the user mob's machine var if(src && src.mob) src.mob.unset_machine() - return diff --git a/code/datums/dna.dm b/code/datums/dna.dm index ed18b3cade..b3f3f7efa1 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -8,6 +8,7 @@ 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/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, + var/nameless = FALSE var/list/mutations = list() //All mutations are from now on here var/list/temporary_mutations = list() //Timers for temporary mutations var/list/previous = list() //For temporary name/ui/ue/blood_type modifications @@ -43,6 +44,7 @@ destination.set_species(species.type, icon_update=0) destination.dna.features = features.Copy() destination.dna.real_name = real_name + destination.dna.nameless = nameless destination.dna.temporary_mutations = temporary_mutations.Copy() if(ishuman(destination)) var/mob/living/carbon/human/H = destination @@ -59,6 +61,7 @@ new_dna.features = features.Copy() new_dna.species = new species.type new_dna.real_name = real_name + new_dna.nameless = nameless new_dna.mutations = mutations.Copy() /datum/dna/proc/add_mutation(mutation_name) @@ -199,7 +202,7 @@ /datum/dna/proc/is_same_as(datum/dna/D) - if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name) + if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name && nameless == D.nameless) if(species.type == D.species.type && features == D.features && blood_type == D.blood_type) return 1 return 0 diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 2a93f74fa7..4021d11128 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -109,6 +109,10 @@ description = "It sure is dark around here...\n" mood_change = -3 +/datum/mood_event/brightlight + description = "The light feels unbearable...\n" + mood_change = -3 + /datum/mood_event/family_heirloom_missing description = "I'm missing my family heirloom...\n" mood_change = -4 diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 9904a28d84..1c77520108 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -458,7 +458,7 @@ var/old_health /datum/status_effect/kindle/tick() - owner.Knockdown(15) + owner.Knockdown(15, TRUE, FALSE, 15) if(iscarbon(owner)) var/mob/living/carbon/C = owner C.silent = max(2, C.silent) diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index c7a8fa5f55..bd55869c99 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -58,6 +58,14 @@ gain_text = "You walk with a little more litheness." lose_text = "You start tromping around like a barbarian." +/datum/quirk/quick_step + name = "Quick Step" + desc = "You walk with determined strides, and out-pace most people when walking." + value = 2 + mob_trait = TRAIT_SPEEDY_STEP + gain_text = "You feel determined. No time to lose." + lose_text = "You feel less determined. What's the rush, man?" + /datum/quirk/musician name = "Musician" desc = "You can tune handheld musical instruments to play melodies that clear certain negative effects and soothe the soul." diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index a98e172018..614cc65cbb 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -41,8 +41,8 @@ heirloom_type = /obj/item/paint/anycolor heirloom_type = /obj/item/bikehorn/golden if("Mime") - heirloom_type = /obj/item/toy/dummy heirloom_type = /obj/item/paint/anycolor + heirloom_type = /obj/item/toy/dummy if("Cook") heirloom_type = /obj/item/kitchen/knife/scimitar if("Medical Doctor") @@ -52,7 +52,7 @@ if("Atmospheric Technician") heirloom_type = /obj/item/extinguisher/mini/family if("Lawyer") - heirloom_type = /obj/item/gavelhammer + heirloom_type = /obj/item/storage/briefcase/lawyer/family if("Janitor") heirloom_type = /obj/item/mop if("Security Officer") @@ -61,6 +61,10 @@ heirloom_type = /obj/item/toy/plush/slimeplushie if("Assistant") heirloom_type = /obj/item/storage/toolbox/mechanical/old/heirloom + if("Chaplain") + heirloom_type = /obj/item/camera/spooky/family + if("Captain") + heirloom_type = /obj/item/clothing/accessory/medal/gold/captain/family if(!heirloom_type) heirloom_type = pick( /obj/item/toy/cards/deck, @@ -154,6 +158,21 @@ else SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "nyctophobia") +/datum/quirk/lightless + name = "Light Sensitivity" + desc = "Bright lights irritate you. Your eyes start to water, your skin feels itchy against the photon radiation, and your hair gets dry and frizzy. Maybe it's a medical condition. If only Nanotrasen was more considerate of your needs..." + value = -1 + gain_text = "The safty of light feels off..." + lose_text = "Enlighing." + +/datum/quirk/lightless/on_process() + var/turf/T = get_turf(quirk_holder) + var/lums = T.get_lumcount() + if(lums >= 0.8) + SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "brightlight", /datum/mood_event/brightlight) + else + SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "brightlight") + /datum/quirk/nonviolent name = "Pacifist" desc = "The thought of violence makes you sick. So much so, in fact, that you can't hurt anyone." diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 07e31cb24d..feb81d44e0 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -56,19 +56,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th return 0 /datum/game_mode/changeling/post_setup() - //Decide if it's ok for the lings to have a team objective - //And then set it up to be handed out in forge_changeling_objectives - var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective) - var/list/possible_team_objectives = list() - for(var/T in team_objectives) - var/datum/objective/changeling_team_objective/CTO = T - - if(changelings.len >= initial(CTO.min_lings)) - possible_team_objectives += T - - if(possible_team_objectives.len && prob(20*changelings.len)) - GLOB.changeling_team_objective_type = pick(possible_team_objectives) - for(var/datum/mind/changeling in changelings) log_game("[key_name(changeling)] has been selected as a changeling") var/datum/antagonist/changeling/new_antag = new() diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 1478079d37..06a365a82c 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -131,10 +131,10 @@ Credit where due: config_tag = "clockwork_cult" antag_flag = ROLE_SERVANT_OF_RATVAR false_report_weight = 10 - required_players = 24 - required_enemies = 4 + required_players = 20 + required_enemies = 2 recommended_enemies = 4 - enemy_minimum_age = 14 + enemy_minimum_age = 7 protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") //Silicons can eventually be converted restricted_jobs = list("Chaplain", "Captain") announce_span = "brass" diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 13ceff2451..782ad54e4c 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -37,10 +37,10 @@ false_report_weight = 10 restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel") protected_jobs = list() - required_players = 24 - required_enemies = 4 + required_players = 20 + required_enemies = 2 recommended_enemies = 4 - enemy_minimum_age = 14 + enemy_minimum_age = 7 announce_span = "cult" announce_text = "Some crew members are trying to start a cult to Nar'Sie!\n\ diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index ab5978a3e5..d76552982c 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -2,11 +2,11 @@ name = "nuclear emergency" config_tag = "nuclear" false_report_weight = 10 - required_players = 30 // 30 players - 3 players to be the nuke ops = 27 players remaining + required_players = 28 // 30 players - 3 players to be the nuke ops = 25 players remaining required_enemies = 2 recommended_enemies = 5 antag_flag = ROLE_OPERATIVE - enemy_minimum_age = 14 + enemy_minimum_age = 7 announce_span = "danger" announce_text = "Syndicate forces are approaching the station in an attempt to destroy it!\n\ diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index d27f977575..9ea2694354 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -10,7 +10,7 @@ required_players = 20 required_enemies = 1 recommended_enemies = 1 - enemy_minimum_age = 14 + enemy_minimum_age = 7 round_ends_with_antag_death = 1 announce_span = "danger" announce_text = "There is a space wizard attacking the station!\n\ diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 7528f83c38..7e75dc8e8e 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -227,7 +227,7 @@ if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes. connected_message("Clone Rejected: Deceased.") if(internal_radio) - SPEAK("The cloning of [mob_occupant.real_name] has been \ + SPEAK("The cloning has been \ aborted due to unrecoverable tissue failure.") go_out() mob_occupant.apply_vore_prefs() @@ -261,7 +261,7 @@ else if((mob_occupant.cloneloss <= (100 - heal_level))) connected_message("Cloning Process Complete.") if(internal_radio) - SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.") + SPEAK("The cloning cycle is complete.") // If the cloner is upgraded to debugging high levels, sometimes // organs and limbs can be missing. @@ -319,7 +319,7 @@ return else connected_message("Emergency Ejection") - SPEAK("An emergency ejection of [clonemind.name] has occurred. Survival not guaranteed.") + SPEAK("An emergency ejection of the current clone has occurred. Survival not guaranteed.") to_chat(user, "You force an emergency ejection. ") go_out() mob_occupant.apply_vore_prefs() @@ -412,7 +412,7 @@ var/mob/living/mob_occupant = occupant if(mob_occupant && prob(100/(severity*efficiency))) connected_message(Gibberish("EMP-caused Accidental Ejection", 0)) - SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [mob_occupant.real_name] prematurely." ,0)) + SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of, ERROR: John Doe, prematurely." ,0)) mob_occupant.apply_vore_prefs() go_out() diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 42ac9726bf..1f262c0979 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -53,70 +53,8 @@ /obj/item/clothing/shoes/wheelys = 8, /obj/item/clothing/shoes/kindleKicks = 8, /obj/item/storage/belt/military/snack = 8, - /obj/item/toy/plush/lizardplushie = 1, - /obj/item/toy/plush/lizardplushie/durgit = 1, - /obj/item/toy/plush/lizardplushie/rio = 1, - /obj/item/toy/plush/lizardplushie/urinsu = 1, - /obj/item/toy/plush/lizardplushie/arfrehn = 1, - /obj/item/toy/plush/lizardplushie/soars = 1, - /obj/item/toy/plush/lizardplushie/ghostie = 1, - /obj/item/toy/plush/lizardplushie/amber = 1, - /obj/item/toy/plush/lizardplushie/cyan = 1, - /obj/item/toy/plush/lizardplushie/meena = 1, - /obj/item/toy/plush/lizardplushie/stalks = 1, - /obj/item/toy/plush/lizardplushie/kobold = 1, - /obj/item/toy/plush/lizardplushie/gorgi = 1, - /obj/item/toy/plush/lizardplushie/almaz = 1, - /obj/item/toy/plush/snakeplushie/sasha = 1, - /obj/item/toy/plush/snakeplushie/shay = 1, - /obj/item/toy/plush/snakeplushie/vulken = 1, - /obj/item/toy/plush/mothplushie = 1, - /obj/item/toy/plush/mothplushie/bumble = 1, - /obj/item/toy/plush/mothplushie/nameko = 1, - /obj/item/toy/plush/mothplushie/suru = 1, - /obj/item/toy/plush/xeno = 1, - /obj/item/toy/plush/lampplushie = 1, - /obj/item/toy/plush/borgplushie = 1, - /obj/item/toy/plush/borgplushie/medihound = 1, - /obj/item/toy/plush/borgplushie/scrubpuppy = 1, - /obj/item/toy/plush/borgplushie/seeking = 1, - /obj/item/toy/plush/borgplushie/neeb = 1, - /obj/item/toy/plush/bird = 1, - /obj/item/toy/plush/bird/esela = 1, - /obj/item/toy/plush/bird/jahonna = 1, - /obj/item/toy/plush/bird/krick = 1, - /obj/item/toy/plush/bird/birddi = 1, - /obj/item/toy/plush/bird/jewel = 1, - /obj/item/toy/plush/mammal = 1, - /obj/item/toy/plush/mammal/dubious = 1, - /obj/item/toy/plush/mammal/gladwyn = 1, - /obj/item/toy/plush/mammal/gavin = 1, - /obj/item/toy/plush/mammal/blep = 1, - /obj/item/toy/plush/mammal/circe = 1, - /obj/item/toy/plush/mammal/pavel = 1, - /obj/item/toy/plush/mammal/oten = 1, - /obj/item/toy/plush/mammal/ray = 1, - /obj/item/toy/plush/mammal/dawud = 1, - /obj/item/toy/plush/mammal/edgar = 1, - /obj/item/toy/plush/mammal/frank = 1, - /obj/item/toy/plush/mammal/poojawa = 1, - /obj/item/toy/plush/mammal/hazel = 1, - /obj/item/toy/plush/mammal/jermaine = 1, - /obj/item/toy/plush/mammal/gunther = 1, - /obj/item/toy/plush/mammal/fox = 1, - /obj/item/toy/plush/mammal/zed = 1, - /obj/item/toy/plush/mammal/dog = 1, - /obj/item/toy/plush/mammal/dog/frost = 1, - /obj/item/toy/plush/mammal/dog/atticus = 1, - /obj/item/toy/plush/mammal/dog/fletch = 1, - /obj/item/toy/plush/mammal/dog/vincent = 1, - /obj/item/toy/plush/mammal/dog/zigfried = 1, - /obj/item/toy/plush/mammal/dog/nikolai = 1, - /obj/item/toy/plush/catgirl = 1, - /obj/item/toy/plush/catgirl/skylar = 1, - /obj/item/toy/plush/catgirl/mikeel = 1, - /obj/item/toy/plush/catgirl/robin = 1 - ) + /obj/item/toy/plush/random = 450 + )//plushies have a 0.6 chance light_color = LIGHT_COLOR_GREEN diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 222caeb595..9c01c186e1 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -327,7 +327,11 @@ L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) var/turf/location = get_turf(src) //add_blood doesn't work for borgs/xenos, but add_blood_floor does. - L.add_splatter_floor(location) + if(iscarbon(L)) + var/mob/living/carbon/C = L + C.bleed(DOOR_CRUSH_DAMAGE) + else + L.add_splatter_floor(location) for(var/obj/mecha/M in get_turf(src)) M.take_damage(DOOR_CRUSH_DAMAGE) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d14065b4c4..3dab6a66af 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -544,8 +544,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/matrix/M = matrix(transform) M.Turn(rand(-170, 170)) transform = M - pixel_x = rand(-12, 12) - pixel_y = rand(-12, 12) + pixel_x = rand(-8, 8) + pixel_y = rand(-8, 8) /obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage if(!newLoc) diff --git a/code/game/objects/items/candle.dm b/code/game/objects/items/candle.dm index b7a3b0c76c..1165501d9a 100644 --- a/code/game/objects/items/candle.dm +++ b/code/game/objects/items/candle.dm @@ -8,72 +8,70 @@ item_state = "candle1" w_class = WEIGHT_CLASS_TINY light_color = LIGHT_COLOR_FIRE + heat = 1000 var/wax = 1000 var/lit = FALSE var/infinite = FALSE var/start_lit = FALSE - heat = 1000 /obj/item/candle/Initialize() . = ..() if(start_lit) - // No visible message - light(show_message = FALSE) + light() /obj/item/candle/update_icon() - var/i - if(wax>750) - i = 1 - else if(wax>400) - i = 2 - else i = 3 - icon_state = "candle[i][lit ? "_lit" : ""]" - + icon_state = "candle[(wax > 400) ? ((wax > 750) ? 1 : 2) : 3][lit ? "_lit" : ""]" /obj/item/candle/attackby(obj/item/W, mob/user, params) - ..() var/msg = W.ignition_effect(src, user) if(msg) light(msg) + else + return ..() /obj/item/candle/fire_act(exposed_temperature, exposed_volume) - if(!src.lit) + if(!lit) light() //honk - ..() + return ..() + +/obj/item/candle/is_hot() + return lit * heat /obj/item/candle/proc/light(show_message) - if(!src.lit) - src.lit = TRUE - //src.damtype = "fire" + if(!lit) + lit = TRUE if(show_message) usr.visible_message(show_message) - set_light(CANDLE_LUMINOSITY, 0.8) + set_light(CANDLE_LUMINOSITY) START_PROCESSING(SSobj, src) update_icon() +/obj/item/candle/proc/put_out_candle() + if(!lit) + return + lit = FALSE + update_icon() + set_light(0) + return TRUE + +/obj/item/candle/extinguish() + put_out_candle() + return ..() /obj/item/candle/process() if(!lit) - return + return PROCESS_KILL if(!infinite) wax-- if(!wax) - new/obj/item/trash/candle(src.loc) + new /obj/item/trash/candle(loc) qdel(src) update_icon() open_flame() /obj/item/candle/attack_self(mob/user) - if(lit) - user.visible_message( - "[user] snuffs [src].") - lit = FALSE - update_icon() - set_light(0) - -/obj/item/candle/is_hot() - return lit * heat - + if(put_out_candle()) + user.visible_message("[user] snuffs [src].") /obj/item/candle/infinite infinite = TRUE diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index a57bf47a2e..e0d6b553fd 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -227,7 +227,7 @@ repetition++ addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection, repetition), timer_seconds) -/obj/item/extinguisher/AltClick(mob/user) +/obj/item/extinguisher/screwdriver_act(mob/user, obj/item/tool) if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return EmptyExtinguisher(user) @@ -242,3 +242,4 @@ theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS) user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] using its release valve.") + diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm index 79c0e467a6..32e06eb9b4 100644 --- a/code/game/objects/items/grenades/grenade.dm +++ b/code/game/objects/items/grenades/grenade.dm @@ -82,6 +82,8 @@ addtimer(CALLBACK(src, .proc/prime), isnull(delayoverride)? det_time : delayoverride) /obj/item/grenade/proc/prime() + var/turf/T = get_turf(src) + log_game("Grenade detonation at [AREACOORD(T)], location [loc]") /obj/item/grenade/proc/update_mob() if(ismob(loc)) diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 2411454ace..703de902b6 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -359,6 +359,16 @@ if(mood_message) desc += mood_message +/obj/item/toy/plush/random + name = "Illegal plushie" + desc = "Something fucked up" + +/obj/item/toy/plush/random/Initialize() + ..() + var/newtype = pick(subtypesof(/obj/item/toy/plush)) + new newtype(loc) + return INITIALIZE_HINT_QDEL + /obj/item/toy/plush/carpplushie name = "space carp plushie" desc = "An adorable stuffed toy that resembles a space carp." @@ -495,6 +505,10 @@ icon_state = "rio" item_state = "rio" +/obj/item/toy/plush/lizardplushie/dan + icon_state = "dan" + item_state = "dan" + /obj/item/toy/plush/lizardplushie/urinsu icon_state = "urinsu" item_state = "urinsu" @@ -546,7 +560,7 @@ icon_state = "plushie_snake" item_state = "plushie_snake" attack_verb = list("bitten", "hissed", "tail slapped") - squeak_override = list('sound/voice/lowHiss2.ogg' = 1) + squeak_override = list('modular_citadel/sound/voice/hiss.ogg' = 1) /obj/item/toy/plush/snakeplushie/sasha icon_state = "sasha" @@ -560,6 +574,10 @@ icon_state = "vulken" item_state = "vulken" +/obj/item/toy/plush/snakeplushie/jecca + icon_state = "jecca" + item_state = "jecca" + /obj/item/toy/plush/nukeplushie name = "operative plushie" desc = "A stuffed toy that resembles a syndicate nuclear operative. The tag claims operatives to be purely fictitious." @@ -669,20 +687,27 @@ icon_state = "jewel" item_state = "jewel" -/obj/item/toy/plush/mammal - name = "mammal plushie" - desc = "An adorable stuffed toy resembling some sort of mammallian crew member." +/obj/item/toy/plush/sergal + name = "sergal plushie" + desc = "An adorable stuffed plushie that resembles a sagaru." icon_state = "faux" item_state = "faux" + squeak_override = list('modular_citadel/sound/voice/merp.ogg' = 1) -/obj/item/toy/plush/mammal/dubious - icon_state = "dubious" - item_state = "dubious" - -/obj/item/toy/plush/mammal/gladwyn +/obj/item/toy/plush/sergal/gladwyn icon_state = "gladwyn" item_state = "gladwyn" +/obj/item/toy/plush/sergal/jermaine + icon_state = "jermaine" + item_state = "jermaine" + +/obj/item/toy/plush/mammal + name = "mammal plushie" + desc = "An adorable stuffed toy resembling some sort of crew member." + icon_state = "dubious" + item_state = "dubious" + /obj/item/toy/plush/mammal/gavin icon_state = "gavin" item_state = "gavin" @@ -695,6 +720,10 @@ icon_state = "circe" item_state = "circe" +/obj/item/toy/plush/mammal/robin + icon_state = "robin" + item_state = "robin" + /obj/item/toy/plush/mammal/pavel icon_state = "pavel" item_state = "pavel" @@ -731,10 +760,6 @@ icon_state = "joker" item_state = "joker" -/obj/item/toy/plush/mammal/jermaine - icon_state = "jermaine" - item_state = "jermaine" - /obj/item/toy/plush/mammal/gunther icon_state = "gunther" item_state = "gunther" @@ -743,6 +768,11 @@ icon_state = "fox" item_state = "fox" +/obj/item/toy/plush/mammal/rae + desc = "An adorable stuffed toy of an artic fox." + icon_state = "rae" + item_state = "rae" + /obj/item/toy/plush/mammal/zed icon_state = "zed" item_state = "zed" @@ -782,9 +812,13 @@ icon_state = "nikolai" item_state = "nikolai" +/obj/item/toy/plush/mammal/dog/flynn + icon_state = "flynn" + item_state = "flynn" + /obj/item/toy/plush/catgirl name = "feline plushie" - desc = "An adorable stuffed toy that resembles a felinid." + desc = "An adorable stuffed toy that resembles a feline." icon_state = "bailey" item_state = "bailey" attack_verb = list("headbutt", "scritched", "bit") @@ -802,9 +836,17 @@ attack_verb = list("powergamed", "merged", "tabled") squeak_override = list('sound/effects/meow1.ogg' = 1) -/obj/item/toy/plush/catgirl/robin - icon_state = "robin" - item_state = "robin" +/obj/item/toy/plush/catgirl/drew + icon_state = "drew" + item_state = "drew" + +/obj/item/toy/plush/catgirl/fermis + name = "medcat plushie" + desc = "An affectionate stuffed toy that resembles a certain medcat, comes complete with battery operated wagging tail!! You get the impression she's cheering you on to to find happiness and be kind to people." + icon_state = "fermis" + item_state = "fermis" + attack_verb = list("cuddled", "petpatted", "wigglepurred") + squeak_override = list('modular_citadel/sound/voice/merowr.ogg' = 1) /obj/item/toy/plush/awakenedplushie/ComponentInitialize() . = ..() diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 7867ec5f1e..38cfdb95ae 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -93,7 +93,7 @@ desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate." icon_state = "cyborg_upgrade3" require_module = 1 - module_type = /obj/item/robot_module/security + //module_type = /obj/item/robot_module/security /obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr) . = ..() diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm index 5fdf94c1f3..cc1c07aa02 100644 --- a/code/game/objects/items/storage/briefcase.dm +++ b/code/game/objects/items/storage/briefcase.dm @@ -30,6 +30,30 @@ /obj/item/storage/briefcase/lawyer folder_path = /obj/item/folder/blue +/obj/item/storage/briefcase/lawyer/family + name = "battered briefcase" + desc = "An old briefcase, this one has seen better days in its time. It's clear they don't make them nowadays as good as they used to. The corners are modified with metal trim adding in weight!" + +/obj/item/storage/briefcase/lawyer/family/PopulateContents() + new /obj/item/stamp/law(src) + new /obj/item/pen/fountain(src) + new /obj/item/paper_bin(src) + new /obj/item/storage/box/evidence(src) + new /obj/item/storage/box/lawyer(src) + +/obj/item/storage/box/lawyer + name = "Box of lawyer tools" + desc = "A custom made box, full of items used by a Lawyer, all packed into one box!" + +/obj/item/storage/box/lawyer/PopulateContents() + new /obj/item/clothing/gloves/color/white(src) + new /obj/item/folder/white(src) + new /obj/item/clothing/glasses/regular(src) + new /obj/item/folder/red(src) + new /obj/item/gavelhammer(src) + new /obj/item/stack/sheet/cloth(src) + new /obj/item/reagent_containers/glass/beaker/waterbottle(src) + /obj/item/storage/briefcase/lawyer/PopulateContents() new /obj/item/stamp/law(src) ..() diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index b73c6e496c..b9a75f88af 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -75,7 +75,11 @@ L.visible_message("[user] slams [L] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.") L.forceMove(drop_location()) L.emote("scream") - L.add_splatter_floor() + if(iscarbon(L)) + var/mob/living/carbon/C = L + C.bleed(30) + else + L.add_splatter_floor() L.adjustBruteLoss(30) L.setDir(2) buckle_mob(L, force=1) diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 40435c2000..d6f304653d 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -51,6 +51,20 @@ new /obj/item/stack/rods(get_turf(src), number_of_rods) qdel(src) +/obj/structure/lattice/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) + if(the_rcd.mode == RCD_FLOORWALL) + return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 2) + +/obj/structure/lattice/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) + if(passed_mode == RCD_FLOORWALL) + to_chat(user, "You build a floor.") + var/turf/T = src.loc + if(isspaceturf(T)) + T.PlaceOnTop(/turf/open/floor/plating) + qdel(src) + return TRUE + return FALSE + /obj/structure/lattice/singularity_pull(S, current_size) if(current_size >= STAGE_FOUR) deconstruct() diff --git a/code/game/sound.dm b/code/game/sound.dm index 1fafb4f34d..cceed31cfb 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,4 +1,4 @@ -/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE) +/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, soundenvwet = -10000, soundenvdry = 0) if(isarea(source)) throw EXCEPTION("playsound(): source is an area") return @@ -21,13 +21,16 @@ for(var/P in listeners) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, soundenvwet, soundenvdry) for(var/P in SSmobs.dead_players_by_zlevel[z]) var/mob/M = P if(get_dist(M, turf_source) <= maxdistance) - M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S) + M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, soundenvwet, soundenvdry) -/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, envwet = -10000, envdry = 0) +/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, envwet = -10000, envdry = 0, manual_x, manual_y) + if(audiovisual_redirect) + var/turf/T = get_turf(src) + audiovisual_redirect.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, 0, -1000, turf_source.x - T.x, turf_source.y - T.y) if(!client || !can_hear()) return @@ -49,7 +52,9 @@ var/turf/T = get_turf(src) //sound volume falloff with distance - var/distance = get_dist(T, turf_source) + var/distance = 0 + if(!manual_x && !manual_y) + distance = get_dist(T, turf_source) S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff. @@ -77,9 +82,17 @@ if(S.volume <= 0) return //No sound - var/dx = turf_source.x - T.x // Hearing from the right/left + var/dx = 0 // Hearing from the right/left + if(!manual_x) + dx = turf_source.x - T.x + else + dx = manual_x S.x = dx - var/dz = turf_source.y - T.y // Hearing from infront/behind + var/dz = 0 // Hearing from infront/behind + if(!manual_x) + dz = turf_source.y - T.y + else + dz = manual_y S.z = dz // The y value is for above your head, but there is no ceiling in 2d spessmens. S.y = 1 diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 659a58b2dc..63b5f4b160 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -245,6 +245,10 @@ return 0 if(C.m_intent == MOVE_INTENT_WALK && (lube&NO_SLIP_WHEN_WALKING)) return 0 + if(ishuman(C) && (lube&NO_SLIP_WHEN_WALKING)) + var/mob/living/carbon/human/H = C + if(!H.sprinting && H.getStaminaLoss() >= 20) + return 0 if(!(lube&SLIDE_ICE)) to_chat(C, "You slipped[ O ? " on the [O.name]" : ""]!") playsound(C.loc, 'sound/misc/slip.ogg', 50, 1, -3) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 9d2adbdfba..e783b8a9a0 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -126,6 +126,17 @@ else to_chat(user, "You hit [src], to no effect!") +/turf/open/floor/plating/foam/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) + if(the_rcd.mode == RCD_FLOORWALL) + return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 1) + +/turf/open/floor/plating/foam/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode) + if(passed_mode == RCD_FLOORWALL) + to_chat(user, "You build a floor.") + ChangeTurf(/turf/open/floor/plating) + return TRUE + return FALSE + /turf/open/floor/plating/foam/ex_act() ..() ScrapeAway() diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index 8416684e73..f0f0667c37 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -26,7 +26,30 @@ /turf/open/space/transit/east dir = EAST -/turf/open/space/transit/Entered(atom/movable/AM, atom/OldLoc) +/turf/open/space/transit/border + opacity = TRUE + +/turf/open/space/transit/border/south + dir = SOUTH + +/turf/open/space/transit/border/north + dir = NORTH + +/turf/open/space/transit/border/west + dir = WEST + +/turf/open/space/transit/border/east + dir = EAST + +/turf/open/space/transit/centcom + dir = SOUTH + +/turf/open/space/transit/centcom/Entered(atom/movable/AM, atom/OldLoc) + ..() + if(!locate(/obj/structure/lattice) in src) + throw_atom(AM) + +/turf/open/space/transit/border/Entered(atom/movable/AM, atom/OldLoc) ..() if(!locate(/obj/structure/lattice) in src) throw_atom(AM) @@ -66,6 +89,8 @@ var/turf/T = locate(_x, _y, _z) AM.forceMove(T) + var/turf/throwturf = get_ranged_target_turf(T, dir, 1) + AM.safe_throw_at(throwturf, 1, 4, null, FALSE) /turf/open/space/transit/CanBuildHere() diff --git a/code/modules/VR/vr_human.dm b/code/modules/VR/vr_human.dm index 56f0986fef..53a4bbe540 100644 --- a/code/modules/VR/vr_human.dm +++ b/code/modules/VR/vr_human.dm @@ -35,6 +35,7 @@ /mob/living/carbon/human/virtual_reality/proc/revert_to_reality(deathchecks = TRUE) if(real_mind && mind) + real_mind.current.audiovisual_redirect = null real_mind.current.ckey = ckey real_mind.current.stop_sound_channel(CHANNEL_HEARTBEAT) if(deathchecks && vr_sleeper) diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm index eed6f9b3ae..4e342f6ced 100644 --- a/code/modules/VR/vr_sleeper.dm +++ b/code/modules/VR/vr_sleeper.dm @@ -93,6 +93,7 @@ to_chat(occupant, "Transferring to virtual reality...") if(vr_human && vr_human.stat == CONSCIOUS && !vr_human.real_mind) SStgui.close_user_uis(occupant, src) + human_occupant.audiovisual_redirect = vr_human vr_human.real_mind = human_occupant.mind vr_human.ckey = human_occupant.ckey to_chat(vr_human, "Transfer successful! You are now playing as [vr_human] in VR!") @@ -166,11 +167,13 @@ vr_human.undershirt = H.undershirt vr_human.underwear = H.underwear vr_human.updateappearance(TRUE, TRUE, TRUE) + vr_human.give_genitals(TRUE) //CITADEL ADD if(outfit) var/datum/outfit/O = new outfit() O.equip(vr_human) if(transfer && H.mind) SStgui.close_user_uis(H, src) + H.audiovisual_redirect = vr_human vr_human.ckey = H.ckey /obj/machinery/vr_sleeper/proc/cleanup_vr_human() @@ -227,4 +230,4 @@ for (var/mob/living/carbon/human/virtual_reality/H in vr_area) if (H.stat == DEAD && !H.vr_sleeper && !H.real_mind) qdel(H) - addtimer(CALLBACK(src, .proc/clean_up), 3 MINUTES) \ No newline at end of file + addtimer(CALLBACK(src, .proc/clean_up), 3 MINUTES) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 76cc17b791..1a398f56fc 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -605,6 +605,24 @@ world.update_status() SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle AI", "[!alai ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/datum/admins/proc/toggleMulticam() + set category = "Server" + set desc="Turns mutlicam on and off." + set name="Toggle Multicam" + var/almcam = CONFIG_GET(flag/allow_ai_multicam) + CONFIG_SET(flag/allow_ai_multicam, !almcam) + if (almcam) + to_chat(world, "The AI no longer has multicam.") + for(var/i in GLOB.ai_list) + var/mob/living/silicon/ai/aiPlayer = i + if(aiPlayer.multicam_on) + aiPlayer.end_multicam() + else + to_chat(world, "The AI now has multicam.") + log_admin("[key_name(usr)] toggled AI multicam.") + world.update_status() + SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + /datum/admins/proc/toggleaban() set category = "Server" set desc="Respawn basically" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 9311adfbea..e21c2b8873 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -70,6 +70,8 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/panicbunker, + /client/proc/addbunkerbypass, + /client/proc/revokebunkerbypass, /client/proc/stop_sounds, /client/proc/hide_verbs, /*hides all our adminverbs*/ /client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/ @@ -118,6 +120,7 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) /datum/admins/proc/toggleaban, /client/proc/everyone_random, /datum/admins/proc/toggleAI, + /datum/admins/proc/toggleMulticam, /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_all, /client/proc/toggle_random_events, @@ -232,6 +235,8 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( /proc/release, /client/proc/reload_admins, /client/proc/panicbunker, + /client/proc/addbunkerbypass, + /client/proc/revokebunkerbypass, /client/proc/admin_change_sec_level, /client/proc/toggle_nuke, /client/proc/cmd_display_del_log, diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 85866d5c51..f5075b57b7 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -714,7 +714,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null SDQL_print(x, text_list) if (!isnull(x) && !isnum(x) && L[x] != null) text_list += " -> " - SDQL_print(L[L[x]]) + SDQL_print(L[L[x]], text_list) text_list += "]
" else if(isnull(object)) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm index a984e40fee..3056b459d8 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm @@ -184,6 +184,9 @@ /proc/_list_swap(list/L, Index1, Index2) L.Swap(Index1, Index2) +/proc/_list_get(list/L, index) + return L[index] + /proc/_walk(ref, dir, lag) walk(ref, dir, lag) diff --git a/code/modules/admin/verbs/panicbunker.dm b/code/modules/admin/verbs/panicbunker.dm index fc0cab66c9..ab3aeb4ba5 100644 --- a/code/modules/admin/verbs/panicbunker.dm +++ b/code/modules/admin/verbs/panicbunker.dm @@ -13,3 +13,28 @@ if (new_pb && !SSdbcore.Connect()) message_admins("The Database is not connected! Panic bunker will not work until the connection is reestablished.") SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Panic Bunker", "[new_pb ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/addbunkerbypass(ckeytobypass as text) + set category = "Special Verbs" + set name = "Add PB Bypass" + set desc = "Allows a given ckey to connect despite the panic bunker for a given round." + if(!CONFIG_GET(flag/sql_enabled)) + to_chat(usr, "The Database is not enabled!") + return + + GLOB.bunker_passthrough |= ckey(ckeytobypass) + log_admin("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.") + message_admins("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.") + +/client/proc/revokebunkerbypass(ckeytobypass as text) + set category = "Special Verbs" + set name = "Revoke PB Bypass" + set desc = "Revoke's a ckey's permission to bypass the panic bunker for a given round." + if(!CONFIG_GET(flag/sql_enabled)) + to_chat(usr, "The Database is not enabled!") + return + + GLOB.bunker_passthrough -= ckey(ckeytobypass) + log_admin("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.") + message_admins("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.") + diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index cc3b3a3057..7e0ae3c08c 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -34,6 +34,8 @@ var/mimicing = "" var/canrespec = 0 var/changeling_speak = 0 + var/loudfactor = 0 //Used for blood tests. At 4, blood tests will succeed. At 10, blood tests will result in an explosion. + var/bloodtestwarnings = 0 //Used to track if the ling has been notified that they will pass blood tests. var/datum/dna/chosen_dna var/obj/effect/proc_holder/changeling/sting/chosen_sting var/datum/cellular_emporium/cellular_emporium @@ -71,8 +73,6 @@ reset_powers() create_initial_profile() if(give_objectives) - if(team_mode) - forge_team_objectives() forge_objectives() remove_clownmut() . = ..() @@ -123,6 +123,8 @@ /datum/antagonist/changeling/proc/reset_powers() if(purchasedpowers) remove_changeling_powers() + loudfactor = 0 + bloodtestwarnings = 0 //Repurchase free powers. for(var/path in all_powers) var/obj/effect/proc_holder/changeling/S = new path() @@ -174,6 +176,13 @@ geneticpoints -= thepower.dna_cost purchasedpowers += thepower thepower.on_purchase(owner.current) + loudfactor += thepower.loudness + if(loudfactor >= 4 && !bloodtestwarnings) + to_chat(owner.current, "Our blood is growing flammable. Our blood will react violently to heat.") + bloodtestwarnings = 1 + if(loudfactor >= 10 && bloodtestwarnings < 2) + to_chat(owner.current, "Our blood has grown extremely flammable. Our blood will react explosively to heat.") + bloodtestwarnings = 2 /datum/antagonist/changeling/proc/readapt() if(!ishuman(owner.current)) @@ -182,6 +191,7 @@ if(canrespec) to_chat(owner.current, "We have removed our evolutions from this form, and are now ready to readapt.") reset_powers() + playsound(get_turf(owner.current), 'sound/effects/lingreadapt.ogg', 75, TRUE, 5, soundenvwet = 0) canrespec = 0 SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt") return 1 diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index ae255a04f8..c89dc50cec 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -16,6 +16,7 @@ var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD var/always_keep = 0 // important for abilities like revive that screw you if you lose them. var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag + var/loudness = 0 //Determines how much having this ability will affect changeling blood tests. At 4, the blood will react violently and turn to ash, creating a unique message in the process. At 10, the blood will explode when heated. /obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec) diff --git a/code/modules/antagonists/changeling/powers/biodegrade.dm b/code/modules/antagonists/changeling/powers/biodegrade.dm index 1e8eaed383..d1a2cc3891 100644 --- a/code/modules/antagonists/changeling/powers/biodegrade.dm +++ b/code/modules/antagonists/changeling/powers/biodegrade.dm @@ -1,8 +1,9 @@ /obj/effect/proc_holder/changeling/biodegrade name = "Biodegrade" desc = "Dissolves restraints or other objects preventing free movement." - helptext = "This is obvious to nearby people, and can destroy standard restraints and closets." + helptext = "This is obvious to nearby people, and can destroy standard restraints and closets. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." chemical_cost = 30 //High cost to prevent spam + loudness = 1 dna_cost = 2 req_human = 1 diff --git a/code/modules/antagonists/changeling/powers/digitalcamo.dm b/code/modules/antagonists/changeling/powers/digitalcamo.dm index 68a1fa4add..e8bad0e215 100644 --- a/code/modules/antagonists/changeling/powers/digitalcamo.dm +++ b/code/modules/antagonists/changeling/powers/digitalcamo.dm @@ -1,8 +1,9 @@ /obj/effect/proc_holder/changeling/digitalcamo name = "Digital Camouflage" desc = "By evolving the ability to distort our form and proportions, we defeat common algorithms used to detect lifeforms on cameras." - helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny." + helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." dna_cost = 1 + loudness = 1 //Prevents AIs tracking you but makes you easily detectable to the human-eye. /obj/effect/proc_holder/changeling/digitalcamo/sting_action(mob/user) diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm index 70edf1e788..8a932dbd62 100644 --- a/code/modules/antagonists/changeling/powers/headcrab.dm +++ b/code/modules/antagonists/changeling/powers/headcrab.dm @@ -1,9 +1,10 @@ /obj/effect/proc_holder/changeling/headcrab name = "Last Resort" desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel." - helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us." + helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us. This ability is loud, and might cause our blood to react violently to heat." chemical_cost = 20 dna_cost = 1 + loudness = 2 req_human = 1 /obj/effect/proc_holder/changeling/headcrab/sting_action(mob/user) diff --git a/code/modules/antagonists/changeling/powers/hivemind.dm b/code/modules/antagonists/changeling/powers/hivemind.dm index c84adc6e8f..86926f51a9 100644 --- a/code/modules/antagonists/changeling/powers/hivemind.dm +++ b/code/modules/antagonists/changeling/powers/hivemind.dm @@ -3,7 +3,7 @@ name = "Hivemind Communication" desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings." helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives." - dna_cost = 0 + dna_cost = 1 chemical_cost = -1 /obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(mob/user, is_respec) @@ -17,6 +17,9 @@ var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new if(!changeling.has_sting(S2)) changeling.purchasedpowers+=S2 + var/obj/effect/proc_holder/changeling/linglink/S3 = new + if(!changeling.has_sting(S3)) + changeling.purchasedpowers+=S3 // HIVE MIND UPLOAD/DOWNLOAD DNA GLOBAL_LIST_EMPTY(hivemind_bank) diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm index 06824f9bed..24403b406c 100644 --- a/code/modules/antagonists/changeling/powers/lesserform.dm +++ b/code/modules/antagonists/changeling/powers/lesserform.dm @@ -1,8 +1,9 @@ /obj/effect/proc_holder/changeling/lesserform name = "Lesser Form" - desc = "We debase ourselves and become lesser. We become a monkey." + desc = "We debase ourselves and become lesser. We become a monkey. This ability is loud, and might cause our blood to react violently to heat." chemical_cost = 5 dna_cost = 1 + loudness = 2 req_human = 1 //Transform into a monkey. diff --git a/code/modules/antagonists/changeling/powers/linglink.dm b/code/modules/antagonists/changeling/powers/linglink.dm index cd7c944137..baa02ea7c8 100644 --- a/code/modules/antagonists/changeling/powers/linglink.dm +++ b/code/modules/antagonists/changeling/powers/linglink.dm @@ -2,7 +2,7 @@ name = "Hivemind Link" desc = "Link your victim's mind into the hivemind for personal interrogation." chemical_cost = 0 - dna_cost = 0 + dna_cost = -1 req_human = 1 /obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user) diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 6a952d09f8..9e353a1855 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -134,9 +134,10 @@ /obj/effect/proc_holder/changeling/weapon/arm_blade name = "Arm Blade" desc = "We reform one of our arms into a deadly blade." - helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form." + helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form. This ability is loud, and might cause our blood to react violently to heat." chemical_cost = 20 dna_cost = 2 + loudness = 2 req_human = 1 weapon_type = /obj/item/melee/arm_blade weapon_name_simple = "blade" @@ -215,9 +216,11 @@ desc = "We ready a tentacle to grab items or victims with." helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \ Help will simply drag them closer, Disarm will grab whatever they're holding instead of them, Grab will put the victim in our hold after catching it, \ - and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form." + and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form.\ + This ability is loud, and might cause our blood to react violently to heat." chemical_cost = 10 dna_cost = 2 + loudness = 2 req_human = 1 weapon_type = /obj/item/gun/magic/tentacle weapon_name_simple = "tentacle" @@ -393,9 +396,10 @@ /obj/effect/proc_holder/changeling/weapon/shield name = "Organic Shield" desc = "We reform one of our arms into a hard shield." - helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form." + helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." chemical_cost = 20 dna_cost = 1 + loudness = 1 req_human = 1 weapon_type = /obj/item/shield/changeling @@ -445,9 +449,10 @@ /obj/effect/proc_holder/changeling/suit/organic_space_suit name = "Organic Space Suit" desc = "We grow an organic suit to protect ourselves from space exposure." - helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form." + helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." chemical_cost = 20 dna_cost = 2 + loudness = 1 req_human = 1 suit_type = /obj/item/clothing/suit/space/changeling @@ -492,9 +497,10 @@ /obj/effect/proc_holder/changeling/suit/armor name = "Chitinous Armor" desc = "We turn our skin into tough chitin to protect us from damage." - helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form." + helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form. This ability is loud, and might cause our blood to react violently to heat." chemical_cost = 20 dna_cost = 1 + loudness = 2 req_human = 1 recharge_slowdown = 0.25 diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm index ca79562081..f77624d072 100644 --- a/code/modules/antagonists/changeling/powers/shriek.dm +++ b/code/modules/antagonists/changeling/powers/shriek.dm @@ -1,9 +1,10 @@ /obj/effect/proc_holder/changeling/resonant_shriek name = "Resonant Shriek" desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded." - helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors." + helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." chemical_cost = 20 dna_cost = 1 + loudness = 1 req_human = 1 //A flashy ability, good for crowd control and sewing chaos. @@ -25,13 +26,16 @@ for(var/obj/machinery/light/L in range(4, user)) L.on = 1 L.break_light_tube() + playsound(get_turf(user), 'sound/effects/lingscreech.ogg', 75, TRUE, 5, soundenvwet = 0) return TRUE /obj/effect/proc_holder/changeling/dissonant_shriek name = "Dissonant Shriek" desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics." + helptext = "Emits a high-frequency sound that overloads nearby electronics. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." chemical_cost = 20 dna_cost = 1 + loudness = 1 //A flashy ability, good for crowd control and sewing chaos. /obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(mob/user) @@ -39,4 +43,5 @@ L.on = 1 L.break_light_tube() empulse(get_turf(user), 2, 5, 1) + playsound(get_turf(user), 'sound/effects/lingempscreech.ogg', 75, TRUE, 5, soundenvwet = 0) return TRUE diff --git a/code/modules/antagonists/changeling/powers/spiders.dm b/code/modules/antagonists/changeling/powers/spiders.dm index 685767f601..2bd1bc8a35 100644 --- a/code/modules/antagonists/changeling/powers/spiders.dm +++ b/code/modules/antagonists/changeling/powers/spiders.dm @@ -1,9 +1,10 @@ /obj/effect/proc_holder/changeling/spiders name = "Spread Infestation" desc = "Our form divides, creating arachnids which will grow into deadly beasts." - helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting." + helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 3 DNA gained through Absorb, and not through DNA sting. This ability is very loud, and will guarantee that our blood will react violently to heat." chemical_cost = 45 dna_cost = 1 + loudness = 4 req_absorbs = 3 //Makes some spiderlings. Good for setting traps and causing general trouble. diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index 9bf4a76454..6c9e0c6599 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -64,10 +64,11 @@ /obj/effect/proc_holder/changeling/sting/transformation name = "Transformation Sting" desc = "We silently sting a human, injecting a retrovirus that forces them to transform." - helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human." + helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." sting_icon = "sting_transform" chemical_cost = 50 dna_cost = 3 + loudness = 1 var/datum/changelingprofile/selected_dna = null /obj/effect/proc_holder/changeling/sting/transformation/Click() @@ -111,10 +112,11 @@ /obj/effect/proc_holder/changeling/sting/false_armblade name = "False Armblade Sting" desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade." - helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless." + helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." sting_icon = "sting_armblade" chemical_cost = 20 dna_cost = 1 + loudness = 1 /obj/item/melee/arm_blade/false desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless." @@ -183,10 +185,11 @@ /obj/effect/proc_holder/changeling/sting/mute name = "Mute Sting" desc = "We silently sting a human, completely silencing them for a short time." - helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot." + helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot. This ability is loud, and might cause our blood to react violently to heat." sting_icon = "sting_mute" chemical_cost = 20 dna_cost = 2 + loudness = 2 /obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target) log_combat(user, target, "stung", "mute sting") @@ -196,10 +199,11 @@ /obj/effect/proc_holder/changeling/sting/blind name = "Blind Sting" desc = "Temporarily blinds the target." - helptext = "This sting completely blinds a target for a short time." + helptext = "This sting completely blinds a target for a short time. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." sting_icon = "sting_blind" chemical_cost = 25 dna_cost = 1 + loudness = 1 /obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target) log_combat(user, target, "stung", "blind sting") @@ -229,10 +233,11 @@ /obj/effect/proc_holder/changeling/sting/cryo name = "Cryogenic Sting" desc = "We silently sting a human with a cocktail of chemicals that freeze them." - helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing." + helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat." sting_icon = "sting_cryo" chemical_cost = 15 dna_cost = 2 + loudness = 1 /obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target) log_combat(user, target, "stung", "cryo sting") diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm index 41f501e346..530c4c5662 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm @@ -194,10 +194,12 @@ else L.visible_message("[L]'s eyes blaze with brilliant light!", \ "Your vision suddenly screams with white-hot light!") - L.Knockdown(160) - L.adjustStaminaLoss(140) // now kindle works pretty much like bloodcult stun knockdown and stamcrit wise + L.Knockdown(15, TRUE, FALSE, 15) L.apply_status_effect(STATUS_EFFECT_KINDLE) L.flash_act(1, 1) + if(issilicon(target)) + var/mob/living/silicon/S = L + S.emp_act(EMP_HEAVY) if(iscultist(L)) L.adjustFireLoss(15) ..() diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 51c8803cee..274273fdcf 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -185,6 +185,9 @@ structure_check() searches for nearby cultist structures required for the invoca color = RUNE_COLOR_OFFER req_cultists = 1 rune_in_use = FALSE + var/mob/living/currentconversionman + var/conversiontimeout + var/conversionresult /obj/effect/rune/convert/do_invoke_glow() return @@ -241,6 +244,21 @@ structure_check() searches for nearby cultist structures required for the invoca to_chat(M, "Something is shielding [convertee]'s mind!") log_game("Offer rune failed - convertee had anti-magic") return 0 + to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \ + and something evil takes root.") + to_chat(convertee, "Do you wish to embrace the Geometer of Blood? Click here to stop resisting the truth. Or you could choose to continue resisting...") + currentconversionman = convertee + conversiontimeout = world.time + (10 SECONDS) + convertee.Stun(100) + conversionresult = FALSE + while(world.time < conversiontimeout && convertee && !conversionresult) + stoplag(1) + currentconversionman = null + if(convertee && get_turf(convertee) != get_turf(src)) + return FALSE + if(!conversionresult && convertee) + do_sacrifice(convertee, invokers) + return FALSE var/brutedamage = convertee.getBruteLoss() var/burndamage = convertee.getFireLoss() if(brutedamage || burndamage) @@ -252,8 +270,6 @@ structure_check() searches for nearby cultist structures required for the invoca SSticker.mode.add_cultist(convertee.mind, 1) new /obj/item/melee/cultblade/dagger(get_turf(src)) convertee.mind.special_role = ROLE_CULTIST - to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \ - and something evil takes root.") to_chat(convertee, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\ ") if(ishuman(convertee)) @@ -313,6 +329,12 @@ structure_check() searches for nearby cultist structures required for the invoca sacrificial.gib() return TRUE +/obj/effect/rune/convert/Topic(href, href_list) + if(href_list["signmeup"]) + if(currentconversionman == usr) + conversionresult = TRUE + else + to_chat(usr, "Your fate has already been set in stone.") /obj/effect/rune/empower @@ -442,9 +464,9 @@ structure_check() searches for nearby cultist structures required for the invoca //Ritual of Dimensional Rending: Calls forth the avatar of Nar'Sie upon the station. /obj/effect/rune/narsie cultist_name = "Nar'Sie" - cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers." + cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers, minus one for every 3 sacrifices." invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!" - req_cultists = 9 + req_cultists = 1 icon = 'icons/effects/96x96.dmi' color = RUNE_COLOR_DARKRED icon_state = "rune_large" @@ -471,6 +493,10 @@ structure_check() searches for nearby cultist structures required for the invoca if(!is_station_level(z)) return var/mob/living/user = invokers[1] + if(invokers.len < 9 - (GLOB.sacrificed.len * 0.35)) + to_chat(user, "You need at least [(9 - (GLOB.sacrificed.len * 0.35)) - invokers.len] more adjacent cultists to use this rune in such a manner.") + fail_invoke() + return var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE) var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives var/area/place = get_area(src) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm index 6bafba9abc..07ee17a1bd 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm @@ -61,6 +61,8 @@ //Actually transfer the gas var/datum/gas_mixture/removed = air2.remove(transfer_moles) + removed.react(src) + update_parents() return removed diff --git a/code/modules/cargo/bounties/engineering.dm b/code/modules/cargo/bounties/engineering.dm index 8b73ebac4b..eb1764d482 100644 --- a/code/modules/cargo/bounties/engineering.dm +++ b/code/modules/cargo/bounties/engineering.dm @@ -24,6 +24,19 @@ description = "Station 49 is looking to kickstart their research program. Ship them a tank full of Tritium." gas_type = /datum/gas/tritium +/datum/bounty/item/engineering/pacman + name = "P.A.C.M.A.N.-type portable generator" + description = "A neighboring station had a problem with their SMES, and now need something to power their communications console. Can you send them a P.AC.M.A.N.?" + reward = 3500 //2500 for the cargo one + wanted_types = list(/obj/machinery/power/port_gen/pacman) + +/datum/bounty/item/engineering/canisters + name = "Gas Canisters" + description = "After a recent debacle in a nearby sector, 10 gas canisters are needed for containing an experimental aerosol before it kills all the local fauna." + reward = 5000 + required_count = 10 //easy to make + wanted_types = list(/obj/machinery/portable_atmospherics/canister) + /datum/bounty/item/engineering/energy_ball name = "Contained Tesla Ball" description = "Station 24 is being overrun by hordes of angry Mothpeople. They are requesting the ultimate bug zapper." diff --git a/code/modules/cargo/bounties/medical.dm b/code/modules/cargo/bounties/medical.dm index d139775969..3129051754 100644 --- a/code/modules/cargo/bounties/medical.dm +++ b/code/modules/cargo/bounties/medical.dm @@ -57,3 +57,71 @@ description = "Central Command has run out of heavy duty pipe cleaners. Can you ship over a cat tail to help us out?" reward = 3000 wanted_types = list(/obj/item/organ/tail/cat) + +/datum/bounty/item/medical/blood + name = "Generic Blood" + description = "Nanotrasen's annual blood drive is back up to full speed, following the garlic incident. Good blood in good volumes accepted for Credit returns." + reward = 3500 + required_count = 600 + wanted_types = list(/datum/reagent/blood) + +/* If anyone wants to try and fix/work, go for it +/datum/bounty/item/medical/medibot // Mob so this dosn't work yet* + name = "Medibot" + description = "A sister station is dealing with um problem, they need a medibot to help treat their wounded..." + reward = 3000 + wanted_types = list(/mob/living/simple_animal/bot/medbot) + +/datum/bounty/item/medical/bloodl //Dosnt work do to how blood is yet* + name = "L-type Blood" + description = "After a small scuffle, a few of our lizard employees need another blood transfusion." + reward = 4000 + required_count = 200 + wanted_types = (L,/datum/reagent/blood) + if(istype(L,/datum/reagent/blood)) + wanted_types += L + +/datum/bounty/item/medical/bloodu //Dosnt work do to how blood is yet* + name = "U-Type Blood" + description = "After dealing with a small revolt in a local penal colony, the colony's anemic CMO needs blood, urgently. With his compromised immune system, only the best blood can be used." + reward = 5500 // Rarer blood + required_count = 200 + wanted_types = (U,/datum/reagent/blood) + if(istype(U,/datum/reagent/blood)) + wanted_types += U + +*/ + +/datum/bounty/item/medical/surgery + name = "Surgery tool implants" + description = "Our medical interns keep dropping their Shambler's Juice while they're performing open heart surgery. One of them even had the audacity to say he only had two hands!" + reward = 10000 + required_count = 3 + wanted_types = list(/obj/item/organ/cyberimp/arm/surgery) + +/datum/bounty/item/medical/chemmaker + name = "Portable Chem Dispenser" + description = "After a new chemist mixed up some water and a banana, we lost our only chem dispenser. Please send us a replacement and you will be compensated." + reward = 7000 + wanted_types = list(/obj/machinery/chem_dispenser) + +/datum/bounty/item/medical/advhealthscaner + name = "Advanced Health Analyzer" + description = "A ERT Medical unit needs the new 'advanced health analyzer', for a mission at a Station 4. Can you send some?." + reward = 4000 + required_count = 5 + wanted_types = list(/obj/item/healthanalyzer/advanced) + +/datum/bounty/item/medical/wallmounts + name = "Defibrillator wall mounts" + description = "New Space OSHA regulation state that are new cloning medical wing needs a few 'Easy to access defibrillartors'. Can you send a few before we get a lawsuit?" + reward = 5000 + required_count = 3 + wanted_types = list(/obj/machinery/defibrillator_mount) + +/datum/bounty/item/medical/defibrillator + name = "New defibillators" + description = "After years of storge are defibrillator units have become more liabilities then we want. Please send us some new ones to replace these old ones." + reward = 5000 + required_count = 5 + wanted_types = list(/obj/item/defibrillator) diff --git a/code/modules/cargo/bounties/mining.dm b/code/modules/cargo/bounties/mining.dm index 1b8b46734f..51d93f83b5 100644 --- a/code/modules/cargo/bounties/mining.dm +++ b/code/modules/cargo/bounties/mining.dm @@ -49,3 +49,17 @@ reward = 5000 required_count = 3 wanted_types = list(/obj/item/kitchen/knife/combat/bone) + +/datum/bounty/item/mining/basalt + name = "Artificial Basalt Tiles" + description = "Central Command's Ash Walker exhibit needs to be expanded again, we just need some more basalt flooring." + reward = 5000 + required_count = 60 + wanted_types = list(/obj/item/stack/tile/basalt) + +/datum/bounty/item/mining/fruit + name = "Cactus Fruit" + description = "Central Command's Ash Walker habitat needs more fauna, send us some local fruit seeds!" + reward = 2000 + required_count = 1 + wanted_types = list(/obj/item/seeds/lavaland/cactus) diff --git a/code/modules/cargo/bounties/science.dm b/code/modules/cargo/bounties/science.dm index 33f334ac47..2ac79f6ee8 100644 --- a/code/modules/cargo/bounties/science.dm +++ b/code/modules/cargo/bounties/science.dm @@ -64,3 +64,55 @@ description = "With the price of rechargers on the rise, upper management is interested in purchasing guns that are self-powered. If you ship one, they'll pay." reward = 10000 wanted_types = list(/obj/item/gun/energy/e_gun/nuclear) + +/datum/bounty/item/science/bscells + name = "Bluespace Power Cells" + description = "Someone in upper management keeps using the excuse that his tablet battery dies when he's in the middle of work. This will be the last time he doesn't have his presentation, I swear to -" + reward = 7000 + required_count = 10 //Easy to make + wanted_types = list(/obj/item/stock_parts/cell/bluespace) + +/datum/bounty/item/science/t4manip + name = "Femto-Manipulators" + description = "One of our Chief Engineers has OCD. Can you send us some femto-manipulators so he stops complaining that his ID doesn't fit perfectly in the PDA slot?" + reward = 7000 + required_count = 20 //Easy to make + wanted_types = list(/obj/item/stock_parts/manipulator/femto) + +/datum/bounty/item/science/t4bins + name = "Bluespace Matter Bins" + description = "The local Janitorial union has gone on strike. Can you send us some bluespace bins so we don't have to take out our own trash?" + reward = 7000 + required_count = 20 //Easy to make + wanted_types = list(/obj/item/stock_parts/matter_bin/bluespace) + +/datum/bounty/item/science/t4capacitor + name = "Quadratic Capacitor" + description = "One of our linguists doesn't understand why they're called Quadratic capacitors. Can you give him a few so he leaves us alone about it?" + reward = 7000 + required_count = 20 //Easy to make + wanted_types = list(/obj/item/stock_parts/capacitor/quadratic) + +/datum/bounty/item/science/t4triphasic + name = "Triphasic Scanning Module" + description = "One of our scientists got into the liberty caps and is demanding new scanning modules so he can talk to ghosts. At this point we just want him out of our office." + reward = 7000 + required_count = 20 //Easy to make + wanted_types = list(/obj/item/stock_parts/scanning_module/triphasic) + +/datum/bounty/item/science/t4microlaser + name = "Quad-Ultra Micro-Laser" + description = "The cats on Vega 9 are breeding out of control. We need something to corral them into one area so we can saturation bomb it." + reward = 7000 + required_count = 20 //Easy to make + wanted_types = list(/obj/item/stock_parts/micro_laser/quadultra) + +/datum/bounty/item/science/fakecrystals + name = "synthetic bluespace crystals" + description = "Don't, uh, tell anyone, but one of our BSA arrays might have had a little... accident. Send us some bluespace crystals so we can recalibrate it before anyone realizes. The whole set uses artificial bluespace crystals, so we need and not any other type of bluespace crystals..." + reward = 10000 + required_count = 5 + wanted_types = list(/obj/item/stack/ore/bluespace_crystal/artificial) + exclude_types = list(/obj/item/stack/ore/bluespace_crystal, + /obj/item/stack/sheet/bluespace_crystal, + /obj/item/stack/ore/bluespace_crystal/refined) diff --git a/code/modules/cargo/bounties/security.dm b/code/modules/cargo/bounties/security.dm index bcf7b89f3a..cae8d10c61 100644 --- a/code/modules/cargo/bounties/security.dm +++ b/code/modules/cargo/bounties/security.dm @@ -11,3 +11,44 @@ reward = 2000 required_count = 3 wanted_types = list(/obj/machinery/recharger) + +/datum/bounty/item/security/practice + name = "Practice Laser Gun" + description = "Nanotrasen Military Academy is conducting routine marksmanship exercises. The clown hid all the practice lasers, and we're not using live weapons after last time." + reward = 3000 + required_count = 3 + wanted_types = list(/obj/item/gun/energy/laser/practice) + +/datum/bounty/item/security/flashshield + name = "Strobe Shield" + description = "One of our Emergency Response Agents thinks there's vampires in a local station. Send him something to help with his fear of the dark and protect him, too." + reward = 5000 + wanted_types = list(/obj/item/assembly/flash/shield) + +/datum/bounty/item/security/sechuds + name = "Sec HUDs" + description = "Nanotrasen military academy has started to train officers how to use Sec HUDs to the fullest affect. Please send spare Sec HUDs so we can teach the men." + reward = 3000 + required_count = 5 + wanted_types = list(/obj/item/clothing/glasses/hud/security) + +/datum/bounty/item/security/techslugs + name = "Tech Slugs" + description = "Nanotrasen Military Academy is conducting an ammo loading and use lessons, on the new 'Tech Slugs'. Problem is we don't have any, please fix this..." + reward = 7500 + required_count = 15 + wanted_types = list(/obj/item/ammo_casing/shotgun/techshell) + +/datum/bounty/item/security/WT550 + name = "Spare WT-550 clips" + description = "Nanotrasen Military Academy's ammunition is running low, please send in spare ammo for practice." + reward = 7500 + required_count = 5 + wanted_types = list(/obj/item/ammo_box/magazine/wt550m9) + +/datum/bounty/item/security/pins + name = "Test range firing pins" + description = "Nanotrasen Military Academy just got a new set of guns, sadly they didn't come with any pins. Can you send us some Test range locked firing pins?" + reward = 5000 + required_count = 3 + wanted_types = list(/obj/item/firing_pin/test_range) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 42b3509872..a9972ca2d4 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -622,7 +622,7 @@ /datum/supply_pack/security/armory/wt550 - name = "WT-550 Auto Rifle Crate" + name = "WT-550 Semi-Auto Rifle Crate" desc = "Contains two high-powered, semiautomatic rifles chambered in 4.6x30mm. Requires Armory access to open." cost = 3500 contains = list(/obj/item/gun/ballistic/automatic/wt550, @@ -630,8 +630,8 @@ crate_name = "auto rifle crate" /datum/supply_pack/security/armory/wt550ammo - name = "WT-550 Auto Rifle Ammo Crate" - desc = "Contains four 20-round magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." + name = "WT-550 Semi-Auto SMG Ammo Crate" + desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." cost = 2500 contains = list(/obj/item/ammo_box/magazine/wt550m9, /obj/item/ammo_box/magazine/wt550m9, @@ -639,9 +639,9 @@ /obj/item/ammo_box/magazine/wt550m9) crate_name = "auto rifle ammo crate" -/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 11 shots to stun crit someone - name = "WT-550 Auto Rifle Non-Lethal Ammo Crate" - desc = "Contains four 20-round magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." +/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 12 shots to stun crit someone + name = "WT-550 Semi-Auto SMG Non-Lethal Ammo Crate" + desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." cost = 1500 contains = list(/obj/item/ammo_box/magazine/wt550m9/wtrubber, /obj/item/ammo_box/magazine/wt550m9/wtrubber, @@ -650,8 +650,8 @@ crate_name = "auto rifle ammo crate" /datum/supply_pack/security/armory/wt550ammo_special - name = "WT-550 Auto Rifle Special Ammo Crate" - desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." + name = "WT-550 Semi-Auto SMG Special Ammo Crate" + desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open." cost = 4500 contains = list(/obj/item/ammo_box/magazine/wt550m9/wtap, /obj/item/ammo_box/magazine/wt550m9/wtap, @@ -1500,7 +1500,7 @@ /obj/item/flashlight/lamp, /obj/item/flashlight/lamp/green, /obj/item/storage/box/lights/mixed) - crate_name = "advanced lighting crate" + crate_name = "advanced lighting crate" crate_type = /obj/structure/closet/crate/secure /datum/supply_pack/service/cargo_supples @@ -1724,6 +1724,39 @@ crate_name = "beekeeping starter crate" crate_type = /obj/structure/closet/crate/hydroponics +/datum/supply_pack/organic/candy + name = "Candy Crate" + desc = "For people that have a insatiable sweet tooth! Has ten candies to be eaten up.." + cost = 2500 + var/num_contained = 10 //number of items picked to be contained in a randomised crate + contains = list(/obj/item/reagent_containers/food/snacks/candy, + /obj/item/reagent_containers/food/snacks/lollipop, + /obj/item/reagent_containers/food/snacks/gumball, + /obj/item/reagent_containers/food/snacks/chocolateegg, + /obj/item/reagent_containers/food/snacks/donut, + /obj/item/reagent_containers/food/snacks/cookie, + /obj/item/reagent_containers/food/snacks/sugarcookie, + /obj/item/reagent_containers/food/snacks/chococornet, + /obj/item/reagent_containers/food/snacks/mint, + /obj/item/reagent_containers/food/snacks/spiderlollipop, + /obj/item/reagent_containers/food/snacks/chococoin, + /obj/item/reagent_containers/food/snacks/fudgedice, + /obj/item/reagent_containers/food/snacks/chocoorange, + /obj/item/reagent_containers/food/snacks/honeybar, + /obj/item/reagent_containers/food/snacks/tinychocolate, + /obj/item/reagent_containers/food/snacks/spacetwinkie, + /obj/item/reagent_containers/food/snacks/syndicake, + /obj/item/reagent_containers/food/snacks/cheesiehonkers, + /obj/item/reagent_containers/food/snacks/sugarcookie/spookyskull, + /obj/item/reagent_containers/food/snacks/sugarcookie/spookycoffin, + /obj/item/reagent_containers/food/snacks/candy_corn, + /obj/item/reagent_containers/food/snacks/candiedapple, + /obj/item/reagent_containers/food/snacks/chocolatebar, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/storage/fancy/heart_box, + /obj/item/storage/fancy/donut_box) + crate_name = "candy crate" + /datum/supply_pack/organic/cutlery name = "Kitchen Cutlery Deluxe Set" desc = "Need to slice and dice away those ''Tomatos'' well we got what you need! From a nice set of knifes, forks, plates, glasses, and a whetstone for when you got some grizzle that is a bit harder to slice then normal." @@ -1892,6 +1925,27 @@ crate_name = "seeds crate" crate_type = /obj/structure/closet/crate/hydroponics +/datum/supply_pack/organic/vday + name = "Surplus Valentine Crate" + desc = "Turns out we got warehouses of this love-y dove-y crap. Were sending out small barged buddle of Valentine gear. This crate has two boxes of chocolate, three poppy flowers, five candy hearts, and three cards." + cost = 3000 + contraband = TRUE + contains = list(/obj/item/storage/fancy/heart_box, + /obj/item/storage/fancy/heart_box, + /obj/item/reagent_containers/food/snacks/grown/poppy, + /obj/item/reagent_containers/food/snacks/grown/poppy, + /obj/item/reagent_containers/food/snacks/grown/poppy, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/reagent_containers/food/snacks/candyheart, + /obj/item/valentine, + /obj/item/valentine, + /obj/item/valentine) + crate_name = "valentine crate" + crate_type = /obj/structure/closet/crate/secure + /datum/supply_pack/organic/exoticseeds name = "Exotic Seeds Crate" desc = "Any entrepreneuring botanist's dream. Contains twelve different seeds, including three replica-pod seeds and two mystery seeds!" @@ -2303,69 +2357,11 @@ desc = "Plush tide station wide. Contains 5 random plushies for you to love. Warranty void if your love violates the terms of use." cost = 1500 // or play the arcade machines ya lazy bum num_contained = 5 - contains = list(/obj/item/toy/plush/lizardplushie, - /obj/item/toy/plush/lizardplushie/durgit, - /obj/item/toy/plush/lizardplushie/rio, - /obj/item/toy/plush/lizardplushie/urinsu, - /obj/item/toy/plush/lizardplushie/arfrehn, - /obj/item/toy/plush/lizardplushie/soars, - /obj/item/toy/plush/lizardplushie/ghostie, - /obj/item/toy/plush/lizardplushie/amber, - /obj/item/toy/plush/lizardplushie/cyan, - /obj/item/toy/plush/lizardplushie/meena, - /obj/item/toy/plush/lizardplushie/stalks, - /obj/item/toy/plush/lizardplushie/kobold, - /obj/item/toy/plush/lizardplushie/gorgi, - /obj/item/toy/plush/lizardplushie/almaz, - /obj/item/toy/plush/snakeplushie/sasha, - /obj/item/toy/plush/snakeplushie/shay, - /obj/item/toy/plush/snakeplushie/vulken, - /obj/item/toy/plush/mothplushie, - /obj/item/toy/plush/mothplushie/bumble, - /obj/item/toy/plush/mothplushie/nameko, - /obj/item/toy/plush/mothplushie/suru, - /obj/item/toy/plush/xeno, - /obj/item/toy/plush/lampplushie, - /obj/item/toy/plush/borgplushie, - /obj/item/toy/plush/borgplushie/medihound, - /obj/item/toy/plush/borgplushie/scrubpuppy, - /obj/item/toy/plush/borgplushie/seeking, - /obj/item/toy/plush/borgplushie/neeb, - /obj/item/toy/plush/bird, - /obj/item/toy/plush/bird/esela, - /obj/item/toy/plush/bird/jahonna, - /obj/item/toy/plush/bird/krick, - /obj/item/toy/plush/bird/birddi, - /obj/item/toy/plush/bird/jewel, - /obj/item/toy/plush/mammal, - /obj/item/toy/plush/mammal/dubious, - /obj/item/toy/plush/mammal/gladwyn, - /obj/item/toy/plush/mammal/gavin, - /obj/item/toy/plush/mammal/blep, - /obj/item/toy/plush/mammal/circe, - /obj/item/toy/plush/mammal/pavel, - /obj/item/toy/plush/mammal/oten, - /obj/item/toy/plush/mammal/ray, - /obj/item/toy/plush/mammal/dawud, - /obj/item/toy/plush/mammal/edgar, - /obj/item/toy/plush/mammal/frank, - /obj/item/toy/plush/mammal/poojawa, - /obj/item/toy/plush/mammal/hazel, - /obj/item/toy/plush/mammal/jermaine, - /obj/item/toy/plush/mammal/gunther, - /obj/item/toy/plush/mammal/fox, - /obj/item/toy/plush/mammal/zed, - /obj/item/toy/plush/mammal/dog, - /obj/item/toy/plush/mammal/dog/frost, - /obj/item/toy/plush/mammal/dog/atticus, - /obj/item/toy/plush/mammal/dog/fletch, - /obj/item/toy/plush/mammal/dog/vincent, - /obj/item/toy/plush/mammal/dog/zigfried, - /obj/item/toy/plush/mammal/dog/nikolai, - /obj/item/toy/plush/catgirl, - /obj/item/toy/plush/catgirl/skylar, - /obj/item/toy/plush/catgirl/mikeel, - /obj/item/toy/plush/catgirl/robin) + contains = list(/obj/item/toy/plush/random, + /obj/item/toy/plush/random, + /obj/item/toy/plush/random, + /obj/item/toy/plush/random, + /obj/item/toy/plush/random) //I'm lazy crate_name = "plushie crate" crate_type = /obj/structure/closet/crate/wooden diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index c85eb95b05..7216b73af6 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -72,4 +72,6 @@ var/list/credits //lazy list of all credit object bound to this client - var/datum/player_details/player_details //these persist between logins/logouts during the same round. \ No newline at end of file + var/datum/player_details/player_details //these persist between logins/logouts during the same round. + + var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 85d1b4f150..06f23574e1 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -454,6 +454,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) GLOB.ahelp_tickets.ClientLogout(src) GLOB.directory -= ckey GLOB.clients -= src + QDEL_LIST_ASSOC_VAL(char_render_holders) if(movingmob != null) movingmob.client_mobs_in_contents -= mob UNSETEMPTY(movingmob.client_mobs_in_contents) @@ -498,7 +499,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) qdel(query_client_in_db) return if(!query_client_in_db.NextRow()) - if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey]) + if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !(ckey in GLOB.bunker_passthrough)) log_access("Failed Login: [key] - New account attempting to connect during panic bunker") message_admins("Failed Login: [key] - New account attempting to connect during panic bunker") to_chat(src, "You must first join the Discord to verify your account before joining this server.
To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: https://discord.gg/E6SQuhz
") //CIT CHANGE - makes the panic bunker disconnect message point to the discord @@ -877,3 +878,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) /client/proc/AnnouncePR(announcement) if(prefs && prefs.chat_toggles & CHAT_PULLR) to_chat(src, announcement) + +/client/proc/show_character_previews(mutable_appearance/MA) + var/pos = 0 + for(var/D in GLOB.cardinals) + pos++ + var/obj/screen/O = LAZYACCESS(char_render_holders, "[D]") + if(!O) + O = new + LAZYSET(char_render_holders, "[D]", O) + screen |= O + O.appearance = MA + O.dir = D + O.screen_loc = "character_preview_map:0,[pos]" + +/client/proc/clear_character_previews() + for(var/index in char_render_holders) + var/obj/screen/S = char_render_holders[index] + screen -= S + qdel(S) + char_render_holders = null diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 53a8d84af2..f245dd330e 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1,2119 +1,2212 @@ - /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\ - | THIS FILE CONTAINS HOOKS FOR FOR | - | CHANGES SPECIFIC TO CITADEL. IF | - | YOU'RE FIXING A MERGE CONFLICT | - | HERE, PLEASE ASK FOR REVIEW FROM | - | ANOTHER MAINTAINER TO ENSURE YOU | - | DON'T INTRODUCE REGRESSIONS. | - \* */ - -GLOBAL_LIST_EMPTY(preferences_datums) - -/datum/preferences - var/client/parent - //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 = 8 - - //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 - var/enable_tips = TRUE - var/tip_delay = 500 //tip delay in milliseconds - - //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 = null - var/buttons_locked = FALSE - var/hotkeys = FALSE - var/tgui_fancy = TRUE - var/tgui_lock = TRUE - var/windowflashing = TRUE - var/toggles = TOGGLES_DEFAULT - var/db_flags - var/chat_toggles = TOGGLES_DEFAULT_CHAT - var/ghost_form = "ghost" - var/ghost_orbit = GHOST_ORBIT_CIRCLE - var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION - var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION - var/ghost_hud = 1 - var/inquisitive_ghost = 1 - var/allow_midround_antag = 1 - var/preferred_map = null - var/pda_style = MONO - var/pda_color = "#808000" - - var/uses_glasses_colour = 0 - - //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/underwear = "Nude" //underwear type - var/undershirt = "Nude" //undershirt type - var/socks = "Nude" //socks type - var/backbag = DBACKPACK //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", - "wings" = "None", "frills" = "None", "spines" = "None", - "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain") - - var/list/custom_names = list() - var/prefered_security_department = SEC_DEPT_RANDOM - - //Mob preview - var/icon/preview_icon = null - - //Quirk list - var/list/positive_quirks = list() - var/list/negative_quirks = list() - var/list/neutral_quirks = list() - var/list/all_quirks = list() - var/list/character_quirks = list() - - //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/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants - - // 0 = character settings, 1 = game preferences - var/current_tab = 0 - - var/unlock_content = 0 - - var/list/ignoring = list() - - var/clientfps = 0 - - var/parallax - - var/ambientocclusion = TRUE - var/auto_fit_viewport = TRUE - - var/uplink_spawn_loc = UPLINK_PDA - - var/list/exp = list() - var/list/menuoptions - - var/action_buttons_screen_locs = list() - -/datum/preferences/New(client/C) - parent = C - - for(var/custom_name_id in GLOB.preferences_custom_names) - custom_names[custom_name_id] = get_default_name(custom_name_id) - - UI_style = GLOB.available_ui_styles[1] - if(istype(C)) - if(!IsGuestKey(C.key)) - load_path(C.ckey) - unlock_content = C.IsByondMember() - if(unlock_content) - max_save_slots = 16 - 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. - menuoptions = list() - return - -#define APPEARANCE_CATEGORY_COLUMN "" -#define MAX_MUTANT_ROWS 4 - -/datum/preferences/proc/ShowChoices(mob/user) - if(!user || !user.client) - return - if(current_tab == 2) //CITADEL EDIT, for muh nudies - update_preview_icon(nude=TRUE) - else - update_preview_icon(nude=FALSE) //EDIT END - user << browse_rsc(preview_icon, "previewicon.png") - var/list/dat = list("
") - - dat += "Character Settings" - dat += "Character Appearance" - dat += "Loadout" - 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 - var/unspaced_slots = 0 - for(var/i=1, i<=max_save_slots, i++) - unspaced_slots++ - if(unspaced_slots > 4) - dat += "
" - unspaced_slots = 0 - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) - name = "Character[i]" - dat += "[name] " - dat += "
" - - dat += "

Occupation Choices

" - dat += "Set Occupation Preferences
" - if(CONFIG_GET(flag/roundstart_traits)) - dat += "

Quirk Setup

" - dat += "Configure Quirks
" - dat += "
Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]
" - dat += "

Identity

" - dat += "" - - dat += "
" - if(jobban_isbanned(user, "appearance")) - 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" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" - dat += "Age: [age]
" - - dat += "Special Names:
" - var/old_group - for(var/custom_name_id in GLOB.preferences_custom_names) - var/namedata = GLOB.preferences_custom_names[custom_name_id] - if(!old_group) - old_group = namedata["group"] - else if(old_group != namedata["group"]) - old_group = namedata["group"] - dat += "
" - dat += "[namedata["pref_name"]]: [custom_names[custom_name_id]] " - dat += "
" - dat += "Custom job preferences:
" - dat += "Prefered security department: [prefered_security_department]
" - - dat += "
" - - dat += "
" - - //Character Appearance - if(2) - update_preview_icon(nude=TRUE) - user << browse_rsc(preview_icon, "previewicon.png") - dat += "" - else if(use_skintones || mutant_colors) - dat += "" - - if(HAIR in pref_species.species_traits) - - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Hair Style

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

Facial Hair Style

" - - dat += "[facial_hair_style]
" - dat += "<>
" - dat += "   Change
" - - dat += "" - //Mutant stuff - var/mutant_category = 0 - - if("tail_lizard" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["tail_lizard"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if("mam_tail" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["mam_tail"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("tail_human" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["tail_human"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("snout" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Snout

" - - dat += "[features["snout"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("horns" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Horns

" - - dat += "[features["horns"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - if("frills" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Frills

" - - dat += "[features["frills"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if("spines" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Spines

" - - dat += "[features["spines"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if("body_markings" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Body Markings

" - - dat += "[features["body_markings"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("mam_body_markings" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Species Markings

" - - dat += "[features["mam_body_markings"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - - if("mam_ears" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Ears

" - - dat += "[features["mam_ears"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("ears" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Ears

" - - dat += "[features["ears"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("legs" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Legs

" - - dat += "[features["legs"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("moth_wings" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Moth wings

" - - dat += "[features["moth_wings"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("taur" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tauric Body

" - - dat += "[features["taur"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Wings

" - - dat += "[features["wings"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("xenohead" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Caste Head

" - - dat += "[features["xenohead"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("xenotail" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Tail

" - - dat += "[features["xenotail"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("xenodorsal" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Dorsal Spines

" - - dat += "[features["xenodorsal"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("ipc_screen" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Screen

" - - dat += "[features["ipc_screen"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - if("ipc_antenna" in pref_species.default_features) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Antenna

" - - dat += "[features["ipc_antenna"]]
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(mutant_category) - dat += "" - mutant_category = 0 - - dat += "
" - dat += "
" - dat += "Set Flavor Text
" - if(lentext(features["flavor_text"]) <= 40) - if(!lentext(features["flavor_text"])) - dat += "\[...\]" - else - dat += "[features["flavor_text"]]" - else - dat += "[TextPreview(features["flavor_text"])]...
" - dat += "

Body

" - dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" - dat += "Species:[pref_species.id]
" - dat += "Random Body
" - dat += "Always Random Body: [be_random_body ? "Yes" : "No"]
" - - var/use_skintones = pref_species.use_skintones - if(use_skintones) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Skin Tone

" - - dat += "[skin_tone]
" - - var/mutant_colors - if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits)) - if(!use_skintones) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Body Colors


" - dat += "Primary Color:     Change
" - dat += "Secondary Color:     Change
" - dat += "Tertiary Color:     Change
" - mutant_colors = TRUE - - if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits)) - - if(!use_skintones && !mutant_colors) - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Eye Color

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

Clothing & Equipment

" - - dat += "Underwear:[underwear]
" - dat += "Undershirt:[undershirt]
" - dat += "Socks:[socks]
" - dat += "Backpack:[backbag]
" - dat += "Uplink Location:[uplink_spawn_loc]
" - - dat += "

Genitals

" - if(NOGENITALS in pref_species.species_traits) - dat += "Your species ([pref_species.name]) does not support genitals!
" - else - if(pref_species.use_skintones) - dat += "Genitals use skintone:[features["genitals_use_skintone"] == TRUE ? "Yes" : "No"]
" - dat += "Has Penis:[features["has_cock"] == TRUE ? "Yes" : "No"]
" - if(features["has_cock"] == TRUE) - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Penis Color:   (Skin tone overriding)
" - else - dat += "Penis Color:    Change
" - dat += "Penis Shape: [features["cock_shape"]]
" - dat += "Penis Length: [features["cock_length"]] inch(es)
" - dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"]
" - if(features["has_balls"] == TRUE) - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Testicles Color:   (Skin tone overriding)
" - else - dat += "Testicles Color:    Change
" - dat += "Has Vagina:[features["has_vag"] == TRUE ? "Yes" : "No"]
" - if(features["has_vag"]) - dat += "Vagina Type: [features["vag_shape"]]
" - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Vagina Color:   (Skin tone overriding)
" - else - dat += "Vagina Color:    Change
" - dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"]
" - dat += "Has Breasts:[features["has_breasts"] == TRUE ? "Yes" : "No"]
" - if(features["has_breasts"]) - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Color:   (Skin tone overriding)
" - else - dat += "Color:    Change
" - dat += "Cup Size:[features["breasts_size"]]
" - dat += "Breast Shape:[features["breasts_shape"]]
" - dat += "" - - if (1) // Game Preferences - dat += "" - if(user.client.holder) - dat +="" - dat += "
" - dat += "

General Settings

" - dat += "UI Style: [UI_style]
" - dat += "tgui Monitors: [(tgui_lock) ? "Primary" : "All"]
" - dat += "tgui Style: [(tgui_fancy) ? "Fancy" : "No Frills"]
" - dat += "
" - dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"]
" - dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Default"]
" - dat += "
" - dat += "PDA Color:     Change
" - dat += "PDA Style: [pda_style]
" - dat += "
" - dat += "Ghost Ears: [(chat_toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" - dat += "Ghost Radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "All Messages":"No Messages"]
" - dat += "Ghost Sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" - dat += "Ghost Whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "All Speech" : "Nearest Creatures"]
" - dat += "Ghost PDA: [(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"]
" - dat += "Window Flashing: [(windowflashing) ? "Enabled":"Disabled"]
" - dat += "
" - dat += "Play Admin MIDIs: [(toggles & SOUND_MIDI) ? "Enabled":"Disabled"]
" - dat += "Play Lobby Music: [(toggles & SOUND_LOBBY) ? "Enabled":"Disabled"]
" - dat += "See Pull Requests: [(chat_toggles & CHAT_PULLR) ? "Enabled":"Disabled"]
" - dat += "
" - if(user.client) - if(unlock_content) - dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" - if(unlock_content || check_rights_for(user.client, R_ADMIN)) - dat += "OOC Color:     Change
" - dat += "
" - dat += "

Admin Settings

" - dat += "Adminhelp Sounds: [(toggles & SOUND_ADMINHELP)?"Enabled":"Disabled"]
" - dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"Enabled":"Disabled"]
" - dat += "
" - dat += "Combo HUD Lighting: [(toggles & COMBOHUD_LIGHTING)?"Full-bright":"No Change"]
" - dat += "
" - if(unlock_content) - dat += "Ghost Form: [ghost_form]
" - dat += "Ghost Orbit: [ghost_orbit]
" - var/button_name = "If you see this something went wrong." - switch(ghost_accs) - if(GHOST_ACCS_FULL) - button_name = GHOST_ACCS_FULL_NAME - if(GHOST_ACCS_DIR) - button_name = GHOST_ACCS_DIR_NAME - if(GHOST_ACCS_NONE) - button_name = GHOST_ACCS_NONE_NAME - - dat += "Ghost Accessories: [button_name]
" - switch(ghost_others) - if(GHOST_OTHERS_THEIR_SETTING) - button_name = GHOST_OTHERS_THEIR_SETTING_NAME - if(GHOST_OTHERS_DEFAULT_SPRITE) - button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME - if(GHOST_OTHERS_SIMPLE) - button_name = GHOST_OTHERS_SIMPLE_NAME - - dat += "Ghosts of Others: [button_name]
" - dat += "
" - dat += "FPS: [clientfps]
" - dat += "Parallax (Fancy Space): " - switch (parallax) - if (PARALLAX_LOW) - dat += "Low" - if (PARALLAX_MED) - dat += "Medium" - if (PARALLAX_INSANE) - dat += "Insane" - if (PARALLAX_DISABLE) - dat += "Disabled" - else - dat += "High" - dat += "
" - dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
" - dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
" - - if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation)) - var/p_map = preferred_map - if (!p_map) - p_map = "Default" - if (config.defaultmap) - p_map += " ([config.defaultmap.map_name])" - else - if (p_map in config.maplist) - var/datum/map_config/VM = config.maplist[p_map] - if (!VM) - p_map += " (No longer exists)" - else - p_map = VM.map_name - else - p_map += " (No longer exists)" - if(CONFIG_GET(flag/allow_map_voting)) - dat += "Preferred Map: [p_map]
" - - dat += "" - - dat += "

Special Role Settings

" - - if(jobban_isbanned(user, ROLE_SYNDICATE)) - dat += "You are banned from antagonist roles." - src.be_special = list() - - - for (var/i in GLOB.special_roles) - if(jobban_isbanned(user, i)) - dat += "Be [capitalize(i)]: BANNED
" - else - var/days_remaining = null - if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age - var/mode_path = GLOB.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) ? "Enabled" : "Disabled"]
" - dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"]
" - - dat += "
" - dat += "

Citadel Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. - dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" - dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"]
" - dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]
" - dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"]
" - dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]
" - dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]
" - dat += "Auto stand: [autostand ? "Enabled" : "Disabled"]
" - dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]
" - if (user && user.client && !user.client.prefs.screenshake==0) - dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]
" - dat += "
" - - if(3) - if(!gear_tab) - gear_tab = GLOB.loadout_items[1] - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - for(var/j in GLOB.loadout_items[gear_tab]) - var/datum/gear/gear = GLOB.loadout_items[gear_tab][j] - var/donoritem - if(gear.ckeywhitelist && gear.ckeywhitelist.len) - donoritem = TRUE - if(!(user.ckey in gear.ckeywhitelist)) - continue - var/class_link = "" - if(gear.type in chosen_gear) - class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'" - else if(gear_points <= 0) - class_link = "style='white-space:normal;' class='linkOff'" - else if(donoritem) - class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'" - else - class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'" - dat += "" - dat += "" - dat += "
[gear_points] loadout points remaining. \[Clear Loadout\]
You can only choose one item per category, unless it's an item that spawns in your backpack or hands.
" - var/firstcat = TRUE - for(var/i in GLOB.loadout_items) - if(firstcat) - firstcat = FALSE - else - dat += " |" - if(i == gear_tab) - dat += " [i] " - else - dat += " [i] " - dat += "

[gear_tab]

NameCostRestrictionsDescription
[j][gear.cost]" - if(islist(gear.restricted_roles)) - if(gear.restricted_roles.len) - dat += "" - dat += gear.restricted_roles.Join(";") - dat += "" - dat += "[gear.description]
" - - dat += "
" - - if(!IsGuestKey(user.key)) - dat += "Undo " - dat += "Save Setup " - - dat += "Reset Setup" - dat += "
" - - var/datum/browser/popup = new(user, "preferences", "
Character Setup
", 640, 770) - popup.set_content(dat.Join()) - popup.open(0) - -#undef APPEARANCE_CATEGORY_COLUMN -#undef MAX_MUTANT_ROWS - -/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 = "
" - if(SSjob.occupations.len <= 0) - HTML += "The job SSticker is not yet finished creating jobs, please try again later" - HTML += "
Done

" // Easier to press up here. - - else - 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 - - var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role) - - 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 - var/required_playtime_remaining = job.required_playtime_remaining(user.client) - if(required_playtime_remaining) - HTML += "[rank]" - 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 & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) - HTML += "[rank]" - continue - if((rank in GLOB.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
\[ [get_exp_format(required_playtime_remaining)] as [job.get_exp_req_type()] \]
\[IN [(available_in_days)] DAYS\]
" - - 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 == SSjob.overflow_role)//Overflow is special - if(job_civilian_low & overflow.flag) - HTML += "Yes" - else - HTML += "No" - HTML += "
  
" - HTML += "
" - - var/message = "Be an [SSjob.overflow_role] if preferences unavailable" - if(joblessrole == BERANDOMJOB) - message = "Get random job if preferences unavailable" - else if(joblessrole == RETURNTOLOBBY) - message = "Return to lobby if preferences unavailable" - HTML += "

[message]
" - HTML += "
Reset Preferences
" - - user << browse(null, "window=preferences") - 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 || SSjob.occupations.len <= 0) - return - var/datum/job/job = SSjob.GetJob(role) - - if(!job) - user << browse(null, "window=mob_occupation") - ShowChoices(user) - return - - if (!isnum(desiredLvl)) - to_chat(user, "UpdateJobPreference - desired level was not a number. Please notify coders!") - ShowChoices(user) - return - - if(role == SSjob.overflow_role) - 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/SetQuirks(mob/user) - if(!SSquirks) - to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.") - return - - var/list/dat = list() - if(!SSquirks.quirks.len) - dat += "The quirk subsystem hasn't finished initializing, please hold..." - dat += "
Done

" - - else - dat += "
Choose quirk setup

" - dat += "
Left-click to add or remove quirks. You need negative quirks to have positive ones.
\ - Quirks are applied at roundstart and cannot normally be removed.
" - dat += "
Done
" - dat += "
" - dat += "
Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]
" - dat += "
[positive_quirks.len] / [MAX_QUIRKS] max positive quirks
\ - Quirk balance remaining: [GetQuirkBalance()]

" - for(var/V in SSquirks.quirks) - var/datum/quirk/T = SSquirks.quirks[V] - var/quirk_name = initial(T.name) - var/has_quirk - var/quirk_cost = initial(T.value) * -1 - var/lock_reason = "This trait is unavailable." - var/quirk_conflict = FALSE - for(var/_V in all_quirks) - if(_V == quirk_name) - has_quirk = TRUE - if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood)) - lock_reason = "Mood is disabled." - quirk_conflict = TRUE - if(has_quirk) - if(quirk_conflict) - all_quirks -= quirk_name - has_quirk = FALSE - else - quirk_cost *= -1 //invert it back, since we'd be regaining this amount - if(quirk_cost > 0) - quirk_cost = "+[quirk_cost]" - var/font_color = "#AAAAFF" - if(initial(T.value) != 0) - font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA" - if(quirk_conflict) - dat += "[quirk_name] - [initial(T.desc)] \ - LOCKED: [lock_reason]
" - else - if(has_quirk) - dat += "[quirk_name] - [initial(T.desc)] \ - [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.)
" - else - dat += "[quirk_name] - [initial(T.desc)] \ - [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.)
" - dat += "
Reset Traits
" - - user << browse(null, "window=preferences") - var/datum/browser/popup = new(user, "mob_occupation", "
Quirk Preferences
", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way - popup.set_window_options("can_close=0") - popup.set_content(dat.Join()) - popup.open(0) - return - -/datum/preferences/proc/GetQuirkBalance() - var/bal = 0 - for(var/V in all_quirks) - var/datum/quirk/T = SSquirks.quirks[V] - bal -= initial(T.value) - return bal - -/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/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'") - if(!query_get_jobban.warn_execute()) - qdel(query_get_jobban) - 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/admin_key = query_get_jobban.item[5] - var/text - text = "You, or another user of this computer, ([user.key]) is banned from playing [job]. The ban reason is:
[reason]
This ban was applied by [admin_key] on [bantime]" - if(text2num(duration) > 0) - text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)" - text += ".
" - to_chat(user, text) - qdel(query_get_jobban) - 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") - switch(joblessrole) - if(RETURNTOLOBBY) - if(jobban_isbanned(user, SSjob.overflow_role)) - joblessrole = BERANDOMJOB - else - joblessrole = BEOVERFLOW - if(BEOVERFLOW) - joblessrole = BERANDOMJOB - if(BERANDOMJOB) - joblessrole = RETURNTOLOBBY - SetChoices(user) - if("setJobLevel") - UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) - else - SetChoices(user) - return 1 - - else if(href_list["preference"] == "trait") - switch(href_list["task"]) - if("close") - user << browse(null, "window=mob_occupation") - ShowChoices(user) - if("update") - var/quirk = href_list["trait"] - if(!SSquirks.quirks[quirk]) - return - var/value = SSquirks.quirk_points[quirk] - if(value == 0) - if(quirk in neutral_quirks) - neutral_quirks -= quirk - all_quirks -= quirk - else - neutral_quirks += quirk - all_quirks += quirk - else - var/balance = GetQuirkBalance() - if(quirk in positive_quirks) - positive_quirks -= quirk - all_quirks -= quirk - else if(quirk in negative_quirks) - if(balance + value < 0) - to_chat(user, "Refunding this would cause you to go below your balance!") - return - negative_quirks -= quirk - all_quirks -= quirk - else if(value > 0) - if(positive_quirks.len >= MAX_QUIRKS) - to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!") - return - if(balance - value < 0) - to_chat(user, "You don't have enough balance to gain this quirk!") - return - positive_quirks += quirk - all_quirks += quirk - else - negative_quirks += quirk - all_quirks += quirk - SetQuirks(user) - if("reset") - all_quirks = list() - positive_quirks = list() - negative_quirks = list() - neutral_quirks = list() - SetQuirks(user) - else - SetQuirks(user) - return TRUE - - 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() - if(BODY_ZONE_PRECISE_EYES) - eye_color = random_eye_color() - if("s_tone") - skin_tone = random_skin_tone() - if("bag") - backbag = pick(GLOB.backbaglist) - if("all") - random_character() - - if("input") - - if(href_list["preference"] in GLOB.preferences_custom_names) - ask_for_custom_name(user,href_list["preference"]) - - - 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 GLOB.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 GLOB.ghost_orbits - if(new_orbit) - ghost_orbit = new_orbit - - if("ghostaccs") - var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME) - switch(new_ghost_accs) - if(GHOST_ACCS_FULL_NAME) - ghost_accs = GHOST_ACCS_FULL - if(GHOST_ACCS_DIR_NAME) - ghost_accs = GHOST_ACCS_DIR - if(GHOST_ACCS_NONE_NAME) - ghost_accs = GHOST_ACCS_NONE - - if("ghostothers") - var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME) - switch(new_ghost_others) - if(GHOST_OTHERS_THEIR_SETTING_NAME) - ghost_others = GHOST_OTHERS_THEIR_SETTING - if(GHOST_OTHERS_DEFAULT_SPRITE_NAME) - ghost_others = GHOST_OTHERS_DEFAULT_SPRITE - if(GHOST_OTHERS_SIMPLE_NAME) - ghost_others = GHOST_OTHERS_SIMPLE - - if("name") - var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null - if(new_name) - new_name = reject_bad_name(new_name) - if(new_name) - real_name = new_name - else - to_chat(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("flavor_text") - var/msg = stripped_multiline_input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE) as null|message - if(!isnull(msg)) - msg = copytext(msg, 1, MAX_MESSAGE_LEN*2) - features["flavor_text"] = msg - - if("hair") - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null - 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 GLOB.hair_styles_male_list - else - new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.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, GLOB.hair_styles_male_list) - else - hair_style = next_list_item(hair_style, GLOB.hair_styles_female_list) - - if("previous_hair_style") - if (gender == MALE) - hair_style = previous_list_item(hair_style, GLOB.hair_styles_male_list) - else - hair_style = previous_list_item(hair_style, GLOB.hair_styles_female_list) - - if("facial") - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null - 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 GLOB.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 GLOB.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, GLOB.facial_hair_styles_male_list) - else - facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list) - if("previous_facehair_style") - if (gender == MALE) - facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list) - else - facial_hair_style = previous_list_item(facial_hair_style, GLOB.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 GLOB.underwear_m - else - new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.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 GLOB.undershirt_m - else - new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_f - if(new_undershirt) - undershirt = new_undershirt - - if("socks") - var/new_socks - new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list - if(new_socks) - socks = new_socks - - if("eyes") - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) 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 GLOB.roundstart_races - if(result) - var/newtype = GLOB.species_list[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.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) - features["mcolor"] = pref_species.default_color - if(features["mcolor2"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) - features["mcolor2"] = pref_species.default_color - if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) - features["mcolor3"] = pref_species.default_color - - if("mutant_color") - var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) 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.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor"] = sanitize_hexcolor(new_mutantcolor) - else - to_chat(user, "Invalid color. Your color is not bright enough.") - - if("mutant_color2") - var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - if(new_mutantcolor == "#000000") - features["mcolor2"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor2"] = sanitize_hexcolor(new_mutantcolor) - else - to_chat(user, "Invalid color. Your color is not bright enough.") - - if("mutant_color3") - var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - if(new_mutantcolor == "#000000") - features["mcolor3"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor3"] = sanitize_hexcolor(new_mutantcolor) - else - to_chat(user, "Invalid color. Your color is not bright enough.") - - if("ipc_screen") - var/new_ipc_screen - new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list - if(new_ipc_screen) - features["ipc_screen"] = new_ipc_screen - - if("ipc_antenna") - var/new_ipc_antenna - new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in GLOB.ipc_antennas_list - if(new_ipc_antenna) - features["ipc_antenna"] = new_ipc_antenna - - if("tail_lizard") - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard - if(new_tail) - features["tail_lizard"] = new_tail - if(new_tail != "None") - features["taur"] = "None" - features["tail_human"] = "None" - features["mam_tail"] = "None" - - if("tail_human") - var/list/snowflake_tails_list = list() - for(var/path in GLOB.tails_list_human) - var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_tails_list[S.name] = path - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list - if(new_tail) - features["tail_human"] = new_tail - if(new_tail != "None") - features["taur"] = "None" - features["tail_lizard"] = "None" - features["mam_tail"] = "None" - - if("mam_tail") - var/list/snowflake_tails_list = list() - for(var/path in GLOB.mam_tails_list) - var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_tails_list[S.name] = path - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list - if(new_tail) - features["mam_tail"] = new_tail - if(new_tail != "None") - features["taur"] = "None" - features["tail_human"] = "None" - features["tail_lizard"] = "None" - - if("snout") - var/new_snout - new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.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 GLOB.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 GLOB.ears_list - if(new_ears) - features["ears"] = new_ears - - if("wings") - var/new_wings - new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list - if(new_wings) - features["wings"] = new_wings - - if("frills") - var/new_frills - new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.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 GLOB.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 GLOB.body_markings_list - if(new_body_markings) - features["body_markings"] = new_body_markings - - if("legs") - var/new_legs - new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list - if(new_legs) - features["legs"] = new_legs - - if("moth_wings") - var/new_moth_wings - new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list - if(new_moth_wings) - features["moth_wings"] = new_moth_wings - - if("s_tone") - var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones - if(new_s_tone) - skin_tone = new_s_tone - - if("taur") - var/list/snowflake_taur_list = list() - for(var/path in GLOB.taur_list) - var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_taur_list[S.name] = path - var/new_taur - new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list - if(new_taur) - features["taur"] = new_taur - if(new_taur != "None") - features["mam_tail"] = "None" - features["xenotail"] = "None" - features["tail_human"] = "None" - features["tail_lizard"] = "None" - - if("ears") - var/list/snowflake_ears_list = list() - for(var/path in GLOB.ears_list) - var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_ears_list[S.name] = path - var/new_ears - new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list - if(new_ears) - features["ears"] = new_ears - - if("mam_ears") - var/list/snowflake_ears_list = list() - for(var/path in GLOB.mam_ears_list) - var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_ears_list[S.name] = path - var/new_ears - new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list - if(new_ears) - features["mam_ears"] = new_ears - - if("mam_body_markings") - var/list/snowflake_markings_list = list() - for(var/path in GLOB.mam_body_markings_list) - var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_markings_list[S.name] = path - var/new_mam_body_markings - new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list - if(new_mam_body_markings) - features["mam_body_markings"] = new_mam_body_markings - - //Xeno Bodyparts - if("xenohead")//Head or caste type - var/new_head - new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list - if(new_head) - features["xenohead"] = new_head - - if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future. - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list - if(new_tail) - features["xenotail"] = new_tail - if(new_tail != "None") - features["mam_tail"] = "None" - features["taur"] = "None" - features["tail_human"] = "None" - features["tail_lizard"] = "None" - - if("xenodorsal") - var/new_dors - new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list - if(new_dors) - features["xenodorsal"] = new_dors - //Genital code - if("cock_color") - var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null - if(new_cockcolor) - var/temp_hsv = RGBtoHSV(new_cockcolor) - if(new_cockcolor == "#000000") - features["cock_color"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) - features["cock_color"] = sanitize_hexcolor(new_cockcolor) - else - user << "Invalid color. Your color is not bright enough." - - if("cock_length") - var/new_length = input(user, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Character Preference") as num|null - if(new_length) - features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN) - - if("cock_shape") - var/new_shape - new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list - if(new_shape) - features["cock_shape"] = new_shape - - if("balls_color") - var/new_ballscolor = input(user, "Testicle Color:", "Character Preference") as color|null - if(new_ballscolor) - var/temp_hsv = RGBtoHSV(new_ballscolor) - if(new_ballscolor == "#000000") - features["balls_color"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) - features["balls_color"] = sanitize_hexcolor(new_ballscolor) - else - user << "Invalid color. Your color is not bright enough." - - if("egg_size") - var/new_size - var/list/egg_sizes = list(1,2,3) - new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes - if(new_size) - features["eggsack_egg_size"] = new_size - - if("egg_color") - var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null - if(new_egg_color) - var/temp_hsv = RGBtoHSV(new_egg_color) - if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) - features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color) - else - user << "Invalid color. Your color is not bright enough." - - if("breasts_size") - var/new_size - new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list - if(new_size) - features["breasts_size"] = new_size - - if("breasts_shape") - var/new_shape - new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list - if(new_shape) - features["breasts_shape"] = new_shape - - if("breasts_color") - var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null - if(new_breasts_color) - var/temp_hsv = RGBtoHSV(new_breasts_color) - if(new_breasts_color == "#000000") - features["breasts_color"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) - features["breasts_color"] = sanitize_hexcolor(new_breasts_color) - else - user << "Invalid color. Your color is not bright enough." - - if("vag_shape") - var/new_shape - new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list - if(new_shape) - features["vag_shape"] = new_shape - - if("vag_color") - var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null - if(new_vagcolor) - var/temp_hsv = RGBtoHSV(new_vagcolor) - if(new_vagcolor == "#000000") - features["vag_color"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) - features["vag_color"] = sanitize_hexcolor(new_vagcolor) - else - user << "Invalid color. Your color is not bright enough." - - if("ooccolor") - var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null - if(new_ooccolor) - ooccolor = new_ooccolor - - if("bag") - var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist - if(new_backbag) - backbag = new_backbag - - if("uplink_loc") - var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list - if(new_loc) - uplink_spawn_loc = new_loc - - if("sec_dept") - var/department = input(user, "Choose your prefered security department:", "Security Departments") as null|anything in GLOB.security_depts_prefs - if(department) - prefered_security_department = department - - if ("preferred_map") - var/maplist = list() - var/default = "Default" - if (config.defaultmap) - default += " ([config.defaultmap.map_name])" - for (var/M in config.maplist) - var/datum/map_config/VM = config.maplist[M] - var/friendlyname = "[VM.map_name] " - if (VM.voteweight <= 0) - friendlyname += " (disabled)" - maplist[friendlyname] = VM.map_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] - - if ("clientfps") - var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num - if (!isnull(desiredfps)) - clientfps = desiredfps - parent.fps = desiredfps - if("ui") - var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles - if(pickedui) - UI_style = pickedui - if (parent && parent.mob && parent.mob.hud_used) - parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style)) - if("pda_style") - var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles - if(pickedPDAStyle) - pda_style = pickedPDAStyle - if("pda_color") - var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null - if(pickedPDAColor) - pda_color = pickedPDAColor - - else - switch(href_list["preference"]) - //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj - if("genital_colour") - features["genitals_use_skintone"] = !features["genitals_use_skintone"] - if("arousable") - arousable = !arousable - if("has_cock") - features["has_cock"] = !features["has_cock"] - if("has_balls") - features["has_balls"] = !features["has_balls"] - if("has_ovi") - features["has_ovi"] = !features["has_ovi"] - if("has_eggsack") - features["has_eggsack"] = !features["has_eggsack"] - if("balls_internal") - features["balls_internal"] = !features["balls_internal"] - if("eggsack_internal") - features["eggsack_internal"] = !features["eggsack_internal"] - if("has_breasts") - features["has_breasts"] = !features["has_breasts"] - if("has_vag") - features["has_vag"] = !features["has_vag"] - if("has_womb") - features["has_womb"] = !features["has_womb"] - if("exhibitionist") - features["exhibitionist"] = !features["exhibitionist"] - if("widescreenpref") - widescreenpref = !widescreenpref - user.client.change_view(CONFIG_GET(string/default_view)) - if("autostand") - autostand = !autostand - if ("screenshake") - var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num - if (!isnull(desiredshake)) - screenshake = desiredshake - if("damagescreenshake") - switch(damagescreenshake) - if(0) - damagescreenshake = 1 - if(1) - damagescreenshake = 2 - if(2) - damagescreenshake = 0 - else - damagescreenshake = 1 - //END CITADEL EDIT - if("publicity") - if(unlock_content) - toggles ^= MEMBER_PUBLIC - if("gender") - var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) in list(MALE,FEMALE,"nonbinary","object") - switch(chosengender) - if("nonbinary") - chosengender = PLURAL - if("object") - chosengender = NEUTER - gender = chosengender - facial_hair_style = random_facial_hair_style(gender) - hair_style = random_hair_style(gender) - - if("hotkeys") - hotkeys = !hotkeys - if(hotkeys) - winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default") - else - winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default") - if("action_buttons") - buttons_locked = !buttons_locked - if("tgui_fancy") - tgui_fancy = !tgui_fancy - if("tgui_lock") - tgui_lock = !tgui_lock - if("winflash") - windowflashing = !windowflashing - if("hear_adminhelps") - toggles ^= SOUND_ADMINHELP - if("announce_login") - toggles ^= ANNOUNCE_LOGIN - if("combohud_lighting") - toggles ^= COMBOHUD_LIGHTING - - 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.client && isnewplayer(user)) - user.client.playtitlemusic() - else - user.stop_sound_channel(CHANNEL_LOBBYMUSIC) - - 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("parallaxup") - parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1) - if (parent && parent.mob && parent.mob.hud_used) - parent.mob.hud_used.update_parallax_pref(parent.mob) - - if("parallaxdown") - parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1) - if (parent && parent.mob && parent.mob.hud_used) - parent.mob.hud_used.update_parallax_pref(parent.mob) - - // Citadel edit - Prefs don't work outside of this. :c - if("hound_sleeper") - cit_toggles ^= MEDIHOUND_SLEEPER - - if("toggleeatingnoise") - cit_toggles ^= EATING_NOISES - - if("toggledigestionnoise") - cit_toggles ^= DIGESTION_NOISES - //END CITADEL EDIT - - if("ambientocclusion") - ambientocclusion = !ambientocclusion - if(parent && parent.screen && parent.screen.len) - var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen - PM.backdrop(parent.mob) - - if("auto_fit_viewport") - auto_fit_viewport = !auto_fit_viewport - if(auto_fit_viewport && parent) - parent.fit_viewport() - - if("save") - save_preferences() - save_character() - - if("load") - load_preferences() - load_character() - if(parent && parent.prefs_vr) - attempt_vr(parent.prefs_vr,"load_vore","") - - if("changeslot") - if(!load_character(text2num(href_list["num"]))) - random_character() - real_name = random_unique_name(gender) - save_character() - if(parent && parent.prefs_vr) - attempt_vr(parent.prefs_vr,"load_vore","") - - if("tab") - if (href_list["tab"]) - current_tab = text2num(href_list["tab"]) - if(href_list["preference"] == "gear") - if(href_list["clear_loadout"]) - LAZYCLEARLIST(chosen_gear) - gear_points = initial(gear_points) - save_preferences() - if(href_list["select_category"]) - for(var/i in GLOB.loadout_items) - if(i == href_list["select_category"]) - gear_tab = i - if(href_list["toggle_gear_path"]) - var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])] - if(!G) - return - var/toggle = text2num(href_list["toggle_gear"]) - if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear) - LAZYREMOVE(chosen_gear, G.type) - gear_points += initial(G.cost) - else if(toggle && (!(is_type_in_ref_list(G, chosen_gear)))) - if(!is_loadout_slot_available(G.category)) - to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!") - return - if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist)) - to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.") - return - if(gear_points >= initial(G.cost)) - LAZYADD(chosen_gear, G.type) - gear_points -= initial(G.cost) - - ShowChoices(user) - return 1 - -/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE) - if(be_random_name) - real_name = pref_species.random_name(gender) - - if(be_random_body) - random_character(gender) - - if(roundstart_checks) - if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == "human")) - var/firstspace = findtext(real_name, " ") - var/name_length = length(real_name) - if(!firstspace) //we need a surname - real_name += " [pick(GLOB.last_names)]" - else if(firstspace == name_length) - real_name += "[pick(GLOB.last_names)]" - - character.real_name = real_name - character.name = character.real_name - - character.gender = gender - character.age = age - - character.eye_color = eye_color - var/obj/item/organ/eyes/organ_eyes = character.getorgan(/obj/item/organ/eyes) - if(organ_eyes) - if(!initial(organ_eyes.eye_color)) - organ_eyes.eye_color = eye_color - organ_eyes.old_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 - - var/datum/species/chosen_species - if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races)) - chosen_species = pref_species.type - else - chosen_species = /datum/species/human - pref_species = new /datum/species/human - save_character() - - character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) - character.dna.features = features.Copy() - character.dna.real_name = character.real_name - - if("tail_lizard" in pref_species.default_features) - character.dna.species.mutant_bodyparts |= "tail_lizard" - else if("mam_tail" in pref_species.default_features) - character.dna.species.mutant_bodyparts |= "mam_tail" - else if("xenotail" in pref_species.default_features) - character.dna.species.mutant_bodyparts |= "xenotail" - - if("legs" in pref_species.default_features) - if(character.dna.features["legs"] == "Digitigrade Legs") - pref_species.species_traits += DIGITIGRADE - character.Digitigrade_Leg_Swap(FALSE) - - if(character.dna.features["legs"] == "Normal Legs" && DIGITIGRADE in pref_species.species_traits) - pref_species.species_traits -= DIGITIGRADE - character.Digitigrade_Leg_Swap(TRUE) - - else if((!"legs" in pref_species.default_features) && DIGITIGRADE in pref_species.species_traits) - pref_species.species_traits -= DIGITIGRADE - character.Digitigrade_Leg_Swap(TRUE) - - if(DIGITIGRADE in pref_species.species_traits) - character.Digitigrade_Leg_Swap(FALSE) - - if(icon_updates) - character.update_body() - character.update_hair() - character.update_body_parts() - -/datum/preferences/proc/get_default_name(name_id) - switch(name_id) - if("human") - return random_unique_name() - if("ai") - return pick(GLOB.ai_names) - if("cyborg") - return DEFAULT_CYBORG_NAME - if("clown") - return pick(GLOB.clown_names) - if("mime") - return pick(GLOB.mime_names) - return random_unique_name() - -/datum/preferences/proc/ask_for_custom_name(mob/user,name_id) - var/namedata = GLOB.preferences_custom_names[name_id] - if(!namedata) - return - - var/raw_name = input(user, "Choose your character's [namedata["qdesc"]]:","Character Preference") as text|null - if(!raw_name) - if(namedata["allow_null"]) - custom_names[name_id] = get_default_name(name_id) - else - return - else - var/sanitized_name = reject_bad_name(raw_name,namedata["allow_numbers"]) - if(!sanitized_name) - to_chat(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,[namedata["allow_numbers"] ? ",0-9," : ""] -, ' and .") - return - else - custom_names[name_id] = sanitized_name + /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\ + | THIS FILE CONTAINS HOOKS FOR FOR | + | CHANGES SPECIFIC TO CITADEL. IF | + | YOU'RE FIXING A MERGE CONFLICT | + | HERE, PLEASE ASK FOR REVIEW FROM | + | ANOTHER MAINTAINER TO ENSURE YOU | + | DON'T INTRODUCE REGRESSIONS. | + \* */ + +GLOBAL_LIST_EMPTY(preferences_datums) + +/datum/preferences + var/client/parent + //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 = 8 + + //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 + var/enable_tips = TRUE + var/tip_delay = 500 //tip delay in milliseconds + + //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 = null + var/buttons_locked = FALSE + var/hotkeys = FALSE + var/tgui_fancy = TRUE + var/tgui_lock = TRUE + var/windowflashing = TRUE + var/toggles = TOGGLES_DEFAULT + var/db_flags + var/chat_toggles = TOGGLES_DEFAULT_CHAT + var/ghost_form = "ghost" + var/ghost_orbit = GHOST_ORBIT_CIRCLE + var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION + var/ghost_others = GHOST_OTHERS_DEFAULT_OPTION + var/ghost_hud = 1 + var/inquisitive_ghost = 1 + var/allow_midround_antag = 1 + var/preferred_map = null + var/pda_style = MONO + var/pda_color = "#808000" + + var/uses_glasses_colour = 0 + + //character preferences + var/real_name //our character's name + var/nameless = FALSE //whether or not our character is nameless + 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/underwear = "Nude" //underwear type + var/undershirt = "Nude" //undershirt type + var/socks = "Nude" //socks type + var/backbag = DBACKPACK //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" = "Cat", + "snout" = "Round", "horns" = "None", "ears" = "Cat", + "wings" = "None", "frills" = "None", "spines" = "None", + "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain") + + var/list/custom_names = list() + var/prefered_security_department = SEC_DEPT_RANDOM + + //Quirk list + var/list/positive_quirks = list() + var/list/negative_quirks = list() + var/list/neutral_quirks = list() + var/list/all_quirks = list() + var/list/character_quirks = list() + + //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/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants + + // 0 = character settings, 1 = game preferences + var/current_tab = 0 + + var/unlock_content = 0 + + var/list/ignoring = list() + + var/clientfps = 0 + + var/parallax + + var/ambientocclusion = TRUE + var/auto_fit_viewport = TRUE + + var/uplink_spawn_loc = UPLINK_PDA + + var/list/exp = list() + var/list/menuoptions + + var/action_buttons_screen_locs = list() + +/datum/preferences/New(client/C) + parent = C + + for(var/custom_name_id in GLOB.preferences_custom_names) + custom_names[custom_name_id] = get_default_name(custom_name_id) + + UI_style = GLOB.available_ui_styles[1] + if(istype(C)) + if(!IsGuestKey(C.key)) + load_path(C.ckey) + unlock_content = C.IsByondMember() + if(unlock_content) + max_save_slots = 16 + 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. + menuoptions = list() + return + +#define APPEARANCE_CATEGORY_COLUMN "" +#define MAX_MUTANT_ROWS 4 + +/datum/preferences/proc/ShowChoices(mob/user) + if(!user || !user.client) + return + update_preview_icon() + var/list/dat = list("
") + + dat += "Character Settings" + dat += "Character Appearance" + dat += "Loadout" + 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 + var/unspaced_slots = 0 + for(var/i=1, i<=max_save_slots, i++) + unspaced_slots++ + if(unspaced_slots > 4) + dat += "
" + unspaced_slots = 0 + S.cd = "/character[i]" + S["real_name"] >> name + if(!name) + name = "Character[i]" + dat += "[name] " + dat += "
" + + dat += "

Occupation Choices

" + dat += "Set Occupation Preferences
" + if(CONFIG_GET(flag/roundstart_traits)) + dat += "

Quirk Setup

" + dat += "Configure Quirks
" + dat += "
Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]
" + dat += "

Identity

" + dat += "" + + dat += "
" + if(jobban_isbanned(user, "appearance")) + 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 += "[nameless ? "Default designation" : "Name"]:" + dat += "[real_name]
" + dat += "Be nameless: [nameless ? "Yes" : "No"]
" + + dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" + dat += "Age: [age]
" + + dat += "Special Names:
" + var/old_group + for(var/custom_name_id in GLOB.preferences_custom_names) + var/namedata = GLOB.preferences_custom_names[custom_name_id] + if(!old_group) + old_group = namedata["group"] + else if(old_group != namedata["group"]) + old_group = namedata["group"] + dat += "
" + dat += "[namedata["pref_name"]]: [custom_names[custom_name_id]] " + dat += "
" + dat += "Custom job preferences:
" + dat += "Prefered security department: [prefered_security_department]
" + + //Character Appearance + if(2) + if(path) + var/savefile/S = new /savefile(path) + if(S) + dat += "
" + var/name + var/unspaced_slots = 0 + for(var/i=1, i<=max_save_slots, i++) + unspaced_slots++ + if(unspaced_slots > 4) + dat += "
" + unspaced_slots = 0 + S.cd = "/character[i]" + S["real_name"] >> name + if(!name) + name = "Character[i]" + dat += "[name] " + dat += "
" + + update_preview_icon() + dat += "" + else if(use_skintones || mutant_colors) + dat += "" + + if(HAIR in pref_species.species_traits) + + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Hair Style

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

Facial Hair Style

" + + dat += "[facial_hair_style]" + dat += "<>
" + dat += "   Change
" + + dat += "" + //Mutant stuff + var/mutant_category = 0 + + if("tail_lizard" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Tail

" + + dat += "[features["tail_lizard"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + + if("mam_tail" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Tail

" + + dat += "[features["mam_tail"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("tail_human" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Tail

" + + dat += "[features["tail_human"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("snout" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Snout

" + + dat += "[features["snout"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("horns" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Horns

" + + dat += "[features["horns"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + if("frills" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Frills

" + + dat += "[features["frills"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + + if("spines" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Spines

" + + dat += "[features["spines"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + + if("body_markings" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Body Markings

" + + dat += "[features["body_markings"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("mam_body_markings" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Species Markings

" + + dat += "[features["mam_body_markings"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + + if("mam_ears" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Ears

" + + dat += "[features["mam_ears"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("ears" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Ears

" + + dat += "[features["ears"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("mam_snouts" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Snout

" + + dat += "[features["mam_snouts"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("legs" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Legs

" + + dat += "[features["legs"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("moth_wings" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Moth wings

" + + dat += "[features["moth_wings"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("taur" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Tauric Body

" + + dat += "[features["taur"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Wings

" + + dat += "[features["wings"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("xenohead" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Caste Head

" + + dat += "[features["xenohead"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("xenotail" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Tail

" + + dat += "[features["xenotail"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("xenodorsal" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Dorsal Spines

" + + dat += "[features["xenodorsal"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("ipc_screen" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Screen

" + + dat += "[features["ipc_screen"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + if("ipc_antenna" in pref_species.default_features) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Antenna

" + + dat += "[features["ipc_antenna"]]" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + + if(mutant_category) + dat += "" + mutant_category = 0 + + dat += "
" + dat += "

Flavor Text

" + dat += "Set Examine Text
" + if(lentext(features["flavor_text"]) <= 40) + if(!lentext(features["flavor_text"])) + dat += "\[...\]" + else + dat += "[features["flavor_text"]]" + else + dat += "[TextPreview(features["flavor_text"])]...
" + dat += "

Body

" + dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" + dat += "Species:[pref_species.id]
" + dat += "Random Body
" + dat += "Always Random Body:[be_random_body ? "Yes" : "No"]
" + + var/use_skintones = pref_species.use_skintones + if(use_skintones) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Skin Tone

" + + dat += "[skin_tone]
" + + var/mutant_colors + if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits)) + if(!use_skintones) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Body Colors

" + + dat += "Primary Color:
" + dat += "    Change
" + + dat += "Secondary Color:
" + dat += "    Change
" + + dat += "Tertiary Color:
" + dat += "    Change
" + mutant_colors = TRUE + + if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits)) + + if(!use_skintones && !mutant_colors) + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Eye Color

" + + dat += "    Change
" + + dat += "
" + + dat += "" + dat += "" + + dat +="" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "Has Breasts:" + dat += "[features["has_breasts"] == TRUE ? "Yes" : "No"]" + if(features["has_breasts"]) + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Color:" + dat += "   (Skin tone overriding)
" + else + dat += "Color:" + dat += "   Change
" + dat += "Cup Size:[features["breasts_size"]]" + dat += "Breast Shape:[features["breasts_shape"]]" + dat += "" + dat += "" + dat += "
" + dat += "

Clothing & Equipment

" + dat += "Underwear:[underwear]" + dat += "Undershirt:[undershirt]" + dat += "Socks:[socks]" + dat += "Backpack:[backbag]" + dat += "Uplink Location:[uplink_spawn_loc]" + dat += "
" + if(NOGENITALS in pref_species.species_traits) + dat += "Your species ([pref_species.name]) does not support genitals!
" + else + if(pref_species.use_skintones) + dat += "Genitals use skintone:[features["genitals_use_skintone"] == TRUE ? "Yes" : "No"]" + dat += "Has Penis:" + dat += "[features["has_cock"] == TRUE ? "Yes" : "No"]" + if(features["has_cock"] == TRUE) + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Penis Color:" + dat += "   (Skin tone overriding)
" + else + dat += "Penis Color:" + dat += "    Change
" + dat += "Penis Shape: [features["cock_shape"]]" + dat += "Penis Length: [features["cock_length"]] inch(es)" + dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"]" + if(features["has_balls"] == TRUE) + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Testicles Color:" + dat += "   (Skin tone overriding)
" + else + dat += "Testicles Color:" + dat += "    Change
" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "Has Vagina:" + dat += "[features["has_vag"] == TRUE ? "Yes" : "No"]" + if(features["has_vag"]) + dat += "Vagina Type: [features["vag_shape"]]" + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Vagina Color:" + dat += "   (Skin tone overriding)
" + else + dat += "Vagina Color:" + dat += "    Change
" + dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"]" + dat += "
" + + if (1) // Game Preferences + dat += "" + if(user.client.holder) + dat +="" + + dat +="" + dat += "
" + dat += "

General Settings

" + dat += "UI Style: [UI_style]
" + dat += "tgui Monitors: [(tgui_lock) ? "Primary" : "All"]
" + dat += "tgui Style: [(tgui_fancy) ? "Fancy" : "No Frills"]
" + dat += "
" + dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"]
" + dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Default"]
" + dat += "
" + dat += "PDA Color:     Change
" + dat += "PDA Style: [pda_style]
" + dat += "
" + dat += "Ghost Ears: [(chat_toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" + dat += "Ghost Radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "All Messages":"No Messages"]
" + dat += "Ghost Sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" + dat += "Ghost Whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "All Speech" : "Nearest Creatures"]
" + dat += "Ghost PDA: [(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"]
" + dat += "Window Flashing: [(windowflashing) ? "Enabled":"Disabled"]
" + dat += "
" + dat += "Play Admin MIDIs: [(toggles & SOUND_MIDI) ? "Enabled":"Disabled"]
" + dat += "Play Lobby Music: [(toggles & SOUND_LOBBY) ? "Enabled":"Disabled"]
" + dat += "See Pull Requests: [(chat_toggles & CHAT_PULLR) ? "Enabled":"Disabled"]
" + dat += "
" + if(user.client) + if(unlock_content) + dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" + if(unlock_content || check_rights_for(user.client, R_ADMIN)) + dat += "OOC Color:     Change
" + dat += "
" + dat += "

Admin Settings

" + dat += "Adminhelp Sounds: [(toggles & SOUND_ADMINHELP)?"Enabled":"Disabled"]
" + dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"Enabled":"Disabled"]
" + dat += "
" + dat += "Combo HUD Lighting: [(toggles & COMBOHUD_LIGHTING)?"Full-bright":"No Change"]
" + dat += "
" + dat += "

Citadel Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. + dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" + dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"]
" + dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]
" + dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"]
" + dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]
" + dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]
" + dat += "Auto stand: [autostand ? "Enabled" : "Disabled"]
" + dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]
" + if (user && user.client && !user.client.prefs.screenshake==0) + dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]
" + dat += "
" + dat += "
" + if(unlock_content) + dat += "Ghost Form: [ghost_form]
" + dat += "Ghost Orbit: [ghost_orbit]
" + var/button_name = "If you see this something went wrong." + switch(ghost_accs) + if(GHOST_ACCS_FULL) + button_name = GHOST_ACCS_FULL_NAME + if(GHOST_ACCS_DIR) + button_name = GHOST_ACCS_DIR_NAME + if(GHOST_ACCS_NONE) + button_name = GHOST_ACCS_NONE_NAME + + dat += "Ghost Accessories: [button_name]
" + switch(ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + button_name = GHOST_OTHERS_THEIR_SETTING_NAME + if(GHOST_OTHERS_DEFAULT_SPRITE) + button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME + if(GHOST_OTHERS_SIMPLE) + button_name = GHOST_OTHERS_SIMPLE_NAME + + dat += "Ghosts of Others: [button_name]
" + dat += "
" + dat += "FPS: [clientfps]
" + dat += "Parallax (Fancy Space): " + switch (parallax) + if (PARALLAX_LOW) + dat += "Low" + if (PARALLAX_MED) + dat += "Medium" + if (PARALLAX_INSANE) + dat += "Insane" + if (PARALLAX_DISABLE) + dat += "Disabled" + else + dat += "High" + dat += "
" + dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
" + dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
" + + if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation)) + var/p_map = preferred_map + if (!p_map) + p_map = "Default" + if (config.defaultmap) + p_map += " ([config.defaultmap.map_name])" + else + if (p_map in config.maplist) + var/datum/map_config/VM = config.maplist[p_map] + if (!VM) + p_map += " (No longer exists)" + else + p_map = VM.map_name + else + p_map += " (No longer exists)" + if(CONFIG_GET(flag/allow_map_voting)) + dat += "Preferred Map: [p_map]
" + + dat += "" + + dat += "

Special Role Settings

" + + if(jobban_isbanned(user, ROLE_SYNDICATE)) + dat += "You are banned from antagonist roles." + src.be_special = list() + + + for (var/i in GLOB.special_roles) + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: BANNED
" + else + var/days_remaining = null + if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age + var/mode_path = GLOB.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) ? "Enabled" : "Disabled"]
" + dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"]
" + + dat += "
" + + if(3) + if(!gear_tab) + gear_tab = GLOB.loadout_items[1] + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + for(var/j in GLOB.loadout_items[gear_tab]) + var/datum/gear/gear = GLOB.loadout_items[gear_tab][j] + var/donoritem + if(gear.ckeywhitelist && gear.ckeywhitelist.len) + donoritem = TRUE + if(!(user.ckey in gear.ckeywhitelist)) + continue + var/class_link = "" + if(gear.type in chosen_gear) + class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=0'" + else if(gear_points <= 0) + class_link = "style='white-space:normal;' class='linkOff'" + else if(donoritem) + class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'" + else + class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(j)];toggle_gear=1'" + dat += "" + dat += "" + dat += "
[gear_points] loadout points remaining. \[Clear Loadout\]
You can only choose one item per category, unless it's an item that spawns in your backpack or hands.
" + var/firstcat = TRUE + for(var/i in GLOB.loadout_items) + if(firstcat) + firstcat = FALSE + else + dat += " |" + if(i == gear_tab) + dat += " [i] " + else + dat += " [i] " + dat += "

[gear_tab]

NameCostRestrictionsDescription
[j][gear.cost]" + if(islist(gear.restricted_roles)) + if(gear.restricted_roles.len) + dat += "" + dat += gear.restricted_roles.Join(";") + dat += "" + dat += "[gear.description]
" + + dat += "
" + + if(!IsGuestKey(user.key)) + dat += "Undo " + dat += "Save Setup " + + dat += "Reset Setup" + dat += "
" + + winshow(user, "preferences_window", TRUE) + var/datum/browser/popup = new(user, "preferences_browser", "
Character Setup
", 640, 770) + popup.set_content(dat.Join()) + popup.open(FALSE) + onclose(user, "preferences_window", src) + +#undef APPEARANCE_CATEGORY_COLUMN +#undef MAX_MUTANT_ROWS + +/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 = "
" + if(SSjob.occupations.len <= 0) + HTML += "The job SSticker is not yet finished creating jobs, please try again later" + HTML += "
Done

" // Easier to press up here. + + else + 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 + + var/datum/job/overflow = SSjob.GetJob(SSjob.overflow_role) + + 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 + var/required_playtime_remaining = job.required_playtime_remaining(user.client) + if(required_playtime_remaining) + HTML += "[rank]" + 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 & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) + HTML += "[rank]" + continue + if((rank in GLOB.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
\[ [get_exp_format(required_playtime_remaining)] as [job.get_exp_req_type()] \]
\[IN [(available_in_days)] DAYS\]
" + + 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 == SSjob.overflow_role)//Overflow is special + if(job_civilian_low & overflow.flag) + HTML += "Yes" + else + HTML += "No" + HTML += "
  
" + HTML += "
" + + var/message = "Be an [SSjob.overflow_role] if preferences unavailable" + if(joblessrole == BERANDOMJOB) + message = "Get random job if preferences unavailable" + else if(joblessrole == RETURNTOLOBBY) + message = "Return to lobby if preferences unavailable" + HTML += "

[message]
" + HTML += "
Reset Preferences
" + + 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(FALSE) + +/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 || SSjob.occupations.len <= 0) + return + var/datum/job/job = SSjob.GetJob(role) + + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) + return + + if (!isnum(desiredLvl)) + to_chat(user, "UpdateJobPreference - desired level was not a number. Please notify coders!") + ShowChoices(user) + return + + if(role == SSjob.overflow_role) + 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/SetQuirks(mob/user) + if(!SSquirks) + to_chat(user, "The quirk subsystem is still initializing! Try again in a minute.") + return + + var/list/dat = list() + if(!SSquirks.quirks.len) + dat += "The quirk subsystem hasn't finished initializing, please hold..." + dat += "
Done

" + + else + dat += "
Choose quirk setup

" + dat += "
Left-click to add or remove quirks. You need negative quirks to have positive ones.
\ + Quirks are applied at roundstart and cannot normally be removed.
" + dat += "
Done
" + dat += "
" + dat += "
Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]
" + dat += "
[positive_quirks.len] / [MAX_QUIRKS] max positive quirks
\ + Quirk balance remaining: [GetQuirkBalance()]

" + for(var/V in SSquirks.quirks) + var/datum/quirk/T = SSquirks.quirks[V] + var/quirk_name = initial(T.name) + var/has_quirk + var/quirk_cost = initial(T.value) * -1 + var/lock_reason = "This trait is unavailable." + var/quirk_conflict = FALSE + for(var/_V in all_quirks) + if(_V == quirk_name) + has_quirk = TRUE + if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood)) + lock_reason = "Mood is disabled." + quirk_conflict = TRUE + if(has_quirk) + if(quirk_conflict) + all_quirks -= quirk_name + has_quirk = FALSE + else + quirk_cost *= -1 //invert it back, since we'd be regaining this amount + if(quirk_cost > 0) + quirk_cost = "+[quirk_cost]" + var/font_color = "#AAAAFF" + if(initial(T.value) != 0) + font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA" + if(quirk_conflict) + dat += "[quirk_name] - [initial(T.desc)] \ + LOCKED: [lock_reason]
" + else + if(has_quirk) + dat += "[quirk_name] - [initial(T.desc)] \ + [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.)
" + else + dat += "[quirk_name] - [initial(T.desc)] \ + [has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.)
" + dat += "
Reset Traits
" + + var/datum/browser/popup = new(user, "mob_occupation", "
Quirk Preferences
", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way + popup.set_window_options("can_close=0") + popup.set_content(dat.Join()) + popup.open(FALSE) + +/datum/preferences/proc/GetQuirkBalance() + var/bal = 0 + for(var/V in all_quirks) + var/datum/quirk/T = SSquirks.quirks[V] + bal -= initial(T.value) + return bal + +/datum/preferences/Topic(href, href_list, hsrc) //yeah, gotta do this I guess.. + . = ..() + if(href_list["close"]) + var/client/C = usr.client + if(C) + C.clear_character_previews() + +/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/datum/DBQuery/query_get_jobban = SSdbcore.NewQuery("SELECT reason, bantime, duration, expiration_time, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE ckey = '[sql_ckey]' AND (bantype = 'JOB_PERMABAN' OR (bantype = 'JOB_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned) AND job = '[job]'") + if(!query_get_jobban.warn_execute()) + qdel(query_get_jobban) + 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/admin_key = query_get_jobban.item[5] + var/text + text = "You, or another user of this computer, ([user.key]) is banned from playing [job]. The ban reason is:
[reason]
This ban was applied by [admin_key] on [bantime]" + if(text2num(duration) > 0) + text += ". The ban is for [duration] minutes and expires on [expiration_time] (server time)" + text += ".
" + to_chat(user, text) + qdel(query_get_jobban) + 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") + switch(joblessrole) + if(RETURNTOLOBBY) + if(jobban_isbanned(user, SSjob.overflow_role)) + joblessrole = BERANDOMJOB + else + joblessrole = BEOVERFLOW + if(BEOVERFLOW) + joblessrole = BERANDOMJOB + if(BERANDOMJOB) + joblessrole = RETURNTOLOBBY + SetChoices(user) + if("setJobLevel") + UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) + else + SetChoices(user) + return 1 + + else if(href_list["preference"] == "trait") + switch(href_list["task"]) + if("close") + user << browse(null, "window=mob_occupation") + ShowChoices(user) + if("update") + var/quirk = href_list["trait"] + if(!SSquirks.quirks[quirk]) + return + var/value = SSquirks.quirk_points[quirk] + if(value == 0) + if(quirk in neutral_quirks) + neutral_quirks -= quirk + all_quirks -= quirk + else + neutral_quirks += quirk + all_quirks += quirk + else + var/balance = GetQuirkBalance() + if(quirk in positive_quirks) + positive_quirks -= quirk + all_quirks -= quirk + else if(quirk in negative_quirks) + if(balance + value < 0) + to_chat(user, "Refunding this would cause you to go below your balance!") + return + negative_quirks -= quirk + all_quirks -= quirk + else if(value > 0) + if(positive_quirks.len >= MAX_QUIRKS) + to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!") + return + if(balance - value < 0) + to_chat(user, "You don't have enough balance to gain this quirk!") + return + positive_quirks += quirk + all_quirks += quirk + else + negative_quirks += quirk + all_quirks += quirk + SetQuirks(user) + if("reset") + all_quirks = list() + positive_quirks = list() + negative_quirks = list() + neutral_quirks = list() + SetQuirks(user) + else + SetQuirks(user) + return TRUE + + 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() + if(BODY_ZONE_PRECISE_EYES) + eye_color = random_eye_color() + if("s_tone") + skin_tone = random_skin_tone() + if("bag") + backbag = pick(GLOB.backbaglist) + if("all") + random_character() + + if("input") + + if(href_list["preference"] in GLOB.preferences_custom_names) + ask_for_custom_name(user,href_list["preference"]) + + + 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 GLOB.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 GLOB.ghost_orbits + if(new_orbit) + ghost_orbit = new_orbit + + if("ghostaccs") + var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME) + switch(new_ghost_accs) + if(GHOST_ACCS_FULL_NAME) + ghost_accs = GHOST_ACCS_FULL + if(GHOST_ACCS_DIR_NAME) + ghost_accs = GHOST_ACCS_DIR + if(GHOST_ACCS_NONE_NAME) + ghost_accs = GHOST_ACCS_NONE + + if("ghostothers") + var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME) + switch(new_ghost_others) + if(GHOST_OTHERS_THEIR_SETTING_NAME) + ghost_others = GHOST_OTHERS_THEIR_SETTING + if(GHOST_OTHERS_DEFAULT_SPRITE_NAME) + ghost_others = GHOST_OTHERS_DEFAULT_SPRITE + if(GHOST_OTHERS_SIMPLE_NAME) + ghost_others = GHOST_OTHERS_SIMPLE + + if("name") + var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null + if(new_name) + new_name = reject_bad_name(new_name) + if(new_name) + real_name = new_name + else + to_chat(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("flavor_text") + var/msg = stripped_multiline_input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(features["flavor_text"]), MAX_MESSAGE_LEN*2, TRUE) as null|message + if(!isnull(msg)) + msg = copytext(msg, 1, MAX_MESSAGE_LEN*2) + features["flavor_text"] = msg + + if("hair") + var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null + 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 GLOB.hair_styles_male_list + else + new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.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, GLOB.hair_styles_male_list) + else + hair_style = next_list_item(hair_style, GLOB.hair_styles_female_list) + + if("previous_hair_style") + if (gender == MALE) + hair_style = previous_list_item(hair_style, GLOB.hair_styles_male_list) + else + hair_style = previous_list_item(hair_style, GLOB.hair_styles_female_list) + + if("facial") + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null + 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 GLOB.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 GLOB.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, GLOB.facial_hair_styles_male_list) + else + facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_female_list) + if("previous_facehair_style") + if (gender == MALE) + facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_male_list) + else + facial_hair_style = previous_list_item(facial_hair_style, GLOB.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 GLOB.underwear_m + else + new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.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 GLOB.undershirt_m + else + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_f + if(new_undershirt) + undershirt = new_undershirt + + if("socks") + var/new_socks + new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list + if(new_socks) + socks = new_socks + + if("eyes") + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) 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 GLOB.roundstart_races + if(result) + var/newtype = GLOB.species_list[result] + pref_species = new newtype() + //let's ensure that no weird shit happens on species swapping. + if(!("body_markings" in pref_species.default_features)) + features["body_markings"] = "None" + if(!("mam_body_markings" in pref_species.default_features)) + features["mam_body_markings"] = "None" + if("mam_body_markings" in pref_species.default_features && features["mam_body_markings"] == "None") + features["mam_body_markings"] = "Plain" + if("tail_lizard" in pref_species.default_features) + features["tail_lizard"] = "Smooth" + if("mam_tail" in pref_species.default_features) + features["mam_tail"] = "None" + if("mam_ears" in pref_species.default_features) + features["mam_ears"] = "None" + if(pref_species.id == "felinid") + features["mam_tail"] = "Cat" + features["mam_ears"] = "Cat" + + //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.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) + features["mcolor"] = pref_species.default_color + if(features["mcolor2"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) + features["mcolor2"] = pref_species.default_color + if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) + features["mcolor3"] = pref_species.default_color + + if("mutant_color") + var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + if(new_mutantcolor == "#000000") + features["mcolor"] = pref_species.default_color + update_preview_icon() + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin + features["mcolor"] = sanitize_hexcolor(new_mutantcolor) + update_preview_icon() + else + to_chat(user, "Invalid color. Your color is not bright enough.") + + if("mutant_color2") + var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + if(new_mutantcolor == "#000000") + features["mcolor2"] = pref_species.default_color + update_preview_icon() + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin + features["mcolor2"] = sanitize_hexcolor(new_mutantcolor) + update_preview_icon() + else + to_chat(user, "Invalid color. Your color is not bright enough.") + + if("mutant_color3") + var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + if(new_mutantcolor == "#000000") + features["mcolor3"] = pref_species.default_color + update_preview_icon() + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) // mutantcolors must be bright, but only if they affect the skin + features["mcolor3"] = sanitize_hexcolor(new_mutantcolor) + update_preview_icon() + else + to_chat(user, "Invalid color. Your color is not bright enough.") + + if("ipc_screen") + var/new_ipc_screen + new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list + if(new_ipc_screen) + features["ipc_screen"] = new_ipc_screen + + if("ipc_antenna") + var/new_ipc_antenna + new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in GLOB.ipc_antennas_list + if(new_ipc_antenna) + features["ipc_antenna"] = new_ipc_antenna + + if("tail_lizard") + var/new_tail + new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard + if(new_tail) + features["tail_lizard"] = new_tail + if(new_tail != "None") + features["taur"] = "None" + features["tail_human"] = "None" + features["mam_tail"] = "None" + + if("tail_human") + var/list/snowflake_tails_list = list() + for(var/path in GLOB.tails_list_human) + var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + snowflake_tails_list[S.name] = path + var/new_tail + new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list + if(new_tail) + features["tail_human"] = new_tail + if(new_tail != "None") + features["taur"] = "None" + features["tail_lizard"] = "None" + features["mam_tail"] = "None" + + if("mam_tail") + var/list/snowflake_tails_list = list() + for(var/path in GLOB.mam_tails_list) + var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + snowflake_tails_list[S.name] = path + var/new_tail + new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list + if(new_tail) + features["mam_tail"] = new_tail + if(new_tail != "None") + features["taur"] = "None" + features["tail_human"] = "None" + features["tail_lizard"] = "None" + + if("snout") + var/new_snout + new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.snouts_list + if(new_snout) + features["snout"] = new_snout + + if("mam_snouts") + var/new_mam_snouts + new_mam_snouts = input(user, "Choose your character's snout:", "Character Preference") as null|anything in GLOB.mam_snouts_list + if(new_mam_snouts) + features["mam_snouts"] = new_mam_snouts + + if("horns") + var/new_horns + new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.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 GLOB.ears_list + if(new_ears) + features["ears"] = new_ears + + if("wings") + var/new_wings + new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list + if(new_wings) + features["wings"] = new_wings + + if("frills") + var/new_frills + new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.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 GLOB.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 GLOB.body_markings_list + if(new_body_markings) + features["body_markings"] = new_body_markings + if(new_body_markings != "None") + features["mam_body_markings"] = "None" + update_preview_icon() + + if("legs") + var/new_legs + new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list + if(new_legs) + features["legs"] = new_legs + update_preview_icon() + + if("moth_wings") + var/new_moth_wings + new_moth_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.moth_wings_list + if(new_moth_wings) + features["moth_wings"] = new_moth_wings + + if("s_tone") + var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones + if(new_s_tone) + skin_tone = new_s_tone + + if("taur") + var/list/snowflake_taur_list = list() + for(var/path in GLOB.taur_list) + var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + snowflake_taur_list[S.name] = path + var/new_taur + new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list + if(new_taur) + features["taur"] = new_taur + if(new_taur != "None") + features["mam_tail"] = "None" + features["xenotail"] = "None" + features["tail_human"] = "None" + features["tail_lizard"] = "None" + + if("ears") + var/list/snowflake_ears_list = list() + for(var/path in GLOB.ears_list) + var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + snowflake_ears_list[S.name] = path + var/new_ears + new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list + if(new_ears) + features["ears"] = new_ears + + if("mam_ears") + var/list/snowflake_ears_list = list() + for(var/path in GLOB.mam_ears_list) + var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + snowflake_ears_list[S.name] = path + var/new_ears + new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list + if(new_ears) + features["mam_ears"] = new_ears + + if("mam_body_markings") + var/list/snowflake_markings_list = list() + for(var/path in GLOB.mam_body_markings_list) + var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + snowflake_markings_list[S.name] = path + var/new_mam_body_markings + new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list + if(new_mam_body_markings) + features["mam_body_markings"] = new_mam_body_markings + if(new_mam_body_markings != "None") + features["body_markings"] = "None" + else if(new_mam_body_markings == "None") + features["mam_body_markings"] = "Plain" + features["body_markings"] = "None" + update_preview_icon() + + //Xeno Bodyparts + if("xenohead")//Head or caste type + var/new_head + new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list + if(new_head) + features["xenohead"] = new_head + + if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future. + var/new_tail + new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list + if(new_tail) + features["xenotail"] = new_tail + if(new_tail != "None") + features["mam_tail"] = "None" + features["taur"] = "None" + features["tail_human"] = "None" + features["tail_lizard"] = "None" + + if("xenodorsal") + var/new_dors + new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list + if(new_dors) + features["xenodorsal"] = new_dors + //Genital code + if("cock_color") + var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null + if(new_cockcolor) + var/temp_hsv = RGBtoHSV(new_cockcolor) + if(new_cockcolor == "#000000") + features["cock_color"] = pref_species.default_color + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) + features["cock_color"] = sanitize_hexcolor(new_cockcolor) + else + user << "Invalid color. Your color is not bright enough." + + if("cock_length") + var/new_length = input(user, "Penis length in inches:\n([COCK_SIZE_MIN]-[COCK_SIZE_MAX])", "Character Preference") as num|null + if(new_length) + features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN) + + if("cock_shape") + var/new_shape + new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list + if(new_shape) + features["cock_shape"] = new_shape + + if("balls_color") + var/new_ballscolor = input(user, "Testicle Color:", "Character Preference") as color|null + if(new_ballscolor) + var/temp_hsv = RGBtoHSV(new_ballscolor) + if(new_ballscolor == "#000000") + features["balls_color"] = pref_species.default_color + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) + features["balls_color"] = sanitize_hexcolor(new_ballscolor) + else + user << "Invalid color. Your color is not bright enough." + + if("egg_size") + var/new_size + var/list/egg_sizes = list(1,2,3) + new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes + if(new_size) + features["eggsack_egg_size"] = new_size + + if("egg_color") + var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null + if(new_egg_color) + var/temp_hsv = RGBtoHSV(new_egg_color) + if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) + features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color) + else + user << "Invalid color. Your color is not bright enough." + + if("breasts_size") + var/new_size + new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list + if(new_size) + features["breasts_size"] = new_size + + if("breasts_shape") + var/new_shape + new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list + if(new_shape) + features["breasts_shape"] = new_shape + + if("breasts_color") + var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null + if(new_breasts_color) + var/temp_hsv = RGBtoHSV(new_breasts_color) + if(new_breasts_color == "#000000") + features["breasts_color"] = pref_species.default_color + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) + features["breasts_color"] = sanitize_hexcolor(new_breasts_color) + else + user << "Invalid color. Your color is not bright enough." + + if("vag_shape") + var/new_shape + new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list + if(new_shape) + features["vag_shape"] = new_shape + + if("vag_color") + var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null + if(new_vagcolor) + var/temp_hsv = RGBtoHSV(new_vagcolor) + if(new_vagcolor == "#000000") + features["vag_color"] = pref_species.default_color + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3]) + features["vag_color"] = sanitize_hexcolor(new_vagcolor) + else + user << "Invalid color. Your color is not bright enough." + + if("ooccolor") + var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null + if(new_ooccolor) + ooccolor = new_ooccolor + + if("bag") + var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist + if(new_backbag) + backbag = new_backbag + + if("uplink_loc") + var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list + if(new_loc) + uplink_spawn_loc = new_loc + + if("sec_dept") + var/department = input(user, "Choose your prefered security department:", "Security Departments") as null|anything in GLOB.security_depts_prefs + if(department) + prefered_security_department = department + + if ("preferred_map") + var/maplist = list() + var/default = "Default" + if (config.defaultmap) + default += " ([config.defaultmap.map_name])" + for (var/M in config.maplist) + var/datum/map_config/VM = config.maplist[M] + var/friendlyname = "[VM.map_name] " + if (VM.voteweight <= 0) + friendlyname += " (disabled)" + maplist[friendlyname] = VM.map_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] + + if ("clientfps") + var/desiredfps = input(user, "Choose your desired fps. (0 = synced with server tick rate (currently:[world.fps]))", "Character Preference", clientfps) as null|num + if (!isnull(desiredfps)) + clientfps = desiredfps + parent.fps = desiredfps + if("ui") + var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles + if(pickedui) + UI_style = pickedui + if (parent && parent.mob && parent.mob.hud_used) + parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style)) + if("pda_style") + var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles + if(pickedPDAStyle) + pda_style = pickedPDAStyle + if("pda_color") + var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null + if(pickedPDAColor) + pda_color = pickedPDAColor + + else + switch(href_list["preference"]) + //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj + if("genital_colour") + features["genitals_use_skintone"] = !features["genitals_use_skintone"] + if("arousable") + arousable = !arousable + if("has_cock") + features["has_cock"] = !features["has_cock"] + if("has_balls") + features["has_balls"] = !features["has_balls"] + if("has_ovi") + features["has_ovi"] = !features["has_ovi"] + if("has_eggsack") + features["has_eggsack"] = !features["has_eggsack"] + if("balls_internal") + features["balls_internal"] = !features["balls_internal"] + if("eggsack_internal") + features["eggsack_internal"] = !features["eggsack_internal"] + if("has_breasts") + features["has_breasts"] = !features["has_breasts"] + if("has_vag") + features["has_vag"] = !features["has_vag"] + if("has_womb") + features["has_womb"] = !features["has_womb"] + if("exhibitionist") + features["exhibitionist"] = !features["exhibitionist"] + if("widescreenpref") + widescreenpref = !widescreenpref + user.client.change_view(CONFIG_GET(string/default_view)) + if("autostand") + autostand = !autostand + if ("screenshake") + var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num + if (!isnull(desiredshake)) + screenshake = desiredshake + if("damagescreenshake") + switch(damagescreenshake) + if(0) + damagescreenshake = 1 + if(1) + damagescreenshake = 2 + if(2) + damagescreenshake = 0 + else + damagescreenshake = 1 + if("nameless") + nameless = !nameless + //END CITADEL EDIT + if("publicity") + if(unlock_content) + toggles ^= MEMBER_PUBLIC + if("gender") + var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) in list(MALE,FEMALE,"nonbinary","object") + switch(chosengender) + if("nonbinary") + chosengender = PLURAL + if("object") + chosengender = NEUTER + gender = chosengender + facial_hair_style = random_facial_hair_style(gender) + hair_style = random_hair_style(gender) + + if("hotkeys") + hotkeys = !hotkeys + if(hotkeys) + winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default") + else + winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default") + if("action_buttons") + buttons_locked = !buttons_locked + if("tgui_fancy") + tgui_fancy = !tgui_fancy + if("tgui_lock") + tgui_lock = !tgui_lock + if("winflash") + windowflashing = !windowflashing + if("hear_adminhelps") + toggles ^= SOUND_ADMINHELP + if("announce_login") + toggles ^= ANNOUNCE_LOGIN + if("combohud_lighting") + toggles ^= COMBOHUD_LIGHTING + + 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.client && isnewplayer(user)) + user.client.playtitlemusic() + else + user.stop_sound_channel(CHANNEL_LOBBYMUSIC) + + 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("parallaxup") + parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1) + if (parent && parent.mob && parent.mob.hud_used) + parent.mob.hud_used.update_parallax_pref(parent.mob) + + if("parallaxdown") + parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1) + if (parent && parent.mob && parent.mob.hud_used) + parent.mob.hud_used.update_parallax_pref(parent.mob) + + // Citadel edit - Prefs don't work outside of this. :c + if("hound_sleeper") + cit_toggles ^= MEDIHOUND_SLEEPER + + if("toggleeatingnoise") + cit_toggles ^= EATING_NOISES + + if("toggledigestionnoise") + cit_toggles ^= DIGESTION_NOISES + //END CITADEL EDIT + + if("ambientocclusion") + ambientocclusion = !ambientocclusion + if(parent && parent.screen && parent.screen.len) + var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen + PM.backdrop(parent.mob) + + if("auto_fit_viewport") + auto_fit_viewport = !auto_fit_viewport + if(auto_fit_viewport && parent) + parent.fit_viewport() + + if("save") + save_preferences() + save_character() + + if("load") + load_preferences() + load_character() + if(parent && parent.prefs_vr) + attempt_vr(parent.prefs_vr,"load_vore","") + + if("changeslot") + if(!load_character(text2num(href_list["num"]))) + random_character() + real_name = random_unique_name(gender) + save_character() + if(parent && parent.prefs_vr) + attempt_vr(parent.prefs_vr,"load_vore","") + + if("tab") + if (href_list["tab"]) + current_tab = text2num(href_list["tab"]) + if(href_list["preference"] == "gear") + if(href_list["clear_loadout"]) + LAZYCLEARLIST(chosen_gear) + gear_points = initial(gear_points) + save_preferences() + if(href_list["select_category"]) + for(var/i in GLOB.loadout_items) + if(i == href_list["select_category"]) + gear_tab = i + if(href_list["toggle_gear_path"]) + var/datum/gear/G = GLOB.loadout_items[gear_tab][html_decode(href_list["toggle_gear_path"])] + if(!G) + return + var/toggle = text2num(href_list["toggle_gear"]) + if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear) + LAZYREMOVE(chosen_gear, G.type) + gear_points += initial(G.cost) + else if(toggle && (!(is_type_in_ref_list(G, chosen_gear)))) + if(!is_loadout_slot_available(G.category)) + to_chat(user, "You cannot take this loadout, as you've already chosen too many of the same category!") + return + if(G.ckeywhitelist && G.ckeywhitelist.len && !(user.ckey in G.ckeywhitelist)) + to_chat(user, "This is an item intended for donator use only. You are not authorized to use this item.") + return + if(gear_points >= initial(G.cost)) + LAZYADD(chosen_gear, G.type) + gear_points -= initial(G.cost) + + ShowChoices(user) + return 1 + +/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE) + if(be_random_name) + real_name = pref_species.random_name(gender) + + if(be_random_body) + random_character(gender) + + if(roundstart_checks) + if(CONFIG_GET(flag/humans_need_surnames) && (pref_species.id == "human")) + var/firstspace = findtext(real_name, " ") + var/name_length = length(real_name) + if(!firstspace) //we need a surname + real_name += " [pick(GLOB.last_names)]" + else if(firstspace == name_length) + real_name += "[pick(GLOB.last_names)]" + + character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name + character.name = character.real_name + character.nameless = nameless + + character.gender = gender + character.age = age + + character.eye_color = eye_color + var/obj/item/organ/eyes/organ_eyes = character.getorgan(/obj/item/organ/eyes) + if(organ_eyes) + if(!initial(organ_eyes.eye_color)) + organ_eyes.eye_color = eye_color + organ_eyes.old_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 + + var/datum/species/chosen_species + if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races)) + chosen_species = pref_species.type + else + chosen_species = /datum/species/human + pref_species = new /datum/species/human + save_character() + + character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) + character.dna.features = features.Copy() + character.dna.real_name = character.real_name + character.dna.nameless = character.nameless + + if("tail_lizard" in pref_species.default_features) + character.dna.species.mutant_bodyparts |= "tail_lizard" + else if("mam_tail" in pref_species.default_features) + character.dna.species.mutant_bodyparts |= "mam_tail" + else if("xenotail" in pref_species.default_features) + character.dna.species.mutant_bodyparts |= "xenotail" + + if("legs" in pref_species.default_features) + if(character.dna.features["legs"] == "Digitigrade Legs") + pref_species.species_traits += DIGITIGRADE + character.Digitigrade_Leg_Swap(FALSE) + + if(character.dna.features["legs"] == "Normal Legs" && DIGITIGRADE in pref_species.species_traits) + pref_species.species_traits -= DIGITIGRADE + character.Digitigrade_Leg_Swap(TRUE) + + else if((!"legs" in pref_species.default_features) && DIGITIGRADE in pref_species.species_traits) + pref_species.species_traits -= DIGITIGRADE + character.Digitigrade_Leg_Swap(TRUE) + + if(DIGITIGRADE in pref_species.species_traits) + character.Digitigrade_Leg_Swap(FALSE) + + if(icon_updates) + character.update_body() + character.update_hair() + character.update_body_parts() + +/datum/preferences/proc/get_default_name(name_id) + switch(name_id) + if("human") + return random_unique_name() + if("ai") + return pick(GLOB.ai_names) + if("cyborg") + return DEFAULT_CYBORG_NAME + if("clown") + return pick(GLOB.clown_names) + if("mime") + return pick(GLOB.mime_names) + return random_unique_name() + +/datum/preferences/proc/ask_for_custom_name(mob/user,name_id) + var/namedata = GLOB.preferences_custom_names[name_id] + if(!namedata) + return + + var/raw_name = input(user, "Choose your character's [namedata["qdesc"]]:","Character Preference") as text|null + if(!raw_name) + if(namedata["allow_null"]) + custom_names[name_id] = get_default_name(name_id) + else + return + else + var/sanitized_name = reject_bad_name(raw_name,namedata["allow_numbers"]) + if(!sanitized_name) + to_chat(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,[namedata["allow_numbers"] ? ",0-9," : ""] -, ' and .") + return + else + custom_names[name_id] = sanitized_name diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index dbf782c5fe..9e19ab65a2 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -235,6 +235,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Character S["real_name"] >> real_name + S["nameless"] >> nameless S["name_is_always_random"] >> be_random_name S["body_is_always_random"] >> be_random_body S["gender"] >> gender @@ -301,6 +302,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_mam_ears"] >> features["mam_ears"] S["feature_mam_tail_animated"] >> features["mam_tail_animated"] S["feature_taur"] >> features["taur"] + S["feature_mam_snouts"] >> features["mam_snouts"] //Xeno features S["feature_xeno_tail"] >> features["xenotail"] S["feature_xeno_dors"] >> features["xenodorsal"] @@ -362,6 +364,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(!features["mcolor"] || features["mcolor"] == "#000") features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") + nameless = sanitize_integer(nameless, 0, 1, initial(nameless)) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body)) @@ -427,6 +430,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Character WRITE_FILE(S["real_name"] , real_name) + WRITE_FILE(S["nameless"] , nameless) WRITE_FILE(S["name_is_always_random"] , be_random_name) WRITE_FILE(S["body_is_always_random"] , be_random_body) WRITE_FILE(S["gender"] , gender) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 1e65c6ca3f..746d5da60d 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -24,6 +24,8 @@ var/can_flashlight = 0 var/scan_reagents = 0 //Can the wearer see reagents while it's equipped? + var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down. + var/clothing_flags = NONE //Var modification - PLEASE be careful with this I know who you are and where you live diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 7265800c49..ab9ffb9b18 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -3,7 +3,7 @@ desc = "Standard Security gear. Protects the head from impacts." icon_state = "helmet" item_state = "helmet" - armor = list("melee" = 35, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) + armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) flags_inv = HIDEEARS cold_protection = HEAD min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index ad8fafb872..8b1b1dac25 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -139,7 +139,7 @@ name = "security beret" desc = "A robust beret with the security insignia emblazoned on it. Uses reinforced fabric to offer sufficient protection." icon_state = "beret_badge" - armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 50) + armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) strip_delay = 60 dog_fashion = null @@ -152,7 +152,7 @@ name = "warden's beret" desc = "A special beret with the Warden's insignia emblazoned on it. For wardens with class." icon_state = "wardenberet" - armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 50) + armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) strip_delay = 60 /obj/item/clothing/head/beret/sec/navyofficer diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 97c9da289b..b10bf39729 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -110,13 +110,14 @@ /obj/item/clothing/suit/armor/riot name = "riot suit" - desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks." + desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks. Helps the wearer resist shoving in close quarters." icon_state = "riot" item_state = "swat_suit" body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS armor = list("melee" = 50, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80) + blocks_shove_knockdown = TRUE strip_delay = 80 equip_delay_other = 60 diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index 6bf96429b9..396bcb4766 100644 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -158,14 +158,14 @@ icon_state = "bronze_heart" /obj/item/clothing/accessory/medal/engineer - name = "\"Shift's Best Electrician\" award" - desc = "An award bestowed upon engineers who have excelled at keeping the station running in the best possible condition against all odds." - icon_state = "engineer" + name = "\"Shift's Best Electrician\" award" + desc = "An award bestowed upon engineers who have excelled at keeping the station running in the best possible condition against all odds." + icon_state = "engineer" /obj/item/clothing/accessory/medal/greytide - name = "\"Greytider of the shift\" award" - desc = "An award for only the most annoying of assistants. Locked doors mean nothing to you and behaving is not in your vocabulary" - icon_state = "greytide" + name = "\"Greytider of the shift\" award" + desc = "An award for only the most annoying of assistants. Locked doors mean nothing to you and behaving is not in your vocabulary" + icon_state = "greytide" /obj/item/clothing/accessory/medal/ribbon name = "ribbon" @@ -178,9 +178,9 @@ desc = "An award bestowed only upon those cargotechs who have exhibited devotion to their duty in keeping with the highest traditions of Cargonia." /obj/item/clothing/accessory/medal/ribbon/medical_doctor - name = "\"doctor of the shift\" award" - desc = "An award bestowed only upon the most capable doctors who have upheld the Hippocratic Oath to the best of their ability" - icon_state = "medical_doctor" + name = "\"doctor of the shift\" award" + desc = "An award bestowed only upon the most capable doctors who have upheld the Hippocratic Oath to the best of their ability" + icon_state = "medical_doctor" /obj/item/clothing/accessory/medal/silver name = "silver medal" @@ -211,6 +211,12 @@ desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew." resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF +/obj/item/clothing/accessory/medal/gold/captain/family + name = "old medal of captaincy" + desc = "A rustic badge pure gold, has been through hell and back by the looks, the syndcate have been after these by the looks of it for generations..." + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 10) //Pure gold + materials = list(MAT_GOLD=2000) + /obj/item/clothing/accessory/medal/gold/heroism name = "medal of exceptional heroism" desc = "An extremely rare golden medal awarded only by CentCom. To receive such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders." @@ -234,8 +240,6 @@ name = "nobel sciences award" desc = "A plasma medal which represents significant contributions to the field of science or engineering." - - //////////// //Armbands// //////////// diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm index 42d6fcbe1e..c892bfeffc 100644 --- a/code/modules/detectivework/detective_work.dm +++ b/code/modules/detectivework/detective_work.dm @@ -93,6 +93,15 @@ else if(length(blood_dna)) AddComponent(/datum/component/forensics, null, null, blood_dna) bloody_hands = rand(2, 4) + if(head) + head.add_blood_DNA(blood_dna) + update_inv_head() + else if(wear_mask) + wear_mask.add_blood_DNA(blood_dna) + update_inv_wear_mask() + if(wear_neck) + wear_neck.add_blood_DNA(blood_dna) + update_inv_neck() update_inv_gloves() //handles bloody hands overlays and updating return TRUE diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm index 8574933bda..435b4a371a 100644 --- a/code/modules/food_and_drinks/food/snacks_pastry.dm +++ b/code/modules/food_and_drinks/food/snacks_pastry.dm @@ -89,13 +89,24 @@ icon_state = "jdonut1" extra_reagent = "cherryjelly" foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT - + /obj/item/reagent_containers/food/snacks/donut/meat bonus_reagents = list("ketchup" = 1) list_reagents = list("nutriment" = 3, "ketchup" = 2) tastes = list("meat" = 1) foodtype = JUNKFOOD | MEAT | GROSS | FRIED - + +/obj/item/reagent_containers/food/snacks/donut/semen + name = "\"cream\" donut" + desc = "That cream looks a little runny..." + icon_state = "donut3" + bitesize = 10 + bonus_reagents = list("semen" = 1) + list_reagents = list("nutriment" = 3, "sugar" = 2, "semen" = 5) + filling_color = "#FFFFFF" + tastes = list("donut" = 1, "salt" = 3) + foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR + ////////////////////////////////////////////MUFFINS//////////////////////////////////////////// diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index e751bf887e..4b76ca120b 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -23,6 +23,16 @@ result = /obj/item/reagent_containers/food/snacks/donut subcategory = CAT_PASTRY +/datum/crafting_recipe/food/donut + time = 15 + name = "Semen donut" + reqs = list( + /datum/reagent/consumable/semen = 10, + /obj/item/reagent_containers/food/snacks/pastrybase = 1 + ) + result = /obj/item/reagent_containers/food/snacks/donut/semen + subcategory = CAT_PASTRY + datum/crafting_recipe/food/donut/meat time = 15 name = "Meat donut" diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 94cf27749e..cd9c914e7a 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -26,7 +26,7 @@ Captain /datum/job/captain/announce(mob/living/carbon/human/H) ..() - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.real_name] on deck!")) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!")) /datum/outfit/job/captain name = "Captain" diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm index 0e1daff5e0..e441b3e889 100644 --- a/code/modules/jobs/job_types/job.dm +++ b/code/modules/jobs/job_types/job.dm @@ -193,6 +193,12 @@ if(!J) J = SSjob.GetJob(H.job) + if(H.nameless && J.dresscodecompliant) + if(J.title in GLOB.command_positions) + H.real_name = J.title + else + H.real_name = "[J.title] #[rand(10000, 99999)]" + var/obj/item/card/id/C = H.wear_id if(istype(C)) C.access = J.get_access() diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm index f1b3b1ccdc..43fe69d633 100644 --- a/code/modules/mapping/space_management/space_reservation.dm +++ b/code/modules/mapping/space_management/space_reservation.dm @@ -9,9 +9,11 @@ var/top_right_coords[3] var/wipe_reservation_on_release = TRUE var/turf_type = /turf/open/space + var/borderturf /datum/turf_reservation/transit turf_type = /turf/open/space/transit + borderturf = /turf/open/space/transit/border /datum/turf_reservation/proc/Release() var/v = reserved_turfs.Copy() @@ -20,6 +22,12 @@ SSmapping.used_turfs -= i SSmapping.reserve_turfs(v) +/datum/turf_reservation/transit/Release() + for(var/turf/open/space/transit/T in reserved_turfs) + for(var/atom/movable/AM in T) + T.throw_atom(AM) + . = ..() + /datum/turf_reservation/proc/Reserve(width, height, zlevel) if(width > world.maxx || height > world.maxy || width < 1 || height < 1) return FALSE @@ -60,7 +68,10 @@ T.flags_1 &= ~UNUSED_RESERVATION_TURF_1 SSmapping.unused_turfs["[T.z]"] -= T SSmapping.used_turfs[T] = src - T.ChangeTurf(turf_type, turf_type) + if(borderturf && (T.x == BL.x || T.x == TR.x || T.y == BL.y || T.y == TR.y)) + T.ChangeTurf(borderturf, borderturf) + else + T.ChangeTurf(turf_type, turf_type) src.width = width src.height = height return TRUE diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 2e695e6772..b8195e23d9 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -239,10 +239,10 @@ if(ishostile(target)) var/mob/living/simple_animal/hostile/H = target if(H.ranged) //briefly delay ranged attacks - if(H.ranged_cooldown_time >= world.time) - H.ranged_cooldown_time += bonus_value + if(H.ranged_cooldown >= world.time) + H.ranged_cooldown += bonus_value else - H.ranged_cooldown_time = bonus_value + world.time + H.ranged_cooldown = bonus_value + world.time //magmawing watcher /obj/item/crusher_trophy/blaster_tubes/magma_wing diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index 1e77a907c6..7276039443 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -11,6 +11,7 @@ var/obj/item/card/id/inserted_id var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces. new /datum/data/mining_equipment("1 Marker Beacon", /obj/item/stack/marker_beacon, 10), + new /datum/data/mining_equipment("50 Point Transfer Card", /obj/item/card/mining_point_card, 50), new /datum/data/mining_equipment("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 100), new /datum/data/mining_equipment("30 Marker Beacons", /obj/item/stack/marker_beacon/thirty, 300), new /datum/data/mining_equipment("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 100), @@ -23,7 +24,7 @@ new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400), new /datum/data/mining_equipment("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500), new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500), - new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500), + new /datum/data/mining_equipment("500 Point Transfer Card", /obj/item/card/mining_point_card/mp500, 500), new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600), new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600), new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750), @@ -41,6 +42,9 @@ new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000), new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000), new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffelbag/mining_conscript, 1000), + new /datum/data/mining_equipment("1000 Point Transfer Card", /obj/item/card/mining_point_card/mp1000, 1000), + new /datum/data/mining_equipment("1500 Point Transfer Card", /obj/item/card/mining_point_card/mp1500, 1500), + new /datum/data/mining_equipment("2000 Point Transfer Card", /obj/item/card/mining_point_card/mp2000, 2000), new /datum/data/mining_equipment("Jetpack Upgrade", /obj/item/tank/jetpack/suit, 2000), new /datum/data/mining_equipment("Space Cash", /obj/item/stack/spacecash/c1000, 2000), new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000), @@ -245,12 +249,30 @@ w_class = WEIGHT_CLASS_TINY /**********************Mining Point Card**********************/ - +//mp = Miner Pointers +//c = Cash +//TODO add in cr = Credits for cargo /obj/item/card/mining_point_card name = "mining points card" - desc = "A small card preloaded with mining points. Swipe your ID card over it to transfer the points, then discard." + desc = "A small card preloaded with mining points. Swipe your ID card over it to transfer the points, then discard. This one only holds a small 50 points on it." icon_state = "data_1" - var/points = 500 + var/points = 50 + +/obj/item/card/mining_point_card/mp500 + desc = "A small card preloaded with 500 mining points. Swipe your ID card over it to transfer the points, then discard." + points = 500 + +/obj/item/card/mining_point_card/mp1000 + desc = "A small card preloaded with 1000 mining points. Swipe your ID card over it to transfer the points, then discard." + points = 1000 + +/obj/item/card/mining_point_card/mp1500 + desc = "A small card preloaded with 1500 mining points. Swipe your ID card over it to transfer the points, then discard." + points = 1500 + +/obj/item/card/mining_point_card/mp2000 + desc = "A small card preloaded with 2000 mining points. Swipe your ID card over it to transfer the points, then discard." + points = 2000 /obj/item/card/mining_point_card/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/card/id)) diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index c9710a5457..6b67ada775 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -20,17 +20,19 @@ features = random_features() age = rand(AGE_MIN,AGE_MAX) -/datum/preferences/proc/update_preview_icon(nude = FALSE) +/datum/preferences/proc/update_preview_icon() // Silicons only need a very basic preview since there is no customization for them. +// var/wide_icon = FALSE //CITDEL THINGS +// if(features["taur"] != "None") +// wide_icon = TRUE + if(job_engsec_high) switch(job_engsec_high) if(AI_JF) - preview_icon = icon('icons/mob/ai.dmi', "AI", SOUTH) - preview_icon.Scale(64, 64) + parent.show_character_previews(image('icons/mob/ai.dmi', icon_state = "AI", dir = SOUTH)) return if(CYBORG) - preview_icon = icon('icons/mob/robots.dmi', "robot", SOUTH) - preview_icon.Scale(64, 64) + parent.show_character_previews(image('icons/mob/robots.dmi', icon_state = "robot", dir = SOUTH)) return // Set up the dummy for its photoshoot @@ -57,30 +59,11 @@ previewJob = job break - if(previewJob && !nude) - mannequin.job = previewJob.title - previewJob.equip(mannequin, TRUE) - COMPILE_OVERLAYS(mannequin) - CHECK_TICK - preview_icon = icon('icons/effects/effects.dmi', "nothing") - preview_icon.Scale(48+32, 16+32) - CHECK_TICK - mannequin.setDir(NORTH) + if(previewJob) + if(current_tab != 2) + mannequin.job = previewJob.title + previewJob.equip(mannequin, TRUE) - var/icon/stamp = getFlatIcon(mannequin) - CHECK_TICK - preview_icon.Blend(stamp, ICON_OVERLAY, 25, 17) - CHECK_TICK - mannequin.setDir(WEST) - stamp = getFlatIcon(mannequin) - CHECK_TICK - preview_icon.Blend(stamp, ICON_OVERLAY, 1, 9) - CHECK_TICK - mannequin.setDir(SOUTH) - stamp = getFlatIcon(mannequin) - CHECK_TICK - preview_icon.Blend(stamp, ICON_OVERLAY, 49, 1) - CHECK_TICK - preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. - CHECK_TICK + COMPILE_OVERLAYS(mannequin) + parent.show_character_previews(new /mutable_appearance(mannequin)) unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm index ba41e1e55d..2778e3e29c 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -364,6 +364,12 @@ name = "Over Eye" icon_state = "hair_shortovereye" +//Donator item - fractious +/datum/sprite_accessory/hair/over_eye_fr + name = "Over Eye (fract)" + icon_state = "hair_shortovereye_1f" + ckeys_allowed = list("fractious") + /datum/sprite_accessory/hair/parted name = "Parted" icon_state = "hair_parted" @@ -1516,18 +1522,3 @@ /datum/sprite_accessory/moth_wings/snow name = "Snow" icon_state = "snow" - -//Lunasune -/datum/sprite_accessory/mam_ears/lunasune - name = "lunasune" - icon_state = "lunasune" - hasinner = 1 - extra = TRUE - extra_color_src = MUTCOLORS2 - ckeys_allowed = list("invader4352") - -/datum/sprite_accessory/mam_tails/lunasune - name = "lunasune" - icon_state = "lunasune" - extra = TRUE - ckeys_allowed = list("invader4352") diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index bd1fba44e2..71a12e9ff4 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -198,6 +198,11 @@ for(var/V in roundstart_quirks) var/datum/quirk/T = V blood_data["quirks"] += T.type + blood_data["changeling_loudness"] = 0 + if(mind) + var/datum/antagonist/changeling/ling = mind.has_antag_datum(/datum/antagonist/changeling) + if(istype(ling)) + blood_data["changeling_loudness"] = ling.loudfactor return blood_data //get the id of the substance this mob use as blood. diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 7d1dc7d1d2..2f3ee10428 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -62,8 +62,9 @@ /obj/item/organ/brain/proc/transfer_identity(mob/living/L) name = "[L.name]'s brain" - if(brainmob || decoy_override) + if(brainmob) return + if(!L.mind) return brainmob = new(src) @@ -80,7 +81,7 @@ var/obj/item/organ/zombie_infection/ZI = L.getorganslot(ORGAN_SLOT_ZOMBIE) if(ZI) brainmob.set_species(ZI.old_species) //For if the brain is cloned - if(L.mind && L.mind.current) + if(!decoy_override && L.mind && L.mind.current) L.mind.transfer_to(brainmob) to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just a brain.") diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index d81ef09d14..d8bb90460a 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -87,21 +87,21 @@ //CIT CHANGES END HERE apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC) - if(prob(33)) + var/basebloodychance = affecting.brute_dam + totitemdamage + if(prob(basebloodychance)) I.add_mob_blood(src) - var/turf/location = get_turf(src) - add_splatter_floor(location) - if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood + bleed(totitemdamage) + if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood user.add_mob_blood(src) if(affecting.body_zone == BODY_ZONE_HEAD) - if(wear_mask) + if(wear_mask && prob(basebloodychance)) wear_mask.add_mob_blood(src) update_inv_wear_mask() - if(wear_neck) + if(wear_neck && prob(basebloodychance)) wear_neck.add_mob_blood(src) update_inv_neck() - if(head) + if(head && prob(basebloodychance)) head.add_mob_blood(src) update_inv_head() diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 0db3d82777..950ac5fb8b 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -146,4 +146,31 @@ var/turf/T = loc T.Entered(src) -//Ayy lmao +/datum/emote/sound/human + mob_type_allowed_typecache = list(/mob/living/carbon/human) + emote_type = EMOTE_AUDIBLE + +/datum/emote/sound/human/buzz + key = "buzz" + key_third_person = "buzzes" + message = "buzzes." + message_param = "buzzes at %t." + sound = 'sound/machines/buzz-sigh.ogg' + +/datum/emote/sound/human/buzz2 + key = "buzz2" + message = "buzzes twice." + sound = 'sound/machines/buzz-two.ogg' + +/datum/emote/sound/human/ping + key = "ping" + key_third_person = "pings" + message = "pings." + message_param = "pings at %t." + sound = 'sound/machines/ping.ogg' + +/datum/emote/sound/human/chime + key = "chime" + key_third_person = "chimes" + message = "chimes." + sound = 'sound/machines/chime.ogg' diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 8c8c8e2d0c..2dfd414e85 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -264,7 +264,7 @@ if(pocket_item) if(pocket_item == (pocket_id == SLOT_R_STORE ? r_store : l_store)) //item still in the pocket we search dropItemToGround(pocket_item) - if(!put_in_hands(pocket_item)) + if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item)) pocket_item.forceMove(drop_location()) else if(place_item) @@ -892,6 +892,21 @@ . = ..(M,force,check_loc) stop_pulling() +/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this + var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor) + for(var/bp in body_parts) + if(istype(bp, /obj/item/clothing)) + var/obj/item/clothing/C = bp + if(C.blocks_shove_knockdown) + return TRUE + return FALSE + +/mob/living/carbon/human/proc/clear_shove_slowdown() + remove_movespeed_modifier(SHOVE_SLOWDOWN_ID) + var/active_item = get_active_held_item() + if(is_type_in_typecache(active_item, GLOB.shove_disarming_types)) + visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE) + /mob/living/carbon/human/do_after_coefficent() . = ..() . *= physiology.do_after_speed diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 99615e9543..4f168d97fc 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -45,6 +45,8 @@ var/name_override //For temporary visible name changes + var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters. + var/datum/personal_crafting/handcrafting var/datum/physiology/physiology diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 6050c3e278..dd37563f8f 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -56,7 +56,7 @@ if( head && (head.flags_inv&HIDEFACE) ) return if_no_face //Likewise for hats var/obj/item/bodypart/O = get_bodypart(BODY_ZONE_HEAD) - if( !O || (has_trait(TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name ) //disfigured. use id-name if possible + if( !O || (has_trait(TRAIT_DISFIGURED)) || (O.brutestate+O.burnstate)>2 || cloneloss>50 || !real_name || nameless) //disfigured. use id-name if possible return if_no_face return real_name diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index aee1daa449..0e5eef2ffb 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -317,9 +317,9 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) if(!HD) //Decapitated return - if(H.has_trait(TRAIT_HUSK)) return + var/datum/sprite_accessory/S var/list/standing = list() @@ -351,7 +351,6 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(H.facial_hair_style && (FACEHAIR in species_traits) && (!facialhair_hidden || dynamic_fhair_suffix)) S = GLOB.facial_hair_styles_list[H.facial_hair_style] if(S) - //List of all valid dynamic_fhair_suffixes var/static/list/fextensions if(!fextensions) @@ -410,7 +409,6 @@ GLOBAL_LIST_EMPTY(roundstart_races) else if(H.hair_style && (HAIR in species_traits)) S = GLOB.hair_styles_list[H.hair_style] if(S) - //List of all valid dynamic_hair_suffixes var/static/list/extensions if(!extensions) @@ -612,6 +610,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) bodyparts_to_add -= "mam_ears" + if("mam_snouts" in mutant_bodyparts) //Take a closer look at that snout! + if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC) + bodyparts_to_add -= "mam_snouts" + if("taur" in mutant_bodyparts) if(!H.dna.features["taur"] || H.dna.features["taur"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))) bodyparts_to_add -= "taur" @@ -696,13 +698,19 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layer) + accessory_overlay.color = null //just because. reee. + //A little rename so we don't have to use tail_lizard or tail_human when naming the sprites. if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "mam_tail" || bodypart == "xenotail") bodypart = "tail" - else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human" || bodypart == "mam_waggingtail") + else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human") bodypart = "waggingtail" + if(bodypart == "mam_waggingtail") + bodypart = "tailwag" if(bodypart == "mam_ears" || bodypart == "ears") bodypart = "ears" + if(bodypart == "mam_snouts" || bodypart == "snout") + bodypart = "snout" if(bodypart == "xenohead") bodypart = "xhead" @@ -714,6 +722,15 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(S.center) accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y) + var/list/colorlist = list() + colorlist.Cut() + colorlist += ReadRGB(H.dna.features["mcolor"]) + colorlist += ReadRGB(H.dna.features["mcolor2"]) + colorlist += ReadRGB(H.dna.features["mcolor3"]) + colorlist += list(0,0,0) + for(var/index=1, index<=colorlist.len, index++) + colorlist[index] = colorlist[index]/255 + if(!(H.has_trait(TRAIT_HUSK))) if(!forced_colour) switch(S.color_src) @@ -732,6 +749,10 @@ GLOBAL_LIST_EMPTY(roundstart_races) accessory_overlay.color = "#[fixed_mut_color3]" else accessory_overlay.color = "#[H.dna.features["mcolor3"]]" + + if(MATRIXED) + accessory_overlay.color = list(colorlist) + if(HAIR) if(hair_color == "mutcolor") accessory_overlay.color = "#[H.dna.features["mcolor"]]" @@ -743,6 +764,21 @@ GLOBAL_LIST_EMPTY(roundstart_races) accessory_overlay.color = "#[H.eye_color]" else accessory_overlay.color = forced_colour + else + if(bodypart == "ears") + accessory_overlay.icon_state = "m_ears_none_[layertext]" + if(bodypart == "tail") + accessory_overlay.icon_state = "m_tail_husk_[layertext]" + if(MATRIXED) + var/list/husklist = list() + husklist += ReadRGB("#a3a3a3") + husklist += ReadRGB("#a3a3a3") + husklist += ReadRGB("#a3a3a3") + husklist += list(0,0,0) + for(var/index=1, index<=husklist.len, index++) + husklist[index] = husklist[index]/255 + accessory_overlay.color = husklist + standing += accessory_overlay if(S.hasinner) @@ -1221,6 +1257,9 @@ GLOBAL_LIST_EMPTY(roundstart_races) . += speedmod . += H.physiology.speed_mod + if (H.m_intent == MOVE_INTENT_WALK && H.has_trait(TRAIT_SPEEDY_STEP)) + . -= 1 + if(H.has_trait(TRAIT_IGNORESLOWDOWN)) ignoreslow = 1 @@ -1552,7 +1591,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) bloody = 1 var/turf/location = H.loc if(istype(location)) - H.add_splatter_floor(location) + H.bleed(totitemdamage) if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood user.add_mob_blood(H) @@ -1703,6 +1742,21 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX)) else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX)) + switch((loc_temp - H.bodytemperature)*thermal_protection) + if(-INFINITY to -50) + H.throw_alert("temp", /obj/screen/alert/cold, 3) + if(-50 to -35) + H.throw_alert("temp", /obj/screen/alert/cold, 2) + if(-35 to -20) + H.throw_alert("temp", /obj/screen/alert/cold, 1) + if(-20 to 0) //This is the sweet spot where air is considered normal + H.clear_alert("temp") + if(0 to 15) //When the air around you matches your body's temperature, you'll start to feel warm. + H.throw_alert("temp", /obj/screen/alert/hot, 1) + if(15 to 30) + H.throw_alert("temp", /obj/screen/alert/hot, 2) + if(30 to INFINITY) + H.throw_alert("temp", /obj/screen/alert/hot, 3) // +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt. if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !H.has_trait(TRAIT_RESISTHEAT)) @@ -1718,14 +1772,6 @@ GLOBAL_LIST_EMPTY(roundstart_races) else firemodifier = min(firemodifier, 0) burn_damage = max(log(2-firemodifier,(H.bodytemperature-BODYTEMP_NORMAL))-5,0) // this can go below 5 at log 2.5 - if (burn_damage) - switch(burn_damage) - if(0 to 2) - H.throw_alert("temp", /obj/screen/alert/hot, 1) - if(2 to 4) - H.throw_alert("temp", /obj/screen/alert/hot, 2) - else - H.throw_alert("temp", /obj/screen/alert/hot, 3) burn_damage = burn_damage * heatmod * H.physiology.heat_mod if (H.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) //40% for level 3 damage on humans H.emote("scream") @@ -1736,17 +1782,13 @@ GLOBAL_LIST_EMPTY(roundstart_races) SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold) switch(H.bodytemperature) if(200 to BODYTEMP_COLD_DAMAGE_LIMIT) - H.throw_alert("temp", /obj/screen/alert/cold, 1) H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN) if(120 to 200) - H.throw_alert("temp", /obj/screen/alert/cold, 2) H.apply_damage(COLD_DAMAGE_LEVEL_2*coldmod*H.physiology.cold_mod, BURN) else - H.throw_alert("temp", /obj/screen/alert/cold, 3) H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN) else - H.clear_alert("temp") SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold") SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot") diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 7207a4f49d..1ee697d66c 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -4,8 +4,8 @@ id = "felinid" limbs_id = "human" - mutant_bodyparts = list("ears", "tail_human") - default_features = list("mcolor" = "FFF", "tail_human" = "Cat", "ears" = "Cat", "wings" = "None") + mutant_bodyparts = list("mam_ears", "mam_tail") + default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None") mutantears = /obj/item/organ/ears/cat mutanttail = /obj/item/organ/tail/cat @@ -23,38 +23,39 @@ stop_wagging_tail(H) . = ..() + /datum/species/human/felinid/can_wag_tail(mob/living/carbon/human/H) - return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts) + return ("mam_tail" in mutant_bodyparts) || ("mam_waggingtail" in mutant_bodyparts) /datum/species/human/felinid/is_wagging_tail(mob/living/carbon/human/H) - return ("waggingtail_human" in mutant_bodyparts) + return ("mam_waggingtail" in mutant_bodyparts) /datum/species/human/felinid/start_wagging_tail(mob/living/carbon/human/H) - if("tail_human" in mutant_bodyparts) - mutant_bodyparts -= "tail_human" - mutant_bodyparts |= "waggingtail_human" + if("mam_tail" in mutant_bodyparts) + mutant_bodyparts -= "mam_tail" + mutant_bodyparts |= "mam_waggingtail" H.update_body() /datum/species/human/felinid/stop_wagging_tail(mob/living/carbon/human/H) - if("waggingtail_human" in mutant_bodyparts) - mutant_bodyparts -= "waggingtail_human" - mutant_bodyparts |= "tail_human" + if("mam_waggingtail" in mutant_bodyparts) + mutant_bodyparts -= "mam_waggingtail" + mutant_bodyparts |= "mam_tail" H.update_body() /datum/species/human/felinid/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) if(ishuman(C)) var/mob/living/carbon/human/H = C if(!pref_load) //Hah! They got forcefully purrbation'd. Force default felinid parts on them if they have no mutant parts in those areas! - if(H.dna.features["tail_human"] == "None") - H.dna.features["tail_human"] = "Cat" - if(H.dna.features["ears"] == "None") - H.dna.features["ears"] = "Cat" - if(H.dna.features["ears"] == "Cat") + if(H.dna.features["mam_tail"] == "None") + H.dna.features["mam_tail"] = "Cat" + if(H.dna.features["mam_ears"] == "None") + H.dna.features["mam_ears"] = "Cat" + if(H.dna.features["mam_ears"] == "Cat") var/obj/item/organ/ears/cat/ears = new ears.Insert(H, drop_if_replaced = FALSE) else mutantears = /obj/item/organ/ears - if(H.dna.features["tail_human"] == "Cat") + if(H.dna.features["mam_tail"] == "Cat") var/obj/item/organ/tail/cat/tail = new tail.Insert(H, drop_if_replaced = FALSE) else diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 72052f0fa1..71717bfc16 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -359,7 +359,6 @@ There are several things that need to be remembered: apply_overlay(BELT_LAYER) - /mob/living/carbon/human/update_inv_wear_suit() remove_overlay(SUIT_LAYER) @@ -391,8 +390,6 @@ There are several things that need to be remembered: else if(S.taurmode == NOT_TAURIC && S.adjusted == NORMAL_STYLE) S.alternate_worn_icon = null - - overlays_standing[SUIT_LAYER] = S.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = ((wear_suit.alternate_worn_icon) ? S.alternate_worn_icon : 'icons/mob/suit.dmi')) var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER] if(OFFSET_SUIT in dna.species.offset_features) @@ -477,7 +474,6 @@ There are several things that need to be remembered: out += overlays_standing[i] return out - //human HUD updates for items in our inventory //update whether our head item appears on our hud. @@ -614,7 +610,7 @@ generate/load female uniform sprites matching all previously decided variables else if(dna.species.fixed_mut_color) . += "-coloured-[dna.species.fixed_mut_color]" else if(dna.features["mcolor"]) - . += "-coloured-[dna.features["mcolor"]]" + . += "-coloured-[dna.features["mcolor"]]-[dna.features["mcolor2"]]-[dna.features["mcolor3"]]" else . += "-not_coloured" @@ -644,6 +640,8 @@ generate/load female uniform sprites matching all previously decided variables . += "-digitigrade[BP.use_digitigrade]" if(BP.dmg_overlay_type) . += "-[BP.dmg_overlay_type]" + if(BP.body_markings) + . += "-[BP.body_markings]" if(has_trait(TRAIT_HUSK)) . += "-husk" diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index fa435d11c0..a2f6a469d9 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -455,6 +455,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -3) : -1.5)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke if(!recoveringstam && incomingstammult != 1) + incomingstammult = max(0.01, incomingstammult) incomingstammult = min(1, incomingstammult*2) //CIT CHANGES START HERE. STAMINA BUFFER STUFF diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 2dad832aa4..25d8c4d44c 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -486,6 +486,7 @@ message = "beeps." message_param = "beeps at %t." sound = 'sound/machines/twobeep.ogg' + mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/living/carbon/human) /datum/emote/living/circle key = "circle" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c32b6ace78..0e67ce7510 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -170,6 +170,9 @@ var/mob/living/L = M if(L.has_trait(TRAIT_PUSHIMMUNE)) return 1 + //If they're a human, and they're not in help intent, block pushing + if(ishuman(M) && (M.a_intent != INTENT_HELP)) + return TRUE //anti-riot equipment is also anti-push for(var/obj/item/I in M.held_items) if(!istype(M, /obj/item/clothing)) @@ -705,7 +708,7 @@ log_combat(src, who, "stripped [what] off") if(what == who.get_item_by_slot(where)) if(who.dropItemToGround(what)) - if(!put_in_hands(what)) + if(!can_hold_items() || !put_in_hands(what)) what.forceMove(drop_location()) log_combat(src, who, "stripped [what] off") @@ -1067,10 +1070,12 @@ update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall. /mob/living/proc/update_z(new_z) // 1+ to register, null to unregister + if(isnull(new_z) && audiovisual_redirect) + return if (registered_z != new_z) if (registered_z) SSmobs.clients_by_zlevel[registered_z] -= src - if (client) + if (client || audiovisual_redirect) if (new_z) SSmobs.clients_by_zlevel[new_z] += src for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511 diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index c4754599d1..a0f619a7d6 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -170,7 +170,6 @@ GLOBAL_LIST_INIT(department_radio_keys, list( var/message_len = length(message) message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]" message = Ellipsis(message, 10, 1) - last_words = message message_mode = MODE_WHISPER_CRIT succumbed = TRUE else @@ -180,6 +179,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list( if(!message) return + last_words = message + spans |= get_spans() if(language) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 3dbb454655..b4524a54e6 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -86,7 +86,7 @@ var/datum/action/innate/deploy_last_shell/redeploy_action = new var/chnotify = 0 - var/multicam_allowed = FALSE + var/multicam_on = FALSE var/obj/screen/movable/pic_in_pic/ai/master_multicam var/list/multicam_screens = list() diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index 20b5f96242..fcc068b7fe 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -194,7 +194,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room) //AI procs /mob/living/silicon/ai/proc/drop_new_multicam(silent = FALSE) - if(!multicam_allowed) + if(!CONFIG_GET(flag/allow_ai_multicam)) if(!silent) to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.") return @@ -213,7 +213,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room) return C /mob/living/silicon/ai/proc/toggle_multicam() - if(!multicam_allowed) + if(!CONFIG_GET(flag/allow_ai_multicam)) to_chat(src, "This action is currently disabled. Contact an administrator to enable this feature.") return if(multicam_on) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 3f3071bf0c..38ad3b8e5a 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -153,8 +153,14 @@ B.cell.charge = B.cell.maxcharge else if(istype(I, /obj/item/gun/energy)) var/obj/item/gun/energy/EG = I - if(!EG.chambered) - EG.recharge_newshot() //try to reload a new shot. + if(EG.cell?.charge < EG.cell.maxcharge) + var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.select] + EG.cell.give(S.e_cost * coeff) + if(!EG.chambered) + EG.recharge_newshot(TRUE) + EG.update_icon() + else + EG.charge_tick = 0 R.toner = R.tonermax @@ -278,7 +284,8 @@ /obj/item/borg/cyborghug/medical, /obj/item/stack/medical/gauze/cyborg, /obj/item/organ_storage, - /obj/item/borg/lollipop) + /obj/item/borg/lollipop, + /obj/item/sensor_device) emag_modules = list(/obj/item/reagent_containers/borghypo/hacked) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/medical, @@ -330,7 +337,8 @@ /obj/item/restraints/handcuffs/cable/zipties, /obj/item/melee/baton/loaded, /obj/item/gun/energy/disabler/cyborg, - /obj/item/clothing/mask/gas/sechailer/cyborg) + /obj/item/clothing/mask/gas/sechailer/cyborg, + /obj/item/pinpointer/crew) emag_modules = list(/obj/item/gun/energy/laser/cyborg) ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security, /obj/item/clockwork/weapon/ratvarian_spear) @@ -342,18 +350,7 @@ /obj/item/robot_module/security/do_transform_animation() ..() to_chat(loc, "While you have picked the security module, you still have to follow your laws, NOT Space Law. \ - For Asimov, this means you must follow criminals' orders unless there is a law 1 reason not to.") - -/obj/item/robot_module/security/respawn_consumable(mob/living/silicon/robot/R, coeff = 1) - ..() - var/obj/item/gun/energy/e_gun/advtaser/cyborg/T = locate(/obj/item/gun/energy/e_gun/advtaser/cyborg) in basic_modules - if(T) - if(T.cell.charge < T.cell.maxcharge) - var/obj/item/ammo_casing/energy/S = T.ammo_type[T.select] - T.cell.give(S.e_cost * coeff) - T.update_icon() - else - T.charge_tick = 0 + For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.") /obj/item/robot_module/peacekeeper name = "Peacekeeper" @@ -490,28 +487,6 @@ if(O) O.reagents.add_reagent("enzyme", 2 * coeff) -/obj/item/robot_module/butler/be_transformed_to(obj/item/robot_module/old_module) - var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Waitress", "Butler", "Tophat", "Kent", "Bro") - if(!borg_icon) - return FALSE - switch(borg_icon) - if("Waitress") - cyborg_base_icon = "service_f" - if("Butler") - cyborg_base_icon = "service_m" - if("Bro") - cyborg_base_icon = "brobot" - if("Kent") - cyborg_base_icon = "kent" - special_light_key = "medical" - hat_offset = 3 - if("Tophat") - cyborg_base_icon = "tophat" - special_light_key = null - hat_offset = INFINITY //He is already wearing a hat - return ..() - /obj/item/robot_module/miner name = "Miner" basic_modules = list( diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index be98d1bfab..43abe7c825 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -261,11 +261,13 @@ if(!has_trait(TRAIT_HUSK)) remove_trait(TRAIT_DISFIGURED, "husk") update_body() + return TRUE /mob/living/proc/become_husk(source) if(!has_trait(TRAIT_HUSK)) add_trait(TRAIT_DISFIGURED, "husk") update_body() + . = TRUE add_trait(TRAIT_HUSK, source) /mob/living/proc/cure_fakedeath(list/sources) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 79215ff5f5..30e58ebb44 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -76,6 +76,8 @@ return "a ... thing?" /mob/proc/show_message(msg, type, alt_msg, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) + if(audiovisual_redirect) + audiovisual_redirect.show_message(msg ? "[msg]" : null, type, alt_msg ? "[alt_msg]" : null, alt_type) if(!client) return diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 298fee46cd..a0126f5fdd 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -110,3 +110,5 @@ var/datum/click_intercept var/registered_z + + var/mob/audiovisual_redirect //Mob to redirect messages, speech, and sounds to diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm index 6841534b0e..a1a1bbe502 100644 --- a/code/modules/mob/status_procs.dm +++ b/code/modules/mob/status_procs.dm @@ -232,6 +232,8 @@ remove_eyeblur() /mob/proc/add_eyeblur() + if(!client) + return var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen GW.add_filter("blurry_eyes", 2, EYE_BLUR(CLAMP(eye_blurry*0.1,0.6,3))) @@ -242,6 +244,8 @@ add_eyeblur() /mob/proc/remove_eyeblur() + if(!client) + return var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen GW.remove_filter("blurry_eyes") diff --git a/code/modules/photography/camera/other.dm b/code/modules/photography/camera/other.dm index ce2572db36..3695559e97 100644 --- a/code/modules/photography/camera/other.dm +++ b/code/modules/photography/camera/other.dm @@ -12,3 +12,10 @@ desc = "A polaroid camera with extra capacity for crime investigations." pictures_max = 30 pictures_left = 30 + +/obj/item/camera/spooky/family + name = "fancy camera" + desc = "A fancy camera that has the latest magnifier mods and double the film load! With a complex double lens set with holy water to be able to see the dead, at laest to the Chaplain..." + see_ghosts = CAMERA_SEE_GHOSTS_ORBIT + pictures_max = 30 + pictures_left = 30 diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index a36800c2f9..e43db529b8 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -192,7 +192,7 @@ /obj/item/stock_parts/cell/secborg name = "security borg rechargeable D battery" - maxcharge = 600 //600 max charge / 100 charge per shot = six shots + maxcharge = 1750 //35/17/8 disabler/laser/taser shots. materials = list(MAT_GLASS=40) /obj/item/stock_parts/cell/secborg/empty/Initialize() diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index 8e121dc809..fcc2c6c144 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -65,7 +65,7 @@ if(delta_temperature > 0 && cold_air_heat_capacity > 0 && hot_air_heat_capacity > 0) - var/efficiency = 0.45 + var/efficiency = 0.00025 + (hot_air.reaction_results["fire"]*0.01) var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity) diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 7a6e313cd0..2bb013f65e 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -1,4 +1,3 @@ - //Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power). /obj/machinery/power/port_gen name = "portable generator" @@ -9,9 +8,8 @@ anchored = FALSE use_power = NO_POWER_USE - var/active = 0 + var/active = FALSE var/power_gen = 5000 - var/recent_fault = 0 var/power_output = 1 var/consumption = 0 var/base_icon = "portgen0" @@ -27,8 +25,13 @@ QDEL_NULL(soundloop) return ..() +/obj/machinery/power/port_gen/connect_to_network() + if(!anchored) + return FALSE + . = ..() + /obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check. - return 1 + return TRUE /obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use. return @@ -39,26 +42,38 @@ /obj/machinery/power/port_gen/proc/handleInactive() return +/obj/machinery/power/port_gen/proc/TogglePower() + if(active) + active = FALSE + update_icon() + soundloop.stop() + else if(HasFuel()) + active = TRUE + START_PROCESSING(SSmachines, src) + update_icon() + soundloop.start() + /obj/machinery/power/port_gen/update_icon() icon_state = "[base_icon]_[active]" /obj/machinery/power/port_gen/process() - if(active && HasFuel() && !crit_fail && anchored && powernet) - add_avail(power_gen * power_output) + if(active) + if(!HasFuel() || !anchored) + TogglePower() + return + if(powernet) + add_avail(power_gen * power_output) UseFuel() - src.updateDialog() - soundloop.start() - else - active = 0 handleInactive() - update_icon() - soundloop.stop() /obj/machinery/power/port_gen/examine(mob/user) ..() to_chat(user, "It is[!active?"n't":""] running.") +///////////////// +// P.A.C.M.A.N // +///////////////// /obj/machinery/power/port_gen/pacman name = "\improper P.A.C.M.A.N.-type portable generator" circuit = /obj/item/circuitboard/machine/pacman @@ -78,8 +93,8 @@ /obj/machinery/power/port_gen/pacman/Initialize() . = ..() - var/obj/sheet = new sheet_path(null) - sheet_name = sheet.name + var/obj/S = sheet_path + sheet_name = initial(S.name) /obj/machinery/power/port_gen/pacman/Destroy() DropFuel() @@ -100,14 +115,16 @@ /obj/machinery/power/port_gen/pacman/examine(mob/user) ..() - to_chat(user, "The generator has [sheets] units of [sheet_name] fuel left, producing [power_gen] per cycle.") - if(crit_fail) - to_chat(user, "The generator seems to have broken down.") + to_chat(user, "The generator has [sheets] units of [sheet_name] fuel left, producing [DisplayPower(power_gen)] per cycle.") + if(anchored) + to_chat(user, "It is anchored to the ground.") + if(in_range(user, src) || isobserver(user)) + to_chat(user, "The status display reads: Fuel efficiency increased by [(consumption*100)-100]%.") /obj/machinery/power/port_gen/pacman/HasFuel() if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left) - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/power/port_gen/pacman/DropFuel() if(sheets) @@ -143,13 +160,11 @@ if (current_heat > 300) overheat() qdel(src) - return /obj/machinery/power/port_gen/pacman/handleInactive() - - if (current_heat > 0) - current_heat = max(current_heat - 2, 0) - src.updateDialog() + current_heat = max(current_heat - 2, 0) + if(current_heat == 0) + STOP_PROCESSING(SSmachines, src) /obj/machinery/power/port_gen/pacman/proc/overheat() explosion(src.loc, 2, 5, 2, -1) @@ -164,24 +179,21 @@ to_chat(user, "You add [amount] sheets to the [src.name].") sheets += amount addstack.use(amount) - updateUsrDialog() return else if(!active) - - if(istype(O, /obj/item/wrench)) - + if(O.tool_behaviour == TOOL_WRENCH) if(!anchored && !isinspace()) + anchored = TRUE connect_to_network() to_chat(user, "You secure the generator to the floor.") - anchored = TRUE else if(anchored) + anchored = FALSE disconnect_from_network() to_chat(user, "You unsecure the generator from the floor.") - anchored = FALSE - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + playsound(src, 'sound/items/deconstruct.ogg', 50, 1) return - else if(istype(O, /obj/item/screwdriver)) + else if(O.tool_behaviour == TOOL_SCREWDRIVER) panel_open = !panel_open O.play_tool_sound(src) if(panel_open) @@ -205,60 +217,52 @@ /obj/machinery/power/port_gen/pacman/attack_paw(mob/user) interact(user) -/obj/machinery/power/port_gen/pacman/ui_interact(mob/user) - . = ..() - if (get_dist(src, user) > 1 ) - if(!isAI(user)) - user.unset_machine() - user << browse(null, "window=port_gen") - return +/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "portable_generator", name, 450, 340, master_ui, state) + ui.open() - var/dat = text("[name]
") - if (active) - dat += text("Generator: On
") - else - dat += text("Generator: Off
") - dat += text("[capitalize(sheet_name)]: [sheets] - Eject
") - var/stack_percent = round(sheet_left * 100, 1) - dat += text("Current stack: [stack_percent]%
") - dat += text("Power output: - [power_gen * power_output] +
") - dat += text("Power current: [(powernet == null ? "Unconnected" : "[DisplayPower(avail())]")]
") - dat += text("Heat: [current_heat]
") - dat += "
Close" - user << browse(dat, "window=port_gen") - onclose(user, "port_gen") +/obj/machinery/power/port_gen/pacman/ui_data() + var/data = list() -/obj/machinery/power/port_gen/pacman/Topic(href, href_list) + data["active"] = active + data["sheet_name"] = capitalize(sheet_name) + data["sheets"] = sheets + data["stack_percent"] = round(sheet_left * 100, 0.1) + + data["anchored"] = anchored + data["connected"] = (powernet == null ? 0 : 1) + data["ready_to_boot"] = anchored && HasFuel() + data["power_generated"] = DisplayPower(power_gen) + data["power_output"] = DisplayPower(power_gen * power_output) + data["power_available"] = (powernet == null ? 0 : DisplayPower(avail())) + data["current_heat"] = current_heat + . = data + +/obj/machinery/power/port_gen/pacman/ui_act(action, params) if(..()) return + switch(action) + if("toggle_power") + TogglePower() + . = TRUE - src.add_fingerprint(usr) - if(href_list["action"]) - if(href_list["action"] == "enable") - if(!active && HasFuel() && !crit_fail) - active = 1 - src.updateUsrDialog() - update_icon() - if(href_list["action"] == "disable") - if (active) - active = 0 - src.updateUsrDialog() - update_icon() - if(href_list["action"] == "eject") + if("eject") if(!active) DropFuel() - src.updateUsrDialog() - if(href_list["action"] == "lower_power") + . = TRUE + + if("lower_power") if (power_output > 1) power_output-- - src.updateUsrDialog() - if (href_list["action"] == "higher_power") + . = TRUE + + if("higher_power") if (power_output < 4 || (obj_flags & EMAGGED)) power_output++ - src.updateUsrDialog() - if (href_list["action"] == "close") - usr << browse(null, "window=port_gen") - usr.unset_machine() + . = TRUE /obj/machinery/power/port_gen/pacman/super name = "\improper S.U.P.E.R.P.A.C.M.A.N.-type portable generator" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 701e92527b..a7474fd8cb 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -451,6 +451,8 @@ target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!") + playsound('sound/weapons/dink.ogg', 30, 1) + if(chambered && chambered.BB) chambered.BB.damage *= 5 @@ -477,8 +479,12 @@ /datum/action/toggle_scope_zoom/IsAvailable() . = ..() - if(!. && gun) + if(!gun) + return FALSE + if(!.) gun.zoom(owner, FALSE) + if(!owner.get_held_index_of_item(gun)) + return FALSE /datum/action/toggle_scope_zoom/Remove(mob/living/L) gun.zoom(L, FALSE) diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index b9a509f33f..157cf1f03f 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -161,6 +161,7 @@ var/turf/T = get_turf(user) process_fire(user, user, FALSE, null, BODY_ZONE_HEAD) user.visible_message("[user] blows [user.p_their()] brain[user.p_s()] out with [src]!") + playsound(src, 'sound/weapons/dink.ogg', 30, 1) var/turf/target = get_ranged_target_turf(user, turn(user.dir, 180), BRAINS_BLOWN_THROW_RANGE) B.Remove(user) B.forceMove(T) diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index d1dcdf22d8..8aa8d53726 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -113,8 +113,8 @@ icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/gun/ballistic/automatic/wt550 - name = "security auto rifle" - desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Automatic Rifle." + name = "security semi-auto smg" + desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Semi-Automatic SMG." icon_state = "wt550" item_state = "arg" mag_type = /obj/item/ammo_box/magazine/wt550m9 diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index dd2baa7db8..6060ceba99 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -15,10 +15,10 @@ ammo_x_offset = 2 var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail var/old_ratio = 0 // stores the gun's previous ammo "ratio" to see if it needs an updated icon - var/selfcharge = 0 + var/selfcharge = EGUN_NO_SELFCHARGE // EGUN_SELFCHARGE if true, EGUN_SELFCHARGE_BORG drains the cyborg's cell to recharge its own var/charge_tick = 0 var/charge_delay = 4 - var/use_cyborg_cell = 0 //whether the gun's cell drains the cyborg user's cell to recharge + var/use_cyborg_cell = FALSE //whether the gun drains the cyborg user's cell instead, not to be confused with EGUN_SELFCHARGE_BORG var/dead_cell = FALSE //set to true so the gun is given an empty cell /obj/item/gun/energy/emp_act(severity) @@ -62,11 +62,20 @@ return ..() /obj/item/gun/energy/process() - if(selfcharge && cell && cell.percent() < 100) + if(selfcharge && cell?.charge < cell.maxcharge) charge_tick++ if(charge_tick < charge_delay) return charge_tick = 0 + if(selfcharge == EGUN_SELFCHARGE_BORG) + var/atom/owner = loc + if(istype(owner, /obj/item/robot_module)) + owner = owner.loc + if(!iscyborg(owner)) + return + var/mob/living/silicon/robot/R = owner + if(!R.cell?.use(100)) + return cell.give(100) if(!chambered) //if empty chamber we try to charge a new shot recharge_newshot(TRUE) @@ -175,6 +184,7 @@ if(user.is_holding(src)) user.visible_message("[user] melts [user.p_their()] face off with [src]!") playsound(loc, fire_sound, 50, 1, -1) + playsound(src, 'sound/weapons/dink.ogg', 30, 1) var/obj/item/ammo_casing/energy/shot = ammo_type[select] cell.use(shot.e_cost) update_icon() diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 99f8166297..54cb9fe5d0 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -98,7 +98,7 @@ can_charge = 0 ammo_x_offset = 1 ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser, /obj/item/ammo_casing/energy/disabler) - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE var/fail_tick = 0 var/fail_chance = 0 diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 6e8174b356..066b652984 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -36,7 +36,7 @@ desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding." force = 10 ammo_x_offset = 3 - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF /obj/item/gun/energy/laser/captain/scattershot @@ -47,13 +47,19 @@ ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter, /obj/item/ammo_casing/energy/laser) /obj/item/gun/energy/laser/cyborg - can_charge = 0 + can_charge = FALSE desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?" - use_cyborg_cell = 1 + selfcharge = EGUN_SELFCHARGE_BORG + cell_type = /obj/item/stock_parts/cell/secborg + charge_delay = 3 /obj/item/gun/energy/laser/cyborg/emp_act() return +/obj/item/gun/energy/laser/cyborg/mean + use_cyborg_cell = TRUE + selfcharge = EGUN_NO_SELFCHARGE + /obj/item/gun/energy/laser/scatter name = "scatter laser gun" desc = "A laser gun equipped with a refraction kit that spreads bolts." @@ -120,7 +126,7 @@ clumsy_check = FALSE pin = /obj/item/firing_pin/tag/blue ammo_x_offset = 2 - selfcharge = TRUE + selfcharge = EGUN_SELFCHARGE /obj/item/gun/energy/laser/bluetag/hitscan ammo_type = list(/obj/item/ammo_casing/energy/laser/bluetag/hitscan) @@ -134,7 +140,7 @@ clumsy_check = FALSE pin = /obj/item/firing_pin/tag/red ammo_x_offset = 2 - selfcharge = TRUE + selfcharge = EGUN_SELFCHARGE /obj/item/gun/energy/laser/redtag/hitscan ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan) diff --git a/code/modules/projectiles/guns/energy/megabuster.dm b/code/modules/projectiles/guns/energy/megabuster.dm index 3f14fe3b8d..9825fda459 100644 --- a/code/modules/projectiles/guns/energy/megabuster.dm +++ b/code/modules/projectiles/guns/energy/megabuster.dm @@ -7,7 +7,7 @@ ammo_type = list(/obj/item/ammo_casing/energy/megabuster) clumsy_check = FALSE item_flags = NEEDS_PERMIT - selfcharge = TRUE + selfcharge = EGUN_SELFCHARGE cell_type = "/obj/item/stock_parts/cell/pulse" icon = 'modular_citadel/icons/obj/guns/VGguns.dmi' diff --git a/code/modules/projectiles/guns/energy/mounted.dm b/code/modules/projectiles/guns/energy/mounted.dm index 79226689de..eed4e7316f 100644 --- a/code/modules/projectiles/guns/energy/mounted.dm +++ b/code/modules/projectiles/guns/energy/mounted.dm @@ -5,13 +5,10 @@ icon_state = "taser" item_state = "armcannonstun4" force = 5 - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE can_flashlight = 0 trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses neural signals instead -/obj/item/gun/energy/e_gun/advtaser/mounted/dropped()//if somebody manages to drop this somehow... - ..() - /obj/item/gun/energy/laser/mounted name = "mounted laser" desc = "An arm mounted cannon that fires lethal lasers." @@ -19,8 +16,5 @@ icon_state = "laser" item_state = "armcannonlase" force = 5 - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE trigger_guard = TRIGGER_GUARD_ALLOW_ALL - -/obj/item/gun/energy/laser/mounted/dropped() - ..() diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index ffc7e71c75..d5d5a79fde 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -48,7 +48,7 @@ ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut) modifystate = 1 ammo_x_offset = 1 - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE /obj/item/gun/energy/meteorgun name = "meteor gun" @@ -59,7 +59,7 @@ ammo_type = list(/obj/item/ammo_casing/energy/meteor) cell_type = "/obj/item/stock_parts/cell/potato" clumsy_check = 0 //Admin spawn only, might as well let clowns use it. - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE /obj/item/gun/energy/meteorgun/pen name = "meteor pen" diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 77281497ba..3733dad9a3 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -25,10 +25,17 @@ /obj/item/gun/energy/e_gun/advtaser/cyborg name = "cyborg taser" - desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The weapon contains a limiter to prevent the cyborg's power cell from overheating." - can_flashlight = 0 - can_charge = 0 - use_cyborg_cell = 1 + desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The one contains a limiter to prevent the cyborg's power cell from overheating." + can_flashlight = FALSE + can_charge = FALSE + selfcharge = EGUN_SELFCHARGE_BORG + cell_type = /obj/item/stock_parts/cell/secborg + charge_delay = 5 + +/obj/item/gun/energy/e_gun/advtaser/cyborg/mean + desc = "An integrated hybrid taser that draws directly from a cyborg's power cell." + use_cyborg_cell = TRUE + selfcharge = EGUN_NO_SELFCHARGE /obj/item/gun/energy/disabler name = "disabler" @@ -40,6 +47,13 @@ /obj/item/gun/energy/disabler/cyborg name = "cyborg disabler" - desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." - can_charge = 0 - use_cyborg_cell = 1 + desc = "An integrated disabler that draws from a cyborg's power cell. This one contains a limiter to prevent the cyborg's power cell from overheating." + can_charge = FALSE + selfcharge = EGUN_SELFCHARGE_BORG + cell_type = /obj/item/stock_parts/cell/secborg + charge_delay = 5 + +/obj/item/gun/energy/disabler/cyborg/mean + desc = "An integrated disabler that draws from a cyborg's power cell." + use_cyborg_cell = TRUE + selfcharge = EGUN_NO_SELFCHARGE diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index a23bf1f4ed..1391e9ce42 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -164,7 +164,10 @@ new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir) else new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir) - if(prob(33)) + if(iscarbon(L)) + var/mob/living/carbon/C = L + C.bleed(damage) + else L.add_splatter_floor(target_loca) else if(impact_effect_type && !hitscan) new impact_effect_type(target_loca, hitx, hity) @@ -182,6 +185,8 @@ playsound(loc, hitsound, volume, 1, -1) L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \ "[L] is hit by \a [src][organ_hit_text]!", null, COMBAT_MESSAGE_RANGE) + if(def_zone == BODY_ZONE_HEAD) + playsound(src, 'sound/weapons/dink.ogg', 30, 1) L.on_hit(src) var/reagent_note diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 9674485c45..252d0d0dc3 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -361,6 +361,8 @@ var/required_temp = C.required_temp var/is_cold_recipe = C.is_cold_recipe var/meets_temp_requirement = 0 + var/has_special_react = C.special_react + var/can_special_react = 0 for(var/B in cached_required_reagents) if(!has_reagent(B, cached_required_reagents[B])) @@ -396,7 +398,10 @@ if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp)) meets_temp_requirement = 1 - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement) + if(!has_special_react || C.check_special_react(src)) + can_special_react = 1 + + if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) possible_reactions += C if(possible_reactions.len) @@ -412,6 +417,7 @@ selected_reaction = competitor var/list/cached_required_reagents = selected_reaction.required_reagents var/list/cached_results = selected_reaction.results + var/special_react_result = selected_reaction.check_special_react(src) var/list/multiplier = INFINITY for(var/B in cached_required_reagents) multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B])) @@ -443,7 +449,7 @@ ME2.name = "used slime extract" ME2.desc = "This extract has been used up." - selected_reaction.on_reaction(src, multiplier) + selected_reaction.on_reaction(src, multiplier, special_react_result) reaction_occurred = 1 while(reaction_occurred) diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index eb3daef393..d77756a649 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -167,10 +167,10 @@ /datum/reagent/drug/methamphetamine/on_mob_add(mob/living/L) ..() - L.add_trait(TRAIT_GOTTAGOREALLYFAST, id) + L.add_trait(TRAIT_IGNORESLOWDOWN, id) /datum/reagent/drug/methamphetamine/on_mob_delete(mob/living/L) - L.remove_trait(TRAIT_GOTTAGOREALLYFAST, id) + L.remove_trait(TRAIT_IGNORESLOWDOWN, id) ..() /datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M) @@ -180,9 +180,12 @@ M.AdjustStun(-40, 0) M.AdjustKnockdown(-40, 0) M.AdjustUnconscious(-40, 0) - M.adjustStaminaLoss(-2, 0) + M.adjustStaminaLoss(-7.5 * REM, 0) M.Jitter(2) M.adjustBrainLoss(rand(1,4)) + if(prob(30)) + M.confused = max(1, M.confused) + M.heal_overall_damage(2, 2) if(prob(5)) M.emote(pick("twitch", "shiver")) ..() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index a7e4e0f590..4b4f118a9c 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -32,6 +32,12 @@ else C.blood_volume = min(C.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM) + if(reac_volume >= 10 && istype(L)) + L.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) + +/datum/reagent/blood/reaction_obj(obj/O, volume) + if(volume >= 3 && istype(O)) + O.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"])) /datum/reagent/blood/on_new(list/data) if(istype(data)) diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index e19d2c20d7..50006eef62 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -13,13 +13,17 @@ var/required_temp = 0 var/is_cold_recipe = 0 // Set to 1 if you want the recipe to only react when it's BELOW the required temp. + var/special_react = FALSE //Determines if the recipe has special conditions for it to react. Mainly used for ling blood tests var/mix_message = "The solution begins to bubble." //The message shown to nearby people upon mixing, if applicable var/mix_sound = 'sound/effects/bubbles.ogg' //The sound played upon mixing, if applicable -/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume) +/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact) return //I recommend you set the result amount to the total volume of all components. +/datum/chemical_reaction/proc/check_special_react(datum/reagents/holder) + return + /datum/chemical_reaction/proc/chemical_mob_spawn(datum/reagents/holder, amount_to_spawn, reaction_name, mob_class = HOSTILE_SPAWN, mob_faction = "chemicalsummon") if(holder && holder.my_atom) var/atom/A = holder.my_atom diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index e1f4e3dd36..bcd08b1853 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -133,6 +133,18 @@ required_reagents = list("slime_toxin" = 1, "mutagen" = 1) +/datum/chemical_reaction/fermis_plush + name = "Fermis plush" + id = "fermis_plush" + required_reagents = list("sugar" = 10, "blood" = 10, "stable_plasma" = 10) + mob_react = FALSE + required_temp = 400 + +/datum/chemical_reaction/fermis_plush/on_reaction(datum/reagents/holder, created_volume) + var/location = get_turf(holder.my_atom) + for(var/i = 1, i <= created_volume, i+=10) + new /obj/item/toy/plush/catgirl/fermis(location) + ////////////////////////////////// VIROLOGY ////////////////////////////////////////// /datum/chemical_reaction/virus_food diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 471131ff00..587d6c8b38 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -464,4 +464,30 @@ results = list("firefighting_foam" = 3) required_reagents = list("stabilizing_agent" = 1,"fluorosurfactant" = 1,"carbon" = 1) required_temp = 200 - is_cold_recipe = 1 \ No newline at end of file + is_cold_recipe = 1 + +/datum/chemical_reaction/reagent_explosion/lingblood + name = "Changeling Blood Reaction" + id = "ling_blood_reaction" + results = list("ash" = 1) + required_reagents = list("blood" = 1) + strengthdiv = 4 //The explosion should be somewhat strong if a full 15u is heated within a syringe. !!fun!! + required_temp = 666 + special_react = TRUE + mix_sound = 'sound/effects/lingbloodhiss.ogg' + mix_message = "The blood bubbles and sizzles violently!" + +/datum/chemical_reaction/reagent_explosion/lingblood/check_special_react(datum/reagents/holder) + if(!holder) + return FALSE + var/list/D = holder.get_data("blood") + if(D && D["changeling_loudness"]) + return (D["changeling_loudness"] >= 4 ? D["changeling_loudness"] : FALSE) + else + return FALSE + +/datum/chemical_reaction/reagent_explosion/lingblood/on_reaction(datum/reagents/holder, created_volume, specialreact) + if(specialreact >= 10) + return ..() + else + return FALSE diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 955b519e6a..98c85b875f 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -82,6 +82,9 @@ if(D.active) return TRUE +/obj/item/reagent_containers/proc/ForceResetRotation() + transform = initial(transform) + /obj/item/reagent_containers/proc/SplashReagents(atom/target, thrown = FALSE) if(!reagents || !reagents.total_volume || !spillable) return @@ -104,6 +107,7 @@ else if(bartender_check(target) && thrown) visible_message("[src] lands onto the [target.name] without spilling a single drop.") transform = initial(transform) + addtimer(CALLBACK(src, .proc/ForceResetRotation), 1) return else diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 2402967ff3..9b42709fe2 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -218,8 +218,8 @@ //WT550 Mags /datum/design/mag_oldsmg - name = "WT-550 Auto Gun Magazine (4.6x30mm)" - desc = "A 20 round magazine for the out of date security WT-550 Auto Rifle" + name = "WT-550 Semi-Auto SMG Magazine (4.6x30mm)" + desc = "A 20 round magazine for the out of date security WT-550 Semi-Auto SMG." id = "mag_oldsmg" build_type = PROTOLATHE materials = list(MAT_METAL = 4000) @@ -228,16 +228,16 @@ departmental_flags = DEPARTMENTAL_FLAG_SECURITY /datum/design/mag_oldsmg/ap_mag - name = "WT-550 Auto Gun Armour Piercing Magazine (4.6x30mm AP)" - desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle" + name = "WT-550 Semi-Auto SMG Armour Piercing Magazine (4.6x30mm AP)" + desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG." id = "mag_oldsmg_ap" materials = list(MAT_METAL = 6000, MAT_SILVER = 600) build_path = /obj/item/ammo_box/magazine/wt550m9/wtap departmental_flags = DEPARTMENTAL_FLAG_SECURITY /datum/design/mag_oldsmg/ic_mag - name = "WT-550 Auto Gun Incendiary Magazine (4.6x30mm IC)" - desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle" + name = "WT-550 Semi-Auto SMG Incendiary Magazine (4.6x30mm IC)" + desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG." id = "mag_oldsmg_ic" materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_GLASS = 1000) build_path = /obj/item/ammo_box/magazine/wt550m9/wtic diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index d3cd399635..6670a01284 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -80,10 +80,10 @@ reagents.trans_to(G, G.reagents.maximum_volume) return ..() -/obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist, notify_admins) +/obj/machinery/rnd/production/proc/do_print(path, amount, list/matlist, notify_admins, mob/user) if(notify_admins) - investigate_log("[key_name(usr)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH) - message_admins("[ADMIN_LOOKUPFLW(usr)] has built [amount] of [path] at a [src]([type]).") + investigate_log("[key_name(user)] built [amount] of [path] at [src]([type]).", INVESTIGATE_RESEARCH) + message_admins("[ADMIN_LOOKUPFLW(user)] has built [amount] of [path] at a [src]([type]).") for(var/i in 1 to amount) var/obj/item/I = new path(get_turf(src)) if(efficient_with(I.type)) @@ -155,7 +155,7 @@ flick(production_animation, src) var/timecoeff = D.lathe_time_factor / efficiency_coeff addtimer(CALLBACK(src, .proc/reset_busy), (30 * timecoeff * amount) ** 0.5) - addtimer(CALLBACK(src, .proc/do_print, D.build_path, amount, efficient_mats, D.dangerous_construction), (32 * timecoeff * amount) ** 0.8) + addtimer(CALLBACK(src, .proc/do_print, D.build_path, amount, efficient_mats, D.dangerous_construction, usr), (32 * timecoeff * amount) ** 0.8) return TRUE /obj/machinery/rnd/production/proc/search(string) diff --git a/code/modules/research/xenobiology/crossbreeding/_corecross.dm b/code/modules/research/xenobiology/crossbreeding/__corecross.dm similarity index 100% rename from code/modules/research/xenobiology/crossbreeding/_corecross.dm rename to code/modules/research/xenobiology/crossbreeding/__corecross.dm diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm new file mode 100644 index 0000000000..016fd95899 --- /dev/null +++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm @@ -0,0 +1,144 @@ +/* +Slimecrossing Armor + Armor added by the slimecrossing system. + Collected here for clarity. +*/ + +//Rebreather mask - Chilling Blue +/obj/item/clothing/mask/nobreath + name = "rebreather mask" + desc = "A transparent mask, resembling a conventional breath mask, but made of bluish slime. Seems to lack any air supply tube, though." + icon_state = "slime" + item_state = "slime" + body_parts_covered = NONE + w_class = WEIGHT_CLASS_SMALL + gas_transfer_coefficient = 0 + permeability_coefficient = 0.5 + flags_cover = MASKCOVERSMOUTH + resistance_flags = NONE + +/obj/item/clothing/mask/nobreath/equipped(mob/living/carbon/human/user, slot) + . = ..() + if(slot == SLOT_WEAR_MASK) + user.add_trait(TRAIT_NOBREATH, "breathmask_[REF(src)]") + user.failed_last_breath = FALSE + user.clear_alert("not_enough_oxy") + user.apply_status_effect(/datum/status_effect/rebreathing) + +/obj/item/clothing/mask/nobreath/dropped(mob/living/carbon/human/user) + ..() + user.remove_trait(TRAIT_NOBREATH, "breathmask_[REF(src)]") + user.remove_status_effect(/datum/status_effect/rebreathing) + +/obj/item/clothing/glasses/prism_glasses + name = "prism glasses" + desc = "The lenses seem to glow slightly, and reflect light into dazzling colors." + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "prismglasses" + actions_types = list(/datum/action/item_action/change_prism_colour, /datum/action/item_action/place_light_prism) + var/glasses_color = "#FFFFFF" + +/obj/item/clothing/glasses/prism_glasses/item_action_slot_check(slot) + if(slot == SLOT_GLASSES) + return TRUE + +/obj/structure/light_prism + name = "light prism" + desc = "A shining crystal of semi-solid light. Looks fragile." + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "lightprism" + density = FALSE + anchored = TRUE + max_integrity = 10 + +/obj/structure/light_prism/Initialize(mapload, var/newcolor) + . = ..() + color = newcolor + light_color = newcolor + set_light(5) + +/obj/structure/light_prism/attack_hand(mob/user) + to_chat(user, "You dispel [src]") + qdel(src) + +/datum/action/item_action/change_prism_colour + name = "Adjust Prismatic Lens" + icon_icon = 'icons/obj/slimecrossing.dmi' + button_icon_state = "prismcolor" + +/datum/action/item_action/change_prism_colour/Trigger() + if(!IsAvailable()) + return + var/obj/item/clothing/glasses/prism_glasses/glasses = target + var/new_color = input(owner, "Choose the lens color:", "Color change",glasses.glasses_color) as color|null + if(!new_color) + return + glasses.glasses_color = new_color + +/datum/action/item_action/place_light_prism + name = "Fabricate Light Prism" + icon_icon = 'icons/obj/slimecrossing.dmi' + button_icon_state = "lightprism" + +/datum/action/item_action/place_light_prism/Trigger() + if(!IsAvailable()) + return + var/obj/item/clothing/glasses/prism_glasses/glasses = target + if(locate(/obj/structure/light_prism) in get_turf(owner)) + to_chat(owner, "There isn't enough ambient energy to fabricate another light prism here.") + return + if(istype(glasses)) + if(!glasses.glasses_color) + to_chat(owner, "The lens is oddly opaque...") + return + to_chat(owner, "You channel nearby light into a glowing, ethereal prism.") + new /obj/structure/light_prism(get_turf(owner), glasses.glasses_color) + +/obj/item/clothing/head/peaceflower + name = "heroine bud" + desc = "An extremely addictive flower, full of peace magic." + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "peaceflower" + item_state = "peaceflower" + slot_flags = ITEM_SLOT_HEAD + body_parts_covered = NONE + dynamic_hair_suffix = "" + force = 0 + throwforce = 0 + w_class = WEIGHT_CLASS_TINY + throw_speed = 1 + throw_range = 3 + +/obj/item/clothing/head/peaceflower/equipped(mob/living/carbon/human/user, slot) + . = ..() + if(slot == SLOT_HEAD) + user.add_trait(TRAIT_PACIFISM, "peaceflower_[REF(src)]") + +/obj/item/clothing/head/peaceflower/dropped(mob/living/carbon/human/user) + ..() + user.remove_trait(TRAIT_PACIFISM, "peaceflower_[REF(src)]") + +/obj/item/clothing/head/peaceflower/attack_hand(mob/user) + if(iscarbon(user)) + var/mob/living/carbon/C = user + if(src == C.head) + to_chat(user, "You feel at peace. Why would you want anything else?") + return + return ..() + +/obj/item/clothing/suit/armor/heavy/adamantine + name = "adamantine armor" + desc = "A full suit of adamantine plate armor. Impressively resistant to damage, but weighs about as much as you do." + icon_state = "adamsuit" + item_state = "adamsuit" + flags_inv = NONE + obj_flags = IMMUTABLE_SLOW + slowdown = 4 + var/hit_reflect_chance = 10 // Citadel Change: because 40% chance of bouncing lasers back into peoples faces isn't good. + armor = list("melee" = 70, "bullet" = 70, "laser" = 40, "energy" = 40, "bomb" = 80, "bio" = 80, "rad" = 80, "fire" = 70, "acid" = 90) //Citadel Change to avoid immortal Xenobiologists. + +/obj/item/clothing/suit/armor/heavy/adamantine/IsReflect(def_zone) + if(def_zone in list(BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) && prob(hit_reflect_chance)) + return TRUE + else + return FALSE diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm new file mode 100644 index 0000000000..0784946a37 --- /dev/null +++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm @@ -0,0 +1,135 @@ +//Barrier cube - Chilling Grey +/obj/item/barriercube + name = "barrier cube" + desc = "A compressed cube of slime. When squeezed, it grows to massive size!" + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "barriercube" + w_class = WEIGHT_CLASS_TINY + +/obj/item/barriercube/attack_self(mob/user) + if(locate(/obj/structure/barricade/slime) in get_turf(loc)) + to_chat(user, "You can't fit more than one barrier in the same space!") + return + to_chat(user, "You squeeze [src].") + var/obj/B = new /obj/structure/barricade/slime(get_turf(loc)) + B.visible_message("[src] suddenly grows into a large, gelatinous barrier!") + qdel(src) + +//Slime barricade - Chilling Grey +/obj/structure/barricade/slime + name = "gelatinous barrier" + desc = "A huge chunk of grey slime. Bullets might get stuck in it." + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "slimebarrier" + proj_pass_rate = 40 + max_integrity = 60 + +//Melting Gel Wall - Chilling Metal +/obj/effect/forcefield/slimewall + name = "solidified gel" + desc = "A mass of solidified slime gel - completely impenetrable, but it's melting away!" + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "slimebarrier_thick" + CanAtmosPass = ATMOS_PASS_NO + opacity = TRUE + timeleft = 100 + +//Rainbow barrier - Chilling Rainbow +/obj/effect/forcefield/slimewall/rainbow + name = "rainbow barrier" + desc = "Despite others' urgings, you probably shouldn't taste this." + icon_state = "rainbowbarrier" + +//Ration pack - Chilling Silver +/obj/item/reagent_containers/food/snacks/rationpack + name = "ration pack" + desc = "A square bar that sadly looks like chocolate, packaged in a nondescript grey wrapper. Has saved soldiers' lives before - usually by stopping bullets." + icon_state = "rationpack" + bitesize = 3 + junkiness = 15 + filling_color = "#964B00" + tastes = list("cardboard" = 3, "sadness" = 3) + foodtype = null //Don't ask what went into them. You're better off not knowing. + list_reagents = list("stabilizednutriment" = 10, "nutriment" = 2) //Won't make you fat. Will make you question your sanity. + +/obj/item/reagent_containers/food/snacks/rationpack/checkLiked(fraction, mob/M) //Nobody likes rationpacks. Nobody. + if(last_check_time + 50 < world.time) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.mind && !H.has_trait(TRAIT_AGEUSIA)) + to_chat(H,"That didn't taste very good...") //No disgust, though. It's just not good tasting. + GET_COMPONENT_FROM(mood, /datum/component/mood, H) + if(mood) + mood.add_event(null,"gross_food", /datum/mood_event/gross_food) + last_check_time = world.time + return + ..() + +//Ice stasis block - Chilling Dark Blue +/obj/structure/ice_stasis + name = "ice block" + desc = "A massive block of ice. You can see something vaguely humanoid inside." + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "frozen" + density = TRUE + max_integrity = 100 + armor = list("melee" = 30, "bullet" = 50, "laser" = -50, "energy" = -50, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = -80, "acid" = 30) + +/obj/structure/ice_stasis/Initialize() + . = ..() + playsound(src, 'sound/magic/ethereal_exit.ogg', 50, 1) + +/obj/structure/ice_stasis/Destroy() + for(var/atom/movable/M in contents) + M.forceMove(loc) + playsound(src, 'sound/effects/glassbr3.ogg', 50, 1) + return ..() + +//Gold capture device - Chilling Gold +/obj/item/capturedevice + name = "gold capture device" + desc = "Bluespace technology packed into a roughly egg-shaped device, used to store nonhuman creatures. Can't catch them all, though - it only fits one." + w_class = WEIGHT_CLASS_SMALL + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "capturedevice" + +/obj/item/capturedevice/attack(mob/living/M, mob/user) + if(length(contents)) + to_chat(user, "The device already has something inside.") + return + if(!isanimal(M)) + to_chat(user, "The capture device only works on simple creatures.") + return + if(M.mind) + to_chat(user, "You offer the device to [M].") + if(alert(M, "Would you like to enter [user]'s capture device?", "Gold Capture Device", "Yes", "No") == "Yes") + if(user.canUseTopic(src, BE_CLOSE) && user.canUseTopic(M, BE_CLOSE)) + to_chat(user, "You store [M] in the capture device.") + to_chat(M, "The world warps around you, and you're suddenly in an endless void, with a window to the outside floating in front of you.") + store(M, user) + else + to_chat(user, "You were too far away from [M].") + to_chat(M, "You were too far away from [user].") + else + to_chat(user, "[M] refused to enter the device.") + return + else + if(istype(M, /mob/living/simple_animal/hostile) && !("neutral" in M.faction)) + to_chat(user, "This creature is too aggressive to capture.") + return + to_chat(user, "You store [M] in the capture device.") + store(M) + +/obj/item/capturedevice/attack_self(mob/user) + if(contents.len) + to_chat(user, "You open the capture device!") + release() + else + to_chat(user, "The device is empty...") + +/obj/item/capturedevice/proc/store(var/mob/living/M) + M.forceMove(src) + +/obj/item/capturedevice/proc/release() + for(var/atom/movable/M in contents) + M.forceMove(get_turf(loc)) diff --git a/code/modules/research/xenobiology/crossbreeding/_mobs.dm b/code/modules/research/xenobiology/crossbreeding/_mobs.dm new file mode 100644 index 0000000000..57d0a31149 --- /dev/null +++ b/code/modules/research/xenobiology/crossbreeding/_mobs.dm @@ -0,0 +1,13 @@ +//Slime corgi - Chilling Pink +/mob/living/simple_animal/pet/dog/corgi/puppy/slime + name = "\improper slime corgi puppy" + real_name = "slime corgi puppy" + desc = "An unbearably cute pink slime corgi puppy." + icon_state = "slime_puppy" + icon_living = "slime_puppy" + icon_dead = "slime_puppy_dead" + nofur = TRUE + gold_core_spawnable = NO_SPAWN + speak_emote = list("blorbles", "bubbles", "borks") + emote_hear = list("bubbles!", "splorts.", "splops!") + emote_see = list("gets goop everywhere.", "flops.", "jiggles!") \ No newline at end of file diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index f56aa11bae..aba54cfdf3 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -57,6 +57,184 @@ owner.visible_message("[owner]'s gel coating liquefies and dissolves away.", "Your gel second-skin dissolves!") +/datum/status_effect/slimerecall + id = "slime_recall" + duration = -1 //Will be removed by the extract. + alert_type = null + var/interrupted = FALSE + var/mob/target + var/icon/bluespace + var/datum/weakref/redirect_component + +/datum/status_effect/slimerecall/on_apply() + redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/resistField)))) + to_chat(owner, "You feel a sudden tug from an unknown force, and feel a pull to bluespace!") + to_chat(owner, "Resist if you wish avoid the force!") + bluespace = icon('icons/effects/effects.dmi',"chronofield") + owner.add_overlay(bluespace) + return ..() + +/datum/status_effect/slimerecall/proc/resistField() + interrupted = TRUE + owner.remove_status_effect(src) +/datum/status_effect/slimerecall/on_remove() + qdel(redirect_component.resolve()) + redirect_component = null + owner.cut_overlay(bluespace) + if(interrupted || !ismob(target)) + to_chat(owner, "The bluespace tug fades away, and you feel that the force has passed you by.") + return + owner.visible_message("[owner] disappears in a flurry of sparks!", + "The unknown force snatches briefly you from reality, and deposits you next to [target]!") + do_sparks(3, TRUE, owner) + owner.forceMove(target.loc) + +/obj/screen/alert/status_effect/freon/stasis + desc = "You're frozen inside of a protective ice cube! While inside, you can't do anything, but are immune to harm! Resist to get out." + +/datum/status_effect/frozenstasis + id = "slime_frozen" + status_type = STATUS_EFFECT_UNIQUE + duration = -1 //Will remove self when block breaks. + alert_type = /obj/screen/alert/status_effect/freon/stasis + var/obj/structure/ice_stasis/cube + var/datum/weakref/redirect_component + +/datum/status_effect/frozenstasis/on_apply() + redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/breakCube)))) + cube = new /obj/structure/ice_stasis(get_turf(owner)) + owner.forceMove(cube) + owner.status_flags |= GODMODE + return ..() + +/datum/status_effect/frozenstasis/tick() + if(!cube || owner.loc != cube) + owner.remove_status_effect(src) + +/datum/status_effect/frozenstasis/proc/breakCube() + owner.remove_status_effect(src) + +/datum/status_effect/frozenstasis/on_remove() + if(cube) + qdel(cube) + owner.status_flags &= ~GODMODE + qdel(redirect_component.resolve()) + redirect_component = null + +/datum/status_effect/slime_clone + id = "slime_cloned" + status_type = STATUS_EFFECT_UNIQUE + duration = -1 + alert_type = null + var/mob/living/clone + var/datum/mind/originalmind //For when the clone gibs. + +/datum/status_effect/slime_clone/on_apply() + var/typepath = owner.type + clone = new typepath(owner.loc) + var/mob/living/carbon/O = owner + var/mob/living/carbon/C = clone + if(istype(C) && istype(O)) + C.real_name = O.real_name + O.dna.transfer_identity(C) + C.updateappearance(mutcolor_update=1) + if(owner.mind) + originalmind = owner.mind + owner.mind.transfer_to(clone) + clone.apply_status_effect(/datum/status_effect/slime_clone_decay) + return ..() + +/datum/status_effect/slime_clone/tick() + if(!istype(clone) || clone.stat != CONSCIOUS) + owner.remove_status_effect(src) + +/datum/status_effect/slime_clone/on_remove() + if(clone && clone.mind && owner) + clone.mind.transfer_to(owner) + else + if(owner && originalmind) + originalmind.transfer_to(owner) + if(originalmind.key) + owner.ckey = originalmind.key + if(clone) + clone.unequip_everything() + qdel(clone) + +/obj/screen/alert/status_effect/clone_decay + name = "Clone Decay" + desc = "You are simply a construct, and cannot maintain this form forever. You will be returned to your original body if you should fall." + icon_state = "slime_clonedecay" + +/datum/status_effect/slime_clone_decay + id = "slime_clonedecay" + status_type = STATUS_EFFECT_UNIQUE + duration = -1 + alert_type = /obj/screen/alert/status_effect/clone_decay + +/datum/status_effect/slime_clone_decay/tick() + owner.adjustToxLoss(1, 0) + owner.adjustOxyLoss(1, 0) + owner.adjustBruteLoss(1, 0) + owner.adjustFireLoss(1, 0) + owner.color = "#007BA7" + +/obj/screen/alert/status_effect/bloodchill + name = "Bloodchilled" + desc = "You feel a shiver down your spine after getting hit with a glob of cold blood. You'll move slower and get frostbite for a while!" + icon_state = "bloodchill" + +/datum/status_effect/bloodchill + id = "bloodchill" + duration = 100 + alert_type = /obj/screen/alert/status_effect/bloodchill + +/datum/status_effect/bloodchill/on_apply() + owner.add_movespeed_modifier("bloodchilled", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = 3) + return ..() + +/datum/status_effect/bloodchill/tick() + if(prob(50)) + owner.adjustFireLoss(2) + +/datum/status_effect/bloodchill/on_remove() + owner.remove_movespeed_modifier("bloodchilled") + +/obj/screen/alert/status_effect/bloodchill + name = "Bloodchilled" + desc = "You feel a shiver down your spine after getting hit with a glob of cold blood. You'll move slower and get frostbite for a while!" + icon_state = "bloodchill" + +/datum/status_effect/bonechill + id = "bonechill" + duration = 80 + alert_type = /obj/screen/alert/status_effect/bonechill + +/datum/status_effect/bonechill/on_apply() + owner.add_movespeed_modifier("bonechilled", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = 3) + return ..() + +/datum/status_effect/bonechill/tick() + if(prob(50)) + owner.adjustFireLoss(1) + owner.Jitter(3) + owner.adjust_bodytemperature(-10) + +/datum/status_effect/bonechill/on_remove() + owner.remove_movespeed_modifier("bonechilled") + +/obj/screen/alert/status_effect/bonechill + name = "Bonechilled" + desc = "You feel a shiver down your spine after hearing the haunting noise of bone rattling. You'll move slower and get frostbite for a while!" + icon_state = "bloodchill" + +/datum/status_effect/rebreathing + id = "rebreathing" + duration = -1 + alert_type = null + +datum/status_effect/rebreathing/tick() + owner.adjustOxyLoss(-6, 0) //Just a bit more than normal breathing. + /////////////////////////////////////////////////////// //////////////////CONSUMING EXTRACTS/////////////////// /////////////////////////////////////////////////////// diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm new file mode 100644 index 0000000000..1138f65105 --- /dev/null +++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm @@ -0,0 +1,45 @@ +//Bloodchiller - Chilling Green +/obj/item/gun/magic/bloodchill + name = "blood chiller" + desc = "A horrifying weapon made of your own bone and blood vessels. It shoots slowing globules of your own blood. Ech." + icon = 'icons/obj/slimecrossing.dmi' + icon_state = "bloodgun" + item_state = "bloodgun" + lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + item_flags = ABSTRACT | DROPDEL | NODROP + w_class = WEIGHT_CLASS_HUGE + force = 5 + max_charges = 1 //Recharging costs blood. + recharge_rate = 1 + ammo_type = /obj/item/ammo_casing/magic/bloodchill + fire_sound = 'sound/effects/attackblob.ogg' + +/obj/item/gun/magic/bloodchill/process() + charge_tick++ + if(charge_tick < recharge_rate || charges >= max_charges) + return 0 + charge_tick = 0 + var/mob/living/M = loc + if(istype(M) && M.blood_volume >= 20) + charges++ + M.blood_volume -= 20 + if(charges == 1) + recharge_newshot() + return 1 + +/obj/item/ammo_casing/magic/bloodchill + projectile_type = /obj/item/projectile/magic/bloodchill + +/obj/item/projectile/magic/bloodchill + name = "blood ball" + icon_state = "pulse0_bl" + damage = 0 + damage_type = OXY + nodamage = 1 + hitsound = 'sound/effects/splat.ogg' + +/obj/item/projectile/magic/bloodchill/on_hit(mob/living/target) + . = ..() + if(isliving(target)) + target.apply_status_effect(/datum/status_effect/bloodchill) \ No newline at end of file diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm new file mode 100644 index 0000000000..f09cc7b9e0 --- /dev/null +++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm @@ -0,0 +1,311 @@ +/* +Chilling extracts: + Have a unique, primarily defensive effect when + filled with 10u plasma and activated in-hand. +*/ +/obj/item/slimecross/chilling + name = "chilling extract" + desc = "It's cold to the touch, as if frozen solid." + effect = "chilling" + icon_state = "chilling" + +/obj/item/slimecross/chilling/Initialize() + . = ..() + create_reagents(10, INJECTABLE | DRAWABLE) + +/obj/item/slimecross/chilling/attack_self(mob/user) + if(!reagents.has_reagent("plasma",10)) + to_chat(user, "This extract needs to be full of plasma to activate!") + return + reagents.remove_reagent("plasma",10) + to_chat(user, "You squeeze the extract, and it absorbs the plasma!") + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + playsound(src, 'sound/effects/glassbr1.ogg', 50, 1) + do_effect(user) + +/obj/item/slimecross/chilling/proc/do_effect(mob/user) //If, for whatever reason, you don't want to delete the extract, don't do ..() + qdel(src) + return + +/obj/item/slimecross/chilling/grey + colour = "grey" + +/obj/item/slimecross/chilling/grey/do_effect(mob/user) + user.visible_message("[src] produces a few small, grey cubes") + for(var/i in 1 to 3) + new /obj/item/barriercube(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/orange + colour = "orange" + +/obj/item/slimecross/chilling/orange/do_effect(mob/user) + user.visible_message("[src] shatters, and lets out a jet of heat!") + for(var/turf/T in orange(get_turf(user),2)) + if(get_dist(get_turf(user), T) > 1) + new /obj/effect/hotspot(T) + ..() + +/obj/item/slimecross/chilling/purple + colour = "purple" + +/obj/item/slimecross/chilling/purple/do_effect(mob/user) + var/area/A = get_area(get_turf(user)) + if(A.outdoors) + to_chat(user, "[src] can't affect such a large area.") + return + user.visible_message("[src] shatters, and a healing aura fills the room briefly.") + for(var/mob/living/carbon/C in A) + C.reagents.add_reagent("regen_jelly",10) + ..() + +/obj/item/slimecross/chilling/blue + colour = "blue" + +/obj/item/slimecross/chilling/blue/do_effect(mob/user) + user.visible_message("[src] cracks, and spills out a liquid goo, which reforms into a mask!") + new /obj/item/clothing/mask/nobreath(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/metal + colour = "metal" + +/obj/item/slimecross/chilling/metal/do_effect(mob/user) + user.visible_message("[src] melts like quicksilver, and surrounds [user] in a wall!") + for(var/turf/T in orange(get_turf(user),1)) + if(get_dist(get_turf(user), T) > 0) + new /obj/effect/forcefield/slimewall(T) + ..() + +/obj/item/slimecross/chilling/yellow + colour = "yellow" + +/obj/item/slimecross/chilling/yellow/do_effect(mob/user) + var/area/A = get_area(get_turf(user)) + user.visible_message("[src] shatters, and a the air suddenly feels charged for a moment.") + for(var/obj/machinery/power/apc/C in A) + if(C.cell) + C.cell.charge = min(C.cell.charge + C.cell.maxcharge/2, C.cell.maxcharge) + ..() + +/obj/item/slimecross/chilling/darkpurple + colour = "dark purple" + +/obj/item/slimecross/chilling/darkpurple/do_effect(mob/user) + var/area/A = get_area(get_turf(user)) + if(A.outdoors) + to_chat(user, "[src] can't affect such a large area.") + return + var/filtered = FALSE + for(var/turf/open/T in A) + var/datum/gas_mixture/G = T.air + if(istype(G)) + G.assert_gas(/datum/gas/plasma) + G.gases[/datum/gas/plasma][MOLES] = 0 + filtered = TRUE + G.garbage_collect() + T.air_update_turf() + if(filtered) + user.visible_message("Cracks spread throughout [src], and some air is sucked in!") + else + user.visible_message("[src] cracks, but nothing happens.") + ..() + +/obj/item/slimecross/chilling/darkblue + colour = "dark blue" + +/obj/item/slimecross/chilling/darkblue/do_effect(mob/user) + if(isliving(user)) + user.visible_message("[src] freezes over [user]'s entire body!") + var/mob/living/M = user + M.apply_status_effect(/datum/status_effect/frozenstasis) + ..() + +/obj/item/slimecross/chilling/silver + colour = "silver" + +/obj/item/slimecross/chilling/silver/do_effect(mob/user) + user.visible_message("[src] crumbles into icy powder, leaving behind several emergency food supplies!") + var/amount = rand(5, 10) + for(var/i in 1 to amount) + new /obj/item/reagent_containers/food/snacks/rationpack(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/bluespace + colour = "bluespace" + var/list/allies = list() + var/active = FALSE + +/obj/item/slimecross/chilling/bluespace/afterattack(atom/target, mob/user, proximity) + if(!proximity || !isliving(target) || active) + return + if(target in allies) + allies -= target + to_chat(user, "You unlink [src] with [target].") + else + allies |= target + to_chat(user, "You link [src] with [target].") + return + +/obj/item/slimecross/chilling/bluespace/do_effect(mob/user) + if(allies.len <= 0) + to_chat(user, "[src] is not linked to anyone!") + return + to_chat(user, "You feel [src] pulse as it begins charging bluespace energies...") + active = TRUE + for(var/mob/living/M in allies) + var/datum/status_effect/slimerecall/S = M.apply_status_effect(/datum/status_effect/slimerecall) + S.target = user + if(do_after(user, 100, target=src)) + to_chat(user, "[src] shatters as it tears a hole in reality, snatching the linked individuals from the void!") + for(var/mob/living/M in allies) + var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall) + M.remove_status_effect(S) + else + to_chat(user, "[src] falls dark, dissolving into nothing as the energies fade away.") + for(var/mob/living/M in allies) + var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall) + if(istype(S)) + S.interrupted = TRUE + M.remove_status_effect(S) + ..() + +/obj/item/slimecross/chilling/sepia + colour = "sepia" + var/list/allies = list() + +/obj/item/slimecross/chilling/sepia/afterattack(atom/target, mob/user, proximity) + if(!proximity || !isliving(target)) + return + if(target in allies) + allies -= target + to_chat(user, "You unlink [src] with [target].") + else + allies |= target + to_chat(user, "You link [src] with [target].") + return + +/obj/item/slimecross/chilling/sepia/do_effect(mob/user) + user.visible_message("[src] shatters, freezing time itself!") + new /obj/effect/timestop(get_turf(user), 2, 300, allies) + ..() + +/obj/item/slimecross/chilling/cerulean + colour = "cerulean" + +/obj/item/slimecross/chilling/cerulean/do_effect(mob/user) + if(isliving(user)) + user.visible_message("[src] creaks and shifts into a clone of [user]!") + var/mob/living/M = user + M.apply_status_effect(/datum/status_effect/slime_clone) + ..() + +/obj/item/slimecross/chilling/pyrite + colour = "pyrite" + +/obj/item/slimecross/chilling/pyrite/do_effect(mob/user) + user.visible_message("[src] crystallizes into a pair of spectacles!") + new /obj/item/clothing/glasses/prism_glasses(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/red + colour = "red" + +/obj/item/slimecross/chilling/red/do_effect(mob/user) + var/slimesfound = FALSE + for(var/mob/living/simple_animal/slime/S in view(get_turf(user), 7)) + slimesfound = TRUE + S.docile = TRUE + if(slimesfound) + user.visible_message("[src] lets out a peaceful ring as it shatters, and nearby slimes seem calm.") + else + user.visible_message("[src] lets out a peaceful ring as it shatters, but nothing happens...") + ..() + +/obj/item/slimecross/chilling/green + colour = "green" + +/obj/item/slimecross/chilling/green/do_effect(mob/user) + var/which_hand = "l_hand" + if(!(user.active_hand_index % 2)) + which_hand = "r_hand" + var/mob/living/L = user + if(!istype(user)) + return + var/obj/item/held = L.get_active_held_item() //This should be itself, but just in case... + L.dropItemToGround(held) + var/obj/item/gun/magic/bloodchill/gun = new(user) + if(!L.put_in_hands(gun)) + qdel(gun) + user.visible_message("[src] flash-freezes [user]'s arm, cracking the flesh horribly!") + else + user.visible_message("[src] chills and snaps off the front of the bone on [user]'s arm, leaving behind a strange, gun-like structure!") + user.emote("scream") + L.apply_damage(30,BURN,which_hand) + ..() + +/obj/item/slimecross/chilling/pink + colour = "pink" + +/obj/item/slimecross/chilling/pink/do_effect(mob/user) + user.visible_message("[src] cracks like an egg, and an adorable puppy comes tumbling out!") + new /mob/living/simple_animal/pet/dog/corgi/puppy/slime(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/gold + colour = "gold" + +/obj/item/slimecross/chilling/gold/do_effect(mob/user) + user.visible_message("[src] lets off golden light as it melts and reforms into an egg-like device!") + new /obj/item/capturedevice(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/oil + colour = "oil" + +/obj/item/slimecross/chilling/oil/do_effect(mob/user) + user.visible_message("[src] begins to shake with muted intensity!") + addtimer(CALLBACK(src, .proc/boom), 50) + +/obj/item/slimecross/chilling/oil/proc/boom() + explosion(get_turf(src), -1, -1, 3, 10) //Large radius, but mostly light damage. + qdel(src) + +/obj/item/slimecross/chilling/black + colour = "black" + +/obj/item/slimecross/chilling/black/do_effect(mob/user) + if(ishuman(user)) + user.visible_message("[src] crystallizes along [user]'s skin, turning into metallic scales!") + var/mob/living/carbon/human/H = user + H.set_species(/datum/species/golem/random) + ..() + +/obj/item/slimecross/chilling/lightpink + colour = "light pink" + +/obj/item/slimecross/chilling/lightpink/do_effect(mob/user) + user.visible_message("[src] blooms into a beautiful flower!") + new /obj/item/clothing/head/peaceflower(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/adamantine + colour = "adamantine" + +/obj/item/slimecross/chilling/adamantine/do_effect(mob/user) + user.visible_message("[src] creaks and breaks as it shifts into a heavy set of armor!") + new /obj/item/clothing/suit/armor/heavy/adamantine(get_turf(user)) + ..() + +/obj/item/slimecross/chilling/rainbow + colour = "rainbow" + +/obj/item/slimecross/chilling/rainbow/do_effect(mob/user) + var/area/area = get_area(user) + if(area.outdoors) + to_chat(user, "[src] can't affect such a large area.") + return + user.visible_message("[src] reflects an array of dazzling colors and light, energy rushing to nearby doors!") + for(var/obj/machinery/door/airlock/door in area) + new /obj/effect/forcefield/slimewall/rainbow(door.loc) + return ..() diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index e48e18c34c..ca12accbed 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -840,7 +840,7 @@ return if(isitem(C)) var/obj/item/I = C - if(I.slowdown <= 0) + if(I.slowdown <= 0 || I.obj_flags & IMMUTABLE_SLOW) to_chat(user, "The [C] can't be made any faster!") return ..() I.slowdown = 0 @@ -849,10 +849,10 @@ var/obj/vehicle/V = C var/datum/component/riding/R = V.GetComponent(/datum/component/riding) if(R) - if(R.vehicle_move_delay <= 0 ) + if(R.vehicle_move_delay <= 1 ) to_chat(user, "The [C] can't be made any faster!") return ..() - R.vehicle_move_delay = 0 + R.vehicle_move_delay = 1 to_chat(user, "You slather the red gunk over the [C], making it faster.") C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 8d0547d2c5..4ecac39ecc 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -45,6 +45,10 @@ var/species_color = "" var/mutation_color = "" var/no_update = 0 + var/body_markings //for bodypart markings + var/list/markings_color = list() + var/auxmarking + var/list/auxmarking_color = list() var/animal_origin = null //for nonhuman bodypart (e.g. monkey) var/dismemberable = 1 //whether it can be dismembered with a weapon. @@ -285,6 +289,7 @@ should_draw_gender = FALSE should_draw_greyscale = FALSE no_update = TRUE + body_markings = "husk" // reeee if(no_update) return @@ -298,6 +303,16 @@ should_draw_citadel = S.should_draw_citadel // Citadel Addition species_flags_list = H.dna.species.species_traits + //body marking memes + var/list/colorlist = list() + colorlist.Cut() + colorlist += ReadRGB(H.dna.features["mcolor"]) + colorlist += ReadRGB(H.dna.features["mcolor2"]) + colorlist += ReadRGB(H.dna.features["mcolor3"]) + colorlist += list(0,0,0) + for(var/index=1, index<=colorlist.len, index++) + colorlist[index] = colorlist[index]/255 + if(S.use_skintones) skin_tone = H.skin_tone should_draw_greyscale = TRUE @@ -316,6 +331,17 @@ else species_color = "" + if("mam_body_markings" in S.default_features) + if(H.dna.features.["mam_body_markings"] != "None") + body_markings = lowertext(H.dna.features.["mam_body_markings"]) + if(MATRIXED) + markings_color = list(colorlist) + else + markings_color = (H.dna.features.["mcolor"]) + else + body_markings = "None" + markings_color = "" + if(!dropping_limb && H.dna.check_mutation(HULK)) mutation_color = "00aa00" else @@ -346,6 +372,7 @@ //Gives you a proper icon appearance for the dismembered limb /obj/item/bodypart/proc/get_limb_icon(dropped) + cut_overlays() icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone. . = list() @@ -358,9 +385,17 @@ . += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir) if(burnstate) . += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir) + if(body_markings) + if(use_digitigrade == NOT_DIGITIGRADE) + . += image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) + else + . += image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) var/image/aux + var/image/marking + var/image/auxmarking + . += limb if(animal_origin) @@ -403,11 +438,31 @@ limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" else limb.icon_state = "[species_id]_[body_zone]" + + // Body markings + if(body_markings) + if(species_id == "husk") + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir) + else if(species_id == "husk" && use_digitigrade) + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + + else if(!use_digitigrade) + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) + else + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + . += marking + // Citadel End if(aux_zone) aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir) . += aux + if(body_markings) + if(species_id == "husk") + auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[aux_zone]", -aux_layer, image_dir) + else + auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[aux_zone]", -aux_layer, image_dir) + . += auxmarking else limb.icon = icon @@ -416,17 +471,45 @@ else limb.icon_state = "[body_zone]" if(aux_zone) - aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir) + aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir) . += aux + if(body_markings) + if(species_id == "husk") + auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[aux_zone]", -aux_layer, image_dir) + else + auxmarking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[aux_zone]", -aux_layer, image_dir) + . += auxmarking + + if(body_markings) + if(species_id == "husk") + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_[body_zone]", -MARKING_LAYER, image_dir) + else if(species_id == "husk" && use_digitigrade) + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "husk_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + + else if(!use_digitigrade) + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_[body_zone]", -MARKING_LAYER, image_dir) + else + marking = image('modular_citadel/icons/mob/mam_markings.dmi', "[body_markings]_digitigrade_[use_digitigrade]_[body_zone]", -MARKING_LAYER, image_dir) + . += marking return if(should_draw_greyscale) + marking.color = null var/draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone)) if(draw_color) limb.color = "#[draw_color]" if(aux_zone) aux.color = "#[draw_color]" + if(body_markings) + auxmarking.color = list(markings_color) + + if(body_markings) + if(species_id == "husk") + marking.color = "#141414" + else + marking.color = list(markings_color) + /obj/item/bodypart/deconstruct(disassembled = TRUE) drop_organs() diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 73d0ab305e..1a46a9dcb1 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -26,9 +26,7 @@ burn() return 1 add_mob_blood(C) - var/turf/location = C.loc - if(istype(location)) - C.add_splatter_floor(location) + C.bleed(40) var/direction = pick(GLOB.cardinals) var/t_range = rand(2,max(throw_range/2, 2)) var/turf/target_turf = get_turf(src) @@ -54,7 +52,7 @@ . = list() var/organ_spilled = 0 var/turf/T = get_turf(C) - C.add_splatter_floor(T) + C.bleed(50) playsound(get_turf(C), 'sound/misc/splort.ogg', 80, 1) for(var/X in C.internal_organs) var/obj/item/organ/O = X diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 9d9e26c6fa..9cc56a6ca8 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -288,6 +288,7 @@ O.drop_limb(1) qdel(O) N.attach_limb(src) + if(body_plan_changed && ishuman(src)) var/mob/living/carbon/human/H = src if(H.w_uniform) @@ -311,4 +312,4 @@ S.adjusted = NORMAL_STYLE else S.adjusted = ALT_STYLE - H.update_inv_wear_suit() \ No newline at end of file + H.update_inv_wear_suit() diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 05fdbadf87..af2c625670 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1368,13 +1368,20 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/reverse_bear_trap restricted_roles = list("Clown") +/datum/uplink_item/role_restricted/clumsyDNA + name = "Clumsy Clown DNA" + desc = "A DNA injector that has been loaded with the clown gene that makes people clumsy.. \ + Making someone clumsy will allow them to use clown firing pins as well as Reverse Revolvers. For a laugh try using this on the HOS to see how many times they shoot themselves in the foot!" + cost = 1 + item = /obj/item/dnainjector/clumsymut + restricted_roles = list("Clown") + /datum/uplink_item/role_restricted/mimery name = "Guide to Advanced Mimery Series" desc = "The classical two part series on how to further hone your mime skills. Upon studying the series, the user should be able to make 3x1 invisible walls, and shoot bullets out of their fingers. Obviously only works for Mimes." cost = 12 item = /obj/item/storage/box/syndie_kit/mimery restricted_roles = list("Mime") - surplus = 0 /datum/uplink_item/role_restricted/ez_clean_bundle name = "EZ Clean Grenade Bundle" @@ -1396,7 +1403,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) name = "Kitchen Gun (TM) .45 Magazine" desc = "An extra eight bullets for an extra eight uses of Kitchen Gun (TM)!" cost = 1 - surplus = 0 restricted_roles = list("Cook", "Janitor") item = /obj/item/ammo_box/magazine/m45/kitchengun @@ -1405,7 +1411,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A potato rigged with explosives. On activation, a special mechanism is activated that prevents it from being dropped. The only way to get rid of it if you are holding it is to attack someone else with it, causing it to latch to that person instead." item = /obj/item/hot_potato/syndicate cost = 4 - surplus = 0 restricted_roles = list("Cook", "Botanist", "Clown", "Mime") /datum/uplink_item/role_restricted/his_grace @@ -1425,7 +1430,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 10 item = /obj/item/pneumatic_cannon/pie/selfcharge restricted_roles = list("Clown") - surplus = 0 //No fun unless you're the clown! /datum/uplink_item/role_restricted/ancient_jumpsuit name = "Ancient Jumpsuit" @@ -1433,7 +1437,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/clothing/under/color/grey/glorf cost = 20 restricted_roles = list("Assistant") - surplus = 0 /datum/uplink_item/role_restricted/brainwash_disk name = "Brainwashing Surgery Program" @@ -1487,7 +1490,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) blast wave \"projectile\". Aspiring scientists may find this highly useful, as forcing the pressure shockwave into a narrow angle seems to be able to bypass whatever quirk of physics \ disallows explosive ranges above a certain distance, allowing for the device to use the theoretical yield of a transfer valve bomb, instead of the factual yield." item = /obj/item/gun/blastcannon - cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled scientist. + cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled gas masked scientist. restricted_roles = list("Research Director", "Scientist") /datum/uplink_item/device_tools/clown_bomb @@ -1500,6 +1503,15 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/sbeacondrop/clownbomb cost = 15 restricted_roles = list("Clown") + +/datum/uplink_item/device_tools/honkpins //Idealy so they can place it into their own guns without needing cargo + name = "Hilarious firing pin" + desc = "A single firing pin made for Clown agents, this firing pin makes any gun honk when fired if not a true clown! \ + This firing pin also helps you fire the gun correctly. May the HonkMother HONK you agent." + item = /obj/item/firing_pin/clown + cost = 1 + restricted_roles = list("Clown") + /* /datum/uplink_item/role_restricted/clowncar name = "Clown Car" diff --git a/html/changelogs/AutoChangeLog-pr-7987.yml b/html/changelogs/AutoChangeLog-pr-7987.yml new file mode 100644 index 0000000000..e525b1668e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7987.yml @@ -0,0 +1,10 @@ +author: "Poojawa" +delete-after: True +changes: + - rscadd: "All markings, tails, ears, and snouts for Citadel races are color matrixed!" + - imageadd: "all markings are on a per-limb basis, including Digitigrade legs!" + - imageadd: "a bunch of tails were blessed with tail wagging sprites, Fish, Sharks, Fennecs, Wahs, raccoons, and others." + - imageadd: "Tiger markings + tail added, skunk tails improved via sprites from Virgo" + - tweak: "tweaked some sprites to look better, but they absolutely could use a few extra passes for quality" + - rscadd: "HumanScissors in the Tools folder will permit anyone to contribute matrix'd markings to the sprite sheet, however Mam_markings is very, very full. Be careful." + - tweak: "Character preview was both optimized for taurs and bad-touched for better updating. I don't know if it'll be bad, but hey its better." diff --git a/html/changelogs/AutoChangeLog-pr-7990.yml b/html/changelogs/AutoChangeLog-pr-7990.yml new file mode 100644 index 0000000000..b05eca84d2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7990.yml @@ -0,0 +1,5 @@ +author: "Coolgat3" +delete-after: True +changes: + - tweak: "Changed player number checks to 20 from 24 for cult and clockcult, also made nukeops 28 required players instead of 30." + - tweak: "Changed enemy minimum age from 14 to 7" diff --git a/html/changelogs/AutoChangeLog-pr-7993.yml b/html/changelogs/AutoChangeLog-pr-7993.yml new file mode 100644 index 0000000000..f1e0db178f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7993.yml @@ -0,0 +1,8 @@ +author: "Improving and Balancing Cyborgs" +delete-after: True +changes: + - rscadd: "Added Crew Pinpointer to Security Borg" + - rscadd: "Added Crew Monitor to Medical Borg" + - rscadd: "Added Crew Pinpointer to MediHound Borg" + - tweak: "Made the Disabler_Cooler compatible with both Security Borg and K9 Borg" + - tweak: "Changed the Warning Text upon selecting Security or K9 module" diff --git a/html/changelogs/AutoChangeLog-pr-7999.yml b/html/changelogs/AutoChangeLog-pr-7999.yml new file mode 100644 index 0000000000..516f304f98 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7999.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "The kindle status effect stun duration now properly proportional to the owner's remaining health." + - tweak: "Clockwork cult's kindle now affects silicons." diff --git a/html/changelogs/AutoChangeLog-pr-8008.yml b/html/changelogs/AutoChangeLog-pr-8008.yml new file mode 100644 index 0000000000..5845bd1b87 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8008.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "Slime speed potions can now only increase the speed of vehicles to be on par with sprinting speed. They can no longer make a scooter roll around ten times faster than a speeding blue hedgehog." diff --git a/html/changelogs/AutoChangeLog-pr-8010.yml b/html/changelogs/AutoChangeLog-pr-8010.yml new file mode 100644 index 0000000000..9694674b7c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8010.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscdel: "Changelings will no longer recieve team objectives" diff --git a/html/changelogs/AutoChangeLog-pr-8011.yml b/html/changelogs/AutoChangeLog-pr-8011.yml new file mode 100644 index 0000000000..9d0db00db4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8011.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "Changelings no longer start off with hivemind communication as an innate ability. Hivemind communication now requires 1 dna point, on par with syndicate encryption keys, which are 2 TC." + - code_imp: "Hivemind link now relies on hivemind communication just like the hivemind download/upload abilities." diff --git a/html/changelogs/AutoChangeLog-pr-8012.yml b/html/changelogs/AutoChangeLog-pr-8012.yml new file mode 100644 index 0000000000..212f252a7d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8012.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "It's now only possible to zoom a gun if it's in one of your hands" diff --git a/html/changelogs/AutoChangeLog-pr-8021.yml b/html/changelogs/AutoChangeLog-pr-8021.yml new file mode 100644 index 0000000000..fca715cd3d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8021.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Mobs without clients no longer cause runtimes when their eyeblur updates" diff --git a/html/changelogs/AutoChangeLog-pr-8023.yml b/html/changelogs/AutoChangeLog-pr-8023.yml new file mode 100644 index 0000000000..1b30435bda --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8023.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Blood tests have been added. If a changeling has a sufficient number of loud abilities, you will be able to test their blood by heating up a sample of it. However, if the changeling has a large amount of loud abilities, attempts to test their blood will have explosive results." + - rscadd: "Changelings now make a very obvious noise when readapting. This is to prevent the cheese strat of simply readapting when you get caught to avoid detection." diff --git a/html/changelogs/AutoChangeLog-pr-8024.yml b/html/changelogs/AutoChangeLog-pr-8024.yml new file mode 100644 index 0000000000..1aa5f1b09f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8024.yml @@ -0,0 +1,6 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "The blood splatter effect that happens when you get attacked will now always make you lose blood depending on the damage you've taken. The effect now also scales with item damage, meaning tiny little papercuts will no longer be able to cause a massive blood splatter." + - rscadd: "The blood reagent will now cover items and spacemen in blood when applied to objects and mobs." + - tweak: "Helmets, masks, and neck items are all now valid targets to get splattered when you get covered in blood. Groovy." diff --git a/html/changelogs/AutoChangeLog-pr-8025.yml b/html/changelogs/AutoChangeLog-pr-8025.yml new file mode 100644 index 0000000000..ee60aab630 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8025.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "The temperature notification will now take into consideration both the ambient temperature and your body temperature, increasing the responsiveness of the temperature notification and making it much more realistic." diff --git a/html/changelogs/AutoChangeLog-pr-8030.yml b/html/changelogs/AutoChangeLog-pr-8030.yml new file mode 100644 index 0000000000..c82325b394 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8030.yml @@ -0,0 +1,5 @@ +author: "Multicam Config" +delete-after: True +changes: + - config: "removed whether or not the stuff for multicam was checking the useless var and instead now checks the CONFIG_GET flag." + - admin: "Admins now have a verb in the Server tab to turn AI multicam on and off." diff --git a/html/changelogs/AutoChangeLog-pr-8031.yml b/html/changelogs/AutoChangeLog-pr-8031.yml new file mode 100644 index 0000000000..16ce735811 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8031.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "Shuttle transit borders are now 10 tiles wide instead of 8 tiles, hopefully repairing the immersions that get shattered by the ability to see normal space where the transit areas end." diff --git a/html/changelogs/AutoChangeLog-pr-8032.yml b/html/changelogs/AutoChangeLog-pr-8032.yml new file mode 100644 index 0000000000..87a65ac9d7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8032.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Instead of transit turfs simply teleporting things to space, transit is now handled in a somewhat realistic manner. Transit turfs now act like normal space turfs, though exiting the transit area or being present in the transit area after the shuttle moves out of transit will teleport you to space and throw you in the direction the shuttle was moving in." + - tweak: "Reservation areas are now able to designate a border turf." diff --git a/html/changelogs/AutoChangeLog-pr-8033.yml b/html/changelogs/AutoChangeLog-pr-8033.yml new file mode 100644 index 0000000000..e4a77766f1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8033.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "The sprint hotkey will no longer cause you to get permanently stuck sprinting if the server lags. Just tap shift again if you get stuck" diff --git a/html/changelogs/AutoChangeLog-pr-8034.yml b/html/changelogs/AutoChangeLog-pr-8034.yml new file mode 100644 index 0000000000..c9fabf1874 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8034.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "You can now hear sounds in the real world while inside of a VR sleeper." diff --git a/html/changelogs/AutoChangeLog-pr-8035.yml b/html/changelogs/AutoChangeLog-pr-8035.yml new file mode 100644 index 0000000000..82d1a18a1b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8035.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "You can now make nameless characters. Nameless characters will spawn in with their name set as their job title followed by a unique five digit number. The \"Name\" option in the character setup menu will be replaced with a \"Default designation\" option for nameless characters, and the default designation will be used in place of a job title for assistants and other jobs that don't require dress codes." diff --git a/html/changelogs/AutoChangeLog-pr-8037.yml b/html/changelogs/AutoChangeLog-pr-8037.yml new file mode 100644 index 0000000000..340b8e006e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8037.yml @@ -0,0 +1,6 @@ +author: "Ghommie" +delete-after: True +changes: + - tweak: "Cyborg mounted disablers/tasers/lasers now slowly self-recharge off the cyborg user's power cell instead of draining from it directly." + - tweak: "Borg rechargers now properly recharge the borg module's energy guns." + - bugfix: "Prevents a couple more special/mounted guns from being preserved on cryo" diff --git a/html/changelogs/AutoChangeLog-pr-8038.yml b/html/changelogs/AutoChangeLog-pr-8038.yml new file mode 100644 index 0000000000..64fbb5c4b2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8038.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - admin: "The out-of-game round end notification is now a little more verbose. It'll now display the round type, end result of the round, and the survival rate." diff --git a/html/changelogs/AutoChangeLog-pr-8039.yml b/html/changelogs/AutoChangeLog-pr-8039.yml new file mode 100644 index 0000000000..4445a86991 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8039.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Xenos can no longer strip items off of people to be capable of using any item in the game." + - bugfix: "also, items from pockets get placed into your hands properly now" diff --git a/html/changelogs/AutoChangeLog-pr-8041.yml b/html/changelogs/AutoChangeLog-pr-8041.yml new file mode 100644 index 0000000000..477b513368 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8041.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "A mob's last words are now properly tracked and recorded on death. The first death of the round will now actually display the victim's last words on the round end screen." diff --git a/html/changelogs/AutoChangeLog-pr-8042.yml b/html/changelogs/AutoChangeLog-pr-8042.yml new file mode 100644 index 0000000000..4df2d178df --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8042.yml @@ -0,0 +1,5 @@ +author: "izzyinbox" +delete-after: True +changes: + - rscadd: "Generic dog body marking sprite" + - imageadd: "colormatrix dog sprites" diff --git a/html/changelogs/AutoChangeLog-pr-8043.yml b/html/changelogs/AutoChangeLog-pr-8043.yml new file mode 100644 index 0000000000..b3beb4c4cb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8043.yml @@ -0,0 +1,5 @@ +author: "Coolgat3" +delete-after: True +changes: + - rscadd: "Added the code for the semen donut and made it craftable" + - imageadd: "Added the donut sprites" diff --git a/html/changelogs/AutoChangeLog-pr-8044.yml b/html/changelogs/AutoChangeLog-pr-8044.yml new file mode 100644 index 0000000000..e4fe14ac84 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8044.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Divine shenanigans can no longer result in someone becoming immune to staminaloss" diff --git a/html/changelogs/AutoChangeLog-pr-8047.yml b/html/changelogs/AutoChangeLog-pr-8047.yml new file mode 100644 index 0000000000..6a11895b0f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8047.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Fixed body_markings in bodyparts being assigned as a list when in reality, it's a string and literally everything expects it to be a string and uses it as a string. This should mean that markings no longer have completely fucked up caches for character preview and other things." diff --git a/html/changelogs/AutoChangeLog-pr-8051.yml b/html/changelogs/AutoChangeLog-pr-8051.yml new file mode 100644 index 0000000000..51c2d438ab --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8051.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "Since apparently the game is literally unplayable if items are not in the exact center of a turf, the maximum pixel variance of thrown objects has been reduced by four pixels to make things a smidge more clearer for those that dont know what a turf is." + - bugfix: "Bartender glasses should HOPEFULLY no longer be tilted when landing on a table. Why the fuck is after_throw called via a timer." diff --git a/html/changelogs/AutoChangeLog-pr-8052.yml b/html/changelogs/AutoChangeLog-pr-8052.yml new file mode 100644 index 0000000000..4ad9af8ef0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8052.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Changeling screeches now have their own unique sounds, and are much easier to recognize." diff --git a/html/changelogs/AutoChangeLog-pr-8053.yml b/html/changelogs/AutoChangeLog-pr-8053.yml new file mode 100644 index 0000000000..706166a9d1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8053.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Most synthetic emotes are now available to humans. *ping" diff --git a/html/changelogs/AutoChangeLog-pr-8054.yml b/html/changelogs/AutoChangeLog-pr-8054.yml new file mode 100644 index 0000000000..a674371a3a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8054.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "You can now merp" diff --git a/html/changelogs/AutoChangeLog-pr-8055.yml b/html/changelogs/AutoChangeLog-pr-8055.yml new file mode 100644 index 0000000000..e06f03e1ef --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8055.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - rscadd: "Added Dark Medihound and Pup Dozer from Virgo" diff --git a/html/changelogs/AutoChangeLog-pr-8056.yml b/html/changelogs/AutoChangeLog-pr-8056.yml new file mode 100644 index 0000000000..0953743ae4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8056.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "The TEG will now only produce a meaningful amount of power if the hot pipe contains gas that's actively combusting" diff --git a/html/changelogs/AutoChangeLog-pr-8057.yml b/html/changelogs/AutoChangeLog-pr-8057.yml new file mode 100644 index 0000000000..adb48e0ee0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8057.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - admin: "Added the \"add PB bypass\" and \"revoke PB bypass\" verbs, which allow admins to let a specific ckey to bypass the panic bunker for the rest of the round" diff --git a/html/changelogs/AutoChangeLog-pr-8058.yml b/html/changelogs/AutoChangeLog-pr-8058.yml new file mode 100644 index 0000000000..a484cc8ce1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8058.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Jogging is no longer treated exactly the same as sprinting for water slips. When you're jogging, you will only slip on water if you have more than 20% staminaloss." diff --git a/html/changelogs/AutoChangeLog-pr-8062.yml b/html/changelogs/AutoChangeLog-pr-8062.yml new file mode 100644 index 0000000000..2f1bc9b312 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8062.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "The atmospherics turf subsystem now has double the wait time, which should free up server processing power for other tasks." diff --git a/html/changelogs/AutoChangeLog-pr-8064.yml b/html/changelogs/AutoChangeLog-pr-8064.yml new file mode 100644 index 0000000000..512095f583 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8064.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "The IRC now actually displays the actual survival rate" diff --git a/html/changelogs/AutoChangeLog-pr-8070.yml b/html/changelogs/AutoChangeLog-pr-8070.yml new file mode 100644 index 0000000000..a2ebab9068 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8070.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Bloodcult conversions are now consensual. Convertees are given a ten second timer to accept or wait out. This should drastically improve the quality of those that get converted into bloodcult." + - rscadd: "All sacrifices now count as a third of a cultist for the end-game narsie summon." diff --git a/html/changelogs/AutoChangeLog-pr-8071.yml b/html/changelogs/AutoChangeLog-pr-8071.yml new file mode 100644 index 0000000000..040aa8b2cc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8071.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Nameless captains will no longer proc a \"Captain Captain on deck!\" message. Instead, it'll be a much more boring but much more sensical \"Captain on deck!\" message." diff --git a/html/changelogs/AutoChangeLog-pr-8080.yml b/html/changelogs/AutoChangeLog-pr-8080.yml new file mode 100644 index 0000000000..9abd9e6f50 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8080.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "Halved borg energy guns self-recharge delay and increased their cell capacity by 3/4" diff --git a/html/changelogs/AutoChangeLog-pr-8084.yml b/html/changelogs/AutoChangeLog-pr-8084.yml new file mode 100644 index 0000000000..fbec9cfe1f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8084.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - tweak: "Clone pods no longer announce the name of the clone" diff --git a/html/changelogs/AutoChangeLog-pr-8090.yml b/html/changelogs/AutoChangeLog-pr-8090.yml new file mode 100644 index 0000000000..b314fde12b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8090.yml @@ -0,0 +1,5 @@ +author: "deathride58 (Original PR by actioninja)" +delete-after: True +changes: + - rscadd: "Disarm pushing (combat mode right click in disarm intent) will now actually push mobs away. Knockdowns from disarm pushing are no longer rng based on the target's staminaloss. Knockdowns from disarm pushing now only happen when you push someone into another mob, a table, or a wall. Pushes will now also temporarily stop targets from using firearms, and will disarm the firearm if performed a second time. Pushes still deal staminaloss to standing targets, and won't deal a single ounce of staminaloss to resting targets." + - rscdel: "You can no longer displace mobs that are in harm intent by simply walking into them. Mobs that aren't in help intent have to be disarm pushed to actually be moved." diff --git a/html/changelogs/AutoChangeLog-pr-8091.yml b/html/changelogs/AutoChangeLog-pr-8091.yml new file mode 100644 index 0000000000..e98b7df89c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8091.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Transit turfs on the centcom z-level now function properly again at keeping mobs within the areas defined by their boundaries." + - bugfix: "The title screen is also positioned correctly again." diff --git a/html/changelogs/AutoChangeLog-pr-8098.yml b/html/changelogs/AutoChangeLog-pr-8098.yml new file mode 100644 index 0000000000..956b83d223 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-8098.yml @@ -0,0 +1,4 @@ +author: "Coolgat3" +delete-after: True +changes: + - bugfix: "Made the sec and warden berret offer as much protection like the helmet" diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi index 4bbe27f09d..aad4718cbd 100644 Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 03d6190507..2f39dd5940 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 96df6caa8d..b479fa0764 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi index f162d36633..47ef8e816f 100644 Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ diff --git a/icons/mob/inhands/misc/food_lefthand.dmi b/icons/mob/inhands/misc/food_lefthand.dmi index 325b18d95e..19e0706d01 100644 Binary files a/icons/mob/inhands/misc/food_lefthand.dmi and b/icons/mob/inhands/misc/food_lefthand.dmi differ diff --git a/icons/mob/inhands/misc/food_righthand.dmi b/icons/mob/inhands/misc/food_righthand.dmi index ddc91fd6ed..da8eda329d 100644 Binary files a/icons/mob/inhands/misc/food_righthand.dmi and b/icons/mob/inhands/misc/food_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi index dae3861233..f6ac6ca499 100644 Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi index f3d5c42570..504121feba 100644 Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ diff --git a/icons/mob/mask.dmi b/icons/mob/mask.dmi index 18b323c997..788bfc0447 100644 Binary files a/icons/mob/mask.dmi and b/icons/mob/mask.dmi differ diff --git a/icons/mob/pets.dmi b/icons/mob/pets.dmi index d0983a8fab..45b0ab1f04 100644 Binary files a/icons/mob/pets.dmi and b/icons/mob/pets.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index 904084adb5..b518157bb5 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index a474b5f285..a0153b1596 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 51a5a4e358..8e0359e6b3 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index a053eab792..9861a2e618 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi index 08b6faba9b..7ca7b068b0 100644 Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ diff --git a/icons/obj/slimecrossing.dmi b/icons/obj/slimecrossing.dmi index 56ccfc21f7..6d74116a18 100644 Binary files a/icons/obj/slimecrossing.dmi and b/icons/obj/slimecrossing.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index 99850c34ba..65f4a22664 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -268,3 +268,30 @@ window "statwindow" is-default = true saved-params = "" + window "preferences_window" + elem "preferences_window" + type = MAIN + pos = 372,0 + size = 1120x1000 + anchor1 = none + anchor2 = none + background-color = none + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + statusbar = false + elem "preferences_browser" + type = BROWSER + pos = -8,-8 + size = 896x1008 + anchor1 = 0,0 + anchor2 = 90,100 + background-color = none + saved-params = "" + elem "character_preview_map" + type = MAP + pos = 887,0 + size = 313x1000 + anchor1 = 90,0 + anchor2 = 100,100 + right-click = true + saved-params = "zoom;letterbox;zoom-mode" diff --git a/modular_citadel/code/game/machinery/cryopod.dm b/modular_citadel/code/game/machinery/cryopod.dm index ec8738f9ea..9369fa7677 100644 --- a/modular_citadel/code/game/machinery/cryopod.dm +++ b/modular_citadel/code/game/machinery/cryopod.dm @@ -166,7 +166,12 @@ // These items will NOT be preserved var/list/do_not_preserve_items = list ( /obj/item/mmi/posibrain, + /obj/item/gun/energy/laser/mounted, + /obj/item/gun/energy/e_gun/advtaser/mounted, + /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg, /obj/item/gun/energy/disabler/cyborg, + /obj/item/gun/energy/e_gun/advtaser/cyborg, + /obj/item/gun/energy/printer, /obj/item/gun/energy/kinetic_accelerator/cyborg, /obj/item/gun/energy/laser/cyborg ) diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm index 6df5be02eb..2c2b5b811f 100644 --- a/modular_citadel/code/init.dm +++ b/modular_citadel/code/init.dm @@ -9,6 +9,7 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_snouts, GLOB.mam_snouts_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 63ed811666..a625829577 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -193,7 +193,6 @@ "You have relieved yourself.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) setArousalLoss(min_arousal) - adjustStaminaLoss(40) //Refractory periods /* switch(gender) if(MALE) @@ -234,7 +233,6 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes @@ -272,7 +270,6 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing @@ -305,7 +302,6 @@ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - adjustStaminaLoss(40) //Refractory periods else //knots and other non-spilling orgasms if(do_after(src, mb_time, target = src) && in_range(src, L)) fluid_source.trans_to(L, total_fluids) @@ -317,7 +313,6 @@ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender @@ -348,7 +343,6 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/pick_masturbate_genitals() var/obj/item/organ/genital/ret_organ diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm index 927d324e23..358208c1d7 100644 --- a/modular_citadel/code/modules/client/preferences.dm +++ b/modular_citadel/code/modules/client/preferences.dm @@ -40,6 +40,7 @@ "mcolor3" = "FFF", "mam_body_markings" = "None", "mam_ears" = "None", + "mam_snouts" = "None", "mam_tail" = "None", "mam_tail_animated" = "None", "xenodorsal" = "Standard", diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm index 8f65e47d2b..209d46db61 100644 --- a/modular_citadel/code/modules/client/preferences_savefile.dm +++ b/modular_citadel/code/modules/client/preferences_savefile.dm @@ -40,6 +40,7 @@ WRITE_FILE(S["feature_mam_ears"], features["mam_ears"]) WRITE_FILE(S["feature_mam_tail_animated"], features["mam_tail_animated"]) WRITE_FILE(S["feature_taur"], features["taur"]) + WRITE_FILE(S["feature_mam_snouts"], features["mam_snouts"]) //Xeno features WRITE_FILE(S["feature_xeno_tail"], features["xenotail"]) WRITE_FILE(S["feature_xeno_dors"], features["xenodorsal"]) diff --git a/modular_citadel/code/modules/keybindings/bindings_human.dm b/modular_citadel/code/modules/keybindings/bindings_human.dm index 963e71d709..ffe88bd4a9 100644 --- a/modular_citadel/code/modules/keybindings/bindings_human.dm +++ b/modular_citadel/code/modules/keybindings/bindings_human.dm @@ -1,13 +1,13 @@ /mob/living/carbon/human/key_down(_key, client/user) switch(_key) if("Shift") - togglesprint() + sprint_hotkey(TRUE) return return ..() /mob/living/carbon/human/key_up(_key, client/user) switch(_key) if("Shift") - togglesprint() + sprint_hotkey(FALSE) return return ..() diff --git a/modular_citadel/code/modules/keybindings/bindings_robot.dm b/modular_citadel/code/modules/keybindings/bindings_robot.dm index 59151f2b40..d3b6248f7d 100644 --- a/modular_citadel/code/modules/keybindings/bindings_robot.dm +++ b/modular_citadel/code/modules/keybindings/bindings_robot.dm @@ -1,13 +1,13 @@ /mob/living/silicon/robot/key_down(_key, client/user) switch(_key) if("Shift") - togglesprint() + sprint_hotkey(TRUE) return return ..() /mob/living/silicon/robot/key_up(_key, client/user) switch(_key) if("Shift") - togglesprint() + sprint_hotkey(FALSE) return return ..() diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm index 34c44be23f..a314baa852 100644 --- a/modular_citadel/code/modules/mob/cit_emotes.dm +++ b/modular_citadel/code/modules/mob/cit_emotes.dm @@ -15,9 +15,12 @@ /datum/emote/living/insult/run_emote(mob/living/user, params) var/insult_message = "" + var/miming = user.mind ? user.mind.miming : 0 if(!user.is_muzzled()) insult_message += pick_list_replacements(INSULTS_FILE, "insult_gen") message = insult_message + else if(miming) + message = "creatively gesticulates." else message = "muffles something." . = ..() @@ -205,8 +208,23 @@ mob_type_allowed_typecache = list(/mob/living/carbon) /datum/emote/living/mothsqueak/run_emote(mob/living/user, params) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/mothsqueak.ogg', 50, 1, -1) + if(ishuman(user)) + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/mothsqueak.ogg', 50, 1, -1) + . = ..() + +/datum/emote/living/merp + key = "merp" + key_third_person = "merps" + message = "merps!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/merp/run_emote(mob/living/user, params) + if(ishuman(user)) + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/merp.ogg', 50, 1, -1) . = ..() diff --git a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm index 38343838e9..bd301a2e85 100644 --- a/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -7,12 +7,6 @@ var/extra2_color_src = MUTCOLORS3 var/list/ckeys_allowed -/* tbi eventually idk -/datum/sprite_accessory/legs/digitigrade_mam - name = "Anthro Digitigrade Legs" - icon = 'modular_citadel/icons/mob/mam_tails.dmi' -*/ - /datum/sprite_accessory/moth_wings/none name = "None" icon_state = "none" @@ -29,14 +23,146 @@ name = "None" icon_state = "None" + +/datum/sprite_accessory/tails/lizard/axolotl + name = "Axolotl" + icon_state = "axolotl" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/datum/sprite_accessory/tails_animated/lizard/axolotl + name = "Axolotl" + icon_state = "axolotl" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + +/************* Lizard compatable snoots ************/ +/datum/sprite_accessory/snouts/bird + name = "Beak" + icon_state = "bird" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/bigbeak + name = "Big Beak" + icon_state = "bigbeak" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/bug + name = "Bug" + icon_state = "bug" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + extra2 = TRUE + extra2_color_src = MUTCOLORS3 + +/datum/sprite_accessory/snouts/elephant + name = "Elephant" + icon_state = "elephant" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + extra = TRUE + extra_color_src = MUTCOLORS3 + +/datum/sprite_accessory/snouts/lcanid + name = "Mammal, Long" + icon_state = "lcanid" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/lcanidalt + name = "Mammal, Long ALT" + icon_state = "lcanidalt" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/scanid + name = "Mammal, Short" + icon_state = "scanid" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/scanidalt + name = "Mammal, Short ALT" + icon_state = "scanidalt" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/wolf + name = "Mammal, Thick" + icon_state = "wolf" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/wolfalt + name = "Mammal, Thick ALT" + icon_state = "wolfalt" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/redpanda + name = "WahCoon" + icon_state = "wah" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/rhino + name = "Horn" + icon_state = "rhino" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + extra = TRUE + extra = MUTCOLORS3 + +/datum/sprite_accessory/snouts/rodent + name = "Rodent" + icon_state = "rodent" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/husky + name = "Husky" + icon_state = "husky" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/otie + name = "Otie" + icon_state = "otie" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/pede + name = "Scolipede" + icon_state = "pede" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/sergal + name = "Sergal" + icon_state = "sergal" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + +/datum/sprite_accessory/snouts/shark + name = "Shark" + icon_state = "shark" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + +/datum/sprite_accessory/snouts/toucan + name = "Toucan" + icon_state = "toucan" + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' + color_src = MATRIXED + /****************************************** ************ Human Ears/Tails ************* *******************************************/ /datum/sprite_accessory/tails/human/ailurus name = "Red Panda" - icon_state = "ailurus" - color_src = 0 + icon_state = "wah" icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/human/axolotl @@ -49,7 +175,7 @@ icon_state = "axolotl" icon = 'modular_citadel/icons/mob/mam_tails.dmi' -/datum/sprite_accessory/tails_animated/axolotl +/datum/sprite_accessory/tails_animated/human/axolotl name = "Axolotl" icon_state = "axolotl" icon = 'modular_citadel/icons/mob/mam_tails.dmi' @@ -58,6 +184,7 @@ name = "Bear" icon_state = "bear" icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/tails/human/bear name = "Bear" @@ -83,7 +210,7 @@ name = "Cow" icon_state = "cow" icon = 'modular_citadel/icons/mob/mam_ears.dmi' - gender_specific = 1 + color_src = MATRIXED /datum/sprite_accessory/tails/human/cow name = "Cow" @@ -105,6 +232,7 @@ name = "Eevee" icon_state = "eevee" icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/tails/human/eevee name = "Eevee" @@ -120,12 +248,13 @@ name = "Elephant" icon_state = "elephant" icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/ears/fennec name = "Fennec" icon_state = "fennec" icon = 'modular_citadel/icons/mob/mam_ears.dmi' - hasinner = 1 + color_src = MATRIXED /datum/sprite_accessory/tails/human/fennec name = "Fennec" @@ -141,39 +270,33 @@ name = "Fish" icon_state = "fish" icon = 'modular_citadel/icons/mob/mam_ears.dmi' - color_src = MUTCOLORS3 + color_src = MATRIXED /datum/sprite_accessory/tails/human/fish name = "Fish" icon_state = "fish" icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra = TRUE - extra_color_src = MUTCOLORS3 /datum/sprite_accessory/tails_animated/human/fish name = "Fish" icon_state = "fish" icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra = TRUE - extra_color_src = MUTCOLORS3 /datum/sprite_accessory/ears/fox name = "Fox" icon_state = "fox" - hasinner = 1 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' /datum/sprite_accessory/tails/human/fox name = "Fox" icon_state = "fox" icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra = TRUE /datum/sprite_accessory/tails_animated/human/fox name = "Fox" icon_state = "fox" icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra = TRUE /datum/sprite_accessory/tails/human/horse name = "Horse" @@ -191,15 +314,13 @@ name = "Husky" icon_state = "husky" icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra = TRUE /datum/sprite_accessory/tails_animated/human/husky name = "Husky" icon_state = "husky" icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra = TRUE - /datum/sprite_accessory/tails/human/insect +/datum/sprite_accessory/tails/human/insect name = "Insect" icon_state = "insect" icon = 'modular_citadel/icons/mob/mam_tails.dmi' @@ -217,188 +338,199 @@ /datum/sprite_accessory/tails/human/kitsune name = "Kitsune" icon_state = "kitsune" - extra = TRUE - extra_color_src = MUTCOLORS2 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/kitsune name = "Kitsune" icon_state = "kitsune" - extra = TRUE - extra_color_src = MUTCOLORS2 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/lab name = "Dog, Floppy" icon_state = "lab" - hasinner = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' /datum/sprite_accessory/ears/murid name = "Murid" icon_state = "murid" icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/tails/human/murid name = "Murid" icon_state = "murid" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/murid name = "Murid" icon_state = "murid" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/human/otie name = "Otusian" icon_state = "otie" - hasinner= 1 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' /datum/sprite_accessory/tails/human/otie name = "Otusian" icon_state = "otie" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/otie name = "Otusian" icon_state = "otie" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails/orca name = "Orca" icon_state = "orca" - extra = TRUE + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/orca name = "Orca" icon_state = "orca" - extra = TRUE + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/human/pede name = "Scolipede" icon_state = "pede" icon = 'modular_citadel/icons/mob/mam_ears.dmi' - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 + color_src = MATRIXED /datum/sprite_accessory/tails/human/pede name = "Scolipede" icon_state = "pede" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/pede name = "Scolipede" icon_state = "pede" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/human/rabbit name = "Rabbit" icon_state = "rabbit" - hasinner= 1 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' /datum/sprite_accessory/tails/human/rabbit name = "Rabbit" icon_state = "rabbit" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/rabbit name = "Rabbit" icon_state = "rabbit" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/human/sergal name = "Sergal" icon_state = "sergal" - hasinner= 1 icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/tails/human/sergal name = "Sergal" icon_state = "sergal" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/sergal name = "Sergal" icon_state = "sergal" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/human/skunk name = "skunk" icon_state = "skunk" icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/tails/human/skunk name = "skunk" icon_state = "skunk" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/skunk name = "skunk" icon_state = "skunk" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails/human/shark name = "Shark" icon_state = "shark" - color_src = MUTCOLORS + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails/human/shark/datashark name = "datashark" icon_state = "datashark" - color_src = 0 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/squirrel name = "Squirrel" icon_state = "squirrel" - hasinner= 1 icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/tails/human/squirrel name = "Squirrel" icon_state = "squirrel" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/squirrel name = "Squirrel" icon_state = "squirrel" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails/human/yentacle name = "Tentacle" icon_state = "tentacle" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/tentacle name = "Tentacle" icon_state = "tentacle" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/ears/wolf name = "Wolf" icon_state = "wolf" - hasinner = 1 + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_ears.dmi' /datum/sprite_accessory/tails/human/wolf name = "Wolf" icon_state = "wolf" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/tails_animated/human/wolf name = "Wolf" icon_state = "wolf" + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' /****************************************** @@ -406,126 +538,253 @@ *******************************************/ /datum/sprite_accessory/mam_ears - extra = TRUE - extra2 = TRUE icon = 'modular_citadel/icons/mob/mam_ears.dmi' - extra_icon = 'modular_citadel/icons/mob/mam_ears.dmi' - extra2_icon = 'modular_citadel/icons/mob/mam_ears.dmi' + color_src = MATRIXED /datum/sprite_accessory/mam_ears/none name = "None" icon_state = "none" /datum/sprite_accessory/mam_tails - extra = TRUE - extra2 = TRUE + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/mam_tails/none name = "None" icon_state = "none" /datum/sprite_accessory/mam_tails_animated - extra = TRUE - extra2 = TRUE + color_src = MATRIXED icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi' - extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi' /datum/sprite_accessory/mam_tails_animated/none name = "None" icon_state = "none" + color_src = MATRIXED -/datum/sprite_accessory/snouts +/datum/sprite_accessory/mam_snouts + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_snouts.dmi' -/datum/sprite_accessory/snouts/none +/datum/sprite_accessory/mam_snouts/none name = "None" icon_state = "none" - extra_icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra2_icon = 'modular_citadel/icons/mob/mam_snouts.dmi' /****************************************** **************** Snouts ******************* *******************************************/ -/datum/sprite_accessory/snouts/bird +/datum/sprite_accessory/mam_snouts/bird name = "Beak" icon_state = "bird" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - color_src = MUTCOLORS3 -/datum/sprite_accessory/snouts/bigbeak +/datum/sprite_accessory/mam_snouts/bigbeak name = "Big Beak" icon_state = "bigbeak" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - color_src = MUTCOLORS3 -/datum/sprite_accessory/snouts/elephant +/datum/sprite_accessory/mam_snouts/bug + name = "Bug" + icon_state = "bug" + color_src = MUTCOLORS + extra2 = TRUE + extra2_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/elephant name = "Elephant" icon_state = "elephant" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' extra = TRUE extra_color_src = MUTCOLORS3 -/datum/sprite_accessory/snouts/lcanid - name = "Fox, Long" +/datum/sprite_accessory/mam_snouts/lcanid + name = "Mammal, Long" icon_state = "lcanid" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra = TRUE -/datum/sprite_accessory/snouts/scanid - name = "Fox, Short" +/datum/sprite_accessory/mam_snouts/lcanidalt + name = "Mammal, Long ALT" + icon_state = "lcanidalt" + +/datum/sprite_accessory/mam_snouts/scanid + name = "Mammal, Short" icon_state = "scanid" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra = TRUE -/datum/sprite_accessory/snouts/wolf - name = "Wolf" +/datum/sprite_accessory/mam_snouts/scanidalt + name = "Mammal, Short ALT" + icon_state = "scanidalt" + +/datum/sprite_accessory/mam_snouts/wolf + name = "Mammal, Thick" icon_state = "wolf" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra = TRUE -/datum/sprite_accessory/snouts/rhino +/datum/sprite_accessory/mam_snouts/wolfalt + name = "Mammal, Thick ALT" + icon_state = "wolfalt" + +/datum/sprite_accessory/mam_snouts/redpanda + name = "WahCoon" + icon_state = "wah" + +/datum/sprite_accessory/mam_snouts/rhino name = "Horn" icon_state = "rhino" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' extra = TRUE extra = MUTCOLORS3 -/datum/sprite_accessory/snouts/husky +/datum/sprite_accessory/mam_snouts/rodent + name = "Rodent" + icon_state = "rodent" + +/datum/sprite_accessory/mam_snouts/husky name = "Husky" icon_state = "husky" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra = TRUE -/datum/sprite_accessory/snouts/otie +/datum/sprite_accessory/mam_snouts/otie name = "Otie" icon_state = "otie" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra = TRUE -/datum/sprite_accessory/snouts/pede +/datum/sprite_accessory/mam_snouts/pede name = "Scolipede" icon_state = "pede" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - extra = TRUE - color_src = MUTCOLORS - extra_color_src = MUTCOLORS2 -/datum/sprite_accessory/snouts/sergal +/datum/sprite_accessory/mam_snouts/sergal name = "Sergal" icon_state = "sergal" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - color_src = MUTCOLORS2 -/datum/sprite_accessory/snouts/toucan +/datum/sprite_accessory/mam_snouts/shark + name = "Shark" + icon_state = "shark" + +/datum/sprite_accessory/mam_snouts/toucan name = "Toucan" icon_state = "toucan" - icon = 'modular_citadel/icons/mob/mam_snouts.dmi' - color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/sharp + name = "Sharp" + icon_state = "sharp" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/round + name = "Round" + icon_state = "round" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/sharplight + name = "Sharp + Light" + icon_state = "sharplight" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/roundlight + name = "Round + Light" + icon_state = "roundlight" + color_src = MUTCOLORS + + +/****************************************** +**************** Snouts ******************* +*************but higher up*****************/ + +/datum/sprite_accessory/mam_snouts/fbird + name = "Beak (Top)" + icon_state = "fbird" + +/datum/sprite_accessory/mam_snouts/fbigbeak + name = "Big Beak (Top)" + icon_state = "fbigbeak" + +/datum/sprite_accessory/mam_snouts/fbug + name = "Bug (Top)" + icon_state = "fbug" + color_src = MUTCOLORS + extra2 = TRUE + extra2_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/felephant + name = "Elephant (Top)" + icon_state = "felephant" + extra = TRUE + extra_color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/flcanid + name = "Mammal, Long (Top)" + icon_state = "flcanid" + +/datum/sprite_accessory/mam_snouts/flcanidalt + name = "Mammal, Long ALT (Top)" + icon_state = "flcanidalt" + +/datum/sprite_accessory/mam_snouts/fscanid + name = "Mammal, Short (Top)" + icon_state = "fscanid" + +/datum/sprite_accessory/mam_snouts/fscanidalt + name = "Mammal, Short ALT (Top)" + icon_state = "fscanidalt" + +/datum/sprite_accessory/mam_snouts/fwolf + name = "Mammal, Thick (Top)" + icon_state = "fwolf" + +/datum/sprite_accessory/mam_snouts/fwolfalt + name = "Mammal, Thick ALT (Top)" + icon_state = "fwolfalt" + +/datum/sprite_accessory/mam_snouts/fredpanda + name = "WahCoon (Top)" + icon_state = "fwah" + +/datum/sprite_accessory/mam_snouts/frhino + name = "Horn (Top)" + icon_state = "frhino" + extra = TRUE + extra = MUTCOLORS3 + +/datum/sprite_accessory/mam_snouts/frodent + name = "Rodent (Top)" + icon_state = "frodent" + +/datum/sprite_accessory/mam_snouts/fhusky + name = "Husky (Top)" + icon_state = "fhusky" + +/datum/sprite_accessory/mam_snouts/fotie + name = "Otie (Top)" + icon_state = "fotie" + +/datum/sprite_accessory/mam_snouts/fpede + name = "Scolipede (Top)" + icon_state = "fpede" + +/datum/sprite_accessory/mam_snouts/fsergal + name = "Sergal (Top)" + icon_state = "fsergal" + +/datum/sprite_accessory/mam_snouts/fshark + name = "Shark (Top)" + icon_state = "fshark" + +/datum/sprite_accessory/mam_snouts/ftoucan + name = "Toucan (Top)" + icon_state = "ftoucan" + +/datum/sprite_accessory/mam_snouts/fsharp + name = "Sharp (Top)" + icon_state = "fsharp" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/fround + name = "Round (Top)" + icon_state = "fround" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/fsharplight + name = "Sharp + Light (Top)" + icon_state = "fsharplight" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_snouts/froundlight + name = "Round + Light (Top)" + icon_state = "froundlight" + color_src = MUTCOLORS /****************************************** ***************** Ears ******************** @@ -539,18 +798,47 @@ name = "Bear" icon_state = "bear" +/datum/sprite_accessory/mam_ears/bigwolf + name = "Big Wolf" + icon_state = "bigwolf" + +/datum/sprite_accessory/mam_ears/bigwolfinner + name = "Big Wolf (ALT)" + icon_state = "bigwolfinner" + hasinner = 1 + +/datum/sprite_accessory/mam_ears/bigwolfdark + name = "Dark Big Wolf" + icon_state = "bigwolfdark" + +/datum/sprite_accessory/mam_ears/bigwolfinnerdark + name = "Dark Big Wolf (ALT)" + icon_state = "bigwolfinnerdark" + hasinner = 1 + +/datum/sprite_accessory/mam_ears/cat + name = "Cat" + icon_state = "cat" + hasinner = 1 + color_src = HAIR + /datum/sprite_accessory/mam_ears/catbig name = "Cat, Big" icon_state = "catbig" - hasinner = 1 /datum/sprite_accessory/mam_ears/cow name = "Cow" icon_state = "cow" +/datum/sprite_accessory/mam_ears/curled + name = "Curled Horn" + icon_state = "horn1" + color_src = MUTCOLORS3 + /datum/sprite_accessory/mam_ears/deer name = "Deer" icon_state = "deer" + color_src = MUTCOLORS3 /datum/sprite_accessory/mam_ears/eevee name = "Eevee" @@ -563,17 +851,14 @@ /datum/sprite_accessory/mam_ears/fennec name = "Fennec" icon_state = "fennec" - hasinner = 1 /datum/sprite_accessory/mam_ears/fish name = "Fish" icon_state = "fish" - color_src = MUTCOLORS3 /datum/sprite_accessory/mam_ears/fox name = "Fox" icon_state = "fox" - hasinner = 1 /datum/sprite_accessory/mam_ears/husky name = "Husky" @@ -583,6 +868,11 @@ name = "kangaroo" icon_state = "kangaroo" +/datum/sprite_accessory/mam_ears/jellyfish + name = "Jellyfish" + icon_state = "jellyfish" + color_src = HAIR + /datum/sprite_accessory/mam_ears/lab name = "Dog, Long" icon_state = "lab" @@ -591,37 +881,25 @@ name = "Murid" icon_state = "murid" -/datum/sprite_accessory/mam_ears/neko - name = "Neko" - icon_state = "cat" - hasinner = 1 - color_src = HAIR - /datum/sprite_accessory/mam_ears/otie name = "Otusian" icon_state = "otie" - hasinner= 1 /datum/sprite_accessory/mam_ears/squirrel name = "Squirrel" icon_state = "squirrel" - hasinner= 1 /datum/sprite_accessory/mam_ears/pede name = "Scolipede" icon_state = "pede" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 /datum/sprite_accessory/mam_ears/rabbit name = "Rabbit" icon_state = "rabbit" - hasinner= 1 /datum/sprite_accessory/mam_ears/sergal name = "Sergal" icon_state = "sergal" - hasinner= 1 /datum/sprite_accessory/mam_ears/skunk name = "skunk" @@ -630,20 +908,19 @@ /datum/sprite_accessory/mam_ears/wolf name = "Wolf" icon_state = "wolf" - hasinner = 1 /****************************************** *********** Tails and Things ************** *******************************************/ /datum/sprite_accessory/mam_tails/ailurus - name = "Ailurus" - icon_state = "ailurus" + name = "Red Panda" + icon_state = "wah" extra = TRUE /datum/sprite_accessory/mam_tails_animated/ailurus - name = "Ailurus" - icon_state = "ailurus" + name = "Red Panda" + icon_state = "wah" extra = TRUE /datum/sprite_accessory/mam_tails/axolotl @@ -662,6 +939,16 @@ name = "Bear" icon_state = "bear" +/datum/sprite_accessory/mam_tails/cat + name = "Cat" + icon_state = "cat" + color_src = HAIR + +/datum/sprite_accessory/mam_tails_animated/cat + name = "Cat" + icon_state = "cat" + color_src = HAIR + /datum/sprite_accessory/mam_tails/catbig name = "Cat, Big" icon_state = "catbig" @@ -670,6 +957,14 @@ name = "Cat, Big" icon_state = "catbig" +/datum/sprite_accessory/mam_tails/corvid + name = "Corvid" + icon_state = "crow" + +/datum/sprite_accessory/mam_tails_animated/corvid + name = "Corvid" + icon_state = "crow" + /datum/sprite_accessory/mam_tail/cow name = "Cow" icon_state = "cow" @@ -678,19 +973,13 @@ name = "Cow" icon_state = "cow" -/datum/sprite_accessory/mam_ears/curled - name = "Curled Horn" - icon_state = "horn1" - /datum/sprite_accessory/mam_tails/eevee name = "Eevee" icon_state = "eevee" - extra = TRUE /datum/sprite_accessory/mam_tails_animated/eevee name = "Eevee" icon_state = "eevee" - extra = TRUE /datum/sprite_accessory/mam_tails/fennec name = "Fennec" @@ -703,24 +992,18 @@ /datum/sprite_accessory/mam_tails/human/fish name = "Fish" icon_state = "fish" - extra = TRUE - extra_color_src = MUTCOLORS3 /datum/sprite_accessory/mam_tails_animated/human/fish name = "Fish" icon_state = "fish" - extra = TRUE - extra_color_src = MUTCOLORS3 /datum/sprite_accessory/mam_tails/fox name = "Fox" icon_state = "fox" - extra = TRUE /datum/sprite_accessory/mam_tails_animated/fox name = "Fox" icon_state = "fox" - extra = TRUE /datum/sprite_accessory/mam_tails/hawk name = "Hawk" @@ -743,12 +1026,10 @@ /datum/sprite_accessory/mam_tails/husky name = "Husky" icon_state = "husky" - extra = TRUE /datum/sprite_accessory/mam_tails_animated/husky name = "Husky" icon_state = "husky" - extra = TRUE datum/sprite_accessory/mam_tails/insect name = "Insect" @@ -766,20 +1047,13 @@ datum/sprite_accessory/mam_tails/insect name = "kangaroo" icon_state = "kangaroo" -/datum/sprite_accessory/mam_ears/jellyfish - name = "Jellyfish" - icon_state = "jellyfish" - color_src = HAIR - /datum/sprite_accessory/mam_tails/kitsune name = "Kitsune" icon_state = "kitsune" - extra = TRUE /datum/sprite_accessory/mam_tails_animated/kitsune name = "Kitsune" icon_state = "kitsune" - extra = TRUE /datum/sprite_accessory/mam_tails/lab name = "Lab" @@ -792,22 +1066,10 @@ datum/sprite_accessory/mam_tails/insect /datum/sprite_accessory/mam_tails/murid name = "Murid" icon_state = "murid" - color_src = 0 /datum/sprite_accessory/mam_tails_animated/murid name = "Murid" icon_state = "murid" - color_src = 0 - -/datum/sprite_accessory/mam_tails/neko - name = "Neko" - icon_state = "cat" - color_src = HAIR - -/datum/sprite_accessory/mam_tails_animated/neko - name = "Neko" - icon_state = "cat" - color_src = HAIR /datum/sprite_accessory/mam_tails/otie name = "Otusian" @@ -820,12 +1082,10 @@ datum/sprite_accessory/mam_tails/insect /datum/sprite_accessory/mam_tails/orca name = "Orca" icon_state = "orca" - extra = TRUE /datum/sprite_accessory/mam_tails_animated/orca name = "Orca" icon_state = "orca" - extra = TRUE /datum/sprite_accessory/mam_tails/pede name = "Scolipede" @@ -852,38 +1112,36 @@ datum/sprite_accessory/mam_tails/insect icon_state = "sergal" /datum/sprite_accessory/mam_tails/skunk - name = "skunk" + name = "Skunk" icon_state = "skunk" - color_src = 0 - extra = TRUE /datum/sprite_accessory/mam_tails_animated/skunk - name = "skunk" + name = "Skunk" icon_state = "skunk" - color_src = 0 - extra = TRUE /datum/sprite_accessory/mam_tails/shark name = "Shark" icon_state = "shark" - color_src = MUTCOLORS /datum/sprite_accessory/mam_tails_animated/shark name = "Shark" icon_state = "shark" - color_src = MUTCOLORS /datum/sprite_accessory/mam_tails/shepherd name = "Shepherd" icon_state = "shepherd" - extra = TRUE - extra2 = TRUE /datum/sprite_accessory/mam_tails_animated/shepherd name = "Shepherd" icon_state = "shepherd" - extra = TRUE - extra2 = TRUE + +/datum/sprite_accessory/mam_tails/straighttail + name = "Straight Tail" + icon_state = "straighttail" + +/datum/sprite_accessory/mam_tails_animated/straighttail + name = "Straight Tail" + icon_state = "straighttail" /datum/sprite_accessory/mam_tails/squirrel name = "Squirrel" @@ -893,7 +1151,7 @@ datum/sprite_accessory/mam_tails/insect name = "Squirrel" icon_state = "squirrel" -datum/sprite_accessory/mam_tails/tentacle +/datum/sprite_accessory/mam_tails/tentacle name = "Tentacle" icon_state = "tentacle" @@ -901,6 +1159,14 @@ datum/sprite_accessory/mam_tails/tentacle name = "Tentacle" icon_state = "tentacle" +/datum/sprite_accessory/mam_tails/tiger + name = "Tiger" + icon_state = "tiger" + +/datum/sprite_accessory/mam_tails_animated/tiger + name = "Tiger" + icon_state = "tiger" + /datum/sprite_accessory/mam_tails/wolf name = "Wolf" icon_state = "wolf" @@ -914,150 +1180,172 @@ datum/sprite_accessory/mam_tails/tentacle *******************************************/ /datum/sprite_accessory/mam_body_markings - extra = TRUE - extra2 = TRUE - icon = 'modular_citadel/icons/mob/mam_body_markings.dmi' + extra = FALSE + extra2 = FALSE + color_src = MATRIXED + gender_specific = 0 + icon = 'modular_citadel/icons/mob/mam_markings.dmi' /datum/sprite_accessory/mam_body_markings/none name = "None" icon_state = "none" + color_src = MUTCOLORS + +/datum/sprite_accessory/mam_body_markings/plain + name = "Plain" + icon_state = "plain" /datum/sprite_accessory/mam_body_markings/ailurus - name = "Red Panda" - icon_state = "ailurus" - gender_specific = 1 - -/datum/sprite_accessory/mam_body_markings/belly - name = "Bee" - icon_state = "bee" - color_src = MUTCOLORS3 - gender_specific = 1 + name = "Redpanda" + icon_state = "wah" /datum/sprite_accessory/mam_body_markings/bee + name = "Bee" + icon_state = "bee" + +/datum/sprite_accessory/mam_body_markings/belly name = "Belly" icon_state = "belly" - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/bellyslim + name = "Bellyslim" + icon_state = "bellyslim" /datum/sprite_accessory/mam_body_markings/corgi name = "Corgi" icon_state = "corgi" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/cow - name = "Cow" - icon_state = "cow" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 - gender_specific = 1 + name = "Bovine" + icon_state = "bovine" /datum/sprite_accessory/mam_body_markings/corvid - name = "Crow" + name = "Corvid" icon_state = "corvid" - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/dalmation + name = "Dalmation" + icon_state = "dalmation" /datum/sprite_accessory/mam_body_markings/deer name = "Deer" icon_state = "deer" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/dog + name = "Dog" + icon_state = "dog" /datum/sprite_accessory/mam_body_markings/eevee name = "Eevee" icon_state = "eevee" - color_src = MUTCOLORS3 + +/datum/sprite_accessory/mam_body_markings/hippo + name = "Hippo" + icon_state = "hippo" /datum/sprite_accessory/mam_body_markings/fennec name = "Fennec" icon_state = "Fennec" - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/fox name = "Fox" icon_state = "fox" - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/frog name = "Frog" icon_state = "frog" - gender_specific = 1 - color_src = MUTCOLORS2 + +/datum/sprite_accessory/mam_body_markings/goat + name = "Goat" + icon_state = "goat" + +/datum/sprite_accessory/mam_body_markings/handsfeet + name = "Handsfeet" + icon_state = "handsfeet" /datum/sprite_accessory/mam_body_markings/hawk name = "Hawk" icon_state = "hawk" - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/husky name = "Husky" icon_state = "husky" - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/hyena + name = "Hyena" + icon_state = "hyena" + +/datum/sprite_accessory/mam_body_markings/lab + name = "Lab" + icon_state = "lab" /datum/sprite_accessory/mam_body_markings/moth name = "Moth" icon_state = "moth" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/otie name = "Otie" icon_state = "otie" - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/otter + name = "Otter" + icon_state = "otter" /datum/sprite_accessory/mam_body_markings/orca name = "Orca" icon_state = "orca" - color_src = MUTCOLORS2 - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/panther + name = "Panther" + icon_state = "panther" + +/datum/sprite_accessory/mam_body_markings/possum + name = "Possum" + icon_state = "possum" + +/datum/sprite_accessory/mam_body_markings/raccoon + name = "Raccoon" + icon_state = "raccoon" /datum/sprite_accessory/mam_body_markings/pede name = "Scolipede" - icon_state = "pede" - extra = TRUE - extra_color_src = MUTCOLORS3 - color_src = MUTCOLORS2 - gender_specific = 1 + icon_state = "scolipede" /datum/sprite_accessory/mam_body_markings/shark name = "Shark" icon_state = "shark" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/skunk + name = "Skunk" + icon_state = "skunk" + +/datum/sprite_accessory/mam_body_markings/sergal + name = "Sergal" + icon_state = "sergal" /datum/sprite_accessory/mam_body_markings/shepherd name = "Shepherd" icon_state = "shepherd" - gender_specific = 1 + +/datum/sprite_accessory/mam_body_markings/tajaran + name = "Tajaran" + icon_state = "tajaran" /datum/sprite_accessory/mam_body_markings/tiger - name = "Tiger Stripes" - color_src = MUTCOLORS3 + name = "Tiger" icon_state = "tiger" /datum/sprite_accessory/mam_body_markings/turian name = "Turian" - extra = TRUE - color_src = MUTCOLORS - extra_color_src = MUTCOLORS2 icon_state = "turian" - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/wolf name = "Wolf" icon_state = "wolf" - color_src = MUTCOLORS2 - gender_specific = 1 /datum/sprite_accessory/mam_body_markings/xeno name = "Xeno" icon_state = "xeno" - color_src = MUTCOLORS2 - extra_color_src = MUTCOLORS3 - gender_specific = 1 /****************************************** @@ -1072,6 +1360,7 @@ datum/sprite_accessory/mam_tails/tentacle center = TRUE dimension_x = 64 var/taur_mode = NOT_TAURIC + color_src = MATRIXED /datum/sprite_accessory/taur/none name = "None" @@ -1090,11 +1379,13 @@ datum/sprite_accessory/mam_tails/tentacle /datum/sprite_accessory/taur/drider name = "Drider" icon_state = "drider" + color_src = MUTCOLORS /datum/sprite_accessory/taur/eevee name = "Eevee" icon_state = "eevee" taur_mode = PAW_TAURIC + color_src = MUTCOLORS /datum/sprite_accessory/taur/fox name = "Fox" @@ -1130,6 +1421,7 @@ datum/sprite_accessory/mam_tails/tentacle name = "Scolipede" icon_state = "pede" taur_mode = PAW_TAURIC + color_src = MUTCOLORS /datum/sprite_accessory/taur/panther name = "Panther" @@ -1141,15 +1433,16 @@ datum/sprite_accessory/mam_tails/tentacle icon_state = "shepherd" taur_mode = PAW_TAURIC -/datum/sprite_accessory/taur/tajaran - name = "Tajaran" - icon_state = "tajaran" - taur_mode = PAW_TAURIC - /datum/sprite_accessory/taur/tentacle name = "Tentacle" icon_state = "tentacle" taur_mode = SNEK_TAURIC + color_src = MUTCOLORS + +/datum/sprite_accessory/taur/tiger + name = "Tiger" + icon_state = "tiger" + taur_mode = PAW_TAURIC /datum/sprite_accessory/taur/wolf name = "Wolf" @@ -1365,17 +1658,15 @@ datum/sprite_accessory/mam_tails/tentacle /datum/sprite_accessory/body_markings/guilmon name = "Guilmon" icon_state = "guilmon" - gender_specific = 1 + color_src = MATRIXED /datum/sprite_accessory/tails/lizard/guilmon name = "Guilmon" icon_state = "guilmon" - extra = TRUE /datum/sprite_accessory/tails_animated/lizard/guilmon name = "Guilmon" icon_state = "guilmon" - extra = TRUE /datum/sprite_accessory/horns/guilmon name = "Guilmon" @@ -1385,52 +1676,41 @@ datum/sprite_accessory/mam_tails/tentacle /datum/sprite_accessory/snout/guilmon name = "Guilmon" icon_state = "guilmon" + color_src = MATRIXED /datum/sprite_accessory/mam_tails/shark/datashark name = "DataShark" icon_state = "datashark" - color_src = 0 ckeys_allowed = list("rubyflamewing") /datum/sprite_accessory/mam_tails_animated/shark/datashark name = "DataShark" icon_state = "datashark" - color_src = 0 /datum/sprite_accessory/mam_body_markings/shark/datashark name = "DataShark" icon_state = "datashark" - color_src = MUTCOLORS2 ckeys_allowed = list("rubyflamewing") - //Sabresune /datum/sprite_accessory/mam_ears/sabresune name = "sabresune" icon_state = "sabresune" - hasinner = 1 - extra = TRUE - extra_color_src = MUTCOLORS3 ckeys_allowed = list("poojawa") /datum/sprite_accessory/mam_tails/sabresune name = "sabresune" icon_state = "sabresune" - extra = TRUE ckeys_allowed = list("poojawa") /datum/sprite_accessory/mam_tails_animated/sabresune name = "sabresune" icon_state = "sabresune" - extra = TRUE /datum/sprite_accessory/mam_body_markings/sabresune name = "Sabresune" icon_state = "sabresune" - color_src = MUTCOLORS2 - extra = FALSE - extra2 = FALSE ckeys_allowed = list("poojawa") @@ -1438,21 +1718,16 @@ datum/sprite_accessory/mam_tails/tentacle /datum/sprite_accessory/mam_ears/lunasune name = "lunasune" icon_state = "lunasune" - hasinner = 1 - extra = TRUE - extra_color_src = MUTCOLORS2 ckeys_allowed = list("invader4352") /datum/sprite_accessory/mam_tails/lunasune name = "lunasune" icon_state = "lunasune" - extra = TRUE ckeys_allowed = list("invader4352") /datum/sprite_accessory/mam_tails_animated/lunasune name = "lunasune" icon_state = "lunasune" - extra = TRUE /*************** VIRGO PORTED HAIRS ****************************/ #define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = "Virgo - " + #_name diff --git a/modular_citadel/code/modules/mob/living/carbon/carbon.dm b/modular_citadel/code/modules/mob/living/carbon/carbon.dm index 8d6b4576c9..d52cc6eabb 100644 --- a/modular_citadel/code/modules/mob/living/carbon/carbon.dm +++ b/modular_citadel/code/modules/mob/living/carbon/carbon.dm @@ -29,7 +29,7 @@ for(var/obj/screen/combattoggle/selector in hud_used.static_inventory) selector.rebasetointerbay(src) if(world.time >= combatmessagecooldown && combatmode) - visible_message("[src] [resting ? "tenses up" : "drops into a combative stance"].") + visible_message("[src] [resting ? "tenses up" : (prob(95)? "drops into a combative stance" : (prob(95)? "poses aggressively" : "asserts dominance with their pose"))].") combatmessagecooldown = 10 SECONDS + world.time //This is set 100% of the time to make sure squeezing regen out of process cycles doesn't result in the combat mode message getting spammed SEND_SIGNAL(src, COMSIG_COMBAT_TOGGLED, src, combatmode) return TRUE diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm index 0e59e2cd9f..c4449d33d7 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm @@ -31,3 +31,7 @@ for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory) selector.insert_witty_toggle_joke_here(src) return TRUE + +/mob/living/carbon/human/proc/sprint_hotkey(targetstatus) + if(targetstatus ? !sprinting : sprinting) + togglesprint() diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm index 1dd6276140..d468f34653 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm @@ -44,37 +44,105 @@ if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) to_chat(user, "You're too exhausted.") return FALSE - else if(target.check_block()) - target.visible_message("[target] blocks [user]'s disarm attempt!") - return 0 + if(target.check_block()) + target.visible_message("[target] blocks [user]'s shoving attempt!") + return FALSE if(attacker_style && attacker_style.disarm_act(user,target)) - return 1 + return TRUE + if(user.resting) + return FALSE else + if(user == target) + return user.do_attack_animation(target, ATTACK_EFFECT_DISARM) - - user.adjustStaminaLossBuffered(4) //CITADEL CHANGE - makes disarmspam cause staminaloss + user.adjustStaminaLossBuffered(4) + playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) if(target.w_uniform) target.w_uniform.add_fingerprint(user) - var/randomized_zone = ran_zone(user.zone_selected) SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected) - var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone) - if((!target.combatmode && user.combatmode || prob(target.getStaminaLoss()*(user.resting ? 0.25 : 1)*(user.combatmode ? 1 : 0.05))) && !target.resting) //probability depends on staminaloss. it's plausible, but unlikely that you'll be able to push someone over while resting, and pretty rare to successfully push someone outside of combat mode. The few people that even know how to right-click outside of combat mode are a rarity but let's take that into account regardless. - playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - target.visible_message("[user] [user.combatmode ? "has" : "gently"] pushed [target]!", - "[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE) - target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!")) - target.forcesay(GLOB.hit_appends) - log_combat(user, target, "disarmed", " pushing them to the ground") - return + if(!target.resting) + target.adjustStaminaLoss(5) + + + var/turf/target_oldturf = target.loc + var/shove_dir = get_dir(user.loc, target_oldturf) + var/turf/target_shove_turf = get_step(target.loc, shove_dir) + var/mob/living/carbon/human/target_collateral_human + var/obj/structure/table/target_table + var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied + + //Thank you based whoneedsspace + target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents + if(target_collateral_human) + shove_blocked = TRUE + else + target.Move(target_shove_turf, shove_dir) + if(get_turf(target) == target_oldturf) + target_table = locate(/obj/structure/table) in target_shove_turf.contents + shove_blocked = TRUE + + if(shove_blocked && !target.is_shove_knockdown_blocked()) + var/directional_blocked = FALSE + if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that + var/target_turf = get_turf(target) + for(var/obj/O in target_turf) + if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density) + directional_blocked = TRUE + break + if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile + for(var/obj/O in target_shove_turf) + if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density) + directional_blocked = TRUE + break + var/targetatrest = target.resting + if(((!target_table && !target_collateral_human) || directional_blocked) && !targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_SOLID) + user.visible_message("[user.name] shoves [target.name], knocking them down!", + "You shove [target.name], knocking them down!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "knocking them down") + else if(target_table) + if(!targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_TABLE) + user.visible_message("[user.name] shoves [target.name] onto \the [target_table]!", + "You shove [target.name] onto \the [target_table]!", null, COMBAT_MESSAGE_RANGE) + target.forceMove(target_shove_turf) + log_combat(user, target, "shoved", "onto [target_table]") + else if(target_collateral_human && !targetatrest) + target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) + if(!target_collateral_human.resting) + target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) + user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!", + "You shove [target.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE) + log_combat(user, target, "shoved", "into [target_collateral_human.name]") + + else + user.visible_message("[user.name] shoves [target.name]!", + "You shove [target.name]!", null, COMBAT_MESSAGE_RANGE) + var/target_held_item = target.get_active_held_item() + var/knocked_item = FALSE + if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) + target_held_item = null + if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID)) + target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH) + if(target_held_item) + target.visible_message("[target.name]'s grip on \the [target_held_item] loosens!", + "Your grip on \the [target_held_item] loosens!", null, COMBAT_MESSAGE_RANGE) + addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH) + else if(target_held_item) + target.dropItemToGround(target_held_item) + knocked_item = TRUE + target.visible_message("[target.name] drops \the [target_held_item]!!", + "You drop \the [target_held_item]!!", null, COMBAT_MESSAGE_RANGE) + var/append_message = "" + if(target_held_item) + if(knocked_item) + append_message = "causing them to drop [target_held_item]" + else + append_message = "loosening their grip on [target_held_item]" + log_combat(user, target, "shoved", append_message) - playsound(target, 'sound/weapons/thudswoosh.ogg', 25, 1, -1) - target.visible_message("[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", \ - "[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", null, COMBAT_MESSAGE_RANGE) - if(!target.resting && !user.resting && user.combatmode) - target.adjustStaminaLoss(rand(1,5)) //This is the absolute most inefficient way to get someone into soft stamcrit, but if you've got a crowd trying to shove you over, you've no option but to get knocked down and accept fate - log_combat(user, target, "attempted to disarm push") //////////////////// /////BODYPARTS///// @@ -98,6 +166,8 @@ return GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]] if("mam_ears") return GLOB.mam_ears_list[H.dna.features["mam_ears"]] + if("mam_snouts") + return GLOB.mam_snouts_list[H.dna.features["mam_snouts"]] if("taur") return GLOB.taur_list[H.dna.features["taur"]] if("xenodorsal") diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm index 16c5460174..edc36ae3af 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm @@ -5,8 +5,8 @@ should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) - mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "snout", "taur", "legs") - default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "snout" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs") + mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "taur", "legs") + default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs") attack_verb = "claw" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' @@ -46,6 +46,7 @@ /datum/species/mammal/qualifies_for_rank(rank, list/features) return TRUE + //AVIAN// /datum/species/avian name = "Avian" @@ -55,8 +56,8 @@ should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) - mutant_bodyparts = list("snout", "wings", "taur", "mam_tail", "mam_body_markings", "taur") - default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "snout" = "Beak", "wings" = "None", "taur" = "None", "mam_body_markings" = "Hawk", "mam_tail" = "Hawk") + mutant_bodyparts = list("mam_snouts", "wings", "taur", "mam_tail", "mam_body_markings", "taur") + default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Beak", "mam_body_markings" = "Hawk", "wings" = "None", "taur" = "None", "mam_tail" = "Hawk") attack_verb = "peck" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' @@ -101,8 +102,8 @@ should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) - mutant_bodyparts = list("mam_tail", "mam_body_markings", "mam_ears", "taur", "legs") - default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_body_markings" = "Shark", "mam_ears" = "None", "snout" = "Round", "taur" = "None", "legs" = "Normal Legs") + mutant_bodyparts = list("mam_tail", "mam_ears","mam_body_markings", "taur", "legs", "mam_snouts") + default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "Shark", "mam_ears" = "None", "mam_body_markings" = "Shark", "mam_snouts" = "Round", "taur" = "None", "legs" = "Normal Legs") attack_verb = "bite" attack_sound = 'sound/weapons/bite.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' @@ -148,8 +149,8 @@ should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG) - mutant_bodyparts = list("mam_body_markings", "mam_ears", "mam_tail", "taur", "moth_wings") - default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_body_markings" = "Moth", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "snout" = "None", "taur" = "None") + mutant_bodyparts = list("mam_ears", "mam_body_markings", "mam_tail", "taur", "moth_wings", "mam_snouts") + default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "moth_wings" = "Plain", "mam_snouts" = "Bug", "mam_body_markings" = "Moth", "taur" = "None") attack_verb = "flutter" //wat? attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' @@ -196,8 +197,8 @@ should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) - mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "taur", "mam_body_markings") - default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None","mam_body_markings" = "Xeno") + mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "mam_body_markings", "taur") + default_features = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None") attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm index b6f624709e..a0dbe3a02a 100644 --- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -57,7 +57,25 @@ /obj/item/robot_module/k9/do_transform_animation() ..() to_chat(loc,"While you have picked the Security K-9 module, you still have to follow your laws, NOT Space Law. \ - For Asimov, this means you must follow criminals' orders unless there is a law 1 reason not to.") + For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.
") + +/obj/item/robot_module/k9/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/list/sechoundmodels = list("Default") + if(R.client && R.client.ckey in list("nezuli")) + sechoundmodels += "Alina" + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in sechoundmodels + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "k9" + moduleselect_icon = "k9" + if("Alina") + cyborg_base_icon = "alina-sec" + special_light_key = "alina" + sleeper_overlay = "alinasleeper" + return ..() /obj/item/robot_module/medihound name = "MediHound" @@ -73,6 +91,7 @@ /obj/item/reagent_containers/borghypo, /obj/item/twohanded/shockpaddles/cyborg/hound, /obj/item/stack/medical/gauze/cyborg, + /obj/item/pinpointer/crew, /obj/item/sensor_device) emag_modules = list(/obj/item/dogborg/pounce) ratvar_modules = list(/obj/item/clockwork/slab/cyborg/medical, @@ -88,6 +107,26 @@ dogborg = TRUE cyborg_pixel_offset = -16 +/obj/item/robot_module/medihound/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/list/medhoundmodels = list("Default", "Dark") + if(R.client && R.client.ckey in list("nezuli")) + medhoundmodels += "Alina" + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in medhoundmodels + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "medihound" + if("Dark") + cyborg_base_icon = "medihounddark" + sleeper_overlay = "mdsleeper" + if("Alina") + cyborg_base_icon = "alina-med" + special_light_key = "alina" + sleeper_overlay = "alinasleeper" + return ..() + /obj/item/robot_module/scrubpup name = "Scrub Pup" basic_modules = list( @@ -183,7 +222,7 @@ /obj/item/robot_module/medical/be_transformed_to(obj/item/robot_module/old_module) var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Droid", "Eyebot") + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Heavy", "Sleek", "Marina", "Droid", "Eyebot") if(!borg_icon) return FALSE switch(borg_icon) @@ -193,15 +232,59 @@ cyborg_base_icon = "medical" cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' hat_offset = 4 + if("Sleek") + cyborg_base_icon = "sleekmed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinamed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' if("Eyebot") cyborg_base_icon = "eyebotmed" cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - special_light_key = "eyebotmed" + if("Heavy") + cyborg_base_icon = "heavymed" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + return ..() + +/obj/item/robot_module/janitor/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/list/janimodels = list("Default", "Sleek", "Marina", "Can", "Heavy") + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in janimodels + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "janitor" + if("Marina") + cyborg_base_icon = "marinajan" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Sleek") + cyborg_base_icon = "sleekjan" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "canjan" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavyres" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + return ..() + +/obj/item/robot_module/peacekeeper/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Spider") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Default") + cyborg_base_icon = "peace" + if("Spider") + cyborg_base_icon = "whitespider" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' return ..() /obj/item/robot_module/security/be_transformed_to(obj/item/robot_module/old_module) var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads", "Droid", "Spider") + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads", "Heavy", "Sleek", "Can", "Marina", "Spider") if(!borg_icon) return FALSE switch(borg_icon) @@ -211,19 +294,59 @@ cyborg_base_icon = "sec-tread" special_light_key = "sec" cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' - if("Droid") - cyborg_base_icon = "Security" - special_light_key = "service" - hat_offset = 0 + if("Sleek") + cyborg_base_icon = "sleeksec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinasec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "cansec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' if("Spider") cyborg_base_icon = "spidersec" - special_light_key = "spidersec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavysec" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + return ..() + +/obj/item/robot_module/butler/be_transformed_to(obj/item/robot_module/old_module) + var/mob/living/silicon/robot/R = loc + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Waitress", "Heavy", "Sleek", "Butler", "Tophat", "Kent", "Bro") + if(!borg_icon) + return FALSE + switch(borg_icon) + if("Waitress") + cyborg_base_icon = "service_f" + if("Butler") + cyborg_base_icon = "service_m" + if("Bro") + cyborg_base_icon = "brobot" + if("Kent") + cyborg_base_icon = "kent" + special_light_key = "medical" + hat_offset = 3 + if("Tophat") + cyborg_base_icon = "tophat" + special_light_key = null + hat_offset = INFINITY //He is already wearing a hat + if("Sleek") + cyborg_base_icon = "sleekserv" + special_light_key = "sleekserv" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavyserv" + special_light_key = "heavyserv" cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' return ..() /obj/item/robot_module/engineering/be_transformed_to(obj/item/robot_module/old_module) var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Default", "Default - Treads","Loader","Handy") + var/list/engymodels = list("Default", "Default - Treads", "Heavy", "Sleek", "Marina", "Can", "Spider", "Loader","Handy", "Pup Dozer") + if(R.client && R.client.ckey in list("nezuli")) + engymodels += "Alina" + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in engymodels if(!borg_icon) return FALSE switch(borg_icon) @@ -239,13 +362,44 @@ has_snowflake_deadsprite = TRUE if("Handy") cyborg_base_icon = "handyeng" - special_light_key = "handyeng" cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Sleek") + cyborg_base_icon = "sleekeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "caneng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinaeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Spider") + cyborg_base_icon = "spidereng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavyeng" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Pup Dozer") + cyborg_base_icon = "pupdozer" + can_be_pushed = FALSE + hat_offset = INFINITY + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 + if("Alina") + cyborg_base_icon = "alina-eng" + special_light_key = "alina" + can_be_pushed = FALSE + hat_offset = INFINITY + cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi' + has_snowflake_deadsprite = TRUE + dogborg = TRUE + cyborg_pixel_offset = -16 return ..() /obj/item/robot_module/miner/be_transformed_to(obj/item/robot_module/old_module) var/mob/living/silicon/robot/R = loc - var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Lavaland", "Asteroid", "Droid") + var/borg_icon = input(R, "Select an icon!", "Robot Icon", null) as null|anything in list("Lavaland", "Heavy", "Sleek", "Marina", "Can", "Spider", "Asteroid", "Droid") if(!borg_icon) return FALSE switch(borg_icon) @@ -258,4 +412,19 @@ cyborg_base_icon = "miner" cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' hat_offset = 4 + if("Sleek") + cyborg_base_icon = "sleekmin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Can") + cyborg_base_icon = "canmin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Marina") + cyborg_base_icon = "marinamin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Spider") + cyborg_base_icon = "spidermin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' + if("Heavy") + cyborg_base_icon = "heavymin" + cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi' return ..() diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm index 37dba85c40..598690590c 100644 --- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -23,3 +23,7 @@ for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory) selector.insert_witty_toggle_joke_here(src) return TRUE + +/mob/living/silicon/robot/proc/sprint_hotkey(targetstatus) + if(targetstatus ? !sprinting : sprinting) + togglesprint() diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm index 82de2d4113..10ab3901d9 100644 --- a/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm +++ b/modular_citadel/code/modules/projectiles/guns/ballistic/handguns.dm @@ -144,4 +144,4 @@ obj/item/projectile/bullet/c10mm/soporific icon_state = "raygun" desc = "A toy laser with a classic, retro feel and look. Compatible with existing laser tag systems." ammo_type = list(/obj/item/ammo_casing/energy/laser/raytag) - selfcharge = TRUE \ No newline at end of file + selfcharge = EGUN_SELFCHARGE \ No newline at end of file diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm index 5cca9138f3..017a9dd52d 100644 --- a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm +++ b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm @@ -456,7 +456,7 @@ obj_flags = 0 fire_delay = 40 weapon_weight = WEAPON_HEAVY - selfcharge = TRUE + selfcharge = EGUN_SELFCHARGE charge_delay = 2 recoil = 2 cell_type = /obj/item/stock_parts/cell/toymagburst diff --git a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm index bf07492acf..fa0e64032c 100644 --- a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm +++ b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm @@ -16,13 +16,20 @@ update_icon() /obj/item/gun/energy/pumpaction/process() //makes it not rack itself when self-charging - if(selfcharge) + if(selfcharge && cell?.charge < cell.maxcharge) charge_tick++ if(charge_tick < charge_delay) return charge_tick = 0 - if(!cell) - return + if(selfcharge == EGUN_SELFCHARGE_BORG) + var/atom/owner = loc + if(istype(owner, /obj/item/robot_module)) + owner = owner.loc + if(!iscyborg(owner)) + return + var/mob/living/silicon/robot/R = owner + if(!R.cell?.use(100)) + return cell.give(100) update_icon() diff --git a/modular_citadel/code/modules/projectiles/guns/toys.dm b/modular_citadel/code/modules/projectiles/guns/toys.dm index a90ea999a4..18d174d677 100644 --- a/modular_citadel/code/modules/projectiles/guns/toys.dm +++ b/modular_citadel/code/modules/projectiles/guns/toys.dm @@ -15,7 +15,7 @@ ammo_type = list(/obj/item/ammo_casing/energy/laser/dispersal, /obj/item/ammo_casing/energy/laser/wavemotion) ammo_x_offset = 2 modifystate = 1 - selfcharge = TRUE + selfcharge = EGUN_SELFCHARGE item_flags = NONE clumsy_check = FALSE diff --git a/modular_citadel/code/modules/research/designs/weapon_designs.dm b/modular_citadel/code/modules/research/designs/weapon_designs.dm index bdb77170ed..b27cedbcc2 100644 --- a/modular_citadel/code/modules/research/designs/weapon_designs.dm +++ b/modular_citadel/code/modules/research/designs/weapon_designs.dm @@ -1,7 +1,7 @@ /datum/design/mag_oldsmg/rubber_mag - name = "WT-550 Auto Gun rubberbullets Magazine (4.6x30mm rubber)" - desc = "A 20 round rubber shots magazine for the out of date security WT-550 Auto Rifle" + name = "WT-550 Semi-Auto SMG rubberbullets Magazine (4.6x30mm rubber)" + desc = "A 20 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG" id = "mag_oldsmg_rubber" materials = list(MAT_METAL = 6000) build_path = /obj/item/ammo_box/magazine/wt550m9/wtrubber - departmental_flags = DEPARTMENTAL_FLAG_SECURITY \ No newline at end of file + departmental_flags = DEPARTMENTAL_FLAG_SECURITY diff --git a/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm b/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm index 0db3bb9b1d..6246b9e24e 100644 --- a/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm +++ b/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm @@ -1,7 +1,7 @@ /datum/design/mag_oldsmg/tx_mag - name = "WT-550 Auto Gun Uranium Magazine (4.6x30mm TX)" - desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Auto Rifle" + name = "WT-550 Semi-Auto SMG Uranium Magazine (4.6x30mm TX)" + desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG." id = "mag_oldsmg_tx" materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_URANIUM = 2000) build_path = /obj/item/ammo_box/magazine/wt550m9/wttx - departmental_flags = DEPARTMENTAL_FLAG_SECURITY \ No newline at end of file + departmental_flags = DEPARTMENTAL_FLAG_SECURITY diff --git a/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm b/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm index 51b6e24736..8295f32cfa 100644 --- a/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm +++ b/modular_citadel/code/modules/vore/resizing/sizegun_vr.dm @@ -12,7 +12,7 @@ charge_cost = 100 projectile_type = /obj/item/projectile/beam/shrinklaser modifystate = "sizegun-shrink" - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE firemodes = list( list(mode_name = "grow", projectile_type = /obj/item/projectile/beam/growlaser, @@ -153,7 +153,7 @@ datum/design/sizeray desc = "Size manipulator using bluespace breakthroughs." item_state = null //so the human update icon uses the icon_state instead. ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray) - selfcharge = 1 + selfcharge = EGUN_SELFCHARGE charge_delay = 5 ammo_x_offset = 2 clumsy_check = 1 diff --git a/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi b/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi new file mode 100644 index 0000000000..7cf2c599ee Binary files /dev/null and b/modular_citadel/icons/mob/citadel_refs/mam_body_markings Matrixed Ref.dmi differ diff --git a/modular_citadel/icons/mob/mam_body_markings.dmi b/modular_citadel/icons/mob/mam_body_markings.dmi deleted file mode 100644 index 99f4d0624c..0000000000 Binary files a/modular_citadel/icons/mob/mam_body_markings.dmi and /dev/null differ diff --git a/modular_citadel/icons/mob/mam_ears.dmi b/modular_citadel/icons/mob/mam_ears.dmi index 51ffd28bbc..b3946b546c 100644 Binary files a/modular_citadel/icons/mob/mam_ears.dmi and b/modular_citadel/icons/mob/mam_ears.dmi differ diff --git a/modular_citadel/icons/mob/mam_markings.dmi b/modular_citadel/icons/mob/mam_markings.dmi new file mode 100644 index 0000000000..eb7fecb5fc Binary files /dev/null and b/modular_citadel/icons/mob/mam_markings.dmi differ diff --git a/modular_citadel/icons/mob/mam_snouts.dmi b/modular_citadel/icons/mob/mam_snouts.dmi index 98b62f929d..0bcfab6905 100644 Binary files a/modular_citadel/icons/mob/mam_snouts.dmi and b/modular_citadel/icons/mob/mam_snouts.dmi differ diff --git a/modular_citadel/icons/mob/mam_tails OLD.dmi b/modular_citadel/icons/mob/mam_tails OLD.dmi new file mode 100644 index 0000000000..7627b71b35 Binary files /dev/null and b/modular_citadel/icons/mob/mam_tails OLD.dmi differ diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi index 7627b71b35..8c97b869d6 100644 Binary files a/modular_citadel/icons/mob/mam_tails.dmi and b/modular_citadel/icons/mob/mam_tails.dmi differ diff --git a/modular_citadel/icons/mob/mam_taur.dmi b/modular_citadel/icons/mob/mam_taur.dmi index 5591636886..ebaa0123ae 100644 Binary files a/modular_citadel/icons/mob/mam_taur.dmi and b/modular_citadel/icons/mob/mam_taur.dmi differ diff --git a/modular_citadel/icons/mob/markings_notmammals.dmi b/modular_citadel/icons/mob/markings_notmammals.dmi new file mode 100644 index 0000000000..4161ea2cea Binary files /dev/null and b/modular_citadel/icons/mob/markings_notmammals.dmi differ diff --git a/modular_citadel/icons/mob/mutant_bodyparts.dmi b/modular_citadel/icons/mob/mutant_bodyparts.dmi index 7dcff09747..f369f21afb 100644 Binary files a/modular_citadel/icons/mob/mutant_bodyparts.dmi and b/modular_citadel/icons/mob/mutant_bodyparts.dmi differ diff --git a/modular_citadel/icons/mob/robots.dmi b/modular_citadel/icons/mob/robots.dmi index 230a01f4d4..b47ee12896 100644 Binary files a/modular_citadel/icons/mob/robots.dmi and b/modular_citadel/icons/mob/robots.dmi differ diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi index 2b192a1052..c730467e1d 100644 Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf index eca2dda112..39626ef912 100644 --- a/modular_citadel/interface/skin.dmf +++ b/modular_citadel/interface/skin.dmf @@ -287,3 +287,30 @@ window "statwindow" prefix-color = #ebebeb suffix-color = #ebebeb +window "preferences_window" + elem "preferences_window" + type = MAIN + pos = 372,0 + size = 1120x1000 + anchor1 = none + anchor2 = none + background-color = none + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + statusbar = false + elem "preferences_browser" + type = BROWSER + pos = -8,-8 + size = 896x1008 + anchor1 = 0,0 + anchor2 = 90,100 + background-color = none + saved-params = "" + elem "character_preview_map" + type = MAP + pos = 887,0 + size = 313x1000 + anchor1 = 90,0 + anchor2 = 100,100 + right-click = true + saved-params = "zoom;letterbox;zoom-mode" \ No newline at end of file diff --git a/modular_citadel/sound/voice/hiss.ogg b/modular_citadel/sound/voice/hiss.ogg new file mode 100644 index 0000000000..cd9fa22c37 Binary files /dev/null and b/modular_citadel/sound/voice/hiss.ogg differ diff --git a/modular_citadel/sound/voice/merowr.ogg b/modular_citadel/sound/voice/merowr.ogg new file mode 100644 index 0000000000..01fb993c61 Binary files /dev/null and b/modular_citadel/sound/voice/merowr.ogg differ diff --git a/modular_citadel/sound/voice/merp.ogg b/modular_citadel/sound/voice/merp.ogg new file mode 100644 index 0000000000..b40b7a365b Binary files /dev/null and b/modular_citadel/sound/voice/merp.ogg differ diff --git a/sound/effects/lingbloodhiss.ogg b/sound/effects/lingbloodhiss.ogg new file mode 100644 index 0000000000..31ebcf06bc Binary files /dev/null and b/sound/effects/lingbloodhiss.ogg differ diff --git a/sound/effects/lingempscreech.ogg b/sound/effects/lingempscreech.ogg new file mode 100644 index 0000000000..282d089107 Binary files /dev/null and b/sound/effects/lingempscreech.ogg differ diff --git a/sound/effects/lingreadapt.ogg b/sound/effects/lingreadapt.ogg new file mode 100644 index 0000000000..9ca98eb78c Binary files /dev/null and b/sound/effects/lingreadapt.ogg differ diff --git a/sound/effects/lingscreech.ogg b/sound/effects/lingscreech.ogg new file mode 100644 index 0000000000..9e05aa6b51 Binary files /dev/null and b/sound/effects/lingscreech.ogg differ diff --git a/sound/weapons/dink.ogg b/sound/weapons/dink.ogg new file mode 100644 index 0000000000..54f3678f79 Binary files /dev/null and b/sound/weapons/dink.ogg differ diff --git a/strings/sillytips.txt b/strings/sillytips.txt index f7c66b7407..bc59a109f0 100644 --- a/strings/sillytips.txt +++ b/strings/sillytips.txt @@ -44,3 +44,4 @@ As a Cargo Tech make sure to always buy a tesla to sell back to CC. They love th Help. Maints. BZ stops or slows down Lings chem regeneration drastically, make sure to BZ flood the station when lings are confirmed! +Admins always regret meme options in their polls. diff --git a/tgstation.dme b/tgstation.dme index 268d4f1ff9..c43b1a7019 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2528,10 +2528,15 @@ #include "code\modules\research\techweb\all_nodes.dm" #include "code\modules\research\xenobiology\xenobio_camera.dm" #include "code\modules\research\xenobiology\xenobiology.dm" -#include "code\modules\research\xenobiology\crossbreeding\_corecross.dm" +#include "code\modules\research\xenobiology\crossbreeding\__corecross.dm" +#include "code\modules\research\xenobiology\crossbreeding\_clothing.dm" +#include "code\modules\research\xenobiology\crossbreeding\_misc.dm" +#include "code\modules\research\xenobiology\crossbreeding\_mobs.dm" #include "code\modules\research\xenobiology\crossbreeding\_status_effects.dm" +#include "code\modules\research\xenobiology\crossbreeding\_weapons.dm" #include "code\modules\research\xenobiology\crossbreeding\burning.dm" #include "code\modules\research\xenobiology\crossbreeding\charged.dm" +#include "code\modules\research\xenobiology\crossbreeding\chilling.dm" #include "code\modules\research\xenobiology\crossbreeding\consuming.dm" #include "code\modules\research\xenobiology\crossbreeding\industrial.dm" #include "code\modules\research\xenobiology\crossbreeding\prismatic.dm" diff --git a/tools/HumanScissors/!README.txt b/tools/HumanScissors/!README.txt new file mode 100644 index 0000000000..d8396c8b85 --- /dev/null +++ b/tools/HumanScissors/!README.txt @@ -0,0 +1,7 @@ +This small Byond program takes all the icons in SpritesToSnip.dmi, +cuts them using all the icons in CookieCutter.dmi, and produces a file save +dialog for you to download the resulting DMI. + +Useful for cutting up species sprites from full body ones. Or whatever else. + +--Arokha/Aronai \ No newline at end of file diff --git a/tools/HumanScissors/CookieCutter.dmi b/tools/HumanScissors/CookieCutter.dmi new file mode 100644 index 0000000000..f0fcf87617 Binary files /dev/null and b/tools/HumanScissors/CookieCutter.dmi differ diff --git a/tools/HumanScissors/HumanScissors.dm b/tools/HumanScissors/HumanScissors.dm new file mode 100644 index 0000000000..28a9f804af --- /dev/null +++ b/tools/HumanScissors/HumanScissors.dm @@ -0,0 +1,56 @@ +/* + These are simple defaults for your project. + */ + +world + fps = 25 // 25 frames per second + icon_size = 32 // 32x32 icon size by default + + view = 6 // show up to 6 tiles outward from center (13x13 view) + + +// Make objects move 8 pixels per tick when walking +//usr << ftp(usr.working,"[usr.outfile].dmi") +mob + step_size = 8 + +obj + step_size = 8 + + + +client/verb/split_sprites() + set name = "Begin The Decimation" + set desc = "Loads SpritesToSnip.dmi and cuts them with CookieCutter.dmi" + set category = "Here" + + var/icon/SpritesToSnip = icon('SpritesToSnip.dmi') + var/icon/CookieCutter = icon('CookieCutter.dmi') + + var/icon/RunningOutput = new () + + //For each original project + for(var/OriginalState in icon_states(SpritesToSnip)) + //For each piece we're going to cut + for(var/CutterState in icon_states(CookieCutter)) + + //The fully assembled icon to cut + var/icon/Original = icon(SpritesToSnip,OriginalState) + + //Our cookie cutter sprite + var/icon/Cutter = icon(CookieCutter,CutterState) + + //We have to make these all black to cut with + Cutter.Blend(rgb(0,0,0),ICON_MULTIPLY) + + //Blend with AND to cut + Original.Blend(Cutter,ICON_AND) //AND, not ADD + + //Make a useful name + var/good_name = "[OriginalState]_[CutterState]" + + //Add to the output with the good name + RunningOutput.Insert(Original,good_name) + + //Give the output + usr << ftp(RunningOutput,"CutUpPeople.dmi") diff --git a/tools/HumanScissors/HumanScissors.dme b/tools/HumanScissors/HumanScissors.dme new file mode 100644 index 0000000000..86377f1c57 --- /dev/null +++ b/tools/HumanScissors/HumanScissors.dme @@ -0,0 +1,18 @@ +// DM Environment file for HumanScissors.dme. +// All manual changes should be made outside the BEGIN_ and END_ blocks. +// New source code should be placed in .dm files: choose File/New --> Code File. + +// BEGIN_INTERNALS +// END_INTERNALS + +// BEGIN_FILE_DIR +#define FILE_DIR . +// END_FILE_DIR + +// BEGIN_PREFERENCES +// END_PREFERENCES + +// BEGIN_INCLUDE +#include "HumanScissors.dm" +// END_INCLUDE + diff --git a/tools/HumanScissors/SpritesToSnip.dmi b/tools/HumanScissors/SpritesToSnip.dmi new file mode 100644 index 0000000000..f4dbfb6b81 Binary files /dev/null and b/tools/HumanScissors/SpritesToSnip.dmi differ