From 32b2be1b5a13171260320c30fd6eae2e74fe603c Mon Sep 17 00:00:00 2001 From: panurgomatic Date: Fri, 23 Dec 2011 10:54:23 +0000 Subject: [PATCH] - Simple event dispatch system. - atom.forceMove() proc. Ignores density and other Move() restrictions, but calls Exited() and Entered() - var/emagged moved to /obj/machinery class - anyprob() helper proc. - Mecha internal damage vars encapsulated. - Mech Fabricators now require robotics ID to operate. Emag removes this restriction. - Added Odysseus Medical Exosuit and it's parts. Has integrated Medical Hud and ability to mount medical modules. - Added Sleeper Medical module for medical exosuits. Similar to common sleepers, but no ability to inject reagents. - Added Cable Layer module for exosuits. Load with cable (attack cable with it), activate, walk over dismantled floor. - Added another exosuit internal damage type - short circuit. Short-circuited exosuits will drain powercell charge and power relay won't work. - You should be able to send messages to exosuit operators using Exosuit Control Console - Gygax armour and module capacity nerfed. - Exosuit weapon recharge time raised. - Bugfix: EMP actually drains exosuit cell and damages it git-svn-id: http://tgstation13.googlecode.com/svn/trunk@2780 316c924e-a436-60f5-8080-3fe189b3f50e --- code/datums/helper_datums/events.dm | 60 ++ code/datums/helper_datums/global_iterator.dm | 4 +- code/datums/helper_datums/teleport.dm | 6 +- code/defines/atom.dm | 11 +- code/defines/obj/machinery.dm | 2 +- code/defines/obj/vending.dm | 2 +- code/defines/procs/helpers.dm | 4 + code/game/machinery/bots/bots.dm | 2 +- code/game/machinery/computer/arcade.dm | 1 - code/game/machinery/deployable.dm | 1 - code/game/machinery/machinery.dm | 1 - code/game/machinery/portable_turret.dm | 2 +- code/game/magic/library.dm | 1 - code/game/mecha/combat/combat.dm | 2 + code/game/mecha/combat/durand.dm | 2 +- code/game/mecha/combat/gygax.dm | 4 +- code/game/mecha/combat/marauder.dm | 2 +- code/game/mecha/combat/phazon.dm | 1 + code/game/mecha/equipment/mecha_equipment.dm | 17 +- code/game/mecha/equipment/tools/tools.dm | 511 +++++++++-- code/game/mecha/equipment/weapons/weapons.dm | 8 +- code/game/mecha/mech_fabricator.dm | 74 +- code/game/mecha/mecha.dm | 846 +++++++++++-------- code/game/mecha/mecha_construction_paths.dm | 216 ++++- code/game/mecha/mecha_control_console.dm | 22 +- code/game/mecha/mecha_parts.dm | 66 +- code/game/mecha/medical/medical.dm | 22 + code/game/mecha/medical/odysseus.dm | 99 +++ code/modules/power/apc.dm | 1 - code/modules/power/port_gen.dm | 1 - code/modules/research/designs.dm | 52 +- code/modules/research/rdconsole.dm | 1 - html/changelog.html | 18 + icons/mob/mecha.dmi | Bin 105934 -> 106925 bytes tgstation.dme | 4 + 35 files changed, 1570 insertions(+), 496 deletions(-) create mode 100644 code/datums/helper_datums/events.dm create mode 100644 code/game/mecha/medical/medical.dm create mode 100644 code/game/mecha/medical/odysseus.dm diff --git a/code/datums/helper_datums/events.dm b/code/datums/helper_datums/events.dm new file mode 100644 index 0000000000..8ae893b26b --- /dev/null +++ b/code/datums/helper_datums/events.dm @@ -0,0 +1,60 @@ +/* + * WARRANTY VOID IF CODE USED + */ + + +/datum/events + var/list/events + + New() + ..() + events = new + + proc/addEventType(event_type) + if(!(event_type in events) || !islist(events[event_type])) + events[event_type] = list() + return 1 + return + + proc/addEvent(event_type,proc_holder,proc_name) + if(!event_type || !proc_holder || !proc_name) + return + addEventType(event_type) + var/list/event = events[event_type] + var/datum/event/E = new /datum/event(proc_holder,proc_name) + event += E + return E + + proc/fireEvent() + //world << "Events in [args[1]] called" + var/list/event = listgetindex(events,args[1]) + if(istype(event)) + spawn(-1) + for(var/datum/event/E in event) + if(!E.Fire(arglist(args.Copy(2)))) + clearEvent(args[1],E) + return + + proc/clearEvent(event_type,datum/event/E) + if(!event_type || !E) + return + var/list/event = listgetindex(events,event_type) + event -= E + return 1 + + +/datum/event + var/listener + var/proc_name + + New(tlistener,tprocname) + listener = tlistener + proc_name = tprocname + return ..() + + proc/Fire() + //world << "Event fired" + if(listener) + call(listener,proc_name)(arglist(args)) + return 1 + return \ No newline at end of file diff --git a/code/datums/helper_datums/global_iterator.dm b/code/datums/helper_datums/global_iterator.dm index 4ce4cf0d55..0020859f1d 100644 --- a/code/datums/helper_datums/global_iterator.dm +++ b/code/datums/helper_datums/global_iterator.dm @@ -106,7 +106,7 @@ Data storage vars: while(state) sleep(1) if(++lag>10) - CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. Last exec - [get_last_exec_time_as_text()].") + CRASH("The global_iterator loop \ref[src] failed to terminate in designated timeframe. This may be caused by server lagging.") return 1 proc/process() @@ -123,7 +123,7 @@ Data storage vars: proc/set_delay(new_delay) if(isnum(new_delay)) - delay = new_delay>0?(new_delay):1 + delay = max(1, round(new_delay)) return 1 else return 0 diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 39967ecd5c..9918763ba8 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -29,7 +29,7 @@ return 0 setEffects(aeffectin,aeffectout) setForceTeleport(afteleport) - setSounds(asoundin) + setSounds(asoundin,asoundout) return 1 //must succeed @@ -108,9 +108,7 @@ playSpecials(curturf,effectin,soundin) if(force_teleport) - teleatom.loc.Exited(teleatom) - teleatom.loc = destturf - teleatom.loc.Entered(teleatom) + teleatom.forceMove(destturf) playSpecials(destturf,effectout,soundout) else if(teleatom.Move(destturf)) diff --git a/code/defines/atom.dm b/code/defines/atom.dm index 151b81198a..6555dcca59 100644 --- a/code/defines/atom.dm +++ b/code/defines/atom.dm @@ -231,4 +231,13 @@ its easier to just keep the beam vertical. X.pixel_y=Pixel_y sleep(3) //Changing this to a lower value will cause the beam to follow more smoothly with movement, but it will also be more laggy. //I've found that 3 ticks provided a nice balance for my use. - for(var/obj/effect/overlay/beam/O in orange(10,src)) if(O.BeamSource==src) del O \ No newline at end of file + for(var/obj/effect/overlay/beam/O in orange(10,src)) if(O.BeamSource==src) del O + +atom/movable/proc/forceMove(atom/destination) + if(destination) + if(loc) + loc.Exited(src) + loc = destination + loc.Entered(src) + return 1 + return 0 \ No newline at end of file diff --git a/code/defines/obj/machinery.dm b/code/defines/obj/machinery.dm index 4aad8f88df..049c0dc317 100644 --- a/code/defines/obj/machinery.dm +++ b/code/defines/obj/machinery.dm @@ -3,7 +3,7 @@ icon = 'stationobjs.dmi' var stat = 0 - + emagged = 0 use_power = 0 //0 = dont run the auto //1 = run auto, use idle diff --git a/code/defines/obj/vending.dm b/code/defines/obj/vending.dm index 37d29fcbc7..2d0764f6fe 100644 --- a/code/defines/obj/vending.dm +++ b/code/defines/obj/vending.dm @@ -28,7 +28,7 @@ var/slogan_delay = 600 //How long until we can pitch again? var/icon_vend //Icon_state when vending! var/icon_deny //Icon_state when vending! - var/emagged = 0 //Ignores if somebody doesn't have card access to that machine. + //var/emagged = 0 //Ignores if somebody doesn't have card access to that machine. var/seconds_electrified = 0 //Shock customers like an airlock. var/shoot_inventory = 0 //Fire items at customers! We're broken! var/shut_up = 0 //Stop spouting those godawful pitches! diff --git a/code/defines/procs/helpers.dm b/code/defines/procs/helpers.dm index 5ee2993127..9a409816ad 100644 --- a/code/defines/procs/helpers.dm +++ b/code/defines/procs/helpers.dm @@ -1452,6 +1452,10 @@ proc/safepick(list/list) return return pick(list) +//chances are 1:value. anyprob(1) will always return true +proc/anyprob(value) + return (rand(1,value)==value) + proc/view_or_range(distance = world.view , center = usr , type) switch(type) if("view") diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index 83ba4e215d..6545e240aa 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -9,7 +9,7 @@ var/maxhealth = 0 var/fire_dam_coeff = 1.0 var/brute_dam_coeff = 1.0 - var/emagged = 0 //Urist: Moving that var to the general /bot tree as it's used by most bots + //var/emagged = 0 //Urist: Moving that var to the general /bot tree as it's used by most bots /obj/machinery/bot/proc/turn_on() diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index fac540a854..57b87ae93f 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -1,5 +1,4 @@ /obj/machinery/computer/arcade - var/emagged var/turtle = 0 /obj/machinery/computer/arcade/New() diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index f05d34a3fd..998c212cbd 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -157,7 +157,6 @@ for reference: var/health = 100.0 var/maxhealth = 100.0 var/locked = 0.0 - var/emagged = 0.0 // req_access = list(access_maint_tunnels) New() diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 17364faafe..42ab5ea555 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -91,7 +91,6 @@ Class Procs: Compiled by Aygar */ - /obj/machinery/New() ..() machines.Add(src) diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 4b5b3612fe..a0d13f008b 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -43,7 +43,7 @@ var/attacked = 0 // if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!) - var/emagged = 0 // 1: emagged, 0: not emagged + //var/emagged = 0 // 1: emagged, 0: not emagged var/on = 1 // determines if the turret is on var/datum/effect/effect/system/spark_spread/spark_system // the spark system, used for generating... sparks? diff --git a/code/game/magic/library.dm b/code/game/magic/library.dm index 8f65ab1b7a..8fad35e65f 100644 --- a/code/game/magic/library.dm +++ b/code/game/magic/library.dm @@ -407,7 +407,6 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f anchored = 1 density = 1 var - emagged = 0 arcanecheckout = 0 screenstate = 0 // 0 - Main Menu, 1 - Inventory, 2 - Checked Out, 3 - Check Out a Book buffer_book diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index b022f7663f..e5bcb9a42d 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -6,6 +6,8 @@ var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall) internal_damage_threshold = 50 maint_access = 0 + //add_req_access = 0 + //operation_req_access = list(access_hos) damage_absorption = list("brute"=0.7,"fire"=1,"bullet"=0.7,"laser"=0.85,"energy"=1,"bomb"=0.8) /* diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm index 964318a4c1..6dac559b94 100644 --- a/code/game/mecha/combat/durand.dm +++ b/code/game/mecha/combat/durand.dm @@ -6,7 +6,7 @@ dir_in = 1 //Facing North. health = 400 deflect_chance = 20 - damage_absorption = list("brute"=0.4,"fire"=1.1,"bullet"=0.6,"laser"=0.85,"energy"=0.9,"bomb"=0.8) + damage_absorption = list("brute"=0.5,"fire"=1.1,"bullet"=0.65,"laser"=0.85,"energy"=0.9,"bomb"=0.8) max_temperature = 3000 infra_luminosity = 8 force = 40 diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index 0cb3c89388..fa9e2a186d 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -6,13 +6,13 @@ dir_in = 1 //Facing North. health = 300 deflect_chance = 15 - damage_absorption = list("brute"=0.6,"fire"=1,"bullet"=0.8,"laser"=0.6,"energy"=0.7,"bomb"=1) + damage_absorption = list("brute"=0.75,"fire"=1,"bullet"=0.8,"laser"=0.7,"energy"=0.85,"bomb"=1) max_temperature = 3500 infra_luminosity = 6 var/overload = 0 wreckage = /obj/effect/decal/mecha_wreckage/gygax internal_damage_threshold = 35 - max_equip = 4 + max_equip = 3 /* diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index 7b2c66b8b9..80e5ca0448 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -5,7 +5,7 @@ step_in = 5 health = 500 deflect_chance = 25 - damage_absorption = list("brute"=0.4,"fire"=0.7,"bullet"=0.45,"laser"=0.6,"energy"=0.7,"bomb"=0.7) + damage_absorption = list("brute"=0.5,"fire"=0.7,"bullet"=0.45,"laser"=0.6,"energy"=0.7,"bomb"=0.7) max_temperature = 5000 infra_luminosity = 3 var/zoom = 0 diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm index 2cb59a5591..6bcad8dab5 100644 --- a/code/game/mecha/combat/phazon.dm +++ b/code/game/mecha/combat/phazon.dm @@ -12,6 +12,7 @@ infra_luminosity = 3 wreckage = /obj/effect/decal/mecha_wreckage/phazon add_req_access = 1 + //operation_req_access = list() internal_damage_threshold = 25 force = 15 var/phasing = 0 diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 9739c80994..46f4bc649c 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -13,6 +13,8 @@ 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) @@ -31,6 +33,13 @@ if(chassis) send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) send_byjax(chassis.occupant,"exosuit.browser","equipment_menu",chassis.get_equipment_menu(),"dropdowns") + return 1 + return + +/obj/item/mecha_parts/mecha_equipment/proc/update_equip_info() + if(chassis) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",get_equip_info()) + return 1 return /obj/item/mecha_parts/mecha_equipment/proc/destroy()//missiles detonating, teleporter creating singularity? @@ -90,7 +99,7 @@ /obj/item/mecha_parts/mecha_equipment/proc/attach(obj/mecha/M as obj) M.equipment += src - src.chassis = M + chassis = M src.loc = M M.log_message("[src] initialized.") if(!M.selected) @@ -103,10 +112,10 @@ chassis.equipment -= src if(chassis.selected == src) chassis.selected = null - src.update_chassis_page() + update_chassis_page() chassis.log_message("[src] removed from equipment.") - src.chassis = null - src.equip_ready = 1 + chassis = null + set_ready_state(1) return diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index ff693768d0..a3639171dc 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -6,9 +6,9 @@ var/dam_force = 20 var/obj/mecha/working/ripley/cargo_holder - can_attach(obj/mecha/M as obj) + can_attach(obj/mecha/working/ripley/M as obj) if(..()) - if(istype(M, /obj/mecha/working/ripley)) + if(istype(M)) return 1 return 0 @@ -65,6 +65,7 @@ /obj/item/mecha_parts/mecha_equipment/tool/drill name = "Drill" + desc = "This is the drill that'll pierce the heavens! (Can be attached to: Combat and Engineering Exosuits)" icon_state = "mecha_drill" equip_cooldown = 30 energy_drain = 10 @@ -76,7 +77,6 @@ chassis.use_power(energy_drain) chassis.visible_message("[chassis] starts to drill [target]", "You hear the drill.") chassis.occupant_message("You start to drill [target]") - chassis.use_power(energy_drain) var/T = chassis.loc var/C = target.loc //why are these backwards? we may never know -Pete if(do_after_cooldown(target)) @@ -99,9 +99,16 @@ target.ex_act(2) return 1 + 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/tool/extinguisher name = "Extinguisher" + desc = "Exosuit-mounted extinguisher (Can be attached to: Engineering exosuits)" icon_state = "mecha_exting" equip_cooldown = 5 energy_drain = 0 @@ -164,13 +171,19 @@ on_reagent_change() return + can_attach(obj/mecha/working/M as obj) + 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." + desc = "An exosuit-mounted Rapid Construction Device. (Can be attached to: Any exosuit)" icon_state = "mecha_rcd" origin_tech = "materials=4;bluespace=3;magnets=4;powerstorage=4" - equip_cooldown = 20 + equip_cooldown = 10 energy_drain = 250 range = MELEE|RANGED construction_time = 1200 @@ -341,7 +354,7 @@ icon_state = "mecha_teleport" origin_tech = "bluespace=2;magnets=3" equip_cooldown = 10 - energy_drain = 200 + energy_drain = 100 range = MELEE|RANGED var/atom/movable/locked var/mode = 1 //1 - gravsling 2 - gravpush @@ -496,6 +509,7 @@ 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() @@ -528,12 +542,13 @@ icon_state = "repair_droid" origin_tech = "magnets=3;programming=3" equip_cooldown = 20 - energy_drain = 20 + energy_drain = 100 range = 0 construction_cost = list("metal"=10000,"gold"=1000,"silver"=2000,"glass"=5000) 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) New() ..() @@ -583,28 +598,29 @@ process(var/obj/item/mecha_parts/mecha_equipment/repair_droid/RD as obj) if(!RD.chassis) + stop() RD.set_ready_state(1) - return src.stop() + return + var/health_boost = RD.health_boost var/repaired = 0 - if(RD.chassis.health < initial(RD.chassis.health)) - RD.chassis.health += min(RD.health_boost, initial(RD.chassis.health)-RD.chassis.health) + 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(RD.chassis.internal_damage && prob(20)) - if(RD.chassis.internal_damage&MECHA_INT_TEMP_CONTROL) - RD.chassis.internal_damage &= ~MECHA_INT_TEMP_CONTROL - repaired = 1 - else if(RD.chassis.internal_damage&MECHA_INT_SHORT_CIRCUIT) - RD.chassis.internal_damage &= ~MECHA_INT_SHORT_CIRCUIT - repaired = 1 - else if(RD.chassis.internal_damage&MECHA_INT_TANK_BREACH) - RD.chassis.internal_damage &= ~MECHA_INT_TANK_BREACH - repaired = 1 - else if(RD.chassis.internal_damage&MECHA_INT_CONTROL_LOST) - RD.chassis.internal_damage &= ~MECHA_INT_CONTROL_LOST - repaired = 1 if(repaired) - RD.chassis.use_power(RD.energy_drain) - RD.set_ready_state(0) + 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 @@ -614,13 +630,14 @@ name = "Energy Relay" desc = "Wirelessly drains energy from any available power channel in area. The performance index is quite low." icon_state = "tesla" - origin_tech = "magnets=3" + origin_tech = "magnets=4;syndicate=2" equip_cooldown = 10 energy_drain = 0 range = 0 construction_cost = list("metal"=10000,"gold"=2000,"silver"=3000,"glass"=2000) var/datum/global_iterator/pr_energy_relay var/coeff = 100 + var/list/use_channels = list(EQUIP,ENVIRON,LIGHT) New() ..() @@ -631,20 +648,41 @@ detach() pr_energy_relay.stop() chassis.proc_res["dynusepower"] = null + chassis.proc_res["dyngetcharge"] = null ..() return attach(obj/mecha/M) ..() + chassis.proc_res["dyngetcharge"] = src chassis.proc_res["dynusepower"] = src return can_attach(obj/mecha/M) if(..()) - if(!M.proc_res["dynusepower"]) + if(!M.proc_res["dynusepower"] && !M.proc_res["dyngetcharge"]) return 1 return 0 + proc/dyngetcharge() + if(equip_ready) //disabled + return chassis.dyngetcharge() + var/area/A = get_area(chassis) + var/pow_chan = get_power_channel(A) + var/charge + if(pow_chan) + charge = 1000 //making magic + return charge + + 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 + Topic(href, href_list) ..() if(href_list["toggle_relay"]) @@ -663,28 +701,25 @@ proc/dynusepower(amount) if(!equip_ready) //enabled 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) - A.master.use_power(amount*coeff, pow_chan) - return 1 + 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 process(var/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/ER) - if(!ER.chassis) + if(!ER.chassis || ER.chassis.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + stop() ER.set_ready_state(1) - return stop() + return var/cur_charge = ER.chassis.get_charge() if(isnull(cur_charge)) + stop() ER.set_ready_state(1) ER.chassis.occupant_message("No powercell detected.") - return stop() + return if(cur_chargeEG.reliability) + if(anyprob(EG.reliability)) EG.critfail() return stop() var/cur_charge = EG.chassis.get_charge() @@ -827,12 +863,373 @@ if(cur_chargeThe sleeper is already occupied!") + return + target.forceMove(src) + occupant = 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() + chassis.occupant_message("[target] successfully loaded into [src]. Life support functions engaged.") + chassis.visible_message("[chassis] loads [target] into the [src].") + chassis.log_message("[src]: [target] loaded. Life support functions engaged.") + return + + proc/go_out() + if(!occupant) + return + occupant.forceMove(get_turf(src)) + chassis.occupant_message("[occupant] ejected. Life support functions disabled.") + chassis.log_message("[src]: [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 + + detach() + if(occupant) + chassis.occupant_message("Unable to detach [src] - equipment occupied.") + return + pr_mech_sleeper.stop() + return ..() + + get_equip_info() + var/output = ..() + if(output) + var/temp = "" + if(occupant) + temp = "
\[Occupant: [occupant] (Health: [occupant.health]%)\]
View stats|Eject" + return "[output] [temp]" + return + + 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") + onclose(chassis.occupant, "msleeper") + return + if(filter.get("inject")) + inject_reagent(filter.get("inject"),filter.getNum("amount"), filter.get("rname")) + return + + proc/get_occupant_stats() + if(!occupant) + return + return {" + + [occupant] statistics + + + + +

Health statistics

+
+ [get_occupant_dam()] +
+

Reagents in bloodstream

+
+ [get_occupant_reagents()] +
+ + "} + + proc/get_occupant_dam() + var/t1 + switch(occupant.stat) + if(0) + t1 = "Conscious" + if(1) + t1 = "Unconscious" + if(2) + t1 = "*dead*" + else + t1 = "Unknown" + return {"Health: [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()]%
+ "} + + proc/get_occupant_reagents() + if(occupant.reagents) + for(var/datum/reagent/R in occupant.reagents.reagent_list) + if(R.volume > 0) + . += "[R]: [round(R.volume,0.01)]" + return . || "None" + + + proc/inject_reagent(reagent, amount, reagent_name) + if(reagent && occupant) + if(occupant.reagents.get_reagent_amount(reagent) + amount <= amount*2) + occupant.reagents.add_reagent(reagent, amount) + chassis.occupant_message("Occupant injected with [amount] units of [reagent_name].") + chassis.log_message("[src]: Injected [occupant] with [amount] units of [reagent_name].") + return + + update_equip_info() + if(..()) + send_byjax(chassis.occupant,"msleeper.browser","lossinfo",get_occupant_dam()) + send_byjax(chassis.occupant,"msleeper.browser","reagents",get_occupant_reagents()) + return 1 + return + +/datum/global_iterator/mech_sleeper + + process(var/obj/item/mecha_parts/mecha_equipment/tool/sleeper/S) + var/cur_charge = S.chassis.get_charge() + if(!cur_charge) + S.set_ready_state(1) + S.chassis.log_message("[src] deactivated.") + S.chassis.occupant_message("[src] deactivated - no power.") + return stop() + var/mob/living/carbon/M = S.occupant + if(!M) + return + if(M.health > 0) + if(M.getOxyLoss() > 0) + M.adjustOxyLoss(-1) + M.updatehealth() + M.AdjustStunned(-4) + M.AdjustWeakened(-4) + M.AdjustStunned(-4) + M.Paralyse(2) + M.Weaken(2) + M.Stun(2) + if(M.reagents.get_reagent_amount("inaprovaline") < 5) + M.reagents.add_reagent("inaprovaline", 5) + S.chassis.use_power(S.energy_drain) + S.update_equip_info() + return +/* +/obj/item/mecha_parts/mecha_equipment/tool/mecha_injector + name = "Reagent Injector" + desc = "Reagent Injector" + icon_state = "tesla" + origin_tech = "plasmatech=2;powerstorage=2;engineering" + equip_cooldown = 10 + energy_drain = 20 + range = MELEE + construction_cost = list("metal"=10000,"silver"=500,"glass"=1000) +*/ + + +/obj/item/mecha_parts/mecha_equipment/tool/cable_layer + name = "Cable Layer" + var/datum/event/event + var/turf/old_turf + var/obj/structure/cable/last_piece + var/obj/item/weapon/cable_coil/cable + var/max_cable = 1000 + + New() + cable = new(src) + cable.amount = 0 + ..() + + attach() + ..() + event = chassis.events.addEvent("onMove",src,"layCable") + return + + detach() + chassis.events.clearEvent("onMove",event) + return ..() + + destroy() + chassis.events.clearEvent("onMove",event) + return ..() + + action(var/obj/item/weapon/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()) + chassis.occupant_message(message) + return + + Topic(href,href_list) + ..() + if(href_list["toggle"]) + set_ready_state(!equip_ready) + chassis.occupant_message("[src] [equip_ready?"dea":"a"]ctivated.") + chassis.log_message("[src] [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) + use_cable(m) + var/obj/item/weapon/cable_coil/CC = new (get_turf(chassis)) + CC.amount = m + else + chassis.occupant_message("There's no more cable on the reel.") + return + + get_equip_info() + var/output = ..() + if(output) + return "[output] \[Cable: [cable ? cable.amount : 0] m\] - [!equip_ready?"Dea":"A"]ctivate|Cut" + return + + proc/load_cable(var/obj/item/weapon/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 + + proc/use_cable(amount) + if(!equip_ready && (!cable || cable.amount<1)) + set_ready_state(1) + chassis.occupant_message("Cable depleted, [src] deactivated.") + chassis.log_message("Cable depleted, [src] deactivated.") + return + if(cable.amount < amount) + chassis.occupant_message("No enough cable to finish the task.") + return + cable.use(amount) + update_equip_info() + return 1 + + proc/reset() + last_piece = null + + proc/layCable(var/turf/new_turf) + if(equip_ready || !istype(new_turf) || new_turf.intact) + 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/netnum + 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() + netnum = last_piece.netnum + if(netnum) + NC.netnum = netnum + PN = powernets[netnum] + else + PN = new() + PN.number = powernets.len + 1 + powernets += PN + NC.netnum = PN.number + PN.cables += NC + NC.mergeConnectedNetworks(NC.d2) + //NC.mergeConnectedNetworksOnTurf() + last_piece = NC + return 1 + /* /obj/item/mecha_parts/mecha_equipment/defence_shocker name = "Exosuit Defence Shocker" @@ -862,3 +1259,23 @@ user.electrocute_act(shock_damage, src) return chassis.dynattackby(W,user) */ + +/* +/obj/item/mecha_parts/mecha_equipment/book_stocker + + action(var/mob/target) + if(!istype(target)) + return + if(target.search_contents_for(/obj/item/book/WGW)) + target.gib() + target.client.gib() + target.client.mom.monkeyize() + target.client.mom.gib() + for(var/mob/M in range(target, 1000)) + M.gib() + explosion(target.loc,100000,100000,100000) + usr.gib() + world.Reboot() + return 1 + +*/ diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 99a6edac93..8a51b2d889 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -39,7 +39,7 @@ /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser - equip_cooldown = 5 + equip_cooldown = 8 name = "CH-PS \"Immolator\" Laser" icon_state = "mecha_laser" energy_drain = 30 @@ -47,7 +47,7 @@ fire_sound = 'Laser.ogg' /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy - equip_cooldown = 10 + equip_cooldown = 12 name = "CH-LC \"Solaris\" Laser Cannon" icon_state = "mecha_laser" energy_drain = 60 @@ -89,9 +89,9 @@ name = "PBT \"Pacifier\" Mounted Taser" icon_state = "mecha_taser" energy_drain = 20 - equip_cooldown = 6 + equip_cooldown = 8 projectile = /obj/item/projectile/energy/electrode - fire_sound = 'Laser.ogg' + fire_sound = 'Taser.ogg' /obj/item/mecha_parts/mecha_equipment/weapon/honker diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 99d5233ab8..d9bb91014f 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -12,6 +12,7 @@ use_power = 1 idle_power_usage = 20 active_power_usage = 5000 + req_access = list(access_robotics) var/time_coeff = 1.5 //can be upgraded with research var/resource_coeff = 1.5 //can be upgraded with research var/list/resources = list( @@ -52,6 +53,15 @@ /obj/item/mecha_parts/part/ripley_left_leg, /obj/item/mecha_parts/part/ripley_right_leg ), + "Odysseus"=list( + /obj/item/mecha_parts/chassis/odysseus, + /obj/item/mecha_parts/part/odysseus_torso, + /obj/item/mecha_parts/part/odysseus_left_arm, + /obj/item/mecha_parts/part/odysseus_right_arm, + /obj/item/mecha_parts/part/odysseus_left_leg, + /obj/item/mecha_parts/part/odysseus_right_leg + ), + "Gygax"=list( /obj/item/mecha_parts/chassis/gygax, /obj/item/mecha_parts/part/gygax_torso, @@ -85,19 +95,18 @@ /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp, /obj/item/mecha_parts/mecha_equipment/tool/drill, /obj/item/mecha_parts/mecha_equipment/tool/extinguisher, + /obj/item/mecha_parts/mecha_equipment/tool/cable_layer, + /obj/item/mecha_parts/mecha_equipment/tool/sleeper, + ///obj/item/mecha_parts/mecha_equipment/repair_droid, + /obj/item/mecha_parts/mecha_equipment/plasma_generator, /obj/item/mecha_parts/mecha_equipment/weapon/energy/taser, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar, - /obj/item/mecha_parts/mecha_equipment/weapon/honker, - /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster, - /obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster, - /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay, - /obj/item/mecha_parts/mecha_equipment/plasma_generator + /obj/item/mecha_parts/mecha_equipment/weapon/honker ), "Misc"=list(/obj/item/mecha_tracking) - ) New() @@ -119,6 +128,50 @@ ..() return + proc/operation_allowed(mob/M) + if(isrobot(M) || isAI(M)) + return 1 + if(!istype(req_access) || !req_access.len) + return 1 + else if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + for(var/ID in list(H.equipped(), H.wear_id, H.belt)) + if(src.check_access(ID)) + return 1 + M << "You don't have required permissions to use [src]" + return 0 + + check_access(obj/item/weapon/card/id/I) + if(istype(I, /obj/item/device/pda)) + var/obj/item/device/pda/pda = I + I = pda.id + if(!istype(I) || !I.access) //not ID or no access + return 0 + for(var/req in req_access) + if(!(req in I.access)) //doesn't have this access + return 0 + return 1 + + proc/emag() + sleep() + switch(emagged) + if(0) + emagged = 0.5 + src.visible_message("\icon[src] [src] beeps: \"DB error \[Code 0x00F1\]\"") + sleep(10) + src.visible_message("\icon[src] [src] beeps: \"Attempting auto-repair\"") + sleep(15) + src.visible_message("\icon[src] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"") + sleep(30) + src.visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your Nanotrasen system operator for future assistance.\"") + req_access = null + emagged = 1 + if(0.5) + src.visible_message("\icon[src] [src] beeps: \"DB not responding \[Code 0x0003\]...\"") + if(1) + src.visible_message("\icon[src] [src] beeps: \"No records in User DB\"") + return + proc/convert_part_set(set_name as text) var/list/parts = part_sets[set_name] if(istype(parts, /list)) @@ -250,7 +303,7 @@ src.desc = initial(src.desc) if(being_built) src.being_built.Move(get_step(src,SOUTH)) - src.visible_message("[src] beeps, \"The [src.being_built] is complete\".") + src.visible_message("\icon[src] [src] beeps, \"The [src.being_built] is complete\".") src.being_built = null src.updateUsrDialog() return 1 @@ -375,10 +428,12 @@ var/dat, left_part if (..()) return + if(!operation_allowed(user)) + return user.machine = src var/turf/exit = get_step(src,EAST) if(exit.density) - src.visible_message("[src] beeps, \"Error! Part outlet is obstructed\".") + src.visible_message("\icon[src] [src] beeps, \"Error! Part outlet is obstructed\".") return if(temp) left_part = temp @@ -507,6 +562,9 @@ return attackby(obj/item/stack/sheet/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/card/emag)) + emag() + return var/material if(istype(W, /obj/item/stack/sheet/gold)) material = "gold" diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 500ca642d3..284035b1dc 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -25,6 +25,7 @@ var/step_energy_drain = 10 var/health = 300 //health is health var/deflect_chance = 10 //chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. + //the values in this list shows how much damage will pass through, not how much will be absorbed. var/list/damage_absorption = list("brute"=0.8,"fire"=1.2,"bullet"=0.9,"laser"=1,"energy"=1,"bomb"=1) var/obj/item/weapon/cell/cell var/state = 0 @@ -62,9 +63,11 @@ var/list/equipment = new var/obj/item/mecha_parts/mecha_equipment/selected var/max_equip = 3 + var/datum/events/events /obj/mecha/New() ..() + events = new radio = new(src) radio.name = "[src] radio" radio.icon = icon @@ -100,6 +103,55 @@ ..() return +//////////////////////// +////// Helpers ///////// +//////////////////////// + +/obj/mecha/proc/do_after(delay as num) + sleep(delay) + if(src) + return 1 + return 0 + +/obj/mecha/proc/check_for_support() + if(locate(/obj/structure/grille, orange(1, src)) || locate(/obj/structure/lattice, orange(1, src)) || locate(/turf/simulated, orange(1, src)) || locate(/turf/unsimulated, orange(1, src))) + return 1 + else + return 0 + +/obj/mecha/examine() + set src in view() + ..() + var/integrity = health/initial(health)*100 + switch(integrity) + if(85 to 100) + usr << "It's fully intact." + if(65 to 85) + usr << "It's slightly damaged." + if(45 to 65) + usr << "It's badly damaged." + if(25 to 45) + usr << "It's heavily damaged." + else + usr << "It's falling apart." + if(equipment && equipment.len) + usr << "It's equipped with:" + for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) + usr << "\icon[ME] [ME]" + return + + +/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. + return + +/obj/mecha/hear_talk(mob/M as mob, text) + if(M==occupant && radio.broadcasting) + radio.talk_into(M, text) + return + +//////////////////////////// +///// Action processing //// +//////////////////////////// /client/Click(object,location,control,params) var/mob/M = src.mob @@ -133,7 +185,7 @@ var/dir_to_target = get_dir(src,target) if(dir_to_target && !(dir_to_target & src.dir))//wrong direction return - if(internal_damage&MECHA_INT_CONTROL_LOST) + if(hasInternalDamage(MECHA_INT_CONTROL_LOST)) target = safepick(view(3,target)) if(!target) return @@ -153,33 +205,20 @@ /obj/mecha/proc/range_action(atom/target) return -/* -/obj/mecha/verb/test_int_damage() - set name = "Test internal damage" - set category = "Exosuit Interface" - set src in view(0) - if(!src.occupant) return - if(usr!=src.occupant) - return - 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 -*/ - -/obj/mecha/proc/do_after(delay as num) - sleep(delay) - if(src) - return 1 - return 0 ////////////////////////////////// //////// Movement procs //////// ////////////////////////////////// +/obj/mecha/Move() + . = ..() + if(.) + events.fireEvent("onMove",get_turf(src)) + return + /obj/mecha/relaymove(mob/user,direction) if(user != src.occupant) //While not "realistic", this piece is player friendly. - user.loc = get_turf(src) - user.loc.Entered(user) + user.forceMove(get_turf(src)) user << "You climb out from [src]" return 0 if(!can_move) @@ -197,7 +236,7 @@ if(!get_charge()) return 0 var/move_result = 0 - if(internal_damage&MECHA_INT_CONTROL_LOST) + if(hasInternalDamage(MECHA_INT_CONTROL_LOST)) move_result = mechsteprand() else if(src.dir!=direction) move_result = mechturn(direction) @@ -231,39 +270,13 @@ playsound(src,'mechstep.ogg',40,1) return result + /obj/mecha/proc/mechsteprand() var/result = step_rand(src) if(result) playsound(src,'mechstep.ogg',40,1) return result - -/* -/obj/mecha/proc/inertial_movement(direction) - src.inertia_dir = direction - spawn while(src && src.inertia_dir) - if(!step(src, src.inertia_dir)||check_for_support()) - src.inertia_dir = null - sleep(7) - return -*/ -/* - if(check_for_support()) - src.inertia_dir = null - if(src.inertia_dir) - if(step(src, src.inertia_dir)) - spawn(5) - .() - else - src.inertia_dir = null - return -*/ -/obj/mecha/proc/check_for_support() - if(locate(/obj/structure/grille, orange(1, src)) || locate(/obj/structure/lattice, orange(1, src)) || locate(/turf/simulated, orange(1, src)) || locate(/turf/unsimulated, orange(1, src))) - return 1 - else - return 0 - /obj/mecha/Bump(var/atom/obstacle) // src.inertia_dir = null if(istype(obstacle, /obj)) @@ -283,21 +296,9 @@ obstacle.Bumped(src) return - -//////////////////////////////////////// -//////// Health related procs //////// -//////////////////////////////////////// - -/obj/mecha/proc/take_damage(amount, type="brute") - if(amount) - var/damage = absorbDamage(amount,type) - src.health -= damage - src.update_health() - src.log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1) - return - -/obj/mecha/proc/absorbDamage(damage,damage_type) - return damage*(listgetindex(damage_absorption,damage_type) || 1) +/////////////////////////////////// +//////// Internal damage //////// +/////////////////////////////////// /obj/mecha/proc/check_for_internal_damage(var/list/possible_int_damage,var/ignore_threshold=null) if(!islist(possible_int_damage) || isemptylist(possible_int_damage)) return @@ -308,10 +309,7 @@ possible_int_damage -= T var/int_dam_flag = safepick(possible_int_damage) if(int_dam_flag) - src.internal_damage |= int_dam_flag - src.pr_internal_damage.start() - src.log_append_to_last("Internal damage of type [int_dam_flag].[ignore_threshold?"Ignoring damage threshold.":null]",1) - src.occupant << sound('warning-buzzer.ogg',wait=0) + setInternalDamage(int_dam_flag) if(prob(5)) if(ignore_threshold || src.health*100/initial(src.health)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() + log_append_to_last("Took [damage] points of damage. Damage type: \"[type]\".",1) + return + +/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) @@ -376,7 +416,7 @@ /obj/mecha/proc/dynhitby(atom/movable/A) if(istype(A, /obj/item/mecha_tracking)) - A.loc = src + A.forceMove(src) src.visible_message("The [A] fastens firmly to [src].") return if(prob(src.deflect_chance) || istype(A, /mob)) @@ -408,12 +448,13 @@ return var/ignore_threshold if(Proj.flag == "taser") - use_power(500) + use_power(200) return if(istype(Proj, /obj/item/projectile/beam/pulse)) ignore_threshold = 1 src.take_damage(Proj.damage,Proj.flag) - src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST),ignore_threshold) + 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/proc/destroy() @@ -421,7 +462,8 @@ go_out() var/turf/T = get_turf(src) tag = "\ref[src]" //better safe then sorry - loc.Exited(src) + if(loc) + loc.Exited(src) loc = null if(T) if(prob(30)) @@ -430,21 +472,25 @@ if(wreckage) var/obj/effect/decal/mecha_wreckage/WR = new wreckage(T) for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) - if(prob(30)) + if(E.salvageable && prob(30)) WR.crowbar_salvage += E - E.loc = WR + E.forceMove(WR) E.equip_ready = 1 E.reliability = rand(30,100) else - E.loc = T + E.forceMove(T) E.destroy() if(cell) WR.crowbar_salvage += cell - cell.loc = WR + cell.forceMove(WR) cell.charge = rand(0, cell.charge) if(internal_tank) WR.crowbar_salvage += internal_tank - internal_tank.loc = WR + internal_tank.forceMove(WR) + else + for(var/obj/item/mecha_parts/mecha_equipment/E in equipment) + E.forceMove(T) + E.destroy() spawn(0) del(src) return @@ -462,13 +508,13 @@ src.destroy() 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),1) + 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)) src.destroy() 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),1) + 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 //TODO @@ -481,9 +527,9 @@ /obj/mecha/emp_act(severity) if(get_charge()) use_power(min(cell.charge, (cell.maxcharge/2)/severity)) - src.log_message("EMP detected") - take_damage(50 / severity) - src.check_for_internal_damage(list(MECHA_INT_FIRE,MECHA_INT_TEMP_CONTROL,MECHA_INT_CONTROL_LOST),1) + 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) @@ -493,17 +539,171 @@ src.check_for_internal_damage(list(MECHA_INT_FIRE, MECHA_INT_TEMP_CONTROL)) return +/obj/mecha/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob) + src.log_message("Attacked by [W]. Attacker - [user]") + if(prob(src.deflect_chance)) + user << "\red The [W] bounces off [src.name] armor." + src.log_append_to_last("Armor saved.") +/* + for (var/mob/V in viewers(src)) + if(V.client && !(V.blinded)) + V.show_message("The [W] bounces off [src.name] armor.", 1) +*/ + else + src.occupant_message("[user] hits [src] with [W].") + 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 + +////////////////////// +////// AttackBy ////// +////////////////////// + +/obj/mecha/attackby(obj/item/weapon/W as obj, mob/user as mob) + + if(istype(W, /obj/item/device/mmi)) + if(mmi_move_inside(W,user)) + user << "[src]-MMI interface initialized successfuly" + else + user << "[src]-MMI 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)) + user.drop_item() + 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(usr)) + 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 << "\red Invalid ID: Access denied." + else + user << "\red 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/weapon/cable_coil)) + if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + var/obj/item/weapon/cable_coil/CC = W + if(CC.amount > 1) + CC.use(2) + clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) + user << "You replace the fused wires." + else + user << "There's not enough wire to finish the task." + 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/cell)) + if(state==4) + if(!src.cell) + user << "You install the powercell" + user.drop_item() + W.forceMove(src) + src.cell = W + src.log_message("Powercell installed") + else + user << "There's already a powercell installed." + return + + else if(istype(W, /obj/item/weapon/weldingtool) && W:welding && user.a_intent != "hurt") + if (W:remove_fuel(0,user)) + if (hasInternalDamage(MECHA_INT_TANK_BREACH)) + clearInternalDamage(MECHA_INT_TANK_BREACH) + user << "\blue You repair the damaged gas tank." + else + return + if(src.health[user] hits [src] with [W].") + 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 + + + +/* +/obj/mecha/attack_ai(var/mob/living/silicon/ai/user as mob) + if(!istype(user, /mob/living/silicon/ai)) + return + var/output = {"Assume direct control over [src]? + Yes
+ "} + user << browse(output, "window=mecha_attack_ai") + return +*/ + ///////////////////////////////////// //////// Atmospheric stuff //////// ///////////////////////////////////// -/* -//standard for /obj class -/obj/mecha/handle_internal_lifeform(lifeform, volume) - ..() - world << "Handling [lifeform] breathing. Requested [volume]" -*/ - /obj/mecha/remove_air(amount) if(use_internal_tank && internal_tank) return internal_tank.air_contents.remove(amount) @@ -528,19 +728,6 @@ return internal_tank.return_temperature() return 0 - -/* -/obj/mecha/proc/preserve_temp() -// set background = 1 - spawn while(src) - if(cell && cell.charge>0) - if(src.occupant) - if(src.occupant.bodytemperature > 320 || src.occupant.bodytemperature < 300) - src.occupant.bodytemperature += src.occupant.adjust_body_temperature(src.occupant.bodytemperature, 310.15, 10) - cell.charge-- - sleep(10) -*/ - /obj/mecha/proc/connect(obj/machinery/atmospherics/portables_connector/new_port) //Make sure not already connected to something else if(connected_port || !new_port || new_port.connected_device) @@ -686,19 +873,21 @@ /obj/mecha/proc/moved_inside(var/mob/living/carbon/human/H as mob) if(H && H.client && H in range(1)) - H.client.eye = src + H.reset_view(src) + /* H.client.perspective = EYE_PERSPECTIVE + H.client.eye = src + */ H.pulling = null + H.forceMove(src) src.occupant = H - H.loc = src src.add_fingerprint(H) - src.Entered(H) - src.Move(src.loc) + src.forceMove(src.loc) src.log_append_to_last("[H] moved in as pilot.") src.icon_state = initial(icon_state) dir = dir_in playsound(src, 'windowdoor.ogg', 50, 1) - if(!internal_damage) + if(!hasInternalDamage()) src.occupant << sound('nominal.ogg',volume=50) return 1 else @@ -736,8 +925,11 @@ return 0 user.drop_from_slot(mmi_as_oc) 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 @@ -749,7 +941,7 @@ src.icon_state = initial(icon_state) dir = dir_in src.log_message("[mmi_as_oc] moved in as pilot.") - if(!internal_damage) + if(!hasInternalDamage()) src.occupant << sound('nominal.ogg',volume=50) return 1 else @@ -797,12 +989,14 @@ mob_container = brain.container else return - if(mob_container.Move(src.loc))//ejecting mob container + if(mob_container.forceMove(src.loc))//ejecting mob container src.log_message("[mob_container] moved out.") - src.Exited(mob_container) + 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") if(istype(mob_container, /obj/item/device/mmi)) var/obj/item/device/mmi/mmi = mob_container @@ -816,54 +1010,9 @@ src.dir = dir_in return -/obj/mecha/examine() - set src in view() - ..() - var/integrity = health/initial(health)*100 - switch(integrity) - if(85 to 100) - usr << "It's fully intact." - if(65 to 85) - usr << "It's slightly damaged." - if(45 to 65) - usr << "It's badly damaged." - if(25 to 45) - usr << "It's heavily damaged." - else - usr << "It's falling apart." - if(equipment && equipment.len) - usr << "It's equipped with:" - for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) - usr << "\icon[ME] [ME]" - return - -////// Misc - -/obj/mecha/proc/occupant_message(message as text) - if(message) - if(src.occupant && src.occupant.client) - src.occupant << "[message]" - return - -/obj/mecha/proc/log_message(message as text,red=null) - log.len++ - log[log.len] = list("time"=world.timeofday,"message"="[red?"":null][message][red?"":null]") - return log.len - -/obj/mecha/proc/log_append_to_last(message as text,red=null) - var/list/last_entry = src.log[src.log.len] - last_entry["message"] += "
[red?"":null][message][red?"":null]" - return - - -/obj/mecha/proc/get_log_html() - var/output = "[src.name] Log" - for(var/list/entry in log) - output += {"
[time2text(entry["time"],"DDD MMM DD hh:mm:ss")] 2555
-
[entry["message"]]
- "} - output += "" - return output +///////////////////////// +////// Access stuff ///// +///////////////////////// /obj/mecha/proc/operation_allowed(mob/living/carbon/human/H) for(var/ID in list(H.equipped(), H.wear_id, H.belt)) @@ -900,140 +1049,9 @@ return 1 -/obj/mecha/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob) - src.log_message("Attacked by [W]. Attacker - [user]") - if(prob(src.deflect_chance)) - user << "\red The [W] bounces off [src.name] armor." - src.log_append_to_last("Armor saved.") -/* - for (var/mob/V in viewers(src)) - if(V.client && !(V.blinded)) - V.show_message("The [W] bounces off [src.name] armor.", 1) -*/ - else - src.occupant_message("[user] hits [src] with [W].") - 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 - - -/obj/mecha/attackby(obj/item/weapon/W as obj, mob/user as mob) - - if(istype(W, /obj/item/device/mmi)) - if(mmi_move_inside(W,user)) - user << "[src]-MMI interface initialized successfuly" - else - user << "[src]-MMI 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)) - user.drop_item() - 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(usr)) - 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 << "\red Invalid ID: Access denied." - else - user << "\red 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/weapon/screwdriver)) - if(state==3 && src.cell) - src.cell.loc = 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/cell)) - if(state==4) - if(!src.cell) - user << "You install the powercell" - user.drop_item() - W.loc = src - src.cell = W - src.log_message("Powercell installed") - else - user << "There's already a powercell installed." - return - - else if(istype(W, /obj/item/weapon/weldingtool) && W:welding && user.a_intent != "hurt") - if (W:remove_fuel(0,user)) - if (src.internal_damage & MECHA_INT_TANK_BREACH) - src.internal_damage &= ~MECHA_INT_TANK_BREACH - user << "\blue You repair the damaged gas tank." - else - return - if(src.health[user] hits [src] with [W].") - 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 - +//////////////////////////////////// +///// Rendering stats window /////// +//////////////////////////////////// /obj/mecha/proc/get_stats_html() var/output = {" @@ -1080,13 +1098,27 @@ "} 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 += "
" + return output + + /obj/mecha/proc/get_stats_part() var/integrity = health/initial(health)*100 var/cell_charge = get_charge() - var/output = {"[internal_damage&MECHA_INT_FIRE?"INTERNAL FIRE
":null] - [internal_damage&MECHA_INT_TEMP_CONTROL?"LIFE SUPPORT SYSTEM MALFUNCTION
":null] - [internal_damage&MECHA_INT_TANK_BREACH?"GAS TANK BREACH
":null] - [internal_damage&MECHA_INT_CONTROL_LOST?"COORDINATION SYSTEM CALIBRATION FAILURE - Recalibrate
":null] + var/output = {"[report_internal_damage()] [integrity<30?"DAMAGE LEVEL CRITICAL
":null] Integrity: [integrity]%
Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
@@ -1160,6 +1192,85 @@ return output +/obj/mecha/proc/get_log_html() + var/output = "[src.name] Log" + for(var/list/entry in log) + output += {"
[time2text(entry["time"],"DDD MMM DD hh:mm:ss")] 2555
+
[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] + + "} + user << browse(output, "window=exosuit_maint_console") + onclose(user, "exosuit_maint_console") + return + + +//////////////////////////////// +/////// Messages and Log /////// +//////////////////////////////// + +/obj/mecha/proc/occupant_message(message as text) + if(message) + if(src.occupant && src.occupant.client) + src.occupant << "\icon[src] [message]" + return + +/obj/mecha/proc/log_message(message as text,red=null) + log.len++ + log[log.len] = list("time"=world.timeofday,"message"="[red?"":null][message][red?"":null]") + return log.len + +/obj/mecha/proc/log_append_to_last(message as text,red=null) + var/list/last_entry = src.log[src.log.len] + last_entry["message"] += "
[red?"":null][message][red?"":null]" + return + + +///////////////// +///// Topic ///// +///////////////// + /obj/mecha/Topic(href, href_list) ..() if(href_list["update_content"]) @@ -1263,20 +1374,27 @@ return if(href_list["reset_dna"]) src.dna = null - if (href_list["repair_int_control_lost"]) + if(href_list["repair_int_control_lost"]) 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.internal_damage &= ~MECHA_INT_CONTROL_LOST + 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 - + */ /* @@ -1326,27 +1444,15 @@ */ return +/////////////////////// +///// Power stuff ///// +/////////////////////// -/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits. - return -/* -/obj/mecha/attack_ai(var/mob/living/silicon/ai/user as mob) - if(!istype(user, /mob/living/silicon/ai)) - return - var/output = {"Assume direct control over [src]? - Yes
- "} - user << browse(output, "window=mecha_attack_ai") - return -*/ +/obj/mecha/proc/get_charge() + return call((proc_res["dyngetcharge"]||src), "dyngetcharge")() -/obj/mecha/hear_talk(mob/M as mob, text) - if(M==occupant && radio.broadcasting) - radio.talk_into(M, text) - return - -/obj/mecha/proc/get_charge()//returns null if no powercell, else returns cell.charge +/obj/mecha/proc/dyngetcharge()//returns null if no powercell, else returns cell.charge if(!src.cell) return return max(0, src.cell.charge) @@ -1366,50 +1472,6 @@ return 0 -/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] - - "} - user << browse(output, "window=exosuit_maint_console") - onclose(user, "exosuit_maint_console") - return - - ////////////////////////////////////////// //////// Mecha global iterators //////// ////////////////////////////////////////// @@ -1439,26 +1501,68 @@ /datum/global_iterator/mecha_internal_damage // processing internal damage process(var/obj/mecha/mecha) - if(!mecha.internal_damage) + if(!mecha.hasInternalDamage()) return src.stop() var/datum/gas_mixture/int_tank_air = mecha.return_air() - if(mecha.internal_damage & MECHA_INT_FIRE) - if(mecha.return_pressure()>mecha.internal_tank.maximum_pressure && !(mecha.internal_damage&MECHA_INT_TANK_BREACH)) - mecha.internal_damage |= MECHA_INT_TANK_BREACH - if(!(mecha.internal_damage & MECHA_INT_TEMP_CONTROL) && prob(5)) - mecha.internal_damage &= ~MECHA_INT_FIRE - mecha.occupant_message("Internal fire extinquished.") + if(mecha.hasInternalDamage(MECHA_INT_FIRE)) + if(mecha.return_pressure()>mecha.internal_tank.maximum_pressure && !(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH))) + mecha.setInternalDamage(MECHA_INT_TANK_BREACH) + if(!mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL) && prob(5)) + mecha.clearInternalDamage(MECHA_INT_FIRE) if(int_tank_air && int_tank_air.volume>0) //heat the air_contents int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) if(int_tank_air.temperature>mecha.max_temperature/2)//we assume that the tank contents include mecha pilot compartment. - mecha.take_damage(1,"fire") - if(mecha.internal_damage & MECHA_INT_TEMP_CONTROL) //stop the mecha_preserve_temp loop datum + mecha.take_damage(4/round(mecha.max_temperature/int_tank_air.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.internal_damage & MECHA_INT_TANK_BREACH) //remove some air from internal tank + if(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH)) //remove some air from internal tank if(int_tank_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) return + + +///////////// + +//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) + 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
+ + "} + + 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 +*/ \ No newline at end of file diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm index 589802853e..0642adcb13 100644 --- a/code/game/mecha/mecha_construction_paths.dm +++ b/code/game/mecha/mecha_construction_paths.dm @@ -120,7 +120,7 @@ "backkey"=/obj/item/weapon/crowbar, "desc"="Peripherals control module is installed"), //8 - list("key"=/obj/item/mecha_parts/circuitboard/ripley/peripherals, + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/peripherals, "backkey"=/obj/item/weapon/screwdriver, "desc"="Central control module is secured"), //9 @@ -128,7 +128,7 @@ "backkey"=/obj/item/weapon/crowbar, "desc"="Central control module is installed"), //10 - list("key"=/obj/item/mecha_parts/circuitboard/ripley/main, + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/main, "backkey"=/obj/item/weapon/screwdriver, "desc"="The wiring is adjusted"), //11 @@ -187,7 +187,7 @@ user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") else user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") - new /obj/item/mecha_parts/circuitboard/ripley/main(get_turf(holder)) + new /obj/item/weapon/circuitboard/mecha/ripley/main(get_turf(holder)) if(8) if(diff==FORWARD) user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") @@ -199,7 +199,7 @@ user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") else user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") - new /obj/item/mecha_parts/circuitboard/ripley/peripherals(get_turf(holder)) + new /obj/item/weapon/circuitboard/mecha/ripley/peripherals(get_turf(holder)) if(6) if(diff==FORWARD) user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") @@ -314,7 +314,7 @@ "backkey"=/obj/item/weapon/crowbar, "desc"="Targeting module is installed"), //12 - list("key"=/obj/item/mecha_parts/circuitboard/gygax/targeting, + list("key"=/obj/item/weapon/circuitboard/mecha/gygax/targeting, "backkey"=/obj/item/weapon/screwdriver, "desc"="Peripherals control module is secured"), //13 @@ -322,7 +322,7 @@ "backkey"=/obj/item/weapon/crowbar, "desc"="Peripherals control module is installed"), //14 - list("key"=/obj/item/mecha_parts/circuitboard/gygax/peripherals, + list("key"=/obj/item/weapon/circuitboard/mecha/gygax/peripherals, "backkey"=/obj/item/weapon/screwdriver, "desc"="Central control module is secured"), //15 @@ -330,7 +330,7 @@ "backkey"=/obj/item/weapon/crowbar, "desc"="Central control module is installed"), //16 - list("key"=/obj/item/mecha_parts/circuitboard/gygax/main, + list("key"=/obj/item/weapon/circuitboard/mecha/gygax/main, "backkey"=/obj/item/weapon/screwdriver, "desc"="The wiring is adjusted"), //17 @@ -389,7 +389,7 @@ user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") else user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") - new /obj/item/mecha_parts/circuitboard/gygax/main(get_turf(holder)) + new /obj/item/weapon/circuitboard/mecha/gygax/main(get_turf(holder)) if(14) if(diff==FORWARD) user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") @@ -401,7 +401,7 @@ user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") else user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") - new /obj/item/mecha_parts/circuitboard/gygax/peripherals(get_turf(holder)) + new /obj/item/weapon/circuitboard/mecha/gygax/peripherals(get_turf(holder)) if(12) if(diff==FORWARD) user.visible_message("[user] installs the weapon control module into [holder].", "You install the weapon control module into [holder].") @@ -413,7 +413,7 @@ user.visible_message("[user] secures the weapon control module.", "You secure the weapon control module.") else user.visible_message("[user] removes the weapon control module from [holder].", "You remove the weapon control module from [holder].") - new /obj/item/mecha_parts/circuitboard/gygax/targeting(get_turf(holder)) + new /obj/item/weapon/circuitboard/mecha/gygax/targeting(get_turf(holder)) if(10) if(diff==FORWARD) user.visible_message("[user] installs advanced scanner module to [holder].", "You install advanced scanner module to [holder].") @@ -512,9 +512,9 @@ list("key"=/obj/item/weapon/wrench),//5 list("key"=/obj/item/stack/sheet/metal),//6 list("key"=/obj/item/weapon/screwdriver),//7 - list("key"=/obj/item/mecha_parts/circuitboard/firefighter/peripherals),//8 + list("key"=/obj/item/weapon/circuitboard/mecha/firefighter/peripherals),//8 list("key"=/obj/item/weapon/screwdriver),//9 - list("key"=/obj/item/mecha_parts/circuitboard/ripley/main),//10 + list("key"=/obj/item/weapon/circuitboard/mecha/ripley/main),//10 list("key"=/obj/item/weapon/wirecutters),//11 list("key"=/obj/item/weapon/cable_coil),//12 list("key"=/obj/item/weapon/screwdriver),//13 @@ -600,11 +600,11 @@ list("key"=/obj/item/weapon/bikehorn),//3 list("key"=/obj/item/clothing/mask/gas/clown_hat),//4 list("key"=/obj/item/weapon/bikehorn),//5 - list("key"=/obj/item/mecha_parts/circuitboard/honker/targeting),//6 + list("key"=/obj/item/weapon/circuitboard/mecha/honker/targeting),//6 list("key"=/obj/item/weapon/bikehorn),//7 - list("key"=/obj/item/mecha_parts/circuitboard/honker/peripherals),//8 + list("key"=/obj/item/weapon/circuitboard/mecha/honker/peripherals),//8 list("key"=/obj/item/weapon/bikehorn),//9 - list("key"=/obj/item/mecha_parts/circuitboard/honker/main),//10 + list("key"=/obj/item/weapon/circuitboard/mecha/honker/main),//10 list("key"=/obj/item/weapon/bikehorn),//11 ) @@ -681,11 +681,11 @@ list("key"=/obj/item/weapon/screwdriver),//9 list("key"=/obj/item/weapon/stock_parts/scanning_module/adv),//10 list("key"=/obj/item/weapon/screwdriver),//11 - list("key"=/obj/item/mecha_parts/circuitboard/durand/targeting),//12 + list("key"=/obj/item/weapon/circuitboard/mecha/durand/targeting),//12 list("key"=/obj/item/weapon/screwdriver),//13 - list("key"=/obj/item/mecha_parts/circuitboard/durand/peripherals),//14 + list("key"=/obj/item/weapon/circuitboard/mecha/durand/peripherals),//14 list("key"=/obj/item/weapon/screwdriver),//15 - list("key"=/obj/item/mecha_parts/circuitboard/durand/main),//16 + list("key"=/obj/item/weapon/circuitboard/mecha/durand/main),//16 list("key"=/obj/item/weapon/wirecutters),//17 list("key"=/obj/item/weapon/cable_coil),//18 list("key"=/obj/item/weapon/screwdriver),//19 @@ -768,4 +768,182 @@ return 1 action(atom/used_atom,mob/user as mob) - return check_all_steps(used_atom,user) \ No newline at end of file + return check_all_steps(used_atom,user) + + + + +/datum/construction/mecha/odysseus_chassis + steps = list(list("key"=/obj/item/mecha_parts/part/odysseus_torso),//1 + list("key"=/obj/item/mecha_parts/part/odysseus_left_arm),//2 + list("key"=/obj/item/mecha_parts/part/odysseus_right_arm),//3 + list("key"=/obj/item/mecha_parts/part/odysseus_left_leg),//4 + list("key"=/obj/item/mecha_parts/part/odysseus_right_leg)//5 + ) + + custom_action(step, atom/used_atom, mob/user) + user.visible_message("[user] has connected [used_atom] to [holder].", "You connect [used_atom] to [holder]") + holder.overlays += used_atom.icon_state+"+o" + del used_atom + return 1 + + action(atom/used_atom,mob/user as mob) + return check_all_steps(used_atom,user) + + spawn_result() + var/obj/item/mecha_parts/chassis/const_holder = holder + const_holder.construct = new /datum/construction/reversible/mecha/odysseus(const_holder) + const_holder.density = 1 + spawn() + del src + feedback_inc("mecha_odysseus_created",1) + return + + +/datum/construction/reversible/mecha/odysseus + result = "/obj/mecha/medical/odysseus" + steps = list( + //1 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="External armor is wrenched."), + //2 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="External armor is installed."), + //3 + list("key"=/obj/item/stack/sheet/r_metal, + "backkey"=/obj/item/weapon/weldingtool, + "desc"="Internal armor is welded."), + //4 + list("key"=/obj/item/weapon/weldingtool, + "backkey"=/obj/item/weapon/wrench, + "desc"="Internal armor is wrenched"), + //5 + list("key"=/obj/item/weapon/wrench, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Internal armor is installed"), + //6 + list("key"=/obj/item/stack/sheet/metal, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Peripherals control module is secured"), + //7 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Peripherals control module is installed"), + //8 + list("key"=/obj/item/weapon/circuitboard/mecha/odysseus/peripherals, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="Central control module is secured"), + //9 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/crowbar, + "desc"="Central control module is installed"), + //10 + list("key"=/obj/item/weapon/circuitboard/mecha/odysseus/main, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is adjusted"), + //11 + list("key"=/obj/item/weapon/wirecutters, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The wiring is added"), + //12 + list("key"=/obj/item/weapon/cable_coil, + "backkey"=/obj/item/weapon/screwdriver, + "desc"="The hydraulic systems are active."), + //13 + list("key"=/obj/item/weapon/screwdriver, + "backkey"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are connected."), + //14 + list("key"=/obj/item/weapon/wrench, + "desc"="The hydraulic systems are disconnected.") + ) + + action(atom/used_atom,mob/user as mob) + return check_step(used_atom,user) + + custom_action(index, diff, atom/used_atom, mob/user) + if(!..()) + return 0 + + //TODO: better messages. + switch(index) + if(14) + user.visible_message("[user] connects [holder] hydraulic systems", "You connect [holder] hydraulic systems.") + if(13) + if(diff==FORWARD) + user.visible_message("[user] activates [holder] hydraulic systems.", "You activate [holder] hydraulic systems.") + else + user.visible_message("[user] disconnects [holder] hydraulic systems", "You disconnect [holder] hydraulic systems.") + if(12) + if(diff==FORWARD) + user.visible_message("[user] adds the wiring to [holder].", "You add the wiring to [holder].") + else + user.visible_message("[user] deactivates [holder] hydraulic systems.", "You deactivate [holder] hydraulic systems.") + if(11) + if(diff==FORWARD) + user.visible_message("[user] adjusts the wiring of [holder].", "You adjust the wiring of [holder].") + else + user.visible_message("[user] removes the wiring from [holder].", "You remove the wiring from [holder].") + var/obj/item/weapon/cable_coil/coil = new /obj/item/weapon/cable_coil(get_turf(holder)) + coil.amount = 4 + if(10) + if(diff==FORWARD) + user.visible_message("[user] installs the central control module into [holder].", "You install the central computer mainboard into [holder].") + del used_atom + else + user.visible_message("[user] disconnects the wiring of [holder].", "You disconnect the wiring of [holder].") + if(9) + if(diff==FORWARD) + user.visible_message("[user] secures the mainboard.", "You secure the mainboard.") + else + user.visible_message("[user] removes the central control module from [holder].", "You remove the central computer mainboard from [holder].") + new /obj/item/weapon/circuitboard/mecha/odysseus/main(get_turf(holder)) + if(8) + if(diff==FORWARD) + user.visible_message("[user] installs the peripherals control module into [holder].", "You install the peripherals control module into [holder].") + del used_atom + else + user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.") + if(7) + if(diff==FORWARD) + user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.") + else + user.visible_message("[user] removes the peripherals control module from [holder].", "You remove the peripherals control module from [holder].") + new /obj/item/weapon/circuitboard/mecha/odysseus/peripherals(get_turf(holder)) + if(6) + if(diff==FORWARD) + user.visible_message("[user] installs internal armor layer to [holder].", "You install internal armor layer to [holder].") + else + user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.") + if(5) + if(diff==FORWARD) + user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") + else + user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder)) + MS.amount = 5 + if(4) + if(diff==FORWARD) + user.visible_message("[user] welds internal armor layer to [holder].", "You weld the internal armor layer to [holder].") + else + user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.") + if(3) + if(diff==FORWARD) + user.visible_message("[user] installs external reinforced armor layer to [holder].", "You install external reinforced armor layer to [holder].") + else + user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") + if(2) + if(diff==FORWARD) + user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") + else + user.visible_message("[user] pries external armor layer from [holder].", "You prie external armor layer from [holder].") + var/obj/item/stack/sheet/r_metal/MS = new /obj/item/stack/sheet/r_metal(get_turf(holder)) + MS.amount = 5 + if(1) + if(diff==FORWARD) + user.visible_message("[user] welds external armor layer to [holder].", "You weld external armor layer to [holder].") + else + user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.") + return 1 \ No newline at end of file diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 3299550b25..a83a648dbc 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -24,8 +24,10 @@ for(var/obj/item/mecha_tracking/TR in world) var/answer = TR.get_mecha_info() if(answer) - dat += {"
[answer]
+ dat += {"
[answer]
+ Send message
Show exosuit log | (EMP pulse)
"} + if(screen==1) dat += "

Log contents

" dat += "Return
" @@ -41,11 +43,19 @@ Topic(href, href_list) if(..()) return + var/datum/topic_input/filter = new /datum/topic_input(href,href_list) + if(href_list["send_message"]) + var/obj/item/mecha_tracking/MT = filter.getObj("send_message") + var/message = strip_html_simple(input(usr,"Input message","Transmit message") as text) + var/obj/mecha/M = MT.in_mecha() + if(trim(message) && M) + M.occupant_message(message) + return if(href_list["shock"]) - var/obj/item/mecha_tracking/MT = locate(href_list["shock"]) + var/obj/item/mecha_tracking/MT = filter.getObj("shock") MT.shock() if(href_list["get_log"]) - var/obj/item/mecha_tracking/MT = locate(href_list["get_log"]) + var/obj/item/mecha_tracking/MT = filter.getObj("get_log") stored_data = MT.get_mecha_log() screen = 1 if(href_list["return"]) @@ -92,12 +102,12 @@ proc/in_mecha() if(istype(src.loc, /obj/mecha)) - return 1 + return src.loc return 0 proc/shock() - if(src.in_mecha()) - var/obj/mecha/M = src.loc + var/obj/mecha/M = in_mecha() + if(M) M.emp_act(2) del(src) diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm index 66d2e7dadf..bdf76b9678 100644 --- a/code/game/mecha/mecha_parts.dm +++ b/code/game/mecha/mecha_parts.dm @@ -330,15 +330,66 @@ construction_cost = list("metal"=20000,"plasma"=10000) origin_tech = "materials=5;bluespace=3;magnets=3" +///////// Odysseus + + +/obj/item/mecha_parts/chassis/odysseus + name = "Odysseus Chassis" + + New() + ..() + construct = new /datum/construction/mecha/odysseus_chassis(src) + +/obj/item/mecha_parts/part/odysseus_torso + name="Odysseus Torso" + desc="A torso part of Odysseus. Contains power unit, processing core and life support systems." + icon_state = "ripley_harness" + origin_tech = "programming=2;materials=2;biotech=2;engineering=2" + construction_time = 200 + construction_cost = list("metal"=30000,"glass"=10000) + +/obj/item/mecha_parts/part/odysseus_left_arm + name="Odysseus Left Arm" + desc="An Odysseus left arm. Data and power sockets are compatible with most exosuit tools." + icon_state = "ripley_l_arm" + origin_tech = "programming=2;materials=2;engineering=2" + construction_time = 150 + construction_cost = list("metal"=20000) + +/obj/item/mecha_parts/part/odysseus_right_arm + name="Odysseus Right Arm" + desc="An Odysseus right arm. Data and power sockets are compatible with most exosuit tools." + icon_state = "ripley_r_arm" + origin_tech = "programming=2;materials=2;engineering=2" + construction_time = 150 + construction_cost = list("metal"=20000) + +/obj/item/mecha_parts/part/odysseus_left_leg + name="Odysseus Left Leg" + desc="An Odysseus left leg. Contains somewhat complex servodrives and balance maintaining systems." + icon_state = "ripley_l_leg" + origin_tech = "programming=2;materials=2;engineering=2" + construction_time = 150 + construction_cost = list("metal"=2500) + +/obj/item/mecha_parts/part/odysseus_right_leg + name="Odysseus Right Leg" + desc="A Odysseus right leg. Contains somewhat complex servodrives and balance maintaining systems." + icon_state = "ripley_r_leg" + origin_tech = "programming=2;materials=2;engineering=2" + construction_time = 150 + construction_cost = list("metal"=2500) + + ///////// Circuitboards -/obj/item/mecha_parts/circuitboard +/obj/item/weapon/circuitboard/mecha name = "Exosuit Circuit board" icon = 'module.dmi' icon_state = "std_mod" item_state = "electronic" - flags = FPRINT | TABLEPASS| CONDUCT + flags = FPRINT | TABLEPASS | CONDUCT force = 5.0 w_class = 2.0 throwforce = 5.0 @@ -407,4 +458,15 @@ name = "Circuit board (H.O.N.K Central Control module)" icon_state = "mainboard" + odysseus + origin_tech = "programming=3" + + odysseus/peripherals + name = "Circuit board (Odysseus Peripherals Control module)" + icon_state = "mcontroller" + + odysseus/main + name = "Circuit board (Odysseus Central Control module)" + icon_state = "mainboard" + diff --git a/code/game/mecha/medical/medical.dm b/code/game/mecha/medical/medical.dm new file mode 100644 index 0000000000..851c613f8a --- /dev/null +++ b/code/game/mecha/medical/medical.dm @@ -0,0 +1,22 @@ +/obj/mecha/medical/New() + ..() + new /obj/item/mecha_tracking(src) + return + + +/obj/mecha/medical/mechturn(direction) + dir = direction + playsound(src,'mechmove01.ogg',40,1) + return 1 + +/obj/mecha/medical/mechstep(direction) + var/result = step(src,direction) + if(result) + playsound(src,'mechstep.ogg',25,1) + return result + +/obj/mecha/medical/mechsteprand() + var/result = step_rand(src) + if(result) + playsound(src,'mechstep.ogg',25,1) + return result \ No newline at end of file diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm new file mode 100644 index 0000000000..ff19add9f7 --- /dev/null +++ b/code/game/mecha/medical/odysseus.dm @@ -0,0 +1,99 @@ +/obj/mecha/medical/odysseus + desc = "Odysseus Medical Exosuit" + name = "Odysseus" + icon_state = "placeholder-1" + step_in = 2 + max_temperature = 1500 + health = 120 + wreckage = null + internal_damage_threshold = 35 + deflect_chance = 15 + step_energy_drain = 6 + var/obj/item/clothing/glasses/hud/health/mech/hud + + New() + ..() + hud = new /obj/item/clothing/glasses/hud/health/mech(src) + return + + moved_inside(var/mob/living/carbon/human/H as mob) + if(..()) + if(H.glasses) + occupant_message("[H.glasses] prevent you from using [src] [hud]") + else + H.glasses = hud + return 1 + else + return 0 + + go_out() + if(ishuman(occupant)) + var/mob/living/carbon/human/H = occupant + if(H.glasses == hud) + H.glasses = null + ..() + return +/* + verb/set_perspective() + set name = "Set client perspective." + set category = "Exosuit Interface" + set src = usr.loc + var/perspective = input("Select a perspective type.", + "Client perspective", + occupant.client.perspective) in list(MOB_PERSPECTIVE,EYE_PERSPECTIVE) + world << "[perspective]" + occupant.client.perspective = perspective + return + + verb/toggle_eye() + set name = "Toggle eye." + set category = "Exosuit Interface" + set src = usr.loc + if(occupant.client.eye == occupant) + occupant.client.eye = src + else + occupant.client.eye = occupant + world << "[occupant.client.eye]" + return +*/ + +//TODO - Check documentation for client.eye and client.perspective... +/obj/item/clothing/glasses/hud/health/mech + name = "Integrated Medical Hud" + + + process_hud(var/mob/M) +/* + world<< "view(M)" + for(var/mob/mob in view(M)) + world << "[mob]" + world<< "view(M.client)" + for(var/mob/mob in view(M.client)) + world << "[mob]" + world<< "view(M.loc)" + for(var/mob/mob in view(M.loc)) + world << "[mob]" +*/ + + if(!M || M.stat || !(M in view(M))) return + if(!M.client) return + var/client/C = M.client + var/icon/tempHud = 'hud.dmi' + for(var/mob/living/carbon/human/patient in view(M.loc)) + if(M.see_invisible < patient.invisibility) + continue + var/foundVirus = 0 + for(var/datum/disease/D in patient.viruses) + if(!D.hidden[SCANNER]) + foundVirus++ + if(patient.virus2) + foundVirus++ + C.images += image(tempHud,patient,"hud[RoundHealth(patient.health)]") + if(patient.stat == 2) + C.images += image(tempHud,patient,"huddead") + else if(patient.alien_egg_flag) + C.images += image(tempHud,patient,"hudxeno") + else if(foundVirus) + C.images += image(tempHud,patient,"hudill") + else + C.images += image(tempHud,patient,"hudhealthy") diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 3021a0bea5..c682561e67 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -47,7 +47,6 @@ var/light_consumption = 0 //not used var/equip_consumption = 0 //not used var/environ_consumption = 0 //not used - var/emagged = 0 var/wiresexposed = 0 var/apcwires = 15 netnum = -1 // set so that APCs aren't found as powernet nodes diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 6774671f16..917744f93f 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -105,7 +105,6 @@ display round(lastgen) and plasmatank amount board_path = "/obj/item/weapon/circuitboard/pacman" coin_left = 0 // How much is left of the coin time_per_coin = 1 - emagged = 0 heat = 0 New() diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index 96c6068fb6..a2e21c3a85 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -493,7 +493,7 @@ datum req_tech = list("programming" = 3) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/ripley/main" + build_path = "/obj/item/weapon/circuitboard/mecha/ripley/main" ripley_peri name = "Circuit Design (APLU \"Ripley\" Peripherals Control module)" @@ -502,7 +502,7 @@ datum req_tech = list("programming" = 3) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/ripley/peripherals" + build_path = "/obj/item/weapon/circuitboard/mecha/ripley/peripherals" gygax_main name = "Circuit Design (\"Gygax\" Central Control module)" @@ -511,7 +511,7 @@ datum req_tech = list("programming" = 4) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/gygax/main" + build_path = "/obj/item/weapon/circuitboard/mecha/gygax/main" gygax_peri name = "Circuit Design (\"Gygax\" Peripherals Control module)" @@ -520,7 +520,7 @@ datum req_tech = list("programming" = 4) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/gygax/peripherals" + build_path = "/obj/item/weapon/circuitboard/mecha/gygax/peripherals" gygax_targ name = "Circuit Design (\"Gygax\" Weapons & Targeting Control module)" @@ -529,7 +529,7 @@ datum req_tech = list("programming" = 4, "combat" = 2) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/gygax/targeting" + build_path = "/obj/item/weapon/circuitboard/mecha/gygax/targeting" durand_main name = "Circuit Design (\"Durand\" Central Control module)" @@ -538,7 +538,7 @@ datum req_tech = list("programming" = 4) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/durand/main" + build_path = "/obj/item/weapon/circuitboard/mecha/durand/main" durand_peri name = "Circuit Design (\"Durand\" Peripherals Control module)" @@ -547,7 +547,7 @@ datum req_tech = list("programming" = 4) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/durand/peripherals" + build_path = "/obj/item/weapon/circuitboard/mecha/durand/peripherals" durand_targ name = "Circuit Design (\"Durand\" Weapons & Targeting Control module)" @@ -556,7 +556,7 @@ datum req_tech = list("programming" = 4, "combat" = 2) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/durand/targeting" + build_path = "/obj/item/weapon/circuitboard/mecha/durand/targeting" honker_main @@ -566,7 +566,7 @@ datum req_tech = list("programming" = 3) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/honker/main" + build_path = "/obj/item/weapon/circuitboard/mecha/honker/main" honker_peri name = "Circuit Design (\"H.O.N.K\" Peripherals Control module)" @@ -575,7 +575,7 @@ datum req_tech = list("programming" = 3) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/honker/peripherals" + build_path = "/obj/item/weapon/circuitboard/mecha/honker/peripherals" honker_targ name = "Circuit Design (\"H.O.N.K\" Weapons & Targeting Control module)" @@ -584,7 +584,7 @@ datum req_tech = list("programming" = 3) build_type = IMPRINTER materials = list("$glass" = 2000, "acid" = 20) - build_path = "/obj/item/mecha_parts/circuitboard/honker/targeting" + build_path = "/obj/item/weapon/circuitboard/mecha/honker/targeting" //////////////////////////////////////// /////////// Mecha Equpment ///////////// @@ -654,14 +654,14 @@ datum req_tech = list("bluespace" = 2, "magnets" = 3, "engineering" = 3) build_path = "/obj/item/mecha_parts/mecha_equipment/gravcatapult" - /*mech_repair_droid + mech_repair_droid name = "Exosuit Module Design (Repair Droid Module)" desc = "Automated Repair Droid. BEEP BOOP" id = "mech_repair_droid" build_type = MECHFAB req_tech = list("magnets" = 3, "programming" = 3, "engineering" = 3) build_path = "/obj/item/mecha_parts/mecha_equipment/repair_droid" - */ + mech_plasma_generator name = "Exosuit Module Design (Plasma Converter Module)" desc = "Exosuit-mounted plasma converter." @@ -670,6 +670,32 @@ datum req_tech = list("plasmatech" = 2, "powerstorage"= 2, "engineering" = 2) build_path = "/obj/item/mecha_parts/mecha_equipment/plasma_generator" + mech_energy_relay + name = "Exosuit Module Design (Tesla Energy Relay)" + desc = "Tesla Energy Relay" + id = "mech_energy_relay" + build_type = MECHFAB + req_tech = list("magnets" = 4, "syndicate" = 3) + build_path = "/obj/item/mecha_parts/mecha_equipment/tesla_energy_relay" + + mech_ccw_armor + name = "Exosuit Module Design(Reactive Armor Booster Module)" + desc = "Exosuit-mounted armor booster." + id = "mech_ccw_armor" + build_type = MECHFAB + req_tech = list("materials" = 5, "combat" = 4) + build_path = "/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster" + + mech_proj_armor + name = "Exosuit Module Design(Reflective Armor Booster Module)" + desc = "Exosuit-mounted armor booster." + id = "mech_proj_armor" + build_type = MECHFAB + req_tech = list("materials" = 5, "combat" = 5, "engineering"=3) + build_path = "/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster" + + + //////////////////////////////////////// //////////Disk Construction Disks/////// //////////////////////////////////////// diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 3bb1649408..fa6178bdee 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -44,7 +44,6 @@ won't update every console in existence) but it's more of a hassle to do. Also, screen = 1.0 //Which screen is currently showing. id = 0 //ID of the computer (for server restrictions). sync = 1 //If sync = 0, it doesn't show up on Server Control Console - emagged = 0 //Turns off ID check req_access = list(access_tox) //Data and setting manipulation requires scientist access. diff --git a/html/changelog.html b/html/changelog.html index fde880b037..0244c43582 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -54,6 +54,24 @@ Stuff which is in development and not yet visible to players or just code relate (ie. code improvements for expandability, etc.) should not be listed here. They should be listed in the changelog upon commit tho. Thanks. --> +23 December 2011 +
    +
  • ConstantA updated: +
      +
    • Mech Fabricators now require robotics ID to operate. Emag removes this restriction.
    • +
    • Added Odysseus Medical Exosuit. Has integrated Medical Hud and ability to mount medical modules.
    • +
    • Added Sleeper Medical module for exosuits. Similar to common sleepers, but no ability to inject reagents.
    • +
    • Added Cable Layer module for exosuits. Load with cable (attack cable with it), activate, walk over dismantled floor.
    • +
    • Added another exosuit internal damage type - short circuit. Short-circuited exosuits will drain powercell charge and power relay won't work.
    • +
    • You should be able to send messages to exosuit operators using Exosuit Control Console
    • +
    • Gygax armour and module capacity nerfed.
    • +
    • Exosuit weapon recharge time raised.
    • +
    • Bugfix: EMP actually drains exosuit cell and damages it
    • +
    +
  • +
+ + 21 December 2011
    diff --git a/icons/mob/mecha.dmi b/icons/mob/mecha.dmi index 9a4e0b686f75510b0b779a34cfcd53697538acd3..01f731f1b661ca3d12a51511e7589ff9e2cc8fbc 100644 GIT binary patch delta 23626 zcmZsj1yodB+x~}6NkxzjL68!V5*fNnNZVaO9Nxz_ABjMyv{3u+$mXd z1OB9oF8yx(7{9dLG^-Pe{U3stS~cgKXYM{ed-TO%w)>o0+mK3c&{dk+6AY8WC2rBX zx>qB^Zx5}G+=WHfvNL6q7LhgH$KEM3DgG7lQ}Y3Ht+P_$XQ`@-@Ln&+`>9%Sf7yk$ zd5Y`zJwh`bT(3baWW}c)=xuYf=3)QsZOTM55;1C2jGx*gok!Hi}=3*(m?)k%dycze}3vL>* zDK$l5D&#ap$!nYA-Gq#xXB|^KgCuNW6uiX6JKP@)iDQ(h(jvRkxEZ9QQ zQe)#XJE?t%|Ltcj$wk@o$fq;X?>HjQqfn!PvO(^C>m5g#(pd(me&{H3lM<2e3qBl! zF^w<6@s{>F*D-y!G5IjAZFhneU8n8W1?Wh|bNX#Ww<<#ln7H^#mnfZCLP`#gqa9= zMyYNKZZ6&QHjHZJ*nMFActGW)QAc5_Z6kV(ciK5E^!CdG)q`qNRoTGsAjgj(s1c9# zxA<`Ad(Z zY#A}b&0CE%h zUg@;nX8E3rM|F@~KvgvA?xDmfBgR4a)GZoLNu1jDWy1G;lbg#NrNT$XN+o#BWitBv zjbY=kzc!abaYUKd9mQG>CSBYe=JA_|KF^z1d5b5GYzT&uTQ%SN5v0x>GwU}&9m*!> za>@9fQEkA)_F)Tw{3~&_%8CkMCW=v*q4bvrmG$GXWglS(9QPa?4r}jb-6z;v`Sdl1 zf(=heeB%2CSuYJ!DIOC(4&j@-bVeb}_(2+&ww;=3!C$|AArKilM4xS_H&N0Bc#;|4 z24+~#N3LB$d_OqRpzJvw^09cSQWmP$uqTu3r;s8{nxgxxXWh-!l|%ZDS&Og?;ZnX6 zZFu$J&(BXF4l5s7*)ey?7hx?aT9XTB=lX)a%)uU1v$UI% zwG!G6Rcmow!z(QBbLZ%&QBG@#LD#*pu`xcI_hB+nhfep(UDMEJM8jsbA>Z8Amiyf_ z#9aHFJk@Nzsw#2Vy|jReDskzIijEVnPv(^CTkx|vi1QRlfg7-nvjf}bhE!Ty)Fp>2 z=Nn0rKoDeUG{`m^R+Rcp;3@ne_5AyHiuOC+-HzGz$r?N7$5_M)d#eS*4Kl8y=eW#n^K8*O zD5iPJiJm_FPK49Vd*t>g(|?;Bwj#%DE9SM!+pYG3? z9g1fRPSUUwG*m1#NoOQsYE?5`EjY0Q8 zAZvw-DpT=G1BHhVA8wC+=)ds__wHX!>+281@=*=d)$&yM^f4W8wRlAfch!Yg2q6gv zQ`Vb=!;WJ5I`{ok(@JWN%66d|TsU9&6dFAIP%GH2)&Vg$@i5LdK6^R<8JN>{K=TO0 zqEYUT;;)6rQ1|+NdcUKAB1GBpsxN!@px?iLAK`MU8j2I0CrWyh7Tcrv#WYzx_1%Z{ znmBjH9tF2|xXG7$a!A=+R;+onXrTw{;c8Z+M=yj=Rgc^_Ztgue2S+Z+;A3>-SdKr1 z!?rmUA&lgN)S^w2F?R*)&Bu(A9C1t9ROa7kc#-hz##BzaT-JOux$*Yijzn_}LX^^y zS20VTiG}4Y(d@PLgYNx|DPw2@B z?|W(YUm*;|k?{kIQLQ#tp~AmH7b!`-VwWG+V|w&RlId+tI-B{g z(&ilUK$6EO)RSiGprWFyhJ4V4Pp8Z8)}Jg`&+L{oHX`%Q5DFo`4h~8;{d}+0KRqbl z)nte?HmSFyj9z%9U)Z!O^NHNS;^u(C#!tUYzN=XS3$+(7mheAVD)<;_{d*NV2S03v z?zirN#{z}e)J6sHOQL(&(LK!-8*0R4r08s08e7u}m+Z-nH9pf`Is=)4WIH* z$VI7e4zGHj_Za%Z0;Q}Psbv}Y(=MCU73x$MEts^TK)USAnwO^8`URfft{y1O@2UDIldj*#_cO6LgJX6gvuJn@S28gAKw+`yoz-aVX=feZUeP@TSV zABE%CIn+c{<<}@KPSmf*(uu?$iXC0C9p6(18zbcF8v!1sADf$a#ENg$Ee9neB;s~! zYiq0O>a;Ffg$!I3rPklnyjeniz;co3e(DP&>|N<##_lh{le<~n#LZ>zA|ynD)N(@W z>u=UUUsemEq`&59Y9{1_TZaz+&}UWN*XgWjn|NJLJ@4t$=^#an`;lMsda+C%t@;s| z1f%y~8}ePQ7+%SOqQMke-1Qqh+Ix^QY>|$7j?wRoG6<1csjRHzWHu5)78(>k7rF$K zU*$MLzgC%FWW;2jYU&5^z?wvCG)+$j9XLH0Jv}lU<6bDdrW*9q zAfq!Svi4Y(=P2Ioic1kO)hRT@6%@khwUO`AR^Wv_{iomV?3?I$D{11|728m_ntm~_ zH<+o*VX@-Eq@}DhIvrY>P-Z|n;+>6RH?ae-FB0FaYZumpyBDL|kBaMA+Ik5^DD>nq zz|(Csv7&5jKh(gQoNT9z@l7xD%i@m=)$J+ULJg`})z=xa-^)4hiVx^1(8;(dR$!Faps{C-#uo%a&Eq-^6j7$BxyoBsqH5<87%2w+Vkch5bZ<1^V~ zgL-R57 zvWjkod>2LsSMi#V4fN^kpP#IM_o>y)y7lJT{w)acru02{9@lHO0$H;Mi8EK456+^V z&X^E_)dD-Ljptx8qF3SWDm8!AJ)oqZ`0M^BLt-!M3X(6bm7Igl=&o1g3F&cao$U@h zVDPqNC^J`hRfVJ`;|{ojnQ>DDJ}s2dX*h_6e{rmwOwr;7FO7yD<2x)NE(#f_uV^TN zPSle&b{`x)dO_*y#{B%ev5sTd91=T^bir2O{2b1``UMv29B`Y!mgl2ZXydFQ! ze9f~9cHSwT8zk&@>br6zGY6chBngX|Sy>;nsO+{0A`(7i4?5a%C%9jiN!5xqE>0)d zHhol|`TSziz{)7O+83cNN*g1H9siT3yZna zQyDLRf9XMqUqQY%plVYdR9lh;!M=YW=LU8DKrTjtxTUi`dSS|c8A{-q{5^RYF%n&{ z8D1hOwiyYb#l3DdP{nK>b9#H11oV|w#ND-u|G00m~G1^)F@)o($bzV3$JEQdXv`g zc1aqFuo6-23ymA{h=J$f2z%~C;vLZat5r6o^b?DC3RfeP#b-Q?O9dTus-CaTOCRtn zyu{b1S=g5Jq4i|uzpt2@^4z-Wmv-y#tImf)=a5R5Ftsx*73l zHOOU>mC$ufVav+;`Y3b3O0f%@9G!jdjdot(MWmct<2>L4JB89GGv%UD1uFak$hfF; zW!J0U@hE_$+MJ@#o;KNTZgv*YXYaM-zi!v9)2^-Jqi~bz3i|jV4tOM3g~4S@^gwTM z3fSK?50P?EsB^~^DRgrtf7UTOfBE5sGq?CtRI~q#F{|dV#=vfJ1|zxcxkgC6wveg6`Evh2Yt3W6Em=0|X}%#9}H zn69*7Zwxscgx&G;yCb?)M$rMSbME~+@|*ZYlKz9o%FEOaM7+VBk5nk>)jHfgRa3a0U-?loUUFxOYyG`E9_FcO?ByJ@%~n3FmMA+_vDc z!SYkn^cKLU5od9ZQ-TCkCy*I-|B&;?a9(|tW0&UI6`S*56a{%CnS2z}x{4GqPHH6g z@SoGjrAb2vCPC+;d0^=g>=;-LgeKkd2igjEk z5_Wb0wms6pa(ZG#RdaLm-s?1IeW+&FB?7Rq_zTb!y{#7doRm2q~cuIhWWWra0K4?Q4hp ztFQJ3SoXD17Nv+*$yTFNu@4-PGSB6_goWd$*tr*6JBI|cFhU^reY*SH4YrZOq2$`( z)mJ9`^YuDJC`A6S!r@7%(>u02=Z)Vq8l~)N+tnxML)DGW>=5a`s%U}Oy*uo8Q_+s< zW7u8Dm%Q7GF6)^nE@Hf)O6~zzoC5*`s~J{m1i6QQ`9g}KuaF-`xlsrPB?(i&&o&ZH z0zEDARMu>kFYE^HA7;7H{&^~9F2i@?1Jopsf;t0M zweCJbp)RZn|1jL4=lrr3yE3kB2NlO``@SnX06Q>%2JST(Q=x&~ElJ|7;cQO)mQrom zJLZfTI)IC-&5DTv#XqNpeUyuHVbZ!WGg%zTGd$7x#^L(uKqU#)4g| z@*P&P{5?y>T<-da^+Yp3KD8nT@vB5`9hl?+PCC+pJby(knl6daR$Y= z6v4EFwR?v#6%ss0fB3T(Dm7_a&>>=Fz$Bd-9S#6~rA&uIb%?SWT29@rhoPCwa5x~N zQPeiO!pU)!ccmP?*w*p!B_jmhWP4xVxezuzW^H~if$`%J>U*z9nlSrDjg(| zH%5=Sz0gQH+e*|AU1(AreqgDLse}sPduFBzl>y^lzdj#ths5Y-9WO=bV7M1|Vq0ue z6T8|yEhK1M6)Ed)5ygtXF<@>=n}_)|le;d@zUgOwKQloxJU(miQ07vUyO&qFG0(fv zmQzNN`S8rwm#2h(Z-6M-o`oICp;XO zo!iZ728$aVvFa62nQ>bHBo!WA$%xo38}3|scY2eFV(vs1NFq8^f+yqF`r!@ujWsnb zfVoCTFYqNjH+$?ga`u-;$)+D*zAQ2l`9DYs`5n6ZQ*N%b0w%RL(OT^h{%+V>TAaCZ zSD4;fm>$5Xk+E!6$3r1OYtt_(^-18W1ktUNfYIU?wcHE@8|_T?l&__-;KFtt&9%IT z(Ach?_$f4Z2><2rmrgS@SqD=-hxrjkUFL#BlNEy-KBM6V%&#*fhNs&JvJ+aMLgb># zg}xofGdTv4DV2W{YLpyJ$HFxL&V%@%LX7QM;>d{g<28Fv_YwhqIZEEKE3?0)-(DuX znr_i)&h)NmLGr$06!Qhdw|$uroPgUVz0Ra=wSsGiZ)t13mmNG@y8C$?)YW~joMzpX zg2Cd4XQhRKL{0i3!f{6;vZPc851R!DX4iq4J<3bZ9=JF_BV~(G?mIhhh zdfKhS47*=3`~I6$k<8}Z)L9V5k89U@Xb63*&CBUZTLvn{H*9Af%) z_2V2f7E~YP&tng!lb;PmBvkwg;AS)T_nN5FLNcMb$F^8q$go^ZO%A6mS)GegzxD*^ zqqe$X6PEaXeVKObDYC-vrRc8fO~t1iu&}Vqe~!G^t+fl@L0R+cyN6YsFEvSOLv3wQ zXa1>?xOlGX?JNP0XD*ZC0W&e*iw1;05mU1Z=#y#tJ|06suSrvV$a~6WPZ~JPA*t#v z^cTG8E!IE$)A$He=@_C~e&dY8DX)W}{o6Oocg)gPsnO-3pg=fdYs$3a6;<@pg4DVn zG7-HuCd<|5EyaUpuk^Ty=0KM(yD{Osg1!OB~KTc$I@_&PE%j(kQAXEM;Qg`BZg!0GU z^I63Z*iHUwVTel)%z0vG>b0*ExC_Pmm%LXKe2-g5hF-3~k}`QKEJF@I#42Q}m*D*# zO_|_1WFd<*?0uabM)d}Gu+YGoyEt8@r0*Gmj+mG|@jtcwP%#dR*3#uCBiax@jQE4L zwvy3YM9ULi32ZBPS4u`rHlx*qlY8WXTKgUxCM6ba0r7Jq3ouFtB`<_{LT}7`REvD-LYg(f1}`MfJ#o+sAXEa`kRZNKE_n? zU!7;?zmc~f2|aL=>!c%*V&a@bkQQg)Pf-E?QOId;Mm18nZwJUKB?6{YdHQ<(b^5cz*U#tzjf4FSvMj zk&x>KOMNv-KQ18N!O6EXo7u?G&&yOk3S+3|B5252T7w>g##TRQAl8RNx#vH*+&Sxd ze(q_j+QOY=f|naEE-r=X^ydE5ckbM&s;+)Eo;O($rSSR{E&&}W!Q~Hjrl8!W20BWw z0NRPWAk_Xb77b`*Lw4eEsf$S`D?GftbJ9nM`=gmUZi&7?HKppl)@#aEjT!Oi7lXc2 z#*O$H2hTw$Y^fLyPi}u8WcwR^866%BRZ06wFrKnlIOp%U&)XpW(xLF9_s?Dy)jpX;#y7gO) zl<0sezzP8sh$e~BkW3uDQvxF7ir>-#ijnAGCOJ<8f(@arByZSb zb|s^a-Yk3C^`1zowMgofqn+l(oA?eCA2W0{ql@9B|Brc<6eY7Q9KVf{U)7xfA4c-k zwQ|M#W27xT=Hee#dO8k?!KQ4z6McQPbMEv`ViW4b(LqC8x~vxhXJTx*U$h<_`7NKG z2H1sMi9AQeW2Fj~JuU9J`@SNnZ12sb$mYv``QN-C#FsTt#1Q*#CXfH_r6?6{r!VZS znVLF5qxQ&f`11h+7}%h>tZ^{j}nmn*_L8@*OOSl06 zGOv?J1x&|DqGMusa`n~i#OlB6yN5AYTp5dDz&PyRc?!4TsL>H4Qnk2g)>Vx|#&*nK>meK% z>n(L5i$?(g?}$en*p8)M%GsBj+9mU{3jc$?ccVDahxL|1Us5;hyycjIjMehK<8y$S zYUUjBD+>S&B#;@&;Zi(3mzO!j5zHhk%aDnb7s_BNx}ijT<*Q?aSks zSb$tZcEft;X65R6|CI%MUSZJzD5u|RIPff;`lC8s0K{o=~iuyFYBnCj1`H!{PT zob19sZ<*5+iX8wz&8cyq9^#6P2ck}CTI{-9^jB%yXx}&bg#{Fi>cThPD7n6TBK!=! zu&~f2E$u_{TXJEgY=w6oC2u3$JaWMN9uW(q#qTLS*UETrTxJ9ZIxCWH%<-Inw8dXP#~M&TrWrEk~x^U~7g zx1)SuQx0L10|YFamF1<Ltj@=P5@DXtpDWhFWW!SV?R_qjJ z^2XpUqoLV4*GG>StIb`V_`WG)X#{)9(1n~Oqz~eL#P|HRvVsyYAv^evXSj~mIkbE8 z#a=n(uJ}FU&e}PWs3zf^3^f*xT%7sB-oJ&U{C&AuFHlEWq6)99rRE1I(tmxA?A^-g ztMR_CF-d)8#)Ij{&!2o(=~A8fTovOOp(iINCx}<}$O&gUU|`+1FVpClr7y{2%O;qO72bv=wBm;3lQ)~~JbVd5M!u@gb_ zy_%$Oe$_l1ZGYbk6Mq#eD=R!=R7s6dWL=E(`1G^|BI0|(uGgDY?HQidC|KkQ5Hr&Oi06T)-g ztLdwMEW0Wz9`IqzK>SDK&pU)P0D=D|;J!STI$4Hy3pHPaz~+g)hfP~qbVWPJO5Ep+ zrDLCRA|60tTntWB`4{b@NoId~m()1>crt{T&x;SB^Ue~y-`D(nIQmQCG(W-RP?x9` zUK43>1}q$*c{94=+*~!E0}X;kn;k`~)NlTMf*g@pN~*3eRJbzxYKe^Mvb8~J$`vai zM&ed?;Kq%TtiJffPx&bRMRs;}1ja-VzC0g*n*$M$v!myn6}uyb=PqFqmVR5djF^QI z3fPNJGW24g-l(BEvPtmfS_!apRI;fXg!C@~mVRYos9v#`0-0c8Ivn=>v-X`Ak08|FGSek_=NE#&Y9nP@j}jC zD?tgY->W3C%Ku-q?e_GlHg8+6n%v;KgVD(kwJD7_fTWp6@&}0J&M?-OuD&(l$0Zi! z(FcBS+1Zl)t2yWzm}WmC;Y~~Pf*4rw9}`y}Qwb`+ZhridVVjcAD}wD-sSY} z1L8FL)u3M(*4o;tl)DOp%u2F$84hEELk}W^4e+s zJQB}ZVVW<2@f;x@R^NO4E0nD%GR*m*^sk$`*8_mvW7<(d{oYtpIX-Gwc_>F@rG{Py zm24hfer7-sg~J+e!Hv8#d%>rfBtOGt0ic875s6m z(uEPM)x;r)g>920b^f&g8hI)?*Zxx38pSXFwN=?oYcg&$S1hPl=jx}HPYTgRdhI)D z)koW%h~`K&`z*ZRa3aKKi+^)FeElzN-rW7@IV1~MIpDqvhi)xfu<`=zO#lH`G!qsO zPsVzwWIYN(zrEB&8uwc(1-OUq$7vbDQRie)9WUBzbpF6?I;s@ogk@U~0MVL@?z?(s zwcnG4Ky5@l6A?p*$E59Wen*0R6z^R*e}ahV%8mD97%JaJF4li9Mbm8zWyB+cXZ%U^9IT}!SFr`Ap#l^z(Z)f+40}W^Ymf&@+c{e zUMQ$z{ZSxSb!4jQSW)d%w^37o=j--%!LGyRrt@TUSc&yYLU|5XXPNV)O64TM@a7ll zuScTO8*g&-M)pBb`{|Z?xt3XD+vs%xSet*P5y;WVKUQ$?(y0SuluA3w0@aE&Ns-JV zU-^JZ+V#gImH1yKDLuv0=j73OtkM)Z`R6tzDFSA!Zd`B!Wt_J(vvT^!Pb;E0b3&y`26L6a%AJTFcX#zyiF^j)d&sTub0{uV8P z+3Ioe^s4Fz7tMVG=3FN@eU1vs9U2ks+uV{27Rv zB<{!j_ONt2U^+yi#^n(qp>6zf6FJWWy=WVdPIz{KZJxz4hCoR*hf8mnZ~0ZSUEk=9 z{XWe#c^frXpkAd+z+>0SKgX;qMcSSxeG<`s$E>7N8WAZdPOJ`gn6kU%A+K z0$^#_-Lm`(SCcg2Zs`c7O6m{4kq^1BVo!gy;07zTlY-qyo=5z5<*OSD0zJ=tiF=|~ zCHudo#i;MUG9pD>u)zy@encQAa95p%#PrvTraIQ306I1?Z9AUfo4NbT=`co_2G$kB43NVJa=58z0OnmjLe}$O%9#qylAi>~vYMJnMT=IN=cT@)czLA$ zqGLhrFhb!qVzOc-*=@b0!i9;M8EB{><(wTJGy*b1L84jz7{BRGf3e6G?!LpVh;&Z# ztbPHg%>}q+3#hgMfMbO^>0yXFuG$(?@B7PKY0MG+O0t3^}A7pQPNaVE{l>B=3`Gl z{v}EUc&!baZZfCsB8y;=+d?WV6RO|9yI0G9A7b=Z>$u5dMC&iC>St+2u?jqEir>{X zbOTdO4)WeV2eIZ2%yT40w< zb(2In5<7e(>#IEm-WVtko(L1!r@h+nd8DISt44^*^Hkwrx03Z~0d?HK?kwb&c^~@6 z0tO3D^A;->@OZ@gpkKfFR8pY~XR(wEq)mElX^O*n5=e%+lginA8h}zVue`MDcO5T& ze=_m17FhbY`lM~gy)qq`Z>OH6XJt85`AINQa2|B&D5#kZ$r!dAoT=Hja8-j1bLSlV z2iGCD0Vr?KarW@gSD!D*P^A{+G_ZfFqpQnv+|EMfwjv<0o)cZ7U--)MgIn($LMuJEMKi%j|UM9K>$oLr_^saDKK(F=mmS1}MV1r&OD=Q2@nl1^#)d8+$}w0wpA!|vRA`|RiT|d{zwwxJVpC*=jhHr#1#Q# z&bRA=TeEyS^Gy9Y8IbwOMN)#_0DR*Q0O!yMpAPh_xPiF>j83=b@Mn*fe6<8Q4Zxut zt_tr%0jahP8Z1Zffa=nJRy$;Z`f|#G46o8L@WO4GnTzljEI(h4gEYJb`uh4@+Q6=Z z2cCDZEeIITLEjeHU&}4m|CRkpNmBAT0rk5$<7%Ni@|FB|S;#|} z4Y}W#?cv@$|66=H2h#u``Z5QtBE0?lq%_4xoH@`veXGYo?uF={rN5lTjfUQc1+UWq z5mS{$+As4Wv}zsNEVr}(P*L{bYs#PA(%-$MHR!zD1CCeo*Io`f=Cq)k-P}OoA)x)a zmUzSG&Jxn}0thMbJz8|J{*wj(H*^4cM_N3n)<0LmH`ErOf%nqbKNIb^!}DH9+=+nm zKPW3$e1=vgNKT8EHXekzyR0sT>%)^>oS<-mm3<3N2N>A(N){vmOB%hdE*j+v5}weT z3a61MPDw17aDGcQg(X=o%Ut#Qe~_vsyF;0620-i)a;-@&_;g*Snb$-A@K>1oUNjSDN_ z{x1E1n25{|Sx~#Io@@^Vs!JelM;`x-a5_2`=HxCs?m4-X|MA z)c9VFq+{=QHb|}qtoHkKfy84K1)CsWakZ@yq~61=y21QTFpZK|F;;V`9U}{J$?=!5 zx#Y(S(s$!u7%k?1e!GMIy=ovs=O9ABve^7W4rHl60Aj;LY#L2@HrH-7Sc+4H&w=9S zE$tA)15=h?Tnr$mOnp{rj?rv8!dD}sR}gHS2v4NWSA1_=^j07@V0w+K>%6{%{8F!S zcm4~bNkZXM+TZgN5c=7QHipb8%v}XSa-#P(H{^pqHQF z;;IkO%705VOi& z-und+yh-y;wtLNr?`t5|`$nge0ypei-_U;`HG63L%RhYjuH?Ub>d9%~O89pkInJG7 z4L5}{t$&??FZ9)A^45ELk6((j!!z|&dP4uDR+Ynw_GO# z2SYosdTxkSjo>eA-WVH_&ZmrpgZ*HM78qF4zE4j(j&TNa1pk57QY^H_c!*6U;$31? ze8~eWbra@yFH%QbD{t}BZJXtX>gM+>S0RGa&%A3b?2fL{lb6)jp95027ow!H@+rW6 zS~ed-?{GcjRF;p@8kAlA&S9J)+!!r26*zOd>pe)HmQ6TwAx{?Anx2wOP@n+)tbHa6 zkrPyummN|>i%&y_rjma%obL?{^izIv- z*uui6jb)oqm@+9E(5$CdbkZ<$87T5S^@n<FP_lyWz?OcCt1k$lq`y}d1+pRvW}A8sHI5oKTPrpqS}mqgw^SUhSkXV} zh(if2t*o*sW@-QSj++3T*lDDyXT&(p&+Q7Gb7U2PjmADd1<~URP1bm)S>U%2Uoqs@ zd3x_y{=a7N!(QmE<9JiAKPQ%ZpZ>$W_xpR9(}1+H%3bJ4r}3v6r6THay>t>C>ltPurK4?6`i70t?wc4uoxJ9U!^%GcoG5z+AxF z^H|=d$5;tqj;^V-!n`0)E(Uxb^;Td-HO?SlhpI=IdmB3`LrHi4swO9T#qo}U5D!Re zzM1(dUjk%ffJ)R<_Abi*DoC}1AaA9`ZB!1Zo@Ne=Zi3pm7X+K-x%mC9oT=7g?Z9P$ z>XMBZ0(F81M}LnFC%Sy+z+KW1B_&_=V}*>CB)#bAvr~2)0X2Zkb+c7ZZ?O9k6q>`fHvW3~{^H}}m3X%;& zd#+WgHnv(aDAv5g!|)rC@p)p2#&w9e&qpHapI~#{50iIKT_)qG=zauvCMV*XCc8|6 zYSkKZAgyo%%4@SoJpa7r8?b)F`J9r~*U?oq#(Wn5h1r&yg7?sIC*3cc;r05?MMN^ zlw^#w?MDl?DeuHoqJ(6qVZ=?7!6Pm9_ntAc)kvJSjQm2LRwF~BSex{WG3vCeTO% zB6(n8d^`MLzs6O80BT~OqVmb{tOg!92PC62QKy^yxqqyTKfua+YtzD#Z@_N#ES(EP zZw>j9I$76CfUSv>4>qr#AWAX|7lp$k`?0KWW&Y`~Fne(^koQ2UD__ul|>@P7l$t?={~42lYh_`cO^K;k!~ z%z*h6`mdc;lD5K%i%1j~zQsz{xhvJ%Jgm>Nx47-ujyoqe4@xCQKSRri0R2L?g_>C- zrWjfc6yEUdc}e`V78))t9eH&_@`N#VW+sSz`*|gQj0zbNTy2*f9u|9<7cN@Ja zBeGw93<2U%@p{Wa;0qN_$TyQ{=0Jkw@jV95YICkbR(THF{wTYxK&!LM!7M`_16@mv zEWJjV=wwc50Mz9I^#S4E3Jm$)W)BkuK>^n!6`zxhfm91xHX9_2Nn0UefF_W^X}%fG zppAknu1H(x=7~EK&k%{AprGqgn2K1K=+`I97LVNBgN%!E6`&Nna_thITIOf=wOWK3 z(~B>Z6vSn3-2ImsJP}>TL-K>F$+?gj{Yg(ct#o>FL!3K-ggfC`ywHt`x~JA@dJY-M zjK66dP;sLv22CO7c|KCj@p%P*-tXJubgk1PyrU%7z-=w zRos1sh{w^~u@lb5QczYG1q+W=Cf*wzmo!JLf0*?*(Das#R?48wDD$UOYOF zR^scs2{62pni5e+qlQ(I#Bw)X^RX!{*3}HrB4MotfbfobmPAw(9qok>qF@JZ$gFVw;SCF5(ic|6{@=0 zG`))Y?N zl=nYv7a+2mf1~ZDAOZr={Q)`IiR4hja~6|s4%?wzF2;wh_!?ORtLaGiT3<={xez(_Pv9A=+;cDd~&s9uN(i+yZ^Oaw$@A{w810 zjH#ZYv8=@ZXEGWDqjiV5$@eM)J%YdNEumRiWg+y`3zWsh1gA%JjjtI>uuUp3=12(L zb2wf3nDsW&FJy?46)))cta1QD2*gnVOw{Q~97x9J4CG11tCO8yEjh1s!>S)O_%b?N z{aE>Erw473%yYxPapv}Z+`crP_5R5ktgp=3WAl?TRVahk`9pCr2P^qw!#`jQ4Qz8> z_6mH_aWAR9^uNuz_A^-c^$wGhtmtxxe2_g1&JTIJXCJ%rXio9KK;J6#e>u!hg-JVT zOS;g}7zaT+VApxK_@8|80LUjlTdolVExIfZr4Jq7imR`M^?sJ`p_I}{?y<8oZE>vP zA%-04@u4gN9Pq!6hbgJ|2R(h#dX@|wQ9vF9)?L!n^Bwhw%@avt+`5!6G2C$;RSga8 z4J(Bg2T&IK!95^m9cQd>HuX~Y@BUogQDH7o9U|}bs`ga^pqHfCgP)AxE14ovd`#HCWh@4XFcKt(KQT z`CmYp{xgNHlKM)YP!U3w9JjMi{)_6vPGI77t7{8EUbM!y*LSQ4wg&euwZivL@#gN& zv+oL(QoyIgLxp1JQXW1VyXviq{Jzd2|8!@ z;-l(*(yMgJh573#u&o^?843<~?DA81iXYpoWz_w^`?%>x&;N{6Gu8jj7T(A5@=zdp zbVozk;`@6a+tg>j;bd@P0IJH7a`?hW&pNgF}ZqyuZ0hQsU2@cNswvfXhf&<0j zoo_gXipw)UtBiv^m-7Gau*W3a6m7wF-?Ju^*E9LbT_rhpH|*VXDTO_ z?sHQ)f35wCga@Iyxw}=D}+V&nhUdSELFlfjMyjPI*cwwle zJJj|RBnZ0ihxAnD=v?Vp^Qpb>odbOyPL&+EsQXrQ(M|9GXywb*@1Aa+#Jvc|XPl~V zIc)e~pRdon^LpXchM#YdSyYAxB_SR#rx#4ipOr0GUlet-AJ_%$izD2XdrJ{`2FGQh zlF`{C!ezya;dY?(3OJa@Mc$MS0fD6x@}ib4$~t!@py)UX&NY5@o>y#z;P%6OjSr-= z62I23)MKQJGm)yR`(vDTTjQg79_8Lcx zJ6ZSKT6Z?rjtp*a|7|jxu`f@~w#NgA*5;cy^4@<&@i#=jo!?(=EuW8!SJ+-K0R4h0 z*ZVx30wL<#V<5Z_>_%ttNc}?mnS)z`=uvVX8J2qx#L57S8M10~!8bF@M1^2`$NPiQ zpjSBx_}yd){XPlRk|wtS&)14t5h1{Z72qAZY8dtL37>8*koOz`t(A402?h;Ny3w$S z#iPSXm;$l&N%g2RONIymd7eTYpe^nK?6fFxJ9efH?2e+Txv0a{1YNAs&S$2~=oqw5M%o=U>aYHq-#+eksZN+-#>|_o^7nKX@~IE4%8{ z_w!NkU*^W$=-5FYoL)O-E&V`uUTKz?B+x?aII*m5eZyctC?@c`q$HH_IP9@>UtdG9 zY8|L-VZJS(r9D2I$agfQYrvUxTDX^J2{C7#^jiE~HG>+{!_-tA_`WEJkMSg{+O~ zeS5Pr+=-NtA(ucy`LFvyVEfw21<1>bR;sbKHnOLu$8hKJVVypK;xz98&f%%y%J+c= zt#&Y`AQ%k&YNuw&$Jqi40x%!`qWna#h*- zXy}Jfaqyx1U5oiss^hbU8WkU(iKe|F*Jm+iQ`am&6$N~uD@ht)Esj1zYyfp(ZH@FO z;IW{&^oIl;t4RC&I@KAb#EzVcbu#F@(~sB_-;9L1UkjZ_wrq}I5RI50!=0#^!>?n| z_Q!3H#f92HkJoETT-#tpjycU$Ax>}Z>h4AxR_@0!kESUvJg%EC)i~JeDMTm zbinUPUCXn#E;C=_Lv?UVh1^Nb{h6?HwC!X{NAcBV>-y2!Qtpm9dd?(%(MwS~gpMV0 zvFB!x*k6+tZV+>t^MUd{n`beZmSQos_J{M<*|mG0*2`k2nAan!HfV4JSJ-uy8)k)< ztY)pdxY|1*sT~8;=FvPIryl{JurTUXcr`*TIJy_31X_hggfza3a$~aIQobzjjsZdD zh||?M4$$!ozBOTgP?9*LbErh>CQz{Mid(wWNNIlx-&5@ZZXOa5*V$ATvt!DQly$PN zNF3NXw5cs78-RX?Xh7}7(k)M=l=+A@Vu6)d3Jqi1ozj*Y%>|2gfFfP7`{=NJtRcE+ zWq=dH-nP<=8H1}L-_Y3N2@KhDf_%5*UnhYwrThUUl~0+1B=R5A*70eNyOF#sY!9ya z1$saChuWpMyJfi4xr-BT5sbV*7ZBo@f&IUU=ClfkcYq;4v$V_aW@*WzfN(CMImz#j zSZa{Ze)bKR9_IZ*aAA9}lb=ADJK+05tiU(Qm|}8gE@runuP=->yK#)&bP0F?ZDrws zhK~Q&#I=Vr{r3NfC<&cNXhYFKwnmQGNQ6kvha5UMM9Mi~d`P7tbC%F3C8Q||h2<-3 z=1?N}qLCpHZE_g1{qB#R=XX8(Z?4OA@BSR#_xp8vPbLsQEz>Co%t_Wc_=&oC5YRy?T{gKyXx?Dsm3>#=b;lBbT6@lCMx}e#F^bbr?!{kZUfUNFxnoU9=beW z0-WO8&NUiE06GIGuZoPIJe@Ea2npNA3mIZ29%FYCl{%9$s`rZ+uCW{257X8c$n6Nw z+olOW^XYux@dH}D4v$lqUN#DTT`Rk*cbC_8(e;F*t4otCVdx$=8x6e{bKbQ^KPV}L z#24kqaT>_Hw9{(Y+oBKEaQotQ+UBa{?!IezbNR@?7rM`nOkkD5g~EXoCJ||p%nKTE zc{?=I?UQj)W0y>)u4mrf)}Z0HY6M2>MGbKB{Emi3M;xo0|b*?|==@fCR;;$C3_sJP^N?0pwEXnRz1A*}IuNEJ%``=#+ zgH80PwD%J0Ft)Ehc$H^}CnUY@y;6NR#{!dMkwNIMc$=<>$qfqZQv5}yjgbe1ya5ND zFshw;^<7O(EJ(ntFU)}BhY**d3woaSn&1(H-s-9!0>EIk4NQ9R1N3T)7jOfF7_C^##Ru8;Dq++wS@NmzX@&bbsH&sY!Ex_uLZ!*2v8)j1>h|15&-_J ze}0504qQx^GF{UTjq1dBQT6W3e&|^@XbND%lX!yP=$X=}Zn!HXbM5xm#^vDdv*MUy zKKAeURoWmRJu;c|;db0~sLUFX@pFtB4Oo&KpkIS*&4HZk*_FGo;LApNu}O<-FvX#- zpZ`Plok1NbVeolol+gdgwTpRp5ZCVL)DVK`${m6G;mk8+za-*~JgVFJ${kzlvJ39> z(?apPvn4!WO2hj!*frWu7sd|20lxOA+8`SVP8A?zq0-?y#X|l{+hD1kzf$L`z@HUMsqB; zp12j4%5jQ)2GO44j=_8fL{a7Ch*?c|+;Z(6ASpcfKI8lZ2k>7yNml`qKe(qcZ=ab0 zn+Od5Q$N1$^&dE8@hD^bA$V;DZi~d)ZTzsOWi)77`HyZ&rLa79_fBi)v^ybgFszeE zktgD&Os|LDSUV ztcFHgmpgp&do3v>0DSLk4mVF+16+}8dSSo+tt}oB;=nuL_@dhVDVG|Uo`Y1-mt?xN z1Ku6DAFkc!o}5xu;`gReY%n&6Hc@2|^oCykO?r2xDc8bczX}lhpD$jXXK9qr9}Vzb z2{`uf#t0O>lNX>utl7*jn>iuFL0j?6O*V-2mdC3jC-l}K zhPw7oRwe(R?XUoBM=%R!J7n7i_j%i3J7X%>vfjPzp-^VB!H%T%MMZtyXpbQ_sQ;-} zAsmB2Z-NneD(QfNyaz6t*5&DRWBSJP5C2Pbocj;e5uujGoI-2rkCMq`fg8HlhDy!8 zosj3w%%~xbFRc6W^4249w>0vZXOT}*! zqHO(hS=Z`%_I#s49JX!A@B>SIvKv-g(B&@`@@Ej8DCzU&Al+TK(=Lp(X_e3&O<+aV zKV+YC4rO2~6{{7FI?hYDyW*tu?_n`3f!&pI8;lb6gdI@A=X145V!m-z$=s^5I_WeapNrqc zEDQRN&y`o+BLpT9l=${p0Ts^eCBrqJ_W8(QTc90X6izummcN{?f`~S;>=uusogKvx8qKSs-~CRl;Mlq-#fJYUv>e4mqZNz zRI&Q~?lTb+dwYf$dF_fS06CeZ_E*l!a3+~V6Qw#Z(nf=7u*5r}C(oU;3x9W)dka(B z1GR?TuN?2Ucvfn#L{i@~yF)eY9JpwUdnw*_fs1#`0jCx2erqU8JW#9*aYMG&?#Pki zgNRkF**galYhl07&+U*&OeAMD25DDC>nq>*erxVc-?2Gk^1~i$;8N;(X!-lgnYq~p zmsI=aTr_m4uO-^xsh3r$N|?r&*cYl6d)B$3aTT@c#)`Cs|6Zd@n3s0d1I841Uel@h zK41>8J70@VqmK>4zE|SXww+)*(uvI!_~QyoNUjC$e|TjyPvSwVb^*w~@Q5EI^cj;h4{@)RkV=CUD(X_k=8;$rb*ns8t}X~Ej55iDP?bV7sn!$2kVjryUe=OMC7i9!TIG%s{YYVXJz^A5sd!H{(n}k z)wz^^FR#X?>LZjGREh-0TjEDdVS`_$x$&qf05iA@F=`hJ)qK&wm90{d^1faq|v9B*9->@qFc&GB!goUb>?) zn|gq^vIp4rd1I ze0_5dWF~QWe=#ZKbU6~qTc8Lc2*0dxY?Us10WOV&Y^Y@DxlD_4Qr%Sa%^uf$`Ir68f>GA?=>)^V3Btyn#;es4xt$s!*E zpt&@yRc~qtU$4(Ct%z8atefFD0681&Z`iF+3sQWU)eb2@l+2)@*!X=?EZ_sla#EnZ z&!gA}u`0E`HO{Vnwnd!oBS4X8U3st-ZvTP+uX;q1(kD(%j1tK8DSp<{q1HSO%}jsX zcq)V6?0>8D#Ys%6n1Veu$Urb~IqM|H=&Ho4`S8k>ki>lq@p5TRO zIHq*zav!gpSek}b_@%98J1KJqxx7nW+;4b&wCJm_+GfvBfk(g8gOyR%6_qDpp*MY!`v2a|t9~A2W zE%-9u1`vM1&|RC&0v4qEXLQeG-2}57PZI1tLv0hN8q)?juI3@W+Cz^9lq)UpW6Ff* z{gwLq`maubt1);@9}$lRQawwYH(bfrv*r;Y?gj3T6ZpGwxp|135=|wu#TW5Nfp5UI zx>o%Z7-9yCM6+7ghd?q02gau&n-Yt*F}BeAqAezE@EvZ#*3PSi7?f!OSd6n5Ry~Qrg+F_k@>J$l0wC{+aky_x%*zRZ50*IR6nJ zot{7b&A7`O+%mKgD20mlIFyTnPICM?G7)Tja&Y$skbV{FnmgZ-HEGIWdGOYYZ?zF6 z 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 PfXC^RXAH{?9HRaUiim`C diff --git a/tgstation.dme b/tgstation.dme index d612f77e42..83b54ca498 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -60,6 +60,7 @@ #define FILE_DIR "code/game/mecha/equipment" #define FILE_DIR "code/game/mecha/equipment/tools" #define FILE_DIR "code/game/mecha/equipment/weapons" +#define FILE_DIR "code/game/mecha/medical" #define FILE_DIR "code/game/mecha/working" #define FILE_DIR "code/game/objects" #define FILE_DIR "code/game/objects/alien" @@ -241,6 +242,7 @@ #include "code\datums\diseases\wizarditis.dm" #include "code\datums\diseases\xeno_transformation.dm" #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\teleport.dm" @@ -527,6 +529,8 @@ #include "code\game\mecha\equipment\mecha_equipment.dm" #include "code\game\mecha\equipment\tools\tools.dm" #include "code\game\mecha\equipment\weapons\weapons.dm" +#include "code\game\mecha\medical\medical.dm" +#include "code\game\mecha\medical\odysseus.dm" #include "code\game\mecha\working\firefighter.dm" #include "code\game\mecha\working\ripley.dm" #include "code\game\mecha\working\working.dm"