From b80a184d9723e47cd8cafb1bf192aeb0c29b21fe Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 00:04:00 -0500 Subject: [PATCH 01/19] up to upstream-merge-27868 --- code/_onclick/autoclick.dm | 49 ++++- code/game/atoms_movable.dm | 4 + .../clock_helpers/clock_powerdrain.dm | 2 +- code/game/gamemodes/events.dm | 2 +- code/game/machinery/cell_charger.dm | 2 +- .../machinery/porta_turret/portable_turret.dm | 192 +----------------- code/game/machinery/recharger.dm | 56 ++--- code/game/machinery/spaceheater.dm | 3 + code/game/mecha/mecha.dm | 5 +- code/game/objects/items/weapons/defib.dm | 47 +++-- code/game/objects/items/weapons/stunbaton.dm | 46 ++--- code/game/objects/items/weapons/teleprod.dm | 2 +- code/game/objects/objs.dm | 10 +- .../closets/secure/engineering.dm | 3 + code/game/objects/structures/watercloset.dm | 4 +- .../modules/admin/verbs/individual_logging.dm | 13 +- .../components/trinary_devices/filter.dm | 8 + code/modules/cargo/packs.dm | 7 + .../mob/living/carbon/human/interactive.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 3 + .../mob/living/silicon/robot/robot_defense.dm | 2 +- .../mob/living/silicon/robot/robot_modules.dm | 42 ++-- .../mob/living/simple_animal/bot/ed209bot.dm | 14 +- .../mob/living/simple_animal/hostile/mimic.dm | 10 +- .../computers/item/computer_power.dm | 5 + code/modules/ninja/suit/ninjaDrainAct.dm | 2 +- code/modules/ninja/suit/suit.dm | 2 + code/modules/ninja/suit/suit_attackby.dm | 2 +- code/modules/power/apc.dm | 12 +- code/modules/power/cell.dm | 17 +- code/modules/projectiles/guns/energy.dm | 63 +++--- .../guns/energy/kinetic_accelerator.dm | 4 +- .../projectiles/guns/energy/special.dm | 10 +- code/modules/projectiles/projectile.dm | 86 ++++---- .../modules/research/designs/power_designs.dm | 11 + icons/mob/inhands/items_lefthand.dmi | Bin 133918 -> 134365 bytes icons/mob/inhands/items_righthand.dmi | Bin 132061 -> 132513 bytes icons/obj/tools.dmi | Bin 10864 -> 11806 bytes tgstation.dme | 2 + 39 files changed, 333 insertions(+), 411 deletions(-) diff --git a/code/_onclick/autoclick.dm b/code/_onclick/autoclick.dm index 7b6e2f108a..23d07e2968 100644 --- a/code/_onclick/autoclick.dm +++ b/code/_onclick/autoclick.dm @@ -1,5 +1,10 @@ /client var/list/atom/selected_target[2] + var/obj/item/active_mousedown_item = null + var/mouseParams = "" + var/mouseLocation = null + var/mouseObject = null + var/mouseControlObject = null /client/MouseDown(object, location, control, params) var/delay = mob.CanMobAutoclick(object, location, params) @@ -9,14 +14,26 @@ while(selected_target[1]) Click(selected_target[1], location, control, selected_target[2]) sleep(delay) + active_mousedown_item = mob.canMobMousedown(object, location, params) + if(active_mousedown_item) + active_mousedown_item.onMouseDown(object, location, params, mob) /client/MouseUp(object, location, control, params) selected_target[1] = null + if(active_mousedown_item) + active_mousedown_item.onMouseUp(object, location, params, mob) + active_mousedown_item = null /client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) + mouseParams = params + mouseLocation = over_location + mouseObject = over_object + mouseControlObject = over_control if(selected_target[1] && over_object && over_object.IsAutoclickable()) selected_target[1] = over_object selected_target[2] = params + if(active_mousedown_item) + active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob) /mob/proc/CanMobAutoclick(object, location, params) @@ -27,8 +44,31 @@ if(h) . = h.CanItemAutoclick(object, location, params) +/mob/proc/canMobMousedown(object, location, params) + +/mob/living/carbon/canMobMousedown(atom/object, location, params) + var/obj/item/H = get_active_held_item() + if(H) + . = H.canItemMouseDown(object, location, params) + /obj/item/proc/CanItemAutoclick(object, location, params) +/obj/item/proc/canItemMouseDown(object, location, params) + if(canMouseDown) + return src + +/obj/item/proc/onMouseDown(object, location, params, mob) + return + +/obj/item/proc/onMouseUp(object, location, params, mob) + return + +/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) + return + +/obj/item + var/canMouseDown = FALSE + /obj/item/weapon/gun var/automatic = 0 //can gun use it, 0 is no, anything above 0 is the delay between clicks in ds @@ -42,4 +82,11 @@ . = 0 /obj/screen/click_catcher/IsAutoclickable() - . = 1 \ No newline at end of file + . = 1 + +//Please don't roast me too hard +/client/MouseMove(object,location,control,params) + mouseParams = params + mouseLocation = location + mouseObject = object + mouseControlObject = control diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index edbb46d7fe..78eaa4d13b 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -679,3 +679,7 @@ set waitfor = FALSE if(!anchored && has_gravity()) step(src, movedir) + +//Returns an atom's power cell, if it has one. Overload for individual items. +/atom/movable/proc/get_cell() + return diff --git a/code/game/gamemodes/clock_cult/clock_helpers/clock_powerdrain.dm b/code/game/gamemodes/clock_cult/clock_helpers/clock_powerdrain.dm index 705273876c..cdde45bb4c 100644 --- a/code/game/gamemodes/clock_cult/clock_helpers/clock_powerdrain.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/clock_powerdrain.dm @@ -29,7 +29,7 @@ if(charge) . = min(charge, 250) charge = use(.) - updateicon() + update_icon() /obj/machinery/light/power_drain(clockcult_user) if(on) diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index b44b6b58b6..2b3e945c1f 100644 --- a/code/game/gamemodes/events.dm +++ b/code/game/gamemodes/events.dm @@ -9,7 +9,7 @@ S.update_icon() S.power_change() - var/list/skipped_areas = list(/area/engine/engineering, /area/ai_monitored/turret_protected/ai) + var/list/skipped_areas = list(/area/engine/engineering, /area/engine/supermatter, /area/engine/atmospherics_engine, /area/ai_monitored/turret_protected/ai) for(var/area/A in world) if( !A.requires_power || A.always_unpowered ) diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index 9f63391c86..8d17831a3b 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -71,7 +71,7 @@ /obj/machinery/cell_charger/proc/removecell() - charging.updateicon() + charging.update_icon() charging = null chargelevel = -1 updateicon() diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 4b2176c603..7f51b4290a 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -87,9 +87,9 @@ if(has_cover) cover = new /obj/machinery/porta_turret_cover(loc) cover.parent_turret = src - var/mutable_appearance/base = mutable_appearance('icons/obj/turrets.dmi', "basedark") - base.layer = NOT_HIGH_OBJ_LAYER - underlays += base + var/mutable_appearance/base = mutable_appearance('icons/obj/turrets.dmi', "basedark") + base.layer = NOT_HIGH_OBJ_LAYER + underlays += base if(!has_cover) INVOKE_ASYNC(src, .proc/popUp) @@ -554,7 +554,7 @@ use_power = 0 has_cover = 0 scan_range = 9 - req_access = list(GLOB.access_syndicate) + req_access = list(GLOB.access_syndicate) stun_projectile = /obj/item/projectile/bullet lethal_projectile = /obj/item/projectile/bullet lethal_projectile_sound = 'sound/weapons/Gunshot.ogg' @@ -571,8 +571,8 @@ return 10 //Syndicate turrets shoot everything not in their faction /obj/machinery/porta_turret/syndicate/pod - max_integrity = 40 - integrity_failure = 20 + max_integrity = 40 + integrity_failure = 20 obj_integrity = 40 stun_projectile = /obj/item/projectile/bullet/weakbullet3 lethal_projectile = /obj/item/projectile/bullet/weakbullet3 @@ -924,182 +924,4 @@ if(istype(P, /obj/item/projectile/beam/lasertag/bluetag)) on = 0 spawn(100) - on = 1 - -/////// MANNED TURRET //////// - -/obj/machinery/manned_turret - name = "machine gun turret" - desc = "While the trigger is held down, this gun will redistribute recoil to allow its user to easily shift targets." - icon = 'icons/obj/turrets.dmi' - icon_state = "machinegun" - can_buckle = TRUE - density = TRUE - max_integrity = 100 - obj_integrity = 100 - buckle_lying = 0 - layer = ABOVE_MOB_LAYER - var/view_range = 10 - var/cooldown = 0 - var/projectile_type = /obj/item/projectile/bullet/weakbullet3 - var/rate_of_fire = 1 - var/number_of_shots = 40 - var/cooldown_duration = 90 - var/atom/target - var/turf/target_turf - var/warned = FALSE - var/mouseparams - -//BUCKLE HOOKS - -/obj/machinery/manned_turret/unbuckle_mob(mob/living/buckled_mob,force = 0) - playsound(src,'sound/mecha/mechmove01.ogg', 50, 1) - for(var/obj/item/I in buckled_mob.held_items) - if(istype(I, /obj/item/gun_control)) - qdel(I) - if(istype(buckled_mob)) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 0 - if(buckled_mob.client) - buckled_mob.client.change_view(world.view) - anchored = FALSE - . = ..() - -/obj/machinery/manned_turret/user_buckle_mob(mob/living/M, mob/living/carbon/user) - if(user.incapacitated() || !istype(user)) - return - M.forceMove(get_turf(src)) - ..() - for(var/V in M.held_items) - var/obj/item/I = V - if(istype(I)) - if(M.dropItemToGround(I)) - var/obj/item/gun_control/TC = new /obj/item/gun_control(src) - M.put_in_hands(TC) - else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand - var/obj/item/gun_control/TC = new /obj/item/gun_control(src) - M.put_in_hands(TC) - M.pixel_y = 14 - layer = ABOVE_MOB_LAYER - setDir(SOUTH) - playsound(src,'sound/mecha/mechmove01.ogg', 50, 1) - anchored = TRUE - if(user.client) - user.client.change_view(view_range) - -/obj/item/gun_control - name = "turret controls" - icon = 'icons/obj/weapons.dmi' - icon_state = "offhand" - w_class = WEIGHT_CLASS_HUGE - flags = ABSTRACT | NODROP | NOBLUDGEON - resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF - var/obj/machinery/manned_turret/turret - -/obj/item/gun_control/New(obj/machinery/manned_turret/MT) - if(MT) - turret = MT - else - qdel(src) - -/obj/item/gun_control/CanItemAutoclick() - return 1 - -/obj/item/gun_control/attack_obj(obj/O, mob/living/user) - user.changeNext_move(CLICK_CD_MELEE) - O.attacked_by(src, user) - -/obj/item/gun_control/attack(mob/living/M, mob/living/user) - user.lastattacked = M - M.lastattacker = user - M.attacked_by(src, user) - add_fingerprint(user) - -/obj/item/gun_control/afterattack(atom/targeted_atom, mob/user, flag, params) - ..() - var/obj/machinery/manned_turret/E = user.buckled - E.setDir(get_dir(E,targeted_atom)) - user.setDir(E.dir) - E.mouseparams = params - switch(E.dir) - if(NORTH) - E.layer = BELOW_MOB_LAYER - user.pixel_x = 0 - user.pixel_y = -14 - if(NORTHEAST) - E.layer = BELOW_MOB_LAYER - user.pixel_x = -8 - user.pixel_y = -4 - if(EAST) - E.layer = ABOVE_MOB_LAYER - user.pixel_x = -14 - user.pixel_y = 0 - if(SOUTHEAST) - E.layer = BELOW_MOB_LAYER - user.pixel_x = -8 - user.pixel_y = 4 - if(SOUTH) - E.layer = ABOVE_MOB_LAYER - user.pixel_x = 0 - user.pixel_y = 14 - if(SOUTHWEST) - E.layer = BELOW_MOB_LAYER - user.pixel_x = 8 - user.pixel_y = 4 - if(WEST) - E.layer = ABOVE_MOB_LAYER - user.pixel_x = 14 - user.pixel_y = 0 - if(NORTHWEST) - E.layer = BELOW_MOB_LAYER - user.pixel_x = 8 - user.pixel_y = -4 - E.checkfire(targeted_atom, user) - -/obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user) - target = targeted_atom - if(target == user || target == get_turf(src)) - return - if(world.time < cooldown) - if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing - warned = TRUE - playsound(src, 'sound/weapons/sear.ogg', 100, 1) - return - else - cooldown = world.time + cooldown_duration - warned = FALSE - volley(user) - -/obj/machinery/manned_turret/proc/volley(mob/user) - target_turf = get_turf(target) - for(var/i in 1 to number_of_shots) - addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper, user), i*rate_of_fire) - - -/obj/machinery/manned_turret/proc/fire_helper(mob/user) - if(!src) - return - var/turf/targets_from = get_turf(src) - if(QDELETED(target)) - target = target_turf - var/obj/item/projectile/P = new projectile_type(targets_from) - P.current = targets_from - P.starting = targets_from - P.firer = user - P.original = target - playsound(src, 'sound/weapons/Gunshot_smg.ogg', 75, 1) - P.preparePixelProjectile(target, target_turf, user, mouseparams, rand(-9, 9)) - P.fire() - -/obj/machinery/manned_turret/ultimate // Admin-only proof of concept for autoclicker automatics - name = "Infinity Gun" - view_range = 12 - projectile_type = /obj/item/projectile/bullet/weakbullet3 - - -/obj/machinery/manned_turret/ultimate/checkfire(atom/targeted_atom, mob/user) - target = targeted_atom - if(target == user || target == get_turf(src)) - return - target_turf = get_turf(target) - fire_helper(user) + on = 1 \ No newline at end of file diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index a081e3eb80..ff1887f699 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -61,7 +61,7 @@ G.loc = src charging = G use_power = 2 - update_icon(scan = TRUE) + update_icon(scan = TRUE) else to_chat(user, "[src] isn't connected to anything!") return 1 @@ -108,41 +108,25 @@ var/using_power = 0 if(charging) - if(istype(charging, /obj/item/weapon/gun/energy)) - var/obj/item/weapon/gun/energy/E = charging - if(E.power_supply.charge < E.power_supply.maxcharge) - E.power_supply.give(E.power_supply.chargerate * recharge_coeff) - E.recharge_newshot() + var/obj/item/weapon/stock_parts/cell/C = charging.get_cell() + if(C) + if(C.charge < C.maxcharge) + C.give(C.chargerate * recharge_coeff) use_power(250 * recharge_coeff) using_power = 1 - - - if(istype(charging, /obj/item/weapon/melee/baton)) - var/obj/item/weapon/melee/baton/B = charging - if(B.bcell) - if(B.bcell.give(B.bcell.chargerate * recharge_coeff)) - use_power(200 * recharge_coeff) - using_power = 1 - + update_icon(using_power) + if(istype(charging, /obj/item/weapon/gun/energy)) + var/obj/item/weapon/gun/energy/E = charging + E.recharge_newshot() + return if(istype(charging, /obj/item/ammo_box/magazine/recharge)) var/obj/item/ammo_box/magazine/recharge/R = charging if(R.stored_ammo.len < R.max_ammo) R.stored_ammo += new R.ammo_type(R) use_power(200 * recharge_coeff) using_power = 1 - - if(istype(charging, /obj/item/device/modular_computer)) - var/obj/item/device/modular_computer/C = charging - var/obj/item/weapon/computer_hardware/battery/battery_module = C.all_components[MC_CELL] - if(battery_module) - var/obj/item/weapon/computer_hardware/battery/B = battery_module - if(B.battery) - if(B.battery.charge < B.battery.maxcharge) - B.battery.give(B.battery.chargerate * recharge_coeff) - use_power(200 * recharge_coeff) - using_power = 1 - - update_icon(using_power) + update_icon(using_power) + return /obj/machinery/recharger/power_change() ..() @@ -152,23 +136,23 @@ if(!(stat & (NOPOWER|BROKEN)) && anchored) if(istype(charging, /obj/item/weapon/gun/energy)) var/obj/item/weapon/gun/energy/E = charging - if(E.power_supply) - E.power_supply.emp_act(severity) + if(E.cell) + E.cell.emp_act(severity) else if(istype(charging, /obj/item/weapon/melee/baton)) var/obj/item/weapon/melee/baton/B = charging - if(B.bcell) - B.bcell.charge = 0 + if(B.cell) + B.cell.charge = 0 ..() -/obj/machinery/recharger/update_icon(using_power = 0, scan) //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier. +/obj/machinery/recharger/update_icon(using_power = 0, scan) //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier. if(stat & (NOPOWER|BROKEN) || !anchored) icon_state = "rechargeroff" return - if(scan) - icon_state = "rechargeroff" - return + if(scan) + icon_state = "rechargeroff" + return if(panel_open) icon_state = "rechargeropen" return diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index df76fef5a9..671dfbbdf2 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -24,6 +24,9 @@ var/settableTemperatureMedian = 30 + T0C var/settableTemperatureRange = 30 +/obj/machinery/space_heater/get_cell() + return cell + /obj/machinery/space_heater/New() ..() cell = new(src) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 1e6fd57b1d..c9be720d75 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -142,6 +142,9 @@ diag_hud_set_mechstat() diag_hud_set_mechtracking() +/obj/mecha/get_cell() + return cell + /obj/mecha/Destroy() go_out() @@ -154,7 +157,7 @@ M.forceMove(loc) if(prob(30)) - explosion(get_turf(loc), 0, 0, 1, 3) + explosion(get_turf(loc), 0, 0, 1, 3) if(wreckage) var/obj/structure/mecha_wreckage/WR = new wreckage(loc, AI) diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index 886d875edc..d616f4aaa4 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -19,7 +19,7 @@ var/safety = 1 //if you can zap people with the defibs on harm mode var/powered = 0 //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise var/obj/item/weapon/twohanded/shockpaddles/paddles - var/obj/item/weapon/stock_parts/cell/high/bcell = null + var/obj/item/weapon/stock_parts/cell/high/cell var/combat = 0 //can we revive through space suits? var/grab_ghost = FALSE // Do we pull the ghost back into their body? @@ -29,10 +29,13 @@ update_icon() return +/obj/item/weapon/defibrillator/get_cell() + return cell + /obj/item/weapon/defibrillator/loaded/Initialize() //starts with hicap . = ..() paddles = make_paddles() - bcell = new(src) + cell = new(src) update_icon() return @@ -42,8 +45,8 @@ update_charge() /obj/item/weapon/defibrillator/proc/update_power() - if(bcell) - if(bcell.charge < paddles.revivecost) + if(cell) + if(cell.charge < paddles.revivecost) powered = 0 else powered = 1 @@ -56,21 +59,21 @@ add_overlay("[initial(icon_state)]-paddles") if(powered) add_overlay("[initial(icon_state)]-powered") - if(!bcell) + if(!cell) add_overlay("[initial(icon_state)]-nocell") if(!safety) add_overlay("[initial(icon_state)]-emagged") /obj/item/weapon/defibrillator/proc/update_charge() if(powered) //so it doesn't show charge if it's unpowered - if(bcell) - var/ratio = bcell.charge / bcell.maxcharge + if(cell) + var/ratio = cell.charge / cell.maxcharge ratio = Ceiling(ratio*4) * 25 add_overlay("[initial(icon_state)]-charge[ratio]") /obj/item/weapon/defibrillator/CheckParts(list/parts_list) ..() - bcell = locate(/obj/item/weapon/stock_parts/cell) in contents + cell = locate(/obj/item/weapon/stock_parts/cell) in contents update_icon() /obj/item/weapon/defibrillator/ui_action_click() @@ -105,7 +108,7 @@ toggle_paddles() else if(istype(W, /obj/item/weapon/stock_parts/cell)) var/obj/item/weapon/stock_parts/cell/C = W - if(bcell) + if(cell) to_chat(user, "[src] already has a cell.") else if(C.maxcharge < paddles.revivecost) @@ -113,15 +116,15 @@ return if(!user.transferItemToLoc(W, src)) return - bcell = W + cell = W to_chat(user, "You install a cell in [src].") update_icon() else if(istype(W, /obj/item/weapon/screwdriver)) - if(bcell) - bcell.updateicon() - bcell.loc = get_turf(src.loc) - bcell = null + if(cell) + cell.update_icon() + cell.loc = get_turf(src.loc) + cell = null to_chat(user, "You remove the cell from [src].") update_icon() else @@ -136,7 +139,7 @@ to_chat(user, "You silently enable [src]'s safety protocols with the cryptographic sequencer.") /obj/item/weapon/defibrillator/emp_act(severity) - if(bcell) + if(cell) deductcharge(1000 / severity) if(safety) safety = 0 @@ -200,11 +203,11 @@ update_icon() /obj/item/weapon/defibrillator/proc/deductcharge(chrgdeductamt) - if(bcell) - if(bcell.charge < (paddles.revivecost+chrgdeductamt)) + if(cell) + if(cell.charge < (paddles.revivecost+chrgdeductamt)) powered = 0 update_icon() - if(bcell.use(chrgdeductamt)) + if(cell.use(chrgdeductamt)) update_icon() return 1 else @@ -213,8 +216,8 @@ /obj/item/weapon/defibrillator/proc/cooldowncheck(mob/user) spawn(50) - if(bcell) - if(bcell.charge >= paddles.revivecost) + if(cell) + if(cell.charge >= paddles.revivecost) user.visible_message("[src] beeps: Unit ready.") playsound(get_turf(src), 'sound/machines/defib_ready.ogg', 50, 0) else @@ -240,7 +243,7 @@ /obj/item/weapon/defibrillator/compact/loaded/Initialize() . = ..() paddles = make_paddles() - bcell = new(src) + cell = new(src) update_icon() /obj/item/weapon/defibrillator/compact/combat @@ -252,7 +255,7 @@ /obj/item/weapon/defibrillator/compact/combat/loaded/Initialize() . = ..() paddles = make_paddles() - bcell = new /obj/item/weapon/stock_parts/cell/infinite(src) + cell = new /obj/item/weapon/stock_parts/cell/infinite(src) update_icon() /obj/item/weapon/defibrillator/compact/combat/loaded/attackby(obj/item/weapon/W, mob/user, params) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index c1b932d1bc..390357047a 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -13,7 +13,7 @@ var/stunforce = 7 var/status = 0 - var/obj/item/weapon/stock_parts/cell/high/bcell = null + var/obj/item/weapon/stock_parts/cell/high/cell = null var/hitcost = 1000 var/throw_hit_chance = 35 @@ -21,8 +21,8 @@ user.visible_message("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!") return (FIRELOSS) -/obj/item/weapon/melee/baton/Initialize() - . = ..() +/obj/item/weapon/melee/baton/Initialize() + . = ..() update_icon() /obj/item/weapon/melee/baton/throw_impact(atom/hit_atom) @@ -31,16 +31,16 @@ if(status && prob(throw_hit_chance) && iscarbon(hit_atom)) baton_stun(hit_atom) -/obj/item/weapon/melee/baton/loaded/Initialize() //this one starts with a cell pre-installed. - bcell = new(src) - . = ..() +/obj/item/weapon/melee/baton/loaded/Initialize() //this one starts with a cell pre-installed. + cell = new(src) + . = ..() /obj/item/weapon/melee/baton/proc/deductcharge(chrgdeductamt) - if(bcell) + if(cell) //Note this value returned is significant, as it will determine //if a stun is applied or not - . = bcell.use(chrgdeductamt) - if(status && bcell.charge < hitcost) + . = cell.use(chrgdeductamt) + if(status && cell.charge < hitcost) //we're below minimum, turn off status = 0 update_icon() @@ -50,22 +50,22 @@ /obj/item/weapon/melee/baton/update_icon() if(status) icon_state = "[initial(name)]_active" - else if(!bcell) + else if(!cell) icon_state = "[initial(name)]_nocell" else icon_state = "[initial(name)]" /obj/item/weapon/melee/baton/examine(mob/user) ..() - if(bcell) - to_chat(user, "The baton is [round(bcell.percent())]% charged.") + if(cell) + to_chat(user, "The baton is [round(cell.percent())]% charged.") else - to_chat(user, "The baton does not have a power source installed.") + to_chat(user, "The baton does not have a power source installed.") /obj/item/weapon/melee/baton/attackby(obj/item/weapon/W, mob/user, params) if(istype(W, /obj/item/weapon/stock_parts/cell)) var/obj/item/weapon/stock_parts/cell/C = W - if(bcell) + if(cell) to_chat(user, "[src] already has a cell.") else if(C.maxcharge < hitcost) @@ -73,15 +73,15 @@ return if(!user.transferItemToLoc(W, src)) return - bcell = W + cell = W to_chat(user, "You install a cell in [src].") update_icon() else if(istype(W, /obj/item/weapon/screwdriver)) - if(bcell) - bcell.updateicon() - bcell.loc = get_turf(src.loc) - bcell = null + if(cell) + cell.update_icon() + cell.forceMove(get_turf(src)) + cell = null to_chat(user, "You remove the cell from [src].") status = 0 update_icon() @@ -89,13 +89,13 @@ return ..() /obj/item/weapon/melee/baton/attack_self(mob/user) - if(bcell && bcell.charge > hitcost) + if(cell && cell.charge > hitcost) status = !status to_chat(user, "[src] is now [status ? "on" : "off"].") playsound(loc, "sparks", 75, 1, -1) else status = 0 - if(!bcell) + if(!cell) to_chat(user, "[src] does not have a power source!") else to_chat(user, "[src] is out of charge.") @@ -186,8 +186,8 @@ slot_flags = SLOT_BACK var/obj/item/device/assembly/igniter/sparkler = 0 -/obj/item/weapon/melee/baton/cattleprod/Initialize() - . = ..() +/obj/item/weapon/melee/baton/cattleprod/Initialize() + . = ..() sparkler = new (src) /obj/item/weapon/melee/baton/cattleprod/baton_stun() diff --git a/code/game/objects/items/weapons/teleprod.dm b/code/game/objects/items/weapons/teleprod.dm index 07af7a30c4..d14788e0b1 100644 --- a/code/game/objects/items/weapons/teleprod.dm +++ b/code/game/objects/items/weapons/teleprod.dm @@ -28,7 +28,7 @@ /obj/item/weapon/melee/baton/cattleprod/attackby(obj/item/I, mob/user, params)//handles sticking a crystal onto a stunprod to make a teleprod if(istype(I, /obj/item/weapon/ore/bluespace_crystal)) - if(!bcell) + if(!cell) var/obj/item/weapon/melee/baton/cattleprod/teleprod/S = new /obj/item/weapon/melee/baton/cattleprod/teleprod remove_item_from_storage(user) qdel(src) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 7482b4ca14..b08f0542a0 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -23,7 +23,7 @@ var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset. var/unique_rename = FALSE // can you customize the description/name of the thing? - + var/dangerous_possession = FALSE //Admin possession yes/no /obj/vv_edit_var(vname, vval) @@ -37,7 +37,7 @@ ..() /obj/Initialize() - . = ..() + . = ..() if (!armor) armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0) if(on_blueprints && isturf(loc)) @@ -193,6 +193,6 @@ ..() if(unique_rename) to_chat(user, "Use a pen on it to rename it or change its description.") - -/obj/proc/gang_contraband_value() - return 0 + +/obj/proc/gang_contraband_value() + return 0 diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index f1c30a0bfb..89273de04e 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -26,6 +26,7 @@ new /obj/item/clothing/glasses/meson/engine(src) new /obj/item/weapon/door_remote/chief_engineer(src) new /obj/item/weapon/pipe_dispenser(src) + new /obj/item/weapon/inducer(src) /obj/structure/closet/secure_closet/engineering_electrical name = "electrical supplies locker" @@ -37,6 +38,8 @@ ..() new /obj/item/clothing/gloves/color/yellow(src) new /obj/item/clothing/gloves/color/yellow(src) + new /obj/item/weapon/inducer(src) + new /obj/item/weapon/inducer(src) for(var/i in 1 to 3) new /obj/item/weapon/storage/toolbox/electrical(src) for(var/i in 1 to 3) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 1e5c16f665..90c26657f5 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -480,8 +480,8 @@ if(istype(O, /obj/item/weapon/melee/baton)) var/obj/item/weapon/melee/baton/B = O - if(B.bcell) - if(B.bcell.charge > 0 && B.status == 1) + if(B.cell) + if(B.cell.charge > 0 && B.status == 1) flick("baton_active", src) var/stunforce = B.stunforce user.Stun(stunforce) diff --git a/code/modules/admin/verbs/individual_logging.dm b/code/modules/admin/verbs/individual_logging.dm index d7db82f5b3..ca84d5d759 100644 --- a/code/modules/admin/verbs/individual_logging.dm +++ b/code/modules/admin/verbs/individual_logging.dm @@ -14,11 +14,12 @@ if(type == INDIVIDUAL_SHOW_ALL_LOG) dat += "
Displaying all logs of [key_name(M)]


" for(var/log_type in M.logging) - var/list/reversed = M.logging[log_type] - reversed = reverseRange(reversed.Copy()) dat += "
[log_type]

" - for(var/entry in reversed) - dat += "[entry]: [reversed[entry]]
" + var/list/reversed = M.logging[log_type] + if(islist(reversed)) + reversed = reverseRange(reversed.Copy()) + for(var/entry in reversed) + dat += "[entry]: [reversed[entry]]
" dat += "
" else dat += "
[type] of [key_name(M)]

