Merge branch 'master' into upstream-merge-33590

This commit is contained in:
LetterJay
2017-12-25 21:29:18 -06:00
committed by GitHub
373 changed files with 2567 additions and 2775 deletions
+10 -3
View File
@@ -107,6 +107,8 @@ GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(target, procname, list/arguments)
var/current_caller = GLOB.AdminProcCaller
@@ -114,9 +116,14 @@ GLOBAL_PROTECT(LastAdminCalledProc)
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
+30 -1
View File
@@ -45,7 +45,8 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
/client/proc/manipulate_organs,
/client/proc/start_line_profiling,
/client/proc/stop_line_profiling,
/client/proc/show_line_profiling
/client/proc/show_line_profiling,
/client/proc/create_mapping_job_icons
))
/obj/effect/debugging/mapfix_marker
@@ -265,3 +266,31 @@ GLOBAL_VAR_INIT(say_disabled, FALSE)
message_admins("[src.ckey] used 'Disable all communication verbs', killing all communication methods.")
else
message_admins("[src.ckey] used 'Disable all communication verbs', restoring all communication methods.")
//This generates the icon states for job starting location landmarks.
/client/proc/create_mapping_job_icons()
set name = "Generate job landmarks icons"
set category = "Mapping"
var/icon/final = icon()
var/mob/living/carbon/human/dummy/D = new(locate(1,1,1)) //spawn on 1,1,1 so we don't have runtimes when items are deleted
D.setDir(SOUTH)
for(var/job in subtypesof(/datum/job))
var/datum/job/JB = new job
switch(JB.title)
if("AI")
final.Insert(icon('icons/mob/ai.dmi', "ai", SOUTH, 1), "AI")
if("Cyborg")
final.Insert(icon('icons/mob/robots.dmi', "robot", SOUTH, 1), "Cyborg")
else
for(var/obj/item/I in D)
qdel(I)
randomize_human(D)
JB.equip(D, TRUE, FALSE)
COMPILE_OVERLAYS(D)
var/icon/I = icon(getFlatIcon(D), frame = 1)
final.Insert(I, JB.title)
qdel(D)
//Also add the x
for(var/x_number in 1 to 4)
final.Insert(icon('icons/mob/screen_gen.dmi', "x[x_number == 1 ? "" : x_number]"), "x[x_number == 1 ? "" : x_number]")
fcopy(final, "icons/mob/landmarks.dmi")
+1 -1
View File
@@ -30,7 +30,7 @@
holder.update_icon()
/obj/item/device/assembly/flash/proc/clown_check(mob/living/carbon/human/user)
if(user.disabilities & CLUMSY && prob(50))
if(user.has_disability(CLUMSY) && prob(50))
flash_carbon(user, user, 15, 0)
return 0
return 1
+142 -142
View File
@@ -1,142 +1,142 @@
/obj/item/device/assembly/mousetrap
name = "mousetrap"
desc = "A handy little spring-loaded trap for catching pesty rodents."
icon_state = "mousetrap"
materials = list(MAT_METAL=100)
attachable = 1
var/armed = 0
/obj/item/device/assembly/mousetrap/examine(mob/user)
..()
if(armed)
to_chat(user, "The mousetrap is armed!")
else
to_chat(user, "The mousetrap is not armed.")
/obj/item/device/assembly/mousetrap/activate()
if(..())
armed = !armed
if(!armed)
if(ishuman(usr))
var/mob/living/carbon/human/user = usr
if((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY && prob(50))
to_chat(user, "<span class='warning'>Your hand slips, setting off the trigger!</span>")
pulse(0)
update_icon()
if(usr)
playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
/obj/item/device/assembly/mousetrap/describe()
return "The pressure switch is [armed?"primed":"safe"]."
/obj/item/device/assembly/mousetrap/update_icon()
if(armed)
icon_state = "mousetraparmed"
else
icon_state = "mousetrap"
if(holder)
holder.update_icon()
/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
if(!armed)
return
var/obj/item/bodypart/affecting = null
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(PIERCEIMMUNE in H.dna.species.species_traits)
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
armed = 0
update_icon()
pulse(0)
return 0
switch(type)
if("feet")
if(!H.shoes)
affecting = H.get_bodypart(pick("l_leg", "r_leg"))
H.Knockdown(60)
if("l_hand", "r_hand")
if(!H.gloves)
affecting = H.get_bodypart(type)
H.Stun(60)
if(affecting)
if(affecting.receive_damage(1, 0))
H.update_damage_overlays()
else if(ismouse(target))
var/mob/living/simple_animal/mouse/M = target
visible_message("<span class='boldannounce'>SPLAT!</span>")
M.splat()
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
armed = 0
update_icon()
pulse(0)
/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
if(!armed)
to_chat(user, "<span class='notice'>You arm [src].</span>")
else
if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50))
var/which_hand = "l_hand"
if(!(user.active_hand_index % 2))
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
to_chat(user, "<span class='notice'>You disarm [src].</span>")
armed = !armed
update_icon()
playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
if(armed)
if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50))
var/which_hand = "l_hand"
if(!(user.active_hand_index % 2))
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
..()
/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
if(armed)
if(ismob(AM))
var/mob/MM = AM
if(!(MM.movement_type & FLYING))
if(ishuman(AM))
var/mob/living/carbon/H = AM
if(H.m_intent == MOVE_INTENT_RUN)
triggered(H)
H.visible_message("<span class='warning'>[H] accidentally steps on [src].</span>", \
"<span class='warning'>You accidentally step on [src]</span>")
else if(ismouse(MM))
triggered(MM)
else if(AM.density) // For mousetrap grenades, set off by anything heavy
triggered(AM)
..()
/obj/item/device/assembly/mousetrap/on_found(mob/finder)
if(armed)
finder.visible_message("<span class='warning'>[finder] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand")
return 1 //end the search!
return 0
/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
if(!armed)
return ..()
visible_message("<span class='warning'>[src] is triggered by [A].</span>")
triggered(null)
/obj/item/device/assembly/mousetrap/armed
icon_state = "mousetraparmed"
armed = TRUE
/obj/item/device/assembly/mousetrap
name = "mousetrap"
desc = "A handy little spring-loaded trap for catching pesty rodents."
icon_state = "mousetrap"
materials = list(MAT_METAL=100)
attachable = 1
var/armed = 0
/obj/item/device/assembly/mousetrap/examine(mob/user)
..()
if(armed)
to_chat(user, "The mousetrap is armed!")
else
to_chat(user, "The mousetrap is not armed.")
/obj/item/device/assembly/mousetrap/activate()
if(..())
armed = !armed
if(!armed)
if(ishuman(usr))
var/mob/living/carbon/human/user = usr
if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
to_chat(user, "<span class='warning'>Your hand slips, setting off the trigger!</span>")
pulse(0)
update_icon()
if(usr)
playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
/obj/item/device/assembly/mousetrap/describe()
return "The pressure switch is [armed?"primed":"safe"]."
/obj/item/device/assembly/mousetrap/update_icon()
if(armed)
icon_state = "mousetraparmed"
else
icon_state = "mousetrap"
if(holder)
holder.update_icon()
/obj/item/device/assembly/mousetrap/proc/triggered(mob/target, type = "feet")
if(!armed)
return
var/obj/item/bodypart/affecting = null
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(PIERCEIMMUNE in H.dna.species.species_traits)
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
armed = 0
update_icon()
pulse(0)
return 0
switch(type)
if("feet")
if(!H.shoes)
affecting = H.get_bodypart(pick("l_leg", "r_leg"))
H.Knockdown(60)
if("l_hand", "r_hand")
if(!H.gloves)
affecting = H.get_bodypart(type)
H.Stun(60)
if(affecting)
if(affecting.receive_damage(1, 0))
H.update_damage_overlays()
else if(ismouse(target))
var/mob/living/simple_animal/mouse/M = target
visible_message("<span class='boldannounce'>SPLAT!</span>")
M.splat()
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
armed = 0
update_icon()
pulse(0)
/obj/item/device/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
if(!armed)
to_chat(user, "<span class='notice'>You arm [src].</span>")
else
if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
var/which_hand = "l_hand"
if(!(user.active_hand_index % 2))
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
to_chat(user, "<span class='notice'>You disarm [src].</span>")
armed = !armed
update_icon()
playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
/obj/item/device/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
if(armed)
if((user.has_disability(DUMB) || user.has_disability(CLUMSY)) && prob(50))
var/which_hand = "l_hand"
if(!(user.active_hand_index % 2))
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
..()
/obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj)
if(armed)
if(ismob(AM))
var/mob/MM = AM
if(!(MM.movement_type & FLYING))
if(ishuman(AM))
var/mob/living/carbon/H = AM
if(H.m_intent == MOVE_INTENT_RUN)
triggered(H)
H.visible_message("<span class='warning'>[H] accidentally steps on [src].</span>", \
"<span class='warning'>You accidentally step on [src]</span>")
else if(ismouse(MM))
triggered(MM)
else if(AM.density) // For mousetrap grenades, set off by anything heavy
triggered(AM)
..()
/obj/item/device/assembly/mousetrap/on_found(mob/finder)
if(armed)
finder.visible_message("<span class='warning'>[finder] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand")
return 1 //end the search!
return 0
/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
if(!armed)
return ..()
visible_message("<span class='warning'>[src] is triggered by [A].</span>")
triggered(null)
/obj/item/device/assembly/mousetrap/armed
icon_state = "mousetraparmed"
armed = 1
+1 -1
View File
@@ -41,7 +41,7 @@
/obj/item/clothing/glasses/proc/thermal_overload()
if(ishuman(src.loc))
var/mob/living/carbon/human/H = src.loc
if(!(H.disabilities & BLIND))
if(!(H.has_disability(BLIND)))
if(H.glasses == src)
to_chat(H, "<span class='danger'>[src] overloads and blinds you!</span>")
H.flash_act(visual = 1)
+3 -3
View File
@@ -13,7 +13,7 @@
var/max_severity = 3
/datum/round_event/disease_outbreak/announce()
/datum/round_event/disease_outbreak/announce(fake)
priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak7.ogg')
/datum/round_event/disease_outbreak/setup()
@@ -33,7 +33,7 @@
var/turf/T = get_turf(H)
if(!T)
continue
if(T.z != ZLEVEL_STATION_PRIMARY)
if(!(T.z in GLOB.station_z_levels))
continue
if(!H.client)
continue
@@ -51,7 +51,7 @@
var/datum/disease/D
if(!advanced_virus)
if(virus_type == /datum/disease/dnaspread) //Dnaspread needs strain_data set to work.
if(!H.dna || (H.disabilities & BLIND)) //A blindness disease would be the worst.
if(!H.dna || (H.has_disability(BLIND))) //A blindness disease would be the worst.
continue
D = new virus_type()
var/datum/disease/dnaspread/DS = D
+4 -21
View File
@@ -1,19 +1,3 @@
/datum/round_event_control/treevenge
name = "Treevenge (Christmas)"
holidayID = CHRISTMAS
typepath = /datum/round_event/treevenge
max_occurrences = 1
weight = 20
/datum/round_event/treevenge/start()
for(var/obj/structure/flora/tree/pine/xmas in world)
var/mob/living/simple_animal/hostile/tree/evil_tree = new /mob/living/simple_animal/hostile/tree(xmas.loc)
evil_tree.icon_state = xmas.icon_state
evil_tree.icon_living = evil_tree.icon_state
evil_tree.icon_dead = evil_tree.icon_state
evil_tree.icon_gib = evil_tree.icon_state
qdel(xmas) //b-but I don't want to delete xmas...
//this is an example of a possible round-start event
/datum/round_event_control/presents
name = "Presents under Trees (Christmas)"
@@ -24,12 +8,11 @@
earliest_start = 0
/datum/round_event/presents/start()
for(var/obj/structure/flora/tree/pine/xmas in world)
for(var/obj/structure/flora/tree/pine/xmas/xmas in world)
if(!(xmas.z in GLOB.station_z_levels))
continue
for(var/turf/open/floor/T in orange(1,xmas))
for(var/i=1,i<=rand(1,5),i++)
new /obj/item/a_gift(T)
xmas.icon_state = "pinepresents"
xmas.gifts_under_tree = TRUE
for(var/mob/living/simple_animal/pet/dog/corgi/Ian/Ian in GLOB.mob_living_list)
Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
for(var/obj/machinery/computer/security/telescreen/entertainment/Monitor in GLOB.machines)
@@ -98,7 +81,7 @@
name = "Santa is coming to town! (Christmas)"
holidayID = CHRISTMAS
typepath = /datum/round_event/santa
weight = 150
weight = 20
max_occurrences = 1
earliest_start = 20000
@@ -1,4 +1,3 @@
/obj/machinery/gibber
name = "gibber"
desc = "The name isn't descriptive enough?"
@@ -12,10 +11,10 @@
circuit = /obj/item/circuitboard/machine/gibber
var/operating = FALSE //Is it on?
var/dirty = 0 // Does it need cleaning?
var/dirty = FALSE // Does it need cleaning?
var/gibtime = 40 // Time from starting until meat appears
var/meat_produced = 0
var/ignore_clothing = 0
var/ignore_clothing = FALSE
/obj/machinery/gibber/Initialize()
@@ -30,7 +29,7 @@
gib_time -= 5 * M.rating
gibtime = gib_time
if(M.rating >= 2)
ignore_clothing = 1
ignore_clothing = TRUE
/obj/machinery/gibber/update_icon()
cut_overlays()
@@ -61,6 +60,10 @@
to_chat(user, "<span class='danger'>It's locked and running.</span>")
return
if(!anchored)
to_chat(user, "<span class='notice'>[src] cannot be used unless bolted to the ground.</span>")
return
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/L = user.pulling
if(!iscarbon(L))
@@ -70,12 +73,17 @@
if(C.buckled ||C.has_buckled_mobs())
to_chat(user, "<span class='warning'>[C] is attached to something!</span>")
return
if(C.abiotic(1) && !ignore_clothing)
to_chat(user, "<span class='danger'>Subject may not have abiotic items on.</span>")
return
if(!ignore_clothing)
for(var/obj/item/I in C.held_items + C.get_equipped_items())
if(!(I.flags_1 & NODROP_1))
to_chat(user, "<span class='danger'>Subject may not have abiotic items on.</span>")
return
user.visible_message("<span class='danger'>[user] starts to put [C] into the gibber!</span>")
src.add_fingerprint(user)
add_fingerprint(user)
if(do_after(user, gibtime, target = src))
if(C && user.pulling == C && !C.buckled && !C.has_buckled_mobs() && !occupant)
user.visible_message("<span class='danger'>[user] stuffs [C] into the gibber!</span>")
+2 -2
View File
@@ -387,9 +387,9 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
/datum/holiday/xmas
name = CHRISTMAS
begin_day = 23
begin_day = 22
begin_month = DECEMBER
end_day = 25
end_day = 27
/datum/holiday/xmas/greet()
return "Have a merry Christmas!"
+2 -2
View File
@@ -146,7 +146,7 @@
/obj/item/reagent_containers/food/snacks/grown/on_grind()
var/nutriment = reagents.get_reagent_amount("nutriment")
if(grind_results.len)
if(grind_results&&grind_results.len)
for(var/i in 1 to grind_results.len)
grind_results[grind_results[i]] = nutriment
reagents.del_reagent("nutriment")
@@ -154,7 +154,7 @@
/obj/item/reagent_containers/food/snacks/grown/on_juice()
var/nutriment = reagents.get_reagent_amount("nutriment")
if(juice_results.len)
if(juice_results&&juice_results.len)
for(var/i in 1 to juice_results.len)
juice_results[juice_results[i]] = nutriment
reagents.del_reagent("nutriment")
@@ -20,6 +20,8 @@
var/charge_tick = FALSE
var/charge_delay = 4
var/use_cyborg_cell = TRUE
max_integrity = 50
armor = list(melee = 50, bullet = 70, laser = 70, energy = 100, bomb = 10, bio = 100, rad = 100, fire = 0, acid = 0)
/obj/item/device/electronic_assembly/proc/check_interactivity(mob/user)
return user.canUseTopic(src,be_close = TRUE)
@@ -30,8 +32,6 @@
START_PROCESSING(SScircuit, src)
materials[MAT_METAL] = round((max_complexity + max_components) / 4) * SScircuit.cost_multiplier
/obj/item/device/electronic_assembly/Destroy()
STOP_PROCESSING(SScircuit, src)
return ..()
@@ -273,22 +273,9 @@
/obj/item/device/electronic_assembly/afterattack(atom/target, mob/user, proximity)
for(var/obj/item/integrated_circuit/input/sensor/S in assembly_components)
if(!proximity)
if(istype(S,/obj/item/integrated_circuit/input/sensor/ranged)||(!user))
if(user.client)
if(!(target in view(user.client)))
continue
else
if(!(target in view(user)))
continue
else
continue
S.set_pin_data(IC_OUTPUT, 1, WEAKREF(target))
S.check_then_do_work()
S.scan(target)
visible_message("<span class='notice'> [user] waves [src] around [target].</span>")
for(var/obj/item/integrated_circuit/input/S in assembly_components)
if(S.sense(target,user,proximity))
visible_message("<span class='notice'> [user] waves [src] around [target].</span>")
/obj/item/device/electronic_assembly/screwdriver_act(mob/living/user, obj/item/S)
@@ -326,8 +313,11 @@
interact(user)
return TRUE
else
for(var/obj/item/integrated_circuit/input/S in assembly_components)
S.attackby_react(I,user,user.a_intent)
return ..()
/obj/item/device/electronic_assembly/attack_self(mob/user)
if(!check_interactivity(user))
return
@@ -391,7 +381,6 @@
/obj/item/device/electronic_assembly/proc/get_object()
return src
// Returns the location to be used for dropping items.
// Same as the regular drop_location(), but with checks being run on acting_object if necessary.
/obj/item/integrated_circuit/drop_location()
@@ -406,6 +395,7 @@
/obj/item/device/electronic_assembly/default //The /default electronic_assemblys are to allow the introduction of the new naming scheme without breaking old saves.
name = "type-a electronic assembly"
/obj/item/device/electronic_assembly/calc
name = "type-b electronic assembly"
icon_state = "setup_small_calc"
@@ -507,4 +497,4 @@
/obj/item/device/electronic_assembly/drone/arms
name = "type-b electronic drone"
icon_state = "setup_drone_arms"
desc = "It's a case, for building mobile electronics with. This one is armed and dangerous."
desc = "It's a case, for building mobile electronics with. This one is armed and dangerous."
@@ -56,7 +56,7 @@
data_to_show = A.name
to_chat(user, "<span class='notice'>You write '[data_to_write ? data_to_show : "NULL"]' to the '[io]' pin of \the [io.holder].</span>")
else if(io.io_type == PULSE_CHANNEL)
io.holder.check_then_do_work(ignore_power = TRUE)
io.holder.check_then_do_work(io.ord,ignore_power = TRUE)
to_chat(user, "<span class='notice'>You pulse \the [io.holder]'s [io].</span>")
io.holder.interact(user) // This is to update the UI.
@@ -15,9 +15,9 @@
io_type_override = io_list_copy[io_entry]
if(io_type_override)
io_list.Add(new io_type_override(src, io_entry, default_data, pin_type))
io_list.Add(new io_type_override(src, io_entry, default_data, pin_type,i))
else
io_list.Add(new io_type(src, io_entry, default_data, pin_type))
io_list.Add(new io_type(src, io_entry, default_data, pin_type,i))
/obj/item/integrated_circuit/proc/set_pin_data(pin_type, pin_number, datum/new_data)
@@ -58,6 +58,12 @@ a creative player the means to solve many problems. Circuits are held inside an
/obj/item/integrated_circuit/proc/any_examine(mob/user)
return
/obj/item/integrated_circuit/proc/attackby_react(var/atom/movable/A,mob/user)
return
/obj/item/integrated_circuit/proc/sense(var/atom/movable/A,mob/user,prox)
return
/obj/item/integrated_circuit/proc/check_interactivity(mob/user)
if(assembly)
return assembly.check_interactivity(user)
@@ -291,17 +297,18 @@ a creative player the means to solve many problems. Circuits are held inside an
return TRUE // Battery has enough.
return FALSE // Not enough power.
/obj/item/integrated_circuit/proc/check_then_do_work(var/ignore_power = FALSE)
/obj/item/integrated_circuit/proc/check_then_do_work(ord,var/ignore_power = FALSE)
if(world.time < next_use) // All intergrated circuits have an internal cooldown, to protect from spam.
return
return FALSE
if(power_draw_per_use && !ignore_power)
if(!check_power())
power_fail()
return
return FALSE
next_use = world.time + cooldown_per_use
do_work()
do_work(ord)
return TRUE
/obj/item/integrated_circuit/proc/do_work()
/obj/item/integrated_circuit/proc/do_work(ord)
return
/obj/item/integrated_circuit/proc/disconnect_all()
@@ -369,4 +376,3 @@ a creative player the means to solve many problems. Circuits are held inside an
return TRUE
return FALSE
@@ -25,14 +25,16 @@ D [1]/ ||
var/list/linked = list()
var/io_type = DATA_CHANNEL
var/pin_type // IC_INPUT, IC_OUTPUT, IC_ACTIVATOR - used in saving assembly wiring
var/ord
/datum/integrated_io/New(loc, _name, _data, _pin_type)
/datum/integrated_io/New(loc, _name, _data, _pin_type,_ord)
name = _name
if(_data)
data = _data
if(_pin_type)
pin_type = _pin_type
if(_ord)
ord = _ord
holder = loc
@@ -148,7 +150,7 @@ D [1]/ ||
/datum/integrated_io/activate/push_data()
for(var/k in 1 to linked.len)
var/datum/integrated_io/io = linked[k]
io.holder.check_then_do_work()
io.holder.check_then_do_work(io.ord)
/datum/integrated_io/proc/pull_data()
for(var/k in 1 to linked.len)
@@ -207,7 +209,7 @@ D [1]/ ||
write_data_to_pin(new_data)
/datum/integrated_io/activate/ask_for_pin_data(mob/user) // This just pulses the pin.
holder.check_then_do_work(ignore_power = TRUE)
holder.check_then_do_work(ord,ignore_power = TRUE)
to_chat(user, "<span class='notice'>You pulse \the [holder]'s [src] pin.</span>")
/datum/integrated_io/activate
@@ -1,4 +1,4 @@
// These pins can only contain integer numbers between 1 and IC_MAX_LIST_LENGTH. Null is not allowed.
// These pins can only contain integer numbers between 0 and IC_MAX_LIST_LENGTH. Null is allowed.
/datum/integrated_io/index
name = "index pin"
data = 1
@@ -11,10 +11,10 @@
/datum/integrated_io/index/write_data_to_pin(new_data)
if(isnull(new_data))
new_data = 1
new_data = 0
if(isnum(new_data))
data = CLAMP(round(new_data), 1, IC_MAX_LIST_LENGTH)
data = CLAMP(round(new_data), 0, IC_MAX_LIST_LENGTH)
holder.on_data_written()
/datum/integrated_io/index/display_pin_type()
@@ -30,10 +30,9 @@
/obj/item/integrated_circuit/arithmetic/addition/do_work()
var/result = 0
for(var/k in 1 to inputs.len)
var/datum/integrated_io/I = inputs[k]
I.pull_data()
if(isnum(I.data))
result = result + I.data
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I))
result += I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -56,13 +55,10 @@
return
var/result = A.data
for(var/k in 1 to inputs.len)
var/datum/integrated_io/I = inputs[k]
if(I == A)
continue
I.pull_data()
if(isnum(I.data))
result = result - I.data
for(var/k in 2 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I))
result -= I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -85,13 +81,10 @@
if(!isnum(A.data))
return
var/result = A.data
for(var/k in 1 to inputs.len)
var/datum/integrated_io/I = inputs[k]
if(I == A)
continue
I.pull_data()
if(isnum(I.data))
result = result * I.data
for(var/k in 2 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I))
result *= I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -114,13 +107,12 @@
return
var/result = A.data
for(var/k in 1 to inputs.len)
var/datum/integrated_io/I = inputs[k]
if(I == A)
continue
I.pull_data()
if(isnum(I.data) && I.data != 0) //No runtimes here.
result = result / I.data
for(var/k in 2 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I) && (I != 0))
result /= I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -228,12 +220,11 @@
/obj/item/integrated_circuit/arithmetic/average/do_work()
var/result = 0
var/inputs_used = 0
for(var/k in 1 to inputs.len)
var/datum/integrated_io/I = inputs[k]
I.pull_data()
if(isnum(I.data))
for(var/k in 2 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I))
inputs_used++
result = result + I.data
result += I
if(inputs_used)
result = result / inputs_used
@@ -288,11 +279,10 @@
/obj/item/integrated_circuit/arithmetic/square_root/do_work()
var/result = 0
for(var/k in 1 to inputs.len)
var/datum/integrated_io/I = inputs[k]
I.pull_data()
if(isnum(I.data))
result = sqrt(I.data)
for(var/k in 2 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(isnum(I))
result += sqrt(I)
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -160,10 +160,10 @@
/obj/item/integrated_circuit/converter/concatenator/do_work()
var/result = null
for(var/datum/integrated_io/I in inputs)
I.pull_data()
if(!isnull(I.data))
result = result + I.data
for(var/k in 1 to inputs.len)
var/I = get_pin_data(IC_INPUT, k)
if(!isnull(I))
result = result + I
set_pin_data(IC_OUTPUT, 1, result)
push_data()
@@ -128,7 +128,7 @@
var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living/carbon/human)
if(!istype(H)) //Invalid input
return
if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range..
if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
var/total_health = round(H.health/H.getMaxHealth(), 0.01)*100
var/missing_health = H.getMaxHealth() - H.health
@@ -143,6 +143,49 @@
push_data()
activate_pin(2)
/obj/item/integrated_circuit/input/slime_scanner
name = "slime_scanner"
desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime."
icon_state = "medscan_adv"
complexity = 12
inputs = list("\<REF\> target")
outputs = list(
"colour" = IC_PINTYPE_STRING,
"adult" = IC_PINTYPE_BOOLEAN,
"nutrition" = IC_PINTYPE_NUMBER,
"charge" = IC_PINTYPE_NUMBER,
"health" = IC_PINTYPE_NUMBER,
"possible mutation" = IC_PINTYPE_LIST,
"genetic destability"= IC_PINTYPE_NUMBER,
"slime core amount" = IC_PINTYPE_NUMBER,
"Growth progress" = IC_PINTYPE_NUMBER,
)
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 80
/obj/item/integrated_circuit/input/slime_scanner/do_work()
var/mob/living/simple_animal/slime/T = get_pin_data_as_type(IC_INPUT, 1, /mob/living/simple_animal/slime)
if(!isslime(T)) //Invalid input
return
if(T in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
set_pin_data(IC_OUTPUT, 1, T.colour)
set_pin_data(IC_OUTPUT, 2, T.is_adult)
set_pin_data(IC_OUTPUT, 3, T.nutrition/T.get_max_nutrition())
set_pin_data(IC_OUTPUT, 4, T.powerlevel)
set_pin_data(IC_OUTPUT, 5, round(T.health/T.maxHealth,0.01)*100)
set_pin_data(IC_OUTPUT, 6, uniqueList(T.slime_mutation))
set_pin_data(IC_OUTPUT, 7, T.mutation_chance)
set_pin_data(IC_OUTPUT, 8, T.cores)
set_pin_data(IC_OUTPUT, 9, T.amount_grown/SLIME_EVOLUTION_THRESHOLD)
push_data()
activate_pin(2)
/obj/item/integrated_circuit/input/plant_scanner
name = "integrated plant analyzer"
desc = "A very small version of the plant analyser. This allows the machine to know all valuable params of plants in trays. \
@@ -180,7 +223,7 @@
return
for(var/i=1, i<=outputs.len, i++)
set_pin_data(IC_OUTPUT, i, null)
if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range..
if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
if(H.myseed)
set_pin_data(IC_OUTPUT, 1, H.myseed.plantname)
set_pin_data(IC_OUTPUT, 2, H.age)
@@ -228,7 +271,7 @@
return
for(var/i=1, i<=outputs.len, i++)
set_pin_data(IC_OUTPUT, i, null)
if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range..
if(H in view(get_turf(src))) // Like medbot's analyzer it can be used in range..
if(H.myseed)
for(var/datum/plant_gene/reagent/G in H.myseed.genes)
greagents.Add(G.get_name())
@@ -671,12 +714,15 @@
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 120
/obj/item/integrated_circuit/input/sensor/proc/scan(var/atom/A)
/obj/item/integrated_circuit/input/sensor/sense(var/atom/A,mob/user,prox)
if(!prox)
return FALSE
if(!check_then_do_work())
return FALSE
var/ignore_bags = get_pin_data(IC_INPUT, 1)
if(ignore_bags)
if(istype(A, /obj/item/storage))
return FALSE
set_pin_data(IC_OUTPUT, 1, WEAKREF(A))
push_data()
activate_pin(1)
@@ -694,6 +740,52 @@
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 120
/obj/item/integrated_circuit/input/sensor/ranged/sense(var/atom/A,mob/user)
if(!user)
return FALSE
if(user.client)
if(!(A in view(user.client)))
return FALSE
else
if(!(A in view(user)))
return FALSE
if(!check_then_do_work())
return FALSE
var/ignore_bags = get_pin_data(IC_INPUT, 1)
if(ignore_bags)
if(istype(A, /obj/item/storage))
return FALSE
set_pin_data(IC_OUTPUT, 1, WEAKREF(A))
push_data()
activate_pin(1)
return TRUE
/obj/item/integrated_circuit/input/objscaner
name = "scaner"
desc = "Scans and obtains a reference for any objects you use on assembly."
extended_desc = "If 'put down' pin is set to true, assembly will take scanned object from your hands to it's location.\
useful for interaction with grabber. Scaner works only with help intent."
icon_state = "recorder"
complexity = 4
inputs = list("put down" = IC_PINTYPE_BOOLEAN)
outputs = list("scanned" = IC_PINTYPE_REF)
activators = list("on scanned" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 20
/obj/item/integrated_circuit/input/objscaner/attackby_react(var/atom/A,var/mob/user,intent)
if(intent!=INTENT_HELP)
return FALSE
if(!check_then_do_work())
return FALSE
var/pu = get_pin_data(IC_INPUT, 1)
if(pu)
user.transferItemToLoc(A,drop_location())
set_pin_data(IC_OUTPUT, 1, WEAKREF(A))
push_data()
activate_pin(1)
return TRUE
/obj/item/integrated_circuit/input/internalbm
name = "internal battery monitor"
desc = "This monitors the charge level of an internal battery."
@@ -760,3 +852,38 @@
activate_pin(2)
push_data()
return
/obj/item/integrated_circuit/input/ntnetsc
name = "NTnet scaner"
desc = "This can return NTnet id of component insi given object, if there is any."
icon_state = "signalsc"
w_class = WEIGHT_CLASS_TINY
complexity = 2
inputs = list("target" = IC_PINTYPE_REF)
outputs = list(
"id" = IC_PINTYPE_STRING
)
activators = list("read" = IC_PINTYPE_PULSE_IN, "found" = IC_PINTYPE_PULSE_OUT,"not found" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 1
/obj/item/integrated_circuit/input/ntnetsc/do_work()
var/atom/AM = get_pin_data_as_type(IC_INPUT, 1, /atom)
var/list/processing_list = list(AM)
var/datum/component/ntnet_interface/net = null
set_pin_data(IC_OUTPUT, 1, null)
while(processing_list.len && !net)
var/atom/A = processing_list[1]
processing_list.Cut(1, 2)
//Byond does not allow things to be in multiple contents, or double parent-child hierarchies, so only += is needed
//This is also why we don't need to check against assembled as we go along
processing_list += A.contents
net = A.GetComponent(/datum/component/ntnet_interface)
if(net)
set_pin_data(IC_OUTPUT, 1, net.hardware_id)
activate_pin(2)
else
activate_pin(3)
push_data()
return
@@ -2,7 +2,7 @@
name = "logic gate"
desc = "This tiny chip will decide for you!"
extended_desc = "Logic circuits will treat a null, 0, and a \"\" string value as FALSE and anything else as TRUE."
complexity = 3
complexity = 1
outputs = list("result")
activators = list("compare" = IC_PINTYPE_PULSE_IN)
category_text = "Logic"
@@ -155,9 +155,11 @@
if(isnum(wanted_dir.data))
if(step(assembly, wanted_dir.data))
activate_pin(2)
return
else
activate_pin(3)
return FALSE
return FALSE
/obj/item/integrated_circuit/manipulation/grenade
name = "grenade primer"
@@ -247,9 +249,14 @@
/obj/item/integrated_circuit/manipulation/plant_module/do_work()
..()
var/turf/T = get_turf(src)
var/obj/machinery/hydroponics/AM = get_pin_data_as_type(IC_INPUT, 1, /obj/machinery/hydroponics)
if(!istype(AM)) //Invalid input
var/obj/OM = get_pin_data_as_type(IC_INPUT, 1, /obj)
if(istype(OM,/obj/structure/spacevine) && get_pin_data(IC_INPUT, 2) == 2)
qdel(OM)
activate_pin(2)
return
var/obj/machinery/hydroponics/AM = OM
if(!istype(AM)) //Invalid input
return FALSE
var/mob/living/M = get_turf(AM)
if(!M.Adjacent(T))
return //Can't reach
@@ -276,6 +283,7 @@
qdel(AM.myseed)
AM.myseed = null
AM.weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
AM.dead = 0
AM.update_icon()
else
activate_pin(2)
@@ -284,7 +292,7 @@
/obj/item/integrated_circuit/manipulation/grabber
name = "grabber"
desc = "A circuit with it's own inventory for small/medium items, used to grab and store things."
desc = "A circuit with it's own inventory for tiny/small items, used to grab and store things."
icon_state = "grabber"
extended_desc = "The circuit accepts a reference to thing to be grabbed. It can store up to 10 things. Modes: 1 for grab. 0 for eject the first thing. -1 for eject all."
w_class = WEIGHT_CLASS_SMALL
@@ -307,7 +315,7 @@
var/mode = get_pin_data(IC_INPUT, 2)
if(mode == 1)
if(check_target(AM, exclude_contents = TRUE))
if(check_target(AM))
if((contents.len < max_items) && (!max_w_class || AM.w_class <= max_w_class))
AM.forceMove(src)
if(mode == 0)
@@ -9,6 +9,11 @@
. = ..()
if(volume)
create_reagents(volume)
push_vol()
/obj/item/integrated_circuit/reagent/proc/push_vol()
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
push_data()
/obj/item/integrated_circuit/reagent/smoke
name = "smoke generator"
@@ -29,7 +34,8 @@
)
activators = list(
"create smoke" = IC_PINTYPE_PULSE_IN,
"on smoked" = IC_PINTYPE_PULSE_OUT
"on smoked" = IC_PINTYPE_PULSE_OUT,
"push ref" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_RESEARCH
power_draw_per_use = 20
@@ -40,24 +46,27 @@
//reset warning only if we have reagents now
if(changetype == ADD_REAGENT)
notified = FALSE
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
push_data()
push_vol()
/obj/item/integrated_circuit/reagent/smoke/do_work()
if(!reagents || (reagents.total_volume < IC_SMOKE_REAGENTS_MINIMUM_UNITS))
return
var/location = get_turf(src)
var/datum/effect_system/smoke_spread/chem/S = new
S.attach(location)
playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
if(S)
S.set_up(reagents, smoke_radius, location, notified)
if(!notified)
notified = TRUE
S.start()
reagents.clear_reagents()
activate_pin(2)
/obj/item/integrated_circuit/reagent/smoke/do_work(ord)
switch(ord)
if(1)
if(!reagents || (reagents.total_volume < IC_SMOKE_REAGENTS_MINIMUM_UNITS))
return
var/location = get_turf(src)
var/datum/effect_system/smoke_spread/chem/S = new
S.attach(location)
playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
if(S)
S.set_up(reagents, smoke_radius, location, notified)
if(!notified)
notified = TRUE
S.start()
reagents.clear_reagents()
activate_pin(2)
if(3)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
/obj/item/integrated_circuit/reagent/injector
name = "integrated hypo-injector"
@@ -85,7 +94,9 @@
activators = list(
"inject" = IC_PINTYPE_PULSE_IN,
"on injected" = IC_PINTYPE_PULSE_OUT,
"on fail" = IC_PINTYPE_PULSE_OUT
"on fail" = IC_PINTYPE_PULSE_OUT,
"push ref" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
power_draw_per_use = 15
@@ -93,15 +104,8 @@
var/transfer_amount = 10
var/busy = FALSE
/obj/item/integrated_circuit/reagent/injector/interact(mob/user)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
..()
/obj/item/integrated_circuit/reagent/injector/on_reagent_change(changetype)
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
push_data()
push_vol()
/obj/item/integrated_circuit/reagent/injector/on_data_written()
var/new_amount = get_pin_data(IC_INPUT, 2)
@@ -127,7 +131,15 @@
temp_reagents.clear_reagents()
qdel(temp_reagents)
/obj/item/integrated_circuit/reagent/injector/do_work()
/obj/item/integrated_circuit/reagent/injector/do_work(ord)
switch(ord)
if(1)
inject()
if(4)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
/obj/item/integrated_circuit/reagent/injector/proc/inject()
set waitfor = FALSE // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing
var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable)
var/atom/movable/acting_object = get_object()
@@ -281,17 +293,15 @@
"volume used" = IC_PINTYPE_NUMBER,
"self reference" = IC_PINTYPE_REF
)
activators = list()
activators = list("push ref" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/reagent/storage/interact(mob/user)
/obj/item/integrated_circuit/reagent/storage/do_work()
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
..()
/obj/item/integrated_circuit/reagent/storage/on_reagent_change(changetype)
set_pin_data(IC_OUTPUT, 1, reagents.total_volume)
push_data()
push_vol()
/obj/item/integrated_circuit/reagent/storage/cryo
name = "cryo reagent storage"
@@ -306,6 +316,7 @@
. = ..()
reagents.set_reacting(FALSE)
/obj/item/integrated_circuit/reagent/storage/big
name = "big reagent storage"
desc = "Stores liquid inside, and away from electrical components. Can store up to 180u."
@@ -317,6 +328,99 @@
complexity = 16
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/reagent/storage/grinder
name = "reagent grinder"
desc = "This is reagent grinder.It accepts ref to something and refines it into reagents. Can store up to 100u."
icon_state = "blender"
extended_desc = ""
inputs = list(
"target" = IC_PINTYPE_REF,
)
outputs = list(
"volume used" = IC_PINTYPE_NUMBER,
"self reference" = IC_PINTYPE_REF
)
activators = list(
"grind" = IC_PINTYPE_PULSE_IN,
"on grind" = IC_PINTYPE_PULSE_OUT,
"on fail" = IC_PINTYPE_PULSE_OUT,
"push ref" = IC_PINTYPE_PULSE_IN
)
volume = 100
power_draw_per_use = 150
complexity = 16
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/reagent/storage/grinder/do_work(ord)
switch(ord)
if(1)
grind()
if(4)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
/obj/item/integrated_circuit/reagent/storage/grinder/proc/grind()
if(reagents.total_volume >= reagents.maximum_volume)
activate_pin(3)
return FALSE
var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
if(istype(I)&&(I.grind_results)&&check_target(I)&&(I.on_grind(src) != -1))
reagents.add_reagent_list(I.grind_results)
if(I.reagents)
I.reagents.trans_to(src, I.reagents.total_volume)
qdel(I)
activate_pin(2)
return TRUE
activate_pin(3)
return FALSE
obj/item/integrated_circuit/reagent/storage/juicer
name = "reagent juicer"
desc = "This is reagent juicer.It accepts ref to something and refines it into reagents. Can store up to 100u."
icon_state = "blender"
extended_desc = ""
inputs = list(
"target" = IC_PINTYPE_REF,
)
outputs = list(
"volume used" = IC_PINTYPE_NUMBER,
"self reference" = IC_PINTYPE_REF
)
activators = list(
"juice" = IC_PINTYPE_PULSE_IN,
"on juice" = IC_PINTYPE_PULSE_OUT,
"on fail" = IC_PINTYPE_PULSE_OUT,
"push ref" = IC_PINTYPE_PULSE_IN
)
volume = 100
power_draw_per_use = 150
complexity = 16
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/reagent/storage/juicer/do_work(ord)
switch(ord)
if(1)
juice()
if(4)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
/obj/item/integrated_circuit/reagent/storage/juicer/proc/juice()
if(reagents.total_volume >= reagents.maximum_volume)
activate_pin(3)
return FALSE
var/obj/item/I = get_pin_data_as_type(IC_INPUT, 1, /obj/item)
if(istype(I)&&check_target(I)&&(I.juice_results)&&(I.on_juice() != -1))
reagents.add_reagent_list(I.juice_results)
qdel(I)
activate_pin(2)
return TRUE
activate_pin(3)
return FALSE
/obj/item/integrated_circuit/reagent/storage/scan
name = "reagent scanner"
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. On pulse this beaker will send list of contained reagents."
@@ -330,17 +434,22 @@
"list of reagents" = IC_PINTYPE_LIST
)
activators = list(
"scan" = IC_PINTYPE_PULSE_IN
"scan" = IC_PINTYPE_PULSE_IN,
"push ref" = IC_PINTYPE_PULSE_IN
)
spawn_flags = IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/reagent/storage/scan/do_work()
var/cont[0]
for(var/datum/reagent/RE in reagents.reagent_list)
cont += RE.id
set_pin_data(IC_OUTPUT, 3, cont)
push_data()
/obj/item/integrated_circuit/reagent/storage/scan/do_work(ord)
switch(ord)
if(1)
var/cont[0]
for(var/datum/reagent/RE in reagents.reagent_list)
cont += RE.id
set_pin_data(IC_OUTPUT, 3, cont)
push_data()
if(2)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
push_data()
/obj/item/integrated_circuit/reagent/filter
name = "reagent filter"
@@ -394,7 +503,8 @@
if(!source.reagents || !target.reagents)
return
if(!source.is_drainable() || !target.is_refillable())
// FALSE in those procs makes mobs invalid targets.
if(!source.is_drawable(FALSE) || !target.is_injectable(FALSE))
return
if(target.reagents.maximum_volume - target.reagents.total_volume <= 0)
@@ -410,3 +520,45 @@
activate_pin(2)
push_data()
/obj/item/integrated_circuit/reagent/storage/heater
name = "chemical heater"
desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. Will heat or freeze reagents \
to target temperature, when turned on."
icon_state = "heater"
container_type = OPENCONTAINER
complexity = 8
inputs = list(
"target temperature" = IC_PINTYPE_NUMBER,
"on" = IC_PINTYPE_BOOLEAN
)
inputs_default = list("1" = 300)
outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF,"temperature" = IC_PINTYPE_NUMBER)
spawn_flags = IC_SPAWN_RESEARCH
var/heater_coefficient = 0.1
/obj/item/integrated_circuit/reagent/storage/heater/on_data_written()
if(get_pin_data(IC_INPUT, 2))
power_draw_idle = 30
else
power_draw_idle = 0
/obj/item/integrated_circuit/reagent/storage/heater/Initialize()
.=..()
START_PROCESSING(SScircuit, src)
/obj/item/integrated_circuit/reagent/storage/heater/Destroy()
STOP_PROCESSING(SScircuit, src)
return ..()
/obj/item/integrated_circuit/reagent/storage/heater/process()
if(power_draw_idle)
var/target_temperature = get_pin_data(IC_INPUT, 1)
if(reagents.chem_temp > target_temperature)
reagents.chem_temp += min(-1, (target_temperature - reagents.chem_temp) * heater_coefficient)
if(reagents.chem_temp < target_temperature)
reagents.chem_temp += max(1, (target_temperature - reagents.chem_temp) * heater_coefficient)
reagents.chem_temp = round(reagents.chem_temp)
reagents.handle_reactions()
set_pin_data(IC_OUTPUT, 3, reagents.chem_temp)
push_data()
@@ -27,6 +27,6 @@
push_data()
return // Can't see the target.
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_turf(A)))
set_pin_data(IC_OUTPUT, 1, get_dir(get_turf(src), get_step_towards2(get_turf(src),A)))
push_data()
activate_pin(2)
+18
View File
@@ -0,0 +1,18 @@
// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
// Only way to do that is to tie the behavior into the focus's keyLoop().
/atom/movable/keyLoop(client/user)
if(!user.keys_held["Ctrl"])
var/movement_dir = NONE
for(var/_key in user.keys_held)
movement_dir = movement_dir | GLOB.movement_keys[_key]
if(user.next_move_dir_add)
movement_dir |= user.next_move_dir_add
if(user.next_move_dir_sub)
movement_dir &= ~user.next_move_dir_sub
// Sanity checks in case you hold left and right and up to make sure you only go up
if((movement_dir & NORTH) && (movement_dir & SOUTH))
movement_dir &= ~(NORTH|SOUTH)
if((movement_dir & EAST) && (movement_dir & WEST))
movement_dir &= ~(EAST|WEST)
user.Move(get_step(src, movement_dir), movement_dir)
+1 -1
View File
@@ -142,7 +142,7 @@
hidden_message = newmessage
creator_name = user.real_name
creator_key = user.ckey
realdate = world.timeofday
realdate = world.realtime
map = SSmapping.config.map_name
update_icon()
@@ -656,7 +656,7 @@
playsound(user, 'sound/magic/clockwork/fellowship_armory.ogg', 35, TRUE, frequency = 90000 - (active * 30000))
/obj/item/melee/transforming/cleaving_saw/clumsy_transform_effect(mob/living/user)
if(user.disabilities & CLUMSY && prob(50))
if(user.has_disability(CLUMSY) && prob(50))
to_chat(user, "<span class='warning'>You accidentally cut yourself with [src], like a doofus!</span>")
user.take_bodypart_damage(10)
+4 -4
View File
@@ -16,7 +16,7 @@
/mob/living/carbon/monkey/handle_blood()
if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood.
if(bodytemperature >= 225 && !(has_disability(NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
@@ -28,7 +28,7 @@
bleed_rate = 0
return
if(bodytemperature >= 225 && !(disabilities & NOCLONE)) //cryosleep or husked people do not pump the blood.
if(bodytemperature >= 225 && !(has_disability(NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL && !(NOHUNGER in dna.species.species_traits))
@@ -201,13 +201,13 @@
return "blood"
/mob/living/carbon/monkey/get_blood_id()
if(!(disabilities & NOCLONE))
if(!(has_disability(NOCLONE)))
return "blood"
/mob/living/carbon/human/get_blood_id()
if(dna.species.exotic_blood)
return dna.species.exotic_blood
else if((NOBLOOD in dna.species.species_traits) || (disabilities & NOCLONE))
else if((NOBLOOD in dna.species.species_traits) || (has_disability(NOCLONE)))
return
return "blood"
+2 -2
View File
@@ -79,8 +79,8 @@
if(!brainmob.stored_dna)
brainmob.stored_dna = new /datum/dna/stored(brainmob)
C.dna.copy_dna(brainmob.stored_dna)
if(L.disabilities & NOCLONE)
brainmob.disabilities |= NOCLONE //This is so you can't just decapitate a husked guy and clone them without needing to get a new body
if(L.has_disability(NOCLONE))
brainmob.disabilities[NOCLONE] = L.disabilities[NOCLONE]
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
+4 -4
View File
@@ -157,7 +157,7 @@
if(!throwable_mob.buckled)
thrown_thing = throwable_mob
stop_pulling()
if(disabilities & PACIFISM)
if(has_disability(PACIFISM))
to_chat(src, "<span class='notice'>You gently let go of [throwable_mob].</span>")
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
@@ -170,7 +170,7 @@
thrown_thing = I
dropItemToGround(I)
if(disabilities & PACIFISM && I.throwforce)
if(has_disability(PACIFISM) && I.throwforce)
to_chat(src, "<span class='notice'>You set [I] down gently on the ground.</span>")
return
@@ -409,7 +409,7 @@
dropItemToGround(I)
var/modifier = 0
if(disabilities & CLUMSY)
if(has_disability(CLUMSY))
modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
switch(rand(1,100)+modifier) //91-100=Nothing special happens
@@ -518,7 +518,7 @@
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
update_stat()
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
become_husk()
become_husk("burn")
med_hud_set_health()
/mob/living/carbon/update_sight()
@@ -306,11 +306,15 @@
if(eyes.eye_damage > 20)
if(prob(eyes.eye_damage - 20))
if(become_nearsighted())
if(!has_disability(NEARSIGHT))
to_chat(src, "<span class='warning'>Your eyes start to burn badly!</span>")
become_nearsighted(EYE_DAMAGE)
else if(prob(eyes.eye_damage - 25))
if(become_blind())
if(!has_disability(BLIND))
to_chat(src, "<span class='warning'>You can't see anything!</span>")
become_blind(EYE_DAMAGE)
else
to_chat(src, "<span class='warning'>Your eyes are really starting to hurt. This can't be good for you!</span>")
if(has_bane(BANE_LIGHT))
@@ -48,7 +48,7 @@
/mob/living/carbon/proc/Drain()
become_husk()
disabilities |= NOCLONE
become_husk(CHANGELING_DRAIN)
add_disability(NOCLONE, CHANGELING_DRAIN)
blood_volume = 0
return 1
@@ -44,7 +44,10 @@
if(mind.martial_art && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
if(prob(mind.martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;)
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
else
visible_message("<span class='danger'>[src] deflects the projectile!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
return 0
@@ -140,8 +143,8 @@
return ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && isliving(pulling))
vore_attack(user, pulling)
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (has_disability(FAT)) && ismonkey(pulling))
devour_mob(pulling)
else
..()
@@ -91,19 +91,8 @@
return wear_id.GetID()
/mob/living/carbon/human/abiotic(full_body = 0)
var/abiotic_hands = FALSE
for(var/obj/item/I in held_items)
if(!(I.flags_1 & NODROP_1))
abiotic_hands = TRUE
break
if(full_body && abiotic_hands && ((back && !(back.flags_1&NODROP_1)) || (wear_mask && !(wear_mask.flags_1&NODROP_1)) || (head && !(head.flags_1&NODROP_1)) || (shoes && !(shoes.flags_1&NODROP_1)) || (w_uniform && !(w_uniform.flags_1&NODROP_1)) || (wear_suit && !(wear_suit.flags_1&NODROP_1)) || (glasses && !(glasses.flags_1&NODROP_1)) || (ears && !(ears.flags_1&NODROP_1)) || (gloves && !(gloves.flags_1&NODROP_1)) ) )
return TRUE
return abiotic_hands
/mob/living/carbon/human/IsAdvancedToolUser()
if(disabilities & MONKEYLIKE)
if(has_disability(MONKEYLIKE))
return FALSE
return TRUE//Humans can use guns and such
@@ -339,7 +339,7 @@
if(TRAITS & TRAIT_SMART)
smartness = 75
else if(TRAITS & TRAIT_DUMB)
disabilities |= CLUMSY
add_disability(CLUMSY, GENETIC_MUTATION)
smartness = 25
if(TRAITS & TRAIT_MEAN)
@@ -187,7 +187,7 @@
if(G.tint)
update_tint()
if(G.vision_correction)
if(disabilities & NEARSIGHT)
if(has_disability(NEARSIGHT))
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
adjust_eye_damage(0)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
@@ -312,7 +312,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!HD) //Decapitated
return
if(H.disabilities & HUSK)
if(H.has_disability(HUSK))
return
var/datum/sprite_accessory/S
var/list/standing = list()
@@ -453,7 +453,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/obj/item/bodypart/head/HD = H.get_bodypart("head")
if(HD && !(H.disabilities & HUSK))
if(HD && !(H.has_disability(HUSK)))
// lipstick
if(H.lip_style && (LIPS in species_traits))
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
@@ -724,7 +724,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(S.center)
accessory_overlay = center_image(accessory_overlay, S.dimension_x, S.dimension_y)
if(!(H.disabilities & HUSK))
if(!(H.has_disability(HUSK)))
if(!forced_colour)
switch(S.color_src)
if(MUTCOLORS)
@@ -1103,16 +1103,16 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/handle_digestion(mob/living/carbon/human/H)
//The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with
if(H.disabilities & FAT)//I share your pain, past coder.
if(H.has_disability(FAT))//I share your pain, past coder.
if(H.overeatduration < 100)
to_chat(H, "<span class='notice'>You feel fit again!</span>")
H.disabilities &= ~FAT
H.remove_disability(FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else
if(H.overeatduration > 500)
to_chat(H, "<span class='danger'>You suddenly feel blubbery!</span>")
H.disabilities |= FAT
H.add_disability(FAT, OBESITY)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
@@ -1269,7 +1269,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
. += (health_deficiency / 25)
if((hungry >= 70) && !flight) //Being hungry won't stop you from using flightpack controls/flapping your wings although it probably will in the wing case but who cares.
. += hungry / 50
if(H.disabilities & FAT)
if(H.has_disability(FAT))
. += (1.5 - flight)
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
. += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR
@@ -1315,7 +1315,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(user.disabilities & PACIFISM)
if(user.has_disability(PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm [target]!</span>")
return FALSE
if(target.check_block())
@@ -725,7 +725,7 @@
/obj/structure/cloth_pile/proc/revive()
if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
return
if(cloth_golem.suiciding || cloth_golem.disabilities & NOCLONE)
if(cloth_golem.suiciding || cloth_golem.has_disability(NOCLONE))
QDEL_NULL(cloth_golem)
return
@@ -11,12 +11,12 @@
amount = dna.species.spec_stun(src,amount)
return ..()
/mob/living/carbon/human/cure_husk()
/mob/living/carbon/human/cure_husk(list/sources)
. = ..()
if(.)
update_hair()
/mob/living/carbon/human/become_husk()
/mob/living/carbon/human/become_husk(source)
if(istype(dna.species, /datum/species/skeleton)) //skeletons shouldn't be husks.
cure_husk()
return
@@ -609,7 +609,7 @@ generate/load female uniform sprites matching all previously decided variables
if(BP.dmg_overlay_type)
. += "-[BP.dmg_overlay_type]"
if(disabilities & HUSK)
if(has_disability(HUSK))
. += "-husk"
/mob/living/carbon/human/load_limb_from_cache()
@@ -121,10 +121,8 @@
if(L == src)
return FALSE
if(disabilities & PACIFISM)
if(has_disability(PACIFISM))
return FALSE
if(enemies[L])
return TRUE
@@ -19,7 +19,7 @@
if(!HD) //Decapitated
return
if(disabilities & HUSK)
if(has_disability(HUSK))
return
var/hair_hidden = 0
+1 -36
View File
@@ -64,43 +64,8 @@
/mob/living/carbon/set_disgust(amount)
disgust = CLAMP(amount, 0, DISGUST_LEVEL_MAXEDOUT)
/mob/living/carbon/cure_blind()
if(disabilities & BLIND)
disabilities &= ~BLIND
adjust_blindness(-1)
return 1
/mob/living/carbon/become_blind()
if(!(disabilities & BLIND))
disabilities |= BLIND
blind_eyes(1)
return 1
/mob/living/carbon/cure_nearsighted()
if(disabilities & NEARSIGHT)
disabilities &= ~NEARSIGHT
clear_fullscreen("nearsighted")
return 1
/mob/living/carbon/become_nearsighted()
if(!(disabilities & NEARSIGHT))
disabilities |= NEARSIGHT
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
return 1
/mob/living/carbon/cure_husk()
if(disabilities & HUSK)
disabilities &= ~HUSK
status_flags &= ~DISFIGURED
update_body()
return 1
/mob/living/carbon/become_husk()
if(disabilities & HUSK)
return
disabilities |= HUSK
status_flags |= DISFIGURED //makes them unknown
update_body()
return 1
////////////////////////////////////////TRAUMAS/////////////////////////////////////////
/mob/living/carbon/proc/get_traumas()
. = list()
@@ -290,7 +290,7 @@
else
. += "-robotic"
if(disabilities & HUSK)
if(has_disability(HUSK))
. += "-husk"
+2 -2
View File
@@ -126,7 +126,7 @@
/mob/living/proc/handle_disabilities()
//Eyes
if(eye_blind) //blindness, heals slowly over time
if(!stat && !(disabilities & BLIND))
if(!stat && !(has_disability(BLIND)))
eye_blind = max(eye_blind-1,0)
if(client && !eye_blind)
clear_alert("blind")
@@ -137,7 +137,7 @@
eye_blurry = max(eye_blurry-1, 0)
if(client && !eye_blurry)
clear_fullscreen("blurry")
if(disabilities & PACIFISM && a_intent == INTENT_HARM)
if(has_disability(PACIFISM) && a_intent == INTENT_HARM)
to_chat(src, "<span class='notice'>You don't feel like harming anybody.</span>")
a_intent_change(INTENT_HELP)
+2 -3
View File
@@ -413,7 +413,6 @@
cure_nearsighted()
cure_blind()
cure_husk()
disabilities = 0
hallucination = 0
heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
@@ -819,7 +818,7 @@
if(G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
to_chat(src, "<span class='warning'>You don't have the dexterity to do this!</span>")
return FALSE
if(disabilities & PACIFISM)
if(has_disability(PACIFISM))
to_chat(src, "<span class='notice'>You don't want to risk harming anyone!</span>")
return FALSE
return TRUE
@@ -1064,4 +1063,4 @@
/mob/living/onTransitZ(old_z,new_z)
..()
update_z(new_z)
update_z(new_z)
+7 -13
View File
@@ -135,11 +135,9 @@
if(!(status_flags & CANPUSH))
to_chat(user, "<span class='warning'>[src] can't be grabbed more aggressively!</span>")
return FALSE
if(user.disabilities & PACIFISM)
if(user.has_disability(PACIFISM))
to_chat(user, "<span class='notice'>You don't want to risk hurting [src]!</span>")
return FALSE
grippedby(user)
//proc to upgrade a simple pull into a more aggressive grab.
@@ -193,10 +191,9 @@
M.Feedstop()
return // can't attack while eating!
if(disabilities & PACIFISM)
if(has_disability(PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
if (stat != DEAD)
add_logs(M, src, "attacked")
M.do_attack_animation(src)
@@ -210,10 +207,9 @@
M.visible_message("<span class='notice'>\The [M] [M.friendly] [src]!</span>")
return FALSE
else
if(M.disabilities & PACIFISM)
if(M.has_disability(PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
if(M.attack_sound)
playsound(loc, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
@@ -229,10 +225,9 @@
return FALSE
if (M.a_intent == INTENT_HARM)
if(M.disabilities & PACIFISM)
if(M.has_disability(PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
to_chat(M, "<span class='warning'>You can't bite with your mouth covered!</span>")
return FALSE
@@ -255,10 +250,9 @@
return FALSE
else
if(L.disabilities & PACIFISM)
if(L.has_disability(PACIFISM))
to_chat(L, "<span class='notice'>You don't want to hurt anyone!</span>")
return
L.do_attack_animation(src)
if(prob(90))
add_logs(L, src, "attacked")
@@ -280,7 +274,7 @@
grabbedby(M)
return FALSE
if("harm")
if(M.disabilities & PACIFISM)
if(M.has_disability(PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
M.do_attack_animation(src)
@@ -370,7 +364,7 @@
//called when the mob receives a bright flash
/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
if(get_eye_protection() < intensity && (override_blindness_check || !(disabilities & BLIND)))
if(get_eye_protection() < intensity && (override_blindness_check || !(has_disability(BLIND))))
overlay_fullscreen("flash", type)
addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
return 1
@@ -26,6 +26,8 @@
var/incorporeal_move = FALSE //FALSE is off, INCORPOREAL_MOVE_BASIC is normal, INCORPOREAL_MOVE_SHADOW is for ninjas
//and INCORPOREAL_MOVE_JAUNT is blocked by holy water/salt
var/list/disabilities = list()
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
var/now_pushing = null //used by living/Collide() and living/PushAM() to prevent potential infinite loop.
+1 -1
View File
@@ -285,7 +285,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
if(disabilities & MUTE)
if(has_disability(MUTE))
return 0
if(is_muzzled())
@@ -1032,9 +1032,9 @@
status_flags &= ~CANPUSH
if(module.clean_on_move)
flags_1 |= CLEAN_ON_MOVE_1
AddComponent(/datum/component/cleaning)
else
flags_1 &= ~CLEAN_ON_MOVE_1
qdel(GetComponent(/datum/component/cleaning))
hat_offset = module.hat_offset
@@ -558,7 +558,7 @@ Difficulty: Very Hard
H.regenerate_limbs()
H.regenerate_organs()
H.revive(1,0)
H.disabilities |= NOCLONE //Free revives, but significantly limits your options for reviving except via the crystal
H.add_disability(NOCLONE, MAGIC_DISABILITY) //Free revives, but significantly limits your options for reviving except via the crystal
H.grab_ghost(force = TRUE)
/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans
@@ -719,7 +719,7 @@ Difficulty: Very Hard
if(isliving(A) && holder_animal)
var/mob/living/L = A
L.notransform = 1
L.disabilities |= MUTE
L.add_disability(MUTE, STASIS_MUTE)
L.status_flags |= GODMODE
L.mind.transfer_to(holder_animal)
var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession
@@ -729,7 +729,7 @@ Difficulty: Very Hard
/obj/structure/closet/stasis/dump_contents(var/kill = 1)
STOP_PROCESSING(SSobj, src)
for(var/mob/living/L in src)
L.disabilities &= ~MUTE
L.remove_disability(MUTE, STASIS_MUTE)
L.status_flags &= ~GODMODE
L.notransform = 0
if(holder_animal)
+73
View File
@@ -137,3 +137,76 @@
to_chat(src, "<span class='boldwarning'>[priority_absorb_key["self_message"]]</span>")
priority_absorb_key["stuns_absorbed"] += amount
return TRUE
/////////////////////////////////// DISABILITIES ////////////////////////////////////
/mob/living/proc/add_disability(disability, source)
if(!disabilities[disability])
disabilities[disability] = list(source)
else
disabilities[disability] |= list(source)
/mob/living/proc/remove_disability(disability, list/sources)
if(!disabilities[disability])
return
if(LAZYLEN(sources))
for(var/S in sources)
if(S in disabilities[disability])
disabilities[disability] -= S
else
disabilities[disability] = list()
if(!LAZYLEN(disabilities[disability]))
disabilities -= disability
/mob/living/proc/has_disability(disability, list/sources)
if(!disabilities[disability])
return FALSE
. = FALSE
if(LAZYLEN(sources))
for(var/S in sources)
if(S in disabilities[disability])
return TRUE
else
if(LAZYLEN(disabilities[disability]))
return TRUE
/mob/living/proc/remove_all_disabilities()
disabilities = list()
/////////////////////////////////// DISABILITY PROCS ////////////////////////////////////
/mob/living/proc/cure_blind(list/sources)
remove_disability(BLIND, sources)
if(!has_disability(BLIND))
adjust_blindness(-1)
/mob/living/proc/become_blind(source)
if(!has_disability(BLIND))
blind_eyes(1)
add_disability(BLIND, source)
/mob/living/proc/cure_nearsighted(list/sources)
remove_disability(NEARSIGHT, sources)
if(!has_disability(NEARSIGHT))
clear_fullscreen("nearsighted")
/mob/living/proc/become_nearsighted(source)
if(!has_disability(NEARSIGHT))
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
add_disability(NEARSIGHT, source)
/mob/living/proc/cure_husk(list/sources)
remove_disability(HUSK, sources)
if(!has_disability(HUSK))
status_flags &= ~DISFIGURED
update_body()
/mob/living/proc/become_husk(source)
if(!has_disability(HUSK))
status_flags |= DISFIGURED //makes them unknown
update_body()
add_disability(HUSK, source)
-1
View File
@@ -32,7 +32,6 @@
var/obj/machinery/machine = null
var/other_mobs = null
var/disabilities = 0 //Carbon
var/atom/movable/pulling = null
var/grab_state = 0
-5
View File
@@ -285,11 +285,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
firstname.Find(real_name)
return firstname.match
/mob/proc/abiotic(full_body = 0)
for(var/obj/item/I in held_items)
if(!(I.flags_1 & NODROP_1))
return 1
return 0
//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left
/mob/verb/a_intent_change(input as text)
+10 -27
View File
@@ -160,8 +160,12 @@
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else if(eye_blind)
var/blind_minimum = 0
if((stat != CONSCIOUS && stat != SOFT_CRIT) || (disabilities & BLIND))
if((stat != CONSCIOUS && stat != SOFT_CRIT))
blind_minimum = 1
if(isliving(src))
var/mob/living/L = src
if(L.has_disability(BLIND))
blind_minimum = 1
eye_blind = max(eye_blind+amount, blind_minimum)
if(!eye_blind)
clear_alert("blind")
@@ -177,8 +181,12 @@
overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
else if(eye_blind)
var/blind_minimum = 0
if((stat != CONSCIOUS && stat != SOFT_CRIT) || (disabilities & BLIND))
if(stat != CONSCIOUS && stat != SOFT_CRIT)
blind_minimum = 1
if(isliving(src))
var/mob/living/L = src
if(L.has_disability(BLIND))
blind_minimum = 1
eye_blind = blind_minimum
if(!eye_blind)
clear_alert("blind")
@@ -227,31 +235,6 @@
/mob/proc/set_disgust(amount)
return
/////////////////////////////////// BLIND DISABILITY ////////////////////////////////////
/mob/proc/cure_blind() //when we want to cure the BLIND disability only.
return
/mob/proc/become_blind()
return
/////////////////////////////////// NEARSIGHT DISABILITY ////////////////////////////////////
/mob/proc/cure_nearsighted()
return
/mob/proc/become_nearsighted()
return
//////////////////////////////// HUSK DISABILITY ///////////////////////////:
/mob/proc/cure_husk()
return
/mob/proc/become_husk()
return
+2 -2
View File
@@ -93,7 +93,7 @@
return
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
if(H.disabilities & CLUMSY && prob(25))
if(H.has_disability(CLUMSY) && prob(25))
to_chat(H, "<span class='warning'>You cut yourself on the paper! Ahhhh! Ahhhhh!</span>")
H.damageoverlaytemp = 9001
H.update_damage_hud()
@@ -317,7 +317,7 @@
to_chat(user, "<span class='notice'>You stamp the paper with your rubber stamp.</span>")
if(P.is_hot())
if(user.disabilities & CLUMSY && prob(10))
if(user.has_disability(CLUMSY) && prob(10))
user.visible_message("<span class='warning'>[user] accidentally ignites themselves!</span>", \
"<span class='userdanger'>You miss the paper and accidentally light yourself on fire!</span>")
user.dropItemToGround(P)
+1 -1
View File
@@ -65,7 +65,7 @@
update_icon()
else if(P.is_hot())
if(user.disabilities & CLUMSY && prob(10))
if(user.has_disability(CLUMSY) && prob(10))
user.visible_message("<span class='warning'>[user] accidentally ignites themselves!</span>", \
"<span class='userdanger'>You miss [src] and accidentally light yourself on fire!</span>")
user.dropItemToGround(P)
+3 -2
View File
@@ -158,7 +158,7 @@
//Exclude lasertag guns from the CLUMSY check.
if(clumsy_check)
if(istype(user))
if (user.disabilities & CLUMSY && prob(40))
if (user.has_disability(CLUMSY) && prob(40))
to_chat(user, "<span class='userdanger'>You shoot yourself in the foot with [src]!</span>")
var/shot_leg = pick("l_leg", "r_leg")
process_fire(user,user,0,params, zone_override = shot_leg)
@@ -400,7 +400,8 @@
/obj/item/gun/dropped(mob/user)
..()
zoom(user,FALSE)
if(zoomed)
zoom(user,FALSE)
if(azoom)
azoom.Remove(user)
if(alight)
@@ -349,7 +349,7 @@
clumsy_check = 0
/obj/item/gun/ballistic/revolver/reverse/can_trigger_gun(mob/living/user)
if((user.disabilities & CLUMSY) || (user.mind && user.mind.assigned_role == "Clown"))
if((user.has_disability(CLUMSY)) || (user.mind && user.mind.assigned_role == "Clown"))
return ..()
if(process_fire(user, user, 0, zone_override = "head"))
user.visible_message("<span class='warning'>[user] somehow manages to shoot [user.p_them()]self in the face!</span>", "<span class='userdanger'>You somehow shoot yourself in the face! How the hell?!</span>")
+70 -198
View File
@@ -4,9 +4,6 @@
#define ZOOM_LOCK_CENTER_VIEW 2
#define ZOOM_LOCK_OFF 3
#define ZOOM_SPEED_STEP 0
#define ZOOM_SPEED_INSTANT 1
#define AUTOZOOM_PIXEL_STEP_FACTOR 48
#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1
@@ -45,7 +42,7 @@
var/lastangle = 0
var/aiming_lastangle = 0
var/mob/current_user = null
var/obj/effect/projectile_beam/current_tracer
var/list/obj/effect/projectile_beam/current_tracers
var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later.
var/structure_bleed_coeff = 0.7
@@ -69,9 +66,8 @@
//ZOOMING
var/zoom_current_view_increase = 0
var/zoom_target_view_increase = 10
var/zoom_speed = ZOOM_SPEED_STEP
var/zooming = FALSE
var/zoom_lock = ZOOM_LOCK_AUTOZOOM_FREEMOVE
var/zoom_lock = ZOOM_LOCK_OFF
var/zooming_angle
var/current_zoom_x = 0
var/current_zoom_y = 0
@@ -80,7 +76,6 @@
var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged")
var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty")
var/datum/action/item_action/zoom_speed_action/zoom_speed_action
var/datum/action/item_action/zoom_lock_action/zoom_lock_action
/obj/item/gun/energy/beam_rifle/debug
@@ -103,15 +98,6 @@
. = ..()
/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action)
if(istype(action, /datum/action/item_action/zoom_speed_action))
zoom_speed++
if(zoom_speed > 1)
zoom_speed = ZOOM_SPEED_STEP
switch(zoom_speed)
if(ZOOM_SPEED_STEP)
to_chat(owner, "<span class='boldnotice'>You switch [src]'s digital zoom to stepper mode.</span>")
if(ZOOM_SPEED_INSTANT)
to_chat(owner, "<span class='boldnotice'>You switch [src]'s digital zoom to instant mode.</span>")
if(istype(action, /datum/action/item_action/zoom_lock_action))
zoom_lock++
if(zoom_lock > 3)
@@ -135,8 +121,6 @@
var/total_time = SSfastprocess.wait
if(delay_override)
total_time = delay_override
if(zoom_speed == ZOOM_SPEED_INSTANT)
total_time = 0
zoom_animating = total_time
animate(current_user.client, pixel_x = current_zoom_x, pixel_y = current_zoom_y , total_time, SINE_EASING, ANIMATION_PARALLEL)
zoom_animating = 0
@@ -150,18 +134,10 @@
/obj/item/gun/energy/beam_rifle/proc/handle_zooming()
if(!zooming || !check_user())
return
if(zoom_speed == ZOOM_SPEED_INSTANT)
current_user.client.change_view(world.view + zoom_target_view_increase)
zoom_current_view_increase = zoom_target_view_increase
set_autozoom_pixel_offsets_immediate(zooming_angle)
smooth_zooming()
return
if(zoom_current_view_increase > zoom_target_view_increase)
return
zoom_current_view_increase++
current_user.client.change_view(zoom_current_view_increase + world.view)
current_user.client.change_view(world.view + zoom_target_view_increase)
zoom_current_view_increase = zoom_target_view_increase
set_autozoom_pixel_offsets_immediate(zooming_angle)
smooth_zooming(SSfastprocess.wait * zoom_target_view_increase * zoom_speed)
smooth_zooming()
/obj/item/gun/energy/beam_rifle/proc/start_zooming()
if(zoom_lock == ZOOM_LOCK_OFF)
@@ -169,8 +145,9 @@
zooming = TRUE
/obj/item/gun/energy/beam_rifle/proc/stop_zooming()
zooming = FALSE
reset_zooming()
if(zooming)
zooming = FALSE
reset_zooming()
/obj/item/gun/energy/beam_rifle/proc/reset_zooming()
if(!check_user(FALSE))
@@ -204,14 +181,14 @@
/obj/item/gun/energy/beam_rifle/Initialize()
. = ..()
current_tracers = list()
START_PROCESSING(SSprojectiles, src)
zoom_speed_action = new(src)
zoom_lock_action = new(src)
/obj/item/gun/energy/beam_rifle/Destroy()
STOP_PROCESSING(SSfastprocess, src)
set_user(null)
QDEL_NULL(current_tracer)
QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/emp_act(severity)
@@ -245,6 +222,7 @@
/obj/item/gun/energy/beam_rifle/process()
if(!aiming)
last_process = world.time
return
check_user()
handle_zooming()
@@ -299,7 +277,7 @@
set waitfor = FALSE
aiming_time_left = aiming_time
aiming = FALSE
QDEL_NULL(current_tracer)
QDEL_LIST(current_tracers)
stop_zooming()
/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user)
@@ -341,7 +319,7 @@
sync_ammo()
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
stop_aiming()
QDEL_NULL(current_tracer)
QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
@@ -555,136 +533,103 @@
handle_impact(target)
/obj/item/projectile/beam/beam_rifle/Collide(atom/target)
paused = TRUE
if(check_pierce(target))
permutated += target
return FALSE
if(!QDELETED(target))
cached = get_turf(target)
paused = FALSE
. = ..()
/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE)
paused = TRUE
if(!QDELETED(target))
cached = get_turf(target)
handle_hit(target)
paused = FALSE
. = ..()
/obj/item/projectile/beam/beam_rifle/hitscan
icon_state = ""
var/tracer_type = /obj/effect/projectile_beam/tracer
var/starting_z
var/starting_p_x
var/starting_p_y
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end.
var/constant_tracer = FALSE
var/travelled_p_x = 0
var/travelled_p_y = 0
var/tracer_spawned = FALSE
var/beam_index
/obj/item/projectile/beam/beam_rifle/hitscan/Destroy()
paused = TRUE //STOP HITTING WHEN YOU'RE ALREADY BEING DELETED!
spawn_tracer(constant_tracer)
if(loc)
var/datum/point/pcache = trajectory.copy_to()
beam_segments[beam_index] = pcache
generate_tracers(constant_tracer)
return ..()
/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer(put_in_rifle = FALSE)
if(tracer_spawned)
return
tracer_spawned = TRUE
//Remind me to port baystation trajectories so this shit isn't needed...
var/pixels_travelled = round(sqrt(travelled_p_x**2 + travelled_p_y**2),1)
var/scaling = pixels_travelled/world.icon_size
var/midpoint_p_x = round(starting_p_x + (travelled_p_x / 2))
var/midpoint_p_y = round(starting_p_y + (travelled_p_y / 2))
var/tracer_px = midpoint_p_x % world.icon_size
var/tracer_py = midpoint_p_y % world.icon_size
var/tracer_lx = (midpoint_p_x - tracer_px) / world.icon_size
var/tracer_ly = (midpoint_p_y - tracer_py) / world.icon_size
var/obj/effect/projectile_beam/PB = new tracer_type(src)
PB.apply_vars(Angle, tracer_px, tracer_py, color, scaling, locate(tracer_lx,tracer_ly,starting_z))
if(put_in_rifle && istype(gun))
if(gun.current_tracer)
QDEL_NULL(gun.current_tracer)
gun.current_tracer = PB
else
QDEL_IN(PB, 5)
/obj/item/projectile/beam/beam_rifle/hitscan/Collide(atom/target)
var/datum/point/pcache = trajectory.copy_to()
. = ..()
if(. && !QDELETED(src)) //successful touch and not destroyed.
beam_segments[beam_index] = pcache
beam_index = pcache
beam_segments[beam_index] = null
/obj/item/projectile/beam/beam_rifle/hitscan/proc/check_for_turf_edge(turf/T)
if(!istype(T))
return TRUE
var/tx = T.x
var/ty = T.y
if(tx < 10 || tx > (world.maxx - 10) || ty < 10 || ty > (world.maxy-10))
return TRUE
return FALSE
/obj/item/projectile/beam/beam_rifle/hitscan/before_z_change(turf/oldloc, turf/newloc)
var/datum/point/pcache = trajectory.copy_to()
beam_segments[beam_index] = pcache
beam_index = RETURN_PRECISE_POINT(newloc)
beam_segments[beam_index] = null
return ..()
/obj/item/projectile/beam/beam_rifle/hitscan/proc/generate_tracers(highlander = FALSE, cleanup = TRUE)
set waitfor = FALSE
if(highlander && istype(gun))
QDEL_LIST(gun.current_tracers)
for(var/datum/point/p in beam_segments)
gun.current_tracers += generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 0)
else
for(var/datum/point/p in beam_segments)
generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 5)
if(cleanup)
QDEL_LIST(beam_segments)
beam_segments = null
QDEL_NULL(beam_index)
/obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time
set waitfor = 0
set waitfor = FALSE
var/turf/starting = get_turf(src)
trajectory = new(starting.x, starting.y, starting.z, 0, 0, setAngle? setAngle : Angle, 33)
if(!log_override && firer && original)
add_logs(firer, original, "fired at", src, " [get_area(src)]")
fired = TRUE
if(setAngle)
Angle = setAngle
var/next_run = world.time
var/old_pixel_x = pixel_x
var/old_pixel_y = pixel_y
var/safety = 0 //The code works fine, but... just in case...
var/turf/c2
var/starting_x = loc.x
var/starting_y = loc.y
starting_z = loc.z
starting_p_x = starting_x * world.icon_size + pixel_x
starting_p_y = starting_y * world.icon_size + pixel_y
beam_segments = list() //initialize segment list with the list for the first segment
beam_index = RETURN_PRECISE_POINT(src)
beam_segments[beam_index] = null //record start.
if(spread)
Angle += (rand() - 0.5) * spread
while(loc)
if(paused || QDELETED(src))
return
if(++safety > (range * 3)) //If it's looping for way, way too long...
qdel(src)
stack_trace("WARNING: [type] projectile encountered infinite recursion in [__FILE__]/[__LINE__]!")
return //Kill!
if(spread)
Angle += (rand() - 0.5) * spread
var/matrix/M = new
M.Turn(Angle)
transform = M
var/Pixel_x=sin(Angle)+16*sin(Angle)*2
var/Pixel_y=cos(Angle)+16*cos(Angle)*2
travelled_p_x += Pixel_x
travelled_p_y += Pixel_y
var/pixel_x_offset = old_pixel_x + Pixel_x
var/pixel_y_offset = old_pixel_y + Pixel_y
var/new_x = x
var/new_y = y
while(pixel_x_offset > 16)
pixel_x_offset -= 32
old_pixel_x -= 32
new_x++// x++
while(pixel_x_offset < -16)
pixel_x_offset += 32
old_pixel_x += 32
new_x--
while(pixel_y_offset > 16)
pixel_y_offset -= 32
old_pixel_y -= 32
new_y++
while(pixel_y_offset < -16)
pixel_y_offset += 32
old_pixel_y += 32
new_y--
pixel_x = old_pixel_x
pixel_y = old_pixel_y
step_towards(src, locate(new_x, new_y, z))
next_run += max(world.tick_lag, speed)
var/delay = next_run - world.time
if(delay <= world.tick_lag*2)
pixel_x = pixel_x_offset
pixel_y = pixel_y_offset
trajectory.increment()
var/turf/T = trajectory.return_turf()
if(T.z != loc.z)
before_z_change(loc, T)
trajectory_ignore_forcemove = TRUE
forceMove(T)
trajectory_ignore_forcemove = FALSE
else
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
old_pixel_x = pixel_x_offset
old_pixel_y = pixel_y_offset
step_towards(src, T)
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
if(can_hit_target(original, permutated))
Collide(original)
c2 = loc
Range()
if(check_for_turf_edge(loc))
spawn_tracer(constant_tracer)
c2 = get_turf(src)
if(istype(c2))
cached = c2
@@ -704,76 +649,3 @@
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
qdel(src)
return FALSE
/obj/effect/projectile_beam
icon = 'icons/obj/projectiles.dmi'
layer = ABOVE_MOB_LAYER
anchored = TRUE
light_power = 1
light_range = 2
light_color = "#00ffff"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
flags_1 = ABSTRACT_1
appearance_flags = 0
/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
var/matrix/M
if(!override)
M = transform
else
M = new
M.Scale(nx,ny)
transform = M
/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
var/matrix/M
if(!override)
M = transform
else
M = new
M.Turn(angle)
transform = M
/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
if(angle_override && p_x && p_y && color_override && scaling)
apply_vars(angle_override, p_x, p_y, color_override, scaling)
return ..()
/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x, p_y, color_override, scaling = 1, new_loc, increment = 0)
var/mutable_appearance/look = new(src)
look.pixel_x = p_x
look.pixel_y = p_y
if(color_override)
look.color = color_override
appearance = look
scale_to(1,scaling, FALSE)
turn_to(angle_override, FALSE)
if(!isnull(new_loc)) //If you want to null it just delete it...
forceMove(new_loc)
for(var/i in 1 to increment)
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
/obj/effect/projectile_beam/tracer
icon_state = "tracer_beam"
/obj/effect/projectile_beam/tracer/aiming
icon_state = "gbeam"
/datum/action/item_action/zoom_speed_action
name = "Toggle Zooming Speed"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "projectile"
background_icon_state = "bg_tech"
/datum/action/item_action/zoom_lock_action
name = "Switch Zoom Mode"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "zoom_mode"
background_icon_state = "bg_tech"
/obj/effect/projectile_beam/singularity_pull()
return
/obj/effect/projectile_beam/singularity_act()
return
+1 -1
View File
@@ -129,7 +129,7 @@
// A gun with ultra-honk pin is useful for clown and useless for everyone else.
/obj/item/device/firing_pin/clown/ultra/pin_auth(mob/living/user)
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
if(!(user.disabilities & CLUMSY) && !(user.mind && user.mind.assigned_role == "Clown"))
if(!(user.has_disability(CLUMSY)) && !(user.mind && user.mind.assigned_role == "Clown"))
return 0
return 1
+91 -57
View File
@@ -31,16 +31,11 @@
var/last_projectile_move = 0
var/last_process = 0
var/time_offset = 0
var/old_pixel_x = 0
var/old_pixel_y = 0
var/pixel_x_increment = 0
var/pixel_y_increment = 0
var/pixel_x_offset = 0
var/pixel_y_offset = 0
var/new_x = 0
var/new_y = 0
var/datum/point/vector/trajectory
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN!
var/Angle = 0
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
var/spread = 0 //amount (in degrees) of projectile spread
@@ -48,6 +43,9 @@
var/ricochets = 0
var/ricochets_max = 2
var/ricochet_chance = 30
var/colliding = FALSE //pause processing..
var/ignore_source_check = FALSE
var/damage = 10
@@ -168,20 +166,28 @@
/obj/item/projectile/proc/vol_by_damage()
if(src.damage)
return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100
else
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
/obj/item/projectile/proc/on_ricochet(atom/A)
return
/obj/item/projectile/Collide(atom/A)
colliding = TRUE
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
ricochets++
if(A.handle_ricochet(src))
on_ricochet(A)
ignore_source_check = TRUE
range = initial(range)
return FALSE
return TRUE
if(firer && !ignore_source_check)
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
loc = A.loc
trajectory_ignore_forcemove = TRUE
forceMove(get_turf(A))
trajectory_ignore_forcemove = FALSE
colliding = FALSE
return FALSE
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
@@ -197,25 +203,32 @@
if(!prehit(A))
if(forcedodge)
loc = target_turf
trajectory_ignore_forcemove = TRUE
forceMove(target_turf)
trajectory_ignore_forcemove = FALSE
colliding = FALSE
return FALSE
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
loc = target_turf
trajectory_ignore_forcemove = TRUE
forceMove(target_turf)
trajectory_ignore_forcemove = FALSE
if(A)
permutated.Add(A)
colliding = FALSE
return FALSE
else
var/atom/alt = select_target(A)
if(alt)
if(!prehit(alt))
colliding = FALSE
return FALSE
alt.bullet_act(src, def_zone)
qdel(src)
colliding = FALSE
return TRUE
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
return
@@ -246,12 +259,30 @@
return TRUE
return FALSE
/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight.
if(!trajectory && isnull(forced_angle) && isnull(Angle))
return FALSE
var/datum/point/vector/current = trajectory
if(!current)
var/turf/T = get_turf(src)
current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_speed)
var/datum/point/vector/v = current.return_vector_after_increments(moves)
return v.return_turf()
/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
var/turf/current = get_turf(src)
var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
return getline(current, ending)
/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc)
return
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
return TRUE //Bullets don't drift in space
/obj/item/projectile/process()
last_process = world.time
if(!loc || !fired)
if(!loc || !fired || !trajectory)
fired = FALSE
return PROCESS_KILL
if(paused || !isturf(loc))
@@ -285,73 +316,70 @@
setAngle(angle)
if(spread)
setAngle(Angle + ((rand() - 0.5) * spread))
var/turf/starting = get_turf(src)
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
var/turf/starting = get_turf(src)
if(isnull(xo) || isnull(yo))
stack_trace("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
qdel(src)
return
var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
setAngle(Get_Angle(src, target))
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
old_pixel_x = pixel_x
old_pixel_y = pixel_y
trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
last_projectile_move = world.time
fired = TRUE
if(!isprocessing)
START_PROCESSING(SSprojectiles, src)
pixel_move(1) //move it now!
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
Angle = new_angle
return TRUE
/obj/item/projectile/proc/pixel_move(moves)
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
if(trajectory)
trajectory.set_angle(new_angle)
return TRUE
pixel_x_increment=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
pixel_y_increment=round((cos(Angle)+16*cos(Angle)*2), 1)
pixel_x_offset = old_pixel_x + pixel_x_increment
pixel_y_offset = old_pixel_y + pixel_y_increment
new_x = x
new_y = y
/obj/item/projectile/forceMove(atom/target)
. = ..()
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
while(pixel_x_offset > 16)
pixel_x_offset -= 32
old_pixel_x -= 32
new_x++// x++
while(pixel_x_offset < -16)
pixel_x_offset += 32
old_pixel_x += 32
new_x--
while(pixel_y_offset > 16)
pixel_y_offset -= 32
old_pixel_y -= 32
new_y++
while(pixel_y_offset < -16)
pixel_y_offset += 32
old_pixel_y += 32
new_y--
/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1)
if(!loc || !trajectory)
return
last_projectile_move = world.time
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
trajectory.increment(trajectory_multiplier)
var/turf/T = trajectory.return_turf()
if(T.z != loc.z)
before_z_change(loc, T)
trajectory_ignore_forcemove = TRUE
forceMove(T)
trajectory_ignore_forcemove = FALSE
pixel_x = trajectory.return_px()
pixel_y = trajectory.return_py()
else
step_towards(src, T)
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
step_towards(src, locate(new_x, new_y, z))
pixel_x = old_pixel_x
pixel_y = old_pixel_y
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = 1, flags = ANIMATION_END_NOW)
old_pixel_x = pixel_x_offset
old_pixel_y = pixel_y_offset
if(can_hit_target(original, permutated))
Collide(original)
Range()
last_projectile_move = world.time
//Returns true if the target atom is on our current turf and above the right layer
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
if(target && (target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target))
if(loc == get_turf(target))
if(!(target in passthrough))
return TRUE
return FALSE
return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
var/turf/curloc = get_turf(source)
@@ -362,7 +390,8 @@
if(targloc || !params)
yo = targloc.y - curloc.y
xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc))
if(isliving(source) && params)
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
p_x = calculated[2]
@@ -372,8 +401,13 @@
setAngle(calculated[1] + spread)
else
setAngle(calculated[1])
else
else if(targloc)
yo = targloc.y - curloc.y
xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc))
else
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
qdel(src)
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
var/list/mouse_control = params2list(params)
@@ -70,7 +70,7 @@
//nothing
if(21 to INFINITY)
if(prob(current_cycle-10))
M.cure_nearsighted()
M.cure_nearsighted(list(EYE_DAMAGE))
..()
return
@@ -97,10 +97,10 @@
/datum/reagent/consumable/cooking_oil/reaction_obj(obj/O, reac_volume)
if(holder && holder.chem_temp >= fry_temperature)
if(isitem(O))
if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder))
O.loc.visible_message("<span class='warning'>[O] rapidly fries as it's splashed with hot oil! Somehow.</span>")
var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location())
F.fry(O, volume)
var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location(), O)
F.fry(volume)
/datum/reagent/consumable/cooking_oil/reaction_mob(mob/living/M, method = TOUCH, reac_volume, show_message = 1, touch_protection = 0)
if(!istype(M))
@@ -44,7 +44,7 @@
M.adjustToxLoss(-5, 0)
M.hallucination = 0
M.setBrainLoss(0)
M.disabilities = 0
M.remove_all_disabilities()
M.set_blurriness(0)
M.set_blindness(0)
M.SetKnockdown(0, 0)
@@ -667,16 +667,16 @@
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
if (!eyes)
return
if(M.disabilities & BLIND)
if(M.has_disability(BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "<span class='warning'>Your vision slowly returns...</span>")
M.cure_blind()
M.cure_nearsighted()
M.cure_blind(EYE_DAMAGE)
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(35)
else if(M.disabilities & NEARSIGHT)
else if(M.has_disability(NEARSIGHT, EYE_DAMAGE))
to_chat(M, "<span class='warning'>The blackness in your peripheral vision fades.</span>")
M.cure_nearsighted()
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)
else if(M.eye_blind || M.eye_blurry)
M.set_blindness(0)
@@ -765,7 +765,7 @@
M.visible_message("<span class='warning'>[M]'s body convulses a bit, and then falls still once more.</span>")
return
M.visible_message("<span class='warning'>[M]'s body convulses a bit.</span>")
if(!M.suiciding && !(M.disabilities & NOCLONE) && !M.hellbound)
if(!M.suiciding && !(M.has_disability(NOCLONE)) && !M.hellbound)
if(!M)
return
if(M.notify_ghost_cloning(source = M))
@@ -141,7 +141,7 @@
taste_description = "mint"
/datum/reagent/toxin/minttoxin/on_mob_life(mob/living/M)
if(M.disabilities & FAT)
if(M.has_disability(FAT))
M.gib()
return ..()
+2 -2
View File
@@ -56,8 +56,8 @@
shuttlePortName = "custom location"
jumpto_ports = list("syndicate_ne" = 1, "syndicate_nw" = 1, "syndicate_n" = 1, "syndicate_se" = 1, "syndicate_sw" = 1, "syndicate_s" = 1)
view_range = 13
x_offset = -4
y_offset = -2
x_offset = -7
y_offset = -1
see_hidden = TRUE
#undef SYNDICATE_CHALLENGE_TIMER
@@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
neigbours[A] = src
/datum/space_level/proc/set_neigbours(list/L)
for(var/datum/point/P in L)
for(var/datum/space_transition_point/P in L)
if(P.x == xi)
if(P.y == yi+1)
neigbours[TEXT_NORTH] = P.spl
@@ -35,13 +35,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
neigbours[TEXT_WEST] = P.spl
P.spl.neigbours[TEXT_EAST] = src
/datum/point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
/datum/space_transition_point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
var/list/neigbours = list()
var/x
var/y
var/datum/space_level/spl
/datum/point/New(nx, ny, list/point_grid)
/datum/space_transition_point/New(nx, ny, list/point_grid)
if(!point_grid)
qdel(src)
return
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
return
point_grid[x][y] = src
/datum/point/proc/set_neigbours(list/grid)
/datum/space_transition_point/proc/set_neigbours(list/grid)
var/max_X = grid.len
var/list/max_Y = grid[1]
max_Y = max_Y.len
@@ -86,13 +86,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
k++
var/list/point_grid[conf_set_len*2+1][conf_set_len*2+1]
var/list/grid = list()
var/datum/point/P
var/datum/space_transition_point/P
for(var/i = 1, i<=conf_set_len*2+1, i++)
for(var/j = 1, j<=conf_set_len*2+1, j++)
P = new/datum/point(i,j, point_grid)
P = new/datum/space_transition_point(i,j, point_grid)
point_grid[i][j] = P
grid.Add(P)
for(var/datum/point/pnt in grid)
for(var/datum/space_transition_point/pnt in grid)
pnt.set_neigbours(point_grid)
P = point_grid[conf_set_len+1][conf_set_len+1]
var/list/possible_points = list()
@@ -209,12 +209,14 @@
to_chat(target, "<span class='userdanger'>A freezing darkness surrounds you...</span>")
target.playsound_local(get_turf(target), 'sound/hallucinations/i_see_you1.ogg', 50, 1)
user.playsound_local(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
target.adjust_blindness(5)
target.become_blind("abyssal_gaze")
addtimer(CALLBACK(src, .proc/cure_blindness, target), 40)
target.bodytemperature -= 200
/obj/effect/proc_holder/spell/targeted/abyssal_gaze/proc/cure_blindness(mob/target)
target.adjust_blindness(-5)
if(isliving(target))
var/mob/living/L = target
L.cure_blind(BLIND, "abyssal_gaze")
/obj/effect/proc_holder/spell/targeted/dominate
name = "Dominate"
+28 -26
View File
@@ -1,32 +1,34 @@
/obj/effect/proc_holder/spell/targeted/genetic
name = "Genetic"
desc = "This spell inflicts a set of mutations and disabilities upon the target."
var/disabilities = 0 //bits
var/list/mutations = list() //mutation strings
var/duration = 100 //deciseconds
/*
Disabilities
1st bit - ?
2nd bit - ?
3rd bit - ?
4th bit - ?
5th bit - ?
6th bit - ?
*/
/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
playMagSound()
for(var/mob/living/carbon/target in targets)
if(!target.dna)
continue
for(var/A in mutations)
target.dna.add_mutation(A)
target.disabilities |= disabilities
/obj/effect/proc_holder/spell/targeted/genetic
name = "Genetic"
desc = "This spell inflicts a set of mutations and disabilities upon the target."
var/list/disabilities = list() //disabilities
var/list/mutations = list() //mutation strings
var/duration = 100 //deciseconds
/*
Disabilities
1st bit - ?
2nd bit - ?
3rd bit - ?
4th bit - ?
5th bit - ?
6th bit - ?
*/
/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
playMagSound()
for(var/mob/living/carbon/target in targets)
if(!target.dna)
continue
for(var/A in mutations)
target.dna.add_mutation(A)
for(var/A in disabilities)
target.add_disability(A, GENETICS_SPELL)
addtimer(CALLBACK(src, .proc/remove, target), duration)
/obj/effect/proc_holder/spell/targeted/genetic/proc/remove(mob/living/carbon/target)
if(!QDELETED(target))
for(var/A in mutations)
target.dna.remove_mutation(A)
target.disabilities &= ~disabilities
for(var/A in disabilities)
target.remove_disability(A, GENETICS_SPELL)
+1 -1
View File
@@ -217,7 +217,7 @@
C = owner
no_update = 0
if(C.disabilities & HUSK)
if(C.has_disability(HUSK))
species_id = "husk" //overrides species_id
dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
+1 -1
View File
@@ -61,7 +61,7 @@
C = owner
real_name = C.real_name
if(C.disabilities & HUSK)
if(C.has_disability(HUSK))
real_name = "Unknown"
hair_style = "Bald"
facial_hair_style = "Shaved"
+2 -2
View File
@@ -23,9 +23,9 @@
/datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] successfully fixes [target]'s eyes!", "<span class='notice'>You succeed in fixing [target]'s eyes.</span>")
target.cure_blind()
target.cure_blind(list(EYE_DAMAGE))
target.set_blindness(0)
target.cure_nearsighted()
target.cure_nearsighted(list(EYE_DAMAGE))
target.blur_eyes(35) //this will fix itself slowly.
target.set_eye_damage(0)
return TRUE
+1 -1
View File
@@ -4,7 +4,7 @@
possible_locs = list("chest")
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
if(target.disabilities & FAT)
if(target.has_disability(FAT))
return 1
return 0
+2 -2
View File
@@ -25,7 +25,7 @@
return
var/mob/living/carbon/C = owner
// genetic deafness prevents the body from using the ears, even if healthy
if(C.disabilities & DEAF)
if(C.has_disability(DEAF))
deaf = max(deaf, 1)
else
if(C.ears && (C.ears.flags_2 & HEALS_EARS_2))
@@ -42,7 +42,7 @@
var/mob/living/carbon/C = owner
if(iscarbon(owner) && C.disabilities & DEAF)
if(iscarbon(owner) && C.has_disability(DEAF))
deaf = 1
/obj/item/organ/ears/proc/adjustEarDamage(ddmg, ddeaf)
+4 -1
View File
@@ -13,6 +13,9 @@
var/datum/component/riding/D = LoadComponent(/datum/component/riding)
D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 7), TEXT_EAST = list(-12, 7), TEXT_WEST = list( 12, 7)))
if(floorbuffer)
AddComponent(/datum/component/cleaning)
/obj/vehicle/ridden/janicart/Destroy()
if(mybag)
qdel(mybag)
@@ -47,7 +50,7 @@
floorbuffer = TRUE
qdel(I)
to_chat(user, "<span class='notice'>You upgrade [src] with the floor buffer.</span>")
flags_1 |= CLEAN_ON_MOVE_1
AddComponent(/datum/component/cleaning)
update_icon()
else
return ..()