Files
Bubberstation/code/game/objects/items/robot/robot_items.dm
SkyratBot 6a3b1385a9 [MIRROR] Cyborgs can now shake up compromised carbons [MDB IGNORE] (#9356)
* Cyborgs can now shake up compromised carbons (#62468)

The Hug Module from Medical and Peacekeeper Cyborgs now removes negative stats (the same as a human) from carbons when used on Mode 1. Put in a simple way, this allows the three referred Cyborg types to wake up and remove stuns from carbons with the use of their Hug Module.

* Cyborgs can now shake up compromised carbons

Co-authored-by: Justice <42555530+Justice12354@users.noreply.github.com>
2021-11-10 10:09:47 -05:00

1048 lines
34 KiB
Plaintext

/**********************************************************************
Cyborg Spec Items
***********************************************************************/
/obj/item/borg
icon = 'icons/mob/robot_items.dmi'
/obj/item/borg/stun
name = "electrically-charged arm"
icon_state = "elecarm"
var/charge_cost = 30
/obj/item/borg/stun/attack(mob/living/M, mob/living/user)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.check_shields(src, 0, "[M]'s [name]", MELEE_ATTACK))
playsound(M, 'sound/weapons/genhit.ogg', 50, TRUE)
return FALSE
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(!R.cell.use(charge_cost))
return
user.do_attack_animation(M)
M.Paralyze(100)
M.apply_effect(EFFECT_STUTTER, 5)
M.visible_message(span_danger("[user] prods [M] with [src]!"), \
span_userdanger("[user] prods you with [src]!"))
playsound(loc, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
log_combat(user, M, "stunned", src, "(Combat mode: [user.combat_mode ? "On" : "Off"])")
/obj/item/borg/cyborghug
name = "hugging module"
icon_state = "hugmodule"
desc = "For when a someone really needs a hug."
var/mode = 0 //0 = Hugs 1 = "Hug" 2 = Shock 3 = CRUSH
var/ccooldown = 0
var/scooldown = 0
var/shockallowed = FALSE//Can it be a stunarm when emagged. Only PK borgs get this by default.
var/boop = FALSE
/obj/item/borg/cyborghug/attack_self(mob/living/user)
if(iscyborg(user))
var/mob/living/silicon/robot/P = user
if(P.emagged&&shockallowed == 1)
if(mode < 3)
mode++
else
mode = 0
else if(mode < 1)
mode++
else
mode = 0
switch(mode)
if(0)
to_chat(user, "<span class='infoplain'>Power reset. Hugs!</span>")
if(1)
to_chat(user, "<span class='infoplain'>Power increased!</span>")
if(2)
to_chat(user, "<span class='warningplain'>BZZT. Electrifying arms...</span>")
if(3)
to_chat(user, "<span class='warningplain'>ERROR: ARM ACTUATORS OVERLOADED.</span>")
/obj/item/borg/cyborghug/attack(mob/living/M, mob/living/silicon/robot/user, params)
if(M == user)
return
switch(mode)
if(0)
if(M.health >= 0)
if(isanimal(M))
var/list/modifiers = params2list(params)
if (!user.combat_mode && !LAZYACCESS(modifiers, RIGHT_CLICK))
M.attack_hand(user, modifiers) //This enables borgs to get the floating heart icon and mob emote from simple_animal's that have petbonus == true.
return
if(user.zone_selected == BODY_ZONE_HEAD)
user.visible_message(span_notice("[user] playfully boops [M] on the head!"), \
span_notice("You playfully boop [M] on the head!"))
user.do_attack_animation(M, ATTACK_EFFECT_BOOP)
playsound(loc, 'sound/weapons/tap.ogg', 50, TRUE, -1)
else if(ishuman(M))
if(user.body_position == LYING_DOWN)
user.visible_message(span_notice("[user] shakes [M] trying to get [M.p_them()] up!"), \
span_notice("You shake [M] trying to get [M.p_them()] up!"))
else
user.visible_message(span_notice("[user] hugs [M] to make [M.p_them()] feel better!"), \
span_notice("You hug [M] to make [M.p_them()] feel better!"))
if(M.resting)
M.set_resting(FALSE, TRUE)
else
user.visible_message(span_notice("[user] pets [M]!"), \
span_notice("You pet [M]!"))
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
if(1)
if(M.health >= 0)
if(ishuman(M))
M.adjust_status_effects_on_shake_up()
if(M.body_position == LYING_DOWN)
user.visible_message(span_notice("[user] shakes [M] trying to get [M.p_them()] up!"), \
span_notice("You shake [M] trying to get [M.p_them()] up!"))
else if(user.zone_selected == BODY_ZONE_HEAD)
user.visible_message(span_warning("[user] bops [M] on the head!"), \
span_warning("You bop [M] on the head!"))
user.do_attack_animation(M, ATTACK_EFFECT_PUNCH)
else
user.visible_message(span_warning("[user] hugs [M] in a firm bear-hug! [M] looks uncomfortable..."), \
span_warning("You hug [M] firmly to make [M.p_them()] feel better! [M] looks uncomfortable..."))
if(M.resting)
M.set_resting(FALSE, TRUE)
else
user.visible_message(span_warning("[user] bops [M] on the head!"), \
span_warning("You bop [M] on the head!"))
playsound(loc, 'sound/weapons/tap.ogg', 50, TRUE, -1)
if(2)
if(scooldown < world.time)
if(M.health >= 0)
if(ishuman(M))
M.electrocute_act(5, "[user]", flags = SHOCK_NOGLOVES)
user.visible_message(span_userdanger("[user] electrocutes [M] with [user.p_their()] touch!"), \
span_danger("You electrocute [M] with your touch!"))
else
if(!iscyborg(M))
M.adjustFireLoss(10)
user.visible_message(span_userdanger("[user] shocks [M]!"), \
span_danger("You shock [M]!"))
else
user.visible_message(span_userdanger("[user] shocks [M]. It does not seem to have an effect"), \
span_danger("You shock [M] to no effect."))
playsound(loc, 'sound/effects/sparks2.ogg', 50, TRUE, -1)
user.cell.charge -= 500
scooldown = world.time + 20
if(3)
if(ccooldown < world.time)
if(M.health >= 0)
if(ishuman(M))
user.visible_message(span_userdanger("[user] crushes [M] in [user.p_their()] grip!"), \
span_danger("You crush [M] in your grip!"))
else
user.visible_message(span_userdanger("[user] crushes [M]!"), \
span_danger("You crush [M]!"))
playsound(loc, 'sound/weapons/smash.ogg', 50, TRUE, -1)
M.adjustBruteLoss(15)
user.cell.charge -= 300
ccooldown = world.time + 10
/obj/item/borg/cyborghug/peacekeeper
shockallowed = TRUE
/obj/item/borg/cyborghug/medical
boop = TRUE
/obj/item/borg/charger
name = "power connector"
icon_state = "charger_draw"
item_flags = NOBLUDGEON
var/mode = "draw"
var/static/list/charge_machines = typecacheof(list(/obj/machinery/cell_charger, /obj/machinery/recharger, /obj/machinery/recharge_station, /obj/machinery/mech_bay_recharge_port))
var/static/list/charge_items = typecacheof(list(/obj/item/stock_parts/cell, /obj/item/gun/energy))
/obj/item/borg/charger/update_icon_state()
icon_state = "charger_[mode]"
return ..()
/obj/item/borg/charger/attack_self(mob/user)
if(mode == "draw")
mode = "charge"
else
mode = "draw"
to_chat(user, span_notice("You toggle [src] to \"[mode]\" mode."))
update_appearance()
/obj/item/borg/charger/afterattack(obj/item/target, mob/living/silicon/robot/user, proximity_flag)
. = ..()
if(!proximity_flag || !iscyborg(user))
return
if(mode == "draw")
if(is_type_in_list(target, charge_machines))
var/obj/machinery/M = target
if((M.machine_stat & (NOPOWER|BROKEN)) || !M.anchored)
to_chat(user, span_warning("[M] is unpowered!"))
return
to_chat(user, span_notice("You connect to [M]'s power line..."))
while(do_after(user, 15, target = M, progress = 0))
if(!user || !user.cell || mode != "draw")
return
if((M.machine_stat & (NOPOWER|BROKEN)) || !M.anchored)
break
if(!user.cell.give(150))
break
M.use_power(200)
to_chat(user, span_notice("You stop charging yourself."))
else if(is_type_in_list(target, charge_items))
var/obj/item/stock_parts/cell/cell = target
if(!istype(cell))
cell = locate(/obj/item/stock_parts/cell) in target
if(!cell)
to_chat(user, span_warning("[target] has no power cell!"))
return
if(istype(target, /obj/item/gun/energy))
var/obj/item/gun/energy/E = target
if(!E.can_charge)
to_chat(user, span_warning("[target] has no power port!"))
return
if(!cell.charge)
to_chat(user, span_warning("[target] has no power!"))
to_chat(user, span_notice("You connect to [target]'s power port..."))
while(do_after(user, 15, target = target, progress = 0))
if(!user || !user.cell || mode != "draw")
return
if(!cell || !target)
return
if(cell != target && cell.loc != target)
return
var/draw = min(cell.charge, cell.chargerate*0.5, user.cell.maxcharge-user.cell.charge)
if(!cell.use(draw))
break
if(!user.cell.give(draw))
break
target.update_appearance()
to_chat(user, span_notice("You stop charging yourself."))
else if(is_type_in_list(target, charge_items))
var/obj/item/stock_parts/cell/cell = target
if(!istype(cell))
cell = locate(/obj/item/stock_parts/cell) in target
if(!cell)
to_chat(user, span_warning("[target] has no power cell!"))
return
if(istype(target, /obj/item/gun/energy))
var/obj/item/gun/energy/E = target
if(!E.can_charge)
to_chat(user, span_warning("[target] has no power port!"))
return
if(cell.charge >= cell.maxcharge)
to_chat(user, span_warning("[target] is already charged!"))
to_chat(user, span_notice("You connect to [target]'s power port..."))
while(do_after(user, 15, target = target, progress = 0))
if(!user || !user.cell || mode != "charge")
return
if(!cell || !target)
return
if(cell != target && cell.loc != target)
return
var/draw = min(user.cell.charge, cell.chargerate*0.5, cell.maxcharge-cell.charge)
if(!user.cell.use(draw))
break
if(!cell.give(draw))
break
target.update_appearance()
to_chat(user, span_notice("You stop charging [target]."))
/obj/item/harmalarm
name = "\improper Sonic Harm Prevention Tool"
desc = "Releases a harmless blast that confuses most organics. For when the harm is JUST TOO MUCH."
icon = 'icons/obj/device.dmi'
icon_state = "megaphone"
var/cooldown = 0
/obj/item/harmalarm/emag_act(mob/user)
obj_flags ^= EMAGGED
if(obj_flags & EMAGGED)
to_chat(user, "<font color='red'>You short out the safeties on [src]!</font>")
else
to_chat(user, "<font color='red'>You reset the safeties on [src]!</font>")
/obj/item/harmalarm/attack_self(mob/user)
var/safety = !(obj_flags & EMAGGED)
if(cooldown > world.time)
to_chat(user, "<font color='red'>The device is still recharging!</font>")
return
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(!R.cell || R.cell.charge < 1200)
to_chat(user, span_warning("You don't have enough charge to do this!"))
return
R.cell.charge -= 1000
if(R.emagged)
safety = FALSE
if(safety == TRUE)
user.visible_message("<font color='red' size='2'>[user] blares out a near-deafening siren from its speakers!</font>", \
span_userdanger("The siren pierces your hearing and confuses you!"), \
span_danger("The siren pierces your hearing!"))
for(var/mob/living/carbon/M in get_hearers_in_view(9, user))
if(M.get_ear_protection() == FALSE)
M.add_confusion(6)
audible_message("<font color='red' size='7'>HUMAN HARM</font>")
playsound(get_turf(src), 'sound/ai/harmalarm.ogg', 70, 3)
cooldown = world.time + 200
user.log_message("used a Cyborg Harm Alarm in [AREACOORD(user)]", LOG_ATTACK)
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
to_chat(R.connected_ai, "<br>[span_notice("NOTICE - Peacekeeping 'HARM ALARM' used by: [user]")]<br>")
return
if(safety == FALSE)
user.audible_message("<font color='red' size='7'>BZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZT</font>")
for(var/mob/living/carbon/C in get_hearers_in_view(9, user))
var/bang_effect = C.soundbang_act(2, 0, 0, 5)
switch(bang_effect)
if(1)
C.add_confusion(5)
C.stuttering += 10
C.Jitter(10)
if(2)
C.Paralyze(40)
C.add_confusion(10)
C.stuttering += 15
C.Jitter(25)
playsound(get_turf(src), 'sound/machines/warning-buzzer.ogg', 130, 3)
cooldown = world.time + 600
user.log_message("used an emagged Cyborg Harm Alarm in [AREACOORD(user)]", LOG_ATTACK)
#define DISPENSE_LOLLIPOP_MODE 1
#define THROW_LOLLIPOP_MODE 2
#define THROW_GUMBALL_MODE 3
#define DISPENSE_ICECREAM_MODE 4
/obj/item/borg/lollipop
name = "treat fabricator"
desc = "Reward humans with various treats. Toggle in-module to switch between dispensing and high velocity ejection modes."
icon_state = "lollipop"
var/candy = 5
var/candymax = 5
var/charge_delay = 10 SECONDS
var/charging = FALSE
var/mode = DISPENSE_LOLLIPOP_MODE
var/firedelay = 0
var/hitspeed = 2
/obj/item/borg/lollipop/clown
/obj/item/borg/lollipop/equipped()
. = ..()
check_amount()
/obj/item/borg/lollipop/dropped()
. = ..()
check_amount()
/obj/item/borg/lollipop/proc/check_amount() //Doesn't even use processing ticks.
if(!charging && candy < candymax)
addtimer(CALLBACK(src, .proc/charge_lollipops), charge_delay)
charging = TRUE
/obj/item/borg/lollipop/proc/charge_lollipops()
candy++
charging = FALSE
check_amount()
/obj/item/borg/lollipop/proc/dispense(atom/A, mob/user)
if(candy <= 0)
to_chat(user, span_warning("No treats left in storage!"))
return FALSE
var/turf/T = get_turf(A)
if(!T || !istype(T) || !isopenturf(T))
return FALSE
if(isobj(A))
var/obj/O = A
if(O.density)
return FALSE
var/obj/item/food_item
switch(mode)
if(DISPENSE_LOLLIPOP_MODE)
food_item = new /obj/item/food/lollipop(T)
if(DISPENSE_ICECREAM_MODE)
food_item = new /obj/item/food/icecream(T, list(ICE_CREAM_VANILLA))
food_item.desc = "Eat the ice cream."
var/into_hands = FALSE
if(ismob(A))
var/mob/M = A
into_hands = M.put_in_hands(food_item)
candy--
check_amount()
if(into_hands)
user.visible_message(span_notice("[user] dispenses a treat into the hands of [A]."), span_notice("You dispense a treat into the hands of [A]."), span_hear("You hear a click."))
else
user.visible_message(span_notice("[user] dispenses a treat."), span_notice("You dispense a treat."), span_hear("You hear a click."))
playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
return TRUE
/obj/item/borg/lollipop/proc/shootL(atom/target, mob/living/user, params)
if(candy <= 0)
to_chat(user, span_warning("Not enough lollipops left!"))
return FALSE
candy--
var/obj/item/ammo_casing/caseless/lollipop/A
var/mob/living/silicon/robot/R = user
if(istype(R) && R.emagged)
A = new /obj/item/ammo_casing/caseless/lollipop/harmful(src)
else
A = new /obj/item/ammo_casing/caseless/lollipop(src)
playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
A.fire_casing(target, user, params, 0, 0, null, 0, src)
user.visible_message(span_warning("[user] blasts a flying lollipop at [target]!"))
check_amount()
/obj/item/borg/lollipop/proc/shootG(atom/target, mob/living/user, params) //Most certainly a good idea.
if(candy <= 0)
to_chat(user, span_warning("Not enough gumballs left!"))
return FALSE
candy--
var/obj/item/ammo_casing/caseless/gumball/A
var/mob/living/silicon/robot/R = user
if(istype(R) && R.emagged)
A = new /obj/item/ammo_casing/caseless/gumball/harmful(src)
else
A = new /obj/item/ammo_casing/caseless/gumball(src)
A.loaded_projectile.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
playsound(src.loc, 'sound/weapons/bulletflyby3.ogg', 50, TRUE)
A.fire_casing(target, user, params, 0, 0, null, 0, src)
user.visible_message(span_warning("[user] shoots a high-velocity gumball at [target]!"))
check_amount()
/obj/item/borg/lollipop/afterattack(atom/target, mob/living/user, proximity, click_params)
. = ..()
check_amount()
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(!R.cell.use(12))
to_chat(user, span_warning("Not enough power."))
return FALSE
switch(mode)
if(DISPENSE_LOLLIPOP_MODE, DISPENSE_ICECREAM_MODE)
if(!proximity)
return FALSE
dispense(target, user)
if(THROW_LOLLIPOP_MODE)
shootL(target, user, click_params)
if(THROW_GUMBALL_MODE)
shootG(target, user, click_params)
/obj/item/borg/lollipop/attack_self(mob/living/user)
switch(mode)
if(DISPENSE_LOLLIPOP_MODE)
mode = THROW_LOLLIPOP_MODE
to_chat(user, span_notice("Module is now throwing lollipops."))
if(THROW_LOLLIPOP_MODE)
mode = THROW_GUMBALL_MODE
to_chat(user, span_notice("Module is now blasting gumballs."))
if(THROW_GUMBALL_MODE)
mode = DISPENSE_ICECREAM_MODE
to_chat(user, span_notice("Module is now dispensing ice cream."))
if(DISPENSE_ICECREAM_MODE)
mode = DISPENSE_LOLLIPOP_MODE
to_chat(user, span_notice("Module is now dispensing lollipops."))
..()
#undef DISPENSE_LOLLIPOP_MODE
#undef THROW_LOLLIPOP_MODE
#undef THROW_GUMBALL_MODE
#undef DISPENSE_ICECREAM_MODE
/obj/item/ammo_casing/caseless/gumball
name = "Gumball"
desc = "Why are you seeing this?!"
projectile_type = /obj/projectile/bullet/reusable/gumball
click_cooldown_override = 2
/obj/item/ammo_casing/caseless/gumball/harmful
projectile_type = /obj/projectile/bullet/reusable/gumball/harmful
/obj/projectile/bullet/reusable/gumball
name = "gumball"
desc = "Oh noes! A fast-moving gumball!"
icon_state = "gumball"
ammo_type = /obj/item/food/gumball
nodamage = TRUE
damage = 0
speed = 0.5
/obj/projectile/bullet/reusable/gumball/harmful
nodamage = FALSE
damage = 10 //mediborgs get 5 shots before needing to reload at a rate of 1 shot/10 seconds, so they can do 50 damage from range max before needing to close the distance or retreat
/obj/projectile/bullet/reusable/gumball/handle_drop()
if(!dropped)
var/turf/T = get_turf(src)
var/obj/item/food/gumball/S = new ammo_type(T)
S.color = color
dropped = TRUE
/obj/item/ammo_casing/caseless/lollipop //NEEDS RANDOMIZED COLOR LOGIC.
name = "Lollipop"
desc = "Why are you seeing this?!"
projectile_type = /obj/projectile/bullet/reusable/lollipop
click_cooldown_override = 2
// rejected name: DumDum lollipop (get it, cause it embeds?)
/obj/item/ammo_casing/caseless/lollipop/harmful
projectile_type = /obj/projectile/bullet/reusable/lollipop/harmful
/obj/projectile/bullet/reusable/lollipop
name = "lollipop"
desc = "Oh noes! A fast-moving lollipop!"
icon_state = "lollipop_1"
ammo_type = /obj/item/food/lollipop/cyborg
nodamage = TRUE
damage = 0
speed = 0.5
var/color2 = rgb(0, 0, 0)
/obj/projectile/bullet/reusable/lollipop/harmful
embedding = list(embed_chance=35, fall_chance=2, jostle_chance=0, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=3, rip_time=10)
damage = 10
nodamage = FALSE
embed_falloff_tile = 0
/obj/projectile/bullet/reusable/lollipop/Initialize(mapload)
. = ..()
var/obj/item/food/lollipop/S = new ammo_type(src)
color2 = S.headcolor
var/mutable_appearance/head = mutable_appearance('icons/obj/guns/projectiles.dmi', "lollipop_2")
head.color = color2
add_overlay(head)
/obj/projectile/bullet/reusable/lollipop/handle_drop()
if(!dropped)
var/turf/T = get_turf(src)
var/obj/item/food/lollipop/S = new ammo_type(T)
S.change_head_color(color2)
dropped = TRUE
/obj/item/cautery/prt //it's a subtype of cauteries so that it inherits the cautery sprites and behavior and stuff, because I'm too lazy to make sprites for this thing
name = "plating repair tool"
desc = "A tiny heating device that's powered by a cyborg's excess heat. Its intended purpose is to repair burnt or damaged hull platings, but it can also be used as a crude lighter or cautery."
toolspeed = 1.5 //it's not designed to be used as a cautery (although it's close enough to one to be considered to be a proper cautery instead of just a hot object for the purposes of surgery)
heat = 3800 //this thing is intended for metal-shaping, so it's the same temperature as a lit welder
resistance_flags = FIRE_PROOF //if it's channeling a cyborg's excess heat, it's probably fireproof
force = 5
damtype = BURN
usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') //the usesounds of a lit welder
hitsound = 'sound/items/welder.ogg' //the hitsound of a lit welder
#define PKBORG_DAMPEN_CYCLE_DELAY 20
//Peacekeeper Cyborg Projectile Dampenening Field
/obj/item/borg/projectile_dampen
name = "\improper Hyperkinetic Dampening projector"
desc = "A device that projects a dampening field that weakens kinetic energy above a certain threshold. <span class='boldnotice'>Projects a field that drains power per second while active, that will weaken and slow damaging projectiles inside its field.</span> Still being a prototype, it tends to induce a charge on ungrounded metallic surfaces."
icon = 'icons/obj/device.dmi'
icon_state = "shield"
var/maxenergy = 1500
var/energy = 1500
/// Recharging rate in energy per second
var/energy_recharge = 37.5
var/energy_recharge_cyborg_drain_coefficient = 0.4
var/cyborg_cell_critical_percentage = 0.05
var/mob/living/silicon/robot/host = null
var/datum/proximity_monitor/advanced/dampening_field
var/projectile_damage_coefficient = 0.5
/// Energy cost per tracked projectile damage amount per second
var/projectile_damage_tick_ecost_coefficient = 10
var/projectile_speed_coefficient = 1.5 //Higher the coefficient slower the projectile.
/// Energy cost per tracked projectile per second
var/projectile_tick_speed_ecost = 75
var/list/obj/projectile/tracked
var/image/projectile_effect
var/field_radius = 3
var/active = FALSE
var/cycle_delay = 0
/obj/item/borg/projectile_dampen/debug
maxenergy = 50000
energy = 50000
energy_recharge = 5000
/obj/item/borg/projectile_dampen/Initialize(mapload)
. = ..()
projectile_effect = image('icons/effects/fields.dmi', "projectile_dampen_effect")
tracked = list()
icon_state = "shield0"
START_PROCESSING(SSfastprocess, src)
host = loc
RegisterSignal(host, COMSIG_LIVING_DEATH, .proc/on_death)
/obj/item/borg/projectile_dampen/proc/on_death(datum/source, gibbed)
SIGNAL_HANDLER
deactivate_field()
/obj/item/borg/projectile_dampen/Destroy()
STOP_PROCESSING(SSfastprocess, src)
return ..()
/obj/item/borg/projectile_dampen/attack_self(mob/user)
if(cycle_delay > world.time)
to_chat(user, span_boldwarning("[src] is still recycling its projectors!"))
return
cycle_delay = world.time + PKBORG_DAMPEN_CYCLE_DELAY
if(!active)
if(!user.has_buckled_mobs())
activate_field()
else
to_chat(user, span_warning("[src]'s safety cutoff prevents you from activating it due to living beings being ontop of you!"))
else
deactivate_field()
update_appearance()
to_chat(user, span_boldnotice("You [active? "activate":"deactivate"] [src]."))
/obj/item/borg/projectile_dampen/update_icon_state()
icon_state = "[initial(icon_state)][active]"
return ..()
/obj/item/borg/projectile_dampen/proc/activate_field()
if(istype(dampening_field))
QDEL_NULL(dampening_field)
dampening_field = make_field(/datum/proximity_monitor/advanced/peaceborg_dampener, list("current_range" = field_radius, "host" = src, "projector" = src))
var/mob/living/silicon/robot/owner = get_host()
if(owner)
owner.model.allow_riding = FALSE
active = TRUE
/obj/item/borg/projectile_dampen/proc/deactivate_field()
QDEL_NULL(dampening_field)
visible_message(span_warning("\The [src] shuts off!"))
for(var/P in tracked)
restore_projectile(P)
active = FALSE
var/mob/living/silicon/robot/owner = get_host()
if(owner)
owner.model.allow_riding = TRUE
/obj/item/borg/projectile_dampen/proc/get_host()
if(istype(host))
return host
else
if(iscyborg(host.loc))
return host.loc
return null
/obj/item/borg/projectile_dampen/dropped()
. = ..()
host = loc
/obj/item/borg/projectile_dampen/equipped()
. = ..()
host = loc
/obj/item/borg/projectile_dampen/cyborg_unequip(mob/user)
deactivate_field()
. = ..()
/obj/item/borg/projectile_dampen/process(delta_time)
process_recharge(delta_time)
process_usage(delta_time)
update_location()
/obj/item/borg/projectile_dampen/proc/update_location()
if(dampening_field)
dampening_field.HandleMove()
/obj/item/borg/projectile_dampen/proc/process_usage(delta_time)
var/usage = 0
for(var/I in tracked)
var/obj/projectile/P = I
if(!P.stun && P.nodamage) //No damage
continue
usage += projectile_tick_speed_ecost * delta_time
usage += tracked[I] * projectile_damage_tick_ecost_coefficient * delta_time
energy = clamp(energy - usage, 0, maxenergy)
if(energy <= 0)
deactivate_field()
visible_message(span_warning("[src] blinks \"ENERGY DEPLETED\"."))
/obj/item/borg/projectile_dampen/proc/process_recharge(delta_time)
if(!istype(host))
if(iscyborg(host.loc))
host = host.loc
else
energy = clamp(energy + energy_recharge * delta_time, 0, maxenergy)
return
if(host.cell && (host.cell.charge >= (host.cell.maxcharge * cyborg_cell_critical_percentage)) && (energy < maxenergy))
host.cell.use(energy_recharge * delta_time * energy_recharge_cyborg_drain_coefficient)
energy += energy_recharge * delta_time
/obj/item/borg/projectile_dampen/proc/dampen_projectile(obj/projectile/P, track_projectile = TRUE)
if(tracked[P])
return
if(track_projectile)
tracked[P] = P.damage
P.damage *= projectile_damage_coefficient
P.speed *= projectile_speed_coefficient
P.add_overlay(projectile_effect)
/obj/item/borg/projectile_dampen/proc/restore_projectile(obj/projectile/P)
tracked -= P
P.damage *= (1/projectile_damage_coefficient)
P.speed *= (1/projectile_speed_coefficient)
P.cut_overlay(projectile_effect)
/**********************************************************************
HUD/SIGHT things
***********************************************************************/
/obj/item/borg/sight
var/sight_mode = null
/obj/item/borg/sight/xray
name = "\proper X-ray vision"
icon = 'icons/obj/decals.dmi'
icon_state = "securearea"
sight_mode = BORGXRAY
/obj/item/borg/sight/thermal
name = "\proper thermal vision"
sight_mode = BORGTHERM
icon_state = "thermal"
/obj/item/borg/sight/meson
name = "\proper meson vision"
sight_mode = BORGMESON
icon_state = "meson"
/obj/item/borg/sight/material
name = "\proper material vision"
sight_mode = BORGMATERIAL
icon_state = "material"
/obj/item/borg/sight/hud
name = "hud"
var/obj/item/clothing/glasses/hud/hud = null
/obj/item/borg/sight/hud/med
name = "medical hud"
icon_state = "healthhud"
/obj/item/borg/sight/hud/med/Initialize(mapload)
. = ..()
hud = new /obj/item/clothing/glasses/hud/health(src)
/obj/item/borg/sight/hud/sec
name = "security hud"
icon_state = "securityhud"
/obj/item/borg/sight/hud/sec/Initialize(mapload)
. = ..()
hud = new /obj/item/clothing/glasses/hud/security(src)
/**********************************************************************
Borg apparatus
***********************************************************************/
//These are tools that can hold only specific items. For example, the mediborg gets one that can only hold beakers and bottles.
/obj/item/borg/apparatus/
name = "unknown storage apparatus"
desc = "This device seems nonfunctional."
icon = 'icons/mob/robot_items.dmi'
icon_state = "hugmodule"
var/obj/item/stored
var/list/storable = list()
/obj/item/borg/apparatus/Initialize(mapload)
. = ..()
RegisterSignal(loc.loc, COMSIG_BORG_SAFE_DECONSTRUCT, .proc/safedecon)
/obj/item/borg/apparatus/Destroy()
QDEL_NULL(stored)
. = ..()
///If we're safely deconstructed, we put the item neatly onto the ground, rather than deleting it.
/obj/item/borg/apparatus/proc/safedecon()
SIGNAL_HANDLER
if(stored)
stored.forceMove(get_turf(src))
stored = null
/obj/item/borg/apparatus/Exited(atom/movable/gone, direction)
if(gone == stored) //sanity check
UnregisterSignal(stored, COMSIG_ATOM_UPDATED_ICON)
stored = null
update_appearance()
return ..()
///A right-click verb, for those not using hotkey mode.
/obj/item/borg/apparatus/verb/verb_dropHeld()
set category = "Object"
set name = "Drop"
if(usr != loc || !stored)
return
stored.forceMove(get_turf(usr))
return
/**
* Attack_self will pass for the stored item.
*/
/obj/item/borg/apparatus/attack_self(mob/living/silicon/robot/user)
if(!stored || !issilicon(user))
return ..()
stored.attack_self(user)
//Alt click drops the stored item.
/obj/item/borg/apparatus/AltClick(mob/living/silicon/robot/user)
if(!stored || !issilicon(user))
return ..()
stored.forceMove(user.drop_location())
/obj/item/borg/apparatus/pre_attack(atom/A, mob/living/user, params)
if(!stored)
var/itemcheck = FALSE
for(var/i in storable)
if(istype(A, i))
itemcheck = TRUE
break
if(itemcheck)
var/obj/item/O = A
O.forceMove(src)
stored = O
RegisterSignal(stored, COMSIG_ATOM_UPDATED_ICON, .proc/on_stored_updated_icon)
update_appearance()
return
else
stored.melee_attack_chain(user, A, params)
return
. = ..()
/**
* Updates the appearance of the apparatus when the stored object's icon gets updated.
*
* Returns NONE as we have not done anything to the stored object itself,
* which is where this signal that this handler intercepts is sent from.
*/
/obj/item/borg/apparatus/proc/on_stored_updated_icon(datum/source, updates)
SIGNAL_HANDLER
update_appearance()
return NONE
/obj/item/borg/apparatus/attackby(obj/item/W, mob/user, params)
if(stored)
W.melee_attack_chain(user, stored, params)
return
. = ..()
/////////////////
//beaker holder//
/////////////////
/obj/item/borg/apparatus/beaker
name = "beaker storage apparatus"
desc = "A special apparatus for carrying beakers without spilling the contents."
icon_state = "borg_beaker_apparatus"
storable = list(/obj/item/reagent_containers/glass/beaker,
/obj/item/reagent_containers/glass/bottle)
/obj/item/borg/apparatus/beaker/Initialize(mapload)
. = ..()
stored = new /obj/item/reagent_containers/glass/beaker/large(src)
RegisterSignal(stored, COMSIG_ATOM_UPDATED_ICON, .proc/on_stored_updated_icon)
update_appearance()
/obj/item/borg/apparatus/beaker/Destroy()
if(stored)
var/obj/item/reagent_containers/C = stored
C.SplashReagents(get_turf(src))
QDEL_NULL(stored)
. = ..()
/obj/item/borg/apparatus/beaker/examine()
. = ..()
if(stored)
var/obj/item/reagent_containers/C = stored
. += "The apparatus currently has [C] secured, which contains:"
if(length(C.reagents.reagent_list))
for(var/datum/reagent/R in C.reagents.reagent_list)
. += "[R.volume] units of [R.name]"
else
. += "Nothing."
. += span_notice(" <i>Right-clicking</i> will splash the beaker on the ground.")
. += span_notice(" <i>Alt-click</i> will drop the currently stored beaker. ")
/obj/item/borg/apparatus/beaker/update_overlays()
. = ..()
var/mutable_appearance/arm = mutable_appearance(icon = icon, icon_state = "borg_beaker_apparatus_arm")
if(stored)
COMPILE_OVERLAYS(stored)
stored.pixel_x = 0
stored.pixel_y = 0
var/mutable_appearance/stored_copy = new /mutable_appearance(stored)
if(istype(stored, /obj/item/reagent_containers/glass/beaker))
arm.pixel_y = arm.pixel_y - 3
stored_copy.layer = FLOAT_LAYER
stored_copy.plane = FLOAT_PLANE
. += stored_copy
else
arm.pixel_y = arm.pixel_y - 5
. += arm
/// Secondary attack spills the content of the beaker.
/obj/item/borg/apparatus/beaker/pre_attack_secondary(atom/target, mob/living/silicon/robot/user)
var/obj/item/reagent_containers/stored_beaker = stored
stored_beaker.SplashReagents(drop_location(user))
loc.visible_message(span_notice("[user] spills the contents of [stored_beaker] all over the ground."))
. = ..()
/obj/item/borg/apparatus/beaker/extra
name = "secondary beaker storage apparatus"
desc = "A supplementary beaker storage apparatus."
/obj/item/borg/apparatus/beaker/service
name = "beverage storage apparatus"
desc = "A special apparatus for carrying drinks without spilling the contents. Will resynthesize any drinks you pour out!"
icon_state = "borg_beaker_apparatus"
storable = list(/obj/item/reagent_containers/food/drinks,
/obj/item/reagent_containers/food/condiment)
/obj/item/borg/apparatus/beaker/service/Initialize(mapload)
. = ..()
stored = new /obj/item/reagent_containers/food/drinks/drinkingglass(src)
RegisterSignal(stored, COMSIG_ATOM_UPDATED_ICON, .proc/on_stored_updated_icon)
update_appearance()
/////////////////////
//organ storage bag//
/////////////////////
/obj/item/borg/apparatus/organ_storage //allows medical cyborgs to manipulate organs without hands
name = "organ storage bag"
desc = "A container for holding body parts."
icon = 'icons/obj/storage.dmi'
icon_state = "evidenceobj"
item_flags = SURGICAL_TOOL
storable = list(/obj/item/organ,
/obj/item/bodypart)
/obj/item/borg/apparatus/organ_storage/examine()
. = ..()
. += "The organ bag currently contains:"
if(stored)
var/obj/item/organ = stored
. += organ.name
else
. += "Nothing."
. += span_notice(" <i>Alt-click</i> will drop the currently stored organ. ")
/obj/item/borg/apparatus/organ_storage/update_overlays()
. = ..()
icon_state = null // hides the original icon (otherwise it's drawn underneath)
var/mutable_appearance/bag
if(stored)
COMPILE_OVERLAYS(stored)
var/mutable_appearance/stored_organ = new /mutable_appearance(stored)
stored_organ.layer = FLOAT_LAYER
stored_organ.plane = FLOAT_PLANE
stored_organ.pixel_x = 0
stored_organ.pixel_y = 0
. += stored_organ
bag = mutable_appearance(icon, icon_state = "evidence") // full bag
else
bag = mutable_appearance(icon, icon_state = "evidenceobj") // empty bag
. += bag
/obj/item/borg/apparatus/organ_storage/AltClick(mob/living/silicon/robot/user)
. = ..()
if(stored)
var/obj/item/organ = stored
user.visible_message(span_notice("[user] dumps [organ] from [src]."), span_notice("You dump [organ] from [src]."))
cut_overlays()
organ.forceMove(get_turf(src))
else
to_chat(user, span_notice("[src] is empty."))
return
////////////////////////////
//engi circuitboard holder//
////////////////////////////
/obj/item/borg/apparatus/circuit
name = "circuit manipulation apparatus"
desc = "A special apparatus for carrying and manipulating circuit boards."
icon_state = "borg_hardware_apparatus"
storable = list(/obj/item/circuitboard,
/obj/item/electronics)
/obj/item/borg/apparatus/circuit/Initialize(mapload)
. = ..()
update_appearance()
/obj/item/borg/apparatus/circuit/update_overlays()
. = ..()
var/mutable_appearance/arm = mutable_appearance(icon, "borg_hardware_apparatus_arm1")
if(stored)
COMPILE_OVERLAYS(stored)
stored.pixel_x = -3
stored.pixel_y = 0
if(!istype(stored, /obj/item/circuitboard))
arm.icon_state = "borg_hardware_apparatus_arm2"
var/mutable_appearance/stored_copy = new /mutable_appearance(stored)
stored_copy.layer = FLOAT_LAYER
stored_copy.plane = FLOAT_PLANE
. += stored_copy
. += arm
/obj/item/borg/apparatus/circuit/examine()
. = ..()
if(stored)
. += "The apparatus currently has [stored] secured."
. += span_notice(" <i>Alt-click</i> will drop the currently stored circuit. ")
/obj/item/borg/apparatus/circuit/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(istype(A, /obj/item/ai_module) && !stored) //If an admin wants a borg to upload laws, who am I to stop them? Otherwise, we can hint that it fails
to_chat(user, span_warning("This circuit board doesn't seem to have standard robot apparatus pin holes. You're unable to pick it up."))