Merge remote-tracking branch 'citadel/master' into god_wish_your_plushies_holy_shit

This commit is contained in:
kevinz000
2020-01-20 17:53:06 -07:00
557 changed files with 7710 additions and 4481 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
/obj/screen/staminas/Click(location,control,params)
if(isliving(usr))
var/mob/living/L = usr
to_chat(L, "<span class='notice'>You have <b>[L.getStaminaLoss()]</b> stamina loss.<br>Your stamina buffer can take <b>[L.stambuffer]</b> stamina loss, and will use <b>50%</b> of that stamina loss when recharging.<br>Your stamina buffer is <b>[(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]%</b> full.</span>")
to_chat(L, "<span class='notice'>You have <b>[L.getStaminaLoss()]</b> stamina loss.<br>Your stamina buffer can take <b>[L.stambuffer]</b> stamina loss, and recharges at no cost.<br>Your stamina buffer is <b>[(L.stambuffer*(100/L.stambuffer))-(L.bufferedstam*(100/L.stambuffer))]%</b> full.</span>")
/obj/screen/staminas/update_icon_state()
var/mob/living/carbon/user = hud?.mymob
@@ -268,10 +268,6 @@
RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist) //Do resistance calc if resist is pressed#
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/owner_hear)
mental_capacity = 500 - M.getOrganLoss(ORGAN_SLOT_BRAIN)//It's their brain!
var/mob/living/carbon/human/H = owner
if(H)//Prefs
if(!H.canbearoused)
H.client?.prefs.cit_toggles &= ~HYPNO
lewd = (owner.client?.prefs.cit_toggles & HYPNO) && (master.client?.prefs.cit_toggles & HYPNO)
var/message = "[(lewd ? "I am a good pet for [enthrallGender]." : "[master] is a really inspirational person!")]"
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "enthrall", /datum/mood_event/enthrall, message)
@@ -625,8 +621,6 @@
//Speak (Forces player to talk)
if (lowertext(customTriggers[trigger][1]) == "speak")//trigger2
var/saytext = "Your mouth moves on it's own before you can even catch it."
if(HAS_TRAIT(C, TRAIT_NYMPHO))
saytext += " You find yourself fully believing in the validity of what you just said and don't think to question it."
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='notice'><i>[saytext]</i></span>"), 5)
addtimer(CALLBACK(C, /atom/movable/proc/say, "[customTriggers[trigger][2]]"), 5)
log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been forced to say: \"[customTriggers[trigger][2]]\" from previous trigger.")
@@ -639,8 +633,9 @@
//Shocking truth!
else if (lowertext(customTriggers[trigger]) == "shock")
if (C.canbearoused && lewd)
C.adjustArousalLoss(5)
if (lewd && ishuman(C))
var/mob/living/carbon/human/H = C
H.adjust_arousal(5)
C.jitteriness += 100
C.stuttering += 25
C.Knockdown(60)
@@ -649,13 +644,11 @@
//wah intensifies wah-rks
else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
if (HAS_TRAIT(C, TRAIT_NYMPHO) && lewd)
if (C.getArousalLoss() > 80)
C.mob_climax(forced_climax=TRUE)
C.SetStun(10)//We got your stun effects in somewhere, Kev.
else
C.adjustArousalLoss(10)
to_chat(C, "<span class='love'><i>You feel a surge of arousal!</i></span>")
if (lewd)
if(ishuman(C))
var/mob/living/carbon/human/H = C
H.mob_climax(forced_climax=TRUE)
C.SetStun(10)//We got your stun effects in somewhere, Kev.
else
C.throw_at(get_step_towards(hearing_args[HEARING_SPEAKER],C), 3, 1) //cut this if it's too hard to get working
@@ -734,16 +727,13 @@
if(prob(5))
M.emote("me",1,"squints, shaking their head for a moment.")//shows that you're trying to resist sometimes
deltaResist *= 1.5
//nymphomania
if (M.canbearoused && HAS_TRAIT(M, TRAIT_NYMPHO))//I'm okay with this being removed.
deltaResist*= 0.5-(((2/200)*M.arousalloss)/1)//more aroused you are, the weaker resistance you can give, the less you are, the more you gain. (+/- 0.5)
//chemical resistance, brain and annaphros are the key to undoing, but the subject has to to be willing to resist.
if (owner.reagents.has_reagent(/datum/reagent/medicine/mannitol))
deltaResist *= 1.25
if (owner.reagents.has_reagent(/datum/reagent/medicine/neurine))
deltaResist *= 1.5
if (!(owner.client?.prefs.cit_toggles & NO_APHRO) && M.canbearoused && lewd)
if (!(owner.client?.prefs.cit_toggles & NO_APHRO) && lewd)
if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiac))
deltaResist *= 1.5
if (owner.reagents.has_reagent(/datum/reagent/drug/anaphrodisiacplus))
@@ -1,7 +0,0 @@
/obj/effect/spawner/lootdrop/keg
name = "random keg spawner"
lootcount = 1
loot = list(/obj/structure/reagent_dispensers/keg/mead = 5,
/obj/structure/reagent_dispensers/keg/aphro = 2,
/obj/structure/reagent_dispensers/keg/aphro/strong = 2,
/obj/structure/reagent_dispensers/keg/gargle = 1)
@@ -1,15 +0,0 @@
/obj/item
var/list/alternate_screams = list() //REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
// lazy for screaming.
/obj/item/clothing/head/xenos
alternate_screams = list('sound/voice/hiss6.ogg')
/obj/item/clothing/head/cardborg
alternate_screams = list('modular_citadel/sound/voice/scream_silicon.ogg')
/obj/item/clothing/head/ushanka
alternate_screams = list('sound/voice/human/cyka1.ogg', 'sound/voice/human/cheekibreeki.ogg')
/obj/item/proc/grenade_prime_react(obj/item/grenade/nade)
return
@@ -1,92 +0,0 @@
/* BALLS - GLORIOUS BALLS
//
// Includes:-
// 1) Tennis balls, lines 10 - 92
//
//
//
*/
/obj/item/toy/tennis
name = "tennis ball"
desc = "A classical tennis ball. It appears to have faint bite marks scattered all over its surface."
icon = 'modular_citadel/icons/obj/balls.dmi'
icon_state = "tennis_classic"
lefthand_file = 'modular_citadel/icons/mob/inhands/balls_left.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/balls_right.dmi'
item_state = "tennis_classic"
alternate_worn_icon = 'modular_citadel/icons/mob/mouthball.dmi'
slot_flags = ITEM_SLOT_HEAD | ITEM_SLOT_NECK | ITEM_SLOT_EARS //Fluff item, put it wherever you want!
throw_range = 14
w_class = WEIGHT_CLASS_SMALL
/obj/item/toy/tennis/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
altafterattack(A, user, TRUE, params)
return TRUE
/obj/item/toy/tennis/altafterattack(atom/target, mob/living/carbon/user, proximity_flag, click_parameters) //does right click memes
if(istype(user))
user.visible_message("<span class='notice'>[user] waggles [src] at [target].</span>", "<span class='notice'>You waggle [src] at [target].</span>")
return TRUE
/obj/item/toy/tennis/rainbow
name = "pseudo-euclidean interdimensional tennis sphere"
desc = "A tennis ball from another plane of existance. Really groovy."
icon_state = "tennis_rainbow"
item_state = "tennis_rainbow"
actions_types = list(/datum/action/item_action/squeeze) //Giving the masses easy access to unilimted honks would be annoying
/obj/item/toy/tennis/rainbow/Initialize()
. = ..()
AddComponent(/datum/component/squeak)
/obj/item/toy/tennis/rainbow/izzy //izzyinbox's donator item
name = "Katlin's Ball"
desc = "A tennis ball that's seen a good bit of love, being covered in a few black and white hairs and slobber."
icon_state = "tennis_izzy"
item_state = "tennis_izzy"
/obj/item/toy/tennis/red //da red wuns go fasta
name = "red tennis ball"
desc = "A red tennis ball. It goes three times faster!"
icon_state = "tennis_red"
item_state = "tennis_red"
throw_speed = 9
/obj/item/toy/tennis/yellow //because yellow is hot I guess
name = "yellow tennis ball"
desc = "A yellow tennis ball. It seems to have a flame-retardant coating."
icon_state = "tennis_yellow"
item_state = "tennis_yellow"
resistance_flags = FIRE_PROOF
/obj/item/toy/tennis/green //pestilence
name = "green tennis ball"
desc = "A green tennis ball. It seems to have an impermeable coating."
icon_state = "tennis_green"
item_state = "tennis_green"
permeability_coefficient = 0.9
/obj/item/toy/tennis/cyan //electric
name = "cyan tennis ball"
desc = "A cyan tennis ball. It seems to have odd electrical properties."
icon_state = "tennis_cyan"
item_state = "tennis_cyan"
siemens_coefficient = 0.9
/obj/item/toy/tennis/blue //reliability
name = "blue tennis ball"
desc = "A blue tennis ball. It seems ever so slightly more robust than normal."
icon_state = "tennis_blue"
item_state = "tennis_blue"
max_integrity = 300
/obj/item/toy/tennis/purple //because purple dyes have high pH and would neutralize acids I guess
name = "purple tennis ball"
desc = "A purple tennis ball. It seems to have an acid-resistant coating."
icon_state = "tennis_purple"
item_state = "tennis_purple"
resistance_flags = ACID_PROOF
/datum/action/item_action/squeeze
name = "Squeak!"
@@ -1,61 +0,0 @@
/obj/item/boombox
name = "boombox"
desc = "A dusty, gray, bulky, battery-powered, auto-looping stereo cassette player. An ancient relic from prehistoric times on that one planet with humans and stuff. Yeah, that one."
icon = 'modular_citadel/icons/obj/boombox.dmi'
icon_state = "raiqbawks_off"//PLACEHOLDER UNTIL SOMEONE SPRITES PLAIN NON-FANCY BOOMBOXES
w_class = WEIGHT_CLASS_NORMAL
force = 3
var/baseiconstate = "raiqbawks"
var/boomingandboxing = FALSE
var/list/availabletrackids
/obj/item/boombox/attack_self(mob/user)
. = ..()
if(boomingandboxing)
SSjukeboxes.removejukebox(SSjukeboxes.findjukeboxindex(src))
boomingandboxing = FALSE
to_chat(user, "<span class='notice'>You flip a switch on [src], and the music immediately stops.")
update_icon()
return
if(!availabletrackids || !availabletrackids.len)
to_chat(user, "<span class='notice'>[src] flashes as you prod it senselessly. It doesn't have any songs stored on it.</span>")
return
if(!boomingandboxing)
var/list/tracklist = list()
for(var/datum/track/S in SSjukeboxes.songs)
if(istype(S) && S.song_associated_id in availabletrackids)
tracklist[S.song_name] = S
var/selected = input(user, "Play song", "Track:") as null|anything in tracklist
if(QDELETED(src) || !selected || !istype(tracklist[selected], /datum/track))
return
var/jukeboxslottotake = SSjukeboxes.addjukebox(src, tracklist[selected])
if(jukeboxslottotake)
boomingandboxing = TRUE
update_icon()
/obj/item/boombox/Destroy(mob/user)
SSjukeboxes.removejukebox(SSjukeboxes.findjukeboxindex(src))
. = ..()
/obj/item/boombox/update_icon()
icon_state = "[baseiconstate]_[boomingandboxing ? "on" : "off"]"
return
/obj/item/boombox/raiq
name = "Miami Boomer"
desc = "A shiny, fashionable boombox filled to the brim with neon lights, synthesizers, gang violence, and broken R keys. A worn-out sticker on the back states \"Includes three kickin' beats!\""
icon_state = "raiqbawks_off"
baseiconstate = "raiqbawks"
availabletrackids = list("hotline.ogg","chiptune.ogg","genesis.ogg")
/obj/item/boombox/raiq/update_icon()
. = ..()
if(boomingandboxing)
START_PROCESSING(SSobj, src)
else
STOP_PROCESSING(SSobj, src)
set_light(0)
/obj/item/boombox/raiq/process()
set_light(5,0.95,pick("#d87aff","#7a7aff","#89ecff","#b88eff","#ff59ad"))
return
@@ -1,10 +0,0 @@
/obj/item/encryptionkey/heads/qm
name = "\proper the quartermaster's encryption key"
desc = "An encryption key for a radio headset. Channels are as follows: :u - supply, :c - command."
icon_state = "hop_cypherkey"
channels = list("Supply" = 1, "Command" = 1)
/obj/item/encryptionkey/heads/hop
desc = "An encryption key for a radio headset. Channels are as follows: :v - service, :c - command."
channels = list("Service" = 1, "Command" = 1)
@@ -1,10 +0,0 @@
/obj/item/radio/headset/heads/qm
name = "\proper the quartermaster's headset"
desc = "The headset of the king (or queen) of paperwork.\nChannels are as follows: :u - supply, :c - command."
icon_state = "com_headset"
keyslot = new /obj/item/encryptionkey/heads/qm
/obj/item/radio/headset/heads/hop
desc = "The headset of the guy who will one day be captain.\nChannels are as follows: :v - service, :c - command."
keyslot = new /obj/item/encryptionkey/heads/hop
@@ -1,77 +0,0 @@
/obj/item/electropack/shockcollar
name = "shock collar"
desc = "A reinforced metal collar. It seems to have some form of wiring near the front. Strange.."
icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/neck.dmi'
icon_state = "shockcollar"
item_state = "shockcollar"
body_parts_covered = NECK
slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers
w_class = WEIGHT_CLASS_SMALL
strip_delay = 60
equip_delay_other = 60
materials = list(MAT_METAL=5000, MAT_GLASS=2000)
var/tagname = null
/datum/design/electropack/shockcollar
name = "Shockcollar"
id = "shockcollar"
build_type = AUTOLATHE
build_path = /obj/item/electropack/shockcollar
materials = list(MAT_METAL=5000, MAT_GLASS=2000)
category = list("hacked", "Misc")
/obj/item/electropack/shockcollar/attack_hand(mob/user)
if(loc == user && user.get_item_by_slot(SLOT_NECK))
to_chat(user, "<span class='warning'>The collar is fastened tight! You'll need help taking this off!</span>")
return
return ..()
/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal)
if(!signal || signal.data["code"] != code)
return
if(isliving(loc) && on)
if(shock_cooldown == TRUE)
return
shock_cooldown = TRUE
addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100)
var/mob/living/L = loc
step(L, pick(GLOB.cardinals))
to_chat(L, "<span class='danger'>You feel a sharp shock from the collar!</span>")
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, L)
s.start()
L.Knockdown(100)
if(master)
master.receive_signal()
return
/obj/item/electropack/shockcollar/attackby(obj/item/W, mob/user, params) //moves it here because on_click is being bad
if(istype(W, /obj/item/pen))
var/t = input(user, "Would you like to change the name on the tag?", "Name your new pet", tagname ? tagname : "Spot") as null|text
if(t)
tagname = copytext(sanitize(t), 1, MAX_NAME_LEN)
name = "[initial(name)] - [tagname]"
else
return ..()
/obj/item/electropack/shockcollar/ui_interact(mob/user) //on_click calls this
var/dat = {"
<TT>
<B>Frequency/Code</B> for shock collar:<BR>
Frequency:
[format_frequency(src.frequency)]
<A href='byond://?src=[REF(src)];set=freq'>Set</A><BR>
Code:
[src.code]
<A href='byond://?src=[REF(src)];set=code'>Set</A><BR>
</TT>"}
user << browse(dat, "window=radio")
onclose(user, "radio")
return
@@ -1,41 +0,0 @@
/obj/item/melee/baton/stunsword
name = "stunsword"
desc = "not actually sharp, this sword is functionally identical to a stunbaton"
icon = 'modular_citadel/icons/obj/stunsword.dmi'
icon_state = "stunsword"
item_state = "sword"
lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
/obj/item/melee/baton/stunsword/get_belt_overlay()
if(istype(loc, /obj/item/storage/belt/sabre))
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "stunsword")
return ..()
/obj/item/melee/baton/stunsword/get_worn_belt_overlay(icon_file)
return mutable_appearance(icon_file, "-stunsword")
/obj/item/ssword_kit
name = "stunsword kit"
desc = "a modkit for making a stunbaton into a stunsword"
icon = 'icons/obj/vending_restock.dmi'
icon_state = "refill_donksoft"
var/product = /obj/item/melee/baton/stunsword //what it makes
var/list/fromitem = list(/obj/item/melee/baton, /obj/item/melee/baton/loaded) //what it needs
afterattack(obj/O, mob/user as mob)
if(istype(O, product))
to_chat(user,"<span class='warning'>[O] is already modified!")
else if(O.type in fromitem) //makes sure O is the right thing
var/obj/item/melee/baton/B = O
if(!B.cell) //checks for a powercell in the baton. If there isn't one, continue. If there is, warn the user to take it out
new product(usr.loc) //spawns the product
user.visible_message("<span class='warning'>[user] modifies [O]!","<span class='warning'>You modify the [O]!")
qdel(O) //Gets rid of the baton
qdel(src) //gets rid of the kit
else
to_chat(user,"<span class='warning'>Remove the powercell first!</span>") //We make this check because the stunsword starts without a battery.
else
to_chat(user, "<span class='warning'> You can't modify [O] with this kit!</span>")
-5
View File
@@ -1,5 +0,0 @@
//init file stolen from hippie
/proc/cit_initialize()
load_mentors()
initialize_global_loadout_items()
@@ -1,39 +0,0 @@
/client/proc/citaPPoptions(mob/M) // why is this client and not /datum/admins? noone knows, in PP src == client, instead of holder. wtf.
var/body = "<br>"
if(M.client)
body += "<A href='?_src_=holder;[HrefToken()];makementor=[M.ckey]'>Make mentor</A> | "
body += "<A href='?_src_=holder;[HrefToken()];removementor=[M.ckey]'>Remove mentor</A>"
return body
/client/proc/cmd_admin_man_up(mob/M in GLOB.mob_list)
set category = "Special Verbs"
set name = "Man Up"
if(!M)
return
if(!check_rights(R_ADMIN))
return
to_chat(M, "<span class='warning bold reallybig'>Man up, and deal with it.</span><br><span class='warning big'>Move on.</span>")
M.playsound_local(M, 'sound/voice/manup.ogg', 50, FALSE, pressure_affected = FALSE)
log_admin("Man up: [key_name(usr)] told [key_name(M)] to man up")
var/message = "<span class='adminnotice'>[key_name_admin(usr)] told [key_name_admin(M)] to man up.</span>"
message_admins(message)
admin_ticket_log(M, message)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up")
/client/proc/cmd_admin_man_up_global()
set category = "Special Verbs"
set name = "Man Up Global"
if(!check_rights(R_ADMIN))
return
to_chat(world, "<span class='warning bold reallybig'>Man up, and deal with it.</span><br><span class='warning big'>Move on.</span>")
for(var/mob/M in GLOB.player_list)
M.playsound_local(M, 'sound/voice/manup.ogg', 50, FALSE, pressure_affected = FALSE)
log_admin("Man up global: [key_name(usr)] told everybody to man up")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] told everybody to man up.</span>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up Global")
@@ -1,59 +0,0 @@
/datum/admins/proc/citaTopic(href, href_list)
if(href_list["makementor"])
makeMentor(href_list["makementor"])
else if(href_list["removementor"])
removeMentor(href_list["removementor"])
/datum/admins/proc/makeMentor(ckey)
if(!usr.client)
return
if (!check_rights(0))
return
if(!ckey)
return
var/client/C = GLOB.directory[ckey]
if(C)
if(check_rights_for(C, R_ADMIN,0))
to_chat(usr, "<span class='danger'>The client chosen is an admin! Cannot mentorize.</span>")
return
if(SSdbcore.Connect())
var/datum/DBQuery/query_get_mentor = SSdbcore.NewQuery("SELECT id FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
if(query_get_mentor.NextRow())
to_chat(usr, "<span class='danger'>[ckey] is already a mentor.</span>")
return
var/datum/DBQuery/query_add_mentor = SSdbcore.NewQuery("INSERT INTO `[format_table_name("mentor")]` (`id`, `ckey`) VALUES (null, '[ckey]')")
if(!query_add_mentor.warn_execute())
return
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new mentor [ckey]');")
if(!query_add_admin_log.warn_execute())
return
else
to_chat(usr, "<span class='danger'>Failed to establish database connection. The changes will last only for the current round.</span>")
new /datum/mentors(ckey)
to_chat(usr, "<span class='adminnotice'>New mentor added.</span>")
/datum/admins/proc/removeMentor(ckey)
if(!usr.client)
return
if (!check_rights(0))
return
if(!ckey)
return
var/client/C = GLOB.directory[ckey]
if(C)
if(check_rights_for(C, R_ADMIN,0))
to_chat(usr, "<span class='danger'>The client chosen is an admin, not a mentor! Cannot de-mentorize.</span>")
return
C.remove_mentor_verbs()
C.mentor_datum = null
GLOB.mentors -= C
if(SSdbcore.Connect())
var/datum/DBQuery/query_remove_mentor = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
if(!query_remove_mentor.warn_execute())
return
var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed mentor [ckey]');")
if(!query_add_admin_log.warn_execute())
return
else
to_chat(usr, "<span class='danger'>Failed to establish database connection. The changes will last only for the current round.</span>")
to_chat(usr, "<span class='adminnotice'>Mentor removed.</span>")
+44 -204
View File
@@ -1,17 +1,8 @@
//Mob vars
/mob/living
var/arousalloss = 0 //How aroused the mob is.
var/min_arousal = AROUSAL_MINIMUM_DEFAULT //The lowest this mobs arousal will get. default = 0
var/max_arousal = AROUSAL_MAXIMUM_DEFAULT //The highest this mobs arousal will get. default = 100
var/arousal_rate = AROUSAL_START_VALUE //The base rate that arousal will increase in this mob.
var/arousal_loss_rate = AROUSAL_START_VALUE //How easily arousal can be relieved for this mob.
var/canbearoused = FALSE //Mob-level disabler for arousal. Starts off and can be enabled as features are added for different mob types.
var/mb_cd_length = 5 SECONDS //5 second cooldown for masturbating because fuck spam.
var/mb_cd_timer = 0 //The timer itself
/mob/living/carbon/human
canbearoused = TRUE
var/saved_underwear = ""//saves their underwear so it can be toggled later
var/saved_undershirt = ""
var/saved_socks = ""
@@ -21,8 +12,6 @@
//Species vars
/datum/species
var/arousal_gain_rate = AROUSAL_START_VALUE //Rate at which this species becomes aroused
var/arousal_lose_rate = AROUSAL_START_VALUE //Multiplier for how easily arousal can be relieved
var/list/cum_fluids = list("semen")
var/list/milk_fluids = list("milk")
var/list/femcum_fluids = list("femcum")
@@ -52,130 +41,26 @@
update_body()
/mob/living/proc/handle_arousal(times_fired)
return
/mob/living/carbon/handle_arousal(times_fired)
if(!canbearoused || !dna)
return
var/datum/species/S = dna.species
if(!S || (times_fired % 36) || !getArousalLoss() >= max_arousal)//Totally stolen from breathing code. Do this every 36 ticks.
return
var/our_loss = arousal_rate * S.arousal_gain_rate
if(HAS_TRAIT(src, TRAIT_EXHIBITIONIST) && client)
var/amt_nude = 0
/mob/living/carbon/human/proc/adjust_arousal(strength,aphro = FALSE,maso = FALSE) // returns all genitals that were adjust
var/list/obj/item/organ/genital/genit_list = list()
if(!client?.prefs.arousable || (aphro && (client?.prefs.cit_toggles & NO_APHRO)) || (maso && !HAS_TRAIT(src, TRAIT_MASO)))
return // no adjusting made here
if(strength>0)
for(var/obj/item/organ/genital/G in internal_organs)
if(G.is_exposed())
amt_nude++
if(amt_nude)
var/watchers = 0
for(var/mob/living/L in view(src))
if(L.client && !L.stat && !L.eye_blind && (src in view(L)))
watchers++
if(watchers)
our_loss += (amt_nude * watchers) + S.arousal_gain_rate
adjustArousalLoss(our_loss)
/mob/living/proc/getArousalLoss()
return arousalloss
/mob/living/proc/adjustArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return FALSE
arousalloss = CLAMP(arousalloss + amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/setArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return FALSE
arousalloss = CLAMP(amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/getPercentAroused()
var/percentage = ((100 / max_arousal) * arousalloss)
return percentage
/mob/living/proc/isPercentAroused(percentage)//returns true if the mob's arousal (measured in a percent of 100) is greater than the arg percentage.
if(!isnum(percentage) || percentage > 100 || percentage < 0)
CRASH("Provided percentage is invalid")
if(getPercentAroused() >= percentage)
return TRUE
return FALSE
//H U D//
/mob/living/proc/updatearousal()
update_arousal_hud()
/mob/living/carbon/updatearousal()
. = ..()
for(var/obj/item/organ/genital/G in internal_organs)
if(istype(G))
var/datum/sprite_accessory/S
switch(G.type)
if(/obj/item/organ/genital/penis)
S = GLOB.cock_shapes_list[G.shape]
if(/obj/item/organ/genital/testicles)
S = GLOB.balls_shapes_list[G.shape]
if(/obj/item/organ/genital/vagina)
S = GLOB.vagina_shapes_list[G.shape]
if(/obj/item/organ/genital/breasts)
S = GLOB.breasts_shapes_list[G.shape]
if(S?.alt_aroused)
G.aroused_state = isPercentAroused(G.aroused_amount)
else
G.aroused_state = FALSE
G.update_appearance()
/mob/living/proc/update_arousal_hud()
return FALSE
/mob/living/carbon/human/update_arousal_hud()
if(!client || !(hud_used?.arousal))
return FALSE
if(!canbearoused)
hud_used.arousal.icon_state = ""
return FALSE
if(!G.aroused_state && prob(strength*G.sensitivity))
G.set_aroused_state(TRUE)
G.update_appearance()
if(G.aroused_state)
genit_list += G
else
var/value = FLOOR(getPercentAroused(), 10)
hud_used.arousal.icon_state = "arousal[value]"
return TRUE
/obj/screen/arousal
name = "arousal"
icon_state = "arousal0"
icon = 'modular_citadel/icons/obj/genitals/hud.dmi'
screen_loc = ui_arousal
/obj/screen/arousal/Click()
if(!isliving(usr))
return FALSE
var/mob/living/M = usr
if(M.canbearoused)
M.mob_climax()
return TRUE
else
to_chat(M, "<span class='warning'>Arousal is disabled. Feature is unavailable.</span>")
/mob/living/proc/mob_climax(forced_climax = FALSE)//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while.
set name = "Masturbate"
set category = "IC"
if(canbearoused && !restrained() && !stat)
if(mb_cd_timer <= world.time)
//start the cooldown even if it fails
mb_cd_timer = world.time + mb_cd_length
if(getArousalLoss() >= 33)//one third of average max_arousal or greater required
visible_message("<span class='danger'>[src] starts masturbating!</span>", \
"<span class='userdanger'>You start masturbating.</span>")
if(do_after(src, 30, target = src))
visible_message("<span class='danger'>[src] relieves [p_them()]self!</span>", \
"<span class='userdanger'>You have relieved yourself.</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
setArousalLoss(min_arousal)
else
to_chat(src, "<span class='notice'>You aren't aroused enough for that.</span>")
for(var/obj/item/organ/genital/G in internal_organs)
if(G.aroused_state && prob(strength*G.sensitivity))
G.set_aroused_state(FALSE)
G.update_appearance()
if(G.aroused_state)
genit_list += G
return genit_list
/obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found.
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
@@ -189,48 +74,25 @@
/mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE)
if(!G)
return
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
setArousalLoss(min_arousal)
if(!target || !R)
return
var/turfing = isturf(target)
if(spill & R.total_volume >= 5)
if(spill && R.total_volume >= 5)
R.reaction(turfing ? target : target.loc, TOUCH, 1, 0)
if(!turfing)
R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1))
R.clear_reagents()
//These are various procs that we'll use later, split up for readability instead of having one, huge proc.
//For all of these, we assume the arguments given are proper and have been checked beforehand.
/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
return
var/obj/item/organ/genital/PP = CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) ? G.linked_organ : G
if(!PP)
to_chat(src, "<span class='warning'>You shudder, unable to cum with your [name].</span>")
if(mb_time)
visible_message("<span class='love'>[src] starts to [G.masturbation_verb] [p_their()] [G.name].</span>", \
"<span class='userlove'>You start to [G.masturbation_verb] your [G.name].</span>")
if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
return
visible_message("<span class='love'>[src] orgasms, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with [p_their()] [PP.name]!</span>", \
"<span class='userlove'>You orgasm, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with your [PP.name].</span>")
do_climax(fluid_source, loc, G)
/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
var/datum/reagents/fluid_source = G.climaxable(src, TRUE)
if(!fluid_source)
visible_message("<span class='danger'>[src] shudders, their [G.name] unable to cum.</span>", \
"<span class='userdanger'>Your [G.name] cannot cum, giving no relief.</span>")
to_chat(src,"<span class='userdanger'>Your [G.name] cannot cum.</span>")
return
if(mb_time) //as long as it's not instant, give a warning
visible_message("<span class='love'>[src] looks like they're about to cum.</span>", \
"<span class='userlove'>You feel yourself about to orgasm.</span>")
to_chat(src,"<span class='userlove'>You feel yourself about to orgasm.</span>")
if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
return
visible_message("<span class='love'>[src] orgasms[isturf(loc) ? " onto [loc]" : ""], using [p_their()] [G.name]!</span>", \
"<span class='userlove'>You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].</span>")
to_chat(src,"<span class='userlove'>You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].</span>")
do_climax(fluid_source, loc, G)
/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
@@ -238,48 +100,30 @@
if(!fluid_source)
return
if(mb_time) //Skip warning if this is an instant climax.
visible_message("<span class='love'>[src] is about to climax with [L]!</span>", \
"<span class='userlove'>You're about to climax with [L]!</span>")
to_chat(src,"<span class='userlove'>You're about to climax with [L]!</span>")
to_chat(L,"<span class='userlove'>[src] is about to climax with you!</span>")
if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE))
return
if(spillage)
visible_message("<span class='love'>[src] climaxes with [L], overflowing and spilling, using [p_their()] [G.name]!</span>", \
"<span class='userlove'>You orgasm with [L], spilling out of them, using your [G.name].</span>")
to_chat(src,"<span class='userlove'>You orgasm with [L], spilling out of them, using your [G.name].</span>")
to_chat(L,"<span class='userlove'>[src] climaxes with you, overflowing and spilling, using [p_their()] [G.name]!</span>")
else //knots and other non-spilling orgasms
visible_message("<span class='love'>[src] climaxes with [L], [p_their()] [G.name] spilling nothing!</span>", \
"<span class='userlove'>You ejaculate with [L], your [G.name] spilling nothing.</span>")
to_chat(src,"<span class='userlove'>You climax with [L], your [G.name] spilling nothing.</span>")
to_chat(L,"<span class='userlove'>[src] climaxes with you, [p_their()] [G.name] spilling nothing!</span>")
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
do_climax(fluid_source, spillage ? loc : L, G, spillage)
/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
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
return
if(mb_time)
visible_message("<span class='love'>[src] starts to [G.masturbation_verb] their [G.name] over [container].</span>", \
"<span class='userlove'>You start to [G.masturbation_verb] your [G.name] over [container].</span>")
to_chat(src,"<span class='userlove'>You start to [G.masturbation_verb] your [G.name] over [container].</span>")
if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE))
return
visible_message("<span class='love'>[src] uses [p_their()] [G.name] to fill [container]!</span>", \
"<span class='userlove'>You used your [G.name] to fill [container].</span>")
to_chat(src,"<span class='userlove'>You used your [G.name] to fill [container].</span>")
do_climax(fluid_source, container, G, FALSE)
/mob/living/carbon/human/proc/pick_masturbate_genitals(silent = FALSE)
var/list/genitals_list
var/list/worn_stuff = get_equipped_items()
for(var/obj/item/organ/genital/G in internal_organs)
if(CHECK_BITFIELD(G.genital_flags, CAN_MASTURBATE_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with
if(CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) && !G.linked_organ)
continue
LAZYADD(genitals_list, G)
if(LAZYLEN(genitals_list))
var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list
return ret_organ
else if(!silent)
to_chat(src, "<span class='warning'>You cannot masturbate without available genitals.</span>")
/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE)
var/list/genitals_list
var/list/worn_stuff = get_equipped_items()
@@ -301,6 +145,8 @@
partners += pulledby
//Now we got both of them, let's check if they're proper
for(var/mob/living/L in partners)
if(!L.client || !L.mind) // can't consent, not a partner
partners -= L
if(iscarbon(L))
var/mob/living/carbon/C = L
if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed()) //Nothing through_clothing, no proper partner.
@@ -312,7 +158,9 @@
return //No one left.
var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null
if(target && in_range(src, target))
return target
var/consenting = input(target, "Do you want [src] to climax with you?","Climax mechanics","No") in list("Yes","No")
if(consenting == "Yes")
return target
/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE)
var/list/containers_list = list()
@@ -349,13 +197,13 @@
return TRUE
//Here's the main proc itself
/mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
/mob/living/carbon/human/proc/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
if(mb_cd_timer > world.time)
if(!forced_climax) //Don't spam the message to the victim if forced to come too fast
to_chat(src, "<span class='warning'>You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!</span>")
return
if(!canbearoused || !has_dna())
if(!client?.prefs.arousable || !has_dna())
return
if(stat == DEAD)
if(!forced_climax)
@@ -398,32 +246,19 @@
if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious.
to_chat(src, "<span class='warning'>You must be conscious to do that!</span>")
return
if(getArousalLoss() < 33) //flat number instead of percentage
to_chat(src, "<span class='warning'>You aren't aroused enough for that!</span>")
return
//Ok, now we check what they want to do.
var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Masturbate", "Climax alone", "Climax with partner", "Fill container")
var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Climax alone","Climax with partner", "Fill container")
if(!choice)
return
switch(choice)
if("Masturbate")
if(!available_rosie_palms())
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ = pick_masturbate_genitals()
if(picked_organ && available_rosie_palms(TRUE))
mob_masturbate(picked_organ)
return
if("Climax alone")
if(!available_rosie_palms())
return
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
if(picked_organ && available_rosie_palms(TRUE))
mob_climax_outside(picked_organ)
if("Climax with partner")
//We need no hands, we can be restrained and so on, so let's pick an organ
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
@@ -433,7 +268,6 @@
var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No")
if(spillage && in_range(src, partner))
mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE)
if("Fill container")
//We'll need hands and no restraints.
if(!available_rosie_palms(FALSE, /obj/item/reagent_containers))
@@ -447,4 +281,10 @@
if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers))
mob_fill_container(picked_organ, fluid_container)
mb_cd_timer = world.time + mb_cd_length
mb_cd_timer = world.time + mb_cd_length
/mob/living/carbon/human/verb/climax_verb()
set category = "IC"
set name = "Climax"
set desc = "Lets you choose a couple ways to ejaculate."
mob_climax()
@@ -2,10 +2,12 @@
color = "#fcccb3"
w_class = WEIGHT_CLASS_NORMAL
var/shape = "human"
var/sensitivity = AROUSAL_START_VALUE
var/sensitivity = 1 // wow if this were ever used that'd be cool but it's not but i'm keeping it for my unshit code
var/genital_flags //see citadel_defines.dm
var/masturbation_verb = "masturbate"
var/orgasm_verb = "cumming" //present continous
var/arousal_verb = "You feel aroused"
var/unarousal_verb = "You no longer feel aroused"
var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this?
var/size = 2 //can vary between num or text, just used in icon_state strings
var/datum/reagent/fluid_id = null
@@ -14,7 +16,6 @@
var/fluid_rate = CUM_RATE
var/fluid_mult = 1
var/aroused_state = FALSE //Boolean used in icon_state strings
var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons.
var/obj/item/organ/genital/linked_organ
var/linked_organ_slot //used for linking an apparatus' organ to its other half on update_link().
var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in.
@@ -38,6 +39,11 @@
Remove(owner, TRUE)//this should remove references to it, so it can be GCd correctly
return ..()
/obj/item/organ/genital/proc/set_aroused_state(new_state)
if(!((HAS_TRAIT(owner,TRAIT_PERMABONER) && !new_state) || HAS_TRAIT(owner,TRAIT_NEVERBONER) && new_state))
aroused_state = new_state
return aroused_state
/obj/item/organ/genital/proc/update(removing = FALSE)
if(QDELETED(src))
return
@@ -90,11 +96,9 @@
set desc = "Allows you to toggle which genitals should show through clothes or not."
var/list/genital_list = list()
for(var/obj/item/organ/O in internal_organs)
if(isgenital(O))
var/obj/item/organ/genital/G = O
if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL))
genital_list += G
for(var/obj/item/organ/genital/G in internal_organs)
if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL))
genital_list += G
if(!genital_list.len) //There is nothing to expose
return
//Full list of exposable genitals created
@@ -105,6 +109,39 @@
picked_organ.toggle_visibility(picked_visibility)
return
/mob/living/carbon/verb/toggle_arousal_state()
set category = "IC"
set name = "Toggle genital arousal"
set desc = "Allows you to toggle which genitals are showing signs of arousal."
var/list/genital_list = list()
for(var/obj/item/organ/genital/G in internal_organs)
var/datum/sprite_accessory/S
switch(G.type)
if(/obj/item/organ/genital/penis)
S = GLOB.cock_shapes_list[G.shape]
if(/obj/item/organ/genital/testicles)
S = GLOB.balls_shapes_list[G.shape]
if(/obj/item/organ/genital/vagina)
S = GLOB.vagina_shapes_list[G.shape]
if(/obj/item/organ/genital/breasts)
S = GLOB.breasts_shapes_list[G.shape]
if(S?.alt_aroused)
genital_list += G
if(!genital_list.len) //There's nothing that can show arousal
return
var/obj/item/organ/genital/picked_organ
picked_organ = input(src, "Choose which genitalia to toggle arousal on", "Set genital arousal", null) in genital_list
if(picked_organ)
var/original_state = picked_organ.aroused_state
picked_organ.set_aroused_state(!picked_organ.aroused_state)
if(original_state != picked_organ.aroused_state)
to_chat(src,"<span class='userlove'>[picked_organ.aroused_state ? picked_organ.arousal_verb : picked_organ.unarousal_verb].</span>")
else
to_chat(src,"<span class='userlove'>You can't make that genital [picked_organ.aroused_state ? "unaroused" : "aroused"]!</span>")
picked_organ.update_appearance()
return
/obj/item/organ/genital/proc/modify_size(modifier, min = -INFINITY, max = INFINITY)
fluid_max_volume += modifier*2.5
fluid_rate += modifier/10
@@ -233,7 +270,7 @@
//Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours.
/mob/living/carbon/human/proc/emergent_genital_call()
if(!canbearoused)
if(!client.prefs.arousable)
return FALSE
var/organCheck = locate(/obj/item/organ/genital) in internal_organs
@@ -11,6 +11,8 @@
shape = "pair"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION
masturbation_verb = "massage"
arousal_verb = "Your breasts start feeling sensitive"
unarousal_verb = "Your breasts no longer feel sensitive"
orgasm_verb = "leaking"
fluid_transfer_factor = 0.5
var/static/list/breast_values = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "flat" = 0)
@@ -6,6 +6,8 @@
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_PENIS
masturbation_verb = "stroke"
arousal_verb = "You pop a boner"
unarousal_verb = "Your boner goes down"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH
linked_organ_slot = ORGAN_SLOT_TESTICLES
fluid_transfer_factor = 0.5
@@ -26,7 +28,7 @@
..()
/obj/item/organ/genital/penis/update_size(modified = FALSE)
if(length < 0)//I don't actually know what round() does to negative numbers, so to be safe!!
if(length <= 0)//I don't actually know what round() does to negative numbers, so to be safe!!
if(owner)
to_chat(owner, "<span class='warning'>You feel your tallywacker shrinking away from your body as your groin flattens out!</b></span>")
QDEL_IN(src, 1)
@@ -6,6 +6,8 @@
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_TESTICLES
size = BALLS_SIZE_MIN
arousal_verb = "Your balls ache a little"
unarousal_verb = "Your balls finally stop aching, again"
linked_organ_slot = ORGAN_SLOT_PENIS
genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FUID_PRODUCTION
var/size_name = "average"
@@ -8,6 +8,8 @@
size = 1 //There is only 1 size right now
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH
masturbation_verb = "finger"
arousal_verb = "You feel wetness on your crotch."
unarousal_verb = "You no longer feel wet."
fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS
layer_index = VAGINA_LAYER_INDEX
var/cap_length = 8//D E P T H (cap = capacity)
@@ -5,8 +5,7 @@
name = "dildo"
desc = "Floppy!"
icon = 'modular_citadel/icons/obj/genitals/dildo.dmi'
damtype = AROUSAL
force = 5
force = 0
hitsound = 'sound/weapons/tap.ogg'
throwforce = 0
icon_state = "dildo_knotted_2"
@@ -1,7 +1,7 @@
/datum/gear/greytidestationwide
name = "Grey jumpsuit"
name = "Staff Assistant's jumpsuit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/color/grey
path = /obj/item/clothing/under/staffassistant
restricted_roles = list("Assistant")
/datum/gear/neetsuit
@@ -93,6 +93,7 @@
restricted_desc = "Engineering, Security, and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer","Head of Security","Cargo Technician", "Shaft Miner", "Quartermaster")
/*Commenting out Until next Christmas or made automatic
/datum/gear/santahatr
name = "Red Santa Hat"
category = SLOT_HEAD
@@ -102,6 +103,7 @@
name = "Green Santa Hat"
category = SLOT_HEAD
path = /obj/item/clothing/head/christmashatg
*/
/datum/gear/cowboyhat
name = "Cowboy Hat, Brown"
@@ -129,6 +131,3 @@
path = /obj/item/clothing/head/cowboyhat/sec
restricted_desc = "Security"
restricted_roles = list("Warden","Detective","Security Officer","Head of Security")
@@ -390,6 +390,7 @@
path = /obj/item/clothing/under/gear_harness
//Christmas
/*Commenting out Until next Christmas or made automatic
/datum/gear/christmasmaler
name = "Red Masculine Christmas Suit"
category = SLOT_W_UNIFORM
@@ -415,6 +416,7 @@
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/stripper_pink
cost = 3
*/
/datum/gear/greenstripper
name = "Green stripper outfit"
@@ -49,10 +49,9 @@
if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT)
return TRUE
datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1)
/datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1)
..()
character.give_genitals(TRUE)
character.flavor_text = features["flavor_text"] //Let's update their flavor_text at least initially
character.canbearoused = arousable
if(icon_updates)
character.update_genitals()
@@ -1,53 +0,0 @@
/obj/item/integrated_circuit/manipulation/electric_stimulator
name = "electronic stimulation module"
desc = "Used to induce sexual stimulation in a target via electricity."
icon_state = "power_relay"
extended_desc = "The circuit accepts a reference to a person, as well as a number representing the strength of the shock, and upon activation, attempts to stimulate them to orgasm. The number ranges from -35 to 35, with negative numbers reducing arousal and positive numbers increasing it by that amount."
complexity = 15
size = 2
inputs = list("target" = IC_PINTYPE_REF, "strength" = IC_PINTYPE_NUMBER)
outputs = list("arousal gain"=IC_PINTYPE_NUMBER)
activators = list("fire" = IC_PINTYPE_PULSE_IN, "on success" = IC_PINTYPE_PULSE_OUT, "on fail" = IC_PINTYPE_PULSE_OUT, "on orgasm" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 500
cooldown_per_use = 50
ext_cooldown = 25
/obj/item/integrated_circuit/manipulation/electric_stimulator/do_work()
set_pin_data(IC_OUTPUT, 1, 0)
var/mob/living/M = get_pin_data_as_type(IC_INPUT, 1, /mob/living)
if(!check_target(M))
return
var/arousal_gain = CLAMP(get_pin_data(IC_INPUT, 2),-35,35)
set_pin_data(IC_OUTPUT, 1, arousal_gain)
if(ismob(M) && M.canbearoused && arousal_gain != 0)
var/orgasm = FALSE
if(arousal_gain > 0)
if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
var/mob/living/carbon/human/H = M
var/orgasm_message = pick("A sharp pulse of electricity pushes you to orgasm!", "You feel a jolt of electricity force you into orgasm!")
H.visible_message("<span class='warning'>\The [assembly] electrodes shock [H]!</span>", "<span class='warning'>[orgasm_message]</span>")
playsound(src, "sound/effects/light_flicker.ogg", 30, 1)
H.mob_climax(forced_climax=TRUE)
orgasm = TRUE
else
M.adjustArousalLoss(arousal_gain)
var/stimulate_message = pick("You feel a sharp warming tingle of electricity through your body!", "A burst of arousing electricity flows through your body!")
M.visible_message("<span class='warning'>\The [assembly] electrodes shock [M]!</span>", "<span class='warning'>[stimulate_message]</span>")
else
var/stimulate_message = pick("You feel a dull prickle of electricity through your body!", "A burst of dull electricity flows through your body!")
M.visible_message("<span class='warning'>\The [assembly] electrodes shock [M]!</span>", "<span class='warning'>[stimulate_message]</span>")
M.adjustArousalLoss(arousal_gain)
playsound(src, "sound/effects/light_flicker.ogg", 30, 1)
push_data()
activate_pin(2)
if(orgasm) activate_pin(4)
else
visible_message("<span class='warning'>\The [assembly] electrodes fail to shock [M]!</span>")
push_data()
activate_pin(3)
@@ -416,14 +416,14 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
playsound(src, 'sound/effects/stealthoff.ogg', 25, TRUE, -1)
weather_immunities -= "lava"
/mob/living/silicon/robot/throw_impact(atom/A)
/mob/living/silicon/robot/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!leaping)
return ..()
if(A)
if(isliving(A))
var/mob/living/L = A
if(hit_atom)
if(isliving(hit_atom))
var/mob/living/L = hit_atom
if(!L.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
L.Knockdown(iscarbon(L) ? 60 : 45, override_stamdmg = CLAMP(pounce_stamloss, 0, pounce_stamloss_cap-L.getStaminaLoss())) // Temporary. If someone could rework how dogborg pounces work to accomodate for combat changes, that'd be nice.
@@ -437,8 +437,8 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
pounce_cooldown = !pounce_cooldown
spawn(pounce_cooldown_time) //3s by default
pounce_cooldown = !pounce_cooldown
else if(A.density && !A.CanPass(src))
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='userdanger'>You smash into [A]!</span>")
else if(hit_atom.density && !hit_atom.CanPass(src))
visible_message("<span class ='danger'>[src] smashes into [hit_atom]!</span>", "<span class ='userdanger'>You smash into [hit_atom]!</span>")
playsound(src, 'sound/items/trayhit1.ogg', 50, 1)
Knockdown(15, 1, 1)
@@ -78,3 +78,13 @@
build_path = /obj/item/ammo_box/a357
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/sl357ap
name = "revolver speedloader (.357 AP)"
desc = "A revolver speedloader. Cuts through like a hot knife through butter."
id = "sl357ap"
build_type = PROTOLATHE
materials = list(MAT_METAL = 30000, MAT_TITANIUM = 45000)
build_path = /obj/item/ammo_box/a357/ap
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
@@ -66,6 +66,7 @@ obj/item/projectile/bullet/c10mm/soporific
knockdown = 0
/obj/item/projectile/bullet/c10mm/soporific/on_hit(atom/target, blocked = FALSE)
. = ..()
if((blocked != 100) && isliving(target))
var/mob/living/L = target
L.blur_eyes(6)
@@ -73,7 +74,6 @@ obj/item/projectile/bullet/c10mm/soporific
L.Sleeping(300)
else
L.adjustStaminaLoss(25)
return 1
/obj/item/ammo_casing/c10mm/soporific
name = ".10mm soporific bullet casing"
@@ -355,7 +355,7 @@
damage = 10
armour_penetration = 10
stamina = 10
forcedodge = TRUE
movement_type = FLYING | UNSTOPPABLE
range = 6
light_range = 1
light_color = LIGHT_COLOR_RED
@@ -363,14 +363,14 @@
/obj/item/projectile/bullet/mags/hyper/inferno
icon_state = "magjectile-large"
stamina = 0
forcedodge = FALSE
movement_type = FLYING | UNSTOPPABLE
range = 25
light_range = 4
/obj/item/projectile/bullet/mags/hyper/inferno/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 1, 2, 4, 5)
return 1
return BULLET_ACT_HIT
///ammo casings///
@@ -436,7 +436,7 @@
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "magjectile-toy"
name = "lasertag magbolt"
forcedodge = TRUE //for penetration memes
movement_type = FLYING | UNSTOPPABLE //for penetration memes
range = 5 //so it isn't super annoying
light_range = 2
light_color = LIGHT_COLOR_YELLOW
@@ -9,7 +9,7 @@
/obj/item/projectile/bullet/spinfusor/on_hit(atom/target, blocked = FALSE) //explosion to emulate the spinfusor's AOE
..()
explosion(target, -1, -1, 2, 0, -1)
return 1
return BULLET_ACT_HIT
/obj/item/ammo_casing/caseless/spinfusor
name = "spinfusor disk"
@@ -308,8 +308,6 @@ Creating a chem with a low purity will make you permanently fall in love with so
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have bonded")
else
if(get_dist(M, love) < 8)
if(HAS_TRAIT(M, TRAIT_NYMPHO)) //Add this back when merged/updated.
M.adjustArousalLoss(5)
var/message = "[(lewd?"I'm next to my crush..! Eee!":"I'm making friends with [love]!")]"
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "InLove", /datum/mood_event/InLove, message)
SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "MissingLove")
@@ -97,14 +97,18 @@
color = "#FFADFF"//PINK, rgb(255, 173, 255)
/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/M)
if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO))
if(prob(33))
M.adjustArousalLoss(2)
if(prob(5))
if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO))
if((prob(min(current_cycle/2,5))))
M.emote(pick("moan","blush"))
if(prob(5))
if(prob(min(current_cycle/4,10)))
var/aroused_message = pick("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.")
to_chat(M, "<span class='userlove'>[aroused_message]</span>")
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/list/genits = H.adjust_arousal(current_cycle, aphro = TRUE) // redundant but should still be here
for(var/g in genits)
var/obj/item/organ/genital/G = g
to_chat(M, "<span class='userlove'>[G.arousal_verb]!</span>")
..()
/datum/reagent/drug/aphrodisiacplus
@@ -118,21 +122,26 @@
overdose_threshold = 20
/datum/reagent/drug/aphrodisiacplus/on_mob_life(mob/living/M)
if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO))
if(prob(33))
M.adjustArousalLoss(6)//not quite six times as powerful, but still considerably more powerful.
if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO))
if(prob(5))
if(M.getArousalLoss() > 75)
if(prob(current_cycle))
M.say(pick("Hnnnnngghh...", "Ohh...", "Mmnnn..."))
else
M.emote(pick("moan","blush"))
if(prob(5))
var/aroused_message
if(M.getArousalLoss() > 90)
if(current_cycle>25)
aroused_message = pick("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!")
else
aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
to_chat(M, "<span class='userlove'>[aroused_message]</span>")
REMOVE_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/list/genits = H.adjust_arousal(100, aphro = TRUE) // redundant but should still be here
for(var/g in genits)
var/obj/item/organ/genital/G = g
to_chat(M, "<span class='userlove'>[G.arousal_verb]!</span>")
..()
/datum/reagent/drug/aphrodisiacplus/addiction_act_stage2(mob/living/M)
@@ -150,15 +159,11 @@
..()
/datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M)
if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33))
if(prob(5) && M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
if(prob(5)) //Less spam
to_chat(M, "<span class='love'>Your libido is going haywire!</span>")
if(M.min_arousal < 50)
M.min_arousal += 1
if(M.min_arousal < M.max_arousal)
M.min_arousal += 1
M.adjustArousalLoss(2)
if(M && M.client?.prefs.arousable && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33))
if(prob(5) && ishuman(M) && M.has_dna() && (M.client?.prefs.cit_toggles & BIMBOFICATION))
if(!HAS_TRAIT(M,TRAIT_PERMABONER))
to_chat(M, "<span class='userlove'>Your libido is going haywire!</span>")
ADD_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT)
..()
/datum/reagent/drug/anaphrodisiac
@@ -171,8 +176,12 @@
reagent_state = SOLID
/datum/reagent/drug/anaphrodisiac/on_mob_life(mob/living/M)
if(M && M.canbearoused && prob(33))
M.adjustArousalLoss(-2)
if(M && M.client?.prefs.arousable && prob(16))
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/list/genits = H.adjust_arousal(-100, aphro = TRUE)
if(genits.len)
to_chat(M, "<span class='notice'>You no longer feel aroused.")
..()
/datum/reagent/drug/anaphrodisiacplus
@@ -184,17 +193,20 @@
overdose_threshold = 20
/datum/reagent/drug/anaphrodisiacplus/on_mob_life(mob/living/M)
if(M && M.canbearoused && prob(33))
M.adjustArousalLoss(-4)
if(M && M.client?.prefs.arousable)
REMOVE_TRAIT(M,TRAIT_PERMABONER,APHRO_TRAIT)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/list/genits = H.adjust_arousal(-100, aphro = TRUE)
if(genits.len)
to_chat(M, "<span class='notice'>You no longer feel aroused.")
..()
/datum/reagent/drug/anaphrodisiacplus/overdose_process(mob/living/M)
if(M && M.canbearoused && prob(33))
if(M.min_arousal > 0)
M.min_arousal -= 1
if(M.min_arousal > 50)
M.min_arousal -= 1
M.adjustArousalLoss(-2)
if(M && M.client?.prefs.arousable && prob(5))
to_chat(M, "<span class='userlove'>You feel like you'll never feel aroused again...</span>")
ADD_TRAIT(M,TRAIT_NEVERBONER,APHRO_TRAIT)
..()
//recipes