" @@ -26,6 +27,6 @@ if(reversed) reversed = reverseRange(reversed.Copy()) for(var/entry in reversed) - dat += "[entry]: [reversed[entry]]
" + dat += "[entry]: [reversed[entry]]
" - usr << browse(dat, "window=invidual_logging;size=600x480") \ No newline at end of file + usr << browse(dat, "window=invidual_logging_[M];size=600x480") diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index 3c6c7b2342..01a5b0da3a 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -13,6 +13,14 @@ icon_state = "filter_off_f" flipped = 1 +// These two filter types have critical_machine flagged to on and thus causes the area they are in to be exempt from the Grid Check event. + +/obj/machinery/atmospherics/components/trinary/filter/critical + critical_machine = TRUE + +/obj/machinery/atmospherics/components/trinary/filter/flipped/critical + critical_machine = TRUE + /obj/machinery/atmospherics/components/trinary/filter/proc/set_frequency(new_frequency) SSradio.remove_object(src, frequency) frequency = new_frequency diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index efda086af5..6c09b82402 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -543,6 +543,13 @@ crate_name = "electrical maintenance crate" crate_type = /obj/structure/closet/crate/engineering/electrical +/datum/supply_pack/engineering/inducers + name = "NT-75 Electromagnetic Power Inducers Crate" + cost = 2000 + contains = list(/obj/item/weapon/inducer/sci {cell_type = /obj/item/weapon/stock_parts/cell/{maxcharge = 5000; charge = 5000};opened = 0},/obj/item/weapon/inducer/sci {cell_type = /obj/item/weapon/stock_parts/cell/{maxcharge = 5000; charge = 5000};opened = 0}) //FALSE doesn't work in modified type paths apparently. + crate_name = "inducer crate" + crate_type = /obj/structure/closet/crate/engineering/electrical + /datum/supply_pack/engineering/engiequipment name = "Engineering Gear Crate" cost = 1300 diff --git a/code/modules/mob/living/carbon/human/interactive.dm b/code/modules/mob/living/carbon/human/interactive.dm index 9b4f963d07..c93a79f4fc 100644 --- a/code/modules/mob/living/carbon/human/interactive.dm +++ b/code/modules/mob/living/carbon/human/interactive.dm @@ -1540,7 +1540,7 @@ if(stunning && stunCheck.stunned) shouldFire = 0 if(shouldFire) - if(P.power_supply.charge <= 10) // can shoot seems to bug out for tasers, using this hacky method instead + if(P.cell.charge <= 10) // can shoot seems to bug out for tasers, using this hacky method instead P.update_icon() npcDrop(P,1) else diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 27cf0c3a82..abb81678bb 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -97,6 +97,9 @@ buckle_lying = FALSE can_ride_typecache = list(/mob/living/carbon/human) +/mob/living/silicon/robot/get_cell() + return cell + /mob/living/silicon/robot/Initialize(mapload) spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, src) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 01c700768f..96247fa1b1 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -56,7 +56,7 @@ add_fingerprint(user) if(opened && !wiresexposed && !issilicon(user)) if(cell) - cell.updateicon() + cell.update_icon() cell.add_fingerprint(user) user.put_in_active_hand(cell) to_chat(user, "You remove \the [cell].") diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 4c629412bf..824f5b5f02 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -104,10 +104,10 @@ S.cost = 1 S.source = get_or_create_estorage(/datum/robot_energy_storage/wire) - else if(istype(S, /obj/item/stack/marker_beacon)) - S.cost = 1 - S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon) - + else if(istype(S, /obj/item/stack/marker_beacon)) + S.cost = 1 + S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon) + if(S && S.source) S.materials = list() S.is_cyborg = 1 @@ -149,8 +149,8 @@ F.update_icon() else if(istype(I, /obj/item/weapon/melee/baton)) var/obj/item/weapon/melee/baton/B = I - if(B.bcell) - B.bcell.charge = B.bcell.maxcharge + if(B.cell) + B.cell.charge = B.cell.maxcharge else if(istype(I, /obj/item/weapon/gun/energy)) var/obj/item/weapon/gun/energy/EG = I if(!EG.chambered) @@ -202,9 +202,9 @@ /obj/item/weapon/robot_module/proc/do_transform_animation() var/mob/living/silicon/robot/R = loc R.notransform = TRUE - var/obj/effect/temp_visual/decoy/fading/fivesecond/ANM = new /obj/effect/temp_visual/decoy/fading/fivesecond(R.loc, R) + var/obj/effect/temp_visual/decoy/fading/fivesecond/ANM = new /obj/effect/temp_visual/decoy/fading/fivesecond(R.loc, R) ANM.layer = R.layer - 0.01 - new /obj/effect/temp_visual/small_smoke(R.loc) + new /obj/effect/temp_visual/small_smoke(R.loc) if(R.hat) R.hat.forceMove(get_turf(R)) R.hat = null @@ -226,7 +226,7 @@ if(R.hud_used) R.hud_used.update_robot_modules_display() if(feedback_key && !did_feedback) - SSblackbox.inc(feedback_key, 1) + SSblackbox.inc(feedback_key, 1) /obj/item/weapon/robot_module/standard name = "Standard" @@ -275,7 +275,7 @@ /obj/item/roller/robo, /obj/item/borg/cyborghug/medical, /obj/item/stack/medical/gauze/cyborg, - /obj/item/weapon/organ_storage, + /obj/item/weapon/organ_storage, /obj/item/borg/lollipop) emag_modules = list(/obj/item/weapon/reagent_containers/borghypo/hacked) ratvar_modules = list( @@ -395,9 +395,9 @@ ..() var/obj/item/weapon/gun/energy/e_gun/advtaser/cyborg/T = locate(/obj/item/weapon/gun/energy/e_gun/advtaser/cyborg) in basic_modules if(T) - if(T.power_supply.charge < T.power_supply.maxcharge) + if(T.cell.charge < T.cell.maxcharge) var/obj/item/ammo_casing/energy/S = T.ammo_type[T.select] - T.power_supply.give(S.e_cost * coeff) + T.cell.give(S.e_cost * coeff) T.update_icon() else T.charge_tick = 0 @@ -411,8 +411,8 @@ /obj/item/weapon/reagent_containers/borghypo/peace, /obj/item/weapon/holosign_creator/cyborg, /obj/item/borg/cyborghug/peacekeeper, - /obj/item/weapon/extinguisher, - /obj/item/borg/projectile_dampen) + /obj/item/weapon/extinguisher, + /obj/item/borg/projectile_dampen) emag_modules = list(/obj/item/weapon/reagent_containers/borghypo/peace/hacked) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/peacekeeper, @@ -539,8 +539,8 @@ /obj/item/weapon/storage/bag/sheetsnatcher/borg, /obj/item/device/t_scanner/adv_mining_scanner, /obj/item/weapon/gun/energy/kinetic_accelerator/cyborg, - /obj/item/device/gps/cyborg, - /obj/item/stack/marker_beacon) + /obj/item/device/gps/cyborg, + /obj/item/stack/marker_beacon) emag_modules = list(/obj/item/borg/stun) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/miner, @@ -636,8 +636,8 @@ max_energy = 2500 recharge_rate = 250 name = "Medical Synthesizer" - -/datum/robot_energy_storage/beacon - max_energy = 30 - recharge_rate = 1 - name = "Marker Beacon Storage" + +/datum/robot_energy_storage/beacon + max_energy = 30 + recharge_rate = 1 + name = "Marker Beacon Storage" diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 4a79476bf0..61586e625c 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -9,7 +9,7 @@ maxHealth = 100 damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) obj_damage = 60 - environment_smash = ENVIRONMENT_SMASH_WALLS //Walls can't stop THE LAW + environment_smash = ENVIRONMENT_SMASH_WALLS //Walls can't stop THE LAW mob_size = MOB_SIZE_LARGE radio_key = /obj/item/device/encryptionkey/headset_sec @@ -358,21 +358,21 @@ Auto Patrol[]"}, var/obj/item/weapon/ed209_assembly/Sa = new /obj/item/weapon/ed209_assembly(Tsec) Sa.build_step = 1 - Sa.add_overlay("hs_hole") + Sa.add_overlay("hs_hole") Sa.created_name = name new /obj/item/device/assembly/prox_sensor(Tsec) if(!lasercolor) var/obj/item/weapon/gun/energy/e_gun/advtaser/G = new /obj/item/weapon/gun/energy/e_gun/advtaser(Tsec) - G.power_supply.charge = 0 + G.cell.charge = 0 G.update_icon() else if(lasercolor == "b") var/obj/item/weapon/gun/energy/laser/bluetag/G = new /obj/item/weapon/gun/energy/laser/bluetag(Tsec) - G.power_supply.charge = 0 + G.cell.charge = 0 G.update_icon() else if(lasercolor == "r") var/obj/item/weapon/gun/energy/laser/redtag/G = new /obj/item/weapon/gun/energy/laser/redtag(Tsec) - G.power_supply.charge = 0 + G.cell.charge = 0 G.update_icon() if(prob(50)) @@ -390,7 +390,7 @@ Auto Patrol[]"}, if(lasercolor == "r") new /obj/item/clothing/suit/redtag(Tsec) - do_sparks(3, TRUE, src) + do_sparks(3, TRUE, src) new /obj/effect/decal/cleanable/oil(loc) ..() @@ -444,7 +444,7 @@ Auto Patrol[]"}, if(severity==2 && prob(70)) ..(severity-1) else - new /obj/effect/temp_visual/emp(loc) + new /obj/effect/temp_visual/emp(loc) var/list/mob/living/carbon/targets = new for(var/mob/living/carbon/C in view(12,src)) if(C.stat==2) diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index da45e31d1e..c94557f591 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -100,7 +100,7 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca var/mob/living/creator = null // the creator var/destroy_objects = 0 var/knockdown_people = 0 - var/static/mutable_appearance/googly_eyes = mutable_appearance('icons/mob/mob.dmi', "googly_eyes") + var/static/mutable_appearance/googly_eyes = mutable_appearance('icons/mob/mob.dmi', "googly_eyes") gold_core_spawnable = 0 /mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0) @@ -203,7 +203,7 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca if(..()) emote_see = list("aims menacingly") obj_damage = 0 - environment_smash = ENVIRONMENT_SMASH_NONE //needed? seems weird for them to do so + environment_smash = ENVIRONMENT_SMASH_NONE //needed? seems weird for them to do so ranged = 1 retreat_distance = 1 //just enough to shoot minimum_distance = 6 @@ -229,10 +229,10 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca /mob/living/simple_animal/hostile/mimic/copy/ranged/OpenFire(the_target) if(Zapgun) - if(Zapgun.power_supply) + if(Zapgun.cell) var/obj/item/ammo_casing/energy/shot = Zapgun.ammo_type[Zapgun.select] - if(Zapgun.power_supply.charge >= shot.e_cost) - Zapgun.power_supply.use(shot.e_cost) + if(Zapgun.cell.charge >= shot.e_cost) + Zapgun.cell.use(shot.e_cost) Zapgun.update_icon() ..() else if(Zapstick) diff --git a/code/modules/modular_computers/computers/item/computer_power.dm b/code/modules/modular_computers/computers/item/computer_power.dm index c03570c335..c62b0793ad 100644 --- a/code/modules/modular_computers/computers/item/computer_power.dm +++ b/code/modules/modular_computers/computers/item/computer_power.dm @@ -26,6 +26,11 @@ return battery_module.battery.give(amount) return 0 +/obj/item/device/modular_computer/get_cell() + var/obj/item/weapon/computer_hardware/battery/battery_module = all_components[MC_CELL] + if(battery_module && battery_module.battery) + return battery_module.battery + // Used in following function to reduce copypaste /obj/item/device/modular_computer/proc/power_failure() diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm index 7a3e119a56..c75dd1032d 100644 --- a/code/modules/ninja/suit/ninjaDrainAct.dm +++ b/code/modules/ninja/suit/ninjaDrainAct.dm @@ -111,7 +111,7 @@ They *could* go in their appropriate files, but this is supposed to be modular S.cell.charge += charge charge = 0 corrupt() - updateicon() + update_icon() //RDCONSOLE// diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index d5811e32c9..b304b3c530 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -56,6 +56,8 @@ Contents: var/s_bombs = 10//Number of starting ninja smoke bombs. var/a_boost = 3//Number of adrenaline boosters. +/obj/item/clothing/suit/space/space_ninja/get_cell() + return cell /obj/item/clothing/suit/space/space_ninja/New() ..() diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm index e54a5e0e85..7903d4c3e7 100644 --- a/code/modules/ninja/suit/suit_attackby.dm +++ b/code/modules/ninja/suit/suit_attackby.dm @@ -32,7 +32,7 @@ U.put_in_hands(old_cell) old_cell.add_fingerprint(U) old_cell.corrupt() - old_cell.updateicon() + old_cell.update_icon() cell = CELL to_chat(U, "Upgrade complete. Maximum capacity: [round(cell.maxcharge/100)]%") else diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index d980591ceb..1ce26fb373 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -93,6 +93,10 @@ var/update_overlay = -1 var/icon_update_needed = FALSE +/obj/machinery/power/apc/get_cell() + return cell + + /obj/machinery/power/apc/connect_to_network() //Override because the APC does not directly connect to the network; it goes through a terminal. //The terminal is what the power computer looks for anyway. @@ -622,14 +626,10 @@ return if(usr == user && opened && (!issilicon(user))) if(cell) + user.visible_message("[user] removes \the [cell] from [src]!","You remove \the [cell].") user.put_in_hands(cell) - cell.add_fingerprint(user) - cell.updateicon() - + cell.update_icon() src.cell = null - user.visible_message("[user.name] removes the power cell from [src.name]!",\ - "You remove the power cell.") - //to_chat(user, "You remove the power cell.") charging = 0 src.update_icon() return diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index a4b994e0cf..1c3d44b7ea 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -19,13 +19,16 @@ var/ratingdesc = TRUE var/grown_battery = FALSE // If it's a grown that acts as a battery, add a wire overlay to it. +/obj/item/weapon/stock_parts/cell/get_cell() + return src + /obj/item/weapon/stock_parts/cell/New() ..() START_PROCESSING(SSobj, src) charge = maxcharge if(ratingdesc) desc += " This one has a power rating of [maxcharge], and you should not swallow it." - updateicon() + update_icon() /obj/item/weapon/stock_parts/cell/Destroy() STOP_PROCESSING(SSobj, src) @@ -46,16 +49,16 @@ else return PROCESS_KILL -/obj/item/weapon/stock_parts/cell/proc/updateicon() +/obj/item/weapon/stock_parts/cell/update_icon() cut_overlays() if(grown_battery) - add_overlay("grown_wires") + add_overlay("grown_wires") if(charge < 0.01) return else if(charge/maxcharge >=0.995) - add_overlay("cell-o2") + add_overlay("cell-o2") else - add_overlay("cell-o1") + add_overlay("cell-o1") /obj/item/weapon/stock_parts/cell/proc/percent() // return % charge of cell return 100*charge/maxcharge @@ -69,7 +72,7 @@ return 0 charge = (charge - amount) if(!istype(loc, /obj/machinery/power/apc)) - SSblackbox.add_details("cell_used","[src.type]") + SSblackbox.add_details("cell_used","[src.type]") return 1 // recharge the cell @@ -123,7 +126,7 @@ corrupt() return //explosion(T, 0, 1, 2, 2) - explosion(T, devastation_range, heavy_impact_range, light_impact_range, flash_range) + explosion(T, devastation_range, heavy_impact_range, light_impact_range, flash_range) qdel(src) /obj/item/weapon/stock_parts/cell/proc/corrupt() diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index f8d0911011..2548dd3f74 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -4,13 +4,13 @@ desc = "A basic energy-based gun." icon = 'icons/obj/guns/energy.dmi' - var/obj/item/weapon/stock_parts/cell/power_supply //What type of power cell this uses + var/obj/item/weapon/stock_parts/cell/cell //What type of power cell this uses var/cell_type = /obj/item/weapon/stock_parts/cell var/modifystate = 0 var/list/ammo_type = list(/obj/item/ammo_casing/energy) var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next. var/can_charge = 1 //Can it be charged in a recharger? - var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_icon()? + var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_icon()? var/charge_sections = 4 ammo_x_offset = 2 var/shaded_charge = 0 //if this gun uses a stateful charge bar for more detail @@ -20,19 +20,22 @@ var/use_cyborg_cell = 0 //whether the gun's cell drains the cyborg user's cell to recharge /obj/item/weapon/gun/energy/emp_act(severity) - power_supply.use(round(power_supply.charge / severity)) + cell.use(round(cell.charge / severity)) chambered = null //we empty the chamber recharge_newshot() //and try to charge a new shot update_icon() +/obj/item/weapon/gun/energy/get_cell() + return cell -/obj/item/weapon/gun/energy/Initialize() - . = ..() + +/obj/item/weapon/gun/energy/Initialize() + . = ..() if(cell_type) - power_supply = new cell_type(src) + cell = new cell_type(src) else - power_supply = new(src) - power_supply.give(power_supply.maxcharge) + cell = new(src) + cell.give(cell.maxcharge) update_ammo_types() recharge_newshot(1) if(selfcharge) @@ -50,9 +53,7 @@ fire_delay = shot.delay /obj/item/weapon/gun/energy/Destroy() - if(power_supply) - qdel(power_supply) - power_supply = null + QDEL_NULL(cell) STOP_PROCESSING(SSobj, src) return ..() @@ -62,9 +63,9 @@ if(charge_tick < charge_delay) return charge_tick = 0 - if(!power_supply) + if(!cell) return - power_supply.give(100) + cell.give(100) if(!chambered) //if empty chamber we try to charge a new shot recharge_newshot(1) update_icon() @@ -76,10 +77,10 @@ /obj/item/weapon/gun/energy/can_shoot() var/obj/item/ammo_casing/energy/shot = ammo_type[select] - return power_supply.charge >= shot.e_cost + return cell.charge >= shot.e_cost /obj/item/weapon/gun/energy/recharge_newshot(no_cyborg_drain) - if (!ammo_type || !power_supply) + if (!ammo_type || !cell) return if(use_cyborg_cell && !no_cyborg_drain) if(iscyborg(loc)) @@ -87,10 +88,10 @@ if(R.cell) var/obj/item/ammo_casing/energy/shot = ammo_type[select] //Necessary to find cost of shot if(R.cell.use(shot.e_cost)) //Take power from the borg... - power_supply.give(shot.e_cost) //... to recharge the shot + cell.give(shot.e_cost) //... to recharge the shot if(!chambered) var/obj/item/ammo_casing/energy/AC = ammo_type[select] - if(power_supply.charge >= AC.e_cost) //if there's enough power in the power_supply cell... + if(cell.charge >= AC.e_cost) //if there's enough power in the cell cell... chambered = AC //...prepare a new shot based on the current ammo type selected if(!chambered.BB) chambered.newshot() @@ -98,7 +99,7 @@ /obj/item/weapon/gun/energy/process_chamber() if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... var/obj/item/ammo_casing/energy/shot = chambered - power_supply.use(shot.e_cost)//... drain the power_supply cell + cell.use(shot.e_cost)//... drain the cell cell chambered = null //either way, released the prepared shot recharge_newshot() //try to charge a new shot @@ -117,10 +118,10 @@ return /obj/item/weapon/gun/energy/update_icon() - ..() - if(!automatic_charge_overlays) - return - var/ratio = Ceiling((power_supply.charge / power_supply.maxcharge) * charge_sections) + ..() + if(!automatic_charge_overlays) + return + var/ratio = Ceiling((cell.charge / cell.maxcharge) * charge_sections) var/obj/item/ammo_casing/energy/shot = ammo_type[select] var/iconState = "[icon_state]_charge" var/itemState = null @@ -131,16 +132,16 @@ iconState += "_[shot.select_name]" if(itemState) itemState += "[shot.select_name]" - if(power_supply.charge < shot.e_cost) + if(cell.charge < shot.e_cost) add_overlay("[icon_state]_empty") else if(!shaded_charge) - var/mutable_appearance/charge_overlay = mutable_appearance(icon, iconState) + var/mutable_appearance/charge_overlay = mutable_appearance(icon, iconState) for(var/i = ratio, i >= 1, i--) - charge_overlay.pixel_x = ammo_x_offset * (i - 1) - add_overlay(charge_overlay) + charge_overlay.pixel_x = ammo_x_offset * (i - 1) + add_overlay(charge_overlay) else - add_overlay("[icon_state]_charge[ratio]") + add_overlay("[icon_state]_charge[ratio]") if(itemState) itemState += "[ratio]" item_state = itemState @@ -156,7 +157,7 @@ user.visible_message("[user] melts [user.p_their()] face off with [src]!") playsound(loc, fire_sound, 50, 1, -1) var/obj/item/ammo_casing/energy/shot = ammo_type[select] - power_supply.use(shot.e_cost) + cell.use(shot.e_cost) update_icon() return(FIRELOSS) else @@ -191,17 +192,17 @@ user.visible_message("[user] tries to light their [A.name] with [src], but it doesn't do anything. Dumbass.") playsound(user, E.fire_sound, 50, 1) playsound(user, BB.hitsound, 50, 1) - power_supply.use(E.e_cost) + cell.use(E.e_cost) . = "" else if(BB.damage_type != BURN) user.visible_message("[user] tries to light their [A.name] with [src], but only succeeds in utterly destroying it. Dumbass.") playsound(user, E.fire_sound, 50, 1) playsound(user, BB.hitsound, 50, 1) - power_supply.use(E.e_cost) + cell.use(E.e_cost) qdel(A) . = "" else playsound(user, E.fire_sound, 50, 1) playsound(user, BB.hitsound, 50, 1) - power_supply.use(E.e_cost) + cell.use(E.e_cost) . = "[user] casually lights their [A.name] with [src]. Damn." diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 77328bb422..3c7b15993b 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -98,7 +98,7 @@ empty() /obj/item/weapon/gun/energy/kinetic_accelerator/proc/empty() - power_supply.use(500) + cell.use(500) update_icon() /obj/item/weapon/gun/energy/kinetic_accelerator/proc/attempt_reload(recharge_time) @@ -125,7 +125,7 @@ return /obj/item/weapon/gun/energy/kinetic_accelerator/proc/reload() - power_supply.give(500) + cell.give(500) recharge_newshot(1) if(!suppressed) playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index a8ae4da97a..f6841d6bf9 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -39,7 +39,7 @@ /obj/item/weapon/gun/energy/decloner/update_icon() ..() var/obj/item/ammo_casing/energy/shot = ammo_type[select] - if(power_supply.charge > shot.e_cost) + if(cell.charge > shot.e_cost) add_overlay("decloner_spin") /obj/item/weapon/gun/energy/floragun @@ -137,19 +137,19 @@ /obj/item/weapon/gun/energy/plasmacutter/examine(mob/user) ..() - if(power_supply) - to_chat(user, "[src] is [round(power_supply.percent())]% charged.") + if(cell) + to_chat(user, "[src] is [round(cell.percent())]% charged.") /obj/item/weapon/gun/energy/plasmacutter/attackby(obj/item/A, mob/user) if(istype(A, /obj/item/stack/sheet/mineral/plasma)) var/obj/item/stack/sheet/S = A S.use(1) - power_supply.give(1000) + cell.give(1000) recharge_newshot(1) to_chat(user, "You insert [A] in [src], recharging it.") else if(istype(A, /obj/item/weapon/ore/plasma)) qdel(A) - power_supply.give(500) + cell.give(500) recharge_newshot(1) to_chat(user, "You insert [A] in [src], recharging it.") else diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 8c810155db..d051ec0221 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -78,7 +78,7 @@ return "chest" /obj/item/projectile/proc/prehit(atom/target) - return + return TRUE /obj/item/projectile/proc/on_hit(atom/target, blocked = 0) var/turf/target_loca = get_turf(target) @@ -142,7 +142,7 @@ if(firer && !ricochets) if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech loc = A.loc - return 0 + 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. def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. @@ -155,13 +155,14 @@ var/turf/target_turf = get_turf(A) - prehit(A) + if(!prehit(A)) + 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 if(A) permutated.Add(A) - return 0 + return FALSE else if(A && A.density && !ismob(A) && !(A.flags & ON_BORDER)) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs on that tile. var/list/mobs_list = list() @@ -169,9 +170,11 @@ mobs_list += L if(mobs_list.len) var/mob/living/picked_mob = pick(mobs_list) - prehit(picked_mob) + if(!prehit(picked_mob)) + return FALSE picked_mob.bullet_act(src, def_zone) qdel(src) + return TRUE /obj/item/projectile/proc/check_ricochet() if(prob(ricochet_chance)) @@ -277,46 +280,53 @@ Range() sleep(config.run_speed * 0.9) - /obj/item/projectile/proc/preparePixelProjectile(atom/target, var/turf/targloc, mob/living/user, params, spread) var/turf/curloc = get_turf(user) - src.loc = get_turf(user) - src.starting = get_turf(user) - src.current = curloc - src.yo = targloc.y - curloc.y - src.xo = targloc.x - curloc.x + forceMove(get_turf(user)) + starting = get_turf(user) + current = curloc + yo = targloc.y - curloc.y + xo = targloc.x - curloc.x - if(params) - var/list/mouse_control = params2list(params) - if(mouse_control["icon-x"]) - src.p_x = text2num(mouse_control["icon-x"]) - if(mouse_control["icon-y"]) - src.p_y = text2num(mouse_control["icon-y"]) - if(mouse_control["screen-loc"]) - //Split screen-loc up into X+Pixel_X and Y+Pixel_Y - var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") + var/list/calculated = calculate_projectile_angle_and_pixel_offsets(user, params) + Angle = calculated[1] + p_x = calculated[2] + p_y = calculated[3] - //Split X+Pixel_X up into list(X, Pixel_X) - var/list/screen_loc_X = splittext(screen_loc_params[1],":") - - //Split Y+Pixel_Y up into list(Y, Pixel_Y) - var/list/screen_loc_Y = splittext(screen_loc_params[2],":") - // to_chat(world, "X: [screen_loc_X[1]] PixelX: [screen_loc_X[2]] / Y: [screen_loc_Y[1]] PixelY: [screen_loc_Y[2]]") - var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32 - var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32 - - //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. - var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths - - var/ox = round(screenview/2) //"origin" x - var/oy = round(screenview/2) //"origin" y - // to_chat(world, "Pixel position: [x] [y]") - var/angle = Atan2(y - oy, x - ox) - // to_chat(world, "Angle: [angle]") - src.Angle = angle if(spread) src.Angle += spread +/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params) + var/list/mouse_control = params2list(params) + var/p_x = 0 + var/p_y = 0 + var/angle = 0 + if(mouse_control["icon-x"]) + p_x = text2num(mouse_control["icon-x"]) + if(mouse_control["icon-y"]) + p_y = text2num(mouse_control["icon-y"]) + if(mouse_control["screen-loc"]) + //Split screen-loc up into X+Pixel_X and Y+Pixel_Y + var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") + + //Split X+Pixel_X up into list(X, Pixel_X) + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + + //Split Y+Pixel_Y up into list(Y, Pixel_Y) + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + // to_chat(world, "X: [screen_loc_X[1]] PixelX: [screen_loc_X[2]] / Y: [screen_loc_Y[1]] PixelY: [screen_loc_Y[2]]") + var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32 + var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32 + + //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. + var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths + + var/ox = round(screenview/2) - user.client.pixel_x //"origin" x + var/oy = round(screenview/2) - user.client.pixel_y //"origin" y + // to_chat(world, "Pixel position: [x] [y]") + angle = Atan2(y - oy, x - ox) + // to_chat(world, "Angle: [angle]") + return list(angle, p_x, p_y) /obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it. ..() diff --git a/code/modules/research/designs/power_designs.dm b/code/modules/research/designs/power_designs.dm index f03bb8f3e9..393e64bd0d 100644 --- a/code/modules/research/designs/power_designs.dm +++ b/code/modules/research/designs/power_designs.dm @@ -68,6 +68,17 @@ build_path = /obj/item/device/lightreplacer category = list("Power Designs") +/datum/design/inducer + name = "Inducer" + desc = "The NT-75 Electromagnetic Power Inducer can wirelessly induce electric charge in an object, allowing you to recharge power cells without having to remove them." + id = "inducer" + req_tech = list("powerstorage" = 4, "engineering" = 4, "magnets" = 4) + build_type = PROTOLATHE + materials = list(MAT_METAL = 3000, MAT_GLASS = 1000) + build_path = /obj/item/weapon/inducer/sci + category = list("Power Designs") + + /datum/design/board/pacman name = "Machine Design (PACMAN-type Generator Board)" desc = "The circuit board that for a PACMAN-type portable generator." diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index a20439dea2e55be83165dafd702fe159264d09c8..d08290d169102a2fb4dfcdbe127e6c0735a86eaf 100644 GIT binary patch delta 11334 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 delta 10889 zcmX|m2Uru!_cn-%*buqOMXG`zNKr~ax>6(3q<0mhLqJOCi`bDOq1VtmM5Nb%3K682 z(3_M1A%qq}3;C9x_xsQDOrG7DvuAVOnRCv(XQz_RrN^K9!V6gX8<=>hy!5nr<>>C^ z2y>&M@lDM&*Mdz-UzNw8v+jEmF2BHxb#VrcY5Cmyz$)Yegy`lxep)ARJzt}0@|YB` zyl!$iYiV2P;t!1tlcO?!QrLmtb`%PIyo*`-O+-(zkA8EQlyh010c!oEG|k_4|5%!z z>TY9uwq^WJ_g58EH*2?x@iOa1TaEd>vF`yB-`o7W?c6rxc& zGxtYE29nkvK)8JbFM1PF#Oe+VwZ~?EpaQ8)M7AUy}b5W zpc0byuhfwN?{3Tj?bqo~i;r5?L|f7x3-Mq=YwjHIl71fzv~omxLul9EVhp5M?=Y%X zHMd!2$Vs0%vShi#`0yaJ+2nP|{j)dpVHbVdt?K=ebZuB2%c-EtPh9OX4!cw+4prP z`qbB%eTS<7ZVD~G%>UhIsM&wN?ok|2XpOwpvdc0&y8{&7FH0%gvcV-?jm8$>Qlaq!?2g2%#l4(Yy-ZM9q*H{F++l^*K*J zv$&y&4Y?-}v8V*)4`C4_yiVJAEpVz<53h&S3T8YltE11XJPyeT{oNui2QJY+Q_UI=sWtvJ-QvOrm1uA^o1|Kz%D( zSY#X6o#=%}FiBnH-L^VVxiaYfC&ZUXwS#}i1$bM8z4Tl(uEUJ!&MEh`Rx|i_ux^o-c@uy z|H4p63&R<{e@3%guBUfp&~ty2N6auvL@G&~H`wdYJNJ?MC%yVj?)0g>zKc(U!+J62 zY-I1hA6OIr8VnaP)lq1#wrcCBFvHWU1PAh>;YA^Qm~xhq*wB5_i&%Pfk`Pv_jq!_S z(<2}-A<&=IpCg8gomK{?Ix2tXd-SzC!_scsElN4fUW8MXN7Hv67={QG(zZH@mea>< zuf4PB&j?EE(qvukE!37!zkKG){H=h&f^6>Z<&0kJ!!+>rU@-yplDEEyqw>&GHGc#` z$e-%9Wfhgo9*bH&EHlK$+X;ryi+qW7fBcpWczYcCu;d64sPws!fKpLX#d z4IZXgr7Fi`cM*8wd;D9CDKu8Uv)e7dFg?%kY%V${>i27EclS8%{k?k$Y3h%^JB-TA z`^e=zMWa2=w^mLcDz!0&#IW7&L^osScNf^rW%q-EK8k<1Eeu55RAVS`f;@wkvQ3jlR>w#txU)^tmdwt>Oww#2ilU&W`_ z9Q@<@y57)4`Ry9q!HyO1D|_8j_v?KrkJ{UzQ*{?eu9jDZLiwJd%XmZKivMEp$hHE$ z^GWRH@+it#@8|xWH}?myzFG!F5JJR*_+#RZpC64<>NUXx44J*y& z9FS_H8ylU0*xoC+sY1I;4K2CA_Jc{cIU=1lSK_9N1b^P(;EiXmo1f#i-DR*95qe?> z7%MI-c;*R{@5moV+w68NrFQr@7;U(Fi|kKb75-LUcdJ3@3p(uXjogj1(8h=gH4ScR zFB%>E`dX~sEiuxdn*7reXIK6^aeB08I{^jm^5xre>fz}vrKg;)@$Nd%X1G6N7A6I} zdWeN}{3_*snHn$a(YFb!V@@b=rK6Mb|5O$QS>5)0=HlF-)KVzoL<1Lc3Ld>FDv zdO5$0&QBMWxj5>pwCa#wrYz{7KXPVz(Z=PSdPsFTTZX8E=x$w^URvhG+K}Jerw~9~ zS}QDZ(or%4u7bN>decxV(uGn^JLYn=;AvM7T6ycz`r#DGUKmx*lZAN6z%G9U65w~% z$P+vI?V-ionS&XzVaC=|oQe1m+!?CQLe)EDU&)+X@Zt^ z-VOL3XB2v{hvef?<3n?)SIxE6ygvcGjv_tb{1v{_ABF(7k`B3E9 zUDFqH(+=HZR{aNNtHxZ*B_mDwS$cW>sI8(yW33w0OxA5aPZ^mnjItaYx_B;)7kPDh zv$p6EJmZE!BYGy-7eN0z6g#RW_^z}=+`uRM-!bkFKA~CHZ|3HXKv-5~3a9|=*{_`f zeW6K60_p8Xwgm>w2SatY+rGE3JlBpe(LhInap)H=sxn<4&pNql?s zrE*`jQ@^bz z!@WFMksQ4TUl`g3+41SH^QxC!T9msVJqLr4jjHzA=Te5fkq^iek-i(Pmi)AJ1@F%a z#NF2z>xpGIKnCifk;A)MV%_YKsz!=hwPK&;ueCRuXvKy&^K?z+Ut@q96p)wVIHnVpVxhXUXbM+I`O)qwlH8or{Tr9kkUqp?$ z9DByk@LoIm}9jN^^)c&06fHG=+?GCEHfH!xi@WH zL;2h#Mn$ANiW(9U(LL(0MYXV>y;S-$nDPLNOW|VaEaUtkqRVM^s@XI{E>+>NuZMNQ@Juq2Z>1zDYe_lX{+(V-_%- zI^?9vVV^;TZk$%`aDRHH?dSBrKMPLt`kwzMbm^>o^{wRxPWygU?DZuC!LYFL!P`C_ za=W(*hKt)?RNZ*;kjaJZisOEC@;Coeum9Ya)KhwL*@C+!$7e?IyLi{zqeQO5BtO3G z;L^A@Te1Ch;`GcDvA~K7F8(nF8n6`tb}B2pgHxE9nOc$6k+CVbtO|ZQ81YzaBSS6|<)_;xsaEXsSvQ1d%)4?bicM+XTdCk`q4{qI(@=0M$frLn3xkb{obEJ`** zR8fcTuChNI*owk$=mR34-mj>V#;(*&xZ_ZP9wLWaeXI?>$L?^K;7B?UjZ0?y8g-B_ zwThfB0Ep#Y(`JJM1N>{0Gr#ks*9m=?dUAep*%Fh?h{=oHYVT9(?w~^7JWyfaK}Y`M znkC1Q&d%Rm%f)Ji85v4+y=-@&f_LudT3V)6!)DwTfEav&Z6yS+`=g9rb{b7CF@g?c zzGsZ(LakZGdnn)QhXs^%j3G%#53NNX~P-BABR!C-vfTm-CZxYcSbAiZ$m#D zYn_7t5z1`D{#94}TOaxB!U#*u2<1&zGTQf$>y(co9nC<;&hz}p6#tdpW9k@g$ywGI z^@s0~hevr~!5w2|~i!>6N^LT(9iWH(O!lKPJ&&IlD$Oat({e!dKEP@rnx z(3aiNP|>@xHu^7{GgCinpF|KX&Bv~t=VI&Ta`&x{T$?6qd|%w|{PEj*P*a%Eq}%)8 zUQ&V?XCF9FaZN1xiK=Sd`Sa(!Cc-BqoQCdrd&h5jkHjT0@rVqbEIznv$yJdCAatxj z!*?S7^++mfC_D57QX8BUGzY%FBg-PfcsUX(jUOLx-;|OvUR+$PpAEe*gtAs#ks8dM zd18zXrg*iUVJT>Aw5Y4A)5A3S?rp?6D`@0nd1|j)N!K-(mz25=DO%Kz0QhgNy>2;369c5DVl;>;3gxXt(c6rO&=f0)XA1kk?loNSSH^Q$l{GB zSB+C1oY5vg41UCS!-`-AC5+K!H!FGjREW+1d9 zu*uMR@$LG!_dAFkBe2_;qu=nsRr26!NB30P=bYN)-n6!j7ioNqqEf0iMjS7aHKIY2 z%|H<5amlrHJ|K>KJI>!^L1%N{m0-VA<{aJ53NLL4m{E+=uwBFHbO zsh2UBE>8KDlm51u>j2CZpRSMJi>P6p(52>o1@vFD)a4Bv>4-VOzHlZOc)cQ*@d}8F z5-a&!Ks=t!SAhWWMCss^!M;;x(~0DvK%f0AhP0HF;^MOUq99CuPN`^9 zL8+KTPV}-y$Ij&<&TX7mteM%eYo&;yQl(?&c?{??5R`X`a&r#P_K1b3v)R zK~Djds-nxzlOk4@Ej|!FeWBbOZkA-Am0-j}uheYx+MDAxW$(GIopfYO+45 z2d00d=a4ZUE0XLj4$f3;DJn9yBjx==lJ6zo zTbfT40MaMfLLXR#B_LO4uGI*vKs1#_lgV9;FQ4N8Tz&V$LQ2W}52QR7)lOGIsNZH3k-!xiDaCd)Wt zw2nyQ2wly7@MZ`32liRlXnD_)R>~7)saEo&k(CMNFeLR7uK+Yhamt2ISxt6OGOo|Lfb?@??%j-tOo`t!^ zcGv2WqVc-AoPi<0t?=@p@ACXi5ex;*@q_!F#za@|N|CF1Ej`*+q7KJX=}EJ z_I`o8Gf3wJjSi2-!@EcmigIB#_5+ZS)vZ~IX?{t5L=d8sk!m4+lH?v^bo48>yb-H_(sch-0ZYHdxbs2i2Fvbc?|K)726esKM=AYN8V4TCOy{Qd zr%HR4j#liE?J{mf#H;i)G)+pFvlc$P3@`1G%O04OKZeYyx!c$SA1PN}CqsfzS`AiZ zU^YAs==L^ibPC-DGhk$Z%DaGn)G?UhqVc4?sjJ~JQz<8Fm~IsY$mP(M?cOIx?BdsO1aD<4y_rlC8j000?lRU zlx#vB{AC+9D##cxuOBC*JZcCjT}XbsEnf&h(7%J2^VBY$Wa&yhzglsJ-T5c11n|dmfvaq->Ew3cR6H4R@PaLGt*D#BwI+h zDu1n;^x&90oZR=ux-$+hGO-U7E)i4j)BWSWw6)ex5Z!Qgy4)sTr%~%yo1Qe2uA|jm zD4uZ}s>92NTt7NOs7vlh`SgZZ-t)`Y-?xu)TBRcwc49Cv!1q3RJ(V33YyF_>31u*- zKFEA)gpX=GQZT;7+H!%9QQ|PzJL1@Q%udp6o4Cnl)zu`MNunx`*%|K7Iw1C)b$;!# z_MOOWkEHiS@ulS!xgN_0|M*-7o*#}ClfB}P+$B0D>pZ;)RUj+^E#5Y5Z{+$H+}pl}a}FtRLN*n(WbiJg3wg zBs1oi6#VpOx4kiYLt4Pq@f`B+gP-B;%Kq8^p^rTH@^YMQ|e3nlD$v&WTSdqbO#3kn1fms(TmJQ zP7}z|sHtg(eFMV-mWj;LtrzR^n-k-{rhqG(t!$-XM+w>*+dhb+LMEaKk5{*6=$)Cz z?-2&`Dc{c(8>6r=;BcZKx%|W^4^dkaJ-tk3e(i#+tVb|3rJC)>h^PwSx;XB^F&%v9 z8UQ`ea1fU{73};-eJU_ME8SD#YO_K^bxDx>v-Nk+$pragLxfksoU-%%+w%YDe?2`> z^^)-BP49s^dCJ@sGtJ}d!9_GV- zW?aJIQoxiY4x5&npRP_Tc6CdKc#>|}iRu+Er1`mMM{@KhjX)7yB#?oB{oa&e`E7ec z77N;ybB!%xK3hF1`J}hLp-)*`a}oF5cs4(cQ|+lGA?h6$y8q?!6;7Uf(WfgL?UVV+NV3%9LCZ2SB~aNg^HwU#M9#ai!rn;Fn~KPE7%0iN$ zGt(!qBJiIijRqq6iJ@N|F&SmJxR_VeIQehK_T;J8A!D^3+4Cgn|HS%=<@q`82n$QD zN6wfsIBc|MgOXi{@RV)O0os(!3l}a#$ZFq8o`Rmx`ic{3KNge;>*!=Wc^;slQCbbq zHsh%x?#1QsAMQ%#=H}YPGr}K!fTSbWCPp;!w|sEVm7hP)G`*Sh{re;9GG!rc*-)F- zZvxtynq0!k)i*~Se2C7DE7?iEmkM)pqfU_iU;CO_Sve%<*{?cY14EYG6*cxVj6+3c z+(8w+N{>$sI^11J`V5F{t%WZwE!k0s-yg|u#i5qFm6QNBxxKe6^Sn>yJA7Il!I`q_@X>X5jW>k#jo%$NMZ;I+o+BRm} zbbaL+G0}ZHE>B}V6eg8mkPI@z?kq>Pa9*E>{~6ab8AP78agjn=s)_0B64>O3qe~tj z5#7dv2jI!~Wzk(a9GFIkGuA_@nv1RP>4Mg>He9K}YFcc#(9nBB>T*MkT;`NHkghvi zq<*`KtDDI<{;x$!vFoV{-CjPjR#uXx`biCZQF6Pr!wR$bc?_2n!cTx-{SB%!#u*3v>CG>>PJVB;s z`Bcmrv9KPtE3J6)I&l5DZ@NgCHX#bs_D?Lj-iv;MYuvq1>|v~v=)UnDKHU+U6VIa_ zN>=1AE%#1+XT1KU?7~zoVF~ylOSCOZzc-f=asScC&;8jq3Xm6SolRe}w5A{#GexLZ zVG=#H4H=?6va+>zWxVVwKfjmwYhvT>V1m&DxHi%bII;C;C)ZG*U!s~o)Kc88WW+)0 z0J&Xy|6D4!PP;oVt_*8b)x4=@4V8iSq%x#mv`tE}$Fsq9nu@CoBW(%J?xeM`^Onq) z*mkAN%k|sAb$ViKuL#ykOl4rM30yik---#T=ofdjVZ$ClCLrGg_x!Ec*x1A#H!u_! z-MTGitXS4RlM-zADCH|y6w_P0=I@0;WGZ)oJ@7tCLx@%8r>~!g=dyHWO~OTv7e)(< zZSr=@+H;^k=$n~2oxgCQyE8R4wxG2$m7O`cCID!Z&9LTDJl?}I^CyEs;`v#BD)$(! z_WPouxR8@(@4y7tA3kj)Yy%u`C4Q=5HS_TfNOc`995kr9Pt>Tx+knF!8103b3Ik*R4CK*Ymrru#SMZwP}%*2-o~ z@i|IpEr1oj8vRm+G!4+Xblii|xi|qjGXz#Ec_*0r$~~!trDWnoP8YjNoGy*h$E_DY z$LqQwHyUWa@yt`%t&HLHDZ8m0C~@K=0a6WX+Ii|}uNR%9ulGECZ9?icHutW*Khsc? z^c+~J1GKV44VEE_HGn%R&etvVTk*^3qoyXpj@2lLj`MW%D~x9QXc`z;v6k?umyb0y zB}rj*f~ilRt*)+Sm6<<$__}T}-drMZ&%MH9UQJR;Dj>Sd&>Xdg?hKr>pkUB5nfB>^ ze0hHAw{}#QNF&x(OJ*N>oca()JGezqRU zc=)Cgpaw&qf;AQpH!XdA{h#}(fsNqxZRne`m(I7(e0%vB7C^JvBYPv*GMm;uJySCn z{lHfi+kXENF8u`5i@x)QD_#2h`wEJ3y^~fmSBxqArRGvuU%&PR#sg`kq8!p0K8bB`(nbz^E3zNL8Q4^}<+`N&A ziG$DjB&!ES-chOH>QtbQA$q0P#L9ooD#>{bSHmrS9rtIyr#1EYQ8i-2Ri~@-`GZP#dFKkh(dx1s7U|UN{;0kcgVW}(0 zgUav%ZbeDXJtL=ql~sDaje00pU-)zoAjwH0v;3_# z{NEi=-`FU(xU?iVZrK7Bc(vW!%C@$)8XtG-m;c=u-NvzRr;gW~qh6T3F;Nsvduz3@ z**9}s1}FoE4LSNO0^zElV<|d04~Emxv%~pa`xBaZp*=sVA*H>)G!Dpd>m^+s9^1n` zX|ido^p~YU$(RTpl}Wqp@51IgyP3-V>n*f*JzT@8Z?3OgUbg+}_vHOd)a1Fia0^Pk z!ifzX7etpIL5uly;&0q|5q1-*pRaA`?G02-otAfZ8NB$wEc1*_#g2nbHWpTzg8CYw}Hb%j^;$u3@11 z7!noi;Ntefzw7v}8AIXIo2@VV)TO6Go^yf$Men#cjf6PhIWE zxV?yoh$7-dO;bO0 zIv<+wwsrwxU0@+`cyzSjOj43ewd4Cpm`omc*$Pttbwa70ZC)j4eVd$oXYD5BN6`8* zn-n`;KrvDB8^w7x=j{-n)*Q(pt4#@NDZDS19JER~Ee}xlkBN*uB^*z?OZ17`M>@p^ zY~As!ens?gpoST*a2(n?Jg}Y;&;tGBPXS!iK#m)=Q+2p{zrLxtwGQlKL8Qc4%0vw; zs^B44eQ{0k#D+HLuAb`J+V1(=91k8e%h=tzy3Wq)7^L>TT#g>Mjx~}Wt3f4=Vwd(@ z0N1RZ+z~>^S(o*YJ3>N3>RhCwltJ6yot*}G-^SrQr%xfO1H`mPFHA)1XiDCdW98=r z*RiYIv=edF49Euwf6zPr`JX%-c%-CHu2_{=c`wzJXK`pvH}9Jq>s=#II7gl;IblDX zf6P!!E#VN8thimeV_Ra9YeT7MF9Tv@llo3fR#PYydg(7_R5I}G80t?Uc8PUbtkfWB zG>j!8m~lNTgW->Sk|x3?Mn{(?^-UZqJ?%Rsk(O@LB9!DIm_A zA0Ia`$4_05VUw}4+WApzq1^l0lR6}_Qys8tQG$2lQT&^X@{gy(l_``D2guH-lhP(K zokUNQb2eBhV}v2-{`KC^+~ywsDH>(&X*NH=%~y0CB|5R$=rj1XpHI&(Zyfv>`oE^s<(7PJJg{~?A#at1F@+I+ zH1HOp;rg>8F5lRtTlQ-8$c_Ib1AAS=$DKabZ@T>4GRtCX{lA&7gm7E_kZF5dv!&5| z&|(b#^}Pxm&%E2QXx7 z4U2L@QfY%^u>Y}!V0&+Rua_@#8C;v&Cq8=5dxztVmvU4h>;sxyHE?+jVmB5ga3`OA zX~0i6*r?fpf`YH(A4>}g&Na_@RgX-ZP0srJN*dmtkm`1wOV4;YFTwu~&3Z{>{C$*$ zCS6*53}D!~4%P{@ea=JSAmU5kextMWtT_tP5{U7<+pF)%slI=v4oab|zTndIT78Qj zONH~gpd|m(b_RdRVIpGGz;R7GO-53nTM=EVGq;#G;~) z(cO)N(KHd;V)enYfo1}}b|wa4E6xIZ z55C#2pL*gSFaUhbun8PZHHNm4%}qfH?1!yrLYxe8GfJabed@~Vf7)R5>#vRE>vfa9 z6BoGg!hq|2p7!0M`ZeBY{r7u4g^N~NQdRSV;J^&&1BZYX2;V7Jn*(oaD>`h8rgtpK z{p%*oF^-yUqDB z3UqN-*sPQJ*}lr>`nI@27uozi7P6}_Cn7hy$$kjr8(yyGdp^n(=tMi-GEEPAiH4T_ zTve)U%kbEATpHp@mnL03q_6~u`7iiqVmcnl&&&k8-deAQP0VaFbj*^+?e^3<1crRk zb@`s@DMTVWtX<{*4(j+&<&z94bDSfI=1>1TlE2EOFk8_{($|q+@;HLim&!Ex>Nlyo zv`99A^~Psux|cJq_|A}W-kFAmi@plW`YYS0AnRa}@M(#owxPP{jNS}k*DJ%=-5C8i z{td$evSB61m~U^*qrC3Ybc~IEr`{ELPqJbkw_%KS9$O;e5q9?6RB5(*w_nm*%82ea zWb*Zg&y2w*Gq}OR#SB4zFh`3?xcq3yQQa8|IG9TU&EZfBTyhPG_ht~ufABtt8<$6# zD1_lA=dpBe#lZFNrJ8d8Zjim-elS*EJX-ro@kdNZswExG{X*ZnLtJs%(O~!kwtL^^ z4_|Q|T0R|DVt*^5w?R{$-zsP%O{G@|r^>hHQ%umb$Pd=cDr6m}dSc4X_u<;tp}r#$ z3*fK)$4wTz&E8k65NJ+Zxlfqp*leBS$&2<6q~|S%3GfLDFZpcEWOWY3teCG6B-W?& z1=`-5ytjuP3xxQEZ_CT%4TVlH)1}9}p4DvaiKQt^TPzZRn39rOY7NCcjfYu7>ShAE zMlBA>jU~x__%b}puy06PMM*wpc-}HweFJo9F~`4y_Afjuf1o1J6h5<^kDJ-{yt@gd zj%mH!NsYNYonjdsEZXA$&|QmsSn(``np`1{#h+2-2a_M)xor`1=i>}24YRmkrz2^E+`-!s&iq@bVLA1`>@hg#DlOI>T~ zsB!B=7I$b2r-_?#`qTSY`}wU88C{`^y2Bqu0B4H#L+pNs?~Uw%uZGDOLo;M{SZI>R zVWUe8wcM&kuD{omyqB~wS7}t^@b#S^HvG^gT5fdwmpRR`|=64P6o*Q8acnj zEjyAg1^4~YB-=g<4$Xhq7IKNd;!$=0UeMEGFofrI%%j~I&aX<+p`rX0JwXCdK0}i< z?4Qy+w4K&IiC+I&eb%Qo*` z`|_A{wdPjVEUr^-7SC@d9*eY<8eQCGDA*frqMIJC{W#uH<}@rQ5{^I}1ATdfqY~tL zo_OIrp;waSxjehLEsRf|{ge4mmTQk`6Rxqbjh?apIDy1M+j2pqp8~$yE4D>lVd{@v zH{ZYHGI+hVl{$OTX{jo!{@%w+bgSQe9P&s;P{xeXIyT(wwDN3kkV~;cyUAmV^$aw* zm6I`{cX}Wlx2bgBgkK^12nQ%s>j_A82<0pg z=_zJw*gdLN?0Q=EQHKoDfJlnF;srEDX_B)0|O3P8f!5sA*syCB+|?D z5yuTbsPu1pJ%1bM=2yIY|8p^$V~Ko^(y}V}VcNKHT|m5$=hEebh&%hC@2D~K(p3VE z8f9}CL2jm6&fY%hmzTb8FmZ`=u|H{|d9CeSWw|Zv%$V|33=V+kO>l}YZRju2cePf2 zmhp0u^gO%{N}Y_sM%~YPIhnctg51QD`_j9O-+!2PLx1+nx___+wd~9x&rrB+e93{} zTE9t#(|{Yhc_Myk|EHOe1u=$+IeC?DQfgfq1E4Fl(AhU1Q{VQCy+yHFe?tDIO zdlk1zzO31kR0Bkd*}KXw914D-EGYBkR}FKE1gntpkLZMu{NjzfUX?#|X{?z@YP2t# zTcwWaS>7sdh2O|b`Z7QAwbxfwVc}ZmZ!uZ&vB6?r+QviLicB}W%+*>yDl@GH-^&3! zPZ~hLyQ{(&?H;l?Mssltt^_(0;v)WAd&R1l@~T@^8a2xxA;**4zUdRr1G|kaZz@ON z{0~45^c|G%cx!n=Gq2TUUL%$I3mA<1wsu42K3mc4PLYtMrX`p@f3X!+x$&98d9CF# zsqDQ92Kx7#clbEQEd&iG(>tGU4#^5MMqnFlYCa5n207$93mfr)wp@RjZtZ6)=Y?L5 z`XKE{6{qxo*(Y}xiQ^22bEoEsi9f*ky-~1x%&O_BfX1FQd+mm#$Ze32Fao?_r6>AJ z={M16c^|>noYq)6otLSD;{=nH>zw|b3cjckNK>^tw-+*Ug)>7ub7pT$5Zd41(;xih zG-cbevvlqxL-fpdJ`(8Z>YXglTOMLto18n5ykpbv%qIKW&fLmWX257Q^pQT>;ER=t z4Q<4M{A!&jtP9l4WIjvJgcyW-uuxN5%$gNl{Fa{67`le;95Ysb>Sz4*lyK!9m?mD;x}$ zZaVq-WaI56H`wILnQEV;h!l>Ue>)MK({w`}ws>|?U7vzp6Y`SKGHSL*@?g(5h zmm>j>s}#sWP378nuM&2W#n0gu+i^Rw2@UIMLARPKwkJ7D{c3p1$5G87^1x98PnSg# zPm8VBj>teuG|;JsP*|9#3H`8ols*EH(s5HTlh-JSHYi8*L`bdwEPA&8ZBKI$9v=R4 z?73|B>hm;j>(ToK*XNdtu+a4bXRZRN^|u9~P3zJDZ;(CFME^F75T^!zqo!Q~pc{28 zu=x%XxZU~z5;R_70_lUu@YHH) zzIlf;eAaJm#w$9r8TSN%44gh{HL{k2E)B}wY#?m;W}vqwFxq-Z+337Bin zkRl*AbCD1GP7!dM;b#m90phqF^ckb~l>!8)0Jym^ck{42*zQG&<5y(hTjB1Qh$fitoN8o&cqb{z zhbkwoj$|#xQ7B@3lm3cBlBg z?8%Rvn`oW6;c-+Ii}9)5BlA=oQu4!i0sZu&!&JCc-RMI~ zCfWF`Bk>P!o;}BfMrhy)5syV9*I&>QQ7szJ;?j^t*v8uA@tR&S9v8Ref%a>9TO<)4(#JHHo$p> zG&>{AdBk3ivJfl}`-#0uLek^x{Ke&QV#)#v#)=s4W}gUi8%b^S=($A_TyU)^R`&MH z%uHTW6Y4etL+bbM9D3&FE?a?5mbDEHR~*f;UZ0*(kv%=|vl9D8N}_0K2DgnbM|+)H z5+X&j{%{Ir^Do5lkdWxuFy$widjcQF$|2=%-;%LNy;h9t>xt#$#1Y1ahK6QQ-O+4D zj*f+($dmT z{+Ag2kgBJlIqly`n5iR#$k3(Q+gzXhf_-$#4JQh=|@+#Qy!$gFdBdTPfx~KHIUOP zGl^_KA8-bp28tm_|5Ie^a^*se!uA_Ozybdv$xtAX%i^(hPL6{_mTTy+gtf{>%&N4H z^V>Ze3!(bdK3%OSKJm`!%B3JElxjTW+05zs=gC&_%yyTcOaEy+SqWLjCL0v9^+yCv zF+84GcQXu{+AGNc)+A`Qdu>r`)f$7|i779Mi$s1orwkPduF2EYdmPlSxEakhEya`+~wfp$G4rHAoTxYrc>>7m_2amH(K;2KLTBi>ocy> zFhzBwi4-11Mxn9{oPGsIEtnN=^jRS!QV)m6qX5QK_*pyp>(SB)5#PR21L(?FQDe|v zcB}n=DzD7_M6IU0sLSRr=z6Un_6-R}EY_^}=j-adh-YL5%K#W(jAJ+4bB-bJg z(t3U%!DR^8X!tWd98;R!^z`}j%*-k`BIKjxgeQn@F>!35!Uw&MXY+1iC=Xr$G$VrY zAdt-ybwWJrc*?i0+WQJ>IK58s5j(zh=YMTTge-~-sko;Rgh0dCT7nR`Eplns2BXq- zi+P6v{eVvSS2@MXx~)uGY7ieP=%Q?c<8bAvEl7#Po6H-A7x9KID0c@<=-k>V|6TpX z2-&`Qm@@KLtPp5BA%^O6`shp!1<@xtXN8;9*q!o*Y9~hoI=vu0jq;xfikK3Zbqjp= zsKIW2+pE8kVN7M8#(@Suax~4`Qk|q6H4ZW-)Ww~Hpy|9pR$B$+pm9s$+N)%{6ctl} zMVa*PB=-lce7#Nt`vg3>x;dK~qJZ$+kw5}ic6qnFmb&S^7N=%pvvO?7X7X{Y?`ew1 z4AZ}vr;Cb;UgV*4R(uDnx50yFz~QJ7w(Cp}<;6Whu|^~3sZ;2;^j%l0D||wSDcW4$ zDI-O=EvJ0Db(_*R0JQk7YbLV)RnQ(WxB-qor)t7aCorpG6DwZ+UO@$W@I=7X9Fa07 zS{^IHRwg0Kv@q&0GdUPvmqhiliD9LER5@;IJ1b>SB8aB4WPg8u_Km1r--k|Yu&kCZ z-twW4kYur8>AovYw6m7&Nmq4UA?WZXpPOI-qE2Mnbwdjm`YHAL2HN!nEcH~6khQS# z_7s+#lhcuqknpvrh)>VJ;1ysukajQP6qzOsm$W})UZ@V@Ua#4e&1h;n?RlQtl@a_| z{nE%vCSI<&hcF2aq*|*-0$(2Y1yhHnKj1%PBg6{GMoipnC`resO(U`1U*tWq;lyep zI#G^QtM$P3xsRXyesCzJ2<$OE$7fnigjMvT)P4HXsU8QFfW98f0!+5}fKLSIg)cBk z7Q>kxs=Ufdo%Hndpm2}P~jegw{laBweo=U8cV`+)OTp-3UXM#Q2Jz~}(zm%0RnkxU{Q zYuWgQN4&g%h^wnBA1`n0$eEl05f7iOiCdGbiUtOWCkqUSg1yD=&FpA}IIi>n*1XbE zfz@W5B`7|`>DD_HK|XPtfs?m_xPGR%9FbMqw7blHmf{1M>0)iFfoH-iiB$f?yzm0l zooyj>_Ou@<#3=4~A4qT2uQLYS@}ZbKc(hu9{RwnITFmWEoCv9dguqU*D8|u(Y?Wxf z{sgK;PW6@z0WWQgGB5;9h1vDuqC6ViNs zkf>%EJCgFq_KSd-GEOuLKl=@j)46c;|7oPV9@e?Q#i`E+#J5_Gfwk;tGQx93b0%bv z%zifr9CrlqN*}3GSaJ#bOd-ZmY7LvXXNxRPYoCqCT1ZMtO3ghxDy*#1loV<&u*9HLpJ{xn&T{dLw627umE(JkKcQO^BNu-Te-;Dt90DQ ztiQD+0E8ybSxc*hY>Dag+|UMpb6{D68F>!&Nb$K61xD2NI&aVIF{ZMLF=QLIAXsTmeV1rui z{i8QzfDe+@Cg3^r2sXTqNDgTuT*q&k{46}~c^>}YS5E#>&)x}vVg!Nc8Oa333HO$v zI6qvbj>0&o24{>+ZzeElD~uB+j{JtSj(SddS%sdZeJ?HTcXW0>5DyzaSDu+(r zIkj#x8{iUeO>3PwwlYlJo|O&(|9FgGtkzwNyk3nTVC6hHZx2_(4ZkWOG(TpM{c`Q- z5V7_v15KJql%(*-QR1+mazb10_&5UYP*-gqE95a<007AwnZQ&K|L!>AkHur7(>cm) zJdO&3CrmU~{g@-jM);i3QpSv+0>1dCG|V|FECuAB#J~wDn?GMT4^HRDQ8q@gie(X9 z>bfVYk6Va1-G~lan&f@UZlJHP8i#1e7Y{va(ZLvV#15wDt8psdF4{f4)!JEEKuFG& z41HSw%pYF)>nTk6hQ?u}e21?P(K#l}?sjyHDW zAxLL}xyub-wo~B#F7Zab`u)X^^%2V%oycUl0!#J>0 z@UO@TVCM+B_Yb4lX9<^f)!pf2x)|6KZX@nBk?d!->~>95+CUdNu8NC`_aYz3!E&3M zfoXk1L#K%f>x*?t%_5WFHR~h9brE3;I$Mz(T2Kj_138JbYZW1ky-mx zHjtH(7ZN%pA!kbmJwoclAuB~}UwfACU2b9^mR;8U1MEwxf7|}PDHK{G#Pj#uR1#7F z+MP;E=>=9oXF!sNpflJ(+fF8v@345$+aAftK#y*W?3mR=EYpz<_FDHA@Jpo02oq3U zTdT~0%$jVuy8(WEX55whPi@STK-W@{xIH+jE0-R`%z4Av`D9)$REeXl^@m>V-o5Y@ zIK5J<^;SgGJ^kj8i99c7=VC`!SMi;^;xhnWad5*l&n`eB+86XWdFn!8aKOUkjkT#$ z|5ZV7R8*8E(dfdmG6|&Wc0ngOJ2y<|G*wH+!fD9Cao z)!KITMY>K-C53yJAWF;L{I1c$jy+R z;6(64fr*2YHi?DpabiofYw0iOb8o%EKOa4oz?T|ZYsdKGUU)%kScM)6Us$HD9&tx? zF(cNJ@%B@Ao`tIJQ$~^5^mA` zho;+aiEo2yX3SPs2nnS5oyXTWU%zvglPB5xdxq%WaB1;)szu4Si>%K)Y9r@%&$!<3 zCFm)s*M`UkyBGzkaYZ=dC)pEuBF>COZ@1gmNP%kO!e!Cx~PBW^3Hgl5xprWy;8_@KC zZUthAVAqs$RTPS8U2a{o8n@2`$GQ3A4u3|8i-%LfySh?R+9g}?{@>2_bkWbRB9>pZ z2B~tW&xQ-|qcdZh--BpK5i+wtsW&%9gfIy+G+g#wevsvuR8n;#=`MoJiJjs*% zjg$kC;&MA9oVnJIAC=#(SGKq9k4+=SWqi*Fu;hJR9wEj6IaeukM@Y^>jVA7q_Rw7t zPp5QJU3~N!ZJ^8;lH*(ix2ik3PYVpxZ=Tx;q}!v$yq6THE7Lj{gJ7KrOth?-7L!t z8S&2Z)pK1VBL=lgzcMgUzs;A4nWKS2;%EB`lbKV)SibiM(gtLe?-k!;tFt5UWCkp3 zsYy8Y+aR&28gjRdEIqWHSpk@3Q=G=>QoPp7z4K6s=D+H3InjV$Wf(+QWA(&3i7ofO0WtksHyeo6}3kPN)zJwoN}1j;>stE94(iX3rnnR7W3&o>um9J`rDsPr=2ZAQjs ze4no_pxSK)kg);%9JojmsdTS%V~nIt*V-o}$f&#CgK=~;cRf`S65GF+?>-wqWa97F zAMy?PZEyQKAHOby4@c|6b#-*Ck9KC5lH-j*jPj-oQ0V$^9!-bi3TwVcd_$kh1hs7H znKGCp-7wy+puQCGVr(tsq{~&yQzYN6Dw!~|4*2h^_gm+`4X$S@^SS)4g(WGz-tD3= zZ%+0Gl_U%81fFw%hrF2Tma0MW(RCVI4t-Lezcb9PorJqI?9>@;twp`R&ajejQH5Ai zib9h%|9zYZI;bXXfldgEZZBQ=ltRZ-?SK4Qz}7QiYlYifmTx=G_~x5%RlbgFn53Kz_P!UB$~eG z%=L*yQpec%E-DNz?vHWkmKgSOz1zg*j=hrXH+dyWO;7yS_gWQ8iKmW58TVipg|U9u zg#t5X-QHJC$HUcID2J8<56uECuyi7#12?tO2CY;axM;5)wA1m3mAA}P=0`n3%4#8_ znN|&op5008f+rG7w&?cul;_e1!>x(?y#CT;9~e*p1C%>?UbWd`)0}eC43{EdHmn!P z8Jy+kL*_sAk*)<4BgrCPgz${&yNjCSef39?HT7sB&$=Ds1cPw_L4Tuvg15YhySJm@ zLt&jhs@bdl)7?a7va(+eJRc9*R@=s%27&jtmr9NPF%xif1Cjj5N6)*}s^Kk+g&dwq zUuEfz|4aN($W84>b}{#WLTg{JCU^Y6Tcw{5lSeLme(SMF5%_pq!N(cal8@aVD1aLdh>=um<{fw`Z7Y zR=l`QMgype*ORX!ygn~xkc7sf8Ah45fP;ul@NPgk+l2!5)&OTkGZ@@OVfC~gej7$k z!rD6?|M#McUH;Q0qgY-DU!Rp?F34`+xj98jT`?B0zcPO KDtl`6_J06{&TH!c delta 9009 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 literal 10864 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%0D}xqw=Tky+i6+l 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 Date: Sun, 11 Jun 2017 00:04:13 -0500 Subject: [PATCH 02/19] missing files --- code/game/objects/items/weapons/inducer.dm | 183 +++++++++++++++ code/game/objects/structures/manned_turret.dm | 209 ++++++++++++++++++ 2 files changed, 392 insertions(+) create mode 100644 code/game/objects/items/weapons/inducer.dm create mode 100644 code/game/objects/structures/manned_turret.dm diff --git a/code/game/objects/items/weapons/inducer.dm b/code/game/objects/items/weapons/inducer.dm new file mode 100644 index 0000000000..fdd44795ad --- /dev/null +++ b/code/game/objects/items/weapons/inducer.dm @@ -0,0 +1,183 @@ +/obj/item/weapon/inducer + name = "inducer" + desc = "A tool for inductively charging internal power cells." + icon = 'icons/obj/tools.dmi' + icon_state = "inducer-engi" + item_state = "inducer-engi" + origin_tech = "engineering=4;magnets=4;powerstorage=4" + force = 7 + var/powertransfer = 1000 + var/opened = FALSE + var/cell_type = /obj/item/weapon/stock_parts/cell/high + var/obj/item/weapon/stock_parts/cell/cell + var/recharging = FALSE + +/obj/item/weapon/inducer/Initialize() + . = ..() + if(!cell && cell_type) + cell = new cell_type + +/obj/item/weapon/inducer/proc/induce(obj/item/weapon/stock_parts/cell/target, coefficient) + var/totransfer = min(cell.charge,(powertransfer * coefficient)) + var/transferred = target.give(totransfer) + cell.use(transferred) + cell.update_icon() + target.update_icon() + +/obj/item/weapon/inducer/get_cell() + return cell + +/obj/item/weapon/inducer/emp_act(severity) + ..() + if(cell) + cell.emp_act() + +/obj/item/weapon/inducer/attack_obj(obj/O, mob/living/carbon/user) + if(user.a_intent == INTENT_HARM) + return ..() + + if(cantbeused(user)) + return + + if(recharge(O, user)) + return + + return ..() + +/obj/item/weapon/inducer/proc/cantbeused(mob/user) + if(!user.IsAdvancedToolUser()) + to_chat(user, "You don't have the dexterity to use \the [src]!") + return TRUE + + if(!cell) + to_chat(user, "\The [src] doesn't have a power cell installed!") + return TRUE + + if(!cell.charge) + to_chat(user, "\The [src]'s battery is dead!") + return TRUE + return FALSE + + +/obj/item/weapon/inducer/attackby(obj/item/weapon/W, mob/user) + if(istype(W,/obj/item/weapon/screwdriver)) + playsound(src, W.usesound, 50, 1) + if(!opened) + to_chat(user, "You unscrew the battery compartment.") + opened = TRUE + update_icon() + return + else + to_chat(user, "You close the battery compartment.") + opened = FALSE + update_icon() + return + if(istype(W,/obj/item/weapon/stock_parts/cell)) + if(opened) + if(!cell) + if(!user.transferItemToLoc(W, src)) + return + to_chat(user, "You insert \the [W] into \the [src].") + cell = W + update_icon() + return + else + to_chat(user, "\The [src] already has \a [cell] installed!") + return + + if(cantbeused(user)) + return + + if(recharge(W, user)) + return + + return ..() + +/obj/item/weapon/inducer/proc/recharge(atom/movable/A, mob/user) + if(recharging) + return TRUE + else + recharging = TRUE + var/obj/item/weapon/stock_parts/cell/C = A.get_cell() + var/obj/item/weapon/gun/energy/E + var/obj/O + var/coefficient = 1 + if(istype(A, /obj/item/weapon/gun/energy)) + coefficient = 0.075 // 14 loops to recharge an egun from 0-1000 + E = A + if(istype(A, /obj)) + O = A + if(C) + if(C.charge >= C.maxcharge) + to_chat(user, "\The [A] is fully charged!") + recharging = FALSE + return TRUE + user.visible_message("[user] starts recharging \the [A] with \the [src]","You start recharging [A] with \the [src]") + while(C.charge < C.maxcharge) + if(E) + E.chambered = null // Prevents someone from firing continuously while recharging the gun. + if(do_after(user, 10, target = user) && cell.charge) + induce(C, coefficient) + do_sparks(1, FALSE, A) + if(O) + O.update_icon() + else + break + if(E) + E.recharge_newshot() //We're done charging, so we'll let someone fire it now. + user.visible_message("[user] recharged \the [A]!","You recharged \the [A]!") + recharging = FALSE + return TRUE + + +/obj/item/weapon/inducer/attack(mob/M, mob/user) + if(user.a_intent == INTENT_HARM) + return ..() + + if(cantbeused(user)) + return + + if(recharge(M, user)) + return + return ..() + + +/obj/item/weapon/inducer/attack_self(mob/user) + if(opened && cell) + user.visible_message("[user] removes \the [cell] from \the [src]!","You remove \the [cell].") + cell.update_icon() + user.put_in_hands(cell) + cell = null + update_icon() + + +/obj/item/weapon/inducer/examine(mob/living/M) + ..() + if(cell) + to_chat(M, "It's display shows: [cell.charge]W") + else + to_chat(M,"It's display is dark.") + if(opened) + to_chat(M,"It's battery compartment is open.") + +/obj/item/weapon/inducer/update_icon() + cut_overlays() + if(opened) + if(!cell) + add_overlay("inducer-nobat") + else + add_overlay("inducer-bat") + +/obj/item/weapon/inducer/sci + icon_state = "inducer-sci" + item_state = "inducer-sci" + desc = "A tool for inductively charging internal power cells. This one has a science color scheme, and is less potent than it's engineering counterpart." + cell_type = null + powertransfer = 500 + opened = TRUE + +/obj/item/weapon/inducer/sci/Initialize() + . = ..() + update_icon() + + diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm new file mode 100644 index 0000000000..f2f767f4e6 --- /dev/null +++ b/code/game/objects/structures/manned_turret.dm @@ -0,0 +1,209 @@ +/////// MANNED TURRET //////// + +/obj/machinery/manned_turret + name = "machine gun turret" + desc = "While the trigger is held down, this gun will redistribute recoil to allow its user to easily shift targets." + icon = 'icons/obj/turrets.dmi' + icon_state = "machinegun" + can_buckle = TRUE + density = TRUE + max_integrity = 100 + obj_integrity = 100 + buckle_lying = FALSE + layer = ABOVE_MOB_LAYER + var/view_range = 10 + var/cooldown = 0 + var/projectile_type = /obj/item/projectile/bullet/weakbullet3 + var/rate_of_fire = 1 + var/number_of_shots = 40 + var/cooldown_duration = 90 + var/atom/target + var/turf/target_turf + var/warned = FALSE + var/list/calculated_projectile_vars + +/obj/machinery/manned_turret/Destroy() + target = null + target_turf = null + ..() + +//BUCKLE HOOKS + +/obj/machinery/manned_turret/unbuckle_mob(mob/living/buckled_mob,force = FALSE) + playsound(src,'sound/mecha/mechmove01.ogg', 50, 1) + for(var/obj/item/I in buckled_mob.held_items) + if(istype(I, /obj/item/gun_control)) + qdel(I) + if(istype(buckled_mob)) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 0 + if(buckled_mob.client) + buckled_mob.reset_perspective() + anchored = FALSE + . = ..() + STOP_PROCESSING(SSfastprocess, src) + +/obj/machinery/manned_turret/user_buckle_mob(mob/living/M, mob/living/carbon/user) + if(user.incapacitated() || !istype(user)) + return + M.forceMove(get_turf(src)) + ..() + for(var/V in M.held_items) + var/obj/item/I = V + if(istype(I)) + if(M.dropItemToGround(I)) + var/obj/item/gun_control/TC = new(src) + M.put_in_hands(TC) + else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand + var/obj/item/gun_control/TC = new(src) + M.put_in_hands(TC) + M.pixel_y = 14 + layer = ABOVE_MOB_LAYER + setDir(SOUTH) + playsound(src,'sound/mecha/mechmove01.ogg', 50, 1) + anchored = TRUE + if(user.client) + user.client.change_view(view_range) + START_PROCESSING(SSfastprocess, src) + +/obj/machinery/manned_turret/process() + if(!LAZYLEN(buckled_mobs)) + return PROCESS_KILL + update_positioning() + +/obj/machinery/manned_turret/proc/update_positioning() + var/mob/living/controller = buckled_mobs[1] + if(!istype(controller)) + return + var/client/C = controller.client + if(C) + var/atom/A = C.mouseObject + var/turf/T = get_turf(A) + if(istype(T)) //They're hovering over something in the map. + direction_track(controller, T) + calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, C.mouseParams) + +/obj/machinery/manned_turret/proc/direction_track(mob/user, atom/targeted) + setDir(get_dir(src,targeted)) + user.setDir(dir) + switch(dir) + if(NORTH) + layer = BELOW_MOB_LAYER + user.pixel_x = 0 + user.pixel_y = -14 + if(NORTHEAST) + layer = BELOW_MOB_LAYER + user.pixel_x = -8 + user.pixel_y = -4 + if(EAST) + layer = ABOVE_MOB_LAYER + user.pixel_x = -14 + user.pixel_y = 0 + if(SOUTHEAST) + layer = BELOW_MOB_LAYER + user.pixel_x = -8 + user.pixel_y = 4 + if(SOUTH) + layer = ABOVE_MOB_LAYER + user.pixel_x = 0 + user.pixel_y = 14 + if(SOUTHWEST) + layer = BELOW_MOB_LAYER + user.pixel_x = 8 + user.pixel_y = 4 + if(WEST) + layer = ABOVE_MOB_LAYER + user.pixel_x = 14 + user.pixel_y = 0 + if(NORTHWEST) + layer = BELOW_MOB_LAYER + user.pixel_x = 8 + user.pixel_y = -4 + +/obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user) + target = targeted_atom + if(target == user || target == get_turf(src)) + return + if(world.time < cooldown) + if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing + warned = TRUE + playsound(src, 'sound/weapons/sear.ogg', 100, 1) + return + else + cooldown = world.time + cooldown_duration + warned = FALSE + volley(user) + +/obj/machinery/manned_turret/proc/volley(mob/user) + target_turf = get_turf(target) + for(var/i in 1 to number_of_shots) + addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper, user), i*rate_of_fire) + +/obj/machinery/manned_turret/proc/fire_helper(mob/user) + update_positioning() //REFRESH MOUSE TRACKING!! + var/turf/targets_from = get_turf(src) + if(QDELETED(target)) + target = target_turf + var/obj/item/projectile/P = new projectile_type(targets_from) + P.current = targets_from + P.starting = targets_from + P.firer = user + P.original = target + playsound(src, 'sound/weapons/Gunshot_smg.ogg', 75, 1) + P.xo = target.x - targets_from.x + P.yo = target.y - targets_from.y + P.Angle = calculated_projectile_vars[1] + rand(-9, 9) + P.p_x = calculated_projectile_vars[2] + P.p_y = calculated_projectile_vars[3] + P.fire() + +/obj/machinery/manned_turret/ultimate // Admin-only proof of concept for autoclicker automatics + name = "Infinity Gun" + view_range = 12 + projectile_type = /obj/item/projectile/bullet/weakbullet3 + +/obj/machinery/manned_turret/ultimate/checkfire(atom/targeted_atom, mob/user) + target = targeted_atom + if(target == user || target == get_turf(src)) + return + target_turf = get_turf(target) + fire_helper(user) + +/obj/item/gun_control + name = "turret controls" + icon = 'icons/obj/weapons.dmi' + icon_state = "offhand" + w_class = WEIGHT_CLASS_HUGE + flags = ABSTRACT | NODROP | NOBLUDGEON + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + var/obj/machinery/manned_turret/turret + +/obj/item/gun_control/Initialize() + . = ..() + turret = loc + if(!istype(turret)) + return INITIALIZE_HINT_QDEL + +/obj/item/gun_control/Destroy() + turret = null + ..() + +/obj/item/gun_control/CanItemAutoclick() + return TRUE + +/obj/item/gun_control/attack_obj(obj/O, mob/living/user) + user.changeNext_move(CLICK_CD_MELEE) + O.attacked_by(src, user) + +/obj/item/gun_control/attack(mob/living/M, mob/living/user) + user.lastattacked = M + M.lastattacker = user + M.attacked_by(src, user) + add_fingerprint(user) + +/obj/item/gun_control/afterattack(atom/targeted_atom, mob/user, flag, params) + ..() + var/obj/machinery/manned_turret/E = user.buckled + E.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, params) + E.direction_track(user, targeted_atom) + E.checkfire(targeted_atom, user) From 4624ec7e04e82edea18886d8c03809f883b61eb3 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 00:09:55 -0500 Subject: [PATCH 03/19] upstream-merge-27899 --- code/modules/mob/living/carbon/human/status_procs.dm | 7 +++++-- .../projectiles/guns/energy/kinetic_accelerator.dm | 1 + code/modules/reagents/reagent_containers/pill.dm | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index f1ff497a2a..cc32be6f2f 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -6,17 +6,20 @@ /mob/living/carbon/human/Weaken(amount, updating = 1, ignore_canstun = 0) amount = dna.species.spec_stun(src,amount) return ..() - + /mob/living/carbon/human/Paralyse(amount, updating = 1, ignore_canstun = 0) amount = dna.species.spec_stun(src,amount) return ..() - + /mob/living/carbon/human/cure_husk() . = ..() if(.) update_hair() /mob/living/carbon/human/become_husk() + if(istype(dna.species, /datum/species/skeleton)) //skeletons shouldn't be husks. + cure_husk() + return . = ..() if(.) update_hair() diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 3c7b15993b..62bc464ac1 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -210,6 +210,7 @@ icon = 'icons/obj/objects.dmi' icon_state = "modkit" origin_tech = "programming=2;materials=2;magnets=4" + w_class = WEIGHT_CLASS_SMALL require_module = 1 module_type = /obj/item/weapon/robot_module/miner var/denied_type = null diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index b6bc9b2ccf..37a91e6a88 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -11,8 +11,8 @@ var/roundstart = 0 var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills -/obj/item/weapon/reagent_containers/pill/Initialize() - . = ..() +/obj/item/weapon/reagent_containers/pill/Initialize() + . = ..() if(!icon_state) icon_state = "pill[rand(1,20)]" if(reagents.total_volume && roundstart) @@ -142,3 +142,10 @@ icon_state = "pill18" list_reagents = list("insulin" = 50) roundstart = 1 + +/obj/item/weapon/reagent_containers/pill/shadowtoxin + name = "black pill" + desc = "I wouldn't eat this if I were you." + icon_state = "pill9" + color = "#454545" + list_reagents = list("shadowmutationtoxin" = 1) From 28d4372aa08034c8276ef526f7469a322f48f3f3 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 00:20:55 -0500 Subject: [PATCH 04/19] upstream-merge-27852 --- .../mining/equipment/kinetic_crusher.dm | 96 +++++++++++++++--- .../hostile/mining_mobs/basilisk.dm | 1 + .../hostile/mining_mobs/goliath.dm | 1 + .../hostile/mining_mobs/hivelord.dm | 5 + .../hostile/mining_mobs/mining_mobs.dm | 15 ++- icons/obj/lavaland/artefacts.dmi | Bin 17595 -> 18423 bytes 6 files changed, 102 insertions(+), 16 deletions(-) diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 6d8a99c1a2..a96e14f802 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -21,7 +21,7 @@ sharpness = IS_SHARP var/list/trophies = list() var/charged = TRUE - var/charge_time = 14 + var/charge_time = 15 /obj/item/weapon/twohanded/required/mining_hammer/Destroy() for(var/a in trophies) @@ -92,16 +92,21 @@ for(var/t in trophies) var/obj/item/crusher_trophy/T = t T.on_mark_detonation(target, user) - new /obj/effect/temp_visual/kinetic_blast(get_turf(L)) - var/backstab_dir = get_dir(user, L) - var/def_check = L.getarmor(type = "bomb") - if((user.dir & backstab_dir) && (L.dir & backstab_dir)) - L.apply_damage(80, BRUTE, blocked = def_check) - playsound(user, 'sound/weapons/Kenetic_accel.ogg', 100, 1) //Seriously who spelled it wrong - else - L.apply_damage(50, BRUTE, blocked = def_check) - if(!QDELETED(C) && !QDELETED(L)) - C.total_damage += target_health - L.health //we did some damage, but let's not assume how much we did + if(!QDELETED(L)) + if(!QDELETED(C)) + C.total_damage += target_health - L.health //we did some damage, but let's not assume how much we did + new /obj/effect/temp_visual/kinetic_blast(get_turf(L)) + var/backstab_dir = get_dir(user, L) + var/def_check = L.getarmor(type = "bomb") + if((user.dir & backstab_dir) && (L.dir & backstab_dir)) + if(!QDELETED(C)) + C.total_damage += 80 //cheat a little and add the total before killing it, so certain mobs don't have much lower chances of giving an item + L.apply_damage(80, BRUTE, blocked = def_check) + playsound(user, 'sound/weapons/Kenetic_accel.ogg', 100, 1) //Seriously who spelled it wrong + else + if(!QDELETED(C)) + C.total_damage += 50 + L.apply_damage(50, BRUTE, blocked = def_check) /obj/item/weapon/twohanded/required/mining_hammer/proc/Recharge() if(!charged) @@ -185,9 +190,70 @@ /obj/item/crusher_trophy/proc/on_mark_application(mob/living/target, datum/status_effect/crusher_mark/mark, had_mark) //the target, the mark applied, and if the target had a mark before /obj/item/crusher_trophy/proc/on_mark_detonation(mob/living/target, mob/living/user) //the target and the user +//goliath +/obj/item/crusher_trophy/goliath_tentacle + name = "goliath tentacle" + desc = "A sliced-off goliath tentacle. Suitable as a trophy for a kinetic crusher." + icon_state = "goliath_tentacle" + denied_type = /obj/item/crusher_trophy/goliath_tentacle + bonus_value = 2 + var/missing_health_ratio = 0.1 + var/missing_health_desc = 10 +/obj/item/crusher_trophy/goliath_tentacle/effect_desc() + return "mark detonation to do [bonus_value] more damage for every [missing_health_desc] health you are missing" + +/obj/item/crusher_trophy/goliath_tentacle/on_mark_detonation(mob/living/target, mob/living/user) + var/missing_health = user.health - user.maxHealth + missing_health *= missing_health_ratio //bonus is active at all times, even if you're above 90 health + missing_health *= bonus_value //multiply the remaining amount by bonus_value + if(missing_health > 0) + target.adjustBruteLoss(missing_health) //and do that much damage + +/watcher +/obj/item/crusher_trophy/watcher_wing + name = "watcher wing" + desc = "A wing ripped from a watcher. Suitable as a trophy for a kinetic crusher." + icon_state = "watcher_wing" + denied_type = /obj/item/crusher_trophy/watcher_wing + bonus_value = 8 + +/obj/item/crusher_trophy/watcher_wing/effect_desc() + return "mark detonation to prevent certain creatures from using certain attacks for [bonus_value*0.1] second[bonus_value*0.1 == 1 ? "":"s"]" + +/obj/item/crusher_trophy/watcher_wing/on_mark_detonation(mob/living/target, mob/living/user) + if(ishostile(target)) + var/mob/living/simple_animal/hostile/H = target + if(H.ranged) //briefly delay ranged attacks + if(H.ranged_cooldown_time >= world.time) + H.ranged_cooldown_time += bonus_value + else + H.ranged_cooldown_time = bonus_value + world.time + +//legion +/obj/item/crusher_trophy/legion_skull + name = "legion skull" + desc = "A dead and lifeless legion skull. Suitable as a trophy for a kinetic crusher." + icon_state = "legion_skull" + denied_type = /obj/item/crusher_trophy/legion_skull + bonus_value = 3 + +/obj/item/crusher_trophy/legion_skull/effect_desc() + return "a kinetic crusher to recharge [bonus_value*0.1] second[bonus_value*0.1 == 1 ? "":"s"] faster" + +/obj/item/crusher_trophy/legion_skull/add_to(obj/item/weapon/twohanded/required/mining_hammer/H, mob/living/user) + . = ..() + if(.) + H.charge_time -= bonus_value + +/obj/item/crusher_trophy/legion_skull/remove_from(obj/item/weapon/twohanded/required/mining_hammer/H, mob/living/user) + . = ..() + if(.) + H.charge_time += bonus_value + + //ash drake /obj/item/crusher_trophy/tail_spike - desc = "A spike taken from a ash drake's tail." + desc = "A spike taken from a ash drake's tail. Suitable as a trophy for a kinetic crusher." denied_type = /obj/item/crusher_trophy/tail_spike bonus_value = 5 @@ -210,7 +276,7 @@ //bubblegum /obj/item/crusher_trophy/demon_claws name = "demon claws" - desc = "A set of blood-drenched claws from a massive demon's hand." + desc = "A set of blood-drenched claws from a massive demon's hand. Suitable as a trophy for a kinetic crusher." icon_state = "demon_claws" gender = PLURAL denied_type = /obj/item/crusher_trophy/demon_claws @@ -244,7 +310,7 @@ //colossus /obj/item/crusher_trophy/blaster_tubes name = "blaster tubes" - desc = "The blaster tubes from a colossus's arm." + desc = "The blaster tubes from a colossus's arm. Suitable as a trophy for a kinetic crusher." icon_state = "blaster_tubes" gender = PLURAL denied_type = /obj/item/crusher_trophy/blaster_tubes @@ -273,7 +339,7 @@ //hierophant /obj/item/crusher_trophy/vortex_talisman name = "vortex talisman" - desc = "A glowing trinket that was originally the Hierophant's beacon." + desc = "A glowing trinket that was originally the Hierophant's beacon. Suitable as a trophy for a kinetic crusher." icon_state = "vortex_talisman" denied_type = /obj/item/crusher_trophy/vortex_talisman diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index 19b35b9866..99958268a5 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -76,5 +76,6 @@ stat_attack = UNCONSCIOUS movement_type = FLYING robust_searching = 1 + crusher_loot = /obj/item/crusher_trophy/watcher_wing loot = list() butcher_results = list(/obj/item/weapon/ore/diamond = 2, /obj/item/stack/sheet/sinew = 2, /obj/item/stack/sheet/bone = 1) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm index e95012b519..0a5b9957f2 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm @@ -85,6 +85,7 @@ icon_dead = "goliath_dead" throw_message = "does nothing to the tough hide of the" pre_attack_icon = "goliath2" + crusher_loot = /obj/item/crusher_trophy/goliath_tentacle butcher_results = list(/obj/item/weapon/reagent_containers/food/snacks/meat/slab/goliath = 2, /obj/item/stack/sheet/animalhide/goliath_hide = 1, /obj/item/stack/sheet/bone = 2) loot = list() stat_attack = UNCONSCIOUS diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index fbea8d0f79..b7ecba8431 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -46,6 +46,10 @@ OpenFire() return TRUE +/mob/living/simple_animal/hostile/asteroid/hivelord/spawn_crusher_loot() + loot += crusher_loot //we don't butcher + + /mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed) mouse_opacity = 1 ..(gibbed) @@ -101,6 +105,7 @@ speak_emote = list("echoes") attack_sound = 'sound/weapons/pierce.ogg' throw_message = "bounces harmlessly off of" + crusher_loot = /obj/item/crusher_trophy/legion_skull loot = list(/obj/item/organ/regenerative_core/legion) brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion del_on_death = 1 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm index 1e76860267..f9e458cfd8 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm @@ -11,6 +11,7 @@ response_help = "pokes" response_disarm = "shoves" response_harm = "strikes" + var/crusher_loot status_flags = 0 a_intent = INTENT_HARM var/throw_message = "bounces off of" @@ -19,6 +20,11 @@ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE mob_size = MOB_SIZE_LARGE +/mob/living/simple_animal/hostile/asteroid/Initialize(mapload) + . = ..() + apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + + /mob/living/simple_animal/hostile/asteroid/Aggro() ..() if(vision_range != aggro_vision_range) @@ -44,14 +50,21 @@ if(!stat) Aggro() if(T.throwforce <= 20) - visible_message("The [T.name] [src.throw_message] [src.name]!") + visible_message("The [T.name] [throw_message] [src.name]!") return ..() /mob/living/simple_animal/hostile/asteroid/death(gibbed) SSblackbox.add_details("mobs_killed_mining","[src.type]") + var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + if(C && crusher_loot && prob((C.total_damage/maxHealth)) * 5) //on average, you'll need to kill 20 creatures before getting the item + spawn_crusher_loot() ..(gibbed) +/mob/living/simple_animal/hostile/asteroid/proc/spawn_crusher_loot() + butcher_results[crusher_loot] = 1 + + /mob/living/simple_animal/hostile/asteroid/handle_temperature_damage() if(bodytemperature < minbodytemp) adjustBruteLoss(2) diff --git a/icons/obj/lavaland/artefacts.dmi b/icons/obj/lavaland/artefacts.dmi index 41c1ba56cd3dfc6f328323578ad8973ddfc7c3d9..0deead024a63b5a97da2e72e6c60759b3451d44a 100644 GIT binary patch literal 18423 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 Z_t4p;@}#irF7QAf22WQ%mvv4FO#mOA`oaJJ literal 17595 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 Date: Sun, 11 Jun 2017 01:51:56 -0500 Subject: [PATCH 05/19] map fix --- _maps/map_files/PubbyStation/PubbyStation.dmm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 8937961188..aed8a82687 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -36271,7 +36271,7 @@ }, /obj/effect/landmark/blobstart, /obj/item/weapon/melee/baton/cattleprod{ - bcell = new /obj/item/weapon/stock_parts/cell/high() + cell = new /obj/item/weapon/stock_parts/cell/high() }, /turf/open/floor/plasteel/black, /area/medical/exam_room) From a8b71089aef834545d7a2fb50d4545f685aa1b4c Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 02:03:27 -0500 Subject: [PATCH 06/19] upstream-merge-27933 --- .../chemistry/machinery/chem_dispenser.dm | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 428d1fc114..277b3b8ede 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -9,8 +9,9 @@ idle_power_usage = 40 interact_offline = 1 resistance_flags = FIRE_PROOF | ACID_PROOF - var/energy = 100 - var/max_energy = 100 + var/cell_type = /obj/item/weapon/stock_parts/cell/high + var/obj/item/weapon/stock_parts/cell/cell + var/powerefficiency = 0.01 var/amount = 30 var/recharged = 0 var/recharge_delay = 5 @@ -54,6 +55,7 @@ /obj/machinery/chem_dispenser/Initialize() . = ..() + cell = new cell_type recharge() dispensable_reagents = sortList(dispensable_reagents) @@ -66,11 +68,8 @@ recharged -= 1 /obj/machinery/chem_dispenser/proc/recharge() - if(stat & (BROKEN|NOPOWER)) return - var/addenergy = 1 - var/oldenergy = energy - energy = min(energy + addenergy, max_energy) - if(energy != oldenergy) + var/usedpower = cell.give( 1 / powerefficiency) //Should always be a gain of one on the UI. + if(usedpower) use_power(2500) /obj/machinery/chem_dispenser/emag_act(mob/user) @@ -106,8 +105,8 @@ /obj/machinery/chem_dispenser/ui_data() var/data = list() data["amount"] = amount - data["energy"] = energy - data["maxEnergy"] = max_energy + data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI. + data["maxEnergy"] = cell.maxcharge * powerefficiency data["isBeakerLoaded"] = beaker ? 1 : 0 var beakerContents[0] @@ -149,7 +148,7 @@ if(beaker && dispensable_reagents.Find(reagent)) var/datum/reagents/R = beaker.reagents var/free = R.maximum_volume - R.total_volume - var/actual = min(amount, energy * 10, free) + var/actual = min(amount, (cell.charge * powerefficiency)*10, free) R.add_reagent(reagent, actual) energy = max(energy - actual / 10, 0) @@ -189,15 +188,36 @@ add_overlay(beaker_overlay) else if(user.a_intent != INTENT_HARM && !istype(I, /obj/item/weapon/card/emag)) to_chat(user, "You can't load \the [I] into the machine!") + return ..() else return ..() +/obj/machinery/chem_dispenser/get_cell() + return cell + +/obj/machinery/chem_dispenser/emp_act(severity) + var/list/datum/reagents/R = list() + var/total = min(rand(7,15), Floor(cell.charge*powerefficiency)) + var/datum/reagents/Q = new(total*10) + if(beaker && beaker.reagents) + R += beaker.reagents + for(var/i in 1 to total) + Q.add_reagent(pick(dispensable_reagents), 10) + R += Q + chem_splash(get_turf(src), 3, R) + if(beaker && beaker.reagents) + beaker.reagents.remove_all() + cell.use(total/powerefficiency) + cell.emp_act() + visible_message(" The [src] malfunctions, spraying chemicals everywhere!") + ..() + + /obj/machinery/chem_dispenser/constructable name = "portable chem dispenser" icon = 'icons/obj/chemical.dmi' icon_state = "minidispenser" - energy = 10 - max_energy = 10 + powerefficiency = 0.001 amount = 5 recharge_delay = 30 dispensable_reagents = list() @@ -263,16 +283,13 @@ /obj/machinery/chem_dispenser/constructable/RefreshParts() var/time = 0 - var/temp_energy = 0 var/i ++ for(var/obj/item/weapon/stock_parts/cell/P in component_parts) + cell = P for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) - temp_energy += M.rating - temp_energy-- - max_energy = temp_energy * 5 //max energy = (bin1.rating + bin2.rating - 1) * 5, 5 on lowest 25 on highest + time += M.rating for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) time += C.rating - for(var/obj/item/weapon/stock_parts/cell/P in component_parts) - time += round(P.maxcharge, 10000) / 10000 recharge_delay /= time/2 //delay between recharges, double the usual time on lowest 50% less than usual on highest for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) for(i=1, i<=M.rating, i++) From c760c5281705ff6d613f93f4e3d3980f10be5f09 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 02:11:34 -0500 Subject: [PATCH 07/19] upstream-merge-27951 --- code/datums/helper_datums/getrev.dm | 2 +- code/game/gamemodes/wizard/spellbook.dm | 3 +-- code/modules/events/immovable_rod.dm | 21 +++++++++++-------- code/modules/mapping/map_template.dm | 6 +++--- .../file_system/programs/card.dm | 3 +++ .../chemistry/machinery/chem_dispenser.dm | 2 +- code/modules/spells/spell_types/rod_form.dm | 6 ++++++ 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index ffb5627c6f..42ba4c7b47 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -73,9 +73,9 @@ return "" . = header ? "The following pull requests are currently test merged:
" : "" for(var/line in testmerge) - var/cm = testmerge[line]["commit"] var/details if(world.RunningService()) + var/cm = testmerge[line]["commit"] details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 7))) else if(has_pr_details) //tgs2 support details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["user"]["login"]) diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 143d60be91..b55383a38d 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -106,10 +106,9 @@ name = "Fireball" spell_type = /obj/effect/proc_holder/spell/aimed/fireball -/* /datum/spellbook_entry/rod_form name = "Rod Form" - spell_type = /obj/effect/proc_holder/spell/targeted/rod_form */ + spell_type = /obj/effect/proc_holder/spell/targeted/rod_form /datum/spellbook_entry/magicm name = "Magic Missile" diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 2b46d82df1..5c5fc93e6b 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -21,8 +21,8 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 /datum/round_event/immovable_rod/start() var/startside = pick(GLOB.cardinal) - var/turf/startT = spaceDebrisStartLoc(startside, ZLEVEL_STATION) - var/turf/endT = spaceDebrisFinishLoc(startside, ZLEVEL_STATION) + var/turf/startT = spaceDebrisStartLoc(startside, ZLEVEL_STATION) + var/turf/endT = spaceDebrisFinishLoc(startside, ZLEVEL_STATION) new /obj/effect/immovablerod(startT, endT) /obj/effect/immovablerod @@ -82,13 +82,8 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 if(clong.density) clong.ex_act(2) - else if(ismob(clong)) - if(ishuman(clong)) - var/mob/living/carbon/human/H = clong - H.visible_message("[H.name] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!") - H.adjustBruteLoss(160) - if(clong.density || prob(10)) - clong.ex_act(2) + else if(isliving(clong)) + penetrate(clong) else if(istype(clong, type)) var/obj/effect/immovablerod/other = clong visible_message("[src] collides with [other]!\ @@ -98,3 +93,11 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 smoke.start() qdel(src) qdel(other) + +/obj/effect/immovablerod/proc/penetrate(mob/living/L) + L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!") + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.adjustBruteLoss(160) + if(L && (L.density || prob(10))) + L.ex_act(2) diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index e0588acf2b..2aa2031bbe 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -71,12 +71,12 @@ if(!bounds) return - //initialize things that are normally initialized after map load - initTemplateBounds(bounds) - if(!SSmapping.loading_ruins) //Will be done manually during mapping ss init repopulate_sorted_areas() + //initialize things that are normally initialized after map load + initTemplateBounds(bounds) + log_game("[name] loaded at at [T.x],[T.y],[T.z]") return TRUE diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index fb77197c62..dfe2acd252 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -42,6 +42,9 @@ /datum/computer_file/program/card_mod/New() ..() change_position_cooldown = config.id_console_jobslot_delay + addtimer(CALLBACK(src, .proc/SetConfigCooldown), 0) + +/datum/computer_file/program/card_mod/proc/SetConfigCooldown() /datum/computer_file/program/card_mod/event_idremoved(background, slot) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 277b3b8ede..e02935aa87 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -284,7 +284,7 @@ /obj/machinery/chem_dispenser/constructable/RefreshParts() var/time = 0 var/i -+ for(var/obj/item/weapon/stock_parts/cell/P in component_parts) + for(var/obj/item/weapon/stock_parts/cell/P in component_parts) cell = P for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) time += M.rating diff --git a/code/modules/spells/spell_types/rod_form.dm b/code/modules/spells/spell_types/rod_form.dm index a3754e6a7d..8fc3f34fc4 100644 --- a/code/modules/spells/spell_types/rod_form.dm +++ b/code/modules/spells/spell_types/rod_form.dm @@ -17,6 +17,7 @@ var/obj/effect/immovablerod/wizard/W = new(start, get_ranged_target_turf(M, M.dir, (15 + spell_level * 3))) W.wizard = M W.max_distance += spell_level * 3 //You travel farther when you upgrade the spell + W.damage_bonus += spell_level * 20 //You do more damage when you upgrade the spell W.start_turf = start M.forceMove(W) M.notransform = 1 @@ -26,6 +27,7 @@ /obj/effect/immovablerod/wizard var/max_distance = 13 + var/damage_bonus = 0 var/mob/living/wizard var/turf/start_turf notify = FALSE @@ -41,3 +43,7 @@ wizard.notransform = 0 wizard.forceMove(get_turf(src)) return ..() + +/obj/effect/immovablerod/wizard/penetrate(mob/living/L) + L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!") + L.adjustBruteLoss(70 + damage_bonus) From f694264371098f6d8dfb218132934783d3ef2db1 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 02:14:54 -0500 Subject: [PATCH 08/19] compile fix --- code/modules/reagents/chemistry/machinery/chem_dispenser.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index e02935aa87..527a0e3075 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -151,7 +151,7 @@ var/actual = min(amount, (cell.charge * powerefficiency)*10, free) R.add_reagent(reagent, actual) - energy = max(energy - actual / 10, 0) + cell.use((actual / 10) / powerefficiency) . = TRUE if("remove") var/amount = text2num(params["amount"]) From 55e565ab8c9ceb039c56df300e153fce2dafa944 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 02:16:35 -0500 Subject: [PATCH 09/19] upstream-merge-27973 --- code/game/gamemodes/gang/gang_items.dm | 2 +- code/modules/reagents/chemistry/machinery/chem_dispenser.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/gamemodes/gang/gang_items.dm b/code/game/gamemodes/gang/gang_items.dm index 22b3758379..ddb0ca4608 100644 --- a/code/game/gamemodes/gang/gang_items.dm +++ b/code/game/gamemodes/gang/gang_items.dm @@ -250,7 +250,7 @@ name = "Black Market .50cal Sniper Rifle" id = "sniper" cost = 40 - item_path = /obj/item/weapon/gun/ballistic/automatic/sniper_rifle + item_path = /obj/item/weapon/gun/ballistic/automatic/sniper_rifle/gang /datum/gang_item/weapon/ammo/sniper_ammo name = "Smuggled .50cal Sniper Rounds" diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index 527a0e3075..1f5085ae09 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -217,7 +217,7 @@ name = "portable chem dispenser" icon = 'icons/obj/chemical.dmi' icon_state = "minidispenser" - powerefficiency = 0.001 + powerefficiency = 0.001 amount = 5 recharge_delay = 30 dispensable_reagents = list() From 4386813269126007e473e878e2e737e4f7394891 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 02:17:53 -0500 Subject: [PATCH 10/19] upstream-merge-27996 --- .../gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm index 3e7d0f3779..56f55a8f80 100644 --- a/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm @@ -49,6 +49,9 @@ /turf/open/floor/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) if(locate(/obj/structure/table) in src) return FALSE + if(locate(/obj/structure/falsewall) in contents) + to_chat(user, "There is a false wall in the way, preventing you from proselytizing [src] into a clockwork wall.") + return if(is_blocked_turf(src, TRUE)) to_chat(user, "Something is in the way, preventing you from proselytizing [src] into a clockwork wall.") return TRUE From 9d85cbf3b5717f831e6fe786deb989990098afe3 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 02:19:56 -0500 Subject: [PATCH 11/19] upstream-merge-28006 --- code/modules/ruins/lavaland_ruin_code.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index 00011729e0..6bc1944cfd 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -133,8 +133,7 @@ death = FALSE icon = 'icons/obj/Cryogenic2.dmi' icon_state = "sleeper" - flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. Do not abandon the base without good cause. The base is rigged with explosives should the worst happen, do not let the base fall into enemy hands!
" - id_access_list = list(GLOB.access_syndicate) + flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. DON'T abandon the base without good cause. The base is rigged with explosives should the worst happen, do not let the base fall into enemy hands!" id_access_list = list(GLOB.access_syndicate) faction = list("syndicate") outfit = /datum/outfit/lavaland_syndicate @@ -153,7 +152,7 @@ /obj/effect/mob_spawn/human/lavaland_syndicate/comms name = "Syndicate Comms Agent" - flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Monitor enemy activity as best you can, and try to keep a low profile. Do not abandon the base without good cause. Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands!" + flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Monitor enemy activity as best you can, and try to keep a low profile. DON'T abandon the base without good cause. Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands!" outfit = /datum/outfit/lavaland_syndicate/comms /datum/outfit/lavaland_syndicate/comms From bd4d42a8a65303f9d4cf413748b9869b16068213 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 08:12:27 -0500 Subject: [PATCH 12/19] upstream-merge-28034/compile fix/upstream-merge-28048 --- code/game/objects/structures/tables_racks.dm | 20 +++++++++---------- .../mapGenerators/repair.dm | 4 +++- code/modules/ruins/lavaland_ruin_code.dm | 3 ++- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 73c75e2cc5..febf5ab3af 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -195,7 +195,7 @@ check_break(M) /obj/structure/table/glass/proc/check_break(mob/living/M) - if(M.has_gravity() && M.mob_size > MOB_SIZE_SMALL) + if(M.has_gravity() && M.mob_size > MOB_SIZE_SMALL && !M.movement_type & FLYING) table_shatter(M) /obj/structure/table/glass/proc/table_shatter(mob/M) @@ -271,20 +271,20 @@ frame = /obj/structure/table_frame framestack = /obj/item/stack/rods buildstack = /obj/item/stack/tile/carpet - canSmoothWith = list(/obj/structure/table/wood/fancy,/obj/structure/table/wood/fancy/black) + canSmoothWith = list(/obj/structure/table/wood/fancy,/obj/structure/table/wood/fancy/black) /obj/structure/table/wood/fancy/New() icon = 'icons/obj/smooth_structures/fancy_table.dmi' //so that the tables place correctly in the map editor ..() -/obj/structure/table/wood/fancy/black - icon_state = "fancy_table_black" - buildstack = /obj/item/stack/tile/carpet/black - -/obj/structure/table/wood/fancy/black/New() - ..() - icon = 'icons/obj/smooth_structures/fancy_table_black.dmi' - +/obj/structure/table/wood/fancy/black + icon_state = "fancy_table_black" + buildstack = /obj/item/stack/tile/carpet/black + +/obj/structure/table/wood/fancy/black/New() + ..() + icon = 'icons/obj/smooth_structures/fancy_table_black.dmi' + /* * Reinforced tables */ diff --git a/code/modules/procedural_mapping/mapGenerators/repair.dm b/code/modules/procedural_mapping/mapGenerators/repair.dm index e2f658648c..d568b83e80 100644 --- a/code/modules/procedural_mapping/mapGenerators/repair.dm +++ b/code/modules/procedural_mapping/mapGenerators/repair.dm @@ -1,9 +1,10 @@ /datum/mapGeneratorModule/bottomLayer/repairFloorPlasteel spawnableTurfs = list(/turf/open/floor/plasteel = 100) var/ignore_wall = FALSE + allowAtomsOnSpace = TRUE /datum/mapGeneratorModule/bottomLayer/repairFloorPlasteel/place(turf/T) - if(isclosedturf(T)) + if(isclosedturf(T) && !ignore_wall) return FALSE return TRUE @@ -13,6 +14,7 @@ /datum/mapGeneratorModule/border/normalWalls spawnableAtoms = list() spawnableTurfs = list(/turf/closed/wall = 100) + allowAtomsOnSpace = TRUE /datum/mapGenerator/repair modules = list(/datum/mapGeneratorModule/bottomLayer/repairFloorPlasteel, diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index 6bc1944cfd..16f7d27df0 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -133,7 +133,8 @@ death = FALSE icon = 'icons/obj/Cryogenic2.dmi' icon_state = "sleeper" - flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. DON'T abandon the base without good cause. The base is rigged with explosives should the worst happen, do not let the base fall into enemy hands!" id_access_list = list(GLOB.access_syndicate) + id_access_list = list(GLOB.access_syndicate) + flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. DON'T abandon the base without good cause. The base is rigged with explosives should the worst happen, do not let the base fall into enemy hands!" faction = list("syndicate") outfit = /datum/outfit/lavaland_syndicate From 11ff6a7628ff30bf7044236221f2b0988794c227 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 08:21:14 -0500 Subject: [PATCH 13/19] upstream-merge-27971 --- code/__DEFINES/misc.dm | 2 ++ code/datums/explosion.dm | 29 +++++++------------------- code/game/machinery/doors/door.dm | 12 +++++++++-- code/game/objects/obj_defense.dm | 4 ++++ code/game/objects/structures/window.dm | 9 ++++++++ 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 6ea8cd64ee..f9de982db6 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -430,6 +430,8 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE #define GIBTONITE_ACTIVE 1 #define GIBTONITE_STABLE 2 #define GIBTONITE_DETONATE 3 +//for obj explosion block calculation +#define EXPLOSION_BLOCK_PROC -1 //Gangster starting influences #define GANGSTER_SOLDIER_STARTING_INFLUENCE 5 diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm index b74e4619db..9fb302a63a 100644 --- a/code/datums/explosion.dm +++ b/code/datums/explosion.dm @@ -279,16 +279,9 @@ GLOBAL_LIST_EMPTY(explosions) var/turf/T = affected_turfs[I] var/current_exp_block = T.density ? T.explosion_block : 0 - for(var/obj/machinery/door/D in T) - if(D.density) - current_exp_block += D.explosion_block - - for(var/obj/structure/window/W in T) - if(W.reinf && W.fulltile) - current_exp_block += W.explosion_block - - for(var/obj/structure/blob/B in T) - current_exp_block += B.explosion_block + for(var/obj/O in T) + var/the_block = O.explosion_block + current_exp_block += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block .[T] = current_exp_block @@ -351,20 +344,12 @@ GLOBAL_LIST_EMPTY(explosions) var/turf/TT = T while(TT != epicenter) TT = get_step_towards(TT,epicenter) - if(TT.density && TT.explosion_block) + if(TT.density) dist += TT.explosion_block - for(var/obj/machinery/door/D in TT) - if(D.density && D.explosion_block) - dist += D.explosion_block - - for(var/obj/structure/window/W in TT) - if(W.explosion_block && W.fulltile) - dist += W.explosion_block - - for(var/obj/structure/blob/B in T) - dist += B.explosion_block - + for(var/obj/O in T) + var/the_block = O.explosion_block + dist += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block if(dist < dev) T.color = "red" T.maptext = "Dev" diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index b71aeaca8d..aacb290d40 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -12,7 +12,7 @@ max_integrity = 350 armor = list(melee = 30, bullet = 30, laser = 20, energy = 20, bomb = 10, bio = 100, rad = 100, fire = 80, acid = 70) CanAtmosPass = ATMOS_PASS_DENSITY - flags = PREVENT_CLICK_UNDER + flags = PREVENT_CLICK_UNDER var/secondsElectrified = 0 var/shockedby = list() @@ -32,6 +32,7 @@ var/auto_close //TO BE REMOVED, no longer used, it's just preventing a runtime with a map var edit. var/datum/effect_system/spark_spread/spark_system var/damage_deflection = 10 + var/real_explosion_block //ignore this, just use explosion_block /obj/machinery/door/New() ..() @@ -45,6 +46,10 @@ spark_system = new /datum/effect_system/spark_spread spark_system.set_up(2, 1, src) + //doors only block while dense though so we have to use the proc + real_explosion_block = explosion_block + explosion_block = EXPLOSION_BLOCK_PROC + /obj/machinery/door/Destroy() @@ -284,7 +289,7 @@ /obj/machinery/door/proc/crush() for(var/mob/living/L in get_turf(src)) - L.visible_message("[src] closes on [L], crushing them!", "[src] closes on you and crushes you!") + L.visible_message("[src] closes on [L], crushing them!", "[src] closes on you and crushes you!") if(isalien(L)) //For xenos L.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 1.5) //Xenos go into crit after aproximately the same amount of crushes as humans. L.emote("roar") @@ -346,3 +351,6 @@ //if it blows up a wall it should blow up a door ..(severity ? max(1, severity - 1) : 0, target) +/obj/machinery/door/GetExplosionBlock() + return density ? real_explosion_block : 0 + diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 44281fb26f..747fb1b741 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -259,3 +259,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e obj_break(damage_type) return TRUE return FALSE + +//returns how much the object blocks an explosion +/obj/proc/GetExplosionBlock() + CRASH("Unimplemented GetExplosionBlock()") \ No newline at end of file diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 0c11418003..247a0a70d4 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -24,6 +24,7 @@ resistance_flags = ACID_PROOF armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 80, acid = 100) CanAtmosPass = ATMOS_PASS_PROC + var/real_explosion_block //ignore this, just use explosion_block /obj/structure/window/examine(mob/user) ..() @@ -73,6 +74,10 @@ if(rods) debris += new /obj/item/stack/rods(src, rods) + //windows only block while reinforced and fulltile, so we'll use the proc + real_explosion_block = explosion_block + explosion_block = EXPLOSION_BLOCK_PROC + /obj/structure/window/rcd_vals(mob/user, obj/item/weapon/construction/rcd/the_rcd) switch(the_rcd.mode) if(RCD_DECONSTRUCT) @@ -400,6 +405,10 @@ return 1 +/obj/structure/window/GetExplosionBlock() + return reinf && fulltile ? real_explosion_block : 0 + + /obj/structure/window/unanchored anchored = FALSE From f5f4e3a9d1833802e109f16c3ff6a088dfa91274 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 08:26:09 -0500 Subject: [PATCH 14/19] upstream-merge-28047 --- code/_onclick/hud/alert.dm | 15 +++---- code/game/gamemodes/clock_cult/clock_cult.dm | 5 +-- .../clock_helpers/scripture_checks.dm | 17 ++++---- .../clock_cult/clock_items/clockwork_slab.dm | 43 ++++++++++++++----- 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 7e6f488a47..397eabeb22 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -361,7 +361,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." name = "Next Tier Requirements" desc = "You shouldn't be seeing this description unless you're very fast. If you're very fast, good job!" icon_state = "no-servants-caches" - var/static/list/scripture_states = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE) /obj/screen/alert/clockwork/scripture_reqs/Initialize() . = ..() @@ -374,12 +373,11 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /obj/screen/alert/clockwork/scripture_reqs/process() if(GLOB.clockwork_gateway_activated) - qdel(src) + mob_viewer.clear_alert("scripturereq") return var/current_state - scripture_states = scripture_unlock_check() - for(var/i in scripture_states) - if(!scripture_states[i]) + for(var/i in SSticker.scripture_states) + if(!SSticker.scripture_states[i]) current_state = i break icon_state = "no" @@ -459,7 +457,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." var/servants = 0 var/validservants = 0 var/unconverted_ais_exist = get_unconverted_ais() - var/list/scripture_states = scripture_unlock_check() var/list/textlist for(var/mob/living/L in GLOB.living_mob_list) if(is_servant_of_ratvar(L)) @@ -496,7 +493,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." textlist += "[unconverted_ais_exist] unconverted AIs exist!
" else textlist += "An unconverted AI exists!
" - if(scripture_states[SCRIPTURE_REVENANT]) + if(SSticker.scripture_states[SCRIPTURE_REVENANT]) var/inathneq_available = GLOB.clockwork_generals_invoked["inath-neq"] <= world.time var/sevtug_available = GLOB.clockwork_generals_invoked["sevtug"] <= world.time var/nezbere_available = GLOB.clockwork_generals_invoked["nezbere"] <= world.time @@ -508,9 +505,9 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." textlist += "Generals available: NONE
" else textlist += "Generals available: NONE
" - for(var/i in scripture_states) + for(var/i in SSticker.scripture_states) if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff - textlist += "[i] Scripture: [scripture_states[i] ? "UNLOCKED":"LOCKED"]
" + textlist += "[i] Scripture: [SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]
" desc = textlist.Join() ..() diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 48e1ff1957..9bb0d89e5c 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -207,10 +207,9 @@ Credit where due: text += "
The servants' objective was:
[CLOCKCULT_OBJECTIVE]" text += "
Ratvar's servants had [GLOB.clockwork_caches] Tinkerer's Caches." text += "
Construction Value(CV) was: [GLOB.clockwork_construction_value]" - var/list/scripture_states = scripture_unlock_check() - for(var/i in scripture_states) + for(var/i in SSticker.scripture_states) if(i != SCRIPTURE_DRIVER) - text += "
[i] scripture was: [scripture_states[i] ? "UN":""]LOCKED" + text += "
[i] scripture was: [SSticker.scripture_states[i] ? "UN":""]LOCKED" if(servants_of_ratvar.len) text += "
Ratvar's servants were:" for(var/datum/mind/M in servants_of_ratvar) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm index 914804185e..f2aac78a30 100644 --- a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm @@ -7,13 +7,17 @@ servants++ . = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE) //Drivers: always unlocked - .[SCRIPTURE_SCRIPT] = (servants >= SCRIPT_SERVANT_REQ && GLOB.clockwork_caches >= SCRIPT_CACHE_REQ) + .[SCRIPTURE_SCRIPT] = (SSticker.scripture_states[SCRIPTURE_SCRIPT] || \ + (servants >= SCRIPT_SERVANT_REQ && GLOB.clockwork_caches >= SCRIPT_CACHE_REQ)) //Script: SCRIPT_SERVANT_REQ or more non-brain servants and SCRIPT_CACHE_REQ or more clockwork caches - .[SCRIPTURE_APPLICATION] = (servants >= APPLICATION_SERVANT_REQ && GLOB.clockwork_caches >= APPLICATION_CACHE_REQ && GLOB.clockwork_construction_value >= APPLICATION_CV_REQ) + .[SCRIPTURE_APPLICATION] = (SSticker.scripture_states[SCRIPTURE_APPLICATION] || \ + (servants >= APPLICATION_SERVANT_REQ && GLOB.clockwork_caches >= APPLICATION_CACHE_REQ && GLOB.clockwork_construction_value >= APPLICATION_CV_REQ)) //Application: APPLICATION_SERVANT_REQ or more non-brain servants, APPLICATION_CACHE_REQ or more clockwork caches, and at least APPLICATION_CV_REQ CV - .[SCRIPTURE_REVENANT] = (servants >= REVENANT_SERVANT_REQ && GLOB.clockwork_caches >= REVENANT_CACHE_REQ && GLOB.clockwork_construction_value >= REVENANT_CV_REQ) + .[SCRIPTURE_REVENANT] = (SSticker.scripture_states[SCRIPTURE_REVENANT] || \ + (servants >= REVENANT_SERVANT_REQ && GLOB.clockwork_caches >= REVENANT_CACHE_REQ && GLOB.clockwork_construction_value >= REVENANT_CV_REQ)) //Revenant: REVENANT_SERVANT_REQ or more non-brain servants, REVENANT_CACHE_REQ or more clockwork caches, and at least REVENANT_CV_REQ CV - .[SCRIPTURE_JUDGEMENT] = (servants >= JUDGEMENT_SERVANT_REQ && GLOB.clockwork_caches >= JUDGEMENT_CACHE_REQ && GLOB.clockwork_construction_value >= JUDGEMENT_CV_REQ && !unconverted_ai_exists) + .[SCRIPTURE_JUDGEMENT] = (SSticker.scripture_states[SCRIPTURE_JUDGEMENT] || \ + (servants >= JUDGEMENT_SERVANT_REQ && GLOB.clockwork_caches >= JUDGEMENT_CACHE_REQ && GLOB.clockwork_construction_value >= JUDGEMENT_CV_REQ && !unconverted_ai_exists)) //Judgement: JUDGEMENT_SERVANT_REQ or more non-brain servants, JUDGEMENT_CACHE_REQ or more clockwork caches, at least JUDGEMENT_CV_REQ CV, and there are no living, non-servant ais //reports to servants when scripture is locked or unlocked @@ -21,7 +25,7 @@ . = scripture_unlock_check() for(var/i in .) if(.[i] != previous_states[i]) - hierophant_message("Hierophant Network: [i] Scripture has been [.[i] ? "un":""]locked.") + hierophant_message("Hierophant Network: [i] Scripture has been [.[i] ? "un":""]locked.") //maybe admins fucked with scripture states? update_slab_info() /proc/get_unconverted_ais() @@ -59,6 +63,3 @@ //changes construction value /proc/change_construction_value(amount) GLOB.clockwork_construction_value += amount - -/proc/can_recite_scripture(mob/living/L) - return (is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal() && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L)))) diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm index 72dba26bed..10da3c2a10 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm +++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm @@ -14,6 +14,7 @@ var/target_component_id //the target component ID to create, if any var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks var/speed_multiplier = 1 //multiples how fast this slab recites scripture + var/nonhuman_usable = FALSE //if the slab can be used by nonhumans, defaults to off var/produces_components = TRUE //if it produces components at all var/selected_scripture = SCRIPTURE_DRIVER var/recollecting = FALSE //if we're looking at fancy recollection @@ -32,9 +33,13 @@ no_cost = TRUE produces_components = FALSE +/obj/item/clockwork/slab/scarab + nonhuman_usable = TRUE + /obj/item/clockwork/slab/debug speed_multiplier = 0 no_cost = TRUE + nonhuman_usable = TRUE /obj/item/clockwork/slab/debug/attack_hand(mob/living/user) ..() @@ -44,6 +49,7 @@ /obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and proselytizer clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\ Hitting a slab, a Servant with a slab, or a cache will transfer this slab's components into the target, the target's slab, or the global cache, respectively." + nonhuman_usable = TRUE quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \ /datum/clockwork_scripture/create_object/tinkerers_cache) maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more @@ -100,6 +106,12 @@ slab_ability = null return ..() +/obj/item/clockwork/slab/ratvar_act() + if(GLOB.ratvar_awakens) + nonhuman_usable = TRUE + else + nonhuman_usable = initial(nonhuman_usable) + /obj/item/clockwork/slab/dropped(mob/user) . = ..() addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later @@ -126,7 +138,7 @@ production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown var/mob/living/L L = get_atom_on_turf(src, /mob/living) - if(istype(L) && can_recite_scripture(L)) + if(istype(L) && is_servant_of_ratvar(L) && (nonhuman_usable || ishuman(L))) var/component_to_generate = target_component_id if(!component_to_generate) component_to_generate = get_weighted_component_id(src) //more likely to generate components that we have less of @@ -256,7 +268,7 @@ if(busy) to_chat(user, "[src] refuses to work, displaying the message: \"[busy]!\"") return 0 - if(!can_recite_scripture(user)) + if(!nonhuman_usable && !ishuman(user)) to_chat(user, "[src] hums fitfully in your hands, but doesn't seem to do anything...") return 0 access_display(user) @@ -276,15 +288,14 @@ ui.open() /obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user) - if(!scripture || !user || !user.canUseTopic(src) || !can_recite_scripture(user)) + if(!scripture || !user || !user.canUseTopic(src) || (!nonhuman_usable && !ishuman(user))) return FALSE if(user.get_active_held_item() != src) to_chat(user, "You need to hold the slab in your active hand to recite scripture!") return FALSE var/initial_tier = initial(scripture.tier) if(initial_tier != SCRIPTURE_PERIPHERAL) - var/list/tiers_of_scripture = scripture_unlock_check() - if(!GLOB.ratvar_awakens && !no_cost && !tiers_of_scripture[initial_tier]) + if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier]) to_chat(user, "That scripture is not unlocked, and cannot be recited!") return FALSE var/datum/clockwork_scripture/scripture_to_recite = new scripture @@ -401,15 +412,27 @@ switch(selected_scripture) //display info based on selected scripture tier if(SCRIPTURE_DRIVER) - data["tier_info"] = "These scriptures are always unlocked." + data["tier_info"] = "These scriptures are permenantly unlocked." if(SCRIPTURE_SCRIPT) - data["tier_info"] = "These scriptures require at least [SCRIPT_SERVANT_REQ] Servants and [SCRIPT_CACHE_REQ] Tinkerer's Cache." + if(SSticker.scripture_states[SCRIPTURE_SCRIPT]) + data["tier_info"] = "These scriptures are permenantly unlocked." + else + data["tier_info"] = "These scriptures require at least [SCRIPT_SERVANT_REQ] Servants and [SCRIPT_CACHE_REQ] Tinkerer's Cache." if(SCRIPTURE_APPLICATION) - data["tier_info"] = "These scriptures require at least [APPLICATION_SERVANT_REQ] Servants, [APPLICATION_CACHE_REQ] Tinkerer's Caches, and [APPLICATION_CV_REQ]CV." + if(SSticker.scripture_states[SCRIPTURE_APPLICATION]) + data["tier_info"] = "These scriptures are permenantly unlocked." + else + data["tier_info"] = "These scriptures require at least [APPLICATION_SERVANT_REQ] Servants, [APPLICATION_CACHE_REQ] Tinkerer's Caches, and [APPLICATION_CV_REQ]CV." if(SCRIPTURE_REVENANT) - data["tier_info"] = "These scriptures require at least [REVENANT_SERVANT_REQ] Servants, [REVENANT_CACHE_REQ] Tinkerer's Caches, and [REVENANT_CV_REQ]CV." + if(SSticker.scripture_states[SCRIPTURE_REVENANT]) + data["tier_info"] = "These scriptures are permenantly unlocked." + else + data["tier_info"] = "These scriptures require at least [REVENANT_SERVANT_REQ] Servants, [REVENANT_CACHE_REQ] Tinkerer's Caches, and [REVENANT_CV_REQ]CV." if(SCRIPTURE_JUDGEMENT) - data["tier_info"] = "This scripture requires at least [JUDGEMENT_SERVANT_REQ] Servants, [JUDGEMENT_CACHE_REQ] Tinkerer's Caches, and [JUDGEMENT_CV_REQ]CV.
In addition, there may not be any active non-Servant AIs.
" + if(SSticker.scripture_states[SCRIPTURE_JUDGEMENT]) + data["tier_info"] = "This scripture is permenantly unlocked." + else + data["tier_info"] = "This scripture requires at least [JUDGEMENT_SERVANT_REQ] Servants, [JUDGEMENT_CACHE_REQ] Tinkerer's Caches, and [JUDGEMENT_CV_REQ]CV.
In addition, there may not be any active non-Servant AIs.
" data["selected"] = selected_scripture From 87ce1e1780e20be35c90be1995385969947825c7 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Sun, 11 Jun 2017 08:39:38 -0500 Subject: [PATCH 15/19] upstream-merge-28047 --- code/_onclick/hud/alert.dm | 1 + .../clock_helpers/scripture_checks.dm | 5 ++++- .../clock_cult/clock_items/clockwork_slab.dm | 20 ++++--------------- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 397eabeb22..1a817c90f5 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -362,6 +362,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." desc = "You shouldn't be seeing this description unless you're very fast. If you're very fast, good job!" icon_state = "no-servants-caches" + /obj/screen/alert/clockwork/scripture_reqs/Initialize() . = ..() START_PROCESSING(SSprocessing, src) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm index f2aac78a30..3862791f8c 100644 --- a/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/scripture_checks.dm @@ -25,7 +25,7 @@ . = scripture_unlock_check() for(var/i in .) if(.[i] != previous_states[i]) - hierophant_message("Hierophant Network: [i] Scripture has been [.[i] ? "un":""]locked.") //maybe admins fucked with scripture states? + hierophant_message("Hierophant Network: [i] Scripture has been [.[i] ? "un":""]locked.") update_slab_info() /proc/get_unconverted_ais() @@ -63,3 +63,6 @@ //changes construction value /proc/change_construction_value(amount) GLOB.clockwork_construction_value += amount + +/proc/can_recite_scripture(mob/living/L) + return (is_servant_of_ratvar(L) && L.stat == CONSCIOUS && L.can_speak_vocal() && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L)))) diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm index 10da3c2a10..4bdbf086d1 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm +++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm @@ -14,7 +14,6 @@ var/target_component_id //the target component ID to create, if any var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks var/speed_multiplier = 1 //multiples how fast this slab recites scripture - var/nonhuman_usable = FALSE //if the slab can be used by nonhumans, defaults to off var/produces_components = TRUE //if it produces components at all var/selected_scripture = SCRIPTURE_DRIVER var/recollecting = FALSE //if we're looking at fancy recollection @@ -33,13 +32,9 @@ no_cost = TRUE produces_components = FALSE -/obj/item/clockwork/slab/scarab - nonhuman_usable = TRUE - /obj/item/clockwork/slab/debug speed_multiplier = 0 no_cost = TRUE - nonhuman_usable = TRUE /obj/item/clockwork/slab/debug/attack_hand(mob/living/user) ..() @@ -49,7 +44,6 @@ /obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and proselytizer clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\ Hitting a slab, a Servant with a slab, or a cache will transfer this slab's components into the target, the target's slab, or the global cache, respectively." - nonhuman_usable = TRUE quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \ /datum/clockwork_scripture/create_object/tinkerers_cache) maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more @@ -106,12 +100,6 @@ slab_ability = null return ..() -/obj/item/clockwork/slab/ratvar_act() - if(GLOB.ratvar_awakens) - nonhuman_usable = TRUE - else - nonhuman_usable = initial(nonhuman_usable) - /obj/item/clockwork/slab/dropped(mob/user) . = ..() addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later @@ -138,7 +126,7 @@ production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown var/mob/living/L L = get_atom_on_turf(src, /mob/living) - if(istype(L) && is_servant_of_ratvar(L) && (nonhuman_usable || ishuman(L))) + if(istype(L) && can_recite_scripture(L)) var/component_to_generate = target_component_id if(!component_to_generate) component_to_generate = get_weighted_component_id(src) //more likely to generate components that we have less of @@ -268,7 +256,7 @@ if(busy) to_chat(user, "[src] refuses to work, displaying the message: \"[busy]!\"") return 0 - if(!nonhuman_usable && !ishuman(user)) + if(!can_recite_scripture(user)) to_chat(user, "[src] hums fitfully in your hands, but doesn't seem to do anything...") return 0 access_display(user) @@ -288,7 +276,7 @@ ui.open() /obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user) - if(!scripture || !user || !user.canUseTopic(src) || (!nonhuman_usable && !ishuman(user))) + if(!scripture || !user || !user.canUseTopic(src) || !can_recite_scripture(user)) return FALSE if(user.get_active_held_item() != src) to_chat(user, "You need to hold the slab in your active hand to recite scripture!") @@ -412,7 +400,7 @@ switch(selected_scripture) //display info based on selected scripture tier if(SCRIPTURE_DRIVER) - data["tier_info"] = "These scriptures are permenantly unlocked." + data["tier_info"] = "These scriptures are always unlocked." if(SCRIPTURE_SCRIPT) if(SSticker.scripture_states[SCRIPTURE_SCRIPT]) data["tier_info"] = "These scriptures are permenantly unlocked." From 55d30f865ba7d2af86788ab909c0d6e229b0cb42 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Mon, 12 Jun 2017 12:20:07 -0500 Subject: [PATCH 16/19] upstream-merge-28062 --- code/__DEFINES/clockcult.dm | 6 +- code/__DEFINES/status_effects.dm | 2 + code/datums/status_effects/neutral.dm | 26 ++ .../clock_cult/clock_effects/clock_sigils.dm | 2 +- .../clock_helpers/fabrication_helpers.dm | 372 ++++++++++++++++++ .../clock_items/clock_components.dm | 15 +- .../clock_cult/clock_items/clockwork_slab.dm | 6 +- ..._proselytizer.dm => replica_fabricator.dm} | 179 +++++---- .../clock_scriptures/scripture_revenant.dm | 4 +- .../clock_scriptures/scripture_scripts.dm | 20 +- .../gamemodes/clock_cult/clock_structure.dm | 2 +- .../clock_structures/clock_shells.dm | 2 +- .../ratvar_the_clockwork_justicar.dm | 6 +- .../objects/items/weapons/storage/toolbox.dm | 14 +- .../crates_lockers/closets/secure/security.dm | 1 + code/game/objects/structures/grille.dm | 1 + code/game/objects/structures/lattice.dm | 2 +- .../mining/lavaland/necropolis_chests.dm | 4 +- .../mob/living/silicon/robot/robot_modules.dm | 6 +- .../friendly/drone/extra_drone_types.dm | 62 ++- .../hostile/mining_mobs/basilisk.dm | 3 + .../hostile/mining_mobs/goliath.dm | 4 + .../hostile/mining_mobs/hivelord.dm | 4 + .../hostile/mining_mobs/mining_mobs.dm | 1 + .../hostile/mining_mobs/necropolis_tendril.dm | 6 +- .../guns/energy/kinetic_accelerator.dm | 54 ++- icons/mob/actions.dmi | Bin 194017 -> 194016 bytes icons/obj/clockwork_objects.dmi | Bin 120392 -> 120386 bytes tgstation.dme | 4 +- 29 files changed, 667 insertions(+), 141 deletions(-) create mode 100644 code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm rename code/game/gamemodes/clock_cult/clock_items/{clockwork_proselytizer.dm => replica_fabricator.dm} (54%) diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm index acc0cdc9ab..8b38ca12e5 100644 --- a/code/__DEFINES/clockcult.dm +++ b/code/__DEFINES/clockcult.dm @@ -58,7 +58,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us //clockcult power defines #define MIN_CLOCKCULT_POWER 25 //the minimum amount of power clockcult machines will handle gracefully -#define CLOCKCULT_POWER_UNIT (MIN_CLOCKCULT_POWER*100) //standard power amount for clockwork proselytizer costs +#define CLOCKCULT_POWER_UNIT (MIN_CLOCKCULT_POWER*100) //standard power amount for replica fabricator costs #define POWER_STANDARD (CLOCKCULT_POWER_UNIT*0.2) //how much power is in anything else; doesn't matter as much as the following @@ -76,7 +76,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us #define POWER_PLASTEEL (CLOCKCULT_POWER_UNIT*0.05) //how much power is in one sheet of plasteel -#define RATVAR_POWER_CHECK "ratvar?" //when passed into can_use_power(), converts it into a check for if ratvar has woken/the proselytizer is debug +#define RATVAR_POWER_CHECK "ratvar?" //when passed into can_use_power(), converts it into a check for if ratvar has woken/the fabricator is debug //Ark defines #define GATEWAY_SUMMON_RATE 1 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 1 per tick @@ -99,7 +99,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us #define SIGIL_ACCESS_RANGE 2 //range at which transmission sigils can access power -#define PROSELYTIZER_REPAIR_PER_TICK 4 //how much a proselytizer repairs each tick, and also how many deciseconds each tick is +#define fabricator_REPAIR_PER_TICK 4 //how much a fabricator repairs each tick, and also how many deciseconds each tick is #define OCULAR_WARDEN_EXCLUSION_RANGE 3 //the range at which ocular wardens cannot be placed near other ocular wardens diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 6735ef95e9..cf7acfc543 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -49,3 +49,5 @@ #define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark #define STATUS_EFFECT_CRUSHERDAMAGETRACKING /datum/status_effect/crusher_damage //tracks total kinetic crusher damage on a target + +#define STATUS_EFFECT_SYPHONMARK /datum/status_effect/syphon_mark //tracks kills for the KA death syphon module diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 0946408323..ae0301762e 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -16,3 +16,29 @@ status_type = STATUS_EFFECT_UNIQUE alert_type = null var/total_damage = 0 + +/datum/status_effect/syphon_mark + id = "syphon_mark" + duration = 50 + status_type = STATUS_EFFECT_MULTIPLE + alert_type = null + on_remove_on_mob_delete = TRUE + var/obj/item/borg/upgrade/modkit/bounty/reward_target + +/datum/status_effect/syphon_mark/on_apply() + if(owner.stat == DEAD) + return FALSE + return ..() + +/datum/status_effect/syphon_mark/proc/get_kill() + if(reward_target) + reward_target.get_kill(owner) + +/datum/status_effect/syphon_mark/tick() + if(owner.stat == DEAD) + get_kill() + qdel(src) + +/datum/status_effect/syphon_mark/on_remove() + get_kill() + . = ..() diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm index 7d8c3eb1f9..79dd366789 100644 --- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm +++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm @@ -204,7 +204,7 @@ else if(!GLOB.ratvar_awakens) to_chat(user, "Hitting the [sigil_name] with brass sheets will convert them to power at a rate of 1 brass sheet to [POWER_FLOOR]W power.") if(!GLOB.ratvar_awakens) - to_chat(user, "You can recharge Clockwork Proselytizers from the [sigil_name].") + to_chat(user, "You can recharge Replica Fabricators from the [sigil_name].") /obj/effect/clockwork/sigil/transmission/attackby(obj/item/I, mob/living/user, params) if(is_servant_of_ratvar(user) && istype(I, /obj/item/stack/tile/brass) && !GLOB.ratvar_awakens) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm new file mode 100644 index 0000000000..1dd976d198 --- /dev/null +++ b/code/game/gamemodes/clock_cult/clock_helpers/fabrication_helpers.dm @@ -0,0 +1,372 @@ +//For the clockwork fabricator, this proc exists to make it easy to customize what the fabricator does when hitting something. + +//if a valid target, returns an associated list in this format; +//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "power_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE) +//otherwise, return literally any non-list thing but preferably FALSE +//returning TRUE won't produce the "cannot be fabricated" message and will still prevent fabrication + +/atom/proc/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/atom/proc/consume_visual(obj/item/clockwork/replica_fabricator/fabricator, power_amount) + if(fabricator.can_use_power(power_amount)) + var/obj/effect/temp_visual/ratvar/beam/itemconsume/B = new /obj/effect/temp_visual/ratvar/beam/itemconsume(get_turf(src)) + B.pixel_x = pixel_x + B.pixel_y = pixel_y + +//Turf conversion +/turf/closed/wall/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //four sheets of metal + return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 4), "spawn_dir" = SOUTH) + +/turf/closed/wall/mineral/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal + return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH) + +/turf/closed/wall/mineral/iron/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal, five rods + return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2) - (POWER_ROD * 5), "spawn_dir" = SOUTH) + +/turf/closed/wall/mineral/cult/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //no metal + return list("operation_time" = 80, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = SOUTH) + +/turf/closed/wall/shuttle/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal + return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH) + +/turf/closed/wall/r_wall/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/turf/closed/wall/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = -POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH) + +/turf/open/floor/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(floor_tile == /obj/item/stack/tile/plasteel) + new floor_tile(src) + make_plating() + playsound(src, 'sound/items/Crowbar.ogg', 10, 1) //clink + return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = POWER_FLOOR, "spawn_dir" = SOUTH) + +/turf/open/floor/plating/asteroid/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/turf/open/floor/plating/ashplanet/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/turf/open/floor/plating/lava/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/turf/open/floor/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(locate(/obj/structure/table) in src) + return FALSE + if(locate(/obj/structure/falsewall) in contents) + to_chat(user, "There is a false wall in the way, preventing you from fabricating a clockwork wall on [src].") + return + if(is_blocked_turf(src, TRUE)) + to_chat(user, "Something is in the way, preventing you from fabricating a clockwork wall on [src].") + return TRUE + var/operation_time = 100 + if(!GLOB.ratvar_awakens && fabricator.speed_multiplier > 0) //if ratvar isn't awake, this always takes 10 seconds + operation_time /= fabricator.speed_multiplier + return list("operation_time" = operation_time, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH) + +//False wall conversion +/obj/structure/falsewall/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/cost = POWER_WALL_MINUS_FLOOR + if(ispath(mineral, /obj/item/stack/sheet/metal)) + cost -= (POWER_METAL * (2 + mineral_amount)) //four sheets of metal, plus an assumption that the girder is also two + else + cost -= (POWER_METAL * 2) //anything that doesn't use metal just has the girder + return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = cost, "spawn_dir" = SOUTH) + +/obj/structure/falsewall/iron/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal, two rods; special assumption + return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = POWER_WALL_MINUS_FLOOR - (POWER_METAL * 2) - (POWER_ROD * 2), "spawn_dir" = SOUTH) + +/obj/structure/falsewall/reinforced/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/obj/structure/falsewall/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Metal conversion +/obj/item/stack/tile/plasteel/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(source) + return FALSE + var/amount_temp = get_amount() + var/no_delete = FALSE + if(amount_temp < 2) + to_chat(user, "You need at least 2 floor tiles to convert into power.") + return TRUE + if(IsOdd(amount_temp)) + amount_temp-- + no_delete = TRUE + use(amount_temp) + amount_temp *= 12.5 //each tile is 12.5 power so this is 2 tiles to 25 power + consume_visual(fabricator, amount_temp) + return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = -amount_temp, "spawn_dir" = SOUTH, "no_target_deletion" = no_delete) + +/obj/item/stack/rods/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(source) + return FALSE + var/power_amount = -(amount*POWER_ROD) + consume_visual(fabricator, power_amount) + return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH) + +/obj/item/stack/sheet/metal/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(source) + return FALSE + var/power_amount = -(amount*POWER_METAL) + consume_visual(fabricator, power_amount) + return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH) + +/obj/item/stack/sheet/plasteel/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(source) + return FALSE + var/power_amount = -(amount*POWER_PLASTEEL) + consume_visual(fabricator, power_amount) + return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH) + +//Brass directly to power +/obj/item/stack/tile/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + if(source) + return FALSE + var/power_amount = -(amount*POWER_FLOOR) + consume_visual(fabricator, power_amount) + return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH) + +//Airlock conversion +/obj/machinery/door/airlock/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/doortype = /obj/machinery/door/airlock/clockwork + if(glass) + doortype = /obj/machinery/door/airlock/clockwork/brass + return list("operation_time" = 60, "new_obj_type" = doortype, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = dir) + +/obj/machinery/door/airlock/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Table conversion +/obj/structure/table/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/fabrication_cost = POWER_STANDARD + if(framestack == /obj/item/stack/rods) + fabrication_cost -= POWER_ROD*framestackamount + else if(framestack == /obj/item/stack/tile/brass) + fabrication_cost -= POWER_FLOOR*framestackamount + if(buildstack == /obj/item/stack/sheet/metal) + fabrication_cost -= POWER_METAL*buildstackamount + else if(buildstack == /obj/item/stack/sheet/plasteel) + fabrication_cost -= POWER_PLASTEEL*buildstackamount + return list("operation_time" = 20, "new_obj_type" = /obj/structure/table/reinforced/brass, "power_cost" = fabrication_cost, "spawn_dir" = SOUTH) + +/obj/structure/table/reinforced/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +/obj/structure/table_frame/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/fabrication_cost = POWER_FLOOR + if(framestack == /obj/item/stack/rods) + fabrication_cost -= POWER_ROD*framestackamount + else if(framestack == /obj/item/stack/tile/brass) + fabrication_cost -= POWER_FLOOR*framestackamount + return list("operation_time" = 10, "new_obj_type" = /obj/structure/table_frame/brass, "power_cost" = fabrication_cost, "spawn_dir" = SOUTH) + +/obj/structure/table_frame/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Window conversion +/obj/structure/window/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/windowtype = /obj/structure/window/reinforced/clockwork + var/new_dir = TRUE + var/fabrication_time = 15 + var/fabrication_cost = POWER_FLOOR + if(fulltile) + windowtype = /obj/structure/window/reinforced/clockwork/fulltile + new_dir = FALSE + fabrication_time = 30 + fabrication_cost = POWER_STANDARD + if(reinf) + fabrication_cost -= POWER_ROD + if(reinf) + fabrication_cost -= POWER_ROD + for(var/obj/structure/grille/G in get_turf(src)) + INVOKE_ASYNC(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricate, G, user) + return list("operation_time" = fabrication_time, "new_obj_type" = windowtype, "power_cost" = fabrication_cost, "spawn_dir" = dir, "dir_in_new" = new_dir) + +/obj/structure/window/reinforced/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Windoor conversion +/obj/machinery/door/window/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "power_cost" = POWER_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE) + +/obj/machinery/door/window/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Grille conversion +/obj/structure/grille/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/grilletype = /obj/structure/grille/ratvar + var/fabrication_time = 15 + if(broken) + grilletype = /obj/structure/grille/ratvar/broken + fabrication_time = 5 + return list("operation_time" = fabrication_time, "new_obj_type" = grilletype, "power_cost" = 0, "spawn_dir" = dir) + +/obj/structure/grille/ratvar/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Lattice conversion +/obj/structure/lattice/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE) + +/obj/structure/lattice/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + ratvar_act() //just in case we're the wrong type for some reason?? + return FALSE + +/obj/structure/lattice/catwalk/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/catwalk/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE) + +/obj/structure/lattice/catwalk/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + return FALSE + +//Girder conversion +/obj/structure/girder/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + var/fabrication_cost = POWER_GEAR - (POWER_METAL * 2) + if(state == GIRDER_REINF_STRUTS || state == GIRDER_REINF) + fabrication_cost -= POWER_PLASTEEL + return list("operation_time" = 20, "new_obj_type" = /obj/structure/destructible/clockwork/wall_gear, "power_cost" = fabrication_cost, "spawn_dir" = SOUTH) + +//Hitting a clockwork structure will try to repair it. +/obj/structure/destructible/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + . = TRUE + var/list/repair_values = list() + if(!fabricator.fabricator_repair_checks(repair_values, src, user)) + return + user.visible_message("[user]'s [fabricator.name] starts covering [src] in glowing orange energy...", \ + "You start repairing [src]...") + fabricator.repairing = src + while(fabricator && user && src) + if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \ + extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE))) + break + obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity) + fabricator.modify_stored_power(-repair_values["power_required"]) + playsound(src, 'sound/machines/click.ogg', 50, 1) + + if(fabricator) + fabricator.repairing = null + if(user) + user.visible_message("[user]'s [fabricator.name] stops covering [src] with glowing orange energy.", \ + "You finish repairing [src]. It is now at [obj_integrity]/[max_integrity] integrity.") + +//Hitting a sigil of transmission will try to charge from it. +/obj/effect/clockwork/sigil/transmission/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + . = TRUE + var/list/charge_values = list() + if(!fabricator.sigil_charge_checks(charge_values, src, user)) + return + user.visible_message("[user]'s [fabricator.name] starts draining glowing orange energy from [src]...", \ + "You start recharging your [fabricator.name]...") + fabricator.recharging = src + while(fabricator && user && src) + if(!do_after(user, 10, target = src, extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/sigil_charge_checks, charge_values, src, user, TRUE))) + break + modify_charge(charge_values["power_gain"]) + fabricator.modify_stored_power(charge_values["power_gain"]) + playsound(src, 'sound/effects/light_flicker.ogg', charge_values["power_gain"] * 0.1, 1) + + if(fabricator) + fabricator.recharging = null + if(user) + user.visible_message("[user]'s [fabricator.name] stops draining glowing orange energy from [src].", \ + "You finish recharging your [fabricator.name]. It now contains [fabricator.get_power()]W/[fabricator.get_max_power()]W power.") + +//Fabricator mob heal proc, to avoid as much copypaste as possible. +/mob/living/proc/fabricator_heal(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator) + var/list/repair_values = list() + if(!fabricator.fabricator_repair_checks(repair_values, src, user)) + return + user.visible_message("[user]'s [fabricator.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...", \ + "You start repairin[src == user ? "g yourself" : "g [src]"]...") + fabricator.repairing = src + while(fabricator && user && src) + if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \ + extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE))) + break + fabricator_heal_tick(repair_values["healing_for_cycle"]) + fabricator.modify_stored_power(-repair_values["power_required"]) + playsound(src, 'sound/machines/click.ogg', 50, 1) + + if(fabricator) + fabricator.repairing = null + + return TRUE + +/mob/living/proc/fabricator_heal_tick(amount) + var/static/list/damage_heal_order = list(BRUTE, BURN, TOX, OXY) + heal_ordered_damage(amount, damage_heal_order) + +/mob/living/simple_animal/fabricator_heal_tick(amount) + adjustHealth(-amount) + +//Hitting a ratvar'd silicon will also try to repair it. +/mob/living/silicon/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + . = TRUE + if(health == maxHealth) //if we're at maximum health, replace the turf under us + return FALSE + else if(fabricator_heal(user, fabricator) && user) + user.visible_message("[user]'s [fabricator.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.", \ + "You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at [abs(HEALTH_THRESHOLD_DEAD - health)]/[abs(HEALTH_THRESHOLD_DEAD - maxHealth)] health.") + +//Same with clockwork mobs. +/mob/living/simple_animal/hostile/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + . = TRUE + if(health == maxHealth) //if we're at maximum health, replace the turf under us + return FALSE + else if(fabricator_heal(user, fabricator) && user) + user.visible_message("[user]'s [fabricator.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.", \ + "You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at [health]/[maxHealth] health.") + +//Cogscarabs get special interaction because they're drones and have innate self-heals/revives. +/mob/living/simple_animal/drone/cogscarab/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) + . = TRUE + if(stat == DEAD) + try_reactivate(user) //if we're dead, try to repair us + return + if(health == maxHealth) + return FALSE + else if(!(flags & GODMODE)) + user.visible_message("[user]'s [fabricator.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...", \ + "You start repairin[src == user ? "g yourself" : "g [src]"]...") + fabricator.repairing = src + if(do_after(user, (maxHealth - health)*2, target=src)) + adjustHealth(-maxHealth) + user.visible_message("[user]'s [fabricator.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.", \ + "You finish repairin[src == user ? "g yourself" : "g [src]"].") + if(fabricator) + fabricator.repairing = null + +//Convert shards and gear bits directly to power +/obj/item/clockwork/alloy_shards/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount) + if(!power_amount) + power_amount = -POWER_STANDARD + consume_visual(fabricator, power_amount) + if(!silent) //looper no looping + for(var/obj/item/clockwork/alloy_shards/S in get_turf(src)) //convert all other shards in the turf if we can + if(S == src) + continue //we want the shards to be fabricated after the main shard, thus this delay + addtimer(CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricate, S, user, TRUE), 0) + return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH) + +/obj/item/clockwork/alloy_shards/medium/gear_bit/large/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount) + if(!power_amount) + power_amount = -(CLOCKCULT_POWER_UNIT*0.08) + return ..() + +/obj/item/clockwork/alloy_shards/large/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount) + if(!power_amount) + power_amount = -(CLOCKCULT_POWER_UNIT*0.06) + return ..() + +/obj/item/clockwork/alloy_shards/medium/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount) + if(!power_amount) + power_amount = -(CLOCKCULT_POWER_UNIT*0.04) + return ..() + +/obj/item/clockwork/alloy_shards/small/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount) + if(!power_amount) + power_amount = -(CLOCKCULT_POWER_UNIT*0.02) + return ..() diff --git a/code/game/gamemodes/clock_cult/clock_items/clock_components.dm b/code/game/gamemodes/clock_cult/clock_items/clock_components.dm index f64b361ac1..7550aea74f 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clock_components.dm +++ b/code/game/gamemodes/clock_cult/clock_items/clock_components.dm @@ -153,11 +153,11 @@ icon_state = "obelisk_prism" w_class = WEIGHT_CLASS_NORMAL -//Shards of Alloy, suitable only for proselytization. +//Shards of Alloy, suitable only as a source of power for a replica fabricator. /obj/item/clockwork/alloy_shards name = "replicant alloy shards" desc = "Broken shards of some oddly malleable metal. They occasionally move and seem to glow." - clockwork_desc = "Broken shards of replicant alloy. Can be proselytized for additional power." + clockwork_desc = "Broken shards of replicant alloy." icon_state = "alloy_shards" resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF var/randomsinglesprite = FALSE @@ -172,10 +172,15 @@ pixel_x = rand(-sprite_shift, sprite_shift) pixel_y = rand(-sprite_shift, sprite_shift) +/obj/item/clockwork/alloy_shards/examine(mob/user) + ..() + if(is_servant_of_ratvar(user) || isobserver(user)) + to_chat(user, "Can be consumed by a replica fabricator as a source of power.") + /obj/item/clockwork/alloy_shards/proc/replace_name_desc() name = "replicant alloy shard" desc = "A broken shard of some oddly malleable metal. It occasionally moves and seems to glow." - clockwork_desc = "A broken shard of replicant alloy. Can be proselytized for additional power." + clockwork_desc = "A broken shard of replicant alloy." /obj/item/clockwork/alloy_shards/large w_class = WEIGHT_CLASS_TINY @@ -197,7 +202,7 @@ /obj/item/clockwork/alloy_shards/medium/gear_bit/replace_name_desc() name = "gear bit" desc = "A broken chunk of a gear. You want it." - clockwork_desc = "A broken chunk of a gear. Can be proselytized for additional power." + clockwork_desc = "A broken chunk of a gear." /obj/item/clockwork/alloy_shards/medium/gear_bit/large //gives more power @@ -215,5 +220,5 @@ /obj/item/clockwork/alloy_shards/pinion_lock name = "pinion lock" desc = "A dented and scratched gear. It's very heavy." - clockwork_desc = "A broken gear lock for pinion airlocks. Can be proselytized for additional power." + clockwork_desc = "A broken gear lock for pinion airlocks" icon_state = "pinion_lock" diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm index 4bdbf086d1..38a2cdadc0 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm +++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_slab.dm @@ -41,7 +41,7 @@ if(!is_servant_of_ratvar(user)) add_servant_of_ratvar(user) -/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and proselytizer +/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and fabricator clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\ Hitting a slab, a Servant with a slab, or a cache will transfer this slab's components into the target, the target's slab, or the global cache, respectively." quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \ @@ -49,7 +49,7 @@ maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more actions_types = list() -/obj/item/clockwork/slab/cyborg/engineer //five scriptures, plus a proselytizer +/obj/item/clockwork/slab/cyborg/engineer //five scriptures, plus a fabricator quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/cogscarab, \ /datum/clockwork_scripture/create_object/soul_vessel, /datum/clockwork_scripture/create_object/sigil_of_transmission, /datum/clockwork_scripture/create_object/interdiction_lens) @@ -65,7 +65,7 @@ quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \ /datum/clockwork_scripture/channeled/volt_void/cyborg) -/obj/item/clockwork/slab/cyborg/janitor //five scriptures, plus a proselytizer +/obj/item/clockwork/slab/cyborg/janitor //five scriptures, plus a fabricator quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \ /datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor, /datum/clockwork_scripture/create_object/tinkerers_daemon) diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm b/code/game/gamemodes/clock_cult/clock_items/replica_fabricator.dm similarity index 54% rename from code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm rename to code/game/gamemodes/clock_cult/clock_items/replica_fabricator.dm index aa174adcd8..788d581810 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm +++ b/code/game/gamemodes/clock_cult/clock_items/replica_fabricator.dm @@ -1,51 +1,48 @@ -//Clockwork proselytizer: Converts applicable objects to Ratvarian variants. -/obj/item/clockwork/clockwork_proselytizer - name = "clockwork proselytizer" +//Replica Fabricator: Converts applicable objects to Ratvarian variants. +/obj/item/clockwork/replica_fabricator + name = "replica fabricator" desc = "An odd, L-shaped device that hums with energy." clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires power to function." - icon_state = "clockwork_proselytizer" + icon_state = "replica_fabricator" w_class = WEIGHT_CLASS_NORMAL force = 5 flags = NOBLUDGEON var/stored_power = 0 //Requires power to function var/max_power = CLOCKCULT_POWER_UNIT * 10 var/uses_power = TRUE - var/metal_to_power = FALSE var/repairing = null //what we're currently repairing, if anything var/obj/effect/clockwork/sigil/transmission/recharging = null //the sigil we're charging from, if any - var/speed_multiplier = 1 //how fast this proselytizer works + var/speed_multiplier = 1 //how fast this fabricator works var/charge_rate = MIN_CLOCKCULT_POWER //how much power we gain every two seconds var/charge_delay = 2 //how many proccess ticks remain before we can start to charge -/obj/item/clockwork/clockwork_proselytizer/preloaded +/obj/item/clockwork/replica_fabricator/preloaded stored_power = POWER_WALL_MINUS_FLOOR+POWER_WALL_TOTAL -/obj/item/clockwork/clockwork_proselytizer/scarab - name = "scarab proselytizer" - clockwork_desc = "A cogscarab's internal proselytizer. It can only be successfully used by a cogscarab and requires power to function." - metal_to_power = TRUE +/obj/item/clockwork/replica_fabricator/scarab + name = "scarab fabricator" + clockwork_desc = "A cogscarab's internal fabricator. It can only be successfully used by a cogscarab and requires power to function." item_state = "nothing" w_class = WEIGHT_CLASS_TINY speed_multiplier = 0.5 charge_rate = MIN_CLOCKCULT_POWER * 2 var/debug = FALSE -/obj/item/clockwork/clockwork_proselytizer/scarab/proselytize(atom/target, mob/living/user) +/obj/item/clockwork/replica_fabricator/scarab/fabricate(atom/target, mob/living/user) if(!debug && !isdrone(user)) return 0 return ..() -/obj/item/clockwork/clockwork_proselytizer/scarab/debug - clockwork_desc = "A cogscarab's internal proselytizer. It can convert nearly any object into a Ratvarian variant." +/obj/item/clockwork/replica_fabricator/scarab/debug + clockwork_desc = "A cogscarab's internal fabricator. It can convert nearly any object into a Ratvarian variant." uses_power = FALSE debug = TRUE -/obj/item/clockwork/clockwork_proselytizer/cyborg - name = "cyborg proselytizer" - clockwork_desc = "A cyborg's internal proselytizer. It is capable of using the cyborg's power in addition to stored power." - metal_to_power = TRUE +/obj/item/clockwork/replica_fabricator/cyborg + name = "cyborg fabricator" + clockwork_desc = "A cyborg's internal fabricator. It is capable of using the cyborg's power in addition to stored power." -/obj/item/clockwork/clockwork_proselytizer/cyborg/get_power() //returns power and cyborg's power +/obj/item/clockwork/replica_fabricator/cyborg/get_power() //returns power and cyborg's power var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living) var/borg_power = 0 var/current_charge = 0 @@ -56,14 +53,14 @@ borg_power += MIN_CLOCKCULT_POWER return ..() + borg_power -/obj/item/clockwork/clockwork_proselytizer/cyborg/get_max_power() +/obj/item/clockwork/replica_fabricator/cyborg/get_max_power() var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living) var/cell_maxcharge = 0 if(istype(R) && R.cell) cell_maxcharge = R.cell.maxcharge return ..() + cell_maxcharge -/obj/item/clockwork/clockwork_proselytizer/cyborg/can_use_power(amount) +/obj/item/clockwork/replica_fabricator/cyborg/can_use_power(amount) if(amount != RATVAR_POWER_CHECK) var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living) var/current_charge = 0 @@ -76,7 +73,7 @@ return FALSE . = ..() -/obj/item/clockwork/clockwork_proselytizer/cyborg/modify_stored_power(amount) +/obj/item/clockwork/replica_fabricator/cyborg/modify_stored_power(amount) var/mob/living/silicon/robot/R = get_atom_on_turf(src, /mob/living) if(istype(R) && R.cell && amount) if(amount < 0) @@ -89,15 +86,15 @@ amount -= MIN_CLOCKCULT_POWER . = ..() -/obj/item/clockwork/clockwork_proselytizer/Initialize() +/obj/item/clockwork/replica_fabricator/Initialize() . = ..() START_PROCESSING(SSobj, src) -/obj/item/clockwork/clockwork_proselytizer/Destroy() +/obj/item/clockwork/replica_fabricator/Destroy() STOP_PROCESSING(SSobj, src) return ..() -/obj/item/clockwork/clockwork_proselytizer/process() +/obj/item/clockwork/replica_fabricator/process() if(!charge_rate) return var/mob/living/L = get_atom_on_turf(src, /mob/living) @@ -106,14 +103,14 @@ charge_delay-- return modify_stored_power(charge_rate) - for(var/obj/item/clockwork/clockwork_proselytizer/S in L.GetAllContents()) //no multiple proselytizers + for(var/obj/item/clockwork/replica_fabricator/S in L.GetAllContents()) //no multiple fabricators if(S == src) continue S.charge_delay = 2 else charge_delay = 2 -/obj/item/clockwork/clockwork_proselytizer/ratvar_act() +/obj/item/clockwork/replica_fabricator/ratvar_act() if(GLOB.nezbere_invoked) charge_rate = 1250 else @@ -125,21 +122,19 @@ uses_power = initial(uses_power) speed_multiplier = initial(speed_multiplier) -/obj/item/clockwork/clockwork_proselytizer/examine(mob/living/user) +/obj/item/clockwork/replica_fabricator/examine(mob/living/user) ..() if(is_servant_of_ratvar(user) || isobserver(user)) - to_chat(user, "Can be used to convert walls, floors, windows, airlocks, and a variety of other objects to clockwork variants.") - to_chat(user, "Can also form some objects into Brass sheets, as well as reform Clockwork Walls into Clockwork Floors, and vice versa.") + to_chat(user, "Can be used to replace walls, floors, tables, windows, windoors, and airlocks with Clockwork variants.") + to_chat(user, "Can construct Clockwork Walls on Clockwork Floors and deconstruct Clockwork Walls to Clockwork Floors.") if(uses_power) - if(metal_to_power) - to_chat(user, "It can convert rods, metal, plasteel, and brass to power at rates of 1:[POWER_ROD]W, 1:[POWER_METAL]W, \ - 1:[POWER_PLASTEEL]W, and 1:[POWER_FLOOR]W, respectively.") - else - to_chat(user, "It can convert brass to power at a rate of 1:[POWER_FLOOR]W.") - to_chat(user, "It is storing [get_power()]W/[get_max_power()]W of power, and is gaining [charge_rate*0.5]W of power per second.") + to_chat(user, "It can consume floor tiles, rods, metal, and plasteel for power at rates of 2:[POWER_ROD]W, 1:[POWER_ROD]W, 1:[POWER_METAL]W, \ + and 1:[POWER_PLASTEEL]W, respectively.") + to_chat(user, "It can also consume brass sheets for power at a rate of 1:[POWER_FLOOR]W.") + to_chat(user, "It is storing [get_power()]W/[get_max_power()]W of power[charge_rate ? ", and is gaining [charge_rate*0.5]W of power per second":""].") to_chat(user, "Use it in-hand to produce 5 brass sheets at a cost of [POWER_WALL_TOTAL]W power.") -/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user) +/obj/item/clockwork/replica_fabricator/attack_self(mob/living/user) if(is_servant_of_ratvar(user)) if(uses_power) if(!can_use_power(POWER_WALL_TOTAL)) @@ -148,24 +143,24 @@ modify_stored_power(-POWER_WALL_TOTAL) playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) new/obj/item/stack/tile/brass(user.loc, 5) - to_chat(user, "You user [stored_power ? "some":"all"] of [src]'s power to produce some brass sheets. It now stores [get_power()]W/[get_max_power()]W of power.") + to_chat(user, "You use [stored_power ? "some":"all"] of [src]'s power to produce 5 brass sheets. It now stores [get_power()]W/[get_max_power()]W of power.") -/obj/item/clockwork/clockwork_proselytizer/pre_attackby(atom/target, mob/living/user, params) +/obj/item/clockwork/replica_fabricator/pre_attackby(atom/target, mob/living/user, params) if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/weapon/storage)) return TRUE - return proselytize(target, user) + return fabricate(target, user) -/obj/item/clockwork/clockwork_proselytizer/proc/get_power() +/obj/item/clockwork/replica_fabricator/proc/get_power() return stored_power -/obj/item/clockwork/clockwork_proselytizer/proc/get_max_power() +/obj/item/clockwork/replica_fabricator/proc/get_max_power() return max_power -/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_power(amount) +/obj/item/clockwork/replica_fabricator/proc/modify_stored_power(amount) stored_power = Clamp(stored_power + amount, 0, max_power) return TRUE -/obj/item/clockwork/clockwork_proselytizer/proc/can_use_power(amount) +/obj/item/clockwork/replica_fabricator/proc/can_use_power(amount) if(amount == RATVAR_POWER_CHECK) if(GLOB.ratvar_awakens || !uses_power) return TRUE @@ -178,7 +173,7 @@ return TRUE //A note here; return values are for if we CAN BE PUT ON A TABLE, not IF WE ARE SUCCESSFUL, unless no_table_check is TRUE -/obj/item/clockwork/clockwork_proselytizer/proc/proselytize(atom/target, mob/living/user, silent, no_table_check) +/obj/item/clockwork/replica_fabricator/proc/fabricate(atom/target, mob/living/user, silent, no_table_check) if(!target || !user) return FALSE if(repairing) @@ -189,59 +184,77 @@ if(!silent) to_chat(user, "You are currently recharging [src] from the [recharging.sigil_name]!") return FALSE - var/list/proselytize_values = target.proselytize_vals(user, src, silent) //relevant values for proselytizing stuff, given as an associated list - if(!islist(proselytize_values)) - if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason - if(!isturf(target)) //otherwise, if we didn't get TRUE and the original target wasn't a turf, try to proselytize the turf - return proselytize(get_turf(target), user, no_table_check) + var/list/fabrication_values = target.fabrication_vals(user, src, silent) //relevant values for fabricating stuff, given as an associated list + if(!islist(fabrication_values)) + if(fabrication_values != TRUE) //if we get true, fail, but don't send a message for whatever reason + if(!isturf(target)) //otherwise, if we didn't get TRUE and the original target wasn't a turf, try to fabricate the turf + return fabricate(get_turf(target), user, no_table_check) if(!silent) - to_chat(user, "[target] cannot be proselytized!") + to_chat(user, "[target] cannot be fabricated!") if(!no_table_check) return TRUE return FALSE if(can_use_power(RATVAR_POWER_CHECK)) - proselytize_values["power_cost"] = 0 + fabrication_values["power_cost"] = 0 var/turf/Y = get_turf(user) if(!Y || (Y.z != ZLEVEL_STATION && Y.z != ZLEVEL_CENTCOM && Y.z != ZLEVEL_MINING && Y.z != ZLEVEL_LAVALAND)) - proselytize_values["operation_time"] *= 2 - if(proselytize_values["power_cost"] > 0) - proselytize_values["power_cost"] *= 2 + fabrication_values["operation_time"] *= 2 + if(fabrication_values["power_cost"] > 0) + fabrication_values["power_cost"] *= 2 var/target_type = target.type - if(!proselytize_checks(proselytize_values, target, target_type, user, silent)) + if(!fabricate_checks(fabrication_values, target, target_type, user, silent)) return FALSE - proselytize_values["operation_time"] *= speed_multiplier + fabrication_values["operation_time"] *= speed_multiplier playsound(target, 'sound/machines/click.ogg', 50, 1) - if(proselytize_values["operation_time"]) + if(fabrication_values["operation_time"]) if(!silent) - user.visible_message("[user]'s [name] begins tearing apart [target]!", "You begin proselytizing [target]...") - if(!do_after(user, proselytize_values["operation_time"], target = target, extra_checks = CALLBACK(src, .proc/proselytize_checks, proselytize_values, target, target_type, user, TRUE))) + var/atom/A = fabrication_values["new_obj_type"] + if(A) + user.visible_message("[user]'s [name] starts ripping [target] apart!", \ + "You start fabricating \a [initial(A.name)] from [target]...") + else + user.visible_message("[user]'s [name] starts consuming [target]!", \ + "Your [name] starts consuming [target]...") + if(!do_after(user, fabrication_values["operation_time"], target = target, extra_checks = CALLBACK(src, .proc/fabricate_checks, fabrication_values, target, target_type, user, TRUE))) return FALSE if(!silent) - user.visible_message("[user]'s [name] covers [target] in golden energy!", "You proselytize [target].") + var/atom/A = fabrication_values["new_obj_type"] + if(A) + user.visible_message("[user]'s [name] replaces [target] with \a [initial(A.name)]!", \ + "You fabricate \a [initial(A.name)] from [target].") + else + user.visible_message("[user]'s [name] consumes [target]!", \ + "Your [name] consumes [target].") else if(!silent) - user.visible_message("[user]'s [name] tears apart [target], covering it in golden energy!", "You proselytize [target].") + var/atom/A = fabrication_values["new_obj_type"] + if(A) + user.visible_message("[user]'s [name] rips apart [target], replacing it with \a [initial(A.name)]!", \ + "You fabricate \a [initial(A.name)] from [target].") + else + user.visible_message("[user]'s [name] rapidly consumes [target]!", \ + "Your [name] consumes [target].") playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - var/new_thing_type = proselytize_values["new_obj_type"] + var/new_thing_type = fabrication_values["new_obj_type"] if(isturf(target)) //if our target is a turf, we're just going to ChangeTurf it and assume it'll work out. var/turf/T = target T.ChangeTurf(new_thing_type) else if(new_thing_type) - if(proselytize_values["dir_in_new"]) - new new_thing_type(get_turf(target), proselytize_values["spawn_dir"]) //please verify that your new object actually wants to get a dir in New() + if(fabrication_values["dir_in_new"]) + new new_thing_type(get_turf(target), fabrication_values["spawn_dir"]) //please verify that your new object actually wants to get a dir in New() else var/atom/A = new new_thing_type(get_turf(target)) - A.setDir(proselytize_values["spawn_dir"]) - if(!proselytize_values["no_target_deletion"]) //for some cases where proselytize_vals() modifies the object but doesn't want it deleted + A.setDir(fabrication_values["spawn_dir"]) + if(!fabrication_values["no_target_deletion"]) //for some cases where fabrication_vals() modifies the object but doesn't want it deleted qdel(target) - modify_stored_power(-proselytize_values["power_cost"]) + modify_stored_power(-fabrication_values["power_cost"]) if(no_table_check) return TRUE return FALSE @@ -250,28 +263,34 @@ //What these procs do is they take an existing list of values, which they then modify. //This(modifying an existing object, in this case the list) is the only way to get information OUT of a do_after callback, which this is used as. -//The proselytize check proc. -/obj/item/clockwork/clockwork_proselytizer/proc/proselytize_checks(list/proselytize_values, atom/target, expected_type, mob/user, silent) //checked constantly while proselytizing - if(!islist(proselytize_values) || QDELETED(target) || QDELETED(user)) +//The fabricate check proc. +/obj/item/clockwork/replica_fabricator/proc/fabricate_checks(list/fabrication_values, atom/target, expected_type, mob/user, silent) //checked constantly while fabricating + if(!islist(fabrication_values) || QDELETED(target) || QDELETED(user)) return FALSE if(repairing || recharging) return FALSE if(target.type != expected_type) return FALSE if(can_use_power(RATVAR_POWER_CHECK)) - proselytize_values["power_cost"] = 0 - if(!can_use_power(proselytize_values["power_cost"])) - if(stored_power - proselytize_values["power_cost"] < 0) + fabrication_values["power_cost"] = 0 + if(!can_use_power(fabrication_values["power_cost"])) + if(stored_power - fabrication_values["power_cost"] < 0) if(!silent) - to_chat(user, "You need [proselytize_values["power_cost"]]W power to proselytize [target]!") - else if(stored_power - proselytize_values["power_cost"] > max_power) + var/atom/A = fabrication_values["new_obj_type"] + if(A) + to_chat(user, "You need [fabrication_values["power_cost"]]W power to fabricate \a [initial(A.name)] from [target]!") + else if(stored_power - fabrication_values["power_cost"] > max_power) if(!silent) - to_chat(user, "Your [name] contains too much power to proselytize [target]!") + var/atom/A = fabrication_values["new_obj_type"] + if(A) + to_chat(user, "Your [name] contains too much power to fabricate \a [initial(A.name)] from [target]!") + else + to_chat(user, "Your [name] contains too much power to consume [target]!") return FALSE return TRUE //The repair check proc. -/obj/item/clockwork/clockwork_proselytizer/proc/proselytizer_repair_checks(list/repair_values, atom/target, mob/user, silent) //Exists entirely to avoid an otherwise unreadable series of checks. +/obj/item/clockwork/replica_fabricator/proc/fabricator_repair_checks(list/repair_values, atom/target, mob/user, silent) //Exists entirely to avoid an otherwise unreadable series of checks. if(!islist(repair_values) || QDELETED(target) || QDELETED(user)) return FALSE if(isliving(target)) //standard checks for if we can affect the target @@ -302,7 +321,7 @@ return FALSE if(repair_values["amount_to_heal"] <= 0) //nothing to heal! return FALSE - repair_values["healing_for_cycle"] = min(repair_values["amount_to_heal"], PROSELYTIZER_REPAIR_PER_TICK) //modify the healing for this cycle + repair_values["healing_for_cycle"] = min(repair_values["amount_to_heal"], FABRICATOR_REPAIR_PER_TICK) //modify the healing for this cycle repair_values["power_required"] = round(repair_values["healing_for_cycle"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) //and get the power cost from that if(!can_use_power(RATVAR_POWER_CHECK) && !can_use_power(repair_values["power_required"])) if(!silent) @@ -312,7 +331,7 @@ return TRUE //The sigil charge check proc. -/obj/item/clockwork/clockwork_proselytizer/proc/sigil_charge_checks(list/charge_values, obj/effect/clockwork/sigil/transmission/sigil, mob/user, silent) +/obj/item/clockwork/replica_fabricator/proc/sigil_charge_checks(list/charge_values, obj/effect/clockwork/sigil/transmission/sigil, mob/user, silent) if(!islist(charge_values) || QDELETED(sigil) || QDELETED(user)) return FALSE if(can_use_power(RATVAR_POWER_CHECK)) diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm index 25bedd79d3..ae54b903b6 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_revenant.dm @@ -105,11 +105,11 @@ descname = "Global Structure Buff" name = "Invoke Nezbere, the Brass Eidolon" desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \ - clockwork proselytizers will charge very rapidly." + replica fabricators will charge very rapidly." invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!") channel_time = 150 consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 6, REPLICANT_ALLOY = 10) - usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \ + usage_tip = "Ocular wardens will become empowered, tinkerer's daemons will produce twice as quickly, \ and interdiction lenses, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power." tier = SCRIPTURE_REVENANT primary_component = REPLICANT_ALLOY diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm index 9efb9a8eb2..c6eba3e3c9 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_scripts.dm @@ -33,7 +33,7 @@ /datum/clockwork_scripture/create_object/cogscarab descname = "Constructor Soul Vessel Shell" name = "Cogscarab" - desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer." + desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt fabricator." invocations = list("Call forth...", "...the workers of Armorer.") channel_time = 60 consumed_components = list(BELLIGERENT_EYE = 2, HIEROPHANT_ANSIBLE = 1) @@ -221,24 +221,24 @@ quickbind_desc = "Creates a Soul Vessel, which can be placed in construct shells and cyborg bodies once filled." -//Clockwork Proselytizer: Creates a clockwork proselytizer, used to convert objects and repair clockwork structures. -/datum/clockwork_scripture/create_object/clockwork_proselytizer - descname = "Converts Objects to Ratvarian" - name = "Clockwork Proselytizer" - desc = "Forms a device that, when used on certain objects, converts them into their Ratvarian equivalents. It requires power to function." +//Replica Fabricator: Creates a replica fabricator, used to convert objects and repair clockwork structures. +/datum/clockwork_scripture/create_object/replica_fabricator + descname = "Replaces Objects with Ratvarian Versions" + name = "Replica Fabricator" + desc = "Forms a device that, when used on certain objects, replaces them with their Ratvarian equivalents. It requires power to function." invocations = list("With this device...", "...his presence shall be made known.") channel_time = 20 consumed_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 2) whispered = TRUE - object_path = /obj/item/clockwork/clockwork_proselytizer/preloaded - creator_message = "You form a clockwork proselytizer." - usage_tip = "Clockwork Walls cause nearby tinkerer's caches to generate components passively, making them a vital tool. Clockwork Floors heal toxin damage in Servants standing on them." + object_path = /obj/item/clockwork/replica_fabricator/preloaded + creator_message = "You form a replica fabricator." + usage_tip = "Clockwork Walls cause nearby Tinkerer's Caches to generate components passively, making this a vital tool. Clockwork Floors heal toxin damage in Servants standing on them." tier = SCRIPTURE_SCRIPT space_allowed = TRUE primary_component = REPLICANT_ALLOY sort_priority = 7 quickbind = TRUE - quickbind_desc = "Creates a Clockwork Proselytizer, which can convert various objects to Ratvarian variants." + quickbind_desc = "Creates a Replica Fabricator, which can convert various objects to Ratvarian variants." //Function Call: Grants the invoker the ability to call forth a Ratvarian spear that deals significant damage to silicons. diff --git a/code/game/gamemodes/clock_cult/clock_structure.dm b/code/game/gamemodes/clock_cult/clock_structure.dm index 64c7135971..5cbaa701fa 100644 --- a/code/game/gamemodes/clock_cult/clock_structure.dm +++ b/code/game/gamemodes/clock_cult/clock_structure.dm @@ -9,7 +9,7 @@ anchored = 1 density = 1 resistance_flags = FIRE_PROOF | ACID_PROOF - var/can_be_repaired = TRUE //if a proselytizer can repair it + var/can_be_repaired = TRUE //if a fabricator can repair it break_message = "The frog isn't a meme after all!" //The message shown when a structure breaks break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ diff --git a/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm b/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm index cfcac3b515..e9f02e9e8c 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/clock_shells.dm @@ -34,7 +34,7 @@ /obj/structure/destructible/clockwork/shell/cogscarab name = "cogscarab shell" desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism." - clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer." + clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt fabricator." icon_state = "clockdrone_shell" mobtype = /mob/living/simple_animal/drone/cogscarab spawn_message = "'s eyes blink open, glowing bright red." diff --git a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm index 25f151def5..722ff99c25 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm @@ -14,7 +14,7 @@ light_color = "#BE8700" var/atom/prey //Whatever Ratvar is chasing var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE - var/proselytize_range = 10 + var/convert_range = 10 dangerous_possession = TRUE /obj/structure/destructible/clockwork/massive/ratvar/Initialize() @@ -58,10 +58,10 @@ /obj/structure/destructible/clockwork/massive/ratvar/process() if(clashing) //I'm a bit occupied right now, thanks return - for(var/I in circlerangeturfs(src, proselytize_range)) + for(var/I in circlerangeturfs(src, convert_range)) var/turf/T = I T.ratvar_act() - for(var/I in circleviewturfs(src, round(proselytize_range * 0.5))) + for(var/I in circleviewturfs(src, round(convert_range * 0.5))) var/turf/T = I T.ratvar_act(TRUE) var/dir_to_step_in = pick(GLOB.cardinal) diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm index d90c42fe4a..31f52a42fc 100644 --- a/code/game/objects/items/weapons/storage/toolbox.dm +++ b/code/game/objects/items/weapons/storage/toolbox.dm @@ -21,15 +21,15 @@ if(has_latches) if(prob(10)) latches = "double_latch" - if(prob(1)) - latches = "triple_latch" + if(prob(1)) + latches = "triple_latch" update_icon() /obj/item/weapon/storage/toolbox/update_icon() ..() cut_overlays() if(has_latches) - add_overlay(latches) + add_overlay(latches) /obj/item/weapon/storage/toolbox/suicide_act(mob/user) @@ -140,10 +140,10 @@ max_combined_w_class = 28 storage_slots = 28 attack_verb = list("robusted", "crushed", "smashed") - var/proselytizer_type = /obj/item/clockwork/clockwork_proselytizer/scarab + var/fabricator_type = /obj/item/clockwork/replica_fabricator/scarab /obj/item/weapon/storage/toolbox/brass/prefilled/PopulateContents() - new proselytizer_type(src) + new fabricator_type(src) new /obj/item/weapon/screwdriver/brass(src) new /obj/item/weapon/wirecutters/brass(src) new /obj/item/weapon/wrench/brass(src) @@ -151,7 +151,7 @@ new /obj/item/weapon/weldingtool/experimental/brass(src) /obj/item/weapon/storage/toolbox/brass/prefilled/ratvar - var/slab_type = /obj/item/clockwork/slab + var/slab_type = /obj/item/clockwork/slab /obj/item/weapon/storage/toolbox/brass/prefilled/ratvar/PopulateContents() ..() @@ -159,7 +159,7 @@ /obj/item/weapon/storage/toolbox/brass/prefilled/ratvar/admin slab_type = /obj/item/clockwork/slab/debug - proselytizer_type = /obj/item/clockwork/clockwork_proselytizer/scarab/debug + fabricator_type = /obj/item/clockwork/replica_fabricator/scarab/debug /obj/item/weapon/storage/toolbox/artistic diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 4934636948..c51c543f26 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -84,6 +84,7 @@ new /obj/item/device/flashlight/seclite(src) new /obj/item/weapon/pinpointer(src) new /obj/item/clothing/under/rank/head_of_security/grey(src) + new /obj/item/clothing/under/rank/head_of_security/grey(src) new /obj/item/weapon/storage/lockbox/secmedal(src) /obj/structure/closet/secure_closet/warden diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 64d93e914e..4b912923a2 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -248,6 +248,7 @@ /obj/structure/grille/ratvar icon_state = "ratvargrille" + name = "cog grille" desc = "A strangely-shaped grille." broken_type = /obj/structure/grille/ratvar/broken diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 2f6b03bef1..4b2017fab6 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -50,7 +50,7 @@ deconstruct() /obj/structure/lattice/clockwork - name = "clockwork lattice" + name = "cog lattice" desc = "A lightweight support lattice. These hold the Justicar's station together." icon = 'icons/obj/smooth_structures/lattice_clockwork.dmi' diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 8b6f43ee25..ceb1ca85b5 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -11,7 +11,7 @@ desc = "It's watching you suspiciously." /obj/structure/closet/crate/necropolis/tendril/PopulateContents() - var/loot = rand(1,27) + var/loot = rand(1,28) switch(loot) if(1) new /obj/item/device/shared_storage/red(src) @@ -69,6 +69,8 @@ if(27) new /obj/item/borg/upgrade/modkit/lifesteal(src) new /obj/item/weapon/bedsheet/cult(src) + if(28) + new /obj/item/borg/upgrade/modkit/bounty(src) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 824f5b5f02..f07dca7d32 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -250,7 +250,7 @@ ratvar_modules = list( /obj/item/clockwork/slab/cyborg, /obj/item/clockwork/ratvarian_spear/cyborg, - /obj/item/clockwork/clockwork_proselytizer/cyborg) + /obj/item/clockwork/replica_fabricator/cyborg) moduleselect_icon = "standard" feedback_key = "cyborg_standard" hat_offset = -3 @@ -314,7 +314,7 @@ emag_modules = list(/obj/item/borg/stun) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/engineer, - /obj/item/clockwork/clockwork_proselytizer/cyborg) + /obj/item/clockwork/replica_fabricator/cyborg) cyborg_base_icon = "engineer" moduleselect_icon = "engineer" feedback_key = "cyborg_engineering" @@ -441,7 +441,7 @@ emag_modules = list(/obj/item/weapon/reagent_containers/spray/cyborg_lube) ratvar_modules = list( /obj/item/clockwork/slab/cyborg/janitor, - /obj/item/clockwork/clockwork_proselytizer/cyborg) + /obj/item/clockwork/replica_fabricator/cyborg) cyborg_base_icon = "janitor" moduleselect_icon = "janitor" feedback_key = "cyborg_janitor" diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 1c70ca57e5..7399e727bc 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -91,6 +91,16 @@ icon_living = icon_state icon_dead = "[visualAppearence]_dead" +/obj/item/drone_shell/dusty + name = "derelict drone shell" + desc = "A long-forgotten drone shell. It seems kind of... Space Russian." + drone_type = /mob/living/simple_animal/drone/derelict + +/mob/living/simple_animal/drone/derelict + name = "derelict drone" + default_hatmask = /obj/item/clothing/head/ushanka + + /mob/living/simple_animal/drone/cogscarab name = "cogscarab" desc = "A strange, drone-like machine. It constantly emits the hum of gears." @@ -120,14 +130,14 @@ hacked = TRUE visualAppearence = CLOCKDRONE can_be_held = FALSE - flavortext = "You are a cogscarab, a clockwork creation of Ratvar. As a cogscarab, you have low health, an inbuilt proselytizer that can convert brass \ - to liquified alloy, a set of relatively fast tools, can communicate over the Hierophant Network with :b, and are immune to extreme \ + flavortext = "You are a cogscarab, a clockwork creation of Ratvar. As a cogscarab, you have low health, an inbuilt fabricator that can convert brass \ + to power, a set of relatively fast tools, can communicate over the Hierophant Network with :b, and are immune to extreme \ temperatures and pressures. \nYour goal is to serve the Justiciar and his servants by repairing and defending all they create." -/mob/living/simple_animal/drone/cogscarab/ratvar //a subtype for spawning when ratvar is alive, has a slab that it can use and a normal proselytizer +/mob/living/simple_animal/drone/cogscarab/ratvar //a subtype for spawning when ratvar is alive, has a slab that it can use and a normal fabricatorlab that it can use and a normal fabricator default_storage = /obj/item/weapon/storage/toolbox/brass/prefilled/ratvar -/mob/living/simple_animal/drone/cogscarab/admin //an admin-only subtype of cogscarab with a no-cost proselytizer and slab in its box +/mob/living/simple_animal/drone/cogscarab/admin //an admin-only subtype of cogscarab with a no-cost fabricator and slab in its box default_storage = /obj/item/weapon/storage/toolbox/brass/prefilled/ratvar/admin /mob/living/simple_animal/drone/cogscarab/Initialize() @@ -191,11 +201,41 @@ /mob/living/simple_animal/drone/cogscarab/ratvar_act() fully_heal(TRUE) -/obj/item/drone_shell/dusty - name = "derelict drone shell" - desc = "A long-forgotten drone shell. It seems kind of... Space Russian." - drone_type = /mob/living/simple_animal/drone/derelict +/mob/living/simple_animal/drone/cogscarab/update_icons() + if(stat != DEAD) + if(incapacitated()) + icon_state = "[visualAppearence]_flipped" + else + icon_state = visualAppearence + else + icon_state = "[visualAppearence]_dead" -/mob/living/simple_animal/drone/derelict - name = "derelict drone" - default_hatmask = /obj/item/clothing/head/ushanka +/mob/living/simple_animal/drone/cogscarab/Stun(amount, updating = 1, ignore_canstun = 0) + . = ..() + if(.) + update_icons() + +/mob/living/simple_animal/drone/cogscarab/SetStunned(amount, updating = 1, ignore_canstun = 0) + . = ..() + if(.) + update_icons() + +/mob/living/simple_animal/drone/cogscarab/AdjustStunned(amount, updating = 1, ignore_canstun = 0) + . = ..() + if(.) + update_icons() + +/mob/living/simple_animal/drone/cogscarab/Weaken(amount, updating = 1, ignore_canweaken = 0) + . = ..() + if(.) + update_icons() + +/mob/living/simple_animal/drone/cogscarab/SetWeakened(amount, updating = 1, ignore_canweaken = 0) + . = ..() + if(.) + update_icons() + +/mob/living/simple_animal/drone/cogscarab/AdjustWeakened(amount, updating = 1, ignore_canweaken = 0) + . = ..() + if(.) + update_icons() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index 99958268a5..a379b0e8ac 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -79,3 +79,6 @@ crusher_loot = /obj/item/crusher_trophy/watcher_wing loot = list() butcher_results = list(/obj/item/weapon/ore/diamond = 2, /obj/item/stack/sheet/sinew = 2, /obj/item/stack/sheet/bone = 1) + +/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril + fromtendril = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm index 0a5b9957f2..50f3d7260b 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm @@ -91,6 +91,10 @@ stat_attack = UNCONSCIOUS robust_searching = 1 +/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril + fromtendril = TRUE + + //tentacles /obj/effect/goliath_tentacle name = "Goliath tentacle" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm index b7ecba8431..4bbfb9ab72 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm @@ -124,6 +124,10 @@ new /obj/effect/mob_spawn/human/corpse/damaged(T) ..(gibbed) +/mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril + fromtendril = TRUE + + //Legion skull /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion name = "legion" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm index f9e458cfd8..57e04b1331 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm @@ -16,6 +16,7 @@ a_intent = INTENT_HARM var/throw_message = "bounces off of" var/icon_aggro = null // for swapping to when we get aggressive + var/fromtendril = FALSE see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE mob_size = MOB_SIZE_LARGE diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm index 1ef8dd9f13..02257193ff 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm @@ -17,7 +17,7 @@ maxHealth = 250 max_mobs = 3 spawn_time = 300 //30 seconds default - mob_type = /mob/living/simple_animal/hostile/asteroid/basilisk/watcher + mob_type = /mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril spawn_text = "emerges from" atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 @@ -28,10 +28,10 @@ var/obj/effect/light_emitter/tendril/emitted_light /mob/living/simple_animal/hostile/spawner/lavaland/goliath - mob_type = /mob/living/simple_animal/hostile/asteroid/goliath/beast + mob_type = /mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril /mob/living/simple_animal/hostile/spawner/lavaland/legion - mob_type = /mob/living/simple_animal/hostile/asteroid/hivelord/legion + mob_type = /mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril /mob/living/simple_animal/hostile/spawner/lavaland/Initialize() . = ..() diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 62bc464ac1..2cb9bf0b11 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -163,6 +163,7 @@ range = 3 log_override = TRUE + var/pressure_decrease_active = FALSE var/pressure_decrease = 0.25 var/obj/item/weapon/gun/energy/kinetic_accelerator/kinetic_gun @@ -179,6 +180,7 @@ if(pressure > 50) name = "weakened [name]" damage = damage * pressure_decrease + pressure_decrease_active = TRUE . = ..() /obj/item/projectile/kinetic/on_range() @@ -194,7 +196,10 @@ if(!target_turf) target_turf = get_turf(src) if(kinetic_gun) //hopefully whoever shot this was not very, very unfortunate. - for(var/obj/item/borg/upgrade/modkit/M in kinetic_gun.get_modkits()) + var/list/mods = kinetic_gun.get_modkits() + for(var/obj/item/borg/upgrade/modkit/M in mods) + M.projectile_strike_predamage(src, target_turf, target, kinetic_gun) + for(var/obj/item/borg/upgrade/modkit/M in mods) M.projectile_strike(src, target_turf, target, kinetic_gun) if(ismineralturf(target_turf)) var/turf/closed/mineral/M = target_turf @@ -265,6 +270,10 @@ /obj/item/borg/upgrade/modkit/proc/modify_projectile(obj/item/projectile/kinetic/K) +//use this one for effects you want to trigger before mods that do damage +/obj/item/borg/upgrade/modkit/proc/projectile_strike_predamage(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) +//and this one for things that don't need to trigger before other damage-dealing mods + /obj/item/borg/upgrade/modkit/proc/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) //Range @@ -393,7 +402,7 @@ modifier = -14 //Makes the cooldown 3 seconds(with no cooldown mods) if you miss. Don't miss. cost = 50 -/obj/item/borg/upgrade/modkit/cooldown/repeater/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) +/obj/item/borg/upgrade/modkit/cooldown/repeater/projectile_strike_predamage(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) var/valid_repeat = FALSE if(isliving(target)) var/mob/living/L = target @@ -403,7 +412,7 @@ valid_repeat = TRUE if(valid_repeat) KA.overheat = FALSE - KA.attempt_reload(KA.overheat_time * 0.25) //If you hit, the cooldown drops to 0.75 seconds. + KA.attempt_reload(KA.overheat_time * 0.25) //If you hit, the cooldown drops to 0.75 seconds. /obj/item/borg/upgrade/modkit/lifesteal name = "lifesteal crystal" @@ -414,7 +423,7 @@ cost = 20 var/static/list/damage_heal_order = list(BRUTE, BURN, OXY) -/obj/item/borg/upgrade/modkit/lifesteal/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) +/obj/item/borg/upgrade/modkit/lifesteal/projectile_strike_predamage(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) if(isliving(target) && isliving(K.firer)) var/mob/living/L = target if(L.stat == DEAD) @@ -438,6 +447,43 @@ return new /obj/effect/temp_visual/resonance(target_turf, K.firer, null, 30) +/obj/item/borg/upgrade/modkit/bounty + name = "death syphon" + desc = "Killing or assisting in killing a creature permenantly increases your damage against that type of creature." + denied_type = /obj/item/borg/upgrade/modkit/bounty + modifier = 1.25 + cost = 30 + var/maximum_bounty = 25 + var/list/bounties_reaped = list() + +/obj/item/borg/upgrade/modkit/bounty/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/weapon/gun/energy/kinetic_accelerator/KA) + if(isliving(target)) + var/mob/living/L = target + var/list/existing_marks = L.has_status_effect_list(STATUS_EFFECT_SYPHONMARK) + for(var/i in existing_marks) + var/datum/status_effect/syphon_mark/SM = i + if(SM.reward_target == src) //we want to allow multiple people with bounty modkits to use them, but we need to replace our own marks so we don't multi-reward + SM.reward_target = null + qdel(SM) + var/datum/status_effect/syphon_mark/SM = L.apply_status_effect(STATUS_EFFECT_SYPHONMARK) + SM.reward_target = src + if(bounties_reaped[L.type]) + var/kill_modifier = 1 + if(K.pressure_decrease_active) + kill_modifier *= K.pressure_decrease + var/armor = L.run_armor_check(K.def_zone, K.flag, "", "", K.armour_penetration) + L.apply_damage(bounties_reaped[L.type]*kill_modifier, K.damage_type, K.def_zone, armor) + +/obj/item/borg/upgrade/modkit/bounty/proc/get_kill(mob/living/L) + var/bonus_mod = 1 + if(ismegafauna(L)) //megafauna reward + bonus_mod = 4 + if(!bounties_reaped[L.type]) + bounties_reaped[L.type] = min(modifier * bonus_mod, maximum_bounty) + else + bounties_reaped[L.type] = min(bounties_reaped[L.type] + (modifier * bonus_mod), maximum_bounty) + + //Indoors /obj/item/borg/upgrade/modkit/indoors name = "decrease pressure penalty" diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index c8fc98d4f5018967096dbbb9e5c597cfa3722b77..214bfd744ea9286559443600a5ef9a291bf2a724 100644 GIT binary patch delta 1004 zcmVkHuP3y>rMPmv`nHiA6VE$|$qM}ec^%+O1T6H3~R^Vj#Vj(6;MRx}&^ZOqkKK|9byZU&Mh9U<~9rjQ-|8$YBlm=3CbyNO8lSu(X0WXt{ z0jL7M6q7dsCIL5-UIHTlSCfJQ?g2NGaRZ3~U6cC*D}NoCX+Xs#?8_e%-4p+(bmR%R z`AkXbd-)mSP(T-kP`~a4ot->wf@_SKBJwY(c`IR336_Tc1Jcs=zFv}9+l)_8Vx~AW zpGd*r_W#9+$uDon^WEVS#WgDGFR6J8eq2ytw!qUDXR8C>J?DQED38tcgg%33tjESR z4aAM~&3`9_mg2`wY-@yb^H~g2>3@4GzwzGaTxMifine!{@;1@zE$bO_H0-=JaB9dhz6ua|OCyZX*t{2o%V>U4LO| zSbwb08_cbUrDZaWC;}#f&;(ww>lrNNd;sPz1r7If8_|qkouYqUb9zVD_XoyXhsl=b zXiw1LSITaZl#EGX5biL#4GA0W?ZDwLjP1FA( zWdgr;J=YKT8N3xSMD~mTNLvNNMau-_{0J#6HXRSKx|m{SCE5Ave09D$e@HnBOMfp~ zABRjpb&Sdl`fM5B@1ga_8+)wb)dnexU%P~CxtiQk>||?2w}rTK{nEpM2j%bSYW981 zA{W(poV`9E57jmlX$u+Ncx{9{I_cdYb#NZhWrb=e+llrzC15vz;b`b2 zPz1~C3UUl7yEIy!6ahIehI>08BV0pCaJwpJ)M6fSQZ{U7AFmspkHxQ3y>rMP?04oHiHy(`|up3M}ec^%+O1T6H3~R^Vh$_I^MD4So^XqT#Km66ayZUgEh9U+Tj1%7v(%c)vG=EpA^^FHHXiF)8nI2a+)MJm(A(L>h$8tW9JHVz1&J1Vi72ice@_L z(tosAp*NUY5lh=-8dC&J2B8VOV%IZRO8NlIp9>o9>NcVozc@wzyax4-uI~?wxDJyo z&(fZt!!MNGBq4uuj45Mm05tlTz`r#4-s7psxX-Dq%-=_wQMo+3~U*=?!s~c zzjl*sZ9~C~hA!%xB4!;@q3k9w^cyq$h#b(Gd{Uw8(kO=dZf2I0p(S3fL7o<4YMlNb zDHHg$>$!fw&)}_yA+l!#K-wx8E?Xub=SN6svGI6_)x{JuE6L7R=d1J8`9sQ4Sbuua z`bcB~s$*1c&}YjCe-Euc;MijgFE>b8{MsdC%k|`zVkcWGx-G<=>z5u6JScxpSF`V9 z7P+X-f2|=q&a^q?vY28qhxQi)j>Op9ktIV?;?3XhA#J0K zBim_{!f+4=L#2X ze1L%2Hv8bfq3E!~56guj=d*2AEEhWmEuOyrv{Vj33F<&4OxMeWLJh}kf14F-kF6e~O)hxc?2gLGWB(@6^|=~=NrcJ4J#SXH|+e(^9`#mf1Y^0Ve7#!<;7Ex z4=oDD^UZapR?2-xm}rMF(f6Q#=pIy=*ukqK3CW^gy=y=5P8JT}2#oL@!gO6*x!2%C z4^E*uTUU{Fc@DN_>x8S=o8F<3O{{YQrQodKQNz__RJzs1bwK6~9Xc;0$R=SQ^}`}B z*~py)zM4#e6PbWce~}Di&Ajp)cnC5e1050xJ;e)j&92Cc{$cY z{!D+mpgpl{Q`z34tu@F0MCZsS)Q#3sxn>0`*(#wo7=kgie@h;BIi5e=<>T{k%!!!X zAYkNlgM6_Yn1IH>bkqDfL=K0abDLCvtu;3^?32SS}NYb>L1EB-54Np0m@Z{3^NX*=VHc((6BPah_F z&|1`UX4E++!uLFsvj&B4a0V05+8%{(z^T;q79DKYoRy5{Ppsms$g61`J2GUA&{iha zWPHMEz$xKd&^mQ2{2eM0eEC@T)x+RhRJ3m&r_KrgIC1i5a5X-Tz6Mw0BiPpnPP|f> x{=4FbWs1enGPPQUmer(X%HU)6<=b=i{Pkt|KMs2c)KVh+@`L;XxBLSEOwwgI^t%86 delta 981 zcmV;`11kK&tOv-f2aqHI&ygh{f7Os3XWATcSxm8*L;DK?N8;G*$dVx`@n*lihqR3{ zj%=q*3d2DhkdKegB1PqW_Rr^kpT1^~U!InGbe^oqwpo?)<)SAQnrxe`%H^U#s+(|p z@Bsp5+w7eKhoZv{-z^u4oX@sdv0S`3Xz}>{m!)zDN>B$XVY*%}6lyqRf7`5JBi9M? z+fI=r&^H6zgQ<7mZpTpCwsW>6pVH@g$QsGtE@7*~&A^^fYpT(q2?7s^jH?0cP<|n8 z-8YDd7yI!9QS!7%LP7_Uf^~@uKc#S{5`6)!(FkyD5<998>@-O*L4elwkg$()TC;-j ze8o!6c>Zykj&H#?s00{le^Im zyja7ZzYU93?8#dvcuKfMV}tK($hKLrW<@oEQA~;-+zvg}O%NJQs%%c?y#or3@Eyu& zV{dm_?9uzwI=yWB!6P`?kf|?wt$17^Jl`;$Z&=BAzG0_lo^M!nfA+-l4ODbJpY zd}vWHo^LKQwNman!bCfaiM|E>OLx?0wUw{Eb+4jx)}uZI`X3X;xq8!r;@vFl!4VkY zJA~=lwsNPzi5{FnbF!`?>+%$A&DIH5u`|6xBb!+31WLhK!K0?D$*6R@jcb9-D>`&u zNRUm!KI(}@Ub2xpe+hgsnFJ>?0i7Zl$eMX2I`9x=KnB_;5_*Ui>6%@*mkWnI88sEh zp=`j_sjN1WfzE=C1R6`HN=6w&ROCmw7yK&nQ{k>y02+-KHMYs!;L^Kk(I_&tXl-(H zUquyDa#rN!SReU2J?f11#Ij9gdyTf%9R3rXBcD(=T1(}ce-*4`tAyTQ2*%VddEDiA z{&16zPs33sVseFmk<%6O#cp5%8Uxc!^Vc9b9Dq)3QUSKsT+y(P4%d+XF?9yAMsym& zjO{_pn%~o#XAm>z_c4e$gZr5OtZ91;VD11sN&<|st&q0utVxdIzj4Aku83OOK2e8n zS?__lvNME#_aZEhf z_n@Z_6g_Ay>Nzv&oKxXj9?DsR!Z$dB321E(!Z+YlYI=(fw` Date: Mon, 12 Jun 2017 16:12:00 -0500 Subject: [PATCH 17/19] compile fixes --- code/__DEFINES/clockcult.dm | 2 +- code/datums/status_effects/neutral.dm | 30 ++++++++++++++----- .../friendly/drone/extra_drone_types.dm | 4 +-- .../hostile/megafauna/hierophant.dm | 6 ++++ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm index 8b38ca12e5..ded2c34ef8 100644 --- a/code/__DEFINES/clockcult.dm +++ b/code/__DEFINES/clockcult.dm @@ -99,7 +99,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us #define SIGIL_ACCESS_RANGE 2 //range at which transmission sigils can access power -#define fabricator_REPAIR_PER_TICK 4 //how much a fabricator repairs each tick, and also how many deciseconds each tick is +#define FABRICATOR_REPAIR_PER_TICK 4 //how much a fabricator repairs each tick, and also how many deciseconds each tick is #define OCULAR_WARDEN_EXCLUSION_RANGE 3 //the range at which ocular wardens cannot be placed near other ocular wardens diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index ae0301762e..7adbf4e915 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -17,14 +17,6 @@ alert_type = null var/total_damage = 0 -/datum/status_effect/syphon_mark - id = "syphon_mark" - duration = 50 - status_type = STATUS_EFFECT_MULTIPLE - alert_type = null - on_remove_on_mob_delete = TRUE - var/obj/item/borg/upgrade/modkit/bounty/reward_target - /datum/status_effect/syphon_mark/on_apply() if(owner.stat == DEAD) return FALSE @@ -42,3 +34,25 @@ /datum/status_effect/syphon_mark/on_remove() get_kill() . = ..() + +/datum/status_effect/syphon_mark + id = "syphon_mark" + duration = 50 + status_type = STATUS_EFFECT_MULTIPLE + alert_type = null + on_remove_on_mob_delete = TRUE + var/obj/item/borg/upgrade/modkit/bounty/reward_target + +/datum/status_effect/syphon_mark/on_apply() + if(owner.stat == DEAD) + return FALSE + return ..() + +/datum/status_effect/syphon_mark/tick() + if(owner.stat == DEAD) + get_kill() + qdel(src) + +/datum/status_effect/syphon_mark/on_remove() + get_kill() + . = ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 7399e727bc..11935e7fce 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -177,9 +177,7 @@ ..() /mob/living/simple_animal/drone/cogscarab/can_use_guns(obj/item/weapon/gun/G) - if(!GLOB.ratvar_awakens) - changeNext_move(CLICK_CD_RANGE*4) //about as much delay as an unupgraded kinetic accelerator - return TRUE + return GLOB.ratvar_awakens /mob/living/simple_animal/drone/cogscarab/get_armor_effectiveness() if(GLOB.ratvar_awakens) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 6d44df978e..9675ac25b1 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -132,6 +132,12 @@ Difficulty: Hard if(spawned_beacon && loc == spawned_beacon.loc && did_reset) arena_trap(src) +/mob/living/simple_animal/hostile/megafauna/hierophant/CanAttack(atom/the_target) + . = ..() + if(istype(the_target, /mob/living/simple_animal/hostile/asteroid/hivelordbrood)) //ignore temporary targets in favor of more permenant targets + return FALSE + + /mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount, updating_health = TRUE, forced = FALSE) . = ..() if(src && . > 0 && !blinking) From 226345d82a2cced01287dfe90f693937fbe12533 Mon Sep 17 00:00:00 2001 From: LetterJay Date: Tue, 13 Jun 2017 01:10:21 -0500 Subject: [PATCH 18/19] upstream-merge-28109 upstream-merge-28352 --- code/datums/verbs.dm | 101 ++++ code/game/objects/objs.dm | 5 +- code/modules/admin/adminmenu.dm | 4 +- code/modules/client/client_procs.dm | 8 +- code/modules/client/preferences_toggles.dm | 452 +++++++++--------- .../mob/living/carbon/carbon_movement.dm | 10 + code/modules/mob/mob_movement.dm | 33 +- .../research/designs/medical_designs.dm | 12 + code/modules/surgery/organs/eyes.dm | 173 +++++++ code/world.dm | 2 +- icons/mob/human_face.dmi | Bin 50534 -> 50651 bytes interface/menu.dm | 162 ++----- tgstation.dme | 1 + 13 files changed, 594 insertions(+), 369 deletions(-) create mode 100644 code/datums/verbs.dm diff --git a/code/datums/verbs.dm b/code/datums/verbs.dm new file mode 100644 index 0000000000..f2674a631d --- /dev/null +++ b/code/datums/verbs.dm @@ -0,0 +1,101 @@ +/datum/verbs + var/name + var/list/children + var/datum/verbs/parent + var/list/verblist + var/abstract = FALSE + +//returns the master list for verbs of a type +/datum/verbs/proc/GetList() + CRASH("Abstract verblist for [type]") + +//modify outlist for each entry in Generate_list +/datum/verbs/proc/HandleVerb(list/outlist, atom/verb/verbpath, ...) + +/datum/verbs/New() + var/mainlist = GetList() + var/ourentry = mainlist[type] + children = list() + verblist = list() + if (ourentry) + if (!islist(ourentry)) //some of our childern already loaded + qdel(src) + CRASH("Verb double load: [type]") + Add_children(ourentry) + + mainlist[type] = src + + Load_verbs(type, typesof("[type]/verb")) + + var/datum/verbs/parent = mainlist[parent_type] + if (!parent) + mainlist[parent_type] = list(src) + else if (islist(parent)) + parent += src + else + parent.Add_children(list(src)) + +/datum/verbs/proc/Set_parent(datum/verbs/_parent) + parent = _parent + if (abstract) + parent.Add_children(children) + var/list/verblistoftypes = list() + for(var/thing in verblist) + LAZYADD(verblistoftypes[verblist[thing]], thing) + + for(var/verbparenttype in verblistoftypes) + parent.Load_verbs(verbparenttype, verblistoftypes[verbparenttype]) + +/datum/verbs/proc/Add_children(list/kids) + if (abstract && parent) + parent.Add_children(kids) + return + + for(var/thing in kids) + var/datum/verbs/item = thing + item.Set_parent(src) + if (!item.abstract) + children += item + +/datum/verbs/proc/Load_verbs(verb_parent_type, list/verbs) + if (abstract && parent) + parent.Load_verbs(verb_parent_type, verbs) + return + + for (var/verbpath in verbs) + verblist[verbpath] = verb_parent_type + +/datum/verbs/proc/Generate_list(...) + . = list() + if (length(children)) + for (var/thing in children) + var/datum/verbs/child = thing + var/list/childlist = child.Generate_list(arglist(args)) + if (childlist) + var/childname = "[child]" + if (childname == "[child.type]") + var/list/tree = splittext(childname, "/") + childname = tree[tree.len] + .[child.type] = "parent=[url_encode(type)];name=[url_encode(childname)]" + . += childlist + + for (var/thing in verblist) + var/atom/verb/verbpath = thing + if (!verbpath) + stack_trace("Bad VERB in [type] verblist: [english_list(verblist)]") + var/list/entry = list() + entry["parent"] = "[type]" + entry["name"] = verbpath.desc + if (copytext(verbpath.name,1,2) == "@") + entry["command"] = copytext(verbpath.name,2) + else + entry["command"] = replacetext(verbpath.name, " ", "-") + + HandleVerb(arglist(list(entry, verbpath) + args)) + .[verbpath] = entry + +/world/proc/LoadVerbs(verb_type) + if(!ispath(verb_type, /datum/verbs) || verb_type == /datum/verbs) + CRASH("Invalid verb_type: [verb_type]") + for (var/typepath in subtypesof(verb_type)) + new typepath() diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index b08f0542a0..9a7376c9eb 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -182,7 +182,10 @@ /obj/proc/check_uplink_validity() return 1 -/obj/proc/on_mob_move(dir, mob) +/obj/proc/on_mob_move(dir, mob, oldLoc) + return + +/obj/proc/on_mob_turn(dir, mob) return /obj/vv_get_dropdown() diff --git a/code/modules/admin/adminmenu.dm b/code/modules/admin/adminmenu.dm index 8954244da4..aa654ab252 100644 --- a/code/modules/admin/adminmenu.dm +++ b/code/modules/admin/adminmenu.dm @@ -1,8 +1,8 @@ -/datum/menu/Admin/Generate_list(client/C) +/datum/verbs/menu/Admin/Generate_list(client/C) if (C.holder) . = ..() -/datum/menu/Admin/verb/playerpanel() +/datum/verbs/menu/Admin/verb/playerpanel() set name = "Player Panel" set desc = "Player Panel" set category = "Admin" diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index fc21e9e0d2..5fad078e19 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -353,9 +353,9 @@ GLOBAL_LIST(external_rsc_urls) hook_vr("client_new",list(src)) - var/list/topmenus = GLOB.menulist[/datum/menu] + var/list/topmenus = GLOB.menulist[/datum/verbs/menu] for (var/thing in topmenus) - var/datum/menu/topmenu = thing + var/datum/verbs/menu/topmenu = thing var/topmenuname = "[topmenu]" if (topmenuname == "[topmenu.type]") var/list/tree = splittext(topmenuname, "/") @@ -364,13 +364,13 @@ GLOBAL_LIST(external_rsc_urls) var/list/entries = topmenu.Generate_list(src) for (var/child in entries) winset(src, "[url_encode(child)]", "[entries[child]]") - if (!ispath(child, /datum/menu)) + if (!ispath(child, /datum/verbs/menu)) var/atom/verb/verbpath = child if (copytext(verbpath.name,1,2) != "@") new child(src) for (var/thing in prefs.menuoptions) - var/datum/menu/menuitem = GLOB.menulist[thing] + var/datum/verbs/menu/menuitem = GLOB.menulist[thing] if (menuitem) menuitem.Load_checked(src) diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index eb244937e6..943999aecc 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -1,29 +1,29 @@ //this works as is to create a single checked item, but has no back end code for toggleing the check yet #define TOGGLE_CHECKBOX(PARENT, CHILD) PARENT/CHILD/abstract = TRUE;PARENT/CHILD/checkbox = CHECKBOX_TOGGLE;PARENT/CHILD/verb/CHILD - -//Example usage TOGGLE_CHECKBOX(datum/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)() - + +//Example usage TOGGLE_CHECKBOX(datum/verbs/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)() + //override because we don't want to save preferences twice. -/datum/menu/Settings/Set_checked(client/C, verbpath) +/datum/verbs/menu/Settings/Set_checked(client/C, verbpath) if (checkbox == CHECKBOX_GROUP) C.prefs.menuoptions[type] = verbpath else if (checkbox == CHECKBOX_TOGGLE) var/checked = Get_checked(C) C.prefs.menuoptions[type] = !checked winset(C, "[verbpath]", "is-checked = [!checked]") - -/datum/menu/Settings/verb/setup_character() + +/datum/verbs/menu/Settings/verb/setup_character() set name = "Game Preferences" - set category = "Preferences" + set category = "Preferences" set desc = "Open Game Preferences Window" usr.client.prefs.current_tab = 1 usr.client.prefs.ShowChoices(usr) //toggles -/datum/menu/Settings/Ghost/chatterbox +/datum/verbs/menu/Settings/Ghost/chatterbox name = "Chat Box Spam" - -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)() + +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)() set name = "Show/Hide GhostEars" set category = "Preferences" set desc = "See All Speech" @@ -31,10 +31,10 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_ears)() to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTEARS) ? "see all speech in the world" : "only see speech from nearby mobs"].") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Ghost Ears|[usr.client.prefs.chat_toggles & CHAT_GHOSTEARS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_ears/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/toggle_ghost_ears/Get_checked(client/C) return C.prefs.chat_toggles & CHAT_GHOSTEARS -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_sight)() +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox, toggle_ghost_sight)() set name = "Show/Hide GhostSight" set category = "Preferences" set desc = "See All Emotes" @@ -42,10 +42,10 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_sight)() to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) ? "see all emotes in the world" : "only see emotes from nearby mobs"].") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Ghost Sight|[usr.client.prefs.chat_toggles & CHAT_GHOSTSIGHT]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_sight/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/toggle_ghost_sight/Get_checked(client/C) return C.prefs.chat_toggles & CHAT_GHOSTSIGHT -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_whispers)() +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox, toggle_ghost_whispers)() set name = "Show/Hide GhostWhispers" set category = "Preferences" set desc = "See All Whispers" @@ -53,10 +53,10 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_whispers)() to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTWHISPER) ? "see all whispers in the world" : "only see whispers from nearby mobs"].") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Ghost Whispers|[usr.client.prefs.chat_toggles & CHAT_GHOSTWHISPER]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_whispers/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/toggle_ghost_whispers/Get_checked(client/C) return C.prefs.chat_toggles & CHAT_GHOSTWHISPER -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_radio)() +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox, toggle_ghost_radio)() set name = "Show/Hide GhostRadio" set category = "Preferences" set desc = "See All Radio Chatter" @@ -64,60 +64,60 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_radio)() to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTRADIO) ? "see radio chatter" : "not see radio chatter"].") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Ghost Radio|[usr.client.prefs.chat_toggles & CHAT_GHOSTRADIO]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! //social experiment, increase the generation whenever you copypaste this shamelessly GENERATION 1 -/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_radio/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/toggle_ghost_radio/Get_checked(client/C) return C.prefs.chat_toggles & CHAT_GHOSTRADIO -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox, toggle_ghost_pda)() - set name = "Show/Hide GhostPDA" +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox, toggle_ghost_pda)() + set name = "Show/Hide GhostPDA" set category = "Preferences" set desc = "See All PDA Messages" usr.client.prefs.chat_toggles ^= CHAT_GHOSTPDA to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_GHOSTPDA) ? "see all pda messages in the world" : "only see pda messages from nearby mobs"].") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Ghost PDA|[usr.client.prefs.chat_toggles & CHAT_GHOSTPDA]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Ghost/chatterbox/toggle_ghost_pda/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/toggle_ghost_pda/Get_checked(client/C) return C.prefs.chat_toggles & CHAT_GHOSTPDA -/datum/menu/Settings/Ghost/chatterbox/Events +/datum/verbs/menu/Settings/Ghost/chatterbox/Events name = "Events" - -//please be aware that the following two verbs have inverted stat output, so that "Toggle Deathrattle|1" still means you activated it -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox/Events, toggle_deathrattle)() - set name = "Toggle Deathrattle" + +//please be aware that the following two verbs have inverted stat output, so that "Toggle Deathrattle|1" still means you activated it +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox/Events, toggle_deathrattle)() + set name = "Toggle Deathrattle" set category = "Preferences" set desc = "Death" usr.client.prefs.toggles ^= DISABLE_DEATHRATTLE usr.client.prefs.save_preferences() to_chat(usr, "You will [(usr.client.prefs.toggles & DISABLE_DEATHRATTLE) ? "no longer" : "now"] get messages when a sentient mob dies.") SSblackbox.add_details("preferences_verb", "Toggle Deathrattle|[!(usr.client.prefs.toggles & DISABLE_DEATHRATTLE)]") //If you are copy-pasting this, maybe you should spend some time reading the comments. -/datum/menu/Settings/Ghost/chatterbox/Events/toggle_deathrattle/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/Events/toggle_deathrattle/Get_checked(client/C) return !(C.prefs.toggles & DISABLE_DEATHRATTLE) -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost/chatterbox/Events, toggle_arrivalrattle)() - set name = "Toggle Arrivalrattle" +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost/chatterbox/Events, toggle_arrivalrattle)() + set name = "Toggle Arrivalrattle" set category = "Preferences" set desc = "New Player Arrival" usr.client.prefs.toggles ^= DISABLE_ARRIVALRATTLE to_chat(usr, "You will [(usr.client.prefs.toggles & DISABLE_ARRIVALRATTLE) ? "no longer" : "now"] get messages when someone joins the station.") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb", "Toggle Arrivalrattle|[!(usr.client.prefs.toggles & DISABLE_ARRIVALRATTLE)]") //If you are copy-pasting this, maybe you should rethink where your life went so wrong. -/datum/menu/Settings/Ghost/chatterbox/Events/toggle_arrivalrattle/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/chatterbox/Events/toggle_arrivalrattle/Get_checked(client/C) return !(C.prefs.toggles & DISABLE_ARRIVALRATTLE) -TOGGLE_CHECKBOX(/datum/menu/Settings/Ghost, togglemidroundantag)() - set name = "Toggle Midround Antagonist" +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Ghost, togglemidroundantag)() + set name = "Toggle Midround Antagonist" set category = "Preferences" set desc = "Midround Antagonist" usr.client.prefs.toggles ^= MIDROUND_ANTAG usr.client.prefs.save_preferences() to_chat(usr, "You will [(usr.client.prefs.toggles & MIDROUND_ANTAG) ? "now" : "no longer"] be considered for midround antagonist positions.") SSblackbox.add_details("preferences_verb","Toggle Midround Antag|[usr.client.prefs.toggles & MIDROUND_ANTAG]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Ghost/togglemidroundantag/Get_checked(client/C) +/datum/verbs/menu/Settings/Ghost/togglemidroundantag/Get_checked(client/C) return C.prefs.toggles & MIDROUND_ANTAG -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggletitlemusic)() - set name = "Hear/Silence LobbyMusic" - set category = "Preferences" +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggletitlemusic)() + set name = "Hear/Silence LobbyMusic" + set category = "Preferences" set desc = "Hear Music In Lobby" usr.client.prefs.toggles ^= SOUND_LOBBY usr.client.prefs.save_preferences() @@ -125,33 +125,33 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggletitlemusic)() to_chat(usr, "You will now hear music in the game lobby.") if(isnewplayer(usr)) usr.client.playtitlemusic() - else + else to_chat(usr, "You will no longer hear music in the game lobby.") usr.stop_sound_channel(CHANNEL_LOBBYMUSIC) SSblackbox.add_details("preferences_verb","Toggle Lobby Music|[usr.client.prefs.toggles & SOUND_LOBBY]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Sound/toggletitlemusic/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/toggletitlemusic/Get_checked(client/C) return C.prefs.toggles & SOUND_LOBBY - -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, togglemidis)() - set name = "Hear/Silence Midis" - set category = "Preferences" + +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, togglemidis)() + set name = "Hear/Silence Midis" + set category = "Preferences" set desc = "Hear Admin Triggered Sounds (Midis)" usr.client.prefs.toggles ^= SOUND_MIDI usr.client.prefs.save_preferences() if(usr.client.prefs.toggles & SOUND_MIDI) to_chat(usr, "You will now hear any sounds uploaded by admins.") - else + else to_chat(usr, "You will no longer hear sounds uploaded by admins") usr.stop_sound_channel(CHANNEL_ADMIN) SSblackbox.add_details("preferences_verb","Toggle Hearing Midis|[usr.client.prefs.toggles & SOUND_MIDI]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Sound/togglemidis/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/togglemidis/Get_checked(client/C) return C.prefs.toggles & SOUND_MIDI - - -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_instruments)() + + +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggle_instruments)() set name = "Hear/Silence Instruments" - set category = "Preferences" + set category = "Preferences" set desc = "Hear In-game Instruments" usr.client.prefs.toggles ^= SOUND_INSTRUMENTS usr.client.prefs.save_preferences() @@ -160,57 +160,57 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_instruments)() else to_chat(usr, "You will no longer hear musical instruments.") SSblackbox.add_details("preferences_verb","Toggle Instruments|[usr.client.prefs.toggles & SOUND_INSTRUMENTS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Sound/toggle_instruments/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/toggle_instruments/Get_checked(client/C) return C.prefs.toggles & SOUND_INSTRUMENTS - -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, Toggle_Soundscape)() - set name = "Hear/Silence Ambience" - set category = "Preferences" + +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, Toggle_Soundscape)() + set name = "Hear/Silence Ambience" + set category = "Preferences" set desc = "Hear Ambient Sound Effects" usr.client.prefs.toggles ^= SOUND_AMBIENCE usr.client.prefs.save_preferences() if(usr.client.prefs.toggles & SOUND_AMBIENCE) to_chat(usr, "You will now hear ambient sounds.") - else + else to_chat(usr, "You will no longer hear ambient sounds.") usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1) usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2) SSblackbox.add_details("preferences_verb","Toggle Ambience|[usr.client.prefs.toggles & SOUND_AMBIENCE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Sound/Toggle_Soundscape/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/Toggle_Soundscape/Get_checked(client/C) return C.prefs.toggles & SOUND_AMBIENCE - -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_ship_ambience)() + +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggle_ship_ambience)() set name = "Hear/Silence Ship Ambience" - set category = "Preferences" + set category = "Preferences" set desc = "Hear Ship Ambience Roar" usr.client.prefs.toggles ^= SOUND_SHIP_AMBIENCE usr.client.prefs.save_preferences() if(usr.client.prefs.toggles & SOUND_SHIP_AMBIENCE) to_chat(usr, "You will now hear ship ambience.") - else + else to_chat(usr, "You will no longer hear ship ambience.") usr << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2) usr.client.ambience_playing = 0 SSblackbox.add_details("preferences_verb", "Toggle Ship Ambience|[usr.client.prefs.toggles & SOUND_SHIP_AMBIENCE]") //If you are copy-pasting this, I bet you read this comment expecting to see the same thing :^) -/datum/menu/Settings/Sound/toggle_ship_ambience/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/toggle_ship_ambience/Get_checked(client/C) return C.prefs.toggles & SOUND_SHIP_AMBIENCE - -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggle_announcement_sound)() + +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggle_announcement_sound)() set name = "Hear/Silence Announcements" - set category = "Preferences" + set category = "Preferences" set desc = "Hear Announcement Sound" usr.client.prefs.toggles ^= SOUND_ANNOUNCEMENTS to_chat(usr, "You will now [(usr.client.prefs.toggles & SOUND_ANNOUNCEMENTS) ? "hear announcement sounds" : "no longer hear announcements"].") usr.client.prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Announcement Sound|[usr.client.prefs.toggles & SOUND_ANNOUNCEMENTS]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/Sound/toggle_announcement_sound/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/toggle_announcement_sound/Get_checked(client/C) return C.prefs.toggles & SOUND_ANNOUNCEMENTS -TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggleprayersounds)() +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggleprayersounds)() set name = "Hear/Silence Prayer Sounds" set category = "Preferences" set desc = "Hear Prayer Sounds" @@ -218,14 +218,14 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggleprayersounds)() usr.client.prefs.save_preferences() if(usr.client.prefs.toggles & SOUND_PRAYERS) to_chat(usr, "You will now hear prayer sounds.") - else + else to_chat(usr, "You will no longer prayer sounds.") SSblackbox.add_details("admin_toggle", "Toggle Prayer Sounds|[usr.client.prefs.toggles & SOUND_PRAYERS]") -/datum/menu/Settings/Sound/toggleprayersounds/Get_checked(client/C) +/datum/verbs/menu/Settings/Sound/toggleprayersounds/Get_checked(client/C) return C.prefs.toggles & SOUND_PRAYERS -/datum/menu/Settings/Sound/verb/stop_client_sounds() +/datum/verbs/menu/Settings/Sound/verb/stop_client_sounds() set name = "Stop Sounds" set category = "Preferences" set desc = "Stop Current Sounds" @@ -233,7 +233,7 @@ TOGGLE_CHECKBOX(/datum/menu/Settings/Sound, toggleprayersounds)() SSblackbox.add_details("preferences_verb","Stop Self Sounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -TOGGLE_CHECKBOX(/datum/menu/Settings, listen_ooc)() +TOGGLE_CHECKBOX(/datum/verbs/menu/Settings, listen_ooc)() set name = "Show/Hide OOC" set category = "Preferences" set desc = "Show OOC Chat" @@ -241,171 +241,171 @@ TOGGLE_CHECKBOX(/datum/menu/Settings, listen_ooc)() usr.client.prefs.save_preferences() to_chat(usr, "You will [(usr.client.prefs.chat_toggles & CHAT_OOC) ? "now" : "no longer"] see messages on the OOC channel.") SSblackbox.add_details("preferences_verb","Toggle Seeing OOC|[usr.client.prefs.chat_toggles & CHAT_OOC]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/datum/menu/Settings/listen_ooc/Get_checked(client/C) +/datum/verbs/menu/Settings/listen_ooc/Get_checked(client/C) return C.prefs.chat_toggles & CHAT_OOC - -GLOBAL_LIST_INIT(ghost_forms, list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \ - "ghost_blue","ghost_yellow","ghost_green","ghost_pink", \ - "ghost_cyan","ghost_dblue","ghost_dred","ghost_dgreen", \ - "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink", "ghost_purpleswirl","ghost_funkypurp","ghost_pinksherbert","ghost_blazeit",\ - "ghost_mellow","ghost_rainbow","ghost_camo","ghost_fire", "catghost")) -/client/proc/pick_form() - if(!is_content_unlocked()) - alert("This setting is for accounts with BYOND premium only.") - return - var/new_form = input(src, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms - if(new_form) - prefs.ghost_form = new_form - prefs.save_preferences() - if(isobserver(mob)) - var/mob/dead/observer/O = mob - O.update_icon(new_form) - -GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOST_ORBIT_SQUARE,GHOST_ORBIT_HEXAGON,GHOST_ORBIT_PENTAGON)) - -/client/proc/pick_ghost_orbit() - if(!is_content_unlocked()) - alert("This setting is for accounts with BYOND premium only.") - return - var/new_orbit = input(src, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_orbits - if(new_orbit) - prefs.ghost_orbit = new_orbit - prefs.save_preferences() - if(isobserver(mob)) - var/mob/dead/observer/O = mob - O.ghost_orbit = new_orbit - -/client/proc/pick_ghost_accs() - var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,"full accessories", "only directional sprites", "default sprites") - if(new_ghost_accs) - switch(new_ghost_accs) - if("full accessories") - prefs.ghost_accs = GHOST_ACCS_FULL - if("only directional sprites") - prefs.ghost_accs = GHOST_ACCS_DIR - if("default sprites") - prefs.ghost_accs = GHOST_ACCS_NONE - prefs.save_preferences() - if(isobserver(mob)) - var/mob/dead/observer/O = mob - O.update_icon() - -/client/verb/pick_ghost_customization() - set name = "Ghost Customization" - set category = "Preferences" - set desc = "Customize your ghastly appearance." - if(is_content_unlocked()) - switch(alert("Which setting do you want to change?",,"Ghost Form","Ghost Orbit","Ghost Accessories")) - if("Ghost Form") - pick_form() - if("Ghost Orbit") - pick_ghost_orbit() - if("Ghost Accessories") - pick_ghost_accs() - else - pick_ghost_accs() - -/client/verb/pick_ghost_others() - set name = "Ghosts of Others" - set category = "Preferences" - set desc = "Change display settings for the ghosts of other players." - var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,"Their Setting", "Default Sprites", "White Ghost") - if(new_ghost_others) - switch(new_ghost_others) - if("Their Setting") - prefs.ghost_others = GHOST_OTHERS_THEIR_SETTING - if("Default Sprites") - prefs.ghost_others = GHOST_OTHERS_DEFAULT_SPRITE - if("White Ghost") - prefs.ghost_others = GHOST_OTHERS_SIMPLE - prefs.save_preferences() - if(isobserver(mob)) - var/mob/dead/observer/O = mob - O.update_sight() - -/client/verb/toggle_intent_style() - set name = "Toggle Intent Selection Style" - set category = "Preferences" - set desc = "Toggle between directly clicking the desired intent or clicking to rotate through." - prefs.toggles ^= INTENT_STYLE - to_chat(src, "[(prefs.toggles & INTENT_STYLE) ? "Clicking directly on intents selects them." : "Clicking on intents rotates selection clockwise."]") - prefs.save_preferences() + +GLOBAL_LIST_INIT(ghost_forms, list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \ + "ghost_blue","ghost_yellow","ghost_green","ghost_pink", \ + "ghost_cyan","ghost_dblue","ghost_dred","ghost_dgreen", \ + "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink", "ghost_purpleswirl","ghost_funkypurp","ghost_pinksherbert","ghost_blazeit",\ + "ghost_mellow","ghost_rainbow","ghost_camo","ghost_fire", "catghost")) +/client/proc/pick_form() + if(!is_content_unlocked()) + alert("This setting is for accounts with BYOND premium only.") + return + var/new_form = input(src, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms + if(new_form) + prefs.ghost_form = new_form + prefs.save_preferences() + if(isobserver(mob)) + var/mob/dead/observer/O = mob + O.update_icon(new_form) + +GLOBAL_LIST_INIT(ghost_orbits, list(GHOST_ORBIT_CIRCLE,GHOST_ORBIT_TRIANGLE,GHOST_ORBIT_SQUARE,GHOST_ORBIT_HEXAGON,GHOST_ORBIT_PENTAGON)) + +/client/proc/pick_ghost_orbit() + if(!is_content_unlocked()) + alert("This setting is for accounts with BYOND premium only.") + return + var/new_orbit = input(src, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_orbits + if(new_orbit) + prefs.ghost_orbit = new_orbit + prefs.save_preferences() + if(isobserver(mob)) + var/mob/dead/observer/O = mob + O.ghost_orbit = new_orbit + +/client/proc/pick_ghost_accs() + var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,"full accessories", "only directional sprites", "default sprites") + if(new_ghost_accs) + switch(new_ghost_accs) + if("full accessories") + prefs.ghost_accs = GHOST_ACCS_FULL + if("only directional sprites") + prefs.ghost_accs = GHOST_ACCS_DIR + if("default sprites") + prefs.ghost_accs = GHOST_ACCS_NONE + prefs.save_preferences() + if(isobserver(mob)) + var/mob/dead/observer/O = mob + O.update_icon() + +/client/verb/pick_ghost_customization() + set name = "Ghost Customization" + set category = "Preferences" + set desc = "Customize your ghastly appearance." + if(is_content_unlocked()) + switch(alert("Which setting do you want to change?",,"Ghost Form","Ghost Orbit","Ghost Accessories")) + if("Ghost Form") + pick_form() + if("Ghost Orbit") + pick_ghost_orbit() + if("Ghost Accessories") + pick_ghost_accs() + else + pick_ghost_accs() + +/client/verb/pick_ghost_others() + set name = "Ghosts of Others" + set category = "Preferences" + set desc = "Change display settings for the ghosts of other players." + var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,"Their Setting", "Default Sprites", "White Ghost") + if(new_ghost_others) + switch(new_ghost_others) + if("Their Setting") + prefs.ghost_others = GHOST_OTHERS_THEIR_SETTING + if("Default Sprites") + prefs.ghost_others = GHOST_OTHERS_DEFAULT_SPRITE + if("White Ghost") + prefs.ghost_others = GHOST_OTHERS_SIMPLE + prefs.save_preferences() + if(isobserver(mob)) + var/mob/dead/observer/O = mob + O.update_sight() + +/client/verb/toggle_intent_style() + set name = "Toggle Intent Selection Style" + set category = "Preferences" + set desc = "Toggle between directly clicking the desired intent or clicking to rotate through." + prefs.toggles ^= INTENT_STYLE + to_chat(src, "[(prefs.toggles & INTENT_STYLE) ? "Clicking directly on intents selects them." : "Clicking on intents rotates selection clockwise."]") + prefs.save_preferences() SSblackbox.add_details("preferences_verb","Toggle Intent Selection|[prefs.toggles & INTENT_STYLE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/verb/toggle_ghost_hud_pref() - set name = "Toggle Ghost HUD" - set category = "Preferences" - set desc = "Hide/Show Ghost HUD" - - prefs.ghost_hud = !prefs.ghost_hud - to_chat(src, "Ghost HUD will now be [prefs.ghost_hud ? "visible" : "hidden"].") - prefs.save_preferences() - if(isobserver(mob)) - mob.hud_used.show_hud() + +/client/verb/toggle_ghost_hud_pref() + set name = "Toggle Ghost HUD" + set category = "Preferences" + set desc = "Hide/Show Ghost HUD" + + prefs.ghost_hud = !prefs.ghost_hud + to_chat(src, "Ghost HUD will now be [prefs.ghost_hud ? "visible" : "hidden"].") + prefs.save_preferences() + if(isobserver(mob)) + mob.hud_used.show_hud() SSblackbox.add_details("preferences_verb","Toggle Ghost HUD|[prefs.ghost_hud]") - -/client/verb/toggle_inquisition() // warning: unexpected inquisition - set name = "Toggle Inquisitiveness" - set desc = "Sets whether your ghost examines everything on click by default" - set category = "Preferences" - - prefs.inquisitive_ghost = !prefs.inquisitive_ghost - prefs.save_preferences() - if(prefs.inquisitive_ghost) - to_chat(src, "You will now examine everything you click on.") - else - to_chat(src, "You will no longer examine things you click on.") + +/client/verb/toggle_inquisition() // warning: unexpected inquisition + set name = "Toggle Inquisitiveness" + set desc = "Sets whether your ghost examines everything on click by default" + set category = "Preferences" + + prefs.inquisitive_ghost = !prefs.inquisitive_ghost + prefs.save_preferences() + if(prefs.inquisitive_ghost) + to_chat(src, "You will now examine everything you click on.") + else + to_chat(src, "You will no longer examine things you click on.") SSblackbox.add_details("preferences_verb","Toggle Ghost Inquisitiveness|[prefs.inquisitive_ghost]") - -//Admin Preferences -/client/proc/toggleadminhelpsound() - set name = "Hear/Silence Adminhelps" - set category = "Preferences" - set desc = "Toggle hearing a notification when admin PMs are received" - if(!holder) - return - prefs.toggles ^= SOUND_ADMINHELP - prefs.save_preferences() - to_chat(usr, "You will [(prefs.toggles & SOUND_ADMINHELP) ? "now" : "no longer"] hear a sound when adminhelps arrive.") + +//Admin Preferences +/client/proc/toggleadminhelpsound() + set name = "Hear/Silence Adminhelps" + set category = "Preferences" + set desc = "Toggle hearing a notification when admin PMs are received" + if(!holder) + return + prefs.toggles ^= SOUND_ADMINHELP + prefs.save_preferences() + to_chat(usr, "You will [(prefs.toggles & SOUND_ADMINHELP) ? "now" : "no longer"] hear a sound when adminhelps arrive.") SSblackbox.add_details("admin_toggle","Toggle Adminhelp Sound|[prefs.toggles & SOUND_ADMINHELP]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/toggleannouncelogin() - set name = "Do/Don't Announce Login" - set category = "Preferences" - set desc = "Toggle if you want an announcement to admins when you login during a round" - if(!holder) - return - prefs.toggles ^= ANNOUNCE_LOGIN - prefs.save_preferences() - to_chat(usr, "You will [(prefs.toggles & ANNOUNCE_LOGIN) ? "now" : "no longer"] have an announcement to other admins when you login.") + +/client/proc/toggleannouncelogin() + set name = "Do/Don't Announce Login" + set category = "Preferences" + set desc = "Toggle if you want an announcement to admins when you login during a round" + if(!holder) + return + prefs.toggles ^= ANNOUNCE_LOGIN + prefs.save_preferences() + to_chat(usr, "You will [(prefs.toggles & ANNOUNCE_LOGIN) ? "now" : "no longer"] have an announcement to other admins when you login.") SSblackbox.add_details("admin_toggle","Toggle Login Announcement|[prefs.toggles & ANNOUNCE_LOGIN]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/toggle_hear_radio() - set name = "Show/Hide Radio Chatter" - set category = "Preferences" - set desc = "Toggle seeing radiochatter from nearby radios and speakers" - if(!holder) return - prefs.chat_toggles ^= CHAT_RADIO - prefs.save_preferences() - to_chat(usr, "You will [(prefs.chat_toggles & CHAT_RADIO) ? "now" : "no longer"] see radio chatter from nearby radios or speakers") + +/client/proc/toggle_hear_radio() + set name = "Show/Hide Radio Chatter" + set category = "Preferences" + set desc = "Toggle seeing radiochatter from nearby radios and speakers" + if(!holder) return + prefs.chat_toggles ^= CHAT_RADIO + prefs.save_preferences() + to_chat(usr, "You will [(prefs.chat_toggles & CHAT_RADIO) ? "now" : "no longer"] see radio chatter from nearby radios or speakers") SSblackbox.add_details("admin_toggle","Toggle Radio Chatter|[prefs.chat_toggles & CHAT_RADIO]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/deadchat() - set name = "Show/Hide Deadchat" - set category = "Preferences" - set desc ="Toggles seeing deadchat" - prefs.chat_toggles ^= CHAT_DEAD - prefs.save_preferences() - to_chat(src, "You will [(prefs.chat_toggles & CHAT_DEAD) ? "now" : "no longer"] see deadchat.") + +/client/proc/deadchat() + set name = "Show/Hide Deadchat" + set category = "Preferences" + set desc ="Toggles seeing deadchat" + prefs.chat_toggles ^= CHAT_DEAD + prefs.save_preferences() + to_chat(src, "You will [(prefs.chat_toggles & CHAT_DEAD) ? "now" : "no longer"] see deadchat.") SSblackbox.add_details("admin_toggle","Toggle Deadchat Visibility|[prefs.chat_toggles & CHAT_DEAD]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/client/proc/toggleprayers() - set name = "Show/Hide Prayers" - set category = "Preferences" - set desc = "Toggles seeing prayers" - prefs.chat_toggles ^= CHAT_PRAYER - prefs.save_preferences() - to_chat(src, "You will [(prefs.chat_toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat.") + +/client/proc/toggleprayers() + set name = "Show/Hide Prayers" + set category = "Preferences" + set desc = "Toggles seeing prayers" + prefs.chat_toggles ^= CHAT_PRAYER + prefs.save_preferences() + to_chat(src, "You will [(prefs.chat_toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat.") SSblackbox.add_details("admin_toggle","Toggle Prayer Visibility|[prefs.chat_toggles & CHAT_PRAYER]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - + diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 5b1f43d58c..374ff4bd22 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -57,3 +57,13 @@ nutrition -= HUNGER_FACTOR/10 if((disabilities & FAT) && m_intent == MOVE_INTENT_RUN && bodytemperature <= 360) bodytemperature += 2 + +/mob/living/carbon/Moved(oldLoc, Dir) + . = ..() + for(var/obj/O in internal_organs) + O.on_mob_move(dir, src, oldLoc) + +/mob/living/carbon/setDir(newdir) + . = ..() + for(var/obj/O in internal_organs) + O.on_mob_turn(newdir, src) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 43d8a924a1..9d6ab8410c 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -178,11 +178,18 @@ if(mob.throwing) mob.throwing.finalize(FALSE) - for(var/obj/O in mob) - O.on_mob_move(direct, src) - return . +/mob/Moved(oldLoc, dir) + . = ..() + for(var/obj/O in contents) + O.on_mob_move(dir, src, oldLoc) + +/mob/setDir(newDir) + . = ..() + for(var/obj/O in contents) + O.on_mob_turn(newDir, src) + ///Process_Grab() ///Called by client/Move() @@ -209,10 +216,10 @@ return var/mob/living/L = mob switch(L.incorporeal_move) - if(INCORPOREAL_MOVE_BASIC) + if(INCORPOREAL_MOVE_BASIC) L.loc = get_step(L, direct) L.setDir(direct) - if(INCORPOREAL_MOVE_SHADOW) + if(INCORPOREAL_MOVE_SHADOW) if(prob(50)) var/locx var/locy @@ -242,15 +249,15 @@ L.loc = locate(locx,locy,mobloc.z) var/limit = 2//For only two trailing shadows. for(var/turf/T in getline(mobloc, L.loc)) - new /obj/effect/temp_visual/dir_setting/ninja/shadow(T, L.dir) + new /obj/effect/temp_visual/dir_setting/ninja/shadow(T, L.dir) limit-- if(limit<=0) break else - new /obj/effect/temp_visual/dir_setting/ninja/shadow(mobloc, L.dir) + new /obj/effect/temp_visual/dir_setting/ninja/shadow(mobloc, L.dir) L.loc = get_step(L, direct) L.setDir(direct) - if(INCORPOREAL_MOVE_JAUNT) //Incorporeal move, but blocked by holy-watered tiles and salt piles. + if(INCORPOREAL_MOVE_JAUNT) //Incorporeal move, but blocked by holy-watered tiles and salt piles. var/turf/open/floor/stepTurf = get_step(L, direct) for(var/obj/effect/decal/cleanable/salt/S in stepTurf) to_chat(L, "[S] bars your passage!") @@ -295,12 +302,12 @@ return A else var/atom/movable/AM = A - if(AM == buckled) + if(AM == buckled) continue - if(ismob(AM)) - var/mob/M = AM - if(M.buckled) - continue + if(ismob(AM)) + var/mob/M = AM + if(M.buckled) + continue if(!AM.CanPass(src) || AM.density) if(AM.anchored) return AM diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index f72458af4e..687e3396bd 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -190,6 +190,18 @@ build_path = /obj/item/organ/eyes/robotic/shield category = list("Misc", "Medical Designs") +/datum/design/cyberimp_gloweyes + name = "Luminescent Eyes" + desc = "A pair of cybernetic eyes that can emit multicolored light" + id = "ci-gloweyes" + req_tech = list("materials" = 3, "biotech" = 3, "engineering" = 4) + build_type = PROTOLATHE | MECHFAB + construction_time = 40 + materials = list(MAT_METAL = 600, MAT_GLASS = 1000) + build_path = /obj/item/organ/eyes/robotic/glow + category = list("Misc", "Medical Designs") + + /datum/design/cyberimp_breather name = "Breathing Tube Implant" desc = "This simple implant adds an internals connector to your back, allowing you to use internals without a mask and protecting you from being choked." diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 83b70d33d9..f91ef8f547 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -132,3 +132,176 @@ /obj/item/organ/eyes/robotic/shield/emp_act(severity) return + +#define RGB2EYECOLORSTRING(definitionvar) ("[copytext(definitionvar,2,3)][copytext(definitionvar,4,5)][copytext(definitionvar,6,7)]") + +/obj/item/organ/eyes/robotic/glow + name = "High Luminosity Eyes" + desc = "Special glowing eyes, used by snowflakes who want to be special." + origin_tech = "material=3;biotech=3;engineering=3;magnets=4" + eye_color = "000" + actions_types = list(/datum/action/item_action/organ_action/use, /datum/action/item_action/organ_action/toggle) + var/current_color_string = "#ffffff" + var/active = FALSE + var/max_light_beam_distance = 5 + var/light_beam_distance = 5 + var/light_object_range = 1 + var/light_object_power = 2 + var/list/obj/effect/abstract/eye_lighting/eye_lighting + var/obj/effect/abstract/eye_lighting/on_mob + var/image/mob_overlay + +/obj/item/organ/eyes/robotic/glow/Initialize() + . = ..() + mob_overlay = image('icons/mob/human_face.dmi', "eyes_glow_gs") + +/obj/item/organ/eyes/robotic/glow/Destroy() + terminate_effects() + . = ..() + +/obj/item/organ/eyes/robotic/glow/Remove() + terminate_effects() + . = ..() + +/obj/item/organ/eyes/robotic/glow/proc/terminate_effects() + if(owner && active) + deactivate() + active = FALSE + clear_visuals(TRUE) + STOP_PROCESSING(SSfastprocess, src) + +/obj/item/organ/eyes/robotic/glow/ui_action_click(owner, action) + if(istype(action, /datum/action/item_action/organ_action/toggle)) + toggle_active() + else if(istype(action, /datum/action/item_action/organ_action/use)) + prompt_for_controls(owner) + +/obj/item/organ/eyes/robotic/glow/proc/toggle_active() + if(active) + deactivate() + else + activate() + +/obj/item/organ/eyes/robotic/glow/proc/prompt_for_controls(mob/user) + var/C = input(owner, "Select Color", "Select color", "#ffffff") as null|color + if(!C || QDELETED(src) || QDELETED(user) || QDELETED(owner) || owner != user) + return + var/range = input(user, "Enter range (0 - [max_light_beam_distance])", "Range Select", 0) as null|num + + set_distance(Clamp(range, 0, max_light_beam_distance)) + assume_rgb(C) + +/obj/item/organ/eyes/robotic/glow/proc/assume_rgb(newcolor) + current_color_string = newcolor + eye_color = RGB2EYECOLORSTRING(current_color_string) + sync_light_effects() + cycle_mob_overlay() + if(!QDELETED(owner) && ishuman(owner)) //Other carbon mobs don't have eye color. + owner.dna.species.handle_body(owner) + +/obj/item/organ/eyes/robotic/glow/proc/cycle_mob_overlay() + remove_mob_overlay() + mob_overlay.color = current_color_string + add_mob_overlay() + +/obj/item/organ/eyes/robotic/glow/proc/add_mob_overlay() + if(!QDELETED(owner)) + owner.add_overlay(mob_overlay) + +/obj/item/organ/eyes/robotic/glow/proc/remove_mob_overlay() + if(!QDELETED(owner)) + owner.cut_overlay(mob_overlay) + +/obj/item/organ/eyes/robotic/glow/emp_act() + if(active) + deactivate(silent = TRUE) + +/obj/item/organ/eyes/robotic/glow/on_mob_move() + if(QDELETED(owner) || !active) + return + update_visuals() + +/obj/item/organ/eyes/robotic/glow/on_mob_turn() + if(QDELETED(owner) || !active) + return + update_visuals() + +/obj/item/organ/eyes/robotic/glow/proc/activate(silent = FALSE) + start_visuals() + if(!silent) + to_chat(owner, "Your [src] clicks and makes a whining noise, before shooting out a beam of light!") + active = TRUE + cycle_mob_overlay() + +/obj/item/organ/eyes/robotic/glow/proc/deactivate(silent = FALSE) + clear_visuals() + if(!silent) + to_chat(owner, "Your [src] shuts off!") + active = FALSE + remove_mob_overlay() + +/obj/item/organ/eyes/robotic/glow/proc/update_visuals() + if((LAZYLEN(eye_lighting) < light_beam_distance) || !on_mob) + regenerate_light_effects() + var/turf/scanfrom = get_turf(owner) + var/scandir = owner.dir + if(!istype(scanfrom)) + clear_visuals() + var/turf/scanning = scanfrom + var/stop = FALSE + on_mob.forceMove(scanning) + for(var/i in 1 to light_beam_distance) + scanning = get_step(scanning, scandir) + if(scanning.opacity || scanning.has_opaque_atom) + stop = TRUE + var/obj/effect/abstract/eye_lighting/L = LAZYACCESS(eye_lighting, i) + if(stop) + L.forceMove(src) + else + L.forceMove(scanning) + +/obj/item/organ/eyes/robotic/glow/proc/clear_visuals(delete_everything = FALSE) + if(delete_everything) + QDEL_LIST(eye_lighting) + QDEL_NULL(on_mob) + else + for(var/i in eye_lighting) + var/obj/effect/abstract/eye_lighting/L = i + L.forceMove(src) + if(!QDELETED(on_mob)) + on_mob.forceMove(src) + +/obj/item/organ/eyes/robotic/glow/proc/start_visuals() + if(!islist(eye_lighting)) + regenerate_light_effects() + if((eye_lighting.len < light_beam_distance) || !on_mob) + regenerate_light_effects() + sync_light_effects() + update_visuals() + +/obj/item/organ/eyes/robotic/glow/proc/set_distance(dist) + light_beam_distance = dist + regenerate_light_effects() + +/obj/item/organ/eyes/robotic/glow/proc/regenerate_light_effects() + clear_visuals(TRUE) + on_mob = new(src) + for(var/i in 1 to light_beam_distance) + LAZYADD(eye_lighting,new /obj/effect/abstract/eye_lighting(src)) + sync_light_effects() + +/obj/item/organ/eyes/robotic/glow/proc/sync_light_effects() + for(var/I in eye_lighting) + var/obj/effect/abstract/eye_lighting/L = I + L.set_light(light_object_range, light_object_power, current_color_string) + if(on_mob) + on_mob.set_light(1, 1, current_color_string) + +/obj/effect/abstract/eye_lighting + var/obj/item/organ/eyes/robotic/glow/parent + +/obj/effect/abstract/eye_lighting/Initialize() + . = ..() + parent = loc + if(!istype(parent)) + return INITIALIZE_HINT_QDEL diff --git a/code/world.dm b/code/world.dm index b7beb52d4d..4800975f6b 100644 --- a/code/world.dm +++ b/code/world.dm @@ -34,7 +34,7 @@ load_motd() load_admins() // load_mentors() - load_menu() + LoadVerbs(/datum/verbs/menu) if(config.usewhitelist) load_whitelist() LoadBans() diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index e1dbb99158ff0a9d3e6ca9ffca1cc395d68f4626..1d8098c92b1b504c329ec3a1656f2a5127b48852 100644 GIT binary patch delta 6385 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 TN0j0&ge-{rk2K2FZC?Ek_`c}j delta 6265 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 Date: Wed, 14 Jun 2017 05:07:20 -0500 Subject: [PATCH 19/19] final commit for merge --- .../objects/items/devices/PDA/virus_cart.dm | 108 ++++++++++++++++++ icons/effects/throw_target.dmi | Bin 0 -> 2201 bytes sound/voice/ApproachingTG.ogg | Bin 0 -> 40121 bytes 3 files changed, 108 insertions(+) create mode 100644 code/game/objects/items/devices/PDA/virus_cart.dm create mode 100644 icons/effects/throw_target.dmi create mode 100644 sound/voice/ApproachingTG.ogg diff --git a/code/game/objects/items/devices/PDA/virus_cart.dm b/code/game/objects/items/devices/PDA/virus_cart.dm new file mode 100644 index 0000000000..17c66cac10 --- /dev/null +++ b/code/game/objects/items/devices/PDA/virus_cart.dm @@ -0,0 +1,108 @@ +/obj/item/weapon/cartridge/virus + name = "Generic Virus PDA cart" + var/charges = 5 + +/obj/item/weapon/cartridge/virus/proc/send_virus(obj/item/device/pda/target, mob/living/U) + return + +/obj/item/weapon/cartridge/virus/message_header() + return "[charges] viral files left.


