3203f19290
Adds the Families gamemode to the codebase. In this 1 hour showdown, multiple criminal families are placed onto the station with their goal to rack up the most points by the end of 1 hour. At which point, the Space Cops hit up the station to crack down on the family activity. The severity of the Space Cops is based on how much carnage and murder the families have committed. ## Why It's Good For The Game With an actual official medium/heavy RP server, and the codebase taking a much harder swing towards heavier consequences for death, a more player focused gamemode with a unique swing on teamwork, the concept of what exactly is an antagonist, and trust/paranoia will do wonders to help improve that atmosphere. Previous tests went extremely well(when administrators weren't intentionally sabotaging it by welderbombing families as the Head of Security every single round immediately with no escalation), but suffered from "this just isn't a gamemode for no RP servers like /tg/". However, /tg/ is now an RP server. Get ready to rep your family. ## Isn't this just Gang? Heck no. Only thing similar is tagging turf and the fact criminal groups are involved. This mode is completely different otherwise. ## Heck yeah, where do I sign up? Ask a family member where their Signup Point is, and then simply click on it with an open hand. You'll be signed up for the family instantly, and given some sick threads and a spraycan for tagging. ## How do I rep my family? Wear your gang's uniform or colors similar. ## What does it mean to roll with a crew? Travel in a group of four or more for bonus points towards your gang. However, you receive less for having eight or more, so be careful. Try to spread your crews out! ## I'm an X, what do? Gangster: Yeah, go do whatever. Wanna backstab your gang? Go for it. You can switch sides at any time by clicking on an enemy gang's sign up point. Wanna murder some snitch because they ratted you out to the pigs? Do it. Wanna pressure the locals into supplying you with goods to export? Emergent gameplay. Civilians: Wanna join a gang? Go for it. Gangsters probably shouldn't be arbitrarily murdering you, but if you're repping someone else's colors, don't expect to be given a free pass. After all, uniforms are the only way to really identify a gang member. SPACE COP: Get rid of all the gangsters. Secure the station. Protect the law. Uphold the law. Eat donuts. ## No huds? How can I tell if someone's part of my group? Tough shit, man. I hope you like trust. In short, this gamemode will be a fun exercise in how far the playerbase can go in regards to trusting eachother and unifying to meet a common goal for their group with no rules, gameplay mechanics, or anything actively forcing them to work together. ## How do I know if someone is a gangster? 1. Are they wearing a gang uniform/color? If yes, they're probably a gangster. If no, they're probably a civvie. 2. Are they attacking gangsters? If yes, they're probably a gangster. If no, they're probably a civvie.
838 lines
26 KiB
Plaintext
838 lines
26 KiB
Plaintext
#define RANDOM_GRAFFITI "Random Graffiti"
|
|
#define RANDOM_LETTER "Random Letter"
|
|
#define RANDOM_PUNCTUATION "Random Punctuation"
|
|
#define RANDOM_NUMBER "Random Number"
|
|
#define RANDOM_SYMBOL "Random Symbol"
|
|
#define RANDOM_DRAWING "Random Drawing"
|
|
#define RANDOM_ORIENTED "Random Oriented"
|
|
#define RANDOM_RUNE "Random Rune"
|
|
#define RANDOM_ANY "Random Anything"
|
|
|
|
#define PAINT_NORMAL 1
|
|
#define PAINT_LARGE_HORIZONTAL 2
|
|
#define PAINT_LARGE_HORIZONTAL_ICON 'icons/effects/96x32.dmi'
|
|
|
|
/*
|
|
* Crayons
|
|
*/
|
|
|
|
/obj/item/toy/crayon
|
|
name = "crayon"
|
|
desc = "A colourful crayon. Looks tasty. Mmmm..."
|
|
icon = 'icons/obj/crayons.dmi'
|
|
icon_state = "crayonred"
|
|
|
|
var/icon_capped
|
|
var/icon_uncapped
|
|
var/use_overlays = FALSE
|
|
|
|
var/crayon_color = "red"
|
|
w_class = WEIGHT_CLASS_TINY
|
|
attack_verb = list("attacked", "coloured")
|
|
grind_results = list()
|
|
var/paint_color = "#FF0000" //RGB
|
|
|
|
var/drawtype
|
|
var/text_buffer = ""
|
|
|
|
var/static/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","star","poseur tag","prolizard","antilizard")
|
|
var/static/list/symbols = list("danger","firedanger","electricdanger","biohazard","radiation","safe","evac","space","med","trade","shop","food","peace","like","skull","nay","heart","credit")
|
|
var/static/list/drawings = list("smallbrush","brush","largebrush","splatter","snake","stickman","carp","ghost","clown","taser","disk","fireaxe","toolbox","corgi","cat","toilet","blueprint","beepsky","scroll","bottle","shotgun")
|
|
var/static/list/oriented = list("arrow","line","thinline","shortline","body","chevron","footprint","clawprint","pawprint") // These turn to face the same way as the drawer
|
|
var/static/list/runes = list("rune1","rune2","rune3","rune4","rune5","rune6")
|
|
var/static/list/randoms = list(RANDOM_ANY, RANDOM_RUNE, RANDOM_ORIENTED,
|
|
RANDOM_NUMBER, RANDOM_GRAFFITI, RANDOM_LETTER, RANDOM_SYMBOL, RANDOM_PUNCTUATION, RANDOM_DRAWING)
|
|
var/static/list/graffiti_large_h = list("yiffhell", "secborg", "paint")
|
|
|
|
var/static/list/all_drawables = graffiti + symbols + drawings + oriented + runes + graffiti_large_h
|
|
|
|
var/paint_mode = PAINT_NORMAL
|
|
|
|
var/charges = 30 //-1 or less for unlimited uses
|
|
var/charges_left
|
|
var/volume_multiplier = 1 // Increases reagent effect
|
|
|
|
var/actually_paints = TRUE
|
|
|
|
var/instant = FALSE
|
|
var/self_contained = TRUE // If it deletes itself when it is empty
|
|
|
|
var/edible = TRUE // That doesn't mean eating it is a good idea
|
|
|
|
var/list/reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5)
|
|
// If the user can toggle the colour, a la vanilla spraycan
|
|
var/can_change_colour = FALSE
|
|
|
|
var/has_cap = FALSE
|
|
var/is_capped = FALSE
|
|
|
|
var/pre_noise = FALSE
|
|
var/post_noise = FALSE
|
|
|
|
/obj/item/toy/crayon/proc/isValidSurface(surface)
|
|
return istype(surface, /turf/open/floor)
|
|
|
|
/obj/item/toy/crayon/suicide_act(mob/user)
|
|
user.visible_message("<span class='suicide'>[user] is jamming [src] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
|
return (BRUTELOSS|OXYLOSS)
|
|
|
|
/obj/item/toy/crayon/Initialize()
|
|
. = ..()
|
|
// Makes crayons identifiable in things like grinders
|
|
if(name == "crayon")
|
|
name = "[crayon_color] crayon"
|
|
|
|
dye_color = crayon_color
|
|
|
|
drawtype = pick(all_drawables)
|
|
|
|
refill()
|
|
|
|
/obj/item/toy/crayon/proc/refill()
|
|
if(charges == -1)
|
|
charges_left = 100
|
|
else
|
|
charges_left = charges
|
|
|
|
if(!reagents)
|
|
create_reagents(charges_left * volume_multiplier)
|
|
reagents.clear_reagents()
|
|
|
|
var/total_weight = 0
|
|
for(var/key in reagent_contents)
|
|
total_weight += reagent_contents[key]
|
|
|
|
var/units_per_weight = reagents.maximum_volume / total_weight
|
|
for(var/reagent in reagent_contents)
|
|
var/weight = reagent_contents[reagent]
|
|
var/amount = weight * units_per_weight
|
|
reagents.add_reagent(reagent, amount)
|
|
|
|
/obj/item/toy/crayon/proc/use_charges(mob/user, amount = 1, requires_full = TRUE)
|
|
// Returns number of charges actually used
|
|
if(charges == -1)
|
|
. = amount
|
|
refill()
|
|
else
|
|
if(check_empty(user, amount, requires_full))
|
|
return 0
|
|
else
|
|
. = min(charges_left, amount)
|
|
charges_left -= .
|
|
|
|
/obj/item/toy/crayon/proc/check_empty(mob/user, amount = 1, requires_full = TRUE)
|
|
// When eating a crayon, check_empty() can be called twice producing
|
|
// two messages unless we check for being deleted first
|
|
if(QDELETED(src))
|
|
return TRUE
|
|
|
|
. = FALSE
|
|
// -1 is unlimited charges
|
|
if(charges == -1)
|
|
. = FALSE
|
|
else if(!charges_left)
|
|
to_chat(user, "<span class='warning'>There is no more of [src] left!</span>")
|
|
if(self_contained)
|
|
qdel(src)
|
|
. = TRUE
|
|
else if(charges_left < amount && requires_full)
|
|
to_chat(user, "<span class='warning'>There is not enough of [src] left!</span>")
|
|
. = TRUE
|
|
|
|
/obj/item/toy/crayon/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
|
// tgui is a plague upon this codebase
|
|
|
|
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
|
if(!ui)
|
|
ui = new(user, src, ui_key, "crayon", name, 600, 600,
|
|
master_ui, state)
|
|
ui.open()
|
|
|
|
/obj/item/toy/crayon/spraycan/AltClick(mob/user)
|
|
if(user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
|
|
if(has_cap)
|
|
is_capped = !is_capped
|
|
to_chat(user, "<span class='notice'>The cap on [src] is now [is_capped ? "on" : "off"].</span>")
|
|
update_icon()
|
|
|
|
/obj/item/toy/crayon/proc/staticDrawables()
|
|
|
|
. = list()
|
|
|
|
var/list/g_items = list()
|
|
. += list(list("name" = "Graffiti", "items" = g_items))
|
|
for(var/g in graffiti)
|
|
g_items += list(list("item" = g))
|
|
|
|
var/list/glh_items = list()
|
|
. += list(list("name" = "Graffiti Large Horizontal", "items" = glh_items))
|
|
for(var/glh in graffiti_large_h)
|
|
glh_items += list(list("item" = glh))
|
|
|
|
var/list/S_items = list()
|
|
. += list(list("name" = "Symbols", "items" = S_items))
|
|
for(var/S in symbols)
|
|
S_items += list(list("item" = S))
|
|
|
|
var/list/D_items = list()
|
|
. += list(list("name" = "Drawings", "items" = D_items))
|
|
for(var/D in drawings)
|
|
D_items += list(list("item" = D))
|
|
|
|
var/list/O_items = list()
|
|
. += list(list(name = "Oriented", "items" = O_items))
|
|
for(var/O in oriented)
|
|
O_items += list(list("item" = O))
|
|
|
|
var/list/R_items = list()
|
|
. += list(list(name = "Runes", "items" = R_items))
|
|
for(var/R in runes)
|
|
R_items += list(list("item" = R))
|
|
|
|
var/list/rand_items = list()
|
|
. += list(list(name = "Random", "items" = rand_items))
|
|
for(var/i in randoms)
|
|
rand_items += list(list("item" = i))
|
|
|
|
|
|
/obj/item/toy/crayon/ui_data()
|
|
|
|
var/static/list/crayon_drawables
|
|
|
|
if (!crayon_drawables)
|
|
crayon_drawables = staticDrawables()
|
|
|
|
. = list()
|
|
.["drawables"] = crayon_drawables
|
|
.["selected_stencil"] = drawtype
|
|
.["text_buffer"] = text_buffer
|
|
|
|
.["has_cap"] = has_cap
|
|
.["is_capped"] = is_capped
|
|
.["can_change_colour"] = can_change_colour
|
|
.["current_colour"] = paint_color
|
|
|
|
/obj/item/toy/crayon/ui_act(action, list/params)
|
|
if(..())
|
|
return
|
|
switch(action)
|
|
if("toggle_cap")
|
|
if(has_cap)
|
|
is_capped = !is_capped
|
|
. = TRUE
|
|
if("select_stencil")
|
|
var/stencil = params["item"]
|
|
if(stencil in all_drawables + randoms)
|
|
drawtype = stencil
|
|
. = TRUE
|
|
text_buffer = ""
|
|
if(stencil in graffiti_large_h)
|
|
paint_mode = PAINT_LARGE_HORIZONTAL
|
|
text_buffer = ""
|
|
else
|
|
paint_mode = PAINT_NORMAL
|
|
if("select_colour")
|
|
if(can_change_colour)
|
|
var/chosen_colour = input(usr,"","Choose Color",paint_color) as color|null
|
|
|
|
if (!isnull(chosen_colour))
|
|
paint_color = chosen_colour
|
|
. = TRUE
|
|
else
|
|
. = FALSE
|
|
if("enter_text")
|
|
var/txt = stripped_input(usr,"Choose what to write.",
|
|
"Scribbles",default = text_buffer)
|
|
text_buffer = crayon_text_strip(txt)
|
|
. = TRUE
|
|
paint_mode = PAINT_NORMAL
|
|
drawtype = "a"
|
|
update_icon()
|
|
|
|
/obj/item/toy/crayon/proc/crayon_text_strip(text)
|
|
var/static/regex/crayon_r = new /regex(@"[^\w!?,.=%#&+\/\-]")
|
|
return replacetext(lowertext(text), crayon_r, "")
|
|
|
|
/obj/item/toy/crayon/afterattack(atom/target, mob/user, proximity, params)
|
|
. = ..()
|
|
if(!proximity || !check_allowed_items(target))
|
|
return
|
|
|
|
var/static/list/punctuation = list("!","?",".",",","/","+","-","=","%","#","&")
|
|
var/istagger = HAS_TRAIT(user, TRAIT_TAGGER)
|
|
|
|
var/cost = 1
|
|
if(paint_mode == PAINT_LARGE_HORIZONTAL)
|
|
cost = 5
|
|
if(istype(target, /obj/item/canvas))
|
|
cost = 0
|
|
if(ishuman(user))
|
|
if (istagger)
|
|
cost *= 0.5
|
|
var/charges_used = use_charges(user, cost)
|
|
if(!charges_used)
|
|
return
|
|
. = charges_used
|
|
|
|
if(istype(target, /obj/effect/decal/cleanable))
|
|
target = target.loc
|
|
|
|
if(!isValidSurface(target))
|
|
return
|
|
|
|
var/drawing = drawtype
|
|
switch(drawtype)
|
|
if(RANDOM_LETTER)
|
|
drawing = ascii2text(rand(97, 122)) // a-z
|
|
if(RANDOM_PUNCTUATION)
|
|
drawing = pick(punctuation)
|
|
if(RANDOM_SYMBOL)
|
|
drawing = pick(symbols)
|
|
if(RANDOM_DRAWING)
|
|
drawing = pick(drawings)
|
|
if(RANDOM_GRAFFITI)
|
|
drawing = pick(graffiti)
|
|
if(RANDOM_RUNE)
|
|
drawing = pick(runes)
|
|
if(RANDOM_ORIENTED)
|
|
drawing = pick(oriented)
|
|
if(RANDOM_NUMBER)
|
|
drawing = ascii2text(rand(48, 57)) // 0-9
|
|
if(RANDOM_ANY)
|
|
drawing = pick(all_drawables)
|
|
|
|
|
|
var/temp = "rune"
|
|
var/ascii = (length(drawing) == 1)
|
|
if(ascii && is_alpha(drawing))
|
|
temp = "letter"
|
|
else if(ascii && is_digit(drawing))
|
|
temp = "number"
|
|
else if(drawing in punctuation)
|
|
temp = "punctuation mark"
|
|
else if(drawing in symbols)
|
|
temp = "symbol"
|
|
else if(drawing in drawings)
|
|
temp = "drawing"
|
|
else if(drawing in graffiti|oriented)
|
|
temp = "graffiti"
|
|
|
|
var/gang_mode
|
|
if(user.mind)
|
|
gang_mode = user.mind.has_antag_datum(/datum/antagonist/gang)
|
|
|
|
if(gang_mode && (!can_claim_for_gang(user, target)))
|
|
return
|
|
|
|
|
|
var/graf_rot
|
|
if(drawing in oriented)
|
|
switch(user.dir)
|
|
if(EAST)
|
|
graf_rot = 90
|
|
if(SOUTH)
|
|
graf_rot = 180
|
|
if(WEST)
|
|
graf_rot = 270
|
|
else
|
|
graf_rot = 0
|
|
|
|
var/list/click_params = params2list(params)
|
|
var/clickx
|
|
var/clicky
|
|
|
|
if(click_params && click_params["icon-x"] && click_params["icon-y"])
|
|
clickx = clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
|
clicky = clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
|
|
|
if(!instant)
|
|
to_chat(user, "<span class='notice'>You start drawing a [temp] on the [target.name]...</span>")
|
|
|
|
if(pre_noise)
|
|
audible_message("<span class='notice'>You hear spraying.</span>")
|
|
playsound(user.loc, 'sound/effects/spray.ogg', 5, TRUE, 5)
|
|
|
|
var/wait_time = 50
|
|
if(paint_mode == PAINT_LARGE_HORIZONTAL)
|
|
wait_time *= 3
|
|
|
|
if(gang_mode || !instant)
|
|
if(!do_after(user, 50, target = target))
|
|
return
|
|
|
|
if(length(text_buffer))
|
|
drawing = text_buffer[1]
|
|
|
|
|
|
var/list/turf/affected_turfs = list()
|
|
|
|
if(actually_paints)
|
|
var/obj/effect/decal/cleanable/crayon/C
|
|
if(gang_mode)
|
|
if(!can_claim_for_gang(user, target))
|
|
return
|
|
tag_for_gang(user, target, gang_mode)
|
|
affected_turfs += target
|
|
else
|
|
switch(paint_mode)
|
|
if(PAINT_NORMAL)
|
|
C = new(target, paint_color, drawing, temp, graf_rot)
|
|
C.pixel_x = clickx
|
|
C.pixel_y = clicky
|
|
affected_turfs += target
|
|
if(PAINT_LARGE_HORIZONTAL)
|
|
var/turf/left = locate(target.x-1,target.y,target.z)
|
|
var/turf/right = locate(target.x+1,target.y,target.z)
|
|
if(isValidSurface(left) && isValidSurface(right))
|
|
C = new(left, paint_color, drawing, temp, graf_rot, PAINT_LARGE_HORIZONTAL_ICON)
|
|
affected_turfs += left
|
|
affected_turfs += right
|
|
affected_turfs += target
|
|
else
|
|
to_chat(user, "<span class='warning'>There isn't enough space to paint!</span>")
|
|
return
|
|
C.add_hiddenprint(user)
|
|
if(istagger)
|
|
C.AddComponent(/datum/component/art, GOOD_ART)
|
|
else
|
|
C.AddComponent(/datum/component/art, BAD_ART)
|
|
|
|
if(!instant)
|
|
to_chat(user, "<span class='notice'>You finish drawing \the [temp].</span>")
|
|
else
|
|
to_chat(user, "<span class='notice'>You spray a [temp] on \the [target.name]</span>")
|
|
|
|
if(length(text_buffer) > 1)
|
|
text_buffer = copytext(text_buffer, length(text_buffer[1]) + 1)
|
|
SStgui.update_uis(src)
|
|
|
|
if(post_noise)
|
|
audible_message("<span class='hear'>You hear spraying.</span>")
|
|
playsound(user.loc, 'sound/effects/spray.ogg', 5, TRUE, 5)
|
|
|
|
var/fraction = min(1, . / reagents.maximum_volume)
|
|
if(affected_turfs.len)
|
|
fraction /= affected_turfs.len
|
|
for(var/t in affected_turfs)
|
|
reagents.reaction(t, TOUCH, fraction * volume_multiplier)
|
|
reagents.trans_to(t, ., volume_multiplier, transfered_by = user)
|
|
check_empty(user)
|
|
|
|
/obj/item/toy/crayon/attack(mob/M, mob/user)
|
|
if(edible && (M == user))
|
|
if(iscarbon(M))
|
|
var/mob/living/carbon/C = M
|
|
var/covered = ""
|
|
if(C.is_mouth_covered(head_only = 1))
|
|
covered = "headgear"
|
|
else if(C.is_mouth_covered(mask_only = 1))
|
|
covered = "mask"
|
|
if(covered)
|
|
to_chat(C, "<span class='warning'>You have to remove your [covered] first!</span>")
|
|
return
|
|
to_chat(user, "<span class='notice'>You take a bite of the [src.name]. Delicious!</span>")
|
|
var/eaten = use_charges(user, 5, FALSE)
|
|
if(check_empty(user)) //Prevents divsion by zero
|
|
return
|
|
var/fraction = min(eaten / reagents.total_volume, 1)
|
|
reagents.reaction(M, INGEST, fraction * volume_multiplier)
|
|
reagents.trans_to(M, eaten, volume_multiplier, transfered_by = user)
|
|
// check_empty() is called during afterattack
|
|
else
|
|
..()
|
|
|
|
/obj/item/toy/crayon/proc/can_claim_for_gang(mob/user, atom/target)
|
|
var/area/A = get_area(target)
|
|
if(!A || (!is_station_level(A.z)))
|
|
to_chat(user, "<span class='warning'>[A] is unsuitable for tagging.</span>")
|
|
return FALSE
|
|
|
|
var/spraying_over = FALSE
|
|
for(var/obj/effect/decal/cleanable/crayon/gang/G in target)
|
|
spraying_over = TRUE
|
|
|
|
for(var/obj/machinery/power/apc in target)
|
|
to_chat(user, "<span class='warning'>You can't tag an APC.</span>")
|
|
return FALSE
|
|
|
|
var/occupying_gang = territory_claimed(A, user)
|
|
if(occupying_gang && !spraying_over)
|
|
to_chat(user, "<span class='danger'>[A] has already been tagged by a gang! You must find and spray over the old tag first!</span>")
|
|
return FALSE
|
|
|
|
// stolen from oldgang lmao
|
|
return TRUE
|
|
|
|
/obj/item/toy/crayon/proc/tag_for_gang(mob/user, atom/target, datum/antagonist/gang/user_gang)
|
|
for(var/obj/effect/decal/cleanable/crayon/old_marking in target)
|
|
qdel(old_marking)
|
|
|
|
var/area/territory = get_area(target)
|
|
|
|
var/obj/effect/decal/cleanable/crayon/gang/tag = new /obj/effect/decal/cleanable/crayon/gang(target)
|
|
tag.my_gang = user_gang.my_gang
|
|
tag.icon_state = "[user_gang.gang_id]_tag"
|
|
tag.name = "[tag.my_gang.name] gang tag"
|
|
tag.desc = "Looks like someone's claimed this area for [tag.my_gang.name]."
|
|
to_chat(user, "<span class='notice'>You tagged [territory] for [tag.my_gang.name]!</span>")
|
|
|
|
/obj/item/toy/crayon/proc/territory_claimed(area/territory, mob/user)
|
|
for(var/obj/effect/decal/cleanable/crayon/gang/G in GLOB.gang_tags)
|
|
if(get_area(G) == territory)
|
|
return TRUE
|
|
|
|
/obj/item/toy/crayon/red
|
|
icon_state = "crayonred"
|
|
paint_color = "#DA0000"
|
|
crayon_color = "red"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/red/crayon = 1.5)
|
|
dye_color = DYE_RED
|
|
|
|
/obj/item/toy/crayon/orange
|
|
icon_state = "crayonorange"
|
|
paint_color = "#FF9300"
|
|
crayon_color = "orange"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/orange/crayon = 1.5)
|
|
dye_color = DYE_ORANGE
|
|
|
|
/obj/item/toy/crayon/yellow
|
|
icon_state = "crayonyellow"
|
|
paint_color = "#FFF200"
|
|
crayon_color = "yellow"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/yellow/crayon = 1.5)
|
|
dye_color = DYE_YELLOW
|
|
|
|
/obj/item/toy/crayon/green
|
|
icon_state = "crayongreen"
|
|
paint_color = "#A8E61D"
|
|
crayon_color = "green"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/green/crayon = 1.5)
|
|
dye_color = DYE_GREEN
|
|
|
|
/obj/item/toy/crayon/blue
|
|
icon_state = "crayonblue"
|
|
paint_color = "#00B7EF"
|
|
crayon_color = "blue"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/blue/crayon = 1.5)
|
|
dye_color = DYE_BLUE
|
|
|
|
/obj/item/toy/crayon/purple
|
|
icon_state = "crayonpurple"
|
|
paint_color = "#DA00FF"
|
|
crayon_color = "purple"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/purple/crayon = 1.5)
|
|
dye_color = DYE_PURPLE
|
|
|
|
/obj/item/toy/crayon/black
|
|
icon_state = "crayonblack"
|
|
paint_color = "#1C1C1C" //Not completely black because total black looks bad. So Mostly Black.
|
|
crayon_color = "black"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/black/crayon = 1.5)
|
|
dye_color = DYE_BLACK
|
|
|
|
/obj/item/toy/crayon/white
|
|
icon_state = "crayonwhite"
|
|
paint_color = "#FFFFFF"
|
|
crayon_color = "white"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/white/crayon = 1.5)
|
|
dye_color = DYE_WHITE
|
|
|
|
/obj/item/toy/crayon/mime
|
|
icon_state = "crayonmime"
|
|
desc = "A very sad-looking crayon."
|
|
paint_color = "#FFFFFF"
|
|
crayon_color = "mime"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/invisible = 1.5)
|
|
charges = -1
|
|
dye_color = DYE_MIME
|
|
|
|
/obj/item/toy/crayon/rainbow
|
|
icon_state = "crayonrainbow"
|
|
paint_color = "#FFF000"
|
|
crayon_color = "rainbow"
|
|
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent = 1.5)
|
|
drawtype = RANDOM_ANY // just the default starter.
|
|
charges = -1
|
|
dye_color = DYE_RAINBOW
|
|
|
|
/obj/item/toy/crayon/rainbow/afterattack(atom/target, mob/user, proximity, params)
|
|
paint_color = rgb(rand(0,255), rand(0,255), rand(0,255))
|
|
. = ..()
|
|
|
|
/*
|
|
* Crayon Box
|
|
*/
|
|
|
|
/obj/item/storage/crayons
|
|
name = "box of crayons"
|
|
desc = "A box of crayons for all your rune drawing needs."
|
|
icon = 'icons/obj/crayons.dmi'
|
|
icon_state = "crayonbox"
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
|
|
/obj/item/storage/crayons/Initialize()
|
|
. = ..()
|
|
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
|
STR.max_items = 7
|
|
STR.set_holdable(list(/obj/item/toy/crayon))
|
|
|
|
/obj/item/storage/crayons/PopulateContents()
|
|
new /obj/item/toy/crayon/red(src)
|
|
new /obj/item/toy/crayon/orange(src)
|
|
new /obj/item/toy/crayon/yellow(src)
|
|
new /obj/item/toy/crayon/green(src)
|
|
new /obj/item/toy/crayon/blue(src)
|
|
new /obj/item/toy/crayon/purple(src)
|
|
new /obj/item/toy/crayon/black(src)
|
|
update_icon()
|
|
|
|
/obj/item/storage/crayons/update_overlays()
|
|
. = ..()
|
|
for(var/obj/item/toy/crayon/crayon in contents)
|
|
. += mutable_appearance('icons/obj/crayons.dmi', crayon.crayon_color)
|
|
|
|
/obj/item/storage/crayons/attackby(obj/item/W, mob/user, params)
|
|
if(istype(W, /obj/item/toy/crayon))
|
|
var/obj/item/toy/crayon/C = W
|
|
switch(C.crayon_color)
|
|
if("mime")
|
|
to_chat(usr, "<span class='warning'>This crayon is too sad to be contained in this box!</span>")
|
|
return
|
|
if("rainbow")
|
|
to_chat(usr, "<span class='warning'>This crayon is too powerful to be contained in this box!</span>")
|
|
return
|
|
if(istype(W, /obj/item/toy/crayon/spraycan))
|
|
to_chat(user, "<span class='warning'>Spraycans are not crayons!</span>")
|
|
return
|
|
return ..()
|
|
|
|
//Spraycan stuff
|
|
|
|
/obj/item/toy/crayon/spraycan
|
|
name = "spray can"
|
|
icon_state = "spraycan"
|
|
|
|
icon_capped = "spraycan_cap"
|
|
icon_uncapped = "spraycan"
|
|
use_overlays = TRUE
|
|
paint_color = null
|
|
|
|
item_state = "spraycan"
|
|
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
|
|
desc = "A metallic container containing tasty paint."
|
|
|
|
instant = TRUE
|
|
edible = FALSE
|
|
has_cap = TRUE
|
|
is_capped = TRUE
|
|
self_contained = FALSE // Don't disappear when they're empty
|
|
can_change_colour = TRUE
|
|
|
|
reagent_contents = list(/datum/reagent/fuel = 1, /datum/reagent/consumable/ethanol = 1)
|
|
|
|
pre_noise = TRUE
|
|
post_noise = FALSE
|
|
|
|
/obj/item/toy/crayon/spraycan/isValidSurface(surface)
|
|
return (istype(surface, /turf/open/floor) || istype(surface, /turf/closed/wall))
|
|
|
|
|
|
/obj/item/toy/crayon/spraycan/suicide_act(mob/user)
|
|
var/mob/living/carbon/human/H = user
|
|
if(is_capped || !actually_paints)
|
|
user.visible_message("<span class='suicide'>[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, but nothing happens!</span>")
|
|
user.say("MEDIOCRE!!", forced="spraycan suicide")
|
|
return SHAME
|
|
else
|
|
user.visible_message("<span class='suicide'>[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, spraying paint across [user.p_their()] teeth!</span>")
|
|
user.say("WITNESS ME!!", forced="spraycan suicide")
|
|
if(pre_noise || post_noise)
|
|
playsound(src, 'sound/effects/spray.ogg', 5, TRUE, 5)
|
|
if(can_change_colour)
|
|
paint_color = "#C0C0C0"
|
|
update_icon()
|
|
if(actually_paints)
|
|
H.lip_style = "spray_face"
|
|
H.lip_color = paint_color
|
|
H.update_body()
|
|
var/used = use_charges(user, 10, FALSE)
|
|
var/fraction = min(1, used / reagents.maximum_volume)
|
|
reagents.reaction(user, VAPOR, fraction * volume_multiplier)
|
|
reagents.trans_to(user, used, volume_multiplier, transfered_by = user)
|
|
|
|
return (OXYLOSS)
|
|
|
|
/obj/item/toy/crayon/spraycan/Initialize()
|
|
. = ..()
|
|
// If default crayon red colour, pick a more fun spraycan colour
|
|
if(!paint_color)
|
|
paint_color = pick("#DA0000","#FF9300","#FFF200","#A8E61D","#00B7EF",
|
|
"#DA00FF")
|
|
refill()
|
|
update_icon()
|
|
|
|
|
|
/obj/item/toy/crayon/spraycan/examine(mob/user)
|
|
. = ..()
|
|
if(charges_left)
|
|
. += "It has [charges_left] use\s left."
|
|
else
|
|
. += "It is empty."
|
|
. += "<span class='notice'>Alt-click [src] to [ is_capped ? "take the cap off" : "put the cap on"].</span>"
|
|
|
|
/obj/item/toy/crayon/spraycan/afterattack(atom/target, mob/user, proximity, params)
|
|
if(!proximity)
|
|
return
|
|
|
|
if(is_capped)
|
|
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
|
return
|
|
|
|
if(check_empty(user))
|
|
return
|
|
|
|
if(iscarbon(target))
|
|
if(pre_noise || post_noise)
|
|
playsound(user.loc, 'sound/effects/spray.ogg', 25, TRUE, 5)
|
|
|
|
var/mob/living/carbon/C = target
|
|
user.visible_message("<span class='danger'>[user] sprays [src] into the face of [target]!</span>")
|
|
to_chat(target, "<span class='userdanger'>[user] sprays [src] into your face!</span>")
|
|
|
|
if(C.client)
|
|
C.blur_eyes(3)
|
|
C.blind_eyes(1)
|
|
if(C.get_eye_protection() <= 0) // no eye protection? ARGH IT BURNS. Warning: don't add a stun here. It's a roundstart item with some quirks.
|
|
C.apply_effects(eyeblur = 5, jitter = 10)
|
|
flash_color(C, flash_color=paint_color, flash_time=40)
|
|
if(ishuman(C) && actually_paints)
|
|
var/mob/living/carbon/human/H = C
|
|
H.lip_style = "spray_face"
|
|
H.lip_color = paint_color
|
|
H.update_body()
|
|
|
|
. = use_charges(user, 10, FALSE)
|
|
var/fraction = min(1, . / reagents.maximum_volume)
|
|
reagents.reaction(C, VAPOR, fraction * volume_multiplier)
|
|
|
|
return
|
|
|
|
if(isobj(target) && !istype(target, /obj/effect/decal/cleanable/crayon/gang))
|
|
if(actually_paints)
|
|
if(color_hex2num(paint_color) < 350 && !istype(target, /obj/structure/window) && !istype(target, /obj/effect/decal/cleanable/crayon)) //Colors too dark are rejected
|
|
to_chat(usr, "<span class='warning'>A color that dark on an object like this? Surely not...</span>")
|
|
return FALSE
|
|
|
|
target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
|
|
|
|
if(istype(target, /obj/structure/window))
|
|
if(color_hex2num(paint_color) < 255)
|
|
target.set_opacity(255)
|
|
else
|
|
target.set_opacity(initial(target.opacity))
|
|
|
|
. = use_charges(user, 2)
|
|
var/fraction = min(1, . / reagents.maximum_volume)
|
|
reagents.reaction(target, TOUCH, fraction * volume_multiplier)
|
|
reagents.trans_to(target, ., volume_multiplier, transfered_by = user)
|
|
|
|
if(pre_noise || post_noise)
|
|
playsound(user.loc, 'sound/effects/spray.ogg', 5, TRUE, 5)
|
|
user.visible_message("<span class='notice'>[user] coats [target] with spray paint!</span>", "<span class='notice'>You coat [target] with spray paint.</span>")
|
|
return
|
|
|
|
. = ..()
|
|
|
|
/obj/item/toy/crayon/spraycan/update_icon_state()
|
|
icon_state = is_capped ? icon_capped : icon_uncapped
|
|
|
|
/obj/item/toy/crayon/spraycan/update_overlays()
|
|
. = ..()
|
|
if(use_overlays)
|
|
var/mutable_appearance/spray_overlay = mutable_appearance('icons/obj/crayons.dmi', "[is_capped ? "spraycan_cap_colors" : "spraycan_colors"]")
|
|
spray_overlay.color = paint_color
|
|
. += spray_overlay
|
|
|
|
/obj/item/toy/crayon/spraycan/borg
|
|
name = "cyborg spraycan"
|
|
desc = "A metallic container containing shiny synthesised paint."
|
|
charges = -1
|
|
|
|
/obj/item/toy/crayon/spraycan/borg/afterattack(atom/target,mob/user,proximity, params)
|
|
var/diff = ..()
|
|
if(!iscyborg(user))
|
|
to_chat(user, "<span class='notice'>How did you get this?</span>")
|
|
qdel(src)
|
|
return FALSE
|
|
|
|
var/mob/living/silicon/robot/borgy = user
|
|
|
|
if(!diff)
|
|
return
|
|
// 25 is our cost per unit of paint, making it cost 25 energy per
|
|
// normal tag, 50 per window, and 250 per attack
|
|
var/cost = diff * 25
|
|
// Cyborgs shouldn't be able to use modules without a cell. But if they do
|
|
// it's free.
|
|
if(borgy.cell)
|
|
borgy.cell.use(cost)
|
|
|
|
/obj/item/toy/crayon/spraycan/hellcan
|
|
name = "hellcan"
|
|
desc = "This spraycan doesn't seem to be filled with paint..."
|
|
icon_state = "deathcan2_cap"
|
|
icon_capped = "deathcan2_cap"
|
|
icon_uncapped = "deathcan2"
|
|
use_overlays = FALSE
|
|
|
|
volume_multiplier = 25
|
|
charges = 100
|
|
reagent_contents = list(/datum/reagent/clf3 = 1)
|
|
actually_paints = FALSE
|
|
paint_color = "#000000"
|
|
|
|
/obj/item/toy/crayon/spraycan/lubecan
|
|
name = "slippery spraycan"
|
|
desc = "You can barely keep hold of this thing."
|
|
icon_state = "clowncan2_cap"
|
|
icon_capped = "clowncan2_cap"
|
|
icon_uncapped = "clowncan2"
|
|
use_overlays = FALSE
|
|
|
|
reagent_contents = list(/datum/reagent/lube = 1, /datum/reagent/consumable/banana = 1)
|
|
volume_multiplier = 5
|
|
|
|
/obj/item/toy/crayon/spraycan/lubecan/isValidSurface(surface)
|
|
return istype(surface, /turf/open/floor)
|
|
|
|
/obj/item/toy/crayon/spraycan/mimecan
|
|
name = "silent spraycan"
|
|
desc = "Art is best seen, not heard."
|
|
icon_state = "mimecan_cap"
|
|
icon_capped = "mimecan_cap"
|
|
icon_uncapped = "mimecan"
|
|
use_overlays = FALSE
|
|
|
|
can_change_colour = FALSE
|
|
paint_color = "#FFFFFF" //RGB
|
|
|
|
pre_noise = FALSE
|
|
post_noise = FALSE
|
|
reagent_contents = list(/datum/reagent/consumable/nothing = 1, /datum/reagent/toxin/mutetoxin = 1)
|
|
|
|
/obj/item/toy/crayon/spraycan/infinite
|
|
name = "infinite spraycan"
|
|
charges = -1
|
|
desc = "Now with 30% more bluespace technology."
|
|
|
|
#undef RANDOM_GRAFFITI
|
|
#undef RANDOM_LETTER
|
|
#undef RANDOM_PUNCTUATION
|
|
#undef RANDOM_SYMBOL
|
|
#undef RANDOM_DRAWING
|
|
#undef RANDOM_NUMBER
|
|
#undef RANDOM_ORIENTED
|
|
#undef RANDOM_RUNE
|
|
#undef RANDOM_ANY
|