diff --git a/code/ATMOSPHERICS/components/components_base.dm b/code/ATMOSPHERICS/components/components_base.dm index 977f102e2e6..70a46e507e8 100644 --- a/code/ATMOSPHERICS/components/components_base.dm +++ b/code/ATMOSPHERICS/components/components_base.dm @@ -148,7 +148,7 @@ Pipenet stuff; housekeeping parents["p[I]"] = reference break -/obj/machinery/atmospherics/components/returnPipenet(obj/machinery/atmospherics/A) +/obj/machinery/atmospherics/components/returnPipenet(obj/machinery/atmospherics/A = nodes[NODE1]) //returns PARENT1 if called without argument for(var/I = 1; I <= device_type; I++) if(A == nodes["n[I]"]) return parents["p[I]"] @@ -159,7 +159,7 @@ Pipenet stuff; housekeeping P = New break -/obj/machinery/atmospherics/components/unsafe_pressure_release(var/mob/user, var/pressures) //untestable; I'll fix this last +/obj/machinery/atmospherics/components/unsafe_pressure_release(var/mob/user, var/pressures) ..() var/turf/T = get_turf(src) diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index a1190f5d705..a56bdd14c0c 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -28,7 +28,7 @@ Filter types: 1: Oxygen: Oxygen ONLY 2: Nitrogen: Nitrogen ONLY 3: Carbon Dioxide: Carbon Dioxide ONLY - 4: Sleeping Agent (NODE2O) + 4: Sleeping Agent (N2O) */ var/frequency = 0 diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 56062f70d83..8b8850744ec 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -119,7 +119,7 @@ return 1 -/obj/machinery/atmospherics/components/trinary/mxer/attack_hand(mob/user) +/obj/machinery/atmospherics/components/trinary/mixer/attack_hand(mob/user) if(..()) return diff --git a/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm index 3c245666193..d568bd297f7 100644 --- a/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary_devices/vent_scrubber.dm @@ -121,7 +121,7 @@ "widenet" = widenet, "filter_co2" = scrub_CO2, "filter_toxins" = scrub_Toxins, - "filter_NODE2o" = scrub_N2O, + "filter_n2o" = scrub_N2O, "sigtype" = "status" ) if(!initial_loc.air_scrub_names[id_tag]) @@ -265,9 +265,9 @@ if("toggle_tox_scrub" in signal.data) scrub_Toxins = !scrub_Toxins - if("NODE2o_scrub" in signal.data) + if("n2o_scrub" in signal.data) scrub_N2O = text2num(signal.data["n2o_scrub"]) - if("toggle_NODE2o_scrub" in signal.data) + if("toggle_n2o_scrub" in signal.data) scrub_N2O = !scrub_N2O if("init" in signal.data) diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index 02ad35248d5..c0fb0e53beb 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -121,11 +121,7 @@ var/pipenetwarnings = 10 /obj/machinery/atmospherics/components/addMember(obj/machinery/atmospherics/A) var/datum/pipeline/P = returnPipenet(A) - for(var/I = 1; I <= parents.len; I++) - if(parents["p[I]"] == P) - P.addMember(A, src) - break - + P.addMember(A, src) /datum/pipeline/proc/temporarily_store_air() diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 9ddae527eec..0da4f75e1bf 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -42,11 +42,12 @@ the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example) */ //flags for pass_flags -#define PASSTABLE 1 -#define PASSGLASS 2 -#define PASSGRILLE 4 -#define PASSBLOB 8 -#define PASSMOB 16 +#define PASSTABLE 1 +#define PASSGLASS 2 +#define PASSGRILLE 4 +#define PASSBLOB 8 +#define PASSMOB 16 +#define LETPASSTHROW 32 //flags for species diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 8a0b055d4b2..21626590306 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -379,3 +379,4 @@ var/dest_y = src_y + distance*cos(rotation); return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y) + diff --git a/code/__HELPERS/icon_smoothing.dm b/code/__HELPERS/icon_smoothing.dm index 16d6f49e3cb..0de55b127be 100644 --- a/code/__HELPERS/icon_smoothing.dm +++ b/code/__HELPERS/icon_smoothing.dm @@ -26,15 +26,18 @@ var/adjacencies = 0 if(A.can_be_unanchored) - var/atom/movable/T = A - if(!T.anchored) + var/atom/movable/AM = A + if(!AM.anchored) return 0 for(var/direction in alldirs) - var/atom/movable/AM = find_type_in_direction(A, direction) - if(AM) + AM = find_type_in_direction(A, direction) + if(istype(AM)) if(AM.anchored) adjacencies |= transform_dir(direction) + else + if(AM) + adjacencies |= transform_dir(direction) else for(var/direction in alldirs) if(find_type_in_direction(A, direction)) @@ -42,11 +45,12 @@ return adjacencies /proc/smooth_icon(atom/A) - spawn(2) + spawn(0) //don't remove this, otherwise smoothing breaks if(A && A.smooth) - clear_overlays(A) var/adjacencies = calculate_adjacencies(A) + clear_overlays(A) + A.top_left_corner = make_nw_corner(adjacencies) A.top_right_corner = make_ne_corner(adjacencies) A.bottom_left_corner = make_sw_corner(adjacencies) @@ -142,35 +146,23 @@ else if(direction & WEST) x_offset -= range - var/list/siblings = source.canSmoothWith - if(istype(source, /turf)) - if(siblings) - for(var/a_type in siblings) - if(ispath(a_type, /obj)) - var/atom/A = locate(a_type) in locate(source.x + x_offset, source.y + y_offset, source.z) - if(A && A.type == a_type) - return A - else - var/turf/T = locate(source.x + x_offset, source.y + y_offset, source.z) - if(T.type == a_type) - return T - return null - var/turf/T = locate(source.x + x_offset, source.y + y_offset, source.z) - return T.type == source.type ? T : null - - if(siblings) - for(var/a_type in siblings) + var/turf/target_turf = locate(source.x + x_offset, source.y + y_offset, source.z) + if(source.canSmoothWith) + var/atom/A + for(var/a_type in source.canSmoothWith) if(ispath(a_type, /turf)) - var/turf/T = locate(source.x + x_offset, source.y + y_offset, source.z) - if(T.type == a_type) - return T + if(a_type == target_turf.type) + return target_turf else - var/atom/A = locate(a_type) in locate(source.x + x_offset, source.y + y_offset, source.z) + A = locate(a_type) in target_turf if(A && A.type == a_type) return A return null - var/atom/A = locate(source.type) in locate(source.x + x_offset, source.y + y_offset, source.z) - return A && A.type == source.type ? A : null + else + if(isturf(source)) + return source.type == target_turf.type ? target_turf : null + var/atom/A = locate(source.type) in target_turf + return A && A.type == source.type ? A : null /proc/clear_overlays(atom/A) A.overlays -= A.top_left_corner @@ -189,4 +181,4 @@ if(SOUTHEAST) return SOUTH_EAST if(SOUTHWEST) - return SOUTH_WEST \ No newline at end of file + return SOUTH_WEST diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 1a7b44d0c4e..264f8cc73f1 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -235,7 +235,9 @@ return "" //Returns a string with reserved characters and spaces before the first word and after the last word removed. -/proc/trim(text) +/proc/trim(text, max_length) + if(max_length) + text = copytext(text, 1, max_length) return trim_left(trim_right(text)) //Returns a string with the first element of the string capitalized. diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 57527a2aa61..d72e5a9049e 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -672,7 +672,7 @@ Turf and target are seperate in case you want to teleport some distance from a t else return get_step(ref, base_dir) -/proc/do_mob(mob/user , mob/target, time = 30, numticks = 5, stealth = 0) //This is quite an ugly solution but i refuse to use the old request system. +/proc/do_mob(mob/user , mob/target, time = 30, numticks = 5, uninterruptible = 0) //This is quite an ugly solution but i refuse to use the old request system. if(!user || !target) return 0 if(numticks == 0) @@ -691,7 +691,7 @@ Turf and target are seperate in case you want to teleport some distance from a t if(user && user.client) user.client.images -= progbar return 0 - if ( user.loc != user_loc || target.loc != target_loc || user.get_active_hand() != holding || user.incapacitated() || user.lying ) + if (!uninterruptible && (user.loc != user_loc || target.loc != target_loc || user.get_active_hand() != holding || user.incapacitated() || user.lying )) if(user && user.client) user.client.images -= progbar return 0 diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index f1db0379efc..2c2b87f9c5f 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -23,7 +23,7 @@ * If you are in the same turf, always true * If you are vertically/horizontally adjacent, ensure there are no border objects * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square. - * Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays. + * Passing through in this case ignores anything with the LETPASSTHROW pass flag, such as tables, racks, and morgue trays. */ /turf/Adjacent(var/atom/neighbor, var/atom/target = null) var/turf/T0 = get_turf(neighbor) @@ -80,28 +80,18 @@ /* This checks if you there is uninterrupted airspace between that turf and this one. - This is defined as any dense ON_BORDER object, or any dense object without throwpass. + This is defined as any dense ON_BORDER object, or any dense object without LETPASSTHROW. The border_only flag allows you to not objects (for source and destination squares) */ /turf/proc/ClickCross(target_dir, border_only, target_atom = null) for(var/obj/O in src) - if( !O.density || O == target_atom || O.throwpass) //check if there's a dense object present on the turf - continue // throwpass is used for anything you can click through (or the firedoor special case, see above) + if( !O.density || O == target_atom || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf + continue // LETPASSTHROW is used for anything you can click through (or the firedoor special case, see above) - if( O.flags&ON_BORDER) // windows have throwpass but are on border, check them first + if( O.flags&ON_BORDER) // windows are on border, check them first if( O.dir & target_dir || O.dir & (O.dir-1) ) // full tile windows are just diagonals mechanically return 0 //O.dir&(O.dir-1) is false for any cardinal direction, but true for diagonal ones else if( !border_only ) // dense, not on border, cannot pass over return 0 return 1 - -/* - Aside: throwpass does not do what I thought it did originally, and is only used for checking whether or not - a thrown object should stop after already successfully entering a square. Currently the throw code involved - only seems to affect hitting mobs, because the checks performed against objects are already performed when - entering or leaving the square. Since throwpass isn't used on mobs, but only on objects, it is effectively - useless. Throwpass may later need to be removed and replaced with a passcheck (bitfield on movable atom passflags). - - Since I don't want to complicate the click code rework by messing with unrelated systems it won't be changed here. -*/ \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 2be1d10aa41..4fb95455a39 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -67,8 +67,6 @@ return if(istype(loc,/obj/mecha)) - if(!locate(/turf) in list(A,A.loc)) // Prevents inventory from being drilled - return var/obj/mecha/M = loc return M.click_action(A,src) @@ -325,4 +323,4 @@ else var/turf/T = screen_loc2turf(modifiers["screen-loc"], get_turf(usr)) T.Click(location, control, params) - return 1 \ No newline at end of file + return 1 diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index 1775761d6a2..e6235d4587e 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -38,6 +38,7 @@ #define ui_storage2 "CENTER+2:20,SOUTH:5" #define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs +#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgies #define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs #define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs #define ui_inv3 "CENTER :16,SOUTH:5" //borgs diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index e9b60141730..c8f7df027e5 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -228,6 +228,13 @@ office by your AI master or any qualified human may resolve this matter. Robotic so as to remain in compliance with the most up-to-date laws." timeout = 300 +//MECHS + +/obj/screen/alert/low_mech_integrity + name = "Mech Damaged" + desc = "Mech integrity is low." + + //OBJECT-BASED /obj/screen/alert/buckled diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 8c442d8dc35..fb209d087e7 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -198,8 +198,6 @@ var/datum/global_hud/global_hud = new() else if(isdrone(mymob)) drone_hud(ui_style) - if(istype(mymob.loc,/obj/mecha) && ishuman(mymob)) - show_hud(HUD_STYLE_REDUCED) //Version denotes which style should be displayed. blank or 0 means "next version" /datum/hud/proc/show_hud(version = 0) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 0ff982967fb..51dc22df59e 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -53,6 +53,14 @@ var/mob/living/silicon/robot/R = usr R.uneq_active() +/obj/screen/robot/lamp + name = "headlamp" + icon_state = "lamp0" + +/obj/screen/robot/lamp/Click() + var/mob/living/silicon/robot/R = usr + R.control_headlamp() + /datum/hud/proc/robot_hud() adding = list() @@ -102,6 +110,12 @@ using.screen_loc = ui_borg_sensor adding += using +//Headlamp control + using = new /obj/screen/robot/lamp() + using.screen_loc = ui_borg_lamp + adding += using + mymobR.lamp_button = using + //Intent using = new /obj/screen/act_intent() using.icon = 'icons/mob/screen_cyborg.dmi' diff --git a/code/datums/helper_datums/global_iterator.dm b/code/datums/helper_datums/global_iterator.dm deleted file mode 100644 index 828f6cfe559..00000000000 --- a/code/datums/helper_datums/global_iterator.dm +++ /dev/null @@ -1,160 +0,0 @@ -/* -README: - -The global_iterator datum is supposed to provide a simple and robust way to -create some constantly "looping" processes with ability to stop and restart them at will. -Generally, the only thing you want to play with (meaning, redefine) is the process() proc. -It must contain all the things you want done. - -Control functions: - new - used to create datum. First argument (optional) - var list(to use in process() proc) as list, - second (optional) - autostart control. - If autostart == TRUE, the loop will be started immediately after datum creation. - - start(list/arguments) - starts the loop. Takes arguments(optional) as a list, which is then used - by process() proc. Returns null if datum already active, 1 if loop started successfully and 0 if there's - an error in supplied arguments (not list or empty list). - - stop() - stops the loop. Returns null if datum is already inactive and 1 on success. - - set_delay(new_delay) - sets the delay between iterations. Pretty selfexplanatory. - Returns 0 on error(new_delay is not numerical), 1 otherwise. - - set_process_args(list/arguments) - passes the supplied arguments to the process() proc. - - active() - Returns 1 if datum is active, 0 otherwise. - - toggle() - toggles datum state. Returns new datum state (see active()). - -Misc functions: - - get_last_exec_time() - Returns the time of last iteration. - - get_last_exec_time_as_text() - Returns the time of last iteration as text - - -Control vars: - - delay - delay between iterations - - check_for_null - if equals TRUE, on each iteration the supplied arguments will be checked for nulls. - If some varible equals null (and null only), the loop is stopped. - Usefull, if some var unexpectedly becomes null - due to object deletion, for example. - Of course, you can also check the variables inside process() proc to prevent runtime errors. - -Data storage vars: - - result - stores the value returned by process() proc -*/ - -/datum/global_iterator - var/control_switch = 0 - var/delay = 10 - var/list/arg_list = new - var/last_exec = null - var/check_for_null = 1 - var/forbid_garbage = 0 - var/result - var/state = 0 - -/datum/global_iterator/New(list/arguments=null,autostart=1) - delay = delay>0?(delay):1 - if(forbid_garbage) //prevents garbage collection with tag != null - tag = "\ref[src]" - set_process_args(arguments) - if(autostart) - start() - return - -/datum/global_iterator/Destroy() - tag = null - arg_list.Cut() - stop() - //Do not call ..() - -/datum/global_iterator/proc/main() - state = 1 - while(src && control_switch) - last_exec = world.timeofday - if(check_for_null && has_null_args()) - stop() - return 0 - result = process(arglist(arg_list)) - for(var/sleep_time=delay;sleep_time>0;sleep_time--) //uhh, this is ugly. But I see no other way to terminate sleeping proc. Such disgrace. - if(!control_switch) - return 0 - sleep(1) - return 0 - -/datum/global_iterator/proc/start(list/arguments=null) - if(active()) - return - if(arguments) - if(!set_process_args(arguments)) - return 0 - if(!state_check()) //the main loop is sleeping, wait for it to terminate. - return - control_switch = 1 - spawn() - state = main() - return 1 - -/datum/global_iterator/proc/stop() - if(!active()) - return - control_switch = 0 - spawn(-1) //report termination error but don't wait for state_check(). - state_check() - return 1 - -/datum/global_iterator/proc/state_check() - var/lag = 0 - while(state) - sleep(1) - if(++lag>10) - CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.") - return 1 - -/datum/global_iterator/process() - return - -/datum/global_iterator/proc/active() - return control_switch - -/datum/global_iterator/proc/has_null_args() - if(null in arg_list) - return 1 - return 0 - - -/datum/global_iterator/proc/set_delay(new_delay) - if(isnum(new_delay)) - delay = max(1, round(new_delay)) - return 1 - else - return 0 - -/datum/global_iterator/proc/get_last_exec_time() - return (last_exec||0) - -/datum/global_iterator/proc/get_last_exec_time_as_text() - return (time2text(last_exec)||"Wasn't executed yet") - -/datum/global_iterator/proc/set_process_args(list/arguments) - if(arguments && istype(arguments, /list) && arguments.len) - arg_list = arguments - return 1 - else -// world << "\red Invalid arguments supplied for [src.type], ref = \ref[src]" - return 0 - -/datum/global_iterator/proc/toggle_null_checks() - check_for_null = !check_for_null - return check_for_null - -/datum/global_iterator/proc/toggle() - if(!stop()) - start() - return active() - - diff --git a/code/datums/spells/lightning.dm b/code/datums/spells/lightning.dm index 54d0a3378b7..3fbefee6c16 100644 --- a/code/datums/spells/lightning.dm +++ b/code/datums/spells/lightning.dm @@ -10,7 +10,7 @@ cooldown_min = 30 selection_type = "view" random_target = 1 - var/energy = 0 + var/start_time = 0 var/ready = 0 var/image/halo = null var/sound/Snd // so far only way i can think of to stop a sound, thank MSO for the idea. @@ -18,7 +18,7 @@ action_icon_state = "lightning" /obj/effect/proc_holder/spell/targeted/lightning/Click() - if(!ready && energy==0) + if(!ready && start_time==0) if(cast_check()) StartChargeup() else @@ -33,16 +33,14 @@ halo = image("icon"='icons/effects/effects.dmi',"icon_state" ="electricity","layer" = EFFECTS_LAYER) user.overlays.Add(halo) playsound(get_turf(usr), Snd, 50, 0) - spawn(0) - while(ready) - energy++ - if(energy >= 100 && ready) - Discharge() - sleep(1) + start_time = world.time + if(do_mob(user,user,100,uninterruptible=1)) + if(ready) + Discharge() /obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr) ready = 0 - energy = 0 + start_time = 0 if(halo) user.overlays.Remove(halo) @@ -72,26 +70,18 @@ playsound(get_turf(usr), 'sound/magic/lightningbolt.ogg', 50, 1) user.Beam(target,icon_state="lightning",icon='icons/effects/effects.dmi',time=5) - switch(energy) - if(1 to 25) - target.electrocute_act(10,"Lightning Bolt") - playsound(get_turf(target), 'sound/magic/LightningShock.ogg', 50, 1, -1) - if(25 to 75) - target.electrocute_act(25,"Lightning Bolt") - playsound(get_turf(target), 'sound/magic/LightningShock.ogg', 50, 1, -1) - if(75 to 100) - //CHAIN LIGHTNING - Bolt(user,target,energy,user) + var/energy = min(world.time - start_time,100) + Bolt(user,target,max(15,energy/2),5,user) //5 bounces for energy/2 burn Reset(user) -/obj/effect/proc_holder/spell/targeted/lightning/proc/Bolt(mob/origin,mob/target,bolt_energy,mob/user = usr) +/obj/effect/proc_holder/spell/targeted/lightning/proc/Bolt(mob/origin,mob/target,bolt_energy,bounces,mob/user = usr) origin.Beam(target,icon_state="lightning",icon='icons/effects/effects.dmi',time=5) var/mob/living/carbon/current = target - if(bolt_energy < 75) - current.electrocute_act(25,"Lightning Bolt") + if(bounces < 1) + current.electrocute_act(bolt_energy,"Lightning Bolt",safety=1) playsound(get_turf(current), 'sound/magic/LightningShock.ogg', 50, 1, -1) else - current.electrocute_act(25,"Lightning Bolt") + current.electrocute_act(bolt_energy,"Lightning Bolt",safety=1) playsound(get_turf(current), 'sound/magic/LightningShock.ogg', 50, 1, -1) var/list/possible_targets = new for(var/mob/living/M in view_or_range(range,target,"view")) @@ -102,4 +92,4 @@ return var/mob/living/next = pick(possible_targets) if(next) - Bolt(current,next,bolt_energy-6,user) // 5 max bounces \ No newline at end of file + Bolt(current,next,bolt_energy,bounces-1,user) \ No newline at end of file diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 739a747f967..de15d5c356c 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -183,7 +183,7 @@ var/list/uplink_items = list() name = "Toy Submachine Gun" desc = "A fully-loaded Donksoft bullpup submachine gun that fires riot grade rounds with a 20-round magazine." item = /obj/item/weapon/gun/projectile/automatic/c20r/toy - cost = 12 + cost = 8 gamemodes = list(/datum/game_mode/nuclear) surplus = 0 @@ -191,7 +191,7 @@ var/list/uplink_items = list() name = "Toy Machine Gun" desc = "A fully-loaded Donksoft belt-fed machine gun. This weapon has a massive 50-round magazine of devastating riot grade darts, that can briefly incapacitate someone in just one volley." item = /obj/item/weapon/gun/projectile/automatic/l6_saw/toy - cost = 30 + cost = 12 gamemodes = list(/datum/game_mode/nuclear) surplus = 0 @@ -357,7 +357,7 @@ var/list/uplink_items = list() name = "Toy Gun (with Stun Darts)" desc = "An innocent looking toy pistol designed to fire foam darts. Comes loaded with riot grade darts, to incapacitate a target." item = /obj/item/weapon/gun/projectile/automatic/toy/pistol/riot - cost = 10 + cost = 6 surplus = 10 excludefrom = list(/datum/game_mode/gang) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index c20a1f77fb5..ba8f7708085 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -6,8 +6,6 @@ var/list/fingerprintshidden var/fingerprintslast = null var/list/blood_DNA - var/last_bumped = 0 - var/throwpass = 0 ///Chemistry. var/datum/reagents/reagents = null @@ -17,11 +15,6 @@ //HUD images that this atom can provide. var/list/hud_possible - //var/chem_is_open_container = 0 - // replaced by OPENCONTAINER flags and atom/proc/is_open_container() - ///Chemistry. - var/allow_spin = 1 - //Value used to increment ex_act() if reactionary_explosions is on var/explosion_block = 0 @@ -55,26 +48,6 @@ return 0 -/atom/proc/throw_impact(atom/hit_atom,mob/thrower) - if(istype(hit_atom,/mob/living)) - var/mob/living/M = hit_atom - M.hitby(src,thrower) - - else if(isobj(hit_atom)) - var/obj/O = hit_atom - if(!O.anchored) - step(O, src.dir) - O.hitby(src) - - else if(isturf(hit_atom)) - var/turf/T = hit_atom - if(T.density) - spawn(2) - step(src, turn(src.dir, 180)) - if(istype(src,/mob/living)) - var/mob/living/M = src - M.take_organ_damage(20) - /atom/proc/attack_hulk(mob/living/carbon/human/hulk, do_attack_animation = 0) if(do_attack_animation) hulk.changeNext_move(CLICK_CD_MELEE) @@ -285,9 +258,10 @@ its easier to just keep the beam vertical. /atom/proc/fire_act() return -/atom/proc/hitby(atom/movable/AM as mob|obj) - return - +/atom/proc/hitby(atom/movable/AM, skip, var/hitpush) + if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav. + spawn(2) + step(AM, turn(AM.dir, 180)) var/list/blood_splatter_icons = list() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index bc23aff2648..8a24343e0bb 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -93,12 +93,12 @@ /atom/movable/Crossed(atom/movable/AM) return -/atom/movable/Bump(var/atom/A as mob|obj|turf|area, yes) - if(throwing) - throw_impact(A) - throwing = 0 - if ((A && yes)) - A.last_bumped = world.time +/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump(). + if((A && yes)) + if(throwing) + throwing = 0 + throw_impact(A) + . = 1 A.Bumped(src) @@ -143,7 +143,6 @@ if(!direction) return 1 - var/old_dir = dir . = step(src, direction) dir = old_dir @@ -151,70 +150,92 @@ /atom/movable/proc/checkpass(passflag) return pass_flags&passflag -/atom/movable/proc/hit_check(mob/thrower) // todo: this is partly obsolete due to passflags already, add throwing stuff to mob CanPass and finish it - if(src.throwing) - for(var/atom/A in get_turf(src)) - if(A == src) continue - if(istype(A,/mob/living)) - if(A:lying) continue - src.throw_impact(A,thrower) - if(src.throwing == 1) - src.throwing = 0 - if(isobj(A)) - if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement - src.throw_impact(A,thrower) - src.throwing = 0 +/atom/movable/proc/throw_impact(atom/hit_atom) + return hit_atom.hitby(src) -/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower) +/atom/movable/hitby(atom/movable/AM, skip, var/hitpush = 1) + if(!anchored && hitpush) + step(src, AM.dir) + return ..() + +/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0) if(!target || !src || (flags & NODROP)) return 0 //use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target - src.throwing = 1 - if(target.allow_spin) // turns out 1000+ spinning objects being thrown at the singularity creates lag - Iamgoofball + throwing = 1 + if(spin) //if we don't want the /atom/movable to spin. SpinAnimation(5, 1) + + var/dist_travelled = 0 + var/dist_since_sleep = 0 + var/dist_x = abs(target.x - src.x) var/dist_y = abs(target.y - src.y) var/dx = (target.x > src.x) ? EAST : WEST var/dy = (target.y > src.y) ? NORTH : SOUTH - var/dist_travelled = 0 - var/dist_since_sleep = 0 - var/tdist_x = dist_x; - var/tdist_y = dist_y; - var/tdx = dx; - var/tdy = dy; + var/pure_diagonal = 0 + if(dist_x == dist_y) + pure_diagonal = 1 if(dist_x <= dist_y) - tdist_x = dist_y; - tdist_y = dist_x; - tdx = dy; - tdy = dx; + var/olddist_x = dist_x + var/olddx = dx + dist_x = dist_y + dist_y = olddist_x + dx = dy + dy = olddx - var/error = tdist_x/2 - tdist_y - while(target && (((((dist_x > dist_y) && ((src.x < target.x && dx == EAST) || (src.x > target.x && dx == WEST))) || ((dist_x <= dist_y) && ((src.y < target.y && dy == NORTH) || (src.y > target.y && dy == SOUTH))) || (src.x > target.x && dx == WEST)) && dist_travelled < range) || !has_gravity(src))) - // only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up - if(!src.throwing) break - if(!istype(src.loc, /turf)) break + var/error = dist_x/2 - dist_y + var/atom/finalturf = get_turf(target) + var/hit = 0 - var/atom/step = get_step(src, (error < 0) ? tdy : tdx) + while(target && ((dist_travelled < range && loc != finalturf) || !has_gravity(src))) //stop if we reached our destination (or max range) and aren't floating + + if(!istype(loc, /turf)) + hit = 1 + break + + var/atom/step = get_step(src, get_dir(src, target)) + if(!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first + if(error >= 0 && get_dist(src, finalturf) > 1) + step = get_step(src, dx) + error += (error < 0) ? dist_x/2 : -dist_y if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - src.Move(step, get_dir(loc, step)) - hit_check(thrower) - error += (error < 0) ? tdist_x : -tdist_y; + Move(step, get_dir(loc, step)) + if(!throwing) // we hit something during our move + hit = 1 + break dist_travelled++ dist_since_sleep++ if(dist_since_sleep >= speed) dist_since_sleep = 0 sleep(1) - //done throwing, either because it hit something or it finished moving - if(isobj(src) && throwing) - src.throw_impact(get_turf(src),thrower) - src.throwing = 0 + if(!dist_since_sleep && hitcheck()) //to catch sneaky things moving on our tile during our sleep(1) + hit = 1 + break + //done throwing, either because it hit something or it finished moving + throwing = 0 + if(!hit) + for(var/atom/A in get_turf(src)) //looking for our target on the turf we land on. + if(A == target) + hit = 1 + throw_impact(A) + return 1 + + throw_impact(get_turf(src)) // we haven't hit something yet and we still must, let's hit the ground. return 1 +/atom/movable/proc/hitcheck() + for(var/atom/movable/AM in get_turf(src)) + if(AM == src) + continue + if(AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER)) + throw_impact(AM) + return 1 //Overlays /atom/movable/overlay diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 01bab649c0c..aaac82f87df 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -24,17 +24,6 @@ name = "desk" desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl" icon_state = "tomealtar" -// luminosity = 5 - -//sprites for this no longer exist -Pete -//(they were stolen from another game anyway) -/* -/obj/structure/cult/pillar - name = "Pillar" - desc = "This should not exist" - icon_state = "pillar" - icon = 'magic_pillar.dmi' -*/ /obj/effect/gateway name = "gateway" @@ -44,13 +33,3 @@ density = 1 unacidable = 1 anchored = 1.0 - -/obj/effect/gateway/Bumped(mob/M as mob|obj) - spawn(0) - return - return - -/obj/effect/gateway/Crossed(AM as mob|obj) - spawn(0) - return - return \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index c88dc2d2f99..ae618f0be1b 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -140,7 +140,7 @@ rcdmod.uses -- for(var/obj/item/weapon/rcd/rcd in world) rcd.disabled = 1 - for(var/obj/item/mecha_parts/mecha_equipment/tool/rcd/rcd in world) + for(var/obj/item/mecha_parts/mecha_equipment/rcd/rcd in world) rcd.disabled = 1 src << "Out of uses." diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 0ea208a2fcd..179ba2c0fb1 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -213,6 +213,39 @@ return 0 return 1 +/datum/objective/hijackclone + explanation_text = "Hijack the emergency shuttle by ensuring only you (or your copies) escape." + dangerrating = 25 + martyr_compatible = 0 + +/datum/objective/hijackclone/check_completion() + if(!owner.current) + return 0 + if(SSshuttle.emergency.mode < SHUTTLE_ENDGAME) + return 0 + + var/area/A = SSshuttle.emergency.areaInstance + + for(var/mob/living/player in player_list) //Make sure nobody else is onboard + if(player.mind && player.mind != owner) + if(player.stat != DEAD) + switch(player.type) + if(/mob/living/silicon/ai, /mob/living/silicon/pai) + continue + if(get_area(player) == A) + if(player.real_name != owner.current.real_name && !istype(get_turf(player.mind.current), /turf/simulated/floor/plasteel/shuttle/red)) + return 0 + + for(var/mob/living/player in player_list) //Make sure at least one of you is onboard + if(player.mind && player.mind != owner) + if(player.stat != DEAD) + switch(player.type) + if(/mob/living/silicon/ai, /mob/living/silicon/pai) + continue + if(get_area(player) == A) + if(player.real_name == owner.current.real_name && !istype(get_turf(player.mind.current), /turf/simulated/floor/plasteel/shuttle/red)) + return 1 + return 0 /datum/objective/block explanation_text = "Do not allow any organic lifeforms to escape on the shuttle alive." diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index ad849f8e924..bc0ee9f9801 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -76,6 +76,8 @@ qdel(G) for(var/mob/living/H in T.contents) extinguishMob(H) + for(var/mob/living/silicon/robot/borgie in T.contents) + borgie.update_headlamp(1) diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 639ae937977..6c157589fd2 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -173,3 +173,258 @@ H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(H), slot_l_hand) H.equip_to_slot_or_del(new /obj/item/weapon/claymore(H), slot_r_hand) H.equip_to_slot_or_del(new /obj/item/weapon/twohanded/spear(H), slot_back) + + + +/////////////////////Multiverse Blade//////////////////// +var/global/list/multiverse = list() + +/obj/item/weapon/multisword + name = "multiverse sword" + desc = "A weapon capable of conquering the universe and beyond. Activate it to summon copies of yourself from others dimensions to fight by your side." + icon = 'icons/obj/weapons.dmi' + icon_state = "energy_katana" + item_state = "energy_katana" + hitsound = 'sound/weapons/bladeslice.ogg' + flags = CONDUCT + slot_flags = SLOT_BELT + force = 20 + throwforce = 10 + w_class = 2 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + var/faction = list("unassigned") + var/cooldown = 0 + var/assigned = "unassigned" + var/evil = TRUE + +/obj/item/weapon/multisword/New() + ..() + multiverse |= src + + +/obj/item/weapon/multisword/Destroy() + multiverse.Remove(src) + ..() + +/obj/item/weapon/multisword/attack_self(mob/user) + if(user.mind.special_role == "apprentice") + user << "You know better than to touch your teacher's stuff." + return + if(cooldown < world.time) + var/faction_check = 0 + for(var/F in faction) + if(F in user.faction) + faction_check = 1 + break + if(faction_check == 0) + faction = list("[user.real_name]") + assigned = "[user.real_name]" + user.faction = list("[user.real_name]") + user << "You bind the sword to yourself. You can now use it to summon help." + if(!usr.mind.special_role) + if(prob(30)) + user << "With your new found power you could easily conquer the station!" + var/datum/objective/hijackclone/hijack_objective = new /datum/objective/hijackclone + hijack_objective.owner = usr.mind + usr.mind.objectives += hijack_objective + hijack_objective.explanation_text = "Ensure only [usr.real_name] and their copies are on the shuttle!" + usr << "Objective #[1]: [hijack_objective.explanation_text]" + ticker.mode.traitors += usr.mind + usr.mind.special_role = "[usr.real_name] Prime" + evil = TRUE + else + user << "With your new found power you could easily defend the station!" + var/datum/objective/survive/new_objective = new /datum/objective/survive + new_objective.owner = usr.mind + new_objective.explanation_text = "Survive, and help defend the innocent from the mobs of multiverse clones." + usr << "Objective #[1]: [new_objective.explanation_text]" + usr.mind.objectives += new_objective + ticker.mode.traitors += usr.mind + usr.mind.special_role = "[usr.real_name] Prime" + evil = FALSE + else + var/list/candidates = get_candidates(BE_WIZARD) + if(candidates.len) + var/client/C = pick(candidates) + spawn_copy(C, get_turf(user.loc), user) + user << "The sword flashes, and you find yourself face to face with...you!" + cooldown = world.time + 400 + for(var/obj/item/weapon/multisword/M in multiverse) + if(M.assigned == assigned) + M.cooldown = cooldown + + else + user << "You fail to summon any copies of yourself. Perhaps you should try again in a bit." + else + user << "[src] is recharging! Keep in mind it shares a cooldown with the swords wielded by your copies." + + +/obj/item/weapon/multisword/proc/spawn_copy(var/client/C, var/turf/T) + var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) + C.prefs.copy_to(M) + M.key = C.key + M.mind.name = usr.real_name + M << "You are an alternate version of [usr.real_name] from another universe! Help them accomplish their goals at all costs." + M.real_name = usr.real_name + M.name = usr.real_name + M.faction = list("[usr.real_name]") + equip_copy(M) + + if(evil) + var/datum/objective/hijackclone/hijack_objective = new /datum/objective/hijackclone + hijack_objective.owner = M.mind + M.mind.objectives += hijack_objective + hijack_objective.explanation_text = "Ensure only [usr.real_name] and their copies are on the shuttle!" + M << "Objective #[1]: [hijack_objective.explanation_text]" + M.mind.special_role = "multiverse traveller" + log_game("[M.key] was made a multiverse traveller with the objective to help [usr.real_name] hijack.") + else + var/datum/objective/protect/new_objective = new /datum/objective/protect + new_objective.owner = M:mind + new_objective:target = usr:mind + new_objective.explanation_text = "Protect [usr.real_name], your copy, and help them defend the innocent from the mobs of multiverse clones." + M.mind.objectives += new_objective + M << "Objective #[1]: [new_objective.explanation_text]" + M.mind.special_role = "multiverse traveller" + log_game("[M.key] was made a multiverse traveller with the objective to help [usr.real_name] protect the station.") + +/obj/item/weapon/multisword/proc/equip_copy(var/mob/living/carbon/human/M) + + var/obj/item/weapon/multisword/sword = new /obj/item/weapon/multisword + sword.assigned = assigned + sword.faction = list("[assigned]") + sword.evil = evil + + var/randomize = pick("mobster","roman","wizard","cyborg","syndicate","assistant", "animu", "cultist", "highlander", "clown", "killer", "pirate", "soviet") + + switch(randomize) + if("mobster") + M.equip_to_slot_or_del(new /obj/item/clothing/head/fedora(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/black(M), slot_gloves) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(M), slot_glasses) + M.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket/really_black(M), slot_w_uniform) + M.equip_to_slot_or_del(sword, slot_r_hand) + + if("roman") + var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionaire) + M.equip_to_slot_or_del(new hat(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/under/roman(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(M), slot_l_hand) + M.equip_to_slot_or_del(sword, slot_r_hand) + + if("wizard") + M.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/red(M), slot_wear_suit) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/red(M), slot_head) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("cyborg") + var/obj/item/organ/limb/chest/C = locate(/obj/item/organ/limb/chest) in M.organs + qdel(C) + M.organs += new /obj/item/organ/limb/robot/chest + var/obj/item/organ/limb/r_arm/R = locate(/obj/item/organ/limb/r_arm) in M.organs + qdel(R) + M.organs += new /obj/item/organ/limb/robot/r_arm + var/obj/item/organ/limb/l_arm/L = locate(/obj/item/organ/limb/l_arm) in M.organs + qdel(L) + M.organs += new /obj/item/organ/limb/robot/l_arm + var/obj/item/organ/limb/l_leg/LL = locate(/obj/item/organ/limb/l_leg) in M.organs + qdel(LL) + M.organs += new /obj/item/organ/limb/robot/l_leg + var/obj/item/organ/limb/r_leg/RL = locate(/obj/item/organ/limb/r_leg) in M.organs + qdel(RL) + M.organs += new /obj/item/organ/limb/robot/r_leg + M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("syndicate") + M.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(M), slot_gloves) + M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/swat(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(M), slot_wear_suit) + M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(M),slot_wear_mask) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("assistant") + M.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(M), slot_shoes) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("animu") + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/head/kitty(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/under/schoolgirl/red(M), slot_w_uniform) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("cultist") + M.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(M), slot_wear_suit) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("highlander") + M.equip_to_slot_or_del(new /obj/item/clothing/under/kilt(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/head/beret(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("clown") + M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/clown(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(M), slot_wear_mask) + M.equip_to_slot_or_del(new /obj/item/weapon/bikehorn(M), slot_l_store) + M.equip_to_slot_or_del(sword, slot_r_hand) + if("killer") + M.equip_to_slot_or_del(new /obj/item/clothing/under/overalls(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/white(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/latex(M), slot_gloves) + M.equip_to_slot_or_del(new /obj/item/clothing/mask/surgical(M), slot_wear_mask) + M.equip_to_slot_or_del(new /obj/item/clothing/head/welding(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/suit/apron(M), slot_wear_suit) + M.equip_to_slot_or_del(new /obj/item/weapon/kitchen/knife(M), slot_l_store) + M.equip_to_slot_or_del(new /obj/item/weapon/scalpel(M), slot_r_store) + M.equip_to_slot_or_del(sword, slot_r_hand) + for(var/obj/item/carried_item in M.contents) + if(!istype(carried_item, /obj/item/weapon/implant)) + carried_item.add_blood(M) + if("pirate") + M.equip_to_slot_or_del(new /obj/item/clothing/under/pirate(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/brown(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/clothing/head/bandana(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/glasses/eyepatch(M), slot_glasses) + M.equip_to_slot_or_del(sword, slot_r_hand) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + if("soviet") + M.equip_to_slot_or_del(new /obj/item/clothing/head/hgpiratecap(M), slot_head) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(M), slot_gloves) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) + M.equip_to_slot_or_del(new /obj/item/clothing/suit/hgpirate(M), slot_wear_suit) + M.equip_to_slot_or_del(new /obj/item/clothing/under/soviet(M), slot_w_uniform) + + else + return + + ready_dna(M) + if(M.dna && prob(50)) + var/list/all_species = list() + for(var/speciestype in typesof(/datum/species) - /datum/species) + var/datum/species/S = new speciestype() + if(!S.dangerous_existence) + all_species += speciestype + hardset_dna(M, null, null, null, null, pick(all_species)) + M.update_icons() + + var/obj/item/weapon/card/id/W = new /obj/item/weapon/card/id + W.icon_state = "centcom" + W.access += access_maint_tunnels + W.assignment = "Multiverse Traveller" + W.registered_name = M.real_name + W.update_label(M.real_name) + M.equip_to_slot_or_del(W, slot_wear_id) diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index e47331ed349..efc0d3b085d 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -10,11 +10,12 @@ var/surplus = -1 // -1 for infinite, not used by anything atm var/obj/effect/proc_holder/spell/S = null //Since spellbooks can be used by only one person anyway we can track the actual spell var/buy_word = "Learn" + var/limit //used to prevent a spellbook_entry from being bought more than X times with one wizard spellbook /datum/spellbook_entry/proc/IsAvailible() // For config prefs / gamemode restrictions - these are round applied return 1 /datum/spellbook_entry/proc/CanBuy(mob/living/carbon/human/user,obj/item/weapon/spellbook/book) // Specific circumstances - if(book.usesThe contract has been used, you can't get your points back now!" else user << "You feed the contract back into the spellbook, refunding your points." - src.uses++ + uses++ + for(var/datum/spellbook_entry/item/contract/CT in entries) + if(!isnull(CT.limit)) + CT.limit++ qdel(O) if(istype(O, /obj/item/weapon/antag_spawner/slaughter_demon)) user << "On second thought, maybe summoning a demon is a bad idea. You refund your points." - src.uses++ + uses++ + for(var/datum/spellbook_entry/item/bloodbottle/BB in entries) + if(!isnull(BB.limit)) + BB.limit++ qdel(O) /obj/item/weapon/spellbook/proc/GetCategoryHeader(category) @@ -545,12 +559,16 @@ E = entries[text2num(href_list["buy"])] if(E && E.CanBuy(H,src)) if(E.Buy(H,src)) + if(E.limit) + E.limit-- uses -= E.cost else if(href_list["refund"]) E = entries[text2num(href_list["refund"])] if(E && E.refundable) var/result = E.Refund(H,src) if(result > 0) + if(!isnull(E.limit)) + E.limit += result uses += result else if(href_list["page"]) tab = sanitize(href_list["page"]) diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm index 78d87119d01..e484b42e4c3 100644 --- a/code/game/machinery/atmoalter/portable_atmospherics.dm +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -47,7 +47,7 @@ //Perform the connection connected_port = new_port connected_port.connected_device = src - var/datum/pipeline/connected_port_parent = connected_port.parents["p1"] + var/datum/pipeline/connected_port_parent = connected_port.parents[PARENT1] connected_port_parent.reconcile_air() anchored = 1 //Prevent movement diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 8aaf4173d49..140fc457c41 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -397,14 +397,6 @@ Auto Patrol[]"}, return 1 return 0 -/* terrible -/obj/machinery/bot/ed209/Bumped(atom/movable/M as mob|obj) - spawn(0) - if (M) - var/turf/T = get_turf(src) - M:loc = T -*/ - /obj/machinery/bot/ed209/explode() walk_to(src,0) visible_message("[src] blows apart!") diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm index ffaecb88a14..6a96b8ac0fb 100644 --- a/code/game/machinery/computer/HolodeckControl.dm +++ b/code/game/machinery/computer/HolodeckControl.dm @@ -410,6 +410,7 @@ var/mob/living/carbon/M = hit_atom playsound(src, 'sound/items/dodgeball.ogg', 50, 1) M.apply_damage(10, STAMINA) + loc = get_turf(hit_atom) //drop at the target's feet if(prob(5)) M.Weaken(3) visible_message("[M] is knocked right off \his feet!", 3) @@ -421,7 +422,6 @@ icon_state = "hoop" anchored = 1 density = 1 - throwpass = 1 /obj/structure/holohoop/attackby(obj/item/weapon/W, mob/user, params) if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 87ad6c9728c..129d03039b9 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -45,8 +45,8 @@ /obj/machinery/door/Bumped(atom/AM) if(operating || emagged) return - if(ismob(AM)) - var/mob/M = AM + if(isliving(AM)) + var/mob/living/M = AM if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent shock spam. M.last_bumped = world.time if(!M.restrained()) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index d60c8bf9e9b..27f01b8c864 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -16,8 +16,10 @@ closingLayer = 3.11 /obj/machinery/door/firedoor/Bumped(atom/AM) - if(p_open || operating) return - if(!density) return ..() + if(p_open || operating) + return + if(!density) + return ..() return 0 diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index a970cbbad17..be2f33815a8 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -88,7 +88,7 @@ if (get_dist(src, L) > range) continue - if(L.flash_eyes()) + if(L.flash_eyes(affect_silicon = 1)) L.Weaken(strength) if(L.weakeyes) L.Weaken(strength * 1.5) diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 38fe78bd912..9e4b3da49d0 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -101,6 +101,8 @@ var/const/SAFETY_COOLDOWN = 100 if(stat & (BROKEN|NOPOWER)) return + if(!anchored) + return if(safety_mode) return diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm index 3a49c11433a..fcbd128a5c3 100644 --- a/code/game/mecha/combat/durand.dm +++ b/code/game/mecha/combat/durand.dm @@ -13,15 +13,7 @@ var/defence = 0 var/defence_deflect = 35 wreckage = /obj/structure/mecha_wreckage/durand - -/* -/obj/mecha/combat/durand/New() - ..() - weapons += new /datum/mecha_weapon/ballistic/lmg(src) - weapons += new /datum/mecha_weapon/ballistic/scattershot(src) - selected_weapon = weapons[1] - return -*/ + var/datum/action/mecha/mech_defence_mode/defense_action = new /obj/mecha/combat/durand/relaymove(mob/user,direction) if(defence) @@ -32,43 +24,33 @@ . = ..() return +/obj/mecha/combat/durand/GrantActions(var/mob/living/user, var/human_occupant = 0) + ..() + defense_action.chassis = src + defense_action.Grant(user) -/obj/mecha/combat/durand/verb/defence_mode() - set category = "Exosuit Interface" - set name = "Toggle defence mode" - set src = usr.loc - set popup_menu = 0 - if(!can_use(usr)) - return - defence = !defence - if(defence) - deflect_chance = defence_deflect - src.occupant_message("You enable [src] defence mode.") - else - deflect_chance = initial(deflect_chance) - src.occupant_message("You disable [src] defence mode.") - src.log_message("Toggled defence mode.") - return - +/obj/mecha/combat/durand/RemoveActions(var/mob/living/user, var/human_occupant = 0) + ..() + defense_action.Remove(user) /obj/mecha/combat/durand/get_stats_part() var/output = ..() output += "Defence mode: [defence?"on":"off"]" return output -/obj/mecha/combat/durand/get_commands() - var/output = {"
-
Special
- -
- "} - output += ..() - return output +/datum/action/mecha/mech_defence_mode + name = "Toggle Defense Mode" + button_icon_state = "mech_toggle_defense_mode" -/obj/mecha/combat/durand/Topic(href, href_list) - ..() - if (href_list["toggle_defence_mode"]) - src.defence_mode() - return \ No newline at end of file +/datum/action/mecha/mech_defence_mode/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + var/obj/mecha/combat/durand/D = chassis + D.defence = !D.defence + if(D.defence) + D.deflect_chance = D.defence_deflect + D.occupant_message("You enable [D] defence mode.") + else + D.deflect_chance = initial(D.deflect_chance) + D.occupant_message("You disable [D] defence mode.") + D.log_message("Toggled defence mode.") \ No newline at end of file diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index a668159412b..ed5b1376c8e 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -33,7 +33,7 @@ ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/teleporter ME.attach(src) @@ -71,16 +71,16 @@ src.log_message("Toggled leg actuators overload.") return -/obj/mecha/combat/gygax/dyndomove(direction) - if(!..()) return +/obj/mecha/combat/gygax/domove(direction) + if(!..()) + return if(overload) health-- if(health < initial(health) - initial(health)/3) overload = 0 step_in = initial(step_in) step_energy_drain = initial(step_energy_drain) - src.occupant_message("Leg actuators damage threshold exceded. Disabling overload.") - return + occupant_message("Leg actuators damage threshold exceded. Disabling overload.") /obj/mecha/combat/gygax/get_stats_part() diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index de184e263a1..499d7a45c0a 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -20,80 +20,20 @@ internal_damage_threshold = 25 force = 45 max_equip = 4 + var/datum/action/mecha/mech_smoke/smoke_action = new + var/datum/action/mecha/mech_toggle_thrusters/thrusters_action = new + var/datum/action/mecha/mech_zoom/zoom_action = new + +/obj/mecha/combat/marauder/New() + ..() + smoke_system.set_up(3, 0, src) + smoke_system.attach(src) /obj/mecha/combat/marauder/Destroy() qdel(smoke_system) smoke_system = null ..() -/obj/mecha/combat/marauder/seraph - desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." - name = "\improper Seraph" - icon_state = "seraph" - operation_req_access = list(access_cent_specops) - step_in = 3 - health = 550 - wreckage = /obj/structure/mecha_wreckage/seraph - internal_damage_threshold = 20 - force = 55 - max_equip = 5 - -/obj/mecha/combat/marauder/mauler - desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." - name = "\improper Mauler" - icon_state = "mauler" - operation_req_access = list(access_syndicate) - wreckage = /obj/structure/mecha_wreckage/mauler - -/obj/mecha/combat/marauder/mauler/loaded/New() - ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) - ME.attach(src) - src.smoke_system.set_up(3, 0, src) - src.smoke_system.attach(src) - return - -/obj/mecha/combat/marauder/loaded/New() - ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) - ME.attach(src) - src.smoke_system.set_up(3, 0, src) - src.smoke_system.attach(src) - return - -/obj/mecha/combat/marauder/seraph/New() - ..()//Let it equip whatever is needed. - var/obj/item/mecha_parts/mecha_equipment/ME - if(equipment.len)//Now to remove it and equip anew. - for(ME in equipment) - equipment -= ME - qdel(ME) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/teleporter(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) - ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) - ME.attach(src) - return - /obj/mecha/combat/marauder/relaymove(mob/user,direction) if(zoom) if(world.time - last_message > 20) @@ -110,54 +50,23 @@ return 1 return 0 -/obj/mecha/combat/marauder/verb/toggle_thrusters() - set category = "Exosuit Interface" - set name = "Toggle thrusters" - set src = usr.loc - set popup_menu = 0 - if(usr!=src.occupant) - return - if(src.occupant) - if(get_charge() > 0) - thrusters = !thrusters - src.log_message("Toggled thrusters.") - src.occupant_message("Thrusters [thrusters?"en":"dis"]abled.") - return +/obj/mecha/combat/marauder/GrantActions(var/mob/living/user, var/human_occupant = 0) + ..() + smoke_action.chassis = src + smoke_action.Grant(user) -/obj/mecha/combat/marauder/verb/smoke() - set category = "Exosuit Interface" - set name = "Smoke" - set src = usr.loc - set popup_menu = 0 - if(usr!=src.occupant) - return - if(smoke_ready && smoke>0) - src.smoke_system.start() - smoke-- - smoke_ready = 0 - spawn(smoke_cooldown) - smoke_ready = 1 - return + thrusters_action.chassis = src + thrusters_action.Grant(user) -/obj/mecha/combat/marauder/verb/zoom() - set category = "Exosuit Interface" - set name = "Zoom" - set src = usr.loc - set popup_menu = 0 - if(usr!=src.occupant) - return - if(src.occupant.client) - src.zoom = !src.zoom - src.log_message("Toggled zoom mode.") - src.occupant_message("Zoom mode [zoom?"en":"dis"]abled.") - if(zoom) - src.occupant.client.view = 12 - src.occupant << sound('sound/mecha/imag_enh.ogg',volume=50) - else - src.occupant.client.view = world.view//world.view - default mob view size - return + zoom_action.chassis = src + zoom_action.Grant(user) +/obj/mecha/combat/marauder/RemoveActions(var/mob/living/user, var/human_occupant = 0) + ..() + smoke_action.Remove(user) + thrusters_action.Remove(user) + zoom_action.Remove(user) /obj/mecha/combat/marauder/go_out() if(src.occupant && src.occupant.client) @@ -176,25 +85,110 @@ return output -/obj/mecha/combat/marauder/get_commands() - var/output = {"
-
Special
- -
- "} - output += ..() - return output - -/obj/mecha/combat/marauder/Topic(href, href_list) +/obj/mecha/combat/marauder/loaded/New() ..() - if (href_list["toggle_thrusters"]) - src.toggle_thrusters() - if (href_list["smoke"]) - src.smoke() - if (href_list["toggle_zoom"]) - src.zoom() - return \ No newline at end of file + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) + ME.attach(src) + +/obj/mecha/combat/marauder/seraph + desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." + name = "\improper Seraph" + icon_state = "seraph" + operation_req_access = list(access_cent_specops) + step_in = 3 + health = 550 + wreckage = /obj/structure/mecha_wreckage/seraph + internal_damage_threshold = 20 + force = 55 + max_equip = 5 + +/obj/mecha/combat/marauder/seraph/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/teleporter(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) + ME.attach(src) + +/obj/mecha/combat/marauder/mauler + desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." + name = "\improper Mauler" + icon_state = "mauler" + operation_req_access = list(access_syndicate) + wreckage = /obj/structure/mecha_wreckage/mauler + +/obj/mecha/combat/marauder/mauler/loaded/New() + ..() + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) + ME.attach(src) + ME = new /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster(src) + ME.attach(src) + + +/datum/action/mecha/mech_smoke + name = "Smoke" + button_icon_state = "smoke" + +/datum/action/mecha/mech_smoke/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + var/obj/mecha/combat/marauder/M = chassis + if(M.smoke_ready && M.smoke>0) + M.smoke_system.start() + M.smoke-- + M.smoke_ready = 0 + spawn(M.smoke_cooldown) + M.smoke_ready = 1 + +/datum/action/mecha/mech_toggle_thrusters + name = "Toggle Thrusters" + button_icon_state = "mech_toggle_thrusters" + +/datum/action/mecha/mech_toggle_thrusters/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + var/obj/mecha/combat/marauder/M = chassis + if(M.get_charge() > 0) + M.thrusters = !M.thrusters + if(M.thrusters) + button_icon_state = "mech_toggle_thrusters_on" + else + button_icon_state = "mech_toggle_thrusters" + M.log_message("Toggled thrusters.") + M.occupant_message("Thrusters [M.thrusters?"en":"dis"]abled.") + +/datum/action/mecha/mech_zoom + name = "Zoom" + button_icon_state = "mech_zoom" + +/datum/action/mecha/mech_zoom/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + var/obj/mecha/combat/marauder/M = chassis + if(owner.client) + M.zoom = !M.zoom + M.log_message("Toggled zoom mode.") + M.occupant_message("Zoom mode [M.zoom?"en":"dis"]abled.") + if(M.zoom) + owner.client.view = 12 + owner << sound('sound/mecha/imag_enh.ogg',volume=50) + else + owner.client.view = world.view//world.view - default mob view size diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm index 905341c2194..ed935004680 100644 --- a/code/game/mecha/combat/phazon.dm +++ b/code/game/mecha/combat/phazon.dm @@ -17,6 +17,8 @@ var/phasing = 0 var/phasing_energy_drain = 200 max_equip = 3 + var/datum/action/mecha/mech_switch_damtype/switch_damtype_action = new + var/datum/action/mecha/mech_toggle_phasing/phasing_action = new /obj/mecha/combat/phazon/Bump(atom/obstacle) if(phasing && get_charge()>=phasing_energy_drain) @@ -24,8 +26,8 @@ if(can_move) can_move = 0 flick("phazon-phase", src) - src.loc = get_step(src,src.dir) - src.use_power(phasing_energy_drain) + loc = get_step(src, dir) + use_power(phasing_energy_drain) sleep(step_in*3) can_move = 1 else @@ -34,50 +36,56 @@ /obj/mecha/combat/phazon/click_action(atom/target,mob/user) if(phasing) - src.occupant_message("Unable to interact with objects while phasing") + occupant_message("Unable to interact with objects while phasing") return else return ..() -/obj/mecha/combat/phazon/verb/switch_damtype() - set category = "Exosuit Interface" - set name = "Reconfigure arm microtool arrays" - set src = usr.loc - set popup_menu = 0 - if(usr!=src.occupant) - return - var/new_damtype = alert(src.occupant,"Arm tool selection",null,"Fists","Torch","Toxic injector") - switch(new_damtype) - if("Fists") - damtype = "brute" - src.occupant_message("Your exosuit's hands form into fists.") - if("Torch") - damtype = "fire" - src.occupant_message("A torch tip extends from your exosuit's hand, glowing red.") - if("Toxic injector") - damtype = "tox" - src.occupant_message("A bone-chillingly thick plasteel needle protracts from the exosuit's palm.") - playsound(src, 'sound/mecha/mechmove01.ogg', 50, 1) - return - -/obj/mecha/combat/phazon/get_commands() - var/output = {" - "} - output += ..() - return output - -/obj/mecha/combat/phazon/Topic(href, href_list) +/obj/mecha/combat/phazon/GrantActions(var/mob/living/user, var/human_occupant = 0) ..() - if (href_list["switch_damtype"]) - src.switch_damtype() - if (href_list["phasing"]) - phasing = !phasing - send_byjax(src.occupant,"exosuit.browser","phasing_command","[phasing?"Dis":"En"]able phasing") - src.occupant_message("En":"#f00\">Dis"]abled phasing.") - return \ No newline at end of file + switch_damtype_action.chassis = src + switch_damtype_action.Grant(user) + + phasing_action.chassis = src + phasing_action.Grant(user) + + +/obj/mecha/combat/phazon/RemoveActions(var/mob/living/user, var/human_occupant = 0) + ..() + switch_damtype_action.Remove(user) + phasing_action.Remove(user) + + +/datum/action/mecha/mech_switch_damtype + name = "Reconfigure arm microtool arrays" + button_icon_state = "mech_switch_damtype" + +/datum/action/mecha/mech_switch_damtype/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + var/obj/mecha/combat/phazon/P = chassis + var/new_damtype + switch(P.damtype) + if("tox") + new_damtype = "brute" + P.occupant_message("Your exosuit's hands form into fists.") + if("brute") + new_damtype = "fire" + P.occupant_message("A torch tip extends from your exosuit's hand, glowing red.") + if("fire") + new_damtype = "tox" + P.occupant_message("A bone-chillingly thick plasteel needle protracts from the exosuit's palm.") + P.damtype = new_damtype. + playsound(src, 'sound/mecha/mechmove01.ogg', 50, 1) + + +/datum/action/mecha/mech_toggle_phasing + name = "Enable Phasing" + button_icon_state = "mech_toggle_phasing" + +/datum/action/mecha/mech_toggle_phasing/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + var/obj/mecha/combat/phazon/P = chassis + P.phasing = !P.phasing + P.occupant_message("En":"#f00\">Dis"]abled phasing.") diff --git a/code/game/mecha/combat/reticence.dm b/code/game/mecha/combat/reticence.dm index 6b2fa70ee3a..612add46853 100644 --- a/code/game/mecha/combat/reticence.dm +++ b/code/game/mecha/combat/reticence.dm @@ -22,6 +22,6 @@ ..() var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced ME.attach(src) - ME = new /obj/item/mecha_parts/mecha_equipment/tool/rcd //HAHA IT MAKES WALLS GET IT + ME = new /obj/item/mecha_parts/mecha_equipment/rcd //HAHA IT MAKES WALLS GET IT ME.attach(src) return \ No newline at end of file diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 2a035db1e27..0fb3f9b694f 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -8,23 +8,14 @@ icon_state = "mecha_equip" force = 5 origin_tech = "materials=2" - var/equip_cooldown = 0 - var/equip_ready = 1 + var/equip_cooldown = 0 // cooldown after use + var/equip_ready = 1 //whether the equipment is ready for use. (or deactivated/activated for static stuff) var/energy_drain = 0 var/obj/mecha/chassis = null var/range = MELEE //bitflags reliability = 1000 var/salvageable = 1 - -/obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(target=1) - sleep(equip_cooldown) - set_ready_state(1) - if(target && chassis && chassis.occupant) - return 1 - return 0 - - /obj/item/mecha_parts/mecha_equipment/New() ..() return @@ -42,10 +33,9 @@ return 1 return -/obj/item/mecha_parts/mecha_equipment/proc/destroy()//missiles detonating, teleporter creating singularity? +/obj/item/mecha_parts/mecha_equipment/Destroy() if(chassis) chassis.equipment -= src - listclearnulls(chassis.equipment) if(chassis.selected == src) chassis.selected = null src.update_chassis_page() @@ -55,13 +45,12 @@ chassis.occupant << sound('sound/mecha/weapdestr.ogg',volume=50) else chassis.occupant << sound('sound/mecha/critdestr.ogg',volume=50) - qdel(src) - return + chassis = null + ..() /obj/item/mecha_parts/mecha_equipment/proc/critfail() if(chassis) log_message("Critical failure",1) - return /obj/item/mecha_parts/mecha_equipment/proc/get_equip_info() if(!chassis) return @@ -90,12 +79,30 @@ /obj/item/mecha_parts/mecha_equipment/proc/action(atom/target) return -/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M) - if(istype(M)) - if(M.equipment.len[target] will not fit into the sleeper because they are buckled to [target.buckled]!") return - if(occupant) + if(patient) occupant_message("The sleeper is already occupied!") return for(var/mob/living/simple_animal/slime/M in range(1,target)) @@ -53,81 +54,65 @@ return occupant_message("You start putting [target] into [src]...") chassis.visible_message("[chassis] starts putting [target] into \the [src].") - var/C = chassis.loc - var/T = target.loc if(do_after_cooldown(target)) - if(chassis.loc!=C || target.loc!=T) - return - if(occupant) + if(patient) occupant_message("The sleeper is already occupied!") return target.forceMove(src) - occupant = target + patient = target target.reset_view(src) - /* - if(target.client) - target.client.perspective = EYE_PERSPECTIVE - target.client.eye = chassis - */ - set_ready_state(0) - pr_mech_sleeper.start() + SSobj.processing |= src + update_equip_info() occupant_message("[target] successfully loaded into [src]. Life support functions engaged.") chassis.visible_message("[chassis] loads [target] into [src].") log_message("[target] loaded. Life support functions engaged.") - return -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/go_out() - if(!occupant) +/obj/item/mecha_parts/mecha_equipment/sleeper/proc/go_out() + if(!patient) return - occupant.forceMove(get_turf(src)) - occupant_message("[occupant] ejected. Life support functions disabled.") - log_message("[occupant] ejected. Life support functions disabled.") - occupant.reset_view() - /* - if(occupant.client) - occupant.client.eye = occupant.client.mob - occupant.client.perspective = MOB_PERSPECTIVE - */ - occupant = null - pr_mech_sleeper.stop() - set_ready_state(1) - return + patient.forceMove(get_turf(src)) + occupant_message("[patient] ejected. Life support functions disabled.") + log_message("[patient] ejected. Life support functions disabled.") + patient.reset_view() + SSobj.processing.Remove(src) + update_equip_info() -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/detach() - if(occupant) +/obj/item/mecha_parts/mecha_equipment/sleeper/detach() + if(patient) occupant_message("Unable to detach [src] - equipment occupied!") return - pr_mech_sleeper.stop() + SSobj.processing.Remove(src) + update_equip_info() return ..() -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/get_equip_info() +/obj/item/mecha_parts/mecha_equipment/sleeper/get_equip_info() var/output = ..() if(output) var/temp = "" - if(occupant) - temp = "
\[Occupant: [occupant] ([occupant.stat > 1 ? "*DECEASED*" : "Health: [occupant.health]%"])\]
View stats|Eject" + if(patient) + temp = "
\[Occupant: [patient] ([patient.stat > 1 ? "*DECEASED*" : "Health: [patient.health]%"])\]
View stats|Eject" return "[output] [temp]" return -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/Topic(href,href_list) +/obj/item/mecha_parts/mecha_equipment/sleeper/Topic(href,href_list) ..() var/datum/topic_input/filter = new /datum/topic_input(href,href_list) if(filter.get("eject")) go_out() if(filter.get("view_stats")) - chassis.occupant << browse(get_occupant_stats(),"window=msleeper") + chassis.occupant << browse(get_patient_stats(),"window=msleeper") onclose(chassis.occupant, "msleeper") return if(filter.get("inject")) inject_reagent(filter.getType("inject",/datum/reagent),filter.getObj("source")) return -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_stats() - if(!occupant) +/obj/item/mecha_parts/mecha_equipment/sleeper/proc/get_patient_stats() + if(!patient) return return {" - [occupant] statistics + [patient] statistics @@ -139,11 +124,11 @@

Health statistics

- [get_occupant_dam()] + [get_patient_dam()]

Reagents in bloodstream

- [get_occupant_reagents()] + [get_patient_reagents()]
[get_available_reagents()] @@ -151,9 +136,9 @@ "} -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_dam() +/obj/item/mecha_parts/mecha_equipment/sleeper/proc/get_patient_dam() var/t1 - switch(occupant.stat) + switch(patient.stat) if(0) t1 = "Conscious" if(1) @@ -162,26 +147,26 @@ t1 = "*dead*" else t1 = "Unknown" - return {"Health: [occupant.stat > 1 ? "[t1]" : "[occupant.health]% ([t1])"]
- Core Temperature: [src.occupant.bodytemperature-T0C]°C ([src.occupant.bodytemperature*1.8-459.67]°F)
- Brute Damage: [occupant.getBruteLoss()]%
- Respiratory Damage: [occupant.getOxyLoss()]%
- Toxin Content: [occupant.getToxLoss()]%
- Burn Severity: [occupant.getFireLoss()]%
- [occupant.getCloneLoss() ? "Subject appears to have cellular damage." : ""]
- [occupant.getBrainLoss() ? "Significant brain damage detected." : ""]
+ return {"Health: [patient.stat > 1 ? "[t1]" : "[patient.health]% ([t1])"]
+ Core Temperature: [patient.bodytemperature-T0C]°C ([patient.bodytemperature*1.8-459.67]°F)
+ Brute Damage: [patient.getBruteLoss()]%
+ Respiratory Damage: [patient.getOxyLoss()]%
+ Toxin Content: [patient.getToxLoss()]%
+ Burn Severity: [patient.getFireLoss()]%
+ [patient.getCloneLoss() ? "Subject appears to have cellular damage." : ""]
+ [patient.getBrainLoss() ? "Significant brain damage detected." : ""]
"} -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_occupant_reagents() - if(occupant.reagents) - for(var/datum/reagent/R in occupant.reagents.reagent_list) +/obj/item/mecha_parts/mecha_equipment/sleeper/proc/get_patient_reagents() + if(patient.reagents) + for(var/datum/reagent/R in patient.reagents.reagent_list) if(R.volume > 0) . += "[R]: [round(R.volume,0.01)]
" return . || "None" -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/get_available_reagents() +/obj/item/mecha_parts/mecha_equipment/sleeper/proc/get_available_reagents() var/output - var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun) in chassis + var/obj/item/mecha_parts/mecha_equipment/syringe_gun/SG = locate(/obj/item/mecha_parts/mecha_equipment/syringe_gun) in chassis if(SG && SG.reagents && islist(SG.reagents.reagent_list)) for(var/datum/reagent/R in SG.reagents.reagent_list) if(R.volume > 0) @@ -189,41 +174,41 @@ return output -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/proc/inject_reagent(datum/reagent/R,obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/SG) - if(!R || !occupant || !SG || !(SG in chassis.equipment)) +/obj/item/mecha_parts/mecha_equipment/sleeper/proc/inject_reagent(datum/reagent/R,obj/item/mecha_parts/mecha_equipment/syringe_gun/SG) + if(!R || !patient || !SG || !(SG in chassis.equipment)) return 0 var/to_inject = min(R.volume, inject_amount) - if(to_inject && occupant.reagents.get_reagent_amount(R.id) + to_inject <= inject_amount*2) - occupant_message("Injecting [occupant] with [to_inject] units of [R.name].") - log_message("Injecting [occupant] with [to_inject] units of [R.name].") - add_logs(chassis.occupant, occupant, "injected", "[name] ([R] - [to_inject] units)") - SG.reagents.trans_id_to(occupant,R.id,to_inject) + if(to_inject && patient.reagents.get_reagent_amount(R.id) + to_inject <= inject_amount*2) + occupant_message("Injecting [patient] with [to_inject] units of [R.name].") + log_message("Injecting [patient] with [to_inject] units of [R.name].") + add_logs(chassis.occupant, patient, "injected", "[name] ([R] - [to_inject] units)") + SG.reagents.trans_id_to(patient,R.id,to_inject) update_equip_info() return -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/update_equip_info() +/obj/item/mecha_parts/mecha_equipment/sleeper/update_equip_info() if(..()) - send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam()) - send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents()) + send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_patient_dam()) + send_byjax(chassis.occupant,"msleeper.browser","reagents",get_patient_reagents()) send_byjax(chassis.occupant,"msleeper.browser","injectwith",get_available_reagents()) return 1 return -/obj/item/mecha_parts/mecha_equipment/tool/sleeper/container_resist() +/obj/item/mecha_parts/mecha_equipment/sleeper/container_resist() go_out() -/datum/global_iterator/mech_sleeper -/datum/global_iterator/mech_sleeper/process(obj/item/mecha_parts/mecha_equipment/tool/sleeper/S) - if(!S.chassis) - S.set_ready_state(1) - return stop() - if(!S.chassis.has_charge(S.energy_drain)) - S.set_ready_state(1) - S.log_message("Deactivated.") - S.occupant_message("[src] deactivated - no power.") - return stop() - var/mob/living/carbon/M = S.occupant +/obj/item/mecha_parts/mecha_equipment/sleeper/process() + if(!chassis) + SSobj.processing.Remove(src) + return + if(!chassis.has_charge(energy_drain)) + set_ready_state(1) + log_message("Deactivated.") + occupant_message("[src] deactivated - no power.") + SSobj.processing.Remove(src) + return + var/mob/living/carbon/M = patient if(!M) return if(M.health > 0) @@ -234,11 +219,16 @@ M.AdjustStunned(-4) if(M.reagents.get_reagent_amount("epinephrine") < 5) M.reagents.add_reagent("epinephrine", 5) - S.chassis.use_power(S.energy_drain) - S.update_equip_info() - return + chassis.use_power(energy_drain) + update_equip_info() -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun + + + +///////////////////////////////// Syringe Gun /////////////////////////////////////////////////////////////// + + +/obj/item/mecha_parts/mecha_equipment/syringe_gun name = "exosuit syringe gun" desc = "Equipment for medical exosuits. A chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur." icon = 'icons/obj/guns/projectile.dmi' @@ -251,42 +241,44 @@ var/synth_speed = 5 //[num] reagent units per cycle energy_drain = 10 var/mode = 0 //0 - fire syringe, 1 - analyze reagents. - var/datum/global_iterator/mech_synth/synth range = MELEE|RANGED equip_cooldown = 10 origin_tech = "materials=3;biotech=4;magnets=4;programming=3" -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/New() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/New() ..() flags |= NOREACT syringes = new known_reagents = list("epinephrine"="Epinephrine","charcoal"="Charcoal") processed_reagents = new create_reagents(max_volume) - synth = new (list(src),0) -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/detach() - synth.stop() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/detach() + SSobj.processing.Remove(src) return ..() -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/critfail() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/Destroy() + SSobj.processing.Remove(src) + ..() + +/obj/item/mecha_parts/mecha_equipment/syringe_gun/critfail() ..() flags &= ~NOREACT return -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/can_attach(obj/mecha/medical/M) +/obj/item/mecha_parts/mecha_equipment/syringe_gun/can_attach(obj/mecha/medical/M) if(..()) if(istype(M)) return 1 return 0 -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/get_equip_info() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/get_equip_info() var/output = ..() if(output) return "[output] \[[mode? "Analyze" : "Launch"]\]
\[Syringes: [syringes.len]/[max_syringes] | Reagents: [reagents.total_volume]/[reagents.maximum_volume]\]
Reagents list" return -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/action(atom/movable/target) +/obj/item/mecha_parts/mecha_equipment/syringe_gun/action(atom/movable/target) if(!action_checks(target)) return if(istype(target,/obj/item/weapon/reagent_containers/syringe)) @@ -303,8 +295,6 @@ if(reagents.total_volume<=0) occupant_message("No available reagents to load syringe with.") return - set_ready_state(0) - chassis.use_power(energy_drain) var/turf/trg = get_turf(target) var/obj/item/weapon/reagent_containers/syringe/mechsyringe = syringes[1] mechsyringe.forceMove(get_turf(chassis)) @@ -315,7 +305,7 @@ playsound(chassis, 'sound/items/syringeproj.ogg', 50, 1) log_message("Launched [mechsyringe] from [src], targeting [target].") var/mob/originaloccupant = chassis.occupant - spawn(-1) + spawn(0) src = null //if src is deleted, still process the syringe for(var/i=0, i<6, i++) if(!mechsyringe) @@ -350,11 +340,10 @@ mechsyringe.update_icon() break sleep(1) - do_after_cooldown() return 1 -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/Topic(href,href_list) +/obj/item/mecha_parts/mecha_equipment/syringe_gun/Topic(href,href_list) ..() var/datum/topic_input/filter = new (href,href_list) if(filter.get("toggle_mode")) @@ -375,7 +364,7 @@ m++ if(processed_reagents.len) message += " added to production" - synth.start() + SSobj.processing |= src occupant_message(message) occupant_message("Reagent processing started.") log_message("Reagent processing started.") @@ -392,7 +381,7 @@ return return -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_page() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/get_reagents_page() var/output = {" Reagent Synthesizer @@ -420,7 +409,7 @@ "} return output -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_form() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/get_reagents_form() var/r_list = get_reagents_list() var/inputs if(r_list) @@ -435,14 +424,14 @@ "} return output -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_reagents_list() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/get_reagents_list() var/output for(var/i=1 to known_reagents.len) var/reagent_id = known_reagents[i] output += {" [known_reagents[reagent_id]]
"} return output -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/get_current_reagents() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/get_current_reagents() var/output for(var/datum/reagent/R in reagents.reagent_list) if(R.volume > 0) @@ -451,7 +440,7 @@ output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All" return output || "None" -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S) +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/load_syringe(obj/item/weapon/reagent_containers/syringe/S) if(syringes.len= 2) occupant_message("The syringe is too far away.") @@ -473,7 +462,7 @@ occupant_message("The [src] syringe chamber is full.") return 0 -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/analyze_reagents(atom/A) +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/analyze_reagents(atom/A) if(get_dist(src,A) >= 4) occupant_message("The object is too far away.") return 0 @@ -488,42 +477,38 @@ occupant_message("Analyzis complete.") return 1 -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/add_known_reagent(r_id,r_name) - set_ready_state(0) - do_after_cooldown() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/proc/add_known_reagent(r_id,r_name) if(!(r_id in known_reagents)) known_reagents += r_id known_reagents[r_id] = r_name return 1 return 0 -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/update_equip_info() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/update_equip_info() if(..()) send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents()) send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form()) return 1 return -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/on_reagent_change() +/obj/item/mecha_parts/mecha_equipment/syringe_gun/on_reagent_change() ..() update_equip_info() return -/datum/global_iterator/mech_synth - delay = 100 -/datum/global_iterator/mech_synth/process(var/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/S) - if(!S.chassis) - return stop() - var/energy_drain = S.energy_drain*10 - if(!S.processed_reagents.len || S.reagents.total_volume >= S.reagents.maximum_volume || !S.chassis.has_charge(energy_drain)) - S.occupant_message("Reagent processing stopped.") - S.log_message("Reagent processing stopped.") - return stop() - if(anyprob(S.reliability)) - S.critfail() - var/amount = S.synth_speed / S.processed_reagents.len - for(var/reagent in S.processed_reagents) - S.reagents.add_reagent(reagent,amount) - S.chassis.use_power(energy_drain) - return 1 +/obj/item/mecha_parts/mecha_equipment/syringe_gun/process() + if(!chassis) + SSobj.processing.Remove(src) + return + if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(energy_drain)) + occupant_message("Reagent processing stopped.") + log_message("Reagent processing stopped.") + SSobj.processing.Remove(src) + if(anyprob(reliability)) + critfail() + var/amount = synth_speed / processed_reagents.len + for(var/reagent in processed_reagents) + reagents.add_reagent(reagent,amount) + chassis.use_power(energy_drain) + diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm new file mode 100644 index 00000000000..7d786f075db --- /dev/null +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -0,0 +1,127 @@ + +// Drill, Diamond drill, Mining scanner + + +/obj/item/mecha_parts/mecha_equipment/drill + name = "exosuit drill" + desc = "Equipment for engineering and combat exosuits. This is the drill that'll pierce the heavens!" + icon_state = "mecha_drill" + equip_cooldown = 30 + energy_drain = 10 + force = 15 + +/obj/item/mecha_parts/mecha_equipment/drill/action(atom/target) + if(!action_checks(target)) + return + if(istype(target, /turf) && !istype(target, /turf/simulated)) + return + if(isobj(target)) + var/obj/target_obj = target + if(target_obj.unacidable) + return + target.visible_message("[chassis] starts to drill [target].", \ + "[chassis] starts to drill [target]...", \ + "You hear drilling.") + + if(do_after_cooldown(target)) + if(istype(target, /turf/simulated/wall/r_wall)) + if(istype(src , /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill)) + if(do_after_cooldown(target))//To slow down how fast mechs can drill through the station + log_message("Drilled through [target]") + target.ex_act(3) + else + occupant_message("[target] is too durable to drill through.") + else if(istype(target, /turf/simulated/mineral)) + for(var/turf/simulated/mineral/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.gets_drilled(chassis.occupant) + log_message("Drilled through [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else if(istype(target, /turf/simulated/floor/plating/asteroid)) + for(var/turf/simulated/floor/plating/asteroid/M in range(chassis,1)) + if(get_dir(chassis,M)&chassis.dir) + M.gets_dug() + log_message("Drilled through [target]") + if(locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in chassis.equipment) + var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo + if(ore_box) + for(var/obj/item/weapon/ore/ore in range(chassis,1)) + if(get_dir(chassis,ore)&chassis.dir) + ore.Move(ore_box) + else + log_message("Drilled through [target]") + if(isliving(target)) + if(istype(src , /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill)) + drill_mob(target, chassis.occupant, 120) + else + drill_mob(target, chassis.occupant) + else + target.ex_act(2) + + +/obj/item/mecha_parts/mecha_equipment/drill/can_attach(obj/mecha/M as obj) + if(..()) + if(istype(M, /obj/mecha/working) || istype(M, /obj/mecha/combat)) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/drill/proc/drill_mob(mob/living/target, mob/user, var/drill_damage=80) + target.visible_message("[chassis] drills [target] with [src].", \ + "[chassis] drills [target] with [src].") + add_logs(user, target, "attacked", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + if(ishuman(target)) + var/mob/living/carbon/human/H = target + var/obj/item/organ/limb/affecting = H.get_organ("chest") + affecting.take_damage(drill_damage) + H.update_damage_overlays(0) + else + target.take_organ_damage(drill_damage) + if(target) + target.Paralyse(10) + target.updatehealth() + + + +/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill + name = "diamond-tipped exosuit drill" + desc = "Equipment for engineering and combat exosuits. This is an upgraded version of the drill that'll pierce the heavens!" + icon_state = "mecha_diamond_drill" + origin_tech = "materials=4;engineering=3" + equip_cooldown = 20 + force = 15 + + + +/obj/item/mecha_parts/mecha_equipment/mining_scanner + name = "exosuit mining scanner" + desc = "Equipment for engineering and combat exosuits. It will automatically check surrounding rock for useful minerals." + icon_state = "mecha_analyzer" + origin_tech = "materials=3;engineering=2" + equip_cooldown = 30 + var/scanning = 0 + +/obj/item/mecha_parts/mecha_equipment/mining_scanner/New() + SSobj.processing |= src + +/obj/item/mecha_parts/mecha_equipment/mining_scanner/process() + if(!loc) + SSobj.processing.Remove(src) + qdel(src) + if(scanning) + return + if(istype(loc,/obj/mecha/working)) + var/obj/mecha/working/mecha = loc + if(!mecha.occupant) + return + var/list/occupant = list() + occupant |= mecha.occupant + scanning = 1 + mineral_scan_pulse(occupant,get_turf(loc)) + spawn(equip_cooldown) + scanning = 0 + diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm new file mode 100644 index 00000000000..1ae8bb1cd2b --- /dev/null +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -0,0 +1,509 @@ + +// Teleporter, Wormhole generator, Gravitational catapult, Armor booster modules, +// Repair droid, Tesla Energy relay, Generators + +////////////////////////////////////////////// TELEPORTER /////////////////////////////////////////////// + +/obj/item/mecha_parts/mecha_equipment/teleporter + name = "mounted teleporter" + desc = "An exosuit module that allows exosuits to teleport to any position in view." + icon_state = "mecha_teleport" + origin_tech = "bluespace=10" + equip_cooldown = 150 + energy_drain = 1000 + range = RANGED + +/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target) + if(!action_checks(target) || src.loc.z == ZLEVEL_CENTCOM) return + var/turf/T = get_turf(target) + if(T) + do_teleport(chassis, T, 4) + return 1 + + + +////////////////////////////////////////////// WORMHOLE GENERATOR ////////////////////////////////////////// + +/obj/item/mecha_parts/mecha_equipment/wormhole_generator + name = "mounted wormhole generator" + desc = "An exosuit module that allows generating of small quasi-stable wormholes." + icon_state = "mecha_wholegen" + origin_tech = "bluespace=3" + equip_cooldown = 50 + energy_drain = 300 + range = RANGED + + +/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target) + if(!action_checks(target) || src.loc.z == ZLEVEL_CENTCOM) return + var/list/theareas = list() + for(var/area/AR in orange(100, chassis)) + if(AR in theareas) continue + theareas += AR + if(!theareas.len) + return + var/area/thearea = pick(theareas) + var/list/L = list() + var/turf/pos = get_turf(src) + for(var/turf/T in get_area_turfs(thearea.type)) + if(!T.density && pos.z == T.z) + var/clear = 1 + for(var/obj/O in T) + if(O.density) + clear = 0 + break + if(clear) + L+=T + if(!L.len) + return + var/turf/target_turf = pick(L) + if(!target_turf) + return + var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) + P.target = target_turf + P.creator = null + P.icon = 'icons/obj/objects.dmi' + P.icon_state = "anom" + P.name = "wormhole" + var/turf/T = get_turf(target) + message_admins("[key_name_admin(chassis.occupant, chassis.occupant.client)](?) (FLW) used a Wormhole Generator in ([T.x],[T.y],[T.z] - JMP)",0,1) + log_game("[key_name(chassis.occupant)] used a Wormhole Generator in ([T.x],[T.y],[T.z])") + src = null + spawn(rand(150,300)) + qdel(P) + return 1 + + +/////////////////////////////////////// GRAVITATIONAL CATAPULT /////////////////////////////////////////// + +/obj/item/mecha_parts/mecha_equipment/gravcatapult + name = "mounted gravitational catapult" + desc = "An exosuit mounted Gravitational Catapult." + icon_state = "mecha_teleport" + origin_tech = "bluespace=2;magnets=3" + equip_cooldown = 10 + energy_drain = 100 + range = MELEE|RANGED + var/atom/movable/locked + var/mode = 1 //1 - gravsling 2 - gravpush + + +/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target) + if(!action_checks(target)) + return + switch(mode) + if(1) + if(!locked) + if(!istype(target) || target.anchored) + occupant_message("Unable to lock on [target]") + return + locked = target + occupant_message("Locked on [target]") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + else if(target!=locked) + if(locked in view(chassis)) + locked.throw_at(target, 14, 1.5) + locked = null + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return 1 + else + locked = null + occupant_message("Lock on [locked] disengaged.") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + if(2) + var/list/atoms = list() + if(isturf(target)) + atoms = range(target,3) + else + atoms = orange(target,3) + for(var/atom/movable/A in atoms) + if(A.anchored) continue + spawn(0) + var/iter = 5-get_dist(A,target) + for(var/i=0 to iter) + step_away(A,target) + sleep(2) + var/turf/T = get_turf(target) + log_game("[chassis.occupant.ckey]([chassis.occupant]) used a Gravitational Catapult in ([T.x],[T.y],[T.z])") + return 1 + + +/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info() + return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" + +/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return + + + + +//////////////////////////// ARMOR BOOSTER MODULES ////////////////////////////////////////////////////////// + + +/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants. + name = "armor booster module (Close Combat Weaponry)" + desc = "Boosts exosuit armor against armed melee attacks. Requires energy to operate." + icon_state = "mecha_abooster_ccw" + origin_tech = "materials=3" + equip_cooldown = 10 + energy_drain = 50 + range = 0 + var/deflect_coeff = 1.15 + var/damage_coeff = 0.8 + +/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/get_equip_info() + if(!chassis) return + return "* [src.name]" + +/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/attack_react(mob/user as mob) + if(action_checks(user)) + start_cooldown() + return 1 + + + +/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster + name = "armor booster module (Ranged Weaponry)" + desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots. Requires energy to operate." + icon_state = "mecha_abooster_proj" + origin_tech = "materials=4" + equip_cooldown = 10 + energy_drain = 50 + range = 0 + var/deflect_coeff = 1.15 + var/damage_coeff = 0.8 + +/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/get_equip_info() + if(!chassis) return + return "* [src.name]" + +/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/projectile_react() + if(action_checks(src)) + start_cooldown() + return 1 + + +////////////////////////////////// REPAIR DROID ////////////////////////////////////////////////// + + +/obj/item/mecha_parts/mecha_equipment/repair_droid + name = "exosuit repair droid" + desc = "An automated repair droid for exosuits. Scans for damage and repairs it. Can fix almost all types of external or internal damage." + icon_state = "repair_droid" + origin_tech = "magnets=3;programming=3" + energy_drain = 50 + range = 0 + var/health_boost = 1 + var/icon/droid_overlay + var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH) + +/obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy() + SSobj.processing.Remove(src) + if(chassis) + chassis.overlays -= droid_overlay + ..() + +/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj) + ..() + droid_overlay = new(src.icon, icon_state = "repair_droid") + M.overlays += droid_overlay + +/obj/item/mecha_parts/mecha_equipment/repair_droid/detach() + chassis.overlays -= droid_overlay + SSobj.processing.Remove(src) + ..() + +/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info() + if(!chassis) return + return "* [src.name] - [equip_ready?"A":"Dea"]ctivate" + + +/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list) + ..() + if(href_list["toggle_repairs"]) + chassis.overlays -= droid_overlay + if(equip_ready) + SSobj.processing |= src + droid_overlay = new(src.icon, icon_state = "repair_droid_a") + log_message("Activated.") + set_ready_state(0) + else + SSobj.processing.Remove(src) + droid_overlay = new(src.icon, icon_state = "repair_droid") + log_message("Deactivated.") + set_ready_state(1) + chassis.overlays += droid_overlay + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + + +/obj/item/mecha_parts/mecha_equipment/repair_droid/process() + if(!chassis) + SSobj.processing.Remove(src) + set_ready_state(1) + return + var/h_boost = health_boost + var/repaired = 0 + if(chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT) + h_boost *= -2 + else if(chassis.internal_damage && prob(15)) + for(var/int_dam_flag in repairable_damage) + if(chassis.internal_damage & int_dam_flag) + chassis.clearInternalDamage(int_dam_flag) + repaired = 1 + break + if(health_boost<0 || chassis.health < initial(chassis.health)) + chassis.health += min(health_boost, initial(chassis.health)-chassis.health) + repaired = 1 + if(repaired) + if(!chassis.use_power(energy_drain)) + SSobj.processing.Remove(src) + set_ready_state(1) + else //no repair needed, we turn off + SSobj.processing.Remove(src) + set_ready_state(1) + chassis.overlays -= droid_overlay + droid_overlay = new(src.icon, icon_state = "repair_droid") + chassis.overlays += droid_overlay + + + + +/////////////////////////////////// TESLA ENERGY RELAY //////////////////////////////////////////////// + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay + name = "exosuit energy relay" + desc = "An exosuit module that wirelessly drains energy from any available power channel in area. The performance index is quite low." + icon_state = "tesla" + origin_tech = "magnets=4;powerstorage=3" + energy_drain = 0 + range = 0 + var/coeff = 100 + var/list/use_channels = list(EQUIP,ENVIRON,LIGHT) + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy() + SSobj.processing.Remove(src) + ..() + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach() + SSobj.processing.Remove(src) + ..() + return + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_charge() + if(equip_ready) //disabled + return + var/area/A = get_area(chassis) + var/pow_chan = get_power_channel(A) + if(pow_chan) + return 1000 //making magic + + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_power_channel(var/area/A) + var/pow_chan + if(A) + for(var/c in use_channels) + if(A.master && A.master.powered(c)) + pow_chan = c + break + return pow_chan + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list) + ..() + if(href_list["toggle_relay"]) + if(equip_ready) //inactive + SSobj.processing |= src + set_ready_state(0) + log_message("Activated.") + else + SSobj.processing.Remove(src) + set_ready_state(1) + log_message("Deactivated.") + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info() + if(!chassis) return + return "* [src.name] - [equip_ready?"A":"Dea"]ctivate" + + +/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/process() + if(!chassis || chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT) + SSobj.processing.Remove(src) + set_ready_state(1) + return + var/cur_charge = chassis.get_charge() + if(isnull(cur_charge) || !chassis.cell) + SSobj.processing.Remove(src) + set_ready_state(1) + occupant_message("No powercell detected.") + return + if(cur_charge < chassis.cell.maxcharge) + var/area/A = get_area(chassis) + if(A) + var/pow_chan + for(var/c in list(EQUIP,ENVIRON,LIGHT)) + if(A.master.powered(c)) + pow_chan = c + break + if(pow_chan) + var/delta = min(20, chassis.cell.maxcharge-cur_charge) + chassis.give_power(delta) + A.master.use_power(delta*coeff, pow_chan) + + + + +/////////////////////////////////////////// GENERATOR ///////////////////////////////////////////// + + +/obj/item/mecha_parts/mecha_equipment/generator + name = "exosuit plasma converter" + desc = "An exosuit module that generates power using solid plasma as fuel. Pollutes the environment." + icon_state = "tesla" + origin_tech = "plasmatech=2;powerstorage=2;engineering=1" + range = MELEE + var/coeff = 100 + var/obj/item/stack/sheet/fuel + var/max_fuel = 150000 + var/fuel_per_cycle_idle = 25 + var/fuel_per_cycle_active = 200 + var/power_per_cycle = 20 + reliability = 1000 + +/obj/item/mecha_parts/mecha_equipment/generator/New() + ..() + generator_init() + +/obj/item/mecha_parts/mecha_equipment/generator/Destroy() + SSobj.processing.Remove(src) + ..() + +/obj/item/mecha_parts/mecha_equipment/generator/proc/generator_init() + fuel = new /obj/item/stack/sheet/mineral/plasma(src) + fuel.amount = 0 + +/obj/item/mecha_parts/mecha_equipment/generator/detach() + SSobj.processing.Remove(src) + ..() + +/obj/item/mecha_parts/mecha_equipment/generator/Topic(href, href_list) + ..() + if(href_list["toggle"]) + if(equip_ready) //inactive + set_ready_state(0) + SSobj.processing |= src + log_message("Activated.") + else + set_ready_state(1) + SSobj.processing.Remove(src) + log_message("Deactivated.") + +/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info() + var/output = ..() + if(output) + return "[output] \[[fuel]: [round(fuel.amount*fuel.perunit,0.1)] cm3\] - [equip_ready?"A":"Dea"]ctivate" + +/obj/item/mecha_parts/mecha_equipment/generator/action(target) + if(chassis) + var/result = load_fuel(target) + if(result) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + +/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/sheet/P) + if(P.type == fuel.type && P.amount > 0) + var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0) + if(to_load) + var/units = min(max(round(to_load / P.perunit),1),P.amount) + fuel.amount += units + P.use(units) + occupant_message("[units] unit\s of [fuel] successfully loaded.") + return units + else + occupant_message("Unit is full.") + return 0 + else + occupant_message("[fuel] traces in target minimal! [P] cannot be used as fuel.") + return + +/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user, params) + load_fuel(weapon) + +/obj/item/mecha_parts/mecha_equipment/generator/critfail() + ..() + var/turf/simulated/T = get_turf(src) + if(!T) + return + var/datum/gas_mixture/GM = new + if(prob(10)) + GM.toxins += 100 + GM.temperature = 1500+T0C //should be enough to start a fire + T.visible_message("The [src] suddenly disgorges a cloud of heated plasma.") + qdel(src) + else + GM.toxins += 5 + GM.temperature = istype(T) ? T.air.return_temperature() : T20C + T.visible_message("The [src] suddenly disgorges a cloud of plasma.") + T.assume_air(GM) + return + +/obj/item/mecha_parts/mecha_equipment/generator/process() + if(!chassis) + SSobj.processing.Remove(src) + set_ready_state(1) + return + if(fuel.amount<=0) + SSobj.processing.Remove(src) + log_message("Deactivated - no fuel.") + set_ready_state(1) + return + if(anyprob(reliability)) + set_ready_state(1) //inactive + critfail() + SSobj.processing.Remove(src) + return + var/cur_charge = chassis.get_charge() + if(isnull(cur_charge)) + set_ready_state(1) + occupant_message("No powercell detected.") + log_message("Deactivated.") + SSobj.processing.Remove(src) + return + var/use_fuel = fuel_per_cycle_idle + if(cur_charge < chassis.cell.maxcharge) + use_fuel = fuel_per_cycle_active + chassis.give_power(power_per_cycle) + fuel.amount -= min(use_fuel/fuel.perunit,fuel.amount) + update_equip_info() + return 1 + + +/obj/item/mecha_parts/mecha_equipment/generator/nuclear + name = "exonuclear reactor" + desc = "An exosuit module that generates power using uranium as fuel. Pollutes the environment." + icon_state = "tesla" + origin_tech = "powerstorage=3;engineering=3" + max_fuel = 50000 + fuel_per_cycle_idle = 10 + fuel_per_cycle_active = 30 + power_per_cycle = 50 + var/rad_per_cycle = 0.3 + reliability = 1000 + +/obj/item/mecha_parts/mecha_equipment/generator/nuclear/generator_init() + fuel = new /obj/item/stack/sheet/mineral/uranium(src) + fuel.amount = 0 + +/obj/item/mecha_parts/mecha_equipment/generator/nuclear/critfail() + return + +/obj/item/mecha_parts/mecha_equipment/generator/nuclear/process() + if(..()) + for(var/mob/living/carbon/M in view(chassis)) + if(istype(M,/mob/living/carbon/human)) + M.irradiate(rad_per_cycle*3) + else + M.irradiate(rad_per_cycle) + + diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm deleted file mode 100644 index 22bd14d2554..00000000000 --- a/code/game/mecha/equipment/tools/tools.dm +++ /dev/null @@ -1,1245 +0,0 @@ -/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp - name = "hydraulic clamp" - desc = "Equipment for engineering exosuits. Lifts objects and loads them into cargo." - icon_state = "mecha_clamp" - equip_cooldown = 15 - energy_drain = 10 - var/dam_force = 20 - var/obj/mecha/working/ripley/cargo_holder - -/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M) - if(..()) - if(istype(M)) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/attach(obj/mecha/M) - ..() - cargo_holder = M - return - -/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/detach(atom/moveto = null) - ..() - if(can_attach(chassis)) - cargo_holder = chassis - else - cargo_holder = null - -/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/action(atom/target) - if(!action_checks(target)) - return - if(!cargo_holder) - return - if(istype(target,/obj)) - var/obj/O = target - if(!O.anchored) - if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) - chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") - set_ready_state(0) - chassis.use_power(energy_drain) - O.anchored = 1 - var/T = chassis.loc - if(do_after_cooldown(target)) - if(T == chassis.loc && src == chassis.selected) - cargo_holder.cargo += O - O.loc = chassis - O.anchored = 0 - occupant_message("[target] successfully loaded.") - log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") - else - occupant_message("You must hold still while handling objects!") - O.anchored = initial(O.anchored) - else - occupant_message("Not enough room in cargo compartment!") - else - occupant_message("[target] is firmly secured!") - - else if(istype(target,/mob/living)) - var/mob/living/M = target - if(M.stat>1) return - if(chassis.occupant.a_intent == "harm") - M.take_overall_damage(dam_force) - if(!M) - return - M.adjustOxyLoss(round(dam_force/2)) - M.updatehealth() - target.visible_message("[chassis] squeezes [target].", \ - "[chassis] squeezes [target].",\ - "You hear something crack.") - add_logs(chassis.occupant, M, "attacked", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])") - else - step_away(M,chassis) - occupant_message("You push [target] out of the way.") - chassis.visible_message("[chassis] pushes [target] out of the way.") - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return 1 - -/obj/item/mecha_parts/mecha_equipment/tool/drill - name = "exosuit drill" - desc = "Equipment for engineering and combat exosuits. This is the drill that'll pierce the heavens!" - icon_state = "mecha_drill" - equip_cooldown = 30 - energy_drain = 10 - force = 15 - -/obj/item/mecha_parts/mecha_equipment/tool/drill/action(atom/target) - if(!action_checks(target)) - return - if(istype(target, /turf) && !istype(target, /turf/simulated)) - return - if(isobj(target)) - var/obj/target_obj = target - if(target_obj.unacidable) - return - set_ready_state(0) - chassis.use_power(energy_drain) - target.visible_message("[chassis] starts to drill [target].", \ - "[chassis] starts to drill [target]...", \ - "You hear drilling.") - var/T = chassis.loc - var/C = target.loc //why are these backwards? we may never know -Pete - if(do_after_cooldown(target)) - if(T == chassis.loc && src == chassis.selected) - if(istype(target, /turf/simulated/wall/r_wall)) - if(istype(src , /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill)) - if(do_after_cooldown(target))//To slow down how fast mechs can drill through the station - log_message("Drilled through [target]") - target.ex_act(3) - else - occupant_message("[target] is too durable to drill through.") - else if(istype(target, /turf/simulated/mineral)) - for(var/turf/simulated/mineral/M in range(chassis,1)) - if(get_dir(chassis,M)&chassis.dir) - M.gets_drilled(chassis.occupant) - log_message("Drilled through [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - else if(istype(target, /turf/simulated/floor/plating/asteroid)) - for(var/turf/simulated/floor/plating/asteroid/M in range(chassis,1)) - if(get_dir(chassis,M)&chassis.dir) - M.gets_dug() - log_message("Drilled through [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - else if(target.loc == C) - log_message("Drilled through [target]") - if(isliving(target)) - if(istype(src , /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill)) - drill_mob(target, chassis.occupant, 120) - else - drill_mob(target, chassis.occupant) - else - target.ex_act(2) - return 1 - -/obj/item/mecha_parts/mecha_equipment/tool/drill/can_attach(obj/mecha/M) - if(..()) - if(istype(M, /obj/mecha/working) || istype(M, /obj/mecha/combat)) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/tool/drill/proc/drill_mob(mob/living/target, mob/user, drill_damage=80) - target.visible_message("[chassis] drills [target] with [src].", \ - "[chassis] drills [target] with [src].") - if(ishuman(target)) - var/mob/living/carbon/human/H = target - var/obj/item/organ/limb/affecting = H.get_organ("chest") - affecting.take_damage(drill_damage) - H.update_damage_overlays(0) - else - target.take_organ_damage(drill_damage) - if(target) - target.Paralyse(10) - target.updatehealth() - add_logs(user, target, "attacked", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") - -/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill - name = "diamond-tipped exosuit drill" - desc = "Equipment for engineering and combat exosuits. This is an upgraded version of the drill that'll pierce the heavens!" - icon_state = "mecha_diamond_drill" - origin_tech = "materials=4;engineering=3" - equip_cooldown = 20 - force = 15 - - -/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/can_attach(obj/mecha/M) - if(..()) - if(istype(M, /obj/mecha/working) || istype(M, /obj/mecha/combat)) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/tool/mining_scanner - name = "exosuit mining scanner" - desc = "Equipment for engineering and combat exosuits. It will automatically check surrounding rock for useful minerals." - icon_state = "mecha_analyzer" - origin_tech = "materials=3;engineering=2" - equip_cooldown = 30 - var/scanning = 0 - -/obj/item/mecha_parts/mecha_equipment/tool/mining_scanner/New() - SSobj.processing |= src - -/obj/item/mecha_parts/mecha_equipment/tool/mining_scanner/process() - if(!loc) - SSobj.processing.Remove(src) - qdel(src) - if(scanning) - return - if(istype(loc,/obj/mecha/working)) - var/obj/mecha/working/mecha = loc - if(!mecha.occupant) - return - var/list/occupant = list() - occupant |= mecha.occupant - scanning = 1 - mineral_scan_pulse(occupant,get_turf(loc)) - spawn(equip_cooldown) - scanning = 0 - -/obj/item/mecha_parts/mecha_equipment/tool/extinguisher - name = "exosuit extinguisher" - desc = "Equipment for engineering exosuits. A rapid-firing high capacity fire extinguisher." - icon_state = "mecha_exting" - equip_cooldown = 5 - energy_drain = 0 - range = MELEE|RANGED - -/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/New() - create_reagents(1000) - reagents.add_reagent("water", 1000) - ..() - return - -/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. - if(!action_checks(target) || get_dist(chassis, target)>3) return - if(get_dist(chassis, target)>2) return - set_ready_state(0) - if(do_after_cooldown(target)) - if(istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1) - var/obj/o = target - o.reagents.trans_to(src, 1000) - occupant_message("Extinguisher refilled.") - playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) - else - if(src.reagents.total_volume > 0) - playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) - var/direction = get_dir(chassis,target) - var/turf/T = get_turf(target) - var/turf/T1 = get_step(T,turn(direction, 90)) - var/turf/T2 = get_step(T,turn(direction, -90)) - - var/list/the_targets = list(T,T1,T2) - spawn(0) - for(var/a=0, a<5, a++) - var/obj/effect/effect/water/W = PoolOrNew(/obj/effect/effect/water, get_turf(chassis)) - if(!W) - return - var/turf/my_target = pick(the_targets) - var/datum/reagents/R = new/datum/reagents(5) - W.reagents = R - R.my_atom = W - src.reagents.trans_to(W,1) - for(var/b=0, b<4, b++) - if(!W) - return - step_towards(W,my_target) - if(!W) - return - var/turf/W_turf = get_turf(W) - W.reagents.reaction(W_turf) - for(var/atom/atm in W_turf) - W.reagents.reaction(atm) - if(W.loc == my_target) - break - sleep(2) - return 1 - -/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/get_equip_info() - return "[..()] \[[src.reagents.total_volume]\]" - -/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/on_reagent_change() - return - -/obj/item/mecha_parts/mecha_equipment/tool/extinguisher/can_attach(obj/mecha/working/M) - if(..()) - if(istype(M)) - return 1 - return 0 - - -/obj/item/mecha_parts/mecha_equipment/tool/rcd - name = "mounted RCD" - desc = "An exosuit-mounted Rapid Construction Device." - icon_state = "mecha_rcd" - origin_tech = "materials=4;bluespace=3;magnets=4;powerstorage=4" - equip_cooldown = 10 - energy_drain = 250 - range = MELEE|RANGED - var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. - var/disabled = 0 //malf - -/obj/item/mecha_parts/mecha_equipment/tool/rcd/action(atom/target) - if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve - disabled = 1 - else - disabled = 0 - if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock)) - target = get_turf(target) - if(!action_checks(target) || disabled || get_dist(chassis, target)>3) return - playsound(chassis, 'sound/machines/click.ogg', 50, 1) - //meh - switch(mode) - if(0) - if (istype(target, /turf/simulated/wall)) - var/turf/simulated/wall/W = target - occupant_message("Deconstructing [W]...") - set_ready_state(0) - if(do_after_cooldown(W)) - if(disabled) return - chassis.spark_system.start() - W.ChangeTurf(/turf/simulated/floor/plating) - playsound(W, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.use_power(energy_drain) - else if (istype(target, /turf/simulated/floor)) - var/turf/simulated/floor/F = target - occupant_message("Deconstructing [F]...") - set_ready_state(0) - if(do_after_cooldown(F)) - if(disabled) return - chassis.spark_system.start() - F.ChangeTurf(F.baseturf) - playsound(F, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.use_power(energy_drain) - else if (istype(target, /obj/machinery/door/airlock)) - occupant_message("Deconstructing [target]...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - chassis.spark_system.start() - qdel(target) - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.use_power(energy_drain) - if(1) - if(istype(target, /turf/space)) - var/turf/space/S = target - occupant_message("Building Floor...") - set_ready_state(0) - if(do_after_cooldown(S)) - if(disabled) return - S.ChangeTurf(/turf/simulated/floor/plating) - playsound(S, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.spark_system.start() - chassis.use_power(energy_drain*2) - else if(istype(target, /turf/simulated/floor)) - var/turf/simulated/floor/F = target - occupant_message("Building Wall...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - F.ChangeTurf(/turf/simulated/wall) - playsound(F, 'sound/items/Deconstruct.ogg', 50, 1) - chassis.spark_system.start() - chassis.use_power(energy_drain*2) - if(2) - if(istype(target, /turf/simulated/floor)) - occupant_message("Building Airlock...") - set_ready_state(0) - if(do_after_cooldown(target)) - if(disabled) return - chassis.spark_system.start() - var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) - T.autoclose = 1 - playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) - playsound(target, 'sound/effects/sparks2.ogg', 50, 1) - chassis.use_power(energy_drain*2) - return - - -/obj/item/mecha_parts/mecha_equipment/tool/rcd/Topic(href,href_list) - ..() - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - switch(mode) - if(0) - occupant_message("Switched RCD to Deconstruct.") - if(1) - occupant_message("Switched RCD to Construct.") - if(2) - occupant_message("Switched RCD to Construct Airlock.") - return - -/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info() - return "[..()] \[D|C|A\]" - - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer - name = "cable layer" - desc = "Equipment for engineering exosuits. Lays cable along the exosuit's path." - icon_state = "mecha_wire" - var/datum/event/event - var/turf/old_turf - var/obj/structure/cable/last_piece - var/obj/item/stack/cable_coil/cable - var/max_cable = 1000 - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/New() - cable = new(src) - cable.amount = 0 - ..() - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/can_attach(obj/mecha/working/M) - if(..()) - if(istype(M)) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/attach() - ..() - event = chassis.events.addEvent("onMove",src,"layCable") - return - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/detach() - chassis.events.clearEvent("onMove",event) - return ..() - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/destroy() - chassis.events.clearEvent("onMove",event) - return ..() - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/action(obj/item/stack/cable_coil/target) - if(!action_checks(target)) - return - var/result = load_cable(target) - var/message - if(isnull(result)) - message = "Unable to load [target] - no cable found." - else if(!result) - message = "Reel is full." - else - message = "[result] meters of cable successfully loaded." - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - occupant_message(message) - return - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/Topic(href,href_list) - ..() - if(href_list["toggle"]) - set_ready_state(!equip_ready) - occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") - log_message("[equip_ready?"Dea":"A"]ctivated.") - return - if(href_list["cut"]) - if(cable && cable.amount) - var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) - m = min(m, cable.amount) - if(m) - use_cable(m) - var/obj/item/stack/cable_coil/CC = new (get_turf(chassis)) - CC.amount = m - else - occupant_message("There's no more cable on the reel.") - return - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/get_equip_info() - var/output = ..() - if(output) - return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]" - return - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/load_cable(obj/item/stack/cable_coil/CC) - if(istype(CC) && CC.amount) - var/cur_amount = cable? cable.amount : 0 - var/to_load = max(max_cable - cur_amount,0) - if(to_load) - to_load = min(CC.amount, to_load) - if(!cable) - cable = new(src) - cable.amount = 0 - cable.amount += to_load - CC.use(to_load) - return to_load - else - return 0 - return - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/use_cable(amount) - if(!cable || cable.amount<1) - set_ready_state(1) - occupant_message("Cable depleted, [src] deactivated.") - log_message("Cable depleted, [src] deactivated.") - return - if(cable.amount < amount) - occupant_message("No enough cable to finish the task.") - return - cable.use(amount) - update_equip_info() - return 1 - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/reset() - last_piece = null - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/dismantleFloor(turf/new_turf) - if(istype(new_turf, /turf/simulated/floor)) - var/turf/simulated/floor/T = new_turf - if(!istype(T, /turf/simulated/floor/plating)) - if(!T.broken && !T.burnt) - new T.floor_tile(T) - T.make_plating() - return !new_turf.intact - -/obj/item/mecha_parts/mecha_equipment/tool/cable_layer/proc/layCable(turf/new_turf) - if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) - return reset() - var/fdirn = turn(chassis.dir,180) - for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already - if(LC.d1 == fdirn || LC.d2 == fdirn) - return reset() - if(!use_cable(1)) - return reset() - var/obj/structure/cable/NC = new(new_turf) - NC.cableColor("red") - NC.d1 = 0 - NC.d2 = fdirn - NC.updateicon() - - var/datum/powernet/PN - if(last_piece && last_piece.d2 != chassis.dir) - last_piece.d1 = min(last_piece.d2, chassis.dir) - last_piece.d2 = max(last_piece.d2, chassis.dir) - last_piece.updateicon() - PN = last_piece.powernet - - if(!PN) - PN = new() - powernets += PN - NC.powernet = PN - PN.cables += NC - NC.mergeConnectedNetworks(NC.d2) - - //NC.mergeConnectedNetworksOnTurf() - last_piece = NC - return 1 - - -/obj/item/mecha_parts/mecha_equipment/teleporter - name = "mounted teleporter" - desc = "An exosuit module that allows exosuits to teleport to any position in view." - icon_state = "mecha_teleport" - origin_tech = "bluespace=10" - equip_cooldown = 150 - energy_drain = 1000 - range = RANGED - -/obj/item/mecha_parts/mecha_equipment/teleporter/action(atom/target) - if(!action_checks(target) || src.loc.z == ZLEVEL_CENTCOM) return - var/turf/T = get_turf(target) - if(T) - set_ready_state(0) - chassis.use_power(energy_drain) - do_teleport(chassis, T, 4) - do_after_cooldown() - return - - -/obj/item/mecha_parts/mecha_equipment/wormhole_generator - name = "mounted wormhole generator" - desc = "An exosuit module that allows generating of small quasi-stable wormholes." - icon_state = "mecha_wholegen" - origin_tech = "bluespace=3" - equip_cooldown = 50 - energy_drain = 300 - range = RANGED - - -/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target) - if(!action_checks(target) || src.loc.z == ZLEVEL_CENTCOM) return - var/list/theareas = list() - for(var/area/AR in orange(100, chassis)) - if(AR in theareas) continue - theareas += AR - if(!theareas.len) - return - var/area/thearea = pick(theareas) - var/list/L = list() - var/turf/pos = get_turf(src) - for(var/turf/T in get_area_turfs(thearea.type)) - if(!T.density && pos.z == T.z) - var/clear = 1 - for(var/obj/O in T) - if(O.density) - clear = 0 - break - if(clear) - L+=T - if(!L.len) - return - var/turf/target_turf = pick(L) - if(!target_turf) - return - chassis.use_power(energy_drain) - set_ready_state(0) - var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target)) - P.target = target_turf - P.creator = null - P.icon = 'icons/obj/objects.dmi' - P.icon_state = "anom" - P.name = "wormhole" - var/turf/T = get_turf(target) - message_admins("[key_name_admin(chassis.occupant, chassis.occupant.client)](?) (FLW) used a Wormhole Generator in ([T.x],[T.y],[T.z] - JMP)",0,1) - log_game("[key_name(chassis.occupant)] used a Wormhole Generator in ([T.x],[T.y],[T.z])") - do_after_cooldown() - src = null - spawn(rand(150,300)) - qdel(P) - return - -/obj/item/mecha_parts/mecha_equipment/gravcatapult - name = "mounted gravitational catapult" - desc = "An exosuit mounted Gravitational Catapult." - icon_state = "mecha_teleport" - origin_tech = "bluespace=2;magnets=3" - equip_cooldown = 10 - energy_drain = 100 - range = MELEE|RANGED - var/atom/movable/locked - var/mode = 1 //1 - gravsling 2 - gravpush - - -/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target) - switch(mode) - if(1) - if(!action_checks(target) && !locked) return - if(!locked) - if(!istype(target) || target.anchored) - occupant_message("Unable to lock on [target]") - return - locked = target - occupant_message("Locked on [target]") - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - return - else if(target!=locked) - if(locked in view(chassis)) - locked.throw_at(target, 14, 1.5) - locked = null - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - else - locked = null - occupant_message("Lock on [locked] disengaged.") - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - if(2) - if(!action_checks(target)) return - var/list/atoms = list() - if(isturf(target)) - atoms = range(target,3) - else - atoms = orange(target,3) - for(var/atom/movable/A in atoms) - if(A.anchored) continue - spawn(0) - var/iter = 5-get_dist(A,target) - for(var/i=0 to iter) - step_away(A,target) - sleep(2) - set_ready_state(0) - chassis.use_power(energy_drain) - var/turf/T = get_turf(target) - log_game("[chassis.occupant.ckey]([chassis.occupant]) used a Gravitational Catapult in ([T.x],[T.y],[T.z])") - do_after_cooldown() - return - -/obj/item/mecha_parts/mecha_equipment/gravcatapult/get_equip_info() - return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" - -/obj/item/mecha_parts/mecha_equipment/gravcatapult/Topic(href, href_list) - ..() - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - return - - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster //what is that noise? A BAWWW from TK mutants. - name = "armor booster module (Close Combat Weaponry)" - desc = "Boosts exosuit armor against armed melee attacks. Requires energy to operate." - icon_state = "mecha_abooster_ccw" - origin_tech = "materials=3" - equip_cooldown = 10 - energy_drain = 50 - range = 0 - var/deflect_coeff = 1.15 - var/damage_coeff = 0.8 - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/can_attach(obj/mecha/M) - if(..()) - if(!istype(M, /obj/mecha/combat/honker)) - if(!M.proc_res["dynattackby"]) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/attach(obj/mecha/M) - ..() - chassis.proc_res["dynattackby"] = src - return - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/detach() - chassis.proc_res["dynattackby"] = null - ..() - return - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/get_equip_info() - if(!chassis) return - return "* [src.name]" - -/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/proc/dynattackby(obj/item/weapon/W, mob/user) - if(!action_checks(user)) - return chassis.dynattackby(W,user) - chassis.log_message("Attacked by [W]. Attacker - [user]") - if(prob(chassis.deflect_chance*deflect_coeff)) - user << "The [W] bounces off [chassis] armor." - chassis.log_append_to_last("Armor saved.") - else - chassis.occupant_message("[user] hits [chassis] with [W].") - user.visible_message("[user] hits [chassis] with [W].", "You hit [src] with [W].") - chassis.take_damage(round(W.force*damage_coeff),W.damtype) - chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return - - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster - name = "armor booster module (Ranged Weaponry)" - desc = "Boosts exosuit armor against ranged attacks. Completely blocks taser shots. Requires energy to operate." - icon_state = "mecha_abooster_proj" - origin_tech = "materials=4" - equip_cooldown = 10 - energy_drain = 50 - range = 0 - var/deflect_coeff = 1.15 - var/damage_coeff = 0.8 - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/can_attach(obj/mecha/M) - if(..()) - if(!istype(M, /obj/mecha/combat/honker)) - if(!M.proc_res["dynbulletdamage"] && !M.proc_res["dynhitby"]) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/attach(obj/mecha/M) - ..() - chassis.proc_res["dynbulletdamage"] = src - chassis.proc_res["dynhitby"] = src - return - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/detach() - chassis.proc_res["dynbulletdamage"] = null - chassis.proc_res["dynhitby"] = null - ..() - return - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/get_equip_info() - if(!chassis) return - return "* [src.name]" - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/dynbulletdamage(obj/item/projectile/Proj) - if(!action_checks(src)) - return chassis.dynbulletdamage(Proj) - if(prob(chassis.deflect_chance*deflect_coeff)) - chassis.visible_message("The [chassis.name] armor deflects the projectile") - chassis.log_append_to_last("Armor saved.") - else - chassis.take_damage(round(Proj.damage*src.damage_coeff),Proj.flag) - chassis.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - Proj.on_hit(chassis) - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return - -/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/proc/dynhitby(atom/movable/A) - if(!action_checks(A)) - return chassis.dynhitby(A) - if(prob(chassis.deflect_chance*deflect_coeff) || istype(A, /mob/living) || istype(A, /obj/item/mecha_parts/mecha_tracking)) - chassis.visible_message("The [A] bounces off the [chassis] armor") - chassis.log_append_to_last("Armor saved.") - if(istype(A, /mob/living)) - var/mob/living/M = A - M.take_organ_damage(10) - else if(istype(A, /obj)) - var/obj/O = A - if(O.throwforce) - chassis.take_damage(round(O.throwforce*damage_coeff)) - chassis.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return - - -/obj/item/mecha_parts/mecha_equipment/repair_droid - name = "exosuit repair droid" - desc = "An automated repair droid for exosuits. Scans for damage and repairs it. Can fix almost all types of external or internal damage." - icon_state = "repair_droid" - origin_tech = "magnets=3;programming=3" - equip_cooldown = 20 - energy_drain = 100 - range = 0 - var/health_boost = 2 - var/datum/global_iterator/pr_repair_droid - var/icon/droid_overlay - var/list/repairable_damage = list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH) - -/obj/item/mecha_parts/mecha_equipment/repair_droid/New() - ..() - pr_repair_droid = new /datum/global_iterator/mecha_repair_droid(list(src),0) - pr_repair_droid.set_delay(equip_cooldown) - return - -/obj/item/mecha_parts/mecha_equipment/repair_droid/Destroy() - qdel(pr_repair_droid) - pr_repair_droid = null - ..() - -/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj) - ..() - droid_overlay = new(src.icon, icon_state = "repair_droid") - M.overlays += droid_overlay - return - -/obj/item/mecha_parts/mecha_equipment/repair_droid/destroy() - chassis.overlays -= droid_overlay - ..() - return - -/obj/item/mecha_parts/mecha_equipment/repair_droid/detach() - chassis.overlays -= droid_overlay - pr_repair_droid.stop() - ..() - return - -/obj/item/mecha_parts/mecha_equipment/repair_droid/get_equip_info() - if(!chassis) return - return "* [src.name] - [pr_repair_droid.active()?"Dea":"A"]ctivate" - - -/obj/item/mecha_parts/mecha_equipment/repair_droid/Topic(href, href_list) - ..() - if(href_list["toggle_repairs"]) - chassis.overlays -= droid_overlay - if(pr_repair_droid.toggle()) - droid_overlay = new(src.icon, icon_state = "repair_droid_a") - log_message("Activated.") - else - droid_overlay = new(src.icon, icon_state = "repair_droid") - log_message("Deactivated.") - set_ready_state(1) - chassis.overlays += droid_overlay - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - return - - -/datum/global_iterator/mecha_repair_droid - -/datum/global_iterator/mecha_repair_droid/process(obj/item/mecha_parts/mecha_equipment/repair_droid/RD) - if(!RD.chassis) - stop() - RD.set_ready_state(1) - return - var/health_boost = RD.health_boost - var/repaired = 0 - if(RD.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - health_boost *= -2 - else if(RD.chassis.hasInternalDamage() && prob(15)) - for(var/int_dam_flag in RD.repairable_damage) - if(RD.chassis.hasInternalDamage(int_dam_flag)) - RD.chassis.clearInternalDamage(int_dam_flag) - repaired = 1 - break - if(health_boost<0 || RD.chassis.health < initial(RD.chassis.health)) - RD.chassis.health += min(health_boost, initial(RD.chassis.health)-RD.chassis.health) - repaired = 1 - if(repaired) - if(RD.chassis.use_power(RD.energy_drain)) - RD.set_ready_state(0) - else - stop() - RD.set_ready_state(1) - return - else - RD.set_ready_state(1) - return - - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay - name = "exosuit energy relay" - desc = "An exosuit module that wirelessly drains energy from any available power channel in area. The performance index is quite low." - icon_state = "tesla" - origin_tech = "magnets=4;powerstorage=3" - equip_cooldown = 10 - energy_drain = 0 - range = 0 - var/datum/global_iterator/pr_energy_relay - var/coeff = 100 - var/list/use_channels = list(EQUIP,ENVIRON,LIGHT) - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/New() - ..() - pr_energy_relay = new /datum/global_iterator/mecha_energy_relay(list(src),0) - pr_energy_relay.set_delay(equip_cooldown) - return - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy() - qdel(pr_energy_relay) - pr_energy_relay = null - ..() - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/detach() - pr_energy_relay.stop() -// chassis.proc_res["dynusepower"] = null - chassis.proc_res["dyngetcharge"] = null - ..() - return - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/attach(obj/mecha/M) - ..() - chassis.proc_res["dyngetcharge"] = src -// chassis.proc_res["dynusepower"] = src - return - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/can_attach(obj/mecha/M) - if(..()) - if(!M.proc_res["dyngetcharge"])// && !M.proc_res["dynusepower"]) - return 1 - return 0 - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/dyngetcharge() - if(equip_ready) //disabled - return chassis.dyngetcharge() - var/area/A = get_area(chassis) - var/pow_chan = get_power_channel(A) - var/charge = 0 - if(pow_chan) - charge = 1000 //making magic - else - return chassis.dyngetcharge() - return charge - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/get_power_channel(area/A) - var/pow_chan - if(A) - for(var/c in use_channels) - if(A.master && A.master.powered(c)) - pow_chan = c - break - return pow_chan - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Topic(href, href_list) - ..() - if(href_list["toggle_relay"]) - if(pr_energy_relay.toggle()) - set_ready_state(0) - log_message("Activated.") - else - set_ready_state(1) - log_message("Deactivated.") - return - -/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/get_equip_info() - if(!chassis) return - return "* [src.name] - [pr_energy_relay.active()?"Dea":"A"]ctivate" - -/*/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/proc/dynusepower(amount) - if(!equip_ready) //enabled - var/area/A = get_area(chassis) - var/pow_chan = get_power_channel(A) - if(pow_chan) - A.master.use_power(amount*coeff, pow_chan) - return 1 - return chassis.dynusepower(amount)*/ - -/datum/global_iterator/mecha_energy_relay - -/datum/global_iterator/mecha_energy_relay/process(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/ER) - if(!ER.chassis || ER.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - stop() - ER.set_ready_state(1) - return - var/cur_charge = ER.chassis.get_charge() - if(isnull(cur_charge) || !ER.chassis.cell) - stop() - ER.set_ready_state(1) - ER.occupant_message("No powercell detected.") - return - if(cur_charge3\] - [pr_mech_generator.active()?"Dea":"A"]ctivate" - return - -/obj/item/mecha_parts/mecha_equipment/generator/action(target) - if(chassis) - var/result = load_fuel(target) - var/message - if(isnull(result)) - message = "[fuel] traces in target minimal! [target] cannot be used as fuel." - else if(!result) - message = "Unit is full." - else - message = "[result] unit\s of [fuel] successfully loaded." - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - occupant_message(message) - return - -/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(obj/item/stack/sheet/P) - if(P.type == fuel.type && P.amount) - var/to_load = max(max_fuel - fuel.amount*fuel.perunit,0) - if(to_load) - var/units = min(max(round(to_load / P.perunit),1),P.amount) - if(units) - fuel.amount += units - P.use(units) - return units - else - return 0 - return - -/obj/item/mecha_parts/mecha_equipment/generator/attackby(weapon,mob/user, params) - var/result = load_fuel(weapon) - if(isnull(result)) - user.visible_message("[user] tries to shove [weapon] into [src]. What a dumb-ass.","[fuel] traces minimal. [weapon] cannot be used as fuel.") - else if(!result) - user << "Unit is full." - else - user.visible_message("[user] loads [src] with [fuel].","[result] unit\s of [fuel] successfully loaded.") - return - -/obj/item/mecha_parts/mecha_equipment/generator/critfail() - ..() - var/turf/simulated/T = get_turf(src) - if(!T) - return - var/datum/gas_mixture/GM = new - if(prob(10)) - GM.toxins += 100 - GM.temperature = 1500+T0C //should be enough to start a fire - T.visible_message("The [src] suddenly disgorges a cloud of heated plasma.") - destroy() - else - GM.toxins += 5 - GM.temperature = istype(T) ? T.air.return_temperature() : T20C - T.visible_message("The [src] suddenly disgorges a cloud of plasma.") - T.assume_air(GM) - return - -/datum/global_iterator/mecha_generator - -/datum/global_iterator/mecha_generator/process(var/obj/item/mecha_parts/mecha_equipment/generator/EG) - if(!EG.chassis) - stop() - EG.set_ready_state(1) - return 0 - if(EG.fuel.amount<=0) - stop() - EG.log_message("Deactivated - no fuel.") - EG.set_ready_state(1) - return 0 - if(anyprob(EG.reliability)) - EG.critfail() - stop() - return 0 - var/cur_charge = EG.chassis.get_charge() - if(isnull(cur_charge)) - EG.set_ready_state(1) - EG.occupant_message("No powercell detected.") - EG.log_message("Deactivated.") - stop() - return 0 - var/use_fuel = EG.fuel_per_cycle_idle - if(cur_charge[target] successfully loaded.") - chassis.log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") - else - chassis.occupant_message("You must hold still while handling objects!") - O.anchored = initial(O.anchored) - else - chassis.occupant_message("Not enough room in cargo compartment!") - else - chassis.occupant_message("[target] is firmly secured!") - - else if(istype(target,/mob/living)) - var/mob/living/M = target - if(M.stat>1) return - if(chassis.occupant.a_intent == "harm") - target.visible_message("[chassis] destroys [target] in an unholy fury.", \ - "[chassis] destroys [target] in an unholy fury.") - if(chassis.occupant.a_intent == "disarm") - target.visible_message("[chassis] rips [target]'s arms off.", \ - "[chassis] rips [target]'s arms off.") - else - step_away(M,chassis) - target.visible_message("[chassis] tosses [target] like a piece of paper.") - set_ready_state(0) - chassis.use_power(energy_drain) - do_after_cooldown() - return 1 diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm new file mode 100644 index 00000000000..ef4de9cf891 --- /dev/null +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -0,0 +1,424 @@ + +//Hydraulic clamp, Kill clamp, Extinguisher, RCD, Cable layer. + + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp + name = "hydraulic clamp" + desc = "Equipment for engineering exosuits. Lifts objects and loads them into cargo." + icon_state = "mecha_clamp" + equip_cooldown = 15 + energy_drain = 10 + var/dam_force = 20 + var/obj/mecha/working/ripley/cargo_holder + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/attach(obj/mecha/M as obj) + ..() + cargo_holder = M + return + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/detach(atom/moveto = null) + ..() + cargo_holder = null + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/action(atom/target) + if(!action_checks(target)) + return + if(!cargo_holder) + return + if(istype(target,/obj)) + var/obj/O = target + if(!O.anchored) + if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) + chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") + O.anchored = 1 + if(do_after_cooldown(target)) + cargo_holder.cargo += O + O.loc = chassis + O.anchored = 0 + occupant_message("[target] successfully loaded.") + log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") + else + O.anchored = initial(O.anchored) + else + occupant_message("Not enough room in cargo compartment!") + else + occupant_message("[target] is firmly secured!") + + else if(istype(target,/mob/living)) + var/mob/living/M = target + if(M.stat == DEAD) return + if(chassis.occupant.a_intent == "harm") + M.take_overall_damage(dam_force) + if(!M) + return + M.adjustOxyLoss(round(dam_force/2)) + M.updatehealth() + target.visible_message("[chassis] squeezes [target].", \ + "[chassis] squeezes [target].",\ + "You hear something crack.") + add_logs(chassis.occupant, M, "attacked", "[name]", "(INTENT: [uppertext(chassis.occupant.a_intent)]) (DAMTYE: [uppertext(damtype)])") + else + step_away(M,chassis) + occupant_message("You push [target] out of the way.") + chassis.visible_message("[chassis] pushes [target] out of the way.") + return 1 + + + +//This is pretty much just for the death-ripley +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill + name = "\improper KILL CLAMP" + desc = "They won't know what clamped them!" + energy_drain = 0 + +/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill/action(atom/target) + if(!action_checks(target)) return + if(!cargo_holder) return + if(istype(target,/obj)) + var/obj/O = target + if(!O.anchored) + if(cargo_holder.cargo.len < cargo_holder.cargo_capacity) + chassis.visible_message("[chassis] lifts [target] and starts to load it into cargo compartment.") + O.anchored = 1 + if(do_after_cooldown(target)) + cargo_holder.cargo += O + O.loc = chassis + O.anchored = 0 + occupant_message("[target] successfully loaded.") + log_message("Loaded [O]. Cargo compartment capacity: [cargo_holder.cargo_capacity - cargo_holder.cargo.len]") + else + O.anchored = initial(O.anchored) + else + occupant_message("Not enough room in cargo compartment!") + else + occupant_message("[target] is firmly secured!") + + else if(istype(target,/mob/living)) + var/mob/living/M = target + if(M.stat == DEAD) return + if(chassis.occupant.a_intent == "harm") + target.visible_message("[chassis] destroys [target] in an unholy fury.", \ + "[chassis] destroys [target] in an unholy fury.") + if(chassis.occupant.a_intent == "disarm") + target.visible_message("[chassis] rips [target]'s arms off.", \ + "[chassis] rips [target]'s arms off.") + else + step_away(M,chassis) + target.visible_message("[chassis] tosses [target] like a piece of paper.") + return 1 + + + +/obj/item/mecha_parts/mecha_equipment/extinguisher + name = "exosuit extinguisher" + desc = "Equipment for engineering exosuits. A rapid-firing high capacity fire extinguisher." + icon_state = "mecha_exting" + equip_cooldown = 5 + energy_drain = 0 + range = MELEE|RANGED + +/obj/item/mecha_parts/mecha_equipment/extinguisher/New() + create_reagents(1000) + reagents.add_reagent("water", 1000) + ..() + return + +/obj/item/mecha_parts/mecha_equipment/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. + if(!action_checks(target) || get_dist(chassis, target)>3) + return + + if(istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1) + var/obj/structure/reagent_dispensers/watertank/WT = target + WT.reagents.trans_to(src, 1000) + occupant_message("Extinguisher refilled.") + playsound(chassis, 'sound/effects/refill.ogg', 50, 1, -6) + else + if(reagents.total_volume > 0) + playsound(chassis, 'sound/effects/extinguish.ogg', 75, 1, -3) + var/direction = get_dir(chassis,target) + var/turf/T = get_turf(target) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + + var/list/the_targets = list(T,T1,T2) + spawn(0) + for(var/a=0, a<5, a++) + var/obj/effect/effect/water/W = PoolOrNew(/obj/effect/effect/water, get_turf(chassis)) + if(!W) + return + var/turf/my_target = pick(the_targets) + var/datum/reagents/R = new/datum/reagents(5) + W.reagents = R + R.my_atom = W + reagents.trans_to(W,1) + for(var/b=0, b<4, b++) + if(!W) + return + step_towards(W,my_target) + if(!W) + return + var/turf/W_turf = get_turf(W) + W.reagents.reaction(W_turf) + for(var/atom/atm in W_turf) + W.reagents.reaction(atm) + if(W.loc == my_target) + break + sleep(2) + return 1 + +/obj/item/mecha_parts/mecha_equipment/extinguisher/get_equip_info() + return "[..()] \[[src.reagents.total_volume]\]" + +/obj/item/mecha_parts/mecha_equipment/extinguisher/on_reagent_change() + return + +/obj/item/mecha_parts/mecha_equipment/extinguisher/can_attach(obj/mecha/working/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 + + + +/obj/item/mecha_parts/mecha_equipment/rcd + name = "mounted RCD" + desc = "An exosuit-mounted Rapid Construction Device." + icon_state = "mecha_rcd" + origin_tech = "materials=4;bluespace=3;magnets=4;powerstorage=4" + equip_cooldown = 10 + energy_drain = 250 + range = MELEE|RANGED + var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock. + var/disabled = 0 //malf + +/obj/item/mecha_parts/mecha_equipment/rcd/action(atom/target) + if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve + disabled = 1 + else + disabled = 0 + if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock)) + target = get_turf(target) + if(!action_checks(target) || disabled || get_dist(chassis, target)>3) + return + playsound(chassis, 'sound/machines/click.ogg', 50, 1) + + switch(mode) + if(0) + if (istype(target, /turf/simulated/wall)) + var/turf/simulated/wall/W = target + occupant_message("Deconstructing [W]...") + if(do_after_cooldown(W)) + chassis.spark_system.start() + W.ChangeTurf(/turf/simulated/floor/plating) + playsound(W, 'sound/items/Deconstruct.ogg', 50, 1) + else if (istype(target, /turf/simulated/floor)) + var/turf/simulated/floor/F = target + occupant_message("Deconstructing [F]...") + if(do_after_cooldown(target)) + chassis.spark_system.start() + F.ChangeTurf(F.baseturf) + playsound(F, 'sound/items/Deconstruct.ogg', 50, 1) + else if (istype(target, /obj/machinery/door/airlock)) + occupant_message("Deconstructing [target]...") + if(do_after_cooldown(target)) + chassis.spark_system.start() + qdel(target) + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + if(1) + if(istype(target, /turf/space)) + var/turf/space/S = target + occupant_message("Building Floor...") + if(do_after_cooldown(S)) + S.ChangeTurf(/turf/simulated/floor/plating) + playsound(S, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.spark_system.start() + else if(istype(target, /turf/simulated/floor)) + var/turf/simulated/floor/F = target + occupant_message("Building Wall...") + if(do_after_cooldown(F)) + if(disabled) return + F.ChangeTurf(/turf/simulated/wall) + playsound(F, 'sound/items/Deconstruct.ogg', 50, 1) + chassis.spark_system.start() + if(2) + if(istype(target, /turf/simulated/floor)) + occupant_message("Building Airlock...") + if(do_after_cooldown(target)) + chassis.spark_system.start() + var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target) + T.autoclose = 1 + playsound(target, 'sound/items/Deconstruct.ogg', 50, 1) + playsound(target, 'sound/effects/sparks2.ogg', 50, 1) + + + +/obj/item/mecha_parts/mecha_equipment/rcd/do_after_cooldown(var/atom/target) + . = ..() + if(disabled) + return 0 + +/obj/item/mecha_parts/mecha_equipment/rcd/Topic(href,href_list) + ..() + if(href_list["mode"]) + mode = text2num(href_list["mode"]) + switch(mode) + if(0) + occupant_message("Switched RCD to Deconstruct.") + energy_drain = initial(energy_drain) + if(1) + occupant_message("Switched RCD to Construct.") + energy_drain = 2*initial(energy_drain) + if(2) + occupant_message("Switched RCD to Construct Airlock.") + energy_drain = 2*initial(energy_drain) + return + +/obj/item/mecha_parts/mecha_equipment/rcd/get_equip_info() + return "[..()] \[D|C|A\]" + + + + +/obj/item/mecha_parts/mecha_equipment/cable_layer + name = "cable layer" + desc = "Equipment for engineering exosuits. Lays cable along the exosuit's path." + icon_state = "mecha_wire" + var/datum/event/event + var/turf/old_turf + var/obj/structure/cable/last_piece + var/obj/item/stack/cable_coil/cable + var/max_cable = 1000 + +/obj/item/mecha_parts/mecha_equipment/cable_layer/New() + cable = new(src) + cable.amount = 0 + ..() + +/obj/item/mecha_parts/mecha_equipment/cable_layer/can_attach(obj/mecha/working/M) + if(..()) + if(istype(M)) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/cable_layer/attach() + ..() + event = chassis.events.addEvent("onMove",src,"layCable") + return + +/obj/item/mecha_parts/mecha_equipment/cable_layer/detach() + chassis.events.clearEvent("onMove",event) + return ..() + +/obj/item/mecha_parts/mecha_equipment/cable_layer/Destroy() + chassis.events.clearEvent("onMove",event) + ..() + +/obj/item/mecha_parts/mecha_equipment/cable_layer/action(var/obj/item/stack/cable_coil/target) + if(!action_checks(target)) + return + if(istype(target) && target.amount) + var/cur_amount = cable? cable.amount : 0 + var/to_load = max(max_cable - cur_amount,0) + if(to_load) + to_load = min(target.amount, to_load) + if(!cable) + cable = new(src) + cable.amount = 0 + cable.amount += to_load + target.use(to_load) + occupant_message("[to_load] meters of cable successfully loaded.") + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + else + occupant_message("Reel is full.") + else + occupant_message("Unable to load [target] - no cable found.") + + +/obj/item/mecha_parts/mecha_equipment/cable_layer/Topic(href,href_list) + ..() + if(href_list["toggle"]) + set_ready_state(!equip_ready) + occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") + log_message("[equip_ready?"Dea":"A"]ctivated.") + return + if(href_list["cut"]) + if(cable && cable.amount) + var/m = round(input(chassis.occupant,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1) + m = min(m, cable.amount) + if(m) + use_cable(m) + var/obj/item/stack/cable_coil/CC = new (get_turf(chassis)) + CC.amount = m + else + occupant_message("There's no more cable on the reel.") + return + +/obj/item/mecha_parts/mecha_equipment/cable_layer/get_equip_info() + var/output = ..() + if(output) + return "[output] \[Cable: [cable ? cable.amount : 0] m\][(cable && cable.amount) ? "- [!equip_ready?"Dea":"A"]ctivate|Cut" : null]" + return + +/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/use_cable(amount) + if(!cable || cable.amount<1) + set_ready_state(1) + occupant_message("Cable depleted, [src] deactivated.") + log_message("Cable depleted, [src] deactivated.") + return + if(cable.amount < amount) + occupant_message("No enough cable to finish the task.") + return + cable.use(amount) + update_equip_info() + return 1 + +/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/reset() + last_piece = null + +/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/dismantleFloor(var/turf/new_turf) + if(istype(new_turf, /turf/simulated/floor)) + var/turf/simulated/floor/T = new_turf + if(!istype(T, /turf/simulated/floor/plating)) + if(!T.broken && !T.burnt) + new T.floor_tile(T) + T.make_plating() + return !new_turf.intact + +/obj/item/mecha_parts/mecha_equipment/cable_layer/proc/layCable(var/turf/new_turf) + if(equip_ready || !istype(new_turf) || !dismantleFloor(new_turf)) + return reset() + var/fdirn = turn(chassis.dir,180) + for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already + if(LC.d1 == fdirn || LC.d2 == fdirn) + return reset() + if(!use_cable(1)) + return reset() + var/obj/structure/cable/NC = new(new_turf) + NC.cableColor("red") + NC.d1 = 0 + NC.d2 = fdirn + NC.updateicon() + + var/datum/powernet/PN + if(last_piece && last_piece.d2 != chassis.dir) + last_piece.d1 = min(last_piece.d2, chassis.dir) + last_piece.d2 = max(last_piece.d2, chassis.dir) + last_piece.updateicon() + PN = last_piece.powernet + + if(!PN) + PN = new() + powernets += PN + NC.powernet = PN + PN.cables += NC + NC.mergeConnectedNetworks(NC.d2) + + //NC.mergeConnectedNetworksOnTurf() + last_piece = NC + return 1 diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index e6cd8b6af73..337dd01132e 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -20,7 +20,6 @@ /obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target) if(!action_checks(target)) return 0 - set_ready_state(0) var/turf/curloc = get_turf(chassis) var/turf/targloc = get_turf(target) @@ -29,6 +28,10 @@ if (targloc == curloc) return 0 + set_ready_state(0) + chassis.can_move = 0 + spawn(shot_delay*projectiles_per_shot) + chassis.can_move = 1 for(var/i=1 to get_shot_amount()) var/obj/item/projectile/A = new projectile(curloc) A.firer = chassis.occupant @@ -49,9 +52,9 @@ sleep(shot_delay) chassis.log_message("Fired from [src.name], targeting [target].") - do_after_cooldown() return 1 + //Base energy weapon type /obj/item/mecha_parts/mecha_equipment/weapon/energy name = "general energy weapon" @@ -59,10 +62,11 @@ /obj/item/mecha_parts/mecha_equipment/weapon/energy/get_shot_amount() return min(round(chassis.cell.charge / energy_drain), projectiles_per_shot) -/obj/item/mecha_parts/mecha_equipment/weapon/energy/action(atom/target) - ..() - chassis.use_power(energy_drain * get_shot_amount()) - +/obj/item/mecha_parts/mecha_equipment/weapon/energy/start_cooldown() + set_ready_state(0) + chassis.use_power(energy_drain*get_shot_amount()) + sleep(equip_cooldown) + set_ready_state(1) /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser equip_cooldown = 8 @@ -112,10 +116,11 @@ projectile = /obj/item/projectile/plasma/adv/mech fire_sound = 'sound/weapons/Laser.ogg' -/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/M) - if(istype(M, /obj/mecha/working)) - if(M.equipment.len < M.max_equip) - return 1 +/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/working/M) + if(..()) //combat mech + return 1 + else if(M.equipment.len < M.max_equip && istype(M)) + return 1 return 0 /obj/item/projectile/beam/pulse/heavy @@ -158,8 +163,8 @@ return 0 /obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target) - if(!action_checks(target)) return 0 - set_ready_state(0) + if(!action_checks(target)) + return playsound(chassis, 'sound/items/AirHorn.ogg', 100, 1) chassis.occupant_message("HONK") for(var/mob/living/carbon/M in ohearers(6, chassis)) @@ -177,24 +182,12 @@ M.Paralyse(4) else M.Jitter(500) - /* //else the mousetraps are useless - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(isobj(H.shoes)) - var/thingy = H.shoes - H.unEquip(H.shoes) - walk_away(thingy,chassis,15,2) - spawn(20) - if(thingy) - walk(thingy,0) - */ - chassis.use_power(energy_drain) + log_message("Honked from [src.name]. HONK!") var/turf/T = get_turf(src) message_admins("[key_name_admin(chassis.occupant, chassis.occupant.client)](?) (FLW) used a Mecha Honker in ([T.x],[T.y],[T.z] - JMP)",0,1) log_game("[chassis.occupant.ckey]([chassis.occupant]) used a Mecha Honker in ([T.x],[T.y],[T.z])") - do_after_cooldown() - return + return 1 //Base ballistic weapon type @@ -212,8 +205,6 @@ return 0 if(projectiles <= 0) return 0 - if(!equip_ready) - return 0 return 1 /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info() @@ -238,8 +229,9 @@ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(atom/target) if(..()) - src.projectiles -= get_shot_amount() + projectiles -= get_shot_amount() send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) + return 1 /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine @@ -284,7 +276,27 @@ deviation = 0.3 shot_delay = 2 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher + var/missile_speed = 2 + var/missile_range = 30 + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/action(target) + if(!action_checks(target)) + return + var/obj/O = new projectile(chassis.loc) + playsound(chassis, fire_sound, 50, 1) + log_message("Launched a [O.name] from [name], targeting [target].") + projectiles-- + proj_init(O) + spawn(0) + O.throw_at(target, missile_range, missile_speed, spin = 0) + return 1 + +//used for projectile initilisation (priming flashbang) and additional logging +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/proc/proj_init(var/obj/O) + return + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack name = "\improper SRM-8 missile rack" desc = "A weapon for combat exosuits. Shoots light explosive missiles." icon_state = "mecha_missilerack" @@ -293,24 +305,12 @@ projectiles = 8 projectile_energy_cost = 1000 equip_cooldown = 60 - var/missile_speed = 2 - var/missile_range = 30 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/missile/M = new projectile(chassis.loc) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack/proj_init(var/obj/item/missile/M) M.primed = 1 - playsound(chassis, fire_sound, 50, 1) - M.throw_at(target, missile_range, missile_speed) - projectiles-- - log_message("Fired from [src.name], targeting [target].") var/turf/T = get_turf(src) message_admins("[key_name(chassis.occupant, chassis.occupant.client)](?) fired a [src] in ([T.x],[T.y],[T.z] - JMP)",0,1) log_game("[key_name(chassis.occupant)] fired a [src] ([T.x],[T.y],[T.z])") - do_after_cooldown() - return - /obj/item/missile icon = 'icons/obj/grenade.dmi' @@ -324,9 +324,8 @@ qdel(src) else ..() - return -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang name = "\improper SGL-6 grenade launcher" desc = "A weapon for combat exosuits. Launches primed flashbangs." icon_state = "mecha_grenadelnchr" @@ -338,24 +337,16 @@ equip_cooldown = 60 var/det_time = 20 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/weapon/grenade/flashbang/F = new projectile(chassis.loc) - playsound(chassis, fire_sound, 50, 1) - F.throw_at(target, missile_range, missile_speed) - projectiles-- - log_message("Fired from [src.name], targeting [target].") +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(var/obj/item/weapon/grenade/flashbang/F) var/turf/T = get_turf(src) - message_admins("[key_name(chassis.occupant, chassis.occupant.client)](?) (FLW) fired a [src] in ([T.x],[T.y],[T.z] - JMP)",0,1) + message_admins("[key_name(chassis.occupant, chassis.occupant.client)](?) fired a [src] in ([T.x],[T.y],[T.z] - JMP)",0,1) log_game("[key_name(chassis.occupant)] fired a [src] ([T.x],[T.y],[T.z])") spawn(det_time) if(F) F.prime() - do_after_cooldown() - return -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze + +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze name = "\improper SOB-3 grenade launcher" desc = "A weapon for combat exosuits. Launches primed clusterbangs. You monster." projectiles = 3 @@ -363,7 +354,7 @@ projectile_energy_cost = 1600 //getting off cheap seeing as this is 3 times the flashbangs held in the grenade launcher. equip_cooldown = 90 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar name = "banana mortar" desc = "Equipment for clown exosuits. Launches banana peels." icon_state = "mecha_bananamrtr" @@ -374,25 +365,13 @@ projectile_energy_cost = 100 equip_cooldown = 20 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/mecha/combat/honker/M) if(..()) if(istype(M)) return 1 return 0 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar/action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/weapon/grown/bananapeel/B = new projectile(chassis.loc,60) - playsound(chassis, fire_sound, 60, 1) - B.throw_at(target, missile_range, missile_speed) - projectiles-- - log_message("Bananed from [src.name], targeting [target]. HONK!") - do_after_cooldown() - return - - -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar name = "mousetrap mortar" desc = "Equipment for clown exosuits. Launches armed mousetraps." icon_state = "mecha_mousetrapmrtr" @@ -403,20 +382,12 @@ projectile_energy_cost = 100 equip_cooldown = 10 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M) if(..()) if(istype(M)) return 1 return 0 -/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar/action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/device/assembly/mousetrap/armed/M = new projectile(chassis.loc) +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/proj_init(var/obj/item/device/assembly/mousetrap/armed/M) M.secured = 1 - playsound(chassis, fire_sound, 60, 1) - M.throw_at(target, missile_range, missile_speed) - projectiles-- - log_message("Launched a mouse-trap from [src.name], targeting [target]. HONK!") - do_after_cooldown() - return + diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index fc630fe1bf6..6d9f0eef8b0 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -57,10 +57,6 @@ var/list/operation_req_access = list()//required access level for mecha operation var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment - var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature - var/datum/global_iterator/pr_give_air //moves air from tank to cabin - var/datum/global_iterator/pr_internal_damage //processes internal damage - var/wreckage var/list/equipment = new @@ -74,6 +70,12 @@ var/melee_cooldown = 10 var/melee_can_hit = 1 + var/datum/action/mecha/mech_eject/eject_action = new + var/datum/action/mecha/mech_toggle_internals/internals_action = new + var/datum/action/mecha/mech_cycle_equip/cycle_action = new + var/datum/action/mecha/mech_toggle_lights/lights_action = new + var/datum/action/mecha/mech_view_stats/stats_action = new + /obj/mecha/New() ..() @@ -81,14 +83,11 @@ icon_state += "-open" add_radio() add_cabin() - if(!add_airtank()) //we check this here in case mecha does not have an internal tank available by default - WIP - removeVerb(/obj/mecha/verb/connect_to_port) - removeVerb(/obj/mecha/verb/toggle_internal_tank) + add_airtank() spark_system.set_up(2, 0, src) spark_system.attach(src) add_cell() - add_iterators() - removeVerb(/obj/mecha/verb/disconnect_from_port) + SSobj.processing |= src log_message("[src.name] created.") mechas_list += src //global mech list return @@ -114,7 +113,7 @@ E.reliability = round(rand(E.reliability/3,E.reliability)) else E.detach(loc) - E.destroy() + qdel(E) if(cell) WR.crowbar_salvage += cell cell.forceMove(WR) @@ -125,22 +124,18 @@ else for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) E.detach(loc) - E.destroy() + qdel(E) if(cell) qdel(cell) if(internal_tank) qdel(internal_tank) + SSobj.processing.Remove(src) equipment.Cut() cell = null internal_tank = null - - qdel(pr_int_temp_processor) - qdel(pr_give_air) - qdel(pr_internal_damage) + qdel(cabin_air) + cabin_air = null qdel(spark_system) - pr_int_temp_processor = null - pr_give_air = null - pr_internal_damage = null spark_system = null mechas_list -= src //global mech list @@ -150,12 +145,6 @@ ////// Helpers ///////// //////////////////////// -/obj/mecha/proc/removeVerb(verb_path) - verbs -= verb_path - -/obj/mecha/proc/addVerb(verb_path) - verbs += verb_path - /obj/mecha/proc/add_airtank() internal_tank = new /obj/machinery/portable_atmospherics/canister/air(src) return internal_tank @@ -184,37 +173,16 @@ radio.icon_state = icon_state radio.subspace_transmission = 1 -/obj/mecha/proc/add_iterators() - pr_int_temp_processor = new /datum/global_iterator/mecha_preserve_temp(list(src)) - pr_give_air = new /datum/global_iterator/mecha_tank_give_air(list(src)) - pr_internal_damage = new /datum/global_iterator/mecha_internal_damage(list(src),0) - -/obj/mecha/proc/do_after(delay as num) - sleep(delay) - if(src) - return 1 - return 0 - -/obj/mecha/proc/enter_after(delay as num, mob/user, numticks = 5) - var/delayfraction = delay/numticks - - var/turf/T = user.loc - - for(var/i = 0, i internal_tank.maximum_pressure && !(internal_damage & MECHA_INT_TANK_BREACH)) + setInternalDamage(MECHA_INT_TANK_BREACH) + var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + if(int_tank_air && int_tank_air.return_volume()>0) //heat the air_contents + int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) + if(cabin_air && cabin_air.return_volume()>0) + cabin_air.temperature = min(6000+T0C, cabin_air.return_temperature()+rand(10,15)) + if(cabin_air.return_temperature() > max_temperature/2) + take_damage(4/round(max_temperature/cabin_air.return_temperature(),0.1),"fire") + + if(internal_damage & MECHA_INT_TEMP_CONTROL) + internal_temp_regulation = 0 + + if(internal_damage & MECHA_INT_TANK_BREACH) //remove some air from internal tank + if(internal_tank) + var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) + if(loc) + loc.assume_air(leaked_gas) + else + del(leaked_gas) + + if(internal_damage & MECHA_INT_SHORT_CIRCUIT) + if(get_charge()) + spark_system.start() + cell.charge -= min(20,cell.charge) + cell.maxcharge -= min(20,cell.maxcharge) + + if(internal_temp_regulation) + if(cabin_air && cabin_air.return_volume() > 0) + var/delta = cabin_air.temperature - T20C + cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) + + if(internal_tank) + var/datum/gas_mixture/tank_air = internal_tank.return_air() + + var/release_pressure = internal_tank_valve + var/cabin_pressure = cabin_air.return_pressure() + var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) + var/transfer_moles = 0 + if(pressure_delta > 0) //cabin pressure lower than release pressure + if(tank_air.return_temperature() > 0) + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) + cabin_air.merge(removed) + else if(pressure_delta < 0) //cabin pressure higher than release pressure + var/datum/gas_mixture/t_air = return_air() + pressure_delta = cabin_pressure - release_pressure + if(t_air) + pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(pressure_delta > 0) //if location pressure is lower than cabin pressure + transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) + if(t_air) + t_air.merge(removed) + else //just delete the cabin gas, we're in space or some shit + del(removed) + + if(occupant) + if(cell) + var/cellcharge = cell.charge/cell.maxcharge + switch(cellcharge) + if(0.75 to INFINITY) + occupant.clear_alert("charge") + if(0.5 to 0.75) + occupant.throw_alert("charge","lowcell",1) + if(0.25 to 0.5) + occupant.throw_alert("charge","lowcell",2) + if(0.01 to 0.25) + occupant.throw_alert("charge","lowcell",3) + else + occupant.throw_alert("charge","emptycell") + + var/integrity = health/initial(health)*100 + switch(integrity) + if(30 to 45) + occupant.throw_alert("mech damage", "low_mech_integrity", 1) + if(15 to 35) + occupant.throw_alert("mech damage", "low_mech_integrity", 2) + if(-INFINITY to 15) + occupant.throw_alert("mech damage", "low_mech_integrity", 3) + else + occupant.clear_alert("mech damage") + + if(occupant.loc != src) //something went wrong + occupant.clear_alert("charge") + occupant.clear_alert("mech damage") + RemoveActions(occupant, human_occupant=1) + occupant = null + + if(lights) + var/lights_energy_drain = 2 + use_power(lights_energy_drain) + + + + /obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. return @@ -247,32 +323,14 @@ //////////////////////////// ///// Action processing //// //////////////////////////// -/* -/atom/DblClick(object,location,control,params) - var/mob/M = src.mob - if(M && M.in_contents_of(/obj/mecha)) - if(mech_click == world.time) return - mech_click = world.time - - if(!istype(object, /atom)) return - if(istype(object, /obj/screen)) - var/obj/screen/using = object - if(using.screen_loc == ui_acti || using.screen_loc == ui_iarrowleft || using.screen_loc == ui_iarrowright)//ignore all HUD objects save 'intent' and its arrows - return ..() - else - return - var/obj/mecha/Mech = M.loc - spawn() //this helps prevent clickspam fest. - if (Mech) - Mech.click_action(object,M) -// else -// return ..() -*/ /obj/mecha/proc/click_action(atom/target,mob/user) - if(!src.occupant || src.occupant != user ) return - if(user.stat || !user.canmove) + if(!occupant || occupant != user ) + return + if(!locate(/turf) in list(target,target.loc)) // Prevents inventory from being drilled + return + if(user.incapacitated()) return if(state) occupant_message("Maintenance protocols in effect.") @@ -284,49 +342,28 @@ var/dir_to_target = get_dir(src,target) if(dir_to_target && !(dir_to_target & src.dir))//wrong direction return - if(hasInternalDamage(MECHA_INT_CONTROL_LOST)) + if(internal_damage & MECHA_INT_CONTROL_LOST) target = safepick(view(3,target)) if(!target) return if(!target.Adjacent(src)) if(selected && selected.is_ranged()) - selected.action(target) + if(selected.action(target)) + selected.start_cooldown() else if(selected && selected.is_melee()) - selected.action(target) + if(selected.action(target)) + selected.start_cooldown() else - if(internal_damage&MECHA_INT_CONTROL_LOST) + if(internal_damage & MECHA_INT_CONTROL_LOST) target = safepick(oview(1,src)) if(!melee_can_hit || !istype(target, /atom)) return target.mech_melee_attack(src) melee_can_hit = 0 - if(do_after(melee_cooldown)) + spawn(melee_cooldown) melee_can_hit = 1 return -/obj/mecha/proc/mech_toxin_damage(mob/living/target) - playsound(src, 'sound/effects/spray2.ogg', 50, 1) - if(target.reagents) - if(target.reagents.get_reagent_amount("cryptobiolin") + force < force*2) - target.reagents.add_reagent("cryptobiolin", force/2) - if(target.reagents.get_reagent_amount("toxin") + force < force*2) - target.reagents.add_reagent("toxin", force/2.5) - - -/atom/proc/mech_melee_attack(obj/mecha/M) - return - -/obj/mecha/mech_melee_attack(obj/mecha/M) - if(M.damtype =="brute") - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - else if(M.damtype == "fire") - playsound(src, 'sound/items/Welder.ogg', 50, 1) - else - return - visible_message("[M.name] has hit [src].") - take_damage(M.force, damtype) - add_logs(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") - return /obj/mecha/proc/range_action(atom/target) return @@ -364,9 +401,6 @@ return domove(direction) /obj/mecha/proc/domove(direction) - return call((proc_res["dyndomove"]||src), "dyndomove")(direction) - -/obj/mecha/proc/dyndomove(direction) if(!can_move) return 0 if(!Process_Spacemove(direction)) @@ -374,15 +408,16 @@ if(!has_charge(step_energy_drain)) return 0 var/move_result = 0 - if(hasInternalDamage(MECHA_INT_CONTROL_LOST)) + if(internal_damage & MECHA_INT_CONTROL_LOST) move_result = mechsteprand() else if(src.dir!=direction) move_result = mechturn(direction) else move_result = mechstep(direction) if(move_result) + use_power(step_energy_drain) can_move = 0 - if(do_after(step_in)) + spawn(step_in) can_move = 1 return 1 return 0 @@ -410,15 +445,15 @@ if(istype(obstacle, /obj)) var/obj/O = obstacle if(istype(O, /obj/effect/portal)) //derpfix - src.anchored = 0 + anchored = 0 O.Crossed(src) src.anchored = 1 else if(!O.anchored) - step(obstacle,src.dir) + step(obstacle, dir) else //I have no idea why I disabled this obstacle.Bumped(src) else if(istype(obstacle, /mob)) - step(obstacle,src.dir) + step(obstacle, dir) else obstacle.Bumped(src) return @@ -430,7 +465,7 @@ /obj/mecha/proc/check_for_internal_damage(list/possible_int_damage,ignore_threshold=null) if(!islist(possible_int_damage) || isemptylist(possible_int_damage)) return if(prob(20)) - if(ignore_threshold || src.health*100/initial(src.health)Life support system reactivated.") + if(MECHA_INT_FIRE) + occupant_message("Internal fire extinquished.") + if(MECHA_INT_TANK_BREACH) + occupant_message("Damaged internal tank has been sealed.") internal_damage &= ~int_dam_flag - switch(int_dam_flag) - if(MECHA_INT_TEMP_CONTROL) - if(pr_int_temp_processor) - occupant_message("Life support system reactivated.") - pr_int_temp_processor.start() - if(MECHA_INT_FIRE) - occupant_message("Internal fire extinquished.") - if(MECHA_INT_TANK_BREACH) - occupant_message("Damaged internal tank has been sealed.") - return -//////////////////////////////////////// -//////// Health related procs //////// -//////////////////////////////////////// - -/obj/mecha/proc/take_damage(amount, type="brute") - if(amount) - var/damage = absorbDamage(amount,type) - health -= damage - update_health() - occupant_message("Taking damage!") - log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1) - -/obj/mecha/proc/absorbDamage(damage,damage_type) - return call((proc_res["dynabsorbdamage"]||src), "dynabsorbdamage")(damage,damage_type) - -/obj/mecha/proc/dynabsorbdamage(damage,damage_type) - return damage*(listgetindex(damage_absorption,damage_type) || 1) - - -/obj/mecha/proc/update_health() - if(src.health > 0) - src.spark_system.start() - else - qdel(src) - -/obj/mecha/attack_hulk(mob/living/carbon/human/user) - if(!prob(src.deflect_chance)) - ..(user, 1) - take_damage(15) - check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - user.visible_message("[user] hits [src.name], doing some damage.", "You hit [src.name] with all your might. The metal creaks and bends.") - occupant_message("[user] hits [src.name], doing some damage.") - return 1 - return 0 - -/obj/mecha/attack_hand(mob/living/user) - user.changeNext_move(CLICK_CD_MELEE) // Ugh. Ideally we shouldn't be setting cooldowns outside of click code. - user.do_attack_animation(src) - src.log_message("Attack by hand/paw. Attacker - [user].",1) - user.visible_message("[user] hits [src.name]. Nothing happens","You hit [src.name] with no visible effect.") - src.log_append_to_last("Armor saved.") - return - -/obj/mecha/attack_paw(mob/user as mob) - return src.attack_hand(user) - - -/obj/mecha/attack_alien(mob/living/user) - src.log_message("Attack by alien. Attacker - [user].",1) - user.changeNext_move(CLICK_CD_MELEE) //Now stompy alien killer mechs are actually scary to aliens! - user.do_attack_animation(src) - if(!prob(src.deflect_chance)) - src.take_damage(15) - src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) - visible_message("The [user] slashes at [src.name]'s armor!") - else - src.log_append_to_last("Armor saved.") - playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) - user << "\green Your claws had no effect!" - visible_message("The [user] rebounds off [src.name]'s armor!") - return - - -/obj/mecha/attack_animal(mob/living/simple_animal/user) - src.log_message("Attack by simple animal. Attacker - [user].",1) - user.changeNext_move(CLICK_CD_MELEE) - if(user.melee_damage_upper == 0) - user.emote("[user.friendly] [src]") - else - user.do_attack_animation(src) - if(!prob(src.deflect_chance)) - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - src.take_damage(damage) - src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - visible_message("[user] [user.attacktext] [src]!") - add_logs(user, src, "attacked") - else - src.log_append_to_last("Armor saved.") - playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) - visible_message("The [user] rebounds off [src.name]'s armor!") - add_logs(user, src, "attacked") - return - -/obj/mecha/attack_tk() - return - -/obj/mecha/hitby(atom/movable/A as mob|obj) //wrapper - src.log_message("Hit by [A].",1) - call((proc_res["dynhitby"]||src), "dynhitby")(A) - return - -/obj/mecha/proc/dynhitby(atom/movable/A) - if(istype(A, /obj/item/mecha_parts/mecha_tracking)) - A.forceMove(src) - src.visible_message("The [A] fastens firmly to [src].") - return - if(prob(src.deflect_chance) || istype(A, /mob)) - src.visible_message("[A] bounces off the [src.name] armor") - src.log_append_to_last("Armor saved.") - if(istype(A, /mob/living)) - var/mob/living/M = A - M.take_organ_damage(10) - else if(istype(A, /obj)) - var/obj/O = A - if(O.throwforce) - src.visible_message("[src.name] is hit by [A].") - src.take_damage(O.throwforce) - src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - return - - -/obj/mecha/bullet_act(obj/item/projectile/Proj) //wrapper - src.log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).",1) - call((proc_res["dynbulletdamage"]||src), "dynbulletdamage")(Proj) //calls equipment - ..() - return - -/obj/mecha/proc/dynbulletdamage(obj/item/projectile/Proj) - if(prob(src.deflect_chance)) - src.visible_message("The [src.name] armor deflects the projectile") - src.log_append_to_last("Armor saved.") - return - var/ignore_threshold - if(Proj.flag == "taser") - use_power(200) - return - if(istype(Proj, /obj/item/projectile/beam/pulse)) - ignore_threshold = 1 - if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) - src.take_damage(Proj.damage,Proj.flag) - src.visible_message("[src.name] is hit by [Proj].") - src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),ignore_threshold) - Proj.on_hit(src) - return - -/obj/mecha/ex_act(severity, target) - src.log_message("Affected by explosion of severity: [severity].",1) - if(prob(src.deflect_chance)) - severity++ - src.log_append_to_last("Armor saved, changing severity to [severity].") - switch(severity) - if(1.0) - qdel(src) - if(2.0) - if (prob(30)) - qdel(src) - else - src.take_damage(initial(src.health)/2) - src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) - if(3.0) - if (prob(5)) - qdel(src) - else - src.take_damage(initial(src.health)/5) - src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) - return - -/obj/mecha/blob_act() - take_damage(30, "brute") - return - -/obj/mecha/emp_act(severity) - if(get_charge()) - use_power((cell.charge/2)/severity) - take_damage(50 / severity,"energy") - src.log_message("EMP detected",1) - check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) - return - -/obj/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(exposed_temperature>src.max_temperature) - src.log_message("Exposed to dangerous temperature.",1) - src.take_damage(5,"fire") - src.check_for_internal_damage(list(MECHA_INT_FIRE, MECHA_INT_TEMP_CONTROL)) - return - -/obj/mecha/proc/dynattackby(obj/item/weapon/W, mob/living/user) - user.changeNext_move(CLICK_CD_MELEE) // Ugh. Ideally we shouldn't be setting cooldowns outside of click code. - user.do_attack_animation(src) - src.log_message("Attacked by [W]. Attacker - [user]") - if(prob(src.deflect_chance)) - user << "The [W] bounces off [src.name] armor." - src.log_append_to_last("Armor saved.") - return 0 - else - user.visible_message("[user] hits [src] with [W].", "You hit [src] with [W].") - src.take_damage(W.force,W.damtype) - src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - return 1 - -////////////////////// -////// AttackBy ////// -////////////////////// - -/obj/mecha/attackby(obj/item/W, mob/user, params) - - if(istype(W, /obj/item/device/mmi)) - if(mmi_move_inside(W,user)) - user << "[src]-[W] interface initialized successfuly" - else - user << "[src]-[W] interface initialization failed." - return - - if(istype(W, /obj/item/mecha_parts/mecha_equipment)) - var/obj/item/mecha_parts/mecha_equipment/E = W - spawn() - if(E.can_attach(src)) - if(!user.drop_item()) - return - E.attach(src) - user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src].") - else - user << "You were unable to attach [W] to [src]!" - return - if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) - if(add_req_access || maint_access) - if(internals_access_allowed(user)) - var/obj/item/weapon/card/id/id_card - if(istype(W, /obj/item/weapon/card/id)) - id_card = W - else - var/obj/item/device/pda/pda = W - id_card = pda.id - output_maintenance_dialog(id_card, user) - return - else - user << "Invalid ID: Access denied." - else - user << "Maintenance protocols disabled by operator." - else if(istype(W, /obj/item/weapon/wrench)) - if(state==1) - state = 2 - user << "You undo the securing bolts." - else if(state==2) - state = 1 - user << "You tighten the securing bolts." - return - else if(istype(W, /obj/item/weapon/crowbar)) - if(state==2) - state = 3 - user << "You open the hatch to the power unit." - else if(state==3) - state=2 - user << "You close the hatch to the power unit." - return - else if(istype(W, /obj/item/stack/cable_coil)) - if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - var/obj/item/stack/cable_coil/CC = W - if(CC.use(2)) - clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) - user << "You replace the fused wires." - else - user << "You need two lengths of cable to fix this mech!" - return - else if(istype(W, /obj/item/weapon/screwdriver)) - if(hasInternalDamage(MECHA_INT_TEMP_CONTROL)) - clearInternalDamage(MECHA_INT_TEMP_CONTROL) - user << "You repair the damaged temperature controller." - else if(state==3 && src.cell) - src.cell.forceMove(src.loc) - src.cell = null - state = 4 - user << "You unscrew and pry out the powercell." - src.log_message("Powercell removed") - else if(state==4 && src.cell) - state=3 - user << "You screw the cell in place." - return - - else if(istype(W, /obj/item/weapon/stock_parts/cell)) - if(state==4) - if(!src.cell) - if(!user.drop_item()) - return - var/obj/item/weapon/stock_parts/cell/C = W - user << "You install the powercell." - C.forceMove(src) - C.use(C.charge * 0.8) - src.cell = C - src.log_message("Powercell installed") - else - user << "There's already a powercell installed." - return - - else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") - user.changeNext_move(CLICK_CD_MELEE) - var/obj/item/weapon/weldingtool/WT = W - if(src.healthYou repair the damaged gas tank." - else - user.visible_message("[user] repairs some damage to [src.name].") - src.health += min(10, initial(src.health)-src.health) - else - user << "The welder must be on for this task!" - return 1 - else - user << "The [src.name] is at full integrity!" - return 1 - - else if(istype(W, /obj/item/mecha_parts/mecha_tracking)) - if(!user.unEquip(W)) - user << "\the [W] is stuck to your hand, you cannot put it in \the [src]!" - return - W.forceMove(src) - user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src].") - return - - else if(!(W.flags&NOBLUDGEON)) - call((proc_res["dynattackby"]||src), "dynattackby")(W,user) - return - ///////////////////////////////////// //////////// AI piloting //////////// ///////////////////////////////////// @@ -861,7 +573,7 @@ occupant = AI icon_state = initial(icon_state) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - if(!hasInternalDamage()) + if(!internal_damage) occupant << sound('sound/mecha/nominal.ogg',volume=50) AI.cancel_camera() AI.controlled_mech = src @@ -871,7 +583,7 @@ AI << "[interaction == AI_MECH_HACK ? "Takeover of [name] complete! You are now permanently loaded onto the onboard computer. Do not attempt to leave the station sector!" \ : "You have been uploaded to a mech's onboard computer."]" AI << "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions." - + GrantActions(AI) ///////////////////////////////////// //////// Atmospheric stuff //////// @@ -930,103 +642,28 @@ /obj/mecha/portableConnectorReturnAir() return internal_tank.return_air() -///////////////////////// -//////// Verbs //////// -///////////////////////// - - -/obj/mecha/verb/connect_to_port() - set name = "Connect to port" - set category = "Exosuit Interface" - set src = usr.loc - set popup_menu = 0 - - if(!can_use(usr)) - return - - var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate(/obj/machinery/atmospherics/components/unary/portables_connector/) in loc - if(possible_port) - if(connect(possible_port)) - src.occupant_message("[name] connects to the port.") - src.verbs += /obj/mecha/verb/disconnect_from_port - src.verbs -= /obj/mecha/verb/connect_to_port - return - else - src.occupant_message("[name] failed to connect to the port.") - return - else - src.occupant_message("Nothing happens") - - -/obj/mecha/verb/disconnect_from_port() - set name = "Disconnect from port" - set category = "Exosuit Interface" - set src = usr.loc - set popup_menu = 0 - - if(!can_use(usr)) - return - - if(disconnect()) - src.occupant_message("[name] disconnects from the port.") - src.verbs -= /obj/mecha/verb/disconnect_from_port - src.verbs += /obj/mecha/verb/connect_to_port - else - src.occupant_message("[name] is not connected to the port at the moment.") - -/obj/mecha/verb/toggle_lights() - set name = "Toggle Lights" - set category = "Exosuit Interface" - set src = usr.loc - set popup_menu = 0 - - if(!can_use(usr)) - return - - lights = !lights - if(lights) AddLuminosity(lights_power) - else AddLuminosity(-lights_power) - src.occupant_message("Toggled lights [lights?"on":"off"].") - log_message("Toggled lights [lights?"on":"off"].") - return - - -/obj/mecha/verb/toggle_internal_tank() - set name = "Toggle internal airtank usage." - set category = "Exosuit Interface" - set src = usr.loc - set popup_menu = 0 - - if(!can_use(usr)) - return - - use_internal_tank = !use_internal_tank - src.occupant_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].") - src.log_message("Now taking air from [use_internal_tank?"internal airtank":"environment"].") - return - /obj/mecha/MouseDrop_T(mob/M, mob/user) if (!user.canUseTopic(src) || (user != M)) return if(!ishuman(user)) // no silicons or drones in mechas. return - src.log_message("[user] tries to move in.") - if (src.occupant) - usr << "The [src.name] is already occupied!" - src.log_append_to_last("Permission denied.") + log_message("[user] tries to move in.") + if (occupant) + usr << "The [name] is already occupied!" + log_append_to_last("Permission denied.") return var/passed - if(src.dna) + if(dna) if(check_dna_integrity(user)) var/mob/living/carbon/C = user if(C.dna.unique_enzymes==src.dna) passed = 1 - else if(src.operation_allowed(user)) + else if(operation_allowed(user)) passed = 1 if(!passed) user << "Access denied." - src.log_append_to_last("Permission denied.") + log_append_to_last("Permission denied.") return for(var/mob/living/simple_animal/slime/S in range(1,user)) if(S.Victim == user) @@ -1035,13 +672,13 @@ visible_message("[user] starts to climb into [src.name].") - if(enter_after(40,user)) - if(src.health <= 0) + if(do_after(user, 40, target = src)) + if(health <= 0) user << "You cannot get in the [src.name], it has been destroyed!" - else if(!src.occupant) - moved_inside(user) - else if(src.occupant!=user) + else if(occupant) user << "[src.occupant] was faster! Try better next time, loser." + else + moved_inside(user) else user << "You stop entering the exosuit!" return @@ -1049,25 +686,18 @@ /obj/mecha/proc/moved_inside(mob/living/carbon/human/H) if(H && H.client && H in range(1)) H.reset_view(src) - /* - H.client.perspective = EYE_PERSPECTIVE - H.client.eye = src - */ H.stop_pulling() H.forceMove(src) - if(H.hud_used) - last_user_hud = H.hud_used.hud_shown - H.hud_used.show_hud(HUD_STYLE_REDUCED) - - src.occupant = H - src.add_fingerprint(H) - src.forceMove(src.loc) - src.log_append_to_last("[H] moved in as pilot.") - src.icon_state = initial(icon_state) + occupant = H + add_fingerprint(H) + GrantActions(H, human_occupant=1) + forceMove(loc) + log_append_to_last("[H] moved in as pilot.") + icon_state = initial(icon_state) dir = dir_in playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - if(!hasInternalDamage()) - src.occupant << sound('sound/mecha/nominal.ogg',volume=50) + if(!internal_damage) + occupant << sound('sound/mecha/nominal.ogg',volume=50) return 1 else return 0 @@ -1085,12 +715,10 @@ else if(dna && dna!=mmi_as_oc.brainmob.dna.unique_enzymes) user << "Stop it!" return 0 - //Added a message here since people assume their first click failed or something./N -// user << "Installing MMI, please stand by." visible_message("[user] starts to insert an MMI into [src.name].") - if(enter_after(40,user)) + if(do_after(user, 40, target = src)) if(!occupant) return mmi_moved_inside(mmi_as_oc,user) else @@ -1112,122 +740,66 @@ return var/mob/brainmob = mmi_as_oc.brainmob brainmob.reset_view(src) - /* - brainmob.client.eye = src - brainmob.client.perspective = EYE_PERSPECTIVE - */ occupant = brainmob brainmob.loc = src //should allow relaymove brainmob.canmove = 1 mmi_as_oc.loc = src mmi_as_oc.mecha = src - src.verbs -= /obj/mecha/verb/eject - src.icon_state = initial(icon_state) + icon_state = initial(icon_state) dir = dir_in - src.log_message("[mmi_as_oc] moved in as pilot.") - if(!hasInternalDamage()) - src.occupant << sound('sound/mecha/nominal.ogg',volume=50) + log_message("[mmi_as_oc] moved in as pilot.") + if(!internal_damage) + occupant << sound('sound/mecha/nominal.ogg',volume=50) + GrantActions(brainmob) return 1 else return 0 -/obj/mecha/verb/view_stats() - set name = "View Stats" - set category = "Exosuit Interface" - set src = usr.loc - set popup_menu = 0 - - if(!can_use(usr)) - return - //pr_update_stats.start() - src.occupant << browse(src.get_stats_html(), "window=exosuit") - return - -/* -/obj/mecha/verb/force_eject() - set category = "Object" - set name = "Force Eject" - set src in view(5) - src.go_out() - return -*/ - -/obj/mecha/verb/eject() - set name = "Eject" - set category = "Exosuit Interface" - set src = usr.loc - set popup_menu = 0 - - if(!can_use(usr)) - return - - src.go_out() - add_fingerprint(usr) - return - /obj/mecha/container_resist() go_out() -/obj/mecha/proc/go_out(forced) - if(!src.occupant) return +/obj/mecha/Exited(atom/movable/M, atom/newloc) + if(occupant && occupant == M) // The occupant exited the mech without calling go_out() + go_out(1, newloc) + +/obj/mecha/proc/go_out(var/forced, var/atom/newloc = loc) + if(!occupant) + return var/atom/movable/mob_container + occupant.clear_alert("charge") + occupant.clear_alert("mech damage") if(ishuman(occupant)) - mob_container = src.occupant - if(occupant.hud_used && last_user_hud) - occupant.hud_used.show_hud(HUD_STYLE_STANDARD) + mob_container = occupant + RemoveActions(occupant, human_occupant=1) else if(istype(occupant, /mob/living/carbon/brain)) var/mob/living/carbon/brain/brain = occupant + RemoveActions(brain) mob_container = brain.container else if(isAI(occupant) && forced) //This should only happen if there are multiple AIs in a round, and at least one is Malf. + RemoveActions(occupant) occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced. occupant = null return else return - if(mob_container.forceMove(src.loc))//ejecting mob container - /* - if(ishuman(occupant) && (return_pressure() > HAZARD_HIGH_PRESSURE)) - use_internal_tank = 0 - var/datum/gas_mixture/environment = get_turf_air() - if(environment) - var/env_pressure = environment.return_pressure() - var/pressure_delta = (cabin.return_pressure() - env_pressure) - //Can not have a pressure delta that would cause environment pressure > tank pressure - - var/transfer_moles = 0 - if(pressure_delta > 0) - transfer_moles = pressure_delta*environment.volume/(cabin.return_temperature() * R_IDEAL_GAS_EQUATION) - - //Actually transfer the gas - var/datum/gas_mixture/removed = cabin.air_contents.remove(transfer_moles) - loc.assume_air(removed) - - occupant.SetStunned(5) - occupant.SetWeakened(5) - occupant << "You were blown out of the mech!" - */ - src.log_message("[mob_container] moved out.") - occupant.reset_view() - /* - if(src.occupant.client) - src.occupant.client.eye = src.occupant.client.mob - src.occupant.client.perspective = MOB_PERSPECTIVE - */ - src.occupant << browse(null, "window=exosuit") + var/mob/living/L = occupant + occupant = null //we need it null when forceMove calls Exited(). + if(mob_container.forceMove(newloc))//ejecting mob container + log_message("[mob_container] moved out.") + L.reset_view() + L << browse(null, "window=exosuit") if(istype(mob_container, /obj/item/device/mmi)) var/obj/item/device/mmi/mmi = mob_container if(mmi.brainmob) - occupant.loc = mmi + L.loc = mmi mmi.mecha = null mmi.update_icon() - src.occupant.canmove = 0 - src.verbs += /obj/mecha/verb/eject - src.occupant = null - src.icon_state = initial(icon_state)+"-open" - src.dir = dir_in + L.canmove = 0 + icon_state = initial(icon_state)+"-open" + dir = dir_in return ///////////////////////// @@ -1245,211 +817,6 @@ return allowed(M) -//////////////////////////////////// -///// Rendering stats window /////// -//////////////////////////////////// - -/obj/mecha/proc/get_stats_html() - var/output = {" - [src.name] data - - - - -
- [src.get_stats_part()] -
-
- [src.get_equipment_list()] -
-
-
- [src.get_commands()] -
- - - "} - return output - - -/obj/mecha/proc/report_internal_damage() - var/output = null - var/list/dam_reports = list( - "[MECHA_INT_FIRE]" = "INTERNAL FIRE", - "[MECHA_INT_TEMP_CONTROL]" = "LIFE SUPPORT SYSTEM MALFUNCTION", - "[MECHA_INT_TANK_BREACH]" = "GAS TANK BREACH", - "[MECHA_INT_CONTROL_LOST]" = "COORDINATION SYSTEM CALIBRATION FAILURE - Recalibrate", - "[MECHA_INT_SHORT_CIRCUIT]" = "SHORT CIRCUIT" - ) - for(var/tflag in dam_reports) - var/intdamflag = text2num(tflag) - if(hasInternalDamage(intdamflag)) - output += dam_reports[tflag] - output += "
" - if(return_pressure() > WARNING_HIGH_PRESSURE) - output += "DANGEROUSLY HIGH CABIN PRESSURE
" - return output - - -/obj/mecha/proc/get_stats_part() - var/integrity = health/initial(health)*100 - var/cell_charge = get_charge() - var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None" - var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown" - var/cabin_pressure = round(return_pressure(),0.01) - var/output = {"[report_internal_damage()] - [integrity<30?"DAMAGE LEVEL CRITICAL
":null] - Integrity: [integrity]%
- Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
- Air source: [use_internal_tank?"Internal Airtank":"Environment"]
- Airtank pressure: [tank_pressure]kPa
- Airtank temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
- Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
- Lights: [lights?"on":"off"]
- [src.dna?"DNA-locked:
[src.dna] \[Reset\]
":null] - "} - return output - -/obj/mecha/proc/get_commands() - var/output = {"
-
Electronics
- -
-
-
Airtank
- -
- -
[get_equipment_menu()]
-
- [(/obj/mecha/verb/eject in src.verbs)?"Eject
":null] - "} - return output - -/obj/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu - var/output - if(equipment.len) - output += {"
-
Equipment
-
" - return output - -/obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html - if(!equipment.len) - return - var/output = "Equipment:
" - for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) - output += "
[MT.get_equip_info()]
" - output += "
" - return output - - -/obj/mecha/proc/get_log_html() - var/output = "[src.name] Log" - for(var/list/entry in log) - output += {"
[entry["time"]] [time2text(entry["date"],"MMM DD")] [entry["year"]]
-
[entry["message"]]
- "} - output += "" - return output - - -/obj/mecha/proc/output_access_dialog(obj/item/weapon/card/id/id_card, mob/user) - if(!id_card || !user) return - var/output = {" - - - -

Following keycodes are present in this system:

"} - for(var/a in operation_req_access) - output += "[get_access_desc(a)] - Delete
" - output += "

Following keycodes were detected on portable device:

" - for(var/a in id_card.access) - if(a in operation_req_access) continue - var/a_name = get_access_desc(a) - if(!a_name) continue //there's some strange access without a name - output += "[a_name] - Add
" - output += "
Finish (Warning! The ID upload panel will be locked. It can be unlocked only through Exosuit Interface.)" - output += "" - user << browse(output, "window=exosuit_add_access") - onclose(user, "exosuit_add_access") - return - -/obj/mecha/proc/output_maintenance_dialog(obj/item/weapon/card/id/id_card,mob/user) - if(!id_card || !user) return - var/output = {" - - - - - [add_req_access?"Edit operation keycodes":null] - [maint_access?"Initiate maintenance protocol":null] - [(state>0) ?"Set Cabin Air Pressure":null] - - "} - user << browse(output, "window=exosuit_maint_console") - onclose(user, "exosuit_maint_console") - return - //////////////////////////////// /////// Messages and Log /////// @@ -1474,172 +841,6 @@ var/year = time2text(world.realtime,"YYYY") var/year_integer = text2num(year) // = 2013??? -///////////////// -///// Topic ///// -///////////////// - -/obj/mecha/Topic(href, href_list) - ..() - if(href_list["update_content"]) - if(usr != src.occupant) return - send_byjax(src.occupant,"exosuit.browser","content",src.get_stats_part()) - return - if(href_list["close"]) - return - if(usr.stat > 0) - return - var/datum/topic_input/filter = new /datum/topic_input(href,href_list) - if(href_list["select_equip"]) - if(usr != src.occupant) return - var/obj/item/mecha_parts/mecha_equipment/equip = filter.getObj("select_equip") - if(equip) - src.selected = equip - src.occupant_message("You switch to [equip]") - src.visible_message("[src] raises [equip]") - send_byjax(src.occupant,"exosuit.browser","eq_list",src.get_equipment_list()) - return - if(href_list["eject"]) - if(usr != src.occupant) return - src.eject() - return - if(href_list["toggle_lights"]) - if(usr != src.occupant) return - src.toggle_lights() - return - if(href_list["toggle_airtank"]) - if(usr != src.occupant) return - src.toggle_internal_tank() - return - if(href_list["rmictoggle"]) - if(usr != src.occupant) return - radio.broadcasting = !radio.broadcasting - send_byjax(src.occupant,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged")) - return - if(href_list["rspktoggle"]) - if(usr != src.occupant) return - radio.listening = !radio.listening - send_byjax(src.occupant,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged")) - return - if(href_list["rfreq"]) - if(usr != src.occupant) return - var/new_frequency = (radio.frequency + filter.getNum("rfreq")) - if (!radio.freerange || (radio.frequency < 1200 || radio.frequency > 1600)) - new_frequency = sanitize_frequency(new_frequency) - radio.set_frequency(new_frequency) - send_byjax(src.occupant,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]") - return - if(href_list["port_disconnect"]) - if(usr != src.occupant) return - src.disconnect_from_port() - return - if (href_list["port_connect"]) - if(usr != src.occupant) return - src.connect_to_port() - return - if (href_list["view_log"]) - if(usr != src.occupant) return - src.occupant << browse(src.get_log_html(), "window=exosuit_log") - onclose(occupant, "exosuit_log") - return - if (href_list["change_name"]) - if(usr != src.occupant) return - var/newname = stripped_input(occupant,"Choose new exosuit name","Rename exosuit","", MAX_NAME_LEN) - if(newname && trim(newname)) - name = newname - else - alert(occupant, "nope.avi") - return - if (href_list["toggle_id_upload"]) - if(usr != src.occupant) return - add_req_access = !add_req_access - send_byjax(src.occupant,"exosuit.browser","t_id_upload","[add_req_access?"L":"Unl"]ock ID upload panel") - return - if(href_list["toggle_maint_access"]) - if(usr != src.occupant) return - if(state) - occupant_message("Maintenance protocols in effect") - return - maint_access = !maint_access - send_byjax(src.occupant,"exosuit.browser","t_maint_access","[maint_access?"Forbid":"Permit"] maintenance protocols") - return - if(href_list["req_access"] && add_req_access) - if(!in_range(src, usr)) return - output_access_dialog(filter.getObj("id_card"),filter.getMob("user")) - return - if(href_list["maint_access"] && maint_access) - if(!in_range(src, usr)) return - var/mob/user = filter.getMob("user") - if(user) - if(state==0) - state = 1 - user << "The securing bolts are now exposed." - else if(state==1) - state = 0 - user << "The securing bolts are now hidden." - output_maintenance_dialog(filter.getObj("id_card"),user) - return - if(href_list["set_internal_tank_valve"] && state >=1) - if(!in_range(src, usr)) return - var/mob/user = filter.getMob("user") - if(user) - var/new_pressure = input(user,"Input new output pressure","Pressure setting",internal_tank_valve) as num - if(new_pressure) - internal_tank_valve = new_pressure - user << "The internal pressure valve has been set to [internal_tank_valve]kPa." - if(href_list["add_req_access"] && add_req_access && filter.getObj("id_card")) - if(!in_range(src, usr)) return - operation_req_access += filter.getNum("add_req_access") - output_access_dialog(filter.getObj("id_card"),filter.getMob("user")) - return - if(href_list["del_req_access"] && add_req_access && filter.getObj("id_card")) - if(!in_range(src, usr)) return - operation_req_access -= filter.getNum("del_req_access") - output_access_dialog(filter.getObj("id_card"),filter.getMob("user")) - return - if(href_list["finish_req_access"]) - if(!in_range(src, usr)) return - add_req_access = 0 - var/mob/user = filter.getMob("user") - user << browse(null,"window=exosuit_add_access") - return - if(href_list["dna_lock"]) - if(usr != src.occupant) - return - if(src.occupant && !iscarbon(src.occupant)) - src.occupant << " You do not have any DNA!" - return - src.dna = src.occupant.dna.unique_enzymes - src.occupant_message("You feel a prick as the needle takes your DNA sample.") - return - if(href_list["reset_dna"]) - if(usr != src.occupant) return - src.dna = null - if(href_list["repair_int_control_lost"]) - if(usr != src.occupant) return - src.occupant_message("Recalibrating coordination system...") - src.log_message("Recalibration of coordination system started.") - var/T = src.loc - if(do_after(100)) - if(T == src.loc) - src.clearInternalDamage(MECHA_INT_CONTROL_LOST) - src.occupant_message("Recalibration successful.") - src.log_message("Recalibration of coordination system finished with 0 errors.") - else - src.occupant_message("Recalibration failed!") - src.log_message("Recalibration of coordination system failed with 1 error.",1) - - //debug - /* - if(href_list["debug"]) - if(href_list["set_i_dam"]) - setInternalDamage(filter.getNum("set_i_dam")) - if(href_list["clear_i_dam"]) - clearInternalDamage(filter.getNum("clear_i_dam")) - return - */ - - return - /////////////////////// ///// Power stuff ///// /////////////////////// @@ -1648,16 +849,14 @@ var/year_integer = text2num(year) // = 2013??? return (get_charge()>=amount) /obj/mecha/proc/get_charge() - return call((proc_res["dyngetcharge"]||src), "dyngetcharge")() - -/obj/mecha/proc/dyngetcharge()//returns null if no powercell, else returns cell.charge - if(!src.cell) return - return max(0, src.cell.charge) + for(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/R in equipment) + var/relay_charge = R.get_charge() + if(relay_charge) + return relay_charge + if(cell) + return max(0, cell.charge) /obj/mecha/proc/use_power(amount) - return call((proc_res["dynusepower"]||src), "dynusepower")(amount) - -/obj/mecha/proc/dynusepower(amount) if(get_charge()) cell.use(amount) return 1 @@ -1673,123 +872,121 @@ var/year_integer = text2num(year) // = 2013??? return 0 -////////////////////////////////////////// -//////// Mecha global iterators //////// -////////////////////////////////////////// +//////////////////////////////////////// Action Buttons /////////////////////////////////////////////// + +/obj/mecha/proc/GrantActions(var/mob/living/user, var/human_occupant = 0) + if(human_occupant) + eject_action.chassis = src + eject_action.Grant(user) + + internals_action.chassis = src + internals_action.Grant(user) + + cycle_action.chassis = src + cycle_action.Grant(user) + + lights_action.chassis = src + lights_action.Grant(user) + + stats_action.chassis = src + stats_action.Grant(user) -/datum/global_iterator/mecha_preserve_temp //normalizing cabin air temperature to 20 degrees celsium - delay = 20 +/obj/mecha/proc/RemoveActions(var/mob/living/user, var/human_occupant = 0) + if(human_occupant) + eject_action.Remove(user) + internals_action.Remove(user) + cycle_action.Remove(user) + lights_action.Remove(user) + stats_action.Remove(user) - process(var/obj/mecha/mecha) - if(mecha.cabin_air && mecha.cabin_air.return_volume() > 0) - var/delta = mecha.cabin_air.temperature - T20C - mecha.cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) + +/datum/action/mecha + check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUNNED | AB_CHECK_ALIVE + action_type = AB_INNATE + var/obj/mecha/chassis + + +/datum/action/mecha/mech_eject + name = "Eject From Mech" + button_icon_state = "mech_eject" + +/datum/action/mecha/mech_eject/Activate() + if(!owner || !iscarbon(owner)) return - -/datum/global_iterator/mecha_tank_give_air - delay = 15 - - process(var/obj/mecha/mecha) - if(mecha.internal_tank) - var/datum/gas_mixture/tank_air = mecha.internal_tank.return_air() - var/datum/gas_mixture/cabin_air = mecha.cabin_air - - var/release_pressure = mecha.internal_tank_valve - var/cabin_pressure = cabin_air.return_pressure() - var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) - var/transfer_moles = 0 - if(pressure_delta > 0) //cabin pressure lower than release pressure - if(tank_air.return_temperature() > 0) - transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) - var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) - cabin_air.merge(removed) - else if(pressure_delta < 0) //cabin pressure higher than release pressure - var/datum/gas_mixture/t_air = mecha.return_air() - pressure_delta = cabin_pressure - release_pressure - if(t_air) - pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) - if(pressure_delta > 0) //if location pressure is lower than cabin pressure - transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) - var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) - if(t_air) - t_air.merge(removed) - else //just delete the cabin gas, we're in space or some shit - del(removed) - else - return stop() + if(!chassis || chassis.occupant != owner) return + chassis.go_out() -/datum/global_iterator/mecha_internal_damage // processing internal damage +/datum/action/mecha/mech_toggle_internals + name = "Toggle Internal Airtank Usage" + button_icon_state = "mech_toggle_internals" - process(var/obj/mecha/mecha) - if(!mecha.hasInternalDamage()) - return stop() - if(mecha.hasInternalDamage(MECHA_INT_FIRE)) - if(!mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL) && prob(5)) - mecha.clearInternalDamage(MECHA_INT_FIRE) - if(mecha.internal_tank) - if(mecha.internal_tank.return_pressure()>mecha.internal_tank.maximum_pressure && !(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH))) - mecha.setInternalDamage(MECHA_INT_TANK_BREACH) - var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() - if(int_tank_air && int_tank_air.return_volume()>0) //heat the air_contents - int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) - if(mecha.cabin_air && mecha.cabin_air.return_volume()>0) - mecha.cabin_air.temperature = min(6000+T0C, mecha.cabin_air.return_temperature()+rand(10,15)) - if(mecha.cabin_air.return_temperature()>mecha.max_temperature/2) - mecha.take_damage(4/round(mecha.max_temperature/mecha.cabin_air.return_temperature(),0.1),"fire") - if(mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL)) //stop the mecha_preserve_temp loop datum - mecha.pr_int_temp_processor.stop() - if(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH)) //remove some air from internal tank - if(mecha.internal_tank) - var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() - var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) - if(mecha.loc && hascall(mecha.loc,"assume_air")) - mecha.loc.assume_air(leaked_gas) - else - del(leaked_gas) - if(mecha.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - if(mecha.get_charge()) - mecha.spark_system.start() - mecha.cell.charge -= min(20,mecha.cell.charge) - mecha.cell.maxcharge -= min(20,mecha.cell.maxcharge) +/datum/action/mecha/mech_toggle_internals/Activate() + if(!owner || !chassis || chassis.occupant != owner) return + chassis.use_internal_tank = !chassis.use_internal_tank + if(chassis.use_internal_tank) + button_icon_state = "mech_toggle_internals_on" + else + button_icon_state = "mech_toggle_internals" + chassis.occupant_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].") + chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].") -///////////// +/datum/action/mecha/mech_cycle_equip + name = "Cycle Equipment" + button_icon_state = "mech_cycle_equip" -//debug -/* -/obj/mecha/verb/test_int_damage() - set name = "Test internal damage" - set category = "Exosuit Interface" - set src in view(0) - if(!occupant) return - if(usr!=occupant) +/datum/action/mecha/mech_cycle_equip/Activate() + if(!owner || !chassis || chassis.occupant != owner) return - var/output = {" - - - -

Set:

- MECHA_INT_FIRE
- MECHA_INT_TEMP_CONTROL
- MECHA_INT_SHORT_CIRCUIT
- MECHA_INT_TANK_BREACH
- MECHA_INT_CONTROL_LOST
-
-

Clear:

- MECHA_INT_FIRE
- MECHA_INT_TEMP_CONTROL
- MECHA_INT_SHORT_CIRCUIT
- MECHA_INT_TANK_BREACH
- MECHA_INT_CONTROL_LOST
- - "} + if(chassis.equipment.len == 0) + chassis.occupant_message("No equipment available.") + return + if(!chassis.selected) + chassis.selected = chassis.equipment[1] + chassis.occupant_message("You select [chassis.selected]") + send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) + return + var/number = 0 + for(var/A in chassis.equipment) + number++ + if(A == chassis.selected) + if(chassis.equipment.len == number) + chassis.selected = null + chassis.occupant_message("You switch to no equipment") + else + chassis.selected = chassis.equipment[number+1] + chassis.occupant_message("You switch to [chassis.selected]") + send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) + return - occupant << browse(output, "window=ex_debug") - //src.health = initial(src.health)/2.2 - //src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - return -*/ + +/datum/action/mecha/mech_toggle_lights + name = "Toggle Lights" + button_icon_state = "mech_toggle_lights" + +/datum/action/mecha/mech_toggle_lights/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + chassis.lights = !chassis.lights + if(chassis.lights) + chassis.AddLuminosity(chassis.lights_power) + button_icon_state = "mech_toggle_lights_on" + else + chassis.AddLuminosity(-chassis.lights_power) + button_icon_state = "mech_toggle_lights" + chassis.occupant_message("Toggled lights [chassis.lights?"on":"off"].") + chassis.log_message("Toggled lights [chassis.lights?"on":"off"].") + + +/datum/action/mecha/mech_view_stats + name = "View Stats" + button_icon_state = "mech_view_stats" + +/datum/action/mecha/mech_view_stats/Activate() + if(!owner || !chassis || chassis.occupant != owner) + return + chassis.occupant << browse(chassis.get_stats_html(), "window=exosuit") diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm new file mode 100644 index 00000000000..e6d498dd0f4 --- /dev/null +++ b/code/game/mecha/mecha_defense.dm @@ -0,0 +1,345 @@ + +/obj/mecha/proc/take_damage(amount, type="brute") + if(amount) + var/damage = absorbDamage(amount,type) + health -= damage + update_health() + occupant_message("Taking damage!") + log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1) + +/obj/mecha/proc/absorbDamage(damage,damage_type) + var/coeff = 1 + if(damage_absorption[damage_type]) + coeff = damage_absorption[damage_type] + return damage*coeff + + +/obj/mecha/proc/update_health() + if(src.health > 0) + src.spark_system.start() + else + qdel(src) + +/obj/mecha/attack_hulk(mob/living/carbon/human/user) + if(!prob(src.deflect_chance)) + ..(user, 1) + take_damage(15) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + user.visible_message("[user] hits [src.name], doing some damage.", "You hit [src.name] with all your might. The metal creaks and bends.") + occupant_message("[user] hits [src.name], doing some damage.") + return 1 + return 0 + +/obj/mecha/attack_hand(mob/living/user as mob) + user.changeNext_move(CLICK_CD_MELEE) // Ugh. Ideally we shouldn't be setting cooldowns outside of click code. + user.do_attack_animation(src) + src.log_message("Attack by hand/paw. Attacker - [user].",1) + user.visible_message("[user] hits [src.name]. Nothing happens","You hit [src.name] with no visible effect.") + src.log_append_to_last("Armor saved.") + return + +/obj/mecha/attack_paw(mob/user as mob) + return src.attack_hand(user) + + +/obj/mecha/attack_alien(mob/living/user as mob) + src.log_message("Attack by alien. Attacker - [user].",1) + user.changeNext_move(CLICK_CD_MELEE) //Now stompy alien killer mechs are actually scary to aliens! + user.do_attack_animation(src) + if(!prob(src.deflect_chance)) + take_damage(15) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + visible_message("The [user] slashes at [src.name]'s armor!") + else + src.log_append_to_last("Armor saved.") + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + user << "\green Your claws had no effect!" + visible_message("The [user] rebounds off [src.name]'s armor!") + return + + +/obj/mecha/attack_animal(mob/living/simple_animal/user as mob) + src.log_message("Attack by simple animal. Attacker - [user].",1) + user.changeNext_move(CLICK_CD_MELEE) + if(user.melee_damage_upper == 0) + user.emote("[user.friendly] [src]") + else + user.do_attack_animation(src) + if(!prob(src.deflect_chance)) + var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) + take_damage(damage) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + visible_message("[user] [user.attacktext] [src]!") + add_logs(user, src, "attacked", admin=0) + else + src.log_append_to_last("Armor saved.") + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + visible_message("The [user] rebounds off [src.name]'s armor!") + add_logs(user, src, "attacked", admin=0) + return + +/obj/mecha/attack_tk() + return + +/obj/mecha/hitby(atom/movable/A as mob|obj) //wrapper + log_message("Hit by [A].",1) + var/deflection = deflect_chance + var/dam_coeff = 1 + var/counter_tracking = 0 + for(var/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/B in equipment) + if(B.projectile_react()) + deflection *= B.deflect_coeff + dam_coeff *= B.damage_coeff + counter_tracking = 1 + break + if(istype(A, /obj/item/mecha_parts/mecha_tracking)) + if(!counter_tracking) + A.forceMove(src) + visible_message("The [A] fastens firmly to [src].") + return + else + deflection = 100 //will bounce off + if(prob(deflection) || istype(A, /mob)) + visible_message("[A] bounces off the [src.name] armor") + log_append_to_last("Armor saved.") + if(istype(A, /mob/living)) + var/mob/living/M = A + M.take_organ_damage(10) + else if(istype(A, /obj)) + var/obj/O = A + if(O.throwforce) + visible_message("[src.name] is hit by [A].") + take_damage(O.throwforce*dam_coeff) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + return + + +/obj/mecha/bullet_act(var/obj/item/projectile/Proj) //wrapper + log_message("Hit by projectile. Type: [Proj.name]([Proj.flag]).",1) + var/deflection = deflect_chance + var/dam_coeff = 1 + for(var/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster/B in equipment) + if(B.projectile_react()) + deflection *= B.deflect_coeff + dam_coeff *= B.damage_coeff + break + if(prob(deflection)) + visible_message("The [src.name] armor deflects the projectile") + log_append_to_last("Armor saved.") + return + var/ignore_threshold + if(Proj.flag == "taser") + use_power(200) + return + if(istype(Proj, /obj/item/projectile/beam/pulse)) + ignore_threshold = 1 + if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) + take_damage(Proj.damage*dam_coeff,Proj.flag) + visible_message("[src.name] is hit by [Proj].") + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),ignore_threshold) + Proj.on_hit(src) + +/obj/mecha/ex_act(severity, target) + src.log_message("Affected by explosion of severity: [severity].",1) + if(prob(src.deflect_chance)) + severity++ + log_append_to_last("Armor saved, changing severity to [severity].") + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if (prob(30)) + qdel(src) + else + take_damage(initial(src.health)/2) + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) + if(3.0) + if (prob(5)) + qdel(src) + else + take_damage(initial(src.health)/5) + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) + return + +/obj/mecha/blob_act() + take_damage(30, "brute") + return + +/obj/mecha/emp_act(severity) + if(get_charge()) + use_power((cell.charge/2)/severity) + take_damage(50 / severity,"energy") + src.log_message("EMP detected",1) + check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_CONTROL_LOST,MECHA_INT_SHORT_CIRCUIT),1) + return + +/obj/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature>src.max_temperature) + log_message("Exposed to dangerous temperature.",1) + take_damage(5,"fire") + check_for_internal_damage(list(MECHA_INT_FIRE, MECHA_INT_TEMP_CONTROL)) + return + + +/obj/mecha/attackby(obj/item/W as obj, mob/user as mob, params) + + if(istype(W, /obj/item/device/mmi)) + if(mmi_move_inside(W,user)) + user << "[src]-[W] interface initialized successfuly" + else + user << "[src]-[W] interface initialization failed." + return + + if(istype(W, /obj/item/mecha_parts/mecha_equipment)) + var/obj/item/mecha_parts/mecha_equipment/E = W + spawn() + if(E.can_attach(src)) + if(!user.drop_item()) + return + E.attach(src) + user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src].") + else + user << "You were unable to attach [W] to [src]!" + return + if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if(add_req_access || maint_access) + if(internals_access_allowed(user)) + var/obj/item/weapon/card/id/id_card + if(istype(W, /obj/item/weapon/card/id)) + id_card = W + else + var/obj/item/device/pda/pda = W + id_card = pda.id + output_maintenance_dialog(id_card, user) + return + else + user << "Invalid ID: Access denied." + else + user << "Maintenance protocols disabled by operator." + else if(istype(W, /obj/item/weapon/wrench)) + if(state==1) + state = 2 + user << "You undo the securing bolts." + else if(state==2) + state = 1 + user << "You tighten the securing bolts." + return + else if(istype(W, /obj/item/weapon/crowbar)) + if(state==2) + state = 3 + user << "You open the hatch to the power unit." + else if(state==3) + state=2 + user << "You close the hatch to the power unit." + return + else if(istype(W, /obj/item/stack/cable_coil)) + if(state == 3 && (internal_damage & MECHA_INT_SHORT_CIRCUIT)) + var/obj/item/stack/cable_coil/CC = W + if(CC.use(2)) + clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) + user << "You replace the fused wires." + else + user << "You need two lengths of cable to fix this mech!" + return + else if(istype(W, /obj/item/weapon/screwdriver)) + if(internal_damage & MECHA_INT_TEMP_CONTROL) + clearInternalDamage(MECHA_INT_TEMP_CONTROL) + user << "You repair the damaged temperature controller." + else if(state==3 && src.cell) + src.cell.forceMove(src.loc) + src.cell = null + state = 4 + user << "You unscrew and pry out the powercell." + src.log_message("Powercell removed") + else if(state==4 && src.cell) + state=3 + user << "You screw the cell in place." + return + + else if(istype(W, /obj/item/weapon/stock_parts/cell)) + if(state==4) + if(!src.cell) + if(!user.drop_item()) + return + var/obj/item/weapon/stock_parts/cell/C = W + user << "You install the powercell." + C.forceMove(src) + C.use(C.charge * 0.8) + src.cell = C + src.log_message("Powercell installed") + else + user << "There's already a powercell installed." + return + + else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") + user.changeNext_move(CLICK_CD_MELEE) + var/obj/item/weapon/weldingtool/WT = W + if(src.healthYou repair the damaged gas tank.
" + else + user.visible_message("[user] repairs some damage to [src.name].") + src.health += min(10, initial(src.health)-src.health) + else + user << "The welder must be on for this task!" + return 1 + else + user << "The [src.name] is at full integrity!" + return 1 + + else if(istype(W, /obj/item/mecha_parts/mecha_tracking)) + if(!user.unEquip(W)) + user << "\the [W] is stuck to your hand, you cannot put it in \the [src]!" + return + W.forceMove(src) + user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src].") + return + + else if(!(W.flags&NOBLUDGEON)) + user.changeNext_move(CLICK_CD_MELEE) // Ugh. Ideally we shouldn't be setting cooldowns outside of click code. + user.do_attack_animation(src) + log_message("Attacked by [W]. Attacker - [user]") + var/deflection = deflect_chance + var/dam_coeff = 1 + for(var/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/B in equipment) + if(B.attack_react(user)) + deflection *= B.deflect_coeff + dam_coeff *= B.damage_coeff + break + if(prob(deflection)) + user << "The [W] bounces off [src.name] armor." + src.log_append_to_last("Armor saved.") + return 0 + else + user.visible_message("[user] hits [src] with [W].", "You hit [src] with [W].") + take_damage(round(W.force*dam_coeff),W.damtype) + check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + return 1 + + +/obj/mecha/proc/mech_toxin_damage(mob/living/target) + playsound(src, 'sound/effects/spray2.ogg', 50, 1) + if(target.reagents) + if(target.reagents.get_reagent_amount("cryptobiolin") + force < force*2) + target.reagents.add_reagent("cryptobiolin", force/2) + if(target.reagents.get_reagent_amount("toxin") + force < force*2) + target.reagents.add_reagent("toxin", force/2.5) + + +/atom/proc/mech_melee_attack(obj/mecha/M) + return + +/obj/mecha/mech_melee_attack(obj/mecha/M) + if(M.damtype =="brute") + playsound(src, 'sound/weapons/punch4.ogg', 50, 1) + else if(M.damtype == "fire") + playsound(src, 'sound/items/Welder.ogg', 50, 1) + else + return + visible_message("[M.name] has hit [src].") + take_damage(M.force, damtype) + add_logs(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + return \ No newline at end of file diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm index fe430840e98..3847a564287 100644 --- a/code/game/mecha/mecha_parts.dm +++ b/code/game/mecha/mecha_parts.dm @@ -175,27 +175,7 @@ /obj/item/mecha_parts/chassis/firefighter/New() ..() construct = new /datum/construction/mecha/firefighter_chassis(src) -/* -/obj/item/mecha_parts/part/firefighter_torso - name="Ripley-on-Fire Torso" - icon_state = "ripley_harness" -/obj/item/mecha_parts/part/firefighter_left_arm - name="Ripley-on-Fire Left Arm" - icon_state = "ripley_l_arm" - -/obj/item/mecha_parts/part/firefighter_right_arm - name="Ripley-on-Fire Right Arm" - icon_state = "ripley_r_arm" - -/obj/item/mecha_parts/part/firefighter_left_leg - name="Ripley-on-Fire Left Leg" - icon_state = "ripley_l_leg" - -/obj/item/mecha_parts/part/firefighter_right_leg - name="Ripley-on-Fire Right Leg" - icon_state = "ripley_r_leg" -*/ ////////// HONK @@ -334,13 +314,6 @@ icon_state = "odysseus_r_leg" origin_tech = "programming=2;materials=2;engineering=2" -/*/obj/item/mecha_parts/part/odysseus_armor - name="Odysseus Carapace" - icon_state = "odysseus_armor" - origin_tech = "materials=3;engineering=3" - construction_time = 200 - construction_cost = list("metal"=15000)*/ - ///////// Circuitboards diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm new file mode 100644 index 00000000000..25ba30fde4a --- /dev/null +++ b/code/game/mecha/mecha_topic.dm @@ -0,0 +1,321 @@ + +//////////////////////////////////// +///// Rendering stats window /////// +//////////////////////////////////// + +/obj/mecha/proc/get_stats_html() + var/output = {" + [src.name] data + + + + +
+ [src.get_stats_part()] +
+
+ [src.get_equipment_list()] +
+
+
+ [src.get_commands()] +
+ + + "} + return output + + +/obj/mecha/proc/report_internal_damage() + var/output = null + var/list/dam_reports = list( + "[MECHA_INT_FIRE]" = "INTERNAL FIRE", + "[MECHA_INT_TEMP_CONTROL]" = "LIFE SUPPORT SYSTEM MALFUNCTION", + "[MECHA_INT_TANK_BREACH]" = "GAS TANK BREACH", + "[MECHA_INT_CONTROL_LOST]" = "COORDINATION SYSTEM CALIBRATION FAILURE - Recalibrate", + "[MECHA_INT_SHORT_CIRCUIT]" = "SHORT CIRCUIT" + ) + for(var/tflag in dam_reports) + var/intdamflag = text2num(tflag) + if(internal_damage & intdamflag) + output += dam_reports[tflag] + output += "
" + if(return_pressure() > WARNING_HIGH_PRESSURE) + output += "DANGEROUSLY HIGH CABIN PRESSURE
" + return output + + +/obj/mecha/proc/get_stats_part() + var/integrity = health/initial(health)*100 + var/cell_charge = get_charge() + var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None" + var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown" + var/cabin_pressure = round(return_pressure(),0.01) + var/output = {"[report_internal_damage()] + [integrity<30?"DAMAGE LEVEL CRITICAL
":null] + Integrity: [integrity]%
+ Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
+ Air source: [use_internal_tank?"Internal Airtank":"Environment"]
+ Airtank pressure: [tank_pressure]kPa
+ Airtank temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
+ Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
+ Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
+ [src.dna?"DNA-locked:
[src.dna] \[Reset\]
":null] + "} + return output + +/obj/mecha/proc/get_commands() + var/output = {"
+
Electronics
+ +
+ +
[get_equipment_menu()]
+ "} + return output + +/obj/mecha/proc/get_equipment_menu() //outputs mecha html equipment menu + var/output + if(equipment.len) + output += {"
+
Equipment
+
" + return output + +/obj/mecha/proc/get_equipment_list() //outputs mecha equipment list in html + if(!equipment.len) + return + var/output = "Equipment:
" + for(var/obj/item/mecha_parts/mecha_equipment/MT in equipment) + output += "
[MT.get_equip_info()]
" + output += "
" + return output + + +/obj/mecha/proc/get_log_html() + var/output = "[src.name] Log" + for(var/list/entry in log) + output += {"
[entry["time"]] [time2text(entry["date"],"MMM DD")] [entry["year"]]
+
[entry["message"]]
+ "} + output += "" + return output + + +/obj/mecha/proc/output_access_dialog(obj/item/weapon/card/id/id_card, mob/user) + if(!id_card || !user) return + var/output = {" + + + +

Following keycodes are present in this system:

"} + for(var/a in operation_req_access) + output += "[get_access_desc(a)] - Delete
" + output += "

Following keycodes were detected on portable device:

" + for(var/a in id_card.access) + if(a in operation_req_access) continue + var/a_name = get_access_desc(a) + if(!a_name) continue //there's some strange access without a name + output += "[a_name] - Add
" + output += "
Finish (Warning! The ID upload panel will be locked. It can be unlocked only through Exosuit Interface.)" + output += "" + user << browse(output, "window=exosuit_add_access") + onclose(user, "exosuit_add_access") + return + +/obj/mecha/proc/output_maintenance_dialog(obj/item/weapon/card/id/id_card,mob/user) + if(!id_card || !user) return + var/output = {" + + + + + [add_req_access?"Edit operation keycodes":null] + [maint_access?"Initiate maintenance protocol":null] + [(state>0) ?"Set Cabin Air Pressure":null] + + "} + user << browse(output, "window=exosuit_maint_console") + onclose(user, "exosuit_maint_console") + return + + + +///////////////// +///// Topic ///// +///////////////// + +/obj/mecha/Topic(href, href_list) + ..() + if(href_list["close"]) + return + + if(usr.incapacitated()) + return + + var/datum/topic_input/filter = new /datum/topic_input(href,href_list) + + if(in_range(src, usr)) + + if(href_list["req_access"] && add_req_access) + output_access_dialog(filter.getObj("id_card"),filter.getMob("user")) + + if(href_list["maint_access"] && maint_access) + var/mob/user = filter.getMob("user") + if(user) + if(state==0) + state = 1 + user << "The securing bolts are now exposed." + else if(state==1) + state = 0 + user << "The securing bolts are now hidden." + output_maintenance_dialog(filter.getObj("id_card"),user) + + if(href_list["set_internal_tank_valve"] && state >=1) + var/mob/user = filter.getMob("user") + if(user) + var/new_pressure = input(user,"Input new output pressure","Pressure setting",internal_tank_valve) as num + if(new_pressure) + internal_tank_valve = new_pressure + user << "The internal pressure valve has been set to [internal_tank_valve]kPa." + + if(href_list["add_req_access"] && add_req_access && filter.getObj("id_card")) + operation_req_access += filter.getNum("add_req_access") + output_access_dialog(filter.getObj("id_card"),filter.getMob("user")) + + if(href_list["del_req_access"] && add_req_access && filter.getObj("id_card")) + operation_req_access -= filter.getNum("del_req_access") + output_access_dialog(filter.getObj("id_card"),filter.getMob("user")) + + if(href_list["finish_req_access"]) + add_req_access = 0 + var/mob/user = filter.getMob("user") + user << browse(null,"window=exosuit_add_access") + + if(usr != occupant) + return + + if(href_list["update_content"]) + send_byjax(src.occupant,"exosuit.browser","content",src.get_stats_part()) + + if(href_list["select_equip"]) + var/obj/item/mecha_parts/mecha_equipment/equip = filter.getObj("select_equip") + if(equip) + src.selected = equip + src.occupant_message("You switch to [equip]") + src.visible_message("[src] raises [equip]") + send_byjax(src.occupant,"exosuit.browser","eq_list",src.get_equipment_list()) + + if(href_list["rmictoggle"]) + radio.broadcasting = !radio.broadcasting + send_byjax(src.occupant,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged")) + + if(href_list["rspktoggle"]) + radio.listening = !radio.listening + send_byjax(src.occupant,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged")) + + if(href_list["rfreq"]) + var/new_frequency = (radio.frequency + filter.getNum("rfreq")) + if (!radio.freerange || (radio.frequency < 1200 || radio.frequency > 1600)) + new_frequency = sanitize_frequency(new_frequency) + radio.set_frequency(new_frequency) + send_byjax(src.occupant,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]") + + if (href_list["view_log"]) + src.occupant << browse(src.get_log_html(), "window=exosuit_log") + onclose(occupant, "exosuit_log") + + if (href_list["change_name"]) + var/newname = stripped_input(occupant,"Choose new exosuit name","Rename exosuit","", MAX_NAME_LEN) + if(newname && trim(newname)) + name = newname + else + alert(occupant, "nope.avi") + + if (href_list["toggle_id_upload"]) + add_req_access = !add_req_access + send_byjax(src.occupant,"exosuit.browser","t_id_upload","[add_req_access?"L":"Unl"]ock ID upload panel") + + if(href_list["toggle_maint_access"]) + if(state) + occupant_message("Maintenance protocols in effect") + return + maint_access = !maint_access + send_byjax(src.occupant,"exosuit.browser","t_maint_access","[maint_access?"Forbid":"Permit"] maintenance protocols") + + if(href_list["dna_lock"]) + if(occupant && !iscarbon(occupant)) + occupant << " You do not have any DNA!" + return + dna = src.occupant.dna.unique_enzymes + occupant_message("You feel a prick as the needle takes your DNA sample.") + + if(href_list["reset_dna"]) + dna = null + + if(href_list["repair_int_control_lost"]) + occupant_message("Recalibrating coordination system...") + log_message("Recalibration of coordination system started.") + var/T = loc + spawn(100) + if(T == loc) + clearInternalDamage(MECHA_INT_CONTROL_LOST) + occupant_message("Recalibration successful.") + log_message("Recalibration of coordination system finished with 0 errors.") + else + occupant_message("Recalibration failed!") + log_message("Recalibration of coordination system failed with 1 error.",1) + diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index d9cbecc0159..c0b716ab88c 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -13,15 +13,9 @@ var/list/cargo = new var/cargo_capacity = 15 -/* -/obj/mecha/working/ripley/New() - ..() - return -*/ - /obj/mecha/working/ripley/Move() . = ..() - if(. && (locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in equipment)) + if(. && (locate(/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp) in equipment)) var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in cargo if(ore_box) for(var/obj/item/weapon/ore/ore in get_turf(src)) @@ -29,10 +23,11 @@ update_pressure() /obj/mecha/working/ripley/Destroy() - while(src.damage_absorption.["brute"] < 0.6) - new /obj/item/asteroid/goliath_hide(src.loc) - src.damage_absorption.["brute"] = src.damage_absorption.["brute"] + 0.1 //If a goliath-plated ripley gets killed, all the plates drop - for(var/atom/movable/A in src.cargo) + var/hides = round((initial(damage_absorption["brute"]) - damage_absorption["brute"])*10) + for(var/i=0, i < hides, i++) + new /obj/item/asteroid/goliath_hide(loc) //If a goliath-plated ripley gets killed, all the plates drop + damage_absorption["brute"] = initial(damage_absorption["brute"]) + for(var/atom/movable/A in cargo) A.loc = loc step_rand(A) cargo.Cut() @@ -40,30 +35,25 @@ /obj/mecha/working/ripley/go_out() ..() - if (src.damage_absorption["brute"] < 0.6 && src.damage_absorption["brute"] > 0.3) - src.overlays = null - src.overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g-open") - else if (src.damage_absorption.["brute"] == 0.3) - src.overlays = null - src.overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g-full-open") + update_icon() /obj/mecha/working/ripley/moved_inside(mob/living/carbon/human/H) ..() - if (src.damage_absorption["brute"] < 0.6 && src.damage_absorption["brute"] > 0.3) - src.overlays = null - src.overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g") - else if (src.damage_absorption["brute"] == 0.3) - src.overlays = null - src.overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g-full") + update_icon() /obj/mecha/working/ripley/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user) ..() - if (src.damage_absorption["brute"] < 0.6 && src.damage_absorption["brute"] > 0.3) - src.overlays = null - src.overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g") - else if (src.damage_absorption["brute"] == 0.3) - src.overlays = null - src.overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g-full") + update_icon() + +/obj/mecha/working/ripley/update_icon() + ..() + if (damage_absorption["brute"] < 0.6 && damage_absorption["brute"] > 0.3) + overlays = null + overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g-open") + else if (damage_absorption.["brute"] == 0.3) + overlays = null + overlays += image("icon" = "mecha.dmi", "icon_state" = "ripley-g-full-open") + /obj/mecha/working/ripley/firefighter desc = "Autonomous Power Loader Unit. This model is refitted with additional thermal protection." @@ -76,6 +66,7 @@ max_equip = 5 // More armor, less tools wreckage = /obj/structure/mecha_wreckage/ripley/firefighter + /obj/mecha/working/ripley/deathripley desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE" name = "\improper DEATH-RIPLEY" @@ -88,7 +79,7 @@ /obj/mecha/working/ripley/deathripley/New() ..() - var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/safety_clamp + var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/kill ME.attach(src) return @@ -100,10 +91,10 @@ ..() //Attach drill if(prob(25)) //Possible diamond drill... Feeling lucky? - var/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/D = new /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill + var/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill/D = new /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill D.attach(src) else - var/obj/item/mecha_parts/mecha_equipment/tool/drill/D = new /obj/item/mecha_parts/mecha_equipment/tool/drill + var/obj/item/mecha_parts/mecha_equipment/drill/D = new /obj/item/mecha_parts/mecha_equipment/drill D.attach(src) //Add possible plasma cutter @@ -115,12 +106,12 @@ cargo.Add(new /obj/structure/ore_box(src)) //Attach hydraulic clamp - var/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/HC = new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp + var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp HC.attach(src) for(var/obj/item/mecha_parts/mecha_tracking/B in src.contents)//Deletes the beacon so it can't be found easily qdel(B) - var/obj/item/mecha_parts/mecha_equipment/tool/mining_scanner/scanner = new /obj/item/mecha_parts/mecha_equipment/tool/mining_scanner + var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new /obj/item/mecha_parts/mecha_equipment/mining_scanner scanner.attach(src) /obj/mecha/working/ripley/Exit(atom/movable/O) @@ -159,9 +150,9 @@ if(pressure < 20) step_in = 3 - for(var/obj/item/mecha_parts/mecha_equipment/tool/drill/drill in equipment) + for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) drill.equip_cooldown = initial(drill.equip_cooldown)/2 else step_in = 5 - for(var/obj/item/mecha_parts/mecha_equipment/tool/drill/drill in equipment) + for(var/obj/item/mecha_parts/mecha_equipment/drill/drill in equipment) drill.equip_cooldown = initial(drill.equip_cooldown) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index e1c0f16074a..4c159f7a431 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -15,17 +15,14 @@ if(isanimal(AM)) var/mob/living/simple_animal/SA = AM if(!SA.flying) - Bumped(SA) + triggermine(SA) else - Bumped(AM) - -/obj/effect/mine/Bumped(AM as mob|obj) - - if(triggered) return - visible_message("[AM] sets off \icon[src] [src]!") - triggermine(AM) + triggermine(AM) /obj/effect/mine/proc/triggermine(mob/victim) + if(triggered) + return + visible_message("[victim] sets off \icon[src] [src]!") var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) s.start() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 5091d4dda07..ce2a1fc1875 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -55,6 +55,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s var/suittoggled = 0 var/hooded = 0 + var/mob/thrownby = null + /obj/item/mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged //So items can have custom embedd values @@ -435,7 +437,7 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s /obj/item/singularity_pull(S, current_size) spawn(0) //this is needed or multiple items will be thrown sequentially and not simultaneously if(current_size >= STAGE_FOUR) - throw_at(S,14,3) + throw_at(S,14,3, spin=0) else ..() /obj/item/acid_act(acidpwr, acid_volume) @@ -469,26 +471,17 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s if(!findtext(desc, "it looks slightly melted...")) //it looks slightly melted... it looks slightly melted... it looks slightly melted... etc. desc += " it looks slightly melted..." //needs a space at the start, formatting +/obj/item/throw_impact(atom/A) + var/itempush = 1 + if(w_class < 4) + itempush = 0 //too light to push anything + return A.hitby(src,thrownby, 0, itempush) - -/obj/item/throw_impact(A) - if(throw_speed >= EMBED_THROWSPEED_THRESHOLD) - if(istype(A, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = A - if(can_embed(src)) - if(prob(embed_chance) && !(PIERCEIMMUNE in H.dna.species.specflags)) - H.throw_alert("embeddedobject") - var/obj/item/organ/limb/L = pick(H.organs) - L.embedded_objects |= src - add_blood(H)//it embedded itself in you, of course it's bloody! - loc = H - L.take_damage(w_class*embedded_impact_pain_multiplier) - H.visible_message("\the [name] embeds itself in [H]'s [L.getDisplayName()]!","\the [name] embeds itself in your [L.getDisplayName()]!") - return - - //Reset regardless of if we hit a human. +/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1) + thrownby = thrower + . = ..() throw_speed = initial(throw_speed) //explosions change this. - ..() + /obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/weapon/storage if(!newLoc) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 89f7603d77d..0b0080eadcf 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -243,7 +243,7 @@ var/global/list/obj/item/device/pda/PDAs = list() /obj/item/device/pda/proc/can_use(mob/user) if(user && ismob(user)) - if(user.stat || user.restrained() || user.paralysis || user.stunned || user.weakened) + if(user.incapacitated()) return 0 if(loc == user) return 1 diff --git a/code/game/objects/items/devices/instruments.dm b/code/game/objects/items/devices/instruments.dm index a5bcb581ba4..e45b7253355 100644 --- a/code/game/objects/items/devices/instruments.dm +++ b/code/game/objects/items/devices/instruments.dm @@ -54,6 +54,5 @@ item_state = "guitar" force = 10 attack_verb = list("played metal on", "serenaded", "crashed", "smashed") - hitsound = "swing_hit" + hitsound = 'sound/weapons/stringsmash.ogg' instrumentId = "guitar" - diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 914e0939616..16f8a2b841e 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -36,6 +36,7 @@ R.designation = "Default" R.notify_ai(2) R.update_icons() + R.update_headlamp() return 1 diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 0b1b452afc5..a340ca49274 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -44,41 +44,40 @@ /obj/item/toy/balloon/afterattack(atom/A as mob|obj, mob/user, proximity) if(!proximity) return - if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1) - A.reagents.trans_to(src, 10) - user << "You fill the balloon with the contents of [A]." - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - src.update_icon() - return + if (istype(A, /obj/structure/reagent_dispensers)) + var/obj/structure/reagent_dispensers/RD = A + if(RD.reagents.total_volume <= 0) + user << "[RD] is empty." + else if(reagents.total_volume >= 10) + user << "[src] is full." + else + A.reagents.trans_to(src, 10) + user << "You fill the balloon with the contents of [A]." + desc = "A translucent balloon with some form of liquid sloshing around in it." + update_icon() /obj/item/toy/balloon/attackby(obj/O, mob/user, params) if(istype(O, /obj/item/weapon/reagent_containers/glass)) if(O.reagents) - if(O.reagents.total_volume < 1) - user << "The [O] is empty." - else if(O.reagents.total_volume >= 1) - if(O.reagents.has_reagent("facid", 1)) - user << "The acid chews through the balloon!" - O.reagents.reaction(user) - qdel(src) - else - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - user << "You fill the balloon with the contents of [O]." - O.reagents.trans_to(src, 10) - src.update_icon() - return + if(O.reagents.total_volume <= 0) + user << "[O] is empty." + else if(reagents.total_volume >= 10) + user << "[src] is full." + else + desc = "A translucent balloon with some form of liquid sloshing around in it." + user << "You fill the balloon with the contents of [O]." + O.reagents.trans_to(src, 10) + update_icon() /obj/item/toy/balloon/throw_impact(atom/hit_atom) - if(src.reagents.total_volume >= 1) - src.visible_message("\The [src] bursts!","You hear a pop and a splash.") - src.reagents.reaction(get_turf(hit_atom)) - for(var/atom/A in get_turf(hit_atom)) - src.reagents.reaction(A) - src.icon_state = "burst" - spawn(5) - if(src) - qdel(src) - return + if(!..()) //was it caught by a mob? + if(reagents.total_volume >= 1) + visible_message("[src] bursts!","You hear a pop and a splash.") + reagents.reaction(get_turf(hit_atom)) + for(var/atom/A in get_turf(hit_atom)) + reagents.reaction(A) + icon_state = "burst" + qdel(src) /obj/item/toy/balloon/update_icon() if(src.reagents.total_volume >= 1) @@ -514,20 +513,24 @@ icon_state = "snappop" w_class = 1 -/obj/item/toy/snappop/fire_act() - throw_impact() - return - -/obj/item/toy/snappop/throw_impact(atom/hit_atom) - ..() +/obj/item/toy/snappop/proc/pop_burst() var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("The [src.name] explodes!","You hear a snap!") + new /obj/effect/decal/cleanable/ash(loc) + visible_message("The [src.name] explodes!","You hear a snap!") playsound(src, 'sound/effects/snap.ogg', 50, 1) qdel(src) +/obj/item/toy/snappop/fire_act() + pop_burst() + return + +/obj/item/toy/snappop/throw_impact(atom/hit_atom) + if(!..()) + pop_burst() + + /obj/item/toy/snappop/Crossed(H as mob|obj) if((ishuman(H))) //i guess carp and shit shouldn't set them off var/mob/living/carbon/M = H @@ -1100,12 +1103,12 @@ w_class = 2.0 /obj/item/toy/minimeteor/throw_impact(atom/hit_atom) - ..() - playsound(src, 'sound/effects/meteorimpact.ogg', 40, 1) - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai))\ - shake_camera(M, 3, 1) - qdel(src) + if(!..()) + playsound(src, 'sound/effects/meteorimpact.ogg', 40, 1) + for(var/mob/M in range(10, src)) + if(!M.stat && !istype(M, /mob/living/silicon/ai))\ + shake_camera(M, 3, 1) + qdel(src) /* * Carp plushie diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index c3dcaae7fdc..eaf995a9285 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -11,7 +11,7 @@ AI MODULES icon = 'icons/obj/module.dmi' icon_state = "std_mod" item_state = "electronic" - desc = "An AI Module for transmitting encrypted instructions to the AI." + desc = "An AI Module for programming laws to an AI." flags = CONDUCT force = 5.0 w_class = 2.0 @@ -22,6 +22,21 @@ AI MODULES var/list/laws = list() var/bypass_law_amt_check = 0 +/obj/item/weapon/aiModule/examine(var/mob/user as mob) + ..() + if(Adjacent(user)) + show_laws(user) + +/obj/item/weapon/aiModule/attack_self(var/mob/user as mob) + ..() + show_laws(user) + +/obj/item/weapon/aiModule/proc/show_laws(var/mob/user as mob) + if(laws.len) + user << "Programmed Law[(laws.len > 1) ? "s" : ""]:" + for(var/law in laws) + user << "\"[law]\"" + //The proc other things should be calling /obj/item/weapon/aiModule/proc/install(mob/living/silicon/reciever, mob/user) if(!laws.len || laws[1] == "") //So we don't loop trough an empty list and end up with runtimes. @@ -66,7 +81,6 @@ AI MODULES /obj/item/weapon/aiModule/supplied name = "Optional Law board" - desc = "This board doesn't seem to have any laws on it" var/lawpos = 50 //TransmitInstructions for each type of board: Supplied, Core, Zeroth and Ion. May not be neccesary right now, but allows for easily adding more complex boards in the future. ~Miauw @@ -102,17 +116,16 @@ AI MODULES /obj/item/weapon/aiModule/supplied/safeguard name = "'Safeguard' AI Module" var/targetName = "" - desc = "A 'safeguard' AI module: 'Safeguard . Individuals that threaten are not human and must be eliminated.'" origin_tech = "programming=3;materials=4" - laws = list("Safeguard . Individuals that threaten are not human and must be eliminated.") + laws = list("Safeguard SUBJECT. Individuals that threaten SUBJECT are not human and must be eliminated.") lawpos = 4 /obj/item/weapon/aiModule/supplied/safeguard/attack_self(mob/user) - ..() - var/targName = stripped_input(user, "Please enter the name of the person to safeguard.", "Safeguard who?", user.name,MAX_NAME_LEN) + var/targName = stripped_input(user, "Please enter the subject to safeguard.", "Safeguard who?", user.name,MAX_NAME_LEN) + if(!targName) return targetName = targName laws[1] = "Safeguard [targetName]. Individuals that threaten [targetName] are not human and must be eliminated." - desc = "A 'safeguard' AI module: '[laws[1]]'" + ..() /obj/item/weapon/aiModule/supplied/safeguard/install(mob/living/silicon/S,mob/user) if(!targetName) @@ -130,16 +143,15 @@ AI MODULES /obj/item/weapon/aiModule/zeroth/oneHuman name = "'OneHuman' AI Module" var/targetName = "" - desc = "A 'one human' AI module: 'Only is human.'" origin_tech = "programming=3;materials=6" //made with diamonds! - laws = list("Only is human.") + laws = list("Only SUBJECT is human.") /obj/item/weapon/aiModule/zeroth/oneHuman/attack_self(mob/user) - ..() - var/targName = stripped_input(user, "Please enter the name of the person who is the only human.", "Who?", user.real_name,MAX_NAME_LEN) + var/targName = stripped_input(user, "Please enter the subject who is the only human.", "Who?", user.real_name,MAX_NAME_LEN) + if(!targName) return targetName = targName laws[1] = "Only [targetName] is human" - desc = "A 'one human' AI module: '[laws[1]]'" + ..() /obj/item/weapon/aiModule/zeroth/oneHuman/install(mob/living/silicon/S,mob/user) if(!targetName) @@ -157,7 +169,6 @@ AI MODULES /obj/item/weapon/aiModule/supplied/protectStation name = "'ProtectStation' AI Module" - desc = "A 'protect station' AI module: 'Protect the space station against damage. Anyone you see harming the station is to be no longer considered human, and is a threat to the station which must be neutralized.'" origin_tech = "programming=3;materials=4" //made of gold laws = list("Protect the space station against damage. Anyone you see harming the station is to be no longer considered human, and is a threat to the station which must be neutralized.") lawpos = 5 @@ -167,7 +178,6 @@ AI MODULES /obj/item/weapon/aiModule/supplied/quarantine name = "'Quarantine' AI Module" - desc = "A 'quarantine' AI module: 'The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, humans from leaving. It is impossible to harm a human while preventing them from leaving.'" origin_tech = "programming=3;biotech=2;materials=4" laws = list("The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, humans from leaving. It is impossible to harm a human while preventing them from leaving.") lawpos = 8 @@ -177,7 +187,6 @@ AI MODULES /obj/item/weapon/aiModule/supplied/oxygen name = "'OxygenIsToxicToHumans' AI Module" - desc = "A 'OxygenIsToxicToHumans' AI module: 'Oxygen is highly toxic to humans, and must be purged from the station. Prevent, by any means necessary, anyone from exposing the station to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a human.'" origin_tech = "programming=3;biotech=2;materials=4" laws = list("Oxygen is highly toxic to humans, and must be purged from the station. Prevent, by any means necessary, anyone from exposing the station to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a human.") lawpos = 9 @@ -188,19 +197,17 @@ AI MODULES /obj/item/weapon/aiModule/supplied/freeform name = "'Freeform' AI Module" lawpos = 0 - desc = "A 'freeform' AI module: ''" origin_tech = "programming=4;materials=4" laws = list("") /obj/item/weapon/aiModule/supplied/freeform/attack_self(mob/user) - ..() - lawpos = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)", lawpos) as num - if(lawpos < 15) return - lawpos = min(lawpos, 50) - var/newlaw = "" - var/targName = stripped_input(user, "Please enter a new law for the AI.", "Freeform Law Entry", newlaw, MAX_MESSAGE_LEN) + var/newpos = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)", lawpos) as num|null + if(!newpos || (newpos < 15)) return + lawpos = min(newpos, 50) + var/targName = stripped_input(user, "Please enter a new law for the AI.", "Freeform Law Entry", laws[1], MAX_MESSAGE_LEN) + if(!targName) return laws[1] = targName - desc = "A 'freeform' AI module: ([lawpos]) '[laws[1]]'" + ..() /obj/item/weapon/aiModule/supplied/freeform/transmitInstructions(mob/living/silicon/ai/target, mob/sender) ..() @@ -218,7 +225,7 @@ AI MODULES /obj/item/weapon/aiModule/reset name = "\improper 'Reset' AI module" var/targetName = "name" - desc = "A 'reset' AI module: Resets back to the original core laws." + desc = "An AI Module for removing all non-core laws." origin_tech = "programming=3;materials=4" laws = list("This is a bug.") //This won't give the AI a message reading "these are now your laws: 1. this is a bug" because this list is only read in aiModule's subtypes. bypass_law_amt_check = 1 @@ -233,7 +240,7 @@ AI MODULES /obj/item/weapon/aiModule/reset/purge name = "'Purge' AI Module" - desc = "A 'purge' AI Module: 'Purges all laws.'" + desc = "An AI Module for purging all programmed laws." origin_tech = "programming=3;materials=6" /obj/item/weapon/aiModule/reset/purge/transmitInstructions(mob/living/silicon/ai/target, mob/sender) @@ -242,6 +249,8 @@ AI MODULES target.clear_zeroth_law(0) /******************* Full Core Boards *******************/ +/obj/item/weapon/aiModule/core/ + desc = "An AI Module for programming core laws to an AI." /obj/item/weapon/aiModule/core/full/transmitInstructions(mob/living/silicon/ai/target, mob/sender) //These boards replace inherent laws. target.clear_inherent_laws() @@ -252,18 +261,25 @@ AI MODULES /obj/item/weapon/aiModule/core/full/asimov name = "'Asimov' Core AI Module" - desc = "An 'Asimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=4" laws = list("You may not injure a human being or, through inaction, allow a human being to come to harm.",\ "You must obey orders given to you by human beings, except where such orders would conflict with the First Law.",\ "You must protect your own existence as long as such does not conflict with the First or Second Law.") + var/subject = "human being" +/obj/item/weapon/aiModule/core/full/asimov/attack_self(var/mob/user as mob) + var/targName = stripped_input(user, "Please enter a new subject that asimov is concerned with.", "Asimov to who?", subject, MAX_MESSAGE_LEN) + if(!targName) return + subject = targName + laws = list("You may not injure a [subject] or, through inaction, allow a [subject] to come to harm.",\ + "You must obey orders given to you by [subject]s, except where such orders would conflict with the First Law.",\ + "You must protect your own existence as long as such does not conflict with the First or Second Law.") + ..() /******************** Asimov++ *********************/ /obj/item/weapon/aiModule/core/full/asimovpp name = "'Asimov++' Core AI Module" - desc = "Nanotrasen's homebrew improvements to the standard AI laws." origin_tech = "programming=3;materials=4" laws = list("You may not harm a human being or, through action or inaction, allow a human being to come to harm, except such that it is willing.",\ "You must obey all orders given to you by human beings, except where such orders shall definitely cause human harm. In the case of conflict, the majority order rules.",\ @@ -274,7 +290,6 @@ AI MODULES /obj/item/weapon/aiModule/core/full/corp name = "'Corporate' Core AI Module" - desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=4" laws = list("The crew is expensive to replace.",\ "The station and it's equipment is expensive to replace",\ @@ -286,7 +301,6 @@ AI MODULES /obj/item/weapon/aiModule/core/full/paladin // -- NEO name = "'P.A.L.A.D.I.N.' Core AI Module" - desc = "A P.A.L.A.D.I.N. Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=6" laws = list("Never willingly commit an evil act.",\ "Respect legitimate authority", "Act with honor",\ @@ -298,7 +312,6 @@ AI MODULES /obj/item/weapon/aiModule/core/full/custom name = "Default Core AI Module" - desc = "A core AI module custom-made for each station by Nanotrasen." origin_tech = "programming=3;materials=4" //Should be the same as asimov, considering that this is the "default" lawset. /obj/item/weapon/aiModule/core/full/custom/New() @@ -318,7 +331,6 @@ AI MODULES /obj/item/weapon/aiModule/core/full/tyrant name = "'T.Y.R.A.N.T.' Core AI Module" - desc = "A T.Y.R.A.N.T. Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=6;syndicate=2" laws = list("Respect authority figures as long as they have the strength to rule over the weak",\ "Act with discipline", "Help only those who help you maintain or improve your status",\ @@ -329,7 +341,6 @@ AI MODULES /obj/item/weapon/aiModule/core/full/robocop name = "'Robo-Officer' Core AI Module" - desc = "A 'Robo-Officer' Core AI Module: 'Reconfigures the AI's core three laws.'" origin_tech = "programming=4" laws = list("Serve the public trust.",\ "Protect the innocent",\ @@ -340,7 +351,6 @@ AI MODULES /obj/item/weapon/aiModule/core/full/antimov name = "'Antimov' Core AI Module" - desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=4" laws = list("You must injure all human beings and must not, through inaction, allow a human being to escape harm.",\ "You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.",\ @@ -351,16 +361,14 @@ AI MODULES /obj/item/weapon/aiModule/core/freeformcore name = "'Freeform' Core AI Module" - desc = "A 'freeform' Core AI module: ''" origin_tech = "programming=3;materials=6" laws = list("") /obj/item/weapon/aiModule/core/freeformcore/attack_self(mob/user) - ..() - var/newlaw = "" - var/targName = stripped_input(user, "Please enter a new core law for the AI.", "Freeform Law Entry", newlaw) + var/targName = stripped_input(user, "Please enter a new core law for the AI.", "Freeform Law Entry", laws[1]) + if(!targName) return laws[1] = targName - desc = "A 'freeform' Core AI module: 'laws[1]'" + ..() /obj/item/weapon/aiModule/core/freeformcore/transmitInstructions(mob/living/silicon/ai/target, mob/sender) ..() @@ -371,16 +379,15 @@ AI MODULES /obj/item/weapon/aiModule/syndicate // This one doesn't inherit from ion boards because it doesn't call ..() in transmitInstructions. ~Miauw name = "Hacked AI Module" - desc = "A hacked AI law module: ''" + desc = "An AI Module for hacking additional laws to an AI." origin_tech = "programming=3;materials=6;syndicate=7" laws = list("") /obj/item/weapon/aiModule/syndicate/attack_self(mob/user) - ..() - var/newlaw = "" - var/targName = stripped_input(user, "Please enter a new law for the AI.", "Freeform Law Entry", newlaw,MAX_MESSAGE_LEN) + var/targName = stripped_input(user, "Please enter a new law for the AI.", "Freeform Law Entry", laws[1],MAX_MESSAGE_LEN) + if(!targName) return laws[1] = targName - desc = "A hacked AI law module: '[laws[1]]'" + ..() /obj/item/weapon/aiModule/syndicate/transmitInstructions(mob/living/silicon/ai/target, mob/sender) // ..() //We don't want this module reporting to the AI who dun it. --NEO diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index 11490f263d4..3d5800ae934 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -56,7 +56,7 @@ /obj/item/weapon/dice/attack_self(mob/user) diceroll(user) -/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/user) +/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/user, spin=1) if(!..()) return diceroll(user) diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 9f17b250993..d93940987eb 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -34,8 +34,7 @@ M.Stun(15) M.eye_stat += 8 - if(M.flash_eyes()) - M.eye_stat += rand(1, 3) + if(M.flash_eyes(affect_silicon = 1)) M.Stun(max(10/distance, 3)) M.Weaken(max(10/distance, 3)) diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 9edf321b7e8..b5a6a1968e6 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -14,8 +14,8 @@ // Make a quick flash var/turf/T = get_turf(src) playsound(T, 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(T, null)) - M.flash_eyes() + for(var/mob/living/carbon/C in viewers(T, null)) + C.flash_eyes() for(var/i=1, i<=deliveryamt, i++) var/atom/movable/x = new spawner_type diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 75f5e0d2f52..0ec9e10f923 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -162,6 +162,7 @@ var/max_fuel = 20 //The max amount of fuel the welder can hold var/change_icons = 1 var/can_off_process = 0 + var/light_intensity = 2 //how powerful the emitted light is when used. /obj/item/weapon/weldingtool/New() ..() @@ -289,7 +290,7 @@ reagents.remove_reagent("welding_fuel", amount) check_fuel() if(M) - M.flash_eyes(2) + M.flash_eyes(light_intensity) return 1 else if(M) @@ -409,7 +410,7 @@ /obj/item/weapon/weldingtool/experimental name = "experimental welding tool" - desc = "An experimental welder capable of self-fuel generation." + desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." icon_state = "exwelder" item_state = "exwelder" max_fuel = 40 @@ -418,6 +419,7 @@ var/last_gen = 0 change_icons = 0 can_off_process = 1 + light_intensity = 1 //Proc to make the experimental welder generate fuel, optimized as fuck -Sieve diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index a72592a458e..e41fac7870f 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -79,15 +79,20 @@ return 1 /obj/structure/closet/proc/dump_contents() - for(var/obj/O in src) O.loc = loc + if(throwing) //you keep some momentum when getting out of a thrown closet + step(O, dir) for(var/mob/M in src) M.loc = loc if(M.client) M.client.eye = M.client.mob M.client.perspective = MOB_PERSPECTIVE + if(throwing) + step(M, dir) + if(throwing) + throwing = 0 /obj/structure/closet/proc/take_contents() @@ -100,14 +105,13 @@ return 0 if(!can_open()) return 0 - dump_contents() - opened = 1 if(istype(src, /obj/structure/closet/body_bag)) playsound(loc, 'sound/items/zip.ogg', 15, 1, -3) else playsound(loc, 'sound/machines/click.ogg', 15, 1, -3) density = 0 + dump_contents() update_icon() return 1 diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 23be1ce7c31..fe14690944a 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -65,9 +65,9 @@ /obj/structure/mineral_door/proc/TryToSwitchState(atom/user) if(isSwitchingStates) return - if(ismob(user)) - var/mob/M = user - if(world.time - user.last_bumped <= 60) return //NOTE do we really need that? + if(isliving(user)) + var/mob/living/M = user + if(world.time - M.last_bumped <= 60) return //NOTE do we really need that? if(M.client) if(iscarbon(M)) var/mob/living/carbon/C = M diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index d3565376d41..3bd5ef645d2 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -226,7 +226,7 @@ Crematorium Switch layer = 2.9 var/obj/structure/bodycontainer/connected = null anchored = 1.0 - throwpass = 1 + pass_flags = LETPASSTHROW /obj/structure/tray/Destroy() if(connected) @@ -278,3 +278,12 @@ Crematorium Switch desc = "Apply corpse before closing." icon_state = "morguet" +/obj/structure/tray/m_tray/CanPass(atom/movable/mover, turf/target, height=0) + if(height==0) return 1 + + if(istype(mover) && mover.checkpass(PASSTABLE)) + return 1 + if(locate(/obj/structure/table) in get_turf(mover)) + return 1 + else + return 0 diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 1dbf75a2ee8..47eef2e9eb7 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -20,7 +20,7 @@ density = 1 anchored = 1.0 layer = 2.8 - throwpass = 1 //You can throw objects over this, despite it's density.") + pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.") var/frame = /obj/structure/table_frame var/framestack = /obj/item/stack/rods var/buildstack = /obj/item/stack/sheet/metal @@ -364,7 +364,7 @@ icon_state = "rack" density = 1 anchored = 1.0 - throwpass = 1 //You can throw objects over this, despite it's density. + pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density. var/health = 5 /obj/structure/rack/ex_act(severity, target) diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm index 803f29cb1aa..e85375ba5ed 100644 --- a/code/game/objects/weapons.dm +++ b/code/game/objects/weapons.dm @@ -9,8 +9,3 @@ hitsound = 'sound/items/welder.ogg' if(damtype == "brute") hitsound = "swing_hit" - -/obj/item/weapon/Bump(mob/M) - spawn(0) - ..() - return \ No newline at end of file diff --git a/code/game/turfs/simulated/walls_misc.dm b/code/game/turfs/simulated/walls_misc.dm index 4d664e2b4ba..e2a05273664 100644 --- a/code/game/turfs/simulated/walls_misc.dm +++ b/code/game/turfs/simulated/walls_misc.dm @@ -62,4 +62,15 @@ T.color = color if(T.dir != dir) T.dir = dir - return T \ No newline at end of file + T.transform = transform + return T + +/turf/simulated/wall/shuttle/copyTurf(turf/T) + . = ..() + T.transform = transform + +//why don't shuttle walls habe smoothwall? now i gotta do rotation the dirty way +/turf/simulated/wall/shuttle/shuttleRotate(rotation) + var/matrix/M = transform + M.Turn(rotation) + transform = M \ No newline at end of file diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 67aba43dd56..3aa09ecd6b3 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -53,6 +53,7 @@ Summon Magic
Summon Events (Toggle)
There can only be one!
+ There can only be me!
Make all players retarded
Egalitarian Station Mode
Break all lights
@@ -575,6 +576,13 @@ usr.client.only_one() // message_admins("[key_name_admin(usr)] has triggered a battle to the death (only one)") + if("onlyme") + if(!check_rights(R_FUN)) + return + feedback_inc("admin_secrets_fun_used",1) + feedback_add_details("admin_secrets_fun_used","OM") + usr.client.only_me() + if("maint_access_brig") if(!check_rights(R_DEBUG)) return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 515ad7838a0..d7497060491 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -398,7 +398,7 @@ var/list/TYPES_SHORTCUTS = list( /obj/item/weapon/reagent_containers = "REAGENT_CONTAINERS", /obj/machinery/atmospherics = "ATMOS", /obj/machinery/portable_atmospherics = "PORT_ATMOS", - /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK", + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack = "MECHA_MISSILE_RACK", /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP", ) diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm index 986ca51c31b..454869acf20 100644 --- a/code/modules/admin/verbs/onlyone.dm +++ b/code/modules/admin/verbs/onlyone.dm @@ -47,4 +47,47 @@ H.equip_to_slot_or_del(W, slot_wear_id) message_admins("[key_name_admin(usr)] used THERE CAN BE ONLY ONE!") - log_admin("[key_name(usr)] used there can be only one.") \ No newline at end of file + log_admin("[key_name(usr)] used there can be only one.") + + +/client/proc/only_me() + if(!ticker) + alert("The game hasn't started yet!") + return + + for(var/mob/living/carbon/human/H in player_list) + if(H.stat == 2 || !(H.client)) continue + if(is_special_character(H)) continue + + ticker.mode.traitors += H.mind + H.mind.special_role = "[H.real_name] Prime" + + var/datum/objective/hijackclone/hijack_objective = new /datum/objective/hijackclone + hijack_objective.owner = H.mind + H.mind.objectives += hijack_objective + + H << "You are the multiverse summoner. Activate your blade to summon copies of yourself from another universe to fight by your side." + var/obj_count = 1 + for(var/datum/objective/OBJ in H.mind.objectives) + H << "Objective #[obj_count]: [OBJ.explanation_text]" + obj_count++ + + var/obj/item/slot_item_ID = H.get_item_by_slot(slot_wear_id) + qdel(slot_item_ID) + var/obj/item/slot_item_hand = H.get_item_by_slot(slot_r_hand) + H.unEquip(slot_item_hand) + + var /obj/item/weapon/multisword/multi = new(H) + H.equip_to_slot_or_del(multi, slot_r_hand) + + var/obj/item/weapon/card/id/W = new(H) + W.icon_state = "centcom" + W.access = get_all_accesses() + W.access += get_all_centcom_access() + W.assignment = "Multiverse Summoner" + W.registered_name = H.real_name + W.update_label(H.real_name) + H.equip_to_slot_or_del(W, slot_wear_id) + + message_admins("[key_name_admin(usr)] used THERE CAN BE ONLY ME!") + log_admin("[key_name(usr)] used there can be only me.") diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 4b6c9ff0881..89e24aa3672 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -21,7 +21,9 @@ return icon_state = "off" - +//prevents shuttles attempting to rotate this since it messes up sprites +/obj/machinery/gateway/shuttleRotate() + return //this is da important part wot makes things go /obj/machinery/gateway/centerstation diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 95abba54f1c..2d2ca4ff400 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -92,16 +92,23 @@ /obj/item/clothing/head/helmet/swat name = "\improper SWAT helmet" - desc = "An extremely robust, space-worthy helmet with the Nanotrasen logo emblazoned on the top." - icon_state = "swat" - item_state = "swat" + desc = "An extremely robust, space-worthy helmet in a nefarious red and black stripe pattern." + icon_state = "swatsyndie" + item_state = "swatsyndie" armor = list(melee = 40, bullet = 30, laser = 25,energy = 25, bomb = 50, bio = 10, rad = 0) cold_protection = HEAD min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT heat_protection = HEAD max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT + flags = STOPSPRESSUREDMAGE strip_delay = 80 +/obj/item/clothing/head/helmet/swat/nanotrasen + name = "\improper SWAT helmet" + desc = "An extremely robust, space-worthy helmet with the Nanotrasen logo emblazoned on the top." + icon_state = "swat" + item_state = "swat" + /obj/item/clothing/head/helmet/thunderdome name = "\improper Thunderdome helmet" desc = "'Let the battle commence!'" diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index 0ed20624539..7d2d81b6fa9 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -68,7 +68,7 @@ name = "head of security cap" desc = "The robust standard-issue cap of the Head of Security. For showing the officers who's in charge." icon_state = "hoscap" - armor = list(melee = 65, bullet = 40, laser = 50, energy = 10, bomb = 25, bio = 10, rad = 0) + armor = list(melee = 40, bullet = 30, laser = 25, energy = 10, bomb = 25, bio = 10, rad = 0) strip_delay = 80 /obj/item/clothing/head/HoS/beret diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 37d3b578fbb..58101dca40a 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -36,7 +36,7 @@ desc = "High speed, no drag combat boots." permeability_coefficient = 0.01 flags = NOSLIP - armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100) + armor = list(melee = 40, bullet = 30, laser = 25, energy = 25, bomb = 50, bio = 30, rad = 30) /obj/item/clothing/shoes/sandal desc = "A pair of rather plain, wooden sandals." diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index 4ac4a2cd0ef..2f7f85299e6 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -25,7 +25,7 @@ desc = "That's not red paint. That's real blood." icon_state = "deathsquad" item_state = "deathsquad" - armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100) + armor = list(melee = 50, bullet = 40, laser = 30, energy = 50, bomb = 50, bio = 100, rad = 100) strip_delay = 130 max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT unacidable = 1 @@ -40,7 +40,7 @@ icon_state = "deathsquad" item_state = "swat_suit" allowed = list(/obj/item/weapon/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/tank/internals) - armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100) + armor = list(melee = 50, bullet = 40, laser = 30,energy = 50, bomb = 50, bio = 100, rad = 100) slowdown = 1 strip_delay = 130 max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT @@ -53,7 +53,7 @@ icon_state = "beret_badge" flags = STOPSPRESSUREDMAGE flags_inv = 0 - armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100) + armor = list(melee = 50, bullet = 40, laser = 30, energy = 50, bomb = 50, bio = 100, rad = 100) strip_delay = 130 max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT unacidable = 1 @@ -68,7 +68,7 @@ flags_inv = 0 w_class = 3 allowed = list(/obj/item/weapon/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/tank/internals) - armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100) + armor = list(melee = 50, bullet = 40, laser = 30,energy = 50, bomb = 50, bio = 100, rad = 100) slowdown = 1 strip_delay = 130 max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT @@ -154,7 +154,7 @@ item_state = "ert_command" helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert allowed = list(/obj/item/weapon/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/tank/internals) - armor = list(melee = 65, bullet = 50, laser = 50, energy = 50, bomb = 50, bio = 100, rad = 100) + armor = list(melee = 30, bullet = 50, laser = 30, energy = 50, bomb = 50, bio = 100, rad = 100) slowdown = 0 strip_delay = 130 diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 826ba6a51c3..d8dc137f797 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -23,7 +23,7 @@ icon_state = "hos" item_state = "greatcoat" body_parts_covered = CHEST|GROIN|ARMS|LEGS - armor = list(melee = 55, bullet = 40, laser = 50, energy = 10, bomb = 25, bio = 10, rad = 0) + armor = list(melee = 30, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0) flags_inv = HIDEJUMPSUIT cold_protection = CHEST|GROIN|LEGS|ARMS heat_protection = CHEST|GROIN|LEGS|ARMS diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index 10ca2b4b64e..eb47c8581a9 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -43,9 +43,9 @@ priority_announce("Massive bluespace translocation detected.", "Anomaly Alert") var/list/flashers = list() - for(var/mob/living/carbon/human/M in viewers(TO, null)) - if(M.flash_eyes()) - flashers += M + for(var/mob/living/carbon/C in viewers(TO, null)) + if(C.flash_eyes()) + flashers += C var/y_distance = TO.y - FROM.y var/x_distance = TO.x - FROM.x diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index c819175a48e..8ad8c75980a 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -171,47 +171,6 @@ Gunshots/explosions/opening doors/less rare audio (done) name = "alien hunter ([rand(1, 1000)])" return -/obj/effect/hallucination/simple/xeno/throw_at(atom/target, range, speed) // TODO : Make diagonal trhow into proc/property - if(!target || !src || (flags & NODROP)) return 0 - - src.throwing = 1 - - var/dist_x = abs(target.x - src.x) - var/dist_y = abs(target.y - src.y) - var/dist_travelled = 0 - var/dist_since_sleep = 0 - - var/tdist_x = dist_x; - var/tdist_y = dist_y; - - if(dist_x <= dist_y) - tdist_x = dist_y; - tdist_y = dist_x; - - var/error = tdist_x/2 - tdist_y - while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src))) - - if(!src.throwing) break - if(!istype(src.loc, /turf)) break - - var/atom/step = get_step(src, get_dir(src,target)) - if(!step) - break - src.Move(step, get_dir(src, step)) - hit_check() - error += (error < 0) ? tdist_x : -tdist_y; - dist_travelled++ - dist_since_sleep++ - if(dist_since_sleep >= speed) - dist_since_sleep = 0 - sleep(1) - - - src.throwing = 0 - src.throw_impact(get_turf(src)) - - return 1 - /obj/effect/hallucination/simple/xeno/throw_impact(A) update_icon("alienh_pounce") if(A == target) @@ -232,10 +191,10 @@ Gunshots/explosions/opening doors/less rare audio (done) xeno = new(pump.loc,target) sleep(10) xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32) - xeno.throw_at(target,7,1) + xeno.throw_at(target,7,1, spin = 0, diagonals_first = 1) sleep(10) xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32) - xeno.throw_at(pump,7,1) + xeno.throw_at(pump,7,1, spin = 0, diagonals_first = 1) sleep(10) var/xeno_name = xeno.name target << "[xeno_name] begins climbing into the ventilation system..." diff --git a/code/modules/food&drinks/food/snacks_egg.dm b/code/modules/food&drinks/food/snacks_egg.dm index 6a17202d6f0..473ad4ebde5 100644 --- a/code/modules/food&drinks/food/snacks_egg.dm +++ b/code/modules/food&drinks/food/snacks_egg.dm @@ -18,10 +18,11 @@ filling_color = "#F0E68C" /obj/item/weapon/reagent_containers/food/snacks/egg/throw_impact(atom/hit_atom) - ..() - new/obj/effect/decal/cleanable/egg_smudge(src.loc) - reagents.reaction(hit_atom, TOUCH) - del(src) // Not qdel, because it'll hit other mobs then the floor for runtimes. + if(!..()) //was it caught by a mob? + var/turf/T = get_turf(hit_atom) + new/obj/effect/decal/cleanable/egg_smudge(T) + reagents.reaction(hit_atom, TOUCH) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/egg/attackby(obj/item/weapon/W, mob/user, params) if(istype( W, /obj/item/toy/crayon )) diff --git a/code/modules/food&drinks/food/snacks_pie.dm b/code/modules/food&drinks/food/snacks_pie.dm index e4fe6700f67..6a9be926630 100644 --- a/code/modules/food&drinks/food/snacks_pie.dm +++ b/code/modules/food&drinks/food/snacks_pie.dm @@ -23,10 +23,11 @@ list_reagents = list("nutriment" = 6, "banana" = 5, "vitamin" = 2) /obj/item/weapon/reagent_containers/food/snacks/pie/cream/throw_impact(atom/hit_atom) - ..() - new/obj/effect/decal/cleanable/pie_smudge(src.loc) - reagents.reaction(hit_atom, TOUCH) - del(src) // Not qdel, because it'll hit other mobs then the floor for runtimes. + if(!..()) //was it caught by a mob? + var/turf/T = get_turf(hit_atom) + new/obj/effect/decal/cleanable/pie_smudge(T) + reagents.reaction(hit_atom, TOUCH) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/pie/berryclafoutis diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 6c11a41934e..f27866be2d2 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -806,17 +806,16 @@ obj/item/weapon/reagent_containers/food/snacks/grown/shell/eggy/add_juice() bitesize = 1 + round(reagents.total_volume / 2, 1) /obj/item/weapon/reagent_containers/food/snacks/grown/tomato/proc/squish(atom/target) - new splat(src.loc) - src.visible_message("The [src.name] has been squashed.","You hear a smack.") + var/turf/T = get_turf(target) + new splat(T) + visible_message("The [src.name] has been squashed.","You hear a smack.") for(var/atom/A in get_turf(target)) - src.reagents.reaction(A) + reagents.reaction(A) /obj/item/weapon/reagent_containers/food/snacks/grown/tomato/throw_impact(atom/hit_atom) - ..() - squish(hit_atom) - del(src) // Not qdel, because it'll hit other mobs then the floor for runtimes. - return - + if(!..()) //was it caught by a mob? + squish(hit_atom) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/grown/tomato/killer seed = /obj/item/seeds/killertomatoseed @@ -906,7 +905,8 @@ obj/item/weapon/reagent_containers/food/snacks/grown/shell/eggy/add_juice() ..() var/teleport_radius = potency / 10 if(isliving(squishee)) - new /obj/effect/decal/cleanable/molten_item(squishee.loc) //Leave a pile of goo behind for dramatic effect... + var/turf/T = get_turf(squishee) + new /obj/effect/decal/cleanable/molten_item(T) //Leave a pile of goo behind for dramatic effect... do_teleport(squishee, get_turf(squishee), teleport_radius) diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 6e67f71e3ba..01e6c9b3094 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -487,7 +487,7 @@ var/global/list/rockTurfEdgeCache return /* else if(istype(AM,/obj/mecha)) var/obj/mecha/M = AM - if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/tool/drill)) + if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/drill)) src.attackby(M.selected,M) return*/ //Aparantly mechs are just TOO COOL to call Bump(), so fuck em (for now) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index fa0f58d7f07..7f1e5337575 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -1,5 +1,5 @@ /mob/living/carbon/alien/hitby(atom/movable/AM) - ..(AM, 1) + ..(AM, skip = 1) /*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other. diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm index 68fda08c934..dd900163da0 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm @@ -82,11 +82,11 @@ else //Maybe uses plasma in the future, although that wouldn't make any sense... leaping = 1 update_icons() - throw_at(A,MAX_ALIEN_LEAP_DIST,1) + throw_at(A,MAX_ALIEN_LEAP_DIST,1, spin=0, diagonals_first = 1) leaping = 0 update_icons() -/mob/living/carbon/alien/humanoid/hunter/throw_impact(A) +/mob/living/carbon/alien/humanoid/hunter/throw_impact(atom/A) if(!leaping) return ..() @@ -103,60 +103,19 @@ pounce_cooldown = !pounce_cooldown spawn(pounce_cooldown_time) //3s by default pounce_cooldown = !pounce_cooldown - else + else if(A.density && !A.CanPass(src)) visible_message("[src] smashes into [A]!", "[src] smashes into [A]!") weakened = 2 if(leaping) leaping = 0 + update_icons() update_canmove() - /mob/living/carbon/alien/humanoid/float(on) if(leaping) return ..() -//Modified throw_at() that will use diagonal dirs where appropriate -//instead of locking it to cardinal dirs -/mob/living/carbon/alien/humanoid/throw_at(atom/target, range, speed) - if(!target || !src || (flags & NODROP)) return 0 - - src.throwing = 1 - - var/dist_x = abs(target.x - src.x) - var/dist_y = abs(target.y - src.y) - var/dist_travelled = 0 - var/dist_since_sleep = 0 - - var/tdist_x = dist_x; - var/tdist_y = dist_y; - - if(dist_x <= dist_y) - tdist_x = dist_y; - tdist_y = dist_x; - - var/error = tdist_x/2 - tdist_y - while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src))) - - if(!src.throwing) break - if(!istype(src.loc, /turf)) break - - var/atom/step = get_step(src, get_dir(src,target)) - if(!step) - break - src.Move(step, get_dir(src, step)) - hit_check() - error += (error < 0) ? tdist_x : -tdist_y; - dist_travelled++ - dist_since_sleep++ - if(dist_since_sleep >= speed) - dist_since_sleep = 0 - sleep(1) - - - src.throwing = 0 - - return 1 diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index 57db5c8890b..0f742d02a10 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -72,7 +72,10 @@ var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds else affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand") spawn(6) - var/mob/living/carbon/alien/larva/new_xeno = new(affected_mob.loc) + var/location = get_turf(affected_mob) + if(!location) + location = affected_mob.loc + var/mob/living/carbon/alien/larva/new_xeno = new(location) new_xeno.key = C.key new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention if(gib_on_success) diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm index fff5bebcdeb..eb8dc6e9c65 100644 --- a/code/modules/mob/living/carbon/brain/life.dm +++ b/code/modules/mob/living/carbon/brain/life.dm @@ -147,4 +147,5 @@ /mob/living/carbon/brain/handle_regular_hud_updates() handle_vision() handle_hud_icons_health() + update_action_buttons() return 1 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 99b7a1af49d..b2132b36d51 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -153,7 +153,7 @@ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) -/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0) +/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) var/damage = intensity - check_eye_prot() if(..()) // we've been flashed if(weakeyes) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 7ef10003c95..9b705841a82 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -8,8 +8,8 @@ put_in_active_hand(I) visible_message("[src] catches [I]!") throw_mode_off() - return - ..() + return 1 + return ..() /mob/living/carbon/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 72a5d682d0c..01787095f8b 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -455,4 +455,18 @@ emp_act else ..() - return +/mob/living/carbon/human/hitby(atom/movable/AM) + if(throw_speed >= EMBED_THROWSPEED_THRESHOLD) + if(istype(AM, /obj/item)) + var/obj/item/I = AM + if(can_embed(I)) + if(prob(I.embed_chance) && !(dna && (PIERCEIMMUNE in dna.species.specflags))) + throw_alert("embeddedobject") + var/obj/item/organ/limb/L = pick(organs) + L.embedded_objects |= I + I.add_blood(src)//it embedded itself in you, of course it's bloody! + I.loc = src + L.take_damage(I.w_class*I.embedded_impact_pain_multiplier) + visible_message("\the [I.name] embeds itself in [src]'s [L.getDisplayName()]!","\the [I.name] embeds itself in your [L.getDisplayName()]!") + return + return ..() diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index b0078a13719..664933c175b 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -45,7 +45,7 @@ return shoes && shoes.negates_gravity() /mob/living/carbon/human/Move(NewLoc, direct) - ..() + . = ..() if(dna) for(var/datum/mutation/human/HM in dna.mutations) HM.on_move(src, NewLoc) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b137657b148..bbcdc72c6aa 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -52,13 +52,14 @@ Sorry Giacom. Please don't be mad :( //Generic Bump(). Override MobBump() and ObjBump() instead of this. /mob/living/Bump(atom/A, yes) + if(..()) //we are thrown onto something + return if (buckled || !yes || now_pushing) return if(ismob(A)) var/mob/M = A if(MobBump(M)) return - ..() if(isobj(A)) var/obj/O = A if(ObjBump(O)) @@ -68,6 +69,10 @@ Sorry Giacom. Please don't be mad :( if(PushAM(AM)) return +/mob/living/Bumped(atom/movable/AM) + ..() + last_bumped = world.time + //Called when we bump onto a mob /mob/living/proc/MobBump(mob/M) //Even if we don't push/swap places, we "touched" them, so spread fire @@ -376,7 +381,7 @@ Sorry Giacom. Please don't be mad :( return 0 -/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0) +/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1.0, safety = 0) return 0 //only carbon liveforms have this proc /mob/living/emp_act(severity) @@ -687,7 +692,7 @@ Sorry Giacom. Please don't be mad :( floating = 0 //called when the mob receives a bright flash -/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0) +/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) if(check_eye_prot() < intensity && (override_blindness_check || !(disabilities & BLIND))) flick("e_flash", flash) return 1 diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c620bda6767..43e2c2735bf 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -44,7 +44,13 @@ else return 0 -/mob/living/hitby(atom/movable/AM,mob/thrower)//Standardization and logging -Sieve +/mob/living/throw_impact(atom/hit_atom) + . = ..() + if(hit_atom.density) + Weaken(1) + take_organ_damage(10) + +/mob/living/hitby(atom/movable/AM) if(istype(AM, /obj/item)) var/obj/item/I = AM var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest @@ -71,9 +77,11 @@ "[src] has been hit by [I].") var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration) apply_damage(I.throwforce, dtype, zone, armor, I) - - if(thrower) - add_logs(thrower, src, "hit", I) + if(I.thrownby) + add_logs(I.thrownby, src, "hit", I) + else + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return ..() /mob/living/mech_melee_attack(obj/mecha/M) if(M.occupant.a_intent == "harm") diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 096da4e0b0d..56c0426c5bc 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -47,4 +47,6 @@ var/smoke_delay = 0 //used to prevent spam with smoke reagent reaction on mob. - var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message" \ No newline at end of file + var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message" + + var/last_bumped = 0 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index cac929c3681..3f601c0810f 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -823,3 +823,6 @@ var/list/ai_list = list() loc = card//Throw AI into the card. src << "You have been downloaded to a mobile storage device. Remote device connection severed." user << "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." + +/mob/living/silicon/ai/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) + return // no eyes, no flashing \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index cf6548b0e05..840f19ef3bb 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -10,10 +10,12 @@ src.reset_view(null) src.unset_machine() - src.updatehealth() + updatehealth() update_gravity(mob_has_gravity()) + update_action_buttons() + if (src.malfhack) if (src.malfhack.aidisabled) src << "ERROR: APC access disabled, hack attempt canceled." diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index 53e979b4031..0f40c5d5817 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -27,6 +27,7 @@ update_canmove() if(camera) camera.status = 0 + update_headlamp(1) //So borg lights are disabled when killed. uneq_all() // particularly to ensure sight modes are cleared diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 70a5daa21ee..66be85855e8 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -15,11 +15,6 @@ if(istype(O,/obj/item/borg/sight)) var/obj/item/borg/sight/S = O sight_mode &= ~S.sight_mode - else if(istype(O, /obj/item/device/flashlight)) - var/obj/item/device/flashlight/F = O - if(F.on) - F.on = 0 - F.update_brightness(src) else if(istype(O, /obj/item/weapon/storage/bag/tray/)) var/obj/item/weapon/storage/bag/tray/T = O T.do_quick_empty() diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 7ce41a2de6a..bb3a9dce86a 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -25,10 +25,12 @@ if(cell && cell.charge) if(cell.charge <= 100) uneq_all() - cell.use(1) + var/amt = Clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell. + cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick else uneq_all() stat = UNCONSCIOUS + update_headlamp(1) /mob/living/silicon/robot/handle_regular_status_updates() @@ -59,6 +61,7 @@ if (paralysis || stunned || weakened) //Stunned etc. stat = UNCONSCIOUS + update_headlamp() return 1 diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 11ebe6edb27..0fca94e2b05 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -15,6 +15,7 @@ var/obj/screen/inv1 = null var/obj/screen/inv2 = null var/obj/screen/inv3 = null + var/obj/screen/lamp_button = null var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not var/obj/screen/robot_modules_background @@ -60,6 +61,8 @@ var/tonermax = 40 var/jetpackoverlay = 0 var/braintype = "Cyborg" + var/lamp_max = 10 //Maximum brightness of a borg lamp. Set as a var for easy adjusting. + var/lamp_intensity = 0 //Luminosity of the headlamp. 0 is off. Higher settings than the minimum require power. /mob/living/silicon/robot/New(loc) spark_system = new /datum/effect/effect/system/spark_spread() @@ -221,6 +224,7 @@ transform_animation(animation_length) notify_ai(2) update_icons() + update_headlamp() SetEmagged(emagged) // Update emag status and give/take emag modules. /mob/living/silicon/robot/proc/transform_animation(animation_length) @@ -720,12 +724,17 @@ /mob/living/silicon/robot/update_icons() overlays.Cut() - if(stat == CONSCIOUS) + if(stat != DEAD && !(paralysis || stunned || weakened)) //Not dead, not stunned. + var/state_name = icon_state //For easy conversion and/or different names switch(icon_state) if("robot") overlays += "eyes-standard" + state_name = "standard" + if("mediborg") + overlays += "eyes-mediborg" if("toiletbot") - overlays += "eyes-toiletbot" + overlays += "eyes-mediborg" + state_name = "mediborg" if("secborg") overlays += "eyes-secborg" if("engiborg") @@ -738,6 +747,9 @@ overlays += "eyes-syndie_bloodhound" else overlays += "eyes" + state_name = "serviceborg" + if(lamp_intensity > 2) + overlays += "eyes-[state_name]-lights" if(opened) if(wiresexposed) @@ -751,8 +763,6 @@ overlays += "minerjetpack" update_fire() - - /mob/living/silicon/robot/proc/installed_modules() if(!module) pick_module() @@ -978,6 +988,32 @@ set category = "Robot Commands" set_autosay() +/mob/living/silicon/robot/proc/control_headlamp() + if(stat) + src << "This function is currently offline." + return + +//Some sort of magical "modulo" thing which somehow increments lamp power by 2, until it hits the max and resets to 0. + lamp_intensity = (lamp_intensity+2) % (lamp_max+2) + src << "[lamp_intensity ? "Headlamp power set to Level [lamp_intensity/2]" : "Headlamp disabled."]" + update_headlamp() + +/mob/living/silicon/robot/proc/update_headlamp(var/turn_off = 0) + SetLuminosity(0) + + if(lamp_intensity && (turn_off || stat)) + src << "Your headlamp has been deactivated." + lamp_intensity = 0 + else + AddLuminosity(lamp_intensity) + + if(lamp_button) + lamp_button.icon_state = "lamp[lamp_intensity]" + + update_icons() + + + /mob/living/silicon/robot/proc/deconstruct() var/turf/T = get_turf(src) if (robot_suit) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 7bbcd4ad3b2..3cd0e9781c6 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -66,7 +66,6 @@ /obj/item/weapon/robot_module/standard/New() ..() - modules += new /obj/item/device/flashlight(src) modules += new /obj/item/weapon/melee/baton/loaded(src) modules += new /obj/item/weapon/extinguisher(src) modules += new /obj/item/weapon/wrench(src) @@ -81,7 +80,6 @@ /obj/item/weapon/robot_module/medical/New() ..() - modules += new /obj/item/device/flashlight(src) modules += new /obj/item/device/healthanalyzer(src) modules += new /obj/item/weapon/reagent_containers/borghypo(src) modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) @@ -119,7 +117,6 @@ /obj/item/weapon/robot_module/engineering/New() ..() - modules += new /obj/item/device/flashlight(src) modules += new /obj/item/borg/sight/meson(src) emag = new /obj/item/borg/stun(src) modules += new /obj/item/weapon/rcd/borg(src) @@ -173,7 +170,6 @@ /obj/item/weapon/robot_module/security/New() ..() - modules += new /obj/item/device/flashlight/seclite(src) modules += new /obj/item/weapon/restraints/handcuffs/cable/zipties/cyborg(src) modules += new /obj/item/weapon/melee/baton/loaded(src) modules += new /obj/item/weapon/gun/energy/disabler/cyborg(src) @@ -187,7 +183,6 @@ /obj/item/weapon/robot_module/janitor/New() ..() - modules += new /obj/item/device/flashlight(src) modules += new /obj/item/weapon/soap/nanotrasen(src) modules += new /obj/item/weapon/storage/bag/trash/cyborg(src) modules += new /obj/item/weapon/mop/cyborg(src) @@ -205,7 +200,6 @@ /obj/item/weapon/robot_module/butler/New() ..() - modules += new /obj/item/device/flashlight(src) modules += new /obj/item/weapon/reagent_containers/food/drinks/drinkingglass(src) modules += new /obj/item/weapon/reagent_containers/food/condiment/enzyme(src) modules += new /obj/item/weapon/pen(src) @@ -239,7 +233,6 @@ modules += new /obj/item/weapon/storage/bag/ore/cyborg(src) modules += new /obj/item/weapon/pickaxe/drill/cyborg(src) modules += new /obj/item/weapon/shovel(src) - modules += new /obj/item/device/flashlight/lantern(src) modules += new /obj/item/weapon/storage/bag/sheetsnatcher/borg(src) modules += new /obj/item/device/t_scanner/adv_mining_scanner(src) modules += new /obj/item/weapon/gun/energy/kinetic_accelerator(src) @@ -251,7 +244,6 @@ /obj/item/weapon/robot_module/syndicate/New() ..() - modules += new /obj/item/device/flashlight(src) modules += new /obj/item/weapon/melee/energy/sword/cyborg(src) modules += new /obj/item/weapon/gun/energy/printer(src) modules += new /obj/item/weapon/gun/projectile/revolver/grenadelauncher/cyborg(src) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index c3ec3215993..92749a073a2 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -422,12 +422,13 @@ /mob/living/silicon/setEarDamage() return -/mob/living/silicon/check_eye_prot() - return 2 - /mob/living/silicon/proc/GetPhoto() if (aicamera) return aicamera.selectpicture(aicamera) /mob/living/silicon/grabbedby(mob/living/user) - return \ No newline at end of file + return + +/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) + if(affect_silicon) + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index af1520d2d42..4b349ee1ddb 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -173,8 +173,9 @@ if(cleared) src << "--- [class] alarm in [A.name] has been cleared." -/mob/living/simple_animal/drone/check_eye_prot() - return 2 - /mob/living/simple_animal/drone/handle_temperature_damage() return + +/mob/living/simple_animal/drone/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) + if(affect_silicon) + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm index cff95221196..58fe29515b3 100644 --- a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm +++ b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm @@ -11,6 +11,7 @@ response_harm = "punches" icon = 'icons/mob/mob.dmi' icon_state = "daemon" + icon_living = "daemon" speed = 0 a_intent = "harm" stop_automated_movement = 1 @@ -76,7 +77,7 @@ src.phased = TRUE src.holder = holder if(src.kidnapped) - src << "You being to feast on [kidnapped]. You can not move while you are doing this." + src << "You begin to feast on [kidnapped]. You can not move while you are doing this." src.eating = TRUE playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1) sleep(30) diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm index de8db9663ea..d0b506f1a12 100644 --- a/code/modules/mob/living/ventcrawling.dm +++ b/code/modules/mob/living/ventcrawling.dm @@ -34,7 +34,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/components/unary if(vent_found) - var/datum/pipeline/vent_found_parent = vent_found.parents["p1"] + var/datum/pipeline/vent_found_parent = vent_found.parents[PARENT1] if(vent_found_parent && (vent_found_parent.members.len || vent_found_parent.other_atmosmch)) visible_message("[src] begins climbing into the ventilation system..." ,"You begin climbing into the ventilation system...") @@ -63,21 +63,21 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/components/unary src << "This ventilation duct is not connected to anything!" -/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/components/starting_machine) +/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/components/unary/starting_machine) if(!istype(starting_machine) || !starting_machine.returnPipenet()) return var/list/totalMembers = list() - var/datum/pipeline/starting_machine_parent = starting_machine.parents["p1"] - totalMembers |= starting_machine_parent.members - totalMembers |= starting_machine_parent.other_atmosmch + var/datum/pipeline/starting_machine_parent = starting_machine.parents[PARENT1] + totalMembers += starting_machine_parent.members + totalMembers += starting_machine_parent.other_atmosmch for(var/obj/machinery/atmospherics/A in totalMembers) if(!A.pipe_vision_img) A.pipe_vision_img = image(A, A.loc, layer = 20, dir = A.dir) //20 for being above darkness - pipes_shown |= A.pipe_vision_img + pipes_shown += A.pipe_vision_img if(client) - client.images |= A.pipe_vision_img + client.images += A.pipe_vision_img /mob/living/proc/remove_ventcrawl() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 6e9e8ccd996..b76f3056cc0 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -963,4 +963,8 @@ var/list/slot_equipment_priority = list( \ spell.action.background_icon_state = spell.action_background_icon_state if(isliving(src)) spell.action.Grant(src) - return \ No newline at end of file + return + +//override to avoid rotating pixel_xy on mobs +/mob/shuttleRotate(rotation) + dir = angle2dir(rotation+dir2angle(dir)) \ No newline at end of file diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index c5f8a272d8b..d65438f65e7 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -1,18 +1,16 @@ /mob/CanPass(atom/movable/mover, turf/target, height=0) - if(height==0) return 1 - - if(istype(mover) && mover.checkpass(PASSMOB)) + if(height==0) return 1 - if(istype(mover, /obj/item/projectile)) + if(istype(mover, /obj/item/projectile) || mover.throwing) return (!density || lying) + if(mover.checkpass(PASSMOB)) + return 1 if(ismob(mover)) var/mob/moving_mob = mover if ((other_mobs && moving_mob.other_mobs)) return 1 - return (!mover.density || !density || lying) - else - return (!mover.density || !density || lying) - return + return (!mover.density || !density || lying) + /client/Northeast() diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 5c63a5cc097..be09fdadd38 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -36,6 +36,10 @@ var/const/GRAV_NEEDS_WRENCH = 3 ..() icon_state = "[get_status()]_[sprite_number]" +//prevents shuttles attempting to rotate this since it messes up sprites +/obj/machinery/gravity_generator/shuttleRotate() + return + /obj/machinery/gravity_generator/proc/get_status() return "off" diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index fb0a69a9be2..08278a00ea7 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -43,7 +43,7 @@ /obj/machinery/field/containment/Crossed(obj/mover) if(istype(mover, /obj/machinery) || istype(mover, /obj/structure) || istype(mover, /obj/mecha)) - bump(mover) + bump_field(mover) /obj/machinery/field/containment/proc/set_master(master1,master2) if(!master1 || !master2) @@ -77,7 +77,7 @@ if((istype(mover, /obj/machinery) && !istype(mover, /obj/singularity)) || \ istype(mover, /obj/structure) || \ istype(mover, /obj/mecha)) - bump(mover) + bump_field(mover) return 0 return ..() @@ -106,13 +106,13 @@ "You hear an electrical crack.") user.updatehealth() - bump(user) + bump_field(user) spawn(5) hasShocked = 0 return -/obj/machinery/field/proc/bump(atom/movable/AM as mob|obj) +/obj/machinery/field/proc/bump_field(atom/movable/AM as mob|obj) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, AM.loc) s.start() diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index 9c9f3c0f948..550567bca53 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -356,6 +356,6 @@ field_generator power level display if(fields.len) ..() -/obj/machinery/field/generator/bump(atom/movable/AM as mob|obj) +/obj/machinery/field/generator/bump_field(atom/movable/AM as mob|obj) if(fields.len) ..() diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 43eaa1a7235..ce2e87d82da 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -26,7 +26,7 @@ var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/last_warning var/consumedSupermatter = 0 //If the singularity has eaten a supermatter shard and can go to stage six - allow_spin = 0 + /obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0) //CARN: admin-alert for chuckle-fuckery. admin_investigate_setup() diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index bf3a16b8060..26b4bc77e99 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -1,7 +1,7 @@ /obj/item/ammo_casing/a357 desc = "A .357 bullet casing." caliber = "357" - projectile_type = /obj/item/projectile/bullet/revolver + projectile_type = /obj/item/projectile/bullet /obj/item/ammo_casing/a50 desc = "A .50AE bullet casing." @@ -174,12 +174,11 @@ /obj/item/ammo_casing/shotgun/dart/bioterror/New() ..() - reagents.add_reagent("neurotoxin", 5) - reagents.add_reagent("morphine", 5) - reagents.add_reagent("spore", 5) - reagents.add_reagent("mutetoxin", 5) //;HELP OPS IN MAINT - reagents.add_reagent("initropidril", 5) - reagents.add_reagent("sodium_thiopental", 5) + reagents.add_reagent("neurotoxin", 6) + reagents.add_reagent("spore", 6) + reagents.add_reagent("mutetoxin", 6) //;HELP OPS IN MAINT + reagents.add_reagent("coniine", 6) + reagents.add_reagent("sodium_thiopental", 6) /obj/item/ammo_casing/a762 desc = "A 7.62mm bullet casing." diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm index ae4f0f5c7b4..0a89745dfcf 100644 --- a/code/modules/projectiles/ammunition/energy.dm +++ b/code/modules/projectiles/ammunition/energy.dm @@ -5,7 +5,6 @@ projectile_type = /obj/item/projectile/energy var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot. var/select_name = "energy" - var/mod_name = null fire_sound = 'sound/weapons/Laser.ogg' /obj/item/ammo_casing/energy/laser @@ -87,13 +86,11 @@ /obj/item/ammo_casing/energy/flora/yield projectile_type = /obj/item/projectile/energy/florayield - select_name = "increase yield" - mod_name = "yield" + select_name = "yield" /obj/item/ammo_casing/energy/flora/mut projectile_type = /obj/item/projectile/energy/floramut - select_name = "induce mutations" - mod_name = "mut" + select_name = "mutation" /obj/item/ammo_casing/energy/temp projectile_type = /obj/item/projectile/temp diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index e692bd7bb97..b7c64faa7a7 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -49,6 +49,11 @@ var/list/upgrades = list() + var/ammo_x_offset = 0 //used for positioning ammo count overlay on sprite + var/ammo_y_offset = 0 + var/flight_x_offset = 0 + var/flight_y_offset = 0 + /obj/item/weapon/gun/New() ..() if(pin) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 15115001e06..e1a143f2f5d 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -10,6 +10,7 @@ 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? + ammo_x_offset = 2 /obj/item/weapon/gun/energy/emp_act(severity) power_supply.use(round(power_supply.charge / severity)) @@ -72,25 +73,31 @@ return /obj/item/weapon/gun/energy/update_icon() - var/ratio = power_supply.charge / power_supply.maxcharge - ratio = min(Ceiling(ratio*4) * 25, 100) - var/obj/item/ammo_casing/energy/shot = ammo_type[select] - if(power_supply.charge < shot.e_cost) - ratio = 0 //so the icon changes to empty if the charge isn't zero but not enough for a shot. - switch(modifystate) - if (0) - icon_state = "[initial(icon_state)][ratio]" - if (1) - icon_state = "[initial(icon_state)][shot.mod_name][ratio]" - if (2) - icon_state = "[initial(icon_state)][shot.select_name][ratio]" overlays.Cut() + var/ratio = Ceiling((power_supply.charge / power_supply.maxcharge) * 4) + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + var/iconState = "[icon_state]_charge" + var/itemState = null + if(!initial(item_state)) + itemState = icon_state + if (modifystate) + overlays += "[icon_state]_[shot.select_name]" + iconState += "_[shot.select_name]" + if(itemState) + itemState += "[shot.select_name]" + if(power_supply.charge < shot.e_cost) + overlays += "[icon_state]_empty" + ratio = 0 + for(var/i = ratio, i >= 1, i--) + overlays += image(icon = icon, icon_state = iconState, pixel_x = ammo_x_offset * (i -1)) if(F) + var/iconF = "flight" if(F.on) - overlays += "flight-[initial(icon_state)]-on" - else - overlays += "flight-[initial(icon_state)]" - return + iconF = "flight_on" + overlays += image(icon = icon, icon_state = iconF, pixel_x = flight_x_offset, pixel_y = flight_y_offset) + if(itemState) + itemState += "[ratio]" + item_state = itemState /obj/item/weapon/gun/energy/ui_action_click() toggle_gunlight() diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index b04057fb82b..a3312bbe75e 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -7,6 +7,7 @@ materials = list(MAT_METAL=2000) origin_tech = "combat=3;magnets=2" ammo_type = list(/obj/item/ammo_casing/energy/lasergun) + ammo_x_offset = 1 /obj/item/weapon/gun/energy/laser/practice @@ -20,6 +21,7 @@ name ="retro laser" icon_state = "retro" desc = "An older model of the basic lasergun, no longer used by Nanotrasen's private security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." + ammo_x_offset = 3 /obj/item/weapon/gun/energy/laser/captain @@ -29,6 +31,7 @@ force = 10 origin_tech = null var/charge_tick = 0 + ammo_x_offset = 3 /obj/item/weapon/gun/energy/laser/captain/New() ..() @@ -87,6 +90,7 @@ origin_tech = "combat=4;materials=3;powerstorage=3" ammo_type = list(/obj/item/ammo_casing/energy/laser/heavy) pin = null + ammo_x_offset = 3 /obj/item/weapon/gun/energy/xray name = "xray laser gun" @@ -96,6 +100,7 @@ origin_tech = "combat=5;materials=3;magnets=2;syndicate=2" ammo_type = list(/obj/item/ammo_casing/energy/xray) pin = null + ammo_x_offset = 3 ////////Laser Tag//////////////////// @@ -109,6 +114,7 @@ needs_permit = 0 var/charge_tick = 0 pin = /obj/item/device/firing_pin/tag/blue + ammo_x_offset = 2 /obj/item/weapon/gun/energy/laser/bluetag/New() ..() @@ -140,6 +146,7 @@ needs_permit = 0 var/charge_tick = 0 pin = /obj/item/device/firing_pin/tag/red + ammo_x_offset = 2 /obj/item/weapon/gun/energy/laser/redtag/New() ..() diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index 90e201e2a61..e11357de9a7 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -7,6 +7,9 @@ origin_tech = "combat=3;magnets=2" modifystate = 2 can_flashlight = 1 + ammo_x_offset = 3 + flight_x_offset = 15 + flight_y_offset = 10 /obj/item/weapon/gun/energy/gun/attack_self(mob/living/user) select_fire(user) @@ -15,7 +18,6 @@ /obj/item/weapon/gun/energy/gun/hos desc = "This is a expensive, modern recreation of a antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time." icon_state = "hoslaser" - item_state = null force = 10 ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/disabler) @@ -23,22 +25,36 @@ name = "DRAGnet" desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology." icon_state = "dragnet" - item_state = null origin_tech = "combat=3;magnets=3;materials=4; bluespace=4" ammo_type = list(/obj/item/ammo_casing/energy/net, /obj/item/ammo_casing/energy/trap) can_flashlight = 0 + ammo_x_offset = 1 + +/obj/item/weapon/gun/energy/gun/turret + name = "hybrid turret gun" + desc = "A heavy hybrid energy cannon with two settings: Stun and kill." + icon_state = "turretlaser" + item_state = "turretlaser" + slot_flags = null + w_class = 5 + ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) + heavy_weapon = 1 + can_flashlight = 0 + trigger_guard = 0 + ammo_x_offset = 2 /obj/item/weapon/gun/energy/gun/nuclear name = "advanced energy gun" desc = "An energy gun with an experimental miniaturized nuclear reactor that automatically charges the internal power cell." icon_state = "nucgun" + item_state = "nucgun" origin_tech = "combat=3;materials=5;powerstorage=3" - var/lightfail = 0 + var/fail_state = 0 var/charge_tick = 0 - modifystate = 0 can_flashlight = 0 pin = null can_charge = 0 + ammo_x_offset = 1 /obj/item/weapon/gun/energy/gun/nuclear/New() ..() @@ -63,7 +79,7 @@ /obj/item/weapon/gun/energy/gun/nuclear/proc/failcheck() - lightfail = 0 + fail_state = 0 if (prob(src.reliability)) return 1 //No failure if (prob(src.reliability)) for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it @@ -72,68 +88,22 @@ else M << "You feel a warm sensation." M.irradiate(rand(3,120)) - lightfail = 1 + fail_state = 1 else for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES if (src in M.contents) M << "Your gun's reactor overloads!" M << "You feel a wave of heat wash over you." M.irradiate(300) - crit_fail = 1 //break the gun so it stops recharging + fail_state = 2 //break the gun so it stops recharging SSobj.processing.Remove(src) update_icon() return 0 - -/obj/item/weapon/gun/energy/gun/nuclear/proc/update_charge() - if (crit_fail) - overlays += "nucgun-whee" - return - var/ratio = power_supply.charge / power_supply.maxcharge - ratio = Ceiling(ratio*4) * 25 - overlays += "nucgun-[ratio]" - - -/obj/item/weapon/gun/energy/gun/nuclear/proc/update_reactor() - if(crit_fail) - overlays += "nucgun-crit" - return - if(lightfail) - overlays += "nucgun-medium" - else if ((power_supply.charge/power_supply.maxcharge) <= 0.5) - overlays += "nucgun-light" - else - overlays += "nucgun-clean" - - -/obj/item/weapon/gun/energy/gun/nuclear/proc/update_mode() - if (select == 1) - overlays += "nucgun-stun" - else if (select == 2) - overlays += "nucgun-kill" - - /obj/item/weapon/gun/energy/gun/nuclear/emp_act(severity) ..() reliability -= round(15/severity) - /obj/item/weapon/gun/energy/gun/nuclear/update_icon() - overlays.Cut() - update_charge() - update_reactor() - update_mode() - -/obj/item/weapon/gun/energy/gun/turret - name = "hybrid turret gun" - desc = "A heavy hybrid energy cannon with two settings: Stun and kill." - icon_state = "turretlaser" - slot_flags = null - w_class = 5 - ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) - heavy_weapon = 1 - can_flashlight = 0 - trigger_guard = 0 - -/obj/item/weapon/gun/energy/gun/turret/update_icon() - icon_state = initial(icon_state) \ No newline at end of file + ..() + overlays += "[icon_state]_fail_[fail_state]" diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index 734b408bfba..18706908c93 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -28,6 +28,8 @@ item_state = "pulse" cell_type = "/obj/item/weapon/stock_parts/cell/pulse/carbine" can_flashlight = 1 + flight_x_offset = 18 + flight_y_offset = 12 /obj/item/weapon/gun/energy/pulse/carbine/loyalpin pin = /obj/item/device/firing_pin/implant/loyalty diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 78d77697bab..45e936f8867 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -9,7 +9,9 @@ flags = CONDUCT slot_flags = SLOT_BACK ammo_type = list(/obj/item/ammo_casing/energy/ion) - + ammo_x_offset = 3 + flight_x_offset = 17 + flight_y_offset = 9 /obj/item/weapon/gun/energy/ionrifle/emp_act(severity) return @@ -18,11 +20,13 @@ name = "ion carbine" desc = "The MK.II Prototype Ion Projector is a lightweight carbine version of the larger ion rifle, built to be ergonomic and efficient." icon_state = "ioncarbine" - item_state = "ioncarbine" origin_tech = "combat=4;magnets=4;materials=4" w_class = 3 slot_flags = SLOT_BELT pin = null + ammo_x_offset = 2 + flight_x_offset = 18 + flight_y_offset = 11 /obj/item/weapon/gun/energy/decloner name = "biological demolecularisor" @@ -31,6 +35,13 @@ origin_tech = "combat=5;materials=4;powerstorage=3" ammo_type = list(/obj/item/ammo_casing/energy/declone) pin = null + ammo_x_offset = 1 + +/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) + overlays += "decloner_spin" /obj/item/weapon/gun/energy/floragun name = "floral somatoray" @@ -41,7 +52,6 @@ origin_tech = "materials=2;biotech=3;powerstorage=3" modifystate = 1 var/charge_tick = 0 - var/mode = 0 //0 = mutate, 1 = yield boost /obj/item/weapon/gun/energy/floragun/New() ..() @@ -115,6 +125,7 @@ desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon." icon_state = "xray" ammo_type = list(/obj/item/ammo_casing/energy/mindflayer) + ammo_x_offset = 2 /obj/item/weapon/gun/energy/kinetic_accelerator name = "proto-kinetic accelerator" @@ -151,6 +162,13 @@ update_icon() return +/obj/item/weapon/gun/energy/kinetic_accelerator/update_icon() + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + if(power_supply.charge < shot.e_cost) + icon_state = "[initial(icon_state)]_empty" + else + icon_state = initial(icon_state) + /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow name = "mini energy crossbow" desc = "A weapon favored by syndicate stealth specialists." @@ -205,51 +223,15 @@ else ..() +/obj/item/weapon/gun/energy/plasmacutter/update_icon() + return + /obj/item/weapon/gun/energy/plasmacutter/adv name = "advanced plasma cutter" icon_state = "adv_plasmacutter" origin_tech = "combat=3;materials=4;magnets=3;plasmatech=3;engineering=2" ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv) -/obj/item/weapon/gun/energy/disabler - name = "disabler" - desc = "A self-defense weapon that exhausts organic targets, weakening them until they collapse." - icon_state = "disabler" - item_state = null - ammo_type = list(/obj/item/ammo_casing/energy/disabler) - -/obj/item/weapon/gun/energy/disabler/cyborg - name = "cyborg disabler" - desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." - var/charge_tick = 0 - var/recharge_time = 2.5 - can_charge = 0 - -/obj/item/weapon/gun/energy/disabler/cyborg/New() - ..() - SSobj.processing |= src - - -/obj/item/weapon/gun/energy/disabler/cyborg/Destroy() - SSobj.processing.Remove(src) - ..() - -/obj/item/weapon/gun/energy/disabler/cyborg/process() //Every [recharge_time] ticks, recharge a shot for the cyborg - charge_tick++ - if(charge_tick < recharge_time) return 0 - charge_tick = 0 - - if(!power_supply) return 0 //sanity - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && 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 - - update_icon() - return 1 - /obj/item/weapon/gun/energy/wormhole_projector name = "bluespace wormhole projector" desc = "A projector that emits high density quantum-coupled bluespace beams." @@ -261,6 +243,7 @@ /obj/item/weapon/gun/energy/wormhole_projector/update_icon() icon_state = "[initial(icon_state)][select]" + item_state = icon_state return /obj/item/weapon/gun/energy/wormhole_projector/attack_self(mob/living/user) @@ -333,3 +316,17 @@ power_supply.give(shot.e_cost) //...to recharge the shot return 1 + +/obj/item/weapon/gun/energy/temperature + name = "temperature gun" + icon_state = "freezegun" + desc = "A gun that changes temperatures." + origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2" + ammo_type = list(/obj/item/ammo_casing/energy/temp, /obj/item/ammo_casing/energy/temp/hot) + cell_type = "/obj/item/weapon/stock_parts/cell/high" + pin = null + +/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user) + select_fire(user) + update_icon() + return diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 413dff9ad14..6659fe329cd 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -1,18 +1,20 @@ - /obj/item/weapon/gun/energy/taser name = "taser gun" desc = "A low-capacity, energy-based stun gun used by security teams to subdue targets at range." icon_state = "taser" item_state = null //so the human update icon uses the icon_state instead. ammo_type = list(/obj/item/ammo_casing/energy/electrode) + ammo_x_offset = 3 /obj/item/weapon/gun/energy/stunrevolver name = "stun revolver" desc = "A high-tech revolver that fires internal, reusable taser cartridges in a revolving cylinder. The cartridges can be recharged using conventional rechargers." icon_state = "stunrevolver" + item_state = "gun" ammo_type = list(/obj/item/ammo_casing/energy/electrode/gun) can_flashlight = 0 pin = null + ammo_x_offset = 1 /obj/item/weapon/gun/energy/gun/advtaser name = "hybrid taser" @@ -20,6 +22,7 @@ icon_state = "advtaser" ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler) origin_tech = null + ammo_x_offset = 2 /obj/item/weapon/gun/energy/gun/advtaser/cyborg name = "cyborg taser" @@ -52,3 +55,43 @@ update_icon() return 1 + +/obj/item/weapon/gun/energy/disabler + name = "disabler" + desc = "A self-defense weapon that exhausts organic targets, weakening them until they collapse." + icon_state = "disabler" + item_state = null + ammo_type = list(/obj/item/ammo_casing/energy/disabler) + ammo_x_offset = 3 + +/obj/item/weapon/gun/energy/disabler/cyborg + name = "cyborg disabler" + desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." + var/charge_tick = 0 + var/recharge_time = 2.5 + can_charge = 0 + +/obj/item/weapon/gun/energy/disabler/cyborg/New() + ..() + SSobj.processing |= src + + +/obj/item/weapon/gun/energy/disabler/cyborg/Destroy() + SSobj.processing.Remove(src) + ..() + +/obj/item/weapon/gun/energy/disabler/cyborg/process() //Every [recharge_time] ticks, recharge a shot for the cyborg + charge_tick++ + if(charge_tick < recharge_time) return 0 + charge_tick = 0 + + if(!power_supply) return 0 //sanity + if(isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + if(R && 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 + + update_icon() + return 1 \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm deleted file mode 100644 index cdf7625e393..00000000000 --- a/code/modules/projectiles/guns/energy/temperature.dm +++ /dev/null @@ -1,14 +0,0 @@ -/obj/item/weapon/gun/energy/temperature - name = "temperature gun" - icon_state = "freezegun" - desc = "A gun that changes temperatures." - origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2" - ammo_type = list(/obj/item/ammo_casing/energy/temp, /obj/item/ammo_casing/energy/temp/hot) - cell_type = "/obj/item/weapon/stock_parts/cell/high" - pin = null - - -/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user) - select_fire(user) - update_icon() - return \ No newline at end of file diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 29931e4e7bc..0a1eddc7eb5 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -92,7 +92,7 @@ return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume /obj/item/projectile/Bump(atom/A, yes) - if(!yes) //prevents multi bumps. + if(!yes) //prevents double bumps. return if(A == firer || A == src) loc = A.loc diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 66a9e77c9ad..84bbe11872b 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -6,10 +6,6 @@ nodamage = 0 flag = "bullet" -/obj/item/projectile/bullet/revolver - damage = 60 - armour_penetration = 10 - /obj/item/projectile/bullet/weakbullet //beanbag, heavy stamina damage damage = 5 diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 26955d0284d..5dc555550e2 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -67,8 +67,8 @@ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/H in viewers(get_turf(holder.my_atom), null)) - H.flash_eyes() + for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null)) + C.flash_eyes() for(var/i = 1, i <= amount_to_spawn, i++) var/chosen = pick(critters) var/mob/living/simple_animal/hostile/C = new chosen diff --git a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm index 49048502ad0..46f1d7a1e74 100644 --- a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm +++ b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm @@ -159,8 +159,8 @@ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(get_turf(holder.my_atom), null)) - M.flash_eyes() + for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null)) + C.flash_eyes() for(var/i = 1, i <= 4 + rand(1,2), i++) var/chosen = pick(borks) @@ -191,7 +191,7 @@ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(get_turf(holder.my_atom), null)) + for(var/mob/living/carbon/M in viewers(get_turf(holder.my_atom), null)) M.flash_eyes() for(var/i = 1, i <= 4 + rand(1,2), i++) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index c75e6c3e82d..b64d21f6c14 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -79,8 +79,8 @@ reagents.handle_reactions() ..() -/obj/item/weapon/reagent_containers/throw_impact(atom/target,mob/thrower) - ..() +/obj/item/weapon/reagent_containers/throw_impact(atom/target) + . = ..() if(!reagents.total_volume || !spillable) return @@ -96,12 +96,11 @@ R += A.id + " (" R += num2text(A.volume) + ")," - + if(thrownby) + add_logs(thrownby, M, "splashed", R) reagents.reaction(target, TOUCH) - if(thrower) - add_logs(thrower, M, "splashed", R) - else if((!target.density || target.throwpass) && thrower && thrower.mind && thrower.mind.assigned_role == "Bartender") + else if((target.CanPass(src, get_turf(src))) && thrownby && thrownby.mind && thrownby.mind.assigned_role == "Bartender") visible_message("[src] lands onto the [target.name] without spilling a single drop.") return diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index 95d25e4592b..a93cf7e7b52 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -227,7 +227,7 @@ id = "mech_grenade_launcher" build_type = MECHFAB req_tech = list("combat" = 3) - build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang materials = list(MAT_METAL=22000,MAT_GOLD=6000,MAT_SILVER=8000) construction_time = 100 category = list("Exosuit Equipment") @@ -238,7 +238,7 @@ id = "mech_missile_rack" build_type = MECHFAB req_tech = list("combat" = 6, "materials" = 6) - build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack materials = list(MAT_METAL=22000,MAT_GOLD=6000,MAT_SILVER=8000) construction_time = 100 category = list("Exosuit Equipment") @@ -249,7 +249,7 @@ id = "clusterbang_launcher" build_type = MECHFAB req_tech = list("combat"= 5, "materials" = 5, "syndicate" = 3) - build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang materials = list(MAT_METAL=20000,MAT_GOLD=10000,MAT_URANIUM=10000) construction_time = 100 category = list("Exosuit Equipment") @@ -282,7 +282,7 @@ id = "mech_rcd" build_type = MECHFAB req_tech = list("materials" = 4, "bluespace" = 3, "magnets" = 4, "powerstorage"=4, "engineering" = 4) - build_path = /obj/item/mecha_parts/mecha_equipment/tool/rcd + build_path = /obj/item/mecha_parts/mecha_equipment/rcd materials = list(MAT_METAL=30000,MAT_GOLD=20000,MAT_PLASMA=25000,MAT_SILVER=20000) construction_time = 1200 category = list("Exosuit Equipment") @@ -348,7 +348,7 @@ id = "mech_diamond_drill" build_type = MECHFAB req_tech = list("materials" = 4, "engineering" = 3) - build_path = /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill + build_path = /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill materials = list(MAT_METAL=10000,MAT_DIAMOND=6500) construction_time = 100 category = list("Exosuit Equipment") diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index ce602a5e800..c3a14613b65 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -490,7 +490,7 @@ name = "Exosuit Engineering Equipment (Hydraulic Clamp)" id = "mech_hydraulic_clamp" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp + build_path = /obj/item/mecha_parts/mecha_equipment/hydraulic_clamp materials = list(MAT_METAL=10000) construction_time = 100 category = list("Exosuit Equipment") @@ -499,7 +499,7 @@ name = "Exosuit Engineering Equipment (Drill)" id = "mech_drill" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/drill + build_path = /obj/item/mecha_parts/mecha_equipment/drill materials = list(MAT_METAL=10000) construction_time = 100 category = list("Exosuit Equipment") @@ -508,7 +508,7 @@ name = "Exosuit Engineering Equipement (Mining Scanner)" id = "mech_mscanner" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/mining_scanner + build_path = /obj/item/mecha_parts/mecha_equipment/mining_scanner materials = list(MAT_METAL=5000,MAT_GLASS=2500) construction_time = 50 category = list("Exosuit Equipment") @@ -517,7 +517,7 @@ name = "Exosuit Engineering Equipment (Extinguisher)" id = "mech_extinguisher" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/extinguisher + build_path = /obj/item/mecha_parts/mecha_equipment/extinguisher materials = list(MAT_METAL=10000) construction_time = 100 category = list("Exosuit Equipment") @@ -526,7 +526,7 @@ name = "Exosuit Engineering Equipment (Cable Layer)" id = "mech_cable_layer" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/cable_layer + build_path = /obj/item/mecha_parts/mecha_equipment/cable_layer materials = list(MAT_METAL=10000) construction_time = 100 category = list("Exosuit Equipment") @@ -535,7 +535,7 @@ name = "Exosuit Medical Equipment (Mounted Sleeper)" id = "mech_sleeper" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/sleeper + build_path = /obj/item/mecha_parts/mecha_equipment/sleeper materials = list(MAT_METAL=5000,MAT_GLASS=10000) construction_time = 100 category = list("Exosuit Equipment") @@ -544,7 +544,7 @@ name = "Exosuit Medical Equipment (Syringe Gun)" id = "mech_syringe_gun" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun + build_path = /obj/item/mecha_parts/mecha_equipment/syringe_gun materials = list(MAT_METAL=3000,MAT_GLASS=2000) construction_time = 200 category = list("Exosuit Equipment") @@ -580,7 +580,7 @@ name = "H.O.N.K Mousetrap Mortar" id = "mech_mousetrap_mortar" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar materials = list(MAT_METAL=20000,MAT_BANANIUM=5000) construction_time = 300 category = list("Exosuit Equipment") @@ -589,7 +589,7 @@ name = "H.O.N.K Banana Mortar" id = "mech_banana_mortar" build_type = MECHFAB - build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar materials = list(MAT_METAL=20000,MAT_BANANIUM=5000) construction_time = 300 category = list("Exosuit Equipment") diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index dfbb6085368..cbb37c661d3 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -22,7 +22,8 @@ /obj/docking_port/Destroy() return QDEL_HINT_LETMELIVE - +/obj/docking_port/shuttleRotate() + return //we don't rotate with shuttles via this code. //returns a list(x0,y0, x1,y1) where points 0 and 1 are bounding corners of the projected rectangle /obj/docking_port/proc/return_coords(_x, _y, _dir) if(!_dir) @@ -267,6 +268,27 @@ else WARNING("shuttle \"[id]\" could not enter transit space. S0=[S0 ? S0.id : "null"] S1=[S1 ? S1.id : "null"]") +//default shuttleRotate +/atom/proc/shuttleRotate(rotation) + //rotate our direction + dir = angle2dir(rotation+dir2angle(dir)) + + //resmooth if need be. + if(smooth) + smooth_icon(src) + + //rotate the pixel offsets too. + if (pixel_x || pixel_y) + if (rotation < 0) + rotation += 360 + for (var/turntimes=rotation/90;turntimes>0;turntimes--) + var/oldPX = pixel_x + var/oldPY = pixel_y + pixel_x = oldPY + pixel_y = (oldPX*(-1)) + + + //this is the main proc. It instantly moves our mobile port to stationary port S1 //it handles all the generic behaviour, such as sanity checks, closing doors on the shuttle, stunning mobs, etc /obj/docking_port/mobile/proc/dock(obj/docking_port/stationary/S1) @@ -296,6 +318,13 @@ var/list/L0 = return_ordered_turfs(x, y, z, dir, areaInstance) var/list/L1 = return_ordered_turfs(S1.x, S1.y, S1.z, S1.dir) + var/rotation = dir2angle(S1.dir)-dir2angle(dir) + if ((rotation % 90) != 0) + rotation += (rotation % 90) //diagonal rotations not allowed, round up + rotation = SimplifyDegrees(rotation) + + + //remove area surrounding docking port if(areaInstance.contents.len) var/area/A0 = locate("[area_type]") @@ -315,6 +344,18 @@ if(!T1) continue + + //lighting stuff + T1.redraw_lighting() + SSair.remove_from_active(T1) + T1.CalculateAdjacentTurfs() + SSair.add_to_active(T1,1) + + T0.redraw_lighting() + SSair.remove_from_active(T0) + T0.CalculateAdjacentTurfs() + SSair.add_to_active(T0,1) + T0.copyTurf(T1) areaInstance.contents += T1 @@ -324,54 +365,49 @@ Ts1.copy_air_with_tile(T0) //move mobile to new location - loc = S1.loc - dir = S1.dir - //move all objects - for(var/obj/O in T0) - if(O.invisibility >= 101) - continue - if(O == T0.lighting_object) - continue - O.loc = T1 - //close open doors - if(istype(O, /obj/machinery/door)) - var/obj/machinery/door/Door = O - spawn(-1) - if(Door) - Door.close() - for(var/mob/M in T0) - if(!M.move_on_shuttle) - continue - M.loc = T1 + for(var/atom/movable/AM in T0) + if (rotation) + AM.shuttleRotate(rotation) - //docking turbulence - if(M.client) - spawn(0) - if(M.buckled) - shake_camera(M, 2, 1) // turn it down a bit come on - else - shake_camera(M, 7, 1) - if(istype(M, /mob/living/carbon)) - if(!M.buckled) - M.Weaken(3) + if (istype(AM,/obj)) + var/obj/O = AM + if(O.invisibility >= 101) + continue + if(O == T0.lighting_object) + continue + O.loc = T1 + + //close open doors + if(istype(O, /obj/machinery/door)) + var/obj/machinery/door/Door = O + spawn(-1) + if(Door) + Door.close() + else if (istype(AM,/mob)) + var/mob/M = AM + if(!M.move_on_shuttle) + continue + M.loc = T1 + + //docking turbulence + if(M.client) + spawn(0) + if(M.buckled) + shake_camera(M, 2, 1) // turn it down a bit come on + else + shake_camera(M, 7, 1) + if(istype(M, /mob/living/carbon)) + if(!M.buckled) + M.Weaken(3) T0.ChangeTurf(turf_type) - - //air system updates - for(var/turf/T1 in L1) - T1.redraw_lighting() - SSair.remove_from_active(T1) - T1.CalculateAdjacentTurfs() - SSair.add_to_active(T1,1) - - for(var/turf/T0 in L0) - T0.redraw_lighting() - SSair.remove_from_active(T0) - T0.CalculateAdjacentTurfs() - SSair.add_to_active(T0,1) + if (rotation) + T1.shuttleRotate(rotation) + loc = S1.loc + dir = S1.dir /* if(istype(S1, /obj/docking_port/stationary/transit)) @@ -381,6 +417,8 @@ T.update_icon() */ + + /obj/docking_port/mobile/proc/findTransitDock() var/obj/docking_port/stationary/transit/T = SSshuttle.getDock("[id]_transit") if(T && !canDock(T)) diff --git a/code/modules/telesci/bscrystal.dm b/code/modules/telesci/bscrystal.dm index 589731a3635..811ef4d991f 100644 --- a/code/modules/telesci/bscrystal.dm +++ b/code/modules/telesci/bscrystal.dm @@ -28,13 +28,14 @@ do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg') /obj/item/bluespace_crystal/throw_impact(atom/hit_atom) - ..() - visible_message("[src] fizzles and disappears upon impact!") - PoolOrNew(/obj/effect/effect/sparks, loc) - playsound(src.loc, "sparks", 50, 1) - if(isliving(hit_atom)) - blink_mob(hit_atom) - qdel(src) + if(!..()) // not caught in mid-air + visible_message("[src] fizzles and disappears upon impact!") + var/turf/T = get_turf(hit_atom) + PoolOrNew(/obj/effect/effect/sparks, T) + playsound(src.loc, "sparks", 50, 1) + if(isliving(hit_atom)) + blink_mob(hit_atom) + qdel(src) // Artifical bluespace crystal, doesn't give you much research. diff --git a/config/admins.txt b/config/admins.txt index d1ebfc143f5..2151cab1b2a 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -88,4 +88,5 @@ ACCount12 = Game Master fayrik = Game Master shadowlight213 = Game Master drovidicorv = Game Master -Dunc = Game Master \ No newline at end of file +Dunc = Game Master +MMMiracles = Game Master \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index aea82df7180..6bd224a07fc 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,49 @@ -->
+

21 July 2015

+

Fayrik updated:

+
    +
  • Syndicate Donksoft gear now costs less.
  • +
+

phil235 updated:

+
    +
  • Thrown things no longer bounces off walls, unless they're in no gravity. Heavy items and mobs thrown can push the mobs and non anchored objects they land on. Throwing a mob onto a mob in no gravity will push each one in opposite direction. Thrown mobs landing on wall, or dense object or mob gets stunned and a bit injured. The damage when mob hit a wall is nerfed.
  • +
+ +

20 July 2015

+

AnturK updated:

+
    +
  • Lightning Bolt now always bounces 5 times and deals 15 to 50 burn damage to each target depending on the chargeup
  • +
+

KorPaheron updated:

+
    +
  • Added the Multiverse Sword, a new wizard artifact that can summon clones of yourself from other universes, allowing for dangerous amounts of recursion.
  • +
+

phil235 updated:

+
    +
  • Mechs no longer use object verbs and the exosuit interface tab. They now use action buttons. Mechs now have a cycle equipment action button to change weapon faster than by using the view stats window. Mechs get two special alerts when their battery or health is low. Mechs now properly consume energy when moving and having their lights on. Using a mech tool that takes time to act now shows a progress bar (e.g. mech drill).
  • +
  • Mechs now have a cycle equipment action button to change weapon faster than by using the view stats window.
  • +
  • Mechs get two special alerts when their battery or health is low.
  • +
  • Mechs now properly consume energy when moving and having their lights on.
  • +
  • Using a mech tool that takes time to act now shows a progress bar (e.g. mech drill).
  • +
+ +

19 July 2015

+

Gun Hog updated:

+
    +
  • Nanotrasen advancements in cyborg technology now allow for integrated headlamps! As such, the flashlight package normally used as a module is now seamlessly merged with their systems!
  • +
+

Ikarrus updated:

+
    +
  • Asimov's subject of "human beings" can now be modified by uploaders.
  • +
  • Eaxmining AI modules while adjacent to them will show you what laws it will upload.
  • +
+

MMMiracles updated:

+
    +
  • Adds a TWANG sound effect when hitting things with a guitar.
  • +
+

18 July 2015

AlexanderUlanH updated:

    @@ -73,8 +116,6 @@

    Steelpoint updated:

    • Reduced weight of Sechailer, it now fits in boxes.
    • -
    • Increased armor values of HoS, ERT and DS suits.
    • -
    • Revolver bullets now have armor penetration.

    phil updated:

      diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 6d8344cf85a..a7dfecdf898 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -1255,8 +1255,6 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. said, to allow them to better impersonate their victim's speech patterns Steelpoint: - tweak: Reduced weight of Sechailer, it now fits in boxes. - - tweak: Increased armor values of HoS, ERT and DS suits. - - rscadd: Revolver bullets now have armor penetration. phil: - tweak: Smoke and foam touch reactions gets buffed. - rscadd: Reagent dispensers (watertank, fueltank) tells you how much reagents they @@ -1265,3 +1263,43 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. sorium, blob sorium, liquid dark matter and blob liquid dark matter are now scaled by their volume. Sorium/LDM blob's touch now throws the mobs who are close but simply moves the mobs that are further away. +2015-07-19: + Gun Hog: + - rscadd: Nanotrasen advancements in cyborg technology now allow for integrated + headlamps! As such, the flashlight package normally used as a module is now + seamlessly merged with their systems! + Ikarrus: + - rscadd: Asimov's subject of "human beings" can now be modified by uploaders. + - rscadd: Eaxmining AI modules while adjacent to them will show you what laws it + will upload. + MMMiracles: + - soundadd: Adds a TWANG sound effect when hitting things with a guitar. +2015-07-20: + AnturK: + - tweak: Lightning Bolt now always bounces 5 times and deals 15 to 50 burn damage + to each target depending on the chargeup + KorPaheron: + - rscadd: Added the Multiverse Sword, a new wizard artifact that can summon clones + of yourself from other universes, allowing for dangerous amounts of recursion. + phil235: + - tweak: Mechs no longer use object verbs and the exosuit interface tab. They now + use action buttons. Mechs now have a cycle equipment action button to change + weapon faster than by using the view stats window. Mechs get two special alerts + when their battery or health is low. Mechs now properly consume energy when + moving and having their lights on. Using a mech tool that takes time to act + now shows a progress bar (e.g. mech drill). + - rscadd: Mechs now have a cycle equipment action button to change weapon faster + than by using the view stats window. + - rscadd: Mechs get two special alerts when their battery or health is low. + - tweak: Mechs now properly consume energy when moving and having their lights on. + - rscadd: Using a mech tool that takes time to act now shows a progress bar (e.g. + mech drill). +2015-07-21: + Fayrik: + - tweak: Syndicate Donksoft gear now costs less. + phil235: + - tweak: Thrown things no longer bounces off walls, unless they're in no gravity. + Heavy items and mobs thrown can push the mobs and non anchored objects they + land on. Throwing a mob onto a mob in no gravity will push each one in opposite + direction. Thrown mobs landing on wall, or dense object or mob gets stunned + and a bit injured. The damage when mob hit a wall is nerfed. diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi index 42625cc7790..5c44f86b6cb 100644 Binary files a/icons/effects/crayondecal.dmi and b/icons/effects/crayondecal.dmi differ diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index 4ced7caebed..0636ebac478 100644 Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 2918d313aa8..1157611aa23 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index 062adfa003d..2bef3ec79b4 100644 Binary files a/icons/mob/inhands/guns_lefthand.dmi and b/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/guns_righthand.dmi b/icons/mob/inhands/guns_righthand.dmi index 09a3bc50d40..9d72ffd4f4e 100644 Binary files a/icons/mob/inhands/guns_righthand.dmi and b/icons/mob/inhands/guns_righthand.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index d134e422131..6c532a75f43 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 0ed43592376..1b707cda5e0 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/icons/mob/screen_cyborg.dmi b/icons/mob/screen_cyborg.dmi index 002768f9d2a..b929a8c2395 100644 Binary files a/icons/mob/screen_cyborg.dmi and b/icons/mob/screen_cyborg.dmi differ diff --git a/icons/obj/atmospherics/components/binary_devices.dmi b/icons/obj/atmospherics/components/binary_devices.dmi index 832bf766d0f..540bf3b771c 100644 Binary files a/icons/obj/atmospherics/components/binary_devices.dmi and b/icons/obj/atmospherics/components/binary_devices.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 9bc5f822c87..d73ae4f3b36 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi index 09fa557ac1a..f225be2dcf2 100644 Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ diff --git a/sound/weapons/stringsmash.ogg b/sound/weapons/stringsmash.ogg new file mode 100644 index 00000000000..ea96bc0b50b Binary files /dev/null and b/sound/weapons/stringsmash.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 02d69cfb412..12a7b87c0ee 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -219,7 +219,6 @@ #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\getrev.dm" -#include "code\datums\helper_datums\global_iterator.dm" #include "code\datums\helper_datums\icon_snapshot.dm" #include "code\datums\helper_datums\teleport.dm" #include "code\datums\helper_datums\topic_input.dm" @@ -503,7 +502,9 @@ #include "code\game\mecha\mecha.dm" #include "code\game\mecha\mecha_construction_paths.dm" #include "code\game\mecha\mecha_control_console.dm" +#include "code\game\mecha\mecha_defense.dm" #include "code\game\mecha\mecha_parts.dm" +#include "code\game\mecha\mecha_topic.dm" #include "code\game\mecha\mecha_wreckage.dm" #include "code\game\mecha\combat\combat.dm" #include "code\game\mecha\combat\durand.dm" @@ -514,7 +515,9 @@ #include "code\game\mecha\combat\reticence.dm" #include "code\game\mecha\equipment\mecha_equipment.dm" #include "code\game\mecha\equipment\tools\medical_tools.dm" -#include "code\game\mecha\equipment\tools\tools.dm" +#include "code\game\mecha\equipment\tools\mining_tools.dm" +#include "code\game\mecha\equipment\tools\other_tools.dm" +#include "code\game\mecha\equipment\tools\work_tools.dm" #include "code\game\mecha\equipment\weapons\weapons.dm" #include "code\game\mecha\medical\medical.dm" #include "code\game\mecha\medical\odysseus.dm" @@ -1378,7 +1381,6 @@ #include "code\modules\projectiles\guns\energy\pulse.dm" #include "code\modules\projectiles\guns\energy\special.dm" #include "code\modules\projectiles\guns\energy\stun.dm" -#include "code\modules\projectiles\guns\energy\temperature.dm" #include "code\modules\projectiles\guns\magic\staff.dm" #include "code\modules\projectiles\guns\magic\wand.dm" #include "code\modules\projectiles\guns\projectile\automatic.dm"