" + +/obj/item/weapon/cartridge/virus/message_special(obj/item/device/pda/target) + if (!istype(loc, /obj/item/device/pda)) + return "" //Sanity check, this shouldn't be possible. + return " (
*Send Virus*)" + +/obj/item/weapon/cartridge/virus/special(mob/living/user, list/params) + var/obj/item/device/pda/P = locate(params["target"])//Leaving it alone in case it may do something useful, I guess. + send_virus(P,user) + +/obj/item/weapon/cartridge/virus/clown + name = "\improper Honkworks 5.0 cartridge" + icon_state = "cart-clown" + desc = "A data cartridge for portable microcomputers. It smells vaguely of banannas" + access_clown = 1 + +/obj/item/weapon/cartridge/virus/clown/send_virus(obj/item/device/pda/target, mob/living/U) + if(charges <= 0) + to_chat(U, "Out of charges.") + return + if(!isnull(target) && !target.toff) + charges-- + to_chat(U, "Virus Sent!") + target.honkamt = (rand(15,20)) + else + to_chat(U, "PDA not found.") + +/obj/item/weapon/cartridge/virus/mime + name = "\improper Gestur-O 1000 cartridge" + icon_state = "cart-mi" + access_mime = 1 + +/obj/item/weapon/cartridge/virus/mime/send_virus(obj/item/device/pda/target, mob/living/U) + if(charges <= 0) + to_chat(U, "Out of charges.") + return + if(!isnull(target) && !target.toff) + charges-- + to_chat(U, "Virus Sent!") + target.silent = 1 + target.ttone = "silence" + else + to_chat(U, "PDA not found.") + +/obj/item/weapon/cartridge/virus/syndicate + name = "\improper Detomatix cartridge" + icon_state = "cart" + access_remote_door = 1 + remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. + charges = 4 + +/obj/item/weapon/cartridge/virus/syndicate/send_virus(obj/item/device/pda/target, mob/living/U) + if(charges <= 0) + to_chat(U, "Out of charges.") + return + if(!isnull(target) && !target.toff) + charges-- + var/difficulty = 0 + if(target.cartridge) + difficulty += target.cartridge.access_medical + difficulty += target.cartridge.access_security + difficulty += target.cartridge.access_engine + difficulty += target.cartridge.access_clown + difficulty += target.cartridge.access_janitor + difficulty += target.cartridge.access_manifest * 2 + else + difficulty += 2 + if(prob(difficulty * 15) || (target.hidden_uplink)) + U.show_message("An error flashes on your [src].", 1) + else + U.show_message("Success!", 1) + target.explode() + else + to_chat(U, "PDA not found.") + +/obj/item/weapon/cartridge/virus/frame + name = "\improper F.R.A.M.E. cartridge" + icon_state = "cart" + var/telecrystals = 0 + +/obj/item/weapon/cartridge/virus/frame/send_virus(obj/item/device/pda/target, mob/living/U) + if(charges <= 0) + to_chat(U, "Out of charges.") + return + if(!isnull(target) && !target.toff) + charges-- + var/lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]" + to_chat(U, "Virus Sent! The unlock code to the target is: [lock_code]") + if(!target.hidden_uplink) + var/obj/item/device/uplink/uplink = new(target) + target.hidden_uplink = uplink + target.lock_code = lock_code + else + target.hidden_uplink.hidden_crystals += target.hidden_uplink.telecrystals //Temporarially hide the PDA's crystals, so you can't steal telecrystals. + target.hidden_uplink.telecrystals = telecrystals + telecrystals = 0 + target.hidden_uplink.active = TRUE + else + to_chat(U, "PDA not found.") diff --git a/icons/effects/throw_target.dmi b/icons/effects/throw_target.dmi new file mode 100644 index 0000000000000000000000000000000000000000..660eafbf2b19ae4ce6e4b76c6d2956f5e0ea6d69 GIT binary patch literal 2201 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 Lv}