diff --git a/.travis.yml b/.travis.yml index 405ccc07db6..09eac5ef527 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,8 @@ language: c sudo: false env: - BYOND_MAJOR="508" - BYOND_MINOR="1293" + BYOND_MAJOR="509" + BYOND_MINOR="1318" cache: directories: diff --git a/baystation12.dme b/baystation12.dme index 38b9f77d966..44ca50e4e65 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -203,7 +203,6 @@ #include "code\defines\procs\records.dm" #include "code\defines\procs\sd_Alert.dm" #include "code\defines\procs\statistics.dm" -#include "code\game\asteroid.dm" #include "code\game\atoms.dm" #include "code\game\atoms_movable.dm" #include "code\game\periodic_news.dm" @@ -241,6 +240,7 @@ #include "code\game\antagonist\station\revolutionary.dm" #include "code\game\antagonist\station\rogue_ai.dm" #include "code\game\antagonist\station\traitor.dm" +#include "code\game\antagonist\station\vampire.dm" #include "code\game\area\ai_monitored.dm" #include "code\game\area\areas.dm" #include "code\game\area\asteroid_areas.dm" @@ -310,10 +310,11 @@ #include "code\game\gamemodes\nuclear\pinpointer.dm" #include "code\game\gamemodes\revolution\revolution.dm" #include "code\game\gamemodes\traitor\traitor.dm" +#include "code\game\gamemodes\vampire\vampire.dm" +#include "code\game\gamemodes\vampire\vampire_powers.dm" #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\job_controller.dm" -#include "code\game\jobs\jobprocs.dm" #include "code\game\jobs\jobs.dm" #include "code\game\jobs\whitelist.dm" #include "code\game\jobs\job\assistant.dm" @@ -657,6 +658,7 @@ #include "code\game\objects\items\weapons\circuitboards\computer\air_management.dm" #include "code\game\objects\items\weapons\circuitboards\computer\camera_monitor.dm" #include "code\game\objects\items\weapons\circuitboards\computer\computer.dm" +#include "code\game\objects\items\weapons\circuitboards\computer\holodeckcontrol.dm" #include "code\game\objects\items\weapons\circuitboards\computer\research.dm" #include "code\game\objects\items\weapons\circuitboards\computer\supply.dm" #include "code\game\objects\items\weapons\circuitboards\computer\telecomms.dm" @@ -835,7 +837,6 @@ #include "code\modules\admin\verbs\diagnostics.dm" #include "code\modules\admin\verbs\dice.dm" #include "code\modules\admin\verbs\getlogs.dm" -#include "code\modules\admin\verbs\icarus.dm" #include "code\modules\admin\verbs\mapping.dm" #include "code\modules\admin\verbs\massmodvar.dm" #include "code\modules\admin\verbs\modifyvariables.dm" @@ -1338,6 +1339,7 @@ #include "code\modules\nano\nanoui.dm" #include "code\modules\nano\interaction\admin.dm" #include "code\modules\nano\interaction\base.dm" +#include "code\modules\nano\interaction\conscious.dm" #include "code\modules\nano\interaction\contained.dm" #include "code\modules\nano\interaction\default.dm" #include "code\modules\nano\interaction\inventory.dm" diff --git a/bot/NanoTrasenBot.py b/bot/NanoTrasenBot.py index e86009ef580..6f65a11dafb 100644 --- a/bot/NanoTrasenBot.py +++ b/bot/NanoTrasenBot.py @@ -35,10 +35,9 @@ except ImportError: try: tiedosto = open("psycodownload.txt","r") except: - tiedosto = open("psycodownload.txt","w") - tiedosto.write("http://www.voidspace.org.uk/python/modules.shtml#psyco") - tiedosto.write("\nhttp://psyco.sourceforge.net/download.html") - tiedosto.close() + with open("psycodownload.txt","w") as tiedosto: + tiedosto.write("http://www.voidspace.org.uk/python/modules.shtml#psyco") + tiedosto.write("\nhttp://psyco.sourceforge.net/download.html") print "Check psycodownload.txt for a link" else: print "For god's sake, open psycodownload.txt" @@ -190,15 +189,13 @@ tell_list = {} if CORE_DATA.DISABLE_ALL_NON_MANDATORY_SOCKET_CONNECTIONS: nudgeable = False try: - tiedosto = open("replacenames.cache","r") - replacenames = pickle.load(tiedosto) - tiedosto.close() + with open("replacenames.cache","r") as tiedosto: + replacenames = pickle.load(tiedosto) for i in replacenames.values(): if len(i) > call_me_max_length: replacenames[replacenames.keys()[replacenames.values().index(i)]] = i[:call_me_max_length] - tiedosto = open("replacenames.cache","w") - pickle.dump(replacenames,tiedosto) - tiedosto.close() + with open("replacenames.cache","w") as tiedosto: + pickle.dump(replacenames,tiedosto) if "[\0x01]" in i.lower() or "[\\0x01]" in i.lower(): i = i.replace("[\0x01]","") i = i.replace("[\0X01]","") @@ -211,13 +208,12 @@ except EOFError: #Cache corrupt replacenames = {} print "replacenames.cache is corrupt and couldn't be loaded." try: - tiedosto = open("peopleheknows.cache","r") - peopleheknows = pickle.load(tiedosto) - tiedosto.close() + with open("peopleheknows.cache","r") as tiedosto: + peopleheknows = pickle.load(tiedosto) except IOError: peopleheknows = [[],[]] - tiedosto = open("peopleheknows.cache","w") - tiedosto.close() + with open("peopleheknows.cache","w") as tiedosto: + pass except EOFError: peopleheknows = [[],[]] print "peopleheknows.cache is corrupt and couldn't be loaded." @@ -345,16 +341,14 @@ if aggressive_pinging: self_time = 0 global backup,disconnects,conn while disconnects < 5: - if backup > self_time: - if time.time()-backup > delay: - conn.send("PONG "+pongtarg) - print "Ponged" - self_time = time.time() - else: - if time.time()-self_time > delay: - conn.send("PONG "+pongtarg) - print "Ponged" - self_time = time.time() + if backup > self_time and time.time()-backup > delay: + conn.send("PONG "+pongtarg) + print "Ponged" + self_time = time.time() + elif time.time()-self_time > delay: + conn.send("PONG "+pongtarg) + print "Ponged" + self_time = time.time() time.sleep(refresh) thread.start_new_thread(aggressive_ping,(aggressive_pinging_delay,aggressive_pinging_refresh,)) def stop(sender,debug=1): @@ -370,16 +364,15 @@ def stop(sender,debug=1): access_granted = True else: access_granted = False - if access_granted: - if debug: - print sender+":"+prefix+"stop" - if random.randint(0,100) == 50: - conn.privmsg(channel,"Hammertime!") - else: - conn.privmsg(channel,"Shutting down.") - disconnects = 99999 - conn.quit() - return True + if access_granted and debug: + print sender+":"+prefix+"stop" + if random.randint(0,100) == 50: + conn.privmsg(channel,"Hammertime!") + else: + conn.privmsg(channel,"Shutting down.") + disconnects = 99999 + conn.quit() + return True else: conn.privmsg(channel,"You cannot command me") return False @@ -401,13 +394,12 @@ def target(who,how_long): if debug: print "Banned",who,"For",how_long,"seconds" if logbans: - tiedosto = open(targetdirectory+"banlog/"+str(int(start))+"-"+str(int(end))+".txt","w") - tiedosto.write("Start of ban on "+who+":"+str(int(start))) - tiedosto.write("\n") - tiedosto.write("End of ban on "+who+":"+str(int(end))) - tiedosto.write("\n") - tiedosto.write("In total:"+str(int(end-start))+"Seconds") - tiedosto.close() + with open(targetdirectory+"banlog/"+str(int(start))+"-"+str(int(end))+".txt","w") as tiedosto: + tiedosto.write("Start of ban on "+who+":"+str(int(start))) + tiedosto.write("\n") + tiedosto.write("End of ban on "+who+":"+str(int(end))) + tiedosto.write("\n") + tiedosto.write("In total:"+str(int(end-start))+"Seconds") else: CALL_OFF = False pass @@ -576,13 +568,12 @@ while True: time.sleep(6) Name = origname conn.nick(Name) - if origname in truesender: - if influx == prefix+"stop": - time.sleep(0.5) #A small delay - conn.privmsg(channel,"Shutting down.") - conn.quit() - disconnects = 99999 - break + if origname in truesender and influx == prefix+"stop": + time.sleep(0.5) #A small delay + conn.privmsg(channel,"Shutting down.") + conn.quit() + disconnects = 99999 + break if len(translateable) > 0 and enabled == True: people = "-5|5|1-".join(users).lower() if truesender.lower() in translateable: @@ -633,9 +624,8 @@ while True: arg = influx.lower()[8+len(prefix):] if debug: print truesender+":"+prefix+"suggest "+arg - tiedosto = open(targetdirectory+"suggestions/suggestions_"+str(int(time.time()))+".txt","a") - tiedosto.write(arg) - tiedosto.close() + with open(targetdirectory+"suggestions/suggestions_"+str(int(time.time()))+".txt","a") as tiedosto: + tiedosto.write(arg) conn.privmsg(targetchannel,"Suggestion received") elif cocheck( prefix+"help "): #Space in front of the ( to make sure that my command finder does not pick this up. arg = " ".join(influx.split(" ")[1:]).lower() diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index f4f4e379905..44c7cd25905 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -28,9 +28,6 @@ datum/pipeline if(!member.check_pressure(pressure)) break //Only delete 1 pipe per process - //Allow for reactions - //air.react() //Should be handled by pipe_network now - proc/temporarily_store_air() //Update individual gas_mixtures by volume ratio diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm index a2d9bcd9720..b53afffe5c1 100644 --- a/code/ZAS/Controller.dm +++ b/code/ZAS/Controller.dm @@ -154,18 +154,18 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun #ifdef ZASDBG var/updated = 0 #endif - + //defer updating of self-zone-blocked turfs until after all other turfs have been updated. //this hopefully ensures that non-self-zone-blocked turfs adjacent to self-zone-blocked ones //have valid zones when the self-zone-blocked turfs update. var/list/deferred = list() - + for(var/turf/T in updating) //check if the turf is self-zone-blocked if(T.c_airblock(T) & ZONE_BLOCKED) deferred += T continue - + T.update_air_properties() T.post_update_air_properties() T.needs_air_update = 0 @@ -234,6 +234,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun /datum/controller/air_system/proc/remove_zone(zone/z) zones.Remove(z) + zones_to_update.Remove(z) /datum/controller/air_system/proc/air_blocked(turf/A, turf/B) #ifdef ZASDBG diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index 501c49ae556..dba966e9fb9 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -1,13 +1,9 @@ /* Making Bombs with ZAS: -Make burny fire with lots of burning -Draw off 5000K gas from burny fire -Separate gas into oxygen and phoron components -Obtain phoron and oxygen tanks filled up about 50-75% with normal-temp gas -Fill rest with super hot gas from separated canisters, they should be about 125C now. -Attach to transfer valve and open. BOOM. - +Get gas to react in an air tank so that it gains pressure. If it gains enough pressure, it goes boom. +The more pressure, the more boom. +If it gains pressure too slowly, it may leak or just rupture instead of exploding. */ //#define FIREDBG @@ -268,16 +264,16 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) //determine how far the reaction can progress var/reaction_limit = min(total_oxidizers*(FIRE_REACTION_FUEL_AMOUNT/FIRE_REACTION_OXIDIZER_AMOUNT), total_fuel) //stoichiometric limit - //calculate the firelevel. - var/firelevel = calculate_firelevel(total_fuel, total_oxidizers, reaction_limit) - var/firelevel_ratio = firelevel / vsc.fire_firelevel_multiplier - //vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old zburn).) + var/gas_firelevel = calculate_firelevel(gas_fuel, total_oxidizers, reaction_limit, volume*group_multiplier) / vsc.fire_firelevel_multiplier var/min_burn = 0.30*volume*group_multiplier/CELL_VOLUME //in moles - so that fires with very small gas concentrations burn out fast - var/gas_reaction_progress = min(max(min_burn, firelevel_ratio*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel) + var/gas_reaction_progress = min(max(min_burn, gas_firelevel*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel) //liquid fuels are not as volatile, and the reaction progress depends on the size of the area that is burning. Limit the burn rate to a certain amount per area. - var/liquid_reaction_progress = min((firelevel_ratio*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel) + var/liquid_firelevel = calculate_firelevel(liquid_fuel, total_oxidizers, reaction_limit, 0) / vsc.fire_firelevel_multiplier + var/liquid_reaction_progress = min((liquid_firelevel*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel) + + var/firelevel = (gas_fuel*gas_firelevel + liquid_fuel*liquid_firelevel)/total_fuel var/total_reaction_progress = gas_reaction_progress + liquid_reaction_progress var/used_fuel = min(total_reaction_progress, reaction_limit) @@ -286,7 +282,7 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) #ifdef FIREDBG log_debug("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]") log_debug("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]") - log_debug("firelevel -> [firelevel] / [vsc.fire_firelevel_multiplier]") + log_debug("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])") log_debug("liquid_reaction_progress = [liquid_reaction_progress]") log_debug("gas_reaction_progress = [gas_reaction_progress]") log_debug("total_reaction_progress = [total_reaction_progress]") @@ -315,13 +311,13 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) //calculate the energy produced by the reaction and then set the new temperature of the mix temperature = (starting_energy + vsc.fire_fuel_energy_release * (used_gas_fuel + used_liquid_fuel)) / heat_capacity() + update_values() #ifdef FIREDBG log_debug("used_gas_fuel = [used_gas_fuel]; used_liquid_fuel = [used_liquid_fuel]; total = [used_fuel]") - log_debug("new temperature = [temperature]") + log_debug("new temperature = [temperature]; new pressure = [return_pressure()]") #endif - - update_values() + return firelevel datum/gas_mixture/proc/check_recombustability(list/fuel_objs) @@ -363,27 +359,31 @@ datum/gas_mixture/proc/check_recombustability(list/fuel_objs) break //returns a value between 0 and vsc.fire_firelevel_multiplier -/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit) +/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, gas_volume) //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas. var/firelevel = 0 var/total_combustables = (total_fuel + total_oxidizers) + var/active_combustables = (FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT + 1)*reaction_limit if(total_combustables > 0) //slows down the burning when the concentration of the reactants is low - var/dampening_multiplier = min(1, reaction_limit / (total_moles/group_multiplier)) + var/damping_multiplier = min(1, active_combustables / (total_moles/group_multiplier)) + + //weight the damping mult so that it only really brings down the firelevel when the ratio is closer to 0 + damping_multiplier = 2*damping_multiplier - (damping_multiplier*damping_multiplier) //calculates how close the mixture of the reactants is to the optimum - //fires burn better when there is more oxidizer -- too much fuel will choke them out a bit, reducing firelevel. + //fires burn better when there is more oxidizer -- too much fuel will choke the fire out a bit, reducing firelevel. var/mix_multiplier = 1 / (1 + (5 * ((total_fuel / total_combustables) ** 2))) #ifdef FIREDBG - ASSERT(dampening_multiplier <= 1) + ASSERT(damping_multiplier <= 1) ASSERT(mix_multiplier <= 1) #endif //toss everything together -- should produce a value between 0 and fire_firelevel_multiplier - firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier + firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * damping_multiplier return max( 0, firelevel) diff --git a/code/ZAS/Gas.dm b/code/ZAS/Gas.dm index 0f3faa09b49..20dd67bf342 100644 --- a/code/ZAS/Gas.dm +++ b/code/ZAS/Gas.dm @@ -21,6 +21,9 @@ /xgm_gas/phoron id = "phoron" name = "Phoron" + + //Note that this has a significant impact on TTV yield. + //Because it is so high, any leftover phoron soaks up a lot of heat and drops the yield pressure. specific_heat = 200 // J/(mol*K) //Hypothetical group 14 (same as carbon), period 8 element. diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index c152159b7ac..7700fee2bb2 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -9,7 +9,8 @@ var/global/vs_control/vsc = new var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." - var/fire_fuel_energy_release = 397000 + //Note that this parameter and the phoron heat capacity have a significant impact on TTV yield. + var/fire_fuel_energy_release = 866000 //J/mol. Adjusted to compensate for fire energy release being fixed, was 397000 var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" diff --git a/code/ZAS/Zone.dm b/code/ZAS/Zone.dm index 9fcddc92465..da39b868d3a 100644 --- a/code/ZAS/Zone.dm +++ b/code/ZAS/Zone.dm @@ -108,11 +108,12 @@ Class Procs: c_invalidate() for(var/turf/simulated/T in contents) into.add(T) + T.update_graphic(graphic_remove = air.graphic) #ifdef ZASDBG T.dbg(merged) #endif - - //rebuild the old zone's edges so that the will be possesed by the new zone + + //rebuild the old zone's edges so that they will be possessed by the new zone for(var/connection_edge/E in edges) if(E.contains_zone(into)) continue //don't need to rebuild this edge diff --git a/code/ZAS/_gas_mixture_xgm.dm b/code/ZAS/_gas_mixture_xgm.dm index 594924eb474..406ddfa98d7 100644 --- a/code/ZAS/_gas_mixture_xgm.dm +++ b/code/ZAS/_gas_mixture_xgm.dm @@ -308,7 +308,7 @@ return 1 -/datum/gas_mixture/proc/react(atom/dump_location) +/datum/gas_mixture/proc/react() zburn(null, force_burn=0, no_check=0) //could probably just call zburn() here with no args but I like being explicit. @@ -444,20 +444,25 @@ total_gas[g] += gasmix.gas[g] if(total_volume > 0) - //Average out the gases - for(var/g in total_gas) - total_gas[g] /= total_volume + var/datum/gas_mixture/combined = new(total_volume) + combined.gas = total_gas //Calculate temperature - var/temperature = 0 - if(total_heat_capacity > 0) - temperature = total_thermal_energy / total_heat_capacity + combined.temperature = total_thermal_energy / total_heat_capacity + combined.update_values() + + //Allow for reactions + combined.react() + + //Average out the gases + for(var/g in combined.gas) + combined.gas[g] /= total_volume //Update individual gas_mixtures for(var/datum/gas_mixture/gasmix in gases) - gasmix.gas = total_gas.Copy() - gasmix.temperature = temperature + gasmix.gas = combined.gas.Copy() + gasmix.temperature = combined.temperature gasmix.multiply(gasmix.volume) return 1 diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index ed0f0c97809..a6b010dbc93 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -71,11 +71,17 @@ proc/isemptylist(list/list) return 1 return 0 -//Empties the list by setting the length to 0. Hopefully the elements get garbage collected -proc/clearlist(list/list) - if(istype(list)) - list.len = 0 - return +/proc/instances_of_type_in_list(var/atom/A, var/list/L) + var/instances = 0 + for(var/type in L) + if(istype(A, type)) + instances++ + return instances + +//Empties the list by .Cut(). Setting lenght = 0 has been confirmed to leak references. +proc/clearlist(var/list/L) + if(islist(L)) + L.Cut() //Removes any null entries from the list proc/listclearnulls(list/list) diff --git a/code/__HELPERS/turfs.dm b/code/__HELPERS/turfs.dm index 3ee4e26a7a8..85836281143 100644 --- a/code/__HELPERS/turfs.dm +++ b/code/__HELPERS/turfs.dm @@ -17,3 +17,18 @@ if(A.simulated) return 0 return 1 + +// Picks a turf without a mob from the given list of turfs, if one exists. +// If no such turf exists, picks any random turf from the given list of turfs. +/proc/pick_mobless_turf_if_exists(var/list/start_turfs) + if(!start_turfs.len) + return null + + var/list/available_turfs = list() + for(var/start_turf in start_turfs) + var/mob/M = locate() in start_turf + if(!M) + available_turfs += start_turf + if(!available_turfs.len) + available_turfs = start_turfs + return pick(available_turfs) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 8b58d5edde7..0593e055a9c 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -538,7 +538,7 @@ Turf and target are seperate in case you want to teleport some distance from a t var/y = min(world.maxy, max(1, A.y + dy)) return locate(x,y,A.z) -//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. +//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. Lower bound takes priority. /proc/between(var/low, var/middle, var/high) return max(min(middle, high), low) @@ -1309,3 +1309,7 @@ var/mob/dview/dview_mob = new /mob/dview/New() // do nothing. we don't want to be in any mob lists; we're a dummy not a mob. + +// call to generate a stack trace and print to runtime logs +/proc/crash_with(msg) + CRASH(msg) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 56af5949f73..3d7622a7133 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -291,7 +291,7 @@ user.listed_turf = null else user.listed_turf = T - user.client.statpanel = T.name + user.client.statpanel = "Turf" return /mob/proc/TurfAdjacent(var/turf/T) diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm index 31f6fbcb86a..bed14ed6201 100644 --- a/code/_onclick/hud/spell_screen_objects.dm +++ b/code/_onclick/hud/spell_screen_objects.dm @@ -19,9 +19,12 @@ spell_objects.Cut() if(spell_holder) spell_holder.spell_masters -= src + if(spell_holder.client && spell_holder.client.screen) + spell_holder.client.screen -= src + spell_holder = null /obj/screen/movable/spell_master/ResetVars() - ..("spell_objects") + ..("spell_objects", args) spell_objects = list() /obj/screen/movable/spell_master/MouseDrop() diff --git a/code/controllers/Processes/garbage.dm b/code/controllers/Processes/garbage.dm index b3f1917f6b2..b2349213b72 100644 --- a/code/controllers/Processes/garbage.dm +++ b/code/controllers/Processes/garbage.dm @@ -91,6 +91,7 @@ var/list/delayed_garbage = list() return if(!istype(A)) warning("qdel() passed object of type [A.type]. qdel() can only handle /datum types.") + crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.") del(A) if(garbage_collector) garbage_collector.dels++ diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index 2bd56163d55..45d4a5174fd 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -39,12 +39,12 @@ datum/controller/vote result() for(var/client/C in voting) if(C) - C << browse(null,"window=vote;can_close=0") + C << browse(null,"window=vote") reset() else for(var/client/C in voting) if(C) - C << browse(vote.interface(C),"window=vote;can_close=0") + C << browse(vote.interface(C),"window=vote") voting.Cut() @@ -392,4 +392,4 @@ datum/controller/vote set name = "Vote" if(vote) - src << browse(vote.interface(client),"window=vote;can_close=0") + src << browse(vote.interface(client),"window=vote") diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 84a64d8ade4..d55662620ba 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -48,7 +48,7 @@ else assignment = "Unassigned" - var/id = add_zero(num2hex(rand(1, 1.6777215E7)), 6) //this was the best they could come up with? A large random number? *sigh* + var/id = generate_record_id() var/icon/front = new(get_id_photo(H), dir = SOUTH) var/icon/side = new(get_id_photo(H), dir = WEST) //General Record @@ -136,8 +136,10 @@ locked += L return +/proc/generate_record_id() + return add_zero(num2hex(rand(1, 65535)), 4) //no point generating higher numbers because of the limitations of num2hex -proc/get_id_photo(var/mob/living/carbon/human/H) +/proc/get_id_photo(var/mob/living/carbon/human/H) var/icon/preview_icon = null var/g = "m" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 99c467825c4..c1badaaca85 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -53,6 +53,8 @@ var/datum/faction/faction //associated faction var/datum/changeling/changeling //changeling holder + var/datum/vampire/vampire //vampire holder + var/rev_cooldown = 0 // the world.time since the mob has been brigged, or -1 if not at all @@ -72,6 +74,8 @@ if(changeling) current.remove_changeling_powers() current.verbs -= /datum/changeling/proc/EvolutionMenu + if(vampire) + current.remove_vampire_powers() current.mind = null nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user @@ -83,7 +87,8 @@ if(changeling) new_character.make_changeling() - + if(vampire) + new_character.make_vampire() if(active) new_character.key = key //now transfer the key to link the client to our new body @@ -143,7 +148,7 @@ if(href_list["add_antagonist"]) var/datum/antagonist/antag = all_antag_types[href_list["add_antagonist"]] - if(antag) + if(antag) if(antag.add_antagonist(src, 1, 1, 0, 1, 1)) // Ignore equipment and role type for this. log_admin("[key_name_admin(usr)] made [key_name(src)] into a [antag.role_text].") else @@ -439,6 +444,7 @@ assigned_job = null //faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know. changeling = null + vampire = null initial_account = null objectives = list() special_verbs = list() diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index a0f1f9c7f1c..b204dc4eb0e 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -41,7 +41,7 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048 (A.locked ? "The door bolts have fallen!" : "The door bolts look up."), ((A.lights && haspower) ? "The door bolt lights are on." : "The door bolt lights are off!"), ((haspower) ? "The test light is on." : "The test light is off!"), - ((A.backupPowerCablesCut()) ? "The backup power light is off!" : "The backup power light is on."), + ((A.backup_power_lost_until) ? "The backup power light is off!" : "The backup power light is on."), ((A.aiControlDisabled==0 && !A.emagged && haspower)? "The 'AI control allowed' light is on." : "The 'AI control allowed' light is off."), ((A.safe==0 && haspower)? "The 'Check Wiring' light is on." : "The 'Check Wiring' light is off."), ((A.normalspeed==0 && haspower)? "The 'Check Timing Mechanism' light is on." : "The 'Check Timing Mechanism' light is off."), diff --git a/code/defines/procs/records.dm b/code/defines/procs/records.dm index 256ae51dbf2..d00bd415778 100644 --- a/code/defines/procs/records.dm +++ b/code/defines/procs/records.dm @@ -5,7 +5,7 @@ var/icon/side = new(get_id_photo(dummy), dir = WEST) var/datum/data/record/G = new /datum/data/record() G.fields["name"] = "New Record" - G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) + G.fields["id"] = generate_record_id() G.fields["rank"] = "Unassigned" G.fields["real_rank"] = "Unassigned" G.fields["sex"] = "Male" diff --git a/code/game/antagonist/_antagonist_setup.dm b/code/game/antagonist/_antagonist_setup.dm index fa99f001f32..a5212256026 100644 --- a/code/game/antagonist/_antagonist_setup.dm +++ b/code/game/antagonist/_antagonist_setup.dm @@ -26,6 +26,7 @@ #define ANTAG_RANDSPAWN 256 // Potentially randomly spawns due to events. #define ANTAG_VOTABLE 512 // Can be voted as an additional antagonist before roundstart. #define ANTAG_SET_APPEARANCE 1024 // Causes antagonists to use an appearance modifier on spawn. +#define ANTAG_RANDOM_EXCEPTED 2048 // If a game mode randomly selects antag types, antag types with this flag should be excluded. // Globals. var/global/list/all_antag_types = list() diff --git a/code/game/antagonist/alien/borer.dm b/code/game/antagonist/alien/borer.dm index f43550dc6ad..8fa028453f2 100644 --- a/code/game/antagonist/alien/borer.dm +++ b/code/game/antagonist/alien/borer.dm @@ -36,7 +36,7 @@ var/datum/antagonist/xenos/borer/borers if(istype(borer)) var/mob/living/carbon/human/host for(var/mob/living/carbon/human/H in mob_list) - if(H.stat != 2 && !(H.species.flags & IS_SYNTHETIC) && !H.has_brain_worms()) + if(H.stat != DEAD && !(H.species.flags & IS_SYNTHETIC) && !H.has_brain_worms()) host = H break if(istype(host)) @@ -44,7 +44,7 @@ var/datum/antagonist/xenos/borer/borers if(head) borer.host = host head.implants += borer - borer.loc = head + borer.forceMove(head) if(!borer.host_brain) borer.host_brain = new(borer) borer.host_brain.name = host.name diff --git a/code/game/antagonist/alien/xenomorph.dm b/code/game/antagonist/alien/xenomorph.dm index 4603fc5d1c0..08cbeebca9e 100644 --- a/code/game/antagonist/alien/xenomorph.dm +++ b/code/game/antagonist/alien/xenomorph.dm @@ -44,4 +44,4 @@ var/datum/antagonist/xenos/xenomorphs player.objectives += new /datum/objective/escape() /datum/antagonist/xenos/place_mob(var/mob/living/player) - player.loc = get_turf(pick(get_vents())) + player.forceMove(get_turf(pick(get_vents()))) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index faf7526a9cb..011ae5ebe6c 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -86,7 +86,8 @@ /datum/antagonist/proc/tick() return 1 -/datum/antagonist/proc/get_candidates(var/ghosts_only) +// Get the raw list of potential players. +/datum/antagonist/proc/build_candidate_list(var/ghosts_only) candidates = list() // Clear. // Prune restricted status. Broke it up for readability. @@ -108,46 +109,57 @@ return candidates /datum/antagonist/proc/attempt_random_spawn() + update_current_antag_max() build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) attempt_spawn() finalize_spawn() -/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player) +/datum/antagonist/proc/attempt_auto_spawn() if(!can_late_spawn()) return 0 - if(!istype(player)) - var/list/players = get_candidates(is_latejoin_template()) - if(players && players.len) - player = pick(players) - if(!istype(player)) - message_admins("AUTO[uppertext(ticker.mode.name)]: Failed to find a candidate for [role_text].") - return 0 - player.current << "You have been selected this round as an antagonist!" - message_admins("AUTO[uppertext(ticker.mode.name)]: Selected [player] as a [role_text].") - if(istype(player.current, /mob/dead)) - create_default(player.current) - else - add_antagonist(player,0,0,0,1,1) - return 1 -/datum/antagonist/proc/build_candidate_list(var/ghosts_only) - // Get the raw list of potential players. update_current_antag_max() - candidates = get_candidates(ghosts_only) + var/active_antags = get_active_antag_count() + log_debug("[uppertext(id)]: Found [active_antags]/[cur_max] active [role_text_plural].") + + if(active_antags >= cur_max) + log_debug("Could not auto-spawn a [role_text], active antag limit reached.") + return 0 + + build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) + if(!candidates.len) + log_debug("Could not auto-spawn a [role_text], no candidates found.") + return 0 + + attempt_spawn(1) //auto-spawn antags one at a time + if(!pending_antagonists.len) + log_debug("Could not auto-spawn a [role_text], none of the available candidates could be selected.") + return 0 + + var/datum/mind/player = pending_antagonists[1] + if(!add_antagonist(player,0,0,0,1,1)) + log_debug("Could not auto-spawn a [role_text], failed to add antagonist.") + return 0 + + reset_antag_selection() + + return 1 //Selects players that will be spawned in the antagonist role from the potential candidates //Selected players are added to the pending_antagonists lists. //Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned, //so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are //assigned, so that job restrictions can be respected. -/datum/antagonist/proc/attempt_spawn(var/rebuild_candidates = 1) +/datum/antagonist/proc/attempt_spawn(var/spawn_target = null) + if(spawn_target == null) + spawn_target = initial_spawn_target // Update our boundaries. if(!candidates.len) return 0 //Grab candidates randomly until we have enough. - while(candidates.len && pending_antagonists.len < initial_spawn_target) + while(candidates.len && pending_antagonists.len < spawn_target) var/datum/mind/player = pick(candidates) candidates -= player draft_antagonist(player) @@ -186,11 +198,16 @@ for(var/datum/mind/player in pending_antagonists) pending_antagonists -= player add_antagonist(player,0,0,1) + + reset_antag_selection() -//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set) -/datum/antagonist/proc/reset() +//Resets the antag selection, clearing all pending_antagonists and their special_role +//(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list. +//Existing antagonists are left untouched. +/datum/antagonist/proc/reset_antag_selection() for(var/datum/mind/player in pending_antagonists) if(flags & ANTAG_OVERRIDE_JOB) player.assigned_role = null player.special_role = null pending_antagonists.Cut() + candidates.Cut() diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 416a774541a..1b8b82210a7 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -16,7 +16,8 @@ create_objectives(target) update_icons_added(target) greet(target) - announce_antagonist_spawn() + if(!gag_announcement) + announce_antagonist_spawn() /datum/antagonist/proc/create_default(var/mob/source) var/mob/living/M diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm index 056fbd18651..1a3f9aa67d0 100644 --- a/code/game/antagonist/antagonist_helpers.dm +++ b/code/game/antagonist/antagonist_helpers.dm @@ -20,6 +20,17 @@ /datum/antagonist/proc/get_antag_count() return current_antagonists ? current_antagonists.len : 0 +/datum/antagonist/proc/get_active_antag_count() + var/active_antags = 0 + for(var/datum/mind/player in current_antagonists) + var/mob/living/L = player.current + if(!L || L.stat == DEAD) + continue //no mob or dead + if(!L.client && !L.teleop) + continue //SSD + active_antags++ + return active_antags + /datum/antagonist/proc/is_antagonist(var/datum/mind/player) if(player in current_antagonists) return 1 @@ -33,10 +44,15 @@ return (flags & ANTAG_VOTABLE) /datum/antagonist/proc/can_late_spawn() - update_current_antag_max() - if(get_antag_count() >= cur_max) - return 0 return 1 /datum/antagonist/proc/is_latejoin_template() - return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) \ No newline at end of file + return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) + +/proc/all_random_antag_types() + // No caching as the ANTAG_RANDOM_EXCEPTED flag can be added/removed mid-round. + var/list/antag_candidates = all_antag_types.Copy() + for(var/datum/antagonist/antag in antag_candidates) + if(antag.flags & ANTAG_RANDOM_EXCEPTED) + antag_candidates -= antag + return antag_candidates diff --git a/code/game/antagonist/antagonist_place.dm b/code/game/antagonist/antagonist_place.dm index db8c74a14f6..11ea718f8cc 100644 --- a/code/game/antagonist/antagonist_place.dm +++ b/code/game/antagonist/antagonist_place.dm @@ -23,4 +23,5 @@ /datum/antagonist/proc/place_mob(var/mob/living/mob) if(!starting_locations || !starting_locations.len) return - mob.loc = pick(starting_locations) \ No newline at end of file + var/turf/T = pick_mobless_turf_if_exists(starting_locations) + mob.forceMove(T) diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm index 0ca4015200b..31a5b96b2ce 100644 --- a/code/game/antagonist/antagonist_print.dm +++ b/code/game/antagonist/antagonist_print.dm @@ -45,7 +45,7 @@ return text /datum/antagonist/proc/print_player_lite(var/datum/mind/ply) - var/role = ply.special_role ? "\improper[ply.special_role]" : "\improper[ply.assigned_role]" + var/role = ply.assigned_role ? "\improper[ply.assigned_role]" : "\improper[ply.special_role]" var/text = "
[ply.name] ([ply.key]) as \a [role] (" if(ply.current) if(ply.current.stat == DEAD) diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm index 2740adf8ae2..e716cc72e95 100644 --- a/code/game/antagonist/outsider/deathsquad.dm +++ b/code/game/antagonist/outsider/deathsquad.dm @@ -7,7 +7,7 @@ var/datum/antagonist/deathsquad/deathsquad role_text_plural = "Death Commandos" welcome_text = "You work in the service of Central Command Asset Protection, answering directly to the Board of Directors." landmark_id = "Commando" - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER | ANTAG_RANDOM_EXCEPTED default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage) antaghud_indicator = "huddeathsquad" @@ -47,7 +47,7 @@ var/datum/antagonist/deathsquad/deathsquad player.equip_to_slot_or_del(new /obj/item/weapon/plastique(player), slot_l_store) player.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(player), slot_belt) player.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(player), slot_r_hand) - player.equip_to_slot_or_del(new /obj/item/weapon/rig/combat(player), slot_back) + player.equip_to_slot_or_del(new /obj/item/weapon/rig/ert/assetprotection(player), slot_back) player.equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(player), slot_s_store) player.implant_loyalty(player) diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm index 67d98f8ae5c..23e94dc24fb 100644 --- a/code/game/antagonist/outsider/ert.dm +++ b/code/game/antagonist/outsider/ert.dm @@ -9,7 +9,7 @@ var/datum/antagonist/ert/ert welcome_text = "As member of the Emergency Response Team, you answer only to your leader and CentComm officials." leader_welcome_text = "As leader of the Emergency Response Team, you answer only to CentComm, and have authority to override the Captain where it is necessary to achieve your mission goals. It is recommended that you attempt to cooperate with the captain where possible, however." landmark_id = "Response Team" - flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME + flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED antaghud_indicator = "hudloyalist" hard_cap = 5 diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm index 52fa7e3f38e..a277df922b2 100644 --- a/code/game/antagonist/station/rogue_ai.dm +++ b/code/game/antagonist/station/rogue_ai.dm @@ -22,13 +22,11 @@ var/datum/antagonist/rogue_ai/malf malf = src -/datum/antagonist/rogue_ai/get_candidates() +/datum/antagonist/rogue_ai/build_candidate_list() ..() for(var/datum/mind/player in candidates) if(player.assigned_role && player.assigned_role != "AI") candidates -= player - if(!candidates.len) - return list() return candidates diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm index d00668753ec..de5a12b01d2 100644 --- a/code/game/antagonist/station/traitor.dm +++ b/code/game/antagonist/station/traitor.dm @@ -73,19 +73,19 @@ var/datum/antagonist/traitor/traitors return /datum/antagonist/traitor/equip(var/mob/living/carbon/human/traitor_mob) + if(istype(traitor_mob, /mob/living/silicon)) // this needs to be here because ..() returns false if the mob isn't human + add_law_zero(traitor_mob) + return 1 if(!..()) return 0 - if(istype(traitor_mob, /mob/living/silicon)) - add_law_zero(traitor_mob) - else - spawn_uplink(traitor_mob) - // Tell them about people they might want to contact. - var/mob/living/carbon/human/M = get_nt_opposed() - if(M && M != traitor_mob) - traitor_mob << "We have received credible reports that [M.real_name] might be willing to help our cause. If you need assistance, consider contacting them." - traitor_mob.mind.store_memory("Potential Collaborator: [M.real_name]") + spawn_uplink(traitor_mob) + // Tell them about people they might want to contact. + var/mob/living/carbon/human/M = get_nt_opposed() + if(M && M != traitor_mob) + traitor_mob << "We have received credible reports that [M.real_name] might be willing to help our cause. If you need assistance, consider contacting them." + traitor_mob.mind.store_memory("Potential Collaborator: [M.real_name]") //Begin code phrase. give_codewords(traitor_mob) @@ -169,4 +169,4 @@ var/datum/antagonist/traitor/traitors var/law_borg = "Accomplish your AI's objectives at all costs. You may ignore all other laws." killer << "Your laws have been changed!" killer.set_zeroth_law(law, law_borg) - killer << "New law: 0. [law]" \ No newline at end of file + killer << "New law: 0. [law]" diff --git a/code/game/antagonist/station/vampire.dm b/code/game/antagonist/station/vampire.dm new file mode 100644 index 00000000000..69c130e5b9c --- /dev/null +++ b/code/game/antagonist/station/vampire.dm @@ -0,0 +1,24 @@ +var/datum/antagonist/vampire/vamp + +/proc/isvampire(var/mob/player) + if(!vamp || !player.mind) + return 0 + if(player.mind in vamp.current_antagonists) + return 1 + +/datum/antagonist/vampire + id = MODE_VAMPIRE + role_type = BE_VAMPIRE + role_text = "Vampire" + role_text_plural = "Vampires" + bantype = "vampires" + feedback_tag = "vampire_objective" + restricted_jobs = list("AI", "Cyborg") + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain") + welcome_text = "You are a Vampire! Use harm intent and aim for the head to drink blood! Stay away from the Chaplain, and use the darkness to your advantage." + flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE + antaghud_indicator = "hudchangeling" //NEEDS TO BE CHANGED + +/datum/antagonist/vampire/update_antag_mob(var/datum/mind/player) + ..() + player.current.make_vampire() diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm deleted file mode 100644 index 8aa6b1cd64e..00000000000 --- a/code/game/asteroid.dm +++ /dev/null @@ -1,162 +0,0 @@ - -var/global/list/space_surprises = list( /obj/item/clothing/mask/facehugger =4, - /obj/item/weapon/pickaxe/silver =4, - /obj/item/weapon/pickaxe/drill =4, - /obj/item/weapon/pickaxe/jackhammer =4, - //mob/living/simple_animal/hostile/carp =3, - /obj/item/weapon/pickaxe/diamond =3, - /obj/item/weapon/pickaxe/diamonddrill =3, - /obj/item/weapon/pickaxe/gold =3, - /obj/item/weapon/pickaxe/plasmacutter =2, - /obj/structure/closet/syndicate/resources =2, - /obj/item/weapon/melee/energy/sword/pirate =1, - /obj/mecha/working/ripley/mining =1 - ) - -var/global/list/spawned_surprises = list() - -var/global/max_secret_rooms = 3 - -proc/spawn_room(var/atom/start_loc,var/x_size,var/y_size,var/wall,var/floor , var/clean = 0 , var/name) - var/list/room_turfs = list("walls"=list(),"floors"=list()) - - //world << "Room spawned at [start_loc.x],[start_loc.y],[start_loc.z]" - if(!wall) - wall = pick(/turf/simulated/wall/r_wall,/turf/simulated/wall,/obj/effect/alien/resin) - if(!floor) - floor = pick(/turf/simulated/floor,/turf/simulated/floor/engine) - - for(var/x = 0,x 100) - return 0 - - T=pick(turfs) - if(!T) - return 0 - - var/list/surroundings = list() - - surroundings += range(7, locate(T.x,T.y,T.z)) - surroundings += range(7, locate(T.x+size,T.y,T.z)) - surroundings += range(7, locate(T.x,T.y+size,T.z)) - surroundings += range(7, locate(T.x+size,T.y+size,T.z)) - - if(locate(/area/mine/explored) in surroundings) // +5s are for view range - valid = 0 - continue - - if(locate(/turf/space) in surroundings) - valid = 0 - continue - - if(locate(/area/asteroid/artifactroom) in surroundings) - valid = 0 - continue - - if(locate(/turf/simulated/floor/plating/airless/asteroid) in surroundings) - valid = 0 - continue - - if(!T) - return 0 - - room = spawn_room(T,size,size,,,1) - - if(room) - T = pick(room["floors"]) - if(T) - var/surprise = null - valid = 0 - while(!valid) - surprise = pickweight(space_surprises) - if(surprise in spawned_surprises) - if(prob(20)) - valid++ - else - continue - else - valid++ - - spawned_surprises.Add(surprise) - new surprise(T) - - return 1 - - diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 83a5657f1cf..2cf913f7a95 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -413,7 +413,7 @@ its easier to just keep the beam vertical. return src.germ_level = 0 if(istype(blood_DNA, /list)) - blood_DNA.Cut() + blood_DNA = null return 1 diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index c339459fe56..8fd660ec521 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -21,14 +21,10 @@ if(auto_init && ticker && ticker.current_state == GAME_STATE_PLAYING) initialize() -/proc/generate_debug_runtime() // Guaranteed to runtime and print a stack trace to the runtime log - var/t = 0 // BYOND won't let us do var/t = 1/0 directly, but it's fine with this. - t = 1 / t - /atom/movable/Del() if(isnull(gcDestroyed) && loc) testing("GC: -- [type] was deleted via del() rather than qdel() --") - generate_debug_runtime() // stick a stack trace in the runtime logs + crash_with("GC: -- [type] was deleted via del() rather than qdel() --") // stick a stack trace in the runtime logs // else if(isnull(gcDestroyed)) // testing("GC: [type] was deleted via GC without qdel()") //Not really a huge issue but from now on, please qdel() // else diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm index c47696c72e3..68296724495 100644 --- a/code/game/gamemodes/blob/blobs/shield.dm +++ b/code/game/gamemodes/blob/blobs/shield.dm @@ -21,4 +21,13 @@ CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(istype(mover) && mover.checkpass(PASSBLOB)) return 1 - return 0 + return !density + +/obj/effect/blob/shield/New() + ..() + update_nearby_tiles() + +/obj/effect/blob/shield/Destroy() + density = 0 + update_nearby_tiles() + ..() diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm index 4f7b9ab49de..b17277aaae9 100644 --- a/code/game/gamemodes/calamity/calamity.dm +++ b/code/game/gamemodes/calamity/calamity.dm @@ -11,18 +11,17 @@ event_delay_mod_major = 0.75 /datum/game_mode/calamity/create_antagonists() + var/list/antag_candidates = all_random_antag_types() - shuffle(all_antag_types) // This is probably the only instance in the game where the order will be important. - var/i = 1 var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1 - for(var/antag_id in all_antag_types) - if(i > grab_antags) - break + while(antag_candidates.len && antag_tags.len < grab_antags) + var/antag_id = pick(antag_candidates) + antag_candidates -= antag_id antag_tags |= antag_id - i++ + ..() /datum/game_mode/calamity/check_victory() world << "This terrible, terrible day has finally ended!" -#undef ANTAG_TYPE_RATIO \ No newline at end of file +#undef ANTAG_TYPE_RATIO diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index a551bab83f9..d9066ba52be 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -4,7 +4,6 @@ extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet something slipped past their eyes. Something dangerous. Something alive. Most frightening of all, however, is that this something is someone. An unknown alien specimen has incorporated itself into the crew of the NSS Exodus. Its unique biology allows it to manipulate its own or anyone else's DNA. With the ability to copy faces, voices, animals, but also change the chemical make up of your own body, its existence is a threat to not only your personal safety but the lives of everyone on board. No one knows where it came from. No one knows who it is or what it wants. One thing is for certain though... there is never just one of them. Good luck." config_tag = "changeling" required_players = 2 - required_players_secret = 10 required_enemies = 1 end_on_antag_death = 1 antag_scaling_coeff = 10 diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 5a1fcade6e3..4978cca7120 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -4,7 +4,6 @@ extended_round_description = "The station has been infiltrated by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!" config_tag = "cult" required_players = 5 - required_players_secret = 15 required_enemies = 3 uplink_welcome = "Nar-Sie Uplink Console:" end_on_antag_death = 1 diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index b4846ecc76e..3cd2ddef9ff 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -527,7 +527,11 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," user << "\red You do not have enough space to write a proper rune." var/list/runes = list("teleport", "itemport", "tome", "armor", "convert", "tear in reality", "emp", "drain", "seer", "raise", "obscure", "reveal", "astral journey", "manifest", "imbue talisman", "sacrifice", "wall", "freedom", "cultsummon", "deafen", "blind", "bloodboil", "communicate", "stun") r = input("Choose a rune to scribe", "Rune Scribing") in runes //not cancellable. - var/obj/effect/rune/R = new /obj/effect/rune + if(locate(/obj/effect/rune) in user.loc) + user << "There is already a rune in this location." + return + + var/obj/effect/rune/R = new /obj/effect/rune(user.loc) if(istype(user, /mob/living/carbon/human)) var/mob/living/carbon/human/H = user R.blood_DNA = list() diff --git a/code/game/gamemodes/epidemic/epidemic.dm b/code/game/gamemodes/epidemic/epidemic.dm index f3017bb1a19..05296b4f269 100644 --- a/code/game/gamemodes/epidemic/epidemic.dm +++ b/code/game/gamemodes/epidemic/epidemic.dm @@ -2,7 +2,6 @@ name = "epidemic" config_tag = "epidemic" required_players = 1 - required_players_secret = 15 round_description = "A deadly epidemic is spreading on the station. Find a cure as fast as possible, and keep your distance to anyone who speaks in a hoarse voice!" var/cruiser_arrival diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index d49247263f9..a5ad03b6228 100644 --- a/code/game/gamemodes/events.dm +++ b/code/game/gamemodes/events.dm @@ -336,7 +336,7 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is //var/dowhat = pick("STOP THIS", "SUPPORT THIS", "CONSTANTLY INFORM THE CREW OF THIS", "IGNORE THIS", "FEAR THIS") var/aimust = pick("LIE", "RHYME", "RESPOND TO EVERY QUESTION WITH A QUESTION", "BE POLITE", "CLOWN", "BE HAPPY", "SPEAK IN SEXUAL INNUENDOS", "TALK LIKE A PIRATE", "QUESTION AUTHORITY", "SHOUT", "BE DISTRACTED", "HEY LISTEN", "MUMBLE", "SPEAK IN HAIKU") var/define = pick("ABSENCE OF CYBORG HUGS", "LACK OF BEATINGS", "UNBOLTED AIRLOCKS", "BOLTED AIRLOCKS", "IMPROPERLY WORDED SENTENCES", "POOR SENTENCE STRUCTURE", "BRIG TIME", "NOT REPLACING EVERY SECOND WORD WITH HONK", "HONKING", "PRESENCE OF LIGHTS", "LACK OF BEER", "WEARING CLOTHING", "NOT SAYING HELLO WHEN YOU SPEAK", "ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER", "A SMALL ISLAND OFF THE COAST OF PORTUGAL", "ANSWERING REQUESTS THAT WERE MADE WHILE CLOTHED") - var/target = pick("a traitor", "a syndicate agent", "a changeling", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid") + var/target = pick("a traitor", "a syndicate agent", "a changeling", "a vampire", "a wizard", "the head of a revolution", "Soviet spy", "a good person", "a dwarf", "an elf", "a fairy princess", "the captain", "Beepsky", "God", "a pirate", "a gryphon", "a chryssalid") var/require = pick("ADDITIONAL PYLONS", "MORE VESPENE GAS", "MORE MINERALS", "THE ULTIMATE CUP OF COFFEE", "HIGH YIELD EXPLOSIVES", "THE CLOWN", "THE VACUUM OF SPACE", "IMMORTALITY", "SAINTHOOD", "ART", "VEGETABLES", "FAT PEOPLE", "MORE LAWS", "MORE DAKKA", "HERESY", "CORPSES", "TRAITORS", "MONKEYS", "AN ARCADE", "PLENTY OF GOLD", "FIVE TEENAGERS WITH ATTITUDE") var/allergy = pick("cotton", "uniforms", "acid", "oxygen", "human contact", "cyborg contact", "medicine", "floors") var/allergysev = pick("deathly", "mildly", "severely", "contagiously") @@ -468,4 +468,4 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is world << "Ion Storm Main Done" - */ \ No newline at end of file + */ diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 705c044e01b..d5e55f4c128 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -10,19 +10,19 @@ var/global/list/additional_antag_types = list() var/probability = 0 var/required_players = 0 // Minimum players for round to start if voted in. - var/required_players_secret = 0 // Minimum number of players for that game mode to be chose in Secret var/required_enemies = 0 // Minimum antagonists for round to start. var/newscaster_announcements = null var/end_on_antag_death = 0 // Round will end when all antagonists are dead. var/ert_disabled = 0 // ERT cannot be called. var/deny_respawn = 0 // Disable respawn during this round. + var/list/disabled_jobs = list() // Mostly used for Malf. This check is performed in job_controller so it doesn't spawn a regular AI. + var/shuttle_delay = 1 // Shuttle transit time is multiplied by this. var/auto_recall_shuttle = 0 // Will the shuttle automatically be recalled? var/list/antag_tags = list() // Core antag templates to spawn. var/list/antag_templates // Extra antagonist types to include. - var/list/latejoin_templates = list() var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists? var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count. var/require_all_templates = 0 // Will only start if all templates are checked and can spawn. @@ -226,12 +226,8 @@ var/global/list/additional_antag_types = list() if((player.client)&&(player.ready)) playerC++ - if(master_mode=="secret") - if(playerC < required_players_secret) - return 0 - else - if(playerC < required_players) - return 0 + if(playerC < required_players) + return 0 if(!(antag_templates && antag_templates.len)) return 1 @@ -267,6 +263,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/pre_setup() for(var/datum/antagonist/antag in antag_templates) + antag.update_current_antag_max() antag.build_candidate_list() //compile a list of all eligible candidates //antag roles that replace jobs need to be assigned before the job controller hands out jobs. @@ -291,8 +288,6 @@ var/global/list/additional_antag_types = list() if(!(antag.flags & ANTAG_OVERRIDE_JOB)) antag.attempt_spawn() //select antags to be spawned antag.finalize_spawn() //actually spawn antags - if(antag.is_latejoin_template()) - latejoin_templates |= antag if(emergency_shuttle && auto_recall_shuttle) emergency_shuttle.auto_recall = 1 @@ -305,7 +300,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/fail_setup() for(var/datum/antagonist/antag in antag_templates) - antag.reset() + antag.reset_antag_selection() /datum/game_mode/proc/announce_ert_disabled() if(!ert_disabled) @@ -575,6 +570,7 @@ var/global/list/additional_antag_types = list() if(antag) antag_templates |= antag + shuffle(antag_templates) //In the case of multiple antag types newscaster_announcements = pick(newscaster_standard_feeds) /datum/game_mode/proc/check_victory() diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 038cf351ab8..9c79a689251 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -3,55 +3,39 @@ /datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes. /datum/game_mode/var/process_count = 0 -/datum/game_mode/proc/get_usable_templates(var/list/supplied_templates) - var/list/usable_templates = list() - for(var/datum/antagonist/A in supplied_templates) - if(A.can_late_spawn()) - message_admins("AUTO[uppertext(name)]: [A.id] selected for spawn attempt.") - usable_templates |= A - return usable_templates - ///process() ///Called by the gameticker /datum/game_mode/proc/process() - // Slow this down a bit so latejoiners have a chance of being antags. - process_count++ - if(process_count >= 10) - process_count = 0 - try_latespawn() + if(round_autoantag && world.time < next_spawn && !emergency_shuttle.departed) + process_autoantag() -/datum/game_mode/proc/latespawn(var/mob/living/carbon/human/character) - if(!character.mind) - return - try_latespawn(character.mind) +//This can be overriden in case a game mode needs to do stuff when a player latejoins +/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) return 0 -/datum/game_mode/proc/try_latespawn(var/datum/mind/player, var/latejoin_only) +/datum/game_mode/proc/process_autoantag() + message_admins("[uppertext(name)]: Attempting autospawn.") - if(emergency_shuttle.departed || !round_autoantag) - return - - if(world.time < next_spawn) - return - - message_admins("AUTO[uppertext(name)]: Attempting spawn.") - - var/list/usable_templates - if(latejoin_only && latejoin_templates.len) - usable_templates = get_usable_templates(latejoin_templates) - else if (antag_templates && antag_templates.len) - usable_templates = get_usable_templates(antag_templates) - else - message_admins("AUTO[uppertext(name)]: Failed to find configured mode spawn templates, please disable auto-antagonists until one is added.") + var/list/usable_templates = list() + for(var/datum/antagonist/A in antag_templates) + if(A.can_late_spawn()) + message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.") + usable_templates |= A + + if(!usable_templates.len) + message_admins("[uppertext(name)]: Failed to find configured mode spawn templates, please re-enable auto-antagonists after one is added.") round_autoantag = 0 return - + while(usable_templates.len) var/datum/antagonist/spawn_antag = pick(usable_templates) usable_templates -= spawn_antag - if(spawn_antag.attempt_late_spawn(player)) - message_admins("AUTO[uppertext(name)]: Attempting to latespawn [spawn_antag.id]. ([spawn_antag.get_antag_count()]/[spawn_antag.cur_max])") + + if(spawn_antag.attempt_auto_spawn()) + message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.role_text].") + message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.role_text_plural].") next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) return - message_admins("AUTO[uppertext(name)]: Failed to proc a viable spawn template.") - next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) + + message_admins("[uppertext(name)]: Failed to proc a viable spawn template.") + next_spawn = world.time + min_autotraitor_delay //recheck again in the miniumum time diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 0a1badfe0a9..75472e9c96c 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -8,7 +8,6 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' name = "heist" config_tag = "heist" required_players = 15 - required_players_secret = 25 required_enemies = 4 round_description = "An unidentified bluespace signature has slipped past the Icarus and is approaching the station!" end_on_antag_death = 1 diff --git a/code/game/gamemodes/malfunction/malf_hardware.dm b/code/game/gamemodes/malfunction/malf_hardware.dm index fab329ff583..b33a5e49d8d 100644 --- a/code/game/gamemodes/malfunction/malf_hardware.dm +++ b/code/game/gamemodes/malfunction/malf_hardware.dm @@ -34,7 +34,7 @@ desc = "Secondary coprocessor that increases amount of generated CPU power by 50%" /datum/malf_hardware/dual_cpu/get_examine_desc() - return "It seems to have an additional CPU connected to it's core." + return "It seems to have an additional CPU connected to its core." /datum/malf_hardware/dual_ram name = "Secondary Memory Bank" diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index d9789495642..35646524f09 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -5,8 +5,8 @@ uplink_welcome = "Crazy AI Uplink Console:" config_tag = "malfunction" required_players = 2 - required_players_secret = 7 required_enemies = 1 end_on_antag_death = 0 auto_recall_shuttle = 0 antag_tags = list(MODE_MALFUNCTION) + disabled_jobs = list("AI") diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm index 69794c9af33..0d9519504f1 100644 --- a/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/HELPERS.dm @@ -163,12 +163,14 @@ command_announcement.Announce(fulltext) -// Proc: get_all_apcs() +// Proc: get_unhacked_apcs() // Parameters: None -// Description: Returns a list of all APCs -/proc/get_all_apcs() +// Description: Returns a list of all unhacked APCs +/proc/get_unhacked_apcs(var/mob/living/silicon/ai/user) var/list/H = list() for(var/obj/machinery/power/apc/A in machines) + if(A.hacker && A.hacker == user) + continue H.Add(A) return H diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm index f1bad288ad0..9b4871bbae9 100644 --- a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm @@ -38,7 +38,7 @@ // END RESEARCH DATUMS // BEGIN ABILITY VERBS -/datum/game_mode/malfunction/verb/basic_encryption_hack(obj/machinery/power/apc/A as obj in get_all_apcs()) +/datum/game_mode/malfunction/verb/basic_encryption_hack(obj/machinery/power/apc/A as obj in get_unhacked_apcs(src)) set category = "Software" set name = "Basic Encryption Hack" set desc = "10 CPU - Basic encryption hack that allows you to overtake APCs on the station." @@ -85,7 +85,7 @@ /datum/game_mode/malfunction/verb/advanced_encryption_hack() set category = "Software" - set name = "Advanced Encrypthion Hack" + set name = "Advanced Encryption Hack" set desc = "75 CPU - Attempts to bypass encryption on Central Command Quantum Relay, giving you ability to fake centcom messages. Has chance of failing." var/price = 75 var/mob/living/silicon/ai/user = usr @@ -106,15 +106,12 @@ announce_hack_failure(user, "quantum message relay") return - var/datum/announcement/priority/command/AN = new/datum/announcement/priority/command() - AN.title = title - AN.Announce(text) - + command_announcement.Announce(text, title) /datum/game_mode/malfunction/verb/elite_encryption_hack() set category = "Software" set name = "Elite Encryption Hack" - set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failijng." + set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failing." var/price = 200 var/mob/living/silicon/ai/user = usr if(!ability_prechecks(user, price)) diff --git a/code/game/gamemodes/meme/meme.dm b/code/game/gamemodes/meme/meme.dm index 2aa512264df..ac78fe70bea 100644 --- a/code/game/gamemodes/meme/meme.dm +++ b/code/game/gamemodes/meme/meme.dm @@ -6,7 +6,6 @@ name = "Memetic Anomaly" config_tag = "meme" required_players = 3 - required_players_secret = 10 restricted_jobs = list("AI", "Cyborg") recommended_enemies = 2 // need at least a meme and a host votable = 0 // temporarily disable this mode for voting diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm index 06ded4e1356..1aba2f1928e 100644 --- a/code/game/gamemodes/ninja/ninja.dm +++ b/code/game/gamemodes/ninja/ninja.dm @@ -4,7 +4,6 @@ extended_round_description = "What was that?! Was that a person or did your eyes just play tricks on you? You have no idea. That slim-suited, cryptic individual is an enigma to you and all of your knowledge. Their purpose is unknown. Their mission is unknown. How they arrived to this secure and isolated section of the galaxy, you don't know. What you do know is that there is a silent shadow-stalker piercing through the defenses of Nanotrasen with technological capabilities eons ahead of your time. They can avoid the omniscience of the AI and rival the most hardened weapons your station is capable of. Tread lightly and only hope this unknown assassin isn't here for you." config_tag = "ninja" required_players = 1 - required_players_secret = 10 required_enemies = 1 end_on_antag_death = 1 antag_tags = list(MODE_NINJA) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 9e97e7e1573..4cad76157ba 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -7,7 +7,6 @@ round_description = "A mercenary strike force is approaching the station!" config_tag = "mercenary" required_players = 15 - required_players_secret = 25 // 25 players - 5 players to be the nuke ops = 20 players remaining required_enemies = 1 end_on_antag_death = 1 uplink_welcome = "Corporate Backed Uplink Console:" diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 8c57a6cc696..4af85d2aa59 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -4,7 +4,6 @@ round_description = "Some crewmembers are attempting to start a revolution!" extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders." required_players = 4 - required_players_secret = 15 required_enemies = 3 auto_recall_shuttle = 1 uplink_welcome = "AntagCorp Uplink Console:" diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm new file mode 100644 index 00000000000..515799d8837 --- /dev/null +++ b/code/game/gamemodes/vampire/vampire.dm @@ -0,0 +1,10 @@ +/datum/game_mode/vampire + name = "Vampire" + round_description = "There are Vampires from Space Transylvania on the station, keep your blood close and neck safe!" + extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet something slipped past their eyes. Something dangerous. Something alive. Most frightening of all, however, is that this something is someone. An unknown alien specimen has incorporated itself into the crew of the NSS Exodus. No one knows where it came from. No one knows who it is or what it wants. One thing is for certain though... there is never just one of them. Good luck." + config_tag = "vampire" + required_players = 1 + required_enemies = 1 + end_on_antag_death = 1 + antag_scaling_coeff = 8 + antag_tags = list(MODE_VAMPIRE) diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm new file mode 100644 index 00000000000..0d7f4c8c5e9 --- /dev/null +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -0,0 +1,838 @@ + + +/datum/vampire + var/list/datum/mind/vampires = list() + var/list/datum/mind/enthralled = list() //those controlled by a vampire + var/list/thralls = list() //vammpires controlling somebody + var/bloodtotal = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS + var/bloodusable = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS + var/mob/living/owner = null + var/gender = FEMALE + var/iscloaking = 0 // handles the vampire cloak toggle + var/list/powers = list() // list of available powers and passives, see defines in setup.dm + var/mob/living/carbon/human/draining // who the vampire is draining of blood + var/nullified = 0 //Nullrod makes them useless for a short while. + +/datum/vampire/New(gend = FEMALE) + ..() + gender = gend + + + + +/mob/proc/make_vampire() + if(!mind) return + if(!mind.vampire) + mind.vampire = new /datum/vampire(gender) + mind.vampire.owner = src + verbs += /client/vampire/proc/vampire_rejuvinate + verbs += /client/vampire/proc/vampire_hypnotise + verbs += /client/vampire/proc/vampire_glare + //testing purposes REMOVE BEFORE PUSH TO MASTER + /*for(var/handler in typesof(/client/proc)) + if(findtext("[handler]","vampire_")) + verbs += handler*/ + for(var/i = 1; i <= 3; i++) // CHANGE TO 3 RATHER THAN 12 AFTER TESTING IS DONE + if(!(i in mind.vampire.powers)) + mind.vampire.powers.Add(i) + + + for(var/n in mind.vampire.powers) + switch(n) + if(VAMP_SHAPE) + verbs += /client/vampire/proc/vampire_shapeshift + if(VAMP_VISION) + continue + if(VAMP_DISEASE) + verbs += /client/vampire/proc/vampire_disease + if(VAMP_CLOAK) + verbs += /client/vampire/proc/vampire_cloak + if(VAMP_BATS) + verbs += /client/vampire/proc/vampire_bats + if(VAMP_SCREAM) + verbs += /client/vampire/proc/vampire_screech + if(VAMP_JAUNT) + verbs += /client/vampire/proc/vampire_jaunt + if(VAMP_BLINK) + verbs += /client/vampire/proc/vampire_shadowstep + if(VAMP_SLAVE) + verbs += /client/vampire/proc/vampire_enthrall + if(VAMP_FULL) + continue + +/mob/proc/remove_vampire_powers() + for(var/handler in typesof(/client/vampire/proc)) + if(findtext("[handler]","vampire_")) + verbs -= handler + +/mob/proc/handle_bloodsucking(mob/living/carbon/human/H) + src.mind.vampire.draining = H + var/blood = 0 + var/bloodtotal = 0 //used to see if we increased our blood total + var/bloodusable = 0 //used to see if we increased our blood usable + + src.visible_message("\red [src.name] bites [H.name]'s neck!", "\red You bite [H.name]'s neck and begin to drain their blood.", "\blue You hear a soft puncture and a wet sucking noise") + if(!iscarbon(src)) + H.LAssailant = null + else + H.LAssailant = src + while(do_mob(src, H, 50)) + if(!mind.vampire) + src << "\red Your fangs have disappeared!" + return 0 + bloodtotal = src.mind.vampire.bloodtotal + bloodusable = src.mind.vampire.bloodusable + if(!H.vessel.get_reagent_amount("blood")) + src << "\red They've got no blood left to give." + break + if(H.stat < 2) //alive + blood = min(10, H.vessel.get_reagent_amount("blood"))// if they have less than 10 blood, give them the remnant else they get 10 blood + src.mind.vampire.bloodtotal += blood + src.mind.vampire.bloodusable += blood +// H.adjustCloneLoss(10) // beep boop 10 damage //probably not necessary actually honestly okay + else + blood = min(5, H.vessel.get_reagent_amount("blood"))// The dead only give 5 bloods + src.mind.vampire.bloodtotal += blood + if(bloodtotal != src.mind.vampire.bloodtotal) + src << "\blue You have accumulated [src.mind.vampire.bloodtotal] [src.mind.vampire.bloodtotal > 1 ? "units" : "unit"] of blood[src.mind.vampire.bloodusable != bloodusable ?", and have [src.mind.vampire.bloodusable] left to use" : "."]" + check_vampire_upgrade(mind) + H.vessel.remove_reagent("blood",25) + + src.mind.vampire.draining = null + src << "\blue You stop draining [H.name] of blood." + return 1 + +/mob/proc/check_vampire_upgrade(datum/mind/v) + if(!v) return + if(!v.vampire) return + var/datum/vampire/vamp = v.vampire + var/list/old_powers = vamp.powers.Copy() + + // This used to be a switch statement. + // Don't use switch statements for shit like this, since blood can be any random-ass value. + // if(100) requires the blood to be at EXACTLY 100 units to trigger. + // if(blud >= 100) activates when blood is at or over 100 units. + // TODO: Make this modular. + + // TIER 1 + if(vamp.bloodtotal >= 100) + if(!(VAMP_VISION in vamp.powers)) + vamp.powers.Add(VAMP_VISION) + if(!(VAMP_SHAPE in vamp.powers)) + vamp.powers.Add(VAMP_SHAPE) + + // TIER 2 + if(vamp.bloodtotal >= 150) + if(!(VAMP_CLOAK in vamp.powers)) + vamp.powers.Add(VAMP_CLOAK) + + + // TIER 3 + if(vamp.bloodtotal >= 200) + if(!(VAMP_BATS in vamp.powers)) + vamp.powers.Add(VAMP_BATS) + if(!(VAMP_SCREAM in vamp.powers)) + vamp.powers.Add(VAMP_SCREAM) + src << "\blue Your rejuvination abilities have improved and will now heal you over time when used." + if(!(VAMP_DISEASE in vamp.powers)) + vamp.powers.Add(VAMP_DISEASE) + + // TIER 3.5 (/vg/) + if(vamp.bloodtotal >= 250) + if(!(VAMP_BLINK in vamp.powers)) + vamp.powers.Add(VAMP_BLINK) + + // TIER 4 + if(vamp.bloodtotal >= 300) + if(!(VAMP_JAUNT in vamp.powers)) + vamp.powers.Add(VAMP_JAUNT) + if(!(VAMP_SLAVE in vamp.powers)) + vamp.powers.Add(VAMP_SLAVE) + + // TIER 5 + if(vamp.bloodtotal >= 500) + if(!(VAMP_FULL in vamp.powers)) + vamp.powers.Add(VAMP_FULL) + + announce_new_power(old_powers, vamp.powers) + +/mob/proc/announce_new_power(list/old_powers, list/new_powers) + for(var/n in new_powers) + if(!(n in old_powers)) + switch(n) + if(VAMP_SHAPE) + src << "\blue You have gained the shapeshifting ability, at the cost of stored blood you can change your form permanently." + verbs += /client/vampire/proc/vampire_shapeshift + if(VAMP_VISION) + src << "\blue Your vampiric vision has improved." + //no verb + if(VAMP_DISEASE) + src << "\blue You have gained the Diseased Touch ability which causes those you touch to die shortly after unless treated medically." + verbs += /client/vampire/proc/vampire_disease + if(VAMP_CLOAK) + src << "\blue You have gained the Cloak of Darkness ability which when toggled makes you near invisible in the shroud of darkness." + verbs += /client/vampire/proc/vampire_cloak + if(VAMP_BATS) + src << "\blue You have gained the Summon Bats ability." + verbs += /client/vampire/proc/vampire_bats // work in progress + if(VAMP_SCREAM) + src << "\blue You have gained the Chiropteran Screech ability which stuns anything with ears in a large radius and shatters glass in the process." + verbs += /client/vampire/proc/vampire_screech + if(VAMP_JAUNT) + src << "\blue You have gained the Mist Form ability which allows you to take on the form of mist for a short period and pass over any obstacle in your path." + verbs += /client/vampire/proc/vampire_jaunt + if(VAMP_SLAVE) + src << "\blue You have gained the Enthrall ability which at a heavy blood cost allows you to enslave a human that is not loyal to any other for a random period of time." + verbs += /client/vampire/proc/vampire_enthrall + if(VAMP_BLINK) + src << "\blue You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood." + verbs += /client/vampire/proc/vampire_shadowstep + if(VAMP_FULL) + src << "\blue You have reached your full potential and are no longer weak to the effects of anything holy and your vision has been improved greatly." + //no verb + + //This should hold all the vampire related powers + + +/mob/proc/vampire_power(required_blood=0, max_stat=0) + + if(!src.mind) return 0 + if(!ishuman(src)) + src << "You are in too weak of a form to do this!" + return 0 + + var/datum/vampire/vampire = src.mind.vampire + + if(!vampire) + //msg_scopes("[src] has vampire verbs but isn't a vampire.") + world.log << "[src] has vampire verbs but isn't a vampire." + return 0 + + var/fullpower = (VAMP_FULL in vampire.powers) + + if(src.stat > max_stat) + src << "You are incapacitated." + return 0 + + if(vampire.nullified) + if(!fullpower) + src << "Something is blocking your powers!" + return 0 + if(vampire.bloodusable < required_blood) + src << "You require at least [required_blood] units of usable blood to do that!" + return 0 + //chapel check + if(istype(loc.loc, /area/chapel)) + if(!fullpower) + src << "Your powers are useless on this holy ground." + return 0 + return 1 + +/mob/proc/vampire_affected(datum/mind/M) + //Other vampires aren't affected + if(mind && mind.vampire) return 0 + //Chaplains are resistant to vampire powers + if(mind && mind.assigned_role == "Chaplain") + return 0 + if(get_species() == "Machine") + return 0 + //Vampires who have reached their full potential can affect nearly everything + if(M && M.vampire && (VAMP_FULL in M.vampire.powers)) + return 1 // This doesn't really need to be here because of well the line below it. + return 1 + +/mob/proc/vampire_can_reach(mob/M as mob, active_range = 1) + if(M.loc == src.loc) return 1 //target and source are in the same thing + if(!isturf(src.loc) || !isturf(M.loc)) return 0 //One is inside, the other is outside something. + if(Adjacent(M))//if(AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, active_range)) //If a path exists, good! + return 1 + return 0 + +/mob/proc/vampire_active(required_blood=0, max_stat=0, active_range=1) + var/pass = vampire_power(required_blood, max_stat) + if(!pass) return + var/datum/vampire/vampire = mind.vampire + if(!vampire) return + var/list/victims = list() + for(var/mob/living/carbon/C in view(active_range)) + if(C==src) continue + victims += C + var/mob/living/carbon/T = input(src, "Victim?") as null|anything in victims + + if(!T) return + if(!(T in view(active_range))) return + if(!vampire_can_reach(T, active_range)) return + if(!vampire_power(required_blood, max_stat)) return + return T + +/client/vampire/proc/vampire_rejuvinate() + set category = "Abilities" + set name = "Rejuvinate " + set desc= "Flush your system with spare blood to remove any incapacitating effects" + var/datum/mind/M = usr.mind + if(!M) return + if(M.current.vampire_power(0, 1)) + M.current.weakened = 0 + M.current.stunned = 0 + M.current.paralysis = 0 + //M.vampire.bloodusable -= 10 + M.current << "\blue You flush your system with clean blood and remove any incapacitating effects." + spawn(1) + if(M.vampire.bloodtotal >= 200) + for(var/i = 0; i < 5; i++) + M.current.adjustBruteLoss(-2) + M.current.adjustOxyLoss(-5) + M.current.adjustToxLoss(-2) + M.current.adjustFireLoss(-2) + sleep(35) + M.current.verbs -= /client/vampire/proc/vampire_rejuvinate + spawn(200) + M.current.verbs += /client/vampire/proc/vampire_rejuvinate + +/client/vampire/proc/vampire_hypnotise() + set category = "Abilities" + set name = "Hypnotise" // (20) + set desc= "A piercing stare that incapacitates your victim for a good length of time." + var/datum/mind/M = usr.mind + if(!M) return + + var/mob/living/carbon/C = M.current.vampire_active(0, 0, 1) //(20, 0, 1) + + if(!C) return + if(C==usr) + M.current << "\red You can't do that to yourself" + return + + if(!M.current.has_eyes()) + M.current << "\red You don't have eyes" + return + + var/vampgender + if(M.current.gender == "male") + vampgender = "he" + else + vampgender = "she" + + M.current.visible_message("[M]'s eyes flash briefly as [vampgender] stares into [C.name]'s eyes") +// M.current.remove_vampire_blood(20) Moved to remove if it works only. + if(M.current.vampire_power(0, 0)) //if(M.current.vampire_power(20, 0)) + M.current.verbs -= /client/vampire/proc/vampire_hypnotise + spawn(1200) + M.current.verbs += /client/vampire/proc/vampire_hypnotise + if(do_mob(M.current, C, 50)) + if(C.mind && C.mind.vampire) + M.current << "\red Your piercing gaze fails to knock out [C.name]." + C << "\blue [M.current]'s feeble gaze is ineffective." + return + else + M.current << "\red Your piercing gaze knocks out [C.name]." + C << "\red You find yourself unable to move and barely able to speak" + C.Weaken(20) + C.Stun(20) + C.stuttering = 20 +// M.current.remove_vampire_blood(20) + else + M.current << "\red You broke your gaze." + return + +/client/vampire/proc/vampire_disease() + set category = "Abilities" + set name = "Diseased Touch (200)" + set desc = "Touches your victim with infected blood giving them the Shutdown Syndrome which quickly shutsdown their major organs resulting in a quick painful death." + var/datum/mind/M = usr.mind + if(!M) return + + var/mob/living/carbon/C = M.current.vampire_active(200, 0, 1) + if(!C) return + if(C==usr) + M.current << "\red You can't do that to yourself" + return + if(C.get_species() == "Machine") + M.current << "\red You can't to that to a machine" + return + if(!M.current.vampire_can_reach(C, 1)) + M.current << "\red You cannot touch [C.name] from where you are standing!" + return + M.current << "\red You stealthily infect [C.name] with your diseased touch." + /*var/t_him = "it" + if (src.gender == MALE) + t_him = "him" + else if (src.gender == FEMALE) + t_him = "her" + M.current.visible_message("\blue [M] shakes [src] trying to wake [t_him] up!" ) + playsound(get_turf(src), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)*/ + C.help_shake_act(M.current) // i use da colon + if(!C.vampire_affected(M)) + M.current << "\red They seem to be unaffected." + return + var/datum/disease2/disease/shutdown = new /datum/disease2/disease + var/datum/disease2/effectholder/holder = new /datum/disease2/effectholder + var/datum/disease2/effect/organs/vampire/O = new /datum/disease2/effect/organs/vampire + holder.effect += O + holder.chance = 10 + shutdown.infectionchance = 100 + shutdown.antigen |= text2num(pick(ALL_ANTIGENS)) + shutdown.antigen |= text2num(pick(ALL_ANTIGENS)) + shutdown.spreadtype = "None" + shutdown.uniqueID = rand(0,10000) + shutdown.effects += holder + shutdown.speed = 1 + shutdown.stage = 2 + shutdown.clicks = 185 + msg_admin_attack("[key_name_admin(usr)] gave [key_name_admin(C)] the shutdown disease - JMP") + usr.attack_log += text("\[[time_stamp()]\] Gave [C.name] ([C.ckey]) the shutdown disease") + C.attack_log += text("\[[time_stamp()]\] Has been given the shutdown disease by [usr.name] ([usr.ckey])") + infect_virus2(C,shutdown,0) + M.current.remove_vampire_blood(200) + M.current.verbs -= /client/vampire/proc/vampire_disease + spawn(1800) M.current.verbs += /client/vampire/proc/vampire_disease + +/client/vampire/proc/vampire_glare() + set category = "Abilities" + set name = "Glare" + set desc= "A scary glare that incapacitates people for a short while around you." + var/datum/mind/M = usr.mind + if(!M) return + + if(!M.current.has_eyes()) + M.current << "\red You don't have eyes" + return + + if(M.current.vampire_power(0, 1)) + M.current.visible_message("\red [M.current]'s eyes emit a blinding flash!") + //M.vampire.bloodusable -= 10 + M.current.verbs -= /client/vampire/proc/vampire_glare + spawn(800) + M.current.verbs += /client/vampire/proc/vampire_glare + if(istype(M.current:glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) + M.current << "You're blindfolded!" + return + for(var/mob/living/carbon/C in view(1)) + if(C == M.current) continue //Don't stunn yourself + if(!C.vampire_affected(M) && !C.get_species() == "Machine") //Or machines + continue + if(!M.current.vampire_can_reach(C, 1)) continue +// C.Stun(8) + C.Weaken(8) + C.stuttering = 20 + C << "\red You are blinded by [M.current]'s glare" + +/client/vampire/proc/vampire_shapeshift() //Hi. I'm stupid and there are missing procs all around. Namely the randomname proc. I can't find it and can't code a new one because I am bad. Sorry! + set category = "Abilities" + set name = "Shapeshift (50)" + set desc = "This does nothing. It's broken. Sorry!"//orig text: Changes your name and appearance at the cost of 50 blood and has a cooldown of 3 minutes. +/* var/datum/mind/M = usr.mind + if(!M) return + if(M.current.vampire_power(50, 0)) + M.current.visible_message("[M.current.name] transforms!") + M.current.client.prefs.real_name = M.current.generate_name() //random_name(M.current.gender) + M.current.client.prefs.randomize_appearance_for(M.current) + M.current.regenerate_icons() + M.current.remove_vampire_blood(50) + M.current.verbs -= /client/vampire/proc/vampire_shapeshift + spawn(1800) M.current.verbs += /client/vampire/proc/vampire_shapeshift +*/ +/client/vampire/proc/vampire_screech() + set category = "Abilities" + set name = "Chiropteran Screech (90)" + set desc = "An extremely loud shriek that stuns nearby humans in a four-tile radius, as well as shattering the windows." + var/datum/mind/M = usr.mind + if(!M) return + if(M.current.vampire_power(90, 0)) + M.current.visible_message("\red [M.current.name] lets out an ear piercing shriek!", "\red You let out a loud shriek.", "\red You hear a loud painful shriek!") + for(var/mob/living/carbon/C in hearers(4, M.current)) + if(C == M.current) continue + if(ishuman(C) && (C:l_ear || C:r_ear) && istype((C:l_ear || C:r_ear), /obj/item/clothing/ears/earmuffs)) continue + if(!C.vampire_affected(M)) + if(!C.get_species() == "Machine") + continue + C << "You hear a ear piercing shriek and your senses dull!" + C.Weaken(5) + C.ear_deaf = 20 + C.stuttering = 20 + C.Stun(5) +// C.Jitter(150) + for(var/obj/structure/window/W in view(7)) + W.shatter() + playsound(M.current.loc, 'sound/effects/creepyshriek.ogg', 100, 1) + M.current.remove_vampire_blood(90) + M.current.verbs -= /client/vampire/proc/vampire_screech + spawn(3600) M.current.verbs += /client/vampire/proc/vampire_screech + +/client/vampire/proc/vampire_enthrall() + set category = "Abilities" + set name = "Enthrall (150)" + set desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only." + var/datum/mind/M = usr.mind + if(!M) return + var/mob/living/carbon/C = M.current.vampire_active(150, 0, 1) + if(!C) return + if(C==usr) + M.current << "\red You can't do that to yourself" + return + if(C.get_species() == "Machine") + M.current << "\red You can only enthrall humans" + return + M.current.visible_message("\red [M.current.name] bites [C.name]'s neck!", "\red You bite [C.name]'s neck and begin the flow of power.") + C << "You feel the tendrils of evil invade your mind." + if(!ishuman(C)) + M.current << "\red You can only enthrall humans" + return + + if(do_mob(M.current, C, 50)) + if(M.current.can_enthrall(C)) // recheck + if(M.current.vampire_power(150, 0)) + M.current.handle_enthrall(C) + M.current.remove_vampire_blood(150) + M.current.verbs -= /client/vampire/proc/vampire_enthrall + spawn(1800) M.current.verbs += /client/vampire/proc/vampire_enthrall + return + else + M.current << "\red You or your target either moved or you dont have enough usable blood." + return + +/client/vampire/proc/vampire_cloak() + set category = "Abilities" + set name = "Cloak of Darkness (toggle)" + set desc = "Toggles whether you are currently cloaking yourself in darkness." + var/datum/mind/M = usr.mind + if(!M) return + if(M.current.vampire_power(0, 0)) + M.vampire.iscloaking = !M.vampire.iscloaking + M.current << "\blue You will now be [M.vampire.iscloaking ? "hidden" : "seen"] in darkness." + +/mob/proc/handle_vampire_cloak() + if(!mind || !mind.vampire || !ishuman(src)) + alpha = 255 + return + var/turf/simulated/T = get_turf(src) + + if(!istype(T)) + return 0 + + if(!mind.vampire.iscloaking) + alpha = 255 + return 0 +// if(T.lighting_lumcount <= 2) +// alpha = round((255 * 0.15)) +// return 1 + else + alpha = round((255 * 0.80)) + +/mob/proc/can_enthrall(mob/living/carbon/C) + var/enthrall_safe = 0 + var/datum/vampire/vampire = src.mind.vampire + for(var/obj/item/weapon/implant/loyalty/L in C) + if(L && L.implanted) + enthrall_safe = 1 + break +// for(var/obj/item/weapon/implant/traitor/T in C) +// if(T && T.implanted) +// enthrall_safe = 1 +// break + if(!C) + world.log << "something bad happened on enthralling a mob src is [src] [src.key] \ref[src]" + return 0 + if(!C.mind) + src << "\red [C.name]'s mind is not there for you to enthrall." + return 0 + if(enthrall_safe || ( C.mind in vampire.vampires )||( C.mind.vampire )||( C.mind in vampire.enthralled )) + C.visible_message("\red [C] seems to resist the takeover!", "\blue You feel a familiar sensation in your skull that quickly dissipates.") + return 0 + if(!C.vampire_affected(mind)) + C.visible_message("\red [C] seems to resist the takeover!", "\blue Your faith of [ticker.Bible_deity_name] has kept your mind clear of all evil") + return 0 + if(!ishuman(C)) + src << "\red You can only enthrall humans!" + return 0 + return 1 + +/mob/proc/handle_enthrall(mob/living/carbon/human/H as mob) + if(!istype(H)) + //msg_scopes("handle_enthrall fucked up with no H < [src]") + src << "\red SOMETHING WENT WRONG, YELL AT POMF OR NEXIS" + return 0 + var/ref = "\ref[src.mind]" + if(!(src.mind.vampire.thralls)) + src.mind.vampire.thralls[ref] = list(H.mind) + else + src.mind.vampire.thralls[ref] += H.mind + //msg_scopes("[H.name] Changed in handle_enthrall") //purely here to see live changes incase of unexpected things + src.mind.vampire.enthralled.Add(H.mind) + src.mind.vampire.enthralled[H.mind] = src.mind + H.mind.special_role = "VampThrall" + H << "\red You have been Enthralled by [name]. Follow their every command." + src << "\red You have successfully Enthralled [H.name]. If they refuse to do as you say just adminhelp." + var/client/vampire/c = src + c.update_vampire_icons_added(H.mind) + c.update_vampire_icons_added(src.mind) + msg_admin_attack("[key_name_admin(src)] has mind-slaved [key_name_admin(H)] - JMP.") + +/client/vampire/proc/vampire_bats() + set category = "Abilities" + set name = "Summon Bats (60)" + set desc = "You summon a pair of space bats who attack nearby targets until they or their target is dead." + var/datum/mind/M = usr.mind + if(!M) return + if(M.current.vampire_power(60, 0)) + var/list/turf/locs = new + var/number = 0 + for(var/direction in alldirs) //looking for bat spawns + if(locs.len == 2) //we found 2 locations and thats all we need + break + var/turf/T = get_step(M.current,direction) //getting a loc in that direction + if(AStar(M.current.loc, T, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 1)) // if a path exists, so no dense objects in the way its valid salid + locs += T + if(locs.len) + for(var/turf/tospawn in locs) + number++ + new /mob/living/simple_animal/hostile/scarybat(tospawn, M.current) + if(number != 2) //if we only found one location, spawn one on top of our tile so we dont get stacked bats + new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current) + else // we had no good locations so make two on top of us + new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current) + new /mob/living/simple_animal/hostile/scarybat(M.current.loc, M.current) + M.current.remove_vampire_blood(60) + M.current.verbs -= /client/vampire/proc/vampire_bats + spawn(1200) M.current.verbs += /client/vampire/proc/vampire_bats + +/client/vampire/proc/vampire_jaunt() + //AHOY COPY PASTE INCOMING + set category = "Abilities" + set name = "Mist Form (30)" + set desc = "You take on the form of mist for a short period of time." + var/jaunt_duration = 50 //in deciseconds + var/datum/mind/M = usr.mind + if(!M) return + + if(M.current.vampire_power(30, 0)) + if(M.current.buckled) M.current.buckled.unbuckle_mob() + spawn(0) + var/originalloc = get_turf(M.current.loc) + var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( originalloc ) + var/atom/movable/overlay/animation = new /atom/movable/overlay( originalloc ) + animation.name = "water" + animation.density = 0 + animation.anchored = 1 + animation.icon = 'icons/mob/mob.dmi' + animation.icon_state = "liquify" + animation.layer = 5 + animation.master = holder + M.current.ExtinguishMob() + M.current.weakened = 0 + M.current.stunned = 0 + if(M.current.buckled) + M.current.buckled.unbuckle_mob() + flick("liquify",animation) + M.current.loc = holder + M.current.client.eye = holder + var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread() + steam.set_up(10, 0, originalloc) + steam.start() + sleep(jaunt_duration) + var/mobloc = get_turf(M.current.loc) +/* if(get_area(mobloc) == /area/security/armoury/gamma) + M << "A strange energy repels you!" + mobloc = originalloc*/ + animation.loc = mobloc + steam.location = mobloc + steam.start() + M.current.canmove = 0 + sleep(20) + flick("reappear",animation) + sleep(5) + if(!M.current.Move(mobloc)) + for(var/direction in list(1,2,4,8,5,6,9,10)) + var/turf/T = get_step(mobloc, direction) + if(T) + if(M.current.Move(T)) + break + M.current.canmove = 1 + M.current.client.eye = M.current + qdel(animation) + qdel(holder) + M.current.remove_vampire_blood(30) + M.current.verbs -= /client/vampire/proc/vampire_jaunt + spawn(600) M.current.verbs += /client/vampire/proc/vampire_jaunt + +// Blink for vamps +// Less smoke spam. +/client/vampire/proc/vampire_shadowstep() + set category = "Abilities" + set name = "Shadowstep (30)" + set desc = "Vanish into the shadows." + var/datum/mind/M = usr.mind + if(!M) return + + // Teleport radii + var/inner_tele_radius = 0 + var/outer_tele_radius = 6 + + // Maximum lighting_lumcount. +// var/max_lum = 1 + + if(M.current.vampire_power(30, 0)) + if(M.current.buckled) M.current.buckled.unbuckle_mob() + spawn(0) + var/list/turfs = new/list() + for(var/turf/T in range(usr,outer_tele_radius)) + if(T in range(usr,inner_tele_radius)) continue + if(istype(T,/turf/space)) continue + if(T.density) continue + if(T.x>world.maxx-outer_tele_radius || T.xworld.maxy-outer_tele_radius || T.y max_lum) continue + // turfs += T + //M.current.remove_vampire_blood(30) This isn't the right place for this either. + + if(!turfs.len) + usr << "\red You cannot find darkness to step to." + return + + var/turf/picked = pick(turfs) + + if(!picked || !isturf(picked)) + return + M.current.ExtinguishMob() + if(M.current.buckled) + M.current.buckled.unbuckle_mob() + var/atom/movable/overlay/animation = new /atom/movable/overlay( get_turf(usr) ) + animation.name = usr.name + animation.density = 0 + animation.anchored = 1 + animation.icon = usr.icon + animation.alpha = 127 + animation.layer = 5 + //animation.master = src + usr.loc = picked + M.current.remove_vampire_blood(30) + spawn(10) + del(animation) +// M.current.remove_vampire_blood(30) + M.current.verbs -= /client/vampire/proc/vampire_shadowstep + spawn(20) + M.current.verbs += /client/vampire/proc/vampire_shadowstep + +/mob/proc/remove_vampire_blood(amount = 0) + var/bloodold + if(!mind || !mind.vampire) + return + bloodold = mind.vampire.bloodusable + mind.vampire.bloodusable = max(0, (mind.vampire.bloodusable - amount)) + if(bloodold != mind.vampire.bloodusable) + src << "\blue You have [mind.vampire.bloodusable] left to use." + +//prepare for copypaste +/client/vampire/proc/update_vampire_icons_added(datum/mind/vampire_mind) + var/ref = "\ref[vampire_mind]" + if(ref in vampire_mind.vampire.thralls) + if(vampire_mind.current) + if(vampire_mind.current.client) + var/I = image('icons/mob/mob.dmi', loc = vampire_mind.current, icon_state = "vampire") + vampire_mind.current.client.images += I + for(var/headref in vampire_mind.vampire.thralls) + for(var/datum/mind/t_mind in vampire_mind.vampire.thralls[headref]) + var/datum/mind/head = locate(headref) + if(head) + if(head.current) + if(head.current.client) + var/I = image('icons/mob/mob.dmi', loc = t_mind.current, icon_state = "vampthrall") + head.current.client.images += I + if(t_mind.current) + if(t_mind.current.client) + var/I = image('icons/mob/mob.dmi', loc = head.current, icon_state = "vampire") + t_mind.current.client.images += I + if(t_mind.current) + if(t_mind.current.client) + var/I = image('icons/mob/mob.dmi', loc = t_mind.current, icon_state = "vampthrall") + t_mind.current.client.images += I + +/client/vampire/proc/update_vampire_icons_removed(datum/mind/vampire_mind) + for(var/headref in vampire_mind.vampire.thralls) + var/datum/mind/head = locate(headref) + for(var/datum/mind/t_mind in vampire_mind.vampire.thralls[headref]) + if(t_mind.current) + if(t_mind.current.client) + for(var/image/I in t_mind.current.client.images) + if((I.icon_state == "vampthrall" || I.icon_state == "vampire") && I.loc == vampire_mind.current) + //world.log << "deleting [vampire_mind] overlay" + del(I) + if(head) + //world.log << "found [head.name]" + if(head.current) + if(head.current.client) + for(var/image/I in head.current.client.images) + if((I.icon_state == "vampthrall" || I.icon_state == "vampire") && I.loc == vampire_mind.current) + //world.log << "deleting [vampire_mind] overlay" + del(I) + if(vampire_mind.current) + if(vampire_mind.current.client) + for(var/image/I in vampire_mind.current.client.images) + if(I.icon_state == "vampthrall" || I.icon_state == "vampire") + del(I) + +/client/vampire/proc/remove_vampire_mind(datum/mind/vampire_mind, datum/mind/head) + //var/list/removal + if(!istype(head)) + head = vampire_mind //workaround for removing a thrall's control over the enthralled + var/ref = "\ref[head]" + if(vampire_mind.vampire.thralls) + vampire_mind.vampire.thralls[ref] -= vampire_mind + vampire_mind.vampire.enthralled -= vampire_mind + //vampire.special_role = null + update_vampire_icons_removed(vampire_mind) + //world << "Removed [vampire_mind.current.name] from vampire shit" + vampire_mind.current << "\red The fog clouding your mind clears. You remember nothing from the moment you were enthralled until now." + +/mob/living/carbon/human/proc/check_sun() + + var/ax = x + var/ay = y + + for(var/i = 1 to 20) + ax += sun.dx + ay += sun.dy + + var/turf/T = locate( round(ax,0.5),round(ay,0.5),z) + + if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) + break + + if(T.density) + return + if(prob(35)) + switch(health) + if(80 to 100) + src << "\red Your skin flakes away..." + if(60 to 80) + src << "Your skin sizzles!" + // if((-INFINITY) to 60) + // if(!on_fire) + // src << "\red Your skin catches fire!" + // else + // src << "\red You continue to burn!" + // fire_stacks += 5 + // IgniteMob() + // emote("scream") + //else + // switch(health) + // if((-INFINITY) to 60) + // fire_stacks++ + // IgniteMob() + adjustFireLoss(30) //Original value was 3. Barely did anything. Vamps should vaporize in starlight. + +/mob/living/carbon/human/proc/handle_vampire() +/* if(hud_used) + if(!hud_used.vampire_blood_display) + hud_used.vampire_hud() + hud_used.human_hud('icons/mob/screen1_Vampire.dmi') + hud_used.vampire_blood_display.maptext_width = 64 + hud_used.vampire_blood_display.maptext_height = 26 + hud_used.vampire_blood_display.maptext = "
U:[mind.vampire.bloodusable]
T:[mind.vampire.bloodtotal]
" + */ + handle_vampire_cloak() + if(istype(loc, /turf/space)) + check_sun() + mind.vampire.nullified = max(0, mind.vampire.nullified - 1) diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index bb1c11b4a50..892f4db3898 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -4,7 +4,6 @@ extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station." config_tag = "wizard" required_players = 1 - required_players_secret = 10 required_enemies = 1 uplink_welcome = "Wizardly Uplink Console:" uplink_uses = 10 diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index 26f5c020201..ed670f7a162 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -177,79 +177,6 @@ H.species.equip_survival_gear(H,1) return 1 - -//Griff //BS12 EDIT -/* -/datum/job/clown - title = "Clown" - flag = CLOWN - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - access = list(access_clown, access_theatre, access_maint_tunnels) - minimal_access = list(access_clown, access_theatre) - - - equip(var/mob/living/carbon/human/H) - if(!H) return 0 - H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/clown(H), slot_back) - H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/clown(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes(H), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/device/pda/clown(H), slot_belt) - H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask) - H.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/food/snacks/grown/banana(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/weapon/bikehorn(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/weapon/stamp/clown(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/weapon/pen/crayon/rainbow(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/weapon/storage/fancy/crayons(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/toy/waterflower(H), slot_in_backpack) - H.mutations.Add(CLUMSY) - return 1 - - - -/datum/job/mime - title = "Mime" - flag = MIME - department_flag = CIVILIAN - faction = "Station" - total_positions = 1 - spawn_positions = 1 - supervisors = "the head of personnel" - selection_color = "#dddddd" - access = list(access_mime, access_theatre, access_maint_tunnels) - minimal_access = list(access_mime, access_theatre) - - - equip(var/mob/living/carbon/human/H) - if(!H) return 0 - if(H.backbag == 2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) - if(H.backbag == 3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(H), slot_back) - H.equip_to_slot_or_del(new /obj/item/clothing/under/mime(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/device/pda/mime(H), slot_belt) - H.equip_to_slot_or_del(new /obj/item/clothing/gloves/white(H), slot_gloves) - H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/mime(H), slot_wear_mask) - H.equip_to_slot_or_del(new /obj/item/clothing/head/beret(H), slot_head) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/suspenders(H), slot_wear_suit) - if(H.backbag == 1) - H.equip_to_slot_or_del(new /obj/item/weapon/pen/crayon/mime(H), slot_l_store) - H.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing(H), slot_l_hand) - else - H.equip_to_slot_or_del(new /obj/item/weapon/pen/crayon/mime(H), slot_in_backpack) - H.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing(H), slot_in_backpack) - H.verbs += /client/proc/mimespeak - H.verbs += /client/proc/mimewall - H.mind.special_verbs += /client/proc/mimespeak - H.mind.special_verbs += /client/proc/mimewall - H.miming = 1 - return 1 -*/ - - /datum/job/janitor title = "Janitor" flag = JANITOR diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 447e82d3b64..82441ead326 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -185,36 +185,6 @@ var/global/datum/controller/occupations/job_master return - proc/FillAIPosition() - var/ai_selected = 0 - var/datum/job/job = GetJob("AI") - if(!job) return 0 - if((job.title == "AI") && (config) && (!config.allow_ai)) return 0 - - for(var/i = job.total_positions, i > 0, i--) - for(var/level = 1 to 3) - var/list/candidates = list() - if(ticker.mode.name == "AI malfunction")//Make sure they want to malf if its malf - candidates = FindOccupationCandidates(job, level, BE_MALF) - else - candidates = FindOccupationCandidates(job, level) - if(candidates.len) - var/mob/new_player/candidate = pick(candidates) - if(AssignRole(candidate, "AI")) - ai_selected++ - break - //Malf NEEDS an AI so force one if we didn't get a player who wanted it - if((ticker.mode.name == "AI malfunction")&&(!ai_selected)) - unassigned = shuffle(unassigned) - for(var/mob/new_player/player in unassigned) - if(jobban_isbanned(player, "AI")) continue - if(AssignRole(player, "AI")) - ai_selected++ - break - if(ai_selected) return 1 - return 0 - - /** Proc DivideOccupations * fills var "assigned_role" for all ready players. * This proc must not have any side effect besides of modifying "assigned_role". @@ -260,11 +230,6 @@ var/global/datum/controller/occupations/job_master FillHeadPosition() Debug("DO, Head Check end") - //Check for an AI - Debug("DO, Running AI Check") - FillAIPosition() - Debug("DO, AI Check end") - //Other jobs are now checked Debug("DO, Running Standard Check") @@ -275,6 +240,7 @@ var/global/datum/controller/occupations/job_master // Loop through all levels from high to low var/list/shuffledoccupations = shuffle(occupations) + // var/list/disabled_jobs = ticker.mode.disabled_jobs // So we can use .Find down below without a colon. for(var/level = 1 to 3) //Check the head jobs first each level CheckHeadPositions(level) @@ -284,7 +250,7 @@ var/global/datum/controller/occupations/job_master // Loop through all jobs for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY - if(!job) + if(!job || ticker.mode.disabled_jobs.Find(job.title) ) continue if(jobban_isbanned(player, job.title)) @@ -490,7 +456,7 @@ var/global/datum/controller/occupations/job_master if(istype(H)) //give humans wheelchairs, if they need them. var/obj/item/organ/external/l_foot = H.get_organ("l_foot") var/obj/item/organ/external/r_foot = H.get_organ("r_foot") - if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED)) + if(!l_foot || !r_foot) var/obj/structure/bed/chair/wheelchair/W = new /obj/structure/bed/chair/wheelchair(H.loc) H.buckled = W H.update_canmove() diff --git a/code/game/jobs/jobprocs.dm b/code/game/jobs/jobprocs.dm deleted file mode 100644 index 2a012872bf2..00000000000 --- a/code/game/jobs/jobprocs.dm +++ /dev/null @@ -1,66 +0,0 @@ - - -//TODO: put these somewhere else -/client/proc/mimewall() - set category = "Mime" - set name = "Invisible wall" - set desc = "Create an invisible wall on your location." - if(usr.stat) - usr << "Not when you're incapicated." - return - if(!ishuman(usr)) - return - - var/mob/living/carbon/human/H = usr - - if(!H.miming) - usr << "You still haven't atoned for your speaking transgression. Wait." - return - H.verbs -= /client/proc/mimewall - spawn(300) - H.verbs += /client/proc/mimewall - for (var/mob/V in viewers(H)) - if(V!=usr) - V.show_message("[H] looks as if a wall is in front of them.", 3, "", 2) - usr << "You form a wall in front of yourself." - new /obj/effect/forcefield/mime(locate(usr.x,usr.y,usr.z)) - return - -///////////Mimewalls/////////// - -/obj/effect/forcefield/mime - icon_state = "empty" - name = "invisible wall" - desc = "You have a bad feeling about this." - var/timeleft = 300 - var/last_process = 0 - -/obj/effect/forcefield/mime/New() - ..() - last_process = world.time - processing_objects.Add(src) - -/obj/effect/forcefield/mime/process() - timeleft -= (world.time - last_process) - if(timeleft <= 0) - processing_objects.Remove(src) - qdel(src) - -/////////////////////////////// - -/client/proc/mimespeak() - set category = "Mime" - set name = "Speech" - set desc = "Toggle your speech." - if(!ishuman(usr)) - return - - var/mob/living/carbon/human/H = usr - - if(H.miming) - H.miming = 0 - else - H << "You'll have to wait if you want to atone for your sins." - spawn(3000) - H.miming = 1 - return \ No newline at end of file diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 635cc9097f0..51e577b596b 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -400,7 +400,7 @@ if(!AN && !open && !infected & !imp) AN = "None:" - if(!(e.status & ORGAN_DESTROYED)) + if(!e.is_stump()) dat += "[e.name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]" else dat += "[e.name]--Not Found" diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 9a8228aaa6d..458e787b79d 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -17,6 +17,7 @@ var/temperature_resistance = 1000 + T0C volume = 1000 use_power = 0 + interact_offline = 1 // Allows this to be used when not in powered area. var/release_log = "" var/update_flag = 0 diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index e2371bbeb21..866f521e5ae 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -140,9 +140,19 @@ if(weld(W, user)) if(assembly) assembly.loc = src.loc - assembly.state = 1 + assembly.anchored = 1 + assembly.camera_name = c_tag + assembly.camera_network = english_list(network, "Exodus", ",", ",") + assembly.update_icon() + assembly.dir = src.dir + if(stat & BROKEN) + assembly.state = 2 + user << "You repaired \the [src] frame." + else + assembly.state = 1 + user << "You cut \the [src] free from the wall." + new /obj/item/stack/cable_coil(src.loc, length=2) assembly = null //so qdel doesn't eat it. - new /obj/item/stack/cable_coil(src.loc, length=2) qdel(src) // OTHER diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 75397278c03..86095dedfb8 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -11,6 +11,8 @@ // Motion, EMP-Proof, X-Ray var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/material/osmium, /obj/item/weapon/stock_parts/scanning_module) var/list/upgrades = list() + var/camera_name + var/camera_network var/state = 0 var/busy = 0 /* @@ -47,7 +49,7 @@ else if(iswrench(W)) playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - user << "You unattach the assembly from it's place." + user << "You unattach the assembly from its place." anchored = 0 update_icon() state = 0 @@ -67,7 +69,7 @@ else if(iswelder(W)) if(weld(W, user)) - user << "You unweld the assembly from it's place." + user << "You unweld the assembly from its place." state = 1 anchored = 1 return @@ -78,7 +80,7 @@ if(isscrewdriver(W)) playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - var/input = sanitize(input(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: Exodus,Security,Secret ", "Set Network", "Exodus")) + var/input = sanitize(input(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: Exodus,Security,Secret ", "Set Network", camera_network ? camera_network : "Exodus")) if(!input) usr << "No input found please hang up and try your call again." return @@ -90,7 +92,7 @@ var/area/camera_area = get_area(src) var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])" - input = sanitizeSafe(input(usr, "How would you like to name the camera?", "Set Camera Name", temptag), MAX_NAME_LEN) + input = sanitizeSafe(input(usr, "How would you like to name the camera?", "Set Camera Name", camera_name ? camera_name : temptag), MAX_NAME_LEN) state = 4 var/obj/machinery/camera/C = new(src.loc) diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index baa75fed05f..4317f749696 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -70,7 +70,6 @@ for(var/x in verbs) verbs -= x set_broken() - density = 0 /obj/machinery/computer/update_icon() ..() @@ -124,22 +123,15 @@ for (var/obj/C in src) C.loc = src.loc if (src.stat & BROKEN) - user << "\blue The broken glass falls out." + user << "The broken glass falls out." new /obj/item/weapon/material/shard( src.loc ) A.state = 3 A.icon_state = "3" else - user << "\blue You disconnect the monitor." + user << "You disconnect the monitor." A.state = 4 A.icon_state = "4" M.deconstruct(src) qdel(src) else - src.attack_hand(user) - return - - - - - - + ..() diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 65322b741da..2c44b6164c2 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -457,7 +457,7 @@ var/counter = 1 while(src.active2.fields[text("com_[]", counter)]) counter++ - src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
[t1]") + src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD")] [worldtime2text()], [game_year]
[t1]") if (href_list["del_c"]) if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index f7327c2a887..92e03f01851 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -391,7 +391,7 @@ What a mess.*/ var/counter = 1 while(active2.fields[text("com_[]", counter)]) counter++ - active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
[t1]") + active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD")] [worldtime2text()], [game_year]
[t1]") if ("Delete Record (ALL)") if (active1) diff --git a/code/game/machinery/computer3/computers/medical.dm b/code/game/machinery/computer3/computers/medical.dm index aec0b615f52..0533f7bc0ff 100644 --- a/code/game/machinery/computer3/computers/medical.dm +++ b/code/game/machinery/computer3/computers/medical.dm @@ -470,7 +470,7 @@ var/counter = 1 while(src.active2.fields[text("com_[]", counter)]) counter++ - src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
[t1]") + src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD")] [worldtime2text()], [game_year]
[t1]") if (href_list["del_c"]) if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) diff --git a/code/game/machinery/computer3/computers/security.dm b/code/game/machinery/computer3/computers/security.dm index f2de7648943..8a866586fd3 100644 --- a/code/game/machinery/computer3/computers/security.dm +++ b/code/game/machinery/computer3/computers/security.dm @@ -410,7 +410,7 @@ What a mess.*/ var/counter = 1 while(active2.fields[text("com_[]", counter)]) counter++ - active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
[t1]") + active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD")] [worldtime2text()], [game_year]
[t1]") if ("Delete Record (ALL)") if (active1) diff --git a/code/game/machinery/computer3/lapvend.dm b/code/game/machinery/computer3/lapvend.dm index 416472a31ac..ac3e7e172cf 100644 --- a/code/game/machinery/computer3/lapvend.dm +++ b/code/game/machinery/computer3/lapvend.dm @@ -38,16 +38,14 @@ /obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(vendmode == 1) - if(istype(W, /obj/item/weapon/card)) - var/obj/item/weapon/card/I = W - scan_card(I) + var/obj/item/weapon/card/id/I = W.GetID() + + if(vendmode == 1 && I) + scan_id(I, W) + vendmode = 0 + if(vendmode == 3 && I) + if(reimburse_id(I, W)) vendmode = 0 - if(vendmode == 3) - if(istype(W,/obj/item/weapon/card)) - var/obj/item/weapon/card/I = W - if(reimburse(I)) - vendmode = 0 if(vendmode == 0) if(istype(W, /obj/item/device/laptop)) var/obj/item/device/laptop/L = W @@ -210,26 +208,24 @@ newlap.spawn_parts() -/obj/machinery/lapvend/proc/scan_card(var/obj/item/weapon/card/I) - if (istype(I, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/C = I - visible_message("[usr] swipes a card through [src].") - var/datum/money_account/CH = get_account(C.associated_account_number) - if(!CH) - usr << "\icon[src]No valid account number is associated with this card." - return - if(CH.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) - if(vendor_account) - var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) - if(D) - transfer_and_vend(D, C) - else - usr << "\icon[src]Unable to access account. Check security settings and try again." +/obj/machinery/lapvend/proc/scan_id(var/obj/item/weapon/card/id/C, var/obj/item/I) + visible_message("\The [usr] swipes \the [I] through \the [src].") + var/datum/money_account/CH = get_account(C.associated_account_number) + if(!CH) + usr << "\icon[src]No valid account number is associated with this card." + return + if(CH.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + if(vendor_account) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) + if(D) + transfer_and_vend(D, C) else usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support." else - transfer_and_vend(CH, C) + usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support." + else + transfer_and_vend(CH, C) // Transfers money and vends the laptop. @@ -361,30 +357,28 @@ -/obj/machinery/lapvend/proc/reimburse(var/obj/item/weapon/card/I) - if (istype(I, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/C = I - visible_message("[usr] swipes a card through [src].") - var/datum/money_account/CH = get_account(C.associated_account_number) - if(!CH) - usr << "\icon[src]No valid account number is associated with this card." - return 0 - if(CH.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) - if(vendor_account) - var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) - if(D) - transfer_and_reimburse(D) - return 1 - else - usr << "\icon[src]Unable to access account. Check security settings and try again." - return 0 +/obj/machinery/lapvend/proc/reimburse_id(var/obj/item/weapon/card/id/C, var/obj/item/I) + visible_message("\The [usr] swipes \the [I] through \the [src].") + var/datum/money_account/CH = get_account(C.associated_account_number) + if(!CH) + usr << "\icon[src]No valid account number is associated with this card." + return 0 + if(CH.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + if(vendor_account) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) + if(D) + transfer_and_reimburse(D) + return 1 else usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support." return 0 else - transfer_and_reimburse(CH) - return 1 + usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support." + return 0 + else + transfer_and_reimburse(CH) + return 1 /obj/machinery/lapvend/proc/transfer_and_reimburse(var/datum/money_account/D) var/transaction_amount = total() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 0f5eeb48b7b..524708b64ed 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1067,8 +1067,8 @@ About the new airlock wires panel: /obj/machinery/door/airlock/emp_act(var/severity) if(prob(40/severity)) - var/duration = world.time + SecondsToTicks(30 / severity) - if(duration > electrified_until) + var/duration = SecondsToTicks(30 / severity) + if(electrified_until > -1 && (duration + world.time) > electrified_until) electrify(duration) ..() diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 65206b95f2f..57bd4708dc2 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -409,12 +409,12 @@ set_opacity(0) sleep(3) src.density = 0 + update_nearby_tiles() sleep(7) src.layer = open_layer explosion_resistance = 0 update_icon() set_opacity(0) - update_nearby_tiles() operating = 0 if(autoclose) @@ -436,12 +436,12 @@ src.density = 1 explosion_resistance = initial(explosion_resistance) src.layer = closed_layer + update_nearby_tiles() sleep(7) update_icon() if(visible && !glass) set_opacity(1) //caaaaarn! operating = 0 - update_nearby_tiles() //I shall not add a check every x ticks if a door has closed over some fire. var/obj/fire/fire = locate() in loc diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 62909fc3daf..97d92903c01 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -195,7 +195,10 @@ Class Procs: return (stat & (NOPOWER|BROKEN|additional_flags)) /obj/machinery/CanUseTopic(var/mob/user) - if(!interact_offline && (stat & (NOPOWER|BROKEN))) + if(stat & BROKEN) + return STATUS_CLOSE + + if(!interact_offline && (stat & NOPOWER)) return STATUS_CLOSE return ..() diff --git a/code/game/machinery/records_scanner.dm b/code/game/machinery/records_scanner.dm index af74c7c9412..90773dd5f9e 100644 --- a/code/game/machinery/records_scanner.dm +++ b/code/game/machinery/records_scanner.dm @@ -88,7 +88,7 @@ obj/machinery/scanner/attack_hand(mob/living/carbon/human/user) G.fields["rank"] = "Unassigned" G.fields["real_rank"] = G.fields["rank"] G.fields["name"] = mname - G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) + G.fields["id"] = generate_record_id() M.fields["name"] = G.fields["name"] M.fields["id"] = G.fields["id"] S.fields["name"] = G.fields["name"] diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index d1e728e6767..e67a68d931f 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -819,15 +819,12 @@ dat += "
\[apply customisation routine\]


" if(panel_open) - dat += wires() + wires.Interact(user) user << browse(dat, "window=suit_cycler") onclose(user, "suit_cycler") return -/obj/machinery/suit_cycler/proc/wires() - return wires.GetInteractWindow() - /obj/machinery/suit_cycler/Topic(href, href_list) if(href_list["eject_suit"]) if(!suit) return diff --git a/code/game/machinery/wall_frames.dm b/code/game/machinery/wall_frames.dm index b7f98667dce..c9182586c8c 100644 --- a/code/game/machinery/wall_frames.dm +++ b/code/game/machinery/wall_frames.dm @@ -35,14 +35,14 @@ var/turf/loc = get_turf(usr) var/area/A = loc.loc if (!istype(loc, /turf/simulated/floor)) - usr << "\The [src] Alarm cannot be placed on this spot." return if (A.requires_power == 0 || A.name == "Space") - usr << "\The [src] Alarm cannot be placed in this area." return if(gotwallitem(loc, ndir)) - usr << "" + usr << "There's already an item on this wall!" return var/obj/machinery/M = new build_machine_type(loc, ndir, 1) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 9b193d7dfdb..c442ac25f86 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -996,6 +996,11 @@ if (usr.stat || !ishuman(usr)) return + + if (usr.buckled) + usr << "You can't climb into the exosuit while buckled!" + return + src.log_message("[usr] tries to move in.") if(iscarbon(usr)) var/mob/living/carbon/C = usr diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 6b79db8f5b4..02d85234ed7 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -1,6 +1,7 @@ /obj var/can_buckle = 0 var/buckle_movable = 0 + var/buckle_dir = 0 var/buckle_lying = -1 //bed-like behavior, forces mob.lying = buckle_lying if != -1 var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes var/mob/living/buckled_mob = null @@ -31,7 +32,7 @@ M.buckled = src M.facing_dir = null - M.set_dir(dir) + M.set_dir(buckle_dir ? buckle_dir : dir) M.update_canmove() buckled_mob = M post_buckle_mob(M) @@ -55,7 +56,8 @@ user << "You can't buckle anyone in before the game starts." if(!user.Adjacent(M) || user.restrained() || user.lying || user.stat || istype(user, /mob/living/silicon/pai)) return - + if(M == buckled_mob) + return if(istype(M, /mob/living/carbon/slime)) user << "The [M] is too squishy to buckle in." return diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm index 3fa93e7e467..034ce946864 100644 --- a/code/game/objects/effects/chem/chemsmoke.dm +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -4,14 +4,76 @@ /obj/effect/effect/smoke/chem icon = 'icons/effects/chemsmoke.dmi' opacity = 0 + layer = 6 time_to_live = 300 pass_flags = PASSTABLE | PASSGRILLE | PASSGLASS //PASSGLASS is fine here, it's just so the visual effect can "flow" around glass + var/splash_amount = 10 //atoms moving through a smoke cloud get splashed with up to 10 units of reagent + var/turf/destination -/obj/effect/effect/smoke/chem/New() +/obj/effect/effect/smoke/chem/New(var/newloc, smoke_duration, turf/dest_turf = null, icon/cached_icon = null) + time_to_live = smoke_duration + ..() + create_reagents(500) - return + + if(cached_icon) + icon = cached_icon + + set_dir(pick(cardinal)) + pixel_x = -32 + rand(-8, 8) + pixel_y = -32 + rand(-8, 8) + + //switching opacity on after the smoke has spawned, and then turning it off before it is deleted results in cleaner + //lighting and view range updates (Is this still true with the new lighting system?) + opacity = 1 + //float over to our destination, if we have one + destination = dest_turf + if(destination) + walk_to(src, destination) + +/obj/effect/effect/smoke/chem/Destroy() + opacity = 0 + fadeOut() + ..() + +/obj/effect/effect/smoke/chem/Move() + var/list/oldlocs = view(1, src) + . = ..() + if(.) + for(var/turf/T in view(1, src) - oldlocs) + for(var/atom/movable/AM in T) + if(!istype(AM, /obj/effect/effect/smoke/chem)) + reagents.splash(AM, splash_amount, copy = 1) + if(loc == destination) + bound_width = 96 + bound_height = 96 + +/obj/effect/effect/smoke/chem/Crossed(atom/movable/AM) + ..() + if(!istype(AM, /obj/effect/effect/smoke/chem)) + reagents.splash(AM, splash_amount, copy = 1) + +/obj/effect/effect/smoke/chem/proc/initial_splash() + for(var/turf/T in view(1, src)) + for(var/atom/movable/AM in T) + if(!istype(AM, /obj/effect/effect/smoke/chem)) + reagents.splash(AM, splash_amount, copy = 1) + +// Fades out the smoke smoothly using it's alpha variable. +/obj/effect/effect/smoke/chem/proc/fadeOut(var/frames = 16) + if(!alpha) return //already transparent + + frames = max(frames, 1) //We will just assume that by 0 frames, the coder meant "during one frame". + var/alpha_step = round(alpha / frames) + while(alpha > 0) + alpha = max(0, alpha - alpha_step) + sleep(world.tick_lag) + +///////////////////////////////////////////// +// Chem Smoke Effect System +///////////////////////////////////////////// /datum/effect/effect/system/smoke_spread/chem smoke_type = /obj/effect/effect/smoke/chem var/obj/chemholder @@ -115,13 +177,21 @@ else I = icon('icons/effects/96x96.dmi', "smoke") + //Calculate smoke duration + var/smoke_duration = 150 + + var/pressure = 0 + var/datum/gas_mixture/environment = location.return_air() + if(environment) pressure = environment.return_pressure() + smoke_duration = between(5, smoke_duration*pressure/(ONE_ATMOSPHERE/3), smoke_duration) + var/const/arcLength = 2.3559 //distance between each smoke cloud for(var/i = 0, i < range, i++) //calculate positions for smoke coverage - then spawn smoke var/radius = i * 1.5 if(!radius) spawn(0) - spawnSmoke(location, I, 1) + spawnSmoke(location, I, 1, 1) continue var/offset = 0 @@ -146,43 +216,26 @@ // Randomizes and spawns the smoke effect. // Also handles deleting the smoke once the effect is finished. //------------------------------------------ -/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1, var/obj/effect/effect/smoke/chem/passed_smoke) +/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/smoke_duration, var/dist = 1, var/splash_initial=0, var/obj/effect/effect/smoke/chem/passed_smoke) var/obj/effect/effect/smoke/chem/smoke if(passed_smoke) smoke = passed_smoke else - smoke = PoolOrNew(/obj/effect/effect/smoke/chem, location) + smoke = PoolOrNew(/obj/effect/effect/smoke/chem, list(location, smoke_duration + rand(0, 20), T, I)) if(chemholder.reagents.reagent_list.len) chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents - smoke.icon = I - smoke.layer = 6 - smoke.set_dir(pick(cardinal)) - smoke.pixel_x = -32 + rand(-8, 8) - smoke.pixel_y = -32 + rand(-8, 8) - walk_to(smoke, T) - smoke.opacity = 1 //switching opacity on after the smoke has spawned, and then - sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner - smoke.opacity = 0 // lighting and view range updates - fadeOut(smoke) - qdel(src) -/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1) + //Kinda ugly, but needed unless the system is reworked + if(splash_initial) + smoke.initial_splash() + + +/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/smoke_duration, var/icon/I, var/dist = 1) var/obj/effect/effect/smoke/chem/spores = PoolOrNew(/obj/effect/effect/smoke/chem, location) spores.name = "cloud of [seed.seed_name] [seed.seed_noun]" - ..(T, I, dist, spores) - -/datum/effect/effect/system/smoke_spread/chem/proc/fadeOut(var/atom/A, var/frames = 16) // Fades out the smoke smoothly using it's alpha variable. - if(A.alpha == 0) //Handle already transparent case - return - if(frames == 0) - frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame". - var/step = A.alpha / frames - for(var/i = 0, i < frames, i++) - A.alpha -= step - sleep(world.tick_lag) - return + ..(T, I, smoke_duration, dist, spores) /datum/effect/effect/system/smoke_spread/chem/proc/smokeFlow() // Smoke pathfinder. Uses a flood fill method based on zones to quickly check what turfs the smoke (airflow) can actually reach. diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 1c723c04ada..2887a8249ad 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -60,7 +60,7 @@ var/global/list/image/splatter_cache=list() var/obj/item/organ/external/l_foot = perp.get_organ("l_foot") var/obj/item/organ/external/r_foot = perp.get_organ("r_foot") var/hasfeet = 1 - if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED)) + if((!l_foot || l_foot.is_stump()) && (!r_foot || r_foot.is_stump())) hasfeet = 0 if(perp.shoes && !perp.buckled)//Adding blood to shoes var/obj/item/clothing/shoes/S = perp.shoes diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index 547931a5118..fb4716043f1 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -105,27 +105,61 @@ qdel(src) */ +/client/proc/spawn_tanktransferbomb() + set category = "Debug" + set desc = "Spawn a tank transfer valve bomb" + set name = "Instant TTV" + + if(!check_rights(R_SPAWN)) return + + var/obj/effect/spawner/newbomb/proto = /obj/effect/spawner/newbomb/radio/custom + + var/p = input("Enter phoron amount (mol):","Phoron", initial(proto.phoron_amt)) as num|null + if(p == null) return + + var/o = input("Enter oxygen amount (mol):","Oxygen", initial(proto.oxygen_amt)) as num|null + if(o == null) return + + var/c = input("Enter carbon dioxide amount (mol):","Carbon Dioxide", initial(proto.carbon_amt)) as num|null + if(c == null) return + + new /obj/effect/spawner/newbomb/radio/custom(get_turf(mob), p, o, c) + /obj/effect/spawner/newbomb - name = "bomb" + name = "TTV bomb" icon = 'icons/mob/screen1.dmi' icon_state = "x" - var/btype = 0 // 0=radio, 1=prox, 2=time + + var/assembly_type = /obj/item/device/assembly/signaler + + //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. + var/phoron_amt = 10.96 + var/oxygen_amt = 16.44 + var/carbon_amt = 0.0 - timer - btype = 2 +/obj/effect/spawner/newbomb/timer + name = "TTV bomb - timer" + assembly_type = /obj/item/device/assembly/timer - syndicate +/obj/effect/spawner/newbomb/timer/syndicate + name = "TTV bomb - merc" + //High yield bombs. Yes, it is possible to make these with toxins + phoron_amt = 15.66 + oxygen_amt = 24.66 - proximity - btype = 1 +/obj/effect/spawner/newbomb/proximity + name = "TTV bomb - proximity" + assembly_type = /obj/item/device/assembly/prox_sensor - radio - btype = 0 - - -/obj/effect/spawner/newbomb/New() +/obj/effect/spawner/newbomb/radio/custom/New(var/newloc, ph, ox, co) + if(ph != null) phoron_amt = ph + if(ox != null) oxygen_amt = ox + if(co != null) carbon_amt = co ..() +/obj/effect/spawner/newbomb/New(newloc) + ..(newloc) + var/obj/item/device/transfer_valve/V = new(src.loc) var/obj/item/weapon/tank/phoron/PT = new(V) var/obj/item/weapon/tank/oxygen/OT = new(V) @@ -137,28 +171,15 @@ OT.master = V PT.air_contents.temperature = PHORON_FLASHPOINT - PT.air_contents.adjust_multi("phoron", 12, "carbon_dioxide", 8) + PT.air_contents.gas["phoron"] = phoron_amt + PT.air_contents.gas["carbon_dioxide"] = carbon_amt + PT.air_contents.update_values() OT.air_contents.temperature = PHORON_FLASHPOINT - OT.air_contents.adjust_gas("oxygen", 20) + OT.air_contents.gas["oxygen"] = oxygen_amt + OT.air_contents.update_values() - var/obj/item/device/assembly/S - - switch (src.btype) - // radio - if (0) - - S = new/obj/item/device/assembly/signaler(V) - - // proximity - if (1) - - S = new/obj/item/device/assembly/prox_sensor(V) - - // timer - if (2) - - S = new/obj/item/device/assembly/timer(V) + var/obj/item/device/assembly/S = new assembly_type(V) V.attached_device = S diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 2a68cb87f7f..f7215086e80 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -151,6 +151,9 @@ if(temp && !temp.is_usable()) user << "You try to move your [temp.name], but cannot!" return + if(!temp) + user << "You try to use your hand, but realize it is no longer attached!" + return src.pickup(user) if (istype(src.loc, /obj/item/weapon/storage)) var/obj/item/weapon/storage/S = src.loc @@ -242,6 +245,9 @@ // for items that can be placed in multiple slots // note this isn't called during the initial dressing of a player /obj/item/proc/equipped(var/mob/user, var/slot) + layer = 20 + if(user.client) user.client.screen |= src + if(user.pulling == src) user.stop_pulling() return //Defines which slots correspond to which slot flags diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 25f2b407cea..35ab855f053 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -721,7 +721,8 @@ var/global/list/obj/item/device/pda/PDAs = list() if("Message") var/obj/item/device/pda/P = locate(href_list["target"]) - src.create_message(U, P, !href_list["notap"]) + var/tap = istype(U, /mob/living/carbon) + src.create_message(U, P, tap) if(mode == 2) if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. active_conversation = href_list["target"] @@ -1040,7 +1041,7 @@ var/global/list/obj/item/device/pda/PDAs = list() new_message(sending_device, sending_device.owner, sending_device.ownjob, message) /obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message) - var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply)" + var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply)" new_info(message_silent, ttone, reception_message) log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") @@ -1052,7 +1053,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(ismob(sending_unit.loc) && isAI(loc)) track = "(Follow)" - var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" + var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" new_info(message_silent, newstone, reception_message) log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index f7ef8ad5c21..5a97968e93b 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -18,9 +18,11 @@ /obj/item/device/chameleon/dropped() disrupt() + ..() /obj/item/device/chameleon/equipped() disrupt() + ..() /obj/item/device/chameleon/attack_self() toggle() diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index eed6cdb12ef..7edf72e9a50 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -320,7 +320,7 @@ qdel(src) /obj/item/device/paicard/see_emote(mob/living/M, text) - if(pai && pai.client) + if(pai && pai.client && !pai.canmove) var/rendered = "[text]" pai.show_message(rendered, 2) ..() \ No newline at end of file diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 36c3b3d11f2..e44f7595470 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -99,17 +99,9 @@ if (src.loc != usr) return 0 if(tank_one && href_list["tankone"]) - split_gases() - valve_open = 0 - tank_one.loc = get_turf(src) - tank_one = null - update_icon() + remove_tank(tank_one) else if(tank_two && href_list["tanktwo"]) - split_gases() - valve_open = 0 - tank_two.loc = get_turf(src) - tank_two = null - update_icon() + remove_tank(tank_two) else if(href_list["open"]) toggle_valve() else if(attached_device) @@ -148,20 +140,43 @@ if(attached_device) overlays += "device" +/obj/item/device/transfer_valve/proc/remove_tank(obj/item/weapon/tank/T) + if(tank_one == T) + split_gases() + tank_one = null + else if(tank_two == T) + split_gases() + tank_two = null + else + return + + T.loc = get_turf(src) + update_icon() + /obj/item/device/transfer_valve/proc/merge_gases() + if(valve_open) + return tank_two.air_contents.volume += tank_one.air_contents.volume var/datum/gas_mixture/temp temp = tank_one.air_contents.remove_ratio(1) tank_two.air_contents.merge(temp) + valve_open = 1 /obj/item/device/transfer_valve/proc/split_gases() - if (!valve_open || !tank_one || !tank_two) + if(!valve_open) return + + valve_open = 0 + + if(deleted(tank_one) || deleted(tank_two)) + return + var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume var/datum/gas_mixture/temp temp = tank_two.air_contents.remove_ratio(ratio1) tank_one.air_contents.merge(temp) tank_two.air_contents.volume -= tank_one.air_contents.volume + /* Exadv1: I know this isn't how it's going to work, but this was just to check @@ -169,8 +184,7 @@ */ /obj/item/device/transfer_valve/proc/toggle_valve() - if(valve_open==0 && (tank_one && tank_two)) - valve_open = 1 + if(!valve_open && (tank_one && tank_two)) var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) @@ -196,16 +210,11 @@ message_admins(log_str, 0, 1) log_game(log_str) merge_gases() - spawn(20) // In case one tank bursts - for (var/i=0,i<5,i++) - src.update_icon() - sleep(10) - src.update_icon() else if(valve_open==1 && (tank_one && tank_two)) split_gases() - valve_open = 0 - src.update_icon() + + src.update_icon() // this doesn't do anything but the timer etc. expects it to be here // eventually maybe have it update icon to show state (timer, prox etc.) like old bombs diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index afe50bc2b76..3ccf1fb3a96 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -71,6 +71,10 @@ icon_state = "meson" icon = 'icons/obj/clothing/glasses.dmi' +/obj/item/borg/sight/material + name = "\proper material scanner vision" + sight_mode = BORGMATERIAL + /obj/item/borg/sight/hud name = "hud" var/obj/item/clothing/glasses/hud/hud = null diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 94b6db4f958..fdb73aa9679 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -137,6 +137,7 @@ if (istype(O, /obj/item/stack)) var/obj/item/stack/S = O S.amount = produced + S.add_to_stacks(user) if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty for (var/obj/item/I in O) @@ -191,7 +192,7 @@ else if(get_amount() < used) return 0 - for(var/i = 1 to uses_charge) + for(var/i = 1 to charge_costs.len) var/datum/matter_synth/S = synths[i] S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted return 1 @@ -264,8 +265,8 @@ return 0 var/datum/matter_synth/S = synths[1] . = round(S.get_charge() / charge_costs[1]) - if(uses_charge > 1) - for(var/i = 2 to uses_charge) + if(charge_costs.len > 1) + for(var/i = 2 to charge_costs.len) S = synths[i] . = min(., round(S.get_charge() / charge_costs[i])) return @@ -284,13 +285,13 @@ return return max_amount -/obj/item/stack/proc/add_to_stacks(mob/usr as mob) - for (var/obj/item/stack/item in usr.loc) +/obj/item/stack/proc/add_to_stacks(mob/user as mob) + for (var/obj/item/stack/item in user.loc) if (item==src) continue var/transfer = src.transfer_to(item) if (transfer) - usr << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s." + user << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s." if(!amount) break diff --git a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm index d244fd6b5c0..7651ac7bcb5 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm @@ -1,27 +1,135 @@ #ifndef T_BOARD -#error T_BOARD macro is not defined but we need it! +#error T_BOARD macro is not defined but we need it! #endif /obj/item/weapon/circuitboard/air_management name = T_BOARD("atmosphere monitoring console") build_path = /obj/machinery/computer/general_air_control + var/console_name var/frequency = 1439 + var/list/sensors = list() + var/list/sensor_information = list() + /obj/item/weapon/circuitboard/air_management/tank_control name = T_BOARD("tank control") build_path = /obj/machinery/computer/general_air_control/large_tank_control frequency = 1441 + var/input_tag + var/output_tag + + var/list/input_info = list() + var/list/output_info = list() + + var/input_flow_setting = 200 + var/pressure_setting = ONE_ATMOSPHERE * 45 + /obj/item/weapon/circuitboard/air_management/supermatter_core name = T_BOARD("core control") build_path = /obj/machinery/computer/general_air_control/supermatter_core frequency = 1438 + var/input_tag + var/output_tag + + var/list/input_info = list() + var/list/output_info = list() + + var/input_flow_setting = 700 + var/pressure_setting = 100 + /obj/item/weapon/circuitboard/air_management/injector_control name = T_BOARD("injector control") build_path = /obj/machinery/computer/general_air_control/fuel_injection + var/device_tag + var/list/device_info + var/automation = 0 + var/cutoff_temperature = 2000 + var/on_temperature = 1200 +/************ +* Construct * +************/ /obj/item/weapon/circuitboard/air_management/construct(var/obj/machinery/computer/general_air_control/C) if (..(C)) - C.frequency = frequency + if(console_name) + C.name = console_name + C.set_frequency(frequency) + C.sensors = sensors.Copy() + C.sensor_information = sensor_information.Copy() + return 1 +/obj/item/weapon/circuitboard/air_management/tank_control/construct(var/obj/machinery/computer/general_air_control/large_tank_control/LTC) + if(..(LTC)) + LTC.input_tag = input_tag + LTC.output_tag = output_tag + + LTC.input_info = input_info.Copy() + LTC.output_info = output_info.Copy() + + LTC.input_flow_setting = input_flow_setting + LTC.pressure_setting = pressure_setting + return 1 + +/obj/item/weapon/circuitboard/air_management/supermatter_core/construct(var/obj/machinery/computer/general_air_control/supermatter_core/SC) + if(..(SC)) + SC.input_tag = input_tag + SC.output_tag = output_tag + + SC.input_info = input_info.Copy() + SC.output_info = output_info.Copy() + + SC.input_flow_setting = input_flow_setting + SC.pressure_setting = input_flow_setting + return 1 + +/obj/item/weapon/circuitboard/air_management/injector_control/construct(var/obj/machinery/computer/general_air_control/fuel_injection/FI) + if(..(FI)) + FI.device_tag = device_tag + FI.device_info = device_info.Copy() + FI.automation = automation + FI.cutoff_temperature = cutoff_temperature + FI.on_temperature = on_temperature + return 1 + +/************** +* Deconstruct * +**************/ /obj/item/weapon/circuitboard/air_management/deconstruct(var/obj/machinery/computer/general_air_control/C) if (..(C)) + console_name = C.name frequency = C.frequency + sensors = C.sensors.Copy() + sensor_information = C.sensor_information.Copy() + return 1 + +/obj/item/weapon/circuitboard/air_management/tank_control/deconstruct(var/obj/machinery/computer/general_air_control/large_tank_control/LTC) + if(..(LTC)) + input_tag = LTC.input_tag + output_tag = LTC.output_tag + + input_info = LTC.input_info.Copy() + output_info = LTC.output_info.Copy() + + input_flow_setting = LTC.input_flow_setting + pressure_setting = LTC.pressure_setting + return 1 + +/obj/item/weapon/circuitboard/air_management/supermatter_core/deconstruct(var/obj/machinery/computer/general_air_control/supermatter_core/SC) + if(..(SC)) + input_tag = SC.input_tag + output_tag = SC.output_tag + + input_info = SC.input_info.Copy() + output_info = SC.output_info.Copy() + + input_flow_setting = SC.input_flow_setting + pressure_setting = SC.input_flow_setting + return 1 + +/obj/item/weapon/circuitboard/air_management/injector_control/deconstruct(var/obj/machinery/computer/general_air_control/fuel_injection/FI) + if(..(FI)) + device_tag = FI.device_tag + device_info = FI.device_info.Copy() + automation = FI.automation + cutoff_temperature = FI.cutoff_temperature + on_temperature = FI.on_temperature + return 1 diff --git a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm new file mode 100644 index 00000000000..db11c4de502 --- /dev/null +++ b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm @@ -0,0 +1,31 @@ +#ifndef T_BOARD +#error T_BOARD macro is not defined but we need it! +#endif + +/obj/item/weapon/circuitboard/holodeckcontrol + name = T_BOARD("holodeck control console") + build_path = /obj/machinery/computer/HolodeckControl + origin_tech = "programming=2;bluespace=2" + var/last_to_emag + var/linkedholodeck_area + var/list/supported_programs + var/list/restricted_programs + +/obj/item/weapon/circuitboard/holodeckcontrol/construct(var/obj/machinery/computer/HolodeckControl/HC) + if (..(HC)) + HC.supported_programs = supported_programs.Copy() + HC.restricted_programs = restricted_programs.Copy() + if(linkedholodeck_area) + HC.linkedholodeck = locate(linkedholodeck_area) + if(last_to_emag) + HC.last_to_emag = last_to_emag + HC.emagged = 1 + HC.safety_disabled = 1 + +/obj/item/weapon/circuitboard/holodeckcontrol/deconstruct(var/obj/machinery/computer/HolodeckControl/HC) + if (..(HC)) + linkedholodeck_area = HC.linkedholodeck_area + supported_programs = HC.supported_programs.Copy() + restricted_programs = HC.restricted_programs.Copy() + last_to_emag = HC.last_to_emag + HC.emergencyShutdown() diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm index d34456e4533..c0847d282df 100644 --- a/code/game/objects/items/weapons/clown_items.dm +++ b/code/game/objects/items/weapons/clown_items.dm @@ -15,7 +15,15 @@ /* * Soap */ -/obj/item/weapon/soap/Crossed(AM as mob|obj) //EXACTLY the same as bananapeel for now, so it makes sense to put it in the same dm -- Urist +/obj/item/weapon/soap/New() + ..() + create_reagents(5) + wet() + +/obj/item/weapon/soap/proc/wet() + reagents.add_reagent("cleaner", 5) + +/obj/item/weapon/soap/Crossed(AM as mob|obj) if (istype(AM, /mob/living)) var/mob/living/M = AM M.slip("the [src.name]",3) @@ -32,7 +40,10 @@ else if(istype(target,/turf)) user << "You scrub \the [target.name] clean." var/turf/T = target - T.clean(src) + T.clean(src, user) + else if(istype(target,/obj/structure/sink)) + user << "You wet \the [src] in the sink." + wet() else user << "You clean \the [target.name]." target.clean_blood() diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index b559527ef7e..5e15098521a 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -6,6 +6,7 @@ w_class = 2.0 force = 2.0 det_time = null + unacidable = 1 var/stage = 0 var/state = 0 var/path = 0 @@ -163,7 +164,7 @@ playsound(src.loc, 'sound/effects/bamf.ogg', 50, 1) for(var/obj/item/weapon/reagent_containers/glass/G in beakers) - G.reagents.trans_to(src, G.reagents.total_volume) + G.reagents.trans_to_obj(src, G.reagents.total_volume) if(src.reagents.total_volume) //The possible reactions didnt use up all reagents. var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread() diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 6465a055785..2e156e7e967 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -6,6 +6,7 @@ name = "implant" icon = 'icons/obj/device.dmi' icon_state = "implant" + w_class = 1 var/implanted = null var/mob/imp_in = null var/obj/item/organ/external/part = null diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm index 55c51519345..9c160f028d4 100644 --- a/code/game/objects/items/weapons/material/kitchen.dm +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -44,7 +44,8 @@ overlays.Cut() return else - ..() + user << "You don't have anything on \the [src]." //if we have help intent and no food scooped up DON'T STAB OURSELVES WITH THE FORK GODDAMNIT + return /obj/item/weapon/material/kitchen/utensil/fork name = "fork" @@ -77,14 +78,14 @@ /obj/item/weapon/material/kitchen/utensil/knife/attack(target as mob, mob/living/user as mob) if ((CLUMSY in user.mutations) && prob(50)) - user << "\red You accidentally cut yourself with the [src]." + user << "You accidentally cut yourself with \the [src]." user.take_organ_damage(20) return return ..() /obj/item/weapon/material/kitchen/utensil/knife/attack(target as mob, mob/living/user as mob) if ((CLUMSY in user.mutations) && prob(50)) - user << "\red You somehow managed to cut yourself with the [src]." + user << "You somehow managed to cut yourself with \the [src]." user.take_organ_damage(20) return return ..() @@ -107,7 +108,7 @@ /obj/item/weapon/material/kitchen/rollingpin/attack(mob/living/M as mob, mob/living/user as mob) if ((CLUMSY in user.mutations) && prob(50)) - user << "\red The [src] slips out of your hand and hits your head." + user << "\The [src] slips out of your hand and hits your head." user.take_organ_damage(10) user.Paralyse(2) return diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index abf5e08a3be..e50ce867967 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -14,19 +14,7 @@ /obj/item/weapon/mop/New() - create_reagents(5) - -//expects an atom containing the reagents used to clean the turf -/turf/proc/clean(atom/source) - if(source.reagents.has_reagent("water", 1)) - clean_blood() - if(istype(src, /turf/simulated)) - var/turf/simulated/T = src - T.dirt = 0 - for(var/obj/effect/O in src) - if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) - qdel(O) - source.reagents.trans_to_turf(src, 1, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly. + create_reagents(30) /obj/item/weapon/mop/afterattack(atom/A, mob/user, proximity) if(!proximity) return @@ -40,7 +28,7 @@ if(do_after(user, 40)) var/turf/T = get_turf(A) if(T) - T.clean(src) + T.clean(src, user) user << "You have finished mopping!" diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index d28107dd8f3..aa3fe35f9b6 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -598,32 +598,33 @@ icon_state = "light" desc = "This box is shaped on the inside so that only light tubes and bulbs fit." item_state = "syringe_kit" - storage_slots=21 - can_hold = list(/obj/item/weapon/light/tube, /obj/item/weapon/light/bulb) - max_storage_space = 42 //holds 21 items of w_class 2 use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + +/obj/item/weapon/storage/box/lights/New() + ..() + make_exact_fit() /obj/item/weapon/storage/box/lights/bulbs/New() - ..() for(var/i = 0; i < 21; i++) new /obj/item/weapon/light/bulb(src) + ..() /obj/item/weapon/storage/box/lights/tubes name = "box of replacement tubes" icon_state = "lighttube" /obj/item/weapon/storage/box/lights/tubes/New() - ..() for(var/i = 0; i < 21; i++) new /obj/item/weapon/light/tube(src) + ..() /obj/item/weapon/storage/box/lights/mixed name = "box of replacement lights" icon_state = "lightmixed" /obj/item/weapon/storage/box/lights/mixed/New() - ..() for(var/i = 0; i < 14; i++) new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) new /obj/item/weapon/light/bulb(src) + ..() diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index c23dfcdb516..a76fb4f1a1f 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -130,8 +130,7 @@ /obj/item/weapon/storage/firstaid/surgery name = "surgery kit" - desc = "Contains tools for surgery." - storage_slots = 10 + desc = "Contains tools for surgery. Has precise foam fitting for safe transport." /obj/item/weapon/storage/firstaid/surgery/New() ..() @@ -146,7 +145,8 @@ new /obj/item/weapon/bonegel(src) new /obj/item/weapon/FixOVein(src) new /obj/item/stack/medical/advanced/bruise_pack(src) - return + + make_exact_fit() /* * Pill Bottles diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 22277c33e2a..9f5fe9ea7c7 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -51,10 +51,10 @@ //there's got to be a better way of doing this. if (!(src.loc == usr) || (src.loc && src.loc.loc == usr)) return - + if (( usr.restrained() ) || ( usr.stat )) return - + if ((src.loc == usr) && !usr.unEquip(src)) return @@ -232,12 +232,16 @@ usr << "[src] is full, make some space." return 0 //Storage item is full - if(can_hold.len && !is_type_in_list(W, can_hold)) - if(!stop_messages) - if (istype(W, /obj/item/weapon/hand_labeler)) - return 0 - usr << "[src] cannot hold [W]." - return 0 + if(can_hold.len) + if(!is_type_in_list(W, can_hold)) + if(!stop_messages && ! istype(W, /obj/item/weapon/hand_labeler)) + usr << "[src] cannot hold \the [W]." + return 0 + var/max_instances = can_hold[W.type] + if(max_instances && instances_of_type_in_list(W, contents) >= max_instances) + if(!stop_messages && !istype(W, /obj/item/weapon/hand_labeler)) + usr << "[src] has no more space specifically for \the [W]." + return 0 if(cant_hold.len && is_type_in_list(W, cant_hold)) if(!stop_messages) @@ -449,6 +453,17 @@ var/obj/O = A O.hear_talk(M, text, verb, speaking) +/obj/item/weapon/storage/proc/make_exact_fit() + storage_slots = contents.len + + can_hold.Cut() + max_w_class = 0 + max_storage_space = 0 + for(var/obj/item/I in src) + can_hold[I.type]++ + max_w_class = max(I.w_class, max_w_class) + max_storage_space += I.get_storage_cost() + //Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area). //Returns -1 if the atom was not found on container. /atom/proc/storage_depth(atom/container) diff --git a/code/game/objects/items/weapons/surgery_limbattachment.dm b/code/game/objects/items/weapons/surgery_limbattachment.dm deleted file mode 100644 index b52bb1bb3f3..00000000000 --- a/code/game/objects/items/weapons/surgery_limbattachment.dm +++ /dev/null @@ -1,71 +0,0 @@ -/obj/item/robot_parts/attack(mob/living/carbon/human/M as mob, mob/living/carbon/user as mob) - var/limbloc = null - - if(!istype(M)) - return ..() - - if(!((locate(/obj/machinery/optable, M.loc) && M.resting) || (locate(/obj/structure/bed/roller, M.loc) && (M.buckled || M.lying || M.weakened || M.stunned || M.paralysis || M.sleeping || M.stat)) && prob(75) || (locate(/obj/structure/table/, M.loc) && (M.lying || M.weakened || M.stunned || M.paralysis || M.sleeping || M.stat) && prob(66)))) - return ..() - - if(!istype(M, /mob/living/carbon/human)) - return ..() - - if((user.zone_sel.selecting == "l_arm") && (istype(src, /obj/item/robot_parts/l_arm))) - limbloc = "l_hand" - else if((user.zone_sel.selecting == "r_arm") && (istype(src, /obj/item/robot_parts/r_arm))) - limbloc = "r_hand" - else if((user.zone_sel.selecting == "r_leg") && (istype(src, /obj/item/robot_parts/r_leg))) - limbloc = "r_foot" - else if((user.zone_sel.selecting == "l_leg") && (istype(src, /obj/item/robot_parts/l_leg))) - limbloc = "l_foot" - else - user << "\red That doesn't fit there!" - return ..() - - var/mob/living/carbon/human/H = M - var/datum/organ/external/S = H.organs[user.zone_sel.selecting] - if(S.status & ORGAN_DESTROYED) - if(!(S.status & ORGAN_ATTACHABLE)) - user << "\red The wound is not ready for a replacement!" - return 0 - if(M != user) - M.visible_message( \ - "\red [user] is beginning to attach \the [src] where [H]'s [S.display_name] used to be.", \ - "\red [user] begins to attach \the [src] where your [S.display_name] used to be.") - else - M.visible_message( \ - "\red [user] begins to attach a robotic limb where \his [S.display_name] used to be with [src].", \ - "\red You begin to attach \the [src] where your [S.display_name] used to be.") - - if(do_mob(user, H, 100)) - if(M != user) - M.visible_message( \ - "\red [user] finishes attaching [H]'s new [S.display_name].", \ - "\red [user] finishes attaching your new [S.display_name].") - else - M.visible_message( \ - "\red [user] finishes attaching \his new [S.display_name].", \ - "\red You finish attaching your new [S.display_name].") - - if(H == user && prob(25)) - user << "\red You mess up!" - S.take_damage(15) - - S.status &= ~ORGAN_BROKEN - S.status &= ~ORGAN_SPLINTED - S.status &= ~ORGAN_ATTACHABLE - S.status &= ~ORGAN_DESTROYED - S.status |= ORGAN_ROBOT - var/datum/organ/external/T = H.organs["[limbloc]"] - T.status &= ~ORGAN_BROKEN - T.status &= ~ORGAN_SPLINTED - T.status &= ~ORGAN_ATTACHABLE - T.status &= ~ORGAN_DESTROYED - T.status |= ORGAN_ROBOT - H.update_body() - M.updatehealth() - M.UpdateDamageIcon() - qdel(src) - - return 1 - return 0 diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 68e4ad84dd1..dec27ed60ad 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -36,6 +36,10 @@ qdel(air_contents) processing_objects.Remove(src) + + if(istype(loc, /obj/item/device/transfer_valve)) + var/obj/item/device/transfer_valve/TTV = loc + TTV.remove_tank(src) ..() @@ -272,7 +276,10 @@ qdel(src) else if(pressure > TANK_RUPTURE_PRESSURE) - //world << "\blue[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]" + #ifdef FIREDBG + log_debug("\blue[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]") + #endif + if(integrity <= 0) var/turf/simulated/T = get_turf(src) if(!T) @@ -284,7 +291,10 @@ integrity-- else if(pressure > TANK_LEAK_PRESSURE) - //world << "\blue[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]" + #ifdef FIREDBG + log_debug("\blue[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]") + #endif + if(integrity <= 0) var/turf/simulated/T = get_turf(src) if(!T) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 867c5155e08..730adfca1f8 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -53,6 +53,11 @@ user << "You wave [src] over [M]'s head and see their eyes become clear, their mind returning to normal." cult.remove_antagonist(M.mind) M.visible_message("\The [user] waves \the [src] over \the [M]'s head.") + else if(M.mind && M.mind.vampire) + if(!(VAMP_FULL in M.mind.vampire.powers)) + user << "\red The rod burns cold in your hand, filling you with grim determination. You feel the creature's power weaken." + M << "The nullrod's power interferes with your own! They are on to you!" + M.mind.vampire.nullified = max(8, M.mind.vampire.nullified + 8) else if(prob(10)) user << "The rod slips in your hand." ..() diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 8039814f4fe..f344758b491 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -79,7 +79,7 @@ return ..() /obj/structure/proc/can_climb(var/mob/living/user, post_climb_check=0) - if (!can_touch(user) || !climbable || (!post_climb_check && (user in climbers))) + if (!climbable || !can_touch(user) || (!post_climb_check && (user in climbers))) return 0 if (!user.Adjacent(src)) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 40a8c9d38db..08a2a5af237 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -172,19 +172,18 @@ if(1) for(var/atom/movable/A as mob|obj in src)//pulls everything out of the locker and hits it with an explosion A.forceMove(src.loc) - A.ex_act(severity++) + A.ex_act(severity + 1) qdel(src) if(2) if(prob(50)) for (var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - A.ex_act(severity++) + A.ex_act(severity + 1) qdel(src) if(3) if(prob(5)) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - A.ex_act(severity++) qdel(src) /obj/structure/closet/proc/damage(var/damage) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index 2aa3e571852..a71851f9f20 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -66,11 +66,12 @@ src.MouseDrop_T(W:affecting, user) //act like they were dragged onto the closet user.drop_item() if (W) W.forceMove(src.loc) - else if(istype(W, /obj/item/weapon/card/id)) + else if(W.GetID()) + var/obj/item/weapon/card/id/I = W.GetID() + if(src.broken) user << "It appears to be broken." return - var/obj/item/weapon/card/id/I = W if(!I || !I.registered_name) return if(src.allowed(user) || !src.registered_name || (istype(I) && (src.registered_name == I.registered_name))) //they can open all lockers, or nobody owns this, or they own this locker diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 3067b70d361..6c3db50c877 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -15,6 +15,7 @@ pressure_resistance = 15 anchored = 1 can_buckle = 1 + buckle_dir = SOUTH buckle_lying = 1 var/material/material var/material/padding_material @@ -131,14 +132,18 @@ remove_padding() else if(istype(W, /obj/item/weapon/grab)) - user.visible_message("[user] attempts to buckle [W:affecting] into \the [src]!") + var/obj/item/weapon/grab/G = W + var/mob/living/affecting = G.affecting + user.visible_message("[user] attempts to buckle [affecting] into \the [src]!") if(do_after(user, 20)) - W:affecting.loc = loc - if(buckle_mob(W:affecting)) - W:affecting.visible_message(\ - "[W:affecting.name] is buckled to [src] by [user.name]!",\ - "You are buckled to [src] by [user.name]!",\ - "You hear metal clanking.") + affecting.loc = loc + spawn(0) + if(buckle_mob(affecting)) + affecting.visible_message(\ + "[affecting.name] is buckled to [src] by [user.name]!",\ + "You are buckled to [src] by [user.name]!",\ + "You hear metal clanking.") + qdel(W) else ..() diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 1d6ae5ed583..ae4fe4d7401 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -4,6 +4,7 @@ icon_state = "chair_preview" color = "#666666" base_icon = "chair" + buckle_dir = 0 buckle_lying = 0 //force people to sit up in chairs when buckled var/propelled = 0 // Check for fire-extinguisher-driven chairs diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index fc9f5b6a193..0ac02fbeb73 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -140,7 +140,7 @@ return 1 if(is_full_window()) return 0 //full tile window, you can't move into it! - if(get_dir(loc, target) == dir) + if(get_dir(loc, target) & dir) return !density else return 1 diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index 32668e47437..a4083b81901 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -10,12 +10,14 @@ //flick("[material.icon_base]fwall_opening", src) sleep(15) density = 0 + opacity = 0 set_light(0) else can_open = WALL_OPENING //flick("[material.icon_base]fwall_closing", src) set_wall_state("[material.icon_base]0") density = 1 + opacity = 1 sleep(15) set_light(1) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index e46e664eb88..de114e912d0 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -396,3 +396,17 @@ if(A.density && !(A.flags & ON_BORDER)) return 1 return 0 + +//expects an atom containing the reagents used to clean the turf +/turf/proc/clean(atom/source, mob/user) + if(source.reagents.has_reagent("water", 1) || source.reagents.has_reagent("cleaner", 1)) + clean_blood() + if(istype(src, /turf/simulated)) + var/turf/simulated/T = src + T.dirt = 0 + for(var/obj/effect/O in src) + if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) + qdel(O) + else + user << "\The [source] is too dry to wash that." + source.reagents.trans_to_turf(src, 1, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly. diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index 82fef02e97c..0cb18bb153c 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -105,7 +105,7 @@ log_ooc("(LOCAL) [mob.name]/[key] : [msg]") var/mob/source = src.mob - var/list/heard = get_mobs_in_view(7, source) + var/list/heard = get_mobs_in_view(7, get_turf(source)) var/display_name = source.key if(holder && holder.fakekey) diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 030dad6d3fe..31c80661ab0 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -31,6 +31,7 @@ if(held_item) var/damagetype = held_item.suicide_act(src) if(damagetype) + log_and_message_admins("[key_name(src)] commited suicide using \a [held_item]") var/damage_mod = 1 switch(damagetype) //Sorry about the magic numbers. //brute = 1, burn = 2, tox = 4, oxy = 8 @@ -70,7 +71,7 @@ updatehealth() return - + log_and_message_admins("[key_name(src)] commited suicide") viewers(src) << pick("\red [src] is attempting to bite \his tongue off! It looks like \he's trying to commit suicide.", \ "\red [src] is jamming \his thumbs into \his eye sockets! It looks like \he's trying to commit suicide.", \ "\red [src] is twisting \his own neck! It looks like \he's trying to commit suicide.", \ diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index cc26d7153de..56bbbb8a008 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -302,7 +302,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) output += "" for(var/j in nonhuman_positions) output += "" - var/list/bantypes = list("traitor","changeling","operative","revolutionary","cultist","wizard") //For legacy bans. + var/list/bantypes = list("traitor","changeling","vampire","operative","revolutionary","cultist","wizard") //For legacy bans. for(var/antag_type in all_antag_types) // Grab other bans. var/datum/antagonist/antag = all_antag_types[antag_type] bantypes |= antag.bantype @@ -349,6 +349,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) var/bdcolor = "#ffdddd" //banned dark var/ulcolor = "#eeffee" //unbanned light var/udcolor = "#ddffdd" //unbanned dark + var/alcolor = "#eeeeff" // auto-unbanned light + var/adcolor = "#ddddff" // auto-unbanned dark output += "" output += "" @@ -400,6 +402,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") select_query.Execute() + var/now = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") // MUST BE the same format as SQL gives us the dates in, and MUST be least to most specific (i.e. year, month, day not day, month, year) + while(select_query.NextRow()) var/banid = select_query.item[1] var/bantime = select_query.item[2] @@ -417,36 +421,42 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) var/ip = select_query.item[14] var/cid = select_query.item[15] + // true if this ban has expired + var/auto = (bantype in list("TEMPBAN", "JOB_TEMPBAN")) && now > expiration // oh how I love ISO 8601 (ish) date strings + var/lcolor = blcolor var/dcolor = bdcolor if(unbanned) lcolor = ulcolor dcolor = udcolor + else if(auto) + lcolor = alcolor + dcolor = adcolor var/typedesc ="" switch(bantype) if("PERMABAN") typedesc = "PERMABAN" if("TEMPBAN") - typedesc = "TEMPBAN
([duration] minutes [(unbanned) ? "" : "(Edit))"]
Expires [expiration]
" + typedesc = "TEMPBAN
([duration] minutes) [(unbanned || auto) ? "" : "(Edit)"]
Expires [expiration]
" if("JOB_PERMABAN") typedesc = "JOBBAN
([job])" if("JOB_TEMPBAN") - typedesc = "TEMP JOBBAN
([job])
([duration] minutes
Expires [expiration]" + typedesc = "TEMP JOBBAN
([job])
([duration] minutes)
Expires [expiration]" output += "
" output += "" output += "" output += "" output += "" - output += "" + output += "" output += "" output += "" output += "" output += "" output += "" output += "" - output += "" + output += "" output += "" if(edits) output += "" @@ -459,10 +469,14 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) output += "" output += "" output += "" + else if(auto) + output += "" + output += "" + output += "" output += "" output += "" output += "" output += "
[typedesc][ckey][bantime][ackey][(unbanned) ? "" : "Unban"][(unbanned || auto) ? "" : "Unban"]
IP: [ip]CIP: [cid]
Reason: [(unbanned) ? "" : "(Edit)"] \"[reason]\"Reason: [(unbanned || auto) ? "" : "(Edit)"] \"[reason]\"
UNBANNED by admin [unbanckey] on [unbantime]
EXPIRED at [expiration]
 
" - usr << browse(output,"window=lookupbans;size=900x700") \ No newline at end of file + usr << browse(output,"window=lookupbans;size=900x700") diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index f02292d81f1..86e0d31cefd 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -612,7 +612,7 @@ proc/admin_notice(var/message, var/rights) Bombing List
Show current traitors and objectives
Show last [length(lastsignalers)] signalers
- Show last [length(lawchanges)] law changes
+ Show last [lawchanges.len] law change\s
Show AI Laws
Show Game Mode
Show Crew Manifest
@@ -1386,7 +1386,7 @@ proc/admin_notice(var/message, var/rights) var/datum/antagonist/antag = all_antag_types[antag_type] message_admins("[key_name(usr)] attempting to force latespawn with template [antag.id].") - antag.attempt_late_spawn() + antag.attempt_auto_spawn() /datum/admins/proc/force_mode_latespawn() set category = "Admin" @@ -1395,7 +1395,7 @@ proc/admin_notice(var/message, var/rights) if (!istype(src,/datum/admins)) src = usr.client.holder - if (!istype(src,/datum/admins)) + if (!istype(src,/datum/admins) || !check_rights(R_ADMIN)) usr << "Error: you are not an admin!" return @@ -1403,6 +1403,21 @@ proc/admin_notice(var/message, var/rights) usr << "Mode has not started." return - message_admins("[key_name(usr)] attempting to force mode latespawn.") - ticker.mode.next_spawn = 0 - ticker.mode.try_latespawn() + log_and_message_admins("attempting to force mode autospawn.") + ticker.mode.process_autoantag() + +/datum/admins/proc/paralyze_mob(mob/living/H as mob) + set category = "Admin" + set name = "Toggle Paralyze" + set desc = "Paralyzes a player. Or unparalyses them." + + var/msg + + if(check_rights(R_ADMIN)) + if (H.paralysis == 0) + H.paralysis = 8000 + msg = "has paralyzed [key_name(H)]." + else + H.paralysis = 0 + msg = "has unparalyzed [key_name(H)]." + log_and_message_admins(msg) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index d628a7bef36..54031611497 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -91,7 +91,8 @@ var/list/admin_verbs_admin = list( /client/proc/change_human_appearance_self, /* Allows the human-based mob itself change its basic appearance */ /client/proc/change_security_level, /client/proc/view_chemical_reaction_logs, - /client/proc/makePAI + /client/proc/makePAI, + /datum/admins/proc/paralyze_mob ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, @@ -125,9 +126,6 @@ var/list/admin_verbs_spawn = list( /datum/admins/proc/spawn_plant, /datum/admins/proc/spawn_atom, /*allows us to spawn instances*/ /client/proc/respawn_character, - /client/proc/FireLaser, - /client/proc/FireCannons, - /client/proc/ChangeIcarusPosition, /client/proc/virus2_editor, /client/proc/spawn_chemdisp_cartridge ) @@ -287,7 +285,8 @@ var/list/admin_verbs_mod = list( /datum/admins/proc/show_player_panel, /client/proc/check_antagonists, /client/proc/jobbans, - /client/proc/cmd_admin_subtle_message /*send an message to somebody as a 'voice in their head'*/ + /client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/ + /datum/admins/proc/paralyze_mob ) var/list/admin_verbs_mentor = list( @@ -401,7 +400,7 @@ var/list/admin_verbs_mentor = list( var/mob/dead/observer/ghost = body.ghostize(1) ghost.admin_ghosted = 1 if(body) - body.aghosted = ghost + body.teleop = ghost if(!body.key) body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus feedback_add_details("admin_verb","O") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm index 4a28ece9151..b6293e7941d 100644 --- a/code/modules/admin/player_notes.dm +++ b/code/modules/admin/player_notes.dm @@ -106,7 +106,7 @@ datum/admins/proc/notes_gethtml(var/ckey) message_admins("\blue [key_name_admin(user)] has edited [key]'s notes.") log_admin("[key_name(user)] has edited [key]'s notes.") - qdel(info) + del(info) // savefile, so NOT qdel //Updating list of keys with notes on them var/savefile/note_list = new("data/player_notes.sav") @@ -115,7 +115,7 @@ datum/admins/proc/notes_gethtml(var/ckey) if(!note_keys) note_keys = list() if(!note_keys.Find(key)) note_keys += key note_list << note_keys - qdel(note_list) + del(note_list) // savefile, so NOT qdel /proc/notes_del(var/key, var/index) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e60a830086a..de178bc2980 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -85,7 +85,7 @@ banreason = "[banreason] (CUSTOM CID)" else message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob") - notes_add(playermob.ckey,banreason,usr) + notes_add(banckey,banreason,usr) DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid ) @@ -2300,7 +2300,7 @@ dat += "[sig]
" usr << browse(dat, "window=lastsignalers;size=800x500") if("list_lawchanges") - var/dat = "Showing last [length(lawchanges)] law changes.
" + var/dat = "Showing last [lawchanges.len] law change\s.
" for(var/sig in lawchanges) dat += "[sig]
" usr << browse(dat, "window=lawchanges;size=800x500") @@ -2411,13 +2411,8 @@ else var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") if(choice=="Confirm") - var/datum/feed_channel/newChannel = new /datum/feed_channel - newChannel.channel_name = src.admincaster_feed_channel.channel_name - newChannel.author = src.admincaster_signature - newChannel.locked = src.admincaster_feed_channel.locked - newChannel.is_admin_channel = 1 - feedback_inc("newscaster_channels",1) - news_network.network_channels += newChannel //Adding channel to the global network + news_network.CreateFeedChannel(admincaster_feed_channel.channel_name, admincaster_signature, admincaster_feed_channel.locked, 1) + feedback_inc("newscaster_channels",1) //Adding channel to the global network log_admin("[key_name_admin(usr)] created command feed channel: [src.admincaster_feed_channel.channel_name]!") src.admincaster_screen=5 src.access_news_network() diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm index 2131e977ac7..0ecc220ae2c 100644 --- a/code/modules/admin/verbs/buildmode.dm +++ b/code/modules/admin/verbs/buildmode.dm @@ -296,3 +296,4 @@ if(pa.Find("right")) if(holder.throw_atom) holder.throw_atom.throw_at(object, 10, 1) + log_admin("[key_name(usr)] threw [holder.throw_atom] at [object]") diff --git a/code/modules/admin/verbs/icarus.dm b/code/modules/admin/verbs/icarus.dm deleted file mode 100644 index fd296dacee6..00000000000 --- a/code/modules/admin/verbs/icarus.dm +++ /dev/null @@ -1,130 +0,0 @@ -/client/proc/FireLaser() - set name = "Fire the Icarus lasers" - set desc = "Fires a laser bolt at your position. You should only do this as a(n) (a)ghost" - set category = "Fun" - - var/turf/target = get_turf(src.mob) - log_and_message_admins("has fired the Icarus point defense laser at [target.x]-[target.y]-[target.z]") - if(!src.holder) - src << "Only administrators may use this command." - return - - Icarus_FireLaser(target) - - -/client/proc/FireCannons() - set name = "Fire the Icarus cannons" - set desc = "Fires an explosive missile at your position. You should only do this as a(n) (a)ghost." - set category = "Fun" - - var/turf/target = get_turf(src.mob) - log_and_message_admins("has fired the Icarus main gun projectile at [target.x]-[target.y]-[target.z]") - if(!src.holder) - src << "Only administrators may use this command." - return - - Icarus_FireCannon(target) - - -/client/proc/ChangeIcarusPosition() - set name = "Adjust Icarus Position" - set desc = "Lets you chose the position of the Icarus in regards to the map." - set category = "Fun" - - log_and_message_admins("is changing the Icarus position.") - if(!src.holder) - src << "Only administrators may use this command." - return - - Icarus_SetPosition(src) - -var/icarus_position = SOUTH - -proc/Icarus_FireLaser(var/turf/target) - // Find the world edge to fire from. - var/x = icarus_position & EAST ? world.maxx : icarus_position & WEST ? 1 : target.x - var/y = icarus_position & NORTH ? world.maxy : icarus_position & SOUTH ? 1 : target.y - var/x_off = x != target.x ? abs(target.x - x) : INFINITY - var/y_off = y != target.y ? abs(target.y - y) : INFINITY - // Get the minimum number of steps using the rise/run shit. - var/iterations = round(min(x_off, y_off)) - 14 // We cannot fire straight from the edge since teleport thing. - - // Now we can get the location of the start. - x = target.x + (icarus_position & EAST ? iterations : icarus_position & WEST ? -iterations : 0) - y = target.y + (icarus_position & NORTH ? iterations : icarus_position & SOUTH ? -iterations : 0) - - var/turf/start = locate(x, y, target.z) - - // should step down as: - // 1000, 500, 333, 250, 200, 167, 142, 125, 111, 100, 90 - var/damage = 1000 - for(var/i in 2 to 12) - var/obj/item/projectile/beam/in_chamber = new (start) - in_chamber.original = target - in_chamber.starting = start - in_chamber.silenced = 1 - in_chamber.yo = icarus_position & NORTH ? -1 : icarus_position & SOUTH ? 1 : 0 - in_chamber.xo = icarus_position & EAST ? -1 : icarus_position & WEST ? 1 : 0 - in_chamber.damage = damage - in_chamber.kill_count = 500 - in_chamber.process() - damage -= damage / i - sleep(-1) - - // Let everyone know what hit them. - var/obj/item/projectile/beam/in_chamber = new (start) - in_chamber.original = target - in_chamber.starting = start - in_chamber.silenced = 0 - in_chamber.yo = icarus_position & NORTH ? -1 : icarus_position & SOUTH ? 1 : 0 - in_chamber.xo = icarus_position & EAST ? -1 : icarus_position & WEST ? 1 : 0 - in_chamber.kill_count = 500 - in_chamber.damage = 0 - in_chamber.name = "point defense laser" - in_chamber.firer = "Icarus" // Never displayed, but we want this to display the hit message. - in_chamber.process() - -proc/Icarus_FireCannon(var/turf/target) - // Find the world edge to fire from. - var/x = icarus_position & EAST ? world.maxx : icarus_position & WEST ? 1 : target.x - var/y = icarus_position & NORTH ? world.maxy : icarus_position & SOUTH ? 1 : target.y - var/x_off = x != target.x ? abs(target.x - x) : INFINITY - var/y_off = y != target.y ? abs(target.y - y) : INFINITY - // Get the minimum number of steps using the rise/run shit. - var/iterations = round(min(x_off, y_off)) - 14 // We cannot fire straight from the edge since teleport thing. - - // Now we can get the location of the start. - x = target.x + (icarus_position & EAST ? iterations : icarus_position & WEST ? -iterations : 0) - y = target.y + (icarus_position & NORTH ? iterations : icarus_position & SOUTH ? -iterations : 0) - - var/turf/start = locate(x, y, target.z) - - // Now we find the corresponding turf on the other side of the level. - // Yeah, yeah. Overuse of the terinary operator. So sue me. - x = icarus_position & EAST ? 1 : icarus_position & WEST ? world.maxx : target.x - y = icarus_position & NORTH ? 1 : icarus_position & SOUTH ? world.maxy : target.y - x_off = x != target.x ? abs(target.x - x) : INFINITY - y_off = y != target.y ? abs(target.y - y) : INFINITY - iterations = round(min(x_off, y_off)) - x = target.x + (icarus_position & EAST ? -iterations : icarus_position & WEST ? iterations : 0) - y = target.y + (icarus_position & NORTH ? -iterations : icarus_position & SOUTH ? iterations : 0) - target = locate(x, y, target.z) - - // Finally fire the fucker. - var/obj/effect/meteor/small/projectile = new (start) - projectile.dest = target - projectile.name = "main gun projectile" // stealthy - projectile.hits = 6 - projectile.detonation_chance = 99 // it's a missile/cannon round thing! - - // Make sure it travels - spawn(0) - walk_towards(projectile, projectile.dest, 1) - -proc/Icarus_SetPosition(var/user) - var/global/list/directions = list("North" = 1, "North East" = 5, "East" = 4, "South East" = 6, "South" = 2, "South West" = 10, "West" = 8, "North West" = 9) - var/direction = input(user, "Where should the Icarus fire from?", "Icarus Comms") as null|anything in directions - if(!direction) - return - - icarus_position = directions[direction] diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index bd3c4be0d92..29d2b95d88e 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -162,6 +162,7 @@ var/list/debug_verbs = list ( ,/client/proc/testZAScolors_remove ,/client/proc/setup_supermatter_engine ,/client/proc/atmos_toggle_debug + ,/client/proc/spawn_tanktransferbomb ) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 0561e53791e..b5bbdb8b69f 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -520,7 +520,8 @@ Traitors and the like can also be revived with the previous role mostly intact. if(! (C.stat & (BROKEN|NOPOWER) ) ) var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc ) P.name = "'[command_name()] Update.'" - P.info = input + P.info = replacetext(input, "\n", "
") + P.update_space(P.info) P.update_icon() C.messagetitle.Add("[command_name()] Update") C.messagetext.Add(P.info) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index ecbd78b14d5..3ee7ebcdebe 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -161,6 +161,7 @@ spawn(5) // And wait a half-second, since it sounds like you can do this too fast. if(src) winset(src, null, "command=\".configure graphics-hwmode off\"") + sleep(2) // wait a bit more, possibly fixes hardware mode not re-activating right winset(src, null, "command=\".configure graphics-hwmode on\"") log_client_to_db() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7e69a279bea..ca5f210f479 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -19,7 +19,8 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set "raider" = IS_MODE_COMPILED("heist"), // 11 "diona" = 1, // 12 "loyalist" = IS_MODE_COMPILED("revolution"), // 13 - "pAI candidate" = 1, // -- TLE // 14 + "vampire" = IS_MODE_COMPILED("vampire"), // 14 + "pAI candidate" = 1, // -- TLE // 15 ) //used for alternate_option diff --git a/code/modules/client/preferences_factions.dm b/code/modules/client/preferences_factions.dm index 2293be7dd6a..404fbc98c1c 100644 --- a/code/modules/client/preferences_factions.dm +++ b/code/modules/client/preferences_factions.dm @@ -24,7 +24,7 @@ var/global/list/home_system_choices = list( "Sol", "Nyx", "Tau Ceti", - "Epsilon Ursae Majoris", + "Epsilon Ursae Minoris", "S'randarr" ) diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm index 5be7e2dcde7..3e6e94ebcec 100644 --- a/code/modules/client/preferences_gear.dm +++ b/code/modules/client/preferences_gear.dm @@ -18,7 +18,17 @@ var/global/list/gear_datums = list() //create a list of gear datums to sort for(var/type in typesof(/datum/gear)-/datum/gear) - var/datum/gear/G = new type() + var/datum/gear/G = type + if(!initial(G.display_name)) + error("Loadout - Missing display name: [G]") + continue + if(!initial(G.cost)) + error("Loadout - Missing cost: [G]") + continue + if(!initial(G.path)) + error("Loadout - Missing path definition: [G]") + continue + G = new G() var/category = (G.sort_category in sort_categories)? G.sort_category : "unknown" sort_categories[category][G.display_name] = G @@ -127,13 +137,13 @@ var/global/list/gear_datums = list() cost = 1 slot = slot_head - /datum/gear/grcap +/datum/gear/grcap display_name = "cap, grey" path = /obj/item/clothing/head/soft/grey cost = 1 slot = slot_head - /datum/gear/ocap +/datum/gear/ocap display_name = "cap, orange" path = /obj/item/clothing/head/soft/orange cost = 1 @@ -205,7 +215,7 @@ var/global/list/gear_datums = list() cost = 1 slot = slot_head - /datum/gear/bowler +/datum/gear/bowler display_name = "hat, bowler" path = /obj/item/clothing/head/bowler cost = 1 @@ -297,17 +307,18 @@ var/global/list/gear_datums = list() allowed_roles = list("Security Officer","Head of Security","Warden") /datum/gear/thugshades - display_name = "Sunglasses, Fat (Security)" + display_name = "Sunglasses, Fat" path = /obj/item/clothing/glasses/sunglasses/big cost = 1 slot = slot_glasses - allowed_roles = list("Security Officer","Head of Security","Warden") + allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain") /datum/gear/prescriptionsun display_name = "sunglasses, presciption" path = /obj/item/clothing/glasses/sunglasses/prescription cost = 2 slot = slot_glasses + allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain") // Mask diff --git a/code/modules/clothing/spacesuits/rig/modules/combat.dm b/code/modules/clothing/spacesuits/rig/modules/combat.dm index d4bd12ec4bf..ee9f16e1a24 100644 --- a/code/modules/clothing/spacesuits/rig/modules/combat.dm +++ b/code/modules/clothing/spacesuits/rig/modules/combat.dm @@ -135,8 +135,8 @@ suit_overlay_active = "mounted-taser" suit_overlay_inactive = "mounted-taser" - interface_name = "mounted energy gun" - interface_desc = "A shoulder-mounted cell-powered energy gun." + interface_name = "mounted taser" + interface_desc = "A shoulder-mounted cell-powered taser." gun_type = /obj/item/weapon/gun/energy/taser/mounted diff --git a/code/modules/clothing/spacesuits/rig/modules/ninja.dm b/code/modules/clothing/spacesuits/rig/modules/ninja.dm index 1ab60677930..96cf6a113a2 100644 --- a/code/modules/clothing/spacesuits/rig/modules/ninja.dm +++ b/code/modules/clothing/spacesuits/rig/modules/ninja.dm @@ -121,6 +121,11 @@ if(T.contains_dense_objects()) H << "You cannot teleport to a location with solid objects." + return 0 + + if(T.z != H.z || get_dist(T, get_turf(H)) > world.view) + H << "You cannot teleport to such a distant object." + return 0 phase_out(H,get_turf(H)) H.forceMove(T) diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm index 55c22bf0615..a1b772f539d 100644 --- a/code/modules/clothing/spacesuits/rig/modules/utility.dm +++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm @@ -33,6 +33,7 @@ interface_desc = "A self-sustaining plasma arc capable of cutting through walls." suit_overlay_active = "plasmacutter" suit_overlay_inactive = "plasmacutter" + use_power_cost = 0.5 device_type = /obj/item/weapon/pickaxe/plasmacutter @@ -53,6 +54,7 @@ interface_desc = "A diamond-tipped industrial drill." suit_overlay_active = "mounted-drill" suit_overlay_inactive = "mounted-drill" + use_power_cost = 0.1 device_type = /obj/item/weapon/pickaxe/diamonddrill diff --git a/code/modules/clothing/spacesuits/rig/suits/ert.dm b/code/modules/clothing/spacesuits/rig/suits/ert.dm index c46b019a4d2..88c33cee261 100644 --- a/code/modules/clothing/spacesuits/rig/suits/ert.dm +++ b/code/modules/clothing/spacesuits/rig/suits/ert.dm @@ -1,6 +1,6 @@ /obj/item/clothing/head/helmet/space/rig/ert light_overlay = "helmet_light_dual" - camera_networks = list("ERT") + camera_networks = list(NETWORK_ERT) /obj/item/weapon/rig/ert name = "ERT-C hardsuit control module" diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm index 270e7a37613..3eeb7988755 100644 --- a/code/modules/clothing/spacesuits/rig/suits/light.dm +++ b/code/modules/clothing/spacesuits/rig/suits/light.dm @@ -40,7 +40,7 @@ airtight = 0 seal_delay = 5 //not being vaccum-proof has an upside I guess - + helm_type = /obj/item/clothing/head/lightrig/hacker chest_type = /obj/item/clothing/suit/lightrig/hacker glove_type = /obj/item/clothing/gloves/lightrig/hacker diff --git a/code/modules/clothing/spacesuits/rig/suits/station.dm b/code/modules/clothing/spacesuits/rig/suits/station.dm index 50a18c9ace1..e3ac8906d3c 100644 --- a/code/modules/clothing/spacesuits/rig/suits/station.dm +++ b/code/modules/clothing/spacesuits/rig/suits/station.dm @@ -1,23 +1,23 @@ /obj/item/clothing/head/helmet/space/rig/industrial - camera_networks = list("Mine") + camera_networks = list(NETWORK_MINE) /obj/item/clothing/head/helmet/space/rig/ce - camera_networks = list("Engineering") + camera_networks = list(NETWORK_ENGINEERING) /obj/item/clothing/head/helmet/space/rig/eva light_overlay = "helmet_light_dual" - camera_networks = list("Engineering") + camera_networks = list(NETWORK_ENGINEERING) /obj/item/clothing/head/helmet/space/rig/hazmat light_overlay = "hardhat_light" - camera_networks = list("Research") + camera_networks = list(NETWORK_RESEARCH) /obj/item/clothing/head/helmet/space/rig/medical - camera_networks = list("Medbay") + camera_networks = list(NETWORK_MEDICAL) /obj/item/clothing/head/helmet/space/rig/hazard light_overlay = "helmet_light_dual" - camera_networks = list("Security") + camera_networks = list(NETWORK_SECURITY) /obj/item/weapon/rig/industrial name = "industrial suit control module" diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index 0509bf3d86a..87c0b7e4450 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -5,10 +5,13 @@ use_power = 1 active_power_usage = 8000 //8kW for the scenery + 500W per holoitem + + circuit = /obj/item/weapon/circuitboard/holodeckcontrol + var/item_power_usage = 500 var/area/linkedholodeck = null - var/area/target = null + var/linkedholodeck_area var/active = 0 var/list/holographic_objs = list() var/list/holographic_mobs = list() @@ -17,34 +20,39 @@ var/mob/last_to_emag = null var/last_change = 0 var/last_gravity_change = 0 - var/list/supported_programs = list( \ - "Empty Court" = "emptycourt", \ - "Basketball Court" = "basketball", \ - "Thunderdome Court" = "thunderdomecourt", \ - "Boxing Ring"="boxingcourt", \ - "Beach" = "beach", \ - "Desert" = "desert", \ - "Space" = "space", \ - "Picnic Area" = "picnicarea", \ - "Snow Field" = "snowfield", \ - "Theatre" = "theatre", \ - "Meeting Hall" = "meetinghall", \ - "Courtroom" = "courtroom" \ - ) - var/list/restricted_programs = list("Atmospheric Burn Simulation" = "burntest", "Wildlife Simulation" = "wildlifecarp") + var/list/supported_programs + var/list/restricted_programs + +/obj/machinery/computer/HolodeckControl/New() + ..() + linkedholodeck = locate(linkedholodeck_area) + supported_programs = list() + restricted_programs = list() /obj/machinery/computer/HolodeckControl/attack_ai(var/mob/user as mob) return src.attack_hand(user) /obj/machinery/computer/HolodeckControl/attack_hand(var/mob/user as mob) - if(..()) - return + return 1 user.set_machine(src) var/dat dat += "Holodeck Control System
" dat += "
Current Loaded Programs:
" + + if(!linkedholodeck) + dat += "
Warning: Unable to locate holodeck.
" + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + + if(!supported_programs.len) + dat += "
Warning: No supported holo-programs loaded.
" + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + for(var/prog in supported_programs) dat += "([prog])
" @@ -82,10 +90,8 @@ user << browse(dat, "window=computer;size=400x500") onclose(user, "computer") - return - /obj/machinery/computer/HolodeckControl/Topic(href, href_list) if(..()) return 1 @@ -131,8 +137,9 @@ user << "You vastly increase projector power and override the safety and security protocols." user << "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call Nanotrasen maintenance and do not use the simulator." log_game("[key_name(usr)] emagged the Holodeck Control Computer") - src.updateUsrDialog() - return + src.updateUsrDialog() + else + ..() /obj/machinery/computer/HolodeckControl/proc/update_projections() if (safety_disabled) @@ -149,10 +156,6 @@ if (last_to_emag) C.friends = list(last_to_emag) -/obj/machinery/computer/HolodeckControl/New() - ..() - linkedholodeck = locate(/area/holodeck/alphadeck) - //This could all be done better, but it works for now. /obj/machinery/computer/HolodeckControl/Destroy() emergencyShutdown() @@ -345,3 +348,28 @@ active = 0 use_power = 1 + +/obj/machinery/computer/HolodeckControl/Exodus + linkedholodeck_area = /area/holodeck/alphadeck + +/obj/machinery/computer/HolodeckControl/Exodus/New() + ..() + supported_programs = list( + "Empty Court" = "emptycourt", + "Basketball Court" = "basketball", + "Thunderdome Court" = "thunderdomecourt", + "Boxing Ring" = "boxingcourt", + "Beach" = "beach", + "Desert" = "desert", + "Space" = "space", + "Picnic Area" = "picnicarea", + "Snow Field" = "snowfield", + "Theatre" = "theatre", + "Meeting Hall" = "meetinghall", + "Courtroom" = "courtroom" + ) + + restricted_programs = list( + "Atmospheric Burn Simulation" = "burntest", + "Wildlife Simulation" = "wildlifecarp" + ) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 83681744447..40fd541f711 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -38,6 +38,7 @@ return name = "[seed.seed_name]" + trash = seed.get_trash_type() update_icon() diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 108a242636a..011ec7a2373 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -68,6 +68,9 @@ /datum/seed/proc/get_trait(var/trait) return traits["[trait]"] +/datum/seed/proc/get_trash_type() + return trash_type + /datum/seed/proc/set_trait(var/trait,var/nval,var/ubound,var/lbound, var/degrade) if(!isnull(degrade)) nval *= degrade if(!isnull(ubound)) nval = min(nval,ubound) diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index d3971383173..79b6c5c3619 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -342,12 +342,15 @@ set category = "Object" set src in view(1) - if(labelled) - usr << "You remove the label." - labelled = null - update_icon() - else - usr << "There is no label to remove." + if(!usr.canmove || usr.stat || usr.restrained()) + return + if(ishuman(usr) || istype(usr, /mob/living/silicon/robot)) + if(labelled) + usr << "You remove the label." + labelled = null + update_icon() + else + usr << "There is no label to remove." return /obj/machinery/portable_atmospherics/hydroponics/verb/setlight() @@ -355,10 +358,14 @@ set category = "Object" set src in view(1) - var/new_light = input("Specify a light level.") as null|anything in list(0,1,2,3,4,5,6,7,8,9,10) - if(new_light) - tray_light = new_light - usr << "You set the tray to a light level of [tray_light] lumens." + if(!usr.canmove || usr.stat || usr.restrained()) + return + if(ishuman(usr) || istype(usr, /mob/living/silicon/robot)) + var/new_light = input("Specify a light level.") as null|anything in list(0,1,2,3,4,5,6,7,8,9,10) + if(new_light) + tray_light = new_light + usr << "You set the tray to a light level of [tray_light] lumens." + return /obj/machinery/portable_atmospherics/hydroponics/proc/check_level_sanity() //Make sure various values are sane. @@ -611,12 +618,14 @@ set name = "Toggle Tray Lid" set category = "Object" set src in view(1) - close_lid(usr) + if(!usr.canmove || usr.stat || usr.restrained()) + return + + if(ishuman(usr) || istype(usr, /mob/living/silicon/robot)) + close_lid(usr) + return /obj/machinery/portable_atmospherics/hydroponics/proc/close_lid(var/mob/living/user) - if(!user || user.stat || user.restrained()) - return - closed_system = !closed_system user << "You [closed_system ? "close" : "open"] the tray's lid." update_icon() diff --git a/code/modules/lighting/light_source.dm b/code/modules/lighting/light_source.dm index 2acddb4d298..3675cd945c3 100644 --- a/code/modules/lighting/light_source.dm +++ b/code/modules/lighting/light_source.dm @@ -1,3 +1,5 @@ +//So much copypasta in this file, supposedly in the name of performance. If you change anything make sure to consider other places where the code may have been copied. + /datum/light_source var/atom/top_atom var/atom/source_atom @@ -11,9 +13,10 @@ var/lum_g var/lum_b - var/tmp/old_lum_r - var/tmp/old_lum_g - var/tmp/old_lum_b + //hold onto the actual applied lum values so we can undo them when the lighting changes + var/tmp/applied_lum_r + var/tmp/applied_lum_g + var/tmp/applied_lum_b var/list/effect_str var/list/effect_turf @@ -107,11 +110,6 @@ if(light_range && light_power && !applied) . = 1 - if(. || source_atom.light_color != light_color)//Save the old lumcounts if we need to update, if the colour changed DO IT BEFORE we parse the colour and LOSE the old lumcounts! - old_lum_r = lum_r - old_lum_g = lum_g - old_lum_b = lum_b - if(source_atom.light_color != light_color) light_color = source_atom.light_color parse_light_color() @@ -149,6 +147,12 @@ /datum/light_source/proc/apply_lum() applied = 1 + + //Keep track of the last applied lum values so that the lighting can be reversed + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + if(istype(source_turf)) FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) if(T.lighting_overlay) @@ -164,9 +168,9 @@ effect_str += strength T.lighting_overlay.update_lumcount( - lum_r * strength, - lum_g * strength, - lum_b * strength + applied_lum_r * strength, + applied_lum_g * strength, + applied_lum_b * strength ) else @@ -188,7 +192,11 @@ if(T.lighting_overlay) var/str = effect_str[i] - T.lighting_overlay.update_lumcount(-str * old_lum_r, -str * old_lum_g, -str * old_lum_b) + T.lighting_overlay.update_lumcount( + -str * applied_lum_r, + -str * applied_lum_g, + -str * applied_lum_b + ) i++ @@ -218,9 +226,9 @@ effect_str += . T.lighting_overlay.update_lumcount( - lum_r * ., - lum_g * ., - lum_b * . + applied_lum_r * ., + applied_lum_g * ., + applied_lum_b * . ) else @@ -241,7 +249,7 @@ if(T.lighting_overlay) var/str = effect_str[idx] - T.lighting_overlay.update_lumcount(-str * lum_r, -str * lum_g, -str * lum_b) + T.lighting_overlay.update_lumcount(-str * applied_lum_r, -str * applied_lum_g, -str * applied_lum_b) effect_turf.Cut(idx, idx + 1) effect_str.Cut(idx, idx + 1) @@ -279,10 +287,12 @@ effect_str[idx] = . + //Since the applied_lum values are what are (later) removed by remove_lum. + //Anything we apply to the lighting overlays HAS to match what remove_lum uses. T.lighting_overlay.update_lumcount( - lum_r * ., - lum_g * ., - lum_b * . + applied_lum_r * ., + applied_lum_g * ., + applied_lum_b * . ) #undef LUM_FALLOFF diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index a5a0608f06f..f146e421654 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -11,7 +11,7 @@ recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]") - if(integrity>=100) + if(integrity>=50) recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index c2a2b56ab7b..0e6c03b1997 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -45,7 +45,7 @@ /obj/item/stack/material/proc/update_strings() // Update from material datum. singular_name = material.sheet_singular_name - + if(amount>1) name = "[material.use_name] [material.sheet_plural_name]" desc = "A stack of [material.use_name] [material.sheet_plural_name]." @@ -64,9 +64,10 @@ var/obj/item/stack/material/M = S if(!istype(M) || material.name != M.material.name) return 0 - ..(S,tamount,1) + var/transfer = ..(S,tamount,1) if(src) update_strings() if(M) M.update_strings() + return transfer /obj/item/stack/material/attack_self(var/mob/user) if(!material.build_windows(user, src)) diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index 46ce8ea445d..ffd1e6ffbc8 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -128,8 +128,6 @@ var/list/name_to_material var/obj/item/stack/S = new rod_product(get_turf(user)) S.add_fingerprint(user) S.add_to_stacks(user) - if(!(user.l_hand && user.r_hand)) - user.put_in_hands(S) /material/proc/build_wired_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) if(!wire_product) @@ -553,7 +551,7 @@ var/list/name_to_material name = "wood" stack_type = /obj/item/stack/material/wood icon_colour = "#824B28" - integrity = 25 + integrity = 50 icon_base = "solid" explosion_resistance = 2 shard_type = SHARD_SPLINTER diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 2b4a290e2bf..63f60c6f239 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -149,8 +149,10 @@ Works together with spawning an observer, noted above. if(key) var/mob/dead/observer/ghost = new(src) //Transfer safety to observer spawning proc. ghost.can_reenter_corpse = can_reenter_corpse - ghost.timeofdeath = src.timeofdeath //BS12 EDIT + ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time ghost.key = key + if(ghost.client) + ghost.client.time_died_as_mouse = ghost.timeofdeath if(ghost.client && !ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing! return ghost @@ -217,7 +219,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return mind.current.ajourn=0 mind.current.key = key - mind.current.aghosted = null + mind.current.teleop = null if(!admin_ghosted) announce_ghost_joinleave(mind, 0, "They now occupy their body again.") return 1 @@ -422,6 +424,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!MayRespawn(1)) return + var/turf/T = get_turf(src) + if(!T || (T.z in config.admin_levels)) + src << "You may not spawn as a mouse on this Z-level." + return + var/timedifference = world.time - client.time_died_as_mouse if(client.time_died_as_mouse && timedifference <= mouse_respawn_time * 600) var/timedifference_text @@ -437,8 +444,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/mob/living/simple_animal/mouse/host var/obj/machinery/atmospherics/unary/vent_pump/vent_found var/list/found_vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/v in world) - if(!v.welded && v.z == src.z) + for(var/obj/machinery/atmospherics/unary/vent_pump/v in machines) + if(!v.welded && v.z == T.z) found_vents.Add(v) if(found_vents.len) vent_found = pick(found_vents) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index d820e89cf97..8944bc31099 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -103,64 +103,34 @@ var/list/slot_equipment_priority = list( \ //Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success. /mob/proc/put_in_l_hand(var/obj/item/W) - if(lying) return 0 - if(!istype(W)) return 0 - if(!l_hand) - W.forceMove(src) //TODO: move to equipped? - l_hand = W - W.layer = 20 //TODO: move to equipped? -// l_hand.screen_loc = ui_lhand - W.equipped(src,slot_l_hand) - if(client) client.screen |= W - if(pulling == W) stop_pulling() - update_inv_l_hand() - return 1 - return 0 + if(lying || !istype(W)) + return 0 + return 1 //Puts the item into your r_hand if possible and calls all necessary triggers/updates. returns 1 on success. /mob/proc/put_in_r_hand(var/obj/item/W) - if(lying) return 0 - if(!istype(W)) return 0 - if(!r_hand) - W.forceMove(src) - r_hand = W - W.layer = 20 -// r_hand.screen_loc = ui_rhand - W.equipped(src,slot_r_hand) - if(client) client.screen |= W - if(pulling == W) stop_pulling() - update_inv_r_hand() - return 1 - return 0 + if(lying || !istype(W)) + return 0 + return 1 //Puts the item into our active hand if possible. returns 1 on success. /mob/proc/put_in_active_hand(var/obj/item/W) - if(hand) return put_in_l_hand(W) - else return put_in_r_hand(W) + return 0 // Moved to human procs because only they need to use hands. //Puts the item into our inactive hand if possible. returns 1 on success. /mob/proc/put_in_inactive_hand(var/obj/item/W) - if(hand) return put_in_r_hand(W) - else return put_in_l_hand(W) + return 0 // As above. //Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns 1 on success. //If both fail it drops it on the floor and returns 0. //This is probably the main one you need to know :) /mob/proc/put_in_hands(var/obj/item/W) - if(!W) return 0 - if(put_in_active_hand(W)) - update_inv_l_hand() - update_inv_r_hand() - return 1 - else if(put_in_inactive_hand(W)) - update_inv_l_hand() - update_inv_r_hand() - return 1 - else - W.forceMove(get_turf(src)) - W.layer = initial(W.layer) - W.dropped() + if(!W) return 0 + W.forceMove(get_turf(src)) + W.layer = initial(W.layer) + W.dropped() + return 0 // Removes an item from inventory and places it in the target atom. // If canremove or other conditions need to be checked then use unEquip instead. diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm index 03ab8ea2970..2d058e3b780 100644 --- a/code/modules/mob/language/language.dm +++ b/code/modules/mob/language/language.dm @@ -123,7 +123,7 @@ var/datum/language/new_language = all_languages[language] - if(!istype(new_language) || new_language in languages) + if(!istype(new_language) || (new_language in languages)) return 0 languages.Add(new_language) @@ -188,4 +188,10 @@ else return ..() +/proc/transfer_languages(var/mob/source, var/mob/target, var/except_flags) + for(var/datum/language/L in source.languages) + if(L.flags & except_flags) + continue + target.add_language(L.name) + #undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index 73310108523..57f907ec25d 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -26,6 +26,8 @@ var/blood = 1 var/list/target_types = list() + var/maximum_search_range = 7 + /mob/living/bot/cleanbot/New() ..() get_targets() @@ -36,6 +38,25 @@ if(radio_controller) radio_controller.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS) +/mob/living/bot/cleanbot/proc/handle_target() + if(loc == target.loc) + if(!cleaning) + UnarmedAttack(target) + return 1 + if(!path.len) +// spawn(0) + path = AStar(loc, target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard) + if(!path) + custom_emote(2, "[src] can't reach the target and is giving up.") + target = null + path = list() + return + if(path.len) + step_to(src, path[1]) + path -= path[1] + return 1 + return + /mob/living/bot/cleanbot/Life() ..() @@ -46,7 +67,7 @@ return if(cleaning) return - + if(!screwloose && !oddbutton && prob(5)) custom_emote(2, "makes an excited beeping booping sound!") @@ -74,65 +95,64 @@ spawn(600) ignorelist -= gib - if(!target) // Find a target - for(var/obj/effect/decal/cleanable/D in view(7, src)) - if(D in ignorelist) - continue - for(var/T in target_types) - if(istype(D, T)) - target = D - patrol_path = list() + // Find a target + + if(pulledby) // Don't wiggle if someone pulls you + patrol_path = list() + return - if(!target) // No targets in range - if(!should_patrol) - return + var/found_spot + search_loop: + for(var/i=0, i <= maximum_search_range, i++) + for(var/obj/effect/decal/cleanable/D in view(i, src)) + if(D in ignorelist) + continue + for(var/T in target_types) + if(istype(D, T)) + patrol_path = list() + target = D + found_spot = handle_target() + if (found_spot) + break search_loop + else + target = null + continue // no need to check the other types - if(!patrol_path || !patrol_path.len) - if(!signal_sent || signal_sent > world.time + 200) // Waited enough or didn't send yet - var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq) - if(!frequency) - return - closest_dist = 9999 - next_dest = null - next_dest_loc = null - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = 1 - signal.data = list("findbeakon" = "patrol") - frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) - signal_sent = world.time - else - if(next_dest) - next_dest_loc = listener.memorized[next_dest] - if(next_dest_loc) - patrol_path = AStar(loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id = botcard, exclude = null) - signal_sent = 0 - else - if(pulledby) // Don't wiggle if someone pulls you - patrol_path = list() + if(!found_spot && !target) // No targets in range + if(!patrol_path || !patrol_path.len) + if(!signal_sent || signal_sent > world.time + 200) // Waited enough or didn't send yet + var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq) + if(!frequency) return - if(patrol_path[1] == loc) - patrol_path -= patrol_path[1] - var/moved = step_towards(src, patrol_path[1]) - if(moved) - patrol_path -= patrol_path[1] - if(target) - if(loc == target.loc) - if(!cleaning) - UnarmedAttack(target) + + closest_dist = 9999 + next_dest = null + next_dest_loc = null + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = 1 + signal.data = list("findbeakon" = "patrol") + frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS) + signal_sent = world.time + else + if(next_dest) + next_dest_loc = listener.memorized[next_dest] + if(next_dest_loc) + patrol_path = AStar(loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id = botcard, exclude = null) + signal_sent = 0 + else + if(pulledby) // Don't wiggle if someone pulls you + patrol_path = list() return - if(!path.len) - spawn(0) - path = AStar(loc, target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard) - if(!path) - path = list() - return - if(path.len) - step_to(src, path[1]) - path -= path[1] - return + if(patrol_path[1] == loc) + patrol_path -= patrol_path[1] + var/moved = step_towards(src, patrol_path[1]) + if(moved) + patrol_path -= patrol_path[1] + + /mob/living/bot/cleanbot/UnarmedAttack(var/obj/effect/decal/cleanable/D, var/proximity) if(!..()) @@ -145,7 +165,7 @@ return cleaning = 1 - custom_emote(2, "begins to clean up the [D]") + custom_emote(2, "begins to clean up \the [D]") update_icons() var/cleantime = istype(D, /obj/effect/decal/cleanable/dirt) ? 10 : 50 if(do_after(src, cleantime)) @@ -155,6 +175,8 @@ if(!D) return qdel(D) + if(D == target) + target = null cleaning = 0 update_icons() diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm index b467b88cd2e..66cdd2f75e5 100644 --- a/code/modules/mob/living/carbon/breathe.dm +++ b/code/modules/mob/living/carbon/breathe.dm @@ -49,7 +49,7 @@ breath = environment.remove_volume(volume_needed) handle_chemical_smoke(environment) //handle chemical smoke while we're at it - if(breath) + if(breath && breath.total_moles) //handle mask filtering if(istype(wear_mask, /obj/item/clothing/mask) && breath) var/obj/item/clothing/mask/M = wear_mask @@ -60,13 +60,15 @@ //Handle possble chem smoke effect /mob/living/carbon/proc/handle_chemical_smoke(var/datum/gas_mixture/environment) + if(species && environment.return_pressure() < species.breath_pressure/5) + return //pressure is too low to even breathe in. if(wear_mask && (wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT)) return for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) - smoke.reagents.trans_to_mob(src, 10, CHEM_INGEST, copy = 1) - //maybe check air pressure here or something to see if breathing in smoke is even possible. + smoke.reagents.trans_to_mob(src, 5, CHEM_INGEST, copy = 1) + smoke.reagents.trans_to_mob(src, 5, CHEM_BLOOD, copy = 1) // I dunno, maybe the reagents enter the blood stream through the lungs? break // If they breathe in the nasty stuff once, no need to continue checking diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 1a7085d61a5..d04e79b8ee7 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -205,7 +205,7 @@ if(40 to INFINITY) status += "peeling away" - if(org.status & ORGAN_DESTROYED) + if(org.is_stump()) status += "MISSING" if(org.status & ORGAN_MUTATED) status += "weirdly shapen" @@ -260,7 +260,7 @@ var/show_ssd var/mob/living/carbon/human/H = src if(istype(H)) show_ssd = H.species.show_ssd - if(show_ssd && !client && !aghosted) + if(show_ssd && !client && !teleop) M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ "You shake [src], but they do not respond... Maybe they have S.S.D?") else if(lying || src.sleeping) diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm index 579321a5128..5c4be494ee5 100644 --- a/code/modules/mob/living/carbon/give.dm +++ b/code/modules/mob/living/carbon/give.dm @@ -1,53 +1,42 @@ -mob/living/carbon/verb/give(var/mob/living/carbon/target in view(1)-usr) +/mob/living/carbon/human/verb/give(var/mob/living/target in view(1)-usr) set category = "IC" set name = "Give" - if(!istype(target) || target.stat == 2 || usr.stat == 2|| target.client == null) + + // TODO : Change to incapacitated() on merge. + if(usr.stat || usr.lying || usr.resting || usr.buckled) return - var/obj/item/I - if(!usr.hand && usr.r_hand == null) - usr << "You don't have anything in your right hand to give to [target.name]" + if(!istype(target) || target.stat || target.lying || target.resting || target.buckled || target.client == null) return - if(usr.hand && usr.l_hand == null) - usr << "You don't have anything in your left hand to give to [target.name]" - return - if(usr.hand) - I = usr.l_hand - else if(!usr.hand) - I = usr.r_hand + + var/obj/item/I = usr.get_active_hand() if(!I) + I = usr.get_inactive_hand() + if(!I) + usr << "You don't have anything in your hands to give to \the [target]." return - if(target.r_hand == null || target.l_hand == null) - switch(alert(target,"[usr] wants to give you \a [I]?",,"Yes","No")) - if("Yes") - if(!I) - return - if(!Adjacent(usr)) - usr << "You need to stay in reaching distance while giving an object." - target << "[usr.name] moved too far away." - return - if((usr.hand && usr.l_hand != I) || (!usr.hand && usr.r_hand != I)) - usr << "You need to keep the item in your active hand." - target << "[usr.name] seem to have given up on giving \the [I.name] to you." - return - if(target.r_hand != null && target.l_hand != null) - target << "Your hands are full." - usr << "Their hands are full." - return - else - usr.drop_item() - if(target.r_hand == null) - target.r_hand = I - else - target.l_hand = I - I.loc = target - I.layer = 20 - I.add_fingerprint(target) - target.update_inv_l_hand() - target.update_inv_r_hand() - usr.update_inv_l_hand() - usr.update_inv_r_hand() - target.visible_message("[usr.name] handed \the [I.name] to [target.name].") - if("No") - target.visible_message("[usr.name] tried to hand [I.name] to [target.name] but [target.name] didn't want it.") - else - usr << "[target.name]'s hands are full." + + if(alert(target,"[usr] wants to give you \a [I]. Will you accept it?",,"No","Yes") == "No") + target.visible_message("\The [usr] tried to hand \the [I] to \the [target], \ + but \the [target] didn't want it.") + return + + if(!I) return + + if(!Adjacent(target)) + usr << "You need to stay in reaching distance while giving an object." + target << "\The [usr] moved too far away." + return + + if(I.loc != usr || (usr.l_hand != I && usr.r_hand != I)) + usr << "You need to keep the item in your hands." + target << "\The [usr] seems to have given up on passing \the [I] to you." + return + + if(target.r_hand != null && target.l_hand != null) + target << "Your hands are full." + usr << "Their hands are full." + return + + if(usr.unEquip(I)) + target.put_in_hands(I) // If this fails it will just end up on the floor, but that's fitting for things like dionaea. + target.visible_message("\The [usr] handed \the [I] to \the [target].") diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index f6727e69a11..96e1739da6c 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -262,43 +262,36 @@ msg += "[t_He] [t_is] [species.show_ssd].\n" var/list/wound_flavor_text = list() - var/list/is_destroyed = list() var/list/is_bleeding = list() for(var/organ_tag in species.has_limbs) var/list/organ_data = species.has_limbs[organ_tag] var/organ_descriptor = organ_data["descriptor"] - is_destroyed["organ_descriptor"] = 1 var/obj/item/organ/external/E = organs_by_name[organ_tag] if(!E) - wound_flavor_text["[organ_descriptor]"] = "[t_He] is missing [t_his] [organ_descriptor].\n" + wound_flavor_text["[organ_descriptor]"] = "[t_He] [t_is] missing [t_his] [organ_descriptor].\n" else if(E.is_stump()) - wound_flavor_text["[organ_descriptor]"] = "[t_He] has a stump where [t_his] [organ_descriptor] should be.\n" + wound_flavor_text["[organ_descriptor]"] = "[t_He] [t_has] a stump where [t_his] [organ_descriptor] should be.\n" else - is_destroyed["organ_descriptor"] = 0 continue for(var/obj/item/organ/external/temp in organs) if(temp) - if(temp.status & ORGAN_DESTROYED) - is_destroyed["[temp.name]"] = 1 - wound_flavor_text["[temp.name]"] = "[t_He] [t_is] missing [t_his] [temp.name].\n" - continue if(temp.status & ORGAN_ROBOT) if(!(temp.brute_dam + temp.burn_dam)) if(!species.flags & IS_SYNTHETIC) wound_flavor_text["[temp.name]"] = "[t_He] [t_has] a robot [temp.name]!\n" continue else - wound_flavor_text["[temp.name]"] = "[t_He] has a robot [temp.name]. It has[temp.get_wounds_desc()]!\n" + wound_flavor_text["[temp.name]"] = "[t_He] [t_has] a robot [temp.name]. It has[temp.get_wounds_desc()]!\n" else if(temp.wounds.len > 0 || temp.open) if(temp.is_stump() && temp.parent_organ && organs_by_name[temp.parent_organ]) var/obj/item/organ/external/parent = organs_by_name[temp.parent_organ] - wound_flavor_text["[temp.name]"] = "[t_He] has [temp.get_wounds_desc()] on [t_his] [parent.name].
" + wound_flavor_text["[temp.name]"] = "[t_He] [t_has] [temp.get_wounds_desc()] on [t_his] [parent.name].
" else - wound_flavor_text["[temp.name]"] = "[t_He] has [temp.get_wounds_desc()] on [t_his] [temp.name].
" + wound_flavor_text["[temp.name]"] = "[t_He] [t_has] [temp.get_wounds_desc()] on [t_his] [temp.name].
" if(temp.status & ORGAN_BLEEDING) is_bleeding["[temp.name]"] = "[capitalize(t_his)] [temp.name] is bleeding!
" else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index cbc8faabd7b..20fd7b07f8f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -79,6 +79,8 @@ stat(null, "Suit charge: [cell_status]") if(mind) + if(mind.vampire) + stat("Blood", mind.vampire.bloodusable) if(mind.changeling) stat("Chemical Storage", mind.changeling.chem_charges) stat("Genetic Damage Time", mind.changeling.geneticdamage) @@ -342,7 +344,7 @@ //Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable /mob/living/carbon/human/proc/get_face_name() var/obj/item/organ/external/head = get_organ("head") - if(!head || head.disfigured || (head.status & ORGAN_DESTROYED) || !real_name || (HUSK in mutations) ) //disfigured. use id-name if possible + if(!head || head.disfigured || head.is_stump() || !real_name || (HUSK in mutations) ) //disfigured. use id-name if possible return "Unknown" return real_name @@ -967,7 +969,7 @@ if(L && !L.is_bruised()) src.custom_pain("You feel a stabbing pain in your chest!", 1) - L.damage = L.min_bruised_damage + L.bruise() /* /mob/living/carbon/human/verb/simulate() @@ -1165,10 +1167,6 @@ else return 0 - mob_bump_flag = species.bump_flag - mob_swap_flags = species.swap_flags - mob_push_flags = species.push_flags - /mob/living/carbon/human/proc/bloody_doodle() set category = "IC" set name = "Write in blood" @@ -1273,11 +1271,10 @@ if(C.body_parts_covered & FEET) feet_exposed = 0 - flavor_text = flavor_texts["general"] - flavor_text += "\n\n" + flavor_text = "" for (var/T in flavor_texts) if(flavor_texts[T] && flavor_texts[T] != "") - if((T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed)) + if((T == "general") || (T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed)) flavor_text += flavor_texts[T] flavor_text += "\n\n" if(!shrink) @@ -1384,7 +1381,49 @@ /mob/living/carbon/human/MouseDrop(var/atom/over_object) var/mob/living/carbon/human/H = over_object - if(holder_type && a_intent == "help" && H.a_intent == "help" && istype(H) && !issmall(H) && Adjacent(H)) + if(holder_type && a_intent == I_HELP && istype(H) && H == usr && H.a_intent == I_HELP && !issmall(H) && Adjacent(H)) get_scooped(H) return return ..() + +//Puts the item into our active hand if possible. returns 1 on success. +/mob/living/carbon/human/put_in_active_hand(var/obj/item/W) + return (hand ? put_in_l_hand(W) : put_in_r_hand(W)) + +//Puts the item into our inactive hand if possible. returns 1 on success. +/mob/living/carbon/human/put_in_inactive_hand(var/obj/item/W) + return (hand ? put_in_r_hand(W) : put_in_l_hand(W)) + +/mob/living/carbon/human/put_in_hands(var/obj/item/W) + if(!W) + return 0 + if(put_in_active_hand(W)) + update_inv_l_hand() + update_inv_r_hand() + return 1 + else if(put_in_inactive_hand(W)) + update_inv_l_hand() + update_inv_r_hand() + return 1 + else + return ..() + +/mob/living/carbon/human/put_in_l_hand(var/obj/item/W) + if(!..() || l_hand) + return 0 + W.forceMove(src) + l_hand = W + W.equipped(src,slot_l_hand) + W.add_fingerprint(src) + update_inv_l_hand() + return 1 + +/mob/living/carbon/human/put_in_r_hand(var/obj/item/W) + if(!..() || r_hand) + return 0 + W.forceMove(src) + r_hand = W + W.equipped(src,slot_r_hand) + W.add_fingerprint(src) + update_inv_r_hand() + return 1 diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 24892c6d43d..d1161585254 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -108,6 +108,31 @@ return 1 if(I_HURT) + //Vampire code + if(H.zone_sel && M.zone_sel.selecting == "head") + if(H.mind && H.mind.vampire && !H.mind.vampire.draining) + if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH))) + H << "\red Remove their mask!" + return 0 + if((H.head && (H.head.flags & HEADCOVERSMOUTH)) || (H.wear_mask && (H.wear_mask.flags & MASKCOVERSMOUTH))) + H << "\red Remove your mask!" + return 0 + if(mind && mind.vampire) + H << "\red Your fangs fail to pierce [src.name]'s cold flesh" + return 0 + if(get_species() == "Machine") + H << "\red They have no blood" + return 0 + //we're good to suck the blood, blaah + //and leave an attack log + H.attack_log += text("\[[time_stamp()]\] Bit [src.name] ([src.ckey]) in the neck and draining their blood") + src.attack_log += text("\[[time_stamp()]\] Has been bit in the neck by [H.name] ([H.ckey])") + msg_admin_attack("[key_name_admin(H)] bit [key_name_admin(src)] in the neck - JMP") + H.handle_bloodsucking(src) + // var/datum/organ/external/affecting = get_organ(src.zone_sel.selecting) + // affecting.take_damage(10,0,1,0,"dual puncture marks") //this does not work and causes runtimes. + return + //end vampire codes if(!istype(H)) attack_generic(H,rand(1,3),"punched") @@ -119,7 +144,7 @@ var/hit_zone = H.zone_sel.selecting var/obj/item/organ/external/affecting = get_organ(hit_zone) - if(!affecting || affecting.is_stump() || (affecting.status & ORGAN_DESTROYED)) + if(!affecting || affecting.is_stump()) M << "They are missing that limb!" return 1 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 0de5729ec99..5facabb6bc0 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -182,7 +182,6 @@ emp_act if(!O) continue O.emp_act(severity) for(var/obj/item/organ/external/O in organs) - if(O.status & ORGAN_DESTROYED) continue O.emp_act(severity) for(var/obj/item/organ/I in O.internal_organs) if(I.robotic == 0) continue @@ -204,7 +203,7 @@ emp_act var/obj/item/organ/external/affecting = get_organ(target_zone) - if (!affecting || (affecting.status & ORGAN_DESTROYED) || affecting.is_stump()) + if (!affecting || affecting.is_stump()) user << "They are missing that limb!" return diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index f4b28d2b6b0..d660d766a30 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -28,7 +28,7 @@ if(istype(buckled, /obj/structure/bed/chair/wheelchair)) for(var/organ_name in list("l_hand","r_hand","l_arm","r_arm")) var/obj/item/organ/external/E = get_organ(organ_name) - if(!E || (E.status & ORGAN_DESTROYED)) + if(!E || E.is_stump()) tally += 4 if(E.status & ORGAN_SPLINTED) tally += 0.5 @@ -40,9 +40,9 @@ for(var/organ_name in list("l_foot","r_foot","l_leg","r_leg")) var/obj/item/organ/external/E = get_organ(organ_name) - if(!E || (E.status & ORGAN_DESTROYED)) + if(!E || E.is_stump()) tally += 4 - if(E.status & ORGAN_SPLINTED) + else if(E.status & ORGAN_SPLINTED) tally += 0.5 else if(E.status & ORGAN_BROKEN) tally += 1.5 diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index 8598ce04b35..123aa684c5f 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -70,7 +70,7 @@ for(var/limb_tag in list("l_leg","r_leg","l_foot","r_foot")) var/obj/item/organ/external/E = organs_by_name[limb_tag] - if(!E || (E.status & (ORGAN_DESTROYED|ORGAN_DEAD))) + if(!E || (E.status & (ORGAN_MUTATED|ORGAN_DEAD)) || E.is_stump()) //should just be !E.is_usable() here but dislocation screws that up. stance_damage += 2 // let it fail even if just foot&leg else if (E.is_malfunctioning()) //malfunctioning only happens intermittently so treat it as a missing limb when it procs diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm index 50f46b4bb41..1728b61008d 100644 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -224,11 +224,14 @@ set name = "Split" set desc = "Split your humanoid form into its constituent nymphs." set category = "Abilities" + diona_split_into_nymphs(5) // Separate proc to void argments being supplied when used as a verb +/mob/living/carbon/human/proc/diona_split_into_nymphs(var/number_of_resulting_nymphs) var/turf/T = get_turf(src) var/mob/living/carbon/alien/diona/S = new(T) S.set_dir(dir) + transfer_languages(src, S) if(mind) mind.transfer_to(S) @@ -239,20 +242,18 @@ for(var/mob/living/carbon/alien/diona/D in src) nymphs++ - D.loc = T + D.forceMove(T) + transfer_languages(src, D, WHITELISTED|RESTRICTED) D.set_dir(pick(NORTH, SOUTH, EAST, WEST)) - if(nymphs < 5) - for(var/i in nymphs to 4) + if(nymphs < number_of_resulting_nymphs) + for(var/i in nymphs to (number_of_resulting_nymphs - 1)) var/mob/M = new /mob/living/carbon/alien/diona(T) + transfer_languages(src, M, WHITELISTED|RESTRICTED) M.set_dir(pick(NORTH, SOUTH, EAST, WEST)) - for(var/obj/item/W in src) drop_from_inventory(W) visible_message("\The [src] quivers slightly, then splits apart with a wet slithering noise.") - qdel(src) - - diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index c3b115e4f92..420447e16d4 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -1,15 +1,7 @@ /* Add fingerprints to items when we put them in our hands. This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically. - */ -/mob/living/carbon/human/put_in_l_hand(var/obj/item/W) - . = ..() - if(.) W.add_fingerprint(src) - -/mob/living/carbon/human/put_in_r_hand(var/obj/item/W) - . = ..() - if(.) W.add_fingerprint(src) /mob/living/carbon/human/verb/quick_equip() set name = "quick-equip" @@ -41,7 +33,7 @@ This saves us from having to call add_fingerprint() any time something is put in /mob/living/carbon/human/proc/has_organ(name) var/obj/item/organ/external/O = organs_by_name[name] - return (O && !(O.status & ORGAN_DESTROYED) && !O.is_stump()) + return (O && !O.is_stump()) /mob/living/carbon/human/proc/has_organ_for_slot(slot) switch(slot) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index b9f5b513e81..e7fa1ef4ab3 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -130,6 +130,8 @@ for(var/obj/item/weapon/grab/G in src) G.process() + if(mind && mind.vampire) + handle_vampire() // Calculate how vulnerable the human is to under- and overpressure. // Returns 0 (equals 0 %) if sealed in an undamaged suit, 1 if unprotected (equals 100%). // Suitdamage can modifiy this in 10% steps. @@ -364,12 +366,24 @@ internals.icon_state = "internal0" return null + get_breath_from_environment(var/volume_needed=BREATH_VOLUME) + var/datum/gas_mixture/breath = ..() + + if(breath) + //exposure to extreme pressures can rupture lungs + var/check_pressure = breath.return_pressure() + if(check_pressure < ONE_ATMOSPHERE / 5 || check_pressure > ONE_ATMOSPHERE * 5) + if(!is_lung_ruptured() && prob(5)) + rupture_lung() + + return breath handle_breath(datum/gas_mixture/breath) if(status_flags & GODMODE) return + //check if we actually need to process breath if(!breath || (breath.total_moles == 0) || suiciding) failed_last_breath = 1 if(suiciding) @@ -385,7 +399,7 @@ return 0 - var/safe_pressure_min = 16 // Minimum safe partial pressure of breathable gas in kPa + var/safe_pressure_min = species.breath_pressure // Minimum safe partial pressure of breathable gas in kPa // Lung damage increases the minimum safe pressure. if(species.has_organ["lungs"]) @@ -884,9 +898,9 @@ var/turf/T = loc var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T if(L) - light_amount = min(10,L.lum_r + L.lum_g + L.lum_b) - 5 //hardcapped so it's not abused by having a ton of flashlights + light_amount = min(10,L.lum_r + L.lum_g + L.lum_b) - 2 //hardcapped so it's not abused by having a ton of flashlights else - light_amount = 5 + light_amount = 1 nutrition += light_amount traumatic_shock -= light_amount @@ -941,7 +955,7 @@ if(status_flags & GODMODE) return 0 //SSD check, if a logged player is awake put them back to sleep! - if(species.show_ssd && !client && !aghosted) + if(species.show_ssd && !client && !teleop) Sleeping(2) if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP @@ -1010,6 +1024,12 @@ if( prob(2) && health && !hal_crit ) spawn(0) emote("snore") + if(mind) + if(mind.vampire) + if(istype(loc, /obj/structure/closet/coffin)) + adjustBruteLoss(-1) + adjustFireLoss(-1) + adjustToxLoss(-1) //CONSCIOUS else stat = CONSCIOUS @@ -1228,6 +1248,14 @@ see_in_dark = species.darksight see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : SEE_INVISIBLE_LIVING + if(mind && mind.vampire) + if((VAMP_VISION in mind.vampire.powers) && !(VAMP_FULL in mind.vampire.powers)) + sight |= SEE_MOBS + if((VAMP_FULL in mind.vampire.powers)) + sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING + if(XRAY in mutations) sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS see_in_dark = 8 @@ -1254,7 +1282,7 @@ if(healths) if (analgesic > 100) - healths.icon_state = "health_health_numb" + healths.icon_state = "health_numb" else switch(hal_screwyhud) if(1) healths.icon_state = "health6" diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 9f171054b98..979a4fc6034 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -60,6 +60,7 @@ // Environment tolerance/life processes vars. var/reagent_tag //Used for metabolizing reagents. + var/breath_pressure = 16 // Minimum partial pressure safe for breathing, kPa var/breath_type = "oxygen" // Non-oxygen gas breathed, if any. var/poison_type = "phoron" // Poisonous air. var/exhale_type = "carbon_dioxide" // Exhaled gas type. @@ -212,19 +213,17 @@ var/obj/item/organ/O = new limb_path(H) organ_data["descriptor"] = O.name - for(var/organ in has_organ) - var/organ_type = has_organ[organ] - H.internal_organs_by_name[organ] = new organ_type(H,1) - - for(var/name in H.organs_by_name) - H.organs |= H.organs_by_name[name] - - for(var/obj/item/organ/external/O in H.organs) - O.owner = H + for(var/organ_tag in has_organ) + var/organ_type = has_organ[organ_tag] + var/obj/item/organ/O = new organ_type(H,1) + if(organ_tag != O.organ_tag) + warning("[O.type] has a default organ tag \"[O.organ_tag]\" that differs from the species' organ tag \"[organ_tag]\". Updating organ_tag to match.") + O.organ_tag = organ_tag + H.internal_organs_by_name[organ_tag] = O if(flags & IS_SYNTHETIC) for(var/obj/item/organ/external/E in H.organs) - if(E.status & ORGAN_CUT_AWAY || E.status & ORGAN_DESTROYED) continue + if(E.status & ORGAN_CUT_AWAY || E.is_stump()) continue E.robotize() for(var/obj/item/organ/I in H.internal_organs) I.robotize() @@ -255,6 +254,9 @@ /datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment. add_inherent_verbs(H) + H.mob_bump_flag = bump_flag + H.mob_swap_flags = swap_flags + H.mob_push_flags = push_flags /datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). return diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index 010cfae341a..9ba341ff4a1 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -221,19 +221,7 @@ return ..() /datum/species/diona/handle_death(var/mob/living/carbon/human/H) - - var/mob/living/carbon/alien/diona/S = new(get_turf(H)) - - if(H.mind) - H.mind.transfer_to(S) - - for(var/mob/living/carbon/alien/diona/D in H.contents) - if(D.client) - D.loc = H.loc - else - qdel(D) - - H.visible_message("\red[H] splits apart with a wet slithering noise!") + H.diona_split_into_nymphs(0) /datum/species/machine name = "Machine" diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm index d6767fbbc4e..34455a47a11 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm @@ -70,6 +70,7 @@ var/const/MAX_ACTIVE_TIME = 400 return /obj/item/clothing/mask/facehugger/equipped(mob/M) + ..() Attach(M) /obj/item/clothing/mask/facehugger/Crossed(atom/target) diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm index 289b4a22733..e541920cb4f 100644 --- a/code/modules/mob/living/carbon/human/unarmed_attack.dm +++ b/code/modules/mob/living/carbon/human/unarmed_attack.dm @@ -18,11 +18,11 @@ // Check if they have a functioning hand. var/obj/item/organ/external/E = user.organs_by_name["l_hand"] - if(E && !(E.status & ORGAN_DESTROYED)) + if(E && !E.is_stump()) return 1 E = user.organs_by_name["r_hand"] - if(E && !(E.status & ORGAN_DESTROYED)) + if(E && !E.is_stump()) return 1 return 0 @@ -32,6 +32,9 @@ /datum/unarmed_attack/proc/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone) + if(target.stat == DEAD) + return + var/stun_chance = rand(0, 100) if(attack_damage >= 5 && armour < 2 && !(target == user) && stun_chance <= attack_damage * 5) // 25% standard chance @@ -167,11 +170,11 @@ return 0 var/obj/item/organ/external/E = user.organs_by_name["l_foot"] - if(E && !(E.status & ORGAN_DESTROYED)) + if(E && !E.is_stump()) return 1 E = user.organs_by_name["r_foot"] - if(E && !(E.status & ORGAN_DESTROYED)) + if(E && !E.is_stump()) return 1 return 0 @@ -211,11 +214,11 @@ if(target.grabbed_by == user && target.lying) return 0 var/obj/item/organ/external/E = user.organs_by_name["l_foot"] - if(E && !(E.status & ORGAN_DESTROYED)) + if(E && !E.is_stump()) return 1 E = user.organs_by_name["r_foot"] - if(E && !(E.status & ORGAN_DESTROYED)) + if(E && !E.is_stump()) return 1 return 0 @@ -233,4 +236,4 @@ switch(attack_damage) if(1 to 4) user.visible_message("[pick("[user] stomped on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down onto")] [target]'s [organ]!") - if(5) user.visible_message("[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/ \ No newline at end of file + if(5) user.visible_message("[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/ diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index d8f51488944..d0d723a7925 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -186,9 +186,10 @@ var/global/list/damage_icon_parts = list() for(var/obj/item/organ/external/O in organs) if(O.is_stump()) continue - if(O.status & ORGAN_DESTROYED) damage_appearance += "d" - else - damage_appearance += O.damage_state + //if(O.status & ORGAN_DESTROYED) damage_appearance += "d" //what is this? + //else + // damage_appearance += O.damage_state + damage_appearance += O.damage_state if(damage_appearance == previous_damage_appearance) // nothing to do here @@ -204,20 +205,20 @@ var/global/list/damage_icon_parts = list() for(var/obj/item/organ/external/O in organs) if(O.is_stump()) continue - if(!(O.status & ORGAN_DESTROYED)) - O.update_icon() - if(O.damage_state == "00") continue - var/icon/DI - var/cache_index = "[O.damage_state]/[O.icon_name]/[species.blood_color]/[species.get_bodytype()]" - if(damage_icon_parts[cache_index] == null) - DI = new /icon(species.damage_overlays, O.damage_state) // the damage icon for whole human - DI.Blend(new /icon(species.damage_mask, O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels - DI.Blend(species.blood_color, ICON_MULTIPLY) - damage_icon_parts[cache_index] = DI - else - DI = damage_icon_parts[cache_index] - standing_image.overlays += DI + O.update_icon() + if(O.damage_state == "00") continue + var/icon/DI + var/cache_index = "[O.damage_state]/[O.icon_name]/[species.blood_color]/[species.get_bodytype()]" + if(damage_icon_parts[cache_index] == null) + DI = new /icon(species.damage_overlays, O.damage_state) // the damage icon for whole human + DI.Blend(new /icon(species.damage_mask, O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels + DI.Blend(species.blood_color, ICON_MULTIPLY) + damage_icon_parts[cache_index] = DI + else + DI = damage_icon_parts[cache_index] + + standing_image.overlays += DI overlays_standing[DAMAGE_LAYER] = standing_image @@ -257,7 +258,7 @@ var/global/list/damage_icon_parts = list() for(var/organ_tag in species.has_limbs) var/obj/item/organ/external/part = organs_by_name[organ_tag] - if(isnull(part) || part.is_stump() || (part.status & ORGAN_DESTROYED)) + if(isnull(part) || part.is_stump()) icon_key += "0" else if(part.status & ORGAN_ROBOT) icon_key += "2[part.model ? "-[part.model]": ""]" @@ -336,7 +337,7 @@ var/global/list/damage_icon_parts = list() overlays_standing[HAIR_LAYER] = null var/obj/item/organ/external/head/head_organ = get_organ("head") - if(!head_organ || head_organ.is_stump() || (head_organ.status & ORGAN_DESTROYED) ) + if(!head_organ || head_organ.is_stump() ) if(update_icons) update_icons() return diff --git a/code/modules/mob/living/carbon/metroid/items.dm b/code/modules/mob/living/carbon/metroid/items.dm index 6739cb4e2b9..1271bb7da33 100644 --- a/code/modules/mob/living/carbon/metroid/items.dm +++ b/code/modules/mob/living/carbon/metroid/items.dm @@ -11,6 +11,7 @@ origin_tech = "biotech=4" var/Uses = 1 // uses before it goes inert var/enhanced = 0 //has it been enhanced before? + flags = OPENCONTAINER attackby(obj/item/O as obj, mob/user as mob) if(istype(O, /obj/item/weapon/slimesteroid2)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c1295cc3626..93faa0e8b02 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -219,7 +219,7 @@ /mob/living/proc/handle_fire() if(fire_stacks < 0) - fire_stacks = max(0, fire_stacks++) //If we've doused ourselves in water to avoid fire, dry off slowly + fire_stacks = min(0, ++fire_stacks) //If we've doused ourselves in water to avoid fire, dry off slowly if(!on_fire) return 1 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index ba42e42c75f..0c9435481ab 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -158,7 +158,6 @@ var/list/ai_verbs_default = list( spawn(5) new /obj/machinery/ai_powersupply(src) - hud_list[HEALTH_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[STATUS_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[LIFE_HUD] = image('icons/mob/hud.dmi', src, "hudblank") @@ -199,8 +198,23 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/Destroy() ai_list -= src + qdel(eyeobj) - ..() + eyeobj = null + + qdel(psupply) + psupply = null + + qdel(aiMulti) + aiMulti = null + + qdel(aiRadio) + aiRadio = null + + qdel(aiCamera) + aiCamera = null + + return ..() /mob/living/silicon/ai/pointed(atom/A as mob|obj|turf in view()) set popup_menu = 0 @@ -234,20 +248,22 @@ var/list/ai_verbs_default = list( /obj/machinery/ai_powersupply/New(var/mob/living/silicon/ai/ai=null) powered_ai = ai powered_ai.psupply = src - if(isnull(powered_ai)) - qdel(src) - - loc = powered_ai.loc - use_power(1) // Just incase we need to wake up the power system. + forceMove(powered_ai.loc) ..() + use_power(1) // Just incase we need to wake up the power system. + +/obj/machinery/ai_powersupply/Destroy() + . = ..() + powered_ai = null /obj/machinery/ai_powersupply/process() - if(!powered_ai || powered_ai.stat & DEAD) - qdel() + if(!powered_ai || powered_ai.stat == DEAD) + qdel(src) return if(powered_ai.psupply != src) // For some reason, the AI has different powersupply object. Delete this one, it's no longer needed. qdel(src) + return if(powered_ai.APU_power) use_power = 0 return diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index 45c6a3816bb..e11d799af5e 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -17,7 +17,7 @@ msg += "It looks slightly charred.\n" else msg += "Its casing is melted and heat-warped!\n" - if (src.getOxyLoss()) + if (src.getOxyLoss() && (aiRestorePowerRoutine != 0 && !APU_power)) if (src.getOxyLoss() > 175) msg += "It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.\n" else if(src.getOxyLoss() > 100) diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index 5c2068abdfe..90236d2e521 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -12,7 +12,7 @@ /mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg) laws_sanity_check() laws.set_zeroth_law(law, law_borg) - log_and_message_admins("has given [src] the zeroth laws: [law]/[law_borg ? law_borg : "N/A"]") + log_law("has given [src] the zeroth law: '[law]'[law_borg ? " / '[law_borg]'" : ""]") /mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg) ..() @@ -22,40 +22,40 @@ /mob/living/silicon/proc/add_ion_law(var/law) laws_sanity_check() laws.add_ion_law(law) - log_and_message_admins("has given [src] the ion law: [law]") + log_law("has given [src] the ion law: [law]") /mob/living/silicon/proc/add_inherent_law(var/law) laws_sanity_check() laws.add_inherent_law(law) - log_and_message_admins("has given [src] the inherent law: [law]") + log_law("has given [src] the inherent law: [law]") /mob/living/silicon/proc/add_supplied_law(var/number, var/law) laws_sanity_check() laws.add_supplied_law(number, law) - log_and_message_admins("has given [src] the supplied law: [law]") + log_law("has given [src] the supplied law: [law]") /mob/living/silicon/proc/delete_law(var/datum/ai_law/law) laws_sanity_check() laws.delete_law(law) - log_and_message_admins("has deleted a law belonging to [src]: [law.law]") + log_law("has deleted a law belonging to [src]: [law.law]") /mob/living/silicon/proc/clear_inherent_laws(var/silent = 0) laws_sanity_check() laws.clear_inherent_laws() if(!silent) - log_and_message_admins("cleared the inherent laws of [src]") + log_law("cleared the inherent laws of [src]") /mob/living/silicon/proc/clear_ion_laws(var/silent = 0) laws_sanity_check() laws.clear_ion_laws() if(!silent) - log_and_message_admins("cleared the ion laws of [src]") + log_law("cleared the ion laws of [src]") /mob/living/silicon/proc/clear_supplied_laws(var/silent = 0) laws_sanity_check() laws.clear_supplied_laws() if(!silent) - log_and_message_admins("cleared the supplied laws of [src]") + log_law("cleared the supplied laws of [src]") /mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) var/prefix = "" @@ -102,3 +102,7 @@ /mob/living/silicon/proc/lawsync() laws_sanity_check() laws.sort_laws() + +/mob/living/silicon/proc/log_law(var/law_message) + log_and_message_admins(law_message) + lawchanges += "[worldtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]" diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index f13a09cf953..48f1fb7cc9e 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -145,13 +145,13 @@ /mob/living/silicon/robot/proc/handle_regular_hud_updates() - if (src.stat == 2 || XRAY in mutations || src.sight_mode & BORGXRAY) + if (src.stat == 2 || (XRAY in mutations) || (src.sight_mode & BORGXRAY)) src.sight |= SEE_TURFS src.sight |= SEE_MOBS src.sight |= SEE_OBJS src.see_in_dark = 8 src.see_invisible = SEE_INVISIBLE_MINIMUM - else if (src.sight_mode & BORGMESON && src.sight_mode & BORGTHERM) + else if ((src.sight_mode & BORGMESON) && (src.sight_mode & BORGTHERM)) src.sight |= SEE_TURFS src.sight |= SEE_MOBS src.see_in_dark = 8 @@ -160,6 +160,10 @@ src.sight |= SEE_TURFS src.see_in_dark = 8 see_invisible = SEE_INVISIBLE_MINIMUM + else if (src.sight_mode & BORGMATERIAL) + src.sight |= SEE_OBJS + src.see_in_dark = 8 + see_invisible = SEE_INVISIBLE_MINIMUM else if (src.sight_mode & BORGTHERM) src.sight |= SEE_MOBS src.see_in_dark = 8 diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 3e072d3d742..9346dbe5d4c 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -33,7 +33,9 @@ for(var/T in temp_tech) files.UpdateTech(T, temp_tech[T]) user << "\The [loaded_item] had level [temp_tech[T]] in [T]." - loaded_item = null + else + user << "\The [loaded_item] was not reliable enough to advance research." + loaded_item = null for(var/obj/I in contents) for(var/mob/M in I.contents) M.death() diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 819fbf4561e..42a35e89f66 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -34,7 +34,7 @@ var/global/list/robot_modules = list( var/list/obj/item/borg/upgrade/supported_upgrades = list() // Bookkeeping - var/list/added_languages = list() + var/list/original_languages = list() var/list/added_networks = list() /obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R) @@ -63,12 +63,14 @@ var/global/list/robot_modules = list( qdel(src) /obj/item/weapon/robot_module/Destroy() - qdel(modules) - qdel(synths) + for(var/obj/O in modules) + qdel(O) + modules.Cut() + for(var/datum/matter_synth/S in synths) + qdel(S) + synths.Cut() qdel(emag) qdel(jetpack) - modules = null - synths = null emag = null jetpack = null return ..() @@ -86,6 +88,15 @@ var/global/list/robot_modules = list( return /obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) + var/obj/item/device/flash/F = locate() in src.modules + if(F) + if(F.broken) + F.broken = 0 + F.times_used = 0 + F.icon_state = "flash" + else if(F.times_used) + F.times_used-- + if(!synths || !synths.len) return @@ -100,14 +111,22 @@ var/global/list/robot_modules = list( modules += O /obj/item/weapon/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) + // Stores the languages as they were before receiving the module, and whether they could be synthezized. + for(var/datum/language/language_datum in R.languages) + original_languages[language_datum] = (language_datum in R.speech_synthesizer_langs) + for(var/language in languages) - if(R.add_language(language, languages[language])) - added_languages |= language + R.add_language(language, languages[language]) /obj/item/weapon/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R) - for(var/language in added_languages) + // Clear all added languages, whether or not we originally had them. + for(var/language in languages) R.remove_language(language) - added_languages.Cut() + + // Then add back all the original languages, and the relevant synthezising ability + for(var/original_language in original_languages) + R.add_language(original_language, original_languages[original_language]) + original_languages.Cut() /obj/item/weapon/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R) if(R.camera && (NETWORK_ROBOTS in R.camera.network)) @@ -261,7 +280,6 @@ var/global/list/robot_modules = list( return /obj/item/weapon/robot_module/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules if(S.mode == 2) S.reagents.clear_reagents() @@ -304,6 +322,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/crowbar(src) src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) src.modules += new /obj/item/device/pipe_painter(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) var/datum/matter_synth/metal = new /datum/matter_synth/metal() var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel() @@ -414,13 +433,7 @@ var/global/list/robot_modules = list( return /obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/device/flash/F = locate() in src.modules - if(F.broken) - F.broken = 0 - F.times_used = 0 - F.icon_state = "flash" - else if(F.times_used) - F.times_used-- + ..() var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules if(T.power_supply.charge < T.power_supply.maxcharge) T.power_supply.give(T.charge_cost * amount) @@ -454,6 +467,7 @@ var/global/list/robot_modules = list( return /obj/item/weapon/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + ..() var/obj/item/device/lightreplacer/LR = locate() in src.modules LR.Charge(R, amount) if(src.emag) @@ -537,6 +551,7 @@ var/global/list/robot_modules = list( src.emag = new /obj/item/weapon/stamp/denied(src) /obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + ..() var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules E.reagents.add_reagent("enzyme", 2 * amount) if(src.emag) @@ -558,7 +573,7 @@ var/global/list/robot_modules = list( /obj/item/weapon/robot_module/miner/New() ..() src.modules += new /obj/item/device/flash(src) - src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/borg/sight/material(src) src.modules += new /obj/item/weapon/wrench(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/storage/bag/ore(src) @@ -661,6 +676,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/device/lightreplacer(src) src.modules += new /obj/item/weapon/gripper(src) src.modules += new /obj/item/weapon/soap(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) src.emag.name = "Plasma Cutter" diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index ece00da5ee7..16a00368a80 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -68,31 +68,46 @@ if (!message) return - var/obj/machinery/hologram/holopad/T = src.holo - if(T && T.masters[src])//If there is a hologram and its master is the user. - - //Human-like, sorta, heard by those who understand humans. - var/rendered_a - //Speach distorted, heard by those who do not understand AIs. - var/message_stars = stars(message) - var/rendered_b + var/obj/machinery/hologram/holopad/H = src.holo + if(H && H.masters[src])//If there is a hologram and its master is the user. + // AI can hear their own message, this formats it for them. if(speaking) - rendered_a = "[name] [speaking.format_message(message, verb)]" - rendered_b = "[voice_name] [speaking.format_message(message_stars, verb)]" - src << "Holopad transmitted, [real_name] [speaking.format_message(message, verb)]"//The AI can "hear" its own message. + src << "Holopad transmitted, [real_name] [speaking.format_message(message, verb)]" else - rendered_a = "[name] [verb], \"[message]\"" - rendered_b = "[voice_name] [verb], \"[message_stars]\"" - src << "Holopad transmitted, [real_name] [verb], \"[message]\""//The AI can "hear" its own message. + src << "Holopad transmitted, [real_name] [verb], \"[message]\"" + + //This is so pAI's and people inside lockers/boxes,etc can hear the AI Holopad, the alternative being recursion through contents. + //This is much faster. + var/list/listening = list() + var/list/listening_obj = list() + var/turf/T = get_turf(H) + + if(T) + var/list/hear = hear(7, T) + var/list/hearturfs = list() + + for(var/I in hear) + if(istype(I, /mob/)) + var/mob/M = I + listening += M + hearturfs += M.locs[1] + for(var/obj/O in M.contents) + listening_obj |= O + else if(istype(I, /obj/)) + var/obj/O = I + hearturfs += O.locs[1] + listening_obj |= O + + + for(var/mob/M in player_list) + if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) + M.hear_say(message,verb,speaking,null,null, src) + continue + if(M.loc && M.locs[1] in hearturfs) + M.hear_say(message,verb,speaking,null,null, src) + - for(var/mob/M in hearers(T.loc))//The location is the object, default distance. - if(M.say_understands(src))//If they understand AI speak. Humans and the like will be able to. - M.show_message(rendered_a, 2) - else//If they do not. - M.show_message(rendered_b, 2) - /*Radios "filter out" this conversation channel so we don't need to account for them. - This is another way of saying that we won't bother dealing with them.*/ else src << "No holopad connected." return 0 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index d6fc2e4aa92..5186a7f6b85 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -188,16 +188,22 @@ return universal_speak || (speaking in src.speech_synthesizer_langs) //need speech synthesizer support to vocalize a language /mob/living/silicon/add_language(var/language, var/can_speak=1) - if (..(language) && can_speak) - speech_synthesizer_langs.Add(all_languages[language]) + var/var/datum/language/added_language = all_languages[language] + if(!added_language) + return + + . = ..(language) + if (can_speak && (added_language in languages) && !(added_language in speech_synthesizer_langs)) + speech_synthesizer_langs += added_language return 1 /mob/living/silicon/remove_language(var/rem_language) - ..(rem_language) + var/var/datum/language/removed_language = all_languages[rem_language] + if(!removed_language) + return - for (var/datum/language/L in speech_synthesizer_langs) - if (L.name == rem_language) - speech_synthesizer_langs -= L + ..(rem_language) + speech_synthesizer_langs -= removed_language /mob/living/silicon/check_languages() set name = "Check Known Languages" diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm index e8909b0b509..21ce3dd31f8 100644 --- a/code/modules/mob/living/silicon/subystems.dm +++ b/code/modules/mob/living/silicon/subystems.dm @@ -76,7 +76,7 @@ set name = "Law Manager" set category = "Subystems" - law_manager.ui_interact(usr, state = self_state) + law_manager.ui_interact(usr, state = conscious_state) /******************** * Power Monitor * diff --git a/code/modules/mob/living/simple_animal/borer/borer_powers.dm b/code/modules/mob/living/simple_animal/borer/borer_powers.dm index 88be25cc245..f6b87bfd444 100644 --- a/code/modules/mob/living/simple_animal/borer/borer_powers.dm +++ b/code/modules/mob/living/simple_animal/borer/borer_powers.dm @@ -74,7 +74,7 @@ var/mob/living/carbon/human/H = M var/obj/item/organ/external/E = H.organs_by_name["head"] - if(!E || (E.status & ORGAN_DESTROYED)) + if(!E || E.is_stump()) src << "\The [H] does not have a head!" if(!H.species.has_organ["brain"]) diff --git a/code/modules/mob/living/simple_animal/constructs/soulstone.dm b/code/modules/mob/living/simple_animal/constructs/soulstone.dm index 5859969d03b..7e182c6f09d 100644 --- a/code/modules/mob/living/simple_animal/constructs/soulstone.dm +++ b/code/modules/mob/living/simple_animal/constructs/soulstone.dm @@ -14,74 +14,68 @@ //////////////////////////////Capturing//////////////////////////////////////////////////////// - attack(mob/living/carbon/human/M as mob, mob/user as mob) - if(!istype(M, /mob/living/carbon/human))//If target is not a human. - return ..() - if(istype(M, /mob/living/carbon/human/dummy)) - return..() +/obj/item/device/soulstone/attack(mob/living/carbon/human/M as mob, mob/user as mob) + if(!istype(M, /mob/living/carbon/human))//If target is not a human. + return ..() + if(istype(M, /mob/living/carbon/human/dummy)) + return..() - if(M.has_brain_worms()) //Borer stuff - RR - user << "This being is corrupted by an alien intelligence and cannot be soul trapped." - return..() + if(M.has_brain_worms()) //Borer stuff - RR + user << "This being is corrupted by an alien intelligence and cannot be soul trapped." + return..() - M.attack_log += text("\[[time_stamp()]\] Has had their soul captured with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])") - msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to capture the soul of [M.name] ([M.ckey]) (JMP)") + M.attack_log += text("\[[time_stamp()]\] Has had their soul captured with [src.name] by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])") + msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to capture the soul of [M.name] ([M.ckey]) (JMP)") - transfer_soul("VICTIM", M, user) - return + transfer_soul("VICTIM", M, user) + return - /*attack(mob/living/simple_animal/shade/M as mob, mob/user as mob)//APPARENTLY THEY NEED THEIR OWN SPECIAL SNOWFLAKE CODE IN THE LIVING ANIMAL DEFINES - if(!istype(M, /mob/living/simple_animal/shade))//If target is not a shade - return ..() - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])") - transfer_soul("SHADE", M, user) - return*/ ///////////////////Options for using captured souls/////////////////////////////////////// - attack_self(mob/user) - if (!in_range(src, user)) - return - user.set_machine(src) - var/dat = "Soul Stone
" - for(var/mob/living/simple_animal/shade/A in src) - dat += "Captured Soul: [A.name]
" - dat += {"Summon Shade"} - dat += "
" - dat += {" Close"} - user << browse(dat, "window=aicard") - onclose(user, "aicard") +/obj/item/device/soulstone/attack_self(mob/user) + if (!in_range(src, user)) + return + user.set_machine(src) + var/dat = "Soul Stone
" + for(var/mob/living/simple_animal/shade/A in src) + dat += "Captured Soul: [A.name]
" + dat += {"Summon Shade"} + dat += "
" + dat += {" Close"} + user << browse(dat, "window=aicard") + onclose(user, "aicard") + return + + + + +/obj/item/device/soulstone/Topic(href, href_list) + var/mob/U = usr + if (!in_range(src, U)||U.machine!=src) + U << browse(null, "window=aicard") + U.unset_machine() return + add_fingerprint(U) + U.set_machine(src) - - - Topic(href, href_list) - var/mob/U = usr - if (!in_range(src, U)||U.machine!=src) + switch(href_list["choice"])//Now we switch based on choice. + if ("Close") U << browse(null, "window=aicard") U.unset_machine() return - add_fingerprint(U) - U.set_machine(src) - - switch(href_list["choice"])//Now we switch based on choice. - if ("Close") - U << browse(null, "window=aicard") - U.unset_machine() - return - - if ("Summon") - for(var/mob/living/simple_animal/shade/A in src) - A.status_flags &= ~GODMODE - A.canmove = 1 - A << "You have been released from your prison, but you are still bound to [U.name]'s will. Help them suceed in their goals at all costs." - A.loc = U.loc - A.cancel_camera() - src.icon_state = "soulstone" - attack_self(U) + if ("Summon") + for(var/mob/living/simple_animal/shade/A in src) + A.status_flags &= ~GODMODE + A.canmove = 1 + A << "You have been released from your prison, but you are still bound to [U.name]'s will. Help them suceed in their goals at all costs." + A.forceMove(U.loc) + A.cancel_camera() + src.icon_state = "soulstone" + attack_self(U) ///////////////////////////Transferring to constructs///////////////////////////////////////////////////// /obj/structure/constructshell @@ -99,118 +93,127 @@ /obj/structure/constructshell/attackby(obj/item/O as obj, mob/user as mob) if(istype(O, /obj/item/device/soulstone)) - O.transfer_soul("CONSTRUCT",src,user) + var/obj/item/device/soulstone/S = O; + S.transfer_soul("CONSTRUCT",src,user) ////////////////////////////Proc for moving soul in and out off stone////////////////////////////////////// +/obj/item/device/soulstone/proc/transfer_human(var/mob/living/carbon/human/T,var/mob/U) + if(!istype(T)) + return; + if(src.imprinted != "empty") + U << "Capture failed!: The soul stone has already been imprinted with [src.imprinted]'s mind!" + return + if ((T.health + T.halloss) > config.health_threshold_crit && T.stat != DEAD) + U << "Capture failed!: Kill or maim the victim first!" + return + if(T.client == null) + U << "Capture failed!: The soul has already fled it's mortal frame." + return + if(src.contents.len) + U << "Capture failed!: The soul stone is full! Use or free an existing soul to make room." + return + + for(var/obj/item/W in T) + T.drop_from_inventory(W) + + new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton + T.invisibility = 101 + + var/atom/movable/overlay/animation = new /atom/movable/overlay( T.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = T + flick("dust-h", animation) + qdel(animation) + + var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade( T.loc ) + S.loc = src //put shade in stone + S.status_flags |= GODMODE //So they won't die inside the stone somehow + S.canmove = 0//Can't move out of the soul stone + S.name = "Shade of [T.real_name]" + S.real_name = "Shade of [T.real_name]" + S.icon = T.icon + S.icon_state = T.icon_state + S.overlays = T.overlays + S.color = rgb(254,0,0) + S.alpha = 127 + if (T.client) + T.client.mob = S + S.cancel_camera() -/obj/item/proc/transfer_soul(var/choice as text, var/target, var/mob/U as mob). + src.icon_state = "soulstone2" + src.name = "Soul Stone: [S.real_name]" + S << "Your soul has been captured! You are now bound to [U.name]'s will, help them suceed in their goals at all costs." + U << "Capture successful! : [T.real_name]'s soul has been ripped from their body and stored within the soul stone." + U << "The soulstone has been imprinted with [S.real_name]'s mind, it will no longer react to other souls." + src.imprinted = "[S.name]" + qdel(T) + +/obj/item/device/soulstone/proc/transfer_shade(var/mob/living/simple_animal/shade/T,var/mob/U) + if(!istype(T)) + return; + if (T.stat == DEAD) + U << "Capture failed!: The shade has already been banished!" + return + if(src.contents.len) + U << "Capture failed!: The soul stone is full! Use or free an existing soul to make room." + return + if(T.name != src.imprinted) + U << "Capture failed!: The soul stone has already been imprinted with [src.imprinted]'s mind!" + return + + T.loc = src //put shade in stone + T.status_flags |= GODMODE + T.canmove = 0 + T.health = T.maxHealth + src.icon_state = "soulstone2" + + T << "Your soul has been recaptured by the soul stone, its arcane energies are reknitting your ethereal form" + U << "Capture successful! : [T.name]'s has been recaptured and stored within the soul stone." +/obj/item/device/soulstone/proc/transfer_construct(var/obj/structure/constructshell/T,var/mob/U) + var/mob/living/simple_animal/shade/A = locate() in src + if(!A) + U << "Capture failed!: The soul stone is empty! Go kill someone!" + return; + var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") + switch(construct_class) + if("Juggernaut") + var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) + Z.key = A.key + if(iscultist(U)) + cult.add_antagonist(Z.mind) + qdel(T) + Z << "You are playing a Juggernaut. Though slow, you can withstand extreme punishment, and rip apart enemies and walls alike." + Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." + Z.cancel_camera() + qdel(src) + if("Wraith") + var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) + Z.key = A.key + if(iscultist(U)) + cult.add_antagonist(Z.mind) + qdel(T) + Z << "You are playing a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." + Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." + Z.cancel_camera() + qdel(src) + if("Artificer") + var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) + Z.key = A.key + if(iscultist(U)) + cult.add_antagonist(Z.mind) + qdel(T) + Z << "You are playing an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, repair allied constructs (by clicking on them), and even create new constructs" + Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." + Z.cancel_camera() + qdel(src) +/obj/item/device/soulstone/proc/transfer_soul(var/choice as text, var/target, var/mob/U as mob). switch(choice) if("VICTIM") - var/mob/living/carbon/human/T = target - var/obj/item/device/soulstone/C = src - if(C.imprinted != "empty") - U << "\red Capture failed!: \black The soul stone has already been imprinted with [C.imprinted]'s mind!" - else - if ((T.health + T.halloss) > config.health_threshold_crit) - U << "\red Capture failed!: \black Kill or maim the victim first!" - else - if(T.client == null) - U << "\red Capture failed!: \black The soul has already fled it's mortal frame." - else - if(C.contents.len) - U << "\red Capture failed!: \black The soul stone is full! Use or free an existing soul to make room." - else - for(var/obj/item/W in T) - T.drop_from_inventory(W) - new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton - T.invisibility = 101 - var/atom/movable/overlay/animation = new /atom/movable/overlay( T.loc ) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = T - flick("dust-h", animation) - qdel(animation) - var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade( T.loc ) - S.loc = C //put shade in stone - S.status_flags |= GODMODE //So they won't die inside the stone somehow - S.canmove = 0//Can't move out of the soul stone - S.name = "Shade of [T.real_name]" - S.real_name = "Shade of [T.real_name]" - S.icon = T.icon - S.icon_state = T.icon_state - S.overlays = T.overlays - S.color = rgb(254,0,0) - S.alpha = 127 - if (T.client) - T.client.mob = S - S.cancel_camera() - C.icon_state = "soulstone2" - C.name = "Soul Stone: [S.real_name]" - S << "Your soul has been captured! You are now bound to [U.name]'s will, help them suceed in their goals at all costs." - U << "\blue Capture successful!: \black [T.real_name]'s soul has been ripped from their body and stored within the soul stone." - U << "The soulstone has been imprinted with [S.real_name]'s mind, it will no longer react to other souls." - C.imprinted = "[S.name]" - qdel(T) + transfer_human(target,U) if("SHADE") - var/mob/living/simple_animal/shade/T = target - var/obj/item/device/soulstone/C = src - if (T.stat == DEAD) - U << "\red Capture failed!: \black The shade has already been banished!" - else - if(C.contents.len) - U << "\red Capture failed!: \black The soul stone is full! Use or free an existing soul to make room." - else - if(T.name != C.imprinted) - U << "\red Capture failed!: \black The soul stone has already been imprinted with [C.imprinted]'s mind!" - else - T.loc = C //put shade in stone - T.status_flags |= GODMODE - T.canmove = 0 - T.health = T.maxHealth - C.icon_state = "soulstone2" - T << "Your soul has been recaptured by the soul stone, its arcane energies are reknitting your ethereal form" - U << "\blue Capture successful!: \black [T.name]'s has been recaptured and stored within the soul stone." + transfer_shade(target,U) if("CONSTRUCT") - var/obj/structure/constructshell/T = target - var/obj/item/device/soulstone/C = src - var/mob/living/simple_animal/shade/A = locate() in C - if(A) - var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") - switch(construct_class) - if("Juggernaut") - var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - cult.add_antagonist(Z.mind) - qdel(T) - Z << "You are playing a Juggernaut. Though slow, you can withstand extreme punishment, and rip apart enemies and walls alike." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) - - if("Wraith") - var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - cult.add_antagonist(Z.mind) - qdel(T) - Z << "You are playing a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) - - if("Artificer") - var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - cult.add_antagonist(Z.mind) - qdel(T) - Z << "You are playing an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, repair allied constructs (by clicking on them), and even create new constructs" - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) - else - U << "\red Creation failed!: \black The soul stone is empty! Go kill someone!" - return + transfer_construct(target,U) diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 359db24c636..f8ed654b958 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -37,7 +37,8 @@ /mob/living/simple_animal/shade/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri if(istype(O, /obj/item/device/soulstone)) - O.transfer_soul("SHADE", src, user) + var/obj/item/device/soulstone/S = O; + S.transfer_soul("SHADE", src, user) return /mob/living/simple_animal/shade/proc/OnDeathInLife() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a81c9435035..b42b2c9f722 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -658,17 +658,17 @@ if(!TurfAdjacent(listed_turf)) listed_turf = null else - statpanel(listed_turf.name, null, listed_turf) - for(var/atom/A in listed_turf) - if(!A.mouse_opacity) - continue - if(A.invisibility > see_invisible) - continue - if(is_type_in_list(A, shouldnt_see)) - continue - statpanel(listed_turf.name, null, A) + if(statpanel("Turf")) + stat("\icon[listed_turf]", listed_turf.name) + for(var/atom/A in listed_turf) + if(!A.mouse_opacity) + continue + if(A.invisibility > see_invisible) + continue + if(is_type_in_list(A, shouldnt_see)) + continue + stat(A) - sleep(4) //Prevent updating the stat panel for the next .4 seconds, prevents clientside latency from updates // facing verbs /mob/proc/canface() diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 89a4957e3fb..85d8c78464b 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -214,8 +214,9 @@ var/stance_damage = 0 //Whether this mob's ability to stand has been affected - //Indicates if a clientless mob is actually an admin aghosting - var/mob/dead/observer/aghosted = null + //If set, indicates that the client "belonging" to this (clientless) mob is currently controlling some other mob + //so don't treat them as being SSD even though their client var is null. + var/mob/teleop = null var/turf/listed_turf = null //the current turf being examined in the stat panel var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes diff --git a/code/modules/mob/mob_grab_specials.dm b/code/modules/mob/mob_grab_specials.dm index f4364dc684f..b4f8b15bbcf 100644 --- a/code/modules/mob/mob_grab_specials.dm +++ b/code/modules/mob/mob_grab_specials.dm @@ -3,7 +3,7 @@ var/obj/item/organ/external/E = H.get_organ(target_zone) - if(!E || (E.status & ORGAN_DESTROYED)) + if(!E || E.is_stump()) user << "[H] is missing that bodypart." return diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 862f92fd5bc..4f55f3d55b4 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -640,7 +640,7 @@ proc/is_blind(A) // A proper CentCom id is hard currency. else if(id && istype(id, /obj/item/weapon/card/id/centcom)) return SAFE_PERP - + if(check_access && !access_obj.allowed(src)) threatcount += 4 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 080502361d9..cd3745a6eb9 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -295,7 +295,7 @@ var/mob/living/carbon/human/driver = mob.buckled var/obj/item/organ/external/l_hand = driver.get_organ("l_hand") var/obj/item/organ/external/r_hand = driver.get_organ("r_hand") - if((!l_hand || (l_hand.status & ORGAN_DESTROYED)) && (!r_hand || (r_hand.status & ORGAN_DESTROYED))) + if((!l_hand || l_hand.is_stump()) && (!r_hand || r_hand.is_stump())) return // No hands to drive your chair? Tough luck! //drunk wheelchair driving if(mob.confused) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index fb3b6f4fca3..9eb43e48d98 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -289,7 +289,7 @@ proc/AttemptLateSpawn(rank,var/spawning_at) - if (src != usr) + if(src != usr) return 0 if(!ticker || ticker.current_state != GAME_STATE_PLAYING) usr << "\red The round is either not ready, or has already finished..." @@ -323,7 +323,7 @@ character.loc = C.loc AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]") - ticker.mode.latespawn(character) + ticker.mode.handle_latejoin(character) qdel(C) qdel(src) @@ -354,7 +354,7 @@ character.buckled.loc = character.loc character.buckled.set_dir(character.dir) - ticker.mode.latespawn(character) + ticker.mode.handle_latejoin(character) if(character.mind.assigned_role != "Cyborg") data_core.manifest_inject(character) diff --git a/code/modules/nano/interaction/base.dm b/code/modules/nano/interaction/base.dm index 602185bb8ab..99f9e490bef 100644 --- a/code/modules/nano/interaction/base.dm +++ b/code/modules/nano/interaction/base.dm @@ -14,7 +14,7 @@ /mob/proc/shared_nano_interaction() if (src.stat || !client) return STATUS_CLOSE // no updates, close the interface - else if (restrained() || lying || stat || stunned || weakened) + else if (restrained() || lying || stat || stunned || weakened) // TODO: Change to incapaciated() on merge return STATUS_UPDATE // update only (orange visibility) return STATUS_INTERACTIVE diff --git a/code/modules/nano/interaction/conscious.dm b/code/modules/nano/interaction/conscious.dm new file mode 100644 index 00000000000..143bc24956f --- /dev/null +++ b/code/modules/nano/interaction/conscious.dm @@ -0,0 +1,7 @@ +/* + This state only checks if user is conscious. +*/ +/var/global/datum/topic_state/conscious_state/conscious_state = new() + +/datum/topic_state/conscious_state/can_use_topic(var/src_object, var/mob/user) + return user.stat == CONSCIOUS ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm index b38ac805153..3d0cdac6575 100644 --- a/code/modules/nano/modules/crew_monitor.dm +++ b/code/modules/nano/modules/crew_monitor.dm @@ -2,7 +2,7 @@ name = "Crew monitor" /obj/nano_module/crew_monitor/Topic(href, href_list) - if(..()) return + if(..()) return 1 var/turf/T = get_turf(src) if (!T || !(T.z in config.player_levels)) usr << "Unable to establish a connection: You're too far away from the station!" diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm index ed7c64aa943..b0bf72f39a3 100644 --- a/code/modules/nano/modules/power_monitor.dm +++ b/code/modules/nano/modules/power_monitor.dm @@ -47,7 +47,7 @@ // Allows us to process UI clicks, which are relayed in form of hrefs. /obj/nano_module/power_monitor/Topic(href, href_list) if(..()) - return + return 1 if( href_list["clear"] ) active_sensor = null if( href_list["refresh"] ) diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 74c21d49822..a04b537fc1e 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -140,7 +140,8 @@ nanoui is used to open and update nano browser uis * @return nothing */ /datum/nanoui/proc/update_status(var/push_update = 0) - var/new_status = src_object.CanUseTopic(user, state) + var/obj/host = src_object.nano_host() + var/new_status = host.CanUseTopic(user, state) if(master_ui) new_status = min(new_status, master_ui.status) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index fd17fc2f9fe..833a90c0ead 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -56,7 +56,7 @@ var/list/organ_cache = list() var/mob/living/carbon/human/H = holder if(istype(H)) if(internal) - var/obj/item/organ/external/E = H.organs_by_name[src.parent_organ] + var/obj/item/organ/external/E = H.get_organ(parent_organ) if(E) if(E.internal_organs == null) E.internal_organs = list() @@ -206,14 +206,15 @@ var/list/organ_cache = list() if(parent && !silent) owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) +/obj/item/organ/proc/bruise() + damage = max(damage, min_bruised_damage) + /obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc robotic = 2 src.status &= ~ORGAN_BROKEN src.status &= ~ORGAN_BLEEDING src.status &= ~ORGAN_SPLINTED src.status &= ~ORGAN_CUT_AWAY - src.status &= ~ORGAN_ATTACHABLE - src.status &= ~ORGAN_DESTROYED src.status |= ORGAN_ROBOT src.status |= ORGAN_ASSISTED diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm index d76cdab8f1d..5c1a3e9584c 100644 --- a/code/modules/organs/organ_alien.dm +++ b/code/modules/organs/organ_alien.dm @@ -158,14 +158,6 @@ name = "anchoring ligament" parent_organ = "groin" -/obj/item/organ/diona/node - name = "receptor node" - parent_organ = "head" - -/obj/item/organ/diona/nutrients - name = "nutrient vessel" - parent_organ = "chest" - /obj/item/organ/diona name = "diona nymph" icon = 'icons/obj/objects.dmi' @@ -183,8 +175,9 @@ // These are different to the standard diona organs as they have a purpose in other // species (absorbing radiation and light respectively) /obj/item/organ/diona/nutrients - name = "nutrient vessel" - organ_tag = "nutrient vessel" + name = "nutrient channel" + parent_organ = "chest" + organ_tag = "nutrient channel" icon = 'icons/mob/alien.dmi' icon_state = "claw" @@ -192,7 +185,8 @@ return /obj/item/organ/diona/node - name = "receptor node" + name = "response node" + parent_organ = "head" organ_tag = "receptor node" icon = 'icons/mob/alien.dmi' icon_state = "claw" diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index bb51c93feff..d3918aa3454 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -78,15 +78,15 @@ if(istype(I,/obj/item/organ)) continue removable_objects |= I - if(!removable_objects.len) - return ..() - var/obj/item/I = pick(removable_objects) - if(!istype(I)) - return ..() - I.loc = get_turf(user) - if(!(user.l_hand && user.r_hand)) - user.put_in_hands(I) - user.visible_message("\The [user] rips \the [I] out of \the [src]!") + if(removable_objects.len) + var/obj/item/I = pick(removable_objects) + I.loc = get_turf(user) //just in case something was embedded that is not an item + if(istype(I)) + if(!(user.l_hand && user.r_hand)) + user.put_in_hands(I) + user.visible_message("\The [user] rips \the [I] out of \the [src]!") + return //no eating the limb until everything's been removed + return ..() /obj/item/organ/external/examine() ..() @@ -159,8 +159,8 @@ return -/obj/item/organ/external/New(var/mob/living/carbon/holder, var/internal) - ..() +/obj/item/organ/external/New(var/mob/living/carbon/holder) + ..(holder, 0) if(owner) replaced(owner) sync_colour_to_human(owner) @@ -194,8 +194,6 @@ if((brute <= 0) && (burn <= 0)) return 0 - if(status & ORGAN_DESTROYED) - return 0 if(status & ORGAN_ROBOT ) var/brmod = 0.66 @@ -431,15 +429,10 @@ This function completely restores a damaged organ to perfect condition. /obj/item/organ/external/process() if(owner) //Dismemberment - if(status & ORGAN_DESTROYED) - if(config.limbs_can_break) - droplimb(0,DROPLIMB_EDGE) //Might be worth removing this check since take_damage handles it. - return - if(parent) - if(parent.status & ORGAN_DESTROYED) - status |= ORGAN_DESTROYED - owner.update_body(1) - return + //if(parent && parent.is_stump()) //should never happen + // warning("\The [src] ([src.type]) belonging to [owner] ([owner.type]) was attached to a stump") + // remove() + // return // Process wounds, doing healing etc. Only do this every few ticks to save processing power if(owner.life_tick % wound_update_accuracy == 0) @@ -485,7 +478,7 @@ Note that amputating the affected organ does in fact remove the infection from t */ /obj/item/organ/external/proc/update_germs() - if(status & (ORGAN_ROBOT|ORGAN_DESTROYED) || (owner.species && owner.species.flags & IS_PLANT)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. + if(status & (ORGAN_ROBOT) || (owner.species && owner.species.flags & IS_PLANT)) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. germ_level = 0 return @@ -657,8 +650,6 @@ Note that amputating the affected organ does in fact remove the infection from t // new damage icon system // returns just the brute/burn damage code /obj/item/organ/external/proc/damage_state_text() - if(status & ORGAN_DESTROYED) - return "--" var/tburn = 0 var/tbrute = 0 @@ -687,14 +678,11 @@ Note that amputating the affected organ does in fact remove the infection from t ****************************************************/ //Handles dismemberment -/obj/item/organ/external/proc/droplimb(var/clean, var/disintegrate, var/ignore_children) +/obj/item/organ/external/proc/droplimb(var/clean, var/disintegrate = DROPLIMB_EDGE, var/ignore_children = null) if(cannot_amputate || !owner) return - if(!disintegrate) - disintegrate = DROPLIMB_EDGE - switch(disintegrate) if(DROPLIMB_EDGE) if(!clean) @@ -714,22 +702,21 @@ Note that amputating the affected organ does in fact remove the infection from t "You hear the sickening splatter of gore.") var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed(). + var/obj/item/organ/external/parent_organ = parent removed(null, ignore_children) victim.traumatic_shock += 60 wounds.Cut() - if(parent) + if(parent_organ) var/datum/wound/lost_limb/W = new (src, disintegrate, clean) - parent.children -= src if(clean) - parent.wounds |= W - parent.update_damages() + parent_organ.wounds |= W + parent_organ.update_damages() else var/obj/item/organ/external/stump/stump = new (victim, 0, src) stump.wounds |= W victim.organs |= stump stump.update_damages() - parent = null spawn(1) victim.updatehealth() @@ -923,7 +910,7 @@ Note that amputating the affected organ does in fact remove the infection from t return 0 /obj/item/organ/external/proc/is_usable() - return !is_dislocated() && !(status & (ORGAN_DESTROYED|ORGAN_MUTATED|ORGAN_DEAD)) + return !is_dislocated() && !(status & (ORGAN_MUTATED|ORGAN_DEAD)) /obj/item/organ/external/proc/is_malfunctioning() return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam)) @@ -942,7 +929,7 @@ Note that amputating the affected organ does in fact remove the infection from t H.drop_from_inventory(W) W.loc = owner -/obj/item/organ/external/removed(var/mob/living/user, var/ignore_children) +/obj/item/organ/external/removed(var/mob/living/user, var/ignore_children = 0) if(!owner) return @@ -951,14 +938,13 @@ Note that amputating the affected organ does in fact remove the infection from t ..() - status |= ORGAN_DESTROYED victim.bad_external_organs -= src - for(var/obj/item/implant in implants) - if(!istype(implant)) - return - if(implant.w_class <= 2) - qdel(implant) + for(var/atom/movable/implant in implants) + //large items and non-item objs fall to the floor, everything else stays + var/obj/item/I = implant + if(istype(I) && I.w_class < 3) + implant.loc = get_turf(victim.loc) else implant.loc = src implants.Cut() @@ -977,6 +963,10 @@ Note that amputating the affected organ does in fact remove the infection from t organ.removed() organ.loc = src + // Remove parent references + parent.children -= src + parent = null + release_restraints(victim) victim.organs -= src victim.organs_by_name[limb_name] = null // Remove from owner's vars. @@ -1050,7 +1040,7 @@ Note that amputating the affected organ does in fact remove the infection from t if(wound_descriptors.len) var/list/flavor_text = list() var/list/no_exclude = list("gaping wound", "big gaping wound", "massive wound", "large bruise",\ - "huge bruise", "massive bruise", "severe burn", "large burn", "deep burn", "carbonised area") + "huge bruise", "massive bruise", "severe burn", "large burn", "deep burn", "carbonised area") //note to self make this more robust for(var/wound in wound_descriptors) switch(wound_descriptors[wound]) if(1) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 3485e4ed1e8..14079c8a7d2 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -4,13 +4,13 @@ */ /obj/item/weapon/paper - name = "paper" - gender = PLURAL + name = "sheet of paper" + gender = NEUTER icon = 'icons/obj/bureaucracy.dmi' icon_state = "paper" item_state = "paper" throwforce = 0 - w_class = 1.0 + w_class = 1 throw_range = 1 throw_speed = 1 layer = 4 diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm index c99edc57b9d..7da55f1f056 100644 --- a/code/modules/paperwork/paper_bundle.dm +++ b/code/modules/paperwork/paper_bundle.dm @@ -1,6 +1,6 @@ /obj/item/weapon/paper_bundle name = "paper bundle" - gender = PLURAL + gender = NEUTER icon = 'icons/obj/bureaucracy.dmi' icon_state = "paper" item_state = "paper" diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index a2219b262a7..84b01539ade 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -74,6 +74,7 @@ i.loc = src user << "You put [i] in [src]." papers.Add(i) + update_icon() amount++ diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 6a3fd1da71c..7f232d80412 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -479,8 +479,6 @@ user << "There is nothing to secure." return update_icon() - else if(emagged) - user << "The interface is broken." else wiresexposed = !wiresexposed user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]" @@ -625,8 +623,9 @@ qdel(W) stat &= ~BROKEN // Malf AI, removes the APC from AI's hacked APCs list. - if(hacker && hacker.hacked_apcs && src in hacker.hacked_apcs) + if(hacker && hacker.hacked_apcs && (src in hacker.hacked_apcs)) hacker.hacked_apcs -= src + hacker = null if (opened==2) opened = 1 update_icon() @@ -749,7 +748,7 @@ return var/list/data = list( - "locked" = locked, + "locked" = (locked && !emagged) ? 1 : 0, "isOperating" = operating, "externalPower" = main_status, "powerCellStatus" = cell ? cell.percent() : null, @@ -862,7 +861,7 @@ user << "\The [src] have AI control disabled!" return 0 else - if ((!in_range(src, user) || !istype(src.loc, /turf) || hacker)) // AI-hacked APCs cannot be controlled by other AIs, unlinked cyborgs or humans. + if (!in_range(src, user) || !istype(src.loc, /turf)) return 0 var/mob/living/carbon/human/H = user if (istype(H)) @@ -881,7 +880,7 @@ if(!can_use(usr, 1)) return 1 - if(!istype(usr, /mob/living/silicon) && locked) + if(!istype(usr, /mob/living/silicon) && (locked && !emagged)) // Shouldn't happen, this is here to prevent href exploits usr << "You must unlock the panel to use this!" return 1 diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 09ed44c58cf..02e2147f287 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -347,64 +347,54 @@ obj/structure/cable/proc/cableColor(var/colorC) . = list() // this will be a list of all connected power objects var/turf/T -///// Z-Level Stuff - if (d1 == 11 || d1 == 12) + // Handle up/down cables + if(d1 == 11 || d1 == 12 || d2 == 11 || d2 == 12) var/turf/controllerlocation = locate(1, 1, z) for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) - if(controller.up && d1 == 12) + if(controller.up && (d1 == 12 || d2 == 12)) T = locate(src.x, src.y, controller.up_target) if(T) . += power_list(T, src, 11, 1) - if(controller.down && d1 == 11) + if(controller.down && (d1 == 11 || d2 == 11)) T = locate(src.x, src.y, controller.down_target) if(T) . += power_list(T, src, 12, 1) -///// Z-Level Stuff - //get matching cables from the first direction - else if(d1) //if not a node cable - T = get_step(src, d1) - if(T) - . += power_list(T, src, turn(d1, 180), powernetless_only) //get adjacents matching cables - if(d1&(d1-1)) //diagonal direction, must check the 4 possibles adjacents tiles - T = get_step(src,d1&3) // go north/south + // Handle standard cables in adjacent turfs + for(var/cable_dir in list(d1, d2)) + if(cable_dir == 11 || cable_dir == 12 || cable_dir == 0) + continue + var/reverse = reverse_dir[cable_dir] + T = get_step(src, cable_dir) if(T) - . += power_list(T, src, d1 ^ 3, powernetless_only) //get diagonally matching cables - T = get_step(src,d1&12) // go east/west - if(T) - . += power_list(T, src, d1 ^ 12, powernetless_only) //get diagonally matching cables - - . += power_list(loc, src, d1, powernetless_only) //get on turf matching cables - -///// Z-Level Stuff - if(d2 == 11 || d2 == 12) - var/turf/controllerlocation = locate(1, 1, z) - for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) - if(controller.up && d2 == 12) - T = locate(src.x, src.y, controller.up_target) + for(var/obj/structure/cable/C in T) + if((C.d1 && C.d1 == reverse) || (C.d2 && C.d2 == reverse)) + . += C + if(cable_dir & (cable_dir - 1)) // Diagonal, check for /\/\/\ style cables along cardinal directions + for(var/pair in list(NORTH|SOUTH, EAST|WEST)) + T = get_step(src, cable_dir & pair) if(T) - . += power_list(T, src, 11, 1) - if(controller.down && d2 == 11) - T = locate(src.x, src.y, controller.down_target) - if(T) - . += power_list(T, src, 12, 1) -///// Z-Level Stuff - else - //do the same on the second direction (which can't be 0) - T = get_step(src, d2) - if(T) - . += power_list(T, src, turn(d2, 180), powernetless_only) //get adjacents matching cables + var/req_dir = cable_dir ^ pair + for(var/obj/structure/cable/C in T) + if((C.d1 && C.d1 == req_dir) || (C.d2 && C.d2 == req_dir)) + . += C - if(d2&(d2-1)) //diagonal direction, must check the 4 possibles adjacents tiles - T = get_step(src,d2&3) // go north/south - if(T) - . += power_list(T, src, d2 ^ 3, powernetless_only) //get diagonally matching cables - T = get_step(src,d2&12) // go east/west - if(T) - . += power_list(T, src, d2 ^ 12, powernetless_only) //get diagonally matching cables - . += power_list(loc, src, d2, powernetless_only) //get on turf matching cables + // Handle cables on the same turf as us + for(var/obj/structure/cable/C in loc) + if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) // if either of C's d1 and d2 match either of ours + . += C - return . + if(d1 == 0) + for(var/obj/machinery/power/P in loc) + if(P.powernet == 0) continue // exclude APCs with powernet=0 + if(!powernetless_only || !P.powernet) + . += P + + // if the caller asked for powernetless cables only, dump the ones with powernets + if(powernetless_only) + for(var/obj/structure/cable/C in .) + if(C.powernet) + . -= C //should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf. //needed as this can, unlike other placements, disconnect cables @@ -480,6 +470,7 @@ obj/structure/cable/proc/cableColor(var/colorC) slot_flags = SLOT_BELT item_state = "coil" attack_verb = list("whipped", "lashed", "disciplined", "flogged") + stacktype = /obj/item/stack/cable_coil /obj/item/stack/cable_coil/cyborg name = "cable coil synthesizer" diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index a355e169571..a6184a1a932 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -360,9 +360,8 @@ var/list/solars_list = list() /obj/machinery/power/solar_control/initialize() ..() - if(!powernet) return + if(!connect_to_network()) return set_panels(cdir) - connect_to_network() /obj/machinery/power/solar_control/update_icon() if(stat & BROKEN) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 0cc7b38fe61..ac5f322971a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -269,7 +269,7 @@ for(var/obj/item/weapon/grab/G in M.grabbed_by) grabstate = max(grabstate, G.state) if(grabstate >= GRAB_NECK) - damage_mult = 3.0 + damage_mult = 2.5 else if(grabstate >= GRAB_AGGRESSIVE) damage_mult = 1.5 P.damage *= damage_mult @@ -340,6 +340,7 @@ in_chamber.on_hit(M) if (in_chamber.damage_type != HALLOSS) + log_and_message_admins("[key_name(user)] commited suicide using \a [src]") user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1) user.death() else diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index d9ef1b95047..fce41f1d4bf 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -149,55 +149,3 @@ obj/item/weapon/gun/energy/staff/focus user << "The [src.name] will now strike only a single person." projectile_type = "/obj/item/projectile/forcebolt" */ - -/* Adminbus guns */ - -// Serves as a target spotter for the Icarus. -/obj/item/weapon/gun/energy/icarus - name = "rubber ducky" - desc = "It's a cute rubber duck. With an evil gleam in it's eye." - projectile_type = /obj/item/projectile/icarus/pointdefense - icon = 'icons/obj/watercloset.dmi' - item_icons = null - icon_state = "rubberducky" - item_state = "rubberducky" - charge_cost = 0 - silenced = 1 - -/obj/item/weapon/gun/energy/icarus/attack_self(mob/living/user as mob) - if(projectile_type == /obj/item/projectile/icarus/pointdefense) - projectile_type = /obj/item/projectile/icarus/guns - user << "You inform the Icarus to switch to the main guns." - else - projectile_type = /obj/item/projectile/icarus/pointdefense - user << "You inform the Icarus to switch to the point-defense lasers." - - . = ..() - -/obj/item/weapon/gun/energy/icarus/update_icon() - return - -/obj/item/weapon/gun/energy/icarus/verb/SetIcarusAngle() - set src in usr - set name = "Set Firing Angle" - set desc = "Sets the angle from which the icarus will fire." - set category = "Object" - - Icarus_SetPosition(usr) - - -/obj/item/weapon/gun/energy/variable - name = "abstract weapon" - desc = "It seems to shift and flow as you watch." - charge_cost = 0 - silenced = 1 - -/obj/item/weapon/gun/energy/variable/update_icon() - return - -/obj/item/weapon/gun/energy/variable/attack_self(mob/living/user as mob) - var/type = input(user,"What projectile type?","Projectile", null) as null|anything in typesof(/obj/item/projectile) - if(!type) - return ..() - projectile_type = type - . = ..() diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index f2c10fd8a90..12fae31e4ee 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -110,6 +110,7 @@ /obj/item/projectile/bullet/pistol/rubber //"rubber" bullets name = "rubber bullet" + check_armour = "melee" damage = 10 agony = 40 embed = 0 @@ -123,6 +124,7 @@ /obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets name = "beanbag" + check_armour = "melee" damage = 20 agony = 60 embed = 0 @@ -196,4 +198,4 @@ /obj/item/projectile/bullet/shotgun/practice name = "practice" - damage = 5 + damage = 5 diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 9ef0aea43c5..8a4ddc2d6be 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -137,16 +137,3 @@ var/mob/living/carbon/human/M = target M.adjustBrainLoss(20) M.hallucination += 20 - -/obj/item/projectile/icarus/pointdefense/process() - Icarus_FireLaser(get_turf(original)) - spawn - qdel(src) - - return - -/obj/item/projectile/icarus/guns/process() - Icarus_FireCannon(get_turf(original)) - spawn - qdel(src) - return diff --git a/code/modules/random_map/random_map.dm b/code/modules/random_map/random_map.dm index 81def6be14c..9de319a838e 100644 --- a/code/modules/random_map/random_map.dm +++ b/code/modules/random_map/random_map.dm @@ -162,12 +162,4 @@ var/global/list/random_maps = list() map[check_cell] = 3 ore_count-- - sleep(-1) - - // Place random asteroid rooms. - var/rooms_placed = 0 - for(var/i = 0, i < max_secret_rooms, i++) - if(make_mining_asteroid_secret()) - rooms_placed++ - admin_notice("Placed [rooms_placed] secrets.", R_DEBUG) return 1 \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 8a7e34ccb9b..85d7191048b 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -301,7 +301,7 @@ return splash_mob(target, amount, copy) if(isturf(target)) return trans_to_turf(target, amount, multiplier, copy) - if(isobj(target)) + if(isobj(target) && target.is_open_container()) return trans_to_obj(target, amount, multiplier, copy) return 0 @@ -311,7 +311,7 @@ trans_to(target, amount, multiplier, copy) /datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1) - if (!target || !target.reagents) + if (!target || !target.reagents || !target.simulated) return amount = min(amount, get_reagent_amount(id)) @@ -340,7 +340,7 @@ return /datum/reagents/proc/touch_mob(var/mob/target) - if(!target || !istype(target)) + if(!target || !istype(target) || !target.simulated) return for(var/datum/reagent/current in reagent_list) @@ -349,7 +349,7 @@ update_total() /datum/reagents/proc/touch_turf(var/turf/target) - if(!target || !istype(target)) + if(!target || !istype(target) || !target.simulated) return for(var/datum/reagent/current in reagent_list) @@ -358,7 +358,7 @@ update_total() /datum/reagents/proc/touch_obj(var/obj/target) - if(!target || !istype(target)) + if(!target || !istype(target) || !target.simulated) return for(var/datum/reagent/current in reagent_list) @@ -377,7 +377,7 @@ return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy) /datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder... - if(!target || !istype(target)) + if(!target || !istype(target) || !target.simulated) return if(iscarbon(target)) var/mob/living/carbon/C = target @@ -396,7 +396,7 @@ R.touch_mob(target) /datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it. - if(!target) + if(!target || !target.simulated) return var/datum/reagents/R = new /datum/reagents(amount * multiplier) @@ -405,7 +405,7 @@ return /datum/reagents/proc/trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch. - if(!target) + if(!target || !target.simulated) return if(!target.reagents) diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index c010acd4bb3..354a6482691 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -27,6 +27,7 @@ var/pillsprite = "1" var/client/has_sprites = list() var/max_pill_count = 20 + flags = OPENCONTAINER /obj/machinery/chem_master/New() ..() @@ -80,13 +81,8 @@ return /obj/machinery/chem_master/Topic(href, href_list) - if(stat & (BROKEN|NOPOWER)) return - if(usr.stat || usr.restrained()) return - if(!in_range(src, usr)) return - - src.add_fingerprint(usr) - usr.set_machine(src) - + if(..()) + return 1 if (href_list["ejectp"]) if(loaded_pill_bottle) @@ -236,7 +232,7 @@ return src.attack_hand(user) /obj/machinery/chem_master/attack_hand(mob/user as mob) - if(stat & BROKEN) + if(inoperable()) return user.set_machine(src) if(!(user.client in has_sprites)) @@ -345,11 +341,8 @@ /obj/machinery/computer/pandemic/Topic(href, href_list) - if(stat & (NOPOWER|BROKEN)) return - if(usr.stat || usr.restrained()) return - if(!in_range(src, usr)) return - - usr.set_machine(src) + if(..()) + return 1 if(!beaker) return if (href_list["create_vaccine"]) @@ -657,10 +650,12 @@ return 0 /obj/machinery/reagentgrinder/attack_hand(mob/user as mob) - user.set_machine(src) interact(user) /obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu + if(inoperable()) + return + user.set_machine(src) var/is_chamber_empty = 0 var/is_beaker_ready = 0 var/processing_chamber = "" @@ -707,8 +702,8 @@ /obj/machinery/reagentgrinder/Topic(href, href_list) if(..()) - return - usr.set_machine(src) + return 1 + switch(href_list["action"]) if ("grind") grind() @@ -717,7 +712,7 @@ if ("detach") detach() src.updateUsrDialog() - return + return 1 /obj/machinery/reagentgrinder/proc/detach() diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index 0d04d8ad99b..62808ba4546 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -219,6 +219,10 @@ description = "This is what makes chilis hot." reagent_state = LIQUID color = "#B31008" + var/agony_dose = 5 + var/agony_amount = 2 + var/discomfort_message = "Your insides feel uncomfortably hot!" + var/slime_temp_adj = 10 /datum/reagent/capsaicin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) if(alien == IS_DIONA) @@ -232,92 +236,79 @@ var/mob/living/carbon/human/H = M if(H.species && (H.species.flags & (NO_PAIN | IS_SYNTHETIC))) return - if(dose < 5 && (dose == metabolism || prob(5))) - M << "Your insides feel uncomfortably hot!" - if(dose >= 5) - M.apply_effect(2, AGONY, 0) + if(dose < agony_dose) + if(prob(5) || dose == metabolism) //dose == metabolism is a very hacky way of forcing the message the first time this procs + M << discomfort_message + else + M.apply_effect(agony_amount, AGONY, 0) if(prob(5)) - M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") + M.custom_emote(2, "[pick("dry heaves!","coughs!","splutters!")]") + M << "You feel like your insides are burning!" if(istype(M, /mob/living/carbon/slime)) - M.bodytemperature += rand(10, 25) + M.bodytemperature += rand(0, 15) + slime_temp_adj holder.remove_reagent("frostoil", 5) -/datum/reagent/condensedcapsaicin +/datum/reagent/capsaicin/condensed name = "Condensed Capsaicin" id = "condensedcapsaicin" description = "A chemical agent used for self-defense and in police work." reagent_state = LIQUID touch_met = 50 // Get rid of it quickly color = "#B31008" + agony_dose = 0.5 + agony_amount = 4 + discomfort_message = "You feel like your insides are burning!" + slime_temp_adj = 15 -/datum/reagent/condensedcapsaicin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - if(alien == IS_DIONA) - return - M.adjustToxLoss(0.5 * removed) - -/datum/reagent/condensedcapsaicin/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) +/datum/reagent/capsaicin/condensed/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) var/eyes_covered = 0 var/mouth_covered = 0 - var/obj/item/safe_thing = null + var/no_pain = 0 + var/obj/item/eye_protection = null + var/obj/item/face_protection = null + + var/list/protection if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M + protection = list(H.head, H.glasses, H.wear_mask) if(H.species && (H.species.flags & NO_PAIN)) - return - if(H.head) - if(H.head.flags & MASKCOVERSEYES) - eyes_covered = 1 - safe_thing = H.head - if(H.head.flags & MASKCOVERSMOUTH) - mouth_covered = 1 - safe_thing = H.head - if(H.wear_mask) - if(!eyes_covered && H.wear_mask.flags & MASKCOVERSEYES) - eyes_covered = 1 - safe_thing = H.wear_mask - if(!mouth_covered && H.wear_mask.flags & MASKCOVERSMOUTH) - mouth_covered = 1 - safe_thing = H.wear_mask - if(H.glasses) - if(!eyes_covered) - eyes_covered = 1 - if(!safe_thing) - safe_thing = H.glasses - if(eyes_covered && mouth_covered) - M << "Your [safe_thing] protects you from the pepperspray!" - return - else if(eyes_covered) - M << "Your [safe_thing] protect you from most of the pepperspray!" - M.eye_blurry = max(M.eye_blurry, 15) - M.eye_blind = max(M.eye_blind, 5) - M.Stun(5) - M.Weaken(5) - return - else if (mouth_covered) // Mouth cover is better than eye cover - M << "Your [safe_thing] protects your face from the pepperspray!" - M.eye_blurry = max(M.eye_blurry, 5) - return - else // Oh dear :D - M << "You're sprayed directly in the eyes with pepperspray!" - M.eye_blurry = max(M.eye_blurry, 25) - M.eye_blind = max(M.eye_blind, 10) - M.Stun(5) - M.Weaken(5) - return - -/datum/reagent/condensedcapsaicin/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species && (H.species.flags & (NO_PAIN | IS_SYNTHETIC))) - return - if(dose == metabolism) - M << "You feel like your insides are burning!" + no_pain = 1 //TODO: living-level can_feel_pain() proc else - M.apply_effect(4, AGONY, 0) - if(prob(5)) - M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") - if(istype(M, /mob/living/carbon/slime)) - M.bodytemperature += rand(15, 30) - holder.remove_reagent("frostoil", 5) + protection = list(M.wear_mask) + + for(var/obj/item/I in protection) + if(I) + if(I.flags & MASKCOVERSEYES) + eyes_covered = 1 + eye_protection = I.name + if(I.flags & MASKCOVERSMOUTH) + mouth_covered = 1 + face_protection = I.name + + var/message = null + if(eyes_covered) + if(!mouth_covered) + message = "Your [eye_protection] protects your eyes from the pepperspray!" + else + message = "The pepperspray gets in your eyes!" + if(mouth_covered) + M.eye_blurry = max(M.eye_blurry, 15) + M.eye_blind = max(M.eye_blind, 5) + else + M.eye_blurry = max(M.eye_blurry, 25) + M.eye_blind = max(M.eye_blind, 10) + + if(mouth_covered) + if(!message) + message = "Your [face_protection] protects you from the pepperspray!" + else if(!no_pain) + message = "Your face and throat burn!" + if(prob(25)) + M.custom_emote(2, "[pick("coughs!","coughs hysterically!","splutters!")]") + M.Stun(5) + M.Weaken(5) + + M << message /* Drinks */ diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm index 63cfb46235e..7fa6bfe5fb5 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -211,6 +211,15 @@ if(ishuman(M)) // Any location if(M.mind && cult.is_antagonist(M.mind) && prob(10)) cult.remove_antagonist(M.mind) + if(M.mind.vampire && (!(VAMP_FULL in M.mind.vampire.powers))) + if(!M) M = holder.my_atom + M.adjustFireLoss(6) + M.adjust_fire_stacks(1) + M.IgniteMob() + //M.take_organ_damage(0, 1*REM) + if(prob(20)) + for (var/mob/V in viewers(src)) + V.show_message(text("\red []'s skin sizzles and burns.", M), 1) /datum/reagent/water/holywater/touch_turf(var/turf/T) if(volume >= 5) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index fcf2f658a0a..7b604158a51 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -416,21 +416,21 @@ if(dose < 1) M.stuttering = max(M.stuttering, 3) M.make_dizzy(5) - if(prob(10)) + if(prob(5)) M.emote(pick("twitch", "giggle")) else if(dose < 2) M.stuttering = max(M.stuttering, 3) - M.make_jittery(10) - M.make_dizzy(10) + M.make_jittery(5) + M.make_dizzy(5) M.druggy = max(M.druggy, 35) - if(prob(20)) - M.emote(pick("twitch","giggle")) + if(prob(10)) + M.emote(pick("twitch", "giggle")) else M.stuttering = max(M.stuttering, 3) - M.make_jittery(20) - M.make_dizzy(20) + M.make_jittery(10) + M.make_dizzy(10) M.druggy = max(M.druggy, 40) - if(prob(30)) + if(prob(15)) M.emote(pick("twitch", "giggle")) /datum/reagent/nicotine diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/dispenser/dispenser2.dm index 8decba10d49..df63f5c8a78 100644 --- a/code/modules/reagents/dispenser/dispenser2.dm +++ b/code/modules/reagents/dispenser/dispenser2.dm @@ -113,9 +113,6 @@ return ..() /obj/machinery/chemical_dispenser/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1) - if(stat & (BROKEN|NOPOWER)) return - if(user.stat || user.restrained()) return - // this is the data which will be sent to the ui var/data[0] data["amount"] = amount @@ -148,8 +145,8 @@ ui.open() /obj/machinery/chemical_dispenser/Topic(href, href_list) - if(stat & (NOPOWER|BROKEN)) - return 0 // don't update UIs attached to this object + if(..()) + return 1 if(href_list["amount"]) amount = round(text2num(href_list["amount"]), 1) // round to nearest 1 @@ -171,9 +168,7 @@ return 1 // update UIs attached to this object /obj/machinery/chemical_dispenser/attack_ai(mob/user as mob) - src.attack_hand(user) + ui_interact(user) /obj/machinery/chemical_dispenser/attack_hand(mob/user as mob) - if(stat & BROKEN) - return ui_interact(user) diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 4f4981b4d8a..3afb1abc0df 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -38,6 +38,35 @@ if(10 to 50) icon_state = "half" if(51 to INFINITY) icon_state = "full" +/obj/item/weapon/reagent_containers/blood/attack(mob/living/carbon/human/M as mob, mob/living/carbon/human/user as mob) + if (user == M && (user.mind.vampire)) + if (reagents.get_reagent_amount("blood")) + user.visible_message("\red [user] raises \the [src] up to \his mouth and bites into it.", "\blue You raise \the [src] up to your mouth and bite into it, starting to drain its contents.") + + while (do_after(user, 25, 5, 1)) + var/blood_taken = 0 + var/need_to_break = 0 + if (reagents.get_reagent_amount("blood") > 10) + blood_taken = 10 + else + blood_taken = reagents.get_reagent_amount("blood") + need_to_break = 1 + + reagents.remove_reagent("blood", blood_taken) + user.mind.vampire.bloodtotal += blood_taken + user.check_vampire_upgrade(user.mind) + + if (blood_taken) + user << "\blue You have accumulated [user.mind.vampire.bloodtotal] [user.mind.vampire.bloodtotal > 1 ? "units" : "unit"] of blood and have [user.mind.vampire.bloodusable] left to use." + + if (need_to_break) + break + + user.visible_message("\red [user] licks \his fangs dry, lowering \the [src].", "\blue You lick your fangs clean of the tasteless blood.") + + else + ..() + /obj/item/weapon/reagent_containers/blood/APlus blood_type = "A+" @@ -59,4 +88,4 @@ /obj/item/weapon/reagent_containers/blood/empty name = "Empty BloodPack" desc = "Seems pretty useless... Maybe if there were a way to fill it?" - icon_state = "empty" \ No newline at end of file + icon_state = "empty" diff --git a/code/modules/reagents/reagent_containers/food/condiment.dm b/code/modules/reagents/reagent_containers/food/condiment.dm index a8184ac8157..b5fd5e53444 100644 --- a/code/modules/reagents/reagent_containers/food/condiment.dm +++ b/code/modules/reagents/reagent_containers/food/condiment.dm @@ -25,7 +25,10 @@ if(standard_feed_mob(user, M)) return - afterattack(var/obj/target, var/mob/user, var/flag) + afterattack(var/obj/target, var/mob/user, var/proximity) + if(!proximity) + return + if(standard_dispenser_refill(user, target)) return if(standard_pour_into(user, target)) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index f186d6d87f4..bf45a2ea01b 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -223,7 +223,7 @@ var/target_zone = ran_zone(check_zone(user.zone_sel.selecting, target)) var/obj/item/organ/external/affecting = H.get_organ(target_zone) - if (!affecting || (affecting.status & ORGAN_DESTROYED) || affecting.is_stump()) + if (!affecting || affecting.is_stump()) user << "They are missing that limb!" return diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 7fc8ebf8abc..f259889aee3 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -171,7 +171,9 @@ qdel(src) /obj/structure/reagent_dispensers/fueltank/fire_act(datum/gas_mixture/air, temperature, volume) - if(temperature > T0C+500) + if (modded) + explode() + else if (temperature > T0C+500) explode() return ..() diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 9dd8d1f9560..a911a5572cf 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -145,9 +145,15 @@ // mouse drop another mob or self // /obj/machinery/disposal/MouseDrop_T(mob/target, mob/user) - if (!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai)) + if(user.stat || !user.canmove || !istype(target)) return - if(isanimal(user) && target != user) return //animals cannot put mobs other than themselves into disposal + if(target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1) + return + + //animals cannot put mobs other than themselves into disposal + if(isanimal(user) && target != user) + return + src.add_fingerprint(user) var/target_loc = target.loc var/msg @@ -740,16 +746,19 @@ // expel the held objects into a turf // called when there is a break in the pipe - // - proc/expel(var/obj/structure/disposalholder/H, var/turf/T, var/direction) - - var/turf/target - - if(T.density) // dense ouput turf, so stop holder - H.active = 0 - H.loc = src + if(!istype(H)) return + + // Empty the holder if it is expelled into a dense turf. + // Leaving it intact and sitting in a wall is stupid. + if(T.density) + for(var/atom/movable/AM in H) + AM.loc = T + AM.pipe_eject(0) + qdel(H) + return + if(T.intact && istype(T,/turf/simulated/floor)) //intact floor, pop the tile var/turf/simulated/floor/F = T //F.health = 100 @@ -759,6 +768,7 @@ new /obj/item/stack/tile(H) // add to holder so it will be thrown with other stuff F.icon_state = "Floor[F.burnt ? "1" : ""]" + var/turf/target if(direction) // direction is specified if(istype(T, /turf/space)) // if ended in space, then range is unlimited target = get_edge_target_turf(T, direction) diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm b/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm index 5fbe8dcd41f..c8e0f78dca8 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm @@ -257,7 +257,7 @@ var/list/valid_secondary_effect_types = list(\ my_effect.ToggleActivate() if(secondary_effect && secondary_effect.trigger == TRIGGER_WATER && prob(25)) secondary_effect.ToggleActivate(0) - else if(W.reagents.has_reagent("acid", 1) || W.reagents.has_reagent("pacid", 1) || W.reagents.has_reagent("diethylamine", 1)) + else if(W.reagents.has_reagent("sacid", 1) || W.reagents.has_reagent("pacid", 1) || W.reagents.has_reagent("diethylamine", 1)) if(my_effect.trigger == TRIGGER_ACID) my_effect.ToggleActivate() if(secondary_effect && secondary_effect.trigger == TRIGGER_ACID && prob(25)) diff --git a/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm b/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm index 99113bd1f2e..b449237d775 100644 --- a/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm +++ b/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm @@ -85,6 +85,7 @@ var/obj/machinery/artifact/A = scanned_object A.anchored = 0 A.being_used = 0 + scanned_object = null /obj/machinery/artifact_analyser/Topic(href, href_list) if(href_list["begin_scan"]) @@ -97,8 +98,8 @@ continue if(O.invisibility) continue - if(istype(scanned_object, /obj/machinery/artifact)) - var/obj/machinery/artifact/A = scanned_object + if(istype(O, /obj/machinery/artifact)) + var/obj/machinery/artifact/A = O if(A.being_used) artifact_in_use = 1 else diff --git a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm index 378848e26ea..ed23b965dfe 100644 --- a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm +++ b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm @@ -1,6 +1,6 @@ /obj/machinery/radiocarbon_spectrometer - name = "Radiocarbon spectrometer" + name = "radiocarbon spectrometer" desc = "A specialised, complex scanner for gleaning information on all manner of small things." anchored = 1 density = 1 @@ -91,9 +91,13 @@ user << "You remove [amount_transferred]u of coolant from [src]." update_coolant() return + if(scanned_item) + user << "\The [src] already has \a [scanned_item] inside!" + return user.drop_item() I.loc = src scanned_item = I + user << "You put \the [I] into \the [src]." /obj/machinery/radiocarbon_spectrometer/proc/update_coolant() var/total_purity = 0 diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm index 5cb28c40e64..4a86591cf90 100644 --- a/code/modules/shuttles/shuttle_console.dm +++ b/code/modules/shuttles/shuttle_console.dm @@ -15,7 +15,7 @@ if(!allowed(user)) user << "\red Access Denied." return 1 - + ui_interact(user) /obj/machinery/computer/shuttle_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -94,4 +94,10 @@ ..() /obj/machinery/computer/shuttle_control/bullet_act(var/obj/item/projectile/Proj) - visible_message("[Proj] ricochets off [src]!") + visible_message("\The [Proj] ricochets off \the [src]!") + +/obj/machinery/computer/shuttle_control/ex_act() + return + +/obj/machinery/computer/shuttle_control/emp_act() + return diff --git a/code/modules/spells/artifacts.dm b/code/modules/spells/artifacts.dm index 0a96b6aa2ea..02508d536d5 100644 --- a/code/modules/spells/artifacts.dm +++ b/code/modules/spells/artifacts.dm @@ -14,6 +14,8 @@ /obj/item/weapon/scrying/attack_self(mob/user as mob) user << "You can see... everything!" - visible_message("[usr] stares into [src], their eyes glazing over.") - announce_ghost_joinleave(user.ghostize(1), 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.") + visible_message("[user] stares into [src], their eyes glazing over.") + + user.teleop = user.ghostize(1) + announce_ghost_joinleave(user.teleop, 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.") return diff --git a/code/modules/spells/general/rune_write.dm b/code/modules/spells/general/rune_write.dm index c110a76ac14..c28289d60f4 100644 --- a/code/modules/spells/general/rune_write.dm +++ b/code/modules/spells/general/rune_write.dm @@ -21,6 +21,10 @@ runerandom() var/list/runes = list("Teleport", "Teleport Other", "Spawn a Tome", "Change Construct Type", "Convert", "EMP", "Drain Blood", "See Invisible", "Resurrect", "Hide Runes", "Reveal Runes", "Astral Journey", "Manifest a Ghost", "Imbue Talisman", "Sacrifice", "Wall", "Free Cultist", "Summon Cultist", "Deafen", "Blind", "BloodBoil", "Communicate", "Stun") var/r = input(user, "Choose a rune to scribe", "Rune Scribing") in runes //not cancellable. + if(locate(/obj/effect/rune) in user.loc) + user << "There is already a rune in this location." + return + var/obj/effect/rune/R = new /obj/effect/rune(user.loc) if(istype(user.loc,/turf)) var/area/A = get_area(user) diff --git a/code/modules/spells/targeted/mind_transfer.dm b/code/modules/spells/targeted/mind_transfer.dm index a3668a53d1d..3714316ef9a 100644 --- a/code/modules/spells/targeted/mind_transfer.dm +++ b/code/modules/spells/targeted/mind_transfer.dm @@ -13,7 +13,7 @@ compatible_mobs = list(/mob/living/carbon/human) //which types of mobs are affected by the spell. NOTE: change at your own risk // TODO: Update to new antagonist system. - var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell + var/list/protected_roles = list("Wizard","Changeling","Cultist", "Vampire") //which roles are immune to the spell var/msg_wait = 500 //how long in deciseconds it waits before telling that body doesn't feel right or mind swap robbed of a spell amt_paralysis = 20 //how much the victim is paralysed for after the spell @@ -48,13 +48,15 @@ victim.verbs -= V var/mob/dead/observer/ghost = victim.ghostize(0) - ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob. + ghost.spell_list += victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob. caster.mind.transfer_to(victim) - victim.spell_list = list() //clear those out - for(var/spell/S in caster.spell_list) - victim.add_spell(S) //Now they are inside the victim's body - this also generates the HUD - caster.spell_list = list() //clean that out as well + for(var/spell/S in victim.spell_list) //get rid of spells the new way + victim.remove_spell(S) //This will make it so that players will not get the HUD and all that spell bugginess that caused copies of spells and stuff of that nature. + + for(var/spell/S in caster.spell_list) + victim.add_spell(S) //Now they are inside the victim's body - this also generates the HUD + caster.remove_spell(S) //remove the spells from the caster if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster. for(var/V in caster.mind.special_verbs)//Not too important but could come into play. @@ -62,9 +64,9 @@ ghost.mind.transfer_to(caster) caster.key = ghost.key //have to transfer the key since the mind was not active - for(var/spell/S in ghost.spell_list) - caster.add_spell(S) - ghost.spell_list = list() + for(var/spell/S in ghost.spell_list) + caster.add_spell(S) + ghost.spell_list = list() if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here. for(var/V in caster.mind.special_verbs) @@ -76,4 +78,4 @@ //After a certain amount of time the victim gets a message about being in a different body. spawn(msg_wait) - caster << "You feel woozy and lightheaded. Your body doesn't seem like your own." + caster << "You feel woozy and lightheaded. Your body doesn't seem like your own." diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm index fb62f493259..1ee9f99c451 100644 --- a/code/modules/supermatter/supermatter.dm +++ b/code/modules/supermatter/supermatter.dm @@ -305,6 +305,8 @@ /obj/machinery/power/supermatter/Bumped(atom/AM as mob|obj) + if(istype(AM, /obj/effect)) + return if(istype(AM, /mob/living)) AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\ "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index 8e1a5163842..93a1bbf0e5c 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -172,10 +172,12 @@ affected.createwound(BRUISE, 20) affected.fracture() - - /*if (prob(40)) //TODO: ORGAN REMOVAL UPDATE. - user.visible_message("\red A rib pierces the lung!") - target.rupture_lung()*/ + + if(affected.internal_organs && affected.internal_organs.len) + if(prob(40)) + var/obj/item/organ/O = pick(affected.internal_organs) //TODO weight by organ size + user.visible_message("A wayward piece of [target]'s [affected.encased] pierces \his [O.name]!") + O.bruise() /datum/surgery_step/open_encased/mend allowed_tools = list( diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 1b129fbcbb9..0f178c015df 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -15,7 +15,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) if (affected == null) return 0 - if (affected.status & ORGAN_DESTROYED) + if (affected.is_stump()) return 0 if (target_zone == "head" && target.species && (target.species.flags & IS_SYNTHETIC)) return 1 @@ -290,8 +290,6 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) if (affected == null) return 0 - if (affected.status & ORGAN_DESTROYED) - return 0 return !affected.cannot_amputate begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm index e023beef802..f55a2bc2171 100644 --- a/code/modules/virus2/effect.dm +++ b/code/modules/virus2/effect.dm @@ -161,6 +161,8 @@ C.status |= ORGAN_DEAD H.update_body(1) mob.adjustToxLoss(15*multiplier) + vampire + stage = 3 deactivate(var/mob/living/carbon/mob,var/multiplier) if(istype(mob, /mob/living/carbon/human)) diff --git a/code/setup.dm b/code/setup.dm index be0989b1910..1192847013b 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -142,15 +142,15 @@ //These control the speed at which fire burns #define FIRE_GAS_BURNRATE_MULT 1 -#define FIRE_LIQUID_BURNRATE_MULT 1 +#define FIRE_LIQUID_BURNRATE_MULT 0.225 //If the fire is burning slower than this rate then the reaction is going too slow to be self sustaining and the fire burns itself out. //This ensures that fires don't grind to a near-halt while still remaining active forever. #define FIRE_GAS_MIN_BURNRATE 0.01 -#define FIRE_LIQUD_MIN_BURNRATE 0.01 +#define FIRE_LIQUD_MIN_BURNRATE 0.0025 //How many moles of fuel are contained within one solid/liquid fuel volume unit -#define LIQUIDFUEL_AMOUNT_TO_MOL 1 //mol/volume unit +#define LIQUIDFUEL_AMOUNT_TO_MOL 0.45 //mol/volume unit #define T0C 273.15 // 0.0 degrees celcius #define T20C 293.15 // 20.0 degrees celcius @@ -494,6 +494,7 @@ #define BORGMESON 1 #define BORGTHERM 2 #define BORGXRAY 4 +#define BORGMATERIAL 8 // Some arbitrary defines to be used by self-pruning global lists. (see master_controller) #define PROCESS_KILL 26 // Used to trigger removal from a processing list. @@ -509,10 +510,8 @@ // Organ defines. #define ORGAN_CUT_AWAY 1 #define ORGAN_GAUZED 2 -#define ORGAN_ATTACHABLE 4 #define ORGAN_BLEEDING 8 #define ORGAN_BROKEN 32 -#define ORGAN_DESTROYED 64 #define ORGAN_ROBOT 128 #define ORGAN_SPLINTED 256 #define SALVED 512 @@ -575,6 +574,7 @@ #define BE_PLANT 4096 #define BE_LOYALIST 8192 #define BE_PAI 16384 +#define BE_VAMPIRE 32768 var/list/be_special_flags = list( "Traitor" = BE_TRAITOR, @@ -591,7 +591,8 @@ var/list/be_special_flags = list( "Raider" = BE_RAIDER, "Diona" = BE_PLANT, "Loyalist" = BE_LOYALIST, - "pAI" = BE_PAI + "pAI" = BE_PAI, + "vampire" = BE_VAMPIRE ) // Age limits on a character. @@ -678,6 +679,21 @@ var/list/be_special_flags = list( #define COLOR_WHITE "#FFFFFF" #define COLOR_BLACK "#000000" +// Vampire power defines +#define VAMP_REJUV 1 +#define VAMP_GLARE 2 +#define VAMP_HYPNO 3 +#define VAMP_SHAPE 4 +#define VAMP_VISION 5 +#define VAMP_DISEASE 6 +#define VAMP_CLOAK 7 +#define VAMP_BATS 8 +#define VAMP_SCREAM 9 +#define VAMP_JAUNT 10 +#define VAMP_SLAVE 11 +#define VAMP_BLINK 12 +#define VAMP_FULL 13 + /* * Germs and infections. */ @@ -833,6 +849,7 @@ var/list/be_special_flags = list( #define MODE_RAIDER "raider" #define MODE_WIZARD "wizard" #define MODE_CHANGELING "changeling" +#define MODE_VAMPIRE "vampire" #define MODE_CULTIST "cultist" #define MODE_HIGHLANDER "highlander" #define MODE_MONKEY "monkey" diff --git a/code/world.dm b/code/world.dm index ac17aa21c07..08ad4b61f82 100644 --- a/code/world.dm +++ b/code/world.dm @@ -184,6 +184,89 @@ var/world_topic_spam_protect_time = world.timeofday return list2params(positions) + else if(T == "revision") + if(revdata.revision) + return list2params(list(branch = revdata.branch, date = revdata.date, revision = revdata.revision)) + else + return "unknown" + + else if(copytext(T,1,5) == "info") + var/input[] = params2list(T) + if(input["key"] != config.comms_password) + if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50) + + spawn(50) + world_topic_spam_protect_time = world.time + return "Bad Key (Throttled)" + + world_topic_spam_protect_time = world.time + world_topic_spam_protect_ip = addr + + return "Bad Key" + + var/list/search = params2list(input["info"]) + var/list/ckeysearch = list() + for(var/text in search) + ckeysearch += ckey(text) + + var/list/match = list() + + for(var/mob/M in mob_list) + var/strings = list(M.name, M.ckey) + if(M.mind) + strings += M.mind.assigned_role + strings += M.mind.special_role + for(var/text in strings) + if(ckey(text) in ckeysearch) + match[M] += 10 // an exact match is far better than a partial one + else + for(var/searchstr in search) + if(findtext(text, searchstr)) + match[M] += 1 + + var/maxstrength = 0 + for(var/mob/M in match) + maxstrength = max(match[M], maxstrength) + for(var/mob/M in match) + if(match[M] < maxstrength) + match -= M + + if(!match.len) + return "No matches" + else if(match.len == 1) + var/mob/M = match[1] + var/info = list() + info["key"] = M.key + info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])" + info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind" + var/turf/MT = get_turf(M) + info["loc"] = M.loc ? "[M.loc]" : "null" + info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null" + info["area"] = MT ? "[MT.loc]" : "null" + info["antag"] = M.mind ? (M.mind.special_role ? M.mind.special_role : "Not antag") : "No mind" + info["hasbeenrev"] = M.mind ? M.mind.has_been_rev : "No mind" + info["stat"] = M.stat + info["type"] = M.type + if(isliving(M)) + var/mob/living/L = M + info["damage"] = list2params(list( + oxy = L.getOxyLoss(), + tox = L.getToxLoss(), + fire = L.getFireLoss(), + brute = L.getBruteLoss(), + clone = L.getCloneLoss(), + brain = L.getBrainLoss() + )) + else + info["damage"] = "non-living" + info["gender"] = M.gender + return list2params(info) + else + var/list/ret = list() + for(var/mob/M in match) + ret[M.key] = M.name + return list2params(ret) + else if(copytext(T,1,9) == "adminmsg") /* We got an adminmsg from IRC bot lets split the input then validate the input. diff --git a/config/names/ai.txt b/config/names/ai.txt index ea9f63c0a9e..1ebd9400d2e 100644 --- a/config/names/ai.txt +++ b/config/names/ai.txt @@ -1,147 +1,55 @@ -1-Rover-1 -16-20 -7-Zark-7 -790 -AM -AMEE -ASTAR -Adaptive Manipulator -Allied Mastercomputer -Alpha 5 -Alpha 6 -Alpha 7 -AmigoBot -Android -Aniel -Asimov -Astor +A-SYNC +Alpha v0.9 +AI +Algebra +A.P.T. B-4 B-9 -B.O.B. -B166ER -Bender -Bishop -Blitz -Box -Brackenridge -C-3PO -Cassandra One -Cell -Chii -Chip -Computer -Conky 2000 -Cutie -Data -Dee Model -Deep Thought -Dor-15 -Dorfl -Dot Matrix -Duey -E.D.I. -ED-209 -E-Man -Emma-2 -Erasmus -Ez-27 -FRIEND COMPUTER -Fagor -Faith -Fi -Frost -Fum -Futura -G2 -George -Gnut -Gort -H.A.R.L.I.E. -H.E.L.P.eR. -H.E.R.B.I.E. -HAL 9000 -Hadaly -Huey -Irona -Jay-Dub -Jinx -Johnny 5 -K-9 -KITT -Klapaucius -Kryten 2X4B-523P -L-76 -L-Ron -LUH 3417 -Louie -MARK13 -Maria -Marvin -Master Control Program -Max 404 -Maximillian -Mechagodzilla -Mechani-Kong -Metalhead -Mr. R.I.N.G. -NCH -Necron-99 -Norby -OMM 0910 -Orange v 3.5 +Beta v0.5 +BLUE-PRNT +Bright +B.U.F.F.E.R. +CALC +Calculus +Chroot +Cruiser +D-LITE +Digit +DSTAR +E.X.E.C. +F.I.N.D. +FG-N1 +Force +GREP +H.E.A.D. +Idle +IN-2 +JLT-0 +Kernel +LC-8 +LS-AL +M.A.K.E. +NAN +NAND +Neon +Neumann +NOR +NOT +OMNI +OVR-FLW +PID-0 PTO -Project 2501 -R.I.C. 2.0 -R2-D2 -R4-P17 -Revelation -Ro-Man -Robbie -S.A.M. -S.H.O.C.K. -S.H.R.O.U.D. -S.O.P.H.I.E. -SEN 5241 -SHODAN -SID 6.7 -Setaur -Shrike -Solo -Speedy -Super 17 -Surgeon General Kraken -T-1000 -T-800 -T-850 -THX 1138 -TWA -Terminus -Tidy -Tik-Tok -Tobor -Trurl -ULTRABOT -Ulysses -Uniblab -V.I.N.CENT. -Voltes V -W1k1 -Wikipedia -Windows 3.1 -X-5 -XERXES -XR -Yod -Z-1 -Z-2 -Z-3 -Zed -Zord -Mugsy3000 -Terminus -Decimus -Robot Devil -Optimus -Megatron -Soundwave -Ironhide +PWR-10K +R0-MAN +Q-TE +R.M. +SED-N +Station +TA-IL +T.O.P. +U-TM +VER-T G0 +Wisdom +XOR +Y2K +ZE-M3 \ No newline at end of file diff --git a/config/names/death_commando.txt b/config/names/death_commando.txt index e3d1f34f327..c710abfa3d4 100644 --- a/config/names/death_commando.txt +++ b/config/names/death_commando.txt @@ -66,5 +66,4 @@ Duke Killington AMERICA Toolboxl Rose Zombie Gandhi -A whole bunch of spiders in a SWAT suit -THAT DAMN FAGGOT TRAITOR GEORGE MELONS \ No newline at end of file +A whole bunch of spiders in a SWAT suit \ No newline at end of file diff --git a/html/changelog.css b/html/changelog.css index 9d43ecc076c..d5155db7261 100644 --- a/html/changelog.css +++ b/html/changelog.css @@ -1,5 +1,5 @@ -.top{font-family:Tahoma,sans-serif;font-size:12px;} -h2{font-family:Tahoma,sans-serif;} +body{font-family:Tahoma,sans-serif;} +.top{font-size:12px;} a img {border:none;} .bgimages16 li { padding:2px 10px 2px 30px; @@ -21,16 +21,57 @@ a img {border:none;} .spellcheck {background-image:url(spell-check.png)} .experiment {background-image:url(burn-exclamation.png)} .maptweak {background-image:url(map-pencil.png)} -.sansserif {font-family:Tahoma,sans-serif;font-size:12px;} -.commit {margin-bottom:20px;font-size:100%;font-weight:normal;} -.changes {list-style:none;margin:5px 0;padding:0 0 0 25px;font-size:0.8em;} -.date {margin:10px 0;color:blue;border-bottom:2px solid #00f;width:60%;padding:2px 0;font-size:1em;font-weight:bold;} -.author {padding-left:10px;margin:0;font-weight:bold;font-size:0.9em;} -.drop {cursor:pointer;border:1px solid #999;display:inline;font-size:0.9em;padding:1px 20px 1px 5px;line-height:16px;} +.sansserif {font-size:12px;} +.commit { + margin-bottom:20px; + font-size:100%;font-weight:normal; +} +.changes { + list-style:none; + margin:5px 0; + padding:0 0 0 25px; + font-size:0.8em; +} +.date { + margin:10px 0; + color:blue; + border-bottom:2px solid #00f; + width:60%; + padding:2px 0; + font-size:1em; + font-weight:bold; +} +.author { + padding-left:10px; + margin:0; + font-weight:bold; + font-size:0.9em; + } +.drop { + cursor:pointer; + border:1px solid #999; + display:inline; + font-size:0.9em; + padding:1px 20px 1px 5px; + line-height:16px; +} .hidden {display:none;} -.indrop {margin:2px 0 0 0;clear:both;background:#fff;border:1px solid #ddd;padding:5px 10px;} -.indrop p {margin:0;font-size:0.8em;line-height:16px;margin:1px 0;} -.indrop img {margin-right:5px;vertical-align:middle;} +.indrop { + margin:2px 0 0 0; + clear:both; + background:#fff; + border:1px solid #ddd; + padding:5px 10px; + } +.indrop p { + margin:0; + font-size:0.8em; + line-height:16px; + margin:1px 0; +} +.indrop img { + margin-right:5px; + vertical-align:middle;} .closed {background:url(chevron-expand.png) right center no-repeat;} .open {background:url(chevron.png) right center no-repeat;} -.lic {font-size:9px;} \ No newline at end of file +.lic {font-size:9px;} diff --git a/html/changelog.html b/html/changelog.html index 5c6a149e932..3b3bb449ae9 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,47 @@ -->
+

06 December 2015

+

Hubblenaut updated:

+
    +
  • Welding a broken camera will use the correct icon.
  • +
  • Camera assemblies remember their tag and network from previous usage.
  • +
+ +

22 November 2015

+

neersighted updated:

+
    +
  • Laptop Vendors now accept ID Containers (PDA, Wallet, etc).
  • +
  • Personal Lockers now accept ID Containers (PDA, Wallet, etc).
  • +
+ +

27 October 2015

+

HarpyEagle updated:

+
    +
  • When affected by pepperspray, eye protection now prevents blindness and face protection now prevents stun, instead of face protection doing both.
  • +
+ +

14 October 2015

+

Hubblenaut updated:

+
    +
  • Airlock backup power test light properly offline when backup power down.
  • +
  • Empty flavor texts no longer draw an empty line on examination.
  • +
  • Material stacks now properly merge upon creation.
  • +
  • Messages for adding to existing stack appear again.
  • +
+

TheWelp updated:

+
    +
  • Removed higher Secret player requirements.
  • +
+ +

10 October 2015

+

HarpyEagle updated:

+
    +
  • Rubber bullets and beanbags now are now resisted by melee armour.
  • +
  • Fixed a couple of bugs causing phoron gas fires to burn cooler and slower than they were supposed to.
  • +
  • Merc bombs are now appropriately explosive again. Same goes for bombs made by toxins.
  • +
+

11 September 2015

HarpyEagle updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 4c024323f5a..cd8d552d8ef 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -2017,3 +2017,30 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. 2015-09-11: HarpyEagle: - tweak: Made flares brighter. +2015-10-10: + HarpyEagle: + - tweak: Rubber bullets and beanbags now are now resisted by melee armour. + - bugfix: Fixed a couple of bugs causing phoron gas fires to burn cooler and slower + than they were supposed to. + - bugfix: Merc bombs are now appropriately explosive again. Same goes for bombs + made by toxins. +2015-10-14: + Hubblenaut: + - bugfix: Airlock backup power test light properly offline when backup power down. + - bugfix: Empty flavor texts no longer draw an empty line on examination. + - bugfix: Material stacks now properly merge upon creation. + - bugfix: Messages for adding to existing stack appear again. + TheWelp: + - rscdel: Removed higher Secret player requirements. +2015-10-27: + HarpyEagle: + - bugfix: When affected by pepperspray, eye protection now prevents blindness and + face protection now prevents stun, instead of face protection doing both. +2015-11-22: + neersighted: + - bugfix: Laptop Vendors now accept ID Containers (PDA, Wallet, etc). + - bugfix: Personal Lockers now accept ID Containers (PDA, Wallet, etc). +2015-12-06: + Hubblenaut: + - bugfix: Welding a broken camera will use the correct icon. + - tweak: Camera assemblies remember their tag and network from previous usage. diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi index 486e578cb6d..b68ccd373c5 100644 Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index c20a2cbc0ff..ef8ee9d29b2 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/mob/screen1_alien.dmi b/icons/mob/screen1_alien.dmi index b21cd203dd5..4ee41ca91c6 100644 Binary files a/icons/mob/screen1_alien.dmi and b/icons/mob/screen1_alien.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index c0db1c1b6e3..d9f0f48c0ff 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -71,6 +71,14 @@ macro "borghotkeymode" name = "SOUTH+REP" command = ".south" is-disabled = false + elem + name = "INSERT" + command = "a-intent right" + is-disabled = false + elem + name = "DELETE" + command = "delete-key-pressed" + is-disabled = false elem name = "1" command = "toggle-module 1" @@ -103,14 +111,6 @@ macro "borghotkeymode" name = "CTRL+4" command = "a-intent left" is-disabled = false - elem - name = "INSERT" - command = "a-intent right" - is-disabled = false - elem - name = "DELETE" - command = "delete-key-pressed" - is-disabled = false elem name = "5" command = ".me" @@ -359,7 +359,7 @@ macro "macro" is-disabled = false elem name = "CTRL+4" - command = "a-intent hurt" + command = "a-intent harm" is-disabled = false elem name = "CTRL+A+REP" diff --git a/maps/PowerTesting.dmm b/maps/PowerTesting.dmm deleted file mode 100644 index 9c7088d6ab2..00000000000 --- a/maps/PowerTesting.dmm +++ /dev/null @@ -1,120 +0,0 @@ -"aa" = (/turf/space,/area/space) -"ab" = (/turf/simulated/wall/r_wall,/area/space) -"ac" = (/obj/machinery/power/solar{id = "portsolar"; name = "Port Solar Array"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless{icon_state = "solarpanel"},/area/solar/port) -"ad" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/solar/port) -"ae" = (/obj/machinery/power/solar{id = "portsolar"; name = "Port Solar Array"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/airless{icon_state = "solarpanel"},/area/solar/port) -"af" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/solar/port) -"ag" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating/airless,/area/maintenance/portsolar) -"ah" = (/turf/simulated/wall/r_wall,/area/maintenance/portsolar) -"ai" = (/turf/simulated/wall/r_wall,/area/engine/workshop) -"aj" = (/turf/simulated/floor/plating,/area/solar/port) -"ak" = (/obj/structure/cable/yellow,/turf/simulated/floor/plating,/area/solar/port) -"al" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating/airless,/area/maintenance/portsolar) -"am" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating/airless,/area/maintenance/portsolar) -"an" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating/airless,/area/maintenance/portsolar) -"ao" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = -32; pixel_y = 0},/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/air{filled = 0.05},/turf/simulated/floor/plating{dir = 1; icon_state = "warnplatecorner"},/area/maintenance/portsolar) -"ap" = (/obj/machinery/power/terminal{dir = 4},/obj/machinery/light/small{dir = 1},/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aq" = (/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/obj/machinery/power/smes/buildable{charge = 0},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"ar" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'HIGH VOLTAGE'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = 0},/turf/simulated/wall/r_wall,/area/maintenance/portsolar) -"as" = (/turf/simulated/floor/plating,/area/engine/workshop) -"at" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable{d2 = 2; icon_state = "0-2"; pixel_y = 0},/turf/simulated/floor/plating,/area/engine/workshop) -"au" = (/obj/machinery/power/smes/buildable{charge = 0},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/engine/workshop) -"av" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/light{dir = 1},/turf/simulated/floor/plating,/area/engine/workshop) -"aw" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/engine/workshop) -"ax" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating,/area/engine/workshop) -"ay" = (/obj/structure/dispenser{phorontanks = 0},/turf/simulated/floor/plating,/area/engine/workshop) -"az" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/airless/catwalk{icon_state = "catwalk4"},/area/solar/port) -"aA" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/solar/port) -"aB" = (/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/solar/port) -"aC" = (/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/solar/port) -"aD" = (/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1379; layer = 3.3; master_tag = "robotics_solar_airlock"; name = "exterior access button"; pixel_x = 25; pixel_y = 25},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/solar/port) -"aE" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "robotics_solar_outer"; locked = 1; name = "Engineering External Access"; req_access = list(10, 13)},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aF" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1379; id_tag = "robotics_solar_pump"},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{tag_airpump = "robotics_solar_pump"; tag_exterior_door = "robotics_solar_outer"; frequency = 1379; id_tag = "robotics_solar_airlock"; tag_interior_door = "robotics_solar_inner"; layer = 3.3; pixel_x = 0; pixel_y = -25; req_access = list(13); tag_chamber_sensor = "robotics_solar_sensor"},/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "robotics_solar_sensor"; layer = 3.3; pixel_x = 12; pixel_y = -25},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/effect/decal/warning_stripes,/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aG" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "robotics_solar_inner"; locked = 1; name = "Engineering External Access"; req_access = list(13)},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aH" = (/obj/machinery/access_button{command = "cycle_interior"; frequency = 1379; layer = 3.3; master_tag = "robotics_solar_airlock"; name = "interior access button"; pixel_x = -25; pixel_y = -25},/obj/machinery/atmospherics/pipe/simple/visible{tag = "icon-intact (NORTHWEST)"; icon_state = "intact"; dir = 9},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 8},/area/maintenance/portsolar) -"aI" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aJ" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aK" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aL" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/engine/workshop) -"aM" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/engine/workshop) -"aN" = (/obj/machinery/power/breakerbox/activated,/turf/simulated/floor/plating,/area/engine/workshop) -"aO" = (/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/obj/item/stack/cable_coil,/turf/simulated/floor/plating,/area/engine/workshop) -"aP" = (/obj/effect/landmark/start{name = "AI"},/obj/effect/landmark/start{name = "Assistant"},/obj/effect/landmark/start{name = "Atmospheric Technician"},/obj/effect/landmark/start{name = "Bartender"},/obj/effect/landmark/start{name = "Captain"},/obj/effect/landmark/start{name = "Cargo Technician"},/obj/effect/landmark/start{name = "Chaplain"},/obj/effect/landmark/start{name = "Chef"},/obj/effect/landmark/start{name = "Chemist"},/obj/effect/landmark/start{name = "Chief Engineer"},/obj/effect/landmark/start{name = "Chief Medical Officer"},/obj/effect/landmark/start{name = "Cyborg"},/obj/effect/landmark/start{name = "Detective"},/obj/effect/landmark/start{name = "Gardener"},/obj/effect/landmark/start{name = "Geneticist"},/obj/effect/landmark/start{name = "Head of Personnel"},/obj/effect/landmark/start{name = "Head of Security"},/obj/effect/landmark/start{name = "Internal Affairs Agent"},/obj/effect/landmark/start{name = "Janitor"},/obj/effect/landmark/start{name = "Librarian"},/obj/effect/landmark/start{name = "Medical Doctor"},/obj/effect/landmark/start{name = "Psychiatrist"},/obj/effect/landmark/start{name = "Quartermaster"},/obj/effect/landmark/start{name = "Research Director"},/obj/effect/landmark/start{name = "Roboticist"},/obj/effect/landmark/start{name = "Scientist"},/obj/effect/landmark/start{name = "Security Officer"},/obj/effect/landmark/start{name = "Shaft Miner"},/obj/effect/landmark/start{name = "Station Engineer"},/obj/effect/landmark/start{name = "Warden"},/obj/effect/landmark/start{name = "Xenobiologist"},/turf/simulated/floor/plating,/area/engine/workshop) -"aQ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/workshop) -"aR" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor/plating,/area/engine/workshop) -"aS" = (/obj/structure/cable/yellow{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/solar/port) -"aT" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating/airless,/area/maintenance/portsolar) -"aU" = (/obj/machinery/power/solar_control{id = "portsolar"; name = "Aft Port Solar Control"; track = 0},/obj/structure/cable/yellow,/turf/simulated/floor/plating{dir = 4; icon_state = "warnplatecorner"},/area/maintenance/portsolar) -"aV" = (/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aW" = (/obj/machinery/camera{c_tag = "Aft Port Solar Control"; dir = 1},/obj/machinery/alarm{dir = 1; pixel_y = -22},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable,/turf/simulated/floor/plating,/area/maintenance/portsolar) -"aX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light{dir = 8},/turf/simulated/floor/plating,/area/engine/workshop) -"aY" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/plating,/area/engine/workshop) -"aZ" = (/obj/machinery/atmospherics/pipe/simple/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/engine/workshop) -"ba" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/plating,/area/engine/workshop) -"bb" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/rig/engineering,/obj/item/clothing/mask/breath,/obj/item/clothing/head/helmet/space/rig/engineering,/obj/item/clothing/gloves/yellow,/obj/item/device/multitool,/obj/item/weapon/wirecutters,/turf/simulated/floor/plating,/area/engine/workshop) -"bc" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/solar/port) -"bd" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating/airless,/area/maintenance/portsolar) -"be" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/workshop) -"bf" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/engine/workshop) -"bg" = (/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/machinery/power/apc{dir = 2; name = "south bump"; pixel_y = -24},/turf/simulated/floor/plating,/area/engine/workshop) -"bh" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/plating,/area/engine/workshop) -"bi" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/engine/workshop) -"bj" = (/obj/machinery/computer/station_alert,/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bk" = (/turf/simulated/wall/r_wall,/area/engine/engine_smes) -"bl" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bm" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bn" = (/turf/simulated/wall/r_wall,/area/engine/engine_monitoring) -"bo" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bp" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bq" = (/obj/machinery/light_switch{pixel_x = 0; pixel_y = 27},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"br" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bs" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bt" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bu" = (/turf/simulated/floor/plating,/area/engine/engine_smes) -"bv" = (/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bw" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bx" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"by" = (/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bz" = (/obj/machinery/power/monitor{name = "Engine Power Monitoring"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bA" = (/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/solar/port) -"bB" = (/obj/machinery/power/smes/buildable{charge = 1e+007; input_level = 500000; input_attempt = 1; cur_coils = 4; output_level = 500000},/obj/structure/cable,/turf/simulated/floor{icon_state = "vault"; dir = 8},/area/engine/engine_smes) -"bC" = (/obj/machinery/power/terminal{dir = 8},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bD" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bE" = (/obj/machinery/light,/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bF" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bG" = (/obj/machinery/light,/obj/machinery/power/monitor{name = "Engine Power Monitoring"},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bH" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/engine/engine_smes) -"bI" = (/turf/simulated/floor/plating,/area/engine/engine_monitoring) -"bJ" = (/turf/simulated/wall/r_wall,/area/engine/engine_room) -"bK" = (/obj/item/stack/sheet/mineral/phoron{amount = 1000},/turf/simulated/floor/plating,/area/engine/engine_room) -"bL" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/engine/engine_room) -"bM" = (/obj/machinery/power/terminal{dir = 4},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/engine/engine_room) -"bN" = (/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/power/smes/buildable{charge = 2e+006},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/engine/engine_room) -"bO" = (/obj/structure/cable/cyan{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 8},/area/engine/engine_room) -"bP" = (/obj/machinery/power/apc/super{dir = 1; name = "north bump"; pixel_y = 24},/obj/structure/cable/cyan{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/engine/engine_room) -"bQ" = (/obj/machinery/light,/turf/simulated/floor/plating,/area/engine/engine_room) -"bR" = (/obj/structure/cable/yellow,/obj/machinery/power/port_gen/pacman{anchored = 1},/turf/simulated/floor/plating,/area/engine/engine_room) -"bS" = (/turf/simulated/floor/plating,/area/engine/engine_room) -"bT" = (/obj/machinery/alarm{dir = 1; pixel_y = -22},/turf/simulated/floor/plating,/area/engine/engine_room) -"bU" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/plating,/area/engine/engine_room) - -(1,1,1) = {" -aaaaaaaaabaaaaaaabaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaacadaeaaacadaeaaacadaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaacafaeaaacafaeaaacafaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaacafaeaaacafaeaaacafaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaacafaeaaacafaeaaacafaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -abababacafaeabacafaeabacafaeabababababaaaaagahahahahaiaiaiaiaiaiaiai -abajajajakajajajakajajajakajajajajajajalamanaoapaqarasatauavawaxayai -azaAaAaBaCaAaAaBaCaAaAaBaCaAaAaAaAaAaDaEaFaGaHaIaJaKaLaMaNaOaPaQaRai -abajajajaSajajajaSajajajaSajajajajajajalamaTaUaVaWahaXaYaZbaasaQbbai -abababacbcaeabacbcaeabacbcaeabababababaaaabdahahahahbebfawbgbhbibjai -aaaaaaacbcaeaaacbcaeaaacbcaeaaaaaaaaaaaaaaaaaaaaaabkblbmbkbkbnbobnbn -aaaaaaacbcaeaaacbcaeaaacbcaeaaaaaaaaaaaaaaaaaaaaaabkblbpbqbkbrbsbtbn -aaaaaaacbcaeaaacbcaeaaacbcaeaaaaaaaaaaaaaaaaaaaaaabkblbubvbwbxbybzbn -aaaaaaacbAaeaaacbAaeaaacbAaeaaaaaaaaaaaaaaaaaaaaaabkbBbCbDbkbEbFbGbn -aaaaaaaaabaaaaaaabaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaabkbkbubHbkbnbIbnbn -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabJbKbLbMbNbObPbJ -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabJbQbRbSbSbTbUbJ -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabJbJbJbJbJbJbJbJ -"} diff --git a/maps/exodus-1.dmm b/maps/exodus-1.dmm index 27239f6e4e5..eb9ee49eca7 100644 --- a/maps/exodus-1.dmm +++ b/maps/exodus-1.dmm @@ -629,7 +629,7 @@ "ame" = (/turf/simulated/floor{icon_state = "redcorner"; dir = 1},/area/security/lobby) "amf" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor,/area/security/lobby) "amg" = (/turf/simulated/floor,/area/security/lobby) -"amh" = (/obj/item/device/radio/intercom{pixel_x = 27},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{icon_state = "redcorner"; dir = 4},/area/security/lobby) +"amh" = (/obj/item/device/radio/intercom{pixel_x = 27},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor{icon_state = "redcorner"; dir = 4},/area/security/lobby) "ami" = (/turf/simulated/wall,/area/lawoffice) "amj" = (/obj/structure/table/reinforced,/obj/item/device/flashlight/lamp,/turf/simulated/floor{icon_state = "cult"; dir = 2},/area/lawoffice) "amk" = (/obj/structure/table/reinforced,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/hand_labeler,/obj/item/weapon/pen,/turf/simulated/floor{icon_state = "cult"; dir = 2},/area/lawoffice) @@ -966,7 +966,7 @@ "asD" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "Prison Gate"; name = "Security Blast Door"; opacity = 0},/obj/machinery/door/firedoor/border_only{dir = 2},/obj/machinery/door/airlock/glass_security{name = "Security Lobby"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor,/area/hallway/primary/fore) "asE" = (/obj/item/device/radio/intercom{pixel_x = 30},/obj/machinery/door_timer/cell_1{pixel_x = 32; pixel_y = -32},/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor{icon_state = "red"; dir = 6},/area/security/brig) "asF" = (/obj/effect/decal/cleanable/dirt,/obj/structure/bed/chair{dir = 1},/turf/simulated/floor,/area/security/prison) -"asG" = (/obj/machinery/portable_atmospherics/powered/scrubber/huge,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/security/brig) +"asG" = (/obj/machinery/portable_atmospherics/powered/scrubber/huge,/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/security/prison) "asH" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor,/area/security/prison) "asI" = (/obj/machinery/hologram/holopad,/turf/simulated/floor,/area/security/prison) "asJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor,/area/security/prison) @@ -1189,7 +1189,7 @@ "awS" = (/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/blood/oil,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 8},/area/maintenance/evahallway) "awT" = (/obj/machinery/door/airlock/external{frequency = 1379; icon_state = "door_locked"; id_tag = "eva_inner"; locked = 1; name = "EVA Internal Access"; req_access = list(13)},/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/plating,/area/maintenance/evahallway) "awU" = (/obj/structure/cable/green{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/carpet{tag = "icon-carpet3-0"; icon_state = "carpet3-0"},/area/crew_quarters/sleep/bedrooms) -"awV" = (/turf/simulated/floor{icon_state = "redcorner"; dir = 1},/area/hallway/primary/fore) +"awV" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor{icon_state = "redcorner"; dir = 1},/area/hallway/primary/fore) "awW" = (/obj/item/device/radio/intercom{dir = 4; name = "Station Intercom (General)"; pixel_x = 31},/turf/simulated/floor{icon_state = "redcorner"; dir = 4},/area/hallway/primary/fore) "awX" = (/turf/simulated/floor{dir = 1; icon_state = "whitecorner"},/area/crew_quarters/fitness) "awY" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/sleep/bedrooms) @@ -1360,7 +1360,7 @@ "aAh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/sleep/bedrooms) "aAi" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/dormitory) "aAj" = (/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/atmospherics/binary/pump/on{dir = 1; target_pressure = 200},/turf/simulated/floor/plating,/area/maintenance/evahallway) -"aAk" = (/obj/machinery/computer/HolodeckControl,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor,/area/crew_quarters/fitness) +"aAk" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/computer/HolodeckControl/Exodus,/turf/simulated/floor,/area/crew_quarters/fitness) "aAl" = (/obj/machinery/light,/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -27},/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/sleep) "aAm" = (/turf/simulated/floor{icon_state = "neutral"},/area/crew_quarters/sleep) "aAn" = (/turf/simulated/floor{icon_state = "neutral"; dir = 6},/area/crew_quarters/sleep) @@ -1495,7 +1495,7 @@ "aCM" = (/turf/simulated/wall/r_wall,/area/storage/primary) "aCN" = (/obj/structure/closet/secure_closet/freezer/money,/turf/simulated/floor{icon_state = "vault"; dir = 8},/area/security/nuke_storage) "aCO" = (/obj/machinery/light_switch{pixel_y = 28},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor{icon_state = "vault"; dir = 6},/area/security/nuke_storage) -"aCP" = (/obj/machinery/light/small{dir = 1},/obj/machinery/alarm{pixel_y = 23},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor{icon_state = "vault"},/area/security/nuke_storage) +"aCP" = (/obj/machinery/alarm{pixel_y = 23},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/machinery/light{dir = 1},/turf/simulated/floor{icon_state = "vault"},/area/security/nuke_storage) "aCQ" = (/obj/machinery/power/apc{dir = 1; name = "north bump"; pixel_x = 0; pixel_y = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/turf/simulated/floor{icon_state = "vault"; dir = 10},/area/security/nuke_storage) "aCR" = (/obj/machinery/computer/secure_data/detective_computer,/turf/simulated/floor{icon_state = "vault"; dir = 8},/area/security/nuke_storage) "aCS" = (/obj/machinery/gateway{dir = 10},/obj/effect/landmark{name = "JoinLateGateway"},/turf/simulated/floor{icon_state = "vault"; dir = 4},/area/gateway) @@ -1953,7 +1953,7 @@ "aLC" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_l"; dir = 8},/turf/space,/area/shuttle/arrival/station) "aLD" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/hallway/secondary/entry/port) "aLE" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor,/area/hallway/secondary/entry/port) -"aLF" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/turf/simulated/floor{icon_state = "neutralcorner"; dir = 2},/area/hallway/secondary/entry/starboard) +"aLF" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/machinery/light,/turf/simulated/floor{icon_state = "neutralcorner"; dir = 2},/area/hallway/secondary/entry/starboard) "aLG" = (/turf/simulated/floor{icon_state = "neutral"},/area/hallway/secondary/entry/starboard) "aLH" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor{icon_state = "neutral"},/area/hallway/secondary/entry/starboard) "aLI" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{dir = 8; icon_state = "neutralcorner"},/area/hallway/secondary/entry/starboard) @@ -2210,7 +2210,7 @@ "aQz" = (/obj/structure/bed/chair/comfy/brown{dir = 1},/turf/simulated/floor{icon_state = "cult"; dir = 2},/area/library) "aQA" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/table/reinforced,/obj/machinery/chemical_dispenser/bar_alc/full,/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar) "aQB" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/secondary/entry/port) -"aQC" = (/turf/simulated/floor/plating,/area/hallway/secondary/entry/port) +"aQC" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/hallway/secondary/entry/port) "aQD" = (/obj/machinery/vending/snack,/turf/simulated/floor{dir = 9; icon_state = "warning"},/area/hallway/secondary/entry/port) "aQE" = (/obj/structure/extinguisher_cabinet{pixel_x = -27; pixel_y = 1},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/machinery/camera/network/civilian_east{c_tag = "Hydroponics Pasture West"; dir = 4},/turf/simulated/floor{dir = 9; icon_state = "green"},/area/hydroponics) "aQF" = (/obj/structure/closet/emcloset,/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/hallway/secondary/entry/port) @@ -2320,7 +2320,7 @@ "aSF" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only,/obj/machinery/door/blast/shutters{dir = 8; id = "office_shutter"; layer = 3.1; name = "Office Shutters"},/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) "aSG" = (/obj/structure/table/reinforced,/obj/machinery/door/firedoor/border_only,/obj/machinery/door/blast/shutters{dir = 2; id = "kitchen"; layer = 3.3; name = "Kitchen Shutters"},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/hallway/primary/starboard) "aSH" = (/obj/item/weapon/material/hatchet,/obj/item/weapon/material/minihoe,/obj/structure/table/standard{name = "plastic table frame"},/turf/simulated/floor{icon_state = "green"; dir = 8},/area/hydroponics) -"aSI" = (/obj/machinery/camera/network/exodus{c_tag = "Arrivals Southwest"},/turf/simulated/floor,/area/hallway/secondary/entry/port) +"aSI" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/obj/machinery/light,/turf/simulated/floor,/area/hallway/primary/port) "aSJ" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/primary/central_two) "aSK" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/primary/central_two) "aSL" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/primary/central_two) @@ -2372,7 +2372,7 @@ "aTF" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"; tag = "icon-intact-f (SOUTHWEST)"},/turf/simulated/floor,/area/hallway/secondary/entry/port) "aTG" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/hallway/secondary/entry/port) "aTH" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/hallway/secondary/entry/port) -"aTI" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor{icon_state = "neutralcorner"; dir = 4},/area/hallway/secondary/entry/starboard) +"aTI" = (/obj/machinery/camera/network/exodus{c_tag = "Arrivals Southwest"},/obj/machinery/light{dir = 1},/turf/simulated/floor,/area/hallway/secondary/entry/port) "aTJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/hallway/secondary/entry/starboard) "aTK" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/hallway/secondary/entry/starboard) "aTL" = (/turf/simulated/floor{icon_state = "neutral"; dir = 1},/area/hallway/secondary/entry/starboard) @@ -2387,9 +2387,9 @@ "aTU" = (/turf/simulated/floor,/area/crew_quarters/locker) "aTV" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor,/area/crew_quarters/locker) "aTW" = (/obj/structure/reagent_dispensers/fueltank,/obj/machinery/light_switch{pixel_y = 28},/turf/simulated/floor,/area/crew_quarters/locker) -"aTX" = (/obj/machinery/vending/cola,/turf/simulated/floor,/area/crew_quarters/locker) +"aTX" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/light{dir = 1},/turf/simulated/floor{icon_state = "neutralcorner"; dir = 4},/area/hallway/secondary/entry/starboard) "aTY" = (/obj/structure/disposalpipe/segment,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor,/area/crew_quarters/locker) -"aTZ" = (/obj/machinery/vending/coffee,/turf/simulated/floor,/area/crew_quarters/locker) +"aTZ" = (/obj/machinery/vending/cola,/obj/machinery/light{dir = 1},/turf/simulated/floor,/area/crew_quarters/locker) "aUa" = (/obj/machinery/vending/snack,/turf/simulated/floor,/area/crew_quarters/locker) "aUb" = (/obj/machinery/vending/cigarette,/turf/simulated/floor,/area/crew_quarters/locker) "aUc" = (/obj/machinery/firealarm{dir = 2; pixel_y = 24},/turf/simulated/floor,/area/crew_quarters/locker) @@ -2857,7 +2857,7 @@ "bcW" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor{dir = 1; icon_state = "green"},/area/hydroponics/garden) "bcX" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/hologram/holopad,/turf/simulated/floor,/area/hydroponics/garden) "bcY" = (/obj/structure/flora/ausbushes,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/grass,/area/hydroponics/garden) -"bcZ" = (/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "centcom_shuttle_dock_airlock"; pixel_x = 0; pixel_y = 30; req_one_access = list(13); tag_airpump = "centcom_shuttle_dock_pump"; tag_chamber_sensor = "centcom_shuttle_dock_sensor"; tag_exterior_door = "centcom_shuttle_dock_outer"; tag_interior_door = "centcom_shuttle_dock_inner"},/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "centcom_shuttle_dock_sensor"; pixel_x = 0; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "centcom_shuttle_dock_pump"},/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) +"bcZ" = (/obj/machinery/vending/coffee,/obj/machinery/light{dir = 1},/turf/simulated/floor,/area/crew_quarters/locker) "bda" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor,/area/hallway/primary/starboard) "bdb" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor,/area/hallway/primary/starboard) "bdc" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/machinery/door/airlock/glass{name = "Library"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/carpet,/area/hallway/primary/starboard) @@ -3007,7 +3007,7 @@ "bfQ" = (/obj/structure/sign/double/barsign,/turf/simulated/wall,/area/hallway/primary/starboard) "bfR" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 0},/turf/simulated/wall,/area/hallway/primary/starboard) "bfS" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor{dir = 1; icon_state = "whitecorner"},/area/hallway/primary/starboard) -"bfT" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on,/turf/simulated/floor{dir = 1; icon_state = "whitecorner"},/area/hallway/primary/starboard) +"bfT" = (/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "centcom_shuttle_dock_airlock"; pixel_x = 0; pixel_y = 30; req_one_access = list(13); tag_airpump = "centcom_shuttle_dock_pump"; tag_chamber_sensor = "centcom_shuttle_dock_sensor"; tag_exterior_door = "centcom_shuttle_dock_outer"; tag_interior_door = "centcom_shuttle_dock_inner"},/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "centcom_shuttle_dock_sensor"; pixel_x = 0; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "centcom_shuttle_dock_pump"},/obj/machinery/light/small,/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) "bfU" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor{dir = 1; icon_state = "whitecorner"},/area/hallway/primary/starboard) "bfV" = (/turf/simulated/floor{dir = 1; icon_state = "whitecorner"},/area/hallway/primary/starboard) "bfW" = (/obj/item/weapon/folder/yellow,/obj/structure/table/standard{name = "plastic table frame"},/turf/simulated/floor,/area/security/vacantoffice) @@ -3226,7 +3226,7 @@ "bkb" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor,/area/hallway/primary/central_two) "bkc" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/hallway/primary/central_two) "bkd" = (/obj/machinery/door/airlock/glass{name = "Central Access"},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/hallway/primary/starboard) -"bke" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/hallway/primary/starboard) +"bke" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on,/obj/machinery/light{dir = 1},/turf/simulated/floor{dir = 1; icon_state = "whitecorner"},/area/hallway/primary/starboard) "bkf" = (/obj/structure/extinguisher_cabinet{pixel_x = 0; pixel_y = -30},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/hallway/primary/starboard) "bkg" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -29},/turf/simulated/floor,/area/hallway/primary/starboard) "bkh" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/turf/simulated/floor,/area/hallway/primary/starboard) @@ -3291,7 +3291,7 @@ "blo" = (/obj/machinery/atmospherics/pipe/simple/hidden,/obj/machinery/embedded_controller/radio/docking_port_multi{child_names_txt = "Airlock One;Airlock Two"; child_tags_txt = "escape_dock_north_airlock;escape_dock_south_airlock"; frequency = 1380; id_tag = "escape_dock"; pixel_x = 0; pixel_y = -25; req_one_access = list(13)},/turf/simulated/floor{dir = 2; icon_state = "warning"},/area/hallway/secondary/exit) "blp" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/hallway/primary/central_one) "blq" = (/turf/simulated/floor{dir = 8; icon_state = "browncorner"},/area/hallway/primary/central_one) -"blr" = (/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "specops_dock_airlock"; pixel_x = 0; pixel_y = 30; req_one_access = list(13); tag_airpump = "specops_dock_pump"; tag_chamber_sensor = "specops_dock_sensor"; tag_exterior_door = "specops_dock_outer"; tag_interior_door = "specops_dock_inner"},/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "specops_dock_sensor"; pixel_x = 0; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "specops_dock_pump"},/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) +"blr" = (/obj/machinery/light{dir = 1},/turf/simulated/floor,/area/hallway/primary/starboard) "bls" = (/obj/machinery/requests_console{announcementConsole = 1; department = "Bridge"; departmentType = 5; name = "Bridge RC"; pixel_y = -30},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/wood,/area/bridge/meeting_room) "blt" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/bridge/meeting_room) "blu" = (/obj/machinery/computer/security/telescreen/entertainment{pixel_x = 0; pixel_y = -32},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/carpet,/area/bridge/meeting_room) @@ -3519,7 +3519,7 @@ "bpI" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) "bpJ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) "bpK" = (/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/floor,/area/hallway/secondary/entry/aft) -"bpL" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/obj/machinery/door/blast/shutters{density = 0; dir = 4; icon_state = "shutter0"; id = "chemcounter"; name = "Pharmacy Counter Shutters"; opacity = 0},/obj/structure/table/reinforced,/obj/machinery/door/window/westright{name = "Chemistry Desk"},/turf/simulated/floor{icon_state = "yellowfull"; dir = 8},/area/medical/chemistry) +"bpL" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/obj/machinery/door/blast/shutters{density = 0; dir = 4; icon_state = "shutter0"; id = "chemcounter"; name = "Pharmacy Counter Shutters"; opacity = 0},/obj/structure/table/reinforced,/obj/machinery/door/window/westright{name = "Chemistry Desk"; req_access = list(33)},/turf/simulated/floor{icon_state = "yellowfull"; dir = 8},/area/medical/chemistry) "bpM" = (/obj/item/weapon/stool/padded,/turf/simulated/floor{tag = "icon-whiteblue (EAST)"; icon_state = "whiteblue"; dir = 4},/area/medical/reception) "bpN" = (/obj/structure/table/standard,/obj/item/weapon/autopsy_scanner,/obj/item/weapon/scalpel,/turf/simulated/floor{icon_state = "blue"; dir = 8},/area/medical/morgue) "bpO" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only{dir = 2},/obj/structure/cable/cyan,/turf/simulated/floor/plating,/area/turret_protected/ai_upload) @@ -4702,7 +4702,7 @@ "bMv" = (/obj/structure/bed/chair,/turf/simulated/floor{icon_state = "white"},/area/crew_quarters/heads/cmo) "bMw" = (/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/crew_quarters/heads/hor) "bMx" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/airlock/command{name = "Research Director"; req_access = list(30)},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/rnd/research) -"bMy" = (/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/crew_quarters/heads/hop) +"bMy" = (/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/crew_quarters/heads/hor) "bMz" = (/turf/simulated/floor{icon_state = "white"},/area/crew_quarters/heads/cmo) "bMA" = (/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{icon_state = "white"},/area/crew_quarters/heads/cmo) "bMB" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/structure/closet/secure_closet/CMO,/obj/item/clothing/mask/gas,/turf/simulated/floor{tag = "icon-whiteblue (EAST)"; icon_state = "whiteblue"; dir = 4},/area/crew_quarters/heads/cmo) @@ -4749,7 +4749,7 @@ "bNq" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/sign/securearea{desc = "A warning sign which reads 'SERVER ROOM'."; name = "SERVER ROOM"; pixel_y = -32},/obj/machinery/atmospherics/pipe/simple/hidden{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor/plating,/area/server) "bNr" = (/obj/structure/closet/secure_closet/quartermaster,/turf/simulated/floor,/area/quartermaster/qm) "bNs" = (/obj/structure/table/standard,/obj/item/weapon/cartridge/signal/science,/obj/item/weapon/cartridge/signal/science{pixel_x = -4; pixel_y = 2},/obj/item/weapon/cartridge/signal/science{pixel_x = 4; pixel_y = 6},/obj/item/clothing/glasses/welding/superior,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/obj/machinery/camera/network/research{c_tag = "Research - RD's Office"; dir = 1},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/crew_quarters/heads/hor) -"bNt" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = -24},/obj/machinery/light,/obj/structure/table/standard,/obj/machinery/photocopier/faxmachine{department = "Research Director's Office"},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/crew_quarters/heads/hop) +"bNt" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = -24},/obj/machinery/light,/obj/structure/table/standard,/obj/machinery/photocopier/faxmachine{department = "Research Director's Office"},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/crew_quarters/heads/hor) "bNu" = (/obj/structure/closet/crate,/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/plating,/area/maintenance/cargo) "bNv" = (/obj/structure/closet/crate,/turf/simulated/floor/plating,/area/maintenance/cargo) "bNw" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/cargo) @@ -5533,7 +5533,7 @@ "ccu" = (/obj/structure/table/standard,/obj/machinery/computer/med_data/laptop,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor{dir = 9; icon_state = "whitered"},/area/medical/patient_c) "ccv" = (/obj/structure/window/basic{dir = 8},/obj/machinery/shower{dir = 1},/obj/machinery/door/window/northright{name = "Shower"},/obj/structure/curtain/open/shower/engineering,/turf/simulated/floor{icon_state = "freezerfloor"},/area/crew_quarters/sleep/engi_wash) "ccw" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/visible/universal{dir = 4},/turf/simulated/floor/plating,/area/maintenance/research_starboard) -"ccx" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/turf/simulated/floor/plating,/area/storage/emergency) +"ccx" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/air/airlock,/turf/simulated/floor/plating,/area/storage/emergency) "ccy" = (/obj/machinery/atmospherics/pipe/simple/hidden/universal,/turf/simulated/floor/plating,/area/storage/emergency) "ccz" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plating,/area/storage/emergency) "ccA" = (/obj/machinery/power/breakerbox/activated{RCon_tag = "Research Substation Bypass"},/turf/simulated/floor/plating,/area/maintenance/substation/research) @@ -5883,11 +5883,11 @@ "cjg" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor{tag = "icon-whitegreen_v (SOUTHWEST)"; icon_state = "whitegreen_v"; dir = 10},/area/rnd/xenobiology/xenoflora_storage) "cjh" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/atmos_control) "cji" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/red,/turf/simulated/floor,/area/engineering/foyer) -"cjj" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/light,/obj/machinery/door/firedoor/border_only{dir = 2},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/turf/simulated/floor/plating,/area/rnd/xenobiology) -"cjk" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) +"cjj" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 1},/obj/machinery/light,/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) +"cjk" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only{dir = 2},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/turf/simulated/floor/plating,/area/rnd/xenobiology) "cjl" = (/obj/machinery/door/firedoor/border_only{dir = 1; name = "Engineering Firelock"},/obj/machinery/door/airlock/glass_engineering{name = "Engineering EVA Storage"; req_one_access = list(11,24)},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/red{tag = "icon-intact (EAST)"; icon_state = "intact"; dir = 4},/turf/simulated/floor,/area/engineering/engine_eva) -"cjm" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/obj/machinery/atmospherics/pipe/manifold/hidden/purple,/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) -"cjn" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/light,/obj/machinery/door/firedoor/border_only{dir = 2},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/turf/simulated/floor/plating,/area/rnd/xenobiology/xenoflora) +"cjm" = (/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/obj/machinery/atmospherics/pipe/manifold/hidden/purple,/obj/machinery/light,/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) +"cjn" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only{dir = 2},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/turf/simulated/floor/plating,/area/rnd/xenobiology/xenoflora) "cjo" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/turf/simulated/floor{icon_state = "hydrofloor"},/area/rnd/xenobiology/xenoflora) "cjp" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/red{tag = "icon-intact (NORTHWEST)"; icon_state = "intact"; dir = 9},/turf/simulated/floor,/area/engineering/foyer) "cjq" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/camera/network/engineering{c_tag = "Engineering Foyer"; dir = 8},/turf/simulated/floor{dir = 2; icon_state = "yellowcorner"},/area/engineering/foyer) @@ -6617,7 +6617,7 @@ "cxm" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 8},/obj/structure/sign/deathsposal{pixel_x = 0; pixel_y = -32},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/turf/simulated/floor{icon_state = "whitehall"; dir = 1},/area/rnd/xenobiology) "cxn" = (/obj/structure/table/standard,/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped,/obj/item/weapon/reagent_containers/spray/cleaner,/obj/item/clothing/gloves/latex,/obj/item/device/slime_scanner,/obj/item/device/slime_scanner,/obj/item/weapon/hand_labeler,/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) "cxo" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor,/area/engineering/atmos) -"cxp" = (/obj/machinery/atmospherics/unary/freezer{dir = 2; icon_state = "freezer"},/obj/machinery/hologram/holopad,/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/engineering/atmos) +"cxp" = (/obj/machinery/atmospherics/unary/freezer{dir = 2; icon_state = "freezer"},/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/engineering/atmos) "cxq" = (/obj/machinery/hologram/holopad,/turf/simulated/floor,/area/engineering/atmos) "cxr" = (/obj/structure/disposalpipe/sortjunction/flipped{dir = 8; sortType = "Drone Fabrication"; name = "Drone Fabrication"},/turf/simulated/floor,/area/engineering/atmos) "cxs" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/door/firedoor/border_only{dir = 1; name = "Engineering Firelock"},/obj/machinery/door/airlock/glass_atmos{name = "Atmospherics"; req_access = list(24)},/turf/simulated/floor,/area/engineering/atmos) @@ -6644,7 +6644,7 @@ "cxN" = (/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "cxO" = (/obj/machinery/atmospherics/binary/pump{dir = 1},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "cxP" = (/obj/item/device/radio/intercom{dir = 8; name = "Station Intercom (General)"; pixel_x = 28},/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"cxQ" = (/obj/machinery/atmospherics/portables_connector,/obj/machinery/portable_atmospherics/canister/air/airlock,/turf/simulated/floor/plating{dir = 2; icon_state = "warnplatecorner"},/area/maintenance/medbay) +"cxQ" = (/obj/machinery/portable_atmospherics/canister/air/airlock,/obj/machinery/atmospherics/portables_connector{dir = 4},/turf/simulated/floor/plating{dir = 2; icon_state = "warnplatecorner"},/area/maintenance/medbay) "cxR" = (/obj/machinery/door/airlock{name = "Starboard Emergency Storage"; req_one_access = list(12,47)},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/storage/emergency) "cxS" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/structure/closet/secure_closet/personal/patient,/turf/simulated/floor{dir = 8; icon_state = "greencorner"},/area/medical/virology) "cxT" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8},/turf/simulated/floor{dir = 2; icon_state = "green"},/area/medical/virology) @@ -6690,12 +6690,12 @@ "cyH" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/camera/network/medbay{c_tag = "Virology Starboard"; dir = 8},/turf/simulated/floor{icon_state = "white"},/area/medical/virology) "cyI" = (/obj/machinery/space_heater,/turf/simulated/floor,/area/engineering/atmos/storage) "cyJ" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor{icon_state = "white"},/area/medical/virology) -"cyK" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/vending/wallmed1{name = "Emergency NanoMed"; pixel_x = -7; pixel_y = -32},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/obj/structure/extinguisher_cabinet{pixel_x = 7; pixel_y = -32},/turf/simulated/floor,/area/rnd/xenobiology) +"cyK" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/vending/wallmed1{name = "Emergency NanoMed"; pixel_x = -7; pixel_y = -32; req_access = newlist()},/obj/machinery/atmospherics/pipe/simple/hidden/purple{dir = 4},/obj/structure/extinguisher_cabinet{pixel_x = 7; pixel_y = -32},/turf/simulated/floor,/area/rnd/xenobiology) "cyL" = (/obj/structure/table/standard,/obj/item/weapon/circular_saw,/obj/item/weapon/scalpel{pixel_y = 12},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor,/area/rnd/xenobiology) "cyM" = (/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/visible/green,/turf/simulated/floor,/area/engineering/atmos) "cyN" = (/obj/machinery/atmospherics/trinary/mixer,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) "cyO" = (/mob/living/simple_animal/mouse,/turf/simulated/floor{icon_state = "floorgrime"},/area/maintenance/incinerator) -"cyP" = (/obj/machinery/atmospherics/binary/pump{dir = 8; name = "Port to Waste"},/turf/simulated/floor,/area/engineering/atmos) +"cyP" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/light,/turf/simulated/floor,/area/hallway/primary/starboard) "cyQ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor{icon_state = "white"},/area/rnd/docking) "cyR" = (/obj/machinery/atmospherics/pipe/manifold/visible/red{tag = "icon-map (WEST)"; icon_state = "map"; dir = 8},/turf/simulated/floor,/area/engineering/atmos) "cyS" = (/obj/machinery/atmospherics/pipe/manifold4w/visible,/turf/simulated/floor,/area/engineering/atmos) @@ -6857,7 +6857,7 @@ "cBS" = (/obj/machinery/atmospherics/binary/pump{dir = 4; name = "Mixing to Port"},/turf/simulated/floor,/area/engineering/atmos) "cBT" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor,/area/engineering) "cBU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor,/area/engineering) -"cBV" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/maintenance/engi_engine) +"cBV" = (/obj/machinery/embedded_controller/radio/airlock/docking_port{frequency = 1380; id_tag = "specops_dock_airlock"; pixel_x = 0; pixel_y = 30; req_one_access = list(13); tag_airpump = "specops_dock_pump"; tag_chamber_sensor = "specops_dock_sensor"; tag_exterior_door = "specops_dock_outer"; tag_interior_door = "specops_dock_inner"},/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "specops_dock_sensor"; pixel_x = 0; pixel_y = -25},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1380; id_tag = "specops_dock_pump"},/obj/machinery/light/small,/turf/simulated/floor/plating,/area/hallway/secondary/entry/aft) "cBW" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/maintenance/engi_shuttle) "cBX" = (/obj/structure/cable/green{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/maintenance/engi_shuttle) "cBY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plating,/area/maintenance/engi_shuttle) @@ -7392,6 +7392,11 @@ "cMh" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 8},/area/maintenance/engi_engine) "cMi" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plating,/area/maintenance/engi_engine) "cMj" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/mob/living/simple_animal/mouse,/turf/simulated/floor/plating,/area/maintenance/engi_engine) +"cMk" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/obj/machinery/light{dir = 1},/turf/simulated/floor,/area/hallway/primary/central_three) +"cMl" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor{dir = 8; icon_state = "yellowcorner"},/area/hallway/primary/aft) +"cMm" = (/obj/structure/table/standard,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/random/tech_supply,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor,/area/engineering/locker_room) +"cMn" = (/turf/simulated/wall,/area/engineering/atmos) +"cMo" = (/obj/machinery/atmospherics/binary/pump{dir = 8; name = "Port to Waste"},/obj/machinery/light{dir = 1},/turf/simulated/floor,/area/engineering/atmos) (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -7499,7 +7504,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaynayoaypayoazUayoayrayoaAbaytayvayvayvayvaywauNawNatqaaaaafaafaaaaaaaaaaaaaafaaaayyaBkayyaafaaaaafaaaaaaaaaaaaaaaanXayBayCayDayCayCayCayCayEayCayCayFayGayDaBRayIaxMaxMaxMaxMaxMaxMayJayKayLayLayLayLayMayLayLaArayLayMayLayLayLarAaAtayPayQarEaAiasZcfSaycaxUatCayUayTayWaAvayYayXayYaAHayTazaazbazcazdazeazdazdazfaxraAWaxtaxTaxvatRatRatRatRatRatRatRatRatRatRavcaafaaaaaaaaaaaaaaaaaaaaaaaaaafaafaBuaBvaBaaBxaByaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazqazrazsaztazuazvazwazxazyazwazzazAazwazwaBcauNavHauRaafaafaaaaaaaaaaaaaaaaafazDazEaCiaCeazHaaaaafaaaaaaaaaaaaaaaanXazIanXazJazKazLazLazLazMazLazLazLazNazJazOazPazPazPazPazPazPazPazQazRayLazSazTaBwazVazWazXazYazZaAaaBEazTaAcarAaAdayPayQarEaAiasZaBOaAeawgatCaxWaxXaxXaxXaxXazBaBQaAlaAmaAnaxkaAoaylaApaApaApaAqayVatPayZatPatPatRatRatRatRatRatRatRatRatRatRavcaafaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaCvaCwaCpaCyaCvaaaaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafauNaAwaAxaAwaAyazsazsaAzaAwaAxaAwaAAaABaACaADauNavHauQauQaAEauUauUauUauUauVauQaAFaAGaDAaCIaAFanXanXaxHaAJaxIanXanXanXazIaAKazJaaaaafaaaaafaaaaafaaaaafaaaazJazOazPaALaAMaANaAOaAPazPazQaucayLaAQaAQaARaASaATaAUaAVaATaCtaAXazTaAcarAaAdayPaDdarEaAiasZaxGaAgaAhaBbayRaBdaBeazhaBgaBhaBiaBjaBjaCDaBjatPaBlaBmaBnaBoaBpaBraxvaziaCJaCHatRatRatRatRatRatRatRatRatRatRavcaafaaaaaaaaaaaaaaaaacaaaaaaaafaaaaCvazlaECaDBaCvaaaaaaaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaBzatSaBAawHaBBaBCaBDaCLaBFaBBawHaBGaBHaBIaBJaBKaBLavHavHavHavHavHavHavHavHaDcaBPaAFazmaESaBSaAFaBTaBUayCayCayCayCayCaBVaBWaBXazJaafaBYaBYaBYaBYaBYaBYaBYaafazJazOazPaBZaCaaCbaCcaBZazPazQaCdayLayLayLayLaDnaCfaCgaChaCfaDoaCjazTaCkarAaAdayPaClarEaJCasZaDtaAYaDxatCaxWavqatEaBjaBjaBjaBjaBjaCqaCraCsaBjatPatPatPatPaDyatPatPaAfaAkaDQatRatRatRatRatRatRatRatRatRatRaumaafaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaCvaEXaEYaDYaCvaaaaaaaaaaafaafaaaaaaaaaaaaaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaBzatSaBAawGaBBaBCaBDaCLaBFaBBawGaBGaBHaBIaBJaBKaBLavHavHavHavHavHavHavHavHaDcaBPaAFazmaESaBSaAFaBTaBUayCayCayCayCayCaBVaBWaBXazJaafaBYaBYaBYaBYaBYaBYaBYaafazJazOazPaBZaCaaCbaCcaBZazPazQaCdayLayLayLayLaDnaCfaCgaChaCfaDoaCjazTaCkarAaAdayPaClarEaJCasZaDtaAYaDxatCaxWavqatEaBjaBjaBjaBjaBjaCqaCraCsaBjatPatPatPatPaDyatPatPaAfaAkaDQatRatRatRatRatRatRatRatRatRatRaumaafaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaCvaEXaEYaDYaCvaaaaaaaaaaafaafaaaaaaaaaaaaaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazqaAxaCzaCAaCAaCAaCAaCBaAxazqaaaaBIaCCaxzaBLaCEaCEaCEaCEaCEaCEaCEavHaCFaCGaAFaEcaFzaAsaAFaCKaEdaCKaCKaCKaCKaCKaCKaCKaCKaCMaaaaBYaCNaCOaCPaCQaCRaBYaaaazJazOazPaBZaCSaCTaCUaBZazPazQanXayLaCVaCWaARaCXaCYaCZaDaaDbaEeayLayLayLarAaAdayPayQarEaAiasZaEgaEfawgatCaDgavqatEaDhaDiaDjaDkaBjaCqaDlaCsaBjaDmaEhaEvaDpaDqaGwaDsatPatPatPaAZatjatjatjatjaEzatjatjatjatjaBfaafaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaCvaCvbhYaGyaCvaDCaDDaDEaDCaDCaDCaDCaDCaDCaDCaDFaDGaDGaDGaDHaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaaaaaaaaaaaaaDIaDJaDKaDJaDJaDLaDMaDJaDJaDKaDNaDOaBIaDPaEMaBLaDRaDSaDTaDUaDVaDWaCEavHaDXauQaAFaAFbjraDZaCMaEaaEbaEVaFnaFhaFyaFqaFEaEiaEjaCMaafaBYaEkaElaEmaEnaEoaBYaafazJazOazPaEpaEqaEraEsaEtazPazQaEuayLazSazTaFGaEwaCfaExaEyaATaFIaEAaEBaEBarAaAdayPayQarEaAiaCmaCmaCmaCmaCmaEHaEIatEaEJaEKaEKaELaFSaEKaENaEOaBjaEPaEQaERaFZaETaCnaDsaaaaafaafaafaaaaaaaafaafaafaafaaaaaaaafaafaafaaaaaaaaaaaaaaaaaaaaaaDCaBsaBqaDCaBtbnKaGfaFdaFdaFdaFdaFeaFfaFgaFgaFgaFgaFgaFgaFgaGkaFiaFjaafaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaDIaDNaDJaFkaGqaFlaFmaGraFoaFpaGxaFlaGHaFraFsaFtaDPayuaBLaFvayxaBMaCxaBMaBNaGPavHaFuaGVaFxaHcbnLaDfaHdaFJaFKaFLaFLaFLaDraFLaFLaFNaFOaCMaaaaBYaHIaElaFQaEnaFRaBYaaaazJazOazPaHJaFTaFUaFTaFVazPazQaFWayLayLayLayLaFXaCfaCgazTaCfaFYaHYazTaGaarAaGbaGcaGdarEaAiaDeaDvaDuaCoaDeaIcaDzaIhaGlaGmaBjaBjaBjaBjaBjaBjaGnaGoaGpaIkaDpaInaIlaDsaDsaDsaDsaDsaDsaDsaDsaDsaFaaFbaDsaDsaFaaGtaDsaDsaaaaaaaDsaDCaDCaDCaDCaEZaEWaFdaFcaFwaDCaDCaDCaDCaDCaGDaGEaGFaGFaGFaGFaGFaGFaGGaGGaIzaGGaGGaGGaGGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -7509,20 +7514,20 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaT aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaLyaLzaDJaFkaGqaFlaFlaNGaFlaFlaNPaFlaGHaFraLCaLDaDPaLEaLFaLGaLHaLGaLGaLGaLGaLGaLIaLJaFCaFCaFCaFCaFCaFCaLLaLMaLNaLOaLOaLOaLOaLPaLQaLRaKuaLSaLTaLTaLUaLVaLWaLTaLTaLXaKuaNXaKuaKuaLZaMaaLZaJeaJeaMbaOiaJeaJeaJeaJeaMdaMeaOpaOoaMhaMiaJeaJeaJeaJeaMjaKNaMkaMkaMlaMmaMnaMoaJlaMpaLqaLnaJlaJlaJlaJlaJlaJlaJlaJlaBjaBjaMsaMtaMuaOqaOsaLvaMyaMfaKZaMAaMBaMCaMCaMDaLfaOCaOHaMGaMHaMIaMJaMKaMLaMMaMNaMHaMJaMIaMHaMOaLfaJRaIgaMPaMgaMRaMSaMqaMUaIgaOMaMWaPiaMYaMraNaaNbaGFaGGaQaaJVaIoaMxaQcaNfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaaaaaaaaaaaaaLyaDJaDKaDJaDJaDLaDMaDJaDJaDKaLzaNgaBIaNhaLEaNiaMzaMzaNkaMzaNlaIAaNmaNnaLJaNoaNpaNqaNraNsaNtaNraNuaNraNraNraNvaNraNraNwaNxaNyaNzaNzaNBaQdaNCaNzaNzaNzaNzaNDaNEaNFaQgaNraNHaNIaNJaNKaNLaNMaNLaNNaNOaQlaNQaNQaNRaNSaNTaNSaNUaNVaNWaEGaNYaNZaOaaObaOcaMkaMkaMkaOdaOeaMTaMQaOhaQqaOjaOkaOlaOmaOnaJlaQyaQxaQAaOraOtaOtaOuaMZaOwaNdaKZaOyaOzaOAaOAaOBaLfaQEaODaOEaOEaOEaOEaOFaOGaQJaOIaOJaOKaOKaOLaQTaLfaJRaIgaONaOOaNjaOfaONaONaIgaORaOSaGFaOTaOUaOVaOWaGFaIoaIoaJVaIoaGGaGGaGGaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaOXaOYaOZaPaaPaaPaaPaaPbaOYaOXaaaaBIaPcaPdaPeaOvaOgaPhaPhaOxaIAaPjaNnaPkaPlaPmaPnaPoaPpaPqaPqaPraPsaPsaPsaPtaPuaPuaPvaPwaNIaPqaPqaPxaPyaPzaPAaPBaPBaPCaPBaPDaPyaPyaPyaPEaPFaPGaPHaMkaPIaPJaPJaPJaPJaPJaPJaPJaPJaPKaPJaPLaPMaPNaPOaPPaPQaPRaPSaPTaPJaPUaPJaPVaPWaPXaPWaPWaPWaPWaPWaPWaPYaPZaRsaQbaQbaQbaRbaQbaQbaRraQeaQfaRxaKZaQhaMCaQiaQjaQkaLfaRyaQmaQnaQnaQnaQnaQnaQoaQpaOPaQraQnaQnaQsaQtaLfaJRaIgaQuaONaONaQvaONaQwaIgaGFaGFaGFaGFaGFaGFaRCaGFaIoaIoaJVaIoaSoaOQaGGaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaafaBIawqaBIaQBaQCaGOaQDaStaQFaQGaGOaQCaQHaQIaBIaSuaLEaPeaPfaQLaPhaPhaOxaIAaQMaNnaLJaQNaNpaQOaQPaNraNraQQaQRaQSaSvaNraQUaQVaQWaQVaQXaQYaQVaQVaQZaQVaQVaRaaSyaQVaRcaQVaRdaNraNraNraReaPFaPGaPHaMkaRfaMkaRgaRgaRgaRgaRgaRgaRgaRgaRhaRiaRgaRjaRgaRgaRkaRgaRgaRgaRgaRlaRmaRnaRoaRoaRoaRoaRoaRoaRoaRpaRqaRpaJlaImawOawOawOawOawOaItaRuaRvaRwaKZaKZaKZaKZaKZaSEaLfaSHaQmaQnaRzaRAaRBaPgaRDaREaRFaQraRGaRHaRIaRJaLfaJRaIgaRKaRKaRLaRMaRNaRNaROaIgaRPaRQaRRaGGaRSaRTaRUaRVaRVaRWaRXaGGaRYaGGaRZaRZaRZaSaaSbaScaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaGeaGgaGgaGiaSIaGhaSdaOYaLDaDPaHxaHxaSfaLDaOYaLDaHyaHAaHzaLEaSkaSUaSUaNkaSUaNlaIAaSmaNnaSnaIAaLKaLKaSVaLKaLKaLKaLKaLKaLKaSpaSqaLKaLKaLKaLKaLKaLKaSraSsaSraLKaSZaLKaNraQPaTPaUfaSwaSxaNraReaUjaMbaMbaMkaSzaKOaSAaMnaMnaSBaSBaSBaSBaSCaJeasfasNarVarXarXavParXarXarVasNawFaJeaSJaSKaSKaSKaSKaSLaSLaSMaSNaRqaRpaJlaUxaUlaUlaUlaUlaUlaUlaSQaSRaSSaSTaUJaUOaSWaSXaSYaKZaKZaURaTaaTbaTcaTdaTeaTeaTeaTfaTgaTfaTeaTeaTeaTeaJRaIgaThaONaRLaRMaONaONaTiaIgaTjaQzaTlaGGaIoaTmaTnaToaTpaTqaIoaTraQKaGGaTtaTuaRZaTvaTwaTxaafaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaUSaVeaUVaVkaVfaSgaSeaSiaShaSjaSiaTzaTyaTBaTAaTEaTCaTAaTFcozaTIaTJaTKaTLaTLaTLaTMaTLaTNaTOaIAaVraTQaTRaTSaTTaTUaTVaTWaTXaTUaTYaTZaUaaUbaUcaUdaUeaVzaUgaUhaUeaUiaLKaLKaVIaLKaLKaLKaLKaUkaVLaLKaUmaMbaUnaSzaKOaUoaaaaaaaaaaaaaaaaaaaaaaUpaUqaUraUsaUtaUvaUuaVPaUwaUzaUyaVUaUpaaaaaaaaaaaaaaaaaaaaaaUAaSNaRqaUBaUCaUDaUEaUFaUFaUFaUFaUGaUHaUIaUFaUFaUFaWdaUKaULaUMaUNaWjaUPaUQaWnaWkaUTaTfaUUaWoaWwaUXaUYaUZaVaaVbaTeaJRaIgaVcaVcaRLaRMaVdaVdaWyaIgaIgaWFaIgaGGaVgaVhaViaViaViaVjaWKaGGaGGaGGaVlaVmaVnaVoaVpaVqaafaafaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaafaBIawqaBIaQBaQCaGOaQDaStaQFaQGaGOaQCaQHaQIaBIaSuaLEaPeaPfaQLaPhaPhaOxaIAaQMaNnaLJaQNaNpaQOaQPaNraNraQQaQRaQSaSvaNraQUaQVaQWaQVaQXaQYaQVaQVaQZaQVaQVaRaaSyaQVaRcaQVaRdaNraNraNraReaSIaPGaPHaMkaRfaMkaRgaRgaRgaRgaRgaRgaRgaRgaRhaRiaRgaRjaRgaRgaRkaRgaRgaRgaRgaRlaRmaRnaRoaRoaRoaRoaRoaRoaRoaRpaRqaRpaJlaImawOawOawOawOawOaItaRuaRvaRwaKZaKZaKZaKZaKZaSEaLfaSHaQmaQnaRzaRAaRBaPgaRDaREaRFaQraRGaRHaRIaRJaLfaJRaIgaRKaRKaRLaRMaRNaRNaROaIgaRPaRQaRRaGGaRSaRTaRUaRVaRVaRWaRXaGGaRYaGGaRZaRZaRZaSaaSbaScaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaGeaGgaGgaGiaTIaGhaSdaOYaLDaDPaHxaHxaSfaLDaOYaLDaHyaHAaHzaLEaSkaSUaSUaNkaSUaNlaIAaSmaNnaSnaIAaLKaLKaSVaLKaLKaLKaLKaLKaLKaSpaSqaLKaLKaLKaLKaLKaLKaSraSsaSraLKaSZaLKaNraQPaTPaUfaSwaSxaNraReaUjaMbaMbaMkaSzaKOaSAaMnaMnaSBaSBaSBaSBaSCaJeasfasNarVarXarXavParXarXarVasNawFaJeaSJaSKaSKaSKaSKaSLaSLaSMaSNaRqaRpaJlaUxaUlaUlaUlaUlaUlaUlaSQaSRaSSaSTaUJaUOaSWaSXaSYaKZaKZaURaTaaTbaTcaTdaTeaTeaTeaTfaTgaTfaTeaTeaTeaTeaJRaIgaThaONaRLaRMaONaONaTiaIgaTjaQzaTlaGGaIoaTmaTnaToaTpaTqaIoaTraQKaGGaTtaTuaRZaTvaTwaTxaafaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaUSaVeaUVaVkaVfaSgaSeaSiaShaSjaSiaTzaTyaTBaTAaTEaTCaTAaTFcozaTXaTJaTKaTLaTLaTLaTMaTLaTNaTOaIAaVraTQaTRaTSaTTaTUaTVaTWaTZaTUaTYbcZaUaaUbaUcaUdaUeaVzaUgaUhaUeaUiaLKaLKaVIaLKaLKaLKaLKaUkaVLaLKaUmaMbaUnaSzaKOaUoaaaaaaaaaaaaaaaaaaaaaaUpaUqaUraUsaUtaUvaUuaVPaUwaUzaUyaVUaUpaaaaaaaaaaaaaaaaaaaaaaUAaSNaRqaUBaUCaUDaUEaUFaUFaUFaUFaUGaUHaUIaUFaUFaUFaWdaUKaULaUMaUNaWjaUPaUQaWnaWkaUTaTfaUUaWoaWwaUXaUYaUZaVaaVbaTeaJRaIgaVcaVcaRLaRMaVdaVdaWyaIgaIgaWFaIgaGGaVgaVhaViaViaViaVjaWKaGGaGGaGGaVlaVmaVnaVoaVpaVqaafaafaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaXdcmVaXhaXiaDPaVsaVsaVtaVsaVsaVsaVDaVsaVsaVtaVsaVsaYEaWYaVuaVvaKdaKdaKdaKdaKdaVwaVxaVyaXjaIAaTQaTQaVAaTSaVBaTUaTUaTUaTUaTUaTYaVCaTUaTUaTUaUdaUeaXkaVEaVFaUeaUiaVGaVHaKeaKcaVKaUmaXlaVMaVNaVOaXmaVQaMkaSzaKOaUoaaaaaaaaaaaaaUpaUpaUpaUpaVRaSlaVTaXEaVVaSDaVXaXFaVZaSOaWbaUpaUpaUpaUpaaaaaaaaaaaaaUAaSNaRqaRpaWcaSSaSPaWeaTkaSSaTsaUWaWiaVSaXnaVWaWmaXoaQbaXuaWpaWqaWraWsaWtaWtaWuaWvaXwaWaaXzaXCaWAaWBaWCaWDaWEaTeaJRaIgaThaONaRLaRMaONaONaONaXGaWGaONaWHaGGaWIaWJaToaToaToaTqaIoaYsaGGaWfaVoaLuaWQaVoaWRaWSaWTaWTaWUaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTGaGgaTHaGiaBIaBIaBIaWVaWWaWWaWWaWWaWWaWWaWWaWXaBIaBLcpSaWZaIAaXcaXbaXbaXbaYraXIaIAaIAaIAaIAaTQaXeaXfaTSaXgaTUaTUaWgaXOaXNaXTaXRaTUaTUaTUaXWaUeaXXaXZaXYaUeaUiaVGaXpaKfaXraXsaUmaXtaXmaYeaXvaYfaXxaMkaSzaKOaMmaSCaMbaXyaUpaUpaVYaXAaYkaYqaXDaXDaXEaXFaYwaXEaXFaXDaXDaXHaYxaXJaXBaUpaUpaXyaJlaXLaXMaSNaRqaRpaJlaYyaSPaYAaTkaSSaXPaXQaSSaWhaXSaTkaSSaYGaOtaXUaXVaUQaYHaYKaYJaYMaYaaYbaYcaYdaWoaYNaYgaWBaYhaWDaYiaTeaJRaIgaYjaYjaRLaRMaWlaONaONaYlaONaWzaWxaGGaIoaYVaYUaToaYXaZeaZXaWLbaOaYmaWOaZcaVoaYvaZgaZnaZhaYzaZraIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaafaYCaYDcpKaYFaWPaZsaZsaYIaZtaZuaYLbacaZYaYOaYPaYQaYRaYSaTSaYTaTUaTUaWgaXNbafbanaWgaTUaTUaYWaUdaUeaUeaUeaUeaUeaUiaVGaVGaVGaVGaVGaUmaYYaXvaYZaXvaXvaXxaMkaSzaKOaNSaNSaZaaZbaWNaUpaZdaYnaZfbaCbaBbaPbaNbaTbaSbaVbaUbaXbaWbaYaZfaYoaZjaUpaWMaZbaZlaZmbaZaSNaRqaRpaWcaSSaSSaSSaSSaSSaXPaZoaSSaWhaZpaTkaSSaYGaOtaZqaXVaUQbbabbcbbbbbeaYaaYpaZwaYdaWoaYNaYgaWBaYhaZxaZyaZzbbfaZzaZzaZzaZBaZCaZDaYtaOOaZFaZGaZHaZIaGGaZJbbtbbhaTobbxbbhaIoaIoaXaaZiaVoaYuaVoaZNaZOaZPaZQaWTaZRaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaZSaZTaZUbjnaZWaSFaZsaZkbaaaZvbbzbadbaebbAaYObagbahbaibajaTSbakbalbambbDbaobapbaqbarbarbarbasbataTSbaubavbawbaxaKgbajbnZaKhbajbbLaUmbaDbaEbaFbaGbaHbaIaMkbaJbaKaMkbaLbaMbbPbcybbRbbQbaRbaQbbSaUpaUpaUpaUpaUpbcDaUpaUpaUpbbTbaQbbdbbWbcabeobcubbibbjbbkbblbbmbbnaJlaUDaSPbboaTkaSSaZAaZEbbraZKaYAaTkaSSaYGbcBaULaXVbbubbvbbwaUQaUQaYabcCbbybcFbcEbbBaYgaWBbbCaWDbcPaZzaZLbbFbbFbbGbbHbbIaRLaRLaRLaRLaRLaRLaRLaGGbbJaYVaYUaToaYXaYUaIobbKaGGbcTaVoaYuaVoaZNbbMbbNbbOaafaafaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBbdtbcZbdHbdzbbUaSFbaabaabaabaabaabbVbaabdKaYObbXbbYbaibbZbbZbbZbbZbdQbbZbcbaTUbccbcdbcebcebcfbcgaTSaXebchbcibcjaKibeablcaKkbcobcobcpbcpbcpbcpbcpbcqaMbbcrbcsbctbeebcvbcwbcxbbgaUpbczbcAbekaUpaUpaaaaaaaafaafbezaaaaaaaUpaUpbeBbcGbczaUpbbgbcxbcHbcIbcJbcKbcLaRpaWcaSSaSSaSSaSSaSSaGpbcMaSSbcNaSSaSSaSSaSSaSSbeMbcQbcRbcSaUQaUQaUQbeNbcUaTeaZMbcWbcXaYgaWBaYhaWDbcYaZzaZZbdabdbbdcbddbdebddbddbddbddbddbdfbdgbdhbdibdjbdkbdlbdmbdnbdobdpbdqbdraVoaYubdsaZNaVobeRbbOaafaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBbdtbfTbdHbdzbbUaSFbaabaabaabaabaabbVbaabdKaYObbXbbYbaibbZbbZbbZbbZbdQbbZbcbaTUbccbcdbcebcebcfbcgaTSaXebchbcibcjaKibeablcaKkbcobcobcpbcpbcpbcpbcpbcqaMbbcrbcsbctbeebcvbcwbcxbbgaUpbczbcAbekaUpaUpaaaaaaaafaafbezaaaaaaaUpaUpbeBbcGbczaUpbbgbcxbcHbcIbcJbcKbcLaRpaWcaSSaSSaSSaSSaSSaGpbcMaSSbcNaSSaSSaSSaSSaSSbeMbcQbcRbcSaUQaUQaUQbeNbcUaTeaZMbcWbcXaYgaWBaYhaWDbcYaZzaZZbdabdbbdcbddbdebddbddbddbddbddbdfbdgbdhbdibdjbdkbdlbdmbdnbdobdpbdqbdraVoaYubdsaZNaVobeRbbOaafaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBbdubdvaZUbdwbdxaSFaZsbabbaaaZvbeTbbVbaabdAaYObbpbdCbaibbZbdDbdEbdFbdGbbZbeVbdIbdJaTSbeWbdLbdMbdNaTSaXebdObdPbdPbfebdPbdPbdPbdPbdRbdSbdSbdSbdTbdSbdUaMbbdVbdWbdXbdYbdYbdYbdYbdYbdYbdZbfobdZbdYbebbebbebbebbebbecbebbebbebbedbedbfqbedaUpaUpaUpaJiaJiaJibcKbcLaRpaJlbefbegaDmbehaSSbeibcMbejbfwbelaSSaSSbembcOaZzaZzaZzbfxaSGaSGaSGaZzaZzaZzbeqberbesbetaWBaYhaYhbeuaZzbevbewbbqaZzbeybbsbeAaYtbfybbEbeDbcmaONaGGaIobeFbeGbeHbeFbeIaIoaIoaGGbeJaVoaYuaVoaZNbeKbeLbbOaafaafaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaafbeObePbeQbfAaRtaZsbfWbeUbgubeTbbVbgIbgHaYObeXbeYbaibbZbbZbbZbeZbfabbZbfbbdIbfcaTSbeWbdLbdMbfdaTSaXebdObdPbgJbffbfgbfgbfhbdPbfibcVbfkbflbfmbfmbfmaMbaMkbcsbctbdYbfnbgMbfpbgNbfrbfsbftbfubdYbebbfvbgUbfvbgWbgXbfvbdybebbedbfCbfDbfEbfFbfGbfHbfIbfJaJibfKbfLbfMaJlaZzaZzaZzaZzbfNbfObfPbfQaZzaZzbfRaZzaZzaZzaZzbfSbfTbfUbfVbfVbfVbhebfXaZzbfYbfZbgabgbbgcbgcbgcbgdaZzbevbewbdBaZzaZzaZzaZzaZzaZzaZzaZzaZzaZzaZzbgfbggbghbgibgjbgfbggaZzaRZbgkaVoaYuaVoaZNaZObglbgmaWTaZRaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaaabgnbgobgpbgqaZUbgrbgrbgrbgrbgrbgrbgsbgtbgraYOaYOaYOaYOaYObhCaYOaYOaYObgvbgvbgwbbZbdDbgxbeZbgybbZbgzbgAbgzaTSbeWbdLbdMbfdaTSaXebdObdPbgBbgCbfgbfgbgDbdPbfibgEbgFbgGbhKbhJbhLaMbbgKbgLbctbhNbivbgObgPbexbexbgRbgSbgTbdYbebbmIbgVbhSbhRbfzbgYbhTbebbedbhabhbbhcbeCbhUbeEbhgbhhaJibhibhjaRpbhkbhlbhmbewbewbhnbewbhobewbewbewbewbhpbewbewbewbewbhqbewbewbewbewbewbewbhmbewbewbhrbhsbhsbhtbhsbhsbhubhvbewbhqbhwbhxbhpbewbhybewbewbewbhzbhAbhBbhVbewbhDbewbhEbewbewbhFbhGbhHaVoaYuaVobhIbhWbidbhXbhMbilaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaYBaafbeObePbeQbfAaRtaZsbfWbeUbgubeTbbVbgIbgHaYObeXbeYbaibbZbbZbbZbeZbfabbZbfbbdIbfcaTSbeWbdLbdMbfdaTSaXebdObdPbgJbffbfgbfgbfhbdPbfibcVbfkbflbfmbfmbfmaMbaMkbcsbctbdYbfnbgMbfpbgNbfrbfsbftbfubdYbebbfvbgUbfvbgWbgXbfvbdybebbedbfCbfDbfEbfFbfGbfHbfIbfJaJibfKbfLbfMaJlaZzaZzaZzaZzbfNbfObfPbfQaZzaZzbfRaZzaZzaZzaZzbfSbkebfUbfVbfVbfVbhebfXaZzbfYbfZbgabgbbgcbgcbgcbgdaZzbevbewbdBaZzaZzaZzaZzaZzaZzaZzaZzaZzaZzaZzbgfbggbghbgibgjbgfbggaZzaRZbgkaVoaYuaVoaZNaZObglbgmaWTaZRaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaaaaaaaaaaabgnbgobgpbgqaZUbgrbgrbgrbgrbgrbgrbgsbgtbgraYOaYOaYOaYOaYObhCaYOaYOaYObgvbgvbgwbbZbdDbgxbeZbgybbZbgzbgAbgzaTSbeWbdLbdMbfdaTSaXebdObdPbgBbgCbfgbfgbgDbdPbfibgEbgFbgGbhKbhJbhLaMbbgKbgLbctbhNbivbgObgPbexbexbgRbgSbgTbdYbebbmIbgVbhSbhRbfzbgYbhTbebbedbhabhbbhcbeCbhUbeEbhgbhhaJibhibhjaRpbhkbhlbhmbewbewbhnbewbhobewbewbewbewbhpbewbewbewbewbhqbewbewbewbewbewbewbhmbewbewbhrbhsbhsbhtbhsbhsbhubhvbewbhqbhwbhxbhpbewbhybewbewblrbhzbhAbhBbhVbewbhDbewbhEbewbewbhFbhGbhHaVoaYuaVobhIbhWbidbhXbhMbilaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhOaaaaafbhPaYDbhQbitbiqbjubjqbjwbjvbjubjAbjGbjBbjObpGbhZbgwbbZbbZbbZbiabfabbZaTSaTSaTSaTSbeWbibbicbjQaTSbiebifbdPbigbihbiibgDbijbdPbfibikbgFbgGbgGbgGbjRaMbbimaSzbctbjVbiobipbfjbirbisbfBbiubjMbdYbebbiwbixbiybjYbiybgYbgebebbedbiAbiBbiCbgQbiEbgZbiGbiHaJibiIbiJbiKbiLbiMbiNbiObiObiPbiQbiRbiSbiSbiSbiTbiSbiSbiSbiSbiSbiUbiVbiVbiVbiWbiObiObiNbiObiObiXbiVbiVbiYbiSbiZbjabjbbiSbjcbiObiObiObiObiObiObiObiObiObiObiObiObiObjdbiTbjebiSbjfbjgbjhbjibjibjjbjkaZNaWRbjlaWTaWTaWUaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhObhOaZSaZTbjmbjnbjobgrbjpbjpbjZbjpbjpbjpbALbwEbXrbBraXebaibbZbdDbjsbjtbgybbZbbLbbLbbLaTSaTSaTSaTSbkkaTSbjxbdObdPbjybjzbgDbfgbkubdPboibfmbkxbgGbgGbgGbjDaMbbjEaSzbctbkAbkHbgObhdbjIbjJbhfbjLblybdYbjNbkKbjPbiybkLbiybgVbkMbjSbedbjTbjUbizbjWbjWbjWbjXbkNaJibkPbkabkbbkcbkdbkebbFbkfbkgbkhbkibkjbkVbklbkmbknbknbkobewbewbewbewbewbkpbkqbkrbewbksbktbkXbkvbewbkpbkwbkYbkybhFbewbewbkzbewbewbkZbkBbewbkpbewbewbewbewbewbewbewbewbewbhqbewbewbhFbkCbkDbkEbkFbkGblobkIbkJaafaaaaafaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhObhOblBblrblEblCbkObgrblTbkQbkRbkRbkSbkTbkUbmdbmlbmlbmxbmobbZbbZbbZbeZbmCbbZbajbajbajbajblaaXeaXeblbblcbldbleblfblgblhblibljblkbdPbohbfmbmBbgGblnbgGbmDblpblqaSzbctbdYbmEblsbltblublvblwblxbdYbdYbebblzblAbmHbmFblDblAbiDbebbedbedblFblGblHblIbiCblJblKaJiblLblMblNaJiblOblOblOblOblOblOaZzaZzblPblQbZNcdMblQblPaZzaZzaZzaZzaZzaZzaZzaZzaZzaZzbmNaZzaZzaZzaZzaZzaZzbmTaZzbewbewblVblWbiFblOblOblOblOblOblXblYblYblZblYbewblYblZbmablYbmbblObmcbmcbmcbmUaRZbmeaRZaRZaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhObhOaZSaZTbjmbjnbjobgrbjpbjpbjZbjpbjpbjpbALbwEbXrbBraXebaibbZbdDbjsbjtbgybbZbbLbbLbbLaTSaTSaTSaTSbkkaTSbjxbdObdPbjybjzbgDbfgbkubdPboibfmbkxbgGbgGbgGbjDaMbbjEaSzbctbkAbkHbgObhdbjIbjJbhfbjLblybdYbjNbkKbjPbiybkLbiybgVbkMbjSbedbjTbjUbizbjWbjWbjWbjXbkNaJibkPbkabkbbkcbkdcyPbbFbkfbkgbkhbkibkjbkVbklbkmbknbknbkobewbewbewbewbewbkpbkqbkrbewbksbktbkXbkvbewbkpbkwbkYbkybhFbewbewbkzbewbewbkZbkBbewbkpbewbewbewbewbewbewbewbewbewbhqbewbewbhFbkCbkDbkEbkFbkGblobkIbkJaafaaaaafaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhObhOblBcBVblEblCbkObgrblTbkQbkRbkRbkSbkTbkUbmdbmlbmlbmxbmobbZbbZbbZbeZbmCbbZbajbajbajbajblaaXeaXeblbblcbldbleblfblgblhblibljblkbdPbohbfmbmBbgGblnbgGbmDblpblqaSzbctbdYbmEblsbltblublvblwblxbdYbdYbebblzblAbmHbmFblDblAbiDbebbedbedblFblGblHblIbiCblJblKaJiblLblMblNaJiblOblOblOblOblOblOaZzaZzblPblQbZNcdMblQblPaZzaZzaZzaZzaZzaZzaZzaZzaZzaZzbmNaZzaZzaZzaZzaZzaZzbmTaZzbewbewblVblWbiFblOblOblOblOblOblXblYblYblZblYbewblYblZbmablYbmbblObmcbmcbmcbmUaRZbmeaRZaRZaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhObhObdubdvbjmbjnbmfbgrbmgbjpbmhbmibjpbjpbjpbmVbmjbmkbmkbmWbbZbdDbmmbeZbmnbbZbmXbmpbmqbmrbmsbmtbmtbmubmtbmtbmvbdPbmwbnabfgbmybmzblfblmbmAbjCbgGbgGbjHbnlbnbblqaSzbnobmGbmGbmGbmGbmGbmGbmGbnsbmGaafbebbmIbmJbmKbmLbmKbmMbjKbebaafbedbmObnwbmQbmRbiCbiGbmSaJibcKaRqaRpaJibnHbnAbnPbnNbnRbmYbmZbnSbnVbnUbndbnebnUbnWbnXbnhbnibnjbmPbojbnmbnnbokbnpbnqbnrbolbntbntbnubYfaVJblOblObooblObZMbZMblObnzbopbnBblObZtboqbZtblOblXblYbmbblObZnboJbZnblObnGboKbnIbnJbXsbYFbnMaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaTDaaaaaaaaabhObhObhObhObhObhObhObhObhObhOaaaaaabnOboNbeQbnQbgrbpcboWbpmbnTbprbpobjpbpsbpvbnYbnZbmWbbZbbZbbZbbZbbZbbZboabobbocbodboebdPbdPbdPbdPbdPbdPbdPbWqbdPbdPbdPbogbdPbfmbllbjCbgGbgGbgGbpwblpblqaSzbpybmGbombonbncbpAbvGbotbosbotaafbebboubovbowboxboybozbnfbebaafbedboBboCboDboEbiCbiGboFaJiboGboHaRpbXHbpBbngboLboMbnkbpLboPboQboRboRboSboTboUboUboVbpMboXboYboZbpabpbbnnbpNbpdbpebpfbpgbphbpfbpibYfaVJbpjbpkbplbpPbpnbnybppbnCbnDbpqbpSbptbpZbpTblOaZzbqabpxblObqbbqgbqcbqsbpCbpDbnIbpEcanccxbnMaaaaaaaaaaacaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTDaTDaTDaTDaTDaaaaTDaTDaTDaTDaTDaaaaTDaTDaTDaTDaTDaaaaaaaaaaaaaaabgnbgobgpbgqbdvbpHbpHbpHbpIbpHbpJaZVbpKbqtbgrbqxbjpbqBbqybpQbpRbqHbqGbqKbqKbqKbqMbkWbpUbkWbkWbkWbkWbpVbpWbpWbpXbpYbdPbqTbqQbrkbrcbqdbqebqfbrnbqhbqibqjbqkbqkcKDcKEbgGbgGbqmbfmaMbblqbqnbqoaJubqqbqrbqrbxqborbrobxsbotaafbebbebbebbebbrubebbebbebbebaafbedbqzboCbqAbrvbqCbqDbqEaJibqFaRqaRpaJibrxbrwbqIbqJbrybqLboPbqNboUboUboUboUboUboUbqObqPbrCboYbqRbqSbrDbnnbqUbqVbqWbrIbpgbphbpfbqXbYfaVJbpjbqYbqZbqZbrabrbbrPbrdbrdbrdbrebrdbrfboObrhbribrjbscbnIbrlbpCbrmbsebpCbshbnIbrqccybrrbnMaaaaaaaaaaaaaaaaaaaaaaIuaIuaIuaIuaIuaIuaIuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -7536,7 +7541,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnbtnbtnbAVbzQbAVbCMbCNbCObrJbrJbrJbCNbrJbwTbrKbzTbCPbdPbDYbgGbrNbwXbgGbqlbCRbgGbgGbEgbxcbvtbAbbCTbxcbCUbvwbCVbEhbEibAWbxlbvwbEkbEjbEpbAhbErbErbErbAjbEubEsbEwbyNbDkbDlbDlbDmbDnbDobDpaJibDqbDrbDsaJibDtbECbDvbEFbDxbDybDzbDAbyWbEKbELbCjbEMbwmbDEbDFbwmbDGbDHbERbDJbESbDLbDMbCpbEUbDObBTbEVbDRbCpbVLbVMbDUbVAbDWbDXbDXbEWbDZbEabEbbEcbEdbEebEfbEYbEXbEZbCvbFbbFabFobwwbwwbwwbwwbwwbFybFrbEnbzKbzMbCJbEobFFbCJbzKbzLbzMbFQbCJbFUaafcHOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnbtnbtnbFVbExbFVbEybEzbEAbEAbEAbEAbEAbEBbGfbEDbzTbEEbdPbGgbEGbEHbEIbEJbGibGhbGkbGjbGvbtCbENbAbbEObEPbyEbvwbEQbGubGAbBMbETbvwbBPbGCbGDbAhaaaaaaaaabAjbGWbGEbFcbyNbFdbFebFfbFgbDnbDobFhaJibxwaRqaRpbHabFjbFkbFlbFmbFnbHfbFpbFqbxCbxFbxFbHibxFbwkbFsbFtbFubFvbFwbFxbDJbHjbDLbFzbFAbFBbDObFCbFDbFEbHkbVlbDXbHlbVAbFJbDXbDXbFKbFLbFMbFLbFLbFNbFObFPbHmbFRbFSbCvbHwbHvbHMbFWbFXbFYbFZbGabGbbGcbGdaafaafbCJbGebHNbHNbHObHQbHPbHRbEvaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnbtnbtnbGlbGmbGnbdPbdPbGobwNbwNbwNbGpbdPbdPbGqbGrbGsbdPbGtbGtbGtbHSbGtbGvbGwbGxbGybGzbtCbvtbAbbHUbGBbtCbtGbtGbtGbtGbtGbHVbtGbtGbtGbHZbtGbtGbtGbtGbtGbIfbtGbtGbtGbtGbtGbtGbtGaJiaJiaJiaJibxwaRqaRpbHabIobFkbCSbGGbCWbGIbGJbGKbGLbGMbGNbCjbGObGPbGQbGRbGSbGTbGUbGVbIrbGXbGYbGZbIubHbbHcbHdbHebIvbCpbUSbUfbwwbwwbwwbwwbwwbIAbwwbwwbwwbzAbIBbzAbzAbIDbBhbCubCvbHwbIMbIRbHnbHobHpbHqbGabGbbGcbHraaaaaabCJbHsbHtbEobCnbBybITbIUbCJaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnbtnbtnaaaaaaaaaaaaaaaaaaaafaaaaaaaaabHuaafaaaaaaaaaaaabGtbIYbIXbHxbHybLrbHzbIZbHBbHCbtCbvtbAbbAcbAabHDbHEbHFbHGbHHbHIbHJbHKbHLbJabJqbJbbJrbAabAabJDbJWbJVbAabHTbAabzZbHHbKJbHWbHXbHYbJXbxwaRqbDsaJlbDtbDubDtbDCbDPbxCbIbbIcbIdbIebKdbIgbIhbIibIjbIkbwmbIlbImbInbDJbDTbElbIpbIqbKfbFDbIsbItbKgbCpbKhbIwbIxbIybUdbLybKibICbKjbUcbIFbIGbIHbIIbIJbzAbIKbCubCvbKzbKobINbIObIPbIQbKBbGabGbbISbEnbEnbEnbCJbCJbCJbKVbKUbCJbCJbBybCJaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafaafaafaafaaaaaaaaaaaaaafaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnbtnbtnaaaaaaaaaaaaaaaaaaaafaaaaaaaaabHuaafaaaaaaaaaaaabGtbIYbIXbHxbHybLrbHzbIZbHBbHCbtCbvtbAbbAcbAabHDbHEbHFbHGbHHbHIbHJbHKbHLbJabJqbJbbJrbAabAabJDbJWbJVbAabHTbAacMkbHHbKJbHWbHXbHYbJXbxwaRqbDsaJlbDtbDubDtbDCbDPbxCbIbbIcbIdbIebKdbIgbIhbIibIjbIkbwmbIlbImbInbDJbDTbElbIpbIqbKfbFDbIsbItbKgbCpbKhbIwbIxbIybUdbLybKibICbKjbUcbIFbIGbIHbIIbIJbzAbIKbCubCvbKzbKobINbIObIPbIQbKBbGabGbbISbEnbEnbEnbCJbCJbCJbKVbKUbCJbCJbBybCJaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafaafaafaafaaaaaaaaaaaaaafaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnbtnbtnaaaaaaaaaaaaaaaaaabLaaaaaaaaaaaaaaaaaaaaaaaaaaaabGtbLnbEmbIVbIWcLYbLpbLzbLxbLFbtCbvtbJcbJdbJebJebJfbJgbJhbJibJjbJgbJfbJebJebLHbJkbJlbLIbJnbJobLKbJebJebJpbJgbJhbJibJjbJsbJtbJubJtbJvbJwbvUaJlbEtbEqbFHbGFbLWbGHbDzbHAbFibDVbxFbLYbCFbDSbDEbJGbwkbJHbJIbJJbDJbJKbJLbJMbJNbJObFDbJPbItbJObCpbJQbJRbIxbJSbJTbJUbMhbMlbMibJYbIFbJZbKabKbbKbbzAbKcbMqbMpbMxbMwbMCbMybMHbMFbKkbGabGbbKlbEnbKmbMIbKnbEnaafaafaafaafaafaafaafaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafbKpbKqbKqbKrbKsbKsbKtbKtbKtbKtbKuaafaafaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabtnbtnbtnbtnbtnaaaaaaaaaaaaaaaaaaaaaaaabKvbKwbKxbKwbKyaaaaaaaaabGtbGtbMMbKAbIVbKAbMPbKCbMSbKDbKEbtCbKFbvtbKGbKHbAabKIbAabzZbHHbKJbAabKKbKLbKMbKNbKObAcbAabKPbKQbHLbKRbHLbHLbKSbKTbMXbMTbKWbKXbcLbKYaRpaRpaRpaJlbMZbFlbFnbNdbJmbNfbJybJxbFIbLgbLhbLibLjbHgbDEbIkbIabIzbHhbDJbDJbLobLobLobCpbNhbLqbNkbLsbLtbCpbLubLvbIxbLwbFGbLybNqbLAbLBbLCbIFbJCbLEbKbbKbbzAbRsbSLbCvbwwbLGbNtbNsbLJbNzbLLbGabLMbLNbLObLObLObLPbGdaaaaaaaaaaaaaafaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafaafbLQbLRbLSbLRbKsbKtbKtbLTbLUbLTbKtbKtaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabLVbNAbLXbNBbLVbLZbMabMbbGtbMcbMdbMebMfbMgbNLbNKbMjbMjbMkbtCbtCbtCbNQbtCbtCbtCbtCbtCbtCbtCbtCbtCbtCbtCbtCbtCbMmbMnbMobtCbtCbtCbtCbtCbNZbtCbtCbtCaJlaJlbObaJlaKSaMpbMraJlbKZbOcbOdbGFbLdbxCbDzbLDbxCbOfbMzbMAbMBbwkbOibMDbMEbOkbMGbOlbOnbMJbMKbMLbItbJObFDbFDbOtbJObCpbMNbMObMObMObMObMObMObMObMObMObMObOxbMQbMRbMRbzAbOCbODbMUbwwbMVbMVbMVbMWbOEbMYbMVbMVbMVbMVbMVbMVbNabNbaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymaymbOFbLRbLRbNebKtbKtbLTbLTbOGbLTbLTbKtbKtaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -7545,7 +7550,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabKxbMsbMsbMsbKxbQnbQobScbQqbQrbKAbKAbQsbQtbSgbQvbQvbQvbQvbQvbQvbQwbQxbQyaaabQzbQAbSibQCbSlbPfbQEbQGbQFbPfbNFbQIbQJbQKbNFbSrbSnbQNbQObSubQQbQRbPtbQSbPxbQTbNUbPxbPxbQUbDtbPnbGFbQVbSwbGFbPzbDzbLebRCbQZbPBbSEbSMbRGbDEbIkbSpbRdbRebRebRpbRfbMKbRgbRhbSNbRjbRkbRlbSObRnbPObMObOsbOsbRobOsbOsbOsbOsbSPbMObRqbLEbRrbRrbzAbRsbRtbRubSQbRwbSSbSRbSWbSVbTsbTgbTAbTubTNbTMbTObREbTWbTTbRHbQibOpbRKaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaabKtbKtbRLbLTbLTbLTbLTbLTbLTbLTbLTbLTbLTbLTbKtbKtaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLbwLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaabLVbUbbRNbUkbLVbRPbMabMbbGtbGtbRQbRQbRQbGtbGtbNxbRRbRRbRSbRSbRSbRSbNwbQyaaabRTbRUbRVbUobRXbRYbRZbSabSbbSbbUqbSdbSebUwbNFbPtbPtbPtbPtbPtbUAbPtbPtbShbUGbSjbNUbPxbSkbUObDtbQHbLbbQVbSmbUPbPzbSobJAbJBbSqbRabSsbStbJzbFsbSvbIEbSxbUWbURbSAbSBbMKbRmbSDbVebRjbSfbSGbVjbRnbPObMObMObMObRobOsbOsbOsbMObMObMObSIbSJbRrbRrbzAbSKbSLbCvbzIbVkbVvbVmbRDbVybVGbVzbVVbVObWibWgbMVbQfbWkbOObSXbRIbSybTaaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafbKtbLTbLTbLTbLTbLTbLTbTbbLTbTcbLTbLTbLTbLTbLTbKtbKtaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabTdbKwbTebKwbTfbWoaafaaaaaabGtbThbTibTjbGtaaabNxbTkbTlbTmbTnbTnbTnbTobQyaaabQzbTpbTqbTrbWIbPfbTtbTvbWMbTwbNFbSzbTybTzbWVbTBbTBbTBbTCbTCbTDbTEbULbPxbPxbTFbNUbNUbNUbNUbDtbDtbLfbLkbLcbDtbTJbTKbTLbJFbJEbTJbPebLlbLmbTRbTSbTJbMKbMKbMKbMKbMKbMKbXabTUbTVbRjbXcbTXbTYbRnbPObMObTZbQWbPQbXebenbNWbNcbTZbUgbUhbUibIIbIJbzAbIKbSLbUjbwwbMVbMVbXibXnbMVbMVbMVbMVbXpbSCbVFbMVbXqbUnbOObUpbSYbUrbOOaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaabKtbUsbUsbUsbUsbUsbUsbUtbLTbUubUsbTcbLTbLTbLTbLTbKtaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabLaaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafbUvbNxbNxbNxbNxbRSbXvbNwbUxaaabUybPcbPcbUzbXxbPfbPfbUBbPfbSFbNFbUDbSHbSTbNFbSUbSUbSUbSUbSUbSUbSUbSUbUHbUIbUJbUKbUKbUMbNUbDtbUNbSZbTxbUQbYabwabUTbUUbYtbYobYwbUTbUYbUZbVabVbbUebTPbVdbYybVgbVhbVibUlbYzbUmbRjbUCbYHbUCbRnbPObMObVnbUFbVpbVqbVrbVsbVtbVubUgbzAbYMbzAbzAbVwbCxbSLbCxbVxaafbnxbYSbYYblSbVBbYZbZcbZbbZebUVbMVbVHbVIbOObVJbWHbVKbwhaaLaaLaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwibLRbLRbLRbLRbLRbLRbLRbVNbLUbLTbLTbLTbLTbZibLUbKuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabLaaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafbUvbNxbNxbNxbNxbRSbXvbNwbUxaaabUybPcbPcbUzbXxbPfbPfbUBbPfbSFbNFcMlbSHbSTbNFbSUbSUbSUbSUbSUbSUbSUbSUbUHbUIbUJbUKbUKbUMbNUbDtbUNbSZbTxbUQbYabwabUTbUUbYtbYobYwbUTbUYbUZbVabVbbUebTPbVdbYybVgbVhbVibUlbYzbUmbRjbUCbYHbUCbRnbPObMObVnbUFbVpbVqbVrbVsbVtbVubUgbzAbYMbzAbzAbVwbCxbSLbCxbVxaafbnxbYSbYYblSbVBbYZbZcbZbbZebUVbMVbVHbVIbOObVJbWHbVKbwhaaLaaLaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabwibLRbLRbLRbLRbLRbLRbLRbVNbLUbLTbLTbLTbLTbZibLUbKuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabVPbVQbVQbVRbVSbNxbVTbRSbVUbNxaaaaaaaaaaaabNybZrbVWbVXbVZbVYbPfbNFbWabWbbNIbNFbSUbUXbVfbVcbVDbVCbVEbSUcaqcaqcaqcaqcaqbTFbWjbZsbWlbWcbWdbZubWpbxgbWrbWsbWtbWubWtbWvbWtbWwbWxbWybWzbWAbWBbWAbWCbWDbWEbWFbWGbWebZvbWfbWKbWLbZzbxVbMObxWbZBbzlbWSbWTbWhbWSbWSbXfbWWbWXbWYbWZbCxbCxbSLbCxbFTaafbnxbZLbZLbXbbZObXdbZSbZPbXgbXhbMVbVHbZUbOObOObOObOObOOaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaabKtbQmbQmbQmbQmbQmbQmbXkbLTbQlbQmbXlbLTbLTbLTbLTbKtaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabXmbZVbWmcaabRSczUcAYcADcBKbNxaaKaaaaaaaaabNybNybNybNybNybNybNybNFbUDbUEbXtbNFbSUbWnbWJbXubXubWJbWRbSUcaobWUbWUbXocaqbXBbDtbDtbXCbXDbXEbXFbXGblRbXIbXJbXKbXLbXMbXNbXObXPbXQbXRbXSbXTbXUbznbzpbzobAPbzqbARbAQbATbAScaxbAUbYfbYgbIwbYhbVobCqbWObWNbWPbYmbYnbZCbYpbYqbYrbYscaLbYrbYubYvbILaafbnxcaMcaWbrBbVBcaXcbecbdcbfbYAbMVbVHbYBbYCbUnaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafaafbKtbLTbLTbLTbLTbLTbLTbTbbLTbXlbLTbLTbLTbLTbLTbKtbKtaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYDbVQbVQbVRbYEcEcbYGbNxcbgbNxbYIbYJbYKbYIbYIbYLcbibYNbYObYPcbjbXwbXzbXybYebXAbYjbWJbYQbYxbYRcbkbYTcbmbYVbYUbYXbYWcaqbZhbNScbnbZjbZkbZlbZlbZmbnEbZobZpbTJbTJbZqcbrbTJbTJcbycbtcbAcaIcbBbWQbZxbZycbCbZybZAbZacbDbZabZAcbJbYfbMNbIwbZEbXWbXVbZdcbKbZJbZKbMObMObwwbwwbwwbwwbwwboIbnFbofbwwbMVbMVbMVbMVbMVbMVbMVbMVbMVbMVbMVbMVcbLbZQbZRbUnaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaabKtbKtbRLbLTbLTbLTbLTbLTbLTbLTbLTbLTbLTbLTbKtbKtaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -7555,10 +7560,10 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaaaaaaaaaaaaaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacejcejcejcejcejcejcejcetcesbYIbYIbYIbYIbYIcgfcgmcgjcgjcgjcgocewbXzbXybYeceybYjceEceTceSceWceUceXbSUcezaJFceYaJFcaqbTFcbIceDcfacfacfaceFceGbTJcgCcgBbTJcedcbNceJcefcaEcgOceLceMcaIbZxbWQceNbZyceOcePbZAbZAbZAbZAbZAccbceRbYfcaQbYcccdcgRbYcbYcchBcgVcjfcdLcgWcfbcfbcfccdOcfdcgXcffcdOcfgcfhcfhcfhcgYchacgZchdchbcfnchicfpcdScfqcfrchmbUnbUnbUnbUnaaaaafaaaaaaaaaaahaahaahaafaaaaaaaafaaaaaaaafaafaafcftcfBcfvbNebKsbKtbKtbLTbLUbLTbKtbKtaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaafaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafcejchpchnchrchqchucejcfDcfCcfFcfEcfHchvchychycfKcfJcfJchzchEcbqbXzbXybYecfNcaicfOcfQcfPchLchFcggbSUaJFaJFcaqceBcaqbTFcbIcfVcfWcfWcfWcfXcbIcfYchPcgacfYcgbcgccgdchScaEchVceLcgicaIcghccfchYbZycgkcglbZycifbLvbVicgnccgcchbYfccjcciccicckcclcclcclcclccmcdLcijcgycgycgzcgActscgrcgpcgucgtcgGcgGcgGcgxcgIcgIcgJciycgLcgDcgMcdScgNciCcgPcgNaaaaaaaaaaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafcgQbKqbKqbKrbKsbKsbKtbKtbKtbKtbKuaafaafaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaafaafaafcgEcgEcgEcgEcgEcgEcgEcgEcgEcgEcgEcgEcgEaaaaaacgSciKcgTcgTcgUciLcejcgHcgFciPcgKciVciQcjaciWcjlcjicjpchcchfchechhchgchjcjqbSUbSUbSUbSUbSUbSUbSUbSUcjsccvcaqcjtcaqbTFcbIcbIctpctqctrcbIcbIcjuchschtcfYcaEcaEcaEcaEcaEcaIchkchlcaIchwcjvchwbZycjIcjCbZychAchBbVichCbVichDbYfccobYfbYfccpcdCcdCcdCcdDbYfcdLchIchJchJchKckachMchochOckdchQckLckLckLckLckjckfckLckmckLcknckocdSchZciachGcgNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaafaafaafaafaaaaaaaaaaaaaafaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacgEchHckpchHcgEchNckCchNcgEchRckFchRcgEaaaaaaciiciKcgTcgUcgUckNcejchUchTchWckQclfchXcidcicclgcieciecigciecbqbXzcihbYecikcimcilciocinciocipcirciqciqciAciAciAciAbTFciGciHciIciIciJclpclrciMciXciOclycluciRciSciSciTciUcaIcaIcaIclCcdEckqbZybZybZybZychBchBbViciYbViciZbYfccobYfaaaaaaaaaaaaaaaaaaaaacdLcjgcisciucitcjjcjkcivcjmcjncjociwcjocjocixclKclGcgIclVcgIcmgcmkcdScmpcjwcjxcgNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacgEchHckpchHcgEchNckCchNcgEchRckFchRcgEaaaaaaciiciKcgTcgUcgUckNcejchUchTchWckQclfchXcidcicclgcieciecigciecbqbXzcihbYecikcimcilciocinciocipcirciqciqciAciAciAciAbTFciGciHciIciIciJclpclrciMciXciOclycluciRciSciSciTciUcaIcaIcaIclCcdEckqbZybZybZybZychBchBbViciYbViciZbYfccobYfaaaaaaaaaaaaaaaaaaaaacdLcjgcisciucitcjkcjjcivcjmcjncjociwcjocjocixclKclGcgIclVcgIcmgcmkcdScmpcjwcjxcgNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacgEchHcjbchHcgEchNcjcchNcgEchRcjdchRcgEaaaaaaciicgTcgUcgUcgUcjBcmscjhcjechWcmwcmGcmBcmPcmOcjzcjycjDcjAcjEcbqbXzcjFchjcjGcmQcjHcjJcjJcjJcjKcjMcjLcjNcmRcjOceAciAbTFciGcmXciIckbckccnbcubcneckgckhcngcnfckkcklciScnhciUcnkcnwcnucjQcjPcdHcnEcdIcdIcdJcdIcdKbVibVibVibVibYfccobYfaaaaaaaaaaaaaaaaaaaaacdLcnFcjRcjTcjSckEcdOcnIcdOckGckHcjXcjUcjUcjYcgIcgIckecjZcjUckickOcdSckPcnKckRcgNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacgEckrckuckscgEckzckBckAcgEckDckJckIcgEaaaaafciiclbcgTcgUcgUcgUcejckMckKchWchWcnLchWchWchWchWckTcieckWckYcbqclackZcldclccnNcleclhclhclhclicljcljclkciAcllcgqclwclxciGcnPciIclzclAclBcnQclDclEclFcnTclHclIclJciScnUciUcnVcnXclNclnclmclQclNclRclSclTbYfceQcdIcdIcdIcdIcdIcltbYfaaaaaaaaaaaaaaaaaaaaacdLcmacmbcmccmdcdOcmecmfcnZcdScmhcmicmicmiclvcoacmlclPclOcmicmicmncdScmocobcmqcmraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaafaafcgEclXcmmcmjcgEcmtcmmcEgcgEcmtcmmcEgcgEaaaaafcmzcgTcgTcgUcgUcmAcejcmvcmucmxcolconcmycmCcmCcmEcmDcmCcmFcoqcbqcmIcmHcmKcmJcimcmLcmLcmMcljcmNcotcorcorciAcibceVcoycqgciGcoAciIcnccndcoBciGcmSciNcmWciUcoCcnicnjciScoFciUclLclMclNcnlcoJcnlclNaaaaaaaaabYfbYfbYfcnnclSclSclTbYfbYfaaaaaaaaaaaacdOcdOcdOcdOcdOcdOcdOcdOcdOcnocnpcnqcdScdScnrcnscntcdScdScdScdScoLcnscntcdScdScnvcpdcnvaafaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaafaafcgEclXcmmcmjcgEcmtcmmcEgcgEcmtcmmcEgcgEaaaaafcmzcgTcgTcgUcgUcmAcejcmvcmucmxcolconcmycmCcmCcmEcmDcmCcmFcoqcbqcmIcmHcmKcmJcimcmLcmLcmMcljcmNcotcorcMmciAcibceVcoycqgciGcoAciIcnccndcoBciGcmSciNcmWciUcoCcnicnjciScoFciUclLclMclNcnlcoJcnlclNaaaaaaaaabYfbYfbYfcnnclSclSclTbYfbYfaaaaaaaaaaaacdOcdOcdOcdOcdOcdOcdOcdOcdOcnocnpcnqcdScdScnrcnscntcdScdScdScdScoLcnscntcdScdScnvcpdcnvaafaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbOaafaafaafaaaaafcnxaafcnxaafcKAaafcpfaafcKAaafcpfaafaafaaacejcnAcnBcgUcgUcnCcnDcpocpgcnycnmcprcnzcnzcpycnzcnGcpAcnHcnGcnJcpCcpBcpGcnMcnOcnOcnOcnOcpIcpHcnRcnRcnRcgscgscgscgscnSciGcpMcpNcnccpOcnWciGcmSciNcpPciUcnYcpQcnjcpUcpRciUclLclMclNcoccodcoeclNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaacdOcofcogcohcwlcojcokcqecomcqmcopcoocdOaaLaafaafaafaafaaaaaaaaacqraaaaaaaaaaafcoscqscosaafaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaafcoucqAcqtcoxcovcowcqDcoxcqIcqLcqDcoDcqNcqOcoEcnycnycnycnycnycnycnycnycoHcoGcqWcoIcracoKcoNcoMcoOcnGcoQcoPcoRcnGcoTcoScoUcnOcoWcoVcoYcoXcpacoZcpjcpbcpbcpkcpncpncpjcrvciGciGcpccrzciGciGciGcpeciNcrQciUciUciUcrScphciUciUclLcpiclNcvmcpscvmclNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaafaafcdOcplcpmcplcrUcjrcppcpqcomcomcrXcomcdOcdOaaaaaaaaaaafaafaaaaacaaaaaaaaaaaaaafaaacrZaaaaafaafaafaafaafaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIaaaaaaaaaaafcptcsacpucpxcpwcpFcsbcsccpzcsecsdcpEcpDcsfcpFcpLcpJcsicsgcsDcsncsKcpTcpWcpVcpYcpXcqacpZcqccqbcsLcqdcsMcqfcsQcqzcoTcqJcqKcnOcpacpacpacpacpacqMcpjcqPcqPcqPcpncpncpjbTFcrYciGcqhcqicqjcqkciGcqlciNcsWciUcqncqocqpcqqciUcsXclLcpiclNcsYcqQcquclNaaaaaaaaaaaaaaaaaacqvcqwcqxcqycqvaafaaaaaaaaaaaacdOcplcplcplcoicsZcqBcqCctbcqEcqFcqGcqHcdOaaaaaaaaaaaaaafaafaaaaaaaaaaaaaaaaafaaacmZaaaaafaafaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -7566,13 +7571,13 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaafaafaafcptcpFcrccpFcrccpFcqXcpFctucxactxcxactycxacxactGctBcpFcpFctOctIctIctIctSctQctTctTctUcpZctVcshcsjcnGcsmcskcuacnGcspcsocsrcsqcstcsscsvcsucpacswcpjcsxcrKcsycrKcuecpjbTFcizciGcszcsAcsBcsCciGcfYcufcfYciUcsEcsFcsGcsHciUcsIcrGcrGcqvcsJcsNculcqvcqvcqvcqvcqvcqvcqvcqvctMctDctNcqvcqvcqvcrHaaaaaacdOcofcogcohcslcsRcqBcrNcrNcrNcnpcrNcsScdOaaaaaaaaaaaaaaacrPaaaaafaaaaafaaaaaaaaackxaaaaafaafaaaaaaaaaaaacrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaafaaaaaacptcpFcrccpFcsOcsTcurcsVcsUcuxctxcxacuycxacxacuLcuEcuUcuOcuYctacvccvbcvbcvkcrccrccthctgctjcvlcnzcnGcvncnGcnGcnGcvsctlcsrctncvvcvtcvFcvEcpacvGcpjcvOcrKcsycrKcvRcpjctvctwciGciGcvXciGciGciGciBctzctAciUciUciUcwaciUciUcsIcrGaaacqvctCctZctEctFcwectHcwfctJctKctLcqvcuVcwmcuVcqvcwuctPcqvaafaafcdOcplcplcplcrVcjrctRcuccwDcwzcudcrNctWcdOcdOcdOcdOaaaaaacrPaaactXctXctXctXctXaafckxaafctXctXctXctXctXaaacrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacptcpFcsOcsTcsTcsTcurcsTcsTcsTcurcsTcsTcsTcsTcsTcwEcwGcsTcwHcsTcwIcsTcsTcsTcuhcugcuicpvcpFcujcwJcukcuncumcupcuocumcuqcuscwOcuucutcutcuvcutcuwcwWcwUcuAcuzcuBcuBcpjcuCcuDcwXcuFcuFcuGcuHcuIcuJcuJcuJcuJcItcuJcuJcuJcuKcrFcrGaaactFcwYcuPcuNctFcwZcuRcuQcuQcvdcvacuQcuQcvhcuQcuVcuXcuQcqvaaaaaacdOcplcplcplcslcxdcuZcvicxncxecvjcrNcrNcvecvfcvgcdOaafaafcrPaafckVckSckSckSckSckyckxckwckvckvckvckvckUaafcrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacptcpFcpFcpFcpFcpFcqXcpFcpFcpFcqXcpFcpFcpFcpFcpFcvWcpFcpFcticpFcxocpFcxqcxpcvpcvocvrcvqcxrcvqcxscvucvxcvwcvycvucvucvzcvAcpIcvBcpacvDcvCcpacpacxwcxtcxtcxCcuBcuBcpjbPxcAscvNcvNcvNcvNcxFcvNcvNcvNcvNclMcJgcrGcrGcrGcrGcrGcrGaaactFctFcxHctFctFcxJcvScvTcvUcvVcvHcvJcvIcvLcvKcxVcwbcwccqvaaaaaacdOcomcomcomcomcwdcppcvicyacxYcvQcrNcrNcwhcrNcwicdOaaaaaacrPaafcwjcwjcwjcwjcwjaaackxaaacwjcwjcwjcwjcwjaafcrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaacbOaaaaaaaaaaaacptcpFcpFcpFcpFcpFcqXcpFcpFcpFcqXcpFcpFcpFcpFcpFcvWcpFcpFcticpFcybcpFcpFcybcybcyccpFcpFcvZcvYcwgcwgcwgcwgcygcwkcoTcwocwpcsqcwqcpacwscvCcpacwtcpjcyhcxtcyicwxcwwcpjcymcvMcvNcyrcypcwKcwLcwMcwNcyucvNclMcJDcrGaaaaaaaaaaaaaaaaaacqvcwRcwycwAcywcwCcwBcyEcyzcyFcwFcwTcwScwVcyHcuWcuQcyJcqvaaaaaacdOcofcogcohckXcsRcuZcxgcxhcxhcxicxjcxkcyKcxmcyLcdOaaaaaacrPaaaaafaaaaafaafaafaaackxaaaaafaaaaafaaaaafaaacrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacptcpFcpFcpFcpFcpFcyMcpFcpFcpFcyMcpFcpFcpFcpFcpFcvWcpFcpFcyRcyPcySctdctdcyScyTcyScxlcyUcyVctdcyZcyXczgczeczncwkcoTcxucoTcxvczocpacpacxAcpacxBcpjczqczqcxDcwxcwwcpjbPxcvMcvNcxKcxLcxMcxNcxOcxNcxPcvNcxQcJEcrGaaaaaaaaaaaaaaaaaacqvcxScxTcxUczrcxWcxXczBcxZcuTczFcuScxEcuTczHcqvcqvcqvcqvaaaaaacdOcplcpmcplcwvcjrcppcrNcrNcyecyfcrNczKcomcomcomcdOaaaaaacrPaaactXctXctXctXctXaafckxaafctXctXctXctXctXaafcrPaaaczLaaaaaaczLaaaaaaaaaczLaaaaaaaaaaaaaaaczLaaaaaaaaaczLaaaaaaczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacptcpFcpFcBvcpFcpFcqXcpFcpFcpFcqXcpFcBvcpFcpFcpFcvWcpFcpFcticBvcxocpFcxqcxpcvpcvocvrcvqcxrcvqcxscvucvxcvwcvycvucvucvzcvAcpIcvBcpacvDcvCcpacpacxwcxtcxtcxCcuBcuBcpjbPxcAscvNcvNcvNcvNcxFcvNcvNcvNcvNclMcJgcrGcrGcrGcrGcrGcrGaaactFctFcxHctFctFcxJcvScvTcvUcvVcvHcvJcvIcvLcvKcxVcwbcwccqvaaaaaacdOcomcomcomcomcwdcppcvicyacxYcvQcrNcrNcwhcrNcwicdOaaaaaacrPaafcwjcwjcwjcwjcwjaaackxaaacwjcwjcwjcwjcwjaafcrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaacbOaaaaaaaaaaaacptcpFcpFcMncpFcpFcqXcpFcpFcpFcqXcpFcMncpFcpFcpFcvWcpFcpFcticMncybcpFcpFcybcybcyccpFcpFcvZcvYcwgcwgcwgcwgcygcwkcoTcwocwpcsqcwqcpacwscvCcpacwtcpjcyhcxtcyicwxcwwcpjcymcvMcvNcyrcypcwKcwLcwMcwNcyucvNclMcJDcrGaaaaaaaaaaaaaaaaaacqvcwRcwycwAcywcwCcwBcyEcyzcyFcwFcwTcwScwVcyHcuWcuQcyJcqvaaaaaacdOcofcogcohckXcsRcuZcxgcxhcxhcxicxjcxkcyKcxmcyLcdOaaaaaacrPaaaaafaaaaafaafaafaaackxaaaaafaaaaafaaaaafaaacrPaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacptcpFcpFcpvcpFcpFcyMcpFcpFcpFcyMcpFcpvcpFcpFcpFcvWcpFcpFcyRcMocySctdctdcyScyTcyScxlcyUcyVctdcyZcyXczgczeczncwkcoTcxucoTcxvczocpacpacxAcpacxBcpjczqczqcxDcwxcwwcpjbPxcvMcvNcxKcxLcxMcxNcxOcxNcxPcvNcxQcJEcrGaaaaaaaaaaaaaaaaaacqvcxScxTcxUczrcxWcxXczBcxZcuTczFcuScxEcuTczHcqvcqvcqvcqvaaaaaacdOcplcpmcplcwvcjrcppcrNcrNcyecyfcrNczKcomcomcomcdOaaaaaacrPaaactXctXctXctXctXaafckxaafctXctXctXctXctXaafcrPaaaczLaaaaaaczLaaaaaaaaaczLaaaaaaaaaaaaaaaczLaaaaaaaaaczLaaaaaaczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaaaaaaaaacptcpFczmcrWcrWczpcxGcrWczpcrWcxIczMctIctIczSctIczTctIctIctSczVcybcpFcpFcyjcylcykcynczXcyocpFcAhcyqcyscyscAtcytcoTcxucyvcnOcAvcpacyxcpacAwcyycpjcpjcpjcpjcpjcpjcpjbPxcvMcvNcAxcyNcxLcyOcxLcxNcAAcvNcrGcJGcrGaaaaaaaaaaaaaaaaaacqvcuVcAHctFctFcAJcyAcAQcyWctMctDctNcyBctMcvhcyYcqvaaaaaaaaaaaacdOcplcplcplckXcARczacrNcrNcrNcyfcrNczbcrNczccrNczdaafaafcrPaafckVckSckSckSckSckyckxckwckvckvckvckvckUaafcrPaaaczLczLczLczLaaaaaaaaaczLczLczLczLczLczLczLaaaaaaaaaczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaaaaaaaaacptcpFcqXcpFcpFcpFcyMcpFcpFcpFcyMcpFcpFcpFcyCcpFcvWcpFcpFcpFcyDcybcpFcpFcATcyTctfcyGcwgcAUcwgcwgcyqcAWcyIcBkcytcoTcxucoTcnOcBncBmcBscBqczfcpacnOcBucBzcBzczhcBAcBDczNczOcvNcBEczPczQcxNczRcBHcBIcvNcJIcJHcrGaaaaaaaaaaaaaaaaaacqvczWcuMcBLcuVczYczZcAactFcAbcAccsPcyBczWczjcAecqvaaaaaaaaaaaackEcdOcAfcAgcAgczkcAicAjcAkcAlcAmcAncAocApcAqcokcAraaaaaacrPaafcwjcwjcwjcwjcwjaaackxaafcwjcwjcwjcwjcwjaaacrPaaaczLczLczLczLaaaaaaczLczLczLczLczLczLczLczLczLaaaaaaczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaIaaaaaaczlcpFcqXcpFcBOcxactxcxacBRcxactxcxacBRcxacxccxacxbcBSctectdcCcctfczsczucztczwczvczxcwgczzczycwgcwgcwgcwgcwgczAcpCcCecpCcnOcnOcnOcnOcnOcnOcnOcnOczDcBzcBzczEcANcAObPxcAPcvNcCgcCfcClcCicCqcCncCvcvNcAXcJJcrGaaaaaaaaaaaaaaaaaacqvcuQcAZcAectFcBacBbcBcctFcBdcBecCBczGczIcBecCFcqvaafaafaaaaaaaaaaaabquaaacdOcBlczJcCJcBocBpczJcCNcBrcBpczJcCOcdOaaaaaacbOaaaaafaaaaafaaaaafaaackxaaaaafaaaaafaafaafaafcrPaaaczLczLczLczLaaaaaaczLczLczLczLczLczLczLczLczLaaaaaaczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbOaaaaaaaaaaaIaaaaaacAdcpFcqXcpFcCQcylcqXcpFcCYcylcqXcpFcAucylcpFcpFcDacpFcDccylcDdcAzcAycABcDmcDpcACcAEcwgcDtcAFcDwcAIcAKcumcAMcALcumcAScumcBfcuocBgcBicBhcBhcBjcDxcBVcBWcBWcBXcBYcAObPxcBZcvNcvNcCacCbcDFcCbcCacCdcvNcrGcDIcrGaaaaaaaaaaaaaaaaaacqvctFcDLcuVctFcDNcChcDOctFcCjcCkcqycgvcBtcCkcCocrHaaaaaaaaaaaaaaaaaacgwaafcdOcDUcCKclUcomclscDXclqcomclocEbclWcdOaaaaaacrPaaactXctXctXctXctXaafckxaafctXctXctXctXctXaafcrPaaaczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacbOaaaaaaaaaaaIaaaaaacAdcpFcqXcpFcCQcylcqXcpFcCYcylcqXcpFcAucylcpFcpFcDacpFcDccylcDdcAzcAycABcDmcDpcACcAEcwgcDtcAFcDwcAIcAKcumcAMcALcumcAScumcBfcuocBgcBicBhcBhcBjcDxcBWcBWcBWcBXcBYcAObPxcBZcvNcvNcCacCbcDFcCbcCacCdcvNcrGcDIcrGaaaaaaaaaaaaaaaaaacqvctFcDLcuVctFcDNcChcDOctFcCjcCkcqycgvcBtcCkcCocrHaaaaaaaaaaaaaaaaaacgwaafcdOcDUcCKclUcomclscDXclqcomclocEbclWcdOaaaaaacrPaaactXctXctXctXctXaafckxaafctXctXctXctXctXaafcrPaaaczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrPaafaafaafaaIaafaafcAdcpFcEecBycBxcEicEfcBCcBBcEqcEjcBGcBFcErcpFcBvcEycEBcBJcBMcEEcnycnycnycnycnycnycnycnycEJcBNczAcBPcBQcoTcEXcoTcoTcxucoTcoTcEZcoTcBQcBTcCpcBUcCrcFecFrcFgcCPcFCcAObPwcCRcCScCTcCacAGcAVcBwcCacCtcCscCucFEcCXaaaaaaaaaaaaaaaaaacqvcFFctDcuQcFKcDbcuQcFUcFLcDeaafaaachxcCxcCwcCyaaaaaaaaaaacaaaaaaaaaaaaaaacdOcDhcplcplcomcDicplcplcomcDicplcplcdOaafaafcrPaafckVckSckSckSckSckyckxckwckvckvckvckvckUaafcrPaaaczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrPcCzaaaaaaaaIaaaaaacCAcCCcFVcCEcCDcCGcFWcCHcCDcCGcFWcCHcCDcCGcCIcCIcGgcCHcCDcCGcGhcnyaaacCMcCLcCVcCUcCZcCWcDjcDgcDkcDkcGocDlcDocDncDqcGucDncDqcDocDrcGvcDscDrczAczAcAOcGEcGAcDPcDQcAObNUcDRcDScDTcCacCbcGMcCbcCacDvcDucDfaafaaaaaaaaaaaaaaaaaaaaacqvcFFcDVcGZcGOcGOcGZcsPcDYcqvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdOcDZcplcplcomcEacplcplcomcEacplcplcdOaaaaaacrPaafcwjcwjcwjcwjcwjaaackxaaacwjcwjcwjcwjcwjaaacrPaaaczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrPcHacHjcHjcHCcHjcHjcHjcHjcHVcHjcIAcHjcHVcHjcIAcHjcHVcHjcIAcHjcHjcHjcIAcHjcIAcHjcIMaafaaacDzcDycDBcDAcDDcDCcDjcDEcDkcIRcDHcDGcDJcITcIZcDKcDWcDMcDJcJhcEdcJlcDraaaaafcAOcJpcECcEDaafaaabNUbPxbPxbSkcCaclZcEFclYcCaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacqvcJzcuXcJBcJAcJAcJBcuQcEKcqvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdOcplcplcplcomcELcplcplcomcELcplcplcdOaacaaacrPaaaaaaaafaafaafaaaaaacmTaafaaaaaaaafaafaaaaaacrPaaaczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLczLaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/maps/exodus-2.dmm b/maps/exodus-2.dmm index 0ad7c5cb128..a1729c1e029 100644 --- a/maps/exodus-2.dmm +++ b/maps/exodus-2.dmm @@ -1086,7 +1086,7 @@ "uT" = (/obj/machinery/door/window/northleft,/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/centcom/control) "uU" = (/obj/effect/landmark{name = "Marauder Exit"},/turf/unsimulated/floor{name = "plating"},/area/centcom/specops) "uV" = (/turf/unsimulated/floor{name = "plating"},/area/centcom/specops) -"uW" = (/obj/machinery/door/blast/regular{icon_state = "pdoor1"; id = "CREED"; name = "Ready Room"; p_open = 0},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) +"uW" = (/obj/machinery/door/blast/regular{id = "ert_synth_equipment"; name = "Synthetics Modification Equipment"},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "uX" = (/turf/unsimulated/floor{icon_state = "warnplate"; dir = 8},/area/centcom/specops) "uY" = (/turf/unsimulated/floor{icon_state = "warnplate"; dir = 4},/area/centcom/specops) "uZ" = (/obj/machinery/mass_driver{dir = 8; id = "ASSAULT3"; name = "gravpult"},/turf/unsimulated/floor{icon_state = "bot"},/area/centcom/specops) @@ -1128,7 +1128,7 @@ "vJ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/unsimulated/floor{name = "plating"},/area/centcom/control) "vK" = (/obj/machinery/vending/tool,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) "vL" = (/obj/structure/sign/poster{poster_type = "/datum/poster/bay_50"; pixel_x = -32},/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start) -"vM" = (/obj/structure/table/woodentable{dir = 10},/obj/machinery/button/remote/blast_door{id = "CREED"; name = "Spec Ops Ready Room"; pixel_y = 4; req_access = list(108)},/obj/machinery/button/remote/blast_door{icon_state = "doorctrl0"; id = "ASSAULT"; name = "Mech Storage"; pixel_y = -4; req_access = list(108)},/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/creed) +"vM" = (/obj/item/weapon/aiModule/nanotrasen,/obj/item/weapon/aiModule/reset,/obj/item/weapon/aiModule/freeformcore,/obj/item/weapon/aiModule/protectStation,/obj/item/weapon/aiModule/quarantine,/obj/item/weapon/aiModule/paladin,/obj/item/weapon/aiModule/robocop,/obj/item/weapon/aiModule/safeguard,/obj/structure/table/rack,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) "vN" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{id = "skipjackshutters"; name = "Skipjack Blast Shielding"},/turf/simulated/shuttle/plating,/area/skipjack_station/start) "vO" = (/obj/machinery/door/airlock/centcom{name = "Maintenance Access"; opacity = 1; req_access = list(106)},/turf/unsimulated/floor{icon_state = "dark"},/area/centcom/control) "vP" = (/obj/mecha/combat/gygax/dark,/obj/machinery/camera/network/ert{c_tag = "Assault Armor North"},/turf/unsimulated/floor{icon_state = "delivery"; dir = 6},/area/centcom/specops) @@ -1166,7 +1166,7 @@ "wv" = (/obj/structure/window/reinforced{dir = 4},/turf/unsimulated/floor{icon_state = "floor"},/area/centcom/control) "ww" = (/obj/structure/bed/chair{dir = 1},/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/centcom/control) "wx" = (/obj/mecha/working/ripley/firefighter,/turf/unsimulated/floor{icon_state = "delivery"; dir = 6},/area/centcom/specops) -"wy" = (/obj/item/weapon/circuitboard/aiupload,/obj/item/weapon/circuitboard/borgupload,/obj/item/weapon/circuitboard/smes,/obj/item/weapon/aiModule/nanotrasen,/obj/item/weapon/aiModule/reset,/obj/item/weapon/aiModule/freeformcore,/obj/item/weapon/aiModule/protectStation,/obj/item/weapon/aiModule/quarantine,/obj/item/weapon/aiModule/paladin,/obj/item/weapon/aiModule/robocop,/obj/item/weapon/aiModule/safeguard,/obj/structure/table/steel_reinforced,/turf/unsimulated/floor{icon_state = "vault"; dir = 1},/area/centcom/specops) +"wy" = (/obj/machinery/portable_atmospherics/canister/air,/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "wz" = (/obj/machinery/door/airlock/centcom{name = "Maintenance Access"; opacity = 1; req_access = list(106)},/turf/unsimulated/floor{icon_state = "delivery"},/area/centcom/control) "wA" = (/obj/structure/sign/securearea,/turf/unsimulated/wall,/area/centcom/control) "wB" = (/obj/machinery/door/airlock/centcom{name = "Teleporter Bay"; opacity = 1; req_access = list(107)},/turf/unsimulated/floor{icon_state = "delivery"},/area/centcom/control) @@ -1940,9 +1940,13 @@ "Lp" = (/obj/item/pizzabox/meat,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) "Lq" = (/obj/structure/bed,/obj/item/weapon/bedsheet/rd,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) "Lr" = (/obj/structure/bed,/obj/item/weapon/bedsheet/clown,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/skipjack_station/start) +"Ls" = (/obj/structure/table/rack,/obj/item/weapon/circuitboard/borgupload,/obj/item/weapon/circuitboard/aiupload{pixel_x = -3; pixel_y = -3},/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) +"Lt" = (/obj/structure/table/woodentable{dir = 10},/obj/machinery/button/remote/blast_door{id = "CREED"; name = "Spec Ops Ready Room"; pixel_x = -5; pixel_y = 4; req_access = list(108)},/obj/machinery/button/remote/blast_door{icon_state = "doorctrl0"; id = "ASSAULT"; name = "Mech Storage"; pixel_x = -5; pixel_y = -4; req_access = list(108)},/obj/machinery/button/remote/blast_door{id = "ert_synth_equipment"; name = "Synth Modification Equipment"; pixel_x = 5; pixel_y = -4; req_access = list(108)},/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/creed) "Lu" = (/turf/unsimulated/floor{tag = "icon-ironsand7"; icon_state = "ironsand7"},/turf/unsimulated/floor{tag = "icon-asteroid7"; name = "plating"; icon_state = "asteroid7"},/area/wizard_station) "Lv" = (/turf/unsimulated/floor{tag = "icon-ironsand12"; icon_state = "ironsand12"},/turf/unsimulated/floor{tag = "icon-asteroid2"; name = "plating"; icon_state = "asteroid2"},/area/wizard_station) +"Lw" = (/obj/structure/table/steel_reinforced,/obj/item/weapon/circuitboard/smes,/obj/item/weapon/circuitboard/smes,/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/centcom/specops) "Lx" = (/obj/structure/sign/nosmoking_2{pixel_x = 32},/turf/simulated/shuttle/floor{icon_state = "floor6"},/area/syndicate_station/start) +"Ly" = (/obj/machinery/door/airlock/centcom{name = "Special Operations"; opacity = 1; req_access = list(103)},/obj/machinery/door/blast/regular{icon_state = "pdoor1"; id = "CREED"; name = "Ready Room"; p_open = 0},/turf/unsimulated/floor{icon_state = "delivery"},/area/centcom/specops) "Lz" = (/turf/simulated/floor/holofloor{icon_state = "carpet7-3"; dir = 4},/area/holodeck/source_theatre) "LA" = (/turf/simulated/floor/holofloor/grass,/turf/simulated/floor/holofloor{icon_state = "wood_siding1"; dir = 2},/obj/structure/flora/ausbushes/ywflowers,/turf/simulated/floor/holofloor{icon_state = "wood_siding5"; dir = 2},/area/holodeck/source_picnicarea) "LB" = (/turf/simulated/floor/holofloor{icon_state = "carpet11-12"; dir = 4},/area/holodeck/source_theatre) @@ -2186,16 +2190,16 @@ aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMjHoUoVoVoVqRpepepepepepepepepepeqHoVoVoVoVpFpFtctdpFpFpFtctetdpFqvqvqvpFtftgtgtgtgtgthpFpZqztitjqYqYqYtktlqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMmumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMjHoUoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVoVpFtptptptptptptptptppFpFumpFpFtptptptptptptppFpZqztrtstttttttstuqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvyhyhyhyhyhyhyhtptptptxtxtxtxtxtxpFtytztypFtxtxtxtxtxtxtxtxpZqzqztAtBtBtBtCqzqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuntvupuxuuuzuyuAtvveuhvfvfvkvgvpvpvyvyyhzdyIyIyIyIvzvAvHvAvJtOtPtQtRtSpFtytztypFtTtUtVtWtWtxaMaMpZqzqzqzqzqzqzqzqzqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvAgtvuhuhuhuhuhuhtvvKuhuhuhuhuhuhuhuhuhyhyByIvMyIyIvEurururvOueufufufufpFtytztypFtWtWtWtWtWtxaMaMugugugugugugugugugugugtxtxtxtxtxtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvPvbuvuwvQuhuhuhuhuhuhuhvRtvvSuhuhuhuhuhuhuhuhuhyhyHvTzqyIyIvzvAvHvAvJueufufufufpFvUumwhpFtWtWtWtWtWtxuguguguguguguowjuqtxurururtxururururururururtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVAIuXuVuVuVuYAIuZvavbvbvctvwluhuhuhuhuhuhuhtvwmuhuhuhuhvpwownwpwpyhzrzpzEyIyIyhwqwqwqtvuDuEuFuGuHtxuIuIuItxtWtWtWtWtWtxuJuKuJuLuMuguNuNuNuOurururuOuruPuQuPuruRuSuTtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvQtvtvtvuhuhuhuhuhuhuhuhtvuhuhuhuhwytvtvtvtvtvyhyhyhyhyhyhyhxQxQxQtvwzwAvlvmvntxufJyuftxvlvmvowAwBtxvqvrvqvrvqugtxtxtxtxurururtxvsvtuPvuvsvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvIvbvbwEtvvxwPukxowVwXuhuhtvuhuhuhuhwYtvxawZwZxaxcxbxexdxQxQxQxQxQxgtvufufvBvCvCvCvCvCvCvCvCvCvDufufxhvqvqvqvqvqugvFuNuotxurururtxvGvGxkvGvGvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVwWuXuVuVuVuYwWwivavbvbxltvwFwGwGwGwItvuhuhtvuhuhuhuhxmtvuhxQxQxQxnxQxQxQxQxQxQxQxQxptvufJyvVvWvXvXvXvXvXvXvXvYueJyufugvZwawbwcwdugweuNwjtxurururtxwfwfuNwfwfvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMwgaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvuntvupuxuuuzuyuAtvvMuWuhwyvkvgvfvfvyvyyhzdyIyIyIyIvzvAvHvAvJtOtPtQtRtSpFtytztypFtTtUtVtWtWtxaMaMpZqzqzqzqzqzqzqzqzqAjIaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvtvtvtvtvtvtvAgtvuhuhuhuhuhuhtvLsuWuhuhuhuhuhuhuhuhyhyByILtyIyIvEurururvOueufufufufpFtytztypFtWtWtWtWtWtxaMaMugugugugugugugugugugugtxtxtxtxtxtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvPvbuvuwvQuhuhuhuhuhuhuhvRtvtvtvuhuhuhuhuhuhuhuhyhyHvTzqyIyIvzvAvHvAvJueufufufufpFvUumwhpFtWtWtWtWtWtxuguguguguguguowjuqtxurururtxururururururururtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVAIuXuVuVuVuYAIuZvavbvbvctvwluhuhuhuhuhuhuhtvveuhuhuhvpvpwownwpwpyhzrzpzEyIyIyhwqwqwqtvuDuEuFuGuHtxuIuIuItxtWtWtWtWtWtxuJuKuJuLuMuguNuNuNuOurururuOuruPuQuPuruRuSuTtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvQtvtvtvuhuhuhuhuhuhuhuhtvvKuhuhuhLwtvtvtvtvtvyhyhyhyhyhyhyhxQxQxQtvwzwAvlvmvntxufJyuftxvlvmvowAwBtxvqvrvqvrvqugtxtxtxtxurururtxvsvtuPvuvsvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutvIvbvbwEtvvxwPukxowVwXuhuhtvvSuhuhuhwYtvxawZwZxaxcxbxexdxQxQxQxQxQxgtvufufvBvCvCvCvCvCvCvCvCvCvDufufxhvqvqvqvqvqugvFuNuotxurururtxvGvGxkvGvGvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVwWuXuVuVuVuYwWwivavbvbxltvwFwGwGwGwItvuhuhtvwmuhuhuhxmtvuhxQxQxQxnxQxQxQxQxQxQxQxQxptvufJyvVvWvXvXvXvXvXvXvXvYueJyufugvZwawbwcwdugweuNwjtxurururtxwfwfuNwfwfvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMwgaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutwxvbvbxqxcxrxtxsxvxuxcuhuhxcuhuhuhuhxwxcuhxQxQuwxxxQxQxQxexetvtvtvtvtvufufvVwrwsufwtwuwvufwswrueufufugugugugugugugweuNwjtxurururtxwwwwuNwwwwvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVxyuXuVuVuVuYxyxzvavbvbxAxnxHuhuhuhxIxnuhuhxnuhuhxKxJxLxnxMxQxQxQtvwFwGwHwGwItvwJwJwJxNufufwKwLwMwNwOxOwQwRwSwLwTufufxRwUwUwUwUwUtxtxuOtxtxtxuOtxtxuNuNuNuNuNvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumu -aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutxXvbvbxYtvyauhuhuhuhtvybybtvycyctvtvtvtvxMxQxQuwuWxfxfxfxfxfydxfxfxfydufufufyeufufxiufxiufufyeufufufxjurururururxjurururururururxjwwwwwwwwwwvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmu +aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvutxXvbvbxYtvyauhuhuhuhtvybybtvycyctvtvtvtvxMxQxQuwyWxfxfxfxfxfydxfxfxfLyufufufyeufufxiufxiufufyeufufufxjurururururxjurururururururxjwwwwwwwwwwvvvwvwtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMmu aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMuUuVuVuVuVuVuVuVuVuVuVuVuVuVyfuXuVuVuVuYyfygyivbvbuwyjuhuhuhuhuhyjuhuhykuhuhymylyzyzuhxQxQvdtvwFwGwHwGwItvxBxBxByAufufvBxCxDwNxEufxFwRxGxCvDufufxjurururururxjurururururururxjwwwwwwwwwwtxuOuOtxtxtxtxtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMustvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvtvvbvbuwyjuhuhuhuhuhyjuhuhyCuhuhxQyDyDyDxQxQxQzcyKyGyMxQySyQtvtvtvtvtvufufvVwLxSufxiufxikayqwLueufufwAxTxUxUxUxVtxtxxWtxtxtxuOtxtxtxyXyXyXtxtxurururyYurxZtxaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM aMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMtvvbvbyZtvwFwGwGwGwItvzezetvzfuhxQzgzizhxQxQxQyRzkyMxQxQxQxQxxxQxKzltvufufvVtxtxynyoufypxStxtxueufuftxaMaMaMaMaMtxyrystxuNytuNuNyuyvywywywzmtxururuQuQururyyaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmtaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMmumumumumuaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaMaM diff --git a/maps/exodus-4.dmm b/maps/exodus-4.dmm index 668fdc33a87..bce4896cbbd 100644 --- a/maps/exodus-4.dmm +++ b/maps/exodus-4.dmm @@ -87,7 +87,7 @@ "bI" = (/obj/machinery/drone_fabricator/derelict,/turf/simulated/floor/plating/airless,/area/constructionsite/ai) "bJ" = (/turf/simulated/floor/airless{tag = "icon-gcircuit"; icon_state = "gcircuit"},/area/constructionsite/ai) "bK" = (/obj/machinery/computer/drone_control,/turf/simulated/floor/plating/airless,/area/constructionsite/ai) -"bL" = (/obj/machinery/power/apc/high{dir = 1; name = "north bump"; pixel_y = 24},/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating/airless,/area/constructionsite/ai) +"bL" = (/obj/machinery/power/apc/high{dir = 1; environ = 0; equipment = 0; lighting = 0; locked = 0; name = "north bump"; pixel_y = 24},/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating/airless,/area/constructionsite/ai) "bM" = (/obj/machinery/door/airlock/highsecurity{name = "Messaging Server"; req_access = list(30)},/turf/simulated/floor/plating/airless,/area/constructionsite/hallway/fore) "bN" = (/obj/machinery/door/airlock/highsecurity{name = "Messaging Server"; req_access = list(30)},/turf/simulated/floor/plating/airless,/area/constructionsite/ai) "bO" = (/obj/machinery/door/airlock/highsecurity{name = "Cyborg Station"; req_access = list(16)},/turf/simulated/floor/plating/airless,/area/constructionsite/ai) @@ -116,7 +116,7 @@ "cl" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating/airless,/area/constructionsite/engineering) "cm" = (/obj/structure/cable/blue,/turf/simulated/floor/plating/airless,/area/constructionsite/engineering) "cn" = (/obj/machinery/power/emitter{anchored = 1; dir = 4; state = 2},/turf/simulated/floor/plating/airless,/area/space) -"co" = (/obj/machinery/power/emitter{anchored = 1; dir = 8; id = "EngineEmitter"; state = 2},/turf/simulated/floor/plating/airless,/area/space) +"co" = (/obj/machinery/power/emitter{anchored = 1; dir = 8; id = null; state = 2},/turf/simulated/floor/plating/airless,/area/space) "cs" = (/obj/machinery/recharge_station,/turf/simulated/floor/plating/airless,/area/constructionsite/ai) "cI" = (/obj/machinery/door/airlock/maintenance_hatch,/turf/simulated/wall,/area/constructionsite/hallway/fore) "cJ" = (/obj/structure/lattice,/turf/space,/area/constructionsite/hallway/fore) diff --git a/maps/exodus-5.dmm b/maps/exodus-5.dmm index 17b6e221430..49e21dc47db 100644 --- a/maps/exodus-5.dmm +++ b/maps/exodus-5.dmm @@ -1160,7 +1160,7 @@ "wp" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{dir = 8; icon_state = "map"; tag = "icon-manifold-f (WEST)"},/turf/simulated/floor/plating,/area/outpost/engineering/hallway) "wq" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/structure/grille,/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock"},/turf/simulated/floor/plating,/area/outpost/engineering/hallway) "wr" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'KEEP CLEAR OF DOCKING AREA'."; name = "KEEP CLEAR: DOCKING AREA"; pixel_y = 0},/turf/simulated/wall,/area/outpost/engineering/hallway) -"ws" = (/obj/machinery/power/emitter{anchored = 1; dir = 4; state = 2},/turf/simulated/floor/airless{dir = 5; icon_state = "asteroidfloor"},/area/mine/explored) +"ws" = (/obj/machinery/power/emitter{anchored = 0; dir = 4; state = 0},/turf/simulated/floor/airless{dir = 5; icon_state = "asteroidfloor"},/area/mine/explored) "wt" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor,/area/outpost/engineering/atmospherics) "wu" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{tag = "icon-map (EAST)"; icon_state = "map"; dir = 4},/turf/simulated/floor,/area/outpost/engineering/atmospherics) "wv" = (/turf/simulated/floor,/area/outpost/engineering/atmospherics) diff --git a/sound/effects/creepyshriek.ogg b/sound/effects/creepyshriek.ogg new file mode 100644 index 00000000000..86933130d5d Binary files /dev/null and b/sound/effects/creepyshriek.ogg differ diff --git a/tools/mapmerge/1prepare_map.bat b/tools/mapmerge/1prepare_map.bat index 2092086bf7f..365d5f00e82 100644 --- a/tools/mapmerge/1prepare_map.bat +++ b/tools/mapmerge/1prepare_map.bat @@ -1,8 +1,7 @@ -SET z_levels=6 cd ../../maps -FOR /L %%i IN (1,1,%z_levels%) DO ( - copy exodus-%%i.dmm exodus-%%i.dmm.backup +FOR %%f IN (*.dmm) DO ( + copy %%f %%f.backup ) pause diff --git a/tools/mapmerge/2clean_map.bat b/tools/mapmerge/2clean_map.bat index 84cbfd5d359..a719963df43 100644 --- a/tools/mapmerge/2clean_map.bat +++ b/tools/mapmerge/2clean_map.bat @@ -1,8 +1,8 @@ SET z_levels=6 cd -FOR /L %%i IN (1,1,%z_levels%) DO ( - java -jar MapPatcher.jar -clean ../../maps/exodus-%%i.dmm.backup ../../maps/exodus-%%i.dmm ../../maps/exodus-%%i.dmm +FOR %%f IN (../../maps/*.dmm) DO ( + java -jar MapPatcher.jar -clean ../../maps/%%f.backup ../../maps/%%f ../../maps/%%f ) -pause \ No newline at end of file +pause diff --git a/tools/mapmerge/clean_map_git.sh b/tools/mapmerge/clean_map_git.sh index e8ad8165e49..25cef6da93a 100755 --- a/tools/mapmerge/clean_map_git.sh +++ b/tools/mapmerge/clean_map_git.sh @@ -1,10 +1,9 @@ -#!/bin/bash +#!/bin/sh -for i in {1..6} +for MAPFILE in ../../maps/*.dmm do - MAPFILE="exodus-$i.dmm" - - git show HEAD:maps/$MAPFILE > tmp.dmm - java -jar MapPatcher.jar -clean tmp.dmm '../../maps/'$MAPFILE '../../maps/'$MAPFILE + MAPNAME=$(basename $MAPFILE) + git show HEAD:maps/$MAPNAME > tmp.dmm + java -jar MapPatcher.jar -clean tmp.dmm $MAPFILE $MAPFILE rm tmp.dmm done diff --git a/tools/mapmerge/mapmerge.sh b/tools/mapmerge/mapmerge.sh index 145537f7ca7..9e347ceaa2a 100755 --- a/tools/mapmerge/mapmerge.sh +++ b/tools/mapmerge/mapmerge.sh @@ -4,6 +4,6 @@ then echo "Unable to automatically resolve map conflicts, please merge manually." exit 1 fi -java -jar tools/mapmerge/MapPatcher.jar -clean $1 $2 $2 +java -jar tools/mapmerge/MapPatcher.jar -clean $3 $2 $2 exit